From 3214f6b797bb8ba083eb03f266ecd20341e4ed2d Mon Sep 17 00:00:00 2001 From: lephe Date: Wed, 19 Apr 2017 19:57:31 +0200 Subject: [PATCH] Almost ended quality review, and fixed tales-related vram overflows. --- Makefile | 2 +- TODO | 9 ++-- demo/asm_syscalls.s | 56 +++++++++++++++++++++++++ demo/gintdemo.c | 49 ++++++++++++++++++++++ demo/test_keyboard.c | 9 ++-- demo/test_tales.c | 12 +++--- include/events.h | 19 ++++++++- include/extended/endian.h | 1 + include/gint.h | 9 +++- include/internals/stdio.h | 9 ---- include/internals/tales.h | 3 +- include/modules/macros.h | 4 +- include/mpu.h | 2 +- include/setjmp.h | 4 +- include/tales.h | 52 +++++++++++------------ include/time.h | 2 +- src/gray/gray_engine.c | 7 ++++ src/keyboard/getPressedKey.c | 24 ----------- src/keyboard/getkey.c | 6 +-- src/keyboard/keyboard_core.c | 24 ++++++++--- src/keyboard/keyboard_sh7305.c | 10 ++--- src/keyboard/keyboard_sh7705.c | 10 ++--- src/mmu/pseudoTLBInit.c | 18 ++++---- src/screen/screen_backlight.c | 9 ++-- src/screen/screen_display.c | 32 +++++++++++--- src/setjmp/setjmp.s | 33 +++++++-------- src/stdio/snprintf.c | 1 - src/stdlib/stdlib_rand.c | 1 + src/tales/tales_configuration.c | 4 +- src/tales/tales_gray.c | 11 +++-- src/tales/tales_internals.c | 74 ++++++++++++++++++--------------- src/time/mktime.c | 2 +- version | 2 +- 33 files changed, 327 insertions(+), 183 deletions(-) create mode 100644 demo/asm_syscalls.s delete mode 100644 src/keyboard/getPressedKey.c diff --git a/Makefile b/Makefile index 611c024..83a3ee9 100755 --- a/Makefile +++ b/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])) diff --git a/TODO b/TODO index 88f4c3c..a8403a7 100644 --- a/TODO +++ b/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 diff --git a/demo/asm_syscalls.s b/demo/asm_syscalls.s new file mode 100644 index 0000000..69b4f10 --- /dev/null +++ b/demo/asm_syscalls.s @@ -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 diff --git a/demo/gintdemo.c b/demo/gintdemo.c index 7a4fee2..9532bdb 100644 --- a/demo/gintdemo.c +++ b/demo/gintdemo.c @@ -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); +} diff --git a/demo/test_keyboard.c b/demo/test_keyboard.c index 2046118..3012590 100644 --- a/demo/test_keyboard.c +++ b/demo/test_keyboard.c @@ -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); } diff --git a/demo/test_tales.c b/demo/test_tales.c index 8f26cc2..1ad6a48 100644 --- a/demo/test_tales.c +++ b/demo/test_tales.c @@ -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); diff --git a/include/events.h b/include/events.h index d88c98e..a30729a 100644 --- a/include/events.h +++ b/include/events.h @@ -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 (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; }; diff --git a/include/extended/endian.h b/include/extended/endian.h index 8474a81..b6f5d6f 100644 --- a/include/extended/endian.h +++ b/include/extended/endian.h @@ -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; } diff --git a/include/gint.h b/include/gint.h index fc19d48..ac264cb 100644 --- a/include/gint.h +++ b/include/gint.h @@ -15,11 +15,16 @@ #include #include -// 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; //--- diff --git a/include/internals/stdio.h b/include/internals/stdio.h index 67563d4..7a67647 100644 --- a/include/internals/stdio.h +++ b/include/internals/stdio.h @@ -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 diff --git a/include/internals/tales.h b/include/internals/tales.h index 166f1ad..a599d4c 100644 --- a/include/internals/tales.h +++ b/include/internals/tales.h @@ -3,10 +3,11 @@ #include #include +#include #define OPERATE_ARGS uint32_t *operators, int height, int x, int y -extern struct Font *font; +extern font_t *font; extern color_t operator; /* diff --git a/include/modules/macros.h b/include/modules/macros.h index 664fc7d..f17e817 100644 --- a/include/modules/macros.h +++ b/include/modules/macros.h @@ -3,14 +3,14 @@ #include -// 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; diff --git a/include/mpu.h b/include/mpu.h index d3c751f..d62919c 100644 --- a/include/mpu.h +++ b/include/mpu.h @@ -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. diff --git a/include/setjmp.h b/include/setjmp.h index d9ad7d8..b3aa872 100644 --- a/include/setjmp.h +++ b/include/setjmp.h @@ -10,9 +10,11 @@ #ifndef _SETJMP_H #define _SETJMP_H +#include + // 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]; diff --git a/include/tales.h b/include/tales.h index 81a2f59..2f189b7 100644 --- a/include/tales.h +++ b/include/tales.h @@ -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() diff --git a/include/time.h b/include/time.h index 8833524..9ec8298 100644 --- a/include/time.h +++ b/include/time.h @@ -36,7 +36,7 @@ struct tm clock_t Only used by clock(). */ -typedef signed int clock_t; +typedef signed int clock_t; /* time_t diff --git a/src/gray/gray_engine.c b/src/gray/gray_engine.c index e79af37..3d12bb1 100644 --- a/src/gray/gray_engine.c +++ b/src/gray/gray_engine.c @@ -11,14 +11,18 @@ #include #include +// 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()); } diff --git a/src/keyboard/getPressedKey.c b/src/keyboard/getPressedKey.c deleted file mode 100644 index f7d7d06..0000000 --- a/src/keyboard/getPressedKey.c +++ /dev/null @@ -1,24 +0,0 @@ -#include - -/* - 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; -} diff --git a/src/keyboard/getkey.c b/src/keyboard/getkey.c index 5d3cc68..4889b77 100644 --- a/src/keyboard/getkey.c +++ b/src/keyboard/getkey.c @@ -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; diff --git a/src/keyboard/keyboard_core.c b/src/keyboard/keyboard_core.c index ea76d3c..bb74325 100644 --- a/src/keyboard/keyboard_core.c +++ b/src/keyboard/keyboard_core.c @@ -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); } diff --git a/src/keyboard/keyboard_sh7305.c b/src/keyboard/keyboard_sh7305.c index 68e1fc8..f1647d4 100644 --- a/src/keyboard/keyboard_sh7305.c +++ b/src/keyboard/keyboard_sh7305.c @@ -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; diff --git a/src/keyboard/keyboard_sh7705.c b/src/keyboard/keyboard_sh7705.c index 20cd32c..a7fb0a3 100644 --- a/src/keyboard/keyboard_sh7705.c +++ b/src/keyboard/keyboard_sh7705.c @@ -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; diff --git a/src/mmu/pseudoTLBInit.c b/src/mmu/pseudoTLBInit.c index b27d60d..c947651 100644 --- a/src/mmu/pseudoTLBInit.c +++ b/src/mmu/pseudoTLBInit.c @@ -1,6 +1,5 @@ #include - -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#include /* 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 diff --git a/src/screen/screen_backlight.c b/src/screen/screen_backlight.c index 88e4078..e344212 100644 --- a/src/screen/screen_backlight.c +++ b/src/screen/screen_backlight.c @@ -1,4 +1,5 @@ #include +#include #include /* @@ -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; } } diff --git a/src/screen/screen_display.c b/src/screen/screen_display.c index c04d7d8..0d76d0e 100644 --- a/src/screen/screen_display.c +++ b/src/screen/screen_display.c @@ -1,4 +1,5 @@ #include +#include /* 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++; } } diff --git a/src/setjmp/setjmp.s b/src/setjmp/setjmp.s index 3b6f910..463673e 100644 --- a/src/setjmp/setjmp.s +++ b/src/setjmp/setjmp.s @@ -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 diff --git a/src/stdio/snprintf.c b/src/stdio/snprintf.c index 6c5eb20..20c9c9b 100644 --- a/src/stdio/snprintf.c +++ b/src/stdio/snprintf.c @@ -13,7 +13,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; diff --git a/src/stdlib/stdlib_rand.c b/src/stdlib/stdlib_rand.c index d5c17a6..9cd7765 100644 --- a/src/stdlib/stdlib_rand.c +++ b/src/stdlib/stdlib_rand.c @@ -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; } diff --git a/src/tales/tales_configuration.c b/src/tales/tales_configuration.c index 81b9e32..6f099cc 100644 --- a/src/tales/tales_configuration.c +++ b/src/tales/tales_configuration.c @@ -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; diff --git a/src/tales/tales_gray.c b/src/tales/tales_gray.c index 42918e8..10589b1 100644 --- a/src/tales/tales_gray.c +++ b/src/tales/tales_gray.c @@ -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]; diff --git a/src/tales/tales_internals.c b/src/tales/tales_internals.c index b39b4a8..889fd7a 100644 --- a/src/tales/tales_internals.c +++ b/src/tales/tales_internals.c @@ -4,7 +4,7 @@ #include #include -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); } diff --git a/src/time/mktime.c b/src/time/mktime.c index 928cf6f..0ea26a9 100644 --- a/src/time/mktime.c +++ b/src/time/mktime.c @@ -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; diff --git a/version b/version index 1a72b1c..fa6bbd4 100644 --- a/version +++ b/version @@ -1 +1 @@ -beta-0.9-305 +beta-0.9-349