From 34dd27d7a3198468553e2176f3cc428cab186d92 Mon Sep 17 00:00:00 2001 From: lephe Date: Thu, 14 Jul 2016 21:10:51 +0200 Subject: [PATCH] Major bopti update (one of the last, I hope). Added comparison with ML as fifth application (hidden). --- Makefile | 160 +++++++++++- TODO | 14 + demo/gintdemo.c | 408 ++++++++++++++++++++++-------- demo/resources/bitmap_opt.bmp | Bin 2810 -> 2810 bytes demo/resources/screen.bmp | Bin 0 -> 32906 bytes gintdemo.g1a | Bin 0 -> 24444 bytes include/7305.h | 4 +- include/display.h | 42 +++ include/gray.h | 10 + include/setjmp.h | 5 - include/stdlib.h | 6 +- include/string.h | 8 - info | 16 -- libc.a | Bin 1770 -> 2500 bytes libgint.a | Bin 30732 -> 58406 bytes src/bopti/bopti_internals.c | 211 ++++++++------- src/bopti/bopti_internals.h | 79 ++++-- src/bopti/dimage.c | 40 ++- src/bopti/gimage.c | 41 ++- src/core/crt0.c | 4 +- src/core/gint.c | 5 + src/core/gint_callback.c | 2 + src/display/dclear_area.c | 2 +- src/display/display_internals.h | 38 --- src/display/dline.c | 2 +- src/display/dreverse_area.c | 2 +- src/display/getMasks.c | 5 +- src/gray/gray_engine.c | 21 +- src/keyboard/keyboard_internals.h | 2 +- src/keyboard/keyboard_interrupt.c | 3 +- src/tales/gtext.c | 14 + src/tales/tales_configuration.c | 2 +- src/timer/timer_interrupt.c | 3 +- src/timer/timer_stop.c | 2 + 34 files changed, 808 insertions(+), 343 deletions(-) create mode 100644 demo/resources/screen.bmp create mode 100644 gintdemo.g1a delete mode 100644 info create mode 100644 src/tales/gtext.c 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 66fe7226214989872cf70e3ec0f55d8a21608ce7..dd8d1230bc3e54e185fee97df6ce19b30d414975 100644 GIT binary patch delta 223 zcmew*`b%^H)8vOtqLT$!*npUS@;V^fo`Z8TAG77;!%QBN&ob&x+|V*P9Vq1wR5Fu8 zbn*%&X`m9G$rD-3COfmhl}uz8om>Dm1!NKob58!o8aVkdD-p_6fR?jOUcjzCnT1_t z@?3UKpmEYr2TYv6#>M~!lMeu$u%4Z5@&s14$q$%0CzmlwOy=VRx|YLx@&!gMkZTh- K%{FfEVgvwE`9(DV delta 320 zcmZusJxfC|6n(jAVgnBXfk2@0KoA7MNe~1lK`0hn1t+0@z`<2$p^HxM_JFJYgy-hw z?dP!MSFk=m{Nr=8!@9Z zq<+99?ep6q*CoDt4i^;o&T|v+u06Kp=Fxav6a{Wng4(M1HsDoxsNPV%oNQ2CHu}^% zooQ;@R(LXNAm|I_@HOt9qbuSgeX7YjSiVjuP(XYpP4xeh!j jxrrExPi;KL(z)Yl3-k2T6=&3!e$ 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 #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 29ad94c7daa6a3be0a18e08e6ab6e2d3a408d3f4..587b56ed54bc5700434dc6acb1a7b2aa76b95c85 100644 GIT binary patch delta 509 zcmaFGdqjAGG`od~iJ^t5$wVbh-VY263_#4B!N9vI*C6lLb6$LFTzCKpudC8G)f6+(o#^bMe<2tsK?6Elb_4L44SV=~q^ zw1im$rs2{?3JQh>20-0#(#*s}LBYbnV&YmI#ut-=n14(@#?mSPa{vR>DU(+->P}w3 z>cPbDV)83iWk#9Fd~E7K(vC@dvM-wekQK+K#>BX3avPgEs{t^O3MOx2Q}Se70AvaQ zF$^$*82ZNWKp@I><^~2p*9q1DwK6l9fQ`~%;9y{#?8Wk%uLfv5BLmRA;Lw?z&05RE uPy=+M5);D)p!3ujK_tkL{2&3KD;XIlx3a0TF&qIJ1a_quBgjk)R{{X9Om0O0 delta 252 zcmX>i{EByiG`qQ(nTdgg@kAv}-YNzL1|Vko1i}*|l%$GNOR{nc^osTJ^%X$C(8LU? zd@~ng9FuWzNl|8Ax?VD-JW#EHfdLX}W@4hCU}Y_UWAX=9bs#Cg nsm27P9N5$tnI^|`s++JoNrk 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 NM-KS;C?m#M{|^kQu=M}{ literal 30732 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 Vm%1d)jT##`#RK{UH~~Dr{|Bbgr1Ss) 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