diff --git a/Makefile b/Makefile index ee6613f..bb6d41b 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,161 @@ -## Temporary things there +#! /usr/bin/make -f +#--- +# +# gint project Makefile. +# +#--- + + + +#--- +# Project variables. +#--- + +# Modules +modules-gint = bopti core display gray keyboard mpu screen tales timer +modules-libc = setjmp string + +# Targets +target-g1a = gintdemo.g1a +target-lib = libgint.a +target-std = libc.a + +# Tools +cc = sh3eb-elf-gcc +as = sh3eb-elf-as +ar = sh3eb-elf-ar +ob = sh3eb-elf-objcopy +wr = g1a-wrapper + +# Flags +cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 + +# Demo application (could be done better) +demo-src = $(notdir $(wildcard demo/*.[cs])) +demo-ld = demo/gintdemo.ld +demo-icon = demo/icon.bmp +demo-res = $(notdir $(wildcard demo/resources/*)) +demo-obj = $(patsubst %,build/demo_%.o,$(demo-src) $(demo-res)) +demo-elf = build/gintdemo.elf +demo-bin = build/gintdemo.bin +demo-libs = -lgcc -L. -lgint -lc + + + +#--- +# Automatic variables. +#--- + +# Modules are subfolders of src/. +modules = $(modules-gint) $(modules-libc) + +define n +# This is a newline character. + +endef + +# Module-scope variables. +$(foreach mod, $(modules), $(eval \ + mod-$(mod)-c = $(notdir $(wildcard src/$(mod)/*.c)) $n\ + mod-$(mod)-asm = $(notdir $(wildcard src/$(mod)/*.s)) $n\ + mod-$(mod)-dep = $(wildcard include/*.h src/$(mod)/*.h) $n\ + mod-$(mod)-src = $$(mod-$(mod)-c)$$(mod-$(mod)-asm) $n\ + mod-$(mod)-obj = $$(patsubst %,build/$(mod)_%.o,$$(mod-$(mod)-src)) \ +)) + +# Target-scope variables. +obj-std = $(foreach mod,$(modules-libc),$(mod-$(mod)-obj)) +obj-lib = $(foreach mod,$(modules-gint),$(mod-$(mod)-obj)) + + + +#--- +# Rule templates. +#--- # C source file template: # $1 module name -# $2 file base name +# $2 filename define rule-c-source -build/$1_$2.c.o: src/$1/$2.c - $(cc) $(cflags) -c $$< -o $$@ +build/$1_$2.o: src/$1/$2 $(mod-$1-dep) + $(cc) -c $$< -o $$@ $(cflags) -I src/$1 -O2 endef -$(eval $(call rule-c-source,display,area)) +# asm source file template: +# $1 module name +# $2 filename +define rule-asm-source +build/$1_$2.o: src/$1/$2 + $(as) -c $$< -o $$@ +endef + + + +#--- +# Building. +#--- + +# Generic rules + +all: build $(target-std) $(target-lib) $(target-g1a) + @ echo 'All done!' + +build: + mkdir -p $@ + +$(target-std): $(obj-std) + $(ar) rcs $@ $^ + +$(target-lib): $(target-std) $(obj-lib) + $(ar) rcs $@ $(obj-lib) + +$(target-g1a): $(target-std) $(target-lib) $(demo-obj) + $(cc) -o $(demo-elf) $(cflags) -T $(demo-ld) $(demo-obj) $(demo-libs) + $(ob) -R .comment -R .bss -O binary $(demo-elf) $(demo-bin) + $(wr) $(demo-bin) -o $@ -i $(demo-icon) + +# Automated rules + +$(foreach mod,$(modules), \ + $(foreach source,$(mod-$(mod)-c), $(eval \ + $(call rule-c-source,$(mod),$(source)))) \ + $(foreach source,$(mod-$(mod)-asm), $(eval \ + $(call rule-asm-source,$(mod),$(source)))) \ +) + +# This one should not be optimized. It makes __attribute__((interrupt_handler)) +# buggy... maybe. Anyway there's a bug in this file. +build/core_gint.c.o: src/core/gint.c $(mod-core-dep) + $(cc) -c $< -o $@ $(cflags) -I src/core + +# Demo application + +build/demo_%.c.o: demo/%.c + $(cc) -c $< -o $@ $(cflags) + +build/demo_%.bmp.o: demo/resources/%.bmp + fxconv $< -o $@ -n $(patsubst demo/resources/%.bmp,res_%,$<) + +build/demo_font.bmp.o: demo/resources/font.bmp + fxconv $< -o $@ --font -n res_font + + + +#--- +# Cleaning and others. +#--- + +clean: + @ rm -rf build/* + +mrproper: clean + @ rm -f $(target-g1a) $(target-lib) $(target-std) + @ rm -rf build + +distclean: mrproper + +install: + usb-connector SEND $(target-g1a) $(target-g1a) fls0 + + +.PHONY: all clean mrproper distclean diff --git a/TODO b/TODO index 9f62af2..81094a0 100644 --- a/TODO +++ b/TODO @@ -12,6 +12,7 @@ @ vram overflow @ keyboard test threading interface ++ gint vs. ML with 248x124 at (-60, -28) + use alloca() for tales + call exit handlers + compute frequencies @@ -26,6 +27,7 @@ + bitmap parts + bitmap clipping +- install critical failure handler to prevent failing resets - write and test gray engine - full rtc driver (time) - callbacks and complete user API @@ -34,3 +36,15 @@ ~ exhaustive save for setjmp() ~ registers that need to be saved when configuring gint ~ possible bug when -O2 __attribute__((interrupt_handler)) + + + +Some notes +---------- + +Test cases for bitmap drawing: +- aligned 32 / non-aligned 32 +- monochrome / gray +- small / large +- does not overflow / overflows +# blending modes diff --git a/demo/gintdemo.c b/demo/gintdemo.c index c357690..f41d596 100644 --- a/demo/gintdemo.c +++ b/demo/gintdemo.c @@ -10,15 +10,14 @@ #include #include <7305.h> -extern unsigned int bgint, egint; - //--- -// A few procedures for displaying text in the system's vram. +// A few ugly procedures for displaying text. Will have to enhance this +// soon -- which means printf(). //--- void print(const char *str, int x, int y) { - print_raw(str, x, y); + dtext(str, x, y); } void print_hex(unsigned int n, int x, int y) { @@ -60,6 +59,24 @@ void print_hexa(unsigned int n, int digits, int x, int y) ch[digits] = 0; print(ch, x, y); } +void print_int(int n, int x, int y) +{ + char str[20] = { 0 }; + int i, o = 0; + int digits = 0, copy = n; + + if(!n) { str[o++] = '0'; print(str, x, y); return; } + if(n < 0) str[o++] = '-', n = -n; + while(copy) digits++, copy /= 10; + + for(i = 0; i < digits; i++) + { + str[o + digits - i - 1] = n % 10 + '0'; + n /= 10; + } + + gtext(str, x, y); +} @@ -109,14 +126,16 @@ void keyboard_test(void) timer_start(TIMER_USER, 1700, TIMER_Po_256, keyboard_test_timer, 0); + dclear(); + print("Keyboard state:", 0, 0); + print("multi-getkey ^^", 50, 55); + dupdate(); + 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)) @@ -141,109 +160,73 @@ void keyboard_test(void) 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, -0, 0, 0, 0, 0, 0, 0, 7, 159, 0, 0, 1, 192, 0, 0, 0, 0, 0, 121, 240, 0, 0, 0, -31, 191, 192, 0, 3, 224, 27, 216, 0, 0, 1, 251, 252, 0, 0, 0, 57, 247, 222, -30, 7, 240, 36, 36, 62, 25, 131, 159, 24, 255, 129, 224, 0, 227, 142, 126, 1, -192, 45, 172, 127, 127, 192, 14, 1, 255, 199, 224, 0, 227, 140, 240, 1, 192, -26, 88, 115, 127, 224, 14, 57, 221, 207, 0, 0, 227, 13, 192, 1, 192, 34, 68, -120, 30, 0, 14, 25, 156, 220, 0, 0, 227, 253, 252, 1, 192, 36, 36, 126, 28, -0, 14, 219, 156, 223, 192, 0, 227, 253, 252, 1, 192, 36, 36, 31, 12, 0, 46, -27, 140, 223, 192, 0, 227, 141, 193, 193, 192, 40, 20, 7, 140, 0, 206, 25, 140, -220, 28, 0, 227, 140, 225, 129, 199, 24, 24, 99, 156, 1, 14, 25, 204, 206, 24, -0, 227, 142, 127, 1, 195, 39, 228, 255, 156, 2, 14, 24, 237, 199, 240, 1, 247, -222, 62, 1, 198, 44, 44, 223, 30, 2, 31, 28, 237, 131, 224, 1, 224, 0, 0, 3, -254, 27, 216, 0, 0, 4, 30, 0, 0, 0, 0, 3, 192, 0, 0, 7, 252, 0, 0, 0, 0, 4, -60, 1, 249, 240, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 4, 0, 97, 240, 56, 0, 0, -0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 224, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 47, 192, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 32, 255, 128, 63, 128, -0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 32, 255, 0, 48, 78, 0, 0, 0, 0, 0, 0, 0, 0, -0, 0, 15, 176, 255, 0, 112, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 8, 56, 255, 0, -96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 8, 60, 255, 0, 224, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 130, 56, 126, 255, 3, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 192, -62, 255, 15, 224, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 14, 191, 255, 192, 0, -0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 6, 129, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 6, 0, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 7, 128, 63, 192, -1, 0, 96, 1, 224, 1, 0, 0, 0, 2, 0, 0, 7, 0, 31, 192, 0, 0, 95, 1, 11, 68, 88, -0, 0, 4, 0, 0, 7, 128, 31, 192, 0, 1, 192, 129, 204, 85, 100, 0, 0, 8, 0, 0, -15, 128, 63, 224, 0, 0, 95, 1, 8, 85, 68, 0, 1, 144, 0, 0, 31, 128, 143, 224, -64, 0, 96, 1, 232, 41, 68, 0, 2, 96, 0, 31, 255, 129, 7, 248, 96, 0, 0, 0, 0, -0, 0, 0, 4, 0, 0, 96, 254, 129, 7, 254, 96, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 128, -254, 131, 135, 255, 224, 0, 0, 1, 192, 64, 16, 0, 8, 0, 7, 0, 254, 131, 255, -63, 224, 0, 0, 1, 38, 113, 208, 0, 8, 0, 13, 0, 222, 147, 254, 31, 224, 0, 0, -1, 41, 74, 80, 0, 8, 0, 25, 0, 222, 67, 254, 31, 160, 0, 0, 1, 41, 74, 80, 0, -12, 0, 49, 0, 222, 19, 254, 62, 48, 0, 0, 1, 198, 113, 208, 0, 2, 0, 32, 128, -222, 195, 255, 252, 56, 0, 0, 0, 0, 0, 0, 0, 2, 0, 124, 64, 220, 151, 135, 248, -127, 0, 0, 0, 0, 0, 0, 0, 2, 0, 66, 32, 221, 223, 7, 240, 255, 0, 0, 0, 0, 0, -0, 0, 2, 0, 129, 23, 93, 159, 15, 241, 131, 0, 0, 0, 0, 0, 0, 0, 4, 0, 128, -136, 217, 95, 3, 226, 9, 0, 0, 1, 240, 0, 0, 0, 4, 0, 128, 72, 89, 95, 129, -228, 18, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 72, 73, 127, 128, 224, 36, 0, 0, 0, 0, -0, 0, 0, 28, 1, 0, 76, 129, 127, 192, 96, 8, 0, 0, 0, 0, 0, 0, 0, 16, 1, 0, -231, 203, 124, 96, 64, 0, 0, 0, 0, 0, 0, 0, 0, 16, 1, 1, 28, 123, 240, 12, 64, -1, 0, 0, 0, 0, 0, 0, 0, 16, 1, 2, 28, 143, 128, 15, 192, 7, 0, 0, 0, 0, 0, 0, -0, 16, 1, 4, 17, 143, 24, 15, 192, 14, 0, 0, 0, 0, 0, 0, 0, 28, 1, 4, 1, 135, -24, 31, 192, 24, 0, 0, 0, 0, 0, 0, 0, 18, 1, 62, 1, 135, 248, 63, 224, 192, -0, 0, 0, 0, 0, 0, 0, 35, 1, 195, 1, 135, 128, 254, 126, 1, 0, 0, 0, 0, 0, 0, -0, 35, 193, 131, 195, 135, 255, 248, 112, 1, 0, 0, 0, 0, 0, 0, 0, 67, 241, 131, -14, 207, 255, 192, 224, 3, 0, 0, 0, 0, 0, 0, 3, 67, 15, 143, 56, 255, 7, 1, -224, 7, 0, 0, 0, 0, 0, 0, 28, 130, 7, 255, 112, 204, 7, 131, 224, 31, 0, 0, -0, 0, 0, 0, 32, 134, 30, 29, 120, 156, 7, 255, 224, 127, 0, 0, 0, 0, 0, 63, -197, 206, 60, 56, 192, 248, 15, 255, 248, 255, 0, 0, 0, 0, 0, 120, 5, 227, 248, -56, 195, 248, 127, 191, 254, 63, 0, 0, 0, 0, 7, 254, 255, 193, 255, 15, 193, -255, 15, 31, 252, 31 }; -*/ - /* bitmap_test() Displays various bitmaps to ensure bopti is working correctly. */ 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 res_bitmap_opt_start; + extern Image res_symbol_start; + extern Image res_symbol2_start; + extern Image res_sprites_start; + extern Image res_swords_start; - Image *opt = &binary_resources_bitmap_opt_start; - Image *sprites = &binary_resources_sprites_start; - Image *sybl = &binary_resources_symbol_start; - Image *sybl2 = &binary_resources_symbol2_start; + Image *opt = &res_bitmap_opt_start; + Image *sybl = &res_symbol_start; + Image *sybl2 = &res_symbol2_start; + Image *sprites = &res_sprites_start; + Image *swords = &res_swords_start; -// enum BlendingMode blend = Blend_Or; uint32_t a32 = 0xffffffff; - int black_bg = 0; + int black_bg = 0, gray = 0; int key; + int x = 20, y = 10; while(1) { - dclear(); + if(gray) + { + gray_start(); + gclear(); - if(black_bg) dreverse_area(0, 0, 127, 63); - dimage(opt, 0, 57); + if(black_bg) greverse_area(0, 0, 127, 63); + gimage(opt, 0, 57); - dimage(sprites, 2 & a32, 2); - dimage(sybl, 30 & a32, 40); - dimage(sybl2, 62 & a32, 40); + gimage(sprites, x, y); + gimage(swords, x, y + 35); - dupdate(); + gupdate(); + } + else + { + gray_stop(); + dclear(); + + if(black_bg) dreverse_area(0, 0, 127, 63); + dimage(opt, 0, 57); + + dimage(sybl, 30 & a32, 40); + dimage(sybl2, 62 & a32, 40); + + dupdate(); + + } key = getkey(); if(key == KEY_EXIT) break; -/* - if(key == KEY_F1) blend = Blend_Or; - if(key == KEY_F2) blend = Blend_And; - if(key == KEY_F3) blend = Blend_Invert; -*/ + if(key == KEY_F1) gray = !gray; + if(key == KEY_F2) a32 ^= 31; + if(key == KEY_F3) black_bg = !black_bg; - if(key == KEY_F4) black_bg = !black_bg; - if(key == KEY_F5) a32 ^= 31; + if(key == KEY_UP) y--; + if(key == KEY_DOWN) y++; + if(key == KEY_LEFT) x--; + if(key == KEY_RIGHT) x++; } + gray_stop(); return; } @@ -256,10 +239,10 @@ void bitmap_test(void) void text_test(void) { - extern Font binary_resources_font_start; - Font *font = &binary_resources_font_start; + extern Font res_font_start; + Font *font = &res_font_start; - print_configure(font); + text_configure(font); dclear(); @@ -284,31 +267,89 @@ void text_test(void) void gray_test(void) { - extern Image binary_resources_illustration_start; - Image *illustration = &binary_resources_illustration_start; + extern Image res_illustration_start; + Image *illustration = &res_illustration_start; - int light, dark; - int key; + int *v1, *v2; - gray_getDelays(&light, &dark); + int delays[2]; // { light, dark } + int key, changed = 1, i; + int selected = 0; + + gray_getDelays(delays, delays + 1); gray_start(); while(1) { - gclear(); - dimage(illustration, 0, 0); - gclear_area(64, 0, 127, 63); -// gupdate(); + if(changed) + { + gray_setDelays(delays[0], delays[1]); + gclear(); - key = getkey(); + v1 = gray_lightVRAM(); + v2 = gray_darkVRAM(); + + for(i = 0; i < 63; i++) + { + v1[(i << 2)] = v1[(i << 2) + 1] = + -((i & 31) < 16); + v2[(i << 2)] = v2[(i << 2) + 1] = + -(i < 32); + } + +// gimage(illustration, 0, 0); +// gclear_area(64, 0, 127, 63); + + gtext("light", 78, 6); + print_int(delays[0], 103, 6); + + gtext("dark", 78, 15); + print_int(delays[1], 103, 15); + + gtext(">", 70, selected ? 15 : 6); + gupdate(); + } + + changed = 0; + + key = getkey_opt(Getkey_RepeatArrowKeys, 1); 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); -*/ + changed = 1; + + switch(key) + { + case KEY_F1: + delays[0] = 860; + delays[1] = 1298; + break; + case KEY_F2: + delays[0] = 912; + delays[1] = 1343; + break; + case KEY_F3: + delays[0] = 993; + delays[1] = 1609; + break; + case KEY_F6: + selected = !selected; + break; + case KEY_UP: + delays[selected] += 10; + break; + case KEY_DOWN: + if(delays[selected] >= 110) delays[selected] -= 10; + break; + case KEY_RIGHT: + delays[selected]++; + break; + case KEY_LEFT: + if(delays[selected] >= 101) delays[selected]--; + break; + default: + changed = 0; + break; + } } gray_stop(); @@ -322,6 +363,7 @@ void gray_test(void) */ int main_menu(void) { + extern unsigned int bgint, egint; const char *mpu_names[] = { "MPU_Unkown", "MPU_SH7337", @@ -358,11 +400,158 @@ int main_menu(void) if(key == KEY_2) return 2; if(key == KEY_3) return 3; if(key == KEY_4) return 4; + if(key == KEY_5) return 5; } return 0; } +static const unsigned char screen[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, +0, 0, 0, 0, 0, 0, 0, 7, 159, 0, 0, 1, 192, 0, 0, 0, 0, 0, 121, 240, 0, 0, 0, +31, 191, 192, 0, 3, 224, 27, 216, 0, 0, 1, 251, 252, 0, 0, 0, 57, 247, 222, +30, 7, 240, 36, 36, 62, 25, 131, 159, 24, 255, 129, 224, 0, 227, 142, 126, 1, +192, 45, 172, 127, 127, 192, 14, 1, 255, 199, 224, 0, 227, 140, 240, 1, 192, +26, 88, 115, 127, 224, 14, 57, 221, 207, 0, 0, 227, 13, 192, 1, 192, 34, 68, +120, 30, 0, 14, 25, 156, 220, 0, 0, 227, 253, 252, 1, 192, 36, 36, 126, 28, +0, 14, 219, 156, 223, 192, 0, 227, 253, 252, 1, 192, 36, 36, 31, 12, 0, 46, +27, 140, 223, 192, 0, 227, 141, 193, 193, 192, 40, 20, 7, 140, 0, 206, 25, 140, +220, 28, 0, 227, 140, 225, 129, 199, 24, 24, 99, 156, 1, 14, 25, 204, 206, 24, +0, 227, 142, 127, 1, 195, 39, 228, 255, 156, 2, 14, 24, 237, 199, 240, 1, 247, +222, 62, 1, 198, 44, 44, 223, 30, 2, 31, 28, 237, 131, 224, 1, 224, 0, 0, 3, +254, 27, 216, 0, 0, 4, 30, 0, 0, 0, 0, 3, 192, 0, 0, 7, 252, 0, 0, 0, 0, 4, +60, 1, 249, 240, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 4, 0, 97, 240, 56, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 224, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +4, 0, 47, 192, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 32, 255, 128, 63, 128, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 32, 255, 0, 48, 78, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 15, 176, 255, 0, 112, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 8, 56, 255, 0, +96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 8, 60, 255, 0, 224, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 130, 56, 126, 255, 3, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 192, +62, 255, 15, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 14, 191, 255, 192, 0, +0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 6, 129, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, +1, 0, 0, 6, 0, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 7, 128, 63, 192, +0, 0, 96, 1, 224, 1, 0, 0, 0, 2, 0, 0, 7, 0, 31, 192, 0, 0, 95, 1, 11, 68, 88, +0, 0, 4, 0, 0, 7, 128, 31, 192, 0, 1, 192, 129, 204, 85, 100, 0, 0, 8, 0, 0, +15, 128, 63, 224, 0, 0, 95, 1, 8, 85, 68, 0, 1, 144, 0, 0, 31, 128, 143, 224, +64, 0, 96, 1, 232, 41, 68, 0, 2, 96, 0, 31, 255, 129, 7, 248, 96, 0, 0, 0, 0, +0, 0, 0, 4, 0, 0, 96, 254, 129, 7, 254, 96, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 128, +254, 131, 135, 255, 224, 0, 0, 1, 192, 64, 16, 0, 8, 0, 7, 0, 254, 131, 255, +63, 224, 0, 0, 1, 38, 113, 208, 0, 8, 0, 13, 0, 222, 147, 254, 31, 224, 0, 0, +1, 41, 74, 80, 0, 8, 0, 25, 0, 222, 67, 254, 31, 160, 0, 0, 1, 41, 74, 80, 0, +12, 0, 49, 0, 222, 19, 254, 62, 48, 0, 0, 1, 198, 113, 208, 0, 2, 0, 32, 128, +222, 195, 255, 252, 56, 0, 0, 0, 0, 0, 0, 0, 2, 0, 124, 64, 220, 151, 135, 248, +127, 0, 0, 0, 0, 0, 0, 0, 2, 0, 66, 32, 221, 223, 7, 240, 255, 0, 0, 0, 0, 0, +0, 0, 2, 0, 129, 23, 93, 159, 15, 241, 131, 0, 0, 0, 0, 0, 0, 0, 4, 0, 128, +136, 217, 95, 3, 226, 9, 0, 0, 1, 240, 0, 0, 0, 4, 0, 128, 72, 89, 95, 129, +228, 18, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 72, 73, 127, 128, 224, 36, 0, 0, 0, 0, +0, 0, 0, 28, 1, 0, 76, 129, 127, 192, 96, 8, 0, 0, 0, 0, 0, 0, 0, 16, 1, 0, +231, 203, 124, 96, 64, 0, 0, 0, 0, 0, 0, 0, 0, 16, 1, 1, 28, 123, 240, 12, 64, +1, 0, 0, 0, 0, 0, 0, 0, 16, 1, 2, 28, 143, 128, 15, 192, 7, 0, 0, 0, 0, 0, 0, +0, 16, 1, 4, 17, 143, 24, 15, 192, 14, 0, 0, 0, 0, 0, 0, 0, 28, 1, 4, 1, 135, +24, 31, 192, 24, 0, 0, 0, 0, 0, 0, 0, 18, 1, 62, 1, 135, 248, 63, 224, 192, +0, 0, 0, 0, 0, 0, 0, 35, 1, 195, 1, 135, 128, 254, 126, 1, 0, 0, 0, 0, 0, 0, +0, 35, 193, 131, 195, 135, 255, 248, 112, 1, 0, 0, 0, 0, 0, 0, 0, 67, 241, 131, +14, 207, 255, 192, 224, 3, 0, 0, 0, 0, 0, 0, 3, 67, 15, 143, 56, 255, 7, 1, +224, 7, 0, 0, 0, 0, 0, 0, 28, 130, 7, 255, 112, 204, 7, 131, 224, 31, 0, 0, +0, 0, 0, 0, 32, 134, 30, 29, 120, 156, 7, 255, 224, 127, 0, 0, 0, 0, 0, 63, +197, 206, 60, 56, 192, 248, 15, 255, 248, 255, 0, 0, 0, 0, 0, 120, 5, 227, 248, +56, 195, 248, 127, 191, 254, 63, 0, 0, 0, 0, 7, 254, 255, 193, 255, 15, 193, +255, 15, 31, 252, 31 }; + +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 = display_getCurrentVRAM()+(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< +void debug(void) +{ + extern Image res_screen_start; + struct mod_tmu *timer; + int time1, time2; + int i; + + timer_get(TIMER_USER, &timer, NULL); + + dclear(); + ML_bmp_or_cl(screen, 1, 1, 128, 64); + dupdate(); + getkey(); + + dclear(); + dimage(&res_screen_start, 1, 1); + dupdate(); + getkey(); + + dclear(); + dtext("ML...", 2, 2); + dupdate(); + + timer_start(TIMER_USER, 0x0fffffff, TIMER_Po_4, NULL, 0); + for(i = 0; i < 1000; i++) ML_bmp_or_cl(screen, 1, 1, 128, 64); + time1 = timer->TCNT; + timer_stop(TIMER_USER); + time1 = 0x0fffffff - time1; + + dclear(); + dtext("gint...", 2, 2); + dupdate(); + + timer_start(TIMER_USER, 0x0fffffff, TIMER_Po_4, NULL, 0); + for(i = 0; i < 1000; i++) dimage(&res_screen_start, 1, 1); + time2 = timer->TCNT; + timer_stop(TIMER_USER); + time2 = 0x0fffffff - time2; + + dclear(); + print_hex(time1, 2, 2); + print_hex(time2, 2, 9); + dupdate(); + while(getkey() != KEY_EXIT); +} + /* main() Handles application calls. @@ -371,10 +560,10 @@ int main_menu(void) */ int main(void) { - extern Font binary_resources_font_start; - Font *font = &binary_resources_font_start; + extern Font res_font_start; + Font *font = &res_font_start; - print_configure(font); + text_configure(font); int app; @@ -387,6 +576,7 @@ int main(void) if(app == 2) bitmap_test(); if(app == 3) text_test(); if(app == 4) gray_test(); + if(app == 5) debug(); } return 0; diff --git a/demo/resources/bitmap_opt.bmp b/demo/resources/bitmap_opt.bmp index 66fe722..dd8d123 100644 Binary files a/demo/resources/bitmap_opt.bmp and b/demo/resources/bitmap_opt.bmp differ diff --git a/demo/resources/screen.bmp b/demo/resources/screen.bmp new file mode 100644 index 0000000..050825a Binary files /dev/null and b/demo/resources/screen.bmp differ diff --git a/gintdemo.g1a b/gintdemo.g1a new file mode 100644 index 0000000..ec073c9 Binary files /dev/null and b/gintdemo.g1a differ diff --git a/include/7305.h b/include/7305.h index f6ff1a3..1eb7e71 100644 --- a/include/7305.h +++ b/include/7305.h @@ -62,7 +62,7 @@ struct _st_rtc gap(1); union { - unsigned char; + unsigned char BYTE; struct { unsigned :2; unsigned TENS :2; @@ -208,7 +208,7 @@ struct _st_rtc struct { unsigned ENB :1; unsigned :7; - } + }; } RCR3; } __attribute__((packed)); diff --git a/include/display.h b/include/display.h index afca785..4cca184 100644 --- a/include/display.h +++ b/include/display.h @@ -14,6 +14,7 @@ // Heading declarations. //--- +#include #include enum Color @@ -150,4 +151,45 @@ void dimage(struct Image *image, int x, int y); +//--- +// Rectangle masks. +// +// The concept of 'rectangle masks' is used several times in this module. +// It is based on the fact that an operation that affects a rectangle acts +// the same on all its lines. Therefore the behavior of the operation is +// determined by its behavior on a single line, which is represented using +// 'masks' whose bits indicate whether a pixel is affected (1) or not (0). +// +// For example when clearing the screen rectangle (16, 16, 112, 48), the +// masks will represent information '16 to 112 on x-axis', and will hold +// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These +// masks can then be used by setting vram[offset] &= ~masks[i]. This +// appears to be very flexible : for instance, vram[offset] ^= masks[i] +// will reverse the pixels in the same rectangle. +// +// This technique can also be used in more subtle cases with more complex +// patterns, but within this module it is unlikely to happen. +// +//--- + +/* + adjustRectangle() + Adjusts the given rectangle coordinates to ensure that : + - the rectangle is entirely contained in the screen + - x1 < x2 + - y1 < y2 + which is needed when working with screen rectangles. +*/ +void adjustRectangle(int *x1, int *y1, int *x2, int *y2); + +/* + getMasks() + Computes the rectangle masks needed to affect pixels located between x1 + and x2 (both included). The four masks are stored in the third argument + (seen as an array). +*/ +void getMasks(int x1, int x2, uint32_t *masks); + + + #endif // _DISPLAY_H diff --git a/include/gray.h b/include/gray.h index 94653ac..de14fba 100644 --- a/include/gray.h +++ b/include/gray.h @@ -60,6 +60,16 @@ void gray_getDelays(int *light, int *dark); 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. + + Typical values: + + values stability stripes colors + --------------------------------------------------------- + 860, 1298 excellent worst static good + 912, 1343 bad none very good + 993, 1609 medium light fast good (default) + --------------------------------------------------------- + */ void gray_setDelays(int light, int dark); diff --git a/include/setjmp.h b/include/setjmp.h index 2037b5e..0addccf 100644 --- a/include/setjmp.h +++ b/include/setjmp.h @@ -14,17 +14,12 @@ typedef unsigned int jmp_buf[16]; /* setjmp() Configures a jump by saving data to the given jump buffer. - - @arg env Empty jump buffer. */ int setjmp(jmp_buf env); /* longjmp() Performs a long jump. - - @arg env Jump buffer configure with setjmp(). - @arg value setjmp() will return this integer after the jump. */ void longjmp(jmp_buf env, int value); diff --git a/include/stdlib.h b/include/stdlib.h index de053e8..0a0ff01 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -34,15 +34,15 @@ void exit(int status); /* malloc() - Allocs 'size' bytes and returns a pointer to a free memory area. + Allocates 'size' bytes and returns a pointer to a free memory area. Returns NULL on error. */ void *malloc(size_t size); /* calloc() - Allocs 'n' elements of size 'size' and wipes the memory area. Returns - NULL on error. + Allocates 'n' elements of size 'size' and wipes the memory area. + Returns NULL on error. */ void *calloc(size_t n, size_t size); diff --git a/include/string.h b/include/string.h index d74977a..d5c96dc 100644 --- a/include/string.h +++ b/include/string.h @@ -12,20 +12,12 @@ Copies a memory area. The two areas must not overlap (if they do, use memmove()). A smart copy is performed when possible. To enhance performance, make sure than destination and source are both 4-aligned. - - @arg destination - @arg source - @arg byte_number */ void *memcpy(void *destination, const void *source, size_t byte_number); /* memset() Sets the contents of a memory area. A smart copy is performed. - - @arg area - @arg byte Byte to write in the area. - @arg byte_number */ void *memset(void *destination, int byte, size_t byte_number); diff --git a/info b/info deleted file mode 100644 index 8a2dc33..0000000 --- a/info +++ /dev/null @@ -1,16 +0,0 @@ - -Experimental power reduction as function of the keyboard analysis frequency. - -SH3 - None 0 % - 4 Hz 2.8 % - 16 Hz 2.8 % - 64 Hz 2.8 % - 256 Hz 20.0 % - -SH4 - None 0 % - 4 Hz 1.8 % - 16 Hz 1.8 % - 64 Hz 1.8 % - 256 Hz 3.6 % diff --git a/libc.a b/libc.a index 29ad94c..587b56e 100644 Binary files a/libc.a and b/libc.a differ diff --git a/libgint.a b/libgint.a index 3c26fd7..30b9985 100644 Binary files a/libgint.a and b/libgint.a differ diff --git a/src/bopti/bopti_internals.c b/src/bopti/bopti_internals.c index b258e23..90f3601 100644 --- a/src/bopti/bopti_internals.c +++ b/src/bopti/bopti_internals.c @@ -1,18 +1,22 @@ #include +// Monochrome video ram, light and dark buffers (in this order). +int *vram, *v1, *v2; + /* bopti_op() Operates on a vram long. The operator will often not contain 32 bits of image information. Since neutral bits are not the same for all - operations, the op_mask argument indicates which bits should be used - for the operation. Which operation has to be done is determined by the - channel setting. + operations, a mask is used to indicate which bits should be used for + the operation. This mask is taken for the image's rectangle masks (see + module display for more information on rectangle masks). + Which operation is performed is determined by the channel setting. */ -static void bopti_op_mono(int offset, uint32_t operator, uint32_t op_mask) +void bopti_op_mono(int offset, uint32_t operator, struct Command *c) { - operator &= op_mask; + operator &= c->masks[offset & 3]; - switch(channel) + switch(c->channel) { case Channel_Mono: vram[offset] |= operator; @@ -26,11 +30,11 @@ static void bopti_op_mono(int offset, uint32_t operator, uint32_t op_mask) break; } } -static void bopti_op_gray(int offset, uint32_t operator, uint32_t op_mask) +void bopti_op_gray(int offset, uint32_t operator, struct Command *c) { - operator &= op_mask; + operator &= c->masks[offset & 3]; - switch(channel) + switch(c->channel) { case Channel_Mono: v1[offset] |= operator; @@ -66,74 +70,75 @@ static void bopti_op_gray(int offset, uint32_t operator, uint32_t op_mask) because bopti_grid() will perform a 32-bit shift when x is a multiple of 32, which is undefined behavior. */ -static void bopti_grid_a32(const uint32_t *layer, int x, int y, - int column_count) +void bopti_grid_a32(const uint32_t *layer, int column_count, int height, + struct Command *c) { - int vram_column_offset = (y << 2) + (x >> 5); + int vram_column_offset = (c->y << 2) + (c->x >> 5); int vram_offset = vram_column_offset; int column, row; for(column = 0; column < column_count; column++) { - for(row = 0; row < height; row++) + for(row = c->top; row < c->bottom; row++) { - (*op)(vram_offset, *layer, 0xffffffff); - layer++; + (*c->op)(vram_offset, layer[row], c); vram_offset += 4; } vram_column_offset++; vram_offset = vram_column_offset; + layer += height; } } -static void bopti_grid(const uint32_t *layer, int x, int y, int column_count) +void bopti_grid(const uint32_t *layer, int column_count, int height, + struct Command *c) { if(!column_count) return; - if(!(x & 31)) + if(!(c->x & 31)) { - bopti_grid_a32(layer, x, y, column_count); + bopti_grid_a32(layer, column_count, height, c); return; } const uint32_t *p1, *p2; - uint32_t l1, l2; + uint32_t l1, l2, operator; int right_column, line; - int vram_column_offset = (y << 2) + (x >> 5); + int vram_column_offset = (c->y << 2) + (c->x >> 5) + (c->x < 0); int vram_offset = vram_column_offset; - int shift1 = 32 - (x & 31); - int shift2 = (x & 31); + int shift1 = 32 - (c->x & 31); + int shift2 = (c->x & 31); - uint32_t operator, and_mask; - uint32_t and_mask_0 = 0xffffffff >> shift2; - uint32_t and_mask_1 = 0xffffffff << shift1; - - // Initializing two pointers. Since the columns are written one after - // another, they will be updated directly to parse the whole grid. + // Initializing two pointers. They will read two adjacent columns at + // the same time (p2 is column ahead of p1). Since the columns are + // written one after another, incrementing them will suffice when + // reaching the end of two columns, to move them to the next ones. p1 = layer - height; p2 = layer; - // Drawing vram longwords, using pairs of columns. - for(right_column = 0; right_column <= column_count; right_column++) - { - and_mask = 0xffffffff; - if(right_column == 0) and_mask &= and_mask_0; - if(right_column == column_count) and_mask &= and_mask_1; + // We don't want to write the first vram column when x is negative. + if(c->x < 0) p1 += height, p2 += height; + right_column = (c->x < 0); - for(line = 0; line < height; line++) + // Drawing vram longwords, using pairs of columns. + while(right_column <= column_count) + { + for(line = c->top; line < c->bottom; line++) { - l1 = (right_column > 0) ? (*p1) : (0); - l2 = (right_column < column_count) ? (*p2) : (0); - p1++, p2++; + l1 = (right_column > 0) ? p1[line] : (0); + l2 = (right_column < column_count) ? p2[line] : (0); operator = (l1 << shift1) | (l2 >> shift2); - (*op)(vram_offset, operator, and_mask); + (*c->op)(vram_offset, operator, c); vram_offset += 4; } + p1 += height; + p2 += height; vram_column_offset++; vram_offset = vram_column_offset; + right_column++; } } @@ -144,13 +149,13 @@ static void bopti_grid(const uint32_t *layer, int x, int y, int column_count) is read and updated so that it points to the next line at the end of the operation. */ -static uint32_t bopti_end_get1(const unsigned char **data) +uint32_t bopti_end_get1(const unsigned char **data) { uint32_t operator = **data; *data += 1; return operator; } -static uint32_t bopti_end_get2(const unsigned char **data) +uint32_t bopti_end_get2(const unsigned char **data) { uint32_t operator = *((uint16_t *)*data); *data += 2; @@ -165,63 +170,57 @@ static uint32_t bopti_end_get2(const unsigned char **data) whose with is lower than 32. (Actually is it lower or equal to 16; otherwise it would have been a column and the end would be empty). */ -static void bopti_end_nover(const unsigned char *end, int x, int y, int width) +void bopti_end_nover(const unsigned char *end, int size, struct Command *c) { uint32_t (*get)(const unsigned char **data) = - (width > 8) ? bopti_end_get2 : bopti_end_get1; - - int vram_offset = (y << 2) + (x >> 5); - int row; + (size == 2) ? bopti_end_get2 : bopti_end_get1; // We *have* shift >= 0 because of this function's 'no overlap' // requirement. - int shift_base = (width > 8) ? 16 : 24; - int shift = shift_base - (x & 31); - - uint32_t and_mask = (0xffffffff << (32 - width)) >> (x & 31); + int shift = (32 - (size << 3)) - (c->x & 31); + int vram_offset = (c->y << 2) + (c->x >> 5); uint32_t operator; + int row; - for(row = 0; row < height; row++) + // Skipping c->top lines (because get() function only allows sequential + // access). + end += c->top * size; + + for(row = c->top; row < c->bottom; row++) { operator = (*get)(&end); operator <<= shift; - (*op)(vram_offset, operator, and_mask); + (*c->op)(vram_offset, operator, c); vram_offset += 4; } } -static void bopti_end(const unsigned char *end, int x, int y, int width) +void bopti_end(const unsigned char *end, int size, struct Command *c) { - if((x & 31) + width <= 32) - { - bopti_end_nover(end, x, y, width); - return; - } - uint32_t (*get)(const unsigned char **data) = - (width > 8) ? (bopti_end_get2) : (bopti_end_get1); + (size == 2) ? (bopti_end_get2) : (bopti_end_get1); - int vram_offset = (y << 2) + (x >> 5); + int vram_offset = (c->y << 2) + (c->x >> 5); + uint32_t row_data, operator; int row; - int shift_base = (width > 8) ? 16 : 24; - int shift1 = (x & 31) - shift_base; - int shift2 = shift_base + 32 - (x & 31); + int shift_base = (32 - (size << 3)); + int shift1 = (c->x & 31) - shift_base; + int shift2 = shift_base + 32 - (c-> x & 31); - uint32_t and_mask_0 = 0xffffffff >> (x & 31); - uint32_t and_mask_1 = 0xffffffff << (64 - width - (x & 31)); + // Skipping c->top lines (because get() function only allows sequential + // access). + end += c->top * size; - uint32_t row_data, operator; - - for(row = 0; row < height; row++) + for(row = c->top; row < c->bottom; row++) { row_data = (*get)(&end); operator = row_data >> shift1; - (*op)(vram_offset, operator, and_mask_0); + (*c->op)(vram_offset, operator, c); operator = row_data << shift2; - (*op)(vram_offset + 1, operator, and_mask_1); + (*c->op)(vram_offset + 1, operator, c); vram_offset += 4; } @@ -237,41 +236,63 @@ static void bopti_end(const unsigned char *end, int x, int y, int width) bopti() Draws a layer in the video ram. */ -static void bopti(const unsigned char *layer, int x, int y, int columns, - int end_size) +void bopti(const unsigned char *layer, struct Structure *s, struct Command *c) { - const unsigned char *end = layer + ((columns * height) << 2); - int end_x = x + (columns << 5); + const unsigned char *grid, *end; + int grid_columns, has_end; - bopti_grid((const uint32_t *)layer, x, y, columns); - if(end_size) bopti_end(end, end_x, y, end_size); + // Skipping columns at the beginning. + grid = layer + ((c->left * s->height) << 2); + + // Updating the command arguments to eliminate some information about + // parts that are not being drawn. + c->x += (c->left << 5); + c->y += c->top; + + // Columns are identified by ids 0 to s->columns - 1, and the end has + // id s->columns. So the end is drawn if this last column is included. + has_end = (c->right == s->columns); + // Computing number of grid columns to draw. + grid_columns = c->right - c->left + 1 - has_end; + + bopti_grid((const uint32_t *)grid, grid_columns, s->height, c); + + if(has_end) + { + end = layer + ((s->columns * s->height) << 2); + c->x += (grid_columns << 5); + + if((c->x & 31) + s->end_size <= 32) + bopti_end_nover(end, s->end_bytes, c); + else + bopti_end(end, s->end_bytes, c); + } } /* getStructure() Determines the image size and data pointer. */ -static void getStructure(struct Image *img, int *width, int *height, - int *layer_size, const unsigned char **data, int *columns, - int *end_size) +void getStructure(struct Image *img, struct Structure *s) { int column_count, end, end_bytes, layer; // Large images. if(!img->width && !img->height) { - if(width) *width = (img->data[0] << 8) | img->data[1]; - if(height) *height = (img->data[2] << 8) | img->data[3]; - if(data) *data = img->data + 4; + s->width = (img->data[0] << 8) | img->data[1]; + s->height = (img->data[2] << 8) | img->data[3]; + s->data = img->data + 4; - column_count = (*width + 31) >> 5; - end = end_bytes = 0; + column_count = (s->width + 31) >> 5; + end = 0; + end_bytes = 0; } else { - if(width) *width = img->width; - if(height) *height = img->height; - if(data) *data = img->data; + s->width = img->width; + s->height = img->height; + s->data = img->data; column_count = img->width >> 5; end = img->width & 31; @@ -280,13 +301,21 @@ static void getStructure(struct Image *img, int *width, int *height, end <= 8 ? 1 : end <= 16 ? 2 : 4; + + if(end_bytes == 4) + { + column_count++; + end = 0; + end_bytes = 0; + } } // The layer size must be rounded to a multiple of 4. layer = img->height * ((column_count << 2) + end_bytes); if(layer & 3) layer += 4 - (layer & 3); - if(columns) *columns = column_count; - if(end_size) *end_size = end; - if(layer_size) *layer_size = layer; + s->columns = column_count; + s->end_bytes = end_bytes; + s->end_size = end; + s->layer_size = layer; } diff --git a/src/bopti/bopti_internals.h b/src/bopti/bopti_internals.h index 99a40a2..1883613 100644 --- a/src/bopti/bopti_internals.h +++ b/src/bopti/bopti_internals.h @@ -18,6 +18,7 @@ #define _BOPTI_INTERNALS_H 1 #include +#include /* enum Channel @@ -49,15 +50,43 @@ enum Format Channel_DarkAlpha }; -// The following variables refer to parameters that do not change during the -// drawing operation (at least for the time of a layer). They could be passed -// on by every function from the module, but this would be heavy and useless. -// Using global variables is not really a proper solution but it does simplify -// code much. +/* + struct Structure + Describes an image's structure. +*/ +struct Structure +{ + int width, height; + int layer_size; + + const unsigned char *data; + int columns; + int end_size, end_bytes; +}; + +/* + struct Command + Contains a drawing operation's parameters. +*/ +struct Command +{ + // Channel being drawn. + enum Channel channel; + // Operation used (whether bopti_op_mono() or bopti_op_gray()). + void (*op)(int offset, uint32_t operator, struct Command *command); + // Portion of the bitmap which is drawn. 'top' and 'bottom' refer to + // lines where 'left' and 'right' refer to column ids. + int left, right, top, bottom; + // Position of the bitmap on the screen. + int x, y; + // Rectangle masks. + uint32_t masks[4]; +}; + +// The video ram addresses are set by the public functions and used internally +// by the module. +// Monochrome video ram, light and dark buffers (in this order). extern int *vram, *v1, *v2; -extern enum Channel channel; -extern int height; -extern void (*op)(int offset, uint32_t operator, uint32_t op_mask); @@ -69,12 +98,13 @@ extern void (*op)(int offset, uint32_t operator, uint32_t op_mask); bopti_op() Operates on a vram long. The operator will often not contain 32 bits of image information. Since neutral bits are not the same for all - operations, the op_mask argument indicates which bits should be used - for the operation. Which operation has to be done is determined by the - channel setting. + operations, a mask is used to indicate which bits should be used for + the operation. This mask is taken for the image's rectangle masks (see + module display for more information on rectangle masks). + Which operation is performed is determined by the channel setting. */ -void bopti_op_mono(int offset, uint32_t operator, uint32_t op_mask); -void bopti_op_gray(int offset, uint32_t operator, uint32_t op_mask); +void bopti_op_mono(int offset, uint32_t operator, struct Command *c); +void bopti_op_gray(int offset, uint32_t operator, struct Command *c); /* bopti_grid() -- general form @@ -85,10 +115,12 @@ void bopti_op_gray(int offset, uint32_t operator, uint32_t op_mask); The need for bopti_grid_a32() is not only linked to optimization, because bopti_grid() will perform a 32-bit shift when x is a multiple of 32, which is undefined behavior. + bopti_grid() calls bopti_grid_32() by default. */ -void bopti_grid_a32(const uint32_t *layer, int x, int y, int column_count); -void bopti_grid(const uint32_t *layer, int x, int y, int column_count); - +void bopti_grid_a32(const uint32_t *layer, int columns, int height, + struct Command *c); +void bopti_grid(const uint32_t *layer, int columns, int height, + struct Command *c); /* bopti_end_get() Returns an operator for the end of a line, whose width is lower than 32 @@ -105,23 +137,24 @@ uint32_t bopti_end_get2(const unsigned char **data); Draws the end of a layer, which can be considered as a whole layer whose with is lower than 32. (Actually is it lower or equal to 16; - otherwise it would have been a column and the end would be empty). + otherwise it would have been a column and the end would be empty). The + 'size' arguments is in bytes. + Unlike bopti_grid_a32(), bopti_end_nover() is not called automatically + by bopti_end(). */ -void bopti_end_nover(const unsigned char *end, int x, int y, int width); -void bopti_end(const unsigned char *end, int x, int y, int width); +void bopti_end_nover(const unsigned char *end, int size, struct Command *c); +void bopti_end(const unsigned char *end, int size, struct Command *c); /* bopti() Draws a layer in the video ram. */ -void bopti(const unsigned char *layer, int x, int y, int columns, - int end_size); +void bopti(const unsigned char *layer, struct Structure *s, struct Command *c); /* getStructure() Determines the image size and data pointer. */ -void getStructure(struct Image *img, int *width, int *height, int *layer_size, - const unsigned char **data, int *columns, int *end_size); +void getStructure(struct Image *img, struct Structure *structure); #endif // _BOPTI_INTERNALS_H diff --git a/src/bopti/dimage.c b/src/bopti/dimage.c index f0df4b5..3da393f 100644 --- a/src/bopti/dimage.c +++ b/src/bopti/dimage.c @@ -7,17 +7,33 @@ */ void dimage(struct Image *img, int x, int y) { - int width, layer_size, columns, end; - int format = img->format, i = 0; - const unsigned char *data; - if(img->magic != 0xb7) return; - if(img->format != Format_Mono && img->format != Format_MonoAlpha) - return; - op = bopti_op_mono; - // 'height' refers to a static variable for this file. - getStructure(img, &width, &height, &layer_size, &data, &columns, &end); + struct Structure s; + struct Command command; + int actual_width; + int format = img->format, i = 0; + + if(format != Format_Mono && format != Format_MonoAlpha) return; + getStructure(img, &s); + + //--- + // Adjusting image parameters. + //--- + + if(x + s.width < 0 || x > 127 || y + s.height < 0 || y > 63) return; + + command.top = (y < 0) ? (-y) : (0); + command.bottom = (y + s.height > 64) ? (64 - y) : (s.height); + command.left = ((x < 0) ? (-x) : (0)) >> 5; + actual_width = (x + s.width > 128) ? (128 - x) : (s.width); + command.right = ((actual_width + 31) >> 5) - 1; + + command.x = x; + command.y = y; + command.op = bopti_op_mono; + + getMasks(x, x + actual_width - 1, command.masks); vram = display_getCurrentVRAM(); @@ -26,9 +42,9 @@ void dimage(struct Image *img, int x, int y) // Drawing every layer, in order of formats. if(format & 1) { - channel = (1 << i); - bopti(data, x, y, columns, end); - data += layer_size; + command.channel = (1 << i); + bopti(s.data, &s, &command); + s.data += s.layer_size; } format >>= 1; diff --git a/src/bopti/gimage.c b/src/bopti/gimage.c index d9904af..dd31143 100644 --- a/src/bopti/gimage.c +++ b/src/bopti/gimage.c @@ -1,4 +1,5 @@ #include +#include #include /* @@ -7,15 +8,31 @@ */ void gimage(struct Image *img, int x, int y) { - int width, layer_size, columns, end; - int format = img->format, i = 0; - const unsigned char *data; - if(img->magic != 0xb7) return; - op = bopti_op_gray; - // 'height' refers to a static variable for this file. - getStructure(img, &width, &height, &layer_size, &data, &columns, &end); + struct Structure s; + struct Command command; + int actual_width; + int format = img->format, i = 0; + + getStructure(img, &s); + + //--- + // Adjusting image parameters. + //--- +//-65:-68 + if(x + s.width < 0 || x > 127 || y + s.height < 0 || y > 63) return; + + command.top = (y < 0) ? (-y) : (0); + command.bottom = (y + s.height > 64) ? (64 - y) : (s.height); + command.left = ((x < 0) ? (-x) : (0)) >> 5; + actual_width = (x + s.width > 128) ? (128 - x) : (s.width); + command.right = ((actual_width + 31) >> 5) - 1; + + command.op = bopti_op_gray; + + if(x >= 0) getMasks(x, x + actual_width - 1, command.masks); + else getMasks(0, actual_width + x - 1, command.masks); v1 = gray_lightVRAM(); v2 = gray_darkVRAM(); @@ -25,9 +42,13 @@ void gimage(struct Image *img, int x, int y) // Drawing every layer, in order of formats. if(format & 1) { - channel = (1 << i); - bopti(data, x, y, columns, end); - data += layer_size; + // These members are modified by bopti()! + command.x = x; + command.y = y; + command.channel = (1 << i); + + bopti(s.data, &s, &command); + s.data += s.layer_size; } format >>= 1; diff --git a/src/core/crt0.c b/src/core/crt0.c index a323234..3bb31da 100644 --- a/src/core/crt0.c +++ b/src/core/crt0.c @@ -53,8 +53,8 @@ int start(void) __GLibAddinAplExecutionCheck(0, 1, 1); // Initializing everything. - init(); gint_init(); + init(); @@ -69,8 +69,8 @@ int start(void) // Remember to flush and close opened streams. // Un-initializing everything. - gint_quit(); fini(); + gint_quit(); return exit_code; } diff --git a/src/core/gint.c b/src/core/gint.c index b7c9c45..d6098e0 100644 --- a/src/core/gint.c +++ b/src/core/gint.c @@ -91,6 +91,11 @@ void gint_init(void) unsigned int *ptr = &bgint; unsigned int *src = &gint_data; + // This initialization routine is usually called before any + // constructor. We want to ensure that the MPU type is detected, but + // mpu_init() hasn't been called yet. + mpu_init(); + // Loading the interrupt handler into the memory. while(ptr < &egint) *ptr++ = *src++; diff --git a/src/core/gint_callback.c b/src/core/gint_callback.c index e90e4c2..d9d1ee7 100644 --- a/src/core/gint_callback.c +++ b/src/core/gint_callback.c @@ -1,6 +1,8 @@ #include #include +#include + static void (*rtc_callback)(void) = NULL; /* diff --git a/src/display/dclear_area.c b/src/display/dclear_area.c index 0b9aadb..2648178 100644 --- a/src/display/dclear_area.c +++ b/src/display/dclear_area.c @@ -8,7 +8,7 @@ */ void dclear_area(int x1, int y1, int x2, int y2) { - unsigned int masks[4]; + uint32_t masks[4]; adjustRectangle(&x1, &y1, &x2, &y2); getMasks(x1, x2, masks); diff --git a/src/display/display_internals.h b/src/display/display_internals.h index 7c3471a..560a0c8 100644 --- a/src/display/display_internals.h +++ b/src/display/display_internals.h @@ -4,25 +4,6 @@ // // Handles vram manipulation and drawing. // -// -// :: Rectangle masks -// -// The concept of 'rectangle masks' is used several times in this module. -// It is based on the fact that an operation that affects a rectangle acts -// the same on all its lines. Therefore the behavior of the operation is -// determined by its behavior on a single line, which is represented using -// 'masks' whose bits indicate whether a pixel is affected (1) or not (0). -// -// For example when clearing the screen rectangle (16, 16, 112, 48), the -// masks will represent information '16 to 112 on x-axis', and will hold -// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These -// masks can then be used by setting vram[offset] &= ~masks[i]. This -// appears to be very flexible : for instance, vram[offset] ^= masks[i] -// will reverse the pixels in the same rectangle. -// -// This technique can also be used in more subtle cases with more complex -// patterns, but within this module it is unlikely to happen. -// //--- #ifndef _DISPLAY_INTERNALS_H @@ -30,23 +11,4 @@ extern int *vram; -/* - adjustRectangle() - Adjusts the given rectangle coordinates to ensure that : - - the rectangle is entirely contained in the screen - - x1 < x2 - - y1 < y2 - which is needed when working with screen rectangles. -*/ -static void adjustRectangle(int *x1, int *y1, int *x2, int *y2); - -/* - getMasks() - Computes the rectangle masks needed to affect pixels located between x1 - and x2 (both included). The four masks are stored in the third argument - (seen as an array). - See this module's internals header file for more information. -*/ -static void getMasks(int x1, int x2, unsigned int *masks); - #endif // _DISPLAY_INTERNALS_H diff --git a/src/display/dline.c b/src/display/dline.c index 3f90483..69e331d 100644 --- a/src/display/dline.c +++ b/src/display/dline.c @@ -13,7 +13,7 @@ static void dhline(int x1, int x2, int y, enum Color color) { - unsigned int masks[4]; + uint32_t masks[4]; int offset = y << 2; int i; diff --git a/src/display/dreverse_area.c b/src/display/dreverse_area.c index f3c48fe..c9eeaee 100644 --- a/src/display/dreverse_area.c +++ b/src/display/dreverse_area.c @@ -9,7 +9,7 @@ */ void dreverse_area(int x1, int y1, int x2, int y2) { - unsigned int masks[4]; + uint32_t masks[4]; adjustRectangle(&x1, &y1, &x2, &y2); getMasks(x1, x2, masks); diff --git a/src/display/getMasks.c b/src/display/getMasks.c index bb2b32f..6f3091c 100644 --- a/src/display/getMasks.c +++ b/src/display/getMasks.c @@ -1,13 +1,12 @@ -#include +#include /* getMasks() Computes the rectangle masks needed to affect pixels located between x1 and x2 (both included). The four masks are stored in the third argument (seen as an array). - See this module's internals header file for more information. */ -void getMasks(int x1, int x2, unsigned int *masks) +void getMasks(int x1, int x2, uint32_t *masks) { // Indexes of the first and last longs that are non-blank. int l1 = x1 >> 5; diff --git a/src/gray/gray_engine.c b/src/gray/gray_engine.c index 12015df..de4f0e4 100644 --- a/src/gray/gray_engine.c +++ b/src/gray/gray_engine.c @@ -11,7 +11,7 @@ #include static int internal_vrams[3][256]; -const void *vrams[4]; +static const void *vrams[4]; static int current = 0; static int delays[2]; @@ -33,7 +33,10 @@ static int runs = 0; */ void gray_start(void) { + if(runs) return; + timer_start(TIMER_GRAY, delays[0], GRAY_PRESCALER, gray_interrupt, 0); + current &= 1; runs = 1; } @@ -44,6 +47,8 @@ void gray_start(void) */ void gray_stop(void) { + if(!runs) return; + timer_stop(TIMER_GRAY); runs = 0; @@ -79,18 +84,18 @@ inline int gray_runs(void) gray_lightVRAM() Returns the module's gray vram address. */ -inline void *gray_lightVRAM(void) +void *gray_lightVRAM(void) { - return (void *)vrams[current & 2]; + return (void *)vrams[~current & 2]; } /* gray_lightVRAM() Returns the module's dark vram address. */ -inline void *gray_darkVRAM(void) +void *gray_darkVRAM(void) { - return (void *)vrams[(current & 2) | 1]; + return (void *)vrams[(~current & 2) | 1]; } /* @@ -130,7 +135,7 @@ inline void gupdate(void) */ void gray_interrupt(void) { - timer_reload(TIMER_GRAY, delays[current & 1]); + timer_reload(TIMER_GRAY, delays[(~current) & 1]); screen_display(vrams[current]); current ^= 1; } @@ -146,6 +151,6 @@ void gray_init(void) vrams[2] = (const void *)internal_vrams[1]; vrams[3] = (const void *)internal_vrams[2]; - delays[0] = 900; - delays[1] = 1000; + delays[0] = 993; + delays[1] = 1609; } diff --git a/src/keyboard/keyboard_internals.h b/src/keyboard/keyboard_internals.h index b4a5b2c..b08678b 100644 --- a/src/keyboard/keyboard_internals.h +++ b/src/keyboard/keyboard_internals.h @@ -5,7 +5,7 @@ // Keyboard variables. extern volatile unsigned char keyboard_state[10]; -extern volatile int interrupt_flag = 0; +extern volatile int interrupt_flag; // Key statistics. extern int repeat_first, repeat_next; diff --git a/src/keyboard/keyboard_interrupt.c b/src/keyboard/keyboard_interrupt.c index 4bf12ae..e76aca1 100644 --- a/src/keyboard/keyboard_interrupt.c +++ b/src/keyboard/keyboard_interrupt.c @@ -42,8 +42,7 @@ void keyboard_interrupt(void) */ void keyboard_init(void) { - timer_start(TIMER_KEYBOARD, 1700, TIMER_Po_256, keyboard_interrupt, - 0); + timer_start(TIMER_KEYBOARD, 1700, TIMER_Po_256, keyboard_interrupt, 0); } /* diff --git a/src/tales/gtext.c b/src/tales/gtext.c new file mode 100644 index 0000000..b12d483 --- /dev/null +++ b/src/tales/gtext.c @@ -0,0 +1,14 @@ +#include +#include + +/* + gtext() + Prints the given raw string. +*/ +void gtext(const char *str, int x, int y) +{ + display_useVRAM(gray_lightVRAM()); + dtext(str, x, y); + display_useVRAM(gray_darkVRAM()); + dtext(str, x, y); +} diff --git a/src/tales/tales_configuration.c b/src/tales/tales_configuration.c index be38c33..eb2aefa 100644 --- a/src/tales/tales_configuration.c +++ b/src/tales/tales_configuration.c @@ -5,7 +5,7 @@ text_configure() Sets the font and mode to use for the following print operations. */ -void text_configure(struct Font *font) +void text_configure(struct Font *next_font) { font = next_font; } diff --git a/src/timer/timer_interrupt.c b/src/timer/timer_interrupt.c index 182ea9c..5af1d6c 100644 --- a/src/timer/timer_interrupt.c +++ b/src/timer/timer_interrupt.c @@ -1,6 +1,8 @@ #include #include +#include + struct Timer timers[3] = { { NULL, 0 }, { NULL, 0 }, { NULL, 0 } }; /* @@ -9,7 +11,6 @@ struct Timer timers[3] = { { NULL, 0 }, { NULL, 0 }, { NULL, 0 } }; */ void timer_interrupt(int timer) { - // Getting the timer address. struct mod_tmu *tmu; timer_get(timer, &tmu, NULL); diff --git a/src/timer/timer_stop.c b/src/timer/timer_stop.c index ab58f1e..1c77d5a 100644 --- a/src/timer/timer_stop.c +++ b/src/timer/timer_stop.c @@ -1,6 +1,8 @@ #include #include +#include + /* timer_stop() Stops the given timer. This function may be called even if the timer is