Make room for an fx-cg50 compatible version. Enhanced build system.
13
.gitignore
vendored
|
@ -5,19 +5,12 @@ build/**
|
||||||
*.sublime-project
|
*.sublime-project
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
|
|
||||||
# Object files.
|
# Lots of unordered project notes
|
||||||
*.o
|
|
||||||
|
|
||||||
# Some notes.
|
|
||||||
notes/**
|
notes/**
|
||||||
|
|
||||||
# Output files
|
# Output files
|
||||||
libc.a
|
bin/**
|
||||||
libgint.a
|
|
||||||
gintdemo.g1a
|
|
||||||
gintdbg.g1a
|
|
||||||
|
|
||||||
# Configuration files
|
# Configuration files
|
||||||
gcc.cfg
|
config/**
|
||||||
Makefile.cfg
|
|
||||||
|
|
||||||
|
|
332
Makefile
|
@ -4,267 +4,125 @@
|
||||||
#
|
#
|
||||||
#---
|
#---
|
||||||
|
|
||||||
include Makefile.cfg
|
#
|
||||||
|
# Build configuration
|
||||||
|
#
|
||||||
|
|
||||||
#---
|
# Some rules don't care if config files are missing (eg. clean, etc)
|
||||||
# Project variables
|
cfg := config/Makefile.cfg
|
||||||
#---
|
-include $(cfg)
|
||||||
|
|
||||||
# Modules
|
# Those that do may use this special dependency
|
||||||
modules-gint = bopti clock core display events gray init keyboard mmu rtc \
|
cfgdep := $(if $(shell [ -f $(cfg) ] || echo n),CFGDEP,$(cfg))
|
||||||
screen tales timer
|
|
||||||
modules-libc = ctype math setjmp stdio stdlib string time
|
|
||||||
|
|
||||||
# Targets
|
# Compiler flags, assembler flags, dependency generation, archiving
|
||||||
target-lib = libgint.a
|
cflags := -m3 -mb -ffreestanding -nostdlib -Wall -Wextra -std=c11 -O2 \
|
||||||
target-std = libc.a
|
-I include $(cfg_defs)
|
||||||
target-g1a = gintdemo.g1a
|
dflags = -MMD -MT $@ -MF $(@:.o=.d) -MP
|
||||||
|
arflags :=
|
||||||
|
|
||||||
# Tools
|
#
|
||||||
cc = sh3eb-elf-gcc
|
# File listings
|
||||||
ld = sh3eb-elf-ld
|
#
|
||||||
as = sh3eb-elf-as
|
|
||||||
ar = sh3eb-elf-ar
|
|
||||||
ob = sh3eb-elf-objcopy
|
|
||||||
wr = g1a-wrapper
|
|
||||||
|
|
||||||
# Flags for gint
|
# Target file
|
||||||
lib-cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \
|
target := bin/libgint.a
|
||||||
-Wall -Wextra @gcc.cfg -g0
|
|
||||||
|
|
||||||
# Demo application (could be done better)
|
# Automatic names for object and dependency files
|
||||||
demo-src = $(notdir $(wildcard demo/*.[cs]))
|
src2obj = build/$(1:src/%=%).o
|
||||||
demo-dep = $(wildcard demo/*.h)
|
src2dep = build/$(1:src/%=%).d
|
||||||
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
|
|
||||||
|
|
||||||
# Specific objects
|
# Source files
|
||||||
obj-std-spec =
|
src := $(shell find src -name '*.[cs]')
|
||||||
obj-lib-spec = build/display_font_system.bmp.o build/version.o
|
src_obj := $(foreach s,$(src),$(call src2obj,$s))
|
||||||
|
|
||||||
# Configuration files, require them only if we're not cleaning
|
# Files with special handling
|
||||||
config = gcc.cfg
|
spe := src/display/font.bmp
|
||||||
ifeq "$(filter clean mrproper distclean,$(MAKECMDGOALS))" ""
|
spe_obj := $(foreach s,$(spe),$(call src2obj,$s))
|
||||||
ifeq ($(wildcard $(config)),)
|
|
||||||
$(error "Configuration files are missing. Did you ./configure ?")
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Target folder, require it only if we want to install
|
# All object files
|
||||||
ifneq "$(filter install,$(MAKECMDGOALS))" ""
|
obj := $(src_obj) $(spe_obj)
|
||||||
folder := $(shell fxsdk --folder)
|
|
||||||
ifndef folder
|
|
||||||
$(error "Could not get the fxSDK storage folder. Did you install fxSDK \
|
|
||||||
properly?")
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Toolchain
|
||||||
|
#
|
||||||
|
|
||||||
|
gcc = sh3eb-elf-gcc
|
||||||
|
as = sh3eb-elf-as
|
||||||
|
ld = sh3eb-elf-ld
|
||||||
|
ar = sh3eb-elf-ar
|
||||||
|
conv = fxconv
|
||||||
|
|
||||||
#---
|
#
|
||||||
# Automatic variables
|
# Build rules
|
||||||
#---
|
#
|
||||||
|
|
||||||
# Modules are subfolders of src/.
|
all: $(target)
|
||||||
modules = $(modules-gint) $(modules-libc)
|
|
||||||
|
|
||||||
define n
|
$(target): $(obj) | $(dir $(target))
|
||||||
# This is a newline character.
|
$(call cmd_l,ar,$@) $(ar) -crs $(arflags) $@ $(obj)
|
||||||
|
|
||||||
endef
|
# Assembler sources
|
||||||
|
build/%.s.o: src/%.s build/%.s.d
|
||||||
|
@ mkdir -p $(dir $@)
|
||||||
|
$(call cmd_b,as,$<) $(as) -c $< -o $@ $(sflags)
|
||||||
|
|
||||||
# Module-scope variables.
|
# C sources
|
||||||
$(foreach mod, $(modules), $(eval \
|
build/%.c.o: src/%.c build/%.c.d $(cfgdep)
|
||||||
mod-$(mod)-c = $(notdir $(wildcard src/$(mod)/*.c)) $n\
|
@ mkdir -p $(dir $@)
|
||||||
mod-$(mod)-asm = $(notdir $(wildcard src/$(mod)/*.s)) $n\
|
$(call cmd_b,gcc,$<) $(gcc) -c $< -o $@ $(dflags) $(cflags)
|
||||||
mod-$(mod)-src = $$(mod-$(mod)-c)$$(mod-$(mod)-asm) $n\
|
|
||||||
mod-$(mod)-obj = $$(patsubst %,build/$(mod)_%.o,$$(mod-$(mod)-src)) \
|
|
||||||
))
|
|
||||||
|
|
||||||
# Target-scope variables.
|
# Special files
|
||||||
obj-std = $(foreach mod,$(modules-libc),$(mod-$(mod)-obj)) $(obj-std-spec)
|
$(call src2obj,src/display/font.bmp): src/display/font.bmp
|
||||||
obj-lib = $(foreach mod,$(modules-gint),$(mod-$(mod)-obj)) $(obj-lib-spec)
|
@ mkdir -p $(dir $@)
|
||||||
|
$(call cmd_m,fxconv,$<) $(conv) -font $< -n gint_font -o $@
|
||||||
|
|
||||||
# Dependencies.
|
#
|
||||||
hdr-dep = $(wildcard include/*.h include/*/*.h)
|
# Cleaning
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
#---
|
|
||||||
# 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
|
|
||||||
#---
|
|
||||||
|
|
||||||
clean:
|
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)
|
# Utilities
|
||||||
@ rm -f $(config)
|
#
|
||||||
|
|
||||||
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)
|
# Make directories: make conveniently leaves a '/' at the end of $(dir ...)
|
||||||
$(if $(VERBOSE),,@ printf '\e[35;1m mkdir\e[0m $(folder)\n')
|
%/:
|
||||||
$(if $(VERBOSE),,@) mkdir -p $(folder)
|
@ 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')
|
# Dependency information
|
||||||
$(if $(VERBOSE),,@) install -m 644 $^ $(folder)
|
-include $(shell [ -d build ] && find build -name *.d)
|
||||||
$(if $(VERBOSE),,@ printf '\e[33;1minstall\e[0m 644 demo/gintdemo.ld\n')
|
build/%.d: ;
|
||||||
$(if $(VERBOSE),,@) install -m 644 -T demo/gintdemo.ld $(folder)/linker.ld
|
.PRECIOUS: build/%.d
|
||||||
|
|
||||||
$(if $(VERBOSE),,@ printf '\e[35;1m mkdir\e[0m $(folder)/gint/modules\n')
|
# Do not output full commands by default
|
||||||
$(if $(VERBOSE),,@) mkdir -p $(folder)/gint/modules
|
VERBOSE ?=
|
||||||
|
|
||||||
$(if $(VERBOSE),,@ printf '\e[33;1minstall\e[0m 644 include/**.h\n')
|
# Simple command output method
|
||||||
$(if $(VERBOSE),,@) install -m 644 include/*.h $(folder)/gint
|
# $1 Program name
|
||||||
$(if $(VERBOSE),,@) install -m 644 include/modules/*.h $(folder)/gint/modules
|
# $2 Argument string to display
|
||||||
ifdef config_ext
|
# $3 Command color
|
||||||
$(if $(VERBOSE),,@) install -m 644 include/extended/*.h $(folder)/gint
|
define cmd
|
||||||
endif
|
@ echo -e "\e[""$3"";1m>\e[0;1m $1\e[0m $2"
|
||||||
@ printf "\n\033[32;1m\u00bb\033[0m Successfully installed gint\n\n"
|
$(if $(VERBOSE),,@)
|
||||||
|
endef
|
||||||
|
|
||||||
install-demo: all
|
# Some pre-colored command kinds: misc, build, link, clean, install
|
||||||
p7 send -f $(target-g1a)
|
cmd_m = $(call cmd,$1,$2,30)
|
||||||
|
cmd_b = $(call cmd,$1,$2,32)
|
||||||
.PHONY: all-lib all help
|
cmd_l = $(call cmd,$1,$2,36)
|
||||||
.PHONY: clean mrproper distclean
|
cmd_c = $(call cmd,$1,$2,31)
|
||||||
.PHONY: install install-demo
|
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
|
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.
|
share your changes. No credit of any kind is required, though appreciated.
|
||||||
|
|
||||||
|
**TODO: Update this file for everything related to project organization**
|
||||||
|
|
||||||
|
|
||||||
Programming interface
|
Programming interface
|
||||||
---------------------
|
---------------------
|
||||||
|
|
105
configure
vendored
|
@ -6,8 +6,11 @@
|
||||||
|
|
||||||
declare -A conf
|
declare -A conf
|
||||||
|
|
||||||
|
# Target platform
|
||||||
|
conf_target=
|
||||||
|
|
||||||
# Behavior
|
# Behavior
|
||||||
conf[GINT_STARTUP_LOG]=
|
conf[GINT_BOOT_LOG]=
|
||||||
conf[GINT_NO_SYSCALLS]=
|
conf[GINT_NO_SYSCALLS]=
|
||||||
conf[GINT_EXTENDED_LIBC]=
|
conf[GINT_EXTENDED_LIBC]=
|
||||||
conf[GINT_STATIC_GRAY]=
|
conf[GINT_STATIC_GRAY]=
|
||||||
|
@ -18,45 +21,50 @@ conf[TIMER_SLOTS]=16
|
||||||
conf[EVENTS_QUEUE_SIZE]=64
|
conf[EVENTS_QUEUE_SIZE]=64
|
||||||
|
|
||||||
# Output files
|
# Output files
|
||||||
output_gcc="gcc.cfg"
|
output="config/Makefile.cfg"
|
||||||
output_make="Makefile.cfg"
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Help screen and output util
|
# Help screen and output util
|
||||||
#
|
#
|
||||||
|
|
||||||
error="\e[31;1merror:\e[0m"
|
error="\e[31;1merror:\e[0m"
|
||||||
Cg="$(tput setaf 8)$(tput bold)"
|
C_="$(echo -e '\e[30;1m')"
|
||||||
Cr="$(tput setaf 1)$(tput bold)"
|
Cr="$(echo -e '\e[31;1m')"
|
||||||
Cy="$(tput setaf 2)$(tput bold)"
|
Cg="$(echo -e '\e[32;1m')"
|
||||||
Cp="$(tput setaf 5)$(tput setaf 62)$(tput bold)"
|
Cp="$(echo -e '\e[34;1m')"
|
||||||
C0="$(tput setaf 0)$(tput sgr 0)"
|
C0="$(echo -e '\e[0m')"
|
||||||
|
|
||||||
help()
|
help()
|
||||||
{
|
{
|
||||||
cat << EOF
|
cat << EOF
|
||||||
Configuration script for the gint library.
|
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:
|
Options that affect the behavior of the library:
|
||||||
$Cr--startup-log $Cg[default:$Cp false$Cg]$C0
|
$Cr--boot-log $C_[default:$Cp not specified$C_]$C0
|
||||||
Enable a on-screen log at startup if a key is kept pressed while launching
|
Enable an on-screen log at startup if a key is kept pressed while launching
|
||||||
the add-in, allowing easy debug and crash diagnoses.
|
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
|
Never use syscalls. Expect trouble with malloc() and the gray engine. Do
|
||||||
not trigger this switch unless you know what you are doing.
|
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
|
Enable specific C99 headers/features that are normally not required by
|
||||||
calculator programs. This may allow porting programs from other platforms.
|
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
|
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.
|
use this option when using both the gray engine and --no-syscalls.
|
||||||
|
|
||||||
Options that customize size limits:
|
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().
|
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.
|
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.
|
Number of events simultaneously stored in the event queue.
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
@ -69,8 +77,20 @@ EOF
|
||||||
|
|
||||||
fail=false
|
fail=false
|
||||||
for arg; do case "$arg" in
|
for arg; do case "$arg" in
|
||||||
-h | --help) help;;
|
-h | -? | --help) help;;
|
||||||
--startup-log) conf[GINT_STARTUP_LOG]=true;;
|
|
||||||
|
--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;;
|
--no-syscalls) conf[GINT_NO_SYSCALLS]=true;;
|
||||||
--extended-libc) conf[GINT_EXTENDED_LIBC]=true;;
|
--extended-libc) conf[GINT_EXTENDED_LIBC]=true;;
|
||||||
--static-gray-engine) conf[GINT_STATIC_GRAY]=true;;
|
--static-gray-engine) conf[GINT_STATIC_GRAY]=true;;
|
||||||
|
@ -103,34 +123,41 @@ for arg; do case "$arg" in
|
||||||
esac; done
|
esac; done
|
||||||
|
|
||||||
#
|
#
|
||||||
# Output config routines
|
# Checking mandatory arguments
|
||||||
#
|
#
|
||||||
|
|
||||||
output_config_gcc()
|
if [[ ! $conf_target ]]; then
|
||||||
{
|
echo -e "$error No target specified. See $0 --help."
|
||||||
[ "${conf[GINT_STARTUP_LOG]}" != "" ] && echo "-D GINT_STARTUP_LOG"
|
fail=true;
|
||||||
[ "${conf[GINT_NO_SYSCALLS]}" != "" ] && echo "-D GINT_NO_SYSCALLS"
|
fi
|
||||||
[ "${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"
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Output config
|
# 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
|
if $fail; then
|
||||||
echo "Configuration has not been modified."
|
echo "Output file $output has not been modified."
|
||||||
else
|
else
|
||||||
output_config_gcc > $output_gcc
|
mkdir -p config
|
||||||
output_config_make > $output_make
|
output_config > $output
|
||||||
echo "Configuration saved in $output_gcc and $output_make."
|
echo "Configuration saved in $output, ready to make!"
|
||||||
fi
|
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
|
|