mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-29 13:03:36 +01:00
Almost ended quality review, and fixed tales-related vram overflows.
This commit is contained in:
parent
6c0ae34708
commit
3214f6b797
33 changed files with 327 additions and 183 deletions
2
Makefile
2
Makefile
|
@ -30,7 +30,7 @@ wr = g1a-wrapper
|
|||
|
||||
# Flags for gint
|
||||
lib-cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \
|
||||
-Wall -Wextra @gcc.cfg
|
||||
-Wall -Wextra @gcc.cfg -g0
|
||||
|
||||
# Demo application (could be done better)
|
||||
demo-src = $(notdir $(wildcard demo/*.[cs]))
|
||||
|
|
9
TODO
9
TODO
|
@ -3,14 +3,11 @@ Bugs to fix:
|
|||
- Lost keyboard control at startup (could not reproduce)
|
||||
- Alignment of ALL .data / .rodata files is required to ensure converted data
|
||||
is properly aligned
|
||||
- Reported video ram overflow when rendering text at borderline positions
|
||||
|
||||
Things to do before 1.0:
|
||||
- bopti: Test partial transparency
|
||||
* core: Allow return to menu
|
||||
- demo: Try 284x124 at (-60, -28) (all disadvantages)
|
||||
- display: Implement rectangle-based drawing functions
|
||||
- project: Add a real build-based version system
|
||||
- project: Check size of *all* library structures
|
||||
- project: Clean headers that have some internal definitions
|
||||
- project: Unify this hellish mess of register access!
|
||||
|
@ -24,7 +21,13 @@ Things to do later:
|
|||
- core: Review interrupt system (again) - this one is too slow
|
||||
- errno: Introduce errno and use it more or less everywhere
|
||||
- esper: Cleaner playback, synthesizing
|
||||
- events: Allow customization of keyboard event system (option to return
|
||||
| events with modifiers, etc)
|
||||
- events: Generate keyboard events on-the-fly by reading state arrays,
|
||||
| allowing both a faster interrupt and avoiding supressing other
|
||||
| events inside getkey() and multigetkey()
|
||||
- serial: Implement a driver
|
||||
- stdio: More serious formatted printing functions
|
||||
- string: Use cmp/str to implement memchr() (assembler examples)
|
||||
- string: Do some tests for memcmp() and memcpy()
|
||||
- usb: Implement a driver
|
||||
|
|
56
demo/asm_syscalls.s
Normal file
56
demo/asm_syscalls.s
Normal file
|
@ -0,0 +1,56 @@
|
|||
|
||||
# int BFile_Remove(const uint16_t *file)
|
||||
.global _BFile_Remove
|
||||
|
||||
_BFile_Remove:
|
||||
mov.l 1f, r0
|
||||
mov.l 2f, r1
|
||||
jmp @r1
|
||||
mov #0, r5
|
||||
1: .long 0x0439
|
||||
|
||||
# int BFile_Create(const uint16_t *file, enum { file = 1, folder = 5 },
|
||||
# int *size)
|
||||
.global _BFile_Create
|
||||
|
||||
_BFile_Create:
|
||||
mov.l 1f, r0
|
||||
mov.l 2f, r1
|
||||
jmp @r1
|
||||
nop
|
||||
1: .long 0x0434
|
||||
|
||||
# int BFile_Open(const uint16_t *file, int mode)
|
||||
.global _BFile_Open
|
||||
|
||||
_BFile_Open:
|
||||
mov.l 1f, r0
|
||||
mov.l 2f, r1
|
||||
jmp @r1
|
||||
mov #0, r6
|
||||
1: .long 0x042c
|
||||
|
||||
# int BFile_Close(int handle)
|
||||
.global _BFile_Close
|
||||
|
||||
_BFile_Close:
|
||||
mov.l 1f, r0
|
||||
mov.l 2f, r1
|
||||
jmp @r1
|
||||
nop
|
||||
1: .long 0x042d
|
||||
|
||||
# int BFile_Write(int handle, void *ram_buffer, int even_size)
|
||||
.global _BFile_Write
|
||||
|
||||
_BFile_Write:
|
||||
mov.l 1f, r0
|
||||
mov.l 2f, r1
|
||||
jmp @r1
|
||||
nop
|
||||
1: .long 0x0435
|
||||
|
||||
.align 4
|
||||
|
||||
# Syscall branch address
|
||||
2: .long 0x80010070
|
|
@ -434,6 +434,10 @@ void main_menu(int *category, int *app)
|
|||
index = 0;
|
||||
scroll = 0;
|
||||
break;
|
||||
case KEY_F6:;
|
||||
void screen(void);
|
||||
screen();
|
||||
break;
|
||||
|
||||
case KEY_UP:
|
||||
if(list && list_len > 1)
|
||||
|
@ -533,3 +537,48 @@ void crash(void)
|
|||
"trapa #1 "
|
||||
);
|
||||
}
|
||||
|
||||
void screen(void)
|
||||
{
|
||||
enum { File = 1, Folder = 5 };
|
||||
enum { Read = 0x01, Write = 0x02, ReadWrite = Read | Write };
|
||||
|
||||
int BFile_Remove(const uint16_t *file);
|
||||
int BFile_Create(const uint16_t *file, int type, int *size);
|
||||
int BFile_Open(const uint16_t *file, int mode);
|
||||
int BFile_Close(int handle);
|
||||
int BFile_Write(int handle, const void *ram_buffer, int even_size);
|
||||
|
||||
const uint8_t bmp_header[0x7e] = {
|
||||
0x42, 0x4d, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6c, 0x00,
|
||||
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x13, 0x0b,
|
||||
0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x47,
|
||||
0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
|
||||
};
|
||||
const uint16_t file[] = { '\\', '\\', 'f', 'l', 's', '0', '\\', 'g',
|
||||
's', 'c', 'r', 'e', 'e', 'n', '.', 'b', 'm', 'p', 0x00 };
|
||||
int size = 0x7e + 1024;
|
||||
|
||||
BFile_Remove(file);
|
||||
BFile_Create(file, File, &size);
|
||||
int handle = BFile_Open(file, Write);
|
||||
BFile_Write(handle, bmp_header, 0x7e);
|
||||
void *vram = (void *)display_getCurrentVRAM() + 1024;
|
||||
for(int i = 1; i <= 64; i++)
|
||||
{
|
||||
BFile_Write(handle, vram - 16 * i, 16);
|
||||
}
|
||||
BFile_Close(handle);
|
||||
}
|
||||
|
|
|
@ -53,14 +53,15 @@ static void draw_keyboard(volatile uint8_t *state)
|
|||
|
||||
typedef struct {
|
||||
event_type_t type;
|
||||
int key;
|
||||
uint32_t key;
|
||||
int repeats;
|
||||
|
||||
} enhanced_event_t;
|
||||
|
||||
static void push_history(enhanced_event_t *history, int size, event_t event)
|
||||
{
|
||||
#define event_eq(x, y) ((x).type == (y).type && (x).key == (y).key)
|
||||
#define event_eq(x, y) \
|
||||
((x).type == (y).type && (x).key == (y).key.code)
|
||||
|
||||
// Determining where the history ends.
|
||||
int length = 0;
|
||||
|
@ -82,7 +83,7 @@ static void push_history(enhanced_event_t *history, int size, event_t event)
|
|||
|
||||
// Adding a new entry to the history.
|
||||
history[length].type = event.type;
|
||||
history[length].key = event.key;
|
||||
history[length].key = event.key.code;
|
||||
history[length].repeats = 1;
|
||||
|
||||
#undef event_eq
|
||||
|
@ -135,7 +136,7 @@ void test_keyboard_events(void)
|
|||
dupdate();
|
||||
|
||||
event = waitevent();
|
||||
if(event.type == event_key_press && event.key == KEY_EXIT)
|
||||
if(event.type == event_key_press && event.key.code == KEY_EXIT)
|
||||
break;
|
||||
push_history(history, history_size, event);
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
Displays some text using different modes and clipping options.
|
||||
*/
|
||||
|
||||
static Font *select(Font *current)
|
||||
static font_t *select(font_t *current)
|
||||
{
|
||||
extern Font res_font_modern;
|
||||
extern font_t res_font_modern;
|
||||
struct {
|
||||
Font *font;
|
||||
font_t *font;
|
||||
const char *name;
|
||||
} fonts[] = {
|
||||
{ NULL, "gint default" },
|
||||
|
@ -83,7 +83,7 @@ void test_tales(void)
|
|||
color_t colors[] = { color_black, color_dark, color_light, color_white,
|
||||
color_invert };
|
||||
extern image_t res_opt_tales;
|
||||
Font *font = NULL;
|
||||
font_t *font = NULL;
|
||||
|
||||
int black_bg = 0;
|
||||
int color = 0;
|
||||
|
@ -113,10 +113,8 @@ void test_tales(void)
|
|||
for(int j = 0; j < 16; j++) str[j] = 32 + (i << 4) + j;
|
||||
str[16] = 0;
|
||||
|
||||
gtext(-3, -3 + i * height, str);
|
||||
gtext(1, 1 + i * height, str);
|
||||
}
|
||||
gtext(120, 60, "Hello, World!");
|
||||
gtext(-40, 2, "Try");
|
||||
|
||||
gimage(0, 56, &res_opt_tales);
|
||||
|
||||
|
|
|
@ -41,6 +41,23 @@ typedef enum
|
|||
|
||||
} event_type_t;
|
||||
|
||||
/*
|
||||
key_event_t
|
||||
Keyboard events. "I think the user wants something."
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
// This is the key code as defined in <keyboard.h> (a matrix code), and
|
||||
// probably what you need.
|
||||
uint32_t code;
|
||||
// This is a "compact id" which can be used for array subscript. There
|
||||
// are only a few holes in the "compact id" numbering.
|
||||
uint32_t id;
|
||||
// Character associated with the event key.
|
||||
int character;
|
||||
|
||||
} key_event_t;
|
||||
|
||||
/*
|
||||
event_t
|
||||
Wake up, something's going on. The union member that holds information
|
||||
|
@ -55,7 +72,7 @@ typedef struct
|
|||
// For event_user.
|
||||
void *data;
|
||||
// For event_key_press, event_key_repeat and event_key_release.
|
||||
int key;
|
||||
key_event_t key;
|
||||
// For event_timer_underflow.
|
||||
timer_t *timer;
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@ __attribute__((always_inline)) static inline uint32_t swap32(uint32_t longw)
|
|||
"swap.b r0, %0 \n\t"
|
||||
: "=r"(result)
|
||||
: "r"(longw)
|
||||
: "r0"
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -15,11 +15,16 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// This one is defined by the linked and consists in four fields:
|
||||
// The version symbol is defined through the linker and consists of four
|
||||
// fields:
|
||||
// - Version type, an ascii char ('a'lpha, 'b'eta, 'd'ev, 'r'elease), 8 bits
|
||||
// - Major version number, 4 bits
|
||||
// - Minor version numer, 4 bits
|
||||
// - Minor version number, 4 bits
|
||||
// - Build number, 16 bits
|
||||
// Please note that the version number is the *ADDRESS* of GINT_VERSION, which
|
||||
// you definitely want to cast to uint32_t. Evaluating GINT_VERSION is illegal
|
||||
// (dereferencing a pointer which is actually a four-field version number just
|
||||
// cannot work) and will certainly crash your program.
|
||||
extern uint32_t GINT_VERSION;
|
||||
|
||||
//---
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
//---
|
||||
//
|
||||
// standard library module: stdio
|
||||
//
|
||||
// Handles most input/output for the program. This module does not
|
||||
// interact with the file system directly.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _INTERNALS_STDIO_H
|
||||
#define _INTERNALS_STDIO_H
|
||||
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
#include <tales.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define OPERATE_ARGS uint32_t *operators, int height, int x, int y
|
||||
|
||||
extern struct Font *font;
|
||||
extern font_t *font;
|
||||
extern color_t operator;
|
||||
|
||||
/*
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
// Padding is just empty space, we don't want to give it a name. There's also
|
||||
// Padding is just empty space, we don't want to give it a type. There's also
|
||||
// some subtle preprocessor trick to automatically add a (supposedly) unique
|
||||
// name to each padding member. For instance the substitution may operate as:
|
||||
// name(__LINE__) -> namesub(78) -> _##78 -> _78
|
||||
#define namesub(x) _##x
|
||||
#define name(x) namesub(x)
|
||||
#define pad(bytes) \
|
||||
uint8_t name(__LINE__)[bytes] \
|
||||
uint8_t name(__LINE__)[bytes]
|
||||
|
||||
// Fixed-width types for bit field are totally meaningless.
|
||||
typedef unsigned uint;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// which is stored in a global variable MPU_CURRENT and determined at
|
||||
// startup.
|
||||
//
|
||||
// If you need to do MPU-dependant jobs, use isSH3() or (possibly) isSH4()
|
||||
// If you need to do MPU-dependent jobs, use isSH3() or (possibly) isSH4()
|
||||
// instead of testing the value of MPU_CURRENT because these macros take
|
||||
// care of assuming unknown MPUs are SH4, which is the more reasonable
|
||||
// option.
|
||||
|
|
|
@ -10,9 +10,11 @@
|
|||
#ifndef _SETJMP_H
|
||||
#define _SETJMP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// There are 16 CPU registers that *must* be saved to ensure a basically
|
||||
// safe jump.
|
||||
typedef unsigned int jmp_buf[16];
|
||||
typedef uint32_t jmp_buf[16];
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -19,42 +19,43 @@
|
|||
//---
|
||||
|
||||
/*
|
||||
enum ImageFormat
|
||||
font_format_t
|
||||
This type holds information about the characters in the font. Each bit
|
||||
represents various characters, and the type itself is a combination of
|
||||
several of those bits.
|
||||
Bits represent the following characters (lsb right):
|
||||
-- -- -- non-print | special capitals lower numbers
|
||||
*/
|
||||
enum FontFormat
|
||||
typedef enum
|
||||
{
|
||||
FontFormat_Unknown = 0x00,
|
||||
FontFormat_Numeric = 0x01,
|
||||
FontFormat_LowerCase = 0x02,
|
||||
FontFormat_UpperCase = 0x04,
|
||||
FontFormat_Letters = 0x06,
|
||||
FontFormat_Common = 0x07,
|
||||
FontFormat_Print = 0x0f,
|
||||
FontFormat_Ascii = 0x1f,
|
||||
};
|
||||
font_format_unknown = 0x00,
|
||||
font_format_numeric = 0x01,
|
||||
font_format_lower = 0x02,
|
||||
font_format_upper = 0x04,
|
||||
font_format_letters = 0x06,
|
||||
font_format_common = 0x07,
|
||||
font_format_print = 0x0f,
|
||||
font_format_ascii = 0x1f,
|
||||
|
||||
} font_format_t;
|
||||
|
||||
/*
|
||||
struct FontGlyph
|
||||
font_glyph_t
|
||||
Holds a glyph's data. The width is used for spacing, and the raw data
|
||||
is encoded line after line, from to to bottom, by appending bits
|
||||
without consideration of the byte boundaries.
|
||||
This structure is actually never used, because data is read directly
|
||||
as a longword array (hence the 4-byte alignment).
|
||||
*/
|
||||
struct FontGlyph
|
||||
typedef struct
|
||||
{
|
||||
unsigned char width;
|
||||
uint8_t width;
|
||||
const uint8_t data[];
|
||||
|
||||
const unsigned char data[];
|
||||
} __attribute__((aligned(4)));
|
||||
} __attribute__((packed, aligned(4))) font_glyph_t;
|
||||
|
||||
/*
|
||||
struct Font
|
||||
font_t
|
||||
Holds a font's data. Data is accessed using longword operations, hence
|
||||
the 4-alignment attributes. The line height is the one given in the
|
||||
font image header line, which may be used by applications that write
|
||||
|
@ -65,13 +66,12 @@ struct FontGlyph
|
|||
The name field may not be NUL-terminated when the name contains 28
|
||||
characters. When the name is shorter, the field is padded with zeros.
|
||||
*/
|
||||
struct Font
|
||||
typedef struct
|
||||
{
|
||||
unsigned char magic;
|
||||
|
||||
unsigned char format;
|
||||
unsigned char line_height;
|
||||
unsigned char data_height;
|
||||
uint8_t magic;
|
||||
uint8_t format;
|
||||
uint8_t line_height;
|
||||
uint8_t data_height;
|
||||
|
||||
// Warning : this field may not be NUL-terminated.
|
||||
char name[28];
|
||||
|
@ -80,9 +80,7 @@ struct Font
|
|||
|
||||
__attribute__((aligned(4))) const uint32_t glyphs[];
|
||||
|
||||
} __attribute__((aligned(4)));
|
||||
// Useful shorthand for user code.
|
||||
typedef struct Font Font;
|
||||
} __attribute__((packed, aligned(4))) font_t;
|
||||
|
||||
|
||||
|
||||
|
@ -95,7 +93,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, color_t operator);
|
||||
void text_configure(font_t *font, color_t operator);
|
||||
|
||||
/*
|
||||
text_length()
|
||||
|
|
|
@ -36,7 +36,7 @@ struct tm
|
|||
clock_t
|
||||
Only used by clock().
|
||||
*/
|
||||
typedef signed int clock_t;
|
||||
typedef signed int clock_t;
|
||||
|
||||
/*
|
||||
time_t
|
||||
|
|
|
@ -11,14 +11,18 @@
|
|||
#include <timer.h>
|
||||
#include <mpu.h>
|
||||
|
||||
// Additional video rams used by the gray engine.
|
||||
static uint32_t internal_vrams[3][256];
|
||||
static uint32_t *vrams[4];
|
||||
|
||||
// Current vram set (0 or 1), delays of the light and dark frames respectively.
|
||||
static int current = 0;
|
||||
static int delays[2];
|
||||
|
||||
// Is the engine currently running?
|
||||
static int runs = 0;
|
||||
|
||||
// Hardware timer used to run the engine.
|
||||
static timer_t *gray_timer = NULL;
|
||||
|
||||
|
||||
|
@ -87,6 +91,9 @@ void gray_stop(void)
|
|||
timer_stop(gray_timer);
|
||||
runs = 0;
|
||||
|
||||
/* TODO This may not be very wise considering the fact that the user
|
||||
may have specified another monochrome vram address. This raises again
|
||||
the idea of a parameter stack. */
|
||||
display_useVRAM(display_getLocalVRAM());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
#include <internals/keyboard.h>
|
||||
|
||||
/*
|
||||
getPressedKey()
|
||||
Finds a pressed key in the keyboard state and returns it.
|
||||
*/
|
||||
int getPressedKey(volatile uint8_t *keyboard_state)
|
||||
{
|
||||
int row = 1, column = 0;
|
||||
int state;
|
||||
if(keyboard_state[0] & 1) return KEY_AC_ON;
|
||||
|
||||
while(row <= 9 && !keyboard_state[row]) row++;
|
||||
if(row > 9) return KEY_NONE;
|
||||
|
||||
state = keyboard_state[row];
|
||||
while(!(state & 1))
|
||||
{
|
||||
state >>= 1;
|
||||
column++;
|
||||
}
|
||||
|
||||
return (column << 4) | row;
|
||||
}
|
|
@ -53,7 +53,7 @@ int getkey_opt(getkey_option_t options, int delay_ms)
|
|||
break;
|
||||
|
||||
case event_key_press:
|
||||
key = event.key;
|
||||
key = event.key.code;
|
||||
|
||||
if(options & getkey_manage_backlight && key == KEY_OPTN
|
||||
&& (modifier & MOD_SHIFT))
|
||||
|
@ -79,7 +79,7 @@ int getkey_opt(getkey_option_t options, int delay_ms)
|
|||
return key | modifier;
|
||||
|
||||
case event_key_repeat:
|
||||
key = event.key;
|
||||
key = event.key.code;
|
||||
if(key != last_key) continue;
|
||||
|
||||
// Checking that this type of repetition is allowed.
|
||||
|
@ -98,7 +98,7 @@ int getkey_opt(getkey_option_t options, int delay_ms)
|
|||
break;
|
||||
|
||||
case event_key_release:
|
||||
if(event.key != last_key) break;
|
||||
if((int)event.key.code != last_key) break;
|
||||
last_key = KEY_NONE;
|
||||
last_repeats = 0;
|
||||
last_time = 0;
|
||||
|
|
|
@ -36,27 +36,39 @@ timer_t *vtimer = NULL;
|
|||
|
||||
static inline void push_press(int keycode)
|
||||
{
|
||||
uint32_t id = key_id(keycode);
|
||||
|
||||
event_t event = {
|
||||
.type = event_key_press,
|
||||
.key = keycode,
|
||||
.type = event_key_press,
|
||||
.key.code = keycode,
|
||||
.key.id = id,
|
||||
.key.character = key_char(keycode),
|
||||
};
|
||||
event_push(event);
|
||||
}
|
||||
|
||||
static inline void push_repeat(int keycode)
|
||||
{
|
||||
uint32_t id = key_id(keycode);
|
||||
|
||||
event_t event = {
|
||||
.type = event_key_repeat,
|
||||
.key = keycode,
|
||||
.type = event_key_repeat,
|
||||
.key.code = keycode,
|
||||
.key.id = id,
|
||||
.key.character = key_char(keycode),
|
||||
};
|
||||
event_push(event);
|
||||
}
|
||||
|
||||
static inline void push_release(int keycode)
|
||||
{
|
||||
uint32_t id = key_id(keycode);
|
||||
|
||||
event_t event = {
|
||||
.type = event_key_release,
|
||||
.key = keycode,
|
||||
.type = event_key_release,
|
||||
.key.code = keycode,
|
||||
.key.id = id,
|
||||
.key.character = key_char(keycode),
|
||||
};
|
||||
event_push(event);
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
many keys on the same column are pressed, other keys of the same column
|
||||
may be triggered.
|
||||
|
||||
(The following values do not apply to the latest tests, even if the
|
||||
trend remains the same.)
|
||||
(The following values do not apply to the latest tests, but the trend
|
||||
remains the same.)
|
||||
- Less Bad key detection.
|
||||
- 8 Very few column effects. Most often, three keys may be pressed
|
||||
simultaneously. However, [UP] has latencies and is globally not
|
||||
|
@ -63,7 +63,7 @@ static void kdelay(void)
|
|||
Reads a keyboard row. Works like krow() for SH7705; see source file
|
||||
keyboard_7705.c for more details.
|
||||
*/
|
||||
static int krow(int row)
|
||||
static uint8_t krow(int row)
|
||||
{
|
||||
volatile uint16_t *injector1 = (void *)0xa4050116;
|
||||
volatile uint8_t *data1 = (void *)0xa4050136;
|
||||
|
@ -79,9 +79,9 @@ static int krow(int row)
|
|||
|
||||
uint16_t smask;
|
||||
uint8_t cmask;
|
||||
int result = 0;
|
||||
uint8_t result = 0;
|
||||
|
||||
if(row < 0 || row > 9) return 0;
|
||||
if(row < 0 || row > 9) return 0x00;
|
||||
|
||||
// Additional configuration for SH7305.
|
||||
*detector = 0xaaaa;
|
||||
|
|
|
@ -66,16 +66,16 @@ static void kdelay(void)
|
|||
krow()
|
||||
Reads a keyboard row.
|
||||
*/
|
||||
static int krow(int row)
|
||||
static uint8_t krow(int row)
|
||||
{
|
||||
// '11' on the active row, '00' everywhere else.
|
||||
unsigned short smask = 0x0003 << ((row % 8) * 2);
|
||||
uint16_t smask = 0x0003 << ((row % 8) * 2);
|
||||
// '0' on the active row, '1' everywhere else.
|
||||
unsigned char cmask = ~(1 << (row % 8));
|
||||
uint8_t cmask = ~(1 << (row % 8));
|
||||
// Line results.
|
||||
int result = 0;
|
||||
uint8_t result = 0;
|
||||
|
||||
if(row < 0 || row > 9) return 0;
|
||||
if(row < 0 || row > 9) return 0x00;
|
||||
|
||||
// Initial configuration.
|
||||
PFC.PBCR.WORD = 0xaaaa;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <internals/mmu.h>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
mmu_pseudoTLBInit()
|
||||
|
@ -15,15 +14,16 @@
|
|||
*/
|
||||
void mmu_pseudoTLBInit(void)
|
||||
{
|
||||
extern unsigned int romdata;
|
||||
unsigned int address = 0x00300000;
|
||||
unsigned int x;
|
||||
extern uint32_t romdata;
|
||||
uint32_t limit = (uint32_t)&romdata;
|
||||
|
||||
while(address <= (unsigned int)&romdata)
|
||||
uint32_t address = 0x00300000;
|
||||
|
||||
// Access every page to make the system load everything in the TLB (and
|
||||
// just hope it works and the add-in fits in).
|
||||
while(address <= limit)
|
||||
{
|
||||
x = *((volatile unsigned int *)address);
|
||||
*((volatile uint32_t *)address);
|
||||
address += 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <screen.h>
|
||||
#include <stdint.h>
|
||||
#include <mpu.h>
|
||||
|
||||
/*
|
||||
|
@ -9,13 +10,13 @@ void screen_setBacklight(int on)
|
|||
{
|
||||
if(isSH3())
|
||||
{
|
||||
volatile unsigned char *PGDR = (void *)0xa400012c;
|
||||
volatile uint8_t *PGDR = (void *)0xa400012c;
|
||||
if(on) *PGDR |= 0x80;
|
||||
else *PGDR &= ~0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
volatile unsigned char *PNDR = (void *)0xa4050138;
|
||||
volatile uint8_t *PNDR = (void *)0xa4050138;
|
||||
if(on) *PNDR |= 0x10;
|
||||
else *PNDR &= ~0x10;
|
||||
}
|
||||
|
@ -29,12 +30,12 @@ void screen_toggleBacklight(void)
|
|||
{
|
||||
if(isSH3())
|
||||
{
|
||||
volatile unsigned char *PGDR = (void *)0xa400012c;
|
||||
volatile uint8_t *PGDR = (void *)0xa400012c;
|
||||
*PGDR ^= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
volatile unsigned char *PNDR = (void *)0xa4050138;
|
||||
volatile uint8_t *PNDR = (void *)0xa4050138;
|
||||
*PNDR ^= 0x10;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <screen.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
screen_display()
|
||||
|
@ -9,12 +10,11 @@
|
|||
*/
|
||||
void screen_display(const void *ptr)
|
||||
{
|
||||
const char *vram = (const char *)ptr;
|
||||
volatile char *selector = (char *)0xb4000000;
|
||||
volatile char *data = (char *)0xb4010000;
|
||||
int line, bytes;
|
||||
volatile uint8_t *selector = (void *)0xb4000000;
|
||||
volatile uint8_t *data = (void *)0xb4010000;
|
||||
const uint8_t *vram = ptr;
|
||||
|
||||
for(line = 0; line < 64; line++)
|
||||
for(int line = 0; line < 64; line++)
|
||||
{
|
||||
// Setting the x-address register.
|
||||
*selector = 4;
|
||||
|
@ -29,7 +29,27 @@ void screen_display(const void *ptr)
|
|||
*data = 0;
|
||||
|
||||
// Selecting data write register 7 and sending a line's bytes.
|
||||
// We could loop but I suspect it will be faster to iterate.
|
||||
*selector = 7;
|
||||
for(bytes = 0; bytes < 16; bytes++) *data = *vram++;
|
||||
|
||||
/* TODO Manually load the video-ram line into the cache? */
|
||||
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
*data = *vram++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
/*
|
||||
standard library module: setjmp
|
||||
|
||||
Long jumps. The register contents are saved in a buffer when setjmp()
|
||||
is called and restored at any time when longjmp() performs the jump.
|
||||
|
||||
This is based on a trick that uses pr ; the user program is resumed
|
||||
after the setjmp() call when longjmp() is invoked but this is not
|
||||
setjmp() that returns. longjmp() restores the pr value that was saved
|
||||
by setjmp() and performs an rts instruction.
|
||||
|
||||
setjmp() returns 0 when called to set up the jump point and a non-zero
|
||||
value when invoked through a long jump. If 0 is given as return value
|
||||
to longjmp(), then 1 is returned.
|
||||
*/
|
||||
|
||||
.global _setjmp
|
||||
.global _longjmp
|
||||
|
||||
/*
|
||||
setjmp()
|
||||
|
||||
This function is implemented using a trick that changes the value of
|
||||
pr (so that it points just after the call to setjmp()) within the
|
||||
longjmp() function, which lets the rts function perform the actual
|
||||
jump. This value is obtained from the save buffer.
|
||||
|
||||
setjmp() returns 0 when called to set up the jump point and a non-zero
|
||||
value when invoked through a long jump. If 0 is provided as argument to
|
||||
longjmp(), 1 is returned instead.
|
||||
*/
|
||||
_setjmp:
|
||||
/* Getting some free space. */
|
||||
add #64, r4
|
||||
|
@ -42,8 +39,8 @@ _setjmp:
|
|||
sts.l pr, @-r4
|
||||
|
||||
/* This function always return 0. The cases where setjmp() seems to
|
||||
return non-zero values, when a long jump has just been performed, is
|
||||
actually handled by longjmp(). */
|
||||
return non-zero values, when a long jump has just been performed, are
|
||||
those when the longjmp() function returns. */
|
||||
rts
|
||||
mov #0, r0
|
||||
|
||||
|
@ -52,7 +49,7 @@ _setjmp:
|
|||
_longjmp:
|
||||
/* Restoring the system and control registers. Restoring pr is actually
|
||||
what performs the jump -- and makes the user program think that
|
||||
setjmp() has returned. */
|
||||
setjmp() has just returned. */
|
||||
lds.l @r4+, pr
|
||||
lds.l @r4+, macl
|
||||
lds.l @r4+, mach
|
||||
|
|
|
@ -14,7 +14,6 @@ int snprintf(char *str, size_t size, const char *format, ...)
|
|||
int x = __printf(size, format, args);
|
||||
memcpy(str, __stdio_buffer, x + 1);
|
||||
|
||||
|
||||
va_end(args);
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ void srand(unsigned int new_seed)
|
|||
|
||||
int rand(void)
|
||||
{
|
||||
/* TODO Or maybe seed = (16807 * seed) % ((1 << 31) - 1); */
|
||||
seed = seed * 1103515245 + 12345;
|
||||
return seed & 0x7fffffff;
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
text_configure()
|
||||
Sets the font and mode to use for the following print operations.
|
||||
*/
|
||||
void text_configure(struct Font *next_font, color_t next_operator)
|
||||
void text_configure(font_t *next_font, color_t next_operator)
|
||||
{
|
||||
extern Font gint_font_system;
|
||||
extern font_t gint_font_system;
|
||||
if(next_font) font = next_font;
|
||||
else font = &gint_font_system;
|
||||
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
|
||||
void operate_gray(OPERATE_ARGS)
|
||||
{
|
||||
size_t vram_offset = (x >> 5) + (y << 2);
|
||||
uint32_t *light = gray_lightVRAM() + vram_offset;
|
||||
uint32_t *dark = gray_darkVRAM() + vram_offset;
|
||||
if(x < 0) return;
|
||||
|
||||
int start = (y < 0) ? (-y) : (0);
|
||||
size_t vram_offset = (x >> 5) + ((y + start) << 2);
|
||||
uint32_t *light = (uint32_t *)gray_lightVRAM() + vram_offset;
|
||||
uint32_t *dark = (uint32_t *)gray_darkVRAM() + vram_offset;
|
||||
uint32_t op, old_light;
|
||||
|
||||
for(int i = 0; i < height; i++)
|
||||
for(int i = start; i < height; i++)
|
||||
{
|
||||
op = operators[i];
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <ctype.h>
|
||||
#include <gray.h>
|
||||
|
||||
struct Font *font;
|
||||
font_t *font = NULL;
|
||||
color_t operator;
|
||||
|
||||
/*
|
||||
|
@ -27,8 +27,8 @@ int getCharacterIndex(int c)
|
|||
{
|
||||
const char *data = (const char *)&font->glyphs;
|
||||
int index, current;
|
||||
int offset;
|
||||
int width, bits;
|
||||
size_t offset;
|
||||
|
||||
c &= 0x7f;
|
||||
|
||||
|
@ -36,33 +36,33 @@ int getCharacterIndex(int c)
|
|||
|
||||
// Getting the character index in the glyph array.
|
||||
|
||||
if(font->format == FontFormat_Ascii) index = c;
|
||||
else if(font->format == FontFormat_Print) index = c - 32;
|
||||
if(font->format == font_format_ascii) index = c;
|
||||
else if(font->format == font_format_print) index = c - 32;
|
||||
|
||||
else switch(font->format)
|
||||
{
|
||||
case FontFormat_Numeric:
|
||||
case font_format_numeric:
|
||||
if(!isdigit(c)) return -1;
|
||||
index = c - '0';
|
||||
break;
|
||||
case FontFormat_LowerCase:
|
||||
case font_format_lower:
|
||||
if(!islower(c)) return -1;
|
||||
index = c - 'a';
|
||||
break;
|
||||
case FontFormat_UpperCase:
|
||||
case font_format_upper:
|
||||
if(!isupper(c)) return -1;
|
||||
index = c - 'A';
|
||||
break;
|
||||
case FontFormat_Letters:
|
||||
case font_format_letters:
|
||||
if(!isalpha(c)) return -1;
|
||||
index = c - 'A' - ('a' - 'Z') * (c >= 'a');
|
||||
break;
|
||||
case FontFormat_Common:
|
||||
case font_format_common:
|
||||
if(!isalnum(c)) return -1;
|
||||
index = c - '0' - ('A' - '9') * (c >= 'A') -
|
||||
('a' - 'Z') * (c >= 'a');
|
||||
break;
|
||||
case FontFormat_Unknown:
|
||||
case font_format_unknown:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
@ -93,13 +93,16 @@ int getCharacterIndex(int c)
|
|||
*/
|
||||
void operate_mono(OPERATE_ARGS)
|
||||
{
|
||||
if(x < 0) return;
|
||||
|
||||
uint32_t *vram = display_getCurrentVRAM();
|
||||
uint32_t *video = vram + (x >> 5) + (y << 2);
|
||||
int start = (y < 0) ? (-y) : (0);
|
||||
uint32_t *video = vram + (x >> 5) + ((y + start) << 2);
|
||||
|
||||
switch(operator)
|
||||
{
|
||||
case color_white:
|
||||
for(int i = 0; i < height; i++)
|
||||
for(int i = start; i < height; i++)
|
||||
{
|
||||
*video &= ~operators[i];
|
||||
video += 4;
|
||||
|
@ -107,7 +110,7 @@ void operate_mono(OPERATE_ARGS)
|
|||
break;
|
||||
|
||||
case color_black:
|
||||
for(int i = 0; i < height; i++)
|
||||
for(int i = start; i < height; i++)
|
||||
{
|
||||
*video |= operators[i];
|
||||
video += 4;
|
||||
|
@ -115,7 +118,7 @@ void operate_mono(OPERATE_ARGS)
|
|||
break;
|
||||
|
||||
case color_invert:
|
||||
for(int i = 0; i < height; i++)
|
||||
for(int i = start; i < height; i++)
|
||||
{
|
||||
*video ^= operators[i];
|
||||
video += 4;
|
||||
|
@ -163,7 +166,7 @@ int update(uint32_t *operators, int height, int available, uint32_t *glyph)
|
|||
shift = 32 - available;
|
||||
|
||||
// Getting the next 'width' bits. In some cases these bits will
|
||||
// intersect two different longs.
|
||||
// intersect two different longs...
|
||||
line = data & glyph_mask;
|
||||
line = (shift >= 0) ? (line >> shift) : (line << -shift);
|
||||
operators[i] |= line;
|
||||
|
@ -171,7 +174,7 @@ int update(uint32_t *operators, int height, int available, uint32_t *glyph)
|
|||
data <<= width;
|
||||
bits_available -= width;
|
||||
|
||||
// Continue until they do.
|
||||
// ... continue looping until they do.
|
||||
if(bits_available >= 0) continue;
|
||||
|
||||
// Computing a special mask that extracts just the number of
|
||||
|
@ -180,6 +183,10 @@ int update(uint32_t *operators, int height, int available, uint32_t *glyph)
|
|||
data = glyph[data_index++];
|
||||
shift += width + bits_available;
|
||||
|
||||
// In case this condition is not verified, the program invokes
|
||||
// undefined behavior because of the bit shift. Anyway, it
|
||||
// means that the end of the end of the operators was reached,
|
||||
// in which case the function should not continue writing.
|
||||
if(shift <= 31)
|
||||
{
|
||||
line = data & partial_mask;
|
||||
|
@ -202,34 +209,32 @@ int update(uint32_t *operators, int height, int available, uint32_t *glyph)
|
|||
*/
|
||||
void render(int x, int y, const char *str, void (*op)(OPERATE_ARGS))
|
||||
{
|
||||
if(!font) return;
|
||||
|
||||
// Operator data, and number of available bits in the operators (which
|
||||
// is the same for all operators, since they are treated equally).
|
||||
uint32_t *operators;
|
||||
int available;
|
||||
|
||||
// Raw glyph data, each glyph being represented by one or several
|
||||
// Raw glyph data, each glyph being represented as one or several
|
||||
// longwords, and an index in this array.
|
||||
uint32_t *data = (uint32_t *)font->glyphs;
|
||||
int index;
|
||||
|
||||
// Height of each glyph. This value is constant because the storage
|
||||
// format requires it: it allows greater optimization.
|
||||
int height;
|
||||
|
||||
int i;
|
||||
// Storage height of each glyph. This is a constant for all glyphs
|
||||
// because the format required it. It makes this routine consequently
|
||||
// faster.
|
||||
int height = font->data_height;
|
||||
|
||||
|
||||
|
||||
if(!font) return;
|
||||
|
||||
// Allocating data. There will be one operator for each line.
|
||||
height = font->data_height;
|
||||
if(x > 127 || y > 63 || y <= -height) return;
|
||||
if(y + height > 64) height = 64 - y;
|
||||
|
||||
operators = alloca(height * sizeof(uint32_t));
|
||||
for(i = 0; i < height; i++) operators[i] = 0;
|
||||
if(!operators) return;
|
||||
for(int i = 0; i < height; i++) operators[i] = 0;
|
||||
|
||||
// Computing the initial operator offset to have 32-aligned operators.
|
||||
// This allows to write directly video ram longs instead of having to
|
||||
|
@ -263,22 +268,23 @@ void render(int x, int y, const char *str, void (*op)(OPERATE_ARGS))
|
|||
x += 32;
|
||||
if(x > 96) break;
|
||||
|
||||
memset(operators, 0, height << 2);
|
||||
for(int i = 0; i < height; i++) operators[i] = 0;
|
||||
if(available >= 0)
|
||||
{
|
||||
available = 31 + available;
|
||||
available += 31;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Finishing update, in case it has been only partially done,
|
||||
// because there was not enough bits available to fit all the
|
||||
// information. Also adding a space, assuming that characters
|
||||
// aren't more than 30 bits wide.
|
||||
// Finishing update, in cases where it has been only partially
|
||||
// done because there was not enough bits available to fit all
|
||||
// the information. Also adding a space, assuming that
|
||||
// characters aren't more than 30 bits wide. (=p)
|
||||
available += 32 + (data[index] >> 24);
|
||||
available = update(operators, height, available, data + index);
|
||||
available--;
|
||||
}
|
||||
|
||||
// Final operation.
|
||||
if(x <= 96 && available < 32) (*op)(operators, height, x, y);
|
||||
// Final operation. This condition allows a single bit of the operators
|
||||
// to be used - that's because the loop will add a final spacing pixel.
|
||||
if(x <= 96 && available < 31) (*op)(operators, height, x, y);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ time_t mktime(struct tm *time)
|
|||
time->tm_wday = (1 + days) % 7;
|
||||
|
||||
// This RTC does not seem to have any DST feature.
|
||||
time->tm_isdst = 0;
|
||||
time->tm_isdst = 0;
|
||||
|
||||
if(time->tm_year + 1900 < 1970) return (time_t)-1;
|
||||
|
||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
|||
beta-0.9-305
|
||||
beta-0.9-349
|
||||
|
|
Loading…
Reference in a new issue