diff --git a/Makefile b/Makefile index e368635..6ed5617 100644 --- a/Makefile +++ b/Makefile @@ -37,23 +37,25 @@ lib = -lgcc -L. -lgint -lc # Gint library. src-lib = crt0.c syscalls.s \ gint.c gint_vbr.s gint_7705.c gint_7305.c \ - mpu.c keyboard.c screen.c display.c bopti.c gray.c timer.c + mpu.c keyboard.c screen.c display.c gray.c timer.c tales.c \ + bopti.c hea-lib = 7305.h 7705.h gint.h \ stdlib.h \ - mpu.h keyboard.h screen.h display.h gray.h timer.h + mpu.h keyboard.h screen.h display.h gray.h timer.h tales.h obj-lib = $(addprefix build/, $(addsuffix .o, $(src-lib))) hdr-lib = $(addprefix include/, $(hea-lib)) # Standard library. src-std = setjmp.s string.c -hea-std = setjmp.h string.h +hea-std = setjmp.h string.h ctype.h obj-std = $(addprefix build/, $(addsuffix .o, $(src-std))) hdr-std = $(addprefix include/, $(hea-std)) # Test application. src-app = ginttest.c -img-app = bitmap_opt.bmp swords.bmp sprites.bmp symbol.bmp symbol2.bmp -res-app = $(addprefix build/, $(addsuffix .o, $(img-app))) +img-app = bitmap_opt.bmp swords.bmp sprites.bmp symbol.bmp symbol2.bmp \ + illustration.bmp +res-app = build/font.o $(addprefix build/, $(addsuffix .o, $(img-app))) # @@ -97,6 +99,9 @@ build/%.s.o: src/%.s build/%.bmp.o: resources/%.bmp fxconv $^ -o $@ +build/font.o: resources/font.bmp + fxconv --font $^ -o $@ + # File gint.c should not be optimized... looks like attribute((interrupt_ # handler)) doesn't like it. (It could be a gint bug also, I should check.) build/gint.c.o: src/gint.c $(hdr-lib) $(hdr-std) diff --git a/TODO b/TODO index 8b252f5..304e43c 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,15 @@ +@ vram overflow +@ keyboard interface + +- upgraded blending modes +- blending modes for text +- information masks for text +- test all font encodings +- font clipping + +- bitmap parts +- bitmap clipping + - multi-getkey repeats (if possible, which doesn't seem likely) - it appears that multi-getkey does not always trigger rectangle effects on sh7305 @@ -11,5 +23,5 @@ - check possible bug for optimization of __attribute__((interrupt_handler)) -_ 7305.h -_ libc +- 7305.h +- libc diff --git a/ginttest.c b/ginttest.c index f918f8c..a1ef815 100644 --- a/ginttest.c +++ b/ginttest.c @@ -4,6 +4,11 @@ #include #include #include +#include +#include + +#include +#include <7305.h> extern unsigned int bgint, egint; @@ -11,17 +16,9 @@ extern unsigned int bgint, egint; // A few procedures for displaying text in the system's vram. //--- -extern void __Print(const char *msg, int x, int y); - -void print_clear(void) -{ - char *empty_line = " "; - int i = 0; - while(i < 8) __Print(empty_line, 0, i++); -} void print(const char *str, int x, int y) { - __Print(str, x, y); + print_raw(str, x, y); } void print_hex(unsigned int n, int x, int y) { @@ -34,7 +31,7 @@ void print_hex(unsigned int n, int x, int y) n >>= 4; } ch[10] = 0; - __Print(ch, x, y); + print(ch, x, y); } void print_bin(unsigned char n, int x, int y) { @@ -47,7 +44,7 @@ void print_bin(unsigned char n, int x, int y) n >>= 1; } ch[8] = 0; - __Print(ch, x, y); + print(ch, x, y); } void print_hexa(unsigned int n, int digits, int x, int y) { @@ -61,31 +58,48 @@ void print_hexa(unsigned int n, int digits, int x, int y) } ch[digits] = 0; - __Print(ch, x, y); + print(ch, x, y); } -/* - Keyboard tests. - The user timer reproduces the parameters of the keyboard timer. -*/ + +//--- +// Test applications. +//--- + +/* + keyboard_test_timer() + Displays a keyboard test. The keyboard state is displayed as well, but + there is a timer artifact. The keyboard state timer uses the same + period as the (internal) keyboard analysis timer, but there is a time + gap between a keyboard analysis and an update on the screen. +*/ void keyboard_test_timer(void) { volatile unsigned char *state = keystate(); - print_bin(state[0], 0, 1); - print_bin(state[1], 0, 2); - print_bin(state[2], 0, 3); - print_bin(state[3], 0, 4); - print_bin(state[4], 0, 5); + dclear_area(5, 10, 71, 34); - print_bin(state[5], 9, 1); - print_bin(state[6], 9, 2); - print_bin(state[7], 9, 3); - print_bin(state[8], 9, 4); - print_bin(state[9], 9, 5); + print_bin(state[0], 5, 10); + print_bin(state[1], 5, 16); + print_bin(state[2], 5, 22); + print_bin(state[3], 5, 28); + print_bin(state[4], 5, 34); + + print_bin(state[5], 40, 10); + print_bin(state[6], 40, 16); + print_bin(state[7], 40, 22); + print_bin(state[8], 40, 28); + print_bin(state[9], 40, 34); + + dupdate(); } +/* + keyboard_test() + Displays a multi-getkey test as well as the keyboard state in real + time. +*/ void keyboard_test(void) { int x = 0; @@ -95,37 +109,40 @@ void keyboard_test(void) timer_start(TIMER_USER, 1700, TIMER_Po_256, keyboard_test_timer, 0); - print_clear(); - print("Keyboard state:", 0, 0); - print("multi-getkey ^^", 6, 7); - while(1) { multigetkey(keys, 4, 0); - if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break; + dclear(); + print("Keyboard state:", 0, 0); + print("multi-getkey ^^", 50, 55); + #define hexa(h) ('0' + (h) + 39 * ((h) > 9)) x = (x + 1) & 15; str[0] = hexa(x); str[1] = 0; - print(str, 20, 0); + print(str, 100, 0); for(i = 0; i < 4; i++) { str[0] = hexa((keys[i] >> 4) & 0x0f); str[1] = hexa(keys[i] & 0x0f); str[2] = 0; - print(str, 19, i + 3); + print(str, 100, 16 + 10 * i); } #undef hexa + + dupdate(); } timer_stop(TIMER_USER); } + + /* const unsigned char data[1024] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -180,114 +197,16 @@ const unsigned char data[1024] = { 255, 15, 31, 252, 31 }; */ - /* -static const unsigned char icon[76] = { -0, 0, 0, 0, 51, 156, 10, 68, 74, 82, 11, 68, 74, 82, 234, 196, 122, 82, 10, -68, 75, 156, 10, 68, 0, 0, 0, 4, 0, 254, 0, 4, 0, 130, 124, 4, 0, 130, 68, 4, -0, 2, 4, 4, 3, 238, 196, 4, 2, 170, 93, 252, 0, 254, 65, 252, 7, 40, 65, 252, -5, 232, 65, 252, 7, 15, 193, 252, 0, 0, 1, 252, 127, 255, 255, 252 }; - -char *ML_vram_adress(void) -{ - return display_getVRAM(); -} - -void ML_bmp_or_cl(const unsigned char *bmp, int x, int y, int width, int height) -{ - unsigned short line; - char shift, *screen, *p; - int i, j, real_width, begin_x, end_x, begin_y, end_y; - char bool1=1, bool2=1, bool3; - if(!bmp || x<1-width || x>127 || y<1-height || y>63 || height<1 || width<1) return; - p = (char*)&line; - real_width = (width-1>>3<<3)+8; - if(y < 0) begin_y = -y; - else begin_y = 0; - if(y+height > 64) end_y = 64-y; - else end_y = height; - shift = 8-(x&7); - if(x<0) - { - begin_x = -x>>3; - if(shift != 8) bool1 = 0; - } else begin_x = 0; - if(x+real_width > 128) end_x = 15-(x>>3), bool2 = 0; - else end_x = real_width-1>>3; - bool3 = (end_x == real_width-1>>3); - screen = ML_vram_adress()+(y+begin_y<<4)+(x>>3); - - for(i=begin_y ; i>3)+begin_x] << shift; - if(bool1) screen[begin_x] |= *p; - if(shift!=8) screen[begin_x+1] |= *(p+1); - for(j=begin_x+1 ; j>3)+j] << shift; - screen[j] |= *p; - if(shift!=8) screen[j+1] |= *(p+1); - } - } - line = bmp[i*(real_width>>3)+end_x]; - if(bool3) line &= -1< -#include <7305.h> - -/* -unsigned int exec(void (*f)(void)) -{ - int t, s, dt, ds; - - t = (int)RTC.R64CNT; - s = 10 * (RTC.RSECCNT.TENS) + RTC.RSECCNT.ONES; - - (*f)(); - - dt = (int)RTC.R64CNT - t; - ds = (10 * (RTC.RSECCNT.TENS) + RTC.RSECCNT.ONES) - s; - if(dt < 0) ds--, dt += 64; - - return (ds << 8) | dt; -} - -void btest_ml_icon(void) -{ - int i; - for(i = 0; i < 5000; i++) - { - ML_bmp_or_cl(icon, 0, 30, 30, 19); - } -} -void btest_gint_icon(void) -{ - extern Image binary_icon_start; - - int i; - for(i = 0; i < 5000; i++) - { - dimage(&binary_icon_start, 0, 0, Blend_Or); - } -} -*/ - void bitmap_test(void) { extern Image binary_resources_bitmap_opt_start; extern Image binary_resources_symbol_start; extern Image binary_resources_symbol2_start; extern Image binary_resources_sprites_start; - extern Image binary_resources_swords_start; Image *opt = &binary_resources_bitmap_opt_start; Image *sprites = &binary_resources_sprites_start; @@ -324,64 +243,78 @@ void bitmap_test(void) } return; +} - dclear(); - dreverse_area(0, 0, 127, 30); - dimage(sybl, 0, 0, Blend_Or); - dimage(sybl, 20, 0, Blend_And); - dimage(sybl, 40, 0, Blend_Or | Blend_And); - dimage(sybl, 90, 0, Blend_Or | Blend_Invert); - dimage(sybl2, 0, 20, Blend_Or); - dimage(sybl2, 20, 20, Blend_And); - dimage(sybl2, 28, 20, Blend_And); - dimage(sybl2, 40, 20, Blend_Or | Blend_And); - dimage(sybl2, 90, 20, Blend_Or | Blend_Invert); - - dreverse_area(35, 31, 127, 63); - dimage(&binary_resources_sprites_start, 50, 31, Blend_And); - - dupdate(); /* - do key = getkey(); - while(key != KEY_EXE && key != KEY_EXIT); - if(key == KEY_EXIT) return 0; - - print("h'sszz 64z=1s", 0, 0); - print("ML", 14, 0); - print("gint", 17, 0); - print("---------------------", 0, 1); - - print("30*19 icon", 0, 2); - print(wait, 12, 2); - print_hexa(exec(btest_ml_icon), 4, 12, 2); - print(wait, 17, 2); - print_hexa(exec(btest_gint_icon), 4, 17, 2); + text_test() + Renders text. */ - while(getkey() != KEY_EXE); + +void text_test(void) +{ + extern Font binary_resources_font_start; + Font *font = &binary_resources_font_start; + + print_configure(font, Blend_Or); dclear(); - dimage(&binary_resources_swords_start, 20, 20, Blend_Or); + + print(" !\"#$%&'()*+,-./", 10, 10); + print("0123456789:;<=>?", 10, 16); + print("@ABCDEFGHIJKLMNO", 10, 22); + print("PQRSTUVWXYZ[\\]^_", 10, 28); + print("`abcdefghijklmno", 10, 34); + print("pqrstuvwxyz{|}~", 10, 40); + dupdate(); - while(getkey() != KEY_EXE); + while(getkey() != KEY_EXIT); } -void test(void) + + +/* + gray_test() + Runs the gray engine. +*/ + +void gray_test(void) { - static int x = 0; - x++; + extern Image binary_resources_illustration_start; + Image *illustration = &binary_resources_illustration_start; - print_hex(x, 0, 0); + int light, dark; + int key; + + gray_getDelays(&light, &dark); + gray_start(); + dimage(illustration, 0, 0, Blend_Or); + + while(1) + { + key = getkey(); + if(key == KEY_EXIT) break; + + if(key == KEY_F1) gray_setDelays(--light, dark); + if(key == KEY_F2) gray_setDelays(++light, dark); + + if(key == KEY_F5) gray_setDelays(light, --dark); + if(key == KEY_F6) gray_setDelays(light, ++dark); + } + + gray_stop(); } +/* + main_menu() + Displays the main menu and returns user's choice. + + @return User choice. 0 means EXIT, other numbers are applications. +*/ int main_menu(void) { - /* - Main menu. - */ - const char *mpu_names[] = { "MPU_Unkown", "MPU_SH7337", @@ -392,18 +325,22 @@ int main_menu(void) }; int key; - print_clear(); + dclear(); - print("gint test application", 0, 0); - print("---------------------", 0, 1); + print("gint test application", 19, 1); + dline(19, 8, 107, 8, Color_Black); - print("[1] Keyboard test", 2, 3); - print("[2] Drawing test", 2, 4); + print("[1] Keyboard", 10, 17); + print("[2] Bitmap drawing", 10, 24); + print("[3] Text rendering", 10, 31); + print("[4] Gray engine", 10, 38); - print("mpu type:", 0, 6); - print(mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5], 11, 6); - print("gint size:", 0, 7); - print_hex(&egint - &bgint, 11, 7); + print("mpu type:", 2, 49); + print(mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5], 50, 48); + print("gint size:", 2, 56); + print_hex(&egint - &bgint, 50, 56); + + dupdate(); while(1) { @@ -412,13 +349,26 @@ int main_menu(void) if(key == KEY_1) return 1; if(key == KEY_2) return 2; + if(key == KEY_3) return 3; + if(key == KEY_4) return 4; } return 0; } +/* + main() + Handles application calls. + + @return 0. +*/ int main(void) { + extern Font binary_resources_font_start; + Font *font = &binary_resources_font_start; + + print_configure(font, Blend_Or); + int app; while(1) @@ -428,6 +378,8 @@ int main(void) if(app == 1) keyboard_test(); if(app == 2) bitmap_test(); + if(app == 3) text_test(); + if(app == 4) gray_test(); } return 0; diff --git a/ginttest.g1a b/ginttest.g1a index 076483f..78b5a4e 100644 Binary files a/ginttest.g1a and b/ginttest.g1a differ diff --git a/include/ctype.h b/include/ctype.h new file mode 100644 index 0000000..0a716be --- /dev/null +++ b/include/ctype.h @@ -0,0 +1,27 @@ +#ifndef _CTYPE_H +#define _CTYPE_H 1 + +// Character definition macros. +#define isalnum(c) (isdigit(c) || isalpha(c)) +#define isalpha(c) (islower(c) || isupper(c)) + +#define iscntrl(c) ((c) <= 0x1f || (c) == 0x7f) +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#define isgraph(c) ((c) > ' ' && (c) < 0x7f) +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#define isprint(c) ((c) >= ' ' && (c) < 0x7f) +#define ispunct(c) (((c) >= '!' && (c) <= '/') || \ + ((c) >= ':' && (c) <= '@') || \ + ((c) >= '[' && (c) <= '`') || \ + ((c) >= '{' && (c) <= '~')) +#define isspace(c) (((c) >= '\t' && (c) <= '\r') || (c) == ' ') +#define isupper(c) ((c) >= 'A' && (c) <= 'Z') +#define isxdigit(c) (((c) >= '0' && (c) <= '9') || \ + ((c) >= 'A' && (c) <= 'F') || \ + ((c) >= 'a' && (c) <= 'f')) + +// Character manipulation macros. +#define tolower(c) (isupper(c) ? (c)|32 : (c)) +#define toupper(c) (islower(c) ? (c)&~32 : (c)) + +#endif // _CTYPE_H diff --git a/include/display.h b/include/display.h index 00b4042..58a111e 100644 --- a/include/display.h +++ b/include/display.h @@ -1,6 +1,14 @@ #ifndef _DISPLAY_H #define _DISPLAY_H 1 +//--- +// Included submodules. +//--- + +#include + + + //--- // Types and constants. //--- @@ -60,13 +68,12 @@ enum ImageFormat */ struct Image { + unsigned char magic; + unsigned char width; unsigned char height; unsigned char format; - // Ensures data is 4-aligned. - unsigned char gap; - const unsigned char __attribute__((aligned(4))) data[]; } __attribute__((aligned(4))); @@ -205,4 +212,6 @@ void dline(int x1, int y1, int x2, int y2, enum Color color); */ void dimage(struct Image *image, int x, int y, enum BlendingMode mode); + + #endif // _DISPLAY_H diff --git a/include/gray.h b/include/gray.h index c91b0e5..c685fd1 100644 --- a/include/gray.h +++ b/include/gray.h @@ -31,6 +31,28 @@ void *gray_lightVRAM(void); */ void *gray_darkVRAM(void); +/* + gray_getDelays() + Returns the gray engine delays. + + @arg light Will be set if non-NULL. + @arg dark Will be set if non-NULL. +*/ +void gray_getDelays(int *light, int *dark); + +/* + gray_setDelays() + Changes the gray engine delays. Usually you don't need to call this, + because the engine has its default values. + Finding values that give proper grays is quite the hard part of the + gray engine. Usual values are about 1000, with light being between 75 + and 90% of dark. + + @arg light Light gray duration (the lower). + @arg dark Dark gray duration (the higher). +*/ +void gray_setDelays(int light, int dark); + //--- // Internal API. // Referenced here for documentation purposes only. Do not call. diff --git a/include/keyboard.h b/include/keyboard.h index b8aa1c7..ce22954 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -148,6 +148,7 @@ enum GetkeyOpt non-NULL, it is set to the number of repetitions. @arg repeat_count + @return Key matrix code. */ int keylast(int *repeat_count); @@ -223,6 +224,7 @@ enum KeyType Ignores modifiers. @arg key + @return Modified keycode. */ int keyid(int key); @@ -233,7 +235,8 @@ int keyid(int key); other keys. @arg key - @return Key character. + + @return Associated character. */ int keychar(int key); @@ -242,6 +245,7 @@ int keychar(int key); Returns a key's type. Ignores modifiers. @arg key + @return Key type. */ enum KeyType keytype(int key); diff --git a/include/stdlib.h b/include/stdlib.h index 66f7396..8d0fb91 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -28,4 +28,43 @@ void abort(void); */ void exit(int status); + + +//--- +// Dynamic storage allocation. +//--- + +/* + malloc() + Allocs 'size' bytes and returns a pointer to a free memory area. + Returns NULL on error. + + @arg size Size to allocate, in bytes. + + @return Memory area address, or NULL. +*/ +void *malloc(size_t size); + +/* + calloc() + Allocs 'n' elements of size 'size' and wipes the memory area. Returns + NULL on error. + + @arg n Element number. + @arg size Element size. + + @return Memory area address, or NULL. +*/ +void *calloc(size_t n, size_t size); + +/* + free() + Frees a memory block allocated with malloc(). + + @arg ptr Pointer to free. +*/ +void free(void *ptr); + + + #endif // _STDLIB_H diff --git a/include/tales.h b/include/tales.h new file mode 100644 index 0000000..14e6646 --- /dev/null +++ b/include/tales.h @@ -0,0 +1,105 @@ +#ifndef _TALES_H +#define _TALES_H 1 + +#include +#include + +//--- +// Types and constants. +//--- + +enum BlendingMode; + +/* + enum ImageFormat + 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 +{ + FontFormat_Unknown = 0x00, + FontFormat_Numeric = 0x01, + FontFormat_LowerCase = 0x02, + FontFormat_UpperCase = 0x04, + FontFormat_Letters = 0x06, + FontFormat_Common = 0x07, + FontFormat_Print = 0x0f, + FontFormat_Ascii = 0x1f, +}; + +/* + struct FontGlyph + 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 +{ + unsigned char width; + + const unsigned char data[]; +} __attribute__((aligned(4))); + +/* + struct Font + 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 + strings on several lines. The data height is the height of the biggest + glyph. Every glyph is encoded on 'data_height' lines, for optimization + considerations. + The index field is used to reduce character access time. + 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 +{ + unsigned char magic; + + unsigned char format; + unsigned char line_height; + unsigned char data_height; + + // Warning : this field may not be NUL-terminated. + char name[28]; + + uint16_t index[16]; + + __attribute__((aligned(4))) const struct FontGlyph glyphs[]; + +} __attribute__((aligned(4))); +// Useful shorthand for user code. +typedef struct Font Font; + + + + +//--- +// Generic functions. +//--- + +/* + print_configure() + Sets the font and mode to use for the following print operations. + + @arg font + @arg mode +*/ +void print_configure(struct Font *font, enum BlendingMode mode); + +/* + print_raw() + Prints the given string, without any analysis. + + @arg str + @arg x + @arg y +*/ +void print_raw(const char *str, int x, int y); + +#endif // _TALES_H diff --git a/include/timer.h b/include/timer.h index 84b6dde..3d475bc 100644 --- a/include/timer.h +++ b/include/timer.h @@ -56,6 +56,16 @@ void timer_start(int timer, int delay, int prescaler, void (*callback)(void), */ void timer_stop(int timer); +/* + timer_reload() + Reloads the given timer with the given constant. Starts the timer if + it was stopped. + + @arg timer Timer identifier. + @arg new_delay +*/ +void timer_reload(int timer, int new_delay); + //--- diff --git a/libc.a b/libc.a index fdab1e2..79d61d8 100644 Binary files a/libc.a and b/libc.a differ diff --git a/libgint.a b/libgint.a index d03f064..cf2e8b9 100644 Binary files a/libgint.a and b/libgint.a differ diff --git a/resources/font.bmp b/resources/font.bmp new file mode 100644 index 0000000..c577abd Binary files /dev/null and b/resources/font.bmp differ diff --git a/resources/illustration.bmp b/resources/illustration.bmp new file mode 100644 index 0000000..ca8755a Binary files /dev/null and b/resources/illustration.bmp differ diff --git a/resources/swords.bmp b/resources/swords.bmp index 695bc8d..8aa6416 100644 Binary files a/resources/swords.bmp and b/resources/swords.bmp differ diff --git a/src/bopti.c b/src/bopti.c index 81a3794..aaa6998 100644 --- a/src/bopti.c +++ b/src/bopti.c @@ -286,6 +286,8 @@ void dimage(struct Image *image, int x, int y, enum BlendingMode mode) int height = image->height; const unsigned char *data = (const unsigned char *)&(image->data); + if(image->magic != 0xb7) return; + // Computing the layer size. int columns = image->width >> 5; int rest = image->width & 31; diff --git a/src/gint_7305.c b/src/gint_7305.c index bbdc22c..12f310e 100644 --- a/src/gint_7305.c +++ b/src/gint_7305.c @@ -93,6 +93,7 @@ static void kdelay(void) more details. @arg row Row to check (0 <= row <= 9). + @return Bit-based representation of pressed keys in the checked row. */ static int krow(int row) diff --git a/src/gint_7705.c b/src/gint_7705.c index 4a08601..253a174 100644 --- a/src/gint_7705.c +++ b/src/gint_7705.c @@ -100,6 +100,7 @@ static void kdelay(void) Reads a keyboard row. @arg row Row to check (0 <= row <= 9). + @return Bit-based representation of pressed keys in the checked row. */ static int krow(int row) diff --git a/src/gray.c b/src/gray.c index 53bcb56..8687df9 100644 --- a/src/gray.c +++ b/src/gray.c @@ -1,11 +1,15 @@ #include #include #include +#include static int internal_vrams[3][256]; const void *vrams[4]; static int current = 0; +static int delays[2]; + +#define GRAY_PRESCALER TIMER_Po_64 /* gray_start() @@ -14,6 +18,7 @@ static int current = 0; */ void gray_start(void) { + timer_start(TIMER_GRAY, delays[0], GRAY_PRESCALER, gray_interrupt, 0); } /* @@ -23,6 +28,7 @@ void gray_start(void) */ void gray_stop(void) { + timer_stop(TIMER_GRAY); display_useVRAM(display_getLocalVRAM()); } @@ -44,6 +50,38 @@ void *gray_darkVRAM(void) return (void *)vrams[current + 1]; } +/* + gray_getDelays() + Returns the gray engine delays. + + @arg light Will be set if non-NULL. + @arg dark Will be set if non-NULL. +*/ +void gray_getDelays(int *light, int *dark) +{ + if(light) *light = delays[0]; + if(dark) *dark = delays[1]; +} + +/* + gray_setDelays() + Changes the gray engine delays. + + @arg light Light gray duration (the lower). + @arg dark Dark gray duration (the higher). +*/ +void gray_setDelays(int light, int dark) +{ + delays[0] = light; + delays[1] = dark; +} + + + +//--- +// Internal API. +//--- + /* gray_swap() Swaps the vram buffers. @@ -55,10 +93,11 @@ void gray_swap(void) /* gray_interrupt() - Answers a timer interrupt. Swaps the two buffers. + Answers a timer interrupt. Swaps the buffers. */ void gray_interrupt(void) { + timer_reload(TIMER_GRAY, delays[current & 1]); screen_display(vrams[current]); current ^= 1; } @@ -73,4 +112,7 @@ void gray_init(void) vrams[1] = (const void *)internal_vrams[0]; vrams[2] = (const void *)internal_vrams[1]; vrams[3] = (const void *)internal_vrams[2]; + + delays[0] = 3269; + delays[1] = 6987; } diff --git a/src/keyboard.c b/src/keyboard.c index 1f44d74..f3a8c2c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -201,6 +201,7 @@ void keyboard_setRepeatRate(int first, int next) non-NULL, it is set to the number of repetitions. @arg repeat_count + @return Key matrix code. */ int keylast(int *repeat_count) @@ -426,6 +427,7 @@ void multigetkey(int *keys, int count, int max_cycles) Ignores modifiers. @arg key + @return Modified keycode. */ int keyid(int key) @@ -445,6 +447,8 @@ int keyid(int key) keys. @arg key + + @return Associated character. */ int keychar(int key) { @@ -482,6 +486,7 @@ int keychar(int key) Returns a key's type. Ignores modifiers. @arg key + @return Key type. */ enum KeyType keytype(int key) diff --git a/src/syscalls.s b/src/syscalls.s index c76d3e3..c2a3e1c 100644 --- a/src/syscalls.s +++ b/src/syscalls.s @@ -5,7 +5,9 @@ .global ___Hmem_SetMMU .global ___GLibAddinAplExecutionCheck - .global ___Print + .global _malloc + .global _calloc + .global _free @@ -22,12 +24,26 @@ ___GLibAddinAplExecutionCheck: jmp @r2 nop -___Print: +_malloc: mov.l syscall_table, r2 mov.l 1f, r0 jmp @r2 nop -1: .long 0x15d +1: .long 0xacd + +_calloc: + mov.l syscall_table, r2 + mov.l 1f, r0 + jmp @r2 + nop +1: .long 0xe6b + +_free: + mov.l syscall_table, r2 + mov.l 1f, r0 + jmp @r2 + nop +1: .long 0xacc diff --git a/src/tales.c b/src/tales.c new file mode 100644 index 0000000..fa564a2 --- /dev/null +++ b/src/tales.c @@ -0,0 +1,292 @@ +#include +#include +#include +#include + +#include + +static struct Font *font; +static enum BlendingMode mode; + +//--- +// Local functions. +//--- + +/* + getCharacterIndex() + Returns the index of a character in a font data area depending on the + font format and the size of the characters. + + @arg character + + @return Index in data area (as long array). Returns -1 when the + character does not belong to the font format set. +*/ +static int getCharacterIndex(int c) +{ + const char *data = (const char *)&font->glyphs; + int index, current; + int offset; + int width, bits; + + c &= 0x7f; + + + + // Getting the character index in the glyph array. + + if(font->format == FontFormat_Ascii) index = c; + else if(font->format == FontFormat_Print) index = c - 32; + + else switch(font->format) + { + case FontFormat_Numeric: + if(!isdigit(c)) return -1; + index = c - '0'; + break; + case FontFormat_LowerCase: + if(!islower(c)) return -1; + index = c - 'a'; + break; + case FontFormat_UpperCase: + if(!isupper(c)) return -1; + index = c - 'A'; + break; + case FontFormat_Letters: + if(!isalpha(c)) return -1; + index = c - 'A' - ('a' - 'z') * (c >= 'a'); + break; + case FontFormat_Common: + if(!isalnum(c)) return -1; + index = c - '0' - ('A' - '9') * (c >= 'A') - + ('a' - 'z') * (c >= 'a'); + break; + case FontFormat_Unknown: + default: + return -1; + } + + + + // Reaching the character offset. + + current = index & ~7; + offset = font->index[current >> 3]; + + while(current < index) + { + width = data[offset << 2]; + bits = font->data_height * width + 8; + + offset += (bits + 31) >> 5; + current++; + } + + return offset; +} + +/* + operate() + Operates on the vram using the given operators. The x-coordinate should + be a multiple of 32. + + @arg operators Operator array. + @arg height Number of operators (height of text). + @arg x + @arg y +*/ +static void operate(uint32_t *operators, int height, int x, int y) +{ + int *vram = display_getCurrentVRAM(); + int vram_offset = (x >> 5) + (y << 2); + int i; + + for(i = 0; i < height; i++) + { + // TODO BLENDING MODES // + vram[vram_offset] |= operators[i]; + + vram_offset += 4; + } +} + +/* + update() + Updates the operators using the given glyph. The operation will not be + complete if there are not enough bits available in the operator data. + In this case the offset will become negative, which means that the + calling procedure has to call operate() and re-call update(). + + @arg operators Operator array. + @arg height Number of operators. + @arg available Number of free bits in the operators (lower + bits). + @arg glyph Glyph data, including meta-data. + + @return Number of bits available after the operation. May be negative: + in this case, call operate() and update() again. +*/ +static int update(uint32_t *operators, int height, int available, + uint32_t *glyph) +{ + // Glyph width. + int width = glyph[0] >> 24; + int i; + + // The glyph mask extracts 'width' bits at the left. The partial mask + // is used when there are less than 'width' bits available in the + // current data longword. + uint32_t glyph_mask = 0xffffffff << (32 - width); + uint32_t partial_mask; + + int shift; + uint32_t line; + + // Current data longword, next data array index, and number of bits + // still available in 'data'. + uint32_t data = glyph[0] << 8; + int data_index = 1; + int bits_available = 24; + + for(i = 0; i < height; i++) + { + shift = 32 - available; + + // Getting the next 'width' bits. In some cases these bits will + // intersect two different longs. + line = data & glyph_mask; + line = (shift >= 0) ? (line >> shift) : (line << -shift); + operators[i] |= line; + + data <<= width; + bits_available -= width; + + // Continue until they do. + if(bits_available >= 0) continue; + + // Computing a special mask that extracts just the number of + // bits missing, and loading a new data longword. + partial_mask = 0xffffffff << (32 + bits_available); + data = glyph[data_index++]; + shift += width + bits_available; + + if(shift <= 31) + { + line = data & partial_mask; + line = (shift >= 0) ? (line >> shift) : + (line << -shift); + operators[i] |= line; + } + + data <<= -bits_available; + bits_available += 32; + } + + return available - width; +} + + + +//--- +// Public API. +//--- + +/* + print_configure() + Sets the font and mode to use for the following print operations. + + @arg font + @arg mode +*/ +void print_configure(struct Font *next_font, enum BlendingMode next_mode) +{ + font = next_font; + mode = next_mode; +} + +/* + print_raw() + Prints the given string, without any analysis. + + @arg str + @arg x + @arg y +*/ +void print_raw(const char *str, int x, int y) +{ + // 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 + // 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; + + + + 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; + + operators = calloc(height, sizeof(uint32_t)); + if(!operators) return; + + // Computing the initial operator offset to have 32-aligned operators. + // This allows to write directly video ram longs instead of having to + // shift operators, and do all the vram operation twice. + available = 32 - (x & 31); + x &= ~31; + + // Displaying character after another. + while(*str) + { + index = getCharacterIndex(*str++); + if(index < 0) continue; + + // Updating the operators. + available = update(operators, height, available, data + index); + + // Continue until operators are full (this includes an + // additional bit to add a space between each character). + if(available > 1) + { + available--; + continue; + } + + // When operators are full, updating the video ram and + // preparing the operators for another row. + + operate(operators, height, x, y); + x += 32; + if(x > 96) break; + + memset(operators, 0, height << 2); + if(available >= 0) + { + available = 31 + available; + 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. + available += 32 + (data[index] >> 24); + available = update(operators, height, available, data + index); + available--; + } + + // Final operation. + if(x <= 96 && available < 32) operate(operators, height, x, y); + + free(operators); +} diff --git a/src/timer.c b/src/timer.c index 77c9a9d..5988b8e 100644 --- a/src/timer.c +++ b/src/timer.c @@ -176,3 +176,26 @@ void timer_stop(int timer) // Stopping the timer. *tstr &= ~byte; } + +/* + timer_reload() + Reloads the given timer with the given constant. Starts the timer if + it was stopped. + + @arg timer Timer identifier. + @arg new_delay +*/ +void timer_reload(int timer, int new_delay) +{ + struct mod_tmu *tmu; + unsigned char *tstr; + int byte = (1 << timer); + timer_get(timer, &tmu, &tstr); + + // Setting the constant and the delay. + (*tmu).TCOR = new_delay; + (*tmu).TCNT = new_delay; + + // Starting the timer. + *tstr |= byte; +}