Some quality review. Made keyboard time milliseconds.

This commit is contained in:
lephe 2017-03-26 18:38:32 +02:00
parent 39fedcd271
commit c8170b165a
79 changed files with 1482 additions and 1175 deletions

View file

@ -13,7 +13,7 @@ include Makefile.cfg
# Modules
modules-gint = bopti clock core display events gray keyboard mmu rtc \
screen tales timer
modules-libc = setjmp stdio stdlib string time
modules-libc = ctype setjmp stdio stdlib string time
# Targets
target-lib = libgint.a

4
TODO
View file

@ -23,8 +23,8 @@ Larger improvements:
* core: Allow return to menu
- serial: Implement a driver
- usb: Implement a driver
- esper: Cleaner playback, synthetizing
- clock: Handle overclocking (relaunch clocks when overclocking)
- esper: Cleaner playback, synthesizing
- clock: Handle overclock (relaunch clocks when overclocking)
- project: Unify this hellish mess of register access!
Things to investigate:

View file

@ -288,7 +288,7 @@ void main_menu(int *category, int *app)
// Quite a few things to declare...
//---
extern Image res_opt_menu;
extern image_t res_opt_menu;
const char *mpu, *mpu_names[] = {
"Unknown",
@ -332,7 +332,7 @@ void main_menu(int *category, int *app)
int i;
mpu = mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5];
text_configure(NULL, Color_Black);
text_configure(NULL, color_black);
while(1)
{
@ -386,8 +386,8 @@ void main_menu(int *category, int *app)
if(scroll > 0) locate(20, 2, "\x0d");
if(scroll + 6 < list_len) locate(20, 7, "\x0e");
dreverse_area(0, 8 * (index - scroll) + 8, 127,
8 * (index - scroll) + 15);
drect(0, 8 * (index - scroll) + 8, 127,
8 * (index - scroll) + 15, color_invert);
}
dupdate();
@ -495,8 +495,6 @@ int main(void)
{
int category, app;
sleep_ms(2000);
while(1)
{
main_menu(&category, &app);

View file

@ -23,7 +23,7 @@
---------------------------------------------------------
*/
static void getwh(Image *img, int *width, int *height)
static void getwh(image_t *img, int *width, int *height)
{
const uint8_t *data;
@ -42,7 +42,7 @@ static void getwh(Image *img, int *width, int *height)
*height = (data[2] << 8) | data[3];
}
static void getxy(Image *img, int *x, int *y)
static void getxy(image_t *img, int *x, int *y)
{
int width, height;
@ -51,10 +51,10 @@ static void getxy(Image *img, int *x, int *y)
*y = 28 - (height >> 1);
}
static Image *select(Image *current)
static image_t *select(image_t *current)
{
extern Image res_bopti_thumbs;
extern Image
extern image_t res_bopti_thumbs;
extern image_t
res_items,
res_sprites,
res_swords,
@ -62,7 +62,7 @@ static Image *select(Image *current)
res_isometric;
struct {
Image *img;
image_t *img;
const char *name;
const char *info;
} images[] = {
@ -74,7 +74,7 @@ static Image *select(Image *current)
{ NULL, NULL, NULL }
};
Image *thumbs = &res_bopti_thumbs;
image_t *thumbs = &res_bopti_thumbs;
int items = 0;
static int row = 0;
int leave = 1, i;
@ -106,7 +106,7 @@ static Image *select(Image *current)
}
}
greverse_area(0, 8 * row + 8, 128, 8 * row + 23);
grect(0, 8 * row + 8, 128, 8 * row + 23, color_invert);
gupdate();
do
@ -138,8 +138,8 @@ static Image *select(Image *current)
void test_bopti(void)
{
extern Image res_opt_bitmap;
Image *img = NULL;
extern image_t res_opt_bitmap;
image_t *img = NULL;
int leave = 1;
int black_bg = 0;
@ -152,10 +152,10 @@ void test_bopti(void)
gray_start();
gclear();
if(black_bg) greverse_area(0, 0, 127, 63);
if(black_bg) grect(0, 0, 127, 63, color_invert);
if(img) gimage(x, y, img);
gclear_area(0, 55, 127, 63);
grect(0, 55, 127, 63, color_white);
gimage(0, 56, &res_opt_bitmap);
gupdate();
}
@ -164,10 +164,10 @@ void test_bopti(void)
gray_stop();
dclear();
if(black_bg) dreverse_area(0, 0, 127, 63);
if(black_bg) drect(0, 0, 127, 63, color_invert);
if(img) dimage(x, y, img);
dclear_area(0, 55, 127, 63);
drect(0, 55, 127, 63, color_white);
dimage(0, 56, &res_opt_bitmap);
dupdate();
}

View file

@ -10,9 +10,9 @@
static void draw(int delay1, int delay2, int selected)
{
extern Image res_opt_gray;
unsigned int *vl = gray_lightVRAM();
unsigned int *vd = gray_darkVRAM();
extern image_t res_opt_gray;
uint32_t *vl = gray_lightVRAM();
uint32_t *vd = gray_darkVRAM();
gclear();
locate(1, 1, "Gray engine");
@ -58,7 +58,7 @@ void test_gray(void)
}
changed = 0;
key = getkey_opt(Getkey_RepeatArrowKeys, 1);
key = getkey_opt(getkey_repeat_arrow_keys, 25);
if(key == KEY_EXIT) break;
changed = 1;

View file

@ -31,24 +31,24 @@ static void draw_keyboard(volatile uint8_t *state)
{
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);
dpixel(x + k, y + l, color_black);
}
// Drawing a square border otherwise.
else
{
for(k = -1; k <= 1; k++) for(l = -1; l <= 1; l++)
if(k || l) dpixel(x + k, y + l, Color_Black);
if(k || l) dpixel(x + k, y + l, color_black);
}
}
// Binding the arrow keys together for a more visual thing.
dpixel(28, 19, Color_Black); dpixel(29, 19, Color_Black);
dpixel(28, 24, Color_Black); dpixel(29, 24, Color_Black);
dpixel(26, 21, Color_Black); dpixel(26, 22, Color_Black);
dpixel(31, 21, Color_Black); dpixel(31, 22, Color_Black);
dpixel(28, 19, color_black); dpixel(29, 19, color_black);
dpixel(28, 24, color_black); dpixel(29, 24, color_black);
dpixel(26, 21, color_black); dpixel(26, 22, color_black);
dpixel(31, 21, color_black); dpixel(31, 22, color_black);
// An horizontal line to separate parts of the keyboard.
dline(5, 28, 32, 28, Color_Black);
dline(5, 28, 32, 28, color_black);
}
typedef struct {
@ -64,7 +64,7 @@ static void push_history(enhanced_event_t *history, int size, event_t event)
// Determining where the history ends.
int length = 0;
while(length < size && history[length].type != ET_None) length++;
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))
@ -105,10 +105,10 @@ static void draw_events(enhanced_event_t *history, int size)
"None ", "User ", "Press", "Rept.", "Rel. ", "Timer"
};
for(int i = 0; i < size && history[i].type != ET_None; i++)
for(int i = 0; i < size && history[i].type != event_none; i++)
{
print(8, 3 + i, "%s %s", event_names[history[i].type],
key_names[keyid(history[i].key)]);
key_names[key_id(history[i].key)]);
if(history[i].repeats > 1)
print(19, 3 + i, "%d", history[i].repeats);
}
@ -124,18 +124,19 @@ void test_keyboard_events(void)
int history_size = 5;
event_t event;
for(int i = 0; i < history_size; i++) history[i].type = ET_None;
for(int i = 0; i < history_size; i++) history[i].type = event_none;
while(1)
{
dclear();
locate(1, 1, "Keyboard and events");
draw_keyboard(keystate());
draw_keyboard(keyboard_stateBuffer());
draw_events(history, history_size);
dupdate();
event = waitevent();
if(event.type == ET_KeyPress && event.key == KEY_EXIT) break;
if(event.type == event_key_press && event.key == KEY_EXIT)
break;
push_history(history, history_size, event);
}
}

View file

@ -18,7 +18,7 @@
static void draw(rtc_time_t time)
{
extern Image res_rtc_segments;
extern image_t res_rtc_segments;
const char *days[7] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
@ -42,7 +42,7 @@ static void draw(rtc_time_t time)
12 * digits[i], 0, 11, 19);
// Drawing ':' between pairs of digits.
for(i = 0; i < 16; i++) dpixel(47 + 32 * (i >= 8) + (i & 1),
14 + 5 * !!(i & 4) + !!(i & 2), Color_Black);
14 + 5 * !!(i & 4) + !!(i & 2), color_black);
// This should print time.year + 1900 but for the sake of this demo we
// have tweaked the field so that it already contains time.year + 1900.
@ -52,7 +52,7 @@ static void draw(rtc_time_t time)
static void callback(void)
{
extern Image res_opt_rtc;
extern image_t res_opt_rtc;
rtc_time_t time = rtc_getTime();
dclear();
@ -115,8 +115,8 @@ static void set_region(rtc_time_t *time, int region, int value)
static void set(void)
{
extern Image res_opt_rtc;
Image *opt = &res_opt_rtc;
extern image_t res_opt_rtc;
image_t *opt = &res_opt_rtc;
struct {
int x, y;
@ -136,8 +136,8 @@ static void set(void)
{
dclear();
draw(time);
dreverse_area(regions[n].x, regions[n].y, regions[n].x
+ regions[n].w - 1, regions[n].y + regions[n].h - 1);
drect(regions[n].x, regions[n].y, regions[n].x + regions[n].w
- 1, regions[n].y + regions[n].h - 1, color_invert);
if(n == 6) dimage_part(0, 56, opt, 0, 9 * (1 + slide), 128, 8);
if(n == 7) dimage_part(0, 56, opt, 0, 9 * (3 + slide), 128, 8);
@ -191,9 +191,9 @@ static void set(void)
else leave = 0;
}
else if(isdigit(keychar(key))) // Numbers
else if(isdigit(key_char(key))) // Numbers
{
int val = keychar(key) - '0';
int val = key_char(key) - '0';
int ok = 1;
if(n == 0) ok = (val <= 2);

View file

@ -27,7 +27,7 @@ static Font *select(Font *current)
while(1)
{
text_configure(NULL, Color_Black);
text_configure(NULL, color_black);
dclear();
locate(1, 1, "Select a font:");
@ -39,18 +39,18 @@ static Font *select(Font *current)
int height = fonts[i].font->line_height;
int y = (i + 2) * 8 - 8 + ((7 - height) >> 1);
text_configure(fonts[i].font, Color_Black);
text_configure(fonts[i].font, color_black);
dtext(7, y, fonts[i].name);
}
else
{
text_configure(NULL, Color_Black);
text_configure(NULL, color_black);
locate(2, i + 2, fonts[i].name);
}
}
dreverse_area(0, 8 * row + 8, 128, 8 * row + 15);
drect(0, 8 * row + 8, 128, 8 * row + 15, color_invert);
dupdate();
do
@ -80,9 +80,9 @@ static Font *select(Font *current)
void test_tales(void)
{
enum Color colors[] = { Color_Black, Color_Dark, Color_Light,
Color_White, Color_Invert };
extern Image res_opt_tales;
color_t colors[] = { color_black, color_dark, color_light, color_white,
color_invert };
extern image_t res_opt_tales;
Font *font = NULL;
int black_bg = 0;
@ -94,7 +94,7 @@ void test_tales(void)
while(1)
{
gclear();
if(black_bg) greverse_area(0, 0, 127, 54);
if(black_bg) grect(0, 0, 127, 54, color_invert);
if(font)
{
@ -119,10 +119,10 @@ void test_tales(void)
gimage(0, 56, &res_opt_tales);
x = 45 + 8 * color;
gline(x, 57, x + 5, 57, Color_Black);
gline(x, 57, x, 62, Color_Black);
gline(x + 5, 57, x + 5, 62, Color_Black);
gline(x, 62, x + 5, 62, Color_Black);
gline(x, 57, x + 5, 57, color_black);
gline(x, 57, x, 62, color_black);
gline(x + 5, 57, x + 5, 62, color_black);
gline(x, 62, x + 5, 62, color_black);
gupdate();
@ -146,7 +146,7 @@ void test_tales(void)
case KEY_EXIT:
gray_stop();
text_configure(NULL, Color_Black);
text_configure(NULL, color_black);
return;
default:
leave = 0;

View file

@ -36,7 +36,7 @@ static void timing_timer(void)
static void timing_start(void)
{
uint32_t delay = clock_setting(64, Clock_Hz);
uint32_t delay = clock_setting(64, clock_Hz);
htimer = htimer_setup(timer_user, delay, timer_Po_4, 0);
timer_attach(htimer, timing_timer, NULL);
timer_start(htimer);
@ -59,8 +59,8 @@ static void timing_start(void)
*/
static void small_text(int x, int y, const char *text, int alignment)
{
extern Image res_clock_chars;
Image *chars = &res_clock_chars;
extern image_t res_clock_chars;
image_t *chars = &res_clock_chars;
const char *table = "0123456789kMHz*/";
if(alignment) x -= 2 * strlen(text) - 1, y -= 2;
@ -133,9 +133,9 @@ static void display_freq(int x, int y, int freq)
*/
static void draw(int tab)
{
extern Image res_opt_timer;
extern Image res_clock_7705;
extern Image res_clock_7305;
extern image_t res_opt_timer;
extern image_t res_clock_7705;
extern image_t res_clock_7305;
char buffer[16];
@ -163,14 +163,14 @@ static void draw(int tab)
small_text(84, 34, buffer, 1);
if(conf.Iphi_div1 == 1)
dline(85, 43, 99, 43, Color_Black);
dline(85, 43, 99, 43, color_black);
else
{
sprintf(buffer, "/%d", conf.Iphi_div1);
small_text(89, 41, buffer, 0);
}
if(conf.Pphi_div1 == 1)
dline(85, 50, 99, 50, Color_Black);
dline(85, 50, 99, 50, color_black);
else
{
sprintf(buffer, "/%d", conf.Pphi_div1);
@ -249,13 +249,13 @@ void test_timer(void)
elapsed_rtc = -1;
cb_id = rtc_cb_add(RTCFreq_64Hz, timing_start, 0);
text_configure(NULL, Color_Black);
text_configure(NULL, color_black);
while(1)
{
draw(tab);
switch(getkey_opt(Getkey_NoOption, 1))
switch(getkey_opt(getkey_none, 25))
{
case KEY_EXIT:
rtc_cb_end(cb_id);

View file

@ -3,12 +3,14 @@
// standard library module: alloca
//
// Allows dynamic memory allocation on the stack. Memory is automatically
// freed when the calling function exits.
// freed when the calling function exits, but this function suffers from
// risks of stack overflow; make sure you don't inline functions that use
// alloca or allocate more than a few hundred bytes with it.
//
//---
#ifndef _ALLOCA_H
#define _ALLOCA_H 1
#define _ALLOCA_H
#include <stddef.h>

67
include/bopti.h Normal file
View file

@ -0,0 +1,67 @@
//---
//
// gint drawing module: bopti
//
// This module is a powerful bitmap renderer. It *heavily* relies on the
// line-based structure of the video RAM as well as the high density of
// information. A single CPU access (longword operation) can affect 32
// pixels at once, which is crucial for performance. The same goes for all
// other drawing modules, but this one typically has 350 lines of code
// just to wrap these longword accesses -- and it's blazingly fast.
//
//---
#ifndef _BOPTI_H
#define _BOPTI_H
/*
image_t
This structure holds meta-data of a bitmap encoded with fxconv. Data is
accessed using longword operations for performance considerations,
which requires that the all fields of the structure be properly aligned
and of a correct size.
*/
typedef struct
{
uint8_t magic;
uint8_t format;
uint8_t width;
uint8_t height;
const uint32_t data[];
} __attribute__((packed, aligned(4))) image_t;
/*
dimage()
Displays a monochrome image in the vram. This function does a real lot
of optimization.
*/
void dimage(int x, int y, image_t *image);
/*
dimage_part()
Draws a portion of an image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void dimage_part(int x, int y, image_t *img, int left, int top, int width,
int height);
/*
gimage()
Displays a gray image in the dual-vram.
*/
void gimage(int x, int y, image_t *image);
/*
gimage_part()
Draws a portion of a gray image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void gimage_part(int x, int y, image_t *image, int left, int top, int width,
int height);
#endif // _BOPTI_H

View file

@ -2,8 +2,14 @@
//
// gint core module: clock
//
// Measures the frequency of the MPU clocks. This module assumes that the
// clock mode is 3 on SH7305 (as does FTune).
// This module interfaces with the MPU clocks and is used to measure the
// clock frequencies at the beginning of execution. At this stage, it
// assumes that clock mode 3 is used on SH7305 (as does FTune), because
// there doesn't seem to be a way of getting this information.
//
// It also provides some sleep and time conversion functions, and access
// to how the clocks are configured. In the future, it would be the module
// that supports overclock.
//
//---
@ -18,7 +24,12 @@
/*
sleep()
Puts the processor to sleep until an interrupt request is issued.
Puts the processor to sleep until an interrupt request is accepted.
This function should be called every time the program because idle
because it doesn't have anything to do -- between two game frames or
while waiting for a keyboard event.
This function is called by getkey_opt(), getkey(), waitevent(), this
module's sleep functions among others.
*/
void sleep(void);
@ -41,17 +52,29 @@ void sleep_us(int us_delay);
// Clock management.
//---
enum ClockUnit
/*
clock_unit_t
Enumerated type used by the time conversion functions. It indicates the
type (delay or frequency) of a parameter.
*/
typedef enum
{
Clock_us = 0,
Clock_ms = 1,
Clock_s = 2,
clock_us = 0,
clock_ms = 1,
clock_s = 2,
Clock_Hz = 10,
Clock_kHz = 11,
Clock_MHz = 12,
};
clock_Hz = 10,
clock_kHz = 11,
clock_MHz = 12,
} clock_unit_t;
/*
clock_config_t
A copy of the Clock Pulse Generator (CPG) configuration. Be sure to
check which MPU the program is running on (using <mpu.h>) to access the
right fields.
*/
typedef struct
{
union
@ -75,9 +98,9 @@ typedef struct
int RTCCLK_f; // SH7305
};
int Bphi_f;
int Iphi_f;
int Pphi_f;
int Bphi_f; // Bus clock frequency
int Iphi_f; // Processor clock frequency
int Pphi_f; // Peripheral clock frequency
} clock_config_t;
@ -86,10 +109,8 @@ typedef struct
Returns the P_phi / 4 timer setting that will last for the given time.
Several units can be used. Be aware that the result is approximate, and
very high frequencies or very short delays will yield important errors.
Normally you need not use this function when setting up timers because
timer_start() handles this conversion for you.
*/
uint32_t clock_setting(int duration, enum ClockUnit unit);
uint32_t clock_setting(int duration, clock_unit_t unit);
/*
clock_config()

View file

@ -7,78 +7,29 @@
//---
#ifndef _CTYPE_H
#define _CTYPE_H 1
#define _CTYPE_H
#include <stdint.h>
//---
// Character classes.
//---
extern uint8_t ctype_classes[0x80];
__attribute__((always_inline)) static inline int isalnum(int c) {
return ctype_classes[c] & 0xf0;
}
// Character classes.
#define isalnum(c) (ctype_classes[(int)(c)] & 0xf0)
#define isalpha(c) (ctype_classes[(int)(c)] & 0x30)
#define iscntrl(c) (ctype_classes[(int)(c)] & 0x01)
#define isdigit(c) (ctype_classes[(int)(c)] & 0x40)
#define isgraph(c) (ctype_classes[(int)(c)] & 0xf4)
#define islower(c) (ctype_classes[(int)(c)] & 0x10)
#define isprint(c) (ctype_classes[(int)(c)] & 0x08)
#define ispunct(c) (ctype_classes[(int)(c)] & 0x04)
#define isspace(c) (ctype_classes[(int)(c)] & 0x02)
#define isupper(c) (ctype_classes[(int)(c)] & 0x20)
#define isxdigit(c) (ctype_classes[(int)(c)] & 0x80)
#define isascii(c) ((unsigned)c <= 0x7f)
#define isblank(c) (c == '\t' || c == ' ')
__attribute__((always_inline)) static inline int isalpha(int c) {
return ctype_classes[c] & 0x30;
}
__attribute__((always_inline)) static inline int iscntrl(int c) {
return ctype_classes[c] & 0x01;
}
__attribute__((always_inline)) static inline int isdigit(int c) {
return ctype_classes[c] & 0x40;
}
__attribute__((always_inline)) static inline int isgraph(int c) {
return ctype_classes[c] & 0xf4;
}
__attribute__((always_inline)) static inline int islower(int c) {
return ctype_classes[c] & 0x10;
}
__attribute__((always_inline)) static inline int isprint(int c) {
return ctype_classes[c] & 0x08;
}
__attribute__((always_inline)) static inline int ispunct(int c) {
return ctype_classes[c] & 0x04;
}
__attribute__((always_inline)) static inline int isspace(int c) {
return ctype_classes[c] & 0x02;
}
__attribute__((always_inline)) static inline int isupper(int c) {
return ctype_classes[c] & 0x20;
}
__attribute__((always_inline)) static inline int isxdigit(int c) {
return ctype_classes[c] & 0x80;
}
__attribute__((always_inline)) static inline int isascii(int c) {
return ((unsigned)c <= 0x7f);
}
__attribute__((always_inline)) static inline int isblank(int c) {
return (c == '\t' || c == ' ');
}
//---
// Character manipulation.
//---
__attribute__((always_inline)) static inline int tolower(int c) {
return c | isupper(c);
}
__attribute__((always_inline)) static inline int toupper(int c) {
return c & ~(islower(c) << 1);
}
// Character manipulation.
#define tolower(c) ((c) | isupper(c))
#define toupper(c) ((c) & ~(islower(c) << 1))
#endif // _CTYPE_H

View file

@ -2,94 +2,107 @@
//
// gint drawing module: display
//
// Handles vram manipulation and drawing for plain monochrome display.
// This module does most of the monochrome drawing. It manages the video
// memory although image rendering and text rendering, as complex tasks,
// are left to other modules (bopti and tales, respectively).
//
//---
#ifndef _DISPLAY_H
#define _DISPLAY_H 1
#define _DISPLAY_H
#include <stdint.h>
#include <stddef.h>
//---
// Heading declarations.
// Drawing-related types and constants.
//---
enum Color
{
Color_White = 0,
Color_Light = 1,
Color_Dark = 2,
Color_Black = 3,
Color_None = 4,
Color_Invert = 5,
};
// This header needs enum Color to be defined.
#include <tales.h>
#define DWIDTH 128 /* Width of the screen */
#define DHEIGHT 64 /* Height of the screen */
/*
struct Image
This structure holds information about a bitmap encoded with fxconv.
Data is accessed using longword operations, which *requires* many
sizes to be multiples of 4 (structure alignment, data alignment, layer
size, ...).
color_t
Defines all colors that the library knows about:
- white is exactly what you think it is;
- light is a light gray used by the gray module;
- dark is a dark gray, also used by the gray engine;
- black is nothing more than black; (sorry)
- none means transparent, but is shorter to write.
There are also some transformation-associated colors:
- invert reverses the intensity of the color (white -> black, dark ->
light, etc);
- lighten is some kind of partially-transparent white. It lightens the
color which it is drawn onto (black -> dark, light -> light);
- lighten2 is the same as lighten, except it lightens more (black ->
light, light -> white);
- darken is the exact opposite of lighten (light -> dark, black ->
black).
- darken2 is the same to darken as lighten2 to lighten (white -> dark,
dark -> black);
All transformations except invert only operate when the gray engine is
running.
*/
struct Image
typedef enum
{
uint8_t magic;
uint8_t format;
color_white = 0,
color_light = 1,
color_dark = 2,
color_black = 3,
color_none = 4,
uint8_t width;
uint8_t height;
color_invert = 5,
color_lighten = 6,
color_lighten2 = 7,
color_darken = 8,
color_darken2 = 9,
const uint32_t data[];
} color_t;
} __attribute__((packed, aligned(4)));
// Useful shorthand for user code.
typedef struct Image Image;
// The bopti module provides bitmap rendering functions.
#include <bopti.h>
// A few other constants.
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 64
// The tales module provides text rendering functions but requires the color_t
// type definition.
#include <tales.h>
//---
// Generic functions.
// Video RAM management.
//---
/*
display_getLocalVRAM()
Returns the local video ram address. This function always return the
same address.
The buffer returned by this function should not be used directly when
running the gray engine.
Returns gint's local video RAM address. Gint does not use the system's
buffer because it is misaligned. This function always returns the same
address. Both the display and the gray module heavily use this buffer;
make sure you don't interfere with them if you access it.
This function does not necessarily returns the video ram that is
currently in use; call display_getCurrentVRAM() for this.
*/
void *display_getLocalVRAM(void);
uint32_t *display_getLocalVRAM(void);
/*
display_getCurrentVRAM()
Returns the current video ram. This function usually returns the
parameter of the last call to display_useVRAM(), unless the gray engine
is running (in which case the result is undefined). Returns the local
vram address by default.
Returns the current monochrome video ram buffer. This function usually
returns the parameter of the last call to display_useVRAM(), or the
local vram address (which is default when the library starts).
The return value of this function is undefined if the gray engine is
running.
*/
void *display_getCurrentVRAM(void);
uint32_t *display_getCurrentVRAM(void);
/*
display_useVRAM()
Changes the current video ram address. The argument MUST be a 4-
aligned 1024-byte buffer; otherwise any drawing operation will crash
the program.
Changes the current monochrome video ram address. The argument must be
a 4-aligned 1024-byte buffer because the library's design requires it.
This function refuses misaligned buffers but trusts that enough space
is available; failing to provide enough memory may crash the program.
This function will most likely have no effect when running the gray
engine.
*/
void display_useVRAM(void *vram);
void display_useVRAM(uint32_t *vram);
@ -99,30 +112,24 @@ void display_useVRAM(void *vram);
/*
dupdate()
Displays the vram on the physical screen. Does nothing when the gray
engine is running.
Pushes the video RAM to the physical screen. This function also works
when the gray engine is running, but that's probably not what you want.
*/
void dupdate(void);
/*
dclear()
Clears the whole video ram.
Clears the whole video ram, making all pixels white.
*/
void dclear(void);
/*
dclear_area()
Clears an area of the video ram. Both (x1, y1) and (x2, y2) are
cleared.
drect()
Draws a rectangle on the screen. This function can use any color which
is not associated with the gray engine, including the reverse operator.
Both end points (x1, y1) and (x2, y2) are affected as well.
*/
void dclear_area(int x1, int y1, int x2, int y2);
/*
dreverse_area()
Reverses an area of the vram. (x1, y1) and (x2, y2) are reversed as
well.
*/
void dreverse_area(int x1, int y1, int x2, int y2);
void drect(int x1, int y1, int x2, int y2, color_t operator);
@ -132,9 +139,10 @@ void dreverse_area(int x1, int y1, int x2, int y2);
/*
dpixel()
Puts a pixel in the vram.
Changes a pixel's color in the video ram. The result may depend on the
current color of the pixel.
*/
void dpixel(int x, int y, enum Color color);
void dpixel(size_t x, size_t y, color_t operator);
/*
dline()
@ -143,22 +151,6 @@ void dpixel(int x, int y, enum Color color);
Uses an algorithm written by PierrotLL for MonochromeLib.
*/
void dline(int x1, int y1, int x2, int y2, enum Color color);
/*
dimage()
Displays a monochrome image in the vram. Does a real lot of
optimization.
*/
void dimage(int x, int y, struct Image *image);
/*
dimage_part()
Draws a portion of an image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void dimage_part(int x, int y, struct Image *img, int left, int top,
int width, int height);
void dline(int x1, int y1, int x2, int y2, color_t operator);
#endif // _DISPLAY_H

View file

@ -2,7 +2,17 @@
//
// gint core module: events
//
// Finally some user-friendly API.
// Finally some user-friendly API. This module is in charge of managing
// the event queue. The waitevent() function should be particularly useful
// in program main loops to record key presses and releases in real-time
// games.
//
// Other functions such as the getkey() of the keyboard module provide
// more advanced features such as SHIFT and ALPHA modifiers, backlight
// control for instance; these functions rely on this module and they
// ignore all events that they do not handle. If you want to catch several
// types of events (eg. keyboard and serial communication), then you need
// to use directly this module.
//
//---
@ -17,30 +27,24 @@
*/
typedef enum
{
EventType_None = 0,
ET_None = EventType_None,
// Specific events.
event_none = 0,
event_user = 1,
EventType_User = 1,
ET_User = EventType_User,
// Keyboard events.
event_key_press = 2,
event_key_repeat = 3,
event_key_release = 4,
EventType_KeyPressed = 2,
ET_KeyPress = EventType_KeyPressed,
EventType_KeyRepeated = 3,
ET_KeyRepeat = EventType_KeyRepeated,
EventType_KeyReleased = 4,
ET_KeyRel = EventType_KeyReleased,
EventType_TimerUnderflow = 5,
ET_Timer = EventType_TimerUnderflow,
// Other events.
event_timer_underflow = 5,
} event_type_t;
/*
event_t
Wake up, something's going on. The union member that holds information
about the event is implicitly defined by the type attribute.
about the event is specified by the type attribute.
*/
typedef struct
{
@ -48,11 +52,11 @@ typedef struct
union
{
// For ET_User.
// For event_user.
void *data;
// For ET_KeyPress, ET_KeyRepeat and ET_KeyRel.
// For event_key_press, event_key_repeat and event_key_release.
int key;
// For ET_Timer.
// For event_timer_underflow.
timer_t *timer;
};

View file

@ -2,8 +2,10 @@
//
// gint core module: interrupt handler
//
// Central point of the library. Controls the interrupt handler and
// defines a few functions to configure callbacks for some interrupts.
// This module is the core of the gint library. It controls the interrupt
// handler, allows the user to customize interrupt management, provides
// peripheral register access and some information about the runtime
// environment.
//
//---

View file

@ -7,10 +7,14 @@
//---
#ifndef _GRAY_H
#define _GRAY_H 1
#define _GRAY_H
#include <stdint.h>
#include <display.h>
// This module provides bitmap rendering.
#include <bopti.h>
//---
// Engine control.
//---
@ -39,13 +43,13 @@ void gray_stop(void);
gray_lightVRAM()
Returns the module's light gray vram address.
*/
void *gray_lightVRAM(void);
uint32_t *gray_lightVRAM(void);
/*
gray_darkVRAM()
Returns the module's dark gray vram address.
*/
void *gray_darkVRAM(void);
uint32_t *gray_darkVRAM(void);
/*
gray_getDelays()
@ -81,29 +85,26 @@ void gray_setDelays(int light, int dark);
/*
gupdate()
Swaps the vram buffer sets.
Swaps the vram buffer sets. You need to call this function each time
you finish drawing something in the video ram. Unlike the monochrome
function dupdate(), gupdate() only does a quick operation indicating
that drawing and exposed buffers have been swapped, but nothing on the
screen will change until the gray timer fires.
*/
void gupdate(void);
/*
gclear()
Clears the video ram.
Clears the gray video ram, making all pixels white.
*/
void gclear(void);
/*
gclear_area()
Clears an area of the video ram. End points (x1, y1) and (x2, y2) are
included.
grect()
Draws a rectangle in the gray video ram; this function accepts all
values of the color_t type, including gray operators.
*/
void gclear_area(int x1, int y1, int x2, int y2);
/*
greverse_area()
Reverses an area of the vram. End points (x1, y1) and (x2, y2) are
included.
*/
void greverse_area(int x1, int y1, int x2, int y2);
void grect(int x1, int y1, int x2, int y2, color_t operator);
@ -113,29 +114,18 @@ void greverse_area(int x1, int y1, int x2, int y2);
/*
gpixel()
Puts a pixel in the vram.
Puts a pixel in the vram. This function accepts all values of the
color_t type, including gray operators.
*/
void gpixel(int x, int y, enum Color color);
void gpixel(size_t x, size_t y, color_t operator);
/*
gline()
Draws a line in the vram. Automatically optimizes special cases.
Draws a line in the vram while automatically optimizing special cases.
This function supports all plain colors from the color_t type, but not
the gray operators. If you need them for horizontal or vertical lines,
you may want to use grect() as a replacement.
*/
void gline(int x1, int y1, int x2, int y2, enum Color color);
/*
gimage()
Displays a gray image in the vram.
*/
void gimage(int x, int y, struct Image *image);
/*
gimage_part()
Draws a portion of a gray image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void gimage_part(int x, int y, struct Image *image, int left, int top,
int width, int height);
void gline(int x1, int y1, int x2, int y2, color_t operator);
#endif // _GRAY_H

View file

@ -15,7 +15,7 @@
//---
#ifndef _INTERNALS_BOPTI_H
#define _INTERNALS_BOPTI_H 1
#define _INTERNALS_BOPTI_H
#include <stdint.h>
#include <display.h>
@ -86,7 +86,7 @@ struct Command
// The video ram addresses are set by the public functions and used internally
// by the module.
// Monochrome video ram, light and dark buffers (in this order).
extern int *bopti_vram, *bopti_v1, *bopti_v2;
extern uint32_t *bopti_vram, *bopti_v1, *bopti_v2;
@ -155,6 +155,6 @@ void bopti(const unsigned char *layer, struct Structure *s, struct Command *c);
getStructure()
Determines the image size and data pointer.
*/
void getStructure(struct Image *img, struct Structure *structure);
void getStructure(image_t *img, struct Structure *structure);
#endif // _INTERNALS_BOPTI_H

View file

@ -1,47 +1,40 @@
//---
//
// gint drawing module: display
//
// Handles vram manipulation and drawing.
//
//---
#ifndef _INTERNALS_DISPLAY_H
#define _INTERNALS_DISPLAY_H 1
#define _INTERNALS_DISPLAY_H
#include <stdint.h>
#include <stddef.h>
extern int *vram;
extern uint32_t *vram;
//---
// Rectangle masks.
//
// The concept of 'rectangle masks' is used several times in this module.
// It is based on the fact that an operation that affects a rectangle acts
// the same on all its lines. Therefore the behavior of the operation is
// determined by its behavior on a single line, which is represented using
// 'masks' whose bits indicate whether a pixel is affected (1) or not (0).
// It relies on the fact that operations affecting a rectangle act the
// same for all lines, and line operation is very optimized. A rectangle
// mask is a set of integers, where each bit indicate whether a specific
// pixel is affected (1) by the operation, or not (0).
//
// For example when clearing the screen rectangle (16, 16, 112, 48), the
// masks will represent information '16 to 112 on x-axis', and will hold
// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These
// masks can then be used by setting vram[offset] &= ~masks[i]. This
// appears to be very flexible : for instance, vram[offset] ^= masks[i]
// will reverse the pixels in the same rectangle.
//
// This technique can also be used in more subtle cases with more complex
// patterns, but within this module it is unlikely to happen.
// For example to clear a rectangle such as (14, 16, 112, 48), the masks
// will need to hold 0003ffff ffffffff ffffffff ffff0000. Bitwise-
// combining them with video ram long entries yields very good performance
// as compared to operation on single pixels. Each bitwise operation will
// produce different results, which is very flexible.
//
// This technique can also be used in subtle cases with patterns more
// complicated than rectangles, but within this module this is unlikely to
// happen.
//---
/*
adjustRectangle()
Adjusts the given rectangle coordinates to ensure that :
- the rectangle is entirely contained in the screen
- x1 < x2
- y1 < y2
which is needed when working with screen rectangles.
Returns non-zero if the rectangle is outside the screen.
- the rectangle is entirely contained in the screen;
- x1 < x2;
- y1 < y2,
which is needed when working with screen rectangles. Returns non-zero
if the rectangle is outside the screen, which usually means there is
nothing to do.
*/
int adjustRectangle(int *x1, int *y1, int *x2, int *y2);
@ -51,6 +44,6 @@ int adjustRectangle(int *x1, int *y1, int *x2, int *y2);
and x2 (both included). The four masks are stored in the third argument
(seen as an array).
*/
void getMasks(int x1, int x2, uint32_t *masks);
void getMasks(size_t x1, size_t x2, uint32_t *masks);
#endif // _INTERNALS_DISPLAY_H

View file

@ -1,11 +1,11 @@
#ifndef _INTERNALS_GINT_H
#define _INTERNALS_GINT_H 1
#define _INTERNALS_GINT_H
#include <stdint.h>
#include <gint.h>
//---
// Interrupt handlers
// Interrupt handlers.
//---
// General exception handler.
@ -18,7 +18,7 @@ void gint_int(void);
//---
// Assembler-level VBR management
// Assembler-level VBR management.
//---
/*
@ -37,7 +37,7 @@ void gint_setvbr(uint32_t vbr, void (*setup)(void));
//---
// Initialization and termination routines
// Initialization and termination routines.
//---
/*
@ -58,8 +58,8 @@ void gint_quit(void);
Saves many registers into a buffer to ensure that the system is not
upset by gint's configuration when the application ends.
*/
//void gint_save_7705(gint_save_buffer_t *buffer);
//void gint_save_7305(gint_save_buffer_t *buffer);
// void gint_save_7705(gint_save_buffer_t *buffer);
// void gint_save_7305(gint_save_buffer_t *buffer);
/*
gint_setup()
@ -74,8 +74,8 @@ void gint_setup_7305(void);
Restores the parameters saved in a save buffer to give back the
interrupt control to the system.
*/
//void gint_restore_7705(gint_save_buffer_t *buffer);
//void gint_restore_7305(gint_save_buffer_t *buffer);
// void gint_restore_7705(gint_save_buffer_t *buffer);
// void gint_restore_7305(gint_save_buffer_t *buffer);
/*
gint_reg()

View file

@ -5,7 +5,7 @@
#include <internals/gint.h>
//---
// Interrupt handlers
// Interrupt handlers.
//---
/*
@ -60,7 +60,7 @@ extern gint_interrupt_handler_t gint_handlers[];
//---
// Interrupt maps
// Interrupt maps.
//---
/*

View file

@ -2,6 +2,7 @@
#define _INTERNALS_KEYBOARD_H
#include <keyboard.h>
#include <timer.h>
#include <clock.h>
// Keyboard variables.
@ -10,10 +11,10 @@ extern volatile int interrupt_flag;
// Key statistics.
extern int repeat_first, repeat_next;
extern int last_key, last_repeats, last_events;
extern int last_key, last_repeats, last_time;
// RTC callback id.
extern unsigned cb_id;
// Virtual timer object.
extern timer_t *vtimer;
/*
getPressedKey()

View file

@ -8,8 +8,8 @@
//
//---
#ifndef _MMU_H
#define _MMU_H 1
#ifndef _INTERNALS_MMU_H
#define _INTERNALS_MMU_H
/*
mmu_pseudoTLBInit()

View file

@ -8,7 +8,7 @@
//---
#ifndef _INTERNALS_STDIO_H
#define _INTERNALS_STDIO_H 1
#define _INTERNALS_STDIO_H
#include <stddef.h>
#include <stdarg.h>

View file

@ -1,5 +1,5 @@
#ifndef _INTERNALS_TALES_H
#define _INTERNALS_TALES_H 1
#define _INTERNALS_TALES_H
#include <tales.h>
#include <stdint.h>
@ -7,13 +7,14 @@
#define OPERATE_ARGS uint32_t *operators, int height, int x, int y
extern struct Font *font;
extern enum Color color;
extern color_t operator;
/*
tales_init()
Configures tales with the default font (which is part of gint).
*/
void tales_init(void) __attribute__((constructor));
__attribute__((constructor))
void tales_init(void);
/*
getCharacterIndex()

View file

@ -1,5 +1,5 @@
#ifndef _INTERNALS_TIME_H
#define _INTERNALS_TIME_H 1
#define _INTERNALS_TIME_H
/*
isLeap()

View file

@ -11,7 +11,7 @@
//---
#ifndef _KEYBOARD_H
#define _KEYBOARD_H 1
#define _KEYBOARD_H
#include <stdint.h>
#include <rtc.h>
@ -20,92 +20,87 @@
// Keycodes and related.
//---
// The following codes are gint matrix codes. They are not compatible with the
// system's.
#define KEY_F1 0x69
#define KEY_F2 0x59
#define KEY_F3 0x49
#define KEY_F4 0x39
#define KEY_F4 0x39
#define KEY_F5 0x29
#define KEY_F6 0x19
#define KEY_SHIFT 0x68
#define KEY_OPTN 0x58
#define KEY_VARS 0x48
#define KEY_MENU 0x38
#define KEY_LEFT 0x28
#define KEY_UP 0x18
#define KEY_ALPHA 0x67
#define KEY_SQUARE 0x57
#define KEY_POWER 0x47
#define KEY_EXIT 0x37
#define KEY_DOWN 0x27
#define KEY_RIGHT 0x17
#define KEY_XOT 0x66
#define KEY_LOG 0x56
#define KEY_LN 0x46
#define KEY_SIN 0x36
#define KEY_COS 0x26
#define KEY_TAN 0x16
#define KEY_FRAC 0x65
#define KEY_FD 0x55
#define KEY_LEFTP 0x45
#define KEY_RIGHTP 0x35
#define KEY_COMMA 0x25
#define KEY_ARROW 0x15
#define KEY_7 0x64
#define KEY_8 0x54
#define KEY_9 0x44
#define KEY_DEL 0x34
#define KEY_AC_ON 0x24
#define KEY_4 0x63
#define KEY_5 0x53
#define KEY_6 0x43
#define KEY_MUL 0x33
#define KEY_DIV 0x23
#define KEY_1 0x62
#define KEY_2 0x52
#define KEY_3 0x42
#define KEY_PLUS 0x32
#define KEY_MINUS 0x22
#define KEY_0 0x61
#define KEY_DOT 0x51
#define KEY_EXP 0x41
#define KEY_NEG 0x31
#define KEY_EXE 0x21
// Key modifiers.
#define MOD_SHIFT 0x80
#define MOD_ALPHA 0x100
#define MOD_CLEAR ~(MOD_SHIFT | MOD_ALPHA)
// Key events.
#define KEY_NONE 0x00
#define KEY_NOEVENT 0xff
/*
enum KeyboardFrequency
Possible values for the keyboard frequency.
key_t
The following codes are gint matrix codes. They are not compatible with
the system's. Some keycodes are special event codes; all others are
made of a key identifier and possibly one or more modifiers.
Binary-and a keycode with MOD_CLEAR to remove the modifiers; this will
not work with special event codes.
*/
enum KeyboardFrequency
typedef enum
{
KeyboardFreq_500mHz = RTCFreq_500mHz,
KeyboardFreq_1Hz = RTCFreq_1Hz,
KeyboardFreq_2Hz = RTCFreq_2Hz,
KeyboardFreq_4Hz = RTCFreq_4Hz,
KeyboardFreq_16Hz = RTCFreq_16Hz,
KeyboardFreq_64Hz = RTCFreq_64Hz,
KeyboardFreq_256Hz = RTCFreq_256Hz,
};
// Special events codes.
KEY_NONE = 0x00,
KEY_NOEVENT = 0xff,
// Key modifiers.
MOD_SHIFT = 0x80,
MOD_ALPHA = 0x100,
MOD_CLEAR = ~(MOD_SHIFT | MOD_ALPHA),
// Key identifiers.
KEY_F1 = 0x69,
KEY_F2 = 0x59,
KEY_F3 = 0x49,
KEY_F4 = 0x39,
KEY_F5 = 0x29,
KEY_F6 = 0x19,
KEY_SHIFT = 0x68,
KEY_OPTN = 0x58,
KEY_VARS = 0x48,
KEY_MENU = 0x38,
KEY_LEFT = 0x28,
KEY_UP = 0x18,
KEY_ALPHA = 0x67,
KEY_SQUARE = 0x57,
KEY_POWER = 0x47,
KEY_EXIT = 0x37,
KEY_DOWN = 0x27,
KEY_RIGHT = 0x17,
KEY_XOT = 0x66,
KEY_LOG = 0x56,
KEY_LN = 0x46,
KEY_SIN = 0x36,
KEY_COS = 0x26,
KEY_TAN = 0x16,
KEY_FRAC = 0x65,
KEY_FD = 0x55,
KEY_LEFTP = 0x45,
KEY_RIGHTP = 0x35,
KEY_COMMA = 0x25,
KEY_ARROW = 0x15,
KEY_7 = 0x64,
KEY_8 = 0x54,
KEY_9 = 0x44,
KEY_DEL = 0x34,
KEY_AC_ON = 0x24,
KEY_4 = 0x63,
KEY_5 = 0x53,
KEY_6 = 0x43,
KEY_MUL = 0x33,
KEY_DIV = 0x23,
KEY_1 = 0x62,
KEY_2 = 0x52,
KEY_3 = 0x42,
KEY_PLUS = 0x32,
KEY_MINUS = 0x22,
KEY_0 = 0x61,
KEY_DOT = 0x51,
KEY_EXP = 0x41,
KEY_NEG = 0x31,
KEY_EXE = 0x21,
} key_t;
@ -114,23 +109,31 @@ enum KeyboardFrequency
//---
/*
keyboard_setFrequency()
Sets the keyboard frequency. The default frequency is 16 Hz. Very few
applications will need to change this setting.
At low frequencies, you will miss key hits. At high frequencies, you
may lose execution power.
keyboard_setAnalysisDelay()
Sets the keyboard analysis delay, that is, the delay (in ms) between
two keyboard analyzes. If a key is pressed then released in the lapse
between two analyzes, the program won't notice anything. On the other
hand, if the program spends too much time reading the keyboard, it will
lose a bit of execution power.
The default frequency is about 40 Hz; very few programs will need to
change this setting. Please note that the repeat delays should be
multiples of the analysis delay for better accuracy.
*/
void keyboard_setFrequency(enum KeyboardFrequency frequency);
void keyboard_setAnalysisDelay(int analysis_delay_ms);
/*
keyboard_setRepeatRate()
Sets the default repeat rate for key events. The delay before the first
repeat may have a different value (usually longer). The unit for the
argument is the keyboard period. For example at 32 Hz, values of
(20, 4) will imitate the system default.
Set to 0 to disable repetition. If first = 0, no repetition will be
allowed. If first != 0 and next = 0, only one repetition will be
allowed.
argument is ms, but the repeat events themselves may only be fired when
a keyboard analysis is performed; which means that for better accuracy,
these delays should be a multiple of the keyboard period. The keyboard
period may be changed by calling keyboard_setAnalysisDelay().
For instance, delays of (625 ms, 125 ms) will imitate the system's
default setting.
You can disable repetitions by passing 0 as arguments:
- if first = 0, no repetition will ever occur;
- if first != 0 and next = 0, only one repetition will occur.
*/
void keyboard_setRepeatRate(int first, int next);
@ -141,57 +144,74 @@ void keyboard_setRepeatRate(int first, int next);
//---
/*
enum GetKeyOpt
Options available for use with getkey_opt().
getkey_opt_t
Options available to customize the behavior of the getkey_opt()
function.
*/
enum GetkeyOpt
typedef enum
{
Getkey_NoOption = 0x00,
getkey_none = 0x00,
// Consider [SHIFT] and [ALPHA] as modifiers instead of returning
// KEY_SHIFT and KEY_ALPHA.
Getkey_ShiftModifier = 0x01,
Getkey_AlphaModifier = 0x02,
// Consider [SHIFT] and [ALPHA] as modifiers. Returns key identifiers
// with MOD_SHIFT and MOD_ALPHA flags instead of returning KEY_SHIFT
// and KEY_ALPHA.
getkey_shift_modifier = 0x01,
getkey_alpha_modifier = 0x02,
// Allow changing the backlight status on [SHIFT] + [OPTN].
Getkey_ManageBacklight = 0x04,
// Allow changing the backlight status on [SHIFT] + [OPTN] on
// compatible models.
getkey_manage_backlight = 0x04,
// Key repetition. Notice that modifiers will never be repeated.
Getkey_RepeatArrowKeys = 0x10,
Getkey_RepeatCharKeys = 0x20,
Getkey_RepeatCtrlKeys = 0x40,
Getkey_RepeatFuncKeys = 0x80,
// 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
// pressed continuously.
getkey_repeat_arrow_keys = 0x10,
getkey_repeat_char_keys = 0x20,
getkey_repeat_ctrl_keys = 0x40,
getkey_repeat_func_keys = 0x80,
// Shorthand for the four previous properties.
Getkey_RepeatAllKeys = 0xf0,
};
getkey_repeat_all_keys = 0xf0,
} getkey_option_t;
/*
getkey()
Blocking function with auto-repeat and SHIFT modifying functionalities.
Reproduces the behavior of the system's GetKey(). Returns the matrix
code with a possible MOD_SHIFT bit.
Blocking function with auto-repeat that heeds for the SHIFT and ALPHA
modifiers. In short, this function reproduces the behavior of the
system's GetKey() function. It returns a matrix code, possibly with
modifier bits.
This function does not return until a key is pressed.
*/
int getkey(void);
/*
getkey_opt()
Enhances getkey() with most general functionalities. An OR-combination
of options may be given as first argument.
If max_cycles is non-zero and positive, getkey_opt() will return
KEY_NOEVENT if no event occurs during max_cycle analyzes.
Enhances getkey() with more general functionalities. An OR-combination
of options of type getkey_option_t may be given as first argument.
If delay is non-zero and positive, getkey_opt() will return KEY_NOEVENT
if no event occurs during the given delay. Please note that this
function can only ever return after a keyboard analysis is performed;
the actual delay may exceed the requested time if it's not a multiple
of the keyboard period (which can be changed by calling
keyboard_setAnalysisDelay()).
Like getkey(), returns the pressed key matrix code, possibly with
modifiers depending on the options.
*/
int getkey_opt(enum GetkeyOpt options, int max_cycles);
int getkey_opt(getkey_option_t options, int delay_ms);
/*
multigetkey()
Listens the keyboard for simultaneous key hits. This functions fills
array `keys` with `count` keycodes, adding KEY_NONE at the end if
less than `count` keys are pressed.
If `max_cycles` is non-zero and nothing happens after `max_cycles`
cycles, this function returns an array of KEY_NONE.
the 'keys' array with 'count' keycodes, padding with KEY_NONE values at
the end if less that 'count' keys are detected.
If 'delay_ms' is positive and nothing happens during this delay, this
function returns an array of KEY_NONE. Please note that the delay
detection suffers the same limitation as getkey_opt().
This function suffers from severe limitations and may not be very
convenient to use. For more accuracy, consider using the event system.
WARNING:
Because of hardware limitations, this function generally yields poor
@ -202,7 +222,7 @@ int getkey_opt(enum GetkeyOpt options, int max_cycles);
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
(on both platforms) mess up the results by making this function think
that some keys, which are actually unpressed, are pressed.
that some keys, which are actually released, are pressed.
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
@ -215,25 +235,26 @@ int getkey_opt(enum GetkeyOpt options, int max_cycles);
incorrect results. Please do not expect multigetkey() to work as an
ideal multi-key analyzer.
*/
void multigetkey(int *keys, int count, int max_cycles);
void multigetkey(int *keys, int count, int delay_ms);
/*
keylast()
Returns the matrix code of the last pressed key. If repeat_count is
non-NULL, it is set to the number of repetitions.
*/
int keylast(int *repeat_count);
keyboard_stateBuffer()
/*
keystate()
Returns the address of the keyboard state array. The keyboard state
consists in 10 bytes, in which every key is represented as a bit.
The returned address is the original buffer address. You should avoid
editing the array. It wouldn't influence the behavior of the keyboard
functions, but the buffer data is very volatile. Therefore, data
written to the buffer could be replaced anytime.
functions, but the buffer data is very volatile and any data written to
it could be replaced anytime without prior notice.
If the user wishes to do really advanced keyboard management that they
can't achieve it using the library, they can access this buffer.
Updates of this buffer's contents can be detected by watching the
'interrupt_flag' variable defined in internals/keyboard.h. However, the
library will continue firing events so the user needs to catch them and
ignore them.
*/
volatile uint8_t *keystate(void);
volatile uint8_t *keyboard_stateBuffer(void);
@ -241,32 +262,61 @@ volatile uint8_t *keystate(void);
// Key analysis.
//---
enum KeyType
{
KeyType_Arrow = 1,
KeyType_Character = 2,
KeyType_Control = 4,
KeyType_Function = 8,
};
/*
keyid()
Returns a non-matrix key code that can be used for array subscript.
Ignores modifiers.
Transforms a key identifier and returns a key code that is more
convenient for array subscript that the original matrix codes. The new
codes are laid out the following way:
+0 +1 +2 +3 +4 +5
------------------------------------
+0 | F1 F2 F3 F4 F5 F6
+6 | SHIFT OPTN VARS MENU Left Top
+12 | ALPHA x^2 ^ EXIT Down Right
+18 | X,O,T log ln sin cos tan
+24 | Frac F<>D ( ) , ->
+30 | 7 8 9 DEL AC/ON
+36 | 4 5 6 * /
+42 | 1 2 3 + -
+48 | 0 . x10^ (-) EXE
The returned key code is the sum of the line and column headings. For
instance key_id(KEY_SIN) would be 18 + 3 = 21. Please note that there
are a few holes in the numbering.
This function ignores modifiers and returns -1 on error.
*/
int keyid(int key);
int key_id(int matrix_key);
/*
keychar()
Returns the ASCII character associated with a character key; 0 for
other keys.
key_char()
Returns the ASCII character associated with a character key, and 0 for
other keys. This function expects a matrix code and not a key_id()
code, and heeds for the ALPHA modifier.
*/
int keychar(int key);
int key_char(int matrix_key);
/*
keytype()
Returns a key's type. Ignores modifiers.
key_type_t
Categorizes the keyboard's keys into several types:
- Arrow keys only include the REPLAY pad;
- Function keys only include the F1 .. F6 keys;
- Character keys are those which input characters;
- Control characters are all others.
*/
enum KeyType keytype(int key);
typedef enum
{
key_type_arrow = 1,
key_type_character = 2,
key_type_control = 4,
key_type_function = 8,
} key_type_t;
/*
key_type()
Returns a key's type. This functions ignores modifiers and expects
matrix codes as argument, not key_id() codes.
*/
key_type_t key_type(int matrix_key);
#endif // _KEYBOARD_H

View file

@ -27,7 +27,7 @@
//---
#ifndef _MPU_H
#define _MPU_H 1
#define _MPU_H
/*
mpu_t

View file

@ -7,7 +7,7 @@
//---
#ifndef _RTC_H
#define _RTC_H 1
#define _RTC_H
#include <stdint.h>

View file

@ -12,7 +12,7 @@
//---
#ifndef _SCREEN_H
#define _SCREEN_H 1
#define _SCREEN_H
/*
screen_display()

View file

@ -8,7 +8,7 @@
//---
#ifndef _SETJMP_H
#define _SETJMP_H 1
#define _SETJMP_H
// There are 16 CPU registers that *must* be saved to ensure a basically
// safe jump.

View file

@ -8,7 +8,7 @@
//---
#ifndef _STDIO_H
#define _STDIO_H 1
#define _STDIO_H
#include <stddef.h>
#include <stdarg.h>

View file

@ -8,7 +8,7 @@
//---
#ifndef _STDLIB_H
#define _STDLIB_H 1
#define _STDLIB_H
//---
// Common definitions.

View file

@ -8,7 +8,7 @@
//---
#ifndef _STRING_H
#define _STRING_H 1
#define _STRING_H
#include <stddef.h>

View file

@ -8,7 +8,7 @@
//---
#ifndef _TALES_H
#define _TALES_H 1
#define _TALES_H
#include <display.h>
#include <stdint.h>
@ -95,7 +95,7 @@ typedef struct Font Font;
Sets the font and color to use for subsequent text operations. Pass
font = NULL to use the default font.
*/
void text_configure(struct Font *font, enum Color color);
void text_configure(struct Font *font, color_t operator);
/*
dtext()

View file

@ -7,7 +7,7 @@
//---
#ifndef _TIME_H
#define _TIME_H 1
#define _TIME_H
#include <stddef.h>

View file

@ -8,7 +8,7 @@
//---
#ifndef _TIMER_H
#define _TIMER_H 1
#define _TIMER_H
#include <clock.h>
#include <stdint.h>
@ -49,6 +49,16 @@ typedef struct timer_t timer_t;
*/
timer_t *timer_create(int delay_ms, int repeats);
/*
timer_reload()
Changes a virtual timer's delay. The timer is not stopped nor started:
it keeps running or waiting. Events that were waiting to be handled are
dropped and the number of repeats left is not changed. The timer
restarts counting from 0 regardless of how much time had elapsed since
it last fired.
*/
void timer_reload(timer_t *timer, int new_ms_delay);
/*
timer_destroy()
Destroys a virtual timer. This virtual timer pointer becomes invalid

View file

@ -1,7 +1,7 @@
#include <internals/bopti.h>
// Monochrome video ram, light and dark buffers (in this order).
int *bopti_vram, *bopti_v1, *bopti_v2;
uint32_t *bopti_vram, *bopti_v1, *bopti_v2;
/*
bopti_op()
@ -285,7 +285,7 @@ void bopti(const unsigned char *layer, struct Structure *s, struct Command *c)
getStructure()
Determines the image size and data pointer.
*/
void getStructure(struct Image *img, struct Structure *s)
void getStructure(image_t *img, struct Structure *s)
{
int column_count, end, end_bytes, layer;

View file

@ -7,8 +7,8 @@
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void dimage_part(int x, int y, struct Image *img, int left, int top,
int width, int height)
void dimage_part(int x, int y, image_t *img, int left, int top, int width,
int height)
{
if(!img || img->magic != 0x01) return;
@ -70,7 +70,7 @@ void dimage_part(int x, int y, struct Image *img, int left, int top,
dimage()
Displays a monochrome image in the video ram.
*/
void dimage(int x, int y, struct Image *img)
void dimage(int x, int y, image_t *img)
{
dimage_part(x, y, img, 0, 0, -1, -1);
}

View file

@ -8,8 +8,8 @@
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void gimage_part(int x, int y, struct Image *img, int left, int top,
int width, int height)
void gimage_part(int x, int y, image_t *img, int left, int top, int width,
int height)
{
if(!img || img->magic != 0x01) return;
@ -71,7 +71,7 @@ void gimage_part(int x, int y, struct Image *img, int left, int top,
gimage()
Displays a gray image in the video ram.
*/
void gimage(int x, int y, struct Image *img)
void gimage(int x, int y, image_t *img)
{
gimage_part(x, y, img, 0, 0, -1, -1);
}

View file

@ -19,7 +19,7 @@ static clock_config_t conf = {
Several units can be used. Be aware that the result is approximate, and
very high frequencies or very short delays will yield important errors.
*/
uint32_t clock_setting(int duration, enum ClockUnit unit)
uint32_t clock_setting(int duration, clock_unit_t unit)
{
if(conf.Pphi_f <= 0) return 0xffffffff;
uint64_t f = conf.Pphi_f >> 2;
@ -27,23 +27,23 @@ uint32_t clock_setting(int duration, enum ClockUnit unit)
switch(unit)
{
case Clock_us:
case clock_us:
result = (duration * f) / 1000000;
break;
case Clock_ms:
case clock_ms:
result = (duration * f) / 1000;
break;
case Clock_s:
case clock_s:
result = (duration * f);
break;
case Clock_Hz:
case clock_Hz:
result = f / duration;
break;
case Clock_kHz:
case clock_kHz:
result = f / (duration * 1000);
break;
case Clock_MHz:
case clock_MHz:
result = f / (duration * 1000000);
break;
@ -103,7 +103,7 @@ void sleep_ms(int ms_delay)
void sleep_us(int us_delay)
{
volatile int sleep_done = 0;
const uint32_t constant = clock_setting(us_delay, Clock_us);
const uint32_t constant = clock_setting(us_delay, clock_us);
timer_t *timer = htimer_setup(timer_user, constant, timer_Po_4, 1);
timer_attach(timer, sleep_callback, (void *)&sleep_done);

View file

@ -37,7 +37,7 @@ static void show_error(const char *name, uint32_t *access_mode, uint32_t *tea,
__asm__("stc ssr, %0" : "=rm"(ssr));
dclear();
text_configure(NULL, Color_Black);
text_configure(NULL, color_black);
print(3, 1, "EXCEPTION RAISED!");
for(int i = 0; i < 36; i++) vram[i] = ~vram[i];

43
src/ctype/ctype_classes.c Normal file
View file

@ -0,0 +1,43 @@
#include <ctype.h>
// Let's save up some space and readability (That's Cake's idea, its a bit of a
// preprocessor trick but a rather nice trick).
#define r4(x) (x), (x), (x), (x)
#define r5(x) r4(x), (x)
#define r6(x) r5(x), (x)
#define r7(x) r6(x), (x)
#define r9(x) r7(x), (x), (x)
#define r10(x) r6(x), r4(x)
#define r15(x) r10(x), r4(x), (x)
#define r18(x) r9(x), r9(x)
#define r20(x) r10(x), r10(x)
enum {
cntrl = 0x01,
space = 0x02,
punct = 0x04,
print = 0x08,
upper = 0x20,
lower = 0x10,
digit = 0x40,
xdigt = 0x80,
};
uint8_t ctype_classes[0x80] = {
// Control characters.
r9(cntrl), r5(cntrl | space), r18(cntrl),
// Space and some punctuation.
space | print, r15(punct | print),
// Decimal digits.
r10(digit | xdigt | print),
// Some punctuation.
r7(punct | print),
// Uppercase alphabet.
r6(upper | xdigt | print), r20(upper | print),
// Other punctuation symbols.
r6(punct | print),
// Lowercase alphabet.
r6(lower | xdigt | print), r20(lower | print),
// Last punctuation characters and DEL.
r4(punct | print), cntrl,
};

View file

@ -0,0 +1,71 @@
//---
// Character type functions.
// Normally this functions need not be linked because there are macros to
// optimize performance, but we still need them to get some pointers.
//---
// We don't want to include <ctype.h> because it defines all the macros...
#include <stdint.h>
extern uint8_t ctype_classes[0x80];
#define _inline __attribute__((always_inline)) inline
_inline int isalnum(int c) {
return ctype_classes[c] & 0xf0;
}
_inline int isalpha(int c) {
return ctype_classes[c] & 0x30;
}
_inline int iscntrl(int c) {
return ctype_classes[c] & 0x01;
}
_inline int isdigit(int c) {
return ctype_classes[c] & 0x40;
}
_inline int isgraph(int c) {
return ctype_classes[c] & 0xf4;
}
_inline int islower(int c) {
return ctype_classes[c] & 0x10;
}
_inline int isprint(int c) {
return ctype_classes[c] & 0x08;
}
_inline int ispunct(int c) {
return ctype_classes[c] & 0x04;
}
_inline int isspace(int c) {
return ctype_classes[c] & 0x02;
}
_inline int isupper(int c) {
return ctype_classes[c] & 0x20;
}
_inline int isxdigit(int c) {
return ctype_classes[c] & 0x80;
}
_inline int isascii(int c) {
return ((unsigned)c <= 0x7f);
}
_inline int isblank(int c) {
return (c == '\t' || c == ' ');
}
_inline int tolower(int c) {
return c | isupper(c);
}
_inline int toupper(int c) {
return c & ~(islower(c) << 1);
}

View file

@ -3,10 +3,30 @@
/*
dclear()
Clears the whole vram.
Clears the whole vram, making all pixels white.
*/
void dclear(void)
{
int i;
for(i = 0; i < 256; i++) vram[i] = 0;
// I tend to use pre-decrement more than post-increment.
uint32_t *index = vram + 256;
while(index > vram)
{
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
*--index = 0;
}
}

View file

@ -1,21 +0,0 @@
#include <internals/display.h>
#include <display.h>
/*
dclear_area()
Clears an area of the vram using rectangle masks. Both (x1, y1) and
(x2, y2) are cleared.
*/
void dclear_area(int x1, int y1, int x2, int y2)
{
uint32_t masks[4];
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
getMasks(x1, x2, masks);
int begin = y1 << 2;
int end = (y2 + 1) << 2;
int i;
for(i = 0; i < 4; i++) masks[i] = ~masks[i];
for(i = begin; i < end; i++) vram[i] &= masks[i & 3];
}

View file

@ -1,43 +1,48 @@
#include <display.h>
// Program video ram. It resides in .bss section, therefore it is cleared at
// Program video ram. It resides in BSS section, therefore it is cleared at
// program initialization and stripped from the executable file.
static int local_vram[256];
int *vram = local_vram;
static uint32_t local_vram[256];
uint32_t *vram = local_vram;
/*
display_getLocalVRAM()
Returns the local video ram address. This function always return the
same address.
The buffer returned by this function should not be used directly when
running the gray engine.
Returns gint's local video RAM address. Gint does not use the system's
buffer because it is misaligned. This function always returns the same
address. Both the display and the gray module heavily use this buffer;
make sure you don't interfere with them if you access it.
This function does not necessarily returns the video ram that is
currently in use; call display_getCurrentVRAM() for this.
*/
inline void *display_getLocalVRAM(void)
inline uint32_t *display_getLocalVRAM(void)
{
return (void *)local_vram;
return local_vram;
}
/*
display_getCurrentVRAM()
Returns the current video ram. This function usually returns the
parameter of the last call to display_useVRAM(), unless the gray engine
is running (in which case the result is undefined). Returns the local
vram address by default.
Returns the current monochrome video ram buffer. This function usually
returns the parameter of the last call to display_useVRAM(), or the
local vram address (which is default when the library starts).
The return value of this function is undefined if the gray engine is
running.
*/
inline void *display_getCurrentVRAM(void)
inline uint32_t *display_getCurrentVRAM(void)
{
return (void *)vram;
return vram;
}
/*
display_useVRAM()
Changes the current video ram address. The argument MUST be a 4-
aligned 1024-byte buffer ; otherwise any drawing operation will crash
the program.
Changes the current monochrome video ram address. The argument must be
a 4-aligned 1024-byte buffer because the library's design requires it.
This function refuses misaligned buffers but trusts that enough space
is available; failing to provide enough memory may crash the program.
This function will most likely have no effect when running the gray
engine.
*/
inline void display_useVRAM(void *ptr)
inline void display_useVRAM(uint32_t *ptr)
{
vram = (int *)ptr;
if((intptr_t)ptr & 3) return;
vram = ptr;
}

View file

@ -1,38 +1,41 @@
#include <internals/display.h>
#include <display.h>
#define sgn(x) ((x) < 0 ? -1 : 1)
#define abs(x) ((x) < 0 ? -(x) : (x))
#define rnd(x) ((int)((x) + 0.5))
/*
dline()
Draws a line on the screen. Automatically optimizes horizontal and
vertical lines.
dhline()
Optimized procedure for drawing an horizontal line. Uses a rectangle
mask.
*/
static void dhline(int x1, int x2, int y, enum Color color)
static void dhline(size_t x1, size_t x2, int y, color_t operator)
{
uint32_t masks[4];
int offset = y << 2;
int i;
uint32_t *video = vram + (y << 2) + 4;
// Swapping x1 and x2 if needed.
if(x1 > x2) x1 ^= x2, x2 ^= x1, x1 ^= x2;
getMasks(x1, x2, masks);
switch(color)
switch(operator)
{
case Color_White:
for(i = 0; i < 4; i++) vram[offset + i] &= ~masks[i];
case color_white:
*--video &= ~masks[3];
*--video &= ~masks[2];
*--video &= ~masks[1];
*--video &= ~masks[0];
break;
case Color_Black:
for(i = 0; i < 4; i++) vram[offset + i] |= masks[i];
case color_black:
*--video |= masks[3];
*--video |= masks[2];
*--video |= masks[1];
*--video |= masks[0];
break;
case Color_Invert:
for(i = 0; i < 4; i++) vram[offset + i] ^= masks[i];
case color_invert:
*--video ^= masks[3];
*--video ^= masks[2];
*--video ^= masks[1];
*--video ^= masks[0];
break;
default:
@ -40,24 +43,30 @@ static void dhline(int x1, int x2, int y, enum Color color)
}
}
static void dvline(int y1, int y2, int x, enum Color color)
/*
dvline()
Optimized procedure for drawing a vertical line. This one is far less
powerful than dhline() because the video ram is essentially line-
oriented. It also uses a mask.
*/
static void dvline(int y1, int y2, int x, color_t operator)
{
int offset = (y1 << 2) + (x >> 5);
int end = (y2 << 2) + (x >> 5);
int mask = 0x80000000 >> (x & 31);
uint32_t *base = vram + (y1 << 2) + (x >> 5);
uint32_t *video = vram + (y2 << 2) + (x >> 5) + 4;
uint32_t mask = 0x80000000 >> (x & 31);
switch(color)
switch(operator)
{
case Color_White:
while(offset <= end) vram[offset] &= ~mask, offset += 4;
case color_white:
while(video > base) video -= 4, *video &= ~mask;
break;
case Color_Black:
while(offset <= end) vram[offset] |= mask, offset += 4;
case color_black:
while(video > base) video -= 4, *video |= mask;
break;
case Color_Invert:
while(offset <= end) vram[offset] ^= mask, offset += 4;
case color_invert:
while(video > base) video -= 4, *video ^= mask;
break;
default:
@ -65,19 +74,28 @@ static void dvline(int y1, int y2, int x, enum Color color)
}
}
void dline(int x1, int y1, int x2, int y2, enum Color color)
#define sgn(x) ((x) < 0 ? -1 : 1)
#define abs(x) ((x) < 0 ? -(x) : (x))
/*
dline()
Line drawing algorithm more or less directly taken for MonochromeLib.
Thanks PierrotLL for this. Relies on dhline() and dvline() for specific
cases.
*/
void dline(int x1, int y1, int x2, int y2, color_t operator)
{
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
// Possible optimizations.
if(y1 == y2)
{
dhline(x1, x2, y1, color);
dhline(x1, x2, y1, operator);
return;
}
if(x1 == x2)
{
dvline(y1, y2, x1, color);
dvline(y1, y2, x1, operator);
return;
}
@ -87,7 +105,7 @@ void dline(int x1, int y1, int x2, int y2, enum Color color)
dx = abs(dx), dy = abs(dy);
dpixel(x1, y1, color);
dpixel(x1, y1, operator);
if(dx >= dy)
{
@ -97,7 +115,7 @@ void dline(int x1, int y1, int x2, int y2, enum Color color)
x += sx;
cumul += dy;
if(cumul > dx) cumul -= dx, y += sy;
dpixel(x, y, color);
dpixel(x, y, operator);
}
}
else
@ -108,9 +126,9 @@ void dline(int x1, int y1, int x2, int y2, enum Color color)
y += sy;
cumul += dx;
if(cumul > dy) cumul -= dy, x += sx;
dpixel(x, y, color);
dpixel(x, y, operator);
}
}
dpixel(x2, y2, color);
dpixel(x2, y2, operator);
}

View file

@ -3,30 +3,23 @@
/*
dpixel()
Puts a pixel in the vram.
Changes a pixel's color in the video ram. The result may depend on the
current color of the pixel.
*/
void dpixel(int x, int y, enum Color color)
void dpixel(size_t x, size_t y, color_t operator)
{
if((unsigned int)x > 127 || (unsigned int)y > 63) return;
// Let's be honest, all this module's code *heavily* relies on the
// screen dimension in the end, so it's not that big a deal.
if(x > 127 || y > 63) return;
int offset = (y << 2) + (x >> 5);
int mask = 0x80000000 >> (x & 31);
uint32_t *video = vram + (y << 2) + (x >> 5);
uint32_t mask = 0x80000000 >> (x & 31);
switch(color)
switch(operator)
{
case Color_White:
vram[offset] &= ~mask;
break;
case Color_Black:
vram[offset] |= mask;
break;
case Color_Invert:
vram[offset] ^= mask;
break;
default:
break;
case color_white: *video &= ~mask; break;
case color_black: *video |= mask; break;
case color_invert: *video ^= mask; break;
default: return;
}
}

59
src/display/drect.c Normal file
View file

@ -0,0 +1,59 @@
#include <internals/display.h>
#include <display.h>
/*
drect()
Draws a rectangle on the screen. This function can use any color which
is not associated with the gray engine, including the reverse operator.
*/
void drect(int x1, int y1, int x2, int y2, color_t operator)
{
// Avoid wasting time if the requested operation is invalid here.
if(operator != color_white && operator != color_black
&& operator != color_invert) return;
// Make sure the coordinates are in the right order, and that the
// requested rectangle crosses the screen.
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
uint32_t masks[4];
getMasks(x1, x2, masks);
uint32_t *base = vram + (y1 << 2);
uint32_t *video = vram + (y2 << 2) + 4;
switch(operator)
{
case color_white:
while(video > base)
{
*--video &= ~masks[3];
*--video &= ~masks[2];
*--video &= ~masks[1];
*--video &= ~masks[0];
}
break;
case color_black:
while(video > base)
{
*--video |= masks[3];
*--video |= masks[2];
*--video |= masks[1];
*--video |= masks[0];
}
break;
case color_invert:
while(video > base)
{
*--video ^= masks[3];
*--video ^= masks[2];
*--video ^= masks[1];
*--video ^= masks[0];
}
break;
// Avoid some warnings.
default: return;
}
}

View file

@ -1,21 +0,0 @@
#include <internals/display.h>
#include <display.h>
/*
dreverse_area()
Reverses an area of the vram. This function is a simple application of
the rectangle masks concept. (x1, y1) and (x2, y2) are reversed as
well.
*/
void dreverse_area(int x1, int y1, int x2, int y2)
{
uint32_t masks[4];
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
getMasks(x1, x2, masks);
int begin = y1 << 2;
int end = (y2 + 1) << 2;
int i;
for(i = begin; i < end; i++) vram[i] ^= masks[i & 3];
}

View file

@ -6,18 +6,18 @@
and x2 (both included). The four masks are stored in the third argument
(seen as an array).
*/
void getMasks(int x1, int x2, uint32_t *masks)
void getMasks(size_t x1, size_t x2, uint32_t *masks)
{
// Indexes of the first and last longs that are non-blank.
int l1 = x1 >> 5;
int l2 = x2 >> 5;
int i = 0;
// Indexes of the first and last longs that are not empty.
size_t l1 = x1 >> 5;
size_t l2 = x2 >> 5;
size_t i = 0;
// Setting the base masks. Those are the final values, except for the
// longs with indexes l1 and l2, that still need to be adjusted.
while(i < l1) masks[i++] = 0x00000000;
while(i <= l2) masks[i++] = 0xffffffff;
while(i < 4) masks[i++] = 0x00000000;
// longs between indexes l1 and l2, that still need to be adjusted.
while(i < l1) masks[i++] = 0x00000000;
while(i <= l2) masks[i++] = 0xffffffff;
while(i < 4) masks[i++] = 0x00000000;
// Removing the long number information in x1 and x2 (that is, the
// multiples of 32) to keep only the interesting information -- the

View file

@ -10,7 +10,7 @@
event_t pollevent(void)
{
event_t event = {
.type = ET_None
.type = event_none,
};
if(queue_size <= 0) return event;
@ -33,6 +33,6 @@ event_t waitevent(void)
{
event_t event;
while((event = pollevent()).type == ET_None) sleep();
while((event = pollevent()).type == event_none) sleep();
return event;
}

View file

@ -14,7 +14,7 @@ volatile int queue_size = 0;
int event_push(event_t event)
{
if(queue_size >= EVENTS_QUEUE_SIZE) return 1;
if(event.type == ET_None) return 2;
if(event.type == event_none) return 2;
int index = queue_start + queue_size;
if(index >= EVENTS_QUEUE_SIZE) index -= EVENTS_QUEUE_SIZE;

View file

@ -6,9 +6,28 @@
*/
void gclear(void)
{
int *v1 = gray_lightVRAM();
int *v2 = gray_darkVRAM();
int i;
uint32_t *lbase = gray_lightVRAM();
uint32_t *v1 = lbase + 256;
uint32_t *v2 = gray_darkVRAM() + 256;
for(i = 0; i < 256; i++) v1[i] = v2[i] = 0;
while(v1 > lbase)
{
*--v1 = 0;
*--v1 = 0;
*--v1 = 0;
*--v1 = 0;
*--v1 = 0;
*--v1 = 0;
*--v1 = 0;
*--v1 = 0;
*--v2 = 0;
*--v2 = 0;
*--v2 = 0;
*--v2 = 0;
*--v2 = 0;
*--v2 = 0;
*--v2 = 0;
*--v2 = 0;
}
}

View file

@ -1,15 +0,0 @@
#include <gray.h>
#include <display.h>
/*
gclear_area()
Clears an area of the video ram. End points (x1, y1) and (x2, y2) are
included.
*/
void gclear_area(int x1, int y1, int x2, int y2)
{
display_useVRAM(gray_lightVRAM());
dclear_area(x1, y1, x2, y2);
display_useVRAM(gray_darkVRAM());
dclear_area(x1, y1, x2, y2);
}

View file

@ -3,22 +3,23 @@
/*
gline()
Draws a line in the vram. Automatically optimizes special cases.
Draws a line in the vram. Automatically optimizes special cases. This
function does not support the light operators.
*/
void gline(int x1, int y1, int x2, int y2, enum Color color)
void gline(int x1, int y1, int x2, int y2, color_t operator)
{
enum Color c1, c2;
color_t op1, op2;
if(color == Color_None) return;
else if(color == Color_Invert) c1 = c2 = Color_Invert;
if(operator == color_invert) op1 = op2 = color_invert;
else if(operator >= color_none) return;
else
{
c1 = 3 * (color & 1);
c2 = 3 * (color >> 1);
op1 = 3 * (operator & 1);
op2 = 3 * (operator >> 1);
}
display_useVRAM(gray_lightVRAM());
dline(x1, y1, x2, y2, c1);
dline(x1, y1, x2, y2, op1);
display_useVRAM(gray_darkVRAM());
dline(x1, y1, x2, y2, c2);
dline(x1, y1, x2, y2, op2);
}

View file

@ -4,44 +4,56 @@
gpixel()
Puts a pixel in the vram.
*/
void gpixel(int x, int y, enum Color color)
void gpixel(size_t x, size_t y, color_t operator)
{
if((unsigned int)x > 127 || (unsigned int)y > 63) return;
if(x > 127 || y > 63) return;
int offset = (y << 2) + (x >> 5);
int mask = 0x80000000 >> (x & 31);
uint32_t *light = gray_lightVRAM() + (y << 2) + (x >> 5);
uint32_t *dark = gray_darkVRAM() + (y << 2) + (x >> 5);
uint32_t mask = 0x80000000 >> (x & 31);
int *v1 = gray_lightVRAM();
int *v2 = gray_lightVRAM();
switch(color)
switch(operator)
{
case Color_White:
v1[offset] &= ~mask;
v2[offset] &= ~mask;
case color_white:
*light &= ~mask;
*dark &= ~mask;
break;
case Color_Light:
v1[offset] |= mask;
v2[offset] &= ~mask;
case color_light:
*light |= mask;
*dark &= ~mask;
break;
case Color_Dark:
v1[offset] &= ~mask;
v2[offset] |= mask;
case color_dark:
*light &= ~mask;
*dark |= mask;
break;
case Color_Black:
v1[offset] |= mask;
v2[offset] |= mask;
case color_black:
*light |= mask;
*dark |= mask;
break;
case color_none:
return;
case Color_Invert:
v1[offset] ^= mask;
v2[offset] ^= mask;
case color_invert:
*light ^= mask;
*dark ^= mask;
break;
default:
case color_lighten:;
uint32_t old_light_1 = *light;
*light &= *dark | ~mask;
*dark = (old_light_1 | ~mask) & (mask ^ *dark);
break;
case color_lighten2:
*dark &= *light | ~mask;
*light &= ~mask;
break;
case color_darken:;
uint32_t old_light_2 = *light;
*light |= *dark & mask;
*dark = (old_light_2 & mask) | (mask ^ *dark);
break;
case color_darken2:
*dark |= *light | mask;
*light |= mask;
break;
}
}

View file

@ -11,8 +11,8 @@
#include <timer.h>
#include <mpu.h>
static int internal_vrams[3][256];
static const void *vrams[4];
static uint32_t internal_vrams[3][256];
static uint32_t *vrams[4];
static int current = 0;
static int delays[2];
@ -45,10 +45,10 @@ void gray_interrupt(void)
*/
__attribute__((constructor)) void gray_init(void)
{
vrams[0] = (const void *)display_getLocalVRAM();
vrams[1] = (const void *)internal_vrams[0];
vrams[2] = (const void *)internal_vrams[1];
vrams[3] = (const void *)internal_vrams[2];
vrams[0] = display_getLocalVRAM();
vrams[1] = internal_vrams[0];
vrams[2] = internal_vrams[1];
vrams[3] = internal_vrams[2];
delays[0] = 912;
delays[1] = 1343;
@ -119,18 +119,18 @@ inline int gray_runs(void)
gray_lightVRAM()
Returns the module's gray vram address.
*/
void *gray_lightVRAM(void)
uint32_t *gray_lightVRAM(void)
{
return (void *)vrams[~current & 2];
return vrams[~current & 2];
}
/*
gray_lightVRAM()
Returns the module's dark vram address.
*/
void *gray_darkVRAM(void)
uint32_t *gray_darkVRAM(void)
{
return (void *)vrams[(~current & 2) | 1];
return vrams[(~current & 2) | 1];
}
/*

70
src/gray/grect.c Normal file
View file

@ -0,0 +1,70 @@
#include <internals/display.h>
#include <gray.h>
/*
grect()
Draws a rectangle on the screen. This function can use all colors.
*/
void grect(int x1, int y1, int x2, int y2, color_t operator)
{
if(operator == color_none) return;
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
uint32_t masks[4];
getMasks(x1, x2, masks);
uint32_t *lbase = gray_lightVRAM() + (y1 << 2);
uint32_t *lvideo = gray_lightVRAM() + (y2 << 2) + 4;
uint32_t *dvideo = gray_darkVRAM() + (y2 << 2) + 4;
// Doing things in this order will be slower, but man, I can't stand
// writing that many lines of code for such a simple task. It will be
// terribly heavy in the binary file...
while(lvideo > lbase) for(int i = 0; i < 4; i++) switch(operator)
{
case color_white:
*--lvideo &= ~masks[i];
*--dvideo &= ~masks[i];
break;
case color_light:
*--lvideo |= masks[i];
*--dvideo &= ~masks[i];
break;
case color_dark:
*--lvideo &= ~masks[i];
*--dvideo |= masks[i];
break;
case color_black:
*--lvideo |= masks[i];
*--dvideo |= masks[i];
break;
case color_none: return;
case color_invert:
*--lvideo ^= masks[i];
*--dvideo ^= masks[i];
break;
case color_lighten:;
uint32_t light_1 = *lvideo;
dvideo--;
*--lvideo &= *dvideo | ~masks[i];
*dvideo = (light_1 | ~masks[i]) & (masks[i] ^ *dvideo);
break;
case color_lighten2:
lvideo--;
*--dvideo &= *lvideo | ~masks[i];
*lvideo &= ~masks[i];
break;
case color_darken:;
uint32_t light_2 = *lvideo;
dvideo--;
*--lvideo |= *dvideo & masks[i];
*dvideo = (light_2 & masks[i]) | (masks[i] ^ *dvideo);
break;
case color_darken2:
lvideo--;
*--dvideo |= *lvideo | masks[i];
*lvideo |= masks[i];
break;
}
}

View file

@ -1,15 +0,0 @@
#include <gray.h>
#include <display.h>
/*
greverse_area()
Reverses an area of the vram. End points (x1, y1) and (x2, y2) are
included.
*/
void greverse_area(int x1, int y1, int x2, int y2)
{
display_useVRAM(gray_lightVRAM());
dreverse_area(x1, y1, x2, y2);
display_useVRAM(gray_darkVRAM());
dreverse_area(x1, y1, x2, y2);
}

View file

@ -1,4 +1,5 @@
#include <internals/keyboard.h>
#include <internals/timer.h>
#include <keyboard.h>
#include <events.h>
#include <screen.h>
@ -11,10 +12,11 @@
int getkey(void)
{
return getkey_opt(
Getkey_ShiftModifier |
Getkey_AlphaModifier |
Getkey_ManageBacklight |
Getkey_RepeatArrowKeys,
getkey_shift_modifier |
getkey_alpha_modifier |
getkey_manage_backlight |
getkey_repeat_arrow_keys,
0
);
}
@ -22,101 +24,92 @@ int getkey(void)
/*
getkey_opt()
Enhances getkey() with more general functionalities.
If max_cycles is non-zero and positive, getkey_opt() will return
KEY_NOEVENT if no event occurs during max_cycle analysis.
If delay_ms is non-zero and positive, getkey_opt() will return
KEY_NOEVENT if no event occurs before delay_ms.
*/
static void getkey_opt_wait(int *cycles)
static void getkey_opt_wait(int *delay_ms)
{
while(!interrupt_flag) sleep();
interrupt_flag = 0;
if(*cycles > 0) (*cycles)--;
if(*delay_ms > 0)
{
(*delay_ms) -= vtimer->ms_delay;
if(*delay_ms < 0) *delay_ms = 0;
}
}
int getkey_opt(enum GetkeyOpt options, int cycles)
int getkey_opt(getkey_option_t options, int delay_ms)
{
event_t event;
int modifier = 0;
static int event_ref = 0;
int modifier = 0, key;
key_type_t type;
if(cycles <= 0) cycles = -1;
while(cycles != 0)
if(delay_ms <= 0) delay_ms = -1;
while(delay_ms != 0) switch((event = pollevent()).type)
{
event = pollevent();
switch(event.type)
case event_none:
getkey_opt_wait(&delay_ms);
break;
case event_key_press:
key = event.key;
if(options & getkey_manage_backlight && key == KEY_OPTN
&& (modifier & MOD_SHIFT))
{
case ET_None:
if(last_key == KEY_NONE)
{
getkey_opt_wait(&cycles);
continue;
}
// Handling repetitions.
enum KeyType type = keytype(last_key);
if(!(options & (type << 4))) break;
if(event_ref <= 0)
{
getkey_opt_wait(&cycles);
event_ref++;
continue;
}
last_events++;
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_ManageBacklight && key == KEY_OPTN
&& modifier & MOD_SHIFT)
{
screen_toggleBacklight();
modifier &= ~MOD_SHIFT;
continue;
}
if(options & Getkey_ShiftModifier && key == KEY_SHIFT)
{
modifier ^= MOD_SHIFT;
continue;
}
if(options & Getkey_AlphaModifier && key == KEY_ALPHA)
{
modifier ^= MOD_ALPHA;
continue;
}
last_key = key;
last_repeats = 0;
last_events = 0;
event_ref = 0;
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;
screen_toggleBacklight();
modifier &= ~MOD_SHIFT;
continue;
}
if(options & getkey_shift_modifier && key == KEY_SHIFT)
{
modifier ^= MOD_SHIFT;
continue;
}
if(options & getkey_alpha_modifier && key == KEY_ALPHA)
{
modifier ^= MOD_ALPHA;
continue;
}
last_key = key;
last_repeats = 0;
last_time = 0;
return key | modifier;
case event_key_repeat:
key = event.key;
if(key != last_key) continue;
// Checking that this type of repetition is allowed.
type = key_type(key);
if(!(options & (type << 4))) break;
last_time += vtimer->ms_delay;
int cmp = last_repeats ? repeat_next : repeat_first;
if(last_time >= cmp)
{
last_repeats++;
last_time -= cmp;
return last_key;
}
break;
case event_key_release:
if(event.key != last_key) break;
last_key = KEY_NONE;
last_repeats = 0;
last_time = 0;
break;
default:
break;
}
last_key = KEY_NONE;
last_repeats = 0;
last_events = 0;
event_ref = 0;
last_time = 0;
return KEY_NONE;
}

View file

@ -1,11 +1,12 @@
#include <keyboard.h>
/*
keychar()
Returns the ASCII character associated with a key, or 0 for control
keys.
key_char()
Returns the ASCII character associated with a character key, and 0 for
other keys. This function expects a matrix code and not a key_id()
code, and heeds for the ALPHA modifier.
*/
int keychar(int key)
int key_char(int matrix_key)
{
char flat[] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
@ -30,7 +31,6 @@ int keychar(int key)
'Z', ' ', '"', 0x0, 0x0, 0x0
};
int id = keyid(key);
return (key & MOD_ALPHA) ? alpha[id] : flat[id];
int id = key_id(matrix_key);
return (matrix_key & MOD_ALPHA) ? alpha[id] : flat[id];
}

19
src/keyboard/key_id.c Normal file
View file

@ -0,0 +1,19 @@
#include <keyboard.h>
/*
keyid()
Transforms a key identifier and returns a key code that is more
convenient for array subscript that the original matrix codes. Please
note that there are a few holes in the numbering.
This function ignores modifiers and returns -1 on error.
*/
int key_id(int matrix_key)
{
if(matrix_key < 0) return -1;
matrix_key &= MOD_CLEAR;
int row = 9 - (matrix_key & 0x0f);
int column = 6 - ((matrix_key & 0xf0) >> 4);
return 6 * row + column;
}

24
src/keyboard/key_type.c Normal file
View file

@ -0,0 +1,24 @@
#include <keyboard.h>
/*
key_type()
Returns a key's type. This functions ignores modifiers and expects
matrix codes as argument, not key_id() codes.
*/
key_type_t key_type(int matrix_key)
{
matrix_key &= MOD_CLEAR;
// Arrow keys.
if(matrix_key == KEY_UP || matrix_key == KEY_RIGHT
|| matrix_key == KEY_DOWN || matrix_key == KEY_LEFT)
{
return key_type_arrow;
}
// Function keys (F1 .. F6) are ton only keys of the ninth row.
if((matrix_key & 0x0f) == 0x09) return key_type_function;
// Then character keys are those that have an associated character. =p
return key_char(matrix_key) ? key_type_character : key_type_control;
}

View file

@ -1,20 +0,0 @@
#include <internals/keyboard.h>
#include <keyboard.h>
#include <clock.h>
#include <rtc.h>
/*
keyboard_setRepeatRate()
Sets the default repeat rate for key events. The unit for the argument
is the keyboard period.
For example at 32 Hz, values of (20, 4) will imitate the system
default.
*/
void keyboard_setRepeatRate(int first, int next)
{
if(first < 0) first = 0;
if(next < 0) next = 0;
repeat_first = first;
repeat_next = next;
}

View file

@ -0,0 +1,181 @@
#include <internals/keyboard.h>
#include <keyboard.h>
#include <timer.h>
#include <mpu.h>
#include <clock.h>
#include <events.h>
//---
// Keyboard variables.
//---
// Current keyboard state: each element represents a row, and each bit a key,
// but not all bits are used.
volatile uint8_t keyboard_state[10] = { 0 };
// Interrupt flag: set when an interrupt occurs, and cleared by functions such
// as getkey() that watch it (because such functions will wake up every time an
// interrupt occurs, and they need to know whether it was the keyboard).
volatile int interrupt_flag = 0;
// Delays, in milliseconds, before repeating keys (the first repetition may
// have a different delay).
int repeat_first = 625, repeat_next = 125;
// Which key was pressed last, how many times it has been repeated, and how
// much time (in milliseconds) has elapsed since it was last repeated.
int last_key = KEY_NONE, last_repeats = 0, last_time = 0;
// Virtual timer object.
timer_t *vtimer = NULL;
//---
// Interrupt management.
//---
static inline void push_press(int keycode)
{
event_t event = {
.type = event_key_press,
.key = keycode,
};
event_push(event);
}
static inline void push_repeat(int keycode)
{
event_t event = {
.type = event_key_repeat,
.key = keycode,
};
event_push(event);
}
static inline void push_release(int keycode)
{
event_t event = {
.type = event_key_release,
.key = keycode,
};
event_push(event);
}
/*
keyboard_interrupt()
Callback function for keyboard update; called by the timer manager when
the keyboard's virtual timer fires. Ideally this function should be
interrupt-driven but the PINT interrupts seem to fire continuously,
which is annoying.
*/
void keyboard_interrupt(void)
{
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];
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++)
{
uint8_t pressed = ~keyboard_state[row] & state[row];
uint8_t repeated = keyboard_state[row] & state[row];
uint8_t released = keyboard_state[row] & ~state[row];
keyboard_state[row] = state[row];
// Make this a bit faster.
if(!(pressed | repeated | released)) continue;
for(int column = 0; column < 8; column++)
{
if(pressed & 1) push_press ((column << 4) | row);
if(repeated & 1) push_repeat ((column << 4) | row);
if(released & 1) push_release((column << 4) | row);
pressed >>= 1;
repeated >>= 1;
released >>= 1;
}
}
// Signal the interrupt to the higher-level functions.
interrupt_flag = 1;
}
//---
// Keyboard configuration.
//---
/*
keyboard_init()
Starts the keyboard timer.
*/
__attribute__((constructor)) void keyboard_init(void)
{
keyboard_setRepeatRate(625, 125);
vtimer = timer_create(25, 0);
timer_attach(vtimer, keyboard_interrupt, NULL);
timer_start(vtimer);
}
/*
keyboard_setAnalysisDelay()
Sets the keyboard analysis delay, that is, the delay (in ms) between
two keyboard analyzes. Please note that the repeat delays should be
multiples of the analysis delay for better accuracy.
*/
void keyboard_setAnalysisDelay(int analysis_delay_ms)
{
if(analysis_delay_ms <= 0) return;
timer_reload(vtimer, analysis_delay_ms);
}
/*
keyboard_setRepeatRate()
Sets the default repeat rate for key events. The delay before the first
repeat may have a different value (usually longer). The unit for the
argument is ms, but the repeat events themselves may only be fired when
a keyboard analysis is performed; which means that for better accuracy,
these delays should be a multiple of the keyboard period.
For instance, delays of (625 ms, 125 ms) will imitate the system's
default setting.
*/
void keyboard_setRepeatRate(int first, int next)
{
repeat_first = (first > 0) ? first : 0;
repeat_next = (next > 0) ? next : 0;
}
/*
keyboard_quit()
Stops the keyboard timer.
*/
__attribute__((destructor)) void keyboard_quit(void)
{
timer_destroy(vtimer);
vtimer = NULL;
}
/*
keyboard_stateBuffer()
Returns the address of the keyboard state array. The returned address
is the handler's buffer, therefore it contains volatile data.
*/
volatile uint8_t *keyboard_stateBuffer(void)
{
return keyboard_state;
}

View file

@ -1,132 +0,0 @@
#include <internals/keyboard.h>
#include <keyboard.h>
#include <timer.h>
#include <mpu.h>
#include <clock.h>
#include <events.h>
//---
// Keyboard variables.
//---
// These ones get modified by interrupts.
volatile uint8_t keyboard_state[10] = { 0 };
volatile int interrupt_flag = 0;
// Key statistics.
int repeat_first = 10, repeat_next = 2;
int last_key = KEY_NONE, last_repeats = 0, last_events = 0;
// RTC callback id.
unsigned cb_id;
//---
// Interrupt management.
//---
static void push_press(int keycode)
{
event_t event = {
.type = ET_KeyPress,
.key = keycode,
};
event_push(event);
}
static void push_repeat(int keycode)
{
event_t event = {
.type = ET_KeyRepeat,
.key = keycode,
};
event_push(event);
}
static void push_release(int keycode)
{
event_t event = {
.type = ET_KeyRel,
.key = keycode,
};
event_push(event);
}
/*
keyboard_interrupt()
Callback for keyboard update. Allows keyboard analysis functions to
wake only when keyboard interrupts happen.
*/
void keyboard_interrupt(void)
{
uint8_t state[10] = { 0 };
isSH3() ? keyboard_updateState_7705(state)
: keyboard_updateState_7305(state)
;
// Try to minimize number of operations in common cases... this 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];
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++)
{
uint8_t pressed = ~keyboard_state[row] & state[row];
uint8_t repeated = keyboard_state[row] & state[row];
uint8_t released = keyboard_state[row] & ~state[row];
keyboard_state[row] = state[row];
// Fasten this a bit.
if(!(pressed | repeated | released)) continue;
for(int column = 0; column < 8; column++)
{
if(pressed & 1) push_press ((column << 4) | row);
if(repeated & 1) push_repeat ((column << 4) | row);
if(released & 1) push_release((column << 4) | row);
pressed >>= 1;
repeated >>= 1;
released >>= 1;
}
}
interrupt_flag = 1;
}
/*
keyboard_init()
Starts the keyboard timer.
*/
__attribute__((constructor)) void keyboard_init(void)
{
cb_id = rtc_cb_add(RTCFreq_16Hz, keyboard_interrupt, 0);
}
/*
keyboard_setFrequency()
Sets the keyboard frequency.
*/
void keyboard_setFrequency(enum KeyboardFrequency frequency)
{
if(frequency < 1 || frequency > 7) return;
rtc_cb_edit(cb_id, frequency, keyboard_interrupt);
}
/*
keyboard_quit()
Stops the keyboard timer.
*/
__attribute__((destructor)) void keyboard_quit(void)
{
rtc_cb_end(cb_id);
}

View file

@ -1,25 +0,0 @@
#include <keyboard.h>
#include <internals/keyboard.h>
/*
keylast()
Returns the matrix code of the last pressed key. If repeat_count is
non-NULL, it is set to the number of repetitions.
*/
int keylast(int *repeat_count)
{
if(repeat_count) *repeat_count = last_repeats;
return last_key;
}
/*
keystate()
Returns the address of the keyboard state array. The returned address
is the handler's buffer, therefore it contains volatile data.
*/
volatile uint8_t *keystate(void)
{
return keyboard_state;
}

View file

@ -10,6 +10,7 @@
//
//---
#include <stdint.h>
#include <keyboard.h>
#include <7305.h>
@ -61,20 +62,20 @@ static void kdelay(void)
*/
static int krow(int row)
{
volatile unsigned short *injector1 = (unsigned short *)0xa4050116;
volatile unsigned char *data1 = (unsigned char *)0xa4050136;
volatile uint16_t *injector1 = (void *)0xa4050116;
volatile uint8_t *data1 = (void *)0xa4050136;
volatile unsigned short *injector2 = (unsigned short *)0xa4050118;
volatile unsigned char *data2 = (unsigned char *)0xa4050138;
volatile uint16_t *injector2 = (void *)0xa4050118;
volatile uint8_t *data2 = (void *)0xa4050138;
volatile unsigned short *detector = (unsigned short *)0xa405014c;
volatile unsigned char *keys = (unsigned char *)0xa405016c;
volatile uint16_t *detector = (void *)0xa405014c;
volatile uint8_t *keys = (void *)0xa405016c;
volatile unsigned char *key_register = (unsigned char *)0xa40501c6;
// volatile unsigned short *hizcrb = (unsigned short *)0xa405015a;
volatile uint8_t *key_register = (void *)0xa40501c6;
// volatile uint16_t *hizcrb = (void *)0xa405015a;
unsigned short smask;
unsigned char cmask;
uint16_t smask;
uint8_t cmask;
int result = 0;
if(row < 0 || row > 9) return 0;

View file

@ -1,17 +0,0 @@
#include <keyboard.h>
/*
keyid()
Returns a non-matrix key code that can be used for array subscript.
Ignores modifiers.
*/
int keyid(int key)
{
if(key < 0) return -1;
key &= MOD_CLEAR;
int row = 9 - (key & 0x0f);
int column = 6 - ((key & 0xf0) >> 4);
return 6 * row + column;
}

View file

@ -1,17 +0,0 @@
#include <keyboard.h>
/*
keytype()
Returns a key's type. Ignores modifiers.
*/
enum KeyType keytype(int key)
{
key &= MOD_CLEAR;
if(key == KEY_UP || key == KEY_RIGHT || key == KEY_DOWN ||
key == KEY_LEFT) return KeyType_Arrow;
if((key & 0x0f) == 0x09) return KeyType_Function;
return keychar(key) ? KeyType_Character : KeyType_Control;
}

View file

@ -40,7 +40,7 @@ void multigetkey(int *keys, int count, int cycles)
{
last_key = keys[0];
last_repeats = 0;
last_events = 0;
last_time = 0;
}
if(number) break;
@ -48,7 +48,7 @@ void multigetkey(int *keys, int count, int cycles)
}
do event = pollevent();
while(event.type != ET_None);
while(event.type != event_none);
return;
}

View file

@ -1,64 +0,0 @@
#include <ctype.h>
enum {
cntrl = 0x01,
space = 0x02,
punct = 0x04,
print = 0x08,
upper = 0x20,
lower = 0x10,
digit = 0x40,
xdigt = 0x80,
};
uint8_t ctype_classes[0x80] = {
// Control characters.
cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl,
cntrl | space, // Tabulation
cntrl | space, cntrl | space, cntrl | space, cntrl | space,
cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl,
cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl,
// Space and some punctuation.
space | print,
punct | print, punct | print, punct | print, punct | print,
punct | print, punct | print, punct | print, punct | print,
punct | print, punct | print, punct | print, punct | print,
punct | print, punct | print, punct | print,
// Decimal digits.
digit | xdigt | print, digit | xdigt | print, digit | xdigt | print,
digit | xdigt | print, digit | xdigt | print, digit | xdigt | print,
digit | xdigt | print, digit | xdigt | print, digit | xdigt | print,
digit | xdigt | print,
// Some punctuation.
punct | print, punct | print, punct | print, punct | print,
punct | print, punct | print, punct | print,
// Uppercase alphabet.
upper | xdigt | print, upper | xdigt | print, upper | xdigt | print,
upper | xdigt | print, upper | xdigt | print, upper | xdigt | print,
upper | print, upper | print, upper | print, upper | print,
upper | print, upper | print, upper | print, upper | print,
upper | print, upper | print, upper | print, upper | print,
upper | print, upper | print, upper | print, upper | print,
upper | print, upper | print, upper | print, upper | print,
// Other punctuation symbols.
punct | print, punct | print, punct | print, punct | print,
punct | print, punct | print,
// Lowercase alphabet.
lower | xdigt | print, lower | xdigt | print, lower | xdigt | print,
lower | xdigt | print, lower | xdigt | print, lower | xdigt | print,
lower | print, lower | print, lower | print, lower | print,
lower | print, lower | print, lower | print, lower | print,
lower | print, lower | print, lower | print, lower | print,
lower | print, lower | print, lower | print, lower | print,
lower | print, lower | print, lower | print, lower | print,
// Last punctuation characters and DEL.
punct | print, punct | print, punct | print, punct | print,
cntrl
};

View file

@ -5,11 +5,11 @@
text_configure()
Sets the font and mode to use for the following print operations.
*/
void text_configure(struct Font *next_font, enum Color next_color)
void text_configure(struct Font *next_font, color_t next_operator)
{
extern Font gint_font_system;
if(next_font) font = next_font;
else font = &gint_font_system;
color = next_color;
operator = next_operator;
}

View file

@ -4,42 +4,61 @@
void operate_gray(OPERATE_ARGS)
{
int *vl = gray_lightVRAM();
int *vd = gray_darkVRAM();
int vram_offset = (x >> 5) + (y << 2);
uint32_t op;
int i;
size_t vram_offset = (x >> 5) + (y << 2);
uint32_t *light = gray_lightVRAM() + vram_offset;
uint32_t *dark = gray_darkVRAM() + vram_offset;
uint32_t op, old_light;
for(i = 0; i < height; i++)
for(int i = 0; i < height; i++)
{
op = operators[i];
switch(color)
switch(operator)
{
case Color_White:
vl[vram_offset] &= ~op;
vd[vram_offset] &= ~op;
case color_white:
*light &= ~op;
*dark &= ~op;
break;
case Color_Light:
vl[vram_offset] |= op;
vd[vram_offset] &= ~op;
case color_light:
*light |= op;
*dark &= ~op;
break;
case Color_Dark:
vl[vram_offset] &= ~op;
vd[vram_offset] |= op;
case color_dark:
*light &= ~op;
*dark |= op;
break;
case Color_Black:
vl[vram_offset] |= op;
vd[vram_offset] |= op;
case color_black:
*light |= op;
*dark |= op;
break;
case Color_Invert:
vl[vram_offset] ^= op;
vd[vram_offset] ^= op;
case color_none:
return;
case color_invert:
*light ^= op;
*dark ^= op;
break;
default:
case color_lighten:
old_light = *light;
*light &= *dark | ~op;
*dark = (old_light | ~op) & (op ^ *dark);
break;
case color_lighten2:
*dark &= *light | ~op;
*light &= ~op;
break;
case color_darken:
old_light = *light;
*light |= *dark & op;
*dark = (old_light & op) | (op ^ *dark);
break;
case color_darken2:
*dark |= *light | op;
*light |= op;
break;
}
vram_offset += 4;
light += 4;
dark += 4;
}
}

View file

@ -5,7 +5,7 @@
#include <gray.h>
struct Font *font;
enum Color color;
color_t operator;
/*
tales_init()
@ -13,7 +13,7 @@ enum Color color;
*/
void tales_init(void)
{
text_configure(NULL, Color_Black);
text_configure(NULL, color_black);
}
/*
@ -93,31 +93,36 @@ int getCharacterIndex(int c)
*/
void operate_mono(OPERATE_ARGS)
{
int *vram = display_getCurrentVRAM();
int vram_offset = (x >> 5) + (y << 2);
uint32_t op;
int i;
uint32_t *vram = display_getCurrentVRAM();
uint32_t *video = vram + (x >> 5) + (y << 2);
for(i = 0; i < height; i++)
switch(operator)
{
op = operators[i];
switch(color)
case color_white:
for(int i = 0; i < height; i++)
{
case Color_White:
vram[vram_offset] &= ~op;
break;
case Color_Black:
vram[vram_offset] |= op;
break;
case Color_Invert:
vram[vram_offset] ^= op;
break;
default:
break;
*video &= ~operators[i];
video += 4;
}
break;
vram_offset += 4;
case color_black:
for(int i = 0; i < height; i++)
{
*video |= operators[i];
video += 4;
}
break;
case color_invert:
for(int i = 0; i < height; i++)
{
*video ^= operators[i];
video += 4;
}
break;
default: return;
}
}

View file

@ -94,7 +94,7 @@ void timer_callback_event(timer_t *timer)
else
{
event_t event = {
.type = ET_Timer,
.type = event_timer_underflow,
.timer = timer
};
event_push(event);

View file

@ -38,6 +38,24 @@ timer_t *timer_create(int ms_delay, int repeats)
return timer;
}
/*
timer_reload()
Changes a virtual timer's delay. The timer is not stopped nor started:
it keeps running or waiting. Events that were waiting to be handled are
dropped and the number of repeats left is not changed. The timer
restarts counting from 0 regardless of how much time had elapsed since
it last fired.
*/
void timer_reload(timer_t *timer, int new_ms_delay)
{
if(!timer->virtual) return;
timer->ms_delay = new_ms_delay;
timer->ms_elapsed = 0;
vtimer_updateAll();
}
/*
timer_destroy()
Destroys a virtual timer. This virtual timer pointer becomes invalid
@ -136,7 +154,7 @@ static void vtimer_update(int new_delay)
timer_stop(timer);
return;
}
uint32_t new_constant = clock_setting(new_delay, Clock_ms);
uint32_t new_constant = clock_setting(new_delay, clock_ms);
// The transition needs to be as smooth as possible. We have probably
// spent a lot of time calculating this new GCD delay so we want to
@ -176,7 +194,7 @@ static void vtimer_update(int new_delay)
/*
gcd()
Well, the Euclidean algorithm. That's a O(ln(a)) & O(ln(b)) FWIW.
Well, the Euclidean algorithm. That's O(ln(max(a, b))) FWIW.
*/
static int gcd(int a, int b)
{