Make room for an fx-cg50 compatible version. Enhanced build system.

This commit is contained in:
lephe 2018-04-09 08:31:12 +02:00
parent 131b432cc9
commit c50cbf6a9c
176 changed files with 166 additions and 15715 deletions

13
.gitignore vendored
View file

@ -5,19 +5,12 @@ build/**
*.sublime-project
*.sublime-workspace
# Object files.
*.o
# Some notes.
# Lots of unordered project notes
notes/**
# Output files
libc.a
libgint.a
gintdemo.g1a
gintdbg.g1a
bin/**
# Configuration files
gcc.cfg
Makefile.cfg
config/**

332
Makefile
View file

@ -4,267 +4,125 @@
#
#---
include Makefile.cfg
#
# Build configuration
#
#---
# Project variables
#---
# Some rules don't care if config files are missing (eg. clean, etc)
cfg := config/Makefile.cfg
-include $(cfg)
# Modules
modules-gint = bopti clock core display events gray init keyboard mmu rtc \
screen tales timer
modules-libc = ctype math setjmp stdio stdlib string time
# Those that do may use this special dependency
cfgdep := $(if $(shell [ -f $(cfg) ] || echo n),CFGDEP,$(cfg))
# Targets
target-lib = libgint.a
target-std = libc.a
target-g1a = gintdemo.g1a
# Compiler flags, assembler flags, dependency generation, archiving
cflags := -m3 -mb -ffreestanding -nostdlib -Wall -Wextra -std=c11 -O2 \
-I include $(cfg_defs)
dflags = -MMD -MT $@ -MF $(@:.o=.d) -MP
arflags :=
# Tools
cc = sh3eb-elf-gcc
ld = sh3eb-elf-ld
as = sh3eb-elf-as
ar = sh3eb-elf-ar
ob = sh3eb-elf-objcopy
wr = g1a-wrapper
#
# File listings
#
# Flags for gint
lib-cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \
-Wall -Wextra @gcc.cfg -g0
# Target file
target := bin/libgint.a
# Demo application (could be done better)
demo-src = $(notdir $(wildcard demo/*.[cs]))
demo-dep = $(wildcard demo/*.h)
demo-icon = demo/icon.bmp
demo-res = $(notdir $(wildcard demo/resources/*))
demo-obj = $(patsubst %,build/demo_%.o,$(demo-src) $(demo-res))
demo-elf = build/gintdemo.elf
demo-bin = build/gintdemo.bin
demo-ldflags = $(demo-cflags) -T demo/gintdemo.ld -L. -lgint -lc -lgcc
demo-cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \
-Wall -Wextra
# Automatic names for object and dependency files
src2obj = build/$(1:src/%=%).o
src2dep = build/$(1:src/%=%).d
# Specific objects
obj-std-spec =
obj-lib-spec = build/display_font_system.bmp.o build/version.o
# Source files
src := $(shell find src -name '*.[cs]')
src_obj := $(foreach s,$(src),$(call src2obj,$s))
# Configuration files, require them only if we're not cleaning
config = gcc.cfg
ifeq "$(filter clean mrproper distclean,$(MAKECMDGOALS))" ""
ifeq ($(wildcard $(config)),)
$(error "Configuration files are missing. Did you ./configure ?")
endif
endif
# Files with special handling
spe := src/display/font.bmp
spe_obj := $(foreach s,$(spe),$(call src2obj,$s))
# Target folder, require it only if we want to install
ifneq "$(filter install,$(MAKECMDGOALS))" ""
folder := $(shell fxsdk --folder)
ifndef folder
$(error "Could not get the fxSDK storage folder. Did you install fxSDK \
properly?")
endif
endif
# All object files
obj := $(src_obj) $(spe_obj)
#
# Toolchain
#
gcc = sh3eb-elf-gcc
as = sh3eb-elf-as
ld = sh3eb-elf-ld
ar = sh3eb-elf-ar
conv = fxconv
#---
# Automatic variables
#---
#
# Build rules
#
# Modules are subfolders of src/.
modules = $(modules-gint) $(modules-libc)
all: $(target)
define n
# This is a newline character.
$(target): $(obj) | $(dir $(target))
$(call cmd_l,ar,$@) $(ar) -crs $(arflags) $@ $(obj)
endef
# Assembler sources
build/%.s.o: src/%.s build/%.s.d
@ mkdir -p $(dir $@)
$(call cmd_b,as,$<) $(as) -c $< -o $@ $(sflags)
# Module-scope variables.
$(foreach mod, $(modules), $(eval \
mod-$(mod)-c = $(notdir $(wildcard src/$(mod)/*.c)) $n\
mod-$(mod)-asm = $(notdir $(wildcard src/$(mod)/*.s)) $n\
mod-$(mod)-src = $$(mod-$(mod)-c)$$(mod-$(mod)-asm) $n\
mod-$(mod)-obj = $$(patsubst %,build/$(mod)_%.o,$$(mod-$(mod)-src)) \
))
# C sources
build/%.c.o: src/%.c build/%.c.d $(cfgdep)
@ mkdir -p $(dir $@)
$(call cmd_b,gcc,$<) $(gcc) -c $< -o $@ $(dflags) $(cflags)
# Target-scope variables.
obj-std = $(foreach mod,$(modules-libc),$(mod-$(mod)-obj)) $(obj-std-spec)
obj-lib = $(foreach mod,$(modules-gint),$(mod-$(mod)-obj)) $(obj-lib-spec)
# Special files
$(call src2obj,src/display/font.bmp): src/display/font.bmp
@ mkdir -p $(dir $@)
$(call cmd_m,fxconv,$<) $(conv) -font $< -n gint_font -o $@
# Dependencies.
hdr-dep = $(wildcard include/*.h include/*/*.h)
#---
# Rule templates
#---
# C source file template:
# $1 module name
# $2 filename
# $3 dependencies
define rule-c-source
build/$1_$2.o: src/$1/$2 $3 $(config)
$(if $(VERBOSE),,@ printf '\e[34;1m gcc\e[0m $$<\n')
$(if $(VERBOSE),,@) $(cc) -c $$< -o $$@ $(lib-cflags)
endef
# Asm source file template:
# $1 module name
# $2 filename
define rule-asm-source
build/$1_$2.o: src/$1/$2 $(config)
$(if $(VERBOSE),,@ printf '\e[34;1m as\e[0m $$<\n')
$(if $(VERBOSE),,@) $(as) -c $$< -o $$@
endef
#---
# Version management
#---
# Retrieve version information.
version_string = $(shell cat version | sed 's/[-.]/ /g')
version_type = $(word 1,$(version_string))
version_major = $(word 2,$(version_string))
version_minor = $(word 3,$(version_string))
version_build = $(word 4,$(version_string))
# Make up the new version integer.
version_build_n = $(shell echo $$(($(version_build) + 1)))
version_letter = $(shell echo -n $(version_type) | sed -r 's/^(.).*/\1/')
version_symbol = $(shell printf '0x%02x%01x%01x%04x' "'$(version_letter)'" \
$(version_major) $(version_minor) $(version_build))
#---
# Building
#---
# Generic rules
all-lib: $(config) $(target-std) $(target-lib)
all: $(config) $(target-std) $(target-lib) $(target-g1a)
build:
$(if $(VERBOSE),,@ printf '\e[35;1m mkdir\e[0m $@\n')
$(if $(VERBOSE),,@) mkdir -p $@
version: src include
@ echo '$(version_type)-$(version_major).$(version_minor)-$(version_build_n)' > $@
$(obj-std) $(obj-lib) $(demo-obj): | build
$(target-std): $(obj-std) version
$(if $(VERBOSE),,@ printf '\e[35;1m ar\e[0m ar $@\n')
$(if $(VERBOSE),,@) $(ar) rcs $@ $(obj-std)
@ printf '\n\e[32;1m\u00bb\e[0m Succesfully built libc ('
@ printf $$(stat -c %s $@)
@ printf ' bytes)\n\n'
$(target-lib): $(config) $(target-std) $(obj-lib) version
$(if $(VERBOSE),,@ printf '\e[35;1m ar\e[0m $@\n')
$(if $(VERBOSE),,@) $(ar) rcs $@ $(obj-lib)
@ printf '\n\e[32;1m\u00bb\e[0m Succesfully built libgint ('
@ printf $$(stat -c %s $@)
@ printf ' bytes)\n\n'
$(target-g1a): $(config) $(target-std) $(target-lib) $(demo-obj)
$(if $(VERBOSE),,@ printf '\e[35;1m ld\e[0m $(demo-elf)\n')
$(if $(VERBOSE),,@) $(cc) -o $(demo-elf) $(demo-obj) $(demo-ldflags)
$(if $(VERBOSE),,@ printf '\e[35;1mobjcopy\e[0m $(demo-bin)\n')
$(if $(VERBOSE),,@) $(ob) -R .comment -R .bss -O binary $(demo-elf) $(demo-bin)
$(if $(VERBOSE),,@ printf '\e[35;1m fxg1a\e[0m $@\n')
$(if $(VERBOSE),,@) $(wr) $(demo-bin) -o $@ -i $(demo-icon)
@ printf '\n\e[32;1m\u00bb\e[0m Succesfully built demo application ('
@ printf $$(stat -c %s $@)
@ printf ' bytes)\n\n'
# Automated rules
$(foreach mod,$(modules), \
$(foreach source,$(mod-$(mod)-c), $(eval \
$(call rule-c-source,$(mod),$(source),$(hdr-dep)))) \
$(foreach source,$(mod-$(mod)-asm), $(eval \
$(call rule-asm-source,$(mod),$(source)))) \
)
# Specific rules
# Define the version symbol in a specific object file. ld generates a .stack
# section on sh3eb-elf, which it didn't on x86_64. I don't understand the
# details of why, so I just fall back to removing it afterwards.
build/version.o:
@ echo "_GINT_VERSION = $(version_symbol);" > $@.txt
$(if $(VERBOSE),,@ printf '\e[35;1m ld\e[0m $@\n')
$(if $(VERBOSE),,@) $(ld) -r -R $@.txt -o $@
$(if $(VERBOSE),,@) $(ob) -R .stack $@ $@
build/display_font_%.bmp.o: src/display/font_%.bmp
$(if $(VERBOSE),,@ printf '\e[30;1m fxconv\e[0m -font $<\n')
$(if $(VERBOSE),,@) fxconv -font $< -o $@ -font -n $(<:src/display/font_%.bmp=gint_font_%)
# Demo application
build/demo_%.c.o: demo/%.c $(hdr-dep) $(demo-dep) $(config)
$(if $(VERBOSE),,@ printf '\e[34;1m gcc\e[0m $<\n')
$(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(demo-cflags)
build/demo_%.s.o: demo/%.s $(config)
$(if $(VERBOSE),,@ printf '\e[34;1m as\e[0m $<\n')
$(if $(VERBOSE),,@) $(as) -c $< -o $@
build/demo_font_%.bmp.o: demo/resources/font_%.bmp
$(if $(VERBOSE),,@ printf '\e[30;1m fxconv\e[0m -font $<\n')
$(if $(VERBOSE),,@) fxconv -font $< -o $@ -n $(patsubst demo/resources/%.bmp,res_%,$<)
build/demo_%.bmp.o: demo/resources/%.bmp
$(if $(VERBOSE),,@ printf '\e[30;1m fxconv\e[0m -image $<\n')
$(if $(VERBOSE),,@) fxconv -image $< -o $@ -n $(patsubst demo/resources/%.bmp,res_%,$<)
#---
# Cleaning and install
#---
#
# Cleaning
#
clean:
@ rm -rf build
@ rm -rf build/
distclean: clean
@ rm -rf bin/
@ rm -f $(cfg)
mrproper: clean
@ rm -f $(target-g1a) $(target-lib) $(target-std)
@ rm -f $(config)
#
# Utilities
#
distclean: mrproper
# Evaluated when a rule requires the configuration file but it doesn't exist
CFGDEP:
@ echo "Configuration file $(cfg) is missing. Have you configured?"
@ echo "See \`./configure --help\` for details."
@ false
install: $(target-std) $(target-lib)
$(if $(VERBOSE),,@ printf '\e[35;1m mkdir\e[0m $(folder)\n')
$(if $(VERBOSE),,@) mkdir -p $(folder)
# Make directories: make conveniently leaves a '/' at the end of $(dir ...)
%/:
@ mkdir -p $@
# Don't try to unlink directories once they're built (that wouldn't work =p)
.PRECIOUS: %/
$(if $(VERBOSE),,@ printf '\e[33;1minstall\e[0m 644 $^\n')
$(if $(VERBOSE),,@) install -m 644 $^ $(folder)
$(if $(VERBOSE),,@ printf '\e[33;1minstall\e[0m 644 demo/gintdemo.ld\n')
$(if $(VERBOSE),,@) install -m 644 -T demo/gintdemo.ld $(folder)/linker.ld
# Dependency information
-include $(shell [ -d build ] && find build -name *.d)
build/%.d: ;
.PRECIOUS: build/%.d
$(if $(VERBOSE),,@ printf '\e[35;1m mkdir\e[0m $(folder)/gint/modules\n')
$(if $(VERBOSE),,@) mkdir -p $(folder)/gint/modules
# Do not output full commands by default
VERBOSE ?=
$(if $(VERBOSE),,@ printf '\e[33;1minstall\e[0m 644 include/**.h\n')
$(if $(VERBOSE),,@) install -m 644 include/*.h $(folder)/gint
$(if $(VERBOSE),,@) install -m 644 include/modules/*.h $(folder)/gint/modules
ifdef config_ext
$(if $(VERBOSE),,@) install -m 644 include/extended/*.h $(folder)/gint
endif
@ printf "\n\033[32;1m\u00bb\033[0m Successfully installed gint\n\n"
# Simple command output method
# $1 Program name
# $2 Argument string to display
# $3 Command color
define cmd
@ echo -e "\e[""$3"";1m>\e[0;1m $1\e[0m $2"
$(if $(VERBOSE),,@)
endef
install-demo: all
p7 send -f $(target-g1a)
.PHONY: all-lib all help
.PHONY: clean mrproper distclean
.PHONY: install install-demo
# Some pre-colored command kinds: misc, build, link, clean, install
cmd_m = $(call cmd,$1,$2,30)
cmd_b = $(call cmd,$1,$2,32)
cmd_l = $(call cmd,$1,$2,36)
cmd_c = $(call cmd,$1,$2,31)
cmd_i = $(call cmd,$1,$2,33)

View file

@ -9,6 +9,8 @@ target) and the [fxSDK](http://git.planet-casio.com/lephe/fxsdk).
gint is free software: you may use it for any purpose, share it, modify it and
share your changes. No credit of any kind is required, though appreciated.
**TODO: Update this file for everything related to project organization**
Programming interface
---------------------

105
configure vendored
View file

@ -6,8 +6,11 @@
declare -A conf
# Target platform
conf_target=
# Behavior
conf[GINT_STARTUP_LOG]=
conf[GINT_BOOT_LOG]=
conf[GINT_NO_SYSCALLS]=
conf[GINT_EXTENDED_LIBC]=
conf[GINT_STATIC_GRAY]=
@ -18,45 +21,50 @@ conf[TIMER_SLOTS]=16
conf[EVENTS_QUEUE_SIZE]=64
# Output files
output_gcc="gcc.cfg"
output_make="Makefile.cfg"
output="config/Makefile.cfg"
#
# Help screen and output util
#
error="\e[31;1merror:\e[0m"
Cg="$(tput setaf 8)$(tput bold)"
Cr="$(tput setaf 1)$(tput bold)"
Cy="$(tput setaf 2)$(tput bold)"
Cp="$(tput setaf 5)$(tput setaf 62)$(tput bold)"
C0="$(tput setaf 0)$(tput sgr 0)"
C_="$(echo -e '\e[30;1m')"
Cr="$(echo -e '\e[31;1m')"
Cg="$(echo -e '\e[32;1m')"
Cp="$(echo -e '\e[34;1m')"
C0="$(echo -e '\e[0m')"
help()
{
cat << EOF
Configuration script for the gint library.
Usage: $0 [options...]
Required settings:
$Cr--target$C0=${Cg}fx9860g$C0,${Cg}fxcg50$C0
Select the target platform, either ${Cg}fx9860g$C0 for monochrome
calculators, or ${Cg}fxcg50$C0 for Prizm calculators.
Options that affect the behavior of the library:
$Cr--startup-log $Cg[default:$Cp false$Cg]$C0
Enable a on-screen log at startup if a key is kept pressed while launching
$Cr--boot-log $C_[default:$Cp not specified$C_]$C0
Enable an on-screen log at startup if a key is kept pressed while launching
the add-in, allowing easy debug and crash diagnoses.
$Cr--no-syscalls $Cg[default:$Cp false$Cg]$C0
$Cr--no-syscalls $C_[default:$Cp not specified$C_]$C0
Never use syscalls. Expect trouble with malloc() and the gray engine. Do
not trigger this switch unless you know what you are doing.
$Cr--extended-libc $Cg[default:$Cp false$Cg]$C0
$Cr--extended-libc $C_[default:$Cp not specified$C_]$C0
Enable specific C99 headers/features that are normally not required by
calculator programs. This may allow porting programs from other platforms.
$Cr--static-gray-engine $Cg[default:$Cp false$Cg]$C0
$Cr--static-gray-engine $C_[default:$Cp not specified$C_]$C0
Place the gray engine vram in static ram instead of using the heap. Always
use this option when using both the gray engine and --no-syscalls.
Options that customize size limits:
$Cr--atexit-max=$Cy<integer>$Cg [default:$Cp 16$Cg]$C0
$Cr--atexit-max$C0=${Cg}integer$C_ [default:$Cp 16$C_]$C0
Number of exit handlers that can be registered by atexit().
$Cr--timer-slots=$Cy<integer>$Cg [default:$Cp 16$Cg]$C0
$Cr--timer-slots$C0=${Cg}integer$C_ [default:$Cp 16$C_]$C0
Number of virtual timers that may be registered at the same time.
$Cr--events-queue-size=$Cy<integer>$Cg [default:$Cp 64$Cg]$C0
$Cr--events-queue-size$C0=${Cg}integer$C_ [default:$Cp 64$C_]$C0
Number of events simultaneously stored in the event queue.
EOF
@ -69,8 +77,20 @@ EOF
fail=false
for arg; do case "$arg" in
-h | --help) help;;
--startup-log) conf[GINT_STARTUP_LOG]=true;;
-h | -? | --help) help;;
--target=*)
conf_target=${arg#*=}
if [[ $conf_target = "fx9860g" ]]; then
conf_target="GINT_FX9860G"
else if [[ $conf_target = "fxcg50" ]]; then
conf_target="GINT_FXCG50"
else
echo -e "$error Invalid target. See $0 --help."
fail=true;
fi; fi;;
--boot-log) conf[GINT_BOOT_LOG]=true;;
--no-syscalls) conf[GINT_NO_SYSCALLS]=true;;
--extended-libc) conf[GINT_EXTENDED_LIBC]=true;;
--static-gray-engine) conf[GINT_STATIC_GRAY]=true;;
@ -103,34 +123,41 @@ for arg; do case "$arg" in
esac; done
#
# Output config routines
# Checking mandatory arguments
#
output_config_gcc()
{
[ "${conf[GINT_STARTUP_LOG]}" != "" ] && echo "-D GINT_STARTUP_LOG"
[ "${conf[GINT_NO_SYSCALLS]}" != "" ] && echo "-D GINT_NO_SYSCALLS"
[ "${conf[GINT_EXTENDED_LIBC]}" != "" ] && echo "-D GINT_EXTENDED_LIBC"
[ "${conf[GINT_STATIC_GRAY]}" != "" ] && echo "-D GINT_STATIC_GRAY"
echo "-D ATEXIT_MAX=${conf[ATEXIT_MAX]}"
echo "-D TIMER_SLOTS=${conf[TIMER_SLOTS]}"
echo "-D EVENTS_QUEUE_SIZE=${conf[EVENTS_QUEUE_SIZE]}"
}
output_config_make()
{
[ "${conf[GINT_EXTENDED_LIBC]}" != "" ] && echo "config_ext=true"
}
if [[ ! $conf_target ]]; then
echo -e "$error No target specified. See $0 --help."
fail=true;
fi
#
# Output config
#
output_config()
{
echo -n "cfg_defs ="
echo -n " -D$conf_target"
[ "${conf[GINT_BOOT_LOG]}" ] && echo -n " -DGINT_BOOT_LOG"
[ "${conf[GINT_NO_SYSCALLS]}" ] && echo -n " -DGINT_NO_SYSCALLS"
[ "${conf[GINT_EXTENDED_LIBC]}" ] && echo -n " -DGINT_EXTENDED_LIBC"
[ "${conf[GINT_STATIC_GRAY]}" ] && echo -n " -DGINT_STATIC_GRAY"
echo -n " -DATEXIT_MAX=${conf[ATEXIT_MAX]}"
echo -n " -DTIMER_SLOTS=${conf[TIMER_SLOTS]}"
echo -n " -DEVENTS_QUEUE_SIZE=${conf[EVENTS_QUEUE_SIZE]}"
echo ""
[ "${conf[GINT_EXTENDED_LIBC]}" != "" ] && echo "cfg_ext = true"
}
if $fail; then
echo "Configuration has not been modified."
echo "Output file $output has not been modified."
else
output_config_gcc > $output_gcc
output_config_make > $output_make
echo "Configuration saved in $output_gcc and $output_make."
mkdir -p config
output_config > $output
echo "Configuration saved in $output, ready to make!"
fi

View file

@ -1,456 +0,0 @@
#include "gintdemo.h"
#include <mpu.h>
#include <gint.h>
#include <keyboard.h>
#include <display.h>
#include <gray.h>
#include <internals/stdio.h>
#include <stdio.h>
//---
// A few procedures for displaying text aligned on a 21*8 grid.
// Not really beautiful... but this will do.
//---
void locate(int x, int y, const char *str)
{
if(x < 1 || x > 21 || y < 1 || y > 8) return;
if(gray_runs()) gtext(x * 6 - 5, y * 8 - 8, str);
else dtext(x * 6 - 5, y * 8 - 8, str);
}
void print(int x, int y, const char *format, ...)
{
va_list args;
va_start(args, format);
__printf(0, format, args);
va_end(args);
locate(x, y, __stdio_buffer);
}
/*
printf_test()
Tests formatting functions.
void printf_test(void)
{
dclear();
locate(1, 1, "Formatted printing");
print(2, 3, "%%4.2d 5 :\"%4.2d\"", 5);
print(2, 4, "%%-3c '&':\"%-3c\"", '&');
print(2, 5, "%%#05x 27 :\"%#05x\"", 27);
print(2, 6, "%%1s \"tr\":\"%1s\"", "tr");
print(2, 7, "%%6p NULL :\"%6p\"", NULL);
dupdate();
while(getkey() != KEY_EXIT);
}
*/
/*
tlb_debug()
Displays the TLB contents and some information. Only available for
SH7705, because the SH7305's TLB is much more complicated.
void tlb_debug(void)
{
// Entry address address (pointer in the address array), entry data
// address (pointer in the data address), and their contents.
unsigned int address, data, a, d;
// Virtual page number and physical page number.
unsigned int vpn, ppn;
// Contents of register MMUCR.
unsigned mmucr;
int i, r, key = 0;
int way = 0, entry = 0;
int pointer_base;
const char *protection[] = { "pr", "prw", "ar", "arw" };
mmucr = *((volatile unsigned int *)gint_reg(Register_MMUCR));
dclear();
locate("MMU register info", 1, 1);
locate("MMUCR.IX = ", 2, 3);
locate(mmucr & 0x02 ? "1" : "0", 13, 3);
dupdate();
getkey();
while(key != KEY_EXIT && way < 4)
{
dclear();
print(1, 1, "TLB way=%d %d-%d", way, entry,
entry > 29 ? 31 : entry + 2);
for(i = 0; i < 3 && entry < 32; i++, entry++)
{
address = 0xf2000000 | (entry << 12) | (way << 8);
data = 0xf3000000 | (entry << 12) | (way << 8);
a = *((volatile unsigned int *)address);
d = *((volatile unsigned int *)data);
ppn = (d >> 10) & 0x00007ffff;
// 4-kbyte page
if(d & 0x08)
{
vpn = (a >> 12) | entry;
pointer_base = vpn << 12;
}
// 1-kbyte page
else
{
vpn = (a >> 10) | (entry << 2);
pointer_base = vpn << 10;
}
r = 2 * i + 3;
print(1, r, "%08x :%08x", pointer_base, ppn << 10);
r++;
locate((d & 0x08) ? "4k" : "1k", 1, r);
print(5, r, "pr=%s", protection[(d >> 5) & 3]);
locate((d & 0x02) ? "shared" : "exclusive", 13, r);
}
if(entry == 32) entry = 0, way++;
dupdate();
key = getkey();
}
}
*/
#include <internals/timer.h>
/*
main_menu()
Displays the main menu and returns user's choice: 0 for [EXIT],
application numbers otherwise. Sets the ctaegory and application
number.
*/
void main_menu(int *category, int *app)
{
//---
// Quite a few things to declare...
//---
extern image_t res_opt_menu;
const char *mpu, *mpu_names[] = {
"Unknown",
"SH7337",
"SH7355",
"SH7305",
"SH7724",
"[error]"
};
const char *list_tests[] = {
"Keyboard & events",
"Gray engine",
"Image rendering",
"Text rendering",
"Real-time clock",
"Clocks and timers",
NULL
};
/*
const char *list_perfs[] = {
"Image rendering",
"Text rendering",
NULL
};
*/
const char **list = NULL;
int list_len = 0;
extern unsigned int bgint, egint;
extern unsigned int romdata;
int gint_size = (char *)&egint - (char *)&bgint;
// Building a version string.
char gint_version[20];
uint32_t v = (uint32_t)&GINT_VERSION;
sprintf(gint_version, "%s-%d.%d-%d",
(v >> 24 == 'a') ? "alpha" : (v >> 24 == 'b') ? "beta" :
(v >> 24 == 'd') ? "dev" : (v >> 24 == 'r') ? "release" : "?",
(v >> 20) & 0x0f, (v >> 16) & 0x0f, v & 0xffff);
static int tab = 0, index = 0, scroll = 0;
// Set to 1 when interface has to be redrawn.
int leave = 1;
int i;
mpu = mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5];
text_configure(NULL, color_black);
while(1)
{
//---
// Displaying the current tab.
//---
dclear();
switch(tab)
{
case 0:
print(1, 1, "gint %s", gint_version);
print(2, 3, "MPU type %7s", mpu);
print(2, 4, "Add-in size %3dk",
((uint32_t)&romdata - 0x00300000) >> 10);
print(2, 5, "gint size %5do", gint_size);
list = NULL;
break;
case 1:
locate(1, 1, "Test list");
list = list_tests;
break;
/*
case 2:
locate(1, 1, "Performance");
list = list_perfs;
break;
*/
default:
print(1, 1, "Tab %d", tab);
break;
}
dimage_part(0, 56, &res_opt_menu, 0, 0, 42, 8);
if(list)
{
list_len = 0;
while(list[list_len]) list_len++;
for(i = scroll; list[i] && i < scroll + 6; i++)
locate(2, i - scroll + 2, list[i]);
if(scroll > 0) locate(20, 2, "\x0d");
if(scroll + 6 < list_len) locate(20, 7, "\x0e");
drect(0, 8 * (index - scroll) + 8, 127,
8 * (index - scroll) + 15, color_invert);
}
dupdate();
//---
// Waiting for events.
//---
do
{
leave = 1;
switch(getkey())
{
case KEY_F1:
if(!tab) break;
tab = 0;
index = 0;
break;
case KEY_F2:
if(tab == 1) break;
tab = 1;
index = 0;
scroll = 0;
break;
/* case KEY_F3:
*category = 2;
*app = 1;
return;
*/
/* case KEY_F3:
if(tab == 2) break;
tab = 2;
index = 0;
scroll = 0;
break;
*/
case KEY_UP:
if(list && list_len > 1)
{
if(index)
{
index--;
if(index < scroll) scroll--;
}
else
{
index = list_len - 1;
scroll = list_len - 6;
if(scroll < 0) scroll = 0;
}
}
else leave = 0;
break;
case KEY_DOWN:
if(list && list_len > 1)
{
if(list[index + 1])
{
index++;
if(index >= scroll + 6)
scroll++;
}
else
{
index = 0;
scroll = 0;
}
}
else leave = 0;
break;
case KEY_EXE:
if(!tab) break;
if(category) *category = tab;
if(app) *app = index + 1;
return;
default:
leave = 0;
}
}
while(!leave);
}
if(category) *category = 0;
if(app) *app = 0;
return;
}
/*
main()
No need for description.
*/
int main(void)
{
int category, app;
while(1)
{
main_menu(&category, &app);
if(!category) break;
switch((category << 8) | app)
{
case 0x0101: test_keyboard_events(); break;
case 0x0102: test_gray(); break;
case 0x0103: test_bopti(); break;
case 0x0104: test_tales(); break;
case 0x0105: test_rtc(); break;
case 0x0106: test_timer(); break;
case 0x0201: perf_bopti(); break;
case 0x0202: /* perf_tales(); */ break;
}
}
return 0;
}
/*
#include <bfile.h>
void screen(void)
{
const uint8_t bmp_header[0x7e] = {
0x42, 0x4d, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6c, 0x00,
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x13, 0x0b,
0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x47,
0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
};
const uint16_t file[] = { '\\', '\\', 'f', 'l', 's', '0', '\\', 'g',
's', 'c', 'r', 'e', 'e', 'n', '.', 'b', 'm', 'p', 0x00 };
int size = 0x7e + 1024;
BFile_Remove(file);
BFile_Create(file, BFile_File, &size);
int handle = BFile_Open(file, BFile_WriteOnly);
BFile_Write(handle, bmp_header, 0x7e);
void *vram = (void *)display_getCurrentVRAM() + 1024;
for(int i = 1; i <= 64; i++)
{
BFile_Write(handle, vram - 16 * i, 16);
}
BFile_Close(handle);
}
void screengray(void)
{
const uint8_t bmp_header[0x7e] = {
0x42, 0x4d, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6c, 0x00,
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x13, 0x0b,
0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x47,
0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
};
uint16_t file[] = { '\\', '\\', 'f', 'l', 's', '0', '\\', 'g', 's',
'c', 'r', 'e', 'e', 'n', '#', '.', 'b', 'm', 'p', 0x00 };
int size = 0x7e + 1024;
void *vram;
int handle;
gupdate();
file[14] = 'l';
BFile_Remove(file);
BFile_Create(file, BFile_File, &size);
handle = BFile_Open(file, BFile_WriteOnly);
BFile_Write(handle, bmp_header, 0x7e);
vram = (void *)gray_lightVRAM() + 1024;
for(int i = 1; i <= 64; i++)
{
BFile_Write(handle, vram - 16 * i, 16);
}
BFile_Close(handle);
file[14] = 'd';
BFile_Remove(file);
BFile_Create(file, BFile_File, &size);
handle = BFile_Open(file, BFile_WriteOnly);
BFile_Write(handle, bmp_header, 0x7e);
vram = (void *)gray_darkVRAM() + 1024;
for(int i = 1; i <= 64; i++)
{
BFile_Write(handle, vram - 16 * i, 16);
}
BFile_Close(handle);
gupdate();
}
*/

View file

@ -1,114 +0,0 @@
//---
//
// gint demo application
//
// Displays some tests cases for many features of the library.
//
//---
#ifndef _GINTDEMO_H
#define _GINTDEMO_H
//---
// Main routines and common functions.
//---
/*
main()
No need for description.
*/
int main(void);
/*
main_menu()
Displays the main menu and returns user's choice by setting the
category and application. Category is 0 when the user leaves the
application.
*/
void main_menu(int *category, int *app);
/*
locate()
Displays text using a system-like monospaced font on a 21*8 grid.
*/
void locate(int x, int y, const char *str);
/*
print()
Locates a string using formatted printing.
*/
void print(int x, int y, const char *format, ...);
//---
// Test applications.
//---
/*
test_keyboard_events()
Real-time keyboard management with events.
*/
void test_keyboard_events(void);
/*
test_gray()
Lets the user set the gray delays and see the results.
*/
void test_gray(void);
/*
test_bopti()
Displays and moves many kinds of bitmaps.
*/
void test_bopti(void);
/*
test_tales()
Displays some text using different modes and clipping options.
*/
void test_tales(void);
/*
test_rtc()
Just a clock.
*/
void test_rtc(void);
/*
test_timer()
Clock timer and timer precision.
*/
void test_timer(void);
//---
// Performance applications.
//---
/*
perf_bopti()
Compares bopti and MonochromeLib.
*/
void perf_bopti(void);
/*
perf_tales()
Compares tales and the system's text rendering functions.
*/
void perf_tales(void);
//---
// Debug applications.
//---
/*
debug_tlb()
On SH7705, displays the TLB contents. Does nothing on SH7305.
*/
void debug_tlb(void);
#endif // _GINTDEMO_H

View file

@ -1,113 +0,0 @@
/*
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. The "real ram" is accessed directly while
the other area is virtualized. It is not possible to execute code in
virtualized ram.
*/
OUTPUT_ARCH(sh3)
ENTRY(_start)
MEMORY
{
/* System-managed mappings map this area into the add-in data */
rom : o = 0x00300200, l = 512k
/* 0x0810000 is apparently mapped to 0x8801c0000 */
ram : o = 0x08100000, l = 8k
/* RAM section from P1 area, no MMU involved */
realram : o = 0x8800d000, l = 12k
}
SECTIONS
{
/* ROM sections: binary code and read-only data */
.text : {
/* Initialization code. */
*(.pretext.entry)
*(.pretext)
_bctors = ABSOLUTE(.);
*(.ctors)
_ectors = ABSOLUTE(.);
_bdtors = ABSOLUTE(.);
*(.dtors)
_edtors = ABSOLUTE(.);
*(.text)
*(.text.*)
} > rom
.rodata : {
*(.rodata.fxconv);
*(.rodata.paradox);
*(.rodata)
. = ALIGN(4);
*(.rodata.*)
_romdata = ALIGN(4) ;
} > rom
/* RAM sections: bss section and read/write data
The .bss section is to be stripped from the ELF file and wiped at
startup, hence its location is undefined */
.bss : {
_bbss = ABSOLUTE(.);
_sbss = ABSOLUTE(SIZEOF(.bss));
*(.bss)
} > ram
.data : AT(_romdata) ALIGN(4) {
_bdata = ABSOLUTE(.);
_sdata = ABSOLUTE(SIZEOF(.data));
*(.data)
*(.data.*)
} > ram
.cc : AT(_romdata + SIZEOF(.data)) ALIGN(4) {
*(.eh_frame)
*(.jcr)
. = ALIGN(4);
} > ram
/* Real RAM sections: interrupt handlers and some *uninitialized* gint
data */
_gint_data = _romdata + SIZEOF(.data) + SIZEOF(.cc) ;
.gint : AT(_gint_data) ALIGN(4) {
/* The vbr needs to be 0x100-aligned because of an ld issue */
. = ALIGN(0x100) ;
_gint_vbr = . ;
_bgint = ABSOLUTE(.) ;
/* Exception handler */
. = _gint_vbr + 0x100 ;
*(.gint.exc)
/* TLB miss handler */
. = _gint_vbr + 0x400 ;
*(.gint.tlb)
/* Interrupt handler */
. = _gint_vbr + 0x600 ;
*(.gint.int)
. = ALIGN(4);
_egint = ABSOLUTE(.) ;
} > realram
.gint_bss : AT(_gint_data + SIZEOF(.gint)) ALIGN(4) {
_bgbss = ABSOLUTE(.) ;
*(.gint.bss)
_egbss = ABSOLUTE(.) ;
} > realram
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

View file

@ -1,244 +0,0 @@
#include "gintdemo.h"
#include <display.h>
#include <gray.h>
#include <keyboard.h>
#include <internals/bopti.h>
#include <stddef.h>
/*
test_bopti()
Displays and moves many kinds of bitmaps. Here are the images used:
Name Size Color Alpha
---------------------------------------------------------
items.bmp 266 * 124 Gray -
sprites.bmp 66 * 33 Gray -
swords.bmp 88 * 16 Gray Full
---------------------------------------------------------
zelda.bmp 86 * 280 Mono -
isometric.bmp 37 * 27 Mono Full
- - Mono Greater
---------------------------------------------------------
*/
static void getwh(image_t *img, int *width, int *height)
{
const uint8_t *data;
if(!img)
{
*width = 0;
*height = 0;
return;
}
*width = img->width;
*height = img->height;
if(*width && *height) return;
data = (uint8_t *)img->data;
*width = (data[0] << 8) | data[1];
*height = (data[2] << 8) | data[3];
}
static void getxy(image_t *img, int *x, int *y)
{
int width, height;
getwh(img, &width, &height);
*x = 64 - (width >> 1);
*y = 28 - (height >> 1);
}
static image_t *select(image_t *current)
{
extern image_t res_bopti_thumbs;
extern image_t
res_items,
res_sprites,
res_swords,
res_zelda,
res_isometric;
extern image_t res_screen;
struct {
image_t *img;
const char *name;
const char *info;
} images[] = {
{ &res_items, "Items", "Gray" },
{ &res_sprites, "Sprites", "Gray" },
{ &res_swords, "Swords", "Gray Alpha" },
{ &res_zelda, "Zelda", "Mono" },
{ &res_isometric, "Isometric", "Mono Alpha" },
{ &res_screen, "TLT", "Mono" },
{ NULL, NULL, NULL }
};
image_t *thumbs = &res_bopti_thumbs;
int items = 0;
static int row = 0;
int leave = 1, i;
while(images[items].img) items++;
keyboard_setRepeatRate(625, 125);
gray_start();
while(1)
{
gclear();
locate(1, 1, "Select an image:");
for(i = 0; i < items && i < 7; i++)
{
locate(2, 2 + i + (i > row), images[i].name);
gimage_part(100, 8 + 8 * (i + (i > row)), thumbs, 0,
8 * i, 7, 7);
if(i == row)
{
int width, height;
getwh(images[i].img, &width, &height);
print(2, 2 + i + 1, "%d\x04%d", width, height);
locate(10, 2 + i + 1, images[i].info);
}
}
grect(0, 8 * row + 8, 128, 8 * row + 23, color_invert);
gupdate();
do
{
leave = 1;
switch(getkey())
{
case KEY_UP:
row = (row + items - 1) % items;
break;
case KEY_DOWN:
row = (row + 1) % items;
break;
case KEY_EXE:
return images[row].img;
case KEY_EXIT:
return current;
default:
leave = 0;
break;
}
}
while(!leave);
}
gray_stop();
}
void test_bopti(void)
{
extern image_t res_opt_bitmap;
image_t *img = NULL;
int leave = 1;
int black_bg = 0;
int x = 0, y = 0;
while(1)
{
keyboard_setRepeatRate(25, 25);
if(img && (img->format & channel_light))
{
gray_start();
gclear();
if(black_bg) grect(0, 0, 127, 63, color_invert);
if(img) gimage(x, y, img);
grect(0, 55, 127, 63, color_white);
gimage_part(0, 56, &res_opt_bitmap, 0, 0, 96, 8);
}
else if(img)
{
gray_stop();
dclear();
if(black_bg) drect(0, 0, 127, 63, color_invert);
if(img) dimage(x, y, img);
drect(0, 55, 127, 63, color_white);
dimage_part(0, 56, &res_opt_bitmap, 0, 0, 96, 8);
}
else
{
gray_stop();
dclear();
locate(3, 3, "No image selected");
dimage_part(0, 56, &res_opt_bitmap, 0, 0, 96, 8);
dupdate();
}
if(img)
{
int width, height;
getwh(img, &width, &height);
if(x < 0) print(1, 4, "\x01");
if(x + width > 128) print(21, 4, "\x02");
if(img->format & channel_light)
{
if(y < 0) gimage_part(61, 0, &res_opt_bitmap,
122, 0, 6, 8);
if(y + height > 64) gimage_part(61, 48,
&res_opt_bitmap, 116, 0, 6, 8);
gupdate();
}
else
{
if(y < 0) dimage_part(61, 0, &res_opt_bitmap,
122, 0, 6, 8);
if(y + height > 64) dimage_part(61, 48,
&res_opt_bitmap, 116, 0, 6, 8);
dupdate();
}
}
do
{
leave = 1;
switch(getkey())
{
case KEY_EXIT:
keyboard_setRepeatRate(625, 125);
gray_stop();
return;
case KEY_F1:
img = select(img);
getxy(img, &x, &y);
break;
case KEY_F2:
black_bg = !black_bg;
break;
case KEY_UP: y++; break;
case KEY_DOWN: y--; break;
case KEY_LEFT: x++; break;
case KEY_RIGHT: x--; break;
default:
leave = 0;
}
}
while(!leave);
}
keyboard_setRepeatRate(625, 125);
gray_stop();
return;
}

View file

@ -1,104 +0,0 @@
#include "gintdemo.h"
#include <gray.h>
#include <keyboard.h>
#include <mpu.h>
/*
test_gray()
Lets the user set the gray delays and see the results.
*/
static void draw(int delay1, int delay2, int selected, int gran)
{
extern image_t res_opt_gray;
uint32_t *vl = gray_lightVRAM();
uint32_t *vd = gray_darkVRAM();
gclear();
locate(1, 1, "Gray engine");
for(int i = 0; i < 64; i++)
{
int offset = (i << 2) + 3;
vl[offset] = -(!(i & 16));
vd[offset] = -(i < 32);
}
print(2, 3, "light %d", delay1);
print(2, 4, " dark %d", delay2);
print(2, 6, "Mode: \x04%d", gran);
int lengths[2] = {
4 - (delay1 < 1000),
4 - (delay2 < 1000)
};
print(8, 3 + selected, "\x01");
print(9 + lengths[selected], 3 + selected, "\x02");
gimage(0, 56, &res_opt_gray);
gupdate();
}
void test_gray(void)
{
int delays[2]; // { light, dark }
int key, changed = 1;
int selected = 0;
int gran = 1;
gray_getDelays(delays, delays + 1);
gray_start();
while(1)
{
if(changed)
{
gray_setDelays(delays[0], delays[1]);
draw(delays[0], delays[1], selected, gran);
}
changed = 0;
key = getkey_opt(getkey_default, 25);
if(key == KEY_EXIT) break;
changed = 1;
switch(key)
{
case KEY_F1:
delays[0] = 912;
delays[1] = 1343;
break;
case KEY_F2:
delays[0] = 993;
delays[1] = 1609;
break;
case KEY_F3:
delays[0] = 860;
delays[1] = 1298;
break;
case KEY_F5:
if(gran >= 100) gran = 1;
else gran *= 10;
case KEY_UP:
selected = 0;
break;
case KEY_DOWN:
selected = 1;
break;
case KEY_LEFT:
if(delays[selected] - gran >= 100)
delays[selected] -= gran;
break;
case KEY_RIGHT:
if(delays[selected] + gran < 10000)
delays[selected] += gran;
break;
default:
changed = 0;
break;
}
}
gray_stop();
}

View file

@ -1,195 +0,0 @@
#include "gintdemo.h"
#include <display.h>
#include <keyboard.h>
#include <stdlib.h>
#include <events.h>
static void draw_keyboard(volatile uint8_t *state)
{
int i, j, k, l;
int x, y;
for(i = 0; i < 10; i++) for(j = 1; j < 8; j++)
{
// Eliminating keys that do not exist.
if(!i && j != 7) continue;
if(i && j == 7) continue;
if(i <= 4 && j == 6) continue;
if(i == 4 && j == 5) continue;
x = 5 * j + 1;
y = 59 - 5 * i;
// Space for the horizontal line.
y += 3 * (i < 7);
// Moving the [AC/ON] key.
if(!i) x = 5 * (5) + 1, y = 61 - 5 * (4) + 1;
// Drawing a filled shape when the key is pressed.
if(state[i] & (0x80 >> j))
{
for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++)
if(abs(k) + abs(l) <= 2)
dpixel(x + k, y + l, color_black);
}
// Drawing a square border otherwise.
else
{
for(k = -1; k <= 1; k++) for(l = -1; l <= 1; l++)
if(k || l) dpixel(x + k, y + l, color_black);
}
}
// Binding the arrow keys together for a more visual thing.
dpixel(28, 19, color_black); dpixel(29, 19, color_black);
dpixel(28, 24, color_black); dpixel(29, 24, color_black);
dpixel(26, 21, color_black); dpixel(26, 22, color_black);
dpixel(31, 21, color_black); dpixel(31, 22, color_black);
// An horizontal line to separate parts of the keyboard.
dline(5, 28, 32, 28, color_black);
}
typedef struct {
uint32_t key;
int repeats;
} history_key_t;
typedef struct {
history_key_t *data;
int size;
int pressed;
} history_t;
static int pressed_keys = 0;
static int releases = 0;
static void history_push(history_t *h, event_t event)
{
// Only reset the number of pressed keys in the history when the actual
// number of pressed keys reaches 0.
if(event.type == event_key_release)
{
pressed_keys--;
if(!pressed_keys) h->pressed = 0;
return;
}
// Now we're sure a key was pressed or repeated. Check if it's in the
// last pressed elements of the history array, if so, update it.
// Otherwise make space for a new entry and add it.
if(event.type == event_key_press) pressed_keys++;
for(int i = h->size - h->pressed; i < h->size; i++)
{
if(h->data[i].key == event.key.code)
{
h->data[i].repeats++;
return;
}
}
// If there are already h->size keys pressed, do not add more.
if(event.type == event_key_press) h->pressed++;
if(h->pressed > h->size) return;
for(int i = 0; i < h->size - 1; i++) h->data[i] = h->data[i + 1];
h->data[h->size - 1].key = event.key.code;
h->data[h->size - 1].repeats = 1;
}
static void draw_events(history_t *h)
{
const char *key_names[] = {
"F1", "F2", "F3", "F4", "F5", "F6",
"SHIFT", "OPTN", "VARS", "MENU", "Left", "Up",
"ALPHA", "x^2", "^", "EXIT", "Down", "Right",
"X,\x1d,T", "log", "ln", "sin", "cos", "tan",
"[frac]", "F\x0f\x09" "D", "(", ")", ",", "\x09",
"7", "8", "9", "DEL", "AC/ON", NULL,
"4", "5", "6", "\x04", "\x05", NULL,
"1", "2", "3", "+", "-", NULL,
"0", ".", "\x08", "(-)", "EXE", NULL
};
int y = 3;
int y_limit = 8 - (h->pressed > h->size);
extern font_t res_font_modern;
text_configure(&res_font_modern, color_black);
dtext(49, 12, "Key");
dtext(89, 12, "Rep.");
// dprint(49, 7, "%d %d %d", h->pressed, pressed_keys, releases);
text_configure(NULL, color_black);
dline(45, 18, 120, 18, color_black);
for(int i = 0; i < h->size && y < y_limit; i++) if(h->data[i].key)
{
dtext(49, y * 8 - 4, key_names[key_id(h->data[i].key)]);
if(h->data[i].repeats > 1)
dprint(89, y * 8 - 4, "%d", h->data[i].repeats);
y++;
}
if(h->pressed > h->size) dtext(49, 52, "(more)");
}
/*
test_keyboard_events()
Real-time keyboard management with events.
*/
void test_keyboard_events(void)
{
history_key_t history_data[5] = { 0 };
history_t history = {
.data = history_data,
.size = 5,
.pressed = 0,
};
event_t event;
// There may be keys pressed when this test starts. We need to detect
// which and create a valid history for them.
volatile const uint8_t *buffer = keyboard_stateBuffer();
// For the purpose of this function we don't need to calculate the
// other fields.
event_t push_event = {
.type = event_key_press,
.key.code = KEY_AC_ON,
};
// Finding all the pressed keys and pushing them in the history.
if(buffer[0] & 1) history_push(&history, push_event);
for(int row = 1; row <= 9; row++) for(int col = 0; col < 8; col++)
{
// Eliminate non-existing keys.
if(col > 6 || col <= (row <= 4)) continue;
if(buffer[row] & (1 << col))
{
push_event.key.code = (col << 4) | row;
history_push(&history, push_event);
}
}
while(1)
{
dclear();
locate(1, 1, "Keyboard and events");
draw_keyboard(keyboard_stateBuffer());
draw_events(&history);
dupdate();
event = waitevent();
if(event.type == event_key_release) releases++;
if(event.type == event_key_press && event.key.code == KEY_EXIT)
break;
history_push(&history, event);
}
}

View file

@ -1,260 +0,0 @@
#include "gintdemo.h"
#include <display.h>
#include <rtc.h>
#include <keyboard.h>
#include <stddef.h>
#include <ctype.h>
/*
test_rtc()
Just a clock. Of course using all this RTCTime conversion and this / 10
is awfully un-optimized, but it's a test case so it's made to check the
values in the structure are correct.
*/
#include <internals/rtc.h>
#include <modules/rtc.h>
#include <mpu.h>
static void draw(rtc_time_t *time)
{
extern image_t res_rtc_segments;
const char *days[7] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
}, *months[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"
};
int x[6] = { 20, 33, 52, 65, 84, 97 };
int digits[6];
int i;
digits[0] = time->hours / 10;
digits[1] = time->hours % 10;
digits[2] = time->minutes / 10;
digits[3] = time->minutes % 10;
digits[4] = time->seconds / 10;
digits[5] = time->seconds % 10;
// Drawing digits.
for(i = 0; i < 6; i++) dimage_part(x[i], 8, &res_rtc_segments,
12 * digits[i], 0, 11, 19);
// Drawing ':' between pairs of digits.
for(i = 0; i < 16; i++) dpixel(47 + 32 * (i >= 8) + (i & 1),
14 + 5 * !!(i & 4) + !!(i & 2), color_black);
// This should print time.year + 1900 but for the sake of this demo we
// have tweaked the field so that it already contains time.year + 1900.
print(4, 6, "%s %s %02d %4d", days[time->week_day],
months[time->month], time->month_day, time->year);
}
static void callback(void)
{
extern image_t res_opt_rtc;
rtc_time_t time;
rtc_getTime(&time);
dclear();
draw(&time);
dimage_part(0, 56, &res_opt_rtc, 0, 0, 19, 8);
dupdate();
}
static void set_region(rtc_time_t *time, int region, int value)
{
switch(region)
{
case 0:
time->hours = 10 * value + (time->hours % 10);
break;
case 1:
time->hours = time->hours - (time->hours % 10) + value;
break;
case 2:
time->minutes = 10 * value + (time->minutes % 10);
break;
case 3:
time->minutes = time->minutes - (time->minutes % 10) + value;
break;
case 4:
time->seconds = 10 * value + (time->seconds % 10);
break;
case 5:
time->seconds = time->seconds - (time->seconds % 10) + value;
break;
case 6:
time->week_day = value;
break;
case 7:
time->month = value;
break;
case 8:
time->month_day = 10 * value + (time->month_day % 10);
break;
case 9:
time->month_day = time->month_day - (time->month_day % 10)
+ value;
break;
case 10:
time->year = 1000 * value + (time->year % 1000);
break;
case 11:
time->year = time->year - (time->year % 1000) + 100 * value
+ (time->year % 100);
break;
case 12:
time->year = time->year - (time->year % 100) + 10 * value
+ (time->year % 10);
break;
case 13:
time->year = time->year - (time->year % 10) + value;
break;
}
}
static void set(void)
{
extern image_t res_opt_rtc;
image_t *opt = &res_opt_rtc;
struct {
int x, y;
int w, h;
} regions[] = {
{ 19, 7, 13, 21 }, { 32, 7, 13, 21 }, { 51, 7, 13, 21 },
{ 64, 7, 13, 21 }, { 83, 7, 13, 21 }, { 96, 7, 13, 21 },
{ 18, 39, 19, 9 }, { 42, 39, 19, 9 }, { 66, 39, 7, 9 },
{ 72, 39, 7, 9 }, { 84, 39, 7, 9 }, { 90, 39, 7, 9 },
{ 96, 39, 7, 9 }, { 102, 39, 7, 9 },
};
rtc_time_t time;
int region_count = 14;
int n = 0, slide = 0, key, leave;
rtc_getTime(&time);
while(1)
{
dclear();
draw(&time);
drect(regions[n].x, regions[n].y, regions[n].x + regions[n].w
- 1, regions[n].y + regions[n].h - 1, color_invert);
if(n == 6) dimage_part(0, 56, opt, 0, 9 * (1 + slide), 128, 8);
if(n == 7) dimage_part(0, 56, opt, 0, 9 * (3 + slide), 128, 8);
else dimage_part(0, 56, opt, 22 + 22 * (n == region_count - 1),
0, 19, 8);
dupdate();
do
{
leave = 1;
key = getkey();
if(key == KEY_EXIT) return;
else if(key == KEY_F1 || key == KEY_EXE)
{
slide = 0;
if(++n == region_count)
{
rtc_setTime(&time);
return;
}
}
else if(key == KEY_F6)
{
if(n == 6) slide = (slide + 1) % 2;
if(n == 7) slide = (slide + 1) % 3;
}
else if((key & 0x0f) == 9) // Other F-keys
{
int k = 7 - (key >> 4); // Number of F-key
if(n == 7)
{
int month = k + 4 * slide - 2;
set_region(&time, n, month);
n++;
slide = 0;
}
else if(n == 6 && (slide != 1 || k != 5))
{
int day = (k + 4 * slide - 1) % 7;
set_region(&time, n, day);
n++;
slide = 0;
}
else leave = 0;
}
else if(isdigit(key_char(key))) // Numbers
{
int val = key_char(key) - '0';
int ok = 1;
if(n == 0) ok = (val <= 2);
if(n == 1)
{
int max = time.hours >= 20 ? 3 : 9;
ok = (val <= max);
}
if(n == 2 || n == 4) ok = (val <= 5);
if(n == 8) ok = (val <= 3);
if(n == 9)
{
int max = time.month_day >= 30 ? 1 : 9;
ok = (val <= max);
}
if(ok)
{
set_region(&time, n, val);
n++;
if(n == region_count)
{
rtc_setTime(&time);
return;
}
slide = 0;
}
else leave = 0;
}
else leave = 0;
} while(!leave);
}
while(getkey() != KEY_EXIT);
}
void test_rtc(void)
{
int key, cb_id;
cb_id = rtc_cb_add(rtc_freq_1Hz, callback, 0);
callback();
while(1)
{
key = getkey();
if(key == KEY_EXIT) break;
if(key == KEY_F1)
{
rtc_cb_edit(cb_id, rtc_freq_none, NULL);
set();
callback();
rtc_cb_edit(cb_id, rtc_freq_1Hz, callback);
}
}
rtc_cb_end(cb_id);
}

View file

@ -1,158 +0,0 @@
#include "gintdemo.h"
#include <display.h>
#include <keyboard.h>
#include <gray.h>
#include <stddef.h>
/*
test_tales()
Displays some text using different modes and clipping options.
*/
static font_t *select(font_t *current)
{
extern font_t res_font_modern;
struct {
font_t *font;
const char *name;
} fonts[] = {
{ NULL, "gint default" },
{ &res_font_modern, "Modern" },
};
int font_number = 2;
static int row = 0;
int i, leave;
while(1)
{
text_configure(NULL, color_black);
dclear();
locate(1, 1, "Select a font:");
for(i = 0; i < font_number && i < 6; i++)
{
if(fonts[i].font)
{
int height = fonts[i].font->line_height;
int y = (i + 2) * 8 - 8 + ((7 - height) >> 1);
text_configure(fonts[i].font, color_black);
dtext(7, y, fonts[i].name);
}
else
{
text_configure(NULL, color_black);
locate(2, i + 2, fonts[i].name);
}
}
drect(0, 8 * row + 8, 128, 8 * row + 15, color_invert);
dupdate();
do
{
leave = 1;
switch(getkey())
{
case KEY_UP:
row = (row + font_number - 1) % font_number;
break;
case KEY_DOWN:
row = (row + 1) % font_number;
break;
case KEY_EXE:
return fonts[row].font;
case KEY_EXIT:
return current;
default:
leave = 0;
break;
}
}
while(!leave);
}
}
void test_tales(void)
{
color_t colors[] = { color_black, color_dark, color_light, color_white,
color_invert };
extern image_t res_opt_tales;
font_t *font = NULL;
int black_bg = 0;
int color = 0;
int i, x, height;
int leave;
gray_start();
while(1)
{
gclear();
if(black_bg) grect(0, 0, 127, 54, color_invert);
if(font)
{
text_configure(font, colors[color]);
height = font->line_height + 1;
}
else
{
text_configure(NULL, colors[color]);
height = 8;
}
for(i = 0; i < 6 && 2 + (i + 1) * height < 56; i++)
{
char str[17];
for(int j = 0; j < 16; j++) str[j] = 32 + (i << 4) + j;
str[16] = 0;
gtext(1, 1 + i * height, str);
}
gimage(0, 56, &res_opt_tales);
x = 45 + 8 * color;
gline(x, 57, x + 5, 57, color_black);
gline(x, 57, x, 62, color_black);
gline(x + 5, 57, x + 5, 62, color_black);
gline(x, 62, x + 5, 62, color_black);
gupdate();
do
{
leave = 1;
switch(getkey())
{
case KEY_F1:
gray_stop();
font = select(font);
gray_start();
break;
case KEY_F2:
color = (color + 1) % 5;
break;
case KEY_F5:
black_bg = !black_bg;
break;
case KEY_EXIT:
gray_stop();
text_configure(NULL, color_black);
return;
default:
leave = 0;
break;
}
}
while (!leave);
}
}

View file

@ -1,273 +0,0 @@
#include "gintdemo.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <internals/timer.h>
#include <timer.h>
#include <display.h>
#include <keyboard.h>
#include <clock.h>
#include <mpu.h>
#include <rtc.h>
static void draw(int new_tab);
static clock_config_t conf;
//---
// Timer-RTC comparison.
// The precision of the timer is measured by comparing it to the RTC.
//---
static volatile int elapsed_timer = -1;
static volatile int elapsed_rtc = -1;
static int cb_id = -1;
static timer_t *htimer = NULL;
static void timing_rtc(void)
{
elapsed_rtc++;
}
static void timing_timer(void)
{
elapsed_timer++;
}
static void timing_start(void)
{
uint32_t delay = clock_setting(64, clock_Hz);
htimer = htimer_setup(timer_user, delay, timer_Po_4, 0);
timer_attach(htimer, timing_timer, NULL);
timer_start(htimer);
rtc_cb_edit(cb_id, rtc_freq_64Hz, timing_rtc);
elapsed_timer = 0;
elapsed_rtc = 0;
}
//---
// Drawing.
//---
/*
small_text()
Renders small text using a minimalist bitmap-based font.
*/
static void small_text(int x, int y, const char *text, int alignment)
{
extern image_t res_clock_chars;
image_t *chars = &res_clock_chars;
const char *table = "0123456789kMHz*/";
if(alignment) x -= 2 * strlen(text) - 1, y -= 2;
int c;
while(*text)
{
const char *ptr = strchr(table, *text++);
if(!ptr) continue;
c = ptr - table;
dimage_part(x, y, chars, c << 2, 0, 3, 5);
x += 4;
}
}
/*
getFreq()
Prints the given frequency in a string on the form:
332kHz
There are 1, 2 or 3 characters for the value, and 2 or 3
characters for the unit. The string is compacted.
*/
void getFreq(char *str, int freq)
{
if(freq < 1000) sprintf(str, "%dHz", freq);
else if(freq < 1000000) sprintf(str, "%dkHz", (freq + 500) / 1000);
else sprintf(str, "%dMHz", (freq + 500000) / 1000000);
}
/*
dislay_freq()
Displays a frequency value a unit, in an simple form.
*/
static void display_freq(int x, int y, int freq)
{
int ratio, letter, dot, i;
char buffer[10];
if(freq <= 0)
{
dtext(x, y, "Unknown");
return;
}
if(freq < 10000)
{
dprint(x, y, "%5d", freq);
small_text(x + 31, y + 2, "Hz", 0);
return;
}
if(freq < 10000000) ratio = 1, letter = 'k';
else ratio = 1000, letter = 'M';
dot = 1 + (freq >= 10000 * ratio) + (freq >= 100000 * ratio);
freq += (ratio * (1 + 9 * (dot >= 2) + 90 * (dot >= 3))) / 2;
snprintf(buffer, 6, "%d", freq);
for(i = 4; i > dot; i--) buffer[i] = buffer[i - 1];
buffer[dot] = '.';
dprint(x, y, buffer);
sprintf(buffer, "%cHz", letter);
small_text(x + 31, y + 2, buffer, 0);
}
/*
draw()
Draws the test interface.
*/
static void draw(int tab)
{
extern image_t res_opt_timer;
extern image_t res_clock_7705;
extern image_t res_clock_7305;
char buffer[16];
dclear();
dimage(0, 56, &res_opt_timer);
if(!tab)
{
locate(1, 1, "Clock frequency");
dtext(7, 20, "B\x1e");
display_freq(24, 20, conf.Bphi_f);
dtext(7, 28, "I\x1e");
display_freq(24, 28, conf.Iphi_f);
dtext(7, 36, "P\x1e");
display_freq(24, 36, conf.Pphi_f);
if(isSH3())
{
dimage(64, 0, &res_clock_7705);
getFreq(buffer, conf.CKIO_f);
small_text(84, 16, buffer, 1);
sprintf(buffer, "*%d", conf.PLL1);
small_text(84, 34, buffer, 1);
if(conf.Iphi_div1 == 1)
dline(85, 43, 99, 43, color_black);
else
{
sprintf(buffer, "/%d", conf.Iphi_div1);
small_text(89, 41, buffer, 0);
}
if(conf.Pphi_div1 == 1)
dline(85, 50, 99, 50, color_black);
else
{
sprintf(buffer, "/%d", conf.Pphi_div1);
small_text(89, 48, buffer, 0);
}
}
else
{
dimage(64, 0, &res_clock_7305);
getFreq(buffer, conf.RTCCLK_f);
small_text(82, 13, buffer, 1);
sprintf(buffer, "*%d", conf.FLL);
small_text(82, 23, buffer, 1);
sprintf(buffer, "*%d", conf.PLL);
small_text(82, 33, buffer, 1);
sprintf(buffer, "/%d", conf.Bphi_div1);
small_text(87, 40, buffer, 0);
sprintf(buffer, "/%d", conf.Iphi_div1);
small_text(87, 47, buffer, 0);
sprintf(buffer, "/%d", conf.Pphi_div1);
small_text(87, 54, buffer, 0);
}
}
else
{
int timer = elapsed_timer, rtc = elapsed_rtc; // just in case
locate(1, 1, "Timer/RTC comparison");
locate(2, 3, "Timer");
if(timer >= 0) print(12, 3, "%04x", timer);
else locate(12, 3, "...");
locate(2, 4, "RTC");
if(rtc >= 0) print(12, 4, "%04x", rtc);
else locate(12, 4, "...");
// We define the accuracy of the timer as the ratio between the
// two counters.
locate(2, 5, "Accuracy");
if(rtc > 0 && timer > 0)
{
int ratio;
if(timer <= rtc) ratio = (10000 * timer) / rtc;
else ratio = (10000 * rtc) / timer;
print(12, 5, "%d.%02d%%", ratio / 100, ratio % 100);
}
else locate(12, 5, "...");
}
dupdate();
}
//---
// Timer/clock test.
//---
/*
test_timer()
Clock timer and timer precision.
*/
void test_timer(void)
{
int tab = 0;
conf = clock_config();
elapsed_timer = -1;
elapsed_rtc = -1;
cb_id = rtc_cb_add(rtc_freq_64Hz, timing_start, 0);
text_configure(NULL, color_black);
while(1)
{
draw(tab);
switch(getkey_opt(getkey_none, 25))
{
case KEY_EXIT:
rtc_cb_end(cb_id);
timer_stop(htimer);
return;
case KEY_F1:
tab = 0;
break;
case KEY_F2:
tab = 1;
break;
}
}
}

View file

@ -1,673 +0,0 @@
#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) are used to avoid name
conflicts (e.g. STRUCTURE.RTC would expand to STRUCTURE.((T *)0x...)).
*/
#pragma pack(push, 1)
#define gap(n) unsigned: n << 3
//---
// 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 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

View file

@ -1,25 +0,0 @@
//---
//
// standard library module: alloca
//
// Allows dynamic memory allocation on the stack. Memory is automatically
// freed when the calling function exits, but this function suffers from
// risks of stack overflow; make sure you don't inline functions that use
// alloca or allocate more than a few hundred bytes with it.
//
//---
#ifndef _ALLOCA_H
#define _ALLOCA_H
#include <stddef.h>
/*
alloca()
Allocates a memory block on the stack.
*/
void *alloca(size_t size);
#define alloca(size) __builtin_alloca(size)
#endif // _ALLOCA_H

View file

@ -1,74 +0,0 @@
//---
//
// gint core module: BFile interface
//
// Syscall-based interface to the BFile driver (which I would never dare
// to re-write considering how much the storage memory filesystem is an
// awful mess).
//
//---
#ifndef _BFILE_H
#define _BFILE_H
/*
BFile_Remove()
Remove a file from the filesystem. The path must be encoded as two-byte
fontcharacters!
*/
int BFile_Remove(const uint16_t *file);
/*
BFile_Create()
Creates an entry in the filesystem (two-byte fontcharacter path) of the
given type. The size pointer must point to the file size for files, and
may be NULL for folders.
*/
enum BFile_EntryType
{
BFile_File = 1,
BFile_Folder = 5,
};
int BFile_Create(const uint16_t *file, enum BFile_EntryType type, int *size);
/*
BFile_Open()
Opens an existing file (two-byte fontcharacter path) with the required
mode, and returns a handle (positive integer) on success, or an
negative integer on error.
*/
enum BFile_OpenMode
{
BFile_ReadOnly = 0x01,
BFile_WriteOnly = 0x02,
BFile_ReadWrite = BFile_ReadOnly | BFile_WriteOnly,
};
int BFile_Open(const uint16_t *file, enum BFile_OpenMode mode);
/*
BFile_Close()
Closes an open file.
*/
int BFile_Close(int handle);
/*
BFile_Write()
Writes data to a file. The data is taken from the second-argument
buffer. The size to write is given as third argument.
WARNING: Always write an even number of bytes or you're in for trouble!
*/
int BFile_Write(int handle, const void *ram_buffer, int even_size);
/*
BFile_Read()
Reads from an open file. The second and third arguments indicate where
to store data and how much to read. The location from where the data is
read depends on the value of `whence`:
- If `whence` >= 0, it is considered as the absolute location (in
bytes) of the requested data in the file;
- If `whence` == -1, BFile_Read() reads from the current virtual
position in the file.
*/
int BFile_Read(int handle, void *ram_buffer, int size, int whence);
#endif // _BFILE_H

View file

@ -1,73 +0,0 @@
//---
//
// gint drawing module: bopti
//
// This module is a powerful bitmap renderer. It *heavily* relies on the
// line-based structure of the video RAM as well as the high density of
// information. A single CPU access (longword operation) can affect 32
// pixels at once, which is crucial for performance. The same goes for all
// other drawing modules, but this one typically has 350 lines of code
// just to wrap these longword accesses -- and it's blazingly fast.
//
//---
#ifndef _BOPTI_H
#define _BOPTI_H
/*
image_t
This structure holds meta-data of a bitmap encoded with fxconv. Data is
accessed using longword operations for performance considerations,
which requires that the all fields of the structure be properly aligned
and of a correct size.
*/
typedef struct
{
uint8_t magic;
uint8_t format;
uint8_t width;
uint8_t height;
const uint32_t data[];
} __attribute__((packed, aligned(4))) image_t;
/*
dimage()
Displays a monochrome image in the vram. This function does a real lot
of optimization.
*/
void dimage(int x, int y, image_t *image);
/*
dimage_part()
Draws a portion of an image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void dimage_part(
int x, int y,
image_t *img,
int left, int top, int width, int height
);
/*
gimage()
Displays a gray image in the dual-vram.
*/
void gimage(int x, int y, image_t *image);
/*
gimage_part()
Draws a portion of a gray image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void gimage_part(
int x, int y,
image_t *image,
int left, int top, int width, int height
);
#endif // _BOPTI_H

View file

@ -1,121 +0,0 @@
//---
//
// gint core module: clock
//
// This module interfaces with the MPU clocks and is used to measure the
// clock frequencies at the beginning of execution. At this stage, it
// assumes that clock mode 3 is used on SH7305 (as does FTune), because
// there doesn't seem to be a way of getting this information.
//
// It also provides some sleep and time conversion functions, and access
// to how the clocks are configured. In the future, it would be the module
// that supports overclock.
//
//---
#ifndef _CLOCK_H
#define _CLOCK_H
#include <stdint.h>
//---
// Sleep functions.
//---
/*
sleep()
Puts the processor to sleep until an interrupt request is accepted.
This function should be called every time the program because idle
because it doesn't have anything to do -- between two game frames or
while waiting for a keyboard event.
This function is called by getkey_opt(), getkey(), waitevent(), this
module's sleep functions among others.
*/
void sleep(void);
/*
sleep_ms()
Sleeps for the given number of milliseconds using a virtual timer.
*/
void sleep_ms(int ms_delay);
/*
sleep_us()
Sleeps for the given number of microseconds using the hardware timer
timer_user.
*/
void sleep_us(int us_delay);
//---
// Clock management.
//---
/*
clock_unit_t
Enumerated type used by the time conversion functions. It indicates the
type (delay or frequency) of a parameter.
*/
typedef enum
{
clock_us = 0,
clock_ms = 1,
clock_s = 2,
clock_Hz = 10,
clock_kHz = 11,
clock_MHz = 12,
} clock_unit_t;
/*
clock_config_t
A copy of the Clock Pulse Generator (CPG) configuration. Be sure to
check which MPU the program is running on (using <mpu.h>) to access the
right fields.
*/
typedef struct
{
union
{
int PLL1; // SH7705
int FLL; // SH7305
};
union
{
int PLL2; // SH7705
int PLL; // SH7305
};
int Bphi_div1;
int Iphi_div1;
int Pphi_div1;
union
{
int CKIO_f; // SH7705
int RTCCLK_f; // SH7305
};
int Bphi_f; // Bus clock frequency
int Iphi_f; // Processor clock frequency
int Pphi_f; // Peripheral clock frequency
} clock_config_t;
/*
clock_setting()
Returns the P_phi / 4 timer setting that will last for the given time.
Several units can be used. Be aware that the result is approximate, and
very high frequencies or very short delays will yield important errors.
*/
uint32_t clock_setting(int duration, clock_unit_t unit);
/*
clock_config()
Returns a copy of what the library knows about the clocks.
*/
clock_config_t clock_config(void);
#endif // _CLOCK_H

View file

@ -1,35 +0,0 @@
//---
//
// standard library module: ctype
//
// Some character manipulation.
//
//---
#ifndef _CTYPE_H
#define _CTYPE_H
#include <stdint.h>
extern uint8_t ctype_classes[0x80];
// Character classes.
#define isalnum(c) (ctype_classes[(int)(c)] & 0xf0)
#define isalpha(c) (ctype_classes[(int)(c)] & 0x30)
#define iscntrl(c) (ctype_classes[(int)(c)] & 0x01)
#define isdigit(c) (ctype_classes[(int)(c)] & 0x40)
#define isgraph(c) (ctype_classes[(int)(c)] & 0xf4)
#define islower(c) (ctype_classes[(int)(c)] & 0x10)
#define isprint(c) (ctype_classes[(int)(c)] & 0x08)
#define ispunct(c) (ctype_classes[(int)(c)] & 0x04)
#define isspace(c) (ctype_classes[(int)(c)] & 0x02)
#define isupper(c) (ctype_classes[(int)(c)] & 0x20)
#define isxdigit(c) (ctype_classes[(int)(c)] & 0x80)
#define isascii(c) ((unsigned)c <= 0x7f)
#define isblank(c) (c == '\t' || c == ' ')
// Character manipulation.
#define tolower(c) ((c) | isupper(c))
#define toupper(c) ((c) & ~(islower(c) << 1))
#endif // _CTYPE_H

View file

@ -1,156 +0,0 @@
//---
//
// gint drawing module: display
//
// This module does most of the monochrome drawing. It manages the video
// memory although image rendering and text rendering, as complex tasks,
// are left to other modules (bopti and tales, respectively).
//
//---
#ifndef _DISPLAY_H
#define _DISPLAY_H
#include <stdint.h>
#include <stddef.h>
//---
// Drawing-related types and constants.
//---
#define DWIDTH 128 /* Width of the screen */
#define DHEIGHT 64 /* Height of the screen */
/*
color_t
Defines all colors that the library knows about:
- white is exactly what you think it is;
- light is a light gray used by the gray module;
- dark is a dark gray, also used by the gray engine;
- black is nothing more than black; (sorry)
- none means transparent, but is shorter to write.
There are also some transformation-associated colors:
- invert reverses the intensity of the color (white -> black, dark ->
light, etc);
- lighten is some kind of partially-transparent white. It lightens the
color which it is drawn onto (black -> dark, light -> light);
- lighten2 is the same as lighten, except it lightens more (black ->
light, light -> white);
- darken is the exact opposite of lighten (light -> dark, black ->
black).
- darken2 is the same to darken as lighten2 to lighten (white -> dark,
dark -> black);
All transformations except invert only operate when the gray engine is
running.
*/
typedef enum
{
color_white = 0,
color_light = 1,
color_dark = 2,
color_black = 3,
color_none = 4,
color_invert = 5,
color_lighten = 6,
color_lighten2 = 7,
color_darken = 8,
color_darken2 = 9,
} color_t;
// The bopti module provides bitmap rendering functions.
#include <bopti.h>
// The tales module provides text rendering functions but requires the color_t
// type definition.
#include <tales.h>
//---
// Video RAM management.
//---
/*
display_getLocalVRAM()
Returns gint's local video RAM address. Gint does not use the system's
buffer because it is misaligned. This function always returns the same
address. Both the display and the gray module heavily use this buffer;
make sure you don't interfere with them if you access it.
This function does not necessarily returns the video ram that is
currently in use; call display_getCurrentVRAM() for this.
*/
uint32_t *display_getLocalVRAM(void);
/*
display_getCurrentVRAM()
Returns the current monochrome video ram buffer. This function usually
returns the parameter of the last call to display_useVRAM(), or the
local vram address (which is default when the library starts).
The return value of this function is undefined if the gray engine is
running.
*/
uint32_t *display_getCurrentVRAM(void);
/*
display_useVRAM()
Changes the current monochrome video ram address. The argument must be
a 4-aligned 1024-byte buffer because the library's design requires it.
This function refuses misaligned buffers but trusts that enough space
is available; failing to provide enough memory may crash the program.
This function will most likely have no effect when running the gray
engine.
*/
void display_useVRAM(uint32_t *vram);
//---
// Global drawing functions.
//---
/*
dupdate()
Pushes the video RAM to the physical screen. This function also works
when the gray engine is running, but that's probably not what you want.
*/
void dupdate(void);
/*
dclear()
Clears the whole video ram, making all pixels white.
*/
void dclear(void);
/*
drect()
Draws a rectangle on the screen. This function can use any color which
is not associated with the gray engine, including the reverse operator.
Both end points (x1, y1) and (x2, y2) are affected as well.
*/
void drect(int x1, int y1, int x2, int y2, color_t operator);
//---
// Local drawing functions.
//---
/*
dpixel()
Changes a pixel's color in the video ram. The result may depend on the
current color of the pixel.
*/
void dpixel(size_t x, size_t y, color_t operator);
/*
dline()
Draws a line in the vram. Automatically optimizes horizontal and
vertical lines.
Uses an algorithm written by PierrotLL for MonochromeLib.
*/
void dline(int x1, int y1, int x2, int y2, color_t operator);
#endif // _DISPLAY_H

View file

@ -1,113 +0,0 @@
//---
//
// gint core module: events
//
// Finally some user-friendly API. This module is in charge of managing
// the event queue. The waitevent() function should be particularly useful
// in program main loops to record key presses and releases in real-time
// games.
//
// Other functions such as the getkey() of the keyboard module provide
// more advanced features such as SHIFT and ALPHA modifiers, backlight
// control for instance; these functions rely on this module and they
// ignore all events that they do not handle. If you want to catch several
// types of events (eg. keyboard and serial communication), then you need
// to use directly this module.
//
//---
#ifndef _EVENTS_H
#define _EVENTS_H
#include <timer.h>
/*
event_type_t
Something user programs will surely use most often.
*/
typedef enum
{
// Specific events.
event_none = 0,
event_user = 1,
// Keyboard events.
event_key_press = 2,
event_key_repeat = 3,
event_key_release = 4,
// Other events.
event_timer_underflow = 5,
} event_type_t;
/*
key_event_t
Keyboard events. "I think the user wants something."
*/
typedef struct
{
// This is the key code as defined in <keyboard.h> (a matrix code), and
// probably what you need.
uint16_t code;
// This is a "compact id" which can be used for array subscript. There
// are only a few holes in the "compact id" numbering.
uint16_t id;
// Character associated with the event key.
int character;
} __attribute__((packed, aligned(4))) key_event_t;
/*
event_t
Wake up, something's going on. The union member that holds information
about the event is specified by the type attribute.
*/
typedef struct
{
event_type_t type;
union
{
// For event_user.
void *data;
// For event_key_press, event_key_repeat and event_key_release.
key_event_t key;
// For event_timer_underflow.
timer_t *timer;
};
} __attribute__((packed, aligned(4))) event_t;
//---
// Event management.
//---
/*
event_push()
Queues a user-defined event, allowing it to be retrieved by getevent()
or pollevent() later. Most often you will not need to use this, as
system events are automatically queued. Pushing ET_None events is not
allowed.
Returns non-zero on error.
*/
int event_push(event_t event);
/*
waitevent()
Returns the next event. If no one is available, waits for something to
happen. This function uses low-level sleep and should be preferred to
active waiting using loops.
*/
event_t waitevent(void);
/*
pollevent()
Returns the next event. If no one is available, returns an event whose
type is ET_None. This function always returns immediately.
*/
event_t pollevent(void);
#endif // _EVENTS_H

View file

@ -1,47 +0,0 @@
#ifndef _ENDIAN_H
#define _ENDIAN_H
#include <stdint.h>
//---
// Assembler-optimized byte-ordering functions.
//---
__attribute__((always_inline)) static inline uint16_t swap16(uint16_t word)
{
uint16_t result;
__asm__("swap.b %1, %0": "=r"(result): "r"(word));
return result;
}
__attribute__((always_inline)) static inline uint32_t swap32(uint32_t longw)
{
uint32_t result;
__asm__(
"swap.b %1, r0 \n\t"
"swap.w r0, r0 \n\t"
"swap.b r0, %0 \n\t"
: "=r"(result)
: "r"(longw)
: "r0"
);
return result;
}
//---
// Conversion of values of different endianness.
//---
#define htobe16(host16) (host16)
#define htole16(host16) (swap16(host16))
#define be16toh(be16) (be16)
#define le16toh(le16) (swap16(le16))
#define htobe32(host32) (host32)
#define htole32(host32) (swap32(host32))
#define be32toh(be32) (be32)
#define le32toh(le32) (swap32(le32))
#endif // _ENDIAN_H

View file

@ -1,116 +0,0 @@
#ifndef _INTTYPES_H
#define _INTTYPES_H
// Decimal notation.
#define PRId8 "d"
#define PRId16 "d"
#define PRId32 "d"
#define PRId64 "lld"
#define PRIdLEAST8 "d"
#define PRIdLEAST16 "d"
#define PRIdLEAST32 "d"
#define PRIdLEAST64 "lld"
#define PRIdFAST8 "d"
#define PRIdFAST16 "d"
#define PRIdFAST32 "d"
#define PRIdFAST64 "lld"
// Decimal notation, again.
#define PRIi8 "i"
#define PRIi16 "i"
#define PRIi32 "i"
#define PRIi64 "lli"
#define PRIiLEAST8 "i"
#define PRIiLEAST16 "i"
#define PRIiLEAST32 "i"
#define PRIiLEAST64 "lli"
#define PRIiFAST8 "i"
#define PRIiFAST16 "i"
#define PRIiFAST32 "i"
#define PRIiFAST64 "lli"
// Octal notation.
#define PRIo8 "o"
#define PRIo16 "o"
#define PRIo32 "o"
#define PRIo64 "llo"
#define PRIoLEAST8 "o"
#define PRIoLEAST16 "o"
#define PRIoLEAST32 "o"
#define PRIoLEAST64 "llo"
#define PRIoFAST8 "o"
#define PRIoFAST16 "o"
#define PRIoFAST32 "o"
#define PRIoFAST64 "llo"
// Unsigned integers.
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIu32 "u"
#define PRIu64 "llu"
#define PRIuLEAST8 "u"
#define PRIuLEAST16 "u"
#define PRIuLEAST32 "u"
#define PRIuLEAST64 "llu"
#define PRIuFAST8 "u"
#define PRIuFAST16 "u"
#define PRIuFAST32 "u"
#define PRIuFAST64 "llu"
// Lowercase hexadecimal notation.
#define PRIx8 "x"
#define PRIx16 "x"
#define PRIx32 "x"
#define PRIx64 "llx"
#define PRIxLEAST8 "x"
#define PRIxLEAST16 "x"
#define PRIxLEAST32 "x"
#define PRIxLEAST64 "llx"
#define PRIxFAST8 "x"
#define PRIxFAST16 "x"
#define PRIxFAST32 "x"
#define PRIxFAST64 "llx"
// Uppercase hexadecimal notation.
#define PRIX8 "X"
#define PRIX16 "X"
#define PRIX32 "X"
#define PRIX64 "llX"
#define PRIXLEAST8 "X"
#define PRIXLEAST16 "X"
#define PRIXLEAST32 "X"
#define PRIXLEAST64 "llX"
#define PRIXFAST8 "X"
#define PRIXFAST16 "X"
#define PRIXFAST32 "X"
#define PRIXFAST64 "llX"
// Format specifiers of intmax_t and uintmax_t.
#define PRIdMAX "lld"
#define PRIiMAX "lli"
#define PRIoMAX "llo"
#define PRIuMAX "llu"
#define PRIxMAX "llx"
#define PRIXMAX "llX"
// Format specifiers of intptr_t and uintptr_t.
#define PRIdPTR "d"
#define PRIiPTR "i"
#define PRIoPTR "o"
#define PRIuPTR "u"
#define PRIxPTR "x"
#define PRIXPTR "X"
#endif // _INTTYPES_H

View file

@ -1,251 +0,0 @@
//---
//
// gint core module: interrupt handler
//
// This module is the core of the gint library. It controls the interrupt
// handler, allows the user to customize interrupt management, provides
// peripheral register access and some information about the runtime
// environment.
//
//---
#ifndef _GINT_H
#define _GINT_H
#include <stdint.h>
#include <stddef.h>
// The version symbol is defined through the linker and consists of four
// fields:
// - Version type, an ascii char ('a'lpha, 'b'eta, 'd'ev, 'r'elease), 8 bits
// - Major version number, 4 bits
// - Minor version number, 4 bits
// - Build number, 16 bits
// Please note that the version number is the *ADDRESS* of GINT_VERSION, which
// you definitely want to cast to uint32_t. Evaluating GINT_VERSION is illegal
// (dereferencing a pointer which is actually a four-field version number just
// cannot work) and will certainly crash your program.
extern uint32_t GINT_VERSION;
//---
// System info provided by the library
//---
typedef struct
{
/* Returns the current VBR address. */
uint32_t (*vbr)(void);
/* Gint's VBR address. */
uint32_t gint_vbr;
/* The system's VBR address, saved when gint was initialized. */
uint32_t system_vbr;
} gint_info_t;
extern gint_info_t gint;
//---
// Exception and interrupt handlers
//---
typedef enum
{
//---
// Resets
// Obviously there will be no handler for these ones.
//---
/* Power-on reset: raised when power is supplied */
exc_poweron_reset = 0,
/* Manual reset: probably when RESET button is pressed */
exc_manual_reset = 0,
/* TLB multihit: more than one entry matches the requested address
(SH7305 only) */
exc_tlb_multihit = 0,
//---
// General exceptions
//---
/*
Address error: an invalid address was accessed
- Location of instruction
- Address at fault
- Access type
1: Instruction or data read access
2: Data write access
*/
exc_address_error = 1,
/*
TLB protection violation: address access is prevented by TLB
- Location of instruction
- Address at fault
- Access type
1: Instruction or data read access
2: Data write access
*/
exc_tlb_protection_violation = 2,
/*
TLB invalid: entry was found but valid bit is cleared (SH7705 only)
- Location of instruction
- Address at fault
- Access type
1: Instruction or data read access
2: Data write access
*/
exc_tlb_invalid = 3,
/*
Illegal instruction: current instruction is not a valid opcode
- Location of instruction
- Opcode at fault
*/
exc_illegal_instruction = 4,
/*
Illegal slot: doing something illegal within a delayed slot
- Location of instruction
- Opcode at fault
*/
exc_illegal_slot = 5,
/* User break: a user break request was fulfilled */
exc_user_break = 6,
/* Initial page write: trying to write while dirty bit is reset */
exc_initial_page_write = 7,
/*
Unconditional trap: a 'trapa' instruction was executed
- Location of instruction
- Trap number
*/
exc_trap = 8,
/* DMA address error: the DMAC violated word or long memory access
alignments (SH7705 only) */
exc_dma_address = 9,
//---
// TLB misses
//---
/*
TLB miss: no match found in TLB for requested address
- Location of instruction
- Address at fault
- Access type
1: Instruction or data read access
2: Data write access
*/
exc_tlb_miss = 10,
//---
// Interrupt requests
//---
/*
Non-Maskable Interrupt: triggered by an external pin
*/
int_nmi = 11,
/*
Timer underflow: a timer's counter reached zero
- Timer channel
0: Channel 0
1: Channel 1
2: Channel 2
*/
int_timer_underflow = 12,
/*
Timer input capture: a capture of timer channel 2 has been requested
by the external clock (SH7705 only)
- Captured value
*/
int_timer_input_capture = 13,
/*
Real-time clock alarm interrupt: configured alarm registers and
current time match
*/
int_rtc_alarm = 14,
/*
Real-time clock periodic interrupt: various possible frequencies
- Current interrupt frequency
*/
int_rtc_periodic = 15,
/*
Real-time clock carry interrupt: when a carry occurs while you're
reading time
*/
int_rtc_carry = 16,
//---
// Other flags
//---
// Maximum valid value for this type.
exc_type_max,
} gint_interrupt_type_t;
/*
gint_install()
Installs an exception or interrupt handler for one of gint's recognized
interrupts. The type signature of the handler function depends on the
particular signal it's answering. Please refer to the documentation to
know what parameters each handler function is provided with.
*/
void gint_install(gint_interrupt_type_t signal, void *function);
/*
gint_uninstall()
Uninstalls the exception or interrupt handler that was used for the
given interrupt, falling back to gint's default handler.
*/
void gint_uninstall(gint_interrupt_type_t signal);
//---
// Register access
//---
typedef enum
{
register_expevt = 0,
register_intevt = 1,
register_mmucr = 2,
register_tea = 3,
register_tra = 4,
} gint_register_t;
/*
gint_register()
Returns the address of a platform-shared register. All these registers
exist on both platforms but they may hold different values for the same
kind of information (f.i the periodic RTC interrupt will change the
value of INTEVT to 0x4a0 on SH7705, and 0xaa0 on SH7305). Higher-level
interfaces may provide platform-independent information in such cases.
*/
volatile void *gint_reg(gint_register_t reg);
//---
// Other functions
//---
/*
gint_switch()
Temporarily returns to the system's main menu.
*/
void gint_switch(void);
#endif // _GINT_H

View file

@ -1,139 +0,0 @@
//---
//
// gint core/drawing module: gray
//
// Runs the gray engine and handles drawing for the dual-buffer system.
//
//---
#ifndef _GRAY_H
#define _GRAY_H
#include <stdint.h>
#include <display.h>
// This module provides bitmap rendering.
#include <bopti.h>
//---
// Engine control.
//---
/*
gray_runs()
Returns 1 if the gray engine is running, 0 otherwise.
*/
int gray_runs(void);
/*
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 light gray vram address.
*/
uint32_t *gray_lightVRAM(void);
/*
gray_darkVRAM()
Returns the module's dark gray vram address.
*/
uint32_t *gray_darkVRAM(void);
/*
gray_currentVRAM()
Returns the currently displayed video ram (if the engine runs). Used
internally, but has no interest for the user. You don't want to draw to
this vram.
*/
uint32_t *gray_currentVRAM(void);
/*
gray_getDelays()
Returns the gray engine delays. Pointers are not set if NULL.
*/
void gray_getDelays(int *light, int *dark);
/*
gray_setDelays()
Changes the gray engine delays. Usually you don't need to call this,
because the engine has its default values.
Finding values that give proper grays is quite the hard part of the
gray engine. Usual values are about 1000, with light being between 75
and 90% of dark.
Typical values:
values stability stripes colors
---------------------------------------------------------
860, 1298 excellent worst static good
912, 1343 bad none very good (default)
993, 1609 medium light fast good
1325, 1607 bad light fast excellent
---------------------------------------------------------
*/
void gray_setDelays(int light, int dark);
//---
// Global drawing functions.
//---
/*
gupdate()
Swaps the vram buffer sets. You need to call this function each time
you finish drawing something in the video ram. Unlike the monochrome
function dupdate(), gupdate() only does a quick operation indicating
that drawing and exposed buffers have been swapped, but nothing on the
screen will change until the gray timer fires.
*/
void gupdate(void);
/*
gclear()
Clears the gray video ram, making all pixels white.
*/
void gclear(void);
/*
grect()
Draws a rectangle in the gray video ram; this function accepts all
values of the color_t type, including gray operators.
*/
void grect(int x1, int y1, int x2, int y2, color_t operator);
//---
// Local drawing functions.
//---
/*
gpixel()
Puts a pixel in the vram. This function accepts all values of the
color_t type, including gray operators.
*/
void gpixel(size_t x, size_t y, color_t operator);
/*
gline()
Draws a line in the vram while automatically optimizing special cases.
This function supports all plain colors from the color_t type, but not
the gray operators. If you need them for horizontal or vertical lines,
you may want to use grect() as a replacement.
*/
void gline(int x1, int y1, int x2, int y2, color_t operator);
#endif // _GRAY_H

View file

@ -1,162 +0,0 @@
#ifndef _INTERNALS_BOPTI_H
#define _INTERNALS_BOPTI_H
#include <stdint.h>
#include <display.h>
/*
channel_t
Indicates what operation a layer is made for. Each operation affects
the video ram differently (setting or clearing pixels, transparency,
etc). An image is made of several layers.
*/
typedef enum
{
channel_full_alpha = 0x01,
channel_light_alpha = 0x02,
channel_dark_alpha = 0x04,
channel_mono = 0x08,
channel_light = 0x10,
channel_dark = 0x20,
} channel_t;
/*
format_t
Describes the various combination of layer channels that are allowed by
bopti. Technically one could try other formats but they're not of much
use (transparent gray is even totally useless).
*/
typedef enum
{
format_mono = channel_mono,
format_mono_alpha = format_mono | channel_full_alpha,
format_gray = channel_light | channel_dark,
format_gray_alpha = format_gray | channel_full_alpha,
format_greater_alpha = format_mono | channel_light_alpha |
channel_dark_alpha
} format_t;
/*
structure_t
Basically an image's dimensions, data pointer, and a few other useful
information such as the pitch in bytes.
*/
typedef struct
{
int width, height;
int layer_size;
const uint8_t *data;
int columns;
int end_size, end_bytes;
} structure_t;
/*
command_t
The parameters of a drawing operation. A pointer to such a structure is
created by the public functions and passed down to the module's
sub-functions during rendering.
*/
typedef struct command_t
{
// Channel being drawn.
channel_t channel;
// Operation used (whether bopti_op_mono() or bopti_op_gray()).
void (*op)(int offset, uint32_t operator, struct command_t *command);
// Portion of the bitmap which is drawn. 'top' and 'bottom' refer to
// lines where 'left' and 'right' refer to column ids.
int left, right, top, bottom;
// Position of the bitmap on the screen.
int x, y;
// Rectangle masks that define the drawing area.
uint32_t masks[4];
// Video rams being used.
union {
// "Different names, same fate." (Kingdom Hearts II)
uint32_t *vram;
uint32_t *v1;
};
uint32_t *v2;
} command_t;
// The video ram addresses are set by the public functions and used internally
// by the module.
// Monochrome video ram, light and dark buffers (in this order).
extern uint32_t *bopti_vram, *bopti_v1, *bopti_v2;
//---
// Internal bopti routines.
//---
/*
bopti_op()
Operates on a vram long. The operator will often not contain 32 bits of
image information. Since neutral bits are not the same for all
operations, a mask is used to indicate which bits should be used for
the operation. This mask is taken for the image's rectangle masks (see
the 'display' module internal header for more information on rectangle
masks). Which operation is performed is determined by the channel
setting of the command argument.
*/
void bopti_op_mono(int offset, uint32_t operator, command_t *c);
void bopti_op_gray(int offset, uint32_t operator, command_t *c);
/*
bopti_grid() -- general form
bopti_grid_a32() -- when x is a multiple of 32
Draws the grid at the beginning of a layer's data. The length of this
grid is always a multiple of 32.
The need for bopti_grid_a32() is not only linked to optimization,
because bopti_grid() will perform a 32-bit shift when x is a multiple
of 32, which is undefined behavior.
bopti_grid() automatically calls bopti_grid_a32() when required.
*/
void bopti_grid_a32(const uint32_t *layer, int columns, int height,
command_t *c);
void bopti_grid(const uint32_t *layer, int columns, int height, command_t *c);
/*
bopti_end_get()
Returns an operator for the end of a line, whose width is lower than 32
(by design: otherwise, it would have been a column). The given pointer
is read and updated so that it points to the next line at the end of
the operation.
*/
uint32_t bopti_end_get1(const unsigned char **data);
uint32_t bopti_end_get2(const unsigned char **data);
/*
bopti_rest() -- general form
bopti_rest_nover() -- when the end does not overlap two vram longs
Draws the end of a layer, which can be considered as a whole layer
whose with is lower than 32. (Actually is it lower or equal to 16;
otherwise it would have been a column and the end would be empty). The
'size' arguments is in bytes, thus 1 or 2.
Unlike bopti_grid_a32(), bopti_end_nover() is not called automatically
by bopti_end().
*/
void bopti_end_nover(const unsigned char *end, int size, command_t *c);
void bopti_end(const unsigned char *end, int size, command_t *c);
/*
bopti()
Draws a layer's data in the video ram areas specified in the command
argument.
*/
void bopti(const unsigned char *layer, structure_t *s, command_t *c);
/*
getStructure()
Determines the image size (large images have a somehow different
structure), the data pointer and a few dimensions inside the image.
*/
void getStructure(image_t *img, structure_t *structure);
#endif // _INTERNALS_BOPTI_H

View file

@ -1,21 +0,0 @@
#ifndef _INTERNALS_CLOCK_H
#define _INTERNALS_CLOCK_H
/*
clock_measure()
Begins the frequency measurements. The measurements will end
automatically. While doing measurements, do not use the RTC interrupt
or the user timer.
Call clock_measure_end() to wait until the measurements are finished.
It is possible to execute code during the measurements, so that less
time is spent.
*/
void clock_measure(void);
/*
clock_measure_end()
Waits until the measurements are finished. This may be immediate.
*/
void clock_measure_end(void);
#endif // _INTERNALS_CLOCK_H

View file

@ -1,49 +0,0 @@
#ifndef _INTERNALS_DISPLAY_H
#define _INTERNALS_DISPLAY_H
#include <stdint.h>
#include <stddef.h>
extern uint32_t *vram;
//---
// Rectangle masks.
//
// The concept of 'rectangle masks' is used several times in this module.
// It relies on the fact that operations affecting a rectangle act the
// same for all lines, and line operation is very optimized. A rectangle
// mask is a set of integers, where each bit indicate whether a specific
// pixel is affected (1) by the operation, or not (0).
//
// For example to clear a rectangle such as (14, 16, 112, 48), the masks
// will need to hold 0003ffff ffffffff ffffffff ffff0000. Bitwise-
// combining them with video ram long entries yields very good performance
// as compared to operation on single pixels. Each bitwise operation will
// produce different results, which is very flexible.
//
// This technique can also be used in subtle cases with patterns more
// complicated than rectangles, but within this module this is unlikely to
// happen.
//---
/*
adjustRectangle()
Adjusts the given rectangle coordinates to ensure that :
- the rectangle is entirely contained in the screen;
- x1 < x2;
- y1 < y2,
which is needed when working with screen rectangles. Returns non-zero
if the rectangle is outside the screen, which usually means there is
nothing to do.
*/
int adjustRectangle(int *x1, int *y1, int *x2, int *y2);
/*
getMasks()
Computes the rectangle masks needed to affect pixels located between x1
and x2 (both included). The four masks are stored in the third argument
(seen as an array).
*/
void getMasks(size_t x1, size_t x2, uint32_t *masks);
#endif // _INTERNALS_DISPLAY_H

View file

@ -1,19 +0,0 @@
#ifndef _INTERNALS_EVENTS_H
#define _INTERNALS_EVENTS_H
#include <events.h>
#ifndef EVENTS_QUEUE_SIZE
#define EVENTS_QUEUE_SIZE 64
#endif
/*
This module is just a circular-array queue that pushes and pops events
like any other queue. Trying to add an event when the queue is full
fails, and the operation is ignored.
*/
extern volatile event_t event_queue[];
extern volatile int queue_start;
extern volatile int queue_size;
#endif // _INTERNALS_EVENT_H

View file

@ -1,66 +0,0 @@
#ifndef _INTERNALS_EXCEPTIONS_H
#define _INTERNALS_EXCEPTIONS_H
#include <stdint.h>
/*
exch_address_error()
CPU address error, e.g. alignment issues.
*/
void exch_address_error(uint32_t pc, uint32_t tea, uint32_t access);
/*
exch_tlb_protection_violation()
You don't have the right to access this address.
*/
void exch_tlb_protection_violation(uint32_t pc, uint32_t tea, uint32_t access);
/*
exch_tlb_invalid()
The translation info for this address is marked as invalid.
*/
void exch_tlb_invalid(uint32_t pc, uint32_t tea, uint32_t access);
/*
exch_illegal_instruction()
What's this opcode anyway?
*/
void exch_illegal_instruction(uint32_t pc, uint32_t opcode);
/*
exch_illegal_slot()
You can't execute this in a delay slot.
*/
void exch_illegal_slot(uint32_t pc, uint32_t opcode);
/*
exch_user_break()
One of the user break conditions you requested was fulfilled.
*/
void exch_user_break(void);
/*
exch_initial_page_write()
You can't write to this memory page, it's too early.
*/
void exch_initial_page_write(void);
/*
exch_trap()
You asked for it.
*/
void exch_trap(uint32_t pc, uint32_t trap);
/*
exch_dma_address()
The DMAC is accessing badly-aligned addresses.
*/
void exch_dma_address(void);
/*
exch_tlb_miss()
This virtual address points nowhere.
*/
void exch_tlb_miss(uint32_t pc, uint32_t tea, uint32_t access);
#endif // _INTERNALS_EXCEPTIONS_H

View file

@ -1,139 +0,0 @@
#ifndef _INTERNALS_GINT_H
#define _INTERNALS_GINT_H
#include <stdint.h>
#include <mpu.h>
#include <gint.h>
//---
// Interrupt handlers.
//---
// General exception handler.
void gint_exc(void);
// TLB miss handler.
void gint_tlb(void);
// Interrupt handler.
void gint_int(void);
//---
// Assembler-level VBR management.
//---
/*
gint_getvbr()
Retrieves the current VBR address.
*/
uint32_t gint_getvbr(void);
/*
gint_setvbr()
Sets the VBR address and calls the configuration function while
interrupts are disabled.
*/
void gint_setvbr(uint32_t vbr, void (*setup)(void));
//---
// Initialization and termination routines, environment saves.
//---
/*
gint_init()
Initializes gint. Loads the interrupt handler into the memory and sets
the new vbr address.
*/
void gint_init(mpu_t mpu);
/*
gint_quit()
Stops gint. Restores the system's configuration and vbr address.
*/
void gint_quit(void);
#include <modules/rtc.h>
#include <modules/timer.h>
/*
environment_t
Structure where all registers used by gint are saved by default to
ensure that the operating system is not disturbed.
*/
typedef struct
{
// Interrupt controller.
uint16_t IPR[8];
// Real-Time Clock.
uint8_t RCR1, RCR2;
// Timer Unit.
mod_tmu_timer_t TMU0, TMU1, TMU2;
uint8_t TSTR;
// I/O ports for the keyboard driver.
uint16_t PACR, PBCR, PMCR;
uint8_t PADR, PBDR, PMDR;
} environment_7705_t;
typedef struct
{
// Interrupt controller.
uint16_t IPR[12];
// Real-Time Clock.
uint8_t RCR1, RCR2;
// Timer Unit.
mod_tmu_timer_t TMU0, TMU1, TMU2;
uint8_t TSTR;
// I/O ports for the keyboard driver.
uint16_t PMCR, PNCR, PZCR;
uint8_t PMDR, PNDR, PZDR;
uint8_t key;
} environment_7305_t;
typedef union
{
environment_7705_t env_7705;
environment_7305_t env_7305;
} environment_t;
/*
gint_save()
Saves many registers into an internal environment buffer.
*/
void gint_save_7705(environment_7705_t *env);
void gint_save_7305(environment_7305_t *env);
/*
gint_lock_and_setup()
Locks all interrupts (ie. disables them by default) and sets initial
values to all registers, allows specific interrupts, etc.
*/
void gint_lock_and_setup_7705(void);
void gint_lock_and_setup_7305(void);
/*
gint_restore_and_unlock()
Restores the parameters saved in the environment buffer to give back
the interrupt control to the system.
*/
void gint_restore_and_unlock_7705(environment_7705_t *env);
void gint_restore_and_unlock_7305(environment_7305_t *env);
/*
gint_reg()
Returns the address of a platform-shared register.
*/
volatile void *gint_reg_7705(gint_register_t reg);
volatile void *gint_reg_7305(gint_register_t reg);
#endif // _INTERNALS_GINT_H

View file

@ -1,29 +0,0 @@
//---
// gint core module: init
// Program initialization and display manipulation for the startup logs.
//---
#ifndef _INTERNALS_INIT_H
#define _INTERNALS_INIT_H
#include <display.h>
/* init_version() -- get a version string */
const char *init_version(void);
/* init_stage() -- change the current init stage */
void init_stage(const char *name);
/* init_halt() -- halt the program */
void init_halt(void);
/* print() -- print text on a 21*8 grid */
#define print(x, y, str) dtext((x) * 6 - 5, (y) * 8 - 8, (str))
/* print_dec() -- print a number in base 10 */
void print_dec(int x, int y, int n, int digits);
/* print_hex() -- print a number in base 16 */
void print_hex(int x, int y, uint32_t n, int digits);
#endif // _INTERNALS_INIT_H

View file

@ -1,100 +0,0 @@
#ifndef _INTERRUPT_MAPS
#define _INTERRUPT_MAPS
#include <stdint.h>
#include <internals/gint.h>
//---
// Interrupt handlers.
//---
/*
gint_interrupt_arg_t
8-bit integer representing an argument to pass as uint32_t to an
exception or interrupt handler.
*/
typedef enum
{
// Empty argument (always at end of list).
arg_none = 0x00,
// Signal subtype (f.i address error subtypes: code, read, write).
arg_subtype = 0x01,
// Value of register SPC is passed.
arg_pc = 0x02,
// Instruction pointed at by SPC is passed (re-execution types).
arg_opcode = 0x03,
// Address indicated in register TEA is passed.
arg_tea = 0x04,
// Trap number is passed.
arg_trap = 0x05,
// Timer channel 2 captured input (SH7705 only).
arg_timer_capt = 0x06,
} gint_interrupt_arg_t;
/*
gint_interrupt_handler_t
Contains both static and dynamic information of interrupt handlers:
the current handler is stored there, as well as the type signature
information through an array of parameters.
*/
typedef struct
{
// Current handler function. The type signature may vary, hence the
// void * pointer.
void *function;
// Default handler and fallback if the current handler is un-installed.
void *default_function;
// Default interrupt priorities (interrupts only).
uint8_t priority;
// Arguments passed to the handler (these are values of type arg_t).
// This array is the only thing that defines the type signature of the
// two functions above.
uint8_t args[3];
} gint_interrupt_handler_t;
// Handler array.
extern gint_interrupt_handler_t gint_handlers[];
//---
// Interrupt maps.
//---
/*
gint_interrupt_map_t
Maps an event code to an interrupt type and subtype. The subtypes allow
group-handling similar interrupts (for instance TLB misses for code and
data accesses, or timer underflows from various channels).
*/
typedef struct
{
uint8_t type;
uint8_t subtype;
} __attribute__((packed)) gint_interrupt_map_t;
/*
gint_map_7705()
TLB misses and TLB invalid have the same event code though they are
handled by different functions in the VBR space. The offset argument
expects values 0x100, 0x400 or 0x600 to distinguish between them.
*/
gint_interrupt_map_t gint_map_7705(uint32_t event_code, uint32_t offset);
/*
gint_map_7305()
Maps an event code to an interrupt type. The SH7305 does not have TLB
invalid exceptions so no event codes overlap.
*/
gint_interrupt_map_t gint_map_7305(uint32_t event_code);
/*
gint_invoke()
Invokes an interrupt or exception handler, given its type and subtype.
*/
void gint_invoke(uint8_t type, uint8_t subtype);
#endif // _INTERRUPT_MAPS

View file

@ -1,18 +0,0 @@
#ifndef _INTERNALS_INTERRUPTS_H
#define _INTERNALS_INTERRUPTS_H
#include <stdint.h>
/*
inth_timer_underflow()
Wake up, your timer has expired!
*/
void inth_timer_underflow(uint32_t channel);
/*
inth_rtc_periodic()
Don't you forget to execute the periodic tasks.
*/
void inth_rtc_periodic(void);
#endif // _INTERNALS_INTERRUPTS_H

View file

@ -1,49 +0,0 @@
#ifndef _INTERNALS_KEYBOARD_H
#define _INTERNALS_KEYBOARD_H
#include <keyboard.h>
#include <timer.h>
#include <clock.h>
// Current keyboard state and keyboard interrupt flag.
extern volatile uint8_t keyboard_state[10];
extern volatile int interrupt_flag;
// Delays (milliseconds) before repetitions, last key pressed, how many times
// it has been repeated already, time elapsed since last repetition (ms).
extern int repeat_first, repeat_next;
extern int last_key, last_repeats, last_time;
// Virtual timer object.
extern timer_t *vtimer;
/*
getPressedKey()
Finds a pressed key in the keyboard state and returns it.
*/
int getPressedKey(volatile uint8_t *keyboard_state);
/*
getPressedKeys()
Find 'count' pressed keys in the keyboard state and fills the 'keys'
array. Returns the number of keys found.
WARNING: keyboard artifacts make this function read as pressed keys
that aren't (typically, LEFT + DOWN + SHIFT => ALPHA).
*/
int getPressedKeys(volatile uint8_t *keyboard_state, int *keys, int count);
/*
keyboard_updateState()
Updates the keyboard state.
*/
void keyboard_updateState_7705(volatile uint8_t *state);
void keyboard_updateState_7305(volatile uint8_t *state);
/*
keyboard_interrupt()
Answers an interrupt event by updating the keyboard state and
generating the associated keyboard events.
*/
void keyboard_interrupt(void);
#endif // _INTERNALS_KEYBOARD_H

View file

@ -1,21 +0,0 @@
//---
//
// gint core module: mmu
//
// A wise application should avoid tampering with the system's
// configuration of the MMU and the TLB. This module implicitly forces the
// system to load the required pages but does not interact with the TLB.
//
//---
#ifndef _INTERNALS_MMU_H
#define _INTERNALS_MMU_H
/*
mmu_pseudoTLBInit()
Tries to have the system load enough data into TLB to allow add-in to
execute.
*/
void mmu_pseudoTLBInit(void);
#endif // _MMU_H

View file

@ -1,12 +0,0 @@
#ifndef _INTERNALS_MODULES_H
#define _INTERNALS_MODULES_H
/*
mod_init()
Initializes the module data to make register access cross-platform. The
MPU needs to have been detected or this function will yield wrong
results.
*/
void mod_init(void);
#endif // _INTERNALS_MODULES_H

View file

@ -1,41 +0,0 @@
#ifndef _INTERNALS_RTC_H
#define _INTERNALS_RTC_H
#include <rtc.h>
#include <stddef.h>
#ifndef RTC_CB_ARRAY_SIZE
#define RTC_CB_ARRAY_SIZE 5
#endif
/*
rtc_callback_t
An RTC callback with a unique id.
*/
typedef struct
{
rtc_frequency_t freq;
int id;
void (*callback)(void);
int repeats;
} rtc_callback_t;
// The callback array.
rtc_callback_t cb_array[RTC_CB_ARRAY_SIZE];
/*
rtc_perodic_interrupt()
Handles periodic interrupts and calls the callbacks.
*/
void rtc_periodic_interrupt(void);
/*
rtc_cb_interrupt()
Calls the RTC callbacks if necessary, and updates the repeat counts.
Should only be called when RTC periodic interrupts occur.
*/
void rtc_cb_interrupt(void);
#endif // _INTERNALS_RTC_H

View file

@ -1,23 +0,0 @@
#ifndef _INTERNALS_STDIO_H
#define _INTERNALS_STDIO_H
#include <stddef.h>
#include <stdarg.h>
//---
// Formatted printing.
//---
#ifndef __stdio_buffer_size
#define __stdio_buffer_size 256
#endif
extern char __stdio_buffer[];
/*
__printf()
Formatted printing to the stdio buffer.
*/
int __printf(size_t size, const char *format, va_list args);
#endif // _INTERNALS_STDIO_H

View file

@ -1,29 +0,0 @@
//---
//
// gint core module: syscalls
//
// Some of the functionality still requires interacting with the system.
//
//---
#ifndef _INTERNALS_SYSCALLS_H
#define _INTERNALS_SYSCALLS_H
#include <stddef.h>
/* malloc() -- allocate data in heap */
void *__malloc(size_t size);
/* free() -- free data allocated by malloc(), calloc() or realloc() */
void __free(void *ptr);
/* realloc() -- reallocate a chunk of memory */
void *__realloc(void *chunk, size_t new_size);
/* get_os_version() -- write the OS version in format MM.mm.pppp to a string */
void __get_os_version(char *str);
/* system_menu() -- go back to menu, assuming the system has the control */
void __system_menu(const void *vram);
#endif // _INTERNALS_SYSCALLS_H

View file

@ -1,50 +0,0 @@
#ifndef _INTERNALS_TALES_H
#define _INTERNALS_TALES_H
#include <tales.h>
#include <stdint.h>
#include <stddef.h>
#define OPERATE_ARGS uint32_t *operators, int height, int x, int y
extern font_t *font;
extern color_t operator;
/*
getCharacterIndex()
Returns the index of a character in a font data area depending on the
font format and the size of the characters. Returns the index in the
data area, as long array, or -1 when the character does not belong to
the font format set.
*/
int getCharacterIndex(int c);
/*
operate()
Operates on the vram using the given operators. The x-coordinate should
be a multiple of 32. There should be `height` operators.
*/
void operate_mono(OPERATE_ARGS);
void operate_gray(OPERATE_ARGS);
/*
update()
Updates the operators using the given glyph. The operation will not be
complete if there are not enough bits available in the operator data.
In this case the offset will become negative, which means that the
calling procedure has to call operate() and re-call update().
`available` represents the number of free bits in the operators (lower
bits).
Returns the number of bits available after the operation. If it's
negative, call operate() and update() again.
*/
int update(uint32_t *operators, int height, int available, uint32_t *glyph);
/*
render()
Renders text without any formatting analysis, using the given operation
function.
*/
void render(int x, int y, const char *str, void (*op)(OPERATE_ARGS));
#endif // _INTERNALS_TALES_H

View file

@ -1,16 +0,0 @@
#ifndef _INTERNALS_TIME_H
#define _INTERNALS_TIME_H
/*
isLeap()
Determines whether the given year is a leap year.
*/
int isLeap(int year);
/*
daysInMonth()
Returns number of days for the given month (between 0 and 11) and year.
*/
int daysInMonth(int month, int year);
#endif // _INTERNALS_TIME_H

View file

@ -1,76 +0,0 @@
#ifndef _INTERNALS_TIMER_H
#define _INTERNALS_TIMER_H
#include <timer.h>
#include <stdint.h>
/*
timer_t
A virtual or hardware timer. We need to declare the struct timer_t name
so that we can forward-reference it.
*/
typedef struct timer_t
{
// Current delay, how much time elapsed since last interrupt occurred.
uint32_t ms_delay;
uint32_t ms_elapsed;
// Is the virtual slot free? Is the virtual timer active?
uint8_t used :1;
uint8_t active :1;
// Is this a virtual timer? Is this the virtual timer support?
uint8_t virtual :1;
uint8_t vsupport :1;
// How many events do I have received but not executed?
uint8_t events :4;
// How many repeats are left.
uint32_t repeats_left :24;
// Callback function (NULL for event-firing timers) and its argument.
void *callback;
void *argument;
} __attribute__((packed, aligned(4))) timer_t;
// Hardware timers.
extern timer_t htimers[3];
// Virtual timers.
extern timer_t vtimers[TIMER_SLOTS];
/*
timer_interrupt()
Handles the interrupt for the given timer channel.
*/
void timer_interrupt(int channel);
/*
timer_callback_event()
Executes the callback of a timer, or pushes a new timer event depending
on the timer configuration. Also reduces the amount of repeats left and
clears the active flag (or stops the hardware timer) if this number
falls from one to zero.
*/
void timer_callback_event(timer_t *timer);
/*
vtimer_interrupt()
Interrupt handling subsystem for the virtual timers.
*/
void vtimer_interrupt(void);
/*
vtimer_updateOne()
Update the virtual timer hardware support timer, knowing that a virtual
timer with the given delay has been started.
*/
void vtimer_updateOne(int additional_delay_ms);
/*
vtimer_updateAll()
Updates the virtual timer hardware support after computing the GCD of
all virtual timers delays. This is rather long so avoid calling this
when possible.
*/
void vtimer_updateAll(void);
#endif // _INTERNALS_TIMER_H

View file

@ -1,329 +0,0 @@
//---
//
// gint core module: keyboard analyzer
//
// Probably the most difficult hardware interaction. There is very few
// documentation on how the system actually analyzes the keyboard. While
// disassembling syscalls reveals the following procedure (which was
// already documented by SimonLothar), there is nothing about the
// detection problems of the multi-getkey system.
//
//---
#ifndef _KEYBOARD_H
#define _KEYBOARD_H
#include <stdint.h>
#include <rtc.h>
//---
// Keycodes and related.
//---
/*
key_t
The following codes are gint matrix codes. They are not compatible with
the system's. Some keycodes are special event codes; all others are
made of a key identifier and possibly one or more modifiers.
Binary-and a keycode with MOD_CLEAR to remove the modifiers; this will
not work with special event codes.
*/
typedef enum
{
// Special events codes.
KEY_NONE = 0x00,
KEY_NOEVENT = 0xff,
// Key modifiers.
MOD_SHIFT = 0x80,
MOD_ALPHA = 0x100,
MOD_CLEAR = ~(MOD_SHIFT | MOD_ALPHA),
// Key identifiers.
KEY_F1 = 0x69,
KEY_F2 = 0x59,
KEY_F3 = 0x49,
KEY_F4 = 0x39,
KEY_F5 = 0x29,
KEY_F6 = 0x19,
KEY_SHIFT = 0x68,
KEY_OPTN = 0x58,
KEY_VARS = 0x48,
KEY_MENU = 0x38,
KEY_LEFT = 0x28,
KEY_UP = 0x18,
KEY_ALPHA = 0x67,
KEY_SQUARE = 0x57,
KEY_POWER = 0x47,
KEY_EXIT = 0x37,
KEY_DOWN = 0x27,
KEY_RIGHT = 0x17,
KEY_XOT = 0x66,
KEY_LOG = 0x56,
KEY_LN = 0x46,
KEY_SIN = 0x36,
KEY_COS = 0x26,
KEY_TAN = 0x16,
KEY_FRAC = 0x65,
KEY_FD = 0x55,
KEY_LEFTP = 0x45,
KEY_RIGHTP = 0x35,
KEY_COMMA = 0x25,
KEY_ARROW = 0x15,
KEY_7 = 0x64,
KEY_8 = 0x54,
KEY_9 = 0x44,
KEY_DEL = 0x34,
KEY_AC_ON = 0x24,
KEY_4 = 0x63,
KEY_5 = 0x53,
KEY_6 = 0x43,
KEY_MUL = 0x33,
KEY_DIV = 0x23,
KEY_1 = 0x62,
KEY_2 = 0x52,
KEY_3 = 0x42,
KEY_PLUS = 0x32,
KEY_MINUS = 0x22,
KEY_0 = 0x61,
KEY_DOT = 0x51,
KEY_EXP = 0x41,
KEY_NEG = 0x31,
KEY_EXE = 0x21,
} key_t;
//---
// Keyboard configuration.
//---
/*
keyboard_setAnalysisDelay()
Sets the keyboard analysis delay, that is, the delay (in ms) between
two keyboard analyzes. If a key is pressed then released in the lapse
between two analyzes, the program won't notice anything. On the other
hand, if the program spends too much time reading the keyboard, it will
lose a bit of execution power.
The default frequency is about 40 Hz; very few programs will need to
change this setting. Please note that the repeat delays should be
multiples of the analysis delay for better accuracy.
*/
void keyboard_setAnalysisDelay(int analysis_delay_ms);
/*
keyboard_setRepeatRate()
Sets the default repeat rate for key events. The delay before the first
repeat may have a different value (usually longer). The unit for the
argument is ms, but the repeat events themselves may only be fired when
a keyboard analysis is performed; which means that for better accuracy,
these delays should be a multiple of the keyboard period. The keyboard
period may be changed by calling keyboard_setAnalysisDelay().
For instance, delays of (625 ms, 125 ms) will imitate the system's
default setting.
You can disable repetitions by passing 0 as arguments:
- if first = 0, no repetition will ever occur;
- if first != 0 and next = 0, only one repetition will occur.
*/
void keyboard_setRepeatRate(int first, int next);
//---
// Keyboard access.
//---
/*
getkey_opt_t
Options available to customize the behavior of the getkey_opt()
function.
*/
typedef enum
{
getkey_none = 0x00,
// Consider [SHIFT] and [ALPHA] as modifiers. Returns key identifiers
// with MOD_SHIFT and MOD_ALPHA flags instead of returning KEY_SHIFT
// and KEY_ALPHA.
getkey_shift_modifier = 0x01,
getkey_alpha_modifier = 0x02,
// Allow changing the backlight status on [SHIFT] + [OPTN] on
// compatible models.
getkey_manage_backlight = 0x04,
// Allow returning to menu using the [MENU] key. (This operation is not
// absolutely safe.)
getkey_task_switch = 0x08,
// Allow key repetition. This option does not control the generation of
// repeat events (use keyboard_setRepeatRate() for this) but filters
// them. Please note that modifiers will never be repeated, even when
// pressed continuously.
getkey_repeat_arrow_keys = 0x10,
getkey_repeat_char_keys = 0x20,
getkey_repeat_ctrl_keys = 0x40,
getkey_repeat_func_keys = 0x80,
// Shorthand for the four previous properties.
getkey_repeat_all_keys = 0xf0,
// Default combination of getkey().
getkey_default = 0x1f,
} getkey_option_t;
/*
getkey()
Blocking function with auto-repeat that heeds for the SHIFT and ALPHA
modifiers. In short, this function reproduces the behavior of the
system's GetKey() function. It returns a matrix code, possibly with
modifier bits.
This function does not return until a key is pressed.
*/
int getkey(void);
/*
getkey_opt()
Enhances getkey() with more general functionalities. An OR-combination
of options of type getkey_option_t may be given as first argument.
If delay is non-zero and positive, getkey_opt() will return KEY_NOEVENT
if no event occurs during the given delay. Please note that this
function can only ever return after a keyboard analysis is performed;
the actual delay may exceed the requested time if it's not a multiple
of the keyboard period (which can be changed by calling
keyboard_setAnalysisDelay()).
Like getkey(), returns the pressed key matrix code, possibly with
modifiers depending on the options.
*/
int getkey_opt(getkey_option_t options, int delay_ms);
/*
multigetkey()
Listens the keyboard for simultaneous key hits. This functions fills
the 'keys' array with 'count' keycodes, padding with KEY_NONE values at
the end if less that 'count' keys are detected.
If 'delay_ms' is positive and nothing happens during this delay, this
function returns an array of KEY_NONE. Please note that the delay
detection suffers the same limitation as getkey_opt().
This function suffers from severe limitations and may not be very
convenient to use. For more accuracy, consider using the event system.
WARNING:
Because of hardware limitations, this function generally yields poor
results. Rectangle and column effects make it read unpressed keys as
pressed (see documentation for more information). The more pressed
keys, the more errors.
The results are guaranteed to be exact if two keys or less are pressed.
With three keys or more, column effects (on SH4) and rectangle effects
(on both platforms) mess up the results by making this function think
that some keys, which are actually released, are pressed.
This function is designed to make combinations of one or two arrow keys
with another key as viable as possible. On SH4, this works pretty well
even if combinations like Left + Down + SHIFT trigger ALPHA sometimes.
On SH3, rectangle effects are *always* present, making it impossible to
use Left + Down or Up + Right with any other key in their rows without
having this function return junk.
Any other combination of keys may quite randomly result in variably
incorrect results. Please do not expect multigetkey() to work as an
ideal multi-key analyzer.
*/
void multigetkey(int *keys, int count, int delay_ms);
/*
keyboard_stateBuffer()
Returns the address of the keyboard state array. The keyboard state
consists in 10 bytes, in which every key is represented as a bit.
The returned address is the original buffer address. You should avoid
editing the array. It wouldn't influence the behavior of the keyboard
functions, but the buffer data is very volatile and any data written to
it could be replaced anytime without prior notice.
If the user wishes to do really advanced keyboard management that they
can't achieve it using the library, they can access this buffer.
Updates of this buffer's contents can be detected by watching the
'interrupt_flag' variable defined in internals/keyboard.h. However, the
library will continue firing events so the user needs to catch them and
ignore them.
*/
volatile uint8_t *keyboard_stateBuffer(void);
//---
// Key analysis.
//---
/*
keyid()
Transforms a key identifier and returns a key code that is more
convenient for array subscript that the original matrix codes. The new
codes are laid out the following way:
+0 +1 +2 +3 +4 +5
------------------------------------
+0 | F1 F2 F3 F4 F5 F6
+6 | SHIFT OPTN VARS MENU Left Top
+12 | ALPHA x^2 ^ EXIT Down Right
+18 | X,O,T log ln sin cos tan
+24 | Frac F<>D ( ) , ->
+30 | 7 8 9 DEL AC/ON
+36 | 4 5 6 * /
+42 | 1 2 3 + -
+48 | 0 . x10^ (-) EXE
The returned key code is the sum of the line and column headings. For
instance key_id(KEY_SIN) would be 18 + 3 = 21. Please note that there
are a few holes in the numbering.
This function ignores modifiers and returns -1 on error.
*/
int key_id(int matrix_key);
/*
key_char()
Returns the ASCII character associated with a character key, and 0 for
other keys. This function expects a matrix code and not a key_id()
code, and heeds for the ALPHA modifier.
*/
int key_char(int matrix_key);
/*
key_type_t
Categorizes the keyboard's keys into several types:
- Arrow keys only include the REPLAY pad;
- Function keys only include the F1 .. F6 keys;
- Character keys are those which input characters;
- Control characters are all others.
*/
typedef enum
{
key_type_arrow = 1,
key_type_character = 2,
key_type_control = 4,
key_type_function = 8,
} key_type_t;
/*
key_type()
Returns a key's type. This functions ignores modifiers and expects
matrix codes as argument, not key_id() codes.
*/
key_type_t key_type(int matrix_key);
#endif // _KEYBOARD_H

View file

@ -1,41 +0,0 @@
//---
//
// gint libc module: math
//
// Provides mathematical functions as well as a few useful extensions.
//
//---
#ifndef _MATH_H
#define _MATH_H
#include <stdint.h>
//---
// Function extensions
//---
/*
qdiv()
Quickly divides by predefined integers using a 64-bit multiplication
technique. These functions should be ~10 times faster than dividing
using opeator "/".
*/
typedef struct qdiv_t
{
uint32_t q; /* Quotient */
uint32_t r; /* Remainer */
} __attribute__((packed, aligned(4))) qdiv_t;
qdiv_t qdiv(uint32_t n, uint32_t divider, uint32_t reciprocal);
/* Predefined magic numbers */
#define qdiv_3(n) qdiv(n, 3, 0x55555556)
#define qdiv_5(n) qdiv(n, 5, 0x33333334)
#define qdiv_10(n) qdiv(n, 10, 0x1999999a)
#define qdiv_100(n) qdiv(n, 100, 0x028f5c29)
#define qdiv_1000(n) qdiv(n, 1000, 0x00418938)
#endif // _MATH_H

View file

@ -1,688 +0,0 @@
#ifndef _MODULES_INTERRUPTS_H
#define _MODULES_INTERRUPTS_H
#include <modules/macros.h>
#include <stdint.h>
//---
// Interrupt controller.
// This part is difficult to handle, because the interrupt controllers of
// SH7705 and SH7305 MPUs have virtually nothing in common. I eventually
// decided to completely split it up into two kinds of structures and
// types.
// Use the gint API, not this module, for platform-independent interrupt
// management.
//---
//---
// SH7705-related definitions.
//---
/*
mod_intc_ipc_7705_t
Interrupt priority controller. Just a bunch of 16-bit-registers that
handle the interrupt priority of all interrupt sources.
Please note that because the interrupt priority controller of the
SH7705 MPU has registers scattered everywhere in the memory, its
structure below has a different pointer for each register. On the
opposite, the SH7305 registers are all in a contiguous area thus there
is only one pointer for the whole group.
*/
typedef struct
{
volatile word_union(*IPRA,
uint TMU0 :4; /* Timer 0 */
uint TMU1 :4; /* Timer 1 */
uint TMU2 :4; /* Timer 2 */
uint RTC :4; /* Real-Time Clock */
);
volatile word_union(*IPRB,
uint WDT :4; /* Watchdog Timer */
uint REF :4; /* BSC Refresh Request, SDRAM (?) */
uint :4;
uint :4;
);
volatile word_union(*IPRC,
uint IRQ3 :4; /* Interrupt request 3 */
uint IRQ2 :4; /* Interrupt request 2 */
uint IRQ1 :4; /* Interrupt request 1 */
uint IRQ0 :4; /* Interrupt request 0 */
);
volatile word_union(*IPRD,
uint PINT0_7 :4; /* External interrupt pins 0 to 7 */
uint PINT8_15 :4; /* External interrupt pins 8 to 15 */
uint IRQ5 :4; /* Interrupt request 5 */
uint IRQ4 :4; /* Interrupt request 4 */
);
volatile word_union(*IPRE,
uint DMAC :4; /* Direct Memory Access Controller */
uint SCIF0 :4; /* Serial Communication Interface 0 */
uint SCIF2 :4; /* Serial Communication Interface 2 */
uint ADC :4; /* Analog/Decimal Converter */
);
volatile word_union(*IPRF,
uint :4;
uint :4;
uint USB :4; /* USB Controller */
uint :4;
);
volatile word_union(*IPRG,
uint TPU0 :4; /* Timer Pulse Unit 0 */
uint TPU1 :4; /* Timer Pulse Unit 1 */
uint :4;
uint :4;
);
volatile word_union(*IPRH,
uint TPU2 :4; /* Timer Pulse Unit 2 */
uint TPU3 :4; /* Timer Pulse Unit 3 */
uint :4;
uint :4;
);
} __attribute__((packed)) mod_intc_ipc_7705_t;
/*
mod_intc_icr0_7705_t
Interrupt control register 0: configuration of the NMI interrupt.
*/
typedef struct
{
word_union(,
uint const NMIL :1; /* NMI Input Level */
uint :6;
uint NMIE :1; /* NMI Edge Select */
uint :8;
);
} __attribute__((packed, aligned(2))) mod_intc_icr0_7705_t;
/*
mod_intc_icr1_7705_t
Interrupt control register 1: general interrupt configuration.
*/
typedef struct
{
word_union(,
uint MAI :1; /* Mask All Interrupts */
uint IRQLVL :1; /* Interrupt Request Level Detect */
uint BLMSK :1; /* Enable NMI when BL is set */
uint :1;
uint IRQ5E :2; /* IRQ 5 Edge Detection */
uint IRQ4E :2;
uint IRQ3E :2;
uint IRQ2E :2;
uint IRQ1E :2;
uint IRQ0E :2;
);
} __attribute__((packed, aligned(2))) mod_intc_icr1_7705_t;
/*
mod_intc_icr2_7705_t
Interrupt control register 2: individual PINT interrupt management.
*/
typedef struct
{
word_union(,
uint PINT15 :1; /* PINT15 interrupt detection level */
uint PINT14 :1;
uint PINT13 :1;
uint PINT12 :1;
uint PINT11 :1;
uint PINT10 :1;
uint PINT9 :1;
uint PINT8 :1;
uint PINT7 :1;
uint PINT6 :1;
uint PINT5 :1;
uint PINT4 :1;
uint PINT3 :1;
uint PINT2 :1;
uint PINT1 :1;
uint PINT0 :1;
);
} __attribute__((packed, aligned(2))) mod_intc_icr2_7705_t;
/*
mod_intc_pinter_7705_t
PINTER register: individual masks for all PINT interrupts.
*/
typedef struct
{
word_union(,
uint PINT15 :1; /* PINT15 interrupt enable */
uint PINT14 :1;
uint PINT13 :1;
uint PINT12 :1;
uint PINT11 :1;
uint PINT10 :1;
uint PINT9 :1;
uint PINT8 :1;
uint PINT7 :1;
uint PINT6 :1;
uint PINT5 :1;
uint PINT4 :1;
uint PINT3 :1;
uint PINT2 :1;
uint PINT1 :1;
uint PINT0 :1;
);
} __attribute__((packed, aligned(2))) mod_intc_pinter_7705_t;
/*
mod_intc_irr0_7705_t
Interrupt Request Register 0: Indicates whether interrupt requests are
being input to the various interrupt lines. Also allows to clear the
IRQ request bits in edge-detection mode.
*/
typedef struct
{
byte_union(,
uint const PINT0_7R :1; /* PINT0-7 state */
uint const PINT8_15R :1; /* PINT8-15 state */
uint IRQ5 :1; /* IRQ5 request pin state */
uint IRQ4 :1;
uint IRQ3 :1;
uint IRQ2 :1;
uint IRQ1 :1;
uint IRQ0 :1;
);
} __attribute__((packed)) mod_intc_irr0_7705_t;
/*
mod_intc_irr1_7705_t
Interrupt Request Register 1: State of SCIF0 and DMAC requests.
*/
typedef struct
{
const byte_union(,
uint TXIOR :1; /* SCIF0 TXI interrupt */
uint :1;
uint RXI0R :1; /* SCIF0 RXI interrupt */
uint ERI0R :1; /* SCIF0 ERI interrupt */
uint DEI3R :1; /* DMAC DEI3 interrupt */
uint DEI2R :1; /* DMAC DEI2 interrupt */
uint DEI1R :1; /* DMAC DEI1 interrupt */
uint DEI0R :1; /* DMAC DEI0 interrupt */
);
} __attribute__((packed)) mod_intc_irr1_7705_t;
/*
mod_intc_irr2_7705_t
Interrupt Request Register 2: State of SCIF2 and ADC requests.
*/
typedef struct
{
const byte_union(,
uint :3;
uint ADIR :1; /* AD/C ADI interrupt */
uint TXI2R :1; /* SCIF2 TXI interrupt */
uint :1;
uint RXI2R :1; /* SCIF2 RXI interrupt */
uint ERI2R :1; /* SCIF2 ERI interrupt */
);
} __attribute__((packed, aligned(2))) mod_intc_irr2_7705_t;
/*
mod_intc_7705_t
Finally the SH7705 interrupt controller.
*/
typedef struct
{
/* All interrupt priority registers */
mod_intc_ipc_7705_t iprs;
/* Control registers */
volatile mod_intc_icr0_7705_t *ICR0;
volatile mod_intc_icr1_7705_t *ICR1;
volatile mod_intc_icr2_7705_t *ICR2;
/* PINTER register */
volatile mod_intc_pinter_7705_t *PINTER;
/* Interrupt request registers */
volatile mod_intc_irr0_7705_t *IRR0;
volatile mod_intc_irr1_7705_t *IRR1;
volatile mod_intc_irr2_7705_t *IRR2;
} __attribute__((packed)) mod_intc_7705_t;
//---
// SH7305-related definitions.
//---
/*
mod_intc_ipc_7305_t
Interrupt priority controller, same idea as the previous one.
Some of the interrupt fields of the SH7305 registers, the contents of
which have been directly taken from the SH7724 documentation, have been
left unnamed because the related peripheral modules are *very* unlikely
to even exist in the SH7305, let alone be of any use to us.
*/
typedef struct
{
word_union(IPRA,
uint TMU0_0 :4; /* TMU0 Channel 0 */
uint TMU0_1 :4; /* TMU0 Channel 1 */
uint TMU0_2 :4; /* TMU0 Channel 2 */
uint IrDA :4; /* Infrared Communication */
);
pad(2);
word_union(IPRB,
uint :4; /* JPEG Processing Unit */
uint LCDC :4; /* LCD Controller */
uint DMAC1A :4; /* Direct Memory Access Controller 1 */
uint :4; /* Blending Engine Unit */
);
pad(2);
word_union(IPRC,
uint TMU1_0 :4; /* TMU1 Channel 0 */
uint TMU1_1 :4; /* TMU1 Channel 1 */
uint TMU1_2 :4; /* TMU1 Channel 2 */
uint :4; /* Sound Processing Unit */
);
pad(2);
word_union(IPRD,
uint :4;
uint MMCIF :4; /* MultiMedia Card Interface */
uint :4;
uint :4; /* ATAPI Interface */
);
pad(2);
word_union(IPRE,
uint DMAC0A :4; /* Direct Memory Access Controller 0 */
uint :4; /* Various graphical engines */
uint SCIFA3 :4; /* SCIFA channel 3 interrupt */
uint :4; /* Video Processing Unit */
);
pad(2);
word_union(IPRF,
uint KEYSC :4; /* Key Scan Interface */
uint DMACOB :4; /* DMAC0 transfer/error info */
uint USB0_1 :4; /* USB controller */
uint CMT :4; /* Compare Match Timer */
);
pad(2);
word_union(IPRG,
uint SCIF0 :4; /* SCIF0 transfer/error info */
uint SCIF1 :4; /* SCIF1 transfer/error info */
uint SCIF2 :4; /* SCIF2 transfer/error info */
uint :4; /* Video Engine Unit */
);
pad(2);
word_union(IPRH,
uint MSIOF0 :4; /* Clock-synchronized SCIF channel 0 */
uint MSIOF1 :4; /* Clock-synchronized SCIF channel 1 */
uint :4; /* I2C Interface channel 0 */
uint :4; /* I2C Interface channel 1 */
);
pad(2);
word_union(IPRI,
uint SCIFA4 :4; /* SCIFA channel 4 interrupt */
uint :4; /* MediaRAM InterConnected Buffers */
uint :4; /* Transport Stream Interface */
uint :4; /* 2D Graphics Accelerator & ICB */
);
pad(2);
word_union(IPRJ,
uint :4; /* Capture Engine Unit */
uint :4; /* Ethernet Memory Access Controller */
uint FSI :4; /* FIFO-Buffered Serial Interface */
uint SDHI1 :4; /* SD Card Host Interface channel 1 */
);
pad(2);
word_union(IPRK,
uint RTC :4; /* Real-Time Clock */
uint DMAC1B :4; /* DMAC1 transfer/error info */
uint :4; /* MediaRAM InterConnected Buffers */
uint SDHI0 :4; /* SD Card Host Interface channel 0 */
);
pad(2);
word_union(IPRL,
uint SCIFA5 :4; /* SCIFA channel 5 interrupt */
uint :4;
uint TPU :4; /* Timer-Pulse Unit */
uint :4; /* Image Extraction DMAC */
);
pad(2);
} __attribute((packed, aligned(4))) mod_intc_ipc_7305_t;
/*
mod_intc_icr0_7305_t
Interrupt Control Register 0: Detection mode of external pins.
*/
typedef struct
{
word_union(,
uint const NMIL :1; /* NMI Input Level */
uint MAI :1; /* Mask All Interrupts */
uint :4;
uint NMIB :1; /* Enable NMI when BL is set */
uint NMIE :1; /* NMI Edge Selection */
uint :2;
uint LVLMODE :1; /* Level-Sensed IRQ Retention Mode */
uint :5;
);
} __attribute__((packed, aligned(2))) mod_intc_icr0_7305_t;
/*
mod_intc_icr1_7305_t
Interrupt Control Register 1: Manages detection of IRQ interrupts
*/
typedef struct
{
word_union(,
uint IRQ0 :2; /* IRQ0 Sense (Edge) Select */
uint IRQ1 :2;
uint IRQ2 :2;
uint IRQ3 :2;
uint IRQ4 :2;
uint IRQ5 :2;
uint IRQ6 :2;
uint IRQ7 :2;
);
} __attribute__((packed, aligned(2))) mod_intc_icr1_7305_t;
/*
mod_intc_intpri00_7305_t
Interrupt Priority 00: Priority settings for IRQ interrupts.
*/
typedef struct
{
lword_union(,
uint IRQ0 :4; /* IRQ0 Interrupt Priority */
uint IRQ1 :4;
uint IRQ2 :4;
uint IRQ3 :4;
uint IRQ4 :4;
uint IRQ5 :4;
uint IRQ6 :4;
uint IRQ7 :4;
);
} __attribute((packed, aligned(4))) mod_intc_intpri00_7305_t;
/*
mod_intc_intreq00_7305_t
Interrupt Request 00: Request information of IRQ interrupts. Each of
these bits indicates whether an interrupt is being input.
mod_intc_intmsk00_7305_t
Interrupt Mask 00: Set interrupt mask for IRQ interrupts. Writing 0 to
these bits is ignored, writing 1 masks the interrupt.
mod_intc_intmskclr00_7305_t
Interrupt Mask Clear 00: Clear interrupt mask for IRQ interrupts.
Writing 0 to these bits is ignored, writing 1 clears the mask.
*/
typedef struct
{
byte_union(,
uint IRQ0 :1;
uint IRQ1 :1;
uint IRQ2 :1;
uint IRQ3 :1;
uint IRQ4 :1;
uint IRQ5 :1;
uint IRQ6 :1;
uint IRQ7 :1;
);
} __attribute__((packed)) mod_intc_irq_7305_t;
typedef mod_intc_irq_7305_t mod_intc_intreq00_7305_t;
typedef mod_intc_irq_7305_t mod_intc_intmsk00_7305_t;
typedef mod_intc_irq_7305_t mod_intc_intmskclr00_7305_t;
/*
mod_intc_masks_7305_t
A set of bits to mask individual interrupts.
- Masking interrupts is realized by writing 1 to IMRs ;
- Clearing masks is realized by writing 1 to IMCRs ;
Using the wrong register set, such as writing 0 to IMRs to clear a
mask, will be ignored and have no effect. Reading from IMCRs yields an
undefined value.
*/
typedef struct
{
byte_union(IMR0,
uint :1;
uint TUNI1_2 :1; /* TMU1 overflow interrupts */
uint TUNI1_1 :1;
uint TUNI1_0 :1;
uint SDHII3 :1; /* SD Card Host 1 interrupts */
uint SDHII2 :1;
uint SDHII1 :1;
uint SDHII0 :1;
);
pad(3);
byte_union(IMR1,
uint :4;
uint DEI3 :1; /* DMAC0A interrupts */
uint DEI2 :1;
uint DEI1 :1;
uint DEI0 :1;
);
pad(3);
byte_union(IMR2,
uint :7;
uint SCIFA0 :1; /* Asynchronous Serial interrupts */
);
pad(3);
byte_union(IMR3,
uint DEI3 :1; /* DMAC1A interrupts */
uint DEI2 :1;
uint DEI1 :1;
uint DEI0 :1;
uint :4;
);
pad(3);
byte_union(IMR4,
uint :1;
uint TUNI0_2 :1; /* TMU0 overflow interrupts */
uint TUNI0_1 :1;
uint TUNI0_0 :1;
uint :3;
uint LCDCI :1; /* LCD Controller Interrupt */
);
pad(3);
byte_union(IMR5,
uint KEYI :1; /* Key Interface */
uint DADERR :1; /* DMAC0B interrupts */
uint DEI5 :1;
uint DEI4 :1;
uint :1;
uint SCIF2 :1; /* Serial Communication Interface */
uint SCIF1 :1;
uint SCIF0 :1;
);
pad(3);
byte_union(IMR6,
uint :2;
uint :1;
uint SCIFA4 :1; /* SCIFA4 interrupt */
uint :1;
uint :1;
uint MSIOFI0 :1; /* Clock-synchronized SCIF channel 0 */
uint MSIOFI1 :1; /* Clock-synchronized SCIF channel 1 */
);
pad(3);
uint8_t IMR7;
pad(3);
byte_union(IMR8,
uint SDHII3 :1; /* SD Card Host 0 interrupts */
uint SDHII2 :1;
uint SDHII1 :1;
uint SDHII0 :1;
uint :2;
uint SCFIA5 :1; /* SCIFA5 interrupt */
uint FSI :1; /* FIFO-Buffered Serial Interface */
);
pad(3);
byte_union(IMR9,
uint :3;
uint CMTI :1; /* Compare Match Timer Interrupt */
uint :1;
uint USI1 :1; /* USB1 */
uint USI0 :1; /* USB0 */
uint :1;
);
pad(3);
byte_union(IMR10,
uint :1;
uint DADERR :1; /* DMAC1B interrupts */
uint DEI5 :1;
uint DEI4 :1;
uint :1;
uint ATI :1; /* RTC Alarm interrupt */
uint PRI :1; /* RTC Periodic interrupt */
uint CUI :1; /* RTC Carry interrupt */
);
pad(3);
byte_union(IMR11,
uint :5;
uint TPUI :1; /* Timer-Pulse Unit */
uint :2;
);
pad(3);
uint8_t IMR12;
char gap2[15];
} __attribute__((packed, aligned(4))) mod_intc_masks_7305_t;
/*
mod_intc_userimask_7305_t
User Interrupt Mask: Specifies the minimum required level for
interrupts to be accepted.
WARNING: Writing to this register requires the eight upper bits of the
operand (ie. the new value of USERIMASK) to be 0xa5; otherwise, the
write is ignored. To modify the value of this register, do not access
the bit field directly, backup the variable and modify it:
void set_user_imask(int new_level)
{
mod_intc_userimask_7305_t mask = *(INTC._7305.USERIMASK);
mask._0xa5 = 0xa5;
mask.UIMASK = new_level & 0x0f;
*(INTC._7305.USERIMASK) = mask;
}
*/
typedef struct
{
lword_union(,
uint _0xa5 :8; /* Always set to 0xa5 before writing */
uint :16;
uint UIMASK :4; /* User Interrupt Mask Level */
uint :4;
);
} __attribute__((packed, aligned(4))) mod_intc_userimask_7305_t;
/*
mod_intc_nmifcr_7305_t
NMI Flag Control Register: Indicates the state of the NMI pin and the
NMI interrupt request.
*/
typedef struct
{
word_union(,
uint const NMIL :1; /* NMI Interupt Level */
uint :14;
uint NMIFL :1; /* NMI Interrupt Request Flag */
);
} __attribute__((packed, aligned(2))) mod_intc_nmifcr_7305_t;
/*
mod_intc_7305_t
Finally the whole interrupt controller.
*/
typedef struct
{
/* Control registers */
volatile mod_intc_icr0_7305_t *ICR0;
volatile mod_intc_icr1_7305_t *ICR1;
/* Interrupt priority registers */
volatile mod_intc_intpri00_7305_t *INTPRI00;
volatile mod_intc_ipc_7305_t *iprs;
/* Interrupt mask & mask clear registers */
volatile mod_intc_intmsk00_7305_t *INTMSK00;
volatile mod_intc_masks_7305_t *masks;
volatile mod_intc_intmskclr00_7305_t *INTMSKCLR00;
volatile mod_intc_masks_7305_t *masks_clear;
/* Other registers */
volatile mod_intc_intreq00_7305_t *INTREQ00;
volatile mod_intc_userimask_7305_t *USERIMASK;
volatile mod_intc_nmifcr_7305_t *NMIFCR;
} mod_intc_7305_t;
//---
// Platform-independent structures.
// Unfortunately there is nothing here. Users willing to manage interrupts
// using the INTC register will have to handle explicitely both platforms.
//---
/*
mod_intc_t
Interrupt Controller.
*/
typedef union
{
mod_intc_7705_t _7705;
mod_intc_7305_t _7305;
} __attribute__((packed)) mod_intc_t;
// Here's what you'll need to use.
extern mod_intc_t INTC;
#endif // _MODULE_INTERRUPTS_H

View file

@ -1,57 +0,0 @@
#ifndef _MODULES_MACROS_H
#define _MODULES_MACROS_H
#include <stdint.h>
// Padding is just empty space, we don't want to give it a type. There's also
// some subtle preprocessor trick to automatically add a (supposedly) unique
// name to each padding member. For instance the substitution may operate as:
// name(__LINE__) -> namesub(78) -> _##78 -> _78
#define namesub(x) _##x
#define name(x) namesub(x)
#define pad(bytes) \
uint8_t name(__LINE__)[bytes]
// Fixed-width types for bit field are totally meaningless.
typedef unsigned uint;
/*
byte_union()
Union between an uint8_t 'byte' attribute and a provided bit-field
structure that describe the contents of the byte.
*/
#define byte_union(name, fields) \
union \
{ \
uint8_t byte; \
struct { fields } \
__attribute__((packed)); \
} __attribute__((packed)) name
/*
word_union()
Union between an uint16_t 'word' attribute and a provided bit-field
structure that describe the contents of the word.
*/
#define word_union(name, fields) \
union \
{ \
uint16_t word; \
struct { fields } \
__attribute__((packed)); \
} __attribute__((packed, aligned(2))) name
/*
lword_union()
Union between an uint32_t 'lword' attribute and a provided bit-field
structure that describe the contents of the longword.
*/
#define lword_union(name, fields) \
union \
{ \
uint32_t lword; \
struct { fields } \
__attribute__((packed)); \
} __attribute__((packed, aligned(4))) name
#endif // _MODULES_MACROS_H

View file

@ -1,131 +0,0 @@
#ifndef _MODULES_RTC_H
#define _MODULES_RTC_H
#include <modules/macros.h>
#include <stdint.h>
/*
mod_rtc_rcr1_t
First RTC configuration register.
*/
typedef struct
{
byte_union(,
uint CF :1; /* Carry flag */
uint :2;
uint CIE :1; /* Carry interrupt enable */
uint AIE :1; /* Alarm interrupt enable */
uint :2;
uint AF :1; /* Alarm flag */
);
} __attribute__((packed)) mod_rtc_rcr1_t;
/*
mod_rtc_rcr2_t
Second RTC configuration register.
*/
typedef struct
{
byte_union(,
uint PEF :1; /* Periodic interrupt flag */
uint PES :3; /* Periodic interrupt interval */
uint :1;
uint ADJ :1; /* 30-second adjustment */
uint RESET :1; /* Reset */
uint START :1; /* Start bit */
);
} __attribute__((packed)) mod_rtc_rcr2_t;
/*
mod_rtc_rcr3_t
Third RTC configuration register.
typedef struct
{
byte_union(,
uint YAEN :1;
uint :7;
);
} __attribute__((packed)) mod_rtc_rcr3_t;
*/
/*
mod_rtc_time_t
A set of registers describing the current time in BCD format.
*/
typedef struct
{
const uint8_t R64CNT; /* More or less a 64-Hz counter */
pad(1);
byte_union(RSECCNT, /* Second count */
uint :1;
uint TENS :3;
uint ONES :4;
);
pad(1);
byte_union(RMINCNT, /* Minute count */
uint :1;
uint TENS :3;
uint ONES :4;
);
pad(1);
byte_union(RHRCNT, /* Hour count */
uint :2;
uint TENS :2;
uint ONES :4;
);
pad(1);
/* 0 = Sunday .. 6 = Saturday, other settings are prohibited. */
uint8_t RWKCNT; /* Day of week */
pad(1);
byte_union(RDAYCNT, /* Day count */
uint :2;
uint TENS :2;
uint ONES :4;
);
pad(1);
byte_union(RMONCNT, /* Month count */
uint :3;
uint TENS :1;
uint ONES :4;
);
pad(1);
word_union(RYRCNT, /* Year count */
uint THOUSANDS :4;
uint HUNDREDS :4;
uint TENS :4;
uint ONES :4;
);
} __attribute__((packed, aligned(2))) mod_rtc_time_t;
/*
mod_rtc_t (resides into gint memory)
Three control registers and timer information.
*/
typedef struct
{
/* RCR1, RCR2, and RCR3 are the same for both platforms. */
volatile mod_rtc_rcr1_t *RCR1;
volatile mod_rtc_rcr2_t *RCR2;
// volatile mod_rtc_rcr3_t *RCR3;
/* Current time in register memory */
volatile mod_rtc_time_t *time;
} mod_rtc_t;
// All you need to use is this structure, initialized by gint, which contains
// address that work with your execution platform.
extern mod_rtc_t RTC;
#endif // _INTERNALS_RTC_H

View file

@ -1,64 +0,0 @@
#ifndef _MODULES_TIMER_H
#define _MODULES_TIMER_H
#include <modules/macros.h>
#include <stdint.h>
/*
mod_tmu_timer_t
Registers of a single timer.
*/
typedef struct
{
uint32_t TCOR; /* Timer constant register */
uint32_t TCNT; /* Timer counter */
word_union(TCR,
uint :7;
uint UNF :1; /* Underflow flag */
uint :2;
uint UNIE :1; /* Underflow interrupt enable */
uint CKEG :2; /* Clock edge (SH7705) */
uint TPSC :3; /* Timer prescaler */
);
uint16_t :16;
} __attribute__((packed, aligned(4))) mod_tmu_timer_t;
/*
mod_tmu_tstr_t
The timer start register.
*/
typedef struct
{
byte_union(,
uint :5;
uint STR2 :1; /* Counter start 2 */
uint STR1 :1; /* Counter start 1 */
uint STR0 :1; /* Counter start 0 */
);
} __attribute__((packed)) mod_tmu_tstr_t;
/*
mod_tmu_t (resides into gint memory)
Basically three timer units and an additional register to control who's
running.
*/
typedef struct
{
/* Timer configurations */
volatile mod_tmu_timer_t *timers[3];
/* Timer start register */
volatile mod_tmu_tstr_t *TSTR;
/* Timer input capture 2 (SH7705) */
volatile const uint32_t *TCPR2;
} mod_tmu_t;
// The actual thing is there. It's initialized by gint at startup and contains
// addresses and information suitable for the current platform.
extern mod_tmu_t TMU;
#endif // _MODULES_TIMER

View file

@ -1,71 +0,0 @@
//---
//
// gint core module: mpu
//
// Determines which kind of MPU is running the program. This module
// provides macro tests isSH3(), isSH4(), and the identifier of the MPU,
// which is stored in a global variable MPU_CURRENT and determined at
// startup.
//
// If you need to do MPU-dependent jobs, use isSH3() or (possibly) isSH4()
// instead of testing the value of MPU_CURRENT because these macros take
// care of assuming unknown MPUs are SH4, which is the more reasonable
// option.
//
// It is advised to always use the following alternative (which gint
// does):
//
// if(isSH3())
// {
// ...
// }
// else
// {
// ...
// }
//
//---
#ifndef _MPU_H
#define _MPU_H
/*
mpu_t
This type holds information about the calculator's MPU.
*/
typedef enum
{
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 (no calculator uses it).
mpu_sh7724 = 4,
} mpu_t;
// Global MPU variable, accessible for direct tests. Initialized at the
// beginning of execution.
extern const mpu_t 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.
*/
mpu_t getMPU(void);
#endif // _MPU_H

View file

@ -1,105 +0,0 @@
//---
//
// gint core module: rtc
//
// Manages the Real-Time Clock (RTC). This module provides access to the
// current time as well as regular callbacks at predefined frequencies,
// more or less like a timer.
// The standard time module is built upon this one.
//
//---
#ifndef _RTC_H
#define _RTC_H
#include <stdint.h>
//---
// Time access.
//---
/*
rtc_time_t
Defines a point in time.
*/
typedef struct
{
uint8_t seconds; // Seconds in range 0-59
uint8_t minutes; // Minutes in range 0-59
uint8_t hours; // Hours in range 0-23
uint8_t month_day; // Day of month in range 1-31
uint8_t month; // Month in range 0-11
uint8_t week_day; // Day of week in range 0(Sunday)-6(Saturday).
uint16_t year; // Years (around 2000)
} rtc_time_t;
/*
rtc_getTime()
Reads the current time from the RTC. There is no guarantee that the
week day is correct (use the time API for that).
*/
void rtc_getTime(rtc_time_t *time);
/*
rtc_setTime()
Sets the time in the RTC registers. The week day is set to 0 if greater
than 6. Other fields are not checked.
*/
void rtc_setTime(const rtc_time_t *time);
//---
// Callback API.
//---
/*
rtc_frequency_t
Describes the possible frequencies available for the real-time clock
interrupt.
*/
typedef enum
{
rtc_freq_500mHz = 7,
rtc_freq_1Hz = 6,
rtc_freq_2Hz = 5,
rtc_freq_4Hz = 4,
rtc_freq_16Hz = 3,
rtc_freq_64Hz = 2,
rtc_freq_256Hz = 1,
rtc_freq_none = 0,
} rtc_frequency_t;
/*
rtc_cb_add()
Registers a new callback for the RTC. Returns the callback id on
success (positive integer), or one of the following error codes:
-1 Array is full
-2 Invalid parameter
The number of repeats may be set to 0, in which case the callback is
called indefinitely unless the user calls rtc_cb_end().
*/
int rtc_cb_add(rtc_frequency_t freq, void (*function)(void), int repeats);
/*
rtc_cb_end()
Removes the callback with the given id (as returned by rtc_cb_add())
from the callback array.
*/
void rtc_cb_end(int id);
/*
rtc_cb_edit()
Changes information related to a callback. This function returns 0 on
success, or one of the following error codes:
-1 Callback does not exist
-2 Invalid parameters
This function never removes a callback. Call rtc_cb_end() for this. One
can set the function to NULL or the frequency to rtc_freq_none to
temporarily disable the callback.
*/
int rtc_cb_edit(int id, rtc_frequency_t new_freq, void (*new_function)(void));
#endif // _RTC_H

View file

@ -1,35 +0,0 @@
//---
//
// gint display module: screen
//
// Interacts with the physical screen. See other display modules 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.
//---
#ifndef _SCREEN_H
#define _SCREEN_H
/*
screen_display()
Displays contents on the full screen. Expects a 1024-byte buffer.
*/
void screen_display(const void *vram);
/*
screen_setBacklight()
On compatible models, turns on or turns off the backlight.
*/
void screen_setBacklight(int on);
/*
screen_toggleBacklight()
Changes the backlight state, regardless of its current state.
*/
void screen_toggleBacklight(void);
#endif

View file

@ -1,37 +0,0 @@
//---
//
// gint standard module: setjmp
//
// Long jumps. The register contents are saved in a buffer when setjmp()
// is called and restored at any time when longjmp() performs the jump.
//
//---
#ifndef _SETJMP_H
#define _SETJMP_H
#include <stdint.h>
// There are 16 CPU registers that *must* be saved to ensure a basically
// safe jump.
typedef uint32_t jmp_buf[16];
//---
// Long jump functions.
//---
/*
setjmp() O(1)
Configures a jump by saving data to the given jump buffer.
*/
int setjmp(jmp_buf env);
/*
longjmp() O(1)
Performs a long jump.
*/
void longjmp(jmp_buf env, int value);
#endif // _SETJMP_H

View file

@ -1,44 +0,0 @@
//---
//
// standard library module: stdio
//
// Handles most input/output for the program. This module does not
// interact with the file system directly.
//
//---
#ifndef _STDIO_H
#define _STDIO_H
#include <stddef.h>
#include <stdarg.h>
//---
// Formatted printing.
//---
/*
sprintf()
Prints to a string.
*/
int sprintf(char *str, const char *format, ...);
/*
snprintf()
Prints to a string with a size limit.
*/
int snprintf(char *str, size_t size, const char *format, ...);
/*
vsprintf()
Prints to a string from an argument list.
*/
int vsprintf(char *str, const char *format, va_list args);
/*
vsnprintf()
The most generic formatted printing function around there.
*/
int vsnprintf(char *str, size_t size, const char *format, va_list args);
#endif // _STDIO_H

View file

@ -1,149 +0,0 @@
//---
//
// standard library module: stdlib
//
// Provides standard functionalities such as dynamic allocation,
// string/numeric conversion, and abort calls.
//
//---
#ifndef _STDLIB_H
#define _STDLIB_H
//---
// Common definitions.
//---
#include <stddef.h>
#include <limits.h>
// Common exit codes.
#define EXIT_SUCCESS 1
#define EXIT_FAILURE 0
// Number of atexit() registrations guaranteed.
#ifndef ATEXIT_MAX
#define ATEXIT_MAX 16
#endif
// Maximum value returned by rand().
#define RAND_MAX INT_MAX
// Integer division result.
typedef struct
{
int quot, rem;
} div_t;
typedef struct
{
long quot, rem;
} ldiv_t;
//---
// 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.
*/
void exit(int status);
/*
atexit()
Registers a function to be called at normal program termination.
*/
int atexit(void (*function)(void));
//---
// Dynamic storage allocation.
//---
/*
malloc()
Allocates 'size' bytes and returns a pointer to a free memory area.
Returns NULL on error.
*/
void *malloc(size_t size);
/*
calloc()
Allocates 'n' elements of size 'size' and wipes the memory area.
Returns NULL on error.
*/
void *calloc(size_t n, size_t size);
/*
realloc()
Reallocates a memory block and moves its data.
*/
void *realloc(void *ptr, size_t size);
/*
free()
Frees a memory block allocated by malloc(), calloc() or realloc().
*/
void free(void *ptr);
//---
// Random number generation.
//---
/*
rand()
Returns a pseudo-random number.
*/
int rand(void);
/*
srand()
Changes the seed used by rand().
*/
void srand(unsigned int seed);
//---
// Integer arithmetic.
//---
/*
abs()
Returns the absolute value of an integer.
*/
int abs(int x);
// Use a macro instead, when possible.
#define abs(x) ((x) < 0 ? -(x) : (x))
/*
labs()
Returns the absolute value of a long integer.
*/
long labs(long x);
// Use a macro instead.
#define labs(x) ((x) < 0 ? -(x) : (x))
/*
div()
Computes the integer division of numerator by denominator.
*/
div_t div(int numerator, int denominator);
/*
ldiv()
Computes the integer division of two long integers.
*/
ldiv_t ldiv(long numerator, long denominator);
#endif // _STDLIB_H

View file

@ -1,94 +0,0 @@
//---
//
// standard library module: string
//
// String manipulation using NUL-terminated byte arrays, without extended
// characters.
//
//---
#ifndef _STRING_H
#define _STRING_H
#include <stddef.h>
//---
// Memory manipulation.
//---
/*
memcpy() O(byte_count)
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.
*/
void *memcpy(void *destination, const void *source, size_t byte_count);
/*
memset() O(byte_count)
Sets the contents of a memory area. A smart copy is performed.
*/
void *memset(void *destination, int byte, size_t byte_count);
/*
memchr() O(byte_count)
Looks for a byte in a memory area. Returns the address of the first
occurrence if found, NULL otherwise.
*/
void *memchr(const void *area, int byte, size_t byte_count);
/*
memcmp() O(byte_count)
Compares two memory areas. Returns 0 if all bytes are equal in both
areas, a negative number if the first unequal byte is lower in the
first area, and a positive number otherwise.
A smart comparison is performed when possible.
*/
int memcmp(const void *area1, const void *area2, size_t byte_count);
//---
// String manipulation.
//---
/*
strlen() O(len(str))
Returns the length of a string.
*/
size_t strlen(const char *str);
/*
strnlen() O(len(str))
Returns the minimum of the length of the string and n. This function
never access more than n bytes at the beginning of the string.
*/
size_t strnlen(const char *str, size_t n);
/*
strcpy() O(len(source))
Copies a string to another.
*/
char *strcpy(char *destination, const char *source);
/*
strncpy() O(min(len(source), size))
Copies part of a string to another.
*/
char *strncpy(char *destination, const char *source, size_t size);
/*
strchr() O(len(str))
Searches a character in a string.
*/
const char *strchr(const char *str, int value);
/*
strcmp() O(max(len(str1), len(str2)))
Compares two strings. Returns 0 if they are identical, a negative
number if the first unequal byte is lower in str1 than in str2, and a
positive number otherwise.
*/
int strcmp(const char *str1, const char *str2);
#endif // _STRING_H

View file

@ -1,128 +0,0 @@
//---
//
// gint drawing module: tales
//
// Text displaying. Does some pretty good optimization, though requires
// dynamic allocation. The stack is used.
//
//---
#ifndef _TALES_H
#define _TALES_H
#include <display.h>
#include <stdint.h>
#include <stddef.h>
//---
// Types and constants.
//---
/*
font_format_t
This type holds information about the characters in the font. Each bit
represents various characters, and the type itself is a combination of
several of those bits.
Bits represent the following characters (lsb right):
-- -- -- non-print | special capitals lower numbers
*/
typedef enum
{
font_format_unknown = 0x00,
font_format_numeric = 0x01,
font_format_lower = 0x02,
font_format_upper = 0x04,
font_format_letters = 0x06,
font_format_common = 0x07,
font_format_print = 0x0f,
font_format_ascii = 0x1f,
} font_format_t;
/*
font_glyph_t
Holds a glyph's data. The width is used for spacing, and the raw data
is encoded line after line, from to to bottom, by appending bits
without consideration of the byte boundaries.
This structure is actually never used, because data is read directly
as a longword array (hence the 4-byte alignment).
*/
typedef struct
{
uint8_t width;
const uint8_t data[];
} __attribute__((packed, aligned(4))) font_glyph_t;
/*
font_t
Holds a font's data. Data is accessed using longword operations, hence
the 4-alignment attributes. The line height is the one given in the
font image header line, which may be used by applications that write
strings on several lines. The data height is the height of the biggest
glyph. Every glyph is encoded on 'data_height' lines, for optimization
considerations.
The index field is used to reduce character access time.
The name field may not be NUL-terminated when the name contains 28
characters. When the name is shorter, the field is padded with zeros.
*/
typedef struct
{
uint8_t magic;
uint8_t format;
uint8_t line_height;
uint8_t data_height;
// Warning : this field may not be NUL-terminated.
char name[28];
uint16_t index[16];
__attribute__((aligned(4))) const uint32_t glyphs[];
} __attribute__((packed, aligned(4))) font_t;
//---
// Generic functions.
//---
/*
text_configure()
Sets the font and color to use for subsequent text operations. Pass
font = NULL to use the default font.
*/
void text_configure(font_t *font, color_t operator);
/*
text_length()
Computes the length of a string using the currently configured font.
*/
size_t text_length(const char *str);
/*
dtext()
Prints the given string, without any analysis.
*/
void dtext(int x, int y, const char *str);
/*
gtext()
Prints the given raw string.
*/
void gtext(int x, int y, const char *str);
/*
dprint()
Prints a formatted string. Works the same as printf().
*/
void dprint(int x, int y, const char *format, ...);
/*
gprint()
Prints a formatted string. Works the same as printf().
*/
void gprint(int x, int y, const char *format, ...);
#endif // _TALES_H

View file

@ -1,126 +0,0 @@
//---
//
// standard library module: time
//
// Provides time manipulation and representation functions.
//
//---
#ifndef _TIME_H
#define _TIME_H
#include <stddef.h>
//---
// Some related types.
//---
/*
struct tm
Represents a point in time and gives some date information.
*/
struct tm
{
int tm_sec; // Seconds in range 0-59
int tm_min; // Minutes in range 0-59
int tm_hour; // Hours in range 0-23
int tm_mday; // Day of month in range 1-31
int tm_mon; // Month in range 0-11
int tm_year; // Number of years since 1900
int tm_wday; // Day of week in range 0(Sunday)-6(Saturday).
int tm_yday; // Day of the year in range 0-365.
int tm_isdst; // This will always be 0.
};
/*
clock_t
Only used by clock().
*/
typedef signed int clock_t;
/*
time_t
Number of seconds elapsed since 1970-01-01 00:00:00.
*/
typedef signed int time_t;
//---
// Time access.
//---
/*
clock()
Should return elapsed CPU time since beginning of program execution.
This is currently not implemented and returns -1.
*/
clock_t clock(void);
/*
time()
Returns the current time as calendar time. If you need a broken-down
time, either use the RTC API or gmtime(). However, this function is
already based on mktime() (for hardware reasons) so it would be much
faster to use the RTC API if possible.
If timeptr is not NULL, it is set to the current time, that is, the
value that is returned.
*/
time_t time(time_t *timeptr);
/*
difftime()
Returns the number of seconds between the given points.
*/
double difftime(time_t end, time_t beginning);
// But this macro should do.
#define difftime(end, beginning) ((double)((end) - (beginning)))
//---
// Time representation.
//---
/*
asctime()
Converts broken-down time to string representation on the form
"Wed Jun 30 21:49:08 1993\n". The returned string is statically
allocated and may be overwritten by any subsequent call to a time
function.
*/
char *asctime(const struct tm *time);
/*
ctime()
Converts calendar time to string representation on the form
"Wed Jun 30 21:49:08 1993\n". The returned string is statically
allocated and may be overwritten by any subsequent call to a time
function.
*/
char *ctime(const time_t *timer);
//---
// Time conversion.
//---
/*
mktime()
Converts broken-down time to calendar time. Computes structure fields
tm_wday and tm_yday using the other fields. Member structures outside
their range are normalized (e.g. 40 October becomes 9 November) and
tm_isdst is set.
*/
time_t mktime(struct tm *time);
/*
gmtime()
Converts calendar time to broken-down time. The returned pointer is
statically allocated and may be overwritten by any subsequent call to
a time function.
*/
struct tm *gmtime(const time_t *t);
#endif // _TIME_H

View file

@ -1,177 +0,0 @@
//---
//
// gint core module: timer
//
// Basic timer unit manipulation. Starts and stops timers with variable
// number of repeats, and allows timer reloads without pause.
//
//---
#ifndef _TIMER_H
#define _TIMER_H
#include <clock.h>
#include <stdint.h>
#include <stddef.h>
// The timer object is manipulated by the module; the user needs not access it
// directly. Its contents are defined in <internals/timer.h>.
struct timer_t;
typedef struct timer_t timer_t;
//---
// Virtual timer API
// Gint allows users to create virtual timers with 1-ms precision to
// handle an important amount of timed events. The amount of virtual
// timers available is gapped by the TIMER_SLOTS parameter, but this
// parameter can be customized when building the library; thus, the
// amount of usable virtual timers is not limited.
//---
#ifndef TIMER_SLOTS
#define TIMER_SLOTS 16
#endif
/*
timer_create()
Basic timer configuration. This function creates a virtual timer and
configures its delay and repetition count. It returns a virtual timer
object that will be used by other functions. At most TIMER_SLOTS
virtual timers can be used at the same time: this function returns NULL
if there is no new slot available.
By default a virtual timer configured by timer_configure() will fire
ET_Timer events, which the user will need to catch. The user should
then execute some action.
There is another option: the user may call timer_attach() to attach a
callback to a virtual timer. A virtual timer which has a callback
attached will not fire any ET_Timer event and will call the callback
automatically instead.
*/
timer_t *timer_create(int delay_ms, int repeats);
/*
timer_reload()
Changes a virtual timer's delay. The timer is not stopped nor started:
it keeps running or waiting. Events that were waiting to be handled are
dropped and the number of repeats left is not changed. The timer
restarts counting from 0 regardless of how much time had elapsed since
it last fired.
*/
void timer_reload(timer_t *timer, int new_ms_delay);
/*
timer_destroy()
Destroys a virtual timer. This virtual timer pointer becomes invalid
and should not be used anymore.
*/
void timer_destroy(timer_t *virtual_timer);
//---
// Hardware timer API
// Gint provides access to hardware timer. These timer offer more or less
// microsecond-level control. However, the user should ensure, when using
// hardware timers, that they are not overriding the configuration of
// timers that are already running -- gint won't check.
//---
/*
timer_hard_t
Available hardware timers. The user can use timer_user freely, but
timer_gray and timer_virtual should not be used as long as the gray
engine or virtual timers are running (respectively).
*/
typedef enum
{
timer_tmu0 = 0,
timer_virtual = timer_tmu0,
timer_tmu1 = 1,
timer_gray = timer_tmu1,
timer_tmu2 = 2,
timer_user = timer_tmu2,
} timer_hard_t;
/*
timer_input_t
Available input clocks for the hardware timer:
- Po/4 Peripheral clock (frequency divided by 4)
- Po/16 Peripheral clock (frequency divided by 16)
- Po/64 Peripheral clock (frequency divided by 64)
- Po/256 Peripheral clock (frequency divided by 256)
- TCLK External clock
I'm not totally sure there is any signal on the external clock, so
don't use it unless you know what you are doing.
*/
typedef enum
{
timer_Po_4 = 0,
timer_Po_16 = 1,
timer_Po_64 = 2,
timer_Po_256 = 3,
timer_tclk = 5,
} timer_input_t;
/*
htimer_setup()
Configures a hardware timer. By default hardware timers generates
ET_Timer events but catching them may take some time, especially if
there are other events waiting in the queue. For increased timing, and
for fast timers, the user should consider using callbacks instead.
Returns a hardware timer object.
Returns the correct timer structure if the requested timer is free and
NULL otherwise.
*/
timer_t *htimer_setup(timer_hard_t id, uint32_t constant, timer_input_t input,
int repeats);
/*
htimer_reload()
Reloads a hardware timer without starting or stopping it.
*/
void htimer_reload(timer_hard_t id, uint32_t new_constant);
//---
// Common API
// The following functions work with both virtual and hardware timers.
//---
/*
timer_attach()
This function attaches a callback to a virtual or hardware timer. A
timer with a callback attached will stop firing ET_Timer events and
will call the callback function directly instead.
The type signature of the function should be as follows:
- void callback(void) if argument == NULL
- void callback(void *argument) if argument is non-NULL
In the latter case, the argument pointer will be passed to the callback
function.
*/
void timer_attach(timer_t *timer, void *callback, void *argument);
/*
timer_start()
Starts a virtual or hardware timer. If the timer has a callback
attached, then the callback function will start being called regularly;
otherwise, the timer will start pushing ET_Timer events to the event
queue. It is advised, not to change a timer's configuration while it's
running.
*/
void timer_start(timer_t *timer);
/*
timer_stop()
Stops a timer. If the argument is virtual timer, it is paused and can
be started again later.
If it's a hardware timer, it is freed and made accessible to other
uses. It should be set up again before being started.
*/
void timer_stop(timer_t *timer);
#endif // _TIMER_H

View file

@ -1,331 +0,0 @@
#include <internals/bopti.h>
// Monochrome video ram, light and dark buffers (in this order).
uint32_t *bopti_vram, *bopti_v1, *bopti_v2;
/*
bopti_op()
Operates on a vram long. The operator will often not contain 32 bits of
image information. Since neutral bits are not the same for all
operations, a mask is used to indicate which bits should be used for
the operation. This mask is taken for the image's rectangle masks (see
module display for more information on rectangle masks).
Which operation is performed is determined by the channel setting.
*/
void bopti_op_mono(int offset, uint32_t operator, command_t *c)
{
operator &= c->masks[offset & 3];
switch(c->channel)
{
case channel_full_alpha:
bopti_vram[offset] &= ~operator;
break;
case channel_mono:
bopti_vram[offset] |= operator;
break;
default:
break;
}
}
void bopti_op_gray(int offset, uint32_t operator, command_t *c)
{
operator &= c->masks[offset & 3];
switch(c->channel)
{
case channel_full_alpha:
bopti_v1[offset] &= ~operator;
bopti_v2[offset] &= ~operator;
break;
case channel_light_alpha:
case channel_dark_alpha:
break;
case channel_mono:
bopti_v1[offset] |= operator;
bopti_v2[offset] |= operator;
break;
case channel_light:
bopti_v1[offset] |= operator;
break;
case channel_dark:
bopti_v2[offset] |= operator;
break;
}
}
/*
bopti_grid() -- general form
bopti_grid_a32() -- when x is a multiple of 32
Draws the grid at the beginning of a layer's data. The length of this
grid is always a multiple of 32.
The need for bopti_grid_a32() is not only linked to optimization,
because bopti_grid() will perform a 32-bit shift when x is a multiple
of 32, which is undefined behavior.
*/
void bopti_grid_a32(const uint32_t *layer, int column_count, int height,
command_t *c)
{
int vram_column_offset = (c->y << 2) + (c->x >> 5);
int vram_offset = vram_column_offset;
int column, row;
for(column = 0; column < column_count; column++)
{
for(row = c->top; row < c->bottom; row++)
{
(c->op)(vram_offset, layer[row], c);
vram_offset += 4;
}
vram_column_offset++;
vram_offset = vram_column_offset;
layer += height;
}
}
void bopti_grid(const uint32_t *layer, int column_count, int height,
command_t *c)
{
if(!column_count) return;
if(!(c->x & 31))
{
bopti_grid_a32(layer, column_count, height, c);
return;
}
const uint32_t *p1, *p2;
uint32_t l1, l2, operator;
int right_column, line;
int actual_column_count;
int vram_column_offset = (c->y << 2) + (c->x >> 5) + (c->x < 0);
int vram_offset = vram_column_offset;
int shift2 = (c->x & 31);
int shift1 = 32 - shift2;
// Initializing two pointers. They will read two adjacent columns at
// the same time (p2 is column ahead of p1). Since the columns are
// written one after another, incrementing them will suffice when
// reaching the end of two columns, to move them to the next ones.
p1 = layer - height;
p2 = layer;
// We don't want to write the first vram column when x is negative
// because it's outside the screen.
if(c->x < 0) p1 += height, p2 += height;
right_column = (c->x < 0);
// For the same reason, we don't to draw the additional rightmost
// column when it begins after 96.
if(c->x + (column_count << 5) > 128)
actual_column_count = column_count - 1;
else
actual_column_count = column_count;
// Drawing vram longwords, using pairs of columns.
while(right_column <= actual_column_count)
{
for(line = c->top; line < c->bottom; line++)
{
l1 = (right_column > 0) ? p1[line] : (0);
l2 = (right_column < column_count) ? p2[line] : (0);
operator = (l1 << shift1) | (l2 >> shift2);
(c->op)(vram_offset, operator, c);
vram_offset += 4;
}
p1 += height;
p2 += height;
vram_column_offset++;
vram_offset = vram_column_offset;
right_column++;
}
}
/*
bopti_end_get()
Returns an operator for the end of a line, whose width is lower than 32
(by design: otherwise, it would have been a column). The given pointer
is read and updated so that it points to the next line at the end of
the operation.
*/
uint32_t bopti_end_get1(const unsigned char **data)
{
uint32_t operator = **data;
*data += 1;
return operator;
}
uint32_t bopti_end_get2(const unsigned char **data)
{
uint32_t operator = *((uint16_t *)*data);
*data += 2;
return operator;
}
/*
bopti_rest() -- general form
bopti_rest_nover() -- when the end does not overlap two vram longs
Draws the end of a layer, which can be considered as a whole layer
whose with is lower than 32. (Actually is it lower or equal to 16;
otherwise it would have been a column and the end would be empty.)
*/
void bopti_end_nover(const unsigned char *end, int size, command_t *c)
{
uint32_t (*get)(const unsigned char **data) =
(size == 2) ? bopti_end_get2 : bopti_end_get1;
// We *have* shift >= 0 because of this function's 'no overlap'
// requirement.
int shift = (32 - (size << 3)) - (c->x & 31);
int vram_offset = (c->y << 2) + (c->x >> 5);
uint32_t operator;
int row;
// Skipping c->top lines (because get() function only allows sequential
// access).
end += c->top * size;
for(row = c->top; row < c->bottom; row++)
{
operator = (*get)(&end);
operator <<= shift;
(c->op)(vram_offset, operator, c);
vram_offset += 4;
}
}
void bopti_end(const unsigned char *end, int size, command_t *c)
{
uint32_t (*get)(const unsigned char **data) =
(size == 2) ? (bopti_end_get2) : (bopti_end_get1);
int vram_offset = (c->y << 2) + (c->x >> 5);
uint32_t row_data;
int row;
int shift_base = (32 - (size << 3));
int shift1 = (c->x & 31) - shift_base;
int shift2 = shift_base + 32 - (c-> x & 31);
// Skipping c->top lines (because get() function only allows sequential
// access).
end += c->top * size;
for(row = c->top; row < c->bottom; row++)
{
row_data = (*get)(&end);
(c->op)(vram_offset, row_data >> shift1, c);
(c->op)(vram_offset + 1, row_data << shift2, c);
vram_offset += 4;
}
}
//---
// Wrappers and various functions.
//---
/*
bopti()
Draws a layer in the video ram.
*/
void bopti(const unsigned char *layer, structure_t *s, command_t *c)
{
const unsigned char *grid, *end;
int grid_columns, has_end;
// Skipping columns at the beginning.
grid = layer + ((c->left * s->height) << 2);
// Updating the command arguments to eliminate some information about
// parts that are not being drawn.
c->x += (c->left << 5);
c->y += c->top;
// Columns are identified by ids 0 to s->columns - 1, and the end has
// id s->columns. So the end is drawn if this last column is included.
has_end = (c->right == s->columns);
// Computing number of grid columns to draw.
grid_columns = c->right - c->left + 1 - has_end;
bopti_grid((const uint32_t *)grid, grid_columns, s->height, c);
if(has_end)
{
end = layer + ((s->columns * s->height) << 2);
c->x += (grid_columns << 5);
if((c->x & 31) + s->end_size <= 32)
bopti_end_nover(end, s->end_bytes, c);
else
bopti_end(end, s->end_bytes, c);
}
}
/*
getStructure()
Determines the image size (large images have a somehow different
structure), the data pointer and a few dimensions inside the image.
*/
void getStructure(image_t *img, structure_t *s)
{
int column_count, end, end_bytes, layer;
// Large images.
if(!img->width && !img->height)
{
s->width = img->data[0] >> 16;
s->height = img->data[0] & 0xffff;
s->data = (uint8_t *)img->data + 4;
column_count = (s->width + 31) >> 5;
end = 0;
end_bytes = 0;
}
else
{
s->width = img->width;
s->height = img->height;
s->data = (uint8_t *)img->data;
/* TODO This is the same as
column_count = (img->width + 15) >> 5;
end = (img->width & 0x0f);
end_bytes = (end + 7) >> 3;
*/
column_count = img->width >> 5;
end = img->width & 31;
end_bytes =
!end ? 0 :
end <= 8 ? 1 :
end <= 16 ? 2 :
4;
if(end_bytes == 4)
{
column_count++;
end = 0;
end_bytes = 0;
}
}
// The layer size must be rounded to a multiple of 4.
layer = s->height * ((column_count << 2) + end_bytes);
layer = (layer + 3) & ~3;
s->columns = column_count;
s->end_bytes = end_bytes;
s->end_size = end;
s->layer_size = layer;
}

View file

@ -1,73 +0,0 @@
#include <internals/bopti.h>
#include <internals/display.h>
/*
dimage_part()
Draws a portion of an image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void dimage_part(int x, int y, image_t *img, int left, int top, int width,
int height)
{
if(!img || img->magic != 0x01) return;
structure_t s;
command_t command;
int actual_width, actual_height;
int format = img->format;
if(format != format_mono && format != format_mono_alpha) return;
getStructure(img, &s);
if(width < 0) width = s.width;
if(height < 0) height = s.height;
//---
// Adjusting the bounding rectangle.
//---
// This is what happens when the bounding rectangle overflows from the
// image...
if(left < 0) left = 0;
if(top < 0) top = 0;
if(left + width > s.width) width = s.width - left;
if(top + height > s.height) height = s.height - top;
if(x + width <= 0 || x > 127 || y + height <= 0 || y > 63
|| width <= 0 || height <= 0)
return;
command.top = (y < 0) ? (top - y) : top;
actual_height = (y + height > 64) ? (64 - y) : height;
command.bottom = top + actual_height;
command.left = ((x < 0) ? (left - x) : left) >> 5;
actual_width = (x + width > 128) ? (128 - x) : width;
command.right = (left + actual_width - 1) >> 5;
command.op = bopti_op_mono;
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
else getMasks(0, actual_width + x - 1, command.masks);
bopti_vram = display_getCurrentVRAM();
for(int i = 0; format; format >>= 1, i++) if(format & 1)
{
command.x = x - left;
command.y = y - top;
command.channel = (1 << i);
bopti(s.data, &s, &command);
s.data += s.layer_size;
}
}
/*
dimage()
Displays a monochrome image in the video ram.
*/
void dimage(int x, int y, image_t *img)
{
dimage_part(x, y, img, 0, 0, -1, -1);
}

View file

@ -1,76 +0,0 @@
#include <internals/bopti.h>
#include <internals/display.h>
#include <gray.h>
/*
gimage_part()
Draws a portion of a gray image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void gimage_part(int x, int y, image_t *img, int left, int top, int width,
int height)
{
if(!img || img->magic != 0x01) return;
structure_t s;
command_t command;
int actual_width, actual_height;
int format = img->format;
getStructure(img, &s);
if(width < 0) width = s.width;
if(height < 0) height = s.height;
//---
// Adjusting the bounding rectangle.
//---
// This is what happens when the bounding rectangle overflows from the
// image...
if(left < 0) left = 0;
if(top < 0) top = 0;
if(left + width > s.width) width = s.width - left;
if(top + height > s.height) height = s.height - top;
if(x + width <= 0 || x > 127 || y + height <= 0 || y > 63
|| width <= 0 || height <= 0)
return;
// command.bottom is excluded...
command.top = (y < 0) ? (top - y) : top;
actual_height = (y + height > 64) ? (64 - y) : height;
command.bottom = top + actual_height;
// ... but command.right is included. Great.
command.left = ((x < 0) ? (left - x) : left) >> 5;
actual_width = (x + width > 128) ? (128 - x) : width;
command.right = (left + actual_width - 1) >> 5;
command.op = bopti_op_gray;
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
else getMasks(0, actual_width + x - 1, command.masks);
bopti_v1 = gray_lightVRAM();
bopti_v2 = gray_darkVRAM();
for(int i = 0; format; format >>= 1, i++) if(format & 1)
{
command.x = x - left;
command.y = y - top;
command.channel = (1 << i);
bopti(s.data, &s, &command);
s.data += s.layer_size;
}
}
/*
gimage()
Displays a gray image in the video ram.
*/
void gimage(int x, int y, image_t *img)
{
gimage_part(x, y, img, 0, 0, -1, -1);
}

View file

@ -1,272 +0,0 @@
#include <clock.h>
#include <timer.h>
#include <modules/timer.h>
#include <rtc.h>
#include <stddef.h>
#include <mpu.h>
#include <stdint.h>
static clock_config_t conf = {
.FLL = -1, .PLL = -1,
.Bphi_div1 = -1, .Iphi_div1 = -1, .Pphi_div1 = -1,
.CKIO_f = -1,
.Bphi_f = -1, .Iphi_f = -1, .Pphi_f = -1
};
/*
clock_setting()
Returns the P_phi / 4 timer setting that will last for the given time.
Several units can be used. Be aware that the result is approximate, and
very high frequencies or very short delays will yield important errors.
*/
uint32_t clock_setting(int duration, clock_unit_t unit)
{
if(conf.Pphi_f <= 0) return 0xffffffff;
uint64_t f = conf.Pphi_f >> 2;
uint64_t result;
switch(unit)
{
case clock_us:
result = (duration * f) / 1000000;
break;
case clock_ms:
result = (duration * f) / 1000;
break;
case clock_s:
result = (duration * f);
break;
case clock_Hz:
result = f / duration;
break;
case clock_kHz:
result = f / (duration * 1000);
break;
case clock_MHz:
result = f / (duration * 1000000);
break;
default:
return -1;
}
return (result > 0xffffffff) ? (0xffffffff) : (result);
}
/*
clock_config()
Returns a copy of the clock configuration.
*/
clock_config_t clock_config(void)
{
return conf;
}
/*
sleep()
Sleeps until an interrupt is accepted.
*/
void sleep(void)
{
__asm__(
"sleep"
);
}
static void sleep_callback(void *arg)
{
int *flag = arg;
*flag = 1;
}
/*
sleep_ms()
Sleeps for the given number of milliseconds using a virtual timer.
*/
void sleep_ms(int ms_delay)
{
volatile int sleep_done = 0;
timer_t *timer = timer_create(ms_delay, 1);
timer_attach(timer, sleep_callback, (void *)&sleep_done);
timer_start(timer);
while(!sleep_done) sleep();
}
/*
sleep_us()
Sleeps for the given number of microseconds using the hardware timer
timer_user.
*/
void sleep_us(int us_delay)
{
volatile int sleep_done = 0;
const uint32_t constant = clock_setting(us_delay, clock_us);
timer_t *timer = htimer_setup(timer_user, constant, timer_Po_4, 1);
timer_attach(timer, sleep_callback, (void *)&sleep_done);
timer_start(timer);
while(!sleep_done) sleep();
}
//---
// Clock frequency measurements -- Public API.
//---
// Indicates whether the measurements are finished.
static volatile int clock_measure_done = 0;
// Once again SH7705 and SH7305 need different methods...
static timer_t *htimer_7705 = NULL;
static int cb_id_7705 = -1;
static void clock_measure_7705(void);
static void clock_compute_7305(void);
/*
clock_measure()
Begins the frequency measurements. The measurements will end
automatically. While doing measurements, do not use the RTC interrupt
or the user timer.
Call clock_measure_end() to wait until the measurements are finished.
It is possible to execute code during the measurements, so that less
time is spent.
*/
void clock_measure(void)
{
// On SH7705 we cannot have the value of CKIO simply, so we measure
// P_phi using a timer/RTC combination, and we deduce CKIO.
if(isSH3())
{
htimer_7705 = htimer_setup(timer_user, 0xffffffff, timer_Po_4,
1);
cb_id_7705 = rtc_cb_add(rtc_freq_256Hz, clock_measure_7705, 0);
}
// On SH7305, assuming clock mode 3, we can compute the clock
// frequencies because we know that RTC_CLK oscillates at 32768 Hz.
else
{
clock_compute_7305();
clock_measure_done = 1;
}
}
/*
clock_measure_end()
Waits until the measurements are finished. This may be immediate.
*/
void clock_measure_end(void)
{
while(!clock_measure_done) sleep();
}
//---
// Clock frequency measurements -- SH7305.
//---
/*
clock_compute_7305()
Computes the clock frequencies according to the CPG parameters.
*/
static void clock_compute_7305(void)
{
volatile unsigned int *FRQCRA = (void *)0xa4150000;
volatile unsigned int *PLLCR = (void *)0xa4150024;
volatile unsigned int *FLLFRQ = (void *)0xa4150050;
// Surely the documentation of SH7724 does not meet the specification
// of SH7305 for the PLL setting, because the register accepts other
// values than the ones specified for SH7724. The relation given by
// Sentaro21 (thanks again!) yields good results.
int pll = (*FRQCRA >> 24) & 0x3f; // Raw setting
pll = pll + 1; // Resulting multiplier
conf.PLL = pll;
// This one is simpler. The FLL ratio is actually the setting value.
int fll = *FLLFRQ & 0x7ff; // Raw setting = multiplier
if(*FLLFRQ & (1 << 14)) fll >>= 1; // Halve-output flag
conf.FLL = fll;
// The divider1 ratios are NOT those of SH7724. The relation between
// the values below and the divider ratios is given by Sentaro21
// (thanks to him!) and satisfies ratio = 1 / (2 ** (setting + 1)).
int div1_bphi = (*FRQCRA >> 8) & 0xf;
int div1_iphi = (*FRQCRA >> 20) & 0xf;
int div1_pphi = (*FRQCRA ) & 0xf;
conf.Bphi_div1 = 1 << (div1_bphi + 1);
conf.Iphi_div1 = 1 << (div1_iphi + 1);
conf.Pphi_div1 = 1 << (div1_pphi + 1);
// Computing the frequency of the signal, which is input to divider 1.
int base = 32768;
if(*PLLCR & (1 << 12)) base *= fll;
if(*PLLCR & (1 << 14)) base *= pll;
conf.RTCCLK_f = 32768;
conf.Bphi_f = base >> (div1_bphi + 1);
conf.Iphi_f = base >> (div1_iphi + 1);
conf.Pphi_f = base >> (div1_pphi + 1);
}
//---
// Clock frequency measurements -- SH7705.
//---
/*
clock_measure_7705_finalize()
Given the number of P_phi / 4 timer ticks elapsed between two RTC
256 Hz interrupts, determines the clock configuration.
*/
static void clock_measure_7705_finalize(uint32_t elapsed)
{
volatile unsigned int *FRQCR = (void *)0xffffff80;
conf.Pphi_f = elapsed * 4 * 256;
if(conf.Pphi_f <= 0) return;
conf.PLL1 = ((*FRQCR >> 8) & 0x03) + 1;
conf.PLL2 = -1;
conf.Bphi_div1 = 0;
conf.Iphi_div1 = ((*FRQCR >> 4) & 0x03) + 1;
conf.Pphi_div1 = ((*FRQCR ) & 0x03) + 1;
conf.CKIO_f = (conf.Pphi_f * conf.Pphi_div1) / conf.PLL1;
conf.Bphi_f = conf.CKIO_f;
conf.Iphi_f = (conf.CKIO_f * conf.PLL1) / conf.Iphi_div1;
}
/*
clock_measure_7705_callback()
Starts measurements. Measurements will end automatically. Do not use
RTC interrupt or the user timer will doing measurements.
Call clock_measure_end() when you need to use those, to ensure
measurements are finished.
*/
static void clock_measure_7705_callback(void)
{
timer_stop(htimer_7705);
rtc_cb_end(cb_id_7705);
uint32_t elapsed = 0xffffffff - TMU.timers[timer_user]->TCNT;
clock_measure_7705_finalize(elapsed);
clock_measure_done = 1;
}
/*
clock_measure_7705()
Programs the clock measurements. We need to have the user timer and the
RTC synchronized for this operation, so we wait for an RTC interrupt
and we prepare the timer beforehand to avoid losing processor time in
configuring the registers.
*/
static void clock_measure_7705(void)
{
timer_start(htimer_7705);
rtc_cb_edit(cb_id_7705, rtc_freq_256Hz, clock_measure_7705_callback);
}

View file

@ -1,172 +0,0 @@
#include <internals/exceptions.h>
#include <display.h>
#include <string.h>
//---
// On-screen error messages
//---
#define print(x, y, str) dtext(6 * (x) - 5, 8 * (y) - 7, str)
static void print_hex(int x, int y, uint32_t n, int digits)
{
#define hexdigit(n) ((n) + '0' + 39 * ((n) > 9))
char str[9];
if(digits >= 8) digits = 8;
str[digits] = 0;
while(digits)
{
str[digits - 1] = hexdigit(n & 0xf);
n >>= 4;
digits--;
}
print(x, y, str);
#undef hexdigit
}
static void show_error(const char *name, uint32_t *access_mode, uint32_t *tea,
uint32_t *opcode)
{
uint32_t *vram = display_getCurrentVRAM();
uint32_t spc, ssr;
__asm__("stc spc, %0" : "=r"(spc));
__asm__("stc ssr, %0" : "=r"(ssr));
dclear();
text_configure(NULL, color_black);
print(3, 1, "EXCEPTION RAISED!");
for(int i = 0; i < 36; i++) vram[i] = ~vram[i];
print(1 + ((21 - strlen(name)) >> 1), 2, name);
print(4, 4, "PC");
print_hex(7, 4, spc, 8);
print(4, 5, "SR");
print_hex(7, 5, ssr, 8);
int y = 6;
if(access_mode)
{
print(2, y, "Type");
print(7, y++, *access_mode == 1 ? "Code/Data read" :
"Data write");
}
if(tea)
{
print(3, y, "TEA");
print_hex(7, y++, *tea, 8);
}
if(opcode)
{
print(2, y, "Code");
print_hex(7, y++, *opcode, 4);
}
dupdate();
while(1);
}
#undef print
//---
// Exception handlers
//---
#pragma GCC diagnostic ignored "-Wunused-parameter"
/*
exch_address_error()
CPU address error, e.g. alignment issues.
*/
void exch_address_error(uint32_t pc, uint32_t tea, uint32_t access)
{
show_error("Address error", &access, &tea, NULL);
}
/*
exch_tlb_protection_violation()
You don't have the right to access this address.
*/
void exch_tlb_protection_violation(uint32_t pc, uint32_t tea, uint32_t access)
{
show_error("TLB protection", &access, &tea, NULL);
}
/*
exch_tlb_invalid()
The translation info for this address is marked as invalid.
*/
void exch_tlb_invalid(uint32_t pc, uint32_t tea, uint32_t access)
{
show_error("TLB invalid", &access, &tea, NULL);
}
/*
exch_illegal_instruction()
What's this opcode anyway?
*/
void exch_illegal_instruction(uint32_t pc, uint32_t opcode)
{
show_error("Illegal instruction", NULL, NULL, &opcode);
}
/*
exch_illegal_slot()
You can't execute this in a delay slot.
*/
void exch_illegal_slot(uint32_t pc, uint32_t opcode)
{
show_error("Illegal slot", NULL, NULL, &opcode);
}
/*
exch_user_break()
One of the user break conditions you requested was fulfilled.
*/
void exch_user_break(void)
{
show_error("User break", NULL, NULL, NULL);
}
/*
exch_initial_page_write()
You can't write to this memory page, it's too early.
*/
void exch_initial_page_write(void)
{
show_error("Initial page write", NULL, NULL, NULL);
}
/*
exch_trap()
You asked for it.
*/
void exch_trap(uint32_t pc, uint32_t trap)
{
}
/*
exch_dma_address()
The DMAC is accessing badly-aligned addresses.
*/
void exch_dma_address(void)
{
show_error("DMA address error", NULL, NULL, NULL);
}
/*
exch_tlb_miss()
This virtual address points nowhere.
*/
void exch_tlb_miss(uint32_t pc, uint32_t tea, uint32_t access)
{
show_error("TLB miss", &access, &tea, NULL);
}
#pragma GCC diagnostic pop

View file

@ -1,180 +0,0 @@
#include <internals/gint.h>
#include <internals/interrupt_maps.h>
#include <internals/exceptions.h>
#include <internals/interrupts.h>
#include <gint.h>
#include <mpu.h>
// Referencing the interrupt handlers to force ld to link them in (there should
// be a better way of achieving this, but I can't seem to find it).
__attribute__((used)) static void (*_exc)(void) = &gint_exc;
__attribute__((used)) static void (*_tlb)(void) = &gint_tlb;
__attribute__((used)) static void (*_int)(void) = &gint_int;
//---
// Exception and interrupt handlers
//---
gint_interrupt_handler_t gint_handlers[] = {
//---
// Resets and non-events
//---
{ NULL, NULL, 0, { 0x00, 0x00, 0x00 } },
//---
// General exceptions
//---
// Address error.
{ NULL, exch_address_error, 0,
{ arg_pc, arg_tea, arg_subtype } },
// TLB protection violation.
{ NULL, exch_tlb_protection_violation, 0,
{ arg_pc, arg_tea, arg_subtype } },
// TLB Invalid (SH7705 only).
{ NULL, exch_tlb_invalid, 0,
{ arg_pc, arg_tea, arg_subtype } },
// Illegal instruction.
{ NULL, exch_illegal_instruction, 0,
{ arg_pc, arg_opcode, 0x00 } },
// Illegal opcode.
{ NULL, exch_illegal_slot, 0,
{ arg_pc, arg_opcode, 0x00 } },
// User break.
{ NULL, exch_user_break, 0,
{ 0x00, 0x00, 0x00 } },
// Initial page write.
{ NULL, exch_initial_page_write, 0,
{ 0x00, 0x00, 0x00 } },
// Unconditional trap.
{ NULL, exch_trap, 0,
{ arg_pc, arg_trap, 0x00 } },
// DMA address error.
{ NULL, exch_dma_address, 0,
{ 0x00, 0x00, 0x00 } },
//---
// TLB misses
//---
{ NULL, exch_tlb_miss,
0, { arg_pc, arg_tea, arg_subtype } },
//---
// Interrupt requests
//---
// Non-Maskable Interrupt.
{ NULL, NULL, 0,
{ 0x00, 0x00, 0x00 } },
// Timer underflow.
{ NULL, inth_timer_underflow, 12,
{ arg_subtype, 0x00, 0x00 } },
// Timer channel 2 input capture (SH7705 only)
{ NULL, NULL, 0,
{ arg_timer_capt, 0x00, 0x00 } },
// Real-time clock alarm interrupt.
{ NULL, NULL, 0,
{ 0x00, 0x00, 0x00 } },
// Real-time clock periodic interrupt.
{ NULL, inth_rtc_periodic, 10,
{ 0x00, 0x00, 0x00 } },
// Real-time clock carry interrupt.
{ NULL, NULL, 0,
{ 0x00, 0x00, 0x00 } },
};
/*
gint_invoke()
Invokes an interrupt or exception handler, given its type and subtype.
*/
void gint_invoke(uint8_t type, uint8_t subtype)
{
if(type >= exc_type_max || !gint_handlers[type].function) return;
volatile uint32_t *tea, *tra, *tcpr_2;
uint32_t args[3];
uint16_t *pc;
// Getting some initial information to work with.
__asm__("stc spc, %0" : "=r"(pc));
tea = gint_reg(register_tea);
tra = gint_reg(register_tra);
tcpr_2 = (void *)0xfffffeb8; /* SH7705 only */
// Building up the argument list.
for(int i = 0; i < 3; i++) switch(gint_handlers[type].args[i])
{
case arg_none: args[i] = 0; break;
case arg_subtype: args[i] = subtype; break;
case arg_pc: args[i] = (uint32_t)pc; break;
case arg_opcode: args[i] = *pc; break;
case arg_tea: args[i] = *tea; break;
case arg_trap: args[i] = *tra >> 2; break;
case arg_timer_capt: args[i] = *tcpr_2; break;
}
// Calling the function with the required amount of arguments.
if(gint_handlers[type].args[2])
{
void (*handler)(uint32_t, uint32_t, uint32_t);
handler = gint_handlers[type].function;
(*handler)(args[0], args[1], args[2]);
}
else if(gint_handlers[type].args[1])
{
void (*handler)(uint32_t, uint32_t);
handler = gint_handlers[type].function;
(*handler)(args[0], args[1]);
}
else if(gint_handlers[type].args[0])
{
void (*handler)(uint32_t);
handler = gint_handlers[type].function;
(*handler)(args[0]);
}
else (*(void (*)(void))gint_handlers[type].function)();
}
/*
gint_install()
Installs an exception or interrupt handler for one of gint's recognized
interrupts.
*/
void gint_install(gint_interrupt_type_t type, void *function)
{
if((unsigned)type >= exc_type_max) return;
gint_handlers[type].function = function;
}
/*
gint_uninstall()
Un-installs the exception or interrupt handler that was used for the
given interrupt, falling back to gint's default handler.
*/
void gint_uninstall(gint_interrupt_type_t type)
{
if((unsigned)type >= exc_type_max) return;
gint_handlers[type].function = gint_handlers[type].default_function;
}
//---
// Register access
//---
/*
gint_reg()
Returns the address of a common register. All common registers exist
on both platforms but they may hold different values for the same
information.
*/
volatile void *gint_reg(gint_register_t reg)
{
return isSH3() ? gint_reg_7705(reg) : gint_reg_7305(reg);
}

View file

@ -1,136 +0,0 @@
#include <internals/gint.h>
#include <modules/timer.h>
#include <modules/rtc.h>
#include <gint.h>
#include <timer.h>
#include <7305.h>
#include <rtc.h>
/*
gint_reg()
Returns the address of a common register. All common registers exist
on both platforms but they may hold different values for the same
information (f.i. EXPEVT may not return the same value for a given
exception on both 7705 and 7305).
*/
volatile void *gint_reg_7305(gint_register_t reg)
{
switch(reg)
{
case register_tea: return (void *)0xff00000c;
case register_mmucr: return (void *)0xff000010;
case register_tra: return (void *)0xff000020;
case register_expevt: return (void *)0xff000024;
case register_intevt: return (void *)0xff000028;
default: return NULL;
}
}
//---
// Register saves, setup, interrupt locks, register restoration.
//---
void gint_save_7305(environment_7305_t *e)
{
// Saving interrupt priorities.
e->IPR[0] = INTX.IPRA.WORD;
e->IPR[1] = INTX.IPRB.WORD;
e->IPR[2] = INTX.IPRC.WORD;
e->IPR[3] = INTX.IPRD.WORD;
e->IPR[4] = INTX.IPRE.WORD;
e->IPR[5] = INTX.IPRF.WORD;
e->IPR[6] = INTX.IPRG.WORD;
e->IPR[7] = INTX.IPRH.WORD;
e->IPR[8] = INTX.IPRI.WORD;
e->IPR[9] = INTX.IPRJ.WORD;
e->IPR[10] = INTX.IPRK.WORD;
e->IPR[11] = INTX.IPRL.WORD;
// Saving RTC registers.
e->RCR1 = RTC.RCR1->byte;
e->RCR2 = RTC.RCR2->byte;
// Saving TMU registers.
e->TMU0 = *(TMU.timers[0]);
e->TMU1 = *(TMU.timers[1]);
e->TMU2 = *(TMU.timers[2]);
e->TSTR = TMU.TSTR->byte;
// Saving port data used to access the keyboard.
e->PMCR = *((volatile uint16_t *)0xa4050116);
e->PMDR = *((volatile uint8_t *)0xa4050136);
e->PNCR = *((volatile uint16_t *)0xa4050118);
e->PNDR = *((volatile uint8_t *)0xa4050138);
e->PZCR = *((volatile uint16_t *)0xa405014c);
e->PZDR = *((volatile uint8_t *)0xa405016c);
e->key = *((volatile uint8_t *)0xa40501c6);
}
void gint_lock_and_setup_7305(void)
{
// Disabling everything by default to avoid freezing on non-handled
// 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;
// Allowing RTC and timer to schedule automatic tasks such as keyboard
// analysis.
INTX.IPRK._RTC = 10;
INTX.IPRA.TMU0_0 = 12;
INTX.IPRA.TMU0_1 = 12;
INTX.IPRA.TMU0_2 = 12;
// Don't enable the RTC interrupt by default.
RTC.RCR2->byte = 0x09;
}
void gint_restore_and_unlock_7305(environment_7305_t *e)
{
// Restoring the interrupt priorities.
INTX.IPRA.WORD = e->IPR[0];
INTX.IPRB.WORD = e->IPR[1];
INTX.IPRC.WORD = e->IPR[2];
INTX.IPRD.WORD = e->IPR[3];
INTX.IPRE.WORD = e->IPR[4];
INTX.IPRF.WORD = e->IPR[5];
INTX.IPRG.WORD = e->IPR[6];
INTX.IPRH.WORD = e->IPR[7];
INTX.IPRI.WORD = e->IPR[8];
INTX.IPRJ.WORD = e->IPR[9];
INTX.IPRK.WORD = e->IPR[10];
INTX.IPRL.WORD = e->IPR[11];
// Restoring RTC registers.
RTC.RCR1->byte = e->RCR1;
RTC.RCR2->byte = e->RCR2;
// Restoring TMU registers.
*(TMU.timers[0]) = e->TMU0;
*(TMU.timers[1]) = e->TMU1;
*(TMU.timers[2]) = e->TMU2;
TMU.TSTR->byte = e->TSTR;
// Restoring keyboard-related I/O port registers. However the backlight
// pin is in PNDR and we would like the backlight to persist when we
// leave the application, so we just keep this bit.
*((volatile uint16_t *)0xa4050116) = e->PMCR;
*((volatile uint8_t *)0xa4050136) = e->PMDR;
*((volatile uint16_t *)0xa4050118) = e->PNCR;
*((volatile uint8_t *)0xa4050138) &= 0x10;
*((volatile uint8_t *)0xa4050138) |= (e->PNDR & ~0x10);
*((volatile uint16_t *)0xa405014c) = e->PZCR;
*((volatile uint8_t *)0xa405016c) = e->PZDR;
*((volatile uint8_t *)0xa40501c6) = e->key;
}

View file

@ -1,130 +0,0 @@
#include <internals/gint.h>
#include <modules/rtc.h>
#include <modules/interrupts.h>
#include <gint.h>
#include <timer.h>
#include <rtc.h>
/*
gint_reg()
Returns the address of a common register. All common registers exist
on both platforms but they may hold different values for the same
information (f.i. EXPEVT may not return the same value for a given
exception on both 7705 and 7305).
*/
volatile void *gint_reg_7705(gint_register_t reg)
{
switch(reg)
{
case register_intevt: return (void *)0xa4000000;
case register_tra: return (void *)0xffffffd0;
case register_expevt: return (void *)0xffffffd4;
case register_mmucr: return (void *)0xfffffff4;
case register_tea: return (void *)0xfffffffc;
default: return NULL;
}
}
//---
// Register saves, setup, interrupt locks, register restoration.
//---
void gint_save_7705(environment_7705_t *e)
{
mod_intc_7705_t *intc = &INTC._7705;
mod_intc_ipc_7705_t *ipc = &intc->iprs;
// Saving the interrupt masks from registers IPRA to IPRH.
e->IPR[0] = ipc->IPRA->word;
e->IPR[1] = ipc->IPRB->word;
e->IPR[2] = ipc->IPRC->word;
e->IPR[3] = ipc->IPRD->word;
e->IPR[4] = ipc->IPRE->word;
e->IPR[5] = ipc->IPRF->word;
e->IPR[6] = ipc->IPRG->word;
e->IPR[7] = ipc->IPRH->word;
// Saving RTC registers.
e->RCR1 = RTC.RCR1->byte;
e->RCR2 = RTC.RCR2->byte;
// Saving TMU registers.
e->TMU0 = *(TMU.timers[0]);
e->TMU1 = *(TMU.timers[1]);
e->TMU2 = *(TMU.timers[2]);
e->TSTR = TMU.TSTR->byte;
/* // Saving port data used to access the keyboard.
e->PACR = PFC.PACR.WORD;
e->PADR = PA.DR.BYTE;
e->PBCR = PFC.PBCR.WORD;
e->PBDR = PB.DR.BYTE;
e->PMCR = PFC.PMCR.WORD;
e->PMDR = PM.DR.BYTE;
*/
}
void gint_lock_and_setup_7705(void)
{
mod_intc_7705_t *intc = &INTC._7705;
mod_intc_ipc_7705_t *ipc = &intc->iprs;
// Disabling everything by default to avoid receiving an interrupt that
// the handler doesn't handle, which would cause the user program to
// freeze.
ipc->IPRA->word = 0x0000;
ipc->IPRB->word = 0x0000;
ipc->IPRC->word = 0x0000;
ipc->IPRD->word = 0x0000;
ipc->IPRE->word = 0x0000;
ipc->IPRF->word = 0x0000;
ipc->IPRG->word = 0x0000;
ipc->IPRH->word = 0x0000;
// Allowing RTC and timer (which handles keyboard and a whole bunch of
// other things).
ipc->IPRA->RTC = 10;
ipc->IPRA->TMU0 = 12;
ipc->IPRA->TMU1 = 12;
ipc->IPRA->TMU2 = 12;
// Don't enable RTC periodic signals by default.
RTC.RCR2->byte = 0x09;
}
void gint_restore_and_unlock_7705(environment_7705_t *e)
{
mod_intc_7705_t *intc = &INTC._7705;
mod_intc_ipc_7705_t *ipc = &intc->iprs;
// Restoring the saved states.
ipc->IPRA->word = e->IPR[0];
ipc->IPRB->word = e->IPR[1];
ipc->IPRC->word = e->IPR[2];
ipc->IPRD->word = e->IPR[3];
ipc->IPRE->word = e->IPR[4];
ipc->IPRF->word = e->IPR[5];
ipc->IPRG->word = e->IPR[6];
ipc->IPRH->word = e->IPR[7];
// Restoring RTC registers.
RTC.RCR1->byte = e->RCR1;
RTC.RCR2->byte = e->RCR2;
// Restoring TMU registers.
*(TMU.timers[0]) = e->TMU0;
*(TMU.timers[1]) = e->TMU1;
*(TMU.timers[2]) = e->TMU2;
TMU.TSTR->byte = e->TSTR;
/* // Restoring keyboard-related I/O port registers.
PFC.PACR.WORD = e->PACR;
PA.DR.BYTE = e->PADR;
PFC.PBCR.WORD = e->PBCR;
PB.DR.BYTE = e->PBDR;
PFC.PMCR.WORD = e->PMCR;
PM.DR.BYTE = e->PMDR;
*/
}

View file

@ -1,66 +0,0 @@
/*
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.
*/
_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.
*/
_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
/* Enabling 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)

View file

@ -1,130 +0,0 @@
#include <internals/gint.h>
#include <internals/interrupt_maps.h>
#include <internals/modules.h>
#include <gint.h>
#include <mpu.h>
gint_info_t gint;
static environment_t env;
//---
// Initialization routines
//---
/*
gint_init()
Initializes gint. Loads the interrupt handler into the memory and sets
the new vbr address.
*/
static void setup(void)
{
isSH3() ? gint_lock_and_setup_7705()
: gint_lock_and_setup_7305();
}
void gint_init(mpu_t mpu)
{
// Setting the MPU type. I don't like const-casting but this is still
// better than allowing the user to change the variable by mistake.
*((mpu_t *)&MPU_CURRENT) = mpu;
// Loading the register addresses of the current platform.
mod_init();
// Linker script symbols -- gint.
extern uint32_t
gint_vbr,
gint_data,
bgint, egint;
uint32_t *ptr = &bgint;
uint32_t *src = &gint_data;
// Loading the interrupt handler into the memory.
while(ptr < &egint) *ptr++ = *src++;
isSH3() ? gint_save_7705(&env.env_7705)
: gint_save_7305(&env.env_7305);
// Installing gint's default exception/interrupt handlers.
for(int i = 0; i < exc_type_max; i++)
{
gint_handlers[i].function = gint_handlers[i].default_function;
}
// Filling the information structure for the user.
gint.vbr = gint_getvbr;
gint.system_vbr = gint_getvbr();
gint.gint_vbr = (uint32_t)&gint_vbr;
// Setting the VBR!
gint_setvbr(gint.gint_vbr, setup);
}
//---
// Context restoration routines
//---
/*
gint_quit()
Stops gint. Restores the system's configuration and vbr address.
*/
static void stop(void)
{
isSH3() ? gint_restore_and_unlock_7705(&env.env_7705)
: gint_restore_and_unlock_7305(&env.env_7305);
}
void gint_quit(void)
{
// Restoring the system's VBR.
gint_setvbr(gint.system_vbr, stop);
}
//---
// System-switch technique
//---
#include <display.h>
#include <gray.h>
/*
__system_menu()
Updates the system's vram and triggers the calculator's main menu.
*/
void __system_menu(void *vram);
// Stores gint's configuration while the user visits the main menu.
static environment_t switch_env;
/*
gint_switch()
Temporarily returns to the system's main menu.
*/
static void restore(void)
{
isSH3() ? gint_restore_and_unlock_7705(&switch_env.env_7705)
: gint_restore_and_unlock_7305(&switch_env.env_7305);
}
void gint_switch(void)
{
isSH3() ? gint_save_7705(&switch_env.env_7705)
: gint_save_7305(&switch_env.env_7305);
gint_setvbr(gint.system_vbr, stop);
// When returning to the add-in from the menu, the system displays the
// add-in's video ram again, but it's often blank. We thus need to copy
// the contents of the gint video ram to the system's.
void *vram = gray_runs()
? gray_currentVRAM()
: display_getCurrentVRAM();
// Use system calls to put KEY_MENU in the key buffer and invoke
// GetKeyWait(), triggering the main menu.
__system_menu(vram);
// If the user came back, restore the gint working environment.
gint_setvbr(gint.gint_vbr, restore);
}

View file

@ -1,53 +0,0 @@
#include <internals/interrupt_maps.h>
#include <stddef.h>
//---
// Mapping hardware interrupts info to gint interrupts -- 7305 interrupts
//---
#define NO_EVENT (gint_interrupt_map_t){ .type = 0, .subtype = 0 }
static gint_interrupt_map_t map0[16] = {
{ exc_poweron_reset, 0 }, { exc_manual_reset, 0 },
{ exc_tlb_miss, 1 }, { exc_tlb_miss, 2 },
{ exc_initial_page_write, 0 }, { exc_tlb_protection_violation, 1 },
{ exc_tlb_protection_violation, 2 }, { exc_address_error, 1 },
};
static gint_interrupt_map_t map1[16] = {
{ exc_address_error, 2 }, NO_EVENT, /* FPU exception */
{ exc_tlb_multihit, 0 }, { exc_trap, 0 },
{ exc_illegal_instruction, 0 }, { exc_illegal_slot, 0 },
{ int_nmi, 0 }, { exc_user_break, 0 },
};
static gint_interrupt_map_t map4[16] = {
{ int_timer_underflow, 0 }, { int_timer_underflow, 1 },
{ int_timer_underflow, 2 }, NO_EVENT,
NO_EVENT, NO_EVENT,
NO_EVENT, NO_EVENT, /* SDHI1 [SDHII0] */
};
static gint_interrupt_map_t mapa[16] = {
NO_EVENT, NO_EVENT, /* USB0 [USI0] */
NO_EVENT, /* USB0 [USI1] */ NO_EVENT,
{ int_rtc_alarm, 0 }, { int_rtc_periodic, 0 },
{ int_rtc_carry, 0 }, NO_EVENT,
};
static gint_interrupt_map_t *map[16] = {
map0, map1, NULL, NULL, map4, NULL, NULL, NULL,
NULL, NULL, mapa, NULL, NULL, NULL, NULL, NULL,
};
/*
gint_map()
Maps an event code to an exception/interrupt type and subtype.
*/
gint_interrupt_map_t gint_map_7305(uint32_t event_code)
{
int ctgy = event_code >> 8;
int event = (event_code & 0xff) >> 5;
return map[ctgy] ? map[ctgy][event] : NO_EVENT;
}

View file

@ -1,65 +0,0 @@
#include <internals/interrupt_maps.h>
#include <stddef.h>
//---
// Mapping hardware interrupt info to gint interrupts -- 7705 interrupts
//---
#define NO_EVENT (gint_interrupt_map_t){ .type = 0, .subtype = 0 }
static gint_interrupt_map_t map0[16] = {
NO_EVENT, { exc_manual_reset, 0 },
{ exc_tlb_invalid, 1 }, { exc_tlb_invalid, 2 },
{ exc_initial_page_write, 0 }, { exc_tlb_protection_violation, 1 },
{ exc_tlb_protection_violation, 2 }, { exc_address_error, 1 },
};
static gint_interrupt_map_t map1[16] = {
{ exc_address_error, 2 }, NO_EVENT,
NO_EVENT, { exc_trap, 0 },
{ exc_illegal_instruction, 0 }, { exc_illegal_slot, 0 },
{ int_nmi, 0 }, { exc_user_break, 0 },
};
static gint_interrupt_map_t map4[16] = {
{ int_timer_underflow, 0 }, { int_timer_underflow, 1 },
{ int_timer_underflow, 2 }, { int_timer_input_capture, 0 },
{ int_rtc_alarm, 0 }, { int_rtc_periodic, 0 },
{ int_rtc_carry, 0 }, NO_EVENT,
};
static gint_interrupt_map_t *map[16] = {
map0, map1, NULL, NULL, map4, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
/*
gint_map()
Maps an event code and a VBR offset to an exception/interrupt type and
subtype.
*/
gint_interrupt_map_t gint_map_7705(uint32_t event_code, uint32_t offset)
{
// Handling TLB misses (only two events).
if(offset == 0x400) switch(event_code)
{
case 0x040:
return (gint_interrupt_map_t) {
.type = exc_tlb_miss,
.subtype = 1,
};
case 0x060:
return (gint_interrupt_map_t) {
.type = exc_tlb_miss,
.subtype = 2,
};
default:
return NO_EVENT;
}
// Handling general exceptions and interrupts.
int ctgy = event_code >> 8;
int event = (event_code & 0xff) >> 5;
return map[ctgy] ? map[ctgy][event] : NO_EVENT;
}

View file

@ -1,21 +0,0 @@
#include <internals/interrupts.h>
#include <internals/timer.h>
#include <internals/rtc.h>
/*
inth_timer_underflow()
Wake up, your timer has expired!
*/
void inth_timer_underflow(uint32_t channel)
{
timer_interrupt(channel);
}
/*
inth_rtc_periodic()
Don't you forget to execute the periodic tasks.
*/
void inth_rtc_periodic(void)
{
rtc_periodic_interrupt();
}

View file

@ -1,91 +0,0 @@
#include <modules/timer.h>
#include <modules/rtc.h>
#include <modules/interrupts.h>
#include <stddef.h>
#include <mpu.h>
//---
// Structure information
// Here resides most of the platform-dependent register configuration.
// Module structures are arranged to mask as much as possible hardware
// differences to the user. When it becomes impossible to do so at
// compile-time, gint provides functions to ensure that the user does not
// confront to the hardware directly.
//---
mod_tmu_t TMU;
mod_rtc_t RTC;
mod_intc_t INTC;
//---
// Initializer
//---
static void mod_init_7705(void)
{
INTC._7705.iprs.IPRA = (void *)0xfffffee2;
INTC._7705.iprs.IPRB = (void *)0xfffffee4;
INTC._7705.iprs.IPRC = (void *)0xa4000016;
INTC._7705.iprs.IPRD = (void *)0xa4000018;
INTC._7705.iprs.IPRE = (void *)0xa400001a;
INTC._7705.iprs.IPRF = (void *)0xa4080000;
INTC._7705.iprs.IPRG = (void *)0xa4080002;
INTC._7705.iprs.IPRH = (void *)0xa4080004;
INTC._7705.ICR0 = (void *)0xfffffee0;
INTC._7705.ICR1 = (void *)0xa4000010;
INTC._7705.ICR2 = (void *)0xa4000012;
INTC._7705.PINTER = (void *)0xa4000014;
INTC._7705.IRR0 = (void *)0xa4000004;
INTC._7705.IRR1 = (void *)0xa4000006;
INTC._7705.IRR2 = (void *)0xa4000008;
TMU.timers[0] = (void *)0xfffffe94;
TMU.timers[1] = (void *)0xfffffea0;
TMU.timers[2] = (void *)0xfffffeac;
TMU.TSTR = (void *)0xfffffe92;
TMU.TCPR2 = (void *)0xfffffeb8;
RTC.RCR1 = (void *)0xfffffedc;
RTC.RCR2 = (void *)0xfffffede;
RTC.time = (void *)0xfffffec0;
}
static void mod_init_7305(void)
{
INTC._7305.ICR0 = (void *)0xa4140000;
INTC._7305.ICR1 = (void *)0xa414001c;
INTC._7305.INTPRI00 = (void *)0xa4140010;
INTC._7305.iprs = (void *)0xa4080000;
INTC._7305.INTMSK00 = (void *)0xa4140044;
INTC._7305.masks = (void *)0xa4080080;
INTC._7305.INTMSKCLR00 = (void *)0xa4140064;
INTC._7305.masks_clear = (void *)0xa40800c0;
INTC._7305.INTREQ00 = (void *)0xa4140024;
INTC._7305.USERIMASK = (void *)0xa4700000;
INTC._7305.NMIFCR = (void *)0xa41400c0;
TMU.timers[0] = (void *)0xa4490008;
TMU.timers[1] = (void *)0xa4490014;
TMU.timers[2] = (void *)0xa4490020;
TMU.TSTR = (void *)0xa4490004;
TMU.TCPR2 = NULL;
RTC.RCR1 = (void *)0xa413fedc;
RTC.RCR2 = (void *)0xa413fede;
RTC.time = (void *)0xa413fec0;
}
/*
mod_init()
Initializes the module data to make register access cross-platform. The
MPU needs to have been detected or this function will yield wrong
results.
*/
void mod_init(void)
{
isSH3() ? mod_init_7705() : mod_init_7305();
}

View file

@ -1,70 +0,0 @@
//---
//
// gint core module: mpu
//
// Determines which kind of MPU is running the program.
//
//---
#include <mpu.h>
#include <stdint.h>
/* Located in gint's uninitialized bss section */
__attribute__((section(".gint.bss"))) const mpu_t MPU_CURRENT;
/*
getMPU()
Returns the MPU identifier of the calculator.
Thanks to SimonLothar for this function and related information.
Processor version register (PVR) and product control register (PRR)
hold information about the MPU version, they but are only accessible on
SH-4-based MPUs.
To detect SH-3-based MPUs, 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.
*/
mpu_t getMPU(void)
{
// Processor version register.
volatile uint32_t *pvr = (void *)0xff000030;
// Product version register.
volatile uint32_t *prr = (void *)0xff000044;
// Port L control register.
volatile uint16_t *plcr = (void *)0xa4000114;
// Saved value for PLCR.
uint16_t saved_plcr;
uint16_t 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 the three upper bytes of the processor version register to
// 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, just for reference.
switch(*prr & 0xfffffff0)
{
case 0x00002c00:
return mpu_sh7305;
case 0x00002200:
return mpu_sh7724;
}
// By default, the MPU is unknown.
return mpu_unknown;
}

View file

@ -1,198 +0,0 @@
/*
gint core module: syscalls
System calls (and the like) used by the library. The library should
rely the least possible on the system, but sometimes using the syscalls
is nothing of a nuisance.
For instance, using the malloc()-family syscalls is a bit annoying
because it "locks" many functionalities. On the other hand, getting the
SaveDisp() buffer addresses to store data here is not a problem since
such data can very easily be relocated to static RAM.
*/
/* Dynamic allocation */
.global ___malloc
.global ___free
.global ___realloc
/* OS version */
.global ___get_os_version
/* Return to menu */
.global ___system_menu
/* Storage memory filesystem */
.global _BFile_Remove
.global _BFile_Create
.global _BFile_Open
.global _BFile_Close
.global _BFile_Write
.global _BFile_Read
/* Dynamic memory allocation */
___malloc:
mov.l syscall_table, r2
mov.l 1f, r0
jmp @r2
nop
1: .long 0xacd
___free:
mov.l syscall_table, r2
mov.l 1f, r0
jmp @r2
nop
1: .long 0xacc
___realloc:
mov.l syscall_table, r2
mov.l 1f, r0
jmp @r2
nop
1: .long 0xe6d
/* OS version access */
___get_os_version:
mov.l syscall_table, r2
mov.l 1f, r0
jmp @r2
nop
1: .long 0x02ee
/*
__system_menu()
Brings one back to the system menu by putting KEY_MENU in the system's
key buffer and calling GetKeyWait(). Of course this needs to be
executed while under system control.
*/
___system_menu:
sts.l pr, @-r15
add #-4, r15
/* Copying gint's VRAM into the system's. */
mov.l syscall_table, r1
mov.l .syscall_vram, r0
jsr @r1
mov.l r4, @r15 /* gint video ram */
mov r0, r4
mov.l @r15, r5
mov.w .vram_size, r6
mov.l .memcpy, r1
jsr @r1
nop
/* Putting the matrix code in the key buffer. */
mov r15, r4
mov.w .matrix_menu, r2
mov.w r2, @r4
mov.l syscall_table, r1
mov.l .syscall_putcode, r0
jsr @r1
nop
/* Calling GetKeyWait() to display menu. */
mov r15, r4 /* column pointer */
add #-4, r15
mov r15, r5 /* row pointer */
add #-4, r15
mov r15, r1 /* keycode pointer */
mov #2, r6 /* type of waiting */
mov #0, r7 /* timeout period */
mov.l r1, @-r15
mov #0, r2 /* allow return to menu */
mov.l r2, @-r15
mov.l syscall_table, r1
mov.l .syscall_getkeywait, r0
jsr @r1
nop
/* If the program counter reaches this place, it means that the user
has come back to the program. Restore stack and leave. */
add #20, r15
lds.l @r15+, pr
rts
nop
.align 4
.syscall_getkeywait:
.long 0x0247
.syscall_putcode:
.long 0x024f
.syscall_vram:
.long 0x0135
.matrix_menu:
.word 0x0308
.vram_size:
.word 1024
.memcpy:
.long _memcpy
/* BFile driver */
# int BFile_Remove(const uint16_t *file)
_BFile_Remove:
mov.l 1f, r0
mov.l syscall_table, r1
jmp @r1
mov #0, r5
1: .long 0x0439
# int BFile_Create(const uint16_t *file, enum { file = 1, folder = 5 },
# int *size)
_BFile_Create:
mov.l 1f, r0
mov.l syscall_table, r1
jmp @r1
nop
1: .long 0x0434
# int BFile_Open(const uint16_t *file, int mode)
_BFile_Open:
mov.l 1f, r0
mov.l syscall_table, r1
jmp @r1
mov #0, r6
1: .long 0x042c
# int BFile_Close(int handle)
_BFile_Close:
mov.l 1f, r0
mov.l syscall_table, r1
jmp @r1
nop
1: .long 0x042d
# int BFile_Write(int handle, const void *ram_buffer, int even_size)
_BFile_Write:
mov.l 1f, r0
mov.l syscall_table, r1
jmp @r1
nop
1: .long 0x0435
# int BFile_Read(int handle, void *ram_buffer, int size, int whence)
_BFile_Read:
mov.l 1f, r0
mov.l syscall_table, r1
jmp @r1
nop
1: .long 0x0432
.align 4
syscall_table:
.long 0x80010070

View file

@ -1,98 +0,0 @@
#include <internals/gint.h>
#include <internals/interrupt_maps.h>
#include <mpu.h>
// Compiler optimization of the interrupt handlers seems to cause crashes at
// some point. Some research showed that illegal slot exceptions were raised on
// rte; lds.l @r15+, mach, even though it's a legal slot. For now I just turn
// off optimization until I figure out where the true problem is.
#pragma GCC push_options
#pragma GCC optimize("O0")
//---
// VBR space
//---
#ifdef GINT_DIAGNOSTICS
static void register_interrupt(int offset)
{
volatile gint_diagnostics_t *dg = gint_diagnostics();
volatile uint32_t *expevt, *intevt, *tea;
uint32_t event_code, spc, ssr;
// Getting the addresses of some registers.
expevt = gint_reg(register_expevt);
intevt = gint_reg(register_intevt);
tea = gint_reg(register_tea);
// Adding an entry in the event history.
event_code = (offset == 0x600) ? (*intevt) : (*expevt);
size_t len = sizeof dg->except_vect;
dg->except_vect[dg->excepts++] = event_code >> 4;
if(dg->excepts >= len) dg->excepts -= len;
// Updating some fields in the diagnostic record.
__asm__("stc spc, %0" : "=r"(spc));
__asm__("stc ssr, %0" : "=r"(ssr));
dg->spc = spc;
dg->ssr = ssr;
dg->expevt = event_code;
dg->tea = *tea;
}
#endif
/*
gint_exc()
Handles exceptions.
*/
__attribute__((section(".gint.exc"), interrupt_handler))
void gint_exc(void)
{
#ifdef GINT_DIAGNOSTICS
register_interrupt(0x100);
#endif
uint32_t event = *(uint32_t *)gint_reg(register_expevt);
gint_interrupt_map_t map;
map = isSH3() ? gint_map_7705(event, 0x100) : gint_map_7305(event);
gint_invoke(map.type, map.subtype);
}
/*
gint_tlb()
Handles TLB misses.
*/
__attribute__((section(".gint.tlb"), interrupt_handler))
void gint_tlb(void)
{
#ifdef GINT_DIAGNOSTICS
register_interrupt(0x400);
#endif
uint32_t event = *(uint32_t *)gint_reg(register_expevt);
gint_interrupt_map_t map;
map = isSH3() ? gint_map_7705(event, 0x400) : gint_map_7305(event);
gint_invoke(map.type, map.subtype);
}
/*
gint_int()
Handles interrupts.
*/
__attribute__((section(".gint.int"), interrupt_handler))
void gint_int(void)
{
#ifdef GINT_DIAGNOSTICS
register_interrupt(0x600);
#endif
uint32_t event = *(uint32_t *)gint_reg(register_intevt);
gint_interrupt_map_t map;
map = isSH3() ? gint_map_7705(event, 0x600) : gint_map_7305(event);
gint_invoke(map.type, map.subtype);
}
#pragma GCC pop_options

View file

@ -1,43 +0,0 @@
#include <ctype.h>
// Let's save up some space and readability (that's Cake's idea, it's a bit of
// a preprocessor trick - but a rather nice trick).
#define r4(x) (x), (x), (x), (x)
#define r5(x) r4(x), (x)
#define r6(x) r5(x), (x)
#define r7(x) r6(x), (x)
#define r9(x) r7(x), (x), (x)
#define r10(x) r6(x), r4(x)
#define r15(x) r10(x), r4(x), (x)
#define r18(x) r9(x), r9(x)
#define r20(x) r10(x), r10(x)
enum {
cntrl = 0x01,
space = 0x02,
punct = 0x04,
print = 0x08,
upper = 0x20,
lower = 0x10,
digit = 0x40,
xdigt = 0x80,
};
uint8_t ctype_classes[0x80] = {
// Control characters.
r9(cntrl), r5(cntrl | space), r18(cntrl),
// Space and some punctuation.
space | print, r15(punct | print),
// Decimal digits.
r10(digit | xdigt | print),
// Some punctuation.
r7(punct | print),
// Uppercase alphabet.
r6(upper | xdigt | print), r20(upper | print),
// Other punctuation symbols.
r6(punct | print),
// Lowercase alphabet.
r6(lower | xdigt | print), r20(lower | print),
// Last punctuation characters and DEL.
r4(punct | print), cntrl,
};

View file

@ -1,73 +0,0 @@
//---
// Character type functions.
// Normally this functions need not be linked because there are macros to
// optimize performance, but we still need them to get some pointers.
//---
// We don't want to include <ctype.h> because it defines all the macros...
#include <stdint.h>
extern uint8_t ctype_classes[0x80];
#define _inline __attribute__((always_inline)) inline
_inline int isalnum(int c) {
return ctype_classes[c] & 0xf0;
}
_inline int isalpha(int c) {
return ctype_classes[c] & 0x30;
}
_inline int iscntrl(int c) {
return ctype_classes[c] & 0x01;
}
_inline int isdigit(int c) {
return ctype_classes[c] & 0x40;
}
_inline int isgraph(int c) {
return ctype_classes[c] & 0xf4;
}
_inline int islower(int c) {
return ctype_classes[c] & 0x10;
}
_inline int isprint(int c) {
return ctype_classes[c] & 0x08;
}
_inline int ispunct(int c) {
return ctype_classes[c] & 0x04;
}
_inline int isspace(int c) {
return ctype_classes[c] & 0x02;
}
_inline int isupper(int c) {
return ctype_classes[c] & 0x20;
}
_inline int isxdigit(int c) {
return ctype_classes[c] & 0x80;
}
_inline int isascii(int c) {
return ((unsigned)c <= 0x7f);
}
_inline int isblank(int c) {
return (c == '\t' || c == ' ');
}
_inline int tolower(int c) {
return c | isupper(c);
}
_inline int toupper(int c) {
return c & ~(islower(c) << 1);
}
#undef _inline

Some files were not shown because too many files have changed in this diff Show more