forked from Lephenixnoir/gint
Initial commit. Includes interrupt handler, drivers for keyboard and screen, and parts of the drawing library.
This commit is contained in:
commit
0a7f22d4c1
|
@ -0,0 +1,13 @@
|
|||
# Sources for old gint versions.
|
||||
gint.old.1/**
|
||||
gint.old.2/**
|
||||
|
||||
# Build directory
|
||||
build/**
|
||||
|
||||
# Sublime Text files
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
|
||||
# Object files.
|
||||
*.o
|
|
@ -0,0 +1,119 @@
|
|||
#
|
||||
# fx-9860g lib Makefile.
|
||||
#
|
||||
|
||||
.PHONY: all clean fclean re install
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Variables and configuration.
|
||||
#
|
||||
|
||||
# Tools
|
||||
cc = sh3eb-elf-gcc
|
||||
as = sh3eb-elf-as
|
||||
ar = sh3eb-elf-ar
|
||||
ob = sh3eb-elf-objcopy
|
||||
wr = g1a-wrapper
|
||||
|
||||
# Output files
|
||||
g1a = addin.g1a
|
||||
bin = build/addin.bin
|
||||
elf = build/addin.elf
|
||||
|
||||
# Command-line options
|
||||
cflags = -m3 -mb -nostdlib -ffreestanding \
|
||||
-W -Wall -pedantic -std=c11 \
|
||||
-I . -isystem include
|
||||
lib = -lgcc -L. -lgint -lc
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Source and object files.
|
||||
#
|
||||
|
||||
# Gint library.
|
||||
src-lib = crt0.c syscalls.s \
|
||||
gint.c gint_vbr.s gint_7705.c gint_7305.c \
|
||||
mpu.c keyboard.c screen.c display.c gray.c timer.c
|
||||
hea-lib = 7305.h 7705.h gint.h \
|
||||
stdlib.h \
|
||||
mpu.h keyboard.h screen.h display.h gray.h timer.h
|
||||
obj-lib = $(addprefix build/, $(addsuffix .o, $(src-lib)))
|
||||
hdr-lib = $(addprefix include/, $(hea-lib))
|
||||
|
||||
# Standard library.
|
||||
src-std = setjmp.s string.c
|
||||
hea-std = setjmp.h string.h
|
||||
obj-std = $(addprefix build/, $(addsuffix .o, $(src-std)))
|
||||
hdr-std = $(addprefix include/, $(hea-std))
|
||||
|
||||
# Test application.
|
||||
src-app = addin.c
|
||||
res-app = icon.o swords.o sprites.o symbol.o symbol2.o
|
||||
|
||||
|
||||
#
|
||||
# Building rules.
|
||||
#
|
||||
|
||||
all: build libgint.a libc.a addin.g1a
|
||||
|
||||
build:
|
||||
mkdir -p build
|
||||
|
||||
libgint.a: $(obj-lib)
|
||||
$(ar) rcs libgint.a $(obj-lib)
|
||||
@ echo "\033[32;1mLibrary file size: "`stat -c %s libgint.a` \
|
||||
"bytes\033[0m"
|
||||
|
||||
libc.a: $(obj-std)
|
||||
$(ar) rcs libc.a $(obj-std)
|
||||
@ echo "\033[32;1mStandard file size: "`stat -c %s libc.a` \
|
||||
"bytes\033[0m"
|
||||
|
||||
addin.g1a: libgint.a $(src-app) $(res-app)
|
||||
$(cc) $(src-app) $(res-app) -T addin.ld -o $(elf) $(cflags) $(lib)
|
||||
$(ob) -R .comment -R .bss -O binary $(elf) $(bin)
|
||||
$(wr) $(bin) -o addin.g1a -i icon.bmp
|
||||
@ echo "\033[32;1mBinary file size: "`stat -c %s $(bin)`" bytes\033[0m"
|
||||
# @ sh3eb-elf-objdump -h build/addin.elf
|
||||
|
||||
build/%.c.o: src/%.c $(hdr-lib) $(hdr-std)
|
||||
$(cc) $(cflags) -O2 -c $< -o $@
|
||||
build/%.s.o: src/%.s
|
||||
$(as) -c $^ -o $@
|
||||
|
||||
build/gint.c.o: src/gint.c $(hdr-lib) $(hdr-std)
|
||||
$(cc) $(cflags) -c $< -o $@
|
||||
|
||||
%.c.o: %.c $(hdr-lib) $(hdr-std)
|
||||
$(cc) $(cflags) -c $< -o $@
|
||||
%.s.o: %.s
|
||||
$(as) -c $^ -o $@
|
||||
%.o: %.bmp
|
||||
fxconv $^
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Cleaning rules.
|
||||
#
|
||||
|
||||
clean:
|
||||
@ rm -f $(obj-lib) $(obj-std) $(obj-app) $(bin) $(elf)
|
||||
fclean: clean
|
||||
@ rm -f build/*
|
||||
@ rm -f addin.g1a libc.a libgint.a
|
||||
re: fclean all
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Installing shorthand.
|
||||
#
|
||||
|
||||
install:
|
||||
usb-connector SEND addin.g1a addin.g1a fls0
|
|
@ -0,0 +1,7 @@
|
|||
- screen, display
|
||||
- timer
|
||||
- gray engine
|
||||
- full rtc driver (time)
|
||||
|
||||
_ 7305.h
|
||||
_ libc
|
|
@ -0,0 +1,311 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <mpu.h>
|
||||
#include <keyboard.h>
|
||||
#include <display.h>
|
||||
|
||||
extern void __Print(const char *msg, int x, int y);
|
||||
extern unsigned int gint_vbr, bgint, egint, gint_data;
|
||||
#define print __Print
|
||||
|
||||
void print_hex(unsigned int n, int x, int y)
|
||||
{
|
||||
char ch[11] = "0x";
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
ch[9 - i] = (n & 0xf) + '0' + 39 * ((n & 0xf) > 9);
|
||||
n >>= 4;
|
||||
}
|
||||
ch[10] = 0;
|
||||
print(ch, x, y);
|
||||
}
|
||||
void print_bin(unsigned char n, int x, int y)
|
||||
{
|
||||
char ch[9];
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 8;i ++)
|
||||
{
|
||||
ch[7 - i] = (n & 1) + '0';
|
||||
n >>= 1;
|
||||
}
|
||||
ch[8] = 0;
|
||||
print(ch, x, y);
|
||||
}
|
||||
|
||||
void print_hexa(unsigned int n, int digits, int x, int y)
|
||||
{
|
||||
char ch[20];
|
||||
int i;
|
||||
|
||||
for(i = digits - 1; i >= 0; i--)
|
||||
{
|
||||
ch[i] = (n & 0xf) + '0' + 39 * ((n & 0xf) > 9);
|
||||
n >>= 4;
|
||||
}
|
||||
|
||||
ch[digits] = 0;
|
||||
print(ch, x, y);
|
||||
}
|
||||
|
||||
// Don't forget to enable key state debugging in the interrupt handler.
|
||||
void keyboard_test(void)
|
||||
{
|
||||
const char *names[] = {
|
||||
"MPU_Unkown",
|
||||
"MPU_SH7337",
|
||||
"MPU_SH7355",
|
||||
"MPU_SH7305",
|
||||
"MPU_SH7724",
|
||||
"Error"
|
||||
};
|
||||
int x = 0;
|
||||
char str[3];
|
||||
int keys[4] = { 0 };
|
||||
int i;
|
||||
|
||||
print(names[MPU_CURRENT < 5 ? MPU_CURRENT : 5], 0, 0);
|
||||
|
||||
print("gint size:", 0, 1);
|
||||
print_hex(&egint - &bgint, 11, 1);
|
||||
|
||||
while(1)
|
||||
{
|
||||
multigetkey(keys, 4, 0);
|
||||
|
||||
if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break;
|
||||
|
||||
#define hexa(h) ('0' + (h) + 39 * ((h) > 9))
|
||||
|
||||
x = (x + 1) & 15;
|
||||
str[0] = hexa(x);
|
||||
str[1] = 0;
|
||||
print(str, 20, 0);
|
||||
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
str[0] = hexa((keys[i] >> 4) & 0x0f);
|
||||
str[1] = hexa(keys[i] & 0x0f);
|
||||
str[2] = 0;
|
||||
print(str, 19, i + 3);
|
||||
}
|
||||
|
||||
#undef hexa
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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 };
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
static const unsigned char icon[76] = {
|
||||
0, 0, 0, 0, 51, 156, 10, 68, 74, 82, 11, 68, 74, 82, 234, 196, 122, 82, 10,
|
||||
68, 75, 156, 10, 68, 0, 0, 0, 4, 0, 254, 0, 4, 0, 130, 124, 4, 0, 130, 68, 4,
|
||||
0, 2, 4, 4, 3, 238, 196, 4, 2, 170, 93, 252, 0, 254, 65, 252, 7, 40, 65, 252,
|
||||
5, 232, 65, 252, 7, 15, 193, 252, 0, 0, 1, 252, 127, 255, 255, 252 };
|
||||
|
||||
char *ML_vram_adress(void)
|
||||
{
|
||||
return display_getVRAM();
|
||||
}
|
||||
|
||||
void ML_bmp_or_cl(const unsigned char *bmp, int x, int y, int width, int height)
|
||||
{
|
||||
unsigned short line;
|
||||
char shift, *screen, *p;
|
||||
int i, j, real_width, begin_x, end_x, begin_y, end_y;
|
||||
char bool1=1, bool2=1, bool3;
|
||||
if(!bmp || x<1-width || x>127 || y<1-height || y>63 || height<1 || width<1) return;
|
||||
p = (char*)&line;
|
||||
real_width = (width-1>>3<<3)+8;
|
||||
if(y < 0) begin_y = -y;
|
||||
else begin_y = 0;
|
||||
if(y+height > 64) end_y = 64-y;
|
||||
else end_y = height;
|
||||
shift = 8-(x&7);
|
||||
if(x<0)
|
||||
{
|
||||
begin_x = -x>>3;
|
||||
if(shift != 8) bool1 = 0;
|
||||
} else begin_x = 0;
|
||||
if(x+real_width > 128) end_x = 15-(x>>3), bool2 = 0;
|
||||
else end_x = real_width-1>>3;
|
||||
bool3 = (end_x == real_width-1>>3);
|
||||
screen = ML_vram_adress()+(y+begin_y<<4)+(x>>3);
|
||||
|
||||
for(i=begin_y ; i<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 <stdint.h>
|
||||
#include <7305.h>
|
||||
|
||||
/*
|
||||
unsigned int exec(void (*f)(void))
|
||||
{
|
||||
int t, s, dt, ds;
|
||||
|
||||
t = (int)RTC.R64CNT;
|
||||
s = 10 * (RTC.RSECCNT.TENS) + RTC.RSECCNT.ONES;
|
||||
|
||||
(*f)();
|
||||
|
||||
dt = (int)RTC.R64CNT - t;
|
||||
ds = (10 * (RTC.RSECCNT.TENS) + RTC.RSECCNT.ONES) - s;
|
||||
if(dt < 0) ds--, dt += 64;
|
||||
|
||||
return (ds << 8) | dt;
|
||||
}
|
||||
|
||||
void btest_ml_icon(void)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 5000; i++)
|
||||
{
|
||||
ML_bmp_or_cl(icon, 0, 30, 30, 19);
|
||||
}
|
||||
}
|
||||
void btest_gint_icon(void)
|
||||
{
|
||||
extern Image binary_icon_start;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < 5000; i++)
|
||||
{
|
||||
dimage(&binary_icon_start, 0, 0, Blend_Or);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
extern Image binary_symbol_start;
|
||||
extern Image binary_symbol2_start;
|
||||
extern Image binary_icon_start;
|
||||
extern Image binary_sprites_start;
|
||||
extern Image binary_swords_start;
|
||||
|
||||
extern const void *vrams[4];
|
||||
|
||||
Image *sybl = &binary_symbol_start;
|
||||
Image *sybl2 = &binary_symbol2_start;
|
||||
|
||||
dclear();
|
||||
dreverse_area(0, 0, 127, 30);
|
||||
|
||||
dimage(sybl, 0, 0, Blend_Or);
|
||||
dimage(sybl, 20, 0, Blend_And);
|
||||
dimage(sybl, 40, 0, Blend_Or | Blend_And);
|
||||
dimage(sybl, 90, 0, Blend_Or | Blend_Invert);
|
||||
|
||||
dimage(sybl2, 0, 20, Blend_Or);
|
||||
dimage(sybl2, 20, 20, Blend_And);
|
||||
dimage(sybl2, 28, 20, Blend_And);
|
||||
dimage(sybl2, 40, 20, Blend_Or | Blend_And);
|
||||
dimage(sybl2, 90, 20, Blend_Or | Blend_Invert);
|
||||
|
||||
dimage(&binary_icon_start, 2, 35, Blend_Or);
|
||||
|
||||
dreverse_area(35, 31, 127, 63);
|
||||
dimage(&binary_sprites_start, 50, 31, Blend_And);
|
||||
|
||||
dupdate();
|
||||
/*
|
||||
do key = getkey();
|
||||
while(key != KEY_EXE && key != KEY_EXIT);
|
||||
if(key == KEY_EXIT) return 0;
|
||||
|
||||
print("h'sszz 64z=1s", 0, 0);
|
||||
print("ML", 14, 0);
|
||||
print("gint", 17, 0);
|
||||
print("---------------------", 0, 1);
|
||||
|
||||
print("30*19 icon", 0, 2);
|
||||
print(wait, 12, 2);
|
||||
print_hexa(exec(btest_ml_icon), 4, 12, 2);
|
||||
print(wait, 17, 2);
|
||||
print_hexa(exec(btest_gint_icon), 4, 17, 2);
|
||||
*/
|
||||
while(getkey() != KEY_EXE);
|
||||
|
||||
dclear();
|
||||
dimage(&binary_swords_start, 20, 20, Blend_Or);
|
||||
dupdate();
|
||||
|
||||
while(getkey() != KEY_EXE);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
This linker script links the object files when generating the ELF
|
||||
output. Note how symbols romdata, bbss, ebss, bdata and edata are used
|
||||
in the initialization routine (crt0.c) to initialize the application.
|
||||
|
||||
Two ram areas are specified. It happens, if I'm not wrong, that the
|
||||
"real ram" is accessed directly while the "common" ram is accessed
|
||||
through the mmu. The interrupt handler resides in "real ram" because it
|
||||
couldn't execute well in ram. While SH7335 and SH7355 had no problems,
|
||||
executing the interrupt handler in the common ram on SH7305-based new
|
||||
models caused trouble to the OS, apparently overwriting ram data.
|
||||
*/
|
||||
|
||||
OUTPUT_ARCH(sh3)
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
rom : o = 0x00300200, l = 512k
|
||||
ram : o = 0x08100000, l = 64k
|
||||
/* The "real ram" accessible length remains unknown because some parts
|
||||
are used by the system. At least 12k seem accessible. Use with care. */
|
||||
realram : o = 0x8800d000, l = 12k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/*
|
||||
ROM sections : binary code and read-only data.
|
||||
*/
|
||||
|
||||
.text : {
|
||||
/* Initialization code. */
|
||||
*(.pretext.entry)
|
||||
*(.pretext)
|
||||
|
||||
_bctors = . ;
|
||||
*(.ctors)
|
||||
_ectors = . ;
|
||||
_bdtors = . ;
|
||||
*(.dtors)
|
||||
_edtors = . ;
|
||||
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
} > rom
|
||||
|
||||
.rodata : {
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
|
||||
_romdata = ALIGN(4) ;
|
||||
} > rom
|
||||
|
||||
|
||||
|
||||
/*
|
||||
RAM sections : bss section and read/write data.
|
||||
The BSS section is meant to be stripped from the ELF file (to
|
||||
reduce the binary size) and initialized with zeros in the
|
||||
initialization routine, therefore its location is undefined.
|
||||
*/
|
||||
|
||||
.bss : {
|
||||
_bbss = . ;
|
||||
*(.bss)
|
||||
_ebss = . ;
|
||||
} > ram
|
||||
|
||||
.data : AT(_romdata) ALIGN(4) {
|
||||
_bdata = . ;
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
_edata = . ;
|
||||
} > ram
|
||||
|
||||
.cc : AT(_romdata + SIZEOF(.data)) ALIGN(4) {
|
||||
*(.eh_frame)
|
||||
*(.jcr)
|
||||
|
||||
_gint_data = _romdata + SIZEOF(.data) + SIZEOF(.cc) ;
|
||||
} > ram
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Real RAM : interrupt handler.
|
||||
*/
|
||||
|
||||
.gint_int : AT(_gint_data) ALIGN(4) {
|
||||
/* The vbr needs to be 0x100-aligned because of an ld issue. */
|
||||
. = ALIGN(0x100) ;
|
||||
_gint_vbr = . ;
|
||||
|
||||
_bgint = . ;
|
||||
|
||||
/* Interrupt handler. */
|
||||
. = _gint_vbr + 0x600 ;
|
||||
*(.gint.int.entry)
|
||||
*(.gint.int)
|
||||
|
||||
_egint = . ;
|
||||
} > realram
|
||||
}
|
|
@ -0,0 +1,914 @@
|
|||
#ifndef _7305_H
|
||||
#define _7305_H 1
|
||||
|
||||
/*
|
||||
Double-underscore prefixed structures (e.g. __st_rtc_counter) are used
|
||||
internally but are not meant to be used in user programs.
|
||||
|
||||
Underscore-prefixed names (e.g. _R64CNT) indicate write-only registers.
|
||||
*/
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#define gap(n) unsigned: n << 3
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Real-time clock.
|
||||
//---
|
||||
|
||||
struct _st_rtc
|
||||
{
|
||||
unsigned char const R64CNT;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TENS :3;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RSECCNT;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TENS :3;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RMINCNT;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :2;
|
||||
unsigned TENS :2;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RHRCNT;
|
||||
|
||||
gap(1);
|
||||
|
||||
// 0=Sunday, 1=Monday, ..., 6=Saturday, 7=Reserved (prohibited).
|
||||
unsigned char RWKCNT;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char;
|
||||
struct {
|
||||
unsigned :2;
|
||||
unsigned TENS :2;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RDAYCNT;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :3;
|
||||
unsigned TENS :1;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RMONCNT;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned THOUSANDS :4;
|
||||
unsigned HUNDREDS :4;
|
||||
unsigned TENS :4;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RYRCNT;
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned ENB :1;
|
||||
unsigned TENS :3;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RSECAR;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned ENB :1;
|
||||
unsigned TENS :3;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RMINAR;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned ENB :1;
|
||||
unsigned :1;
|
||||
unsigned TENS :2;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RHRAR;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned ENB :1;
|
||||
unsigned :4;
|
||||
// See RTC.RDAYCNT for day encoding.
|
||||
unsigned DAY :3;
|
||||
};
|
||||
} RWKAR;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned ENB :1;
|
||||
unsigned :1;
|
||||
unsigned TENS :2;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RDAYAR;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned ENB :1;
|
||||
unsigned :2;
|
||||
unsigned TENS :1;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RMONAR;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned CF :1;
|
||||
unsigned :2;
|
||||
unsigned CIE :1;
|
||||
unsigned AIE :1;
|
||||
unsigned :2;
|
||||
unsigned AF :1;
|
||||
};
|
||||
} RCR1;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned PEF :1;
|
||||
unsigned PES :3;
|
||||
unsigned :1;
|
||||
unsigned ADJ :1;
|
||||
unsigned RESET :1;
|
||||
unsigned START :1;
|
||||
};
|
||||
} RCR2;
|
||||
|
||||
gap(1);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned THOUSANDS :4;
|
||||
unsigned HUNDREDS :4;
|
||||
unsigned TENS :4;
|
||||
unsigned ONES :4;
|
||||
};
|
||||
} RYRAR;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned ENB :1;
|
||||
unsigned :7;
|
||||
}
|
||||
} RCR3;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Interrupt controller, part 1.
|
||||
//---
|
||||
|
||||
struct _st_intc
|
||||
{
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned const NMIL :1;
|
||||
unsigned MAI :1;
|
||||
unsigned :4;
|
||||
unsigned NMIB :1;
|
||||
unsigned NMIE :1;
|
||||
unsigned :2;
|
||||
unsigned LVLMODE :1;
|
||||
unsigned :5;
|
||||
};
|
||||
} ICR0;
|
||||
|
||||
char gap1[14];
|
||||
|
||||
union {
|
||||
unsigned int LONG;
|
||||
struct {
|
||||
unsigned IRQ0 :4;
|
||||
unsigned IRQ1 :4;
|
||||
unsigned IRQ2 :4;
|
||||
unsigned IRQ3 :4;
|
||||
unsigned IRQ4 :4;
|
||||
unsigned IRQ5 :4;
|
||||
unsigned IRQ6 :4;
|
||||
unsigned IRQ7 :4;
|
||||
};
|
||||
} INTPRI00;
|
||||
|
||||
char gap2[8];
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned IRQ0S :2;
|
||||
unsigned IRQ1S :2;
|
||||
unsigned IRQ2S :2;
|
||||
unsigned IRQ3S :2;
|
||||
unsigned IRQ4S :2;
|
||||
unsigned IRQ5S :2;
|
||||
unsigned IRQ6S :2;
|
||||
unsigned IRQ7S :2;
|
||||
};
|
||||
} ICR1;
|
||||
|
||||
char gap3[6];
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned IRQ0 :1;
|
||||
unsigned IRQ1 :1;
|
||||
unsigned IRQ2 :1;
|
||||
unsigned IRQ3 :1;
|
||||
unsigned IRQ4 :1;
|
||||
unsigned IRQ5 :1;
|
||||
unsigned IRQ6 :1;
|
||||
unsigned IRQ7 :1;
|
||||
};
|
||||
} INTREQ00;
|
||||
|
||||
char gap4[31];
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned IRQ0 :1;
|
||||
unsigned IRQ1 :1;
|
||||
unsigned IRQ2 :1;
|
||||
unsigned IRQ3 :1;
|
||||
unsigned IRQ4 :1;
|
||||
unsigned IRQ5 :1;
|
||||
unsigned IRQ6 :1;
|
||||
unsigned IRQ7 :1;
|
||||
};
|
||||
} INTMSK00;
|
||||
|
||||
char gap5[31];
|
||||
|
||||
union {
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned _IRQ0 :1;
|
||||
unsigned _IRQ1 :1;
|
||||
unsigned _IRQ2 :1;
|
||||
unsigned _IRQ3 :1;
|
||||
unsigned _IRQ4 :1;
|
||||
unsigned _IRQ5 :1;
|
||||
unsigned _IRQ6 :1;
|
||||
unsigned _IRQ7 :1;
|
||||
};
|
||||
} INTMSKCLR00;
|
||||
|
||||
char gap6[91];
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned const NMIL :1;
|
||||
unsigned :14;
|
||||
unsigned NMIFL :1;
|
||||
};
|
||||
} NMIFCR;
|
||||
|
||||
char gap7[6029118];
|
||||
|
||||
union {
|
||||
unsigned int LONG;
|
||||
struct {
|
||||
unsigned HEXA_A5 :8;
|
||||
unsigned :16;
|
||||
unsigned UIMASK :4;
|
||||
unsigned :4;
|
||||
};
|
||||
} USERIMSK;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Interrupt controller, part 2.
|
||||
//---
|
||||
|
||||
struct _st_intx
|
||||
{
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned TMU0_0 :4;
|
||||
unsigned TMU0_1 :4;
|
||||
unsigned TMU0_2 :4;
|
||||
unsigned IrDA :4;
|
||||
};
|
||||
} IPRA;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned JPU :4;
|
||||
unsigned LCDC :4;
|
||||
unsigned DMAC1A :4;
|
||||
unsigned BEU2_1 :4;
|
||||
};
|
||||
} IPRB;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned TMU1_0 :4;
|
||||
unsigned TMU1_1 :4;
|
||||
unsigned TMU1_2 :4;
|
||||
unsigned SPU :4;
|
||||
};
|
||||
} IPRC;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned :4;
|
||||
unsigned MMCIF :4;
|
||||
unsigned :4;
|
||||
unsigned ATAPI :4;
|
||||
};
|
||||
} IPRD;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned DMAC0A :4;
|
||||
unsigned VARIOUS :4;
|
||||
unsigned SCIFA3 :4;
|
||||
unsigned VPU5F :4;
|
||||
};
|
||||
} IPRE;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned KEYSC :4;
|
||||
unsigned DMAC0B :4;
|
||||
unsigned USB01 :4;
|
||||
unsigned CMT :4;
|
||||
};
|
||||
} IPRF;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned SCIF0 :4;
|
||||
unsigned SCIF1 :4;
|
||||
unsigned SCIF2 :4;
|
||||
unsigned VEU3F0 :4;
|
||||
};
|
||||
} IPRG;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned MSIOF0 :4;
|
||||
unsigned MSIOF1 :4;
|
||||
unsigned I2C1 :4;
|
||||
unsigned I2C0 :4;
|
||||
};
|
||||
} IPRH;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned SCIFA4 :4;
|
||||
unsigned ICB :4;
|
||||
unsigned TSIF :4;
|
||||
unsigned _2DG_ICB :4;
|
||||
};
|
||||
} IPRI;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned CEU2_1 :4;
|
||||
unsigned EtherMAC :4;
|
||||
unsigned FSI :4;
|
||||
unsigned SDHI1 :4;
|
||||
};
|
||||
} IPRJ;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned _RTC :4;
|
||||
unsigned DMAC1B :4;
|
||||
unsigned ICB :4;
|
||||
unsigned SDHI0 :4;
|
||||
};
|
||||
} IPRK;
|
||||
|
||||
gap(2);
|
||||
|
||||
union {
|
||||
unsigned short WORD;
|
||||
struct {
|
||||
unsigned SCIFA5 :4;
|
||||
unsigned :4;
|
||||
unsigned TPU :4;
|
||||
unsigned _2DDMAC :4;
|
||||
};
|
||||
} IPRL;
|
||||
|
||||
char gap1[82];
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TUNI2 :1;
|
||||
unsigned TUNI1 :1;
|
||||
unsigned TUNI0 :1;
|
||||
unsigned SDHII3 :1;
|
||||
unsigned SDHII2 :1;
|
||||
unsigned SDHII1 :1;
|
||||
unsigned SDHII0 :1;
|
||||
};
|
||||
} IMR0;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned VOUI :1;
|
||||
unsigned VEU1I :1;
|
||||
unsigned BEU0I :1;
|
||||
unsigned CEUOI :1;
|
||||
unsigned DEI3 :1;
|
||||
unsigned DEI2 :1;
|
||||
unsigned DEI1 :1;
|
||||
unsigned DEI0 :1;
|
||||
};
|
||||
} IMR1;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :3;
|
||||
unsigned VPUI :1;
|
||||
unsigned ATAPI :1;
|
||||
unsigned EtherMAC :1;
|
||||
unsigned :1;
|
||||
unsigned SCIFA0 :1;
|
||||
};
|
||||
} IMR2;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned DEI3 :1;
|
||||
unsigned DEI2 :1;
|
||||
unsigned DEI1 :1;
|
||||
unsigned DEI0 :1;
|
||||
unsigned :3;
|
||||
unsigned IRDAI :1;
|
||||
};
|
||||
} IMR3;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TUNI2 :1;
|
||||
unsigned TUNI1 :1;
|
||||
unsigned TUNI0 :1;
|
||||
unsigned JPUI :1;
|
||||
unsigned :2;
|
||||
unsigned LCDCI :1;
|
||||
};
|
||||
} IMR4;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned KEYI :1;
|
||||
unsigned DADERR :1;
|
||||
unsigned DEI5 :1;
|
||||
unsigned DEI4 :1;
|
||||
unsigned VEU0I :1;
|
||||
unsigned SCIF2 :1;
|
||||
unsigned SCIF1 :1;
|
||||
unsigned SCIF0 :1;
|
||||
};
|
||||
} IMR5;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :2;
|
||||
unsigned ICBI :1;
|
||||
unsigned SCIFA4 :1;
|
||||
unsigned CEU1I :1;
|
||||
unsigned :1;
|
||||
unsigned MSIOFI0 :1;
|
||||
unsigned MSIOFI1 :1;
|
||||
};
|
||||
} IMR6;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned DTE0I :1;
|
||||
unsigned WAITOI :1;
|
||||
unsigned TACK0I :1;
|
||||
unsigned AL0I :1;
|
||||
unsigned DTE1I :1;
|
||||
unsigned WAIT1I :1;
|
||||
unsigned TACK1I :1;
|
||||
unsigned AL1I :1;
|
||||
};
|
||||
} IMR7;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned SDHII3 :1;
|
||||
unsigned SDHII2 :1;
|
||||
unsigned SDHII1 :1;
|
||||
unsigned SDHII0 :1;
|
||||
unsigned :2;
|
||||
unsigned SCFIA5 :1;
|
||||
unsigned FSI :1;
|
||||
};
|
||||
} IMR8;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :3;
|
||||
unsigned CMTI :1;
|
||||
unsigned :1;
|
||||
unsigned USI1 :1;
|
||||
unsigned USI0 :1;
|
||||
unsigned :1;
|
||||
};
|
||||
} IMR9;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned DADERR :1;
|
||||
unsigned DEI5 :1;
|
||||
unsigned DEI4 :1;
|
||||
unsigned :1;
|
||||
unsigned ATI :1;
|
||||
unsigned PRI :1;
|
||||
unsigned CUI :1;
|
||||
};
|
||||
} IMR10;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned BRK :1;
|
||||
unsigned CEI :1;
|
||||
unsigned INI :1;
|
||||
unsigned TRI :1;
|
||||
unsigned :1;
|
||||
unsigned TPUI :1;
|
||||
unsigned LMBI :1;
|
||||
unsigned TSIFI :1;
|
||||
};
|
||||
} IMR11;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :7;
|
||||
unsigned _2DDMAC :1;
|
||||
};
|
||||
} IMR12;
|
||||
|
||||
char gap2[15];
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TUNI2 :1;
|
||||
unsigned TUNI1 :1;
|
||||
unsigned TUNI0 :1;
|
||||
unsigned SDHII3 :1;
|
||||
unsigned SDHII2 :1;
|
||||
unsigned SDHII1 :1;
|
||||
unsigned SDHII0 :1;
|
||||
};
|
||||
} _IMCR0;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned VOUI :1;
|
||||
unsigned VEU1I :1;
|
||||
unsigned BEU0I :1;
|
||||
unsigned CEUOI :1;
|
||||
unsigned DEI3 :1;
|
||||
unsigned DEI2 :1;
|
||||
unsigned DEI1 :1;
|
||||
unsigned DEI0 :1;
|
||||
};
|
||||
} _IMCR1;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :3;
|
||||
unsigned VPUI :1;
|
||||
unsigned ATAPI :1;
|
||||
unsigned EtherMAC :1;
|
||||
unsigned :1;
|
||||
unsigned SCIFA0 :1;
|
||||
};
|
||||
} _IMCR2;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned DEI3 :1;
|
||||
unsigned DEI2 :1;
|
||||
unsigned DEI1 :1;
|
||||
unsigned DEI0 :1;
|
||||
unsigned :3;
|
||||
unsigned IRDAI :1;
|
||||
};
|
||||
} _IMCR3;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned TUNI2 :1;
|
||||
unsigned TUNI1 :1;
|
||||
unsigned TUNI0 :1;
|
||||
unsigned JPUI :1;
|
||||
unsigned :2;
|
||||
unsigned LCDCI :1;
|
||||
};
|
||||
} _IMCR4;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned KEYI :1;
|
||||
unsigned DADERR :1;
|
||||
unsigned DEI5 :1;
|
||||
unsigned DEI4 :1;
|
||||
unsigned VEU0I :1;
|
||||
unsigned SCIF2 :1;
|
||||
unsigned SCIF1 :1;
|
||||
unsigned SCIF0 :1;
|
||||
};
|
||||
} _IMCR5;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :2;
|
||||
unsigned ICBI :1;
|
||||
unsigned SCIFA4 :1;
|
||||
unsigned CEU1I :1;
|
||||
unsigned :1;
|
||||
unsigned MSIOFI0 :1;
|
||||
unsigned MSIOFI1 :1;
|
||||
};
|
||||
} _IMCR6;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned DTE0I :1;
|
||||
unsigned WAITOI :1;
|
||||
unsigned TACK0I :1;
|
||||
unsigned AL0I :1;
|
||||
unsigned DTE1I :1;
|
||||
unsigned WAIT1I :1;
|
||||
unsigned TACK1I :1;
|
||||
unsigned AL1I :1;
|
||||
};
|
||||
} _IMCR7;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned SDHII3 :1;
|
||||
unsigned SDHII2 :1;
|
||||
unsigned SDHII1 :1;
|
||||
unsigned SDHII0 :1;
|
||||
unsigned :2;
|
||||
unsigned SCFIA5 :1;
|
||||
unsigned FSI :1;
|
||||
};
|
||||
} _IMCR8;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :3;
|
||||
unsigned CMTI :1;
|
||||
unsigned :1;
|
||||
unsigned USI1 :1;
|
||||
unsigned USI0 :1;
|
||||
unsigned :1;
|
||||
};
|
||||
} _IMCR9;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :1;
|
||||
unsigned DADERR :1;
|
||||
unsigned DEI5 :1;
|
||||
unsigned DEI4 :1;
|
||||
unsigned :1;
|
||||
unsigned ATI :1;
|
||||
unsigned PRI :1;
|
||||
unsigned CUI :1;
|
||||
};
|
||||
} _IMCR10;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned BRK :1;
|
||||
unsigned CEI :1;
|
||||
unsigned INI :1;
|
||||
unsigned TRI :1;
|
||||
unsigned :1;
|
||||
unsigned TPUI :1;
|
||||
unsigned LMBI :1;
|
||||
unsigned TSIFI :1;
|
||||
};
|
||||
} _IMCR11;
|
||||
|
||||
gap(3);
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char BYTE;
|
||||
struct {
|
||||
unsigned :7;
|
||||
unsigned _2DDMAC :1;
|
||||
};
|
||||
} _IMCR12;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
#define RTC (*(volatile struct _st_rtc *)0xa413fec0)
|
||||
#define INTC (*(volatile struct _st_intc *)0xa4140000)
|
||||
#define INTX (*(volatile struct _st_intx *)0xa4080000)
|
||||
|
||||
#pragma pack(pop)
|
||||
#endif // _7305_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,181 @@
|
|||
#ifndef _DISPLAY_H
|
||||
#define _DISPLAY_H 1
|
||||
|
||||
//---
|
||||
// Types and constants.
|
||||
//---
|
||||
|
||||
enum Color
|
||||
{
|
||||
Color_White = 0, // White (AND 0)
|
||||
Color_Black = 1, // Black (OR 1)
|
||||
Color_None = 2, // Transparent (NOP)
|
||||
Color_Invert = 3, // Invert (XOR 1)
|
||||
};
|
||||
|
||||
/*
|
||||
enum BlendingMode
|
||||
Describes the various blending modes available for drawing images.
|
||||
Blending modes may be combined for special effects! For instance:
|
||||
- Or Only sets black pixels.
|
||||
- And Only erases white pixels.
|
||||
- Or | And Fully draws the bitmap.
|
||||
- Invert Inverts pixels where the bitmap is black.
|
||||
- Or | Invert Erases black pixels.
|
||||
Adding Checker to an existing combination limits the operation to
|
||||
pixels (x, y) that satisfy (x + y) & 1 == 1.
|
||||
Operations are done in the following order : Or - Invert - And.
|
||||
*/
|
||||
enum BlendingMode
|
||||
{
|
||||
Blend_Or = 0x01,
|
||||
Blend_Invert = 0x02,
|
||||
Blend_And = 0x04,
|
||||
|
||||
Blend_Checker = 0x10,
|
||||
};
|
||||
|
||||
enum ImageFormat
|
||||
{
|
||||
ImageFormat_Mono = 0x01,
|
||||
ImageFormat_Gray = 0x02,
|
||||
|
||||
ImageFormat_Alpha = 0x10,
|
||||
|
||||
ImageFormat_ColorMask = 0x0f,
|
||||
};
|
||||
|
||||
struct Image
|
||||
{
|
||||
unsigned char width;
|
||||
unsigned char height;
|
||||
unsigned char format;
|
||||
|
||||
// Ensures data is 4-aligned.
|
||||
unsigned char gap;
|
||||
|
||||
const unsigned char __attribute__((aligned(4))) data[];
|
||||
|
||||
} __attribute__((aligned(4)));
|
||||
|
||||
typedef struct Image Image;
|
||||
|
||||
|
||||
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 64
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Generic functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
display_getLocalVRAM()
|
||||
Returns the local video ram. This address should not be used directly
|
||||
when running the gray engine.
|
||||
|
||||
@return Video ram address of the monochrome display module.
|
||||
*/
|
||||
void *display_getLocalVRAM(void);
|
||||
|
||||
/*
|
||||
display_useVRAM()
|
||||
Changes the current video ram address. Expects a *4-aligned* 1024-byte
|
||||
buffer.
|
||||
Do not use this function while running the gray engine.
|
||||
|
||||
@arg New video ram address.
|
||||
*/
|
||||
void display_useVRAM(void *vram);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Global drawing functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
dupdate()
|
||||
Displays the vram on the physical screen.
|
||||
*/
|
||||
void dupdate(void);
|
||||
|
||||
/*
|
||||
dclear()
|
||||
Clears the whole video ram.
|
||||
*/
|
||||
void dclear(void);
|
||||
|
||||
/*
|
||||
dclear_area()
|
||||
Clears an area of the video ram.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
*/
|
||||
void dclear_area(int x1, int y1, int x2, int y2);
|
||||
|
||||
/*
|
||||
dreverse_area()
|
||||
Reverses an area of the screen.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
*/
|
||||
void dreverse_area(int x1, int y1, int x2, int y2);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Local drawing functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
dpixel()
|
||||
Puts a pixel on the screen.
|
||||
|
||||
@arg x
|
||||
@arg y
|
||||
@arg color
|
||||
*/
|
||||
void dpixel(int x, int y, enum Color color);
|
||||
|
||||
/*
|
||||
dline()
|
||||
Draws a line on the screen. Automatically optimizes horizontal and
|
||||
vertical lines.
|
||||
|
||||
Uses an algorithm written by PierrotLL for MonochromeLib.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
@arg color
|
||||
*/
|
||||
void dline(int x1, int y1, int x2, int y2, enum Color color);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Image drawing.
|
||||
//---
|
||||
|
||||
/*
|
||||
dimage()
|
||||
Displays an image in the vram.
|
||||
|
||||
@arg image
|
||||
@arg x
|
||||
@arg y
|
||||
@arg mode
|
||||
*/
|
||||
void dimage(struct Image *image, int x, int y, enum BlendingMode mode);
|
||||
|
||||
#endif // _DISPLAY_H
|
|
@ -0,0 +1,97 @@
|
|||
#ifndef _GINT_H
|
||||
#define _GINT_H 1
|
||||
|
||||
//---
|
||||
// Public API.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_getVBR()
|
||||
Returns the current vbr address.
|
||||
|
||||
@return vbr address currently in use.
|
||||
*/
|
||||
unsigned int gint_getVBR(void);
|
||||
|
||||
/*
|
||||
gint_systemVBR()
|
||||
Returns the vbr address used by the system (saved when execution
|
||||
starts).
|
||||
|
||||
@return vbr address used by the system.
|
||||
*/
|
||||
unsigned int gint_systemVBR(void);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced here for documentation purposes only.
|
||||
// Do NOT call these functions, you'll most probably screw up the whole
|
||||
// interrupt handling system.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_setVBR()
|
||||
Sets the vbr address and does some configuration while interrupts are
|
||||
disabled.
|
||||
|
||||
@arg new_vbr_address
|
||||
@arg setup Will be called for configuration under interrupt-safe
|
||||
environment.
|
||||
*/
|
||||
void gint_setVBR(unsigned int new_vbr_address, void (*setup)(void));
|
||||
|
||||
/*
|
||||
gint_init()
|
||||
Initializes gint. Loads the interrupt handler into the memory and sets
|
||||
the new vbr address.
|
||||
*/
|
||||
void gint_init(void);
|
||||
|
||||
/*
|
||||
gint_quit()
|
||||
Stops gint. Restores the system's configuration and vbr address.
|
||||
*/
|
||||
void gint_quit(void);
|
||||
|
||||
/*
|
||||
gint_setup()
|
||||
Configures interrupt priorities and some parameters to allow gint to
|
||||
take control of the interrupt flow.
|
||||
*/
|
||||
void gint_setup_7705(void);
|
||||
void gint_setup_7305(void);
|
||||
|
||||
/*
|
||||
gint_stop()
|
||||
Un-configures the interrupt flow to give back the interrupt control to
|
||||
the system.
|
||||
*/
|
||||
void gint_stop_7705(void);
|
||||
void gint_stop_7305(void);
|
||||
|
||||
/*
|
||||
gint()
|
||||
Handles interrupts.
|
||||
*/
|
||||
void gint(void) __attribute__((
|
||||
section(".gint.int.entry"),
|
||||
interrupt_handler
|
||||
));
|
||||
void gint_7705(void) __attribute__((section(".gint.int")));
|
||||
void gint_7305(void) __attribute__((section(".gint.int")));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal priority definitions.
|
||||
//---
|
||||
|
||||
#define GINT_INTP_WDT 4
|
||||
#define GINT_INTP_RTC 9
|
||||
#define GINT_INTP_KEY 8
|
||||
|
||||
|
||||
|
||||
#endif // _GINT_H
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef _GRAY_H
|
||||
#define _GRAY_H 1
|
||||
|
||||
//---
|
||||
// Public API.
|
||||
//---
|
||||
|
||||
/*
|
||||
gray_start()
|
||||
Starts the gray engine. The control of the screen is transferred to the
|
||||
gray engine.
|
||||
*/
|
||||
void gray_start(void);
|
||||
|
||||
/*
|
||||
gray_stop()
|
||||
Stops the gray engine. The monochrome display system takes control of
|
||||
the video ram.
|
||||
*/
|
||||
void gray_stop(void);
|
||||
|
||||
/*
|
||||
gray_lightVRAM()
|
||||
Returns the module's gray vram address.
|
||||
*/
|
||||
void *gray_lightVRAM(void);
|
||||
|
||||
/*
|
||||
gray_lightVRAM()
|
||||
Returns the module's dark vram address.
|
||||
*/
|
||||
void *gray_darkVRAM(void);
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced here for documentation purposes only. Do not call.
|
||||
//--
|
||||
|
||||
/*
|
||||
gray_swap()
|
||||
Swaps the vram buffers.
|
||||
*/
|
||||
void gray_swap(void);
|
||||
|
||||
/*
|
||||
gray_interrupt()
|
||||
Answers a timer interrupt. Swaps the two buffers.
|
||||
*/
|
||||
void gray_interrupt(void) __attribute__((section(".gint.int")));
|
||||
|
||||
/*
|
||||
gray_init()
|
||||
Initializes the gray engine.
|
||||
*/
|
||||
void gray_init(void) __attribute__((constructor));
|
||||
|
||||
#endif // _GRAY_H
|
|
@ -0,0 +1,254 @@
|
|||
#ifndef _KEYBOARD_H
|
||||
#define _KEYBOARD_H 1
|
||||
|
||||
//---
|
||||
// Keycodes and related.
|
||||
//---
|
||||
|
||||
// The following codes are gint matrix codes. They are not compatible with the
|
||||
// system's.
|
||||
|
||||
#define KEY_F1 0x69
|
||||
#define KEY_F2 0x59
|
||||
#define KEY_F3 0x49
|
||||
#define KEY_F4 0x39
|
||||
#define KEY_F4 0x39
|
||||
#define KEY_F5 0x29
|
||||
#define KEY_F6 0x19
|
||||
|
||||
#define KEY_SHIFT 0x68
|
||||
#define KEY_OPTN 0x58
|
||||
#define KEY_VARS 0x48
|
||||
#define KEY_MENU 0x38
|
||||
#define KEY_LEFT 0x28
|
||||
#define KEY_UP 0x18
|
||||
|
||||
#define KEY_ALPHA 0x67
|
||||
#define KEY_SQUARE 0x57
|
||||
#define KEY_POWER 0x47
|
||||
#define KEY_EXIT 0x37
|
||||
#define KEY_DOWN 0x27
|
||||
#define KEY_RIGHT 0x17
|
||||
|
||||
#define KEY_XOT 0x66
|
||||
#define KEY_LOG 0x56
|
||||
#define KEY_LN 0x46
|
||||
#define KEY_SIN 0x36
|
||||
#define KEY_COS 0x26
|
||||
#define KEY_TAN 0x16
|
||||
|
||||
#define KEY_FRAC 0x65
|
||||
#define KEY_FD 0x55
|
||||
#define KEY_LEFTP 0x45
|
||||
#define KEY_RIGHTP 0x35
|
||||
#define KEY_COMMA 0x25
|
||||
#define KEY_ARROW 0x15
|
||||
|
||||
#define KEY_7 0x64
|
||||
#define KEY_8 0x54
|
||||
#define KEY_9 0x44
|
||||
#define KEY_DEL 0x34
|
||||
#define KEY_AC_ON 0x24
|
||||
|
||||
#define KEY_4 0x63
|
||||
#define KEY_5 0x53
|
||||
#define KEY_6 0x43
|
||||
#define KEY_MUL 0x33
|
||||
#define KEY_DIV 0x23
|
||||
|
||||
#define KEY_1 0x62
|
||||
#define KEY_2 0x52
|
||||
#define KEY_3 0x42
|
||||
#define KEY_PLUS 0x32
|
||||
#define KEY_MINUS 0x22
|
||||
|
||||
#define KEY_0 0x61
|
||||
#define KEY_DOT 0x51
|
||||
#define KEY_EXP 0x41
|
||||
#define KEY_NEG 0x31
|
||||
#define KEY_EXE 0x21
|
||||
|
||||
// Key modifiers.
|
||||
#define MOD_SHIFT 0x80
|
||||
#define MOD_ALPHA 0x100
|
||||
#define MOD_CLEAR ~(MOD_SHIFT | MOD_ALPHA)
|
||||
|
||||
// Key events.
|
||||
#define KEY_NONE 0x00
|
||||
#define KEY_NOEVENT 0xff
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Keyboard configuration.
|
||||
//---
|
||||
|
||||
/*
|
||||
enum KeyboardFrequency
|
||||
Describes the various frequencies available for the keyboard analysis.
|
||||
Default frequency is 16 Hz (system frequency is about 40 Hz). Very few
|
||||
applications will need to change this setting.
|
||||
Be aware that you will miss key hits at low frequencies.
|
||||
At high frequencies, you will lose important execution power. Some
|
||||
loop-driven programs will freeze at 64 Hz because they will never
|
||||
leave the interrupt handling routine. SH3 also have difficulties with
|
||||
64 Hz.
|
||||
*/
|
||||
enum KeyboardFrequency {
|
||||
KeyFreq_500mHz = 7,
|
||||
KeyFreq_1Hz = 6,
|
||||
KeyFreq_2Hz = 5,
|
||||
KeyFreq_4Hz = 4,
|
||||
KeyFreq_16Hz = 3,
|
||||
KeyFreq_64Hz = 2,
|
||||
KeyFreq_256Hz = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
keyboard_setFrequency()
|
||||
Sets the keyboard frequency. Does nothing when the argument is not a
|
||||
valid KeyboardFrequency value.
|
||||
|
||||
@arg frequency
|
||||
*/
|
||||
void keyboard_setFrequency(enum KeyboardFrequency frequency);
|
||||
|
||||
/*
|
||||
keyboard_setRepeatRate()
|
||||
Sets the default repeat rate for key events. The unit for the argument
|
||||
is the keyboard period.
|
||||
For example at 16 Hz, values of (10, 2) will imitate the system
|
||||
default.
|
||||
Set to 0 to disable repetition. If first = 0, no repetition will be
|
||||
allowed. If first != 0 and next = 0, only one repetition will be
|
||||
allowed.
|
||||
|
||||
@arg first Delay before first repeat, in keyboard period units.
|
||||
@arg next Delay before following repeats, in keyboard period
|
||||
units.
|
||||
*/
|
||||
void keyboard_setRepeatRate(int first, int next);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Keyboard access.
|
||||
//---
|
||||
|
||||
/*
|
||||
enum GetKeyOpt
|
||||
Options available for use with getkey_opt().
|
||||
*/
|
||||
enum GetkeyOpt
|
||||
{
|
||||
Getkey_NoOption = 0x00,
|
||||
|
||||
// Return KEY_NONE when a key is released.
|
||||
Getkey_ReleaseEvent = 0x01,
|
||||
|
||||
// Consider [SHIFT] and [ALPHA] as modifiers instead of returning
|
||||
// KEY_SHIFT and KEY_ALPHA.
|
||||
Getkey_ShiftModifier = 0x02,
|
||||
Getkey_AlphaModifier = 0x04,
|
||||
|
||||
// Key repetition. Notice that modifiers will never be repeated.
|
||||
Getkey_RepeatArrowKeys = 0x10,
|
||||
Getkey_RepeatCharKeys = 0x20,
|
||||
Getkey_RepeatCtrlKeys = 0x40,
|
||||
Getkey_RepeatFuncKeys = 0x80,
|
||||
// Shorthand for the four previous properties.
|
||||
Getkey_RepeatAllKeys = 0xf0,
|
||||
};
|
||||
|
||||
/*
|
||||
keylast()
|
||||
Returns the matrix code of the last pressed key. If repeat_count is
|
||||
non-NULL, it is set to the number of repetitions.
|
||||
|
||||
@arg repeat_count
|
||||
@return Key matrix code.
|
||||
*/
|
||||
int keylast(int *repeat_count);
|
||||
|
||||
/*
|
||||
getkey()
|
||||
Blocking function with auto-repeat and SHIFT modifying functionalities.
|
||||
Reproduces the behavior of the system's GetKey().
|
||||
|
||||
@return Pressed key matrix code.
|
||||
*/
|
||||
int getkey(void);
|
||||
|
||||
/*
|
||||
getkey_opt()
|
||||
Enhances getkey() with most general functionalities.
|
||||
If max_cycles is non-zero and positive, getkey_opt() will return
|
||||
KEY_NOEVENT if no event occurs during max_cycle analysis.
|
||||
|
||||
@arg options OR-combination of GetkeyOpt values.
|
||||
@arg max_cycles
|
||||
|
||||
@return Pressed key matrix code.
|
||||
*/
|
||||
int getkey_opt(enum GetkeyOpt options, int max_cycles);
|
||||
|
||||
/*
|
||||
multigetkey()
|
||||
Listens the keyboard for simultaneous key hits. Uses the same options
|
||||
as getkey_opt().
|
||||
multigetkey() fills the 'keys' array with 'count' key codes, adding
|
||||
KEY_NONE if less than 'count' keys are pressed.
|
||||
Be aware that rectangle and column effects can make multigetkey() read
|
||||
unpressed keys as pressed (see documentation for more information).
|
||||
Setting count = 3 is generally safe.
|
||||
|
||||
@arg keys Key code array.
|
||||
@arg count Maximum number of keys that will be read.
|
||||
@arg max_cycles
|
||||
*/
|
||||
void multigetkey(int *keys, int count, int max_cycles);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Key analysis.
|
||||
//---
|
||||
|
||||
enum KeyType
|
||||
{
|
||||
KeyType_Arrow = 1,
|
||||
KeyType_Character = 2,
|
||||
KeyType_Control = 4,
|
||||
KeyType_Function = 8,
|
||||
};
|
||||
|
||||
/*
|
||||
keyid()
|
||||
Returns a non-matrix key code that can be used for array subscript.
|
||||
Ignores modifiers.
|
||||
|
||||
@arg key
|
||||
@return Modified keycode.
|
||||
*/
|
||||
int keyid(int key);
|
||||
|
||||
/*
|
||||
keychar()
|
||||
Returns the ASCII character associated with a character key ; 0 for
|
||||
other keys.
|
||||
|
||||
@arg key
|
||||
@return Key character.
|
||||
*/
|
||||
int keychar(int key);
|
||||
|
||||
/*
|
||||
keytype()
|
||||
Returns a key's type. Ignores modifiers.
|
||||
|
||||
@arg key
|
||||
@return Key type.
|
||||
*/
|
||||
enum KeyType keytype(int key);
|
||||
|
||||
#endif // _KEYBOARD_H
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef _MPU_H
|
||||
#define _MPU_H 1
|
||||
|
||||
//---
|
||||
// enum MPU
|
||||
// This type holds information about the calculator's MPU.
|
||||
//---
|
||||
|
||||
enum MPU
|
||||
{
|
||||
MPU_Unknown = 0,
|
||||
// fx-9860G SH3.
|
||||
MPU_SH7337 = 1,
|
||||
// fx-9860G II SH3.
|
||||
MPU_SH7355 = 2,
|
||||
// fx-9860G II SH4.
|
||||
MPU_SH7305 = 3,
|
||||
// Just for reference.
|
||||
MPU_SH7724 = 4
|
||||
};
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// MPU type tests.
|
||||
// Prefer using an 'if(isSH3()) { ... } else { ... }' alternative for best
|
||||
// results.
|
||||
//---
|
||||
|
||||
// Global MPU variable, accessible for direct tests.
|
||||
extern enum MPU MPU_CURRENT;
|
||||
|
||||
// Quick SH3 test. It is safer to assume that an unknown model is SH4 because
|
||||
// SH3-based models are not produced anymore.
|
||||
#define isSH3() (MPU_CURRENT == MPU_SH7337 || MPU_CURRENT == MPU_SH7355)
|
||||
#define isSH4() !isSH3()
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Public API.
|
||||
//---
|
||||
|
||||
/*
|
||||
getMPU()
|
||||
Determines the MPU type and returns it. MPU_CURRENT is not updated.
|
||||
|
||||
@return MPU type.
|
||||
*/
|
||||
enum MPU getMPU(void);
|
||||
|
||||
#endif // _MPU_H
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef _SCREEN_H
|
||||
#define _SCREEN_H 1
|
||||
|
||||
/*
|
||||
screen_display()
|
||||
Displays contents on the full screen. Expects a 1024-byte buffer.
|
||||
|
||||
@arg vram 1024-byte video buffer.
|
||||
*/
|
||||
void screen_display(const void *vram);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef _SETJMP_H
|
||||
#define _SETJMP_H 1
|
||||
|
||||
// There are 16 CPU registers that *must* be saved to ensure a basically
|
||||
// safe jump.
|
||||
typedef unsigned int jmp_buf[16];
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Long jump functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
#endif // _SETJMP_H
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef _STDLIB_H
|
||||
#define _STDLIB_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// Common exit codes.
|
||||
#define EXIT_SUCCESS 1
|
||||
#define EXIT_FAILURE 0
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Program exit functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
abort()
|
||||
Aborts the program execution without calling the exit handlers.
|
||||
*/
|
||||
void abort(void);
|
||||
|
||||
/*
|
||||
exit()
|
||||
Stops the program execution with the given status code, after calling
|
||||
the exit handlers.
|
||||
|
||||
@arg status
|
||||
*/
|
||||
void exit(int status);
|
||||
|
||||
#endif // _STDLIB_H
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef _STRING_H
|
||||
#define _STRING_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
//---
|
||||
// Memory manipulation.
|
||||
//---
|
||||
|
||||
/*
|
||||
memcpy()
|
||||
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);
|
||||
|
||||
#endif // _STRING_H
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef _TIMER_H
|
||||
#define _TIMER_H 1
|
||||
|
||||
//---
|
||||
// Constants.
|
||||
//---
|
||||
|
||||
// Timer identifiers.
|
||||
#define TIMER_0 0
|
||||
#define TIMER_TMU0 TIMER_0
|
||||
#define TIMER_1 1
|
||||
#define TIMER_TMU1 TIMER_1
|
||||
#define TIMER_2 2
|
||||
#define TIMER_TMU2 TIMER_2
|
||||
// Timer function identifiers.
|
||||
#define TIMER_GRAY TIMER_TMU0
|
||||
#define TIMER_USER1 TIMER_TMU1
|
||||
#define TIMER_USER2 TIMER_TMU2
|
||||
|
||||
// Timer prescalers.
|
||||
#define TIMER_Po_4 0
|
||||
#define TIMER_Po_16 1
|
||||
#define TIMER_Po_64 2
|
||||
#define TIMER_Po_256 3
|
||||
#define TIMER_TCLK 5
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Public API.
|
||||
//---
|
||||
|
||||
/*
|
||||
timer_set()
|
||||
Configures and starts a timer.
|
||||
|
||||
@arg timer Timer identifier. Use only TIMER_USER1 and
|
||||
TIMER_USER2.
|
||||
@arg delay Delay before expiration, in clock counts.
|
||||
@arg prescaler Clock prescaler value. Possible values are
|
||||
TIMER_Po_4, TIMER_Po_16, TIMER_Po_64,
|
||||
TIMER_Po_256 and TIMER_TCLK.
|
||||
@arg callback Callback function.
|
||||
@arg repetitions Number of repetitions, 0 for infinite.
|
||||
*/
|
||||
void timer_set(int timer, int delay, int prescaler, void (*callback)(void),
|
||||
int repetitions);
|
||||
|
||||
/*
|
||||
timer_stop()
|
||||
Stops the given timer. This function may be called even if the timer is
|
||||
not running.
|
||||
|
||||
@arg timer Timer identifier.
|
||||
*/
|
||||
void timer_stop(int timer);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced for documentation purposes only. Do not call.
|
||||
//---
|
||||
|
||||
/*
|
||||
timer_interrupt()
|
||||
Handles the interrupt for the given timer.
|
||||
|
||||
@timer Timer that generated the interrupt.
|
||||
*/
|
||||
void timer_interrupt(int timer);
|
||||
|
||||
#endif // _TIMER_H
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
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 %
|
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
|
@ -0,0 +1,145 @@
|
|||
// Used by the exit()-family functions to save and restore the execution state.
|
||||
#include <setjmp.h>
|
||||
static jmp_buf env;
|
||||
// Provides EXIT_SUCCESS and EXIT_FAILURE.
|
||||
#include <stdlib.h>
|
||||
// Provides gint initialization functionalities.
|
||||
#include <gint.h>
|
||||
// Provides memset() and memcpy().
|
||||
#include <string.h>
|
||||
|
||||
// Some syscall prototypes.
|
||||
void __Hmem_SetMMU(unsigned int, unsigned int, int);
|
||||
void __GLibAddinAplExecutionCheck(int, int, int);
|
||||
int main(void);
|
||||
|
||||
// Local functions.
|
||||
static void init(void);
|
||||
static void fini(void);
|
||||
|
||||
// Symbols imported from the linker script.
|
||||
extern unsigned int
|
||||
romdata,
|
||||
bbss, ebss,
|
||||
bdata, edata;
|
||||
|
||||
// This variable should be overwritten before being returned, so the default
|
||||
// value doesn't matter much.
|
||||
static int exit_code = EXIT_SUCCESS;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
start()
|
||||
|
||||
Program entry point. Loads the data section into the memory and invokes
|
||||
main(). Also prepares the execution environment by initializing all the
|
||||
modules.
|
||||
|
||||
@return Execution status returned to the OS.
|
||||
*/
|
||||
|
||||
int start(void)
|
||||
__attribute__((
|
||||
section(".pretext.entry")
|
||||
));
|
||||
|
||||
int start(void)
|
||||
{
|
||||
// Linker symbols.
|
||||
unsigned int *bss = &bbss;
|
||||
unsigned int *data = &bdata, *src = &romdata;
|
||||
int x;
|
||||
|
||||
// Setting up the TLB.
|
||||
__Hmem_SetMMU(0x08102000, 0x8801e000, 108);
|
||||
|
||||
// Clearing the .bss section.
|
||||
while(bss < &ebss) *bss++ = 0;
|
||||
// Copying the .data section.
|
||||
while(data < &edata) *data++ = *src++;
|
||||
|
||||
__GLibAddinAplExecutionCheck(0, 1, 1);
|
||||
|
||||
// Initializing everything.
|
||||
init();
|
||||
gint_init();
|
||||
|
||||
|
||||
|
||||
// Saving the execution state there.
|
||||
x = setjmp(env);
|
||||
// If the program has just started, executing main(). Otherwise, the
|
||||
// exit code has already been set by abort() or similar.
|
||||
if(!x) exit_code = main();
|
||||
|
||||
|
||||
|
||||
// Remember to flush and close opened streams.
|
||||
|
||||
// Un-initializing everything.
|
||||
gint_quit();
|
||||
fini();
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
extern void
|
||||
(*bctors)(void),
|
||||
(*ectors)(void);
|
||||
void (**func)(void) = &bctors;
|
||||
|
||||
// Calling the constructors.
|
||||
while(func < &ectors)
|
||||
{
|
||||
(*(*func))();
|
||||
func++;
|
||||
}
|
||||
}
|
||||
|
||||
static void fini(void)
|
||||
{
|
||||
extern void
|
||||
(*bdtors)(void),
|
||||
(*edtors)(void);
|
||||
void (**func)(void) = &bdtors;
|
||||
|
||||
// Calling the destructors.
|
||||
while(func < &edtors)
|
||||
{
|
||||
(*(*func))();
|
||||
func++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
abort()
|
||||
|
||||
Immediately ends the program without invoking the exit handlers.
|
||||
*/
|
||||
|
||||
void abort(void)
|
||||
{
|
||||
exit_code = EXIT_FAILURE;
|
||||
longjmp(env, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
exit()
|
||||
|
||||
Ends the program and returns the given exit code status.
|
||||
Calls exit handlers before returning.
|
||||
|
||||
@arg status Exit status.
|
||||
*/
|
||||
|
||||
void exit(int status)
|
||||
{
|
||||
exit_code = status;
|
||||
longjmp(env, 1);
|
||||
}
|
||||
|
|
@ -0,0 +1,715 @@
|
|||
/*
|
||||
display
|
||||
|
||||
Handles vram manipulation and drawing.
|
||||
|
||||
:: Rectangle masks
|
||||
|
||||
The concept of 'rectangle masks' is used several times in this module.
|
||||
It consists in saying that an operation that affects a rectangle acts
|
||||
the same on all the lines (considering that only the lines that
|
||||
intersect the rectangle are changed) and therefore it is possible to
|
||||
represent the behavior on a single line using 'masks' that 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, reversing a rectangle of
|
||||
vram only needs vram[offset] ^= masks[i].
|
||||
|
||||
This technique can also be used in more subtle cases with more complex
|
||||
patterns, but within this module it is unlikely to happen.
|
||||
*/
|
||||
|
||||
#include <screen.h>
|
||||
#include <display.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <gray.h>
|
||||
|
||||
// Program video ram. It resides in .bss section, therefore it is cleared at
|
||||
// program initialization and stripped from the executable file.
|
||||
static int local_vram[256];
|
||||
static int *vram = local_vram;
|
||||
|
||||
#define sgn(x) ((x) < 0 ? -1 : 1)
|
||||
#define abs(x) ((x) < 0 ? -(x) : (x))
|
||||
#define rnd(x) ((int)((x) + 0.5))
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Local helper functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
adjust()
|
||||
Adjusts the given rectangle coordinates to ensure that :
|
||||
- The rectangle is entirely contained in the screen,
|
||||
- x1 < x2 and y1 < y2,
|
||||
which is needed when working with screen rectangles.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
*/
|
||||
static void adjust(int *x1, int *y1, int *x2, int *y2)
|
||||
{
|
||||
#define swap(a, b) tmp = a, a = b, b = tmp
|
||||
int tmp;
|
||||
|
||||
if(*x2 < *x1) swap(*x1, *x2);
|
||||
if(*y2 < *y1) swap(*y1, *y2);
|
||||
|
||||
if(*x1 < 0) *x1 = 0;
|
||||
if(*y1 < 0) *y1 = 0;
|
||||
if(*x2 > 127) *x2 = 127;
|
||||
if(*y2 > 63) *y2 = 63;
|
||||
#undef swap
|
||||
}
|
||||
|
||||
/*
|
||||
getmasks()
|
||||
|
||||
Computes the rectangle masks needed to affect pixels located between x1
|
||||
and x2 (both included).
|
||||
|
||||
@arg x1
|
||||
@arg x2
|
||||
@arg masks Four-integer-array pointer.
|
||||
*/
|
||||
static void getmasks(int x1, int x2, unsigned int *masks)
|
||||
{
|
||||
// Indexes of the first and last longs that are non-blank.
|
||||
int l1 = x1 >> 5;
|
||||
int l2 = x2 >> 5;
|
||||
int i = 0;
|
||||
|
||||
// Setting the base masks. Those are the final values, except for the
|
||||
// longs with indexes l1 and l2, that still need to be adjusted.
|
||||
while(i < l1) masks[i++] = 0x00000000;
|
||||
while(i <= l2) masks[i++] = 0xffffffff;
|
||||
while(i < 4) masks[i++] = 0x00000000;
|
||||
|
||||
// Removing the long number information in x1 and x2 (that is, the
|
||||
// multiples of 32) to keep only the interesting information -- the
|
||||
// number of null bits to add in l1 and l2.
|
||||
x1 &= 31;
|
||||
// Inverting x2 is here the same as computing 32 - x, since 32 is a
|
||||
// power of 2 (actually it creates positive bits at the left but those
|
||||
// ones are removed by the bitwise-and mask).
|
||||
x2 = ~x2 & 31;
|
||||
|
||||
// Setting the last masks.
|
||||
masks[l1] &= (0xffffffff >> x1);
|
||||
masks[l2] &= (0xffffffff << x2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Generic functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
display_getVRAM()
|
||||
Returns the current video ram.
|
||||
|
||||
@return Video ram address.
|
||||
*/
|
||||
void *display_getLocalVRAM(void)
|
||||
{
|
||||
return (void*)local_vram;
|
||||
}
|
||||
|
||||
/*
|
||||
display_useVRAM()
|
||||
Changes the current video ram address. Expects a *4-aligned* 1024-byte
|
||||
buffer.
|
||||
|
||||
@arg New video ram address.
|
||||
*/
|
||||
void display_useVRAM(void *ptr)
|
||||
{
|
||||
vram = (int *)ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Global drawing functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
dupdate()
|
||||
Displays the vram on the physical screen.
|
||||
*/
|
||||
void dupdate(void)
|
||||
{
|
||||
screen_display((const void *)local_vram);
|
||||
}
|
||||
|
||||
/*
|
||||
dclear()
|
||||
Clears the whole vram.
|
||||
*/
|
||||
void dclear(void)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 256; i++) vram[i] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
dclear_area()
|
||||
Clears an area of the vram using rectangle masks.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
*/
|
||||
void dclear_area(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
unsigned int masks[4];
|
||||
adjust(&x1, &y1, &x2, &y2);
|
||||
getmasks(x1, x2, masks);
|
||||
|
||||
int offset = y1 << 2;
|
||||
int end = (y2 + 1) << 2;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 4; i++) masks[i] = ~masks[i];
|
||||
while(offset < end) vram[offset] &= masks[offset & 3], offset++;
|
||||
}
|
||||
|
||||
/*
|
||||
dreverse_area()
|
||||
Reverses an area of the vram. This function is a simple application of
|
||||
the rectangle masks concept.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
*/
|
||||
void dreverse_area(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
unsigned int masks[4];
|
||||
adjust(&x1, &y1, &x2, &y2);
|
||||
getmasks(x1, x2, masks);
|
||||
|
||||
int offset = y1 << 2;
|
||||
int end = (y2 + 1) << 2;
|
||||
|
||||
while(offset < end) vram[offset] ^= masks[offset & 3], offset++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Local drawing functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
dpixel()
|
||||
Puts a pixel on the screen.
|
||||
|
||||
@arg x
|
||||
@arg y
|
||||
@arg color
|
||||
*/
|
||||
void dpixel(int x, int y, enum Color color)
|
||||
{
|
||||
if((unsigned int)x > 127 || (unsigned int)y > 63) return;
|
||||
int offset = (y << 2) + (x >> 5);
|
||||
int mask = 0x80000000 >> (x & 31);
|
||||
|
||||
switch(color)
|
||||
{
|
||||
case Color_White:
|
||||
vram[offset] &= ~mask;
|
||||
break;
|
||||
|
||||
case Color_Black:
|
||||
vram[offset] |= mask;
|
||||
break;
|
||||
|
||||
case Color_None:
|
||||
return;
|
||||
|
||||
case Color_Invert:
|
||||
vram[offset] ^= mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
dline()
|
||||
Draws a line on the screen. Automatically optimizes horizontal and
|
||||
vertical lines.
|
||||
|
||||
@arg x1
|
||||
@arg y1
|
||||
@arg x2
|
||||
@arg y2
|
||||
@arg color
|
||||
*/
|
||||
|
||||
static void dhline(int x1, int x2, int y, enum Color color)
|
||||
{
|
||||
unsigned int masks[4];
|
||||
int offset = y << 2;
|
||||
int i;
|
||||
|
||||
getmasks(x1, x2, masks);
|
||||
|
||||
switch(color)
|
||||
{
|
||||
case Color_White:
|
||||
for(i = 0; i < 4; i++) vram[offset + i] &= ~masks[i];
|
||||
break;
|
||||
|
||||
case Color_Black:
|
||||
for(i = 0; i < 4; i++) vram[offset + i] |= masks[i];
|
||||
break;
|
||||
|
||||
case Color_None:
|
||||
return;
|
||||
|
||||
case Color_Invert:
|
||||
for(i = 0; i < 4; i++) vram[offset + i] ^= masks[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void dvline(int y1, int y2, int x, enum Color color)
|
||||
{
|
||||
int offset = (y1 << 2) + (x >> 5);
|
||||
int end = (y2 << 2) + (x >> 5);
|
||||
int mask = 0x80000000 >> (x & 31);
|
||||
|
||||
switch(color)
|
||||
{
|
||||
case Color_White:
|
||||
while(offset <= end) vram[offset] &= ~mask, offset += 4;
|
||||
break;
|
||||
|
||||
case Color_Black:
|
||||
while(offset <= end) vram[offset] |= mask, offset += 4;
|
||||
break;
|
||||
|
||||
case Color_None:
|
||||
return;
|
||||
|
||||
case Color_Invert:
|
||||
while(offset <= end) vram[offset] ^= mask, offset += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dline(int x1, int y1, int x2, int y2, enum Color color)
|
||||
{
|
||||
adjust(&x1, &y1, &x2, &y2);
|
||||
|
||||
// Possible optimizations.
|
||||
if(y1 == y2)
|
||||
{
|
||||
dhline(x1, x2, y1, color);
|
||||
return;
|
||||
}
|
||||
if(x1 == x2)
|
||||
{
|
||||
dvline(y1, y2, x1, color);
|
||||
return;
|
||||
}
|
||||
|
||||
int i, x = x1, y = y1, cumul;
|
||||
int dx = x2 - x1, dy = y2 - y1;
|
||||
int sx = sgn(dx), sy = sgn(dy);
|
||||
|
||||
dx = abs(dx), dy = abs(dy);
|
||||
|
||||
dpixel(x1, y1, color);
|
||||
|
||||
if(dx >= dy)
|
||||
{
|
||||
cumul = dx >> 1;
|
||||
for(i = 1; i < dx; i++)
|
||||
{
|
||||
x += sx;
|
||||
cumul += dy;
|
||||
if(cumul > dx) cumul -= dx, y += sy;
|
||||
dpixel(x, y, color);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cumul = dy >> 1;
|
||||
for(i = 1; i < dy; i++)
|
||||
{
|
||||
y += sy;
|
||||
cumul += dx;
|
||||
if(cumul > dy) cumul -= dy, x += sx;
|
||||
dpixel(x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
dpixel(x2, y2, color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Image drawing. There is only one public function dimage(), but there
|
||||
// are lots of local methods and optimizations.
|
||||
//
|
||||
// Some expressions may look nonsense sometimes. The procedure is always
|
||||
// the same : get a part of the image in an operator, shift it depending
|
||||
// on the drawing x-coordinate, compute a mask that indicates which bits
|
||||
// of the operator contain information, and modify a vram long using the
|
||||
// operator.
|
||||
//---
|
||||
|
||||
/*
|
||||
bopti_op()
|
||||
Operates on a vram long. The operator will often not contain 32 bits of
|
||||
image information. In this case, the bits outside the image must be set
|
||||
to 0 for Or and Invert operations... 1 for And operations. Which means
|
||||
that the calling produre must indicate what part of the operator
|
||||
belongs to the image, which is done through the image_mask argument.
|
||||
|
||||
@arg offset Vram offset where edition is planned.
|
||||
@arg operator Longword to operate with.
|
||||
@arg image_mask Part of the operator that is inside the image.
|
||||
@arg mode Operation mode.
|
||||
*/
|
||||
static void bopti_op(int offset, uint32_t operator, uint32_t image_mask,
|
||||
enum BlendingMode mode)
|
||||
{
|
||||
if(mode & Blend_Checker) operator &= 0x55555555;
|
||||
if(mode & Blend_Or) vram[offset] |= operator;
|
||||
if(mode & Blend_Invert) vram[offset] ^= operator;
|
||||
operator |= ~image_mask;
|
||||
if(mode & Blend_And) vram[offset] &= operator;
|
||||
}
|
||||
|
||||
/*
|
||||
bopti_grid() -- general form
|
||||
bopti_grid_a32() -- when x is a multiple of 32
|
||||
|
||||
Draws a layer, whose width is a multiple of 32, in the vram.
|
||||
The need for bopti_grid_a32() is not only linked to optimization,
|
||||
because one of the bit shifts in bopti_grid() will reach 32 when x is
|
||||
a multiple of 32, which is undefined behavior.
|
||||
|
||||
@arg layer Raw column data (column data is located at the
|
||||
beginning of layer data).
|
||||
@arg column_number
|
||||
@arg width
|
||||
@arg height
|
||||
@arg x
|
||||
@arg y
|
||||
@arg mode
|
||||
*/
|
||||
|
||||
static void bopti_grid_a32(const uint32_t *layer, int column_number, int width,
|
||||
int height, int x, int y, enum BlendingMode mode)
|
||||
{
|
||||
int vram_column_offset = (y << 2) + (x >> 5);
|
||||
int vram_offset = vram_column_offset;
|
||||
|
||||
int column, line;
|
||||
uint32_t operator, and_mask;
|
||||
uint32_t rightest_and_mask;
|
||||
|
||||
if(width & 31) rightest_and_mask = ~(0xffffffff >> (width & 31));
|
||||
else rightest_and_mask = 0xffffffff;
|
||||
|
||||
for(column = 0; column < column_number; column++)
|
||||
{
|
||||
for(line = 0; line < height; line++)
|
||||
{
|
||||
operator = *layer++;
|
||||
|
||||
and_mask = (column < column_number - 1) ?
|
||||
(0xffffffff) : (rightest_and_mask);
|
||||
bopti_op(vram_offset, operator, and_mask, mode);
|
||||
vram_offset += 4;
|
||||
}
|
||||
|
||||
vram_column_offset++;
|
||||
vram_offset = vram_column_offset;
|
||||
}
|
||||
}
|
||||
|
||||
static void bopti_grid(const uint32_t *layer, int column_number, int width,
|
||||
int height, int x, int y, enum BlendingMode mode)
|
||||
{
|
||||
const uint32_t *p1, *p2;
|
||||
uint32_t l1, l2;
|
||||
int right_column, line;
|
||||
|
||||
int vram_column_offset = (y << 2) + (x >> 5);
|
||||
int vram_offset = vram_column_offset;
|
||||
|
||||
int shift1 = 32 - (x & 31);
|
||||
int shift2 = (x & 31);
|
||||
int combined_shift_last = shift1 + 32 - (width & 31);
|
||||
|
||||
uint32_t operator, and_mask;
|
||||
uint32_t and_mask_0 = 0xffffffff >> shift2;
|
||||
uint32_t and_mask_1 = (0xffffffff) << combined_shift_last;
|
||||
|
||||
if(!column_number) return;
|
||||
if(!(x & 31))
|
||||
{
|
||||
bopti_grid_a32(layer, column_number, width, height, x, y,
|
||||
mode);
|
||||
return;
|
||||
}
|
||||
|
||||
// Initializing two pointers. Since the columns are written one after
|
||||
// another, they will be updated directly to parse the whole grid.
|
||||
p1 = layer - height;
|
||||
p2 = layer;
|
||||
|
||||
// Drawing vram longwords, using pairs of columns.
|
||||
for(right_column = 0; right_column <= column_number; right_column++)
|
||||
{
|
||||
for(line = 0; line < height; line++)
|
||||
{
|
||||
l1 = (right_column > 0) ? (*p1) : (0);
|
||||
l2 = (right_column < column_number) ? (*p2) : (0);
|
||||
p1++, p2++;
|
||||
|
||||
operator = (l1 << shift1) | (l2 >> shift2);
|
||||
|
||||
and_mask = 0xffffffff;
|
||||
if(!right_column) and_mask &= and_mask_0;
|
||||
if(right_column == column_number)
|
||||
and_mask &= and_mask_1;
|
||||
|
||||
bopti_op(vram_offset, operator, and_mask, mode);
|
||||
vram_offset += 4;
|
||||
}
|
||||
|
||||
vram_column_offset++;
|
||||
vram_offset = vram_column_offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bopti_rest8() -- general form, width below 8
|
||||
bopti_rest8_nover() -- when the rest does not meet two longs
|
||||
bopti_rest16() -- general form, width below 16
|
||||
bopti_rest16_nover() -- when the rest does not meet two longs
|
||||
|
||||
Draw rests of row size of 8 and 16 bits, respectively.
|
||||
|
||||
@arg rest Rest data, located at the end of the layer data.
|
||||
@arh width
|
||||
@arg height
|
||||
@arg x
|
||||
@arg y
|
||||
@arg mode
|
||||
*/
|
||||
|
||||
static void bopti_rest8_nover(const uint8_t *rest, int width, int height,
|
||||
int x, int y, enum BlendingMode mode)
|
||||
{
|
||||
int vram_offset = (y << 2) + (x >> 5);
|
||||
int shift = x & 31;
|
||||
|
||||
uint32_t operator;
|
||||
uint32_t and_mask = ~(0xffffffff >> width) >> shift;
|
||||
int line;
|
||||
|
||||
for(line = 0; line < height; line++)
|
||||
{
|
||||
operator = *rest++;
|
||||
// Optimization possible ? Probably not.
|
||||
operator <<= 24;
|
||||
operator >>= shift;
|
||||
|
||||
bopti_op(vram_offset, operator, and_mask, mode);
|
||||
vram_offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void bopti_rest8(const uint8_t *rest, int width, int height, int x,
|
||||
int y, enum BlendingMode mode)
|
||||
{
|
||||
if((x & 31) + width < 32)
|
||||
{
|
||||
bopti_rest8_nover(rest, width, height, x, y, mode);
|
||||
return;
|
||||
}
|
||||
|
||||
int vram_offset = (y << 2) + (x >> 5);
|
||||
int shift1 = (x & 31) - 24;
|
||||
int shift2 = 56 - (x & 31);
|
||||
uint32_t and_mask_1 = 0xffffffff >> (x & 31);
|
||||
uint32_t and_mask_2 = ~(0xffffffff >> ((x & 31) + width - 32));
|
||||
|
||||
uint32_t operator;
|
||||
int line;
|
||||
|
||||
for(line = 0; line < height; line++)
|
||||
{
|
||||
operator = *rest++;
|
||||
|
||||
bopti_op(vram_offset, operator >> shift1, and_mask_1, mode);
|
||||
bopti_op(vram_offset + 1, operator << shift2, and_mask_2,
|
||||
mode);
|
||||
vram_offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void bopti_rest16_nover(const uint16_t *rest, int width, int height,
|
||||
int x, int y, enum BlendingMode mode)
|
||||
{
|
||||
int vram_offset = (y << 2) + (x >> 5);
|
||||
int shift = x & 31;
|
||||
|
||||
uint32_t operator;
|
||||
uint32_t and_mask = ~(0xffffffff >> width) >> shift;
|
||||
int line;
|
||||
|
||||
for(line = 0; line < height; line++)
|
||||
{
|
||||
operator = *rest++;
|
||||
// As far as I know, no, we can't optimize this into a single
|
||||
// shift.
|
||||
operator <<= 16;
|
||||
operator >>= shift;
|
||||
|
||||
bopti_op(vram_offset, operator, and_mask, mode);
|
||||
vram_offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void bopti_rest16(const uint16_t *rest, int width, int height, int x,
|
||||
int y, enum BlendingMode mode)
|
||||
{
|
||||
if((x & 31) + width < 32)
|
||||
{
|
||||
bopti_rest16_nover(rest, width, height, x, y, mode);
|
||||
return;
|
||||
}
|
||||
|
||||
int vram_offset = (y << 2) + (x >> 5);
|
||||
int shift1 = (x & 31) - 16;
|
||||
int shift2 = 48 - (x & 31);
|
||||
uint32_t and_mask_1 = 0xffffffff >> (x & 31);
|
||||
uint32_t and_mask_2 = ~(0xffffffff >> ((x & 31) + width - 32));
|
||||
|
||||
uint32_t operator;
|
||||
int line;
|
||||
|
||||
for(line = 0; line < height; line++)
|
||||
{
|
||||
operator = *rest++;
|
||||
|
||||
bopti_op(vram_offset, operator >> shift1, and_mask_1, mode);
|
||||
bopti_op(vram_offset + 1, operator << shift2, and_mask_2,
|
||||
mode);
|
||||
vram_offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bopti()
|
||||
Draws an image layer in the video ram.
|
||||
|
||||
@arg bitmap Raw layer data.
|
||||
@arg x
|
||||
@arg y
|
||||
@arg width
|
||||
@arg height
|
||||
@arg mode
|
||||
*/
|
||||
void bopti(const unsigned char *layer, int x, int y, int width, int height,
|
||||
enum BlendingMode mode)
|
||||
{
|
||||
int column_number = width >> 5;
|
||||
int rest_width = width & 31;
|
||||
int grid_width = width & ~31;
|
||||
|
||||
if(rest_width > 16)
|
||||
{
|
||||
column_number++;
|
||||
rest_width = 0;
|
||||
grid_width = width;
|
||||
}
|
||||
|
||||
const unsigned char *rest = layer + ((column_number * height) << 2);
|
||||
int rest_x = x + (width - rest_width);
|
||||
|
||||
bopti_grid((const uint32_t *)layer, column_number, grid_width, height,
|
||||
x, y, mode);
|
||||
if(!rest_width) return;
|
||||
|
||||
if(rest_width <= 8)
|
||||
bopti_rest8((const uint8_t *)rest, rest_width, height, rest_x,
|
||||
y, mode);
|
||||
else
|
||||
bopti_rest16((const uint16_t *)rest, rest_width, height,
|
||||
rest_x, y, mode);
|
||||
}
|
||||
|
||||
/*
|
||||
dimage()
|
||||
Displays an image in the vram.
|
||||
|
||||
@arg image
|
||||
@arg x
|
||||
@arg y
|
||||
@arg mode
|
||||
*/
|
||||
|
||||
void dimage(struct Image *image, int x, int y, enum BlendingMode mode)
|
||||
{
|
||||
int width = image->width;
|
||||
int height = image->height;
|
||||
const unsigned char *data = (const unsigned char *)&(image->data);
|
||||
|
||||
// Computing the layer size.
|
||||
int columns = image->width >> 5;
|
||||
int rest = image->width & 31;
|
||||
int rest_size =
|
||||
!rest ? 0 :
|
||||
rest <= 8 ? 1 :
|
||||
rest <= 16 ? 2 :
|
||||
4;
|
||||
int layer_size = ((columns << 2) + rest_size) * image->height;
|
||||
// The layer size must be a multiple of 4.
|
||||
if(layer_size & 3) layer_size += 4 - (layer_size & 3);
|
||||
|
||||
switch(image->format & ImageFormat_ColorMask)
|
||||
{
|
||||
case ImageFormat_Mono:
|
||||
if(image->format & ImageFormat_Alpha)
|
||||
{
|
||||
bopti(data + layer_size, x, y, width, height,
|
||||
Blend_And);
|
||||
}
|
||||
bopti(data, x, y, width, height, mode);
|
||||
break;
|
||||
|
||||
case ImageFormat_Gray:
|
||||
if(image->format & ImageFormat_Alpha)
|
||||
{
|
||||
bopti(data + 2 * layer_size, x, y, width, height,
|
||||
Blend_And);
|
||||
}
|
||||
|
||||
display_useVRAM(gray_darkVRAM());
|
||||
bopti(data, x, y, width, height, mode);
|
||||
display_useVRAM(gray_lightVRAM());
|
||||
bopti(data + layer_size, x, y, width, height, mode);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
#include <gint.h>
|
||||
#include <mpu.h>
|
||||
#include <gray.h>
|
||||
|
||||
//---
|
||||
// Local variables.
|
||||
//---
|
||||
|
||||
static unsigned int
|
||||
new_vbr,
|
||||
sys_vbr;
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Local functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_setup()
|
||||
Configures interrupt priorities and some parameters to allow gint to
|
||||
take control of the interrupt flow.
|
||||
*/
|
||||
static void gint_setup(void)
|
||||
{
|
||||
if(isSH3())
|
||||
gint_setup_7705();
|
||||
else
|
||||
gint_setup_7305();
|
||||
}
|
||||
|
||||
/*
|
||||
gint_stop()
|
||||
Un-configures the interrupt flow to give back the interrupt control to
|
||||
the system.
|
||||
*/
|
||||
static void gint_stop(void)
|
||||
{
|
||||
if(isSH3())
|
||||
gint_stop_7705();
|
||||
else
|
||||
gint_stop_7305();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Public API.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_systemVBR()
|
||||
Returns the vbr address used by the system (saved when execution
|
||||
starts).
|
||||
|
||||
@return vbr address used by the system.
|
||||
*/
|
||||
unsigned int gint_systemVBR(void)
|
||||
{
|
||||
return sys_vbr;
|
||||
}
|
||||
|
||||
/*
|
||||
gint()
|
||||
Handles interrupts.
|
||||
*/
|
||||
void gint(void)
|
||||
{
|
||||
if(isSH3())
|
||||
gint_7705();
|
||||
else
|
||||
gint_7305();
|
||||
}
|
||||
|
||||
/*
|
||||
gint_init()
|
||||
Initializes gint. Loads the interrupt handler into the memory and sets
|
||||
the new vbr address.
|
||||
*/
|
||||
void gint_init(void)
|
||||
{
|
||||
// Linker script symbols -- gint.
|
||||
extern unsigned int
|
||||
gint_vbr,
|
||||
gint_data,
|
||||
bgint, egint;
|
||||
|
||||
unsigned int *ptr = &bgint;
|
||||
unsigned int *src = &gint_data;
|
||||
|
||||
// Loading the interrupt handler into the memory.
|
||||
while(ptr < &egint) *ptr++ = *src++;
|
||||
|
||||
sys_vbr = gint_getVBR();
|
||||
new_vbr = (unsigned int)&gint_vbr;
|
||||
|
||||
gint_setVBR(new_vbr, gint_setup);
|
||||
}
|
||||
|
||||
/*
|
||||
gint_quit()
|
||||
Stops gint. Restores the system's configuration and vbr address.
|
||||
*/
|
||||
void gint_quit(void)
|
||||
{
|
||||
gint_setVBR(sys_vbr, gint_stop);
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
#include <gint.h>
|
||||
#include <7305.h>
|
||||
|
||||
extern void print_hex(unsigned int value, int x, int y);
|
||||
extern void print_bin(unsigned char value, int x, int y);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Interrupt codes.
|
||||
//---
|
||||
|
||||
#define IC_RTC_PRI 0xaa0
|
||||
#define IC_KEYSC 0xbe0
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Keyboard management.
|
||||
//---
|
||||
|
||||
extern volatile unsigned char keyboard_state[10];
|
||||
extern void keyboard_interrupt(void);
|
||||
|
||||
/*
|
||||
kdelay()
|
||||
Should sleep during a few milliseconds. Well...
|
||||
This delay has a great influence on key detection. Here are a few
|
||||
observations of what happens with common numbers of "nop" (without
|
||||
overclock). Take care of the effect of overclock !
|
||||
|
||||
Column effects
|
||||
May have something to do with register HIZCRB not being used here. When
|
||||
many keys on the same column are pressed, other keys of the same column
|
||||
may be triggered.
|
||||
|
||||
- Less Bad key detection.
|
||||
- 8 Very few column effects. Most often, three keys may be pressed
|
||||
simultaneously. However, [UP] has latencies and is globally not
|
||||
detected.
|
||||
- 12 Seems best. Every individual key is detected well. No column
|
||||
effect observed before four keys.
|
||||
- 16 Every single key is detected correctly. Pressing two keys on a
|
||||
same column does not usually create a column effect. Three keys
|
||||
almost always.
|
||||
- More Does not improve single key detection, and increase column
|
||||
effects. At 256 every single key press create a whole column
|
||||
effect.
|
||||
*/
|
||||
static void kdelay(void)
|
||||
{
|
||||
#define r4(str) str str str str
|
||||
|
||||
__asm__
|
||||
(
|
||||
r4("nop\n\t")
|
||||
r4("nop\n\t")
|
||||
r4("nop\n\t")
|
||||
);
|
||||
|
||||
#undef r4
|
||||
}
|
||||
|
||||
/*
|
||||
krow()
|
||||
Reads a keyboard row. Works like krow() for SH7705. See gint_7705.c for
|
||||
more details.
|
||||
|
||||
@arg row Row to check (0 <= row <= 9).
|
||||
@return Bit-based representation of pressed keys in the checked row.
|
||||
*/
|
||||
static int krow(int row)
|
||||
{
|
||||
volatile unsigned short *injector1 = (unsigned short *)0xa4050116;
|
||||
volatile unsigned char *data1 = (unsigned char *)0xa4050136;
|
||||
|
||||
volatile unsigned short *injector2 = (unsigned short *)0xa4050118;
|
||||
volatile unsigned char *data2 = (unsigned char *)0xa4050138;
|
||||
|
||||
volatile unsigned short *detector = (unsigned short *)0xa405014c;
|
||||
volatile unsigned char *keys = (unsigned char *)0xa405016c;
|
||||
|
||||
volatile unsigned char *key_register = (unsigned char *)0xa40501c6;
|
||||
// volatile unsigned short *hizcrb = (unsigned short *)0xa405015a;
|
||||
|
||||
unsigned short smask;
|
||||
unsigned char cmask;
|
||||
int result = 0;
|
||||
|
||||
if(row < 0 || row > 9) return 0;
|
||||
|
||||
// Additional configuration for SH7305.
|
||||
*detector = 0xaaaa;
|
||||
*key_register = 0xff;
|
||||
*injector1 = (*injector1 & 0xf000) | 0x0555;
|
||||
*injector2 = (*injector2 & 0xf000) | 0x0555;
|
||||
*data1 |= 0x3f;
|
||||
*data2 |= 0x3f;
|
||||
kdelay();
|
||||
|
||||
if(row < 6)
|
||||
{
|
||||
smask = 0x0003 << (row * 2);
|
||||
cmask = ~(1 << row);
|
||||
|
||||
*injector1 = ((*injector1 & 0xf000) | 0x0aaa) ^ smask;
|
||||
*injector2 = (*injector2 & 0xf000) | 0x0aaa;
|
||||
kdelay();
|
||||
|
||||
*data1 = (*data1 & 0xc0) | cmask;
|
||||
*data2 |= 0x3f;
|
||||
kdelay();
|
||||
}
|
||||
else
|
||||
{
|
||||
smask = 0x0003 << ((row - 6) * 2);
|
||||
cmask = ~(1 << (row - 6));
|
||||
|
||||
*injector1 = (*injector1 & 0xf000) | 0x0aaa;
|
||||
*injector2 = ((*injector2 & 0xf000) | 0x0aaa) ^ smask;
|
||||
kdelay();
|
||||
|
||||
*data1 |= 0x3f;
|
||||
*data2 = (*data2 & 0xc0) | cmask;
|
||||
kdelay();
|
||||
}
|
||||
|
||||
// Reading the keyboard row.
|
||||
result = ~*keys;
|
||||
kdelay();
|
||||
|
||||
// Re-initializing the port configuration and data.
|
||||
*injector1 = (*injector1 & 0xf000) | 0x0aaa;
|
||||
*injector2 = (*injector2 & 0xf000) | 0x0aaa;
|
||||
kdelay();
|
||||
*injector1 = (*injector1 & 0xf000) | 0x0555;
|
||||
*injector2 = (*injector2 & 0xf000) | 0x0555;
|
||||
kdelay();
|
||||
*data1 &= 0xc0;
|
||||
*data2 &= 0xc0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
kstate()
|
||||
Updates the keyboard state.
|
||||
*/
|
||||
static void kstate(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 10; i++) keyboard_state[i] = krow(i);
|
||||
|
||||
keyboard_interrupt();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Interrupt handler.
|
||||
//---
|
||||
|
||||
void gint_7305(void)
|
||||
{
|
||||
volatile unsigned int *intevt = (unsigned int *)0xff000028;
|
||||
unsigned int code = *intevt;
|
||||
|
||||
switch(code)
|
||||
{
|
||||
case IC_RTC_PRI:
|
||||
// Clearing the interrupt flag.
|
||||
RTC.RCR2.PEF = 0;
|
||||
// Updating the keyboard state.
|
||||
kstate();
|
||||
/*
|
||||
print_bin(keyboard_state[0], 0, 2);
|
||||
print_bin(keyboard_state[1], 0, 3);
|
||||
print_bin(keyboard_state[2], 0, 4);
|
||||
print_bin(keyboard_state[3], 0, 5);
|
||||
print_bin(keyboard_state[4], 0, 6);
|
||||
|
||||
print_bin(keyboard_state[5], 9, 2);
|
||||
print_bin(keyboard_state[6], 9, 3);
|
||||
print_bin(keyboard_state[7], 9, 4);
|
||||
print_bin(keyboard_state[8], 9, 5);
|
||||
print_bin(keyboard_state[9], 9, 6);
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Setup.
|
||||
//---
|
||||
|
||||
static unsigned short ipr[12];
|
||||
static unsigned char rcr2;
|
||||
// Saves of the keyboard registres. Could be better.
|
||||
static unsigned short inj1, inj2, det;
|
||||
static unsigned char data1, data2, keys, reg;
|
||||
|
||||
static void gint_priority_lock_7305(void)
|
||||
{
|
||||
// Saving the current interrupt priorities.
|
||||
ipr[0] = INTX.IPRA.WORD;
|
||||
ipr[1] = INTX.IPRB.WORD;
|
||||
ipr[2] = INTX.IPRC.WORD;
|
||||
ipr[3] = INTX.IPRD.WORD;
|
||||
ipr[4] = INTX.IPRE.WORD;
|
||||
ipr[5] = INTX.IPRF.WORD;
|
||||
ipr[6] = INTX.IPRG.WORD;
|
||||
ipr[7] = INTX.IPRH.WORD;
|
||||
ipr[8] = INTX.IPRI.WORD;
|
||||
ipr[9] = INTX.IPRJ.WORD;
|
||||
ipr[10] = INTX.IPRK.WORD;
|
||||
ipr[11] = INTX.IPRL.WORD;
|
||||
|
||||
// Disabling everything by default to avoid freezing on unhandled
|
||||
// interrupts.
|
||||
INTX.IPRA.WORD = 0x0000;
|
||||
INTX.IPRB.WORD = 0x0000;
|
||||
INTX.IPRC.WORD = 0x0000;
|
||||
INTX.IPRD.WORD = 0x0000;
|
||||
INTX.IPRE.WORD = 0x0000;
|
||||
INTX.IPRF.WORD = 0x0000;
|
||||
INTX.IPRG.WORD = 0x0000;
|
||||
INTX.IPRH.WORD = 0x0000;
|
||||
INTX.IPRI.WORD = 0x0000;
|
||||
INTX.IPRJ.WORD = 0x0000;
|
||||
INTX.IPRK.WORD = 0x0000;
|
||||
INTX.IPRL.WORD = 0x0000;
|
||||
|
||||
// Saving keyboard registers.
|
||||
inj1 = *((volatile unsigned short *)0xa4050116);
|
||||
data1 = *((volatile unsigned char *)0xa4050136);
|
||||
inj2 = *((volatile unsigned short *)0xa4050118);
|
||||
data2 = *((volatile unsigned char *)0xa4050138);
|
||||
det = *((volatile unsigned short *)0xa405014c);
|
||||
keys = *((volatile unsigned char *)0xa405016c);
|
||||
reg = *((volatile unsigned char *)0xa40501c6);
|
||||
|
||||
// Allowing RTC. Keyboard analysis is done regularly using a RTC
|
||||
// because SH7305's special KEYSC interface does not allow us to clear
|
||||
// the keyboard interrupt flags.
|
||||
INTX.IPRK._RTC = GINT_INTP_RTC;
|
||||
}
|
||||
|
||||
static void gint_priority_unlock_7305(void)
|
||||
{
|
||||
// Restoring the interrupt priorities.
|
||||
INTX.IPRA.WORD = ipr[0];
|
||||
INTX.IPRB.WORD = ipr[1];
|
||||
INTX.IPRC.WORD = ipr[2];
|
||||
INTX.IPRD.WORD = ipr[3];
|
||||
INTX.IPRE.WORD = ipr[4];
|
||||
INTX.IPRF.WORD = ipr[5];
|
||||
INTX.IPRG.WORD = ipr[6];
|
||||
INTX.IPRH.WORD = ipr[7];
|
||||
INTX.IPRI.WORD = ipr[8];
|
||||
INTX.IPRJ.WORD = ipr[9];
|
||||
INTX.IPRK.WORD = ipr[10];
|
||||
INTX.IPRL.WORD = ipr[11];
|
||||
|
||||
// Restoring keyboard registers.
|
||||
*((volatile unsigned short *)0xa4050116) = inj1;
|
||||
*((volatile unsigned char *)0xa4050136) = data1;
|
||||
*((volatile unsigned short *)0xa4050118) = inj2;
|
||||
*((volatile unsigned char *)0xa4050138) = data2;
|
||||
*((volatile unsigned short *)0xa405014c) = det;
|
||||
*((volatile unsigned char *)0xa405016c) = keys;
|
||||
*((volatile unsigned char *)0xa40501c6) = reg;
|
||||
}
|
||||
|
||||
void gint_setup_7305(void)
|
||||
{
|
||||
gint_priority_lock_7305();
|
||||
|
||||
// Configuring the RTC to have a 16-Hz keyboard.
|
||||
rcr2 = RTC.RCR2.BYTE;
|
||||
RTC.RCR2.BYTE = 0x39;
|
||||
}
|
||||
|
||||
void gint_stop_7305(void)
|
||||
{
|
||||
gint_priority_unlock_7305();
|
||||
|
||||
// Stopping the RTC interrupt.
|
||||
RTC.RCR2.BYTE = rcr2;
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
#include <gint.h>
|
||||
#include <7705.h>
|
||||
|
||||
extern void print_hex(unsigned int value, int x, int y);
|
||||
extern void print_bin(unsigned char value, int x, int y);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Interrupt codes.
|
||||
//---
|
||||
|
||||
#define IC_RTC_PRI 0x4a0
|
||||
#define IC_PINT07 0x700
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Keyboard management.
|
||||
//---
|
||||
|
||||
extern volatile unsigned char keyboard_state[10];
|
||||
extern void keyboard_interrupt(void);
|
||||
|
||||
/*
|
||||
kdelay()
|
||||
Low-level sleep using the watchdog.
|
||||
*/
|
||||
static void kdelay(void)
|
||||
{
|
||||
#define r4(str) str str str str
|
||||
|
||||
__asm__
|
||||
(
|
||||
r4("nop\n\t")
|
||||
r4("nop\n\t")
|
||||
r4("nop\n\t")
|
||||
);
|
||||
|
||||
#undef r4
|
||||
|
||||
/*
|
||||
const int delay = 0xf4;
|
||||
|
||||
// Disabling the watchdog timer interrupt and resetting the
|
||||
// configuration. Setting the delay.
|
||||
INTC.IPRB.BIT._WDT = 0;
|
||||
WDT.WTCSR.WRITE = 0xa500;
|
||||
WDT.WTCNT.WRITE = 0x5a00 | (delay & 0xff);
|
||||
|
||||
// Counting on Po/256.
|
||||
WDT.WTCSR.WRITE = 0xa505;
|
||||
// Starting the timer (sets again to Po/256).
|
||||
WDT.WTCSR.WRITE = 0xa585;
|
||||
|
||||
// Waiting until it overflows (delaying), then clearing the overflow
|
||||
// flag.
|
||||
while((WDT.WTCSR.READ.BYTE & 0x08) == 0);
|
||||
WDT.WTCSR.WRITE = 0xa500 | (WDT.WTCSR.READ.BYTE & 0xf7);
|
||||
|
||||
// Resetting the configuration and the counter.
|
||||
WDT.WTCSR.WRITE = 0xa500;
|
||||
WDT.WTCSR.WRITE = 0x5a00;
|
||||
|
||||
// Enabling back the watchdog timer interrupt.
|
||||
INTC.IPRB.BIT._WDT = GINT_INTP_WDT;
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
krow()
|
||||
Reads a keyboard row.
|
||||
|
||||
@arg row Row to check (0 <= row <= 9).
|
||||
@return Bit-based representation of pressed keys in the checked row.
|
||||
*/
|
||||
static int krow(int row)
|
||||
{
|
||||
// '11' on the active row, '00' everywhere else.
|
||||
unsigned short smask = 0x0003 << ((row % 8) * 2);
|
||||
// '0' on the active row, '1' everywhere else.
|
||||
unsigned char cmask = ~(1 << (row % 8));
|
||||
// Line results.
|
||||
int result = 0;
|
||||
|
||||
if(row < 0 || row > 9) return 0;
|
||||
|
||||
// Initial configuration.
|
||||
PFC.PBCR.WORD = 0xaaaa;
|
||||
PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x0055;
|
||||
kdelay();
|
||||
|
||||
if(row < 8)
|
||||
{
|
||||
// Configuring port B/M as input except for the row to check,
|
||||
// which has to be an output. This sets '01' (output) on the
|
||||
// active row, '10' (input) everywhere else.
|
||||
PFC.PBCR.WORD = 0xaaaa ^ smask;
|
||||
PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x00aa;
|
||||
kdelay();
|
||||
|
||||
// Every bit set to 1 except the active row bit.
|
||||
PB.DR.BYTE = cmask;
|
||||
PM.DR.BYTE = (PM.DR.BYTE & 0xf0) | 0x0f;
|
||||
kdelay();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The same, but deals with port M.
|
||||
PFC.PBCR.WORD = 0xaaaa;
|
||||
PFC.PMCR.WORD = ((PFC.PMCR.WORD & 0xff00) | 0x00aa) ^ smask;
|
||||
kdelay();
|
||||
|
||||
PB.DR.BYTE = 0xff;
|
||||
PM.DR.BYTE = (PM.DR.BYTE & 0xf0) | cmask;
|
||||
kdelay();
|
||||
}
|
||||
|
||||
// Reading the keyboard row.
|
||||
result = ~PA.DR.BYTE;
|
||||
kdelay();
|
||||
|
||||
// Re-initializing the port configuration and data.
|
||||
PFC.PBCR.WORD = 0xaaaa;
|
||||
PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x00aa;
|
||||
kdelay();
|
||||
PFC.PBCR.WORD = 0x5555;
|
||||
PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x0055;
|
||||
kdelay();
|
||||
PB.DR.BYTE = 0x00;
|
||||
PM.DR.BYTE &= 0xf0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
kstate()
|
||||
Updates the keyboard state.
|
||||
*/
|
||||
static void kstate(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 10; i++) keyboard_state[i] = krow(i);
|
||||
|
||||
keyboard_interrupt();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Interrupt handler.
|
||||
//---
|
||||
|
||||
void gint_7705(void)
|
||||
{
|
||||
volatile unsigned int *intevt2 = (unsigned int *)0xa4000000;
|
||||
unsigned int code = *intevt2;
|
||||
|
||||
switch(code)
|
||||
{
|
||||
case IC_RTC_PRI:
|
||||
// Clearing the interrupt flag.
|
||||
RTC.RCR2.BIT.PEF = 0;
|
||||
// Updating the keyboard state.
|
||||
kstate();
|
||||
/*
|
||||
print_bin(keyboard_state[0], 0, 2);
|
||||
print_bin(keyboard_state[1], 0, 3);
|
||||
print_bin(keyboard_state[2], 0, 4);
|
||||
print_bin(keyboard_state[3], 0, 5);
|
||||
print_bin(keyboard_state[4], 0, 6);
|
||||
|
||||
print_bin(keyboard_state[5], 9, 2);
|
||||
print_bin(keyboard_state[6], 9, 3);
|
||||
print_bin(keyboard_state[7], 9, 4);
|
||||
print_bin(keyboard_state[8], 9, 5);
|
||||
print_bin(keyboard_state[9], 9, 6);
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Setup.
|
||||
//---
|
||||
|
||||
static unsigned short iprs[8];
|
||||
|
||||
static void gint_priority_lock_7705(void)
|
||||
{
|
||||
// Saving the interrupt masks from registers IPRA to IPRH.
|
||||
iprs[0] = INTC.IPRA.WORD;
|
||||
iprs[1] = INTC.IPRB.WORD;
|
||||
iprs[2] = INTX.IPRC.WORD;
|
||||
iprs[3] = INTX.IPRD.WORD;
|
||||
iprs[4] = INTX.IPRE.WORD;
|
||||
iprs[5] = INTX.IPRF.WORD;
|
||||
iprs[6] = INTX.IPRG.WORD;
|
||||
iprs[7] = INTX.IPRH.WORD;
|
||||
|
||||
// Disabling everything by default to avoid receiving an interrupt that
|
||||
// the handler doesn't handle, which would cause the user program to
|
||||
// freeze.
|
||||
INTC.IPRA.WORD = 0x0000;
|
||||
INTC.IPRB.WORD = 0x0000;
|
||||
INTX.IPRC.WORD = 0x0000;
|
||||
INTX.IPRD.WORD = 0x0000;
|
||||
INTX.IPRE.WORD = 0x0000;
|
||||
INTX.IPRF.WORD = 0x0000;
|
||||
INTX.IPRG.WORD = 0x0000;
|
||||
INTX.IPRH.WORD = 0x0000;
|
||||
|
||||
// Allowing RTC, which handles keyboard.
|
||||
INTC.IPRA.BIT._RTC = GINT_INTP_RTC;
|
||||
}
|
||||
|
||||
static void gint_priority_unlock_7705(void)
|
||||
{
|
||||
// Restoring the saved states.
|
||||
INTC.IPRA.WORD = iprs[0];
|
||||
INTC.IPRB.WORD = iprs[1];
|
||||
INTX.IPRC.WORD = iprs[2];
|
||||
INTX.IPRD.WORD = iprs[3];
|
||||
INTX.IPRE.WORD = iprs[4];
|
||||
INTX.IPRF.WORD = iprs[5];
|
||||
INTX.IPRG.WORD = iprs[6];
|
||||
INTX.IPRH.WORD = iprs[7];
|
||||
}
|
||||
|
||||
void gint_setup_7705(void)
|
||||
{
|
||||
gint_priority_lock_7705();
|
||||
|
||||
// Configuring the RTC to have a 16-Hz keyboard.
|
||||
RTC.RCR2.BYTE = 0x39;
|
||||
}
|
||||
|
||||
void gint_stop_7705(void)
|
||||
{
|
||||
gint_priority_unlock_7705();
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
gint_vbr
|
||||
|
||||
Some of the work, especially related to setting and un-setting the vbr
|
||||
address needs to be done in assembler.
|
||||
*/
|
||||
|
||||
.global _gint_getVBR
|
||||
.global _gint_setVBR
|
||||
|
||||
|
||||
|
||||
/*
|
||||
gint_getVBR()
|
||||
Returns the current vbr address.
|
||||
|
||||
@return vbr address currently in use.
|
||||
*/
|
||||
_gint_getVBR:
|
||||
rts
|
||||
stc vbr, r0
|
||||
|
||||
|
||||
|
||||
/*
|
||||
gint_setVBR()
|
||||
|
||||
This is quite the hard part when modifying the vbr. We need to set
|
||||
immediately the interrupt priorities of our own handler, or restore
|
||||
the ones used by the system ; otherwise we may receive interrupts
|
||||
requests that the new handler doesn't handle, which will cause the
|
||||
whole program to freeze.
|
||||
|
||||
Therefore, we must set vbr *and* change interrupt priorities while
|
||||
having disabled all the interrupts in the status register. That's why
|
||||
this function takes as parameter the priority management function.
|
||||
|
||||
@arg New vbr address.
|
||||
@arg Priority management function.
|
||||
*/
|
||||
_gint_setVBR:
|
||||
sts.l pr, @-r15
|
||||
|
||||
/* Blocking all interrupts. */
|
||||
mov.l sr_block, r0
|
||||
stc sr, r3
|
||||
or r0, r3
|
||||
ldc r3, sr
|
||||
|
||||
/* Setting the vbr address. */
|
||||
ldc r4, vbr
|
||||
|
||||
/* Calling the priority manager. */
|
||||
jsr @r5
|
||||
nop
|
||||
|
||||
/* Activating interrupts again. */
|
||||
mov.l sr_block, r0
|
||||
not r0, r0
|
||||
stc sr, r3
|
||||
and r0, r3
|
||||
ldc r3, sr
|
||||
|
||||
lds.l @r15+, pr
|
||||
rts
|
||||
nop
|
||||
|
||||
.align 4
|
||||
|
||||
sr_block:
|
||||
.long (1 << 28)
|
|
@ -0,0 +1,76 @@
|
|||
#include <display.h>
|
||||
#include <gray.h>
|
||||
#include <screen.h>
|
||||
|
||||
static int internal_vrams[3][256];
|
||||
const void *vrams[4];
|
||||
|
||||
static int current = 0;
|
||||
|
||||
/*
|
||||
gray_start()
|
||||
Starts the gray engine. The control of the screen is transferred to the
|
||||
gray engine.
|
||||
*/
|
||||
void gray_start(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
gray_stop()
|
||||
Stops the gray engine. The monochrome display system takes control of
|
||||
the video ram.
|
||||
*/
|
||||
void gray_stop(void)
|
||||
{
|
||||
display_useVRAM(display_getLocalVRAM());
|
||||
}
|
||||
|
||||
/*
|
||||
gray_lightVRAM()
|
||||
Returns the module's gray vram address.
|
||||
*/
|
||||
void *gray_lightVRAM(void)
|
||||
{
|
||||
return (void *)vrams[current];
|
||||
}
|
||||
|
||||
/*
|
||||
gray_lightVRAM()
|
||||
Returns the module's dark vram address.
|
||||
*/
|
||||
void *gray_darkVRAM(void)
|
||||
{
|
||||
return (void *)vrams[current + 1];
|
||||
}
|
||||
|
||||
/*
|
||||
gray_swap()
|
||||
Swaps the vram buffers.
|
||||
*/
|
||||
void gray_swap(void)
|
||||
{
|
||||
current = (current + 2) & 3;
|
||||
}
|
||||
|
||||
/*
|
||||
gray_interrupt()
|
||||
Answers a timer interrupt. Swaps the two buffers.
|
||||
*/
|
||||
void gray_interrupt(void)
|
||||
{
|
||||
screen_display(vrams[current]);
|
||||
current ^= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
gray_init()
|
||||
Initializes the gray engine.
|
||||
*/
|
||||
void gray_init(void)
|
||||
{
|
||||
vrams[0] = (const void *)display_getLocalVRAM();
|
||||
vrams[1] = (const void *)internal_vrams[0];
|
||||
vrams[2] = (const void *)internal_vrams[1];
|
||||
vrams[3] = (const void *)internal_vrams[2];
|
||||
}
|
|
@ -0,0 +1,444 @@
|
|||
#include <keyboard.h>
|
||||
#include <mpu.h>
|
||||
|
||||
//---
|
||||
// Keyboard variables.
|
||||
//---
|
||||
|
||||
volatile unsigned char keyboard_state[10] = { 0 };
|
||||
static int repeat_first = 10, repeat_next = 2;
|
||||
static int last_key = KEY_NONE, last_repeats = 0, last_events = 0;
|
||||
static volatile int interrupt_flag = 0;
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Auxiliary functions.
|
||||
//---
|
||||
|
||||
/*
|
||||
sleep()
|
||||
Puts the CPU in sleep mode and waits for an interrupt to return.
|
||||
*/
|
||||
void sleep(void)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"sleep\n\t"
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
getPressedKey()
|
||||
Finds a pressed key in the keyboard state and returns it.
|
||||
|
||||
@return A pressed key.
|
||||
*/
|
||||
int getPressedKey(void)
|
||||
{
|
||||
int row = 1, column = 0;
|
||||
int state;
|
||||
if(keyboard_state[0] & 1) return KEY_AC_ON;
|
||||
|
||||
while(row <= 9 && !keyboard_state[row]) row++;
|
||||
if(row > 9) return KEY_NONE;
|
||||
|
||||
state = keyboard_state[row];
|
||||
while(!(state & 1))
|
||||
{
|
||||
state >>= 1;
|
||||
column++;
|
||||
}
|
||||
|
||||
return (column << 4) | row;
|
||||
}
|
||||
|
||||
/*
|
||||
getPressedKeys()
|
||||
Find 'count' pressed keys in the keyboard state.
|
||||
|
||||
@arg keys Will be filled.
|
||||
@arg count Size of array.
|
||||
|
||||
@return Number of actual pressed keys found.
|
||||
*/
|
||||
int getPressedKeys(int *keys, int count)
|
||||
{
|
||||
int row = 1, column;
|
||||
int found = 0, actually_pressed;
|
||||
int state;
|
||||
if(count <= 0) return 0;
|
||||
|
||||
if(keyboard_state[0] & 1)
|
||||
{
|
||||
keys[found++] = KEY_AC_ON;
|
||||
count--;
|
||||
}
|
||||
|
||||
while(count && row <= 9)
|
||||
{
|
||||
while(row <= 9 && !keyboard_state[row]) row++;
|
||||
if(row > 9) break;
|
||||
|
||||
state = keyboard_state[row];
|
||||
column = 0;
|
||||
|
||||
while(count && column < 8)
|
||||
{
|
||||
if(state & 1)
|
||||
{
|
||||
keys[found++] = (column << 4) | row;
|
||||
count--;
|
||||
}
|
||||
|
||||
state >>= 1;
|
||||
column++;
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
|
||||
actually_pressed = found;
|
||||
|
||||
while(count)
|
||||
{
|
||||
keys[found++] = KEY_NONE;
|
||||
count--;
|
||||
}
|
||||
|
||||
return actually_pressed;
|
||||
}
|
||||
|
||||
/*
|
||||
keyboard_interrupt()
|
||||
Callback for keyboard update. Allows keyboard analysis functions to
|
||||
wake only when RTC interrupts happen.
|
||||
*/
|
||||
void keyboard_interrupt(void)
|
||||
{
|
||||
interrupt_flag = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Keyboard configuration.
|
||||
//---
|
||||
|
||||
/*
|
||||
keyboard_setFrequency()
|
||||
Sets the keyboard frequency. Does nothing when the argument is not a
|
||||
valid KeyboardFrequency value.
|
||||
|
||||
@arg frequency
|
||||
*/
|
||||
void keyboard_setFrequency(enum KeyboardFrequency frequency)
|
||||
{
|
||||
volatile unsigned char *rcr2;
|
||||
|
||||
if(frequency < 1 || frequency > 7) return;
|
||||
rcr2 = (unsigned char *)(isSH3() ? 0xfffffede : 0xa413fede);
|
||||
|
||||
frequency <<= 4;
|
||||
*rcr2 = (*rcr2 & 0x8f) | frequency;
|
||||
}
|
||||
|
||||
/*
|
||||
keyboard_setRepeatRate()
|
||||
Sets the default repeat rate for key events. The unit for the argument
|
||||
is the keyboard period.
|
||||
For example at 16 Hz, values of (10, 2) will imitate the system
|
||||
default.
|
||||
|
||||
@arg first Delay before first repeat, in keyboard period units.
|
||||
@arg next Delay before following repeats, in keyboard period
|
||||
units.
|
||||
*/
|
||||
void keyboard_setRepeatRate(int first, int next)
|
||||
{
|
||||
if(first < 0) first = 0;
|
||||
if(next < 0) next = 0;
|
||||
|
||||
repeat_first = first;
|
||||
repeat_next = next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Keyboard access.
|
||||
//---
|
||||
|
||||
/*
|
||||
keylast()
|
||||
Returns the matrix code of the last pressed key. If repeat_count is
|
||||
non-NULL, it is set to the number of repetitions.
|
||||
|
||||
@arg repeat_count
|
||||
@return Key matrix code.
|
||||
*/
|
||||
int keylast(int *repeat_count)
|
||||
{
|
||||
if(repeat_count) *repeat_count = last_repeats;
|
||||
return last_key;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
getkey()
|
||||
Blocking function with auto-repeat and SHIFT modifying functionalities.
|
||||
Roughly reproduces the behavior of the system's GetKey().
|
||||
|
||||
@return Pressed key matrix code.
|
||||
*/
|
||||
int getkey(void)
|
||||
{
|
||||
return getkey_opt(
|
||||
Getkey_ShiftModifier |
|
||||
Getkey_AlphaModifier |
|
||||
|
||||
Getkey_RepeatArrowKeys,
|
||||
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
getkey_opt()
|
||||
Enhances getkey() with most general functionalities.
|
||||
If max_cycles is non-zero and positive, getkey_opt() will return
|
||||
KEY_NOEVENT if no event occurs during max_cycle analysis.
|
||||
|
||||
@arg options OR-combination of GetkeyOpt values.
|
||||
@arg max_cycles
|
||||
|
||||
@return Pressed key matrix code.
|
||||
*/
|
||||
int getkey_opt(enum GetkeyOpt options, int max_cycles)
|
||||
{
|
||||
int key;
|
||||
enum KeyType type;
|
||||
int modifier = 0, last_modifier = KEY_NONE;
|
||||
int r;
|
||||
|
||||
if(!max_cycles) max_cycles = -1;
|
||||
|
||||
while(max_cycles != 0)
|
||||
{
|
||||
while(!interrupt_flag) sleep();
|
||||
interrupt_flag = 0;
|
||||
if(max_cycles > 0) max_cycles--;
|
||||
|
||||
// Getting key and adding modifiers.
|
||||
key = getPressedKey();
|
||||
|
||||
// Handling "no_key" event;
|
||||
if(key == KEY_NONE)
|
||||
{
|
||||
// Condition for returning.
|
||||
r = (last_key != KEY_NONE &&
|
||||
options & Getkey_ReleaseEvent);
|
||||
|
||||
last_key = KEY_NONE;
|
||||
last_modifier = KEY_NONE;
|
||||
last_repeats = 0;
|
||||
last_events = 0;
|
||||
|
||||
if(r) return KEY_NONE;
|
||||
}
|
||||
|
||||
// Handling "new key" events.
|
||||
else if(key != last_key)
|
||||
{
|
||||
if(options & Getkey_ShiftModifier && key == KEY_SHIFT)
|
||||
{
|
||||
if(last_modifier != KEY_SHIFT)
|
||||
modifier ^= MOD_SHIFT;
|
||||
last_modifier = KEY_SHIFT;
|
||||
|
||||
continue;
|
||||
}
|
||||
if(options & Getkey_AlphaModifier && key == KEY_ALPHA)
|
||||
{
|
||||
if(last_modifier != KEY_ALPHA)
|
||||
modifier ^= MOD_ALPHA;
|
||||
last_modifier = KEY_ALPHA;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
last_key = key;
|
||||
last_repeats = 0;
|
||||
last_events = 0;
|
||||
|
||||
return key | modifier;
|
||||
}
|
||||
|
||||
// Handling key repetitions.
|
||||
else
|
||||
{
|
||||
type = keytype(key);
|
||||
|
||||
// Checking whether this key type is repeated.
|
||||
if(options & (type << 4))
|
||||
{
|
||||
last_events++;
|
||||
r = last_repeats ? repeat_next : repeat_first;
|
||||
|
||||
if(last_events >= r)
|
||||
{
|
||||
last_repeats++;
|
||||
last_events = 0;
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When no key was pressed during the given delay...
|
||||
return KEY_NOEVENT;
|
||||
}
|
||||
|
||||
/*
|
||||
multigetkey()
|
||||
Listens the keyboard for simultaneous key hits. Uses the same options
|
||||
as getkey_opt().
|
||||
multigetkey() fills the 'keys' array with 'count' key codes, adding
|
||||
KEY_NOKEY if less than 'count' keys are pressed.
|
||||
Be aware that rectangle and column effects can make multigetkey() read
|
||||
unpressed keys as pressed (see documentation for more information).
|
||||
Setting count = 3 is generally safe.
|
||||
|
||||
@arg keys Key code array.
|
||||
@arg count Maximum number of keys that will be read.
|
||||
@arg max_cycles
|
||||
*/
|
||||
void multigetkey(int *keys, int count, int max_cycles)
|
||||
{
|
||||
int number;
|
||||
|
||||
if(!max_cycles) max_cycles = -1;
|
||||
|
||||
while(max_cycles != 0)
|
||||
{
|
||||
while(!interrupt_flag) sleep();
|
||||
interrupt_flag = 0;
|
||||
if(max_cycles > 0) max_cycles--;
|
||||
|
||||
number = getPressedKeys(keys, count);
|
||||
if(number) return;
|
||||
|
||||
// Handle key repetitions.
|
||||
/*
|
||||
else
|
||||
{
|
||||
type = keytype(key);
|
||||
|
||||
// Checking whether this key type is repeated.
|
||||
if(options & (type << 4))
|
||||
{
|
||||
last_events++;
|
||||
r = last_repeats ? repeat_next : repeat_first;
|
||||
|
||||
if(last_events >= r)
|
||||
{
|
||||
last_repeats++;
|
||||
last_events = 0;
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// When no key was pressed during the given delay... (no need to fill
|
||||
// the array, it has already been done by getPressedKeys()).
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Key analysis.
|
||||
//---
|
||||
|
||||
/*
|
||||
keyid()
|
||||
Returns a non-matrix key code that can be used for array subscript.
|
||||
Ignores modifiers.
|
||||
|
||||
@arg key
|
||||
@return Modified keycode.
|
||||
*/
|
||||
int keyid(int key)
|
||||
{
|
||||
if(key < 0) return -1;
|
||||
key &= MOD_CLEAR;
|
||||
|
||||
int row = 9 - (key & 0x0f);
|
||||
int column = 6 - ((key & 0xf0) >> 4);
|
||||
|
||||
return 6 * row + column;
|
||||
}
|
||||
|
||||
/*
|
||||
keychar()
|
||||
Returns the ASCII character associated with a key, or 0 for control
|
||||
keys.
|
||||
|
||||
@arg key
|
||||
*/
|
||||
int keychar(int key)
|
||||
{
|
||||
char flat[] = {
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, '2', '^', 0x0, 0x0, 0x0,
|
||||
'X', 'l', 'l', 's', 'c', 't',
|
||||
0x0, 0x0, '(', ')', ',', '>',
|
||||
'7', '8', '9', 0x0, 0x0, 0x0,
|
||||
'4', '5', '6', '*', '/', 0x0,
|
||||
'1', '2', '3', '+', '-', 0x0,
|
||||
'0', '.', 'e', '-', 0x0, 0x0
|
||||
};
|
||||
char alpha[] = {
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 'r', 'o', 0x0, 0x0, 0x0,
|
||||
'A', 'B', 'C', 'D', 'E', 'F',
|
||||
'G', 'H', 'I', 'J', 'K', 'L',
|
||||
'M', 'N', 'O', 0x0, 0x0, 0x0,
|
||||
'P', 'Q', 'R', 'S', 'T', 0x0,
|
||||
'U', 'V', 'W', 'X', 'Y', 0x0,
|
||||
'Z', ' ', '"', 0x0, 0x0, 0x0
|
||||
};
|
||||
|
||||
int id = keyid(key);
|
||||
|
||||
if(key & MOD_ALPHA) return alpha[id];
|
||||
return flat[id];
|
||||
}
|
||||
|
||||
/*
|
||||
keytype()
|
||||
Returns a key's type. Ignores modifiers.
|
||||
|
||||
@arg key
|
||||
@return Key type.
|
||||
*/
|
||||
enum KeyType keytype(int key)
|
||||
{
|
||||
key &= MOD_CLEAR;
|
||||
|
||||
if(key == KEY_UP || key == KEY_RIGHT || key == KEY_DOWN ||
|
||||
key == KEY_LEFT) return KeyType_Arrow;
|
||||
|
||||
if((key & 0x0f) == 0x09) return KeyType_Function;
|
||||
|
||||
return keychar(key) ? KeyType_Character : KeyType_Control;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
#include <mpu.h>
|
||||
|
||||
enum MPU MPU_CURRENT;
|
||||
|
||||
/*
|
||||
getMPU()
|
||||
|
||||
Returns the MPU identifier of the calculator.
|
||||
Thanks to SimonLothar for this function and related informations.
|
||||
|
||||
Processor version register (PVR) and product control register (PRR)
|
||||
hold information about the MPU version but are only accessible for
|
||||
SH-4-based MPUs.
|
||||
Therefore, this function uses port L control register (PLCR), whose
|
||||
bits 8 to 15 cannot be set with SH7337 where bits 8 to 11 can be set
|
||||
with SH7355.
|
||||
|
||||
Additionally, the CPU core ID register (CPIDR) at 0xff000048 returns 1
|
||||
on SH7305.
|
||||
|
||||
@return MPU identifier as integer value.
|
||||
*/
|
||||
|
||||
enum MPU getMPU(void)
|
||||
{
|
||||
// Processor version register.
|
||||
volatile unsigned int *pvr = (unsigned int *)0xff000030;
|
||||
// Product version register.
|
||||
volatile unsigned int *prr = (unsigned int *)0xff000044;
|
||||
// Port L control register.
|
||||
volatile unsigned short *plcr = (unsigned short *)0xa4000114;
|
||||
// Saved value for PLCR.
|
||||
unsigned short saved_plcr;
|
||||
unsigned int tested_plcr;
|
||||
|
||||
|
||||
// Looking for SH-3-based MPUs by testing PLCR writing access.
|
||||
saved_plcr = *plcr;
|
||||
*plcr = 0xffff;
|
||||
tested_plcr = *plcr;
|
||||
*plcr = saved_plcr;
|
||||
|
||||
// Checking whether we are working with an SH7337 or an SH7355.
|
||||
if(tested_plcr == 0x00ff) return MPU_SH7337;
|
||||
if(tested_plcr == 0x0fff) return MPU_SH7355;
|
||||
|
||||
// Looking for SH-4-based MPUs by testing the version registers. This
|
||||
// needs to have the three upper bytes of the processor version
|
||||
// register match 0x10300b :
|
||||
if((*pvr & 0xffffff00) != 0x10300b00) return MPU_Unknown;
|
||||
|
||||
// Now that we have an SH-4-based MPU, checking whether it is SH7305 or
|
||||
// SH7724.
|
||||
switch(*prr & 0xfffffff0)
|
||||
{
|
||||
case 0x00002c00:
|
||||
return MPU_SH7305;
|
||||
case 0x00002200:
|
||||
return MPU_SH7724;
|
||||
}
|
||||
|
||||
// By default, the MPU is unknown.
|
||||
return MPU_Unknown;
|
||||
}
|
||||
|
||||
static void mpu_init(void)
|
||||
__attribute__((
|
||||
section(".pretext"),
|
||||
constructor
|
||||
));
|
||||
|
||||
static void mpu_init(void)
|
||||
{
|
||||
MPU_CURRENT = getMPU();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
screen.c
|
||||
|
||||
This module is in charge of interaction with the physical screen. See
|
||||
module 'display' for video ram management and drawing.
|
||||
|
||||
The screen basically has two input values, which are a register
|
||||
selector and the selected register's value. What this module does is
|
||||
essentially selecting registers by setting *selector and assigning them
|
||||
values by setting *data.
|
||||
*/
|
||||
|
||||
#include <screen.h>
|
||||
|
||||
|
||||
|
||||
/*
|
||||
screen_display()
|
||||
|
||||
Displays the given vram on the screen. Only bytes can be transferred
|
||||
through the screen registers, which is unfortunate because most of the
|
||||
vram-related operations use longword-base computations.
|
||||
|
||||
@arg vram 1024-byte video buffer.
|
||||
*/
|
||||
void screen_display(const void *ptr)
|
||||
{
|
||||
const char *vram = (const char *)ptr;
|
||||
volatile char *selector = (char *)0xb4000000;
|
||||
volatile char *data = (char *)0xb4010000;
|
||||
int line, bytes;
|
||||
|
||||
for(line = 0; line < 64; line++)
|
||||
{
|
||||
// Setting the x-address register.
|
||||
*selector = 4;
|
||||
*data = line + 0xc0;
|
||||
|
||||
// Setting Y-Up mode.
|
||||
*selector = 1;
|
||||
*data = 1;
|
||||
|
||||
// Setting y-address.
|
||||
*selector = 4;
|
||||
*data = 0;
|
||||
|
||||
// Selecting data write register 7 and sending a line's bytes.
|
||||
*selector = 7;
|
||||
for(bytes = 0; bytes < 16; bytes++) *data = *vram++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
This file implements long jumps. An example of their use is with crt0.c
|
||||
and exit()-family functions that use them to restore the execution
|
||||
state when leaving the program from an unknown location.
|
||||
|
||||
The register contents are saved in a buffer when setjmp() is called and
|
||||
restored at any time when longjmp() performs the jump, through an
|
||||
exit() or abort() call, for instance.
|
||||
|
||||
This is actually a question of playing with pr ; the user program is
|
||||
resumed after the setjmp() call when longjmp() is invoked but setjmp()
|
||||
has nothing to do with this operation. longjmp() restores the pr value
|
||||
that was saved by setjmp() and performs an rts instruction.
|
||||
|
||||
setjmp() returns 0 when called to set up the jump point and a non-zero
|
||||
value when invoked through a long jump. If 0 is given as return value
|
||||
to longjmp(), then 1 is returned.
|
||||
*/
|
||||
|
||||
.global _setjmp
|
||||
.global _longjmp
|
||||
|
||||
_setjmp:
|
||||
/* Getting some free space. */
|
||||
add #64, r4
|
||||
|
||||
/* Saving general-purpose registers. */
|
||||
mov.l r15, @-r4
|
||||
mov.l r14, @-r4
|
||||
mov.l r13, @-r4
|
||||
mov.l r12, @-r4
|
||||
mov.l r11, @-r4
|
||||
mov.l r10, @-r4
|
||||
mov.l r9, @-r4
|
||||
mov.l r8, @-r4
|
||||
|
||||
/* Saving control and system registers. */
|
||||
stc.l sr, @-r4
|
||||
stc.l ssr, @-r4
|
||||
stc.l spc, @-r4
|
||||
stc.l gbr, @-r4
|
||||
stc.l vbr, @-r4
|
||||
sts.l mach, @-r4
|
||||
sts.l macl, @-r4
|
||||
sts.l pr, @-r4
|
||||
|
||||
/* This function always return 0. The cases where setjmp() seems to
|
||||
return non-zero values, when a long jump has just been performed, is
|
||||
actually handled by longjmp(). */
|
||||
rts
|
||||
mov #0, r0
|
||||
|
||||
|
||||
|
||||
_longjmp:
|
||||
/* Restoring the system and control registers. Restoring pr is actually
|
||||
what performs the jump -- and makes the user program thinks that
|
||||
setjmp() has returned. */
|
||||
lds.l @r4+, pr
|
||||
lds.l @r4+, macl
|
||||
lds.l @r4+, mach
|
||||
ldc.l @r4+, vbr
|
||||
ldc.l @r4+, gbr
|
||||
ldc.l @r4+, spc
|
||||
ldc.l @r4+, ssr
|
||||
ldc.l @r4+, sr
|
||||
|
||||
/* Restoring the general-purpose registers. */
|
||||
mov.l @r4+, r8
|
||||
mov.l @r4+, r9
|
||||
mov.l @r4+, r10
|
||||
mov.l @r4+, r11
|
||||
mov.l @r4+, r12
|
||||
mov.l @r4+, r13
|
||||
mov.l @r4+, r14
|
||||
mov.l @r4+, r15
|
||||
|
||||
/* Preventing return value from being 0 (must be at least 1). */
|
||||
tst r5, r5
|
||||
movt r0
|
||||
rts
|
||||
add r5, r0
|
|
@ -0,0 +1,134 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
//---
|
||||
// Memory manipulation.
|
||||
//---
|
||||
|
||||
/*
|
||||
memcpy()
|
||||
Copies a memory area. A smart copy is performed if possible.
|
||||
|
||||
@arg destination
|
||||
@arg source
|
||||
@arg byte_number
|
||||
*/
|
||||
void *memcpy(void *d, const void *s, size_t n)
|
||||
{
|
||||
uint8_t *dest = (uint8_t *)d;
|
||||
const uint8_t *src = (const uint8_t *)s;
|
||||
|
||||
// A long-based copy needs the source and destination to be 4-aligned
|
||||
// at the same time.
|
||||
if(((intptr_t)dest & 3) == ((intptr_t)src & 3))
|
||||
{
|
||||
// Getting to a long offset.
|
||||
while((intptr_t)dest & 3)
|
||||
{
|
||||
*dest++ = *src++;
|
||||
n--;
|
||||
}
|
||||
|
||||
// Copying groups of four bytes.
|
||||
while(n >= 4)
|
||||
{
|
||||
*((uint32_t *)dest) = *((const uint32_t *)src);
|
||||
|
||||
dest += 4, src += 4;
|
||||
n -= 4;
|
||||
}
|
||||
|
||||
// Ending the copy.
|
||||
while(n)
|
||||
{
|
||||
*dest++ = *src++;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
// Or we could try a word-based copy.
|
||||
else if(((intptr_t)dest & 1) == ((intptr_t)src & 1))
|
||||
{
|
||||
// Getting to a word offset.
|
||||
if((intptr_t)dest & 1)
|
||||
{
|
||||
*dest++ = *src++;
|
||||
n--;
|
||||
}
|
||||
|
||||
// Copying groups of two bytes.
|
||||
while(n >= 2)
|
||||
{
|
||||
*((uint16_t *)dest) = *((const uint16_t *)src);
|
||||
|
||||
dest += 2, src += 2;
|
||||
n -= 2;
|
||||
}
|
||||
|
||||
// Ending the copy.
|
||||
while(n)
|
||||
{
|
||||
*dest++ = *src++;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
// In some cases we can just perform a raw copy.
|
||||
else while(n)
|
||||
{
|
||||
*dest++ = *src++;
|
||||
n--;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
/*
|
||||
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 *d, int byte, size_t byte_number)
|
||||
{
|
||||
uint8_t *dest = (uint8_t *)d;
|
||||
unsigned short word = (byte << 8) | byte;
|
||||
unsigned int longword = (word << 16) | word;
|
||||
|
||||
// When the area is small, simply copying using byte operations. The
|
||||
// minimum length used for long operations must be at least 3.
|
||||
if(byte_number < 8)
|
||||
{
|
||||
while(byte_number)
|
||||
{
|
||||
*dest++ = byte;
|
||||
byte_number--;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
// Reaching a long offset.
|
||||
while((intptr_t)dest & 3)
|
||||
{
|
||||
*dest++ = byte;
|
||||
byte_number--;
|
||||
}
|
||||
// Copying using long operations.
|
||||
while(byte_number >= 4)
|
||||
{
|
||||
*((uint32_t *)dest) = longword;
|
||||
dest += 4;
|
||||
byte_number -= 4;
|
||||
}
|
||||
// Ending the copy.
|
||||
while(byte_number)
|
||||
{
|
||||
*dest++ = byte;
|
||||
byte_number--;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
This file contains all the system calls used by the library. Maybe one
|
||||
day we won't need them anymore ?
|
||||
*/
|
||||
|
||||
.global ___Hmem_SetMMU
|
||||
.global ___GLibAddinAplExecutionCheck
|
||||
.global ___Print
|
||||
|
||||
|
||||
|
||||
___Hmem_SetMMU:
|
||||
mov.l syscall_table, r2
|
||||
mov.l 1f, r0
|
||||
jmp @r2
|
||||
nop
|
||||
1: .long 0x3fa
|
||||
|
||||
___GLibAddinAplExecutionCheck:
|
||||
mov.l syscall_table, r2
|
||||
mov #0x13, r0
|
||||
jmp @r2
|
||||
nop
|
||||
|
||||
___Print:
|
||||
mov.l syscall_table, r2
|
||||
mov.l 1f, r0
|
||||
jmp @r2
|
||||
nop
|
||||
1: .long 0x15d
|
||||
|
||||
|
||||
|
||||
.align 4
|
||||
|
||||
syscall_table:
|
||||
.long 0x80010070
|
|
@ -0,0 +1,162 @@
|
|||
#include <timer.h>
|
||||
#include <mpu.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
struct Timer
|
||||
This structure handles a running timer information.
|
||||
*/
|
||||
struct Timer
|
||||
{
|
||||
void (*callback)(void);
|
||||
int repetitions;
|
||||
};
|
||||
|
||||
// Static timers.
|
||||
static struct Timer timers[3] = { { NULL, 0 }, { NULL, 0 }, { NULL, 0 } };
|
||||
|
||||
/*
|
||||
struct mod_tmu
|
||||
This structure allows access to a timer using its address.
|
||||
*/
|
||||
struct mod_tmu
|
||||
{
|
||||
// Timer constant register.
|
||||
unsigned int TCOR;
|
||||
// Timer counter.
|
||||
unsigned int TCNT;
|
||||
|
||||
// Timer control register.
|
||||
union
|
||||
{
|
||||
unsigned short WORD;
|
||||
struct
|
||||
{
|
||||
unsigned :7;
|
||||
// Underflow flag.
|
||||
unsigned UNF :1;
|
||||
unsigned :2;
|
||||
// Underflow interrupt enable.
|
||||
unsigned UNIE :1;
|
||||
// Clock edge, reserved on SH7305.
|
||||
unsigned CKEG :2;
|
||||
// Timer prescaler.
|
||||
unsigned TPSC :3;
|
||||
};
|
||||
} TCR;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
timer_get()
|
||||
|
||||
Returns the timer and TSTR register addresses.
|
||||
|
||||
@arg timer Timer id.
|
||||
@arg tmu mod_tmu structure pointer address.
|
||||
@arg tstr mod_tstr structure pointer address.
|
||||
*/
|
||||
void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr)
|
||||
{
|
||||
// Using SH7705 information for SH-3-based MPUs.
|
||||
if(MPU_CURRENT == MPU_SH7337 || MPU_CURRENT == MPU_SH7355)
|
||||
{
|
||||
if(tstr) *tstr = (unsigned char *)0xfffffe92;
|
||||
if(tmu) *tmu = (struct mod_tmu *)0xfffffe94;
|
||||
}
|
||||
// Assuming SH7305 by default.
|
||||
else
|
||||
{
|
||||
if(tstr) *tstr = (unsigned char *)0xa4490004;
|
||||
if(tmu) *tmu = (struct mod_tmu *)0xa4490008;
|
||||
}
|
||||
|
||||
// Shifting tmu value to get to the timer-nth timer in the unit.
|
||||
if(tmu) *tmu += timer;
|
||||
}
|
||||
|
||||
/*
|
||||
timer_set()
|
||||
Configures and starts a timer.
|
||||
|
||||
@arg timer Timer identifier.
|
||||
@arg delay Delay before expiration.
|
||||
@arg prescaler Clock prescaler value.
|
||||
@arg callback Callback function.
|
||||
@arg repetitions Number of repetitions, 0 for infinite.
|
||||
*/
|
||||
void timer_set(int timer, int delay, int prescaler, void (*callback)(void),
|
||||
int repetitions)
|
||||
{
|
||||
// Getting the timer address. Using a byte to alter TSTR.
|
||||
struct mod_tmu *tmu;
|
||||
unsigned char *tstr;
|
||||
int byte = (1 << timer);
|
||||
timer_get(timer, &tmu, &tstr);
|
||||
|
||||
// Setting the constant register.
|
||||
(*tmu).TCOR = delay;
|
||||
// Loading the delay in the counter.
|
||||
(*tmu).TCNT = delay;
|
||||
|
||||
// Resetting underflow flag.
|
||||
(*tmu).TCR.UNF = 0;
|
||||
// Enabling interruptions on underflow.
|
||||
(*tmu).TCR.UNIE = 1;
|
||||
// Counting on rising edge. On SH7305 these two bits are reserved but
|
||||
// writing 0 is ignored.
|
||||
(*tmu).TCR.CKEG = 0;
|
||||
// Setting the prescaler.
|
||||
(*tmu).TCR.TPSC = prescaler;
|
||||
|
||||
// Loading the structure information.
|
||||
timers[timer].callback = callback;
|
||||
timers[timer].repetitions = repetitions;
|
||||
|
||||
// Starting the timer and returning.
|
||||
*tstr |= byte;
|
||||
}
|
||||
|
||||
/*
|
||||
timer_stop()
|
||||
Stops the given timer. This function may be called even if the timer is
|
||||
not running.
|
||||
|
||||
@arg timer Timer to stop.
|
||||
*/
|
||||
void timer_stop(int timer)
|
||||
{
|
||||
// Getting TSTR address and the corresponding byte.
|
||||
unsigned char *tstr;
|
||||
int byte = (1 << timer);
|
||||
timer_get(timer, NULL, &tstr);
|
||||
|
||||
// Stopping the timer.
|
||||
*tstr &= ~byte;
|
||||
}
|
||||
|
||||
/*
|
||||
timer_interrupt()
|
||||
Handles the interrupt for the given timer.
|
||||
|
||||
@timer Timer that generated the interrupt.
|
||||
*/
|
||||
void timer_interrupt(int timer)
|
||||
{
|
||||
// Getting the timer address.
|
||||
struct mod_tmu *tmu;
|
||||
timer_get(timer, &tmu, NULL);
|
||||
|
||||
// Resetting the interrupt flag.
|
||||
(*tmu).TCR.UNF = 0;
|
||||
|
||||
// Calling the callback function.
|
||||
if(timers[timer].callback) timers[timer].callback();
|
||||
|
||||
// Reducing the number of repetitions left, if not infinite.
|
||||
if(!timers[timer].repetitions) return;
|
||||
// And stopping it if necessary.
|
||||
if(timers[timer].repetitions == 1) timer_stop(timer);
|
||||
else timers[timer].repetitions--;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 554 B |
Binary file not shown.
After Width: | Height: | Size: 242 B |
|
@ -0,0 +1,190 @@
|
|||
|
||||
-----------------------------------
|
||||
Syscall information
|
||||
-----------------------------------
|
||||
|
||||
Syscall id: 0x24a
|
||||
Syscall address: 0x8003fc48
|
||||
|
||||
r4 {short *matrixcode}
|
||||
|
||||
Syscall 0x24a redirects to 8003 f9d6.
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
Stack
|
||||
-----------------------------------
|
||||
|
||||
------ Pointer sent at <3f9fe> (also as first parameter) and <3fa12>
|
||||
(12) Data from a44b 0000
|
||||
------ Pointer sent at <3f9de>
|
||||
(4) {short *matrixcode} at <3f9fe>
|
||||
pr
|
||||
r14
|
||||
------ Bottom
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
Syscall code
|
||||
-----------------------------------
|
||||
|
||||
# Saves some data.
|
||||
3f9d6: 2fe6 mov.l r14, @-r15
|
||||
3f9d8: 4f22 sts.l pr, @-r15
|
||||
3f9da: 7ff0 add #-16, r15
|
||||
|
||||
# First subroutine call: disables keyboard interrupts.
|
||||
# Also pushes {short *matrixcode} on the stack.
|
||||
3f9dc: d128 mov.l #0x8003e264, r1
|
||||
3f9de: 410b jsr @r1
|
||||
3f9e0: 1f43 mov.l r4, @(12, r15)
|
||||
|
||||
# Loads KEYSC data to the stack.
|
||||
# Second subroutine call, with parameters : stack top and {short *matrixcode}.
|
||||
# Checks whether the key given in the matrixcode was pressed.
|
||||
3f9e2: d528 mov.l #0xa44b0000, r5
|
||||
3f9e4: 6451 mov.w @r5, r4
|
||||
3f9e6: 2f41 mov.w r4, @r15
|
||||
3f9e8: 64f3 mov r15, r4
|
||||
3f9ea: 8551 mov.w @(2, r5), r0
|
||||
3f9ec: 81f1 mov.w r0, @(2, r15)
|
||||
3f9ee: 8552 mov.w @(4, r5), r0
|
||||
3f9f0: 81f2 mov.w r0, @(4, r15)
|
||||
3f9f2: 8553 mov.w @(6, r5), r0
|
||||
3f9f4: 81f3 mov.w r0, @(6, r15)
|
||||
3f9f6: 8554 mov.w @(8, r5), r0
|
||||
3f9f8: 81f4 mov.w r0, @(8, r15)
|
||||
3f9fa: 8555 mov.w @(10, r5), r0
|
||||
3f9fc: 81f5 mov.w r0, @(10, r15)
|
||||
3f9fe: bd30 bsr <3f462>
|
||||
3fa00: 55f3 mov.l @(12, r15), r5
|
||||
|
||||
# Loads IPRF address to r6, sets the keyboard interrupt priority to 13 and
|
||||
# performs a third subroutine call : enables keyboard interrupts (curiously
|
||||
# the interrupt priority is set two times).
|
||||
# Also saves the last subroutine result (key pressed) to r14.
|
||||
3fa02: d621 mov.l <3fa88>(#0xa4080014), r6
|
||||
3fa04: 9113 mov.w <3fa2e>(#0x0fff), r1
|
||||
3fa06: 9213 mov.w <3fa30>(#0xd000), r2
|
||||
3fa08: 6e03 mov r0, r14
|
||||
3fa0a: 6761 mov.w @r6, r7
|
||||
3fa0c: 2719 and r1, r7
|
||||
3fa0e: 272b or r2, r7
|
||||
3fa10: d212 mov.l #0x8003e26c, r2
|
||||
3fa12: 420b jsr @r2
|
||||
3fa14: 2671 mov.w r7, @r6
|
||||
|
||||
# Restores the 'key pressed' result to r0, restores saved data and returns.
|
||||
3fa16: 60e3 mov r14, r0
|
||||
3fa18: 7f10 add #16, r15
|
||||
3fa1a: 4f26 lds.l @r15+, pr
|
||||
3fa1c: 000b rts
|
||||
3fa1e: 6ef6 mov.l @r15+, r14
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
Subroutine call at <3f9de>
|
||||
- Denies keyboard interrupt in IMR5.
|
||||
- Disables keyboard interrupt in IPRF.
|
||||
-----------------------------------
|
||||
|
||||
Call redirects to 8003 e278.
|
||||
|
||||
# Loads IMR5 address to r4.
|
||||
3e278: d478 mov.l <3e45c>(#0xa4080094), r4
|
||||
3e27a: e180 mov #-128, r1
|
||||
3e27c: 955b mov.w <3e336>(#0x0fff), r5
|
||||
# Writes 0x80 to IMR5.
|
||||
3e27e: 2410 mov.b r1, @r4
|
||||
|
||||
# Loads IPRF address to r4.
|
||||
3e280: 7480 add #-128, r4
|
||||
# Sets the four upper bits of IPRF to 0.
|
||||
3e282: 6241 mov.w @r4, r2
|
||||
3e284: 2259 and r5, r2
|
||||
3e286: 000b rts
|
||||
3e288: 2421 mov.w r2, @r4
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
Subroutine call at <3f9fe>
|
||||
- Detects whether a specific key is pressed using the KEYSC data loaded onto
|
||||
the stack.
|
||||
- Returns 1 if the key is pressed, 0 otherwise.
|
||||
-----------------------------------
|
||||
|
||||
Stack:
|
||||
r4 (bottom stack address)
|
||||
{short *matrixcode}
|
||||
------ Bottom stack address.
|
||||
|
||||
# Pushes {short *matrixcode} on the stack and on top, pushes r4.
|
||||
# Loads the key column to r2 and replaces r5 by #1 (r5 will then be shifted to
|
||||
# be used as a mask in a KEYSC word).
|
||||
3f462: 7ff8 add #-8, r15
|
||||
3f464: 1f51 mov.l r5, @(4, r15)
|
||||
3f466: 6250 mov.b @r5, r2
|
||||
3f468: e501 mov #1, r5
|
||||
3f46a: 51f1 mov.l @(4, r15), r1
|
||||
3f46c: 622c extu.b r2, r2
|
||||
3f46e: 2f42 mov.l r4, @r15
|
||||
|
||||
# Loads the key row to r0.
|
||||
3f470: 8411 mov.b @(1, r1), r0
|
||||
3f472: 600c extu.b r0, r0
|
||||
# Shifts it right within r6 and tests the row's lower bit.
|
||||
3f474: 6603 mov r0, r6
|
||||
3f476: 4621 shar r6
|
||||
3f478: c801 tst #1, r0
|
||||
|
||||
# Shift r5 by its column number.
|
||||
# If the row's lower bit was 1, then also shift r5 by 8 (because there are two
|
||||
# rows for each word).
|
||||
3f47a: 8d01 bt/s <3f480>
|
||||
3f47c: 452d shld r2, r5
|
||||
3f47e: 4518 shll8 r5
|
||||
|
||||
# Loads the bottom stack address to r1.
|
||||
3f480: 61f2 mov.l @r15, r1
|
||||
# Erases the even/odd bit of the row in r6 (because the KEYSC data is read in
|
||||
# words so we don't want to get on a byte offset, and the lower bit has
|
||||
# already been handled when shifting r5).
|
||||
3f482: 4600 shll r6
|
||||
|
||||
# Loads the final mask into r2.
|
||||
3f484: 625d extu.w r5, r2
|
||||
3f486: 6063 mov r6, r0
|
||||
# Tests whether the key represented by the parameter matrixcode is pressed.
|
||||
3f488: 041d mov.w @(r0, r1), r4
|
||||
3f48a: 2428 tst r2, r4
|
||||
# Returns the KEYSC bit, that is 1 if the key was pressed, 0 otherwise.
|
||||
3f48c: 0029 movt r0
|
||||
3f48e: ca01 xor #1, r0
|
||||
3f490: 000b rts
|
||||
3f492: 7f08 add #8, r15
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
Subroutine call at <3fa12>
|
||||
- Sets the keyboard interrupt priority to 13.
|
||||
- Clears the keyboard interrupt mask.
|
||||
-----------------------------------
|
||||
|
||||
Calls redirects to 8003 e28a.
|
||||
|
||||
3e28a: d475 mov.l #0xa4080014, r4
|
||||
3e28c: 9753 mov.w #0x0fff, r7
|
||||
3e28e: 9253 mov.w #0xd000, r2
|
||||
3e290: e580 mov #-128, r5
|
||||
3e292: 6141 mov.w @r4, r1
|
||||
3e294: 2179 and r7, r1
|
||||
3e296: 212b or r2, r1
|
||||
3e298: 2411 mov.w r1, @r4
|
||||
3e29a: d472 mov.l <3e464>(#0xa40800d4), r4
|
||||
3e29c: 000b rts
|
||||
3e29e: 2450 mov.b r5, @r4
|
|
@ -0,0 +1,558 @@
|
|||
|
||||
-----------------------------------
|
||||
Syscall information
|
||||
-----------------------------------
|
||||
|
||||
Syscall id: 0x24a
|
||||
Syscall address: 0x8003fa28
|
||||
|
||||
r4 {short *matrixcode}
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
Stack
|
||||
-----------------------------------
|
||||
|
||||
#1
|
||||
pr
|
||||
r8
|
||||
r9
|
||||
r10
|
||||
r11
|
||||
r12
|
||||
r13
|
||||
r14
|
||||
------ Bottom
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
Variables
|
||||
-----------------------------------
|
||||
|
||||
r14 Current row
|
||||
r13
|
||||
r12
|
||||
r11 Delay routine address
|
||||
r10 1 << r14 ? Could be the data register mask.
|
||||
r9 Current column.
|
||||
r8 {short *matrixcode}
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
Syscall code
|
||||
-----------------------------------
|
||||
|
||||
# Saves r8-r14 to the stack. Loads data:
|
||||
# r13 = 8, r12 = 1, r11 = 8003 e47a, r10 = 1, r9 = 0, r8 = {short *matrixcode}.
|
||||
3fa28: 2fe6 mov.l r14, @-r15
|
||||
3fa2a: 2fd6 mov.l r13, @-r15
|
||||
3fa2c: 2fc6 mov.l r12, @-r15
|
||||
3fa2e: ed08 mov #8, r13
|
||||
3fa30: 2fb6 mov.l r11, @-r15
|
||||
3fa32: ec01 mov #1, r12
|
||||
3fa34: 2fa6 mov.l r10, @-r15
|
||||
3fa36: 6ac3 mov r12, r10
|
||||
3fa38: 2f96 mov.l r9, @-r15
|
||||
3fa3a: e900 mov #0, r9
|
||||
3fa3c: db22 mov.l #0x8003e47a, r11
|
||||
3fa3e: 2f86 mov.l r8, @-r15
|
||||
3fa40: 4f22 sts.l pr, @-r15
|
||||
3fa42: 6843 mov r4, r8
|
||||
|
||||
# r14 = 0, pushes #1 on the stack and branches to <3fb1a>. This branch does
|
||||
# nothing if r14 is lower than 12 (thus here it does nothing).
|
||||
3fa44: 7ffc add #-4, r15
|
||||
3fa46: 2fc2 mov.l r12, @r15
|
||||
3fa48: a067 bra <3fb1a>
|
||||
3fa4a: 6e93 mov r9, r14
|
||||
|
||||
# Sets gbr = a400 0100: area where the port control registers are located.
|
||||
3fa4c: d21f mov.l #0xa4000100, r2
|
||||
3fa4e: 421e ldc r2, gbr
|
||||
|
||||
# B_CTRL = h'aaaa
|
||||
3fa50: d01f mov.l #0x0000aaaa, r0
|
||||
3fa52: c101 mov.w r0, @(2, gbr)
|
||||
|
||||
# M_CTRL = h'__55
|
||||
3fa54: c50c mov.w @(24, gbr), r0
|
||||
3fa56: d31f mov.l #0x0000ff00, r3
|
||||
3fa58: 2039 and r3, r0
|
||||
3fa5a: cbaa or #0x55, r0
|
||||
3fa5c: c10c mov.w r0, @(24, gbr)
|
||||
|
||||
# Delay.
|
||||
3fa5e: 4b0b jsr @r11
|
||||
3fa60: e402 mov #2, r4
|
||||
|
||||
# Loads 801b e65c as a data segment base. It contains words in this order:
|
||||
# aaa9 aaa6 aa9a aa6a ... 9aaa 6aaa 00a9 00a6 009a 006a.
|
||||
# These words are the B_CTRL/M_CTRL values.
|
||||
# Loads the r14-th word into B_CTRL (r14 <= 8) or the lowest byte of M_CTRL
|
||||
# (r14 > 8). The row-to-check pin is configured as output, and all the others
|
||||
# are configured as inputs.
|
||||
3fa62: 3ed3 cmp/ge r13, r14
|
||||
3fa64: d41c mov.l #0x801be65c, r4
|
||||
3fa66: 8904 bt <3fa72>
|
||||
3fa68: 60e3 mov r14, r0
|
||||
3fa6a: 4000 shll r0
|
||||
3fa6c: 004d mov.w @(r0, r4), r0
|
||||
3fa6e: a009 bra <3fa84>
|
||||
3fa70: c101 mov.w r0, @(2, gbr)
|
||||
3fa72: 60e3 mov r14, r0
|
||||
3fa74: 4000 shll r0
|
||||
3fa76: 004d mov.w @(r0, r4), r0
|
||||
3fa78: 6203 mov r0, r2
|
||||
3fa7a: c50c mov.w @(24, gbr), r0
|
||||
3fa7c: d315 mov.l #0x0000ff00, r3
|
||||
3fa7e: 2039 and r3, r0
|
||||
3fa80: 202b or r2, r0
|
||||
3fa82: c10c mov.w r0, @(24, gbr)
|
||||
|
||||
# Delay.
|
||||
3fa84: 4b0b jsr @r11
|
||||
3fa86: e402 mov #2, r4
|
||||
|
||||
# Loads the port data registers section into gbr.
|
||||
3fa88: d314 mov.l #0xa4000120, r3
|
||||
3fa8a: 431e ldc r3, gbr
|
||||
3fa8c: 3ed3 cmp/ge r13, r14
|
||||
3fa8e: 8d27 bt/s <3fae0>
|
||||
|
||||
# When the row-to-check is lower than or equal to 8.
|
||||
# Writes ~r10 to B_DATA. Sets M_DATA to 0x-f.
|
||||
3fa90: 64a7 not r10, r4
|
||||
3fa92: 6043 mov r4, r0
|
||||
3fa94: c002 mov.b r0, @(2, gbr)
|
||||
3fa96: c418 mov.b @(24, gbr), r0
|
||||
3fa98: c9f0 and #0xf0, r0
|
||||
3fa9a: a026 bra <3faea>
|
||||
3fa9c: cb0f or #15, r0
|
||||
|
||||
3fa9e: 0000 .word 0x0000
|
||||
3faa0: 801b mov.b r0, @(11, r1)
|
||||
3faa2: e6dc mov #-36, r6
|
||||
3faa4: 8006 mov.b r0, @(6, r0)
|
||||
3faa6: 9088 mov.w <3fbba>(#0xc10c), r0
|
||||
3faa8: 8002 mov.b r0, @(2, r0)
|
||||
3faaa: 4e4e ldc r14, spc
|
||||
3faac: 8800 cmp/eq #0, r0
|
||||
3faae: 77ed add #-19, r7
|
||||
3fab0: 8003 mov.b r0, @(3, r0)
|
||||
3fab2: d446 mov.l <3fbcc>(#0x004da007), r4
|
||||
3fab4: 8003 mov.b r0, @(3, r0)
|
||||
3fab6: da54 mov.l <3fc08>(#0x0000aaaa), r10
|
||||
3fab8: 8003 mov.b r0, @(3, r0)
|
||||
3faba: de9c mov.l <3fd2c>(#0xee00eb0a), r14
|
||||
3fabc: 8006 mov.b r0, @(6, r0)
|
||||
3fabe: 90d8 mov.w <3fc72>(#0x421e), r0
|
||||
3fac0: 8006 mov.b r0, @(6, r0)
|
||||
3fac2: 2ed8 tst r13, r14
|
||||
3fac4: 8800 cmp/eq #0, r0
|
||||
3fac6: 7054 add #84, r0
|
||||
|
||||
# Data segment.
|
||||
3fac8: 8003 e47a
|
||||
3facc: a400 0100
|
||||
3fad0: 0000 aaaa
|
||||
3fad4: 0000 ff00
|
||||
3fad8: 801b e65c
|
||||
3fadc: a400 0120
|
||||
|
||||
# When the row-to-check is strictly greater than 8.
|
||||
# Writes 0xff to B_DATA, and ~r10 to M_DATA.
|
||||
3fae0: 908e mov.w <3fc00>(#0x00ff), r0
|
||||
3fae2: c002 mov.b r0, @(2, gbr)
|
||||
3fae4: c418 mov.b @(24, gbr), r0
|
||||
3fae6: c9f0 and #0xf0, r0
|
||||
3fae8: 204b or r4, r0
|
||||
|
||||
# Delay.
|
||||
3faea: c018 mov.b r0, @(24, gbr)
|
||||
3faec: 4b0b jsr @r11
|
||||
3faee: e402 mov #2, r4
|
||||
|
||||
# Loads result in r5, as ~A_DATA.
|
||||
3faf0: c400 mov.b @(0, gbr), r0
|
||||
3faf2: 6507 not r0, r5
|
||||
|
||||
# r9 = 0 the first time. Compares r12 with the result. If none of the bits of
|
||||
# r12 are set in checked row, branches to <3fb04>.
|
||||
3faf4: 6493 mov r9, r4
|
||||
3faf6: 635c extu.b r5, r3
|
||||
3faf8: 23c8 tst r12, r3
|
||||
3fafa: 8903 bt <3fb04>
|
||||
|
||||
# r9 seems to be the key column and r14 the row.
|
||||
3fafc: 2840 mov.b r4, @r8
|
||||
3fafe: 60e3 mov r14, r0
|
||||
3fb00: a00f bra <3fb22>
|
||||
3fb02: 8081 mov.b r0, @(1, r8)
|
||||
|
||||
3fb04: 655c extu.b r5, r5
|
||||
3fb06: 4501 shlr r5
|
||||
3fb08: 7401 add #1, r4
|
||||
3fb0a: 34d3 cmp/ge r13, r4
|
||||
3fb0c: 8bf3 bf <3faf6>
|
||||
3fb0e: 4a00 shll r10
|
||||
3fb10: 60e3 mov r14, r0
|
||||
3fb12: 8807 cmp/eq #7, r0
|
||||
3fb14: 8f01 bf/s <3fb1a>
|
||||
3fb16: 7e01 add #1, r14
|
||||
3fb18: 6ac3 mov r12, r10
|
||||
3fb1a: e30c mov #12, r3
|
||||
3fb1c: 3e33 cmp/ge r3, r14
|
||||
3fb1e: 8b95 bf <3fa4c>
|
||||
3fb20: 2f92 mov.l r9, @r15
|
||||
|
||||
# Ends the procedure and restores everything ?
|
||||
|
||||
# B_CTRL = 0xaaaa. M_CTRL = 0x--aa. Delay.
|
||||
3fb22: d338 mov.l <3fc04>(#0xa4000100), r3
|
||||
3fb24: d038 mov.l <3fc08>(#0x0000aaaa), r0
|
||||
3fb26: 431e ldc r3, gbr
|
||||
3fb28: c101 mov.w r0, @(2, gbr)
|
||||
3fb2a: c50c mov.w @(24, gbr), r0
|
||||
3fb2c: d237 mov.l <3fc0c>(#0x0000ff00), r2
|
||||
3fb2e: 2029 and r2, r0
|
||||
3fb30: cbaa or #0xaa, r0
|
||||
3fb32: c10c mov.w r0, @(24, gbr)
|
||||
3fb34: 4b0b jsr @r11
|
||||
3fb36: e402 mov #2, r4
|
||||
|
||||
# B_CTRL = 0x5555. M_CTRL = 0x--55. Delay.
|
||||
3fb38: 9063 mov.w <3fc02>(#0x5555), r0
|
||||
3fb3a: c101 mov.w r0, @(2, gbr)
|
||||
3fb3c: c50c mov.w @(24, gbr), r0
|
||||
3fb3e: d333 mov.l <3fc0c>(#0x0000ff00), r3
|
||||
3fb40: 2039 and r3, r0
|
||||
3fb42: cb55 or #0x55, r0
|
||||
3fb44: c10c mov.w r0, @(24, gbr)
|
||||
3fb46: 4b0b jsr @r11
|
||||
3fb48: e402 mov #2, r4
|
||||
|
||||
# B_DATA = 0x00. M_DATA = 0x-0.
|
||||
3fb4a: e000 mov #0, r0
|
||||
3fb4c: d230 mov.l <3fc10>(#0xa4000120), r2
|
||||
3fb4e: 421e ldc r2, gbr
|
||||
3fb50: c002 mov.b r0, @(2, gbr)
|
||||
3fb52: c418 mov.b @(24, gbr), r0
|
||||
3fb54: c9f0 and #0xf0, r0
|
||||
3fb56: c018 mov.b r0, @(24, gbr)
|
||||
|
||||
# Returns the value at the top of the stack (originally 1).
|
||||
3fb58: 60f2 mov.l @r15, r0
|
||||
3fb5a: 7f04 add #4, r15
|
||||
3fb5c: 4f26 lds.l @r15+, pr
|
||||
3fb5e: 68f6 mov.l @r15+, r8
|
||||
3fb60: 69f6 mov.l @r15+, r9
|
||||
3fb62: 6af6 mov.l @r15+, r10
|
||||
3fb64: 6bf6 mov.l @r15+, r11
|
||||
3fb66: 6cf6 mov.l @r15+, r12
|
||||
3fb68: 6df6 mov.l @r15+, r13
|
||||
3fb6a: 000b rts
|
||||
3fb6c: 6ef6 mov.l @r15+, r14
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
First subroutine
|
||||
-----------------------------------
|
||||
|
||||
# Go back to <3fa4c> (first call to this subroutine) until r14 reaches 12.
|
||||
3fb1a: e30c mov #12, r3
|
||||
3fb1c: 3e33 cmp/ge r3, r14
|
||||
3fb1e: 8b95 bf <3fa4c>
|
||||
|
||||
3fb20: 2f92 mov.l r9, @r15
|
||||
3fb22: d338 mov.l <3fc04>(#0xa4000100), r3
|
||||
3fb24: d038 mov.l <3fc08>(#0x0000aaaa), r0
|
||||
3fb26: 431e ldc r3, gbr
|
||||
3fb28: c101 mov.w r0, @(2, gbr)
|
||||
3fb2a: c50c mov.w @(24, gbr), r0
|
||||
3fb2c: d237 mov.l <3fc0c>(#0x0000ff00), r2
|
||||
3fb2e: 2029 and r2, r0
|
||||
3fb30: cbaa or #-86, r0
|
||||
3fb32: c10c mov.w r0, @(24, gbr)
|
||||
3fb34: 4b0b jsr @r11
|
||||
3fb36: e402 mov #2, r4
|
||||
3fb38: 9063 mov.w <3fc02>(#0x5555), r0
|
||||
3fb3a: c101 mov.w r0, @(2, gbr)
|
||||
3fb3c: c50c mov.w @(24, gbr), r0
|
||||
3fb3e: d333 mov.l <3fc0c>(#0x0000ff00), r3
|
||||
3fb40: 2039 and r3, r0
|
||||
3fb42: cb55 or #85, r0
|
||||
3fb44: c10c mov.w r0, @(24, gbr)
|
||||
3fb46: 4b0b jsr @r11
|
||||
3fb48: e402 mov #2, r4
|
||||
3fb4a: e000 mov #0, r0
|
||||
3fb4c: d230 mov.l <3fc10>(#0xa4000120), r2
|
||||
3fb4e: 421e ldc r2, gbr
|
||||
3fb50: c002 mov.b r0, @(2, gbr)
|
||||
3fb52: c418 mov.b @(24, gbr), r0
|
||||
3fb54: c9f0 and #-16, r0
|
||||
3fb56: c018 mov.b r0, @(24, gbr)
|
||||
3fb58: 60f2 mov.l @r15, r0
|
||||
3fb5a: 7f04 add #4, r15
|
||||
3fb5c: 4f26 lds.l @r15+, pr
|
||||
3fb5e: 68f6 mov.l @r15+, r8
|
||||
3fb60: 69f6 mov.l @r15+, r9
|
||||
3fb62: 6af6 mov.l @r15+, r10
|
||||
3fb64: 6bf6 mov.l @r15+, r11
|
||||
3fb66: 6cf6 mov.l @r15+, r12
|
||||
3fb68: 6df6 mov.l @r15+, r13
|
||||
3fb6a: 000b rts
|
||||
3fb6c: 6ef6 mov.l @r15+, r14
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
Second subroutine
|
||||
Just a delay ! If also configures IRQ0.
|
||||
-----------------------------------
|
||||
|
||||
Stack:
|
||||
gbr
|
||||
macl
|
||||
pr
|
||||
r14
|
||||
------ Bottom
|
||||
|
||||
# Saves r14, pr, macl and gbr to the stack. Saves parameter (r4 = 2) to r14.
|
||||
# Loads data: r2 = 8006 31dc, r5 = 1 (parameter 'set' for syscall 0x3ed).
|
||||
3e47a: 0312 stc gbr, r3
|
||||
3e47c: d235 mov.l <3e554>(#0x800631dc), r2
|
||||
3e47e: e501 mov #1, r5
|
||||
3e480: 2fe6 mov.l r14, @-r15
|
||||
3e482: 6e43 mov r4, r14
|
||||
3e484: 4f22 sts.l pr, @-r15
|
||||
3e486: 4f12 sts.l macl, @-r15
|
||||
3e488: 7ffc add #-4, r15
|
||||
3e48a: 2f32 mov.l r3, @r15
|
||||
|
||||
# Sets the "watchdog occupied" status in the RAM interrupt status byte.
|
||||
3e48c: 420b jsr @r2
|
||||
3e48e: e410 mov #16, r4
|
||||
|
||||
# Ensures 1 <= r14 <= 40 by setting r14 = 1 or 40 if needed.
|
||||
# Here r14 is always 2.
|
||||
3e490: 4e15 cmp/pl r14
|
||||
3e492: 8d01 bt/s <3e498>
|
||||
3e494: e428 mov #40, r4
|
||||
3e496: ee01 mov #1, r14
|
||||
3e498: 3e47 cmp/gt r4, r14
|
||||
3e49a: 8b00 bf <3e49e>
|
||||
3e49c: 6e43 mov r4, r14
|
||||
|
||||
# r4 = ~((r14 * 92) >> 4) on a single byte, which is 244 when r14 = 2.
|
||||
# 256 - r4 will be used as a delay for the watchdog timer.
|
||||
# Sets gbr to 0xfffffee0 and disables the watchdog interrupt.
|
||||
3e49e: e45c mov #92, r4
|
||||
3e4a0: 924b mov.w <3e53a>(#0xfee0), r2
|
||||
3e4a2: e3fc mov #-4, r3
|
||||
3e4a4: 0e47 mul.l r4, r14
|
||||
3e4a6: 421e ldc r2, gbr
|
||||
3e4a8: 041a sts macl, r4
|
||||
3e4aa: 443c shad r3, r4
|
||||
3e4ac: 6447 not r4, r4
|
||||
3e4ae: 644c extu.b r4, r4
|
||||
3e4b0: c502 mov.w @(4, gbr), r0
|
||||
3e4b2: 9343 mov.w <3e53c>(#0x0fff), r3
|
||||
3e4b4: 2039 and r3, r0
|
||||
3e4b6: c102 mov.w r0, @(4, gbr)
|
||||
|
||||
# Loads the watchdog module base address into gbr. Resets everything in the
|
||||
# watchdog configuration. Then loads r4 (here 244) to the counter, sets the
|
||||
# frequency at Po/256, starts the timer and waits until it overflows.
|
||||
# This is probably just a way of delaying port usage.
|
||||
3e4b8: d027 mov.l <3e558>(#0x0000a500), r0
|
||||
3e4ba: e180 mov #-128, r1
|
||||
3e4bc: 411e ldc r1, gbr
|
||||
3e4be: c103 mov.w r0, @(6, gbr)
|
||||
3e4c0: 903d mov.w <3e53e>(#0x5a00), r0
|
||||
3e4c2: 204b or r4, r0
|
||||
3e4c4: c102 mov.w r0, @(4, gbr)
|
||||
3e4c6: d025 mov.l <3e55c>(#0x0000a505), r0
|
||||
3e4c8: c103 mov.w r0, @(6, gbr)
|
||||
3e4ca: d025 mov.l <3e560>(#0x0000a585), r0
|
||||
3e4cc: c103 mov.w r0, @(6, gbr)
|
||||
3e4ce: e408 mov #8, r4
|
||||
3e4d0: c406 mov.b @(6, gbr), r0
|
||||
3e4d2: 600c extu.b r0, r0
|
||||
3e4d4: 2048 tst r4, r0
|
||||
3e4d6: 89fb bt <3e4d0>
|
||||
|
||||
# Resets the overflow flag, then resets the whole configuration.
|
||||
3e4d8: c406 mov.b @(6, gbr), r0
|
||||
3e4da: 600c extu.b r0, r0
|
||||
3e4dc: d31e mov.l <3e558>(#0x0000a500), r3
|
||||
3e4de: c9f7 and #0xf7, r0
|
||||
3e4e0: 203b or r3, r0
|
||||
3e4e2: c103 mov.w r0, @(6, gbr)
|
||||
3e4e4: 6033 mov r3, r0
|
||||
3e4e6: c103 mov.w r0, @(6, gbr)
|
||||
|
||||
# Resets the counter.
|
||||
3e4e8: 9029 mov.w <3e53e>(#0x5a00), r0
|
||||
3e4ea: c102 mov.w r0, @(4, gbr)
|
||||
|
||||
# Unsets the "watchdog occupied" bit in the RAM interrupt status byte.
|
||||
3e4ec: d219 mov.l <3e554>(#0x800631dc), r2
|
||||
3e4ee: e500 mov #0, r5
|
||||
3e4f0: 420b jsr @r2
|
||||
3e4f2: e410 mov #16, r4
|
||||
|
||||
# Configures IRQ0 if possible (that is, if both the watchdog and the SD card
|
||||
# are idle).
|
||||
3e4f4: d31b mov.l <3e564>(#0x8003dbec), r3
|
||||
3e4f6: 430b jsr @r3
|
||||
3e4f8: 0009 nop
|
||||
|
||||
# Un-stacks everything and returns.
|
||||
3e4fa: 62f2 mov.l @r15, r2
|
||||
3e4fc: 421e ldc r2, gbr
|
||||
3e4fe: 7f04 add #4, r15
|
||||
3e500: 4f16 lds.l @r15+, macl
|
||||
3e502: 4f26 lds.l @r15+, pr
|
||||
3e504: 000b rts
|
||||
3e506: 6ef6 mov.l @r15+, r14
|
||||
|
||||
|
||||
|
||||
-----------------------------------
|
||||
Third subroutine
|
||||
-----------------------------------
|
||||
|
||||
# Erases the lowest bit in an unknown byte (probably an extension of the
|
||||
# interrupt status byte). Returns if this bit was 0.
|
||||
3dbec: 4f22 sts.l pr, @-r15
|
||||
3dbee: e501 mov #1, r5
|
||||
3dbf0: d349 mov.l <3dd18>(#0x80063236), r3
|
||||
3dbf2: 430b jsr @r3
|
||||
3dbf4: 6453 mov r5, r4
|
||||
3dbf6: 8801 cmp/eq #1, r0
|
||||
3dbf8: 8b07 bf <3dc0a>
|
||||
|
||||
# Checks if the watchdog timer is occupied, or if the SD-card is busy (?).
|
||||
# If any of them is in use, aborts. Otherwise controls is transferred to the
|
||||
# extract below, as if called directly.
|
||||
# Probably the SD-card has something to do with generating IRQ0 interrupts.
|
||||
3dbfa: e500 mov #0, r5
|
||||
3dbfc: d347 mov.l <3dd1c>(#0x800631f6), r3
|
||||
3dbfe: 430b jsr @r3
|
||||
3dc00: e418 mov #24, r4
|
||||
3dc02: 2008 tst r0, r0
|
||||
3dc04: 8b01 bf <3dc0a>
|
||||
3dc06: af82 bra <3db0e>
|
||||
3dc08: 4f26 lds.l @r15+, pr
|
||||
|
||||
# Returns.
|
||||
3dc0a: 4f26 lds.l @r15+, pr
|
||||
3dc0c: 000b rts
|
||||
3dc0e: 0009 nop
|
||||
|
||||
Here's the extract of code that takes control when the interrupt conditions
|
||||
required by the main procedure are fulfilled.
|
||||
It configures IRQ0 interrupts.
|
||||
|
||||
# Disables IRQ0 interrupt in IPRC.
|
||||
3db0e: d32d mov.l <3dbc4>(#0xa4000000), r3
|
||||
3db10: 431e ldc r3, gbr
|
||||
3db12: c50b mov.w @(22, gbr), r0
|
||||
3db14: d22e mov.l <3dbd0>(#0x0000fff0), r2
|
||||
3db16: 2029 and r2, r0
|
||||
3db18: c10b mov.w r0, @(22, gbr)
|
||||
|
||||
# Sets PTH0 to 'other functions' mode, which is IRQ0 and IRL0 input for the
|
||||
# interrupt controller.
|
||||
3db1a: d12e mov.l <3dbd4>(#0xa4000100), r1
|
||||
3db1c: 411e ldc r1, gbr
|
||||
3db1e: c507 mov.w @(14, gbr), r0
|
||||
3db20: d32d mov.l <3dbd8>(#0x0000fffc), r3
|
||||
3db22: 2039 and r3, r0
|
||||
3db24: c107 mov.w r0, @(14, gbr)
|
||||
|
||||
# Sets IRQ0 detection mode to low level input in ICR1.
|
||||
3db26: d227 mov.l <3dbc4>(#0xa4000000), r2
|
||||
3db28: 421e ldc r2, gbr
|
||||
3db2a: c508 mov.w @(16, gbr), r0
|
||||
3db2c: 2039 and r3, r0
|
||||
3db2e: cb02 or #2, r0
|
||||
3db30: c108 mov.w r0, @(16, gbr)
|
||||
|
||||
# Clears the IRQ0 interrupt flag.
|
||||
3db32: c404 mov.b @(4, gbr), r0
|
||||
3db34: c9fe and #-2, r0
|
||||
3db36: c004 mov.b r0, @(4, gbr)
|
||||
|
||||
# Enables IRQ0 interrupts with priority 13 in IPRC.
|
||||
3db38: c50b mov.w @(22, gbr), r0
|
||||
3db3a: d125 mov.l <3dbd0>(#0x0000fff0), r1
|
||||
3db3c: 2019 and r1, r0
|
||||
3db3e: cb0d or #13, r0
|
||||
3db40: c10b mov.w r0, @(22, gbr)
|
||||
|
||||
# Returns 1.
|
||||
3db42: 000b rts
|
||||
3db44: e001 mov #1, r0
|
||||
|
||||
Here is the first subroutine, that handles an unknown byte at 0x8800713d.
|
||||
This byte may be an extension of the interrupt status byte.
|
||||
|
||||
Returns 1 if a bit in the unknown byte matches the mask r4.
|
||||
Also, if r5 = 1, erases the bits according to the mask.
|
||||
|
||||
# Sets r6 to 1 if a bit in the mask is set in the unknown byte, 0 otherwise.
|
||||
# Also sets r0 = r5.
|
||||
63236: 624c extu.b r4, r2
|
||||
63238: d72a mov.l <632e4>(#0x8800713d), r7
|
||||
6323a: 6370 mov.b @r7, r3
|
||||
6323c: 633c extu.b r3, r3
|
||||
6323e: 2328 tst r2, r3
|
||||
63240: 8f02 bf/s <63248>
|
||||
63242: 6053 mov r5, r0
|
||||
63244: a001 bra <6324a>
|
||||
63246: e600 mov #0, r6
|
||||
63248: e601 mov #1, r6
|
||||
|
||||
# Uses the mask comparison result as return value. If the operation is 0, then
|
||||
# stop there.
|
||||
6324a: 8801 cmp/eq #1, r0
|
||||
6324c: 8f04 bf/s <63258>
|
||||
6324e: 6063 mov r6, r0
|
||||
|
||||
# Otherwise, erase the mask in the unknown byte.
|
||||
63250: 6370 mov.b @r7, r3
|
||||
63252: 6447 not r4, r4
|
||||
63254: 2349 and r4, r3
|
||||
63256: 2730 mov.b r3, @r7
|
||||
63258: 000b rts
|
||||
6325a: 0009 nop
|
||||
|
||||
Here is the second subroutine.
|
||||
It does exactly the same as the first, except that it uses the common
|
||||
interrupt status byte at 0x8800713c.
|
||||
It's the syscall 0x3ee.
|
||||
|
||||
631f6: 624c extu.b r4, r2
|
||||
631f8: d739 mov.l <632e0>(#0x8800713c), r7
|
||||
631fa: 6370 mov.b @r7, r3
|
||||
631fc: 633c extu.b r3, r3
|
||||
631fe: 2328 tst r2, r3
|
||||
63200: 8f02 bf/s <63208>
|
||||
63202: 6053 mov r5, r0
|
||||
63204: a001 bra <6320a>
|
||||
63206: e600 mov #0, r6
|
||||
63208: e601 mov #1, r6
|
||||
6320a: 8801 cmp/eq #1, r0
|
||||
6320c: 8f04 bf/s <63218>
|
||||
6320e: 6063 mov r6, r0
|
||||
63210: 6370 mov.b @r7, r3
|
||||
63212: 6447 not r4, r4
|
||||
63214: 2349 and r4, r3
|
||||
63216: 2730 mov.b r3, @r7
|
||||
63218: 000b rts
|
||||
6321a: 0009 nop
|
|
@ -0,0 +1,91 @@
|
|||
fxos lephe$ fxos disasm -s 0x24b sh7305.fls -l 200
|
||||
Syscall table: 0x801cdd84
|
||||
Syscall id: 0x24b
|
||||
Syscall address: 0x4cfc0380
|
||||
|
||||
===================================
|
||||
|
||||
Stack state:
|
||||
r4 s1: Parameter of call located at <e>
|
||||
pr
|
||||
r14
|
||||
r13
|
||||
------ Bottom
|
||||
|
||||
===================================
|
||||
|
||||
Missing information:
|
||||
|
||||
- Function of <fffffe44> (negative offset relative to <e>)
|
||||
- Function of <fffffdde> (negative offset relative to <3e>, does not seem to be
|
||||
the same as <fffffe44>, curiously)
|
||||
- Function of <8003e8c8> (probably syscall, but not found)
|
||||
|
||||
===================================
|
||||
|
||||
#
|
||||
# Initialization.
|
||||
#
|
||||
|
||||
# Saves the registers.
|
||||
0: 2fd6 mov.l r13, @-r15
|
||||
2: 2fe6 mov.l r14, @-r15
|
||||
4: 4f22 sts.l pr, @-r15
|
||||
6: 7ffc add #-4, r15
|
||||
8: 2f42 mov.l r4, @r15
|
||||
|
||||
# Loads 1 into r13. If jump at <16> is performed, r13 is changed to 0.
|
||||
a: ed01 mov #1, r13
|
||||
# r14 gets decremented whenever call at <e> is looped (considering the
|
||||
# documentation, it is probably the number of tries before the function
|
||||
# gives up).
|
||||
c: ee05 mov #5, r14
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Main loop, calls <fffffe44>. No more than initial_r14 turns.
|
||||
#
|
||||
|
||||
# Calls <fffffe44>(r4).
|
||||
e: bf19 bsr <fffffe44>
|
||||
10: 64f2 mov.l @r15, r4
|
||||
|
||||
# If result != 0, then <1a>, else <24>.
|
||||
12: 2008 tst r0, r0
|
||||
14: 8b01 bf <1a>
|
||||
16: a005 bra <24>
|
||||
18: ed00 mov #0, r13
|
||||
|
||||
|
||||
|
||||
#
|
||||
# When <fffffe44> returns non-zero, calls <8003e8c8>, decrements r14 and
|
||||
# loops.
|
||||
#
|
||||
|
||||
# Call <fffffe44> returned non-zero (r13 = 1).
|
||||
# Calls <8003e8c8>(10).
|
||||
1a: d22d mov.l <d0>(0x8003e8c8), r2
|
||||
1c: 420b jsr @r2
|
||||
1e: e40a mov #10, r4
|
||||
# Decrementing the number of tries before returning, and looping to <e> if the
|
||||
# number of tries has not been exceeded.
|
||||
20: 4e10 dt r14
|
||||
22: 8bf4 bf <e>
|
||||
|
||||
|
||||
|
||||
#
|
||||
# When <fffffe44> returns zero or the number of tries has been exceeded,
|
||||
# return from the function with the correct value.
|
||||
#
|
||||
|
||||
# Call <fffffe44> returned zero (r13 = 0). Ends the function and returns 1 if
|
||||
# the key is pressed, 0 otherwise.
|
||||
24: 60d3 mov r13, r0
|
||||
26: 7f04 add #4, r15
|
||||
28: 4f26 lds.l @r15+, pr
|
||||
2a: 6ef6 mov.l @r15+, r14
|
||||
2c: 000b rts
|
||||
2e: 6df6 mov.l @r15+, r13
|
Loading…
Reference in New Issue