Major bopti update (one of the last, I hope). Added comparison with ML as fifth application (hidden).

This commit is contained in:
lephe 2016-07-14 21:10:51 +02:00
parent d122624c56
commit 34dd27d7a3
34 changed files with 808 additions and 343 deletions

160
Makefile
View file

@ -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: # C source file template:
# $1 module name # $1 module name
# $2 file base name # $2 filename
define rule-c-source define rule-c-source
build/$1_$2.c.o: src/$1/$2.c build/$1_$2.o: src/$1/$2 $(mod-$1-dep)
$(cc) $(cflags) -c $$< -o $$@ $(cc) -c $$< -o $$@ $(cflags) -I src/$1 -O2
endef 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

14
TODO
View file

@ -12,6 +12,7 @@
@ vram overflow @ vram overflow
@ keyboard test threading interface @ keyboard test threading interface
+ gint vs. ML with 248x124 at (-60, -28)
+ use alloca() for tales + use alloca() for tales
+ call exit handlers + call exit handlers
+ compute frequencies + compute frequencies
@ -26,6 +27,7 @@
+ bitmap parts + bitmap parts
+ bitmap clipping + bitmap clipping
- install critical failure handler to prevent failing resets
- write and test gray engine - write and test gray engine
- full rtc driver (time) - full rtc driver (time)
- callbacks and complete user API - callbacks and complete user API
@ -34,3 +36,15 @@
~ exhaustive save for setjmp() ~ exhaustive save for setjmp()
~ registers that need to be saved when configuring gint ~ registers that need to be saved when configuring gint
~ possible bug when -O2 __attribute__((interrupt_handler)) ~ 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

View file

@ -10,15 +10,14 @@
#include <stdint.h> #include <stdint.h>
#include <7305.h> #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) 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) 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; ch[digits] = 0;
print(ch, x, y); 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); 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) while(1)
{ {
multigetkey(keys, 4, 0); multigetkey(keys, 4, 0);
if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break; 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)) #define hexa(h) ('0' + (h) + 39 * ((h) > 9))
@ -141,109 +160,73 @@ void keyboard_test(void)
timer_stop(TIMER_USER); 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() bitmap_test()
Displays various bitmaps to ensure bopti is working correctly. Displays various bitmaps to ensure bopti is working correctly.
*/ */
void bitmap_test(void) void bitmap_test(void)
{ {
extern Image binary_resources_bitmap_opt_start; extern Image res_bitmap_opt_start;
extern Image binary_resources_symbol_start; extern Image res_symbol_start;
extern Image binary_resources_symbol2_start; extern Image res_symbol2_start;
extern Image binary_resources_sprites_start; extern Image res_sprites_start;
extern Image res_swords_start;
Image *opt = &binary_resources_bitmap_opt_start; Image *opt = &res_bitmap_opt_start;
Image *sprites = &binary_resources_sprites_start; Image *sybl = &res_symbol_start;
Image *sybl = &binary_resources_symbol_start; Image *sybl2 = &res_symbol2_start;
Image *sybl2 = &binary_resources_symbol2_start; Image *sprites = &res_sprites_start;
Image *swords = &res_swords_start;
// enum BlendingMode blend = Blend_Or;
uint32_t a32 = 0xffffffff; uint32_t a32 = 0xffffffff;
int black_bg = 0; int black_bg = 0, gray = 0;
int key; int key;
int x = 20, y = 10;
while(1) while(1)
{ {
if(gray)
{
gray_start();
gclear();
if(black_bg) greverse_area(0, 0, 127, 63);
gimage(opt, 0, 57);
gimage(sprites, x, y);
gimage(swords, x, y + 35);
gupdate();
}
else
{
gray_stop();
dclear(); dclear();
if(black_bg) dreverse_area(0, 0, 127, 63); if(black_bg) dreverse_area(0, 0, 127, 63);
dimage(opt, 0, 57); dimage(opt, 0, 57);
dimage(sprites, 2 & a32, 2);
dimage(sybl, 30 & a32, 40); dimage(sybl, 30 & a32, 40);
dimage(sybl2, 62 & a32, 40); dimage(sybl2, 62 & a32, 40);
dupdate(); dupdate();
}
key = getkey(); key = getkey();
if(key == KEY_EXIT) break; if(key == KEY_EXIT) break;
/* if(key == KEY_F1) gray = !gray;
if(key == KEY_F1) blend = Blend_Or; if(key == KEY_F2) a32 ^= 31;
if(key == KEY_F2) blend = Blend_And; if(key == KEY_F3) black_bg = !black_bg;
if(key == KEY_F3) blend = Blend_Invert;
*/
if(key == KEY_F4) black_bg = !black_bg; if(key == KEY_UP) y--;
if(key == KEY_F5) a32 ^= 31; if(key == KEY_DOWN) y++;
if(key == KEY_LEFT) x--;
if(key == KEY_RIGHT) x++;
} }
gray_stop();
return; return;
} }
@ -256,10 +239,10 @@ void bitmap_test(void)
void text_test(void) void text_test(void)
{ {
extern Font binary_resources_font_start; extern Font res_font_start;
Font *font = &binary_resources_font_start; Font *font = &res_font_start;
print_configure(font); text_configure(font);
dclear(); dclear();
@ -284,31 +267,89 @@ void text_test(void)
void gray_test(void) void gray_test(void)
{ {
extern Image binary_resources_illustration_start; extern Image res_illustration_start;
Image *illustration = &binary_resources_illustration_start; Image *illustration = &res_illustration_start;
int light, dark; int *v1, *v2;
int key;
gray_getDelays(&light, &dark); int delays[2]; // { light, dark }
int key, changed = 1, i;
int selected = 0;
gray_getDelays(delays, delays + 1);
gray_start(); gray_start();
while(1) while(1)
{ {
if(changed)
{
gray_setDelays(delays[0], delays[1]);
gclear(); gclear();
dimage(illustration, 0, 0);
gclear_area(64, 0, 127, 63);
// gupdate();
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_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); changed = 1;
if(key == KEY_F6) gray_setDelays(light, ++dark);
*/ 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(); gray_stop();
@ -322,6 +363,7 @@ void gray_test(void)
*/ */
int main_menu(void) int main_menu(void)
{ {
extern unsigned int bgint, egint;
const char *mpu_names[] = { const char *mpu_names[] = {
"MPU_Unkown", "MPU_Unkown",
"MPU_SH7337", "MPU_SH7337",
@ -358,11 +400,158 @@ int main_menu(void)
if(key == KEY_2) return 2; if(key == KEY_2) return 2;
if(key == KEY_3) return 3; if(key == KEY_3) return 3;
if(key == KEY_4) return 4; if(key == KEY_4) return 4;
if(key == KEY_5) return 5;
} }
return 0; 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<end_y ; i++)
{
if(begin_x < end_x)
{
line = bmp[i*(real_width>>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<end_x ; j++)
{
line = bmp[i*(real_width>>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<<real_width-width;
line <<= shift;
if(begin_x < end_x || bool1) screen[end_x] |= *p;
if(bool2) screen[end_x+1] |= *(p+1);
screen += 16;
}
}
#include <../src/timer/timer_internals.h>
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() main()
Handles application calls. Handles application calls.
@ -371,10 +560,10 @@ int main_menu(void)
*/ */
int main(void) int main(void)
{ {
extern Font binary_resources_font_start; extern Font res_font_start;
Font *font = &binary_resources_font_start; Font *font = &res_font_start;
print_configure(font); text_configure(font);
int app; int app;
@ -387,6 +576,7 @@ int main(void)
if(app == 2) bitmap_test(); if(app == 2) bitmap_test();
if(app == 3) text_test(); if(app == 3) text_test();
if(app == 4) gray_test(); if(app == 4) gray_test();
if(app == 5) debug();
} }
return 0; return 0;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
demo/resources/screen.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
gintdemo.g1a Normal file

Binary file not shown.

View file

@ -62,7 +62,7 @@ struct _st_rtc
gap(1); gap(1);
union { union {
unsigned char; unsigned char BYTE;
struct { struct {
unsigned :2; unsigned :2;
unsigned TENS :2; unsigned TENS :2;
@ -208,7 +208,7 @@ struct _st_rtc
struct { struct {
unsigned ENB :1; unsigned ENB :1;
unsigned :7; unsigned :7;
} };
} RCR3; } RCR3;
} __attribute__((packed)); } __attribute__((packed));

View file

@ -14,6 +14,7 @@
// Heading declarations. // Heading declarations.
//--- //---
#include <stdint.h>
#include <tales.h> #include <tales.h>
enum Color 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 #endif // _DISPLAY_H

View file

@ -60,6 +60,16 @@ void gray_getDelays(int *light, int *dark);
Finding values that give proper grays is quite the hard part of the 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 gray engine. Usual values are about 1000, with light being between 75
and 90% of dark. 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); void gray_setDelays(int light, int dark);

View file

@ -14,17 +14,12 @@ typedef unsigned int jmp_buf[16];
/* /*
setjmp() setjmp()
Configures a jump by saving data to the given jump buffer. Configures a jump by saving data to the given jump buffer.
@arg env Empty jump buffer.
*/ */
int setjmp(jmp_buf env); int setjmp(jmp_buf env);
/* /*
longjmp() longjmp()
Performs a long jump. 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); void longjmp(jmp_buf env, int value);

View file

@ -34,15 +34,15 @@ void exit(int status);
/* /*
malloc() 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. Returns NULL on error.
*/ */
void *malloc(size_t size); void *malloc(size_t size);
/* /*
calloc() calloc()
Allocs 'n' elements of size 'size' and wipes the memory area. Returns Allocates 'n' elements of size 'size' and wipes the memory area.
NULL on error. Returns NULL on error.
*/ */
void *calloc(size_t n, size_t size); void *calloc(size_t n, size_t size);

View file

@ -12,20 +12,12 @@
Copies a memory area. The two areas must not overlap (if they do, use Copies a memory area. The two areas must not overlap (if they do, use
memmove()). A smart copy is performed when possible. To enhance memmove()). A smart copy is performed when possible. To enhance
performance, make sure than destination and source are both 4-aligned. 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); void *memcpy(void *destination, const void *source, size_t byte_number);
/* /*
memset() memset()
Sets the contents of a memory area. A smart copy is performed. 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); void *memset(void *destination, int byte, size_t byte_number);

16
info
View file

@ -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 %

BIN
libc.a

Binary file not shown.

BIN
libgint.a

Binary file not shown.

View file

@ -1,18 +1,22 @@
#include <bopti_internals.h> #include <bopti_internals.h>
// Monochrome video ram, light and dark buffers (in this order).
int *vram, *v1, *v2;
/* /*
bopti_op() bopti_op()
Operates on a vram long. The operator will often not contain 32 bits of 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 image information. Since neutral bits are not the same for all
operations, the op_mask argument indicates which bits should be used operations, a mask is used to indicate which bits should be used for
for the operation. Which operation has to be done is determined by the the operation. This mask is taken for the image's rectangle masks (see
channel setting. 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: case Channel_Mono:
vram[offset] |= operator; vram[offset] |= operator;
@ -26,11 +30,11 @@ static void bopti_op_mono(int offset, uint32_t operator, uint32_t op_mask)
break; 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: case Channel_Mono:
v1[offset] |= operator; 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 because bopti_grid() will perform a 32-bit shift when x is a multiple
of 32, which is undefined behavior. of 32, which is undefined behavior.
*/ */
static void bopti_grid_a32(const uint32_t *layer, int x, int y, void bopti_grid_a32(const uint32_t *layer, int column_count, int height,
int column_count) 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 vram_offset = vram_column_offset;
int column, row; int column, row;
for(column = 0; column < column_count; column++) 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); (*c->op)(vram_offset, layer[row], c);
layer++;
vram_offset += 4; vram_offset += 4;
} }
vram_column_offset++; vram_column_offset++;
vram_offset = 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(!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; return;
} }
const uint32_t *p1, *p2; const uint32_t *p1, *p2;
uint32_t l1, l2; uint32_t l1, l2, operator;
int right_column, line; 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 vram_offset = vram_column_offset;
int shift1 = 32 - (x & 31); int shift1 = 32 - (c->x & 31);
int shift2 = (x & 31); int shift2 = (c->x & 31);
uint32_t operator, and_mask; // Initializing two pointers. They will read two adjacent columns at
uint32_t and_mask_0 = 0xffffffff >> shift2; // the same time (p2 is column ahead of p1). Since the columns are
uint32_t and_mask_1 = 0xffffffff << shift1; // written one after another, incrementing them will suffice when
// reaching the end of two columns, to move them to the next ones.
// Initializing two pointers. Since the columns are written one after
// another, they will be updated directly to parse the whole grid.
p1 = layer - height; p1 = layer - height;
p2 = layer; p2 = layer;
// Drawing vram longwords, using pairs of columns. // We don't want to write the first vram column when x is negative.
for(right_column = 0; right_column <= column_count; right_column++) if(c->x < 0) p1 += height, p2 += height;
{ right_column = (c->x < 0);
and_mask = 0xffffffff;
if(right_column == 0) and_mask &= and_mask_0;
if(right_column == column_count) and_mask &= and_mask_1;
for(line = 0; line < height; line++) // Drawing vram longwords, using pairs of columns.
while(right_column <= column_count)
{ {
l1 = (right_column > 0) ? (*p1) : (0); for(line = c->top; line < c->bottom; line++)
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); operator = (l1 << shift1) | (l2 >> shift2);
(*op)(vram_offset, operator, and_mask); (*c->op)(vram_offset, operator, c);
vram_offset += 4; vram_offset += 4;
} }
p1 += height;
p2 += height;
vram_column_offset++; vram_column_offset++;
vram_offset = 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 is read and updated so that it points to the next line at the end of
the operation. 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; uint32_t operator = **data;
*data += 1; *data += 1;
return operator; 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); uint32_t operator = *((uint16_t *)*data);
*data += 2; *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; 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).
*/ */
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) = 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 row;
// We *have* shift >= 0 because of this function's 'no overlap' // We *have* shift >= 0 because of this function's 'no overlap'
// requirement. // requirement.
int shift_base = (width > 8) ? 16 : 24; int shift = (32 - (size << 3)) - (c->x & 31);
int shift = shift_base - (x & 31); int vram_offset = (c->y << 2) + (c->x >> 5);
uint32_t and_mask = (0xffffffff << (32 - width)) >> (x & 31);
uint32_t operator; 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 = (*get)(&end);
operator <<= shift; operator <<= shift;
(*op)(vram_offset, operator, and_mask); (*c->op)(vram_offset, operator, c);
vram_offset += 4; 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) = 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 row;
int shift_base = (width > 8) ? 16 : 24; int shift_base = (32 - (size << 3));
int shift1 = (x & 31) - shift_base; int shift1 = (c->x & 31) - shift_base;
int shift2 = shift_base + 32 - (x & 31); int shift2 = shift_base + 32 - (c-> x & 31);
uint32_t and_mask_0 = 0xffffffff >> (x & 31); // Skipping c->top lines (because get() function only allows sequential
uint32_t and_mask_1 = 0xffffffff << (64 - width - (x & 31)); // access).
end += c->top * size;
uint32_t row_data, operator; for(row = c->top; row < c->bottom; row++)
for(row = 0; row < height; row++)
{ {
row_data = (*get)(&end); row_data = (*get)(&end);
operator = row_data >> shift1; operator = row_data >> shift1;
(*op)(vram_offset, operator, and_mask_0); (*c->op)(vram_offset, operator, c);
operator = row_data << shift2; operator = row_data << shift2;
(*op)(vram_offset + 1, operator, and_mask_1); (*c->op)(vram_offset + 1, operator, c);
vram_offset += 4; vram_offset += 4;
} }
@ -237,41 +236,63 @@ static void bopti_end(const unsigned char *end, int x, int y, int width)
bopti() bopti()
Draws a layer in the video ram. Draws a layer in the video ram.
*/ */
static void bopti(const unsigned char *layer, int x, int y, int columns, void bopti(const unsigned char *layer, struct Structure *s, struct Command *c)
int end_size)
{ {
const unsigned char *end = layer + ((columns * height) << 2); const unsigned char *grid, *end;
int end_x = x + (columns << 5); int grid_columns, has_end;
bopti_grid((const uint32_t *)layer, x, y, columns); // Skipping columns at the beginning.
if(end_size) bopti_end(end, end_x, y, end_size); 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() getStructure()
Determines the image size and data pointer. Determines the image size and data pointer.
*/ */
static void getStructure(struct Image *img, int *width, int *height, void getStructure(struct Image *img, struct Structure *s)
int *layer_size, const unsigned char **data, int *columns,
int *end_size)
{ {
int column_count, end, end_bytes, layer; int column_count, end, end_bytes, layer;
// Large images. // Large images.
if(!img->width && !img->height) if(!img->width && !img->height)
{ {
if(width) *width = (img->data[0] << 8) | img->data[1]; s->width = (img->data[0] << 8) | img->data[1];
if(height) *height = (img->data[2] << 8) | img->data[3]; s->height = (img->data[2] << 8) | img->data[3];
if(data) *data = img->data + 4; s->data = img->data + 4;
column_count = (*width + 31) >> 5; column_count = (s->width + 31) >> 5;
end = end_bytes = 0; end = 0;
end_bytes = 0;
} }
else else
{ {
if(width) *width = img->width; s->width = img->width;
if(height) *height = img->height; s->height = img->height;
if(data) *data = img->data; s->data = img->data;
column_count = img->width >> 5; column_count = img->width >> 5;
end = img->width & 31; end = img->width & 31;
@ -280,13 +301,21 @@ static void getStructure(struct Image *img, int *width, int *height,
end <= 8 ? 1 : end <= 8 ? 1 :
end <= 16 ? 2 : end <= 16 ? 2 :
4; 4;
if(end_bytes == 4)
{
column_count++;
end = 0;
end_bytes = 0;
}
} }
// The layer size must be rounded to a multiple of 4. // The layer size must be rounded to a multiple of 4.
layer = img->height * ((column_count << 2) + end_bytes); layer = img->height * ((column_count << 2) + end_bytes);
if(layer & 3) layer += 4 - (layer & 3); if(layer & 3) layer += 4 - (layer & 3);
if(columns) *columns = column_count; s->columns = column_count;
if(end_size) *end_size = end; s->end_bytes = end_bytes;
if(layer_size) *layer_size = layer; s->end_size = end;
s->layer_size = layer;
} }

View file

@ -18,6 +18,7 @@
#define _BOPTI_INTERNALS_H 1 #define _BOPTI_INTERNALS_H 1
#include <stdint.h> #include <stdint.h>
#include <display.h>
/* /*
enum Channel enum Channel
@ -49,15 +50,43 @@ enum Format
Channel_DarkAlpha 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 struct Structure
// on by every function from the module, but this would be heavy and useless. Describes an image's structure.
// Using global variables is not really a proper solution but it does simplify */
// code much. 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 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() bopti_op()
Operates on a vram long. The operator will often not contain 32 bits of 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 image information. Since neutral bits are not the same for all
operations, the op_mask argument indicates which bits should be used operations, a mask is used to indicate which bits should be used for
for the operation. Which operation has to be done is determined by the the operation. This mask is taken for the image's rectangle masks (see
channel setting. 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_mono(int offset, uint32_t operator, struct Command *c);
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);
/* /*
bopti_grid() -- general form 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, 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 because bopti_grid() will perform a 32-bit shift when x is a multiple
of 32, which is undefined behavior. 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_a32(const uint32_t *layer, int columns, int height,
void bopti_grid(const uint32_t *layer, int x, int y, int column_count); struct Command *c);
void bopti_grid(const uint32_t *layer, int columns, int height,
struct Command *c);
/* /*
bopti_end_get() bopti_end_get()
Returns an operator for the end of a line, whose width is lower than 32 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 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; 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_nover(const unsigned char *end, int size, struct Command *c);
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);
/* /*
bopti() bopti()
Draws a layer in the video ram. Draws a layer in the video ram.
*/ */
void bopti(const unsigned char *layer, int x, int y, int columns, void bopti(const unsigned char *layer, struct Structure *s, struct Command *c);
int end_size);
/* /*
getStructure() getStructure()
Determines the image size and data pointer. Determines the image size and data pointer.
*/ */
void getStructure(struct Image *img, int *width, int *height, int *layer_size, void getStructure(struct Image *img, struct Structure *structure);
const unsigned char **data, int *columns, int *end_size);
#endif // _BOPTI_INTERNALS_H #endif // _BOPTI_INTERNALS_H

View file

@ -7,17 +7,33 @@
*/ */
void dimage(struct Image *img, int x, int y) 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->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. struct Structure s;
getStructure(img, &width, &height, &layer_size, &data, &columns, &end); 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(); vram = display_getCurrentVRAM();
@ -26,9 +42,9 @@ void dimage(struct Image *img, int x, int y)
// Drawing every layer, in order of formats. // Drawing every layer, in order of formats.
if(format & 1) if(format & 1)
{ {
channel = (1 << i); command.channel = (1 << i);
bopti(data, x, y, columns, end); bopti(s.data, &s, &command);
data += layer_size; s.data += s.layer_size;
} }
format >>= 1; format >>= 1;

View file

@ -1,4 +1,5 @@
#include <bopti_internals.h> #include <bopti_internals.h>
#include <display.h>
#include <gray.h> #include <gray.h>
/* /*
@ -7,15 +8,31 @@
*/ */
void gimage(struct Image *img, int x, int y) 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; if(img->magic != 0xb7) return;
op = bopti_op_gray;
// 'height' refers to a static variable for this file. struct Structure s;
getStructure(img, &width, &height, &layer_size, &data, &columns, &end); 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(); v1 = gray_lightVRAM();
v2 = gray_darkVRAM(); v2 = gray_darkVRAM();
@ -25,9 +42,13 @@ void gimage(struct Image *img, int x, int y)
// Drawing every layer, in order of formats. // Drawing every layer, in order of formats.
if(format & 1) if(format & 1)
{ {
channel = (1 << i); // These members are modified by bopti()!
bopti(data, x, y, columns, end); command.x = x;
data += layer_size; command.y = y;
command.channel = (1 << i);
bopti(s.data, &s, &command);
s.data += s.layer_size;
} }
format >>= 1; format >>= 1;

View file

@ -53,8 +53,8 @@ int start(void)
__GLibAddinAplExecutionCheck(0, 1, 1); __GLibAddinAplExecutionCheck(0, 1, 1);
// Initializing everything. // Initializing everything.
init();
gint_init(); gint_init();
init();
@ -69,8 +69,8 @@ int start(void)
// Remember to flush and close opened streams. // Remember to flush and close opened streams.
// Un-initializing everything. // Un-initializing everything.
gint_quit();
fini(); fini();
gint_quit();
return exit_code; return exit_code;
} }

View file

@ -91,6 +91,11 @@ void gint_init(void)
unsigned int *ptr = &bgint; unsigned int *ptr = &bgint;
unsigned int *src = &gint_data; 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. // Loading the interrupt handler into the memory.
while(ptr < &egint) *ptr++ = *src++; while(ptr < &egint) *ptr++ = *src++;

View file

@ -1,6 +1,8 @@
#include <gint.h> #include <gint.h>
#include <mpu.h> #include <mpu.h>
#include <stddef.h>
static void (*rtc_callback)(void) = NULL; static void (*rtc_callback)(void) = NULL;
/* /*

View file

@ -8,7 +8,7 @@
*/ */
void dclear_area(int x1, int y1, int x2, int y2) void dclear_area(int x1, int y1, int x2, int y2)
{ {
unsigned int masks[4]; uint32_t masks[4];
adjustRectangle(&x1, &y1, &x2, &y2); adjustRectangle(&x1, &y1, &x2, &y2);
getMasks(x1, x2, masks); getMasks(x1, x2, masks);

View file

@ -4,25 +4,6 @@
// //
// Handles vram manipulation and drawing. // 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 #ifndef _DISPLAY_INTERNALS_H
@ -30,23 +11,4 @@
extern int *vram; 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 #endif // _DISPLAY_INTERNALS_H

View file

@ -13,7 +13,7 @@
static void dhline(int x1, int x2, int y, enum Color color) 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 offset = y << 2;
int i; int i;

View file

@ -9,7 +9,7 @@
*/ */
void dreverse_area(int x1, int y1, int x2, int y2) void dreverse_area(int x1, int y1, int x2, int y2)
{ {
unsigned int masks[4]; uint32_t masks[4];
adjustRectangle(&x1, &y1, &x2, &y2); adjustRectangle(&x1, &y1, &x2, &y2);
getMasks(x1, x2, masks); getMasks(x1, x2, masks);

View file

@ -1,13 +1,12 @@
#include <display_internals.h> #include <display.h>
/* /*
getMasks() getMasks()
Computes the rectangle masks needed to affect pixels located between x1 Computes the rectangle masks needed to affect pixels located between x1
and x2 (both included). The four masks are stored in the third argument and x2 (both included). The four masks are stored in the third argument
(seen as an array). (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. // Indexes of the first and last longs that are non-blank.
int l1 = x1 >> 5; int l1 = x1 >> 5;

View file

@ -11,7 +11,7 @@
#include <timer.h> #include <timer.h>
static int internal_vrams[3][256]; static int internal_vrams[3][256];
const void *vrams[4]; static const void *vrams[4];
static int current = 0; static int current = 0;
static int delays[2]; static int delays[2];
@ -33,7 +33,10 @@ static int runs = 0;
*/ */
void gray_start(void) void gray_start(void)
{ {
if(runs) return;
timer_start(TIMER_GRAY, delays[0], GRAY_PRESCALER, gray_interrupt, 0); timer_start(TIMER_GRAY, delays[0], GRAY_PRESCALER, gray_interrupt, 0);
current &= 1;
runs = 1; runs = 1;
} }
@ -44,6 +47,8 @@ void gray_start(void)
*/ */
void gray_stop(void) void gray_stop(void)
{ {
if(!runs) return;
timer_stop(TIMER_GRAY); timer_stop(TIMER_GRAY);
runs = 0; runs = 0;
@ -79,18 +84,18 @@ inline int gray_runs(void)
gray_lightVRAM() gray_lightVRAM()
Returns the module's gray vram address. 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() gray_lightVRAM()
Returns the module's dark vram address. 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) void gray_interrupt(void)
{ {
timer_reload(TIMER_GRAY, delays[current & 1]); timer_reload(TIMER_GRAY, delays[(~current) & 1]);
screen_display(vrams[current]); screen_display(vrams[current]);
current ^= 1; current ^= 1;
} }
@ -146,6 +151,6 @@ void gray_init(void)
vrams[2] = (const void *)internal_vrams[1]; vrams[2] = (const void *)internal_vrams[1];
vrams[3] = (const void *)internal_vrams[2]; vrams[3] = (const void *)internal_vrams[2];
delays[0] = 900; delays[0] = 993;
delays[1] = 1000; delays[1] = 1609;
} }

View file

@ -5,7 +5,7 @@
// Keyboard variables. // Keyboard variables.
extern volatile unsigned char keyboard_state[10]; extern volatile unsigned char keyboard_state[10];
extern volatile int interrupt_flag = 0; extern volatile int interrupt_flag;
// Key statistics. // Key statistics.
extern int repeat_first, repeat_next; extern int repeat_first, repeat_next;

View file

@ -42,8 +42,7 @@ void keyboard_interrupt(void)
*/ */
void keyboard_init(void) void keyboard_init(void)
{ {
timer_start(TIMER_KEYBOARD, 1700, TIMER_Po_256, keyboard_interrupt, timer_start(TIMER_KEYBOARD, 1700, TIMER_Po_256, keyboard_interrupt, 0);
0);
} }
/* /*

14
src/tales/gtext.c Normal file
View file

@ -0,0 +1,14 @@
#include <tales.h>
#include <gray.h>
/*
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);
}

View file

@ -5,7 +5,7 @@
text_configure() text_configure()
Sets the font and mode to use for the following print operations. 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; font = next_font;
} }

View file

@ -1,6 +1,8 @@
#include <timer.h> #include <timer.h>
#include <timer_internals.h> #include <timer_internals.h>
#include <stddef.h>
struct Timer timers[3] = { { NULL, 0 }, { NULL, 0 }, { NULL, 0 } }; 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) void timer_interrupt(int timer)
{ {
// Getting the timer address.
struct mod_tmu *tmu; struct mod_tmu *tmu;
timer_get(timer, &tmu, NULL); timer_get(timer, &tmu, NULL);

View file

@ -1,6 +1,8 @@
#include <timer.h> #include <timer.h>
#include <timer_internals.h> #include <timer_internals.h>
#include <stddef.h>
/* /*
timer_stop() timer_stop()
Stops the given timer. This function may be called even if the timer is Stops the given timer. This function may be called even if the timer is