Make room for an fx-cg50 compatible version. Enhanced build system.
13
.gitignore
vendored
|
@ -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/**
|
||||
|
||||
|
|
342
Makefile
|
@ -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
|
||||
#
|
||||
# File listings
|
||||
#
|
||||
|
||||
# Target file
|
||||
target := bin/libgint.a
|
||||
|
||||
# Automatic names for object and dependency files
|
||||
src2obj = build/$(1:src/%=%).o
|
||||
src2dep = build/$(1:src/%=%).d
|
||||
|
||||
# Source files
|
||||
src := $(shell find src -name '*.[cs]')
|
||||
src_obj := $(foreach s,$(src),$(call src2obj,$s))
|
||||
|
||||
# Files with special handling
|
||||
spe := src/display/font.bmp
|
||||
spe_obj := $(foreach s,$(spe),$(call src2obj,$s))
|
||||
|
||||
# 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
|
||||
ob = sh3eb-elf-objcopy
|
||||
wr = g1a-wrapper
|
||||
conv = fxconv
|
||||
|
||||
# Flags for gint
|
||||
lib-cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \
|
||||
-Wall -Wextra @gcc.cfg -g0
|
||||
#
|
||||
# Build rules
|
||||
#
|
||||
|
||||
# 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
|
||||
all: $(target)
|
||||
|
||||
# Specific objects
|
||||
obj-std-spec =
|
||||
obj-lib-spec = build/display_font_system.bmp.o build/version.o
|
||||
$(target): $(obj) | $(dir $(target))
|
||||
$(call cmd_l,ar,$@) $(ar) -crs $(arflags) $@ $(obj)
|
||||
|
||||
# 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
|
||||
# Assembler sources
|
||||
build/%.s.o: src/%.s build/%.s.d
|
||||
@ mkdir -p $(dir $@)
|
||||
$(call cmd_b,as,$<) $(as) -c $< -o $@ $(sflags)
|
||||
|
||||
# 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
|
||||
# C sources
|
||||
build/%.c.o: src/%.c build/%.c.d $(cfgdep)
|
||||
@ mkdir -p $(dir $@)
|
||||
$(call cmd_b,gcc,$<) $(gcc) -c $< -o $@ $(dflags) $(cflags)
|
||||
|
||||
# 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 $@
|
||||
|
||||
|
||||
#---
|
||||
# Automatic variables
|
||||
#---
|
||||
|
||||
# Modules are subfolders of src/.
|
||||
modules = $(modules-gint) $(modules-libc)
|
||||
|
||||
define n
|
||||
# This is a newline character.
|
||||
|
||||
endef
|
||||
|
||||
# Module-scope variables.
|
||||
$(foreach mod, $(modules), $(eval \
|
||||
mod-$(mod)-c = $(notdir $(wildcard src/$(mod)/*.c)) $n\
|
||||
mod-$(mod)-asm = $(notdir $(wildcard src/$(mod)/*.s)) $n\
|
||||
mod-$(mod)-src = $$(mod-$(mod)-c)$$(mod-$(mod)-asm) $n\
|
||||
mod-$(mod)-obj = $$(patsubst %,build/$(mod)_%.o,$$(mod-$(mod)-src)) \
|
||||
))
|
||||
|
||||
# Target-scope variables.
|
||||
obj-std = $(foreach mod,$(modules-libc),$(mod-$(mod)-obj)) $(obj-std-spec)
|
||||
obj-lib = $(foreach mod,$(modules-gint),$(mod-$(mod)-obj)) $(obj-lib-spec)
|
||||
|
||||
# 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)
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
456
demo/gintdemo.c
|
@ -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();
|
||||
}
|
||||
*/
|
114
demo/gintdemo.h
|
@ -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
|
113
demo/gintdemo.ld
|
@ -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
|
||||
}
|
BIN
demo/icon.bmp
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 4 KiB |
Before Width: | Height: | Size: 97 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 71 KiB |
|
@ -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;
|
||||
}
|
104
demo/test_gray.c
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
260
demo/test_rtc.c
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
673
include/7305.h
|
@ -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
|
1099
include/7705.h
|
@ -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
|
|
@ -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
|
|
@ -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
|
121
include/clock.h
|
@ -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
|
|
@ -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
|
|
@ -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
|
113
include/events.h
|
@ -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
|
|
@ -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
|
|
@ -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
|
251
include/gint.h
|
@ -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
|
139
include/gray.h
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
105
include/rtc.h
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
149
include/stdlib.h
|
@ -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
|
|
@ -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
|
128
include/tales.h
|
@ -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
|
126
include/time.h
|
@ -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
|
177
include/timer.h
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
180
src/core/gint.c
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
*/
|
||||
}
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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,
|
||||
};
|
|
@ -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
|