mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23:36 +01:00
Huh... debug app for crashes & whole new interrupt system. Minor edits.
This commit is contained in:
parent
49df2a5fb4
commit
d852bc3310
66 changed files with 2883 additions and 1187 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -9,12 +9,13 @@ build/**
|
|||
*.o
|
||||
|
||||
# Some notes.
|
||||
LIBC
|
||||
notes/**
|
||||
|
||||
# Output files
|
||||
libc.a
|
||||
libgint.a
|
||||
gintdemo.g1a
|
||||
gintdbg.g1a
|
||||
|
||||
# Configuration files
|
||||
gcc.cfg
|
||||
|
|
106
Makefile
106
Makefile
|
@ -1,25 +1,25 @@
|
|||
#! /usr/bin/make -f
|
||||
#---
|
||||
#
|
||||
# gint project Makefile.
|
||||
# gint project Makefile
|
||||
#
|
||||
#---
|
||||
|
||||
include Makefile.cfg
|
||||
|
||||
#---
|
||||
# Project variables.
|
||||
# Project variables
|
||||
#---
|
||||
|
||||
# Modules
|
||||
modules-gint = core clock keyboard mmu mpu rtc screen timer \
|
||||
bopti display gray tales events
|
||||
modules-libc = setjmp string stdio stdlib time
|
||||
modules-gint = bopti clock core display events gray keyboard mmu rtc \
|
||||
screen tales timer
|
||||
modules-libc = setjmp stdio stdlib string time
|
||||
|
||||
# Targets
|
||||
target-g1a = gintdemo.g1a
|
||||
target-lib = libgint.a
|
||||
target-std = libc.a
|
||||
target-g1a = gintdemo.g1a
|
||||
target-dbg = gintdbg.g1a
|
||||
|
||||
# Tools
|
||||
cc = sh3eb-elf-gcc
|
||||
|
@ -28,27 +28,40 @@ ar = sh3eb-elf-ar
|
|||
ob = sh3eb-elf-objcopy
|
||||
wr = g1a-wrapper
|
||||
|
||||
# Flags
|
||||
cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \
|
||||
-W -Wall -Wextra -pedantic @gcc.cfg
|
||||
# Flags for gint
|
||||
lib-cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \
|
||||
-Wall -Wextra @gcc.cfg
|
||||
|
||||
# Demo application (could be done better)
|
||||
demo-src = $(notdir $(wildcard demo/*.[cs]))
|
||||
demo-dep = $(wildcard demo/*.h)
|
||||
demo-ld = demo/gintdemo.ld
|
||||
demo-icon = demo/icon.bmp
|
||||
demo-res = $(notdir $(wildcard demo/resources/*))
|
||||
demo-obj = $(patsubst %,build/demo_%.o,$(demo-src) $(demo-res))
|
||||
demo-elf = build/gintdemo.elf
|
||||
demo-bin = build/gintdemo.bin
|
||||
demo-libs = -L. -lgint -lc -lgcc
|
||||
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
|
||||
|
||||
# Debugger application (displays past diagnostics without running gint)
|
||||
debug-src = $(notdir $(wildcard debug/*.[cs]))
|
||||
debug-dep = $(wildcard debug/*.h)
|
||||
debug-icon = debug/icon.bmp
|
||||
debug-obj = $(debug-src:%=build/debug_%.o)
|
||||
debug-elf = build/gintdbg.elf
|
||||
debug-bin = build/gintdbg.bin
|
||||
debug-ldflags = $(debug-cflags) -T debug/addin.ld -L debug -lfx -lgcc
|
||||
debug-cflags = -m3 -mb -nostdlib -ffreestanding -I debug/include -I \
|
||||
include -std=c11 -Os -Wall -Wextra
|
||||
|
||||
# Specific objects
|
||||
obj-lib-spec = build/display_font_system.bmp.o
|
||||
obj-lib-spec = build/display_font_system.bmp.o \
|
||||
build/display_font_terminal.bmp.o
|
||||
obj-std-spec =
|
||||
|
||||
# Configuration files
|
||||
config = gcc.cfg
|
||||
config = gcc.cfg
|
||||
ifeq ($(wildcard $(config)),)
|
||||
$(error "Configuration files are missing. Did you ./configure ?")
|
||||
endif
|
||||
|
@ -63,7 +76,7 @@ endif
|
|||
|
||||
|
||||
#---
|
||||
# Automatic variables.
|
||||
# Automatic variables
|
||||
#---
|
||||
|
||||
# Modules are subfolders of src/.
|
||||
|
@ -86,7 +99,7 @@ $(foreach mod, $(modules), $(eval \
|
|||
obj-std = $(foreach mod,$(modules-libc),$(mod-$(mod)-obj)) $(obj-std-spec)
|
||||
obj-lib = $(foreach mod,$(modules-gint),$(mod-$(mod)-obj)) $(obj-lib-spec)
|
||||
|
||||
# Dependencies
|
||||
# Dependencies.
|
||||
hdr-dep = $(wildcard include/*.h include/internals/*.h)
|
||||
|
||||
|
||||
|
@ -95,11 +108,6 @@ hdr-dep = $(wildcard include/*.h include/internals/*.h)
|
|||
# Rule templates.
|
||||
#---
|
||||
|
||||
#ifndef VERBOSE
|
||||
#$(note "default full log")
|
||||
#VERBOSE =
|
||||
#endif
|
||||
|
||||
# C source file template:
|
||||
# $1 module name
|
||||
# $2 filename
|
||||
|
@ -107,10 +115,10 @@ hdr-dep = $(wildcard include/*.h include/internals/*.h)
|
|||
define rule-c-source
|
||||
build/$1_$2.o: src/$1/$2 $3 $(config)
|
||||
$(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $$<\n')
|
||||
$(if $(VERBOSE),,@) $(cc) -c $$< -o $$@ $(cflags) -I src/$1
|
||||
$(if $(VERBOSE),,@) $(cc) -c $$< -o $$@ $(lib-cflags)
|
||||
endef
|
||||
|
||||
# asm source file template:
|
||||
# Asm source file template:
|
||||
# $1 module name
|
||||
# $2 filename
|
||||
define rule-asm-source
|
||||
|
@ -127,8 +135,9 @@ endef
|
|||
|
||||
# Generic rules
|
||||
|
||||
all: $(config) $(target-std) $(target-lib) $(target-g1a)
|
||||
@ printf '\e[32;1mmsg \u00bb\e[0m All done!\n'
|
||||
all-lib: $(config) $(target-std) $(target-lib)
|
||||
|
||||
all: $(config) $(target-std) $(target-lib) $(target-g1a) $(target-dbg)
|
||||
|
||||
build:
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mdir \u00bb\e[0m mkdir $@\n')
|
||||
|
@ -152,7 +161,7 @@ $(target-lib): $(config) $(target-std) $(obj-lib)
|
|||
|
||||
$(target-g1a): $(config) $(target-std) $(target-lib) $(demo-obj)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m ld -o $(demo-elf)\n')
|
||||
$(if $(VERBOSE),,@) $(cc) -o $(demo-elf) $(cflags) -T $(demo-ld) $(demo-obj) $(demo-libs)
|
||||
$(if $(VERBOSE),,@) $(cc) -o $(demo-elf) $(demo-obj) $(demo-ldflags)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m objcopy -o $(demo-bin)\n')
|
||||
$(if $(VERBOSE),,@) $(ob) -R .comment -R .bss -O binary $(demo-elf) $(demo-bin)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m g1a-wrapper -o $@\n')
|
||||
|
@ -161,6 +170,17 @@ $(target-g1a): $(config) $(target-std) $(target-lib) $(demo-obj)
|
|||
@ printf $$(stat -c %s $@)
|
||||
@ printf ' bytes)\n\n'
|
||||
|
||||
$(target-dbg): $(config) $(debug-obj)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m ld -o $(debug-elf)\n')
|
||||
$(if $(VERBOSE),,@) $(cc) -o $(debug-elf) $(debug-obj) $(debug-ldflags)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m objcopy -o $(debug-bin)\n')
|
||||
$(if $(VERBOSE),,@) $(ob) -R .comment -R .bss -O binary $(debug-elf) $(debug-bin)
|
||||
$(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m g1a-wrapper -o $@\n')
|
||||
$(if $(VERBOSE),,@) $(wr) $(debug-bin) -o $@ -i $(debug-icon)
|
||||
@ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built debug application ('
|
||||
@ printf $$(stat -c %s $@)
|
||||
@ printf ' bytes)\n\n'
|
||||
|
||||
# Automated rules
|
||||
|
||||
$(foreach mod,$(modules), \
|
||||
|
@ -172,21 +192,19 @@ $(foreach mod,$(modules), \
|
|||
|
||||
# Specific rules
|
||||
|
||||
# This one should not be optimized. It makes __attribute__((interrupt_handler))
|
||||
# buggy... maybe. Anyway there's some bug in this file that I can't fix now.
|
||||
build/core_gint.c.o: src/core/gint.c $(mod-core-dep) $(config)
|
||||
$(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n')
|
||||
$(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(cflags) -I src/core -O0
|
||||
# Optimizing this one makes the interrupt handler raise illegal slot exception
|
||||
# on rte; lds.l @r15+, mach. This is totally weird but I haven't understood
|
||||
# why for now.
|
||||
|
||||
build/display_font_system.bmp.o: src/display/font_system.bmp
|
||||
build/display_font_%.bmp.o: src/display/font_%.bmp
|
||||
$(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n')
|
||||
$(if $(VERBOSE),,@) fxconv $< -o $@ --font -n gint_font_system
|
||||
$(if $(VERBOSE),,@) fxconv $< -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;1msrc \u00bb\e[0m cc $<\n')
|
||||
$(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(cflags)
|
||||
$(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(demo-cflags)
|
||||
|
||||
build/demo_font_%.bmp.o: demo/resources/font_%.bmp
|
||||
$(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n')
|
||||
|
@ -196,10 +214,20 @@ build/demo_%.bmp.o: demo/resources/%.bmp
|
|||
$(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n')
|
||||
$(if $(VERBOSE),,@) fxconv $< -o $@ -n $(patsubst demo/resources/%.bmp,res_%,$<)
|
||||
|
||||
# Debug application
|
||||
|
||||
build/debug_%.s.o: debug/%.s $(config)
|
||||
$(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m as $<\n')
|
||||
$(if $(VERBOSE),,@) $(as) -c $< -o $@
|
||||
|
||||
build/debug_%.c.o: debug/%.c $(hdr-dep) $(debug-dep) $(config)
|
||||
$(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n')
|
||||
$(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(debug-cflags)
|
||||
|
||||
|
||||
|
||||
#---
|
||||
# Cleaning and others.
|
||||
# Cleaning and install
|
||||
#---
|
||||
|
||||
clean:
|
||||
|
@ -222,7 +250,11 @@ ifdef config_ext
|
|||
endif
|
||||
@ printf '\e[32;1mmsg \u00bb\e[0m All installed!\n'
|
||||
|
||||
install_demo:
|
||||
install-demo:
|
||||
p7 send -f $(target-g1a)
|
||||
install-debug:
|
||||
p7 send -f $(target-dbg)
|
||||
|
||||
.PHONY: all clean mrproper distclean install install_demo help
|
||||
.PHONY: all-lib all help
|
||||
.PHONY: clean mrproper distclean
|
||||
.PHONY: install install-demo install-debug
|
||||
|
|
13
README.md
13
README.md
|
@ -59,13 +59,14 @@ The classical way to build gint is to enter a terminal and use the usual:
|
|||
$ make
|
||||
# make install
|
||||
|
||||
This will build and install the following components in the storage folder of
|
||||
the fxSDK:
|
||||
This will build the `all-lib` target and install the following components in
|
||||
the storage folder of the fxSDK:
|
||||
* `libgint.a`, the gint library
|
||||
* `libc.a`, the partial standard library
|
||||
* The libgint headers for development
|
||||
|
||||
The following additional files will be generated in the working directory:
|
||||
When explicitly running target `all`, the following additional files will be
|
||||
generated in the working directory:
|
||||
* `gintdemo.g1a`, a test application
|
||||
|
||||
The usual `clean`, `mrproper`, and `distclean` rules will clean the directory.
|
||||
|
@ -79,8 +80,8 @@ allocation...).
|
|||
Source organization
|
||||
-------------------
|
||||
|
||||
gint is made of *modules*. Each module may have any of the following
|
||||
components:
|
||||
gint is made of *modules*. Each module has one or more of the following
|
||||
component files:
|
||||
* A header file in `/include`
|
||||
* An internal header file in `/include/internals`
|
||||
* Single-function source files in `/src/module`: to avoid linking against the
|
||||
|
@ -91,4 +92,4 @@ components:
|
|||
often begin with `module_`.
|
||||
* Other files in `/src/module`: the `display` module contains a font.
|
||||
|
||||
The demo application is in the `demo` directory.
|
||||
The demo application is in the `demo` folder.
|
||||
|
|
26
TODO
26
TODO
|
@ -9,30 +9,28 @@ Simple improvements:
|
|||
- demo: Try 284x124 at (-60, -28) (all disadvantages)
|
||||
- display: Rectangle-based drawing functions
|
||||
- time: Compute CLOCKS_PER_SEC
|
||||
- core: Add VBR handlers debugging information (if possible)
|
||||
- events: Introduce KeyRepeat events
|
||||
- library: Implement C99's inttypes.h for Cake's UpdateExe
|
||||
- string: Use cmp/str to implement memchr() (assembler examples)
|
||||
- string: Do some tests for memcmp()
|
||||
- core: Register more interrupts (and understand their parameters)
|
||||
- rtc: Take care of carry when reading time
|
||||
Larger improvements:
|
||||
- errno: Introduce errno and use it more or less everywhere
|
||||
- bopti: Monochrome bitmaps blending modes
|
||||
- bopti: Handle partial transparency
|
||||
- core: Implement all callbacks and a complete user API
|
||||
Other whole modules:
|
||||
- Serial communication through 3-pin
|
||||
- USB communication
|
||||
- Sound playback and synthesizing (if possible)
|
||||
- Overclock (relaunch clocks when overclocking)
|
||||
* core: Better save registers
|
||||
* core: Allow return to menu
|
||||
- serial: Implement a driver
|
||||
- usb: Implement a driver
|
||||
- esper: Cleaner playback, synthetizing
|
||||
- clock: Handle overclocking (relaunch clocks when overclocking)
|
||||
|
||||
Things to investigate:
|
||||
- Packed bit fields alignment
|
||||
- Registers that may need to be saved within setjmp()
|
||||
- Registers that may need to be saved and restored by gint
|
||||
- Possible bug when optimizing __attribute__((interrupt_handler))
|
||||
|
||||
Configuration:
|
||||
- ATEXIT_MAX (16)
|
||||
- RTC_CB_ARRAY_SIZE (5)
|
||||
- EVENTS_QUEUE_SIZE (64)
|
||||
- GINT_NO_SYSCALLS (undefined)
|
||||
- Optimizing core/gint.c leads to raising of an illegal slot exception when
|
||||
running the interrupt handler, although it ends on rte; lds.l @r15+, mach,
|
||||
which is totally not an illegal slot.
|
||||
- Check version registers on SH7705
|
||||
|
|
76
configure
vendored
76
configure
vendored
|
@ -1,18 +1,33 @@
|
|||
#! /bin/bash
|
||||
|
||||
#
|
||||
# Basic configuration
|
||||
#
|
||||
|
||||
declare -A conf
|
||||
|
||||
# Behavior
|
||||
conf[GINT_DIAGNOSTICS]=
|
||||
conf[GINT_NO_SYSCALLS]=
|
||||
conf[GINT_EXTENDED_LIBC]=
|
||||
|
||||
# Size limits
|
||||
conf[ATEXIT_MAX]=16
|
||||
conf[RTC_CB_ARRAY_SIZE]=5
|
||||
conf[EVENTS_QUEUE_SIZE]=64
|
||||
conf[GINT_NO_SYSCALLS]=
|
||||
conf[GINT_EXTENDED_LIBC]=
|
||||
fail=false
|
||||
|
||||
# Output files
|
||||
output_gcc="gcc.cfg"
|
||||
output_make="Makefile.cfg"
|
||||
|
||||
#
|
||||
# Help screen and output util
|
||||
#
|
||||
|
||||
error="\e[31;1merror:\e[0m"
|
||||
Cg="$(tput setaf 8)$(tput bold)"
|
||||
Cr="$(tput setaf 1)$(tput bold)"
|
||||
Cg="$(tput setaf 2)$(tput bold)"
|
||||
Cy="$(tput setaf 2)$(tput bold)"
|
||||
Cp="$(tput setaf 5)$(tput setaf 62)$(tput bold)"
|
||||
C0="$(tput setaf 0)$(tput sgr 0)"
|
||||
|
||||
|
@ -22,28 +37,37 @@ help()
|
|||
Configuration script for the gint library.
|
||||
|
||||
Options that affect the behavior of the library:
|
||||
$Cr--no-syscalls$C0 [default:$Cp false$C0]
|
||||
Never use syscalls. Expect some trouble with the malloc() function...
|
||||
Do not enable this option unless you know what you are doing.
|
||||
$Cr--extended-libc$C0 [default:$Cp false$C0]
|
||||
Enable specific C99 headers/features that are normally not required by
|
||||
calculator programs. May allow porting programs from other platforms.
|
||||
$Cr--diagnostics $Cg[default:$Cp false$Cg]$C0
|
||||
Use gint in debug mode, where the library outputs some diagnostics in
|
||||
memory or briefly on screen to diagnose incompatibilites or crashes.
|
||||
$Cr--no-syscalls $Cg[default:$Cp false$Cg]$C0
|
||||
Never use syscalls. Expect some trouble with the malloc() function... do
|
||||
not trigger this switch unless you know what you are doing.
|
||||
$Cr--extended-libc $Cg[default:$Cp false$Cg]$C0
|
||||
Enable specific C99 headers/features that are normally not required by
|
||||
calculator programs. This may allow porting programs from other platforms.
|
||||
|
||||
Options that customize size limits:
|
||||
$Cr--atexit-max=$C0$Cg<integer>$C0 [default:$Cp 16$C0]
|
||||
Number of exit handlers that can be registered by atexit().
|
||||
$Cr--rtc-callbacks=$C0$Cg<integer>$C0 [default:$Cp 5$C0]
|
||||
Number of RTC callbacks that can be registered.
|
||||
$Cr--events-queue-size=$C0$Cg<integer>$C0 [default:$Cp 64$C0]
|
||||
Number of events simultaneously stored in the event queue.
|
||||
$Cr--atexit-max$C0=$Cy<integer>$Cg [default:$Cp 16$Cg]$C0
|
||||
Number of exit handlers that can be registered by atexit().
|
||||
$Cr--rtc-callbacks$C0=$Cy<integer>$Cg [default:$Cp 5$Cg]$C0
|
||||
Number of RTC callbacks that can be registered.
|
||||
$Cr--events-queue-size$C0=$Cy<integer>$Cg [default:$Cp 64$Cg]$C0
|
||||
Number of events simultaneously stored in the event queue.
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
#
|
||||
# Parsing arguments
|
||||
#
|
||||
|
||||
fail=false
|
||||
for arg; do case "$arg" in
|
||||
-h | --help) help;;
|
||||
--no-syscalls) conf[GINT_NO_SYSCALLS]=true;;
|
||||
--diagnostics) conf[GINT_DIAGNOSTICS]=true;;
|
||||
--no-syscalls) conf[GINT_NO_SYSCALLS]=true;;
|
||||
--extended-libc) conf[GINT_EXTENDED_LIBC]=true;;
|
||||
|
||||
--atexit-max=*)
|
||||
|
@ -73,17 +97,19 @@ for arg; do case "$arg" in
|
|||
echo -e "$error unrecognized argument '$arg'"; fail=true;;
|
||||
esac; done
|
||||
|
||||
#
|
||||
# Output config routines
|
||||
#
|
||||
|
||||
output_config_gcc()
|
||||
{
|
||||
[ "${conf[GINT_DIAGNOSTICS]}" != "" ] && echo "-D GINT_DIAGNOSTICS"
|
||||
[ "${conf[GINT_NO_SYSCALLS]}" != "" ] && echo "-D GINT_NO_SYSCALLS"
|
||||
[ "${conf[GINT_EXTENDED_LIBC]}" != "" ] && echo "-D GINT_EXTENDED_LIBC"
|
||||
|
||||
echo "-D ATEXIT_MAX=${conf[ATEXIT_MAX]}"
|
||||
echo "-D RTC_CB_ARRAY_SIZE=${conf[RTC_CB_ARRAY_SIZE]}"
|
||||
echo "-D EVENTS_QUEUE_SIZE=${conf[EVENTS_QUEUE_SIZE]}"
|
||||
if [ "${conf[GINT_NO_SYSCALLS]}" != "" ]; then
|
||||
echo "-D GINT_NO_SYSCALLS"
|
||||
fi
|
||||
if [ "${conf[GINT_EXTENDED_LIBC]}" != "" ]; then
|
||||
echo "-D GINT_EXTENDED_LIBC"
|
||||
fi
|
||||
}
|
||||
|
||||
output_config_make()
|
||||
|
@ -91,6 +117,10 @@ output_config_make()
|
|||
[ "${conf[GINT_EXTENDED_LIBC]}" != "" ] && echo "config_ext=true"
|
||||
}
|
||||
|
||||
#
|
||||
# Output config
|
||||
#
|
||||
|
||||
if $fail; then
|
||||
echo "Configuration has not been modified."
|
||||
else
|
||||
|
|
31
debug/addin.ld
Normal file
31
debug/addin.ld
Normal file
|
@ -0,0 +1,31 @@
|
|||
OUTPUT_ARCH(sh3)
|
||||
ENTRY(initialize)
|
||||
MEMORY
|
||||
{
|
||||
rom : o = 0x00300200, l = 512k
|
||||
ram : o = 0x08100000, l = 64k /* pretty safe guess */
|
||||
}
|
||||
SECTIONS
|
||||
{
|
||||
.text : {
|
||||
*(.pretext) /* init stuff */
|
||||
*(.text)
|
||||
} > rom
|
||||
.rodata : {
|
||||
*(.rodata)
|
||||
*(.rodata.str1.4)
|
||||
_romdata = . ; /* symbol for initialization data */
|
||||
} > rom
|
||||
.bss : {
|
||||
_bbss = . ;
|
||||
_bssdatasize = . ;
|
||||
LONG(0); /* bssdatasize */
|
||||
*(.bss) *(COMMON);
|
||||
_ebss = . ;
|
||||
} > ram
|
||||
.data : AT(_romdata) {
|
||||
_bdata = . ;
|
||||
*(.data);
|
||||
_edata = . ;
|
||||
} > ram
|
||||
}
|
172
debug/crt0.s
Normal file
172
debug/crt0.s
Normal file
|
@ -0,0 +1,172 @@
|
|||
.section .pretext
|
||||
.global initialize
|
||||
initialize:
|
||||
sts.l pr, @-r15
|
||||
|
||||
! set up TLB
|
||||
mov.l Hmem_SetMMU, r3
|
||||
mov.l address_one, r4 ! 0x8102000
|
||||
mov.l address_two, r5 ! 0x8801E000
|
||||
jsr @r3 ! _Hmem_SetMMU
|
||||
mov #108, r6
|
||||
|
||||
! clear the BSS
|
||||
mov.l bbss, r4 ! start
|
||||
mov.l ebss, r5 ! end
|
||||
bra L_check_bss
|
||||
mov #0, r6
|
||||
L_zero_bss:
|
||||
mov.l r6, @r4 ! zero and advance
|
||||
add #4, r4
|
||||
L_check_bss:
|
||||
cmp/hs r5, r4
|
||||
bf L_zero_bss
|
||||
|
||||
! Copy the .data
|
||||
mov.l bdata, r4 ! dest
|
||||
mov.l edata, r5 ! dest limit
|
||||
mov.l romdata, r6 ! source
|
||||
bra L_check_data
|
||||
nop
|
||||
L_copy_data:
|
||||
mov.l @r6+, r3
|
||||
mov.l r3, @r4
|
||||
add #4, r4
|
||||
L_check_data:
|
||||
cmp/hs r5, r4
|
||||
bf L_copy_data
|
||||
|
||||
mov.l bbss, r4
|
||||
mov.l edata, r5
|
||||
sub r4, r5 ! size of .bss and .data sections
|
||||
add #4, r5
|
||||
mov.l bssdatasize, r4
|
||||
mov.l r5, @r4
|
||||
|
||||
mov.l GLibAddinAplExecutionCheck, r2
|
||||
mov #0, r4
|
||||
mov #1, r5
|
||||
jsr @r2 ! _GLibAddinAplExecutionCheck(0,1,1);
|
||||
mov r5, r6
|
||||
|
||||
mov.l CallbackAtQuitMainFunction, r3
|
||||
mov.l exit_handler, r4
|
||||
jsr @r3 ! _CallbackAtQuitMainFunction(&exit_handler)
|
||||
nop
|
||||
mov.l main, r3
|
||||
jmp @r3 ! _main()
|
||||
lds.l @r15+, pr
|
||||
|
||||
_exit_handler:
|
||||
mov.l r14, @-r15
|
||||
mov.l r13, @-r15
|
||||
mov.l r12, @-r15
|
||||
sts.l pr, @-r15
|
||||
|
||||
mov.l Bdel_cychdr, r14
|
||||
jsr @r14 ! _Bdel_cychdr
|
||||
mov #6, r4
|
||||
jsr @r14 ! _Bdel_cychdr
|
||||
mov #7, r4
|
||||
jsr @r14 ! _Bdel_cychdr
|
||||
mov #8, r4
|
||||
jsr @r14 ! _Bdel_cychdr
|
||||
mov #9, r4
|
||||
jsr @r14 ! _Bdel_cychdr
|
||||
mov #10, r4
|
||||
|
||||
mov.l BfileFLS_CloseFile, r12
|
||||
mov #4, r14
|
||||
mov #0, r13
|
||||
L_close_files:
|
||||
jsr @r12 ! _BfileFLS_CloseFile
|
||||
mov r13, r4
|
||||
add #1, r13
|
||||
cmp/ge r14, r13
|
||||
bf L_close_files
|
||||
|
||||
mov.l flsFindClose, r12
|
||||
mov #0, r13
|
||||
L_close_finds:
|
||||
jsr @r12 ! _flsFindClose
|
||||
mov r13, r4
|
||||
add #1, r13
|
||||
cmp/ge r14, r13
|
||||
bf L_close_finds
|
||||
|
||||
lds.l @r15+, pr
|
||||
mov.l @r15+, r12
|
||||
mov.l @r15+, r13
|
||||
mov.l Bkey_Set_RepeatTime_Default, r2
|
||||
jmp @r2 ! _Bkey_Set_RepeatTime_Default
|
||||
mov.l @r15+, r14
|
||||
|
||||
.align 4
|
||||
address_two: .long 0x8801E000
|
||||
address_one: .long 0x8102000
|
||||
Hmem_SetMMU: .long _Hmem_SetMMU
|
||||
GLibAddinAplExecutionCheck: .long _GLibAddinAplExecutionCheck
|
||||
CallbackAtQuitMainFunction: .long _CallbackAtQuitMainFunction
|
||||
Bdel_cychdr: .long _Bdel_cychdr
|
||||
BfileFLS_CloseFile: .long _BfileFLS_CloseFile
|
||||
flsFindClose: .long _flsFindClose
|
||||
Bkey_Set_RepeatTime_Default: .long _Bkey_Set_RepeatTime_Default
|
||||
bbss: .long _bbss
|
||||
ebss: .long _ebss
|
||||
edata: .long _edata
|
||||
bdata: .long _bdata
|
||||
romdata: .long _romdata
|
||||
bssdatasize: .long _bssdatasize
|
||||
|
||||
exit_handler: .long _exit_handler
|
||||
main: .long _main
|
||||
|
||||
_Hmem_SetMMU:
|
||||
mov.l sc_addr, r2
|
||||
mov.l 1f, r0
|
||||
jmp @r2
|
||||
nop
|
||||
1: .long 0x3FA
|
||||
|
||||
_Bdel_cychdr:
|
||||
mov.l sc_addr, r2
|
||||
mov.l 1f, r0
|
||||
jmp @r2
|
||||
nop
|
||||
1: .long 0x119
|
||||
|
||||
_BfileFLS_CloseFile:
|
||||
mov.l sc_addr, r2
|
||||
mov.l 1f, r0
|
||||
jmp @r2
|
||||
nop
|
||||
1: .long 0x1E7
|
||||
|
||||
_Bkey_Set_RepeatTime_Default:
|
||||
mov.l sc_addr, r2
|
||||
mov.l 1f, r0
|
||||
jmp @r2
|
||||
nop
|
||||
1: .long 0x244
|
||||
|
||||
_CallbackAtQuitMainFunction:
|
||||
mov.l sc_addr, r2
|
||||
mov.l 1f, r0
|
||||
jmp @r2
|
||||
nop
|
||||
1: .long 0x494
|
||||
|
||||
_flsFindClose:
|
||||
mov.l sc_addr, r2
|
||||
mov.l 1f, r0
|
||||
jmp @r2
|
||||
nop
|
||||
1: .long 0x218
|
||||
|
||||
_GLibAddinAplExecutionCheck:
|
||||
mov.l sc_addr, r2
|
||||
mov #0x13, r0
|
||||
jmp @r2
|
||||
nop
|
||||
sc_addr: .long 0x80010070
|
||||
.end
|
178
debug/gintdbg.c
Normal file
178
debug/gintdbg.c
Normal file
|
@ -0,0 +1,178 @@
|
|||
//---
|
||||
//
|
||||
// gintdbg
|
||||
//
|
||||
// A simple debugger for gint applications, providing diagnoses to
|
||||
// determine what went bad.
|
||||
//
|
||||
//---
|
||||
|
||||
// Just for structure definitions, gint does not run here.
|
||||
#define GINT_DIAGNOSTICS
|
||||
#include <internals/gint.h>
|
||||
#include <mpu.h>
|
||||
|
||||
#include <fxlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Some functions from other files...
|
||||
int vsprintf(char *buffer, const char *format, va_list args);
|
||||
int sprintf(char *buffer, const char *format, ...);
|
||||
|
||||
//---
|
||||
// Some util...
|
||||
//---
|
||||
|
||||
static int print_row = 1;
|
||||
|
||||
void print(int col, const char *format, ...)
|
||||
{
|
||||
int row = print_row;
|
||||
print_row++;
|
||||
if(row < 1 || row > 8) return;
|
||||
|
||||
char buffer[256];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf(buffer, format, args);
|
||||
va_end(args);
|
||||
|
||||
locate(col, row);
|
||||
Print((unsigned char *)buffer);
|
||||
}
|
||||
|
||||
void newline(void)
|
||||
{
|
||||
print_row++;
|
||||
}
|
||||
|
||||
void nothing_found(void)
|
||||
{
|
||||
unsigned int key;
|
||||
|
||||
Bdisp_AllClr_VRAM();
|
||||
PopUpWin(6);
|
||||
print_row = 2;
|
||||
print(3, "Apparently there");
|
||||
print(3, "is no diagnostic.");
|
||||
print(3, "");
|
||||
print(3, "Show anyway?");
|
||||
print(3, " Yes:[F1]");
|
||||
print(3, " No :[MENU]");
|
||||
|
||||
do GetKey(&key);
|
||||
while(key != KEY_CTRL_F1);
|
||||
}
|
||||
|
||||
void show_diagnostics(void)
|
||||
{
|
||||
volatile gint_diagnostics_t *dg = gint_diagnostics();
|
||||
|
||||
const char *stages[] = {
|
||||
"Startup", "Sections", "MMU", "Gint", "Clock", "Constructors",
|
||||
"Running", "Leaving", "Destructors", "Terminated",
|
||||
};
|
||||
const char *mpus[] = {
|
||||
"Unknown", "SH7337", "SH7355", "SH7305", "SH7724",
|
||||
};
|
||||
|
||||
print(1, "Gint debugger (%d)", dg->counter);
|
||||
newline();
|
||||
|
||||
print(1, "General information");
|
||||
print(2, "Magic 0x%02x", dg->magic);
|
||||
print(2, "Stage %s", dg->stage <= 9 ? stages[dg->stage] : "-");
|
||||
if(dg->stage >= stage_gint)
|
||||
{
|
||||
print(2, "MPU %s", dg->mpu <= 4 ? mpus[dg->mpu] : "-");
|
||||
}
|
||||
print(2, "Version %08x", dg->version);
|
||||
newline();
|
||||
|
||||
print(1, "Memory map");
|
||||
print(2, "%08x romdata", dg->romdata);
|
||||
print(2, "%08x vbr", dg->vbr_address);
|
||||
print(2, "%08x:%05x text", dg->section_text.address,
|
||||
dg->section_text.length);
|
||||
print(2, "%08x:%05x data", dg->section_data.address,
|
||||
dg->section_data.length);
|
||||
print(2, "%08x:%05x bss", dg->section_bss.address,
|
||||
dg->section_bss.length);
|
||||
|
||||
print(2, "%08x:%05x gint", dg->section_gint.address,
|
||||
dg->section_gint.length);
|
||||
newline();
|
||||
|
||||
print(1, "Exception records");
|
||||
size_t len = sizeof dg->except_vect;
|
||||
char line[19];
|
||||
for(size_t i = 0; i < len; i += 6)
|
||||
{
|
||||
for(size_t n = 0; n < 6 && i + n < len; n++)
|
||||
{
|
||||
size_t index = (dg->excepts + i + n) % len;
|
||||
sprintf(line + 3 * n, " %02x", dg->except_vect[index]);
|
||||
}
|
||||
|
||||
print(1, "%s", line);
|
||||
}
|
||||
print(2, "SPC %08x", dg->spc);
|
||||
print(2, "SSR %08x", dg->ssr);
|
||||
print(2, "EXPEVT %08x", dg->expevt);
|
||||
print(2, "TEA %08x", dg->tea);
|
||||
newline();
|
||||
|
||||
if(dg->stage >= stage_clock)
|
||||
{
|
||||
print(1, "Clock frequencies");
|
||||
print(2, "Bus clock %d MHz", dg->Bphi_f);
|
||||
print(2, "Peripheral %d MHz", dg->Pphi_f);
|
||||
print(2, "Processor %d MHz", dg->Iphi_f);
|
||||
newline();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
main()
|
||||
Let's do this!
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
volatile gint_diagnostics_t *dg = gint_diagnostics();
|
||||
unsigned int key;
|
||||
|
||||
if(dg->magic != GINT_DIAGNOSTICS_MAGIC
|
||||
|| dg->stage > 9
|
||||
|| dg->mpu > 4
|
||||
) nothing_found();
|
||||
|
||||
int total_height = -1;
|
||||
int y = 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
Bdisp_AllClr_VRAM();
|
||||
print_row = 1 - y;
|
||||
|
||||
show_diagnostics();
|
||||
if(total_height < 0) total_height = print_row - 1;
|
||||
|
||||
// Drawing a scrollbar.
|
||||
if(total_height > 8)
|
||||
{
|
||||
int base = (64 * y) / total_height;
|
||||
int height = (64 * 8) / total_height;
|
||||
Bdisp_DrawLineVRAM(127, base, 127, base + height);
|
||||
}
|
||||
Bdisp_PutDisp_DD();
|
||||
|
||||
do GetKey(&key);
|
||||
while(key != KEY_CTRL_UP && key != KEY_CTRL_DOWN);
|
||||
|
||||
if(key == KEY_CTRL_UP && y > 0) y--;
|
||||
else if(key == KEY_CTRL_DOWN && y + 8 < total_height) y++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
BIN
debug/icon.bmp
Normal file
BIN
debug/icon.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
97
debug/include/dispbios.h
Normal file
97
debug/include/dispbios.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*****************************************************************/
|
||||
/* */
|
||||
/* CASIO fx-9860G SDK Library */
|
||||
/* */
|
||||
/* File name : dispbios.h */
|
||||
/* */
|
||||
/* Copyright (c) 2006 CASIO COMPUTER CO., LTD. */
|
||||
/* */
|
||||
/*****************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __DISPBIOS_H__
|
||||
#define __DISPBIOS_H__
|
||||
|
||||
|
||||
// Defines
|
||||
|
||||
#define IM_VRAM_WIDTH 128
|
||||
#define IM_VRAM_HEIGHT 64
|
||||
|
||||
#define IM_VRAM_SIZE 1024
|
||||
|
||||
#define IM_CHARACTERS_MAX_LINE 21
|
||||
#define IM_BYTES_MAX_LINE (IM_CHARACTERS_MAX_LINE*2)
|
||||
|
||||
#define SAVEDISP_PAGE1 1
|
||||
#define SAVEDISP_PAGE2 5
|
||||
#define SAVEDISP_PAGE3 6
|
||||
|
||||
#define MINI_OVER 0x10
|
||||
#define MINI_OR 0x11
|
||||
#define MINI_REV 0x12
|
||||
#define MINI_REVOR 0x13
|
||||
|
||||
#define IM_BIOS_DD_WIDTH IM_VRAM_WIDTH
|
||||
#define IM_BIOS_DD_HEIGHT IM_VRAM_HEIGHT
|
||||
|
||||
#define WRITEKIND unsigned char
|
||||
#define IMB_WRITEKIND_OVER 0x01
|
||||
#define IMB_WRITEKIND_OR 0x02
|
||||
#define IMB_WRITEKIND_AND 0x03
|
||||
#define IMB_WRITEKIND_XOR 0x04
|
||||
|
||||
#define WRITEMODIFY unsigned char
|
||||
#define IMB_WRITEMODIFY_NORMAL 0x01
|
||||
#define IMB_WRITEMODIFY_REVERCE 0x02
|
||||
#define IMB_WRITEMODIFY_MESH 0x03
|
||||
|
||||
#define AREAKIND unsigned char
|
||||
#define IMB_AREAKIND_OVER 0x01
|
||||
#define IMB_AREAKIND_MESH 0x02
|
||||
#define IMB_AREAKIND_CLR 0x03
|
||||
#define IMB_AREAKIND_REVERSE 0x04
|
||||
|
||||
#define EFFECTWIN unsigned char
|
||||
#define IMB_EFFECTWIN_OK 0x01
|
||||
#define IMB_EFFECTWIN_NG 0x02
|
||||
|
||||
|
||||
// Structs
|
||||
|
||||
typedef struct tag_DISPBOX{
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
} DISPBOX;
|
||||
|
||||
typedef struct tag_GRAPHDATA{
|
||||
int width;
|
||||
int height;
|
||||
unsigned char *pBitmap;
|
||||
} GRAPHDATA;
|
||||
|
||||
typedef struct tag_RECTANGLE{
|
||||
DISPBOX LineArea;
|
||||
AREAKIND AreaKind;
|
||||
EFFECTWIN EffectWin;
|
||||
} RECTANGLE;
|
||||
|
||||
typedef struct tag_DISPGRAPH{
|
||||
int x;
|
||||
int y;
|
||||
GRAPHDATA GraphData;
|
||||
WRITEMODIFY WriteModify;
|
||||
WRITEKIND WriteKind;
|
||||
} DISPGRAPH;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
31
debug/include/endian.h
Normal file
31
debug/include/endian.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*****************************************************************/
|
||||
/* */
|
||||
/* CASIO fx-9860G SDK Library */
|
||||
/* */
|
||||
/* File name : endian.h */
|
||||
/* */
|
||||
/* Copyright (c) 2006 CASIO COMPUTER CO., LTD. */
|
||||
/* */
|
||||
/*****************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __ENDIAN_H__
|
||||
#define __ENDIAN_H__
|
||||
|
||||
|
||||
// Macros
|
||||
|
||||
#define UtlSwapWord(w) (unsigned short)((((w) & 0x00ff) << 8) | (((w) & 0xff00) >> 8))
|
||||
#define UtlSwapDword(l) (unsigned long)((((l) & 0x000000ff) << 24) | (((l) & 0x0000ff00) << 8) | (((l) & 0xff000000) >> 24) | (((l) & 0x00ff0000) >> 8))
|
||||
#define UtlSwapInteger(i) UtlSwapDword(i)
|
||||
#define UtlSwapPointer(p) (void*)((((unsigned long)(p) & 0x000000ff) << 24) | (((unsigned long)(p) & 0x0000ff00) << 8) | (((unsigned long)(p) & 0xff000000) >> 24) | (((unsigned long)(p) & 0x00ff0000) >> 8))
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
116
debug/include/filebios.h
Normal file
116
debug/include/filebios.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*****************************************************************/
|
||||
/* */
|
||||
/* CASIO fx-9860G SDK Library */
|
||||
/* */
|
||||
/* File name : filebios.h */
|
||||
/* */
|
||||
/* Copyright (c) 2006 CASIO COMPUTER CO., LTD. */
|
||||
/* */
|
||||
/*****************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __FILEBIOS_H__
|
||||
#define __FILEBIOS_H__
|
||||
|
||||
|
||||
// Defines
|
||||
|
||||
#define FONTCHARACTER unsigned short
|
||||
|
||||
#define _OPENMODE_READ 0x01
|
||||
#define _OPENMODE_READ_SHARE 0x80
|
||||
#define _OPENMODE_WRITE 0x02
|
||||
#define _OPENMODE_READWRITE 0x03
|
||||
#define _OPENMODE_READWRITE_SHARE 0x83
|
||||
|
||||
#define _CREATEMODE_BINARY 1
|
||||
#define _CREATEMODE_DIRECTORY 5
|
||||
|
||||
enum DEVICE_TYPE{
|
||||
DEVICE_MAIN_MEMORY,
|
||||
DEVICE_STORAGE,
|
||||
DEVICE_SD_CARD, // only fx-9860G SD model
|
||||
};
|
||||
|
||||
|
||||
// File system standard error code
|
||||
#define IML_FILEERR_NOERROR 0
|
||||
#define IML_FILEERR_ENTRYNOTFOUND -1
|
||||
#define IML_FILEERR_ILLEGALPARAM -2
|
||||
#define IML_FILEERR_ILLEGALPATH -3
|
||||
#define IML_FILEERR_DEVICEFULL -4
|
||||
#define IML_FILEERR_ILLEGALDEVICE -5
|
||||
#define IML_FILEERR_ILLEGALFILESYS -6
|
||||
#define IML_FILEERR_ILLEGALSYSTEM -7
|
||||
#define IML_FILEERR_ACCESSDENYED -8
|
||||
#define IML_FILEERR_ALREADYLOCKED -9
|
||||
#define IML_FILEERR_ILLEGALTASKID -10
|
||||
#define IML_FILEERR_PERMISSIONERROR -11
|
||||
#define IML_FILEERR_ENTRYFULL -12
|
||||
#define IML_FILEERR_ALREADYEXISTENTRY -13
|
||||
#define IML_FILEERR_READONLYFILE -14
|
||||
#define IML_FILEERR_ILLEGALFILTER -15
|
||||
#define IML_FILEERR_ENUMRATEEND -16
|
||||
#define IML_FILEERR_DEVICECHANGED -17
|
||||
//#define IML_FILEERR_NOTRECORDFILE -18 // Not used
|
||||
#define IML_FILEERR_ILLEGALSEEKPOS -19
|
||||
#define IML_FILEERR_ILLEGALBLOCKFILE -20
|
||||
//#define IML_FILEERR_DEVICENOTEXIST -21 // Not used
|
||||
//#define IML_FILEERR_ENDOFFILE -22 // Not used
|
||||
#define IML_FILEERR_NOTMOUNTDEVICE -23
|
||||
#define IML_FILEERR_NOTUNMOUNTDEVICE -24
|
||||
#define IML_FILEERR_CANNOTLOCKSYSTEM -25
|
||||
#define IML_FILEERR_RECORDNOTFOUND -26
|
||||
//#define IML_FILEERR_NOTDUALRECORDFILE -27 // Not used
|
||||
#define IML_FILEERR_NOTALARMSUPPORT -28
|
||||
#define IML_FILEERR_CANNOTADDALARM -29
|
||||
#define IML_FILEERR_FILEFINDUSED -30
|
||||
#define IML_FILEERR_DEVICEERROR -31
|
||||
#define IML_FILEERR_SYSTEMNOTLOCKED -32
|
||||
#define IML_FILEERR_DEVICENOTFOUND -33
|
||||
#define IML_FILEERR_FILETYPEMISMATCH -34
|
||||
#define IML_FILEERR_NOTEMPTY -35
|
||||
#define IML_FILEERR_BROKENSYSTEMDATA -36
|
||||
#define IML_FILEERR_MEDIANOTREADY -37
|
||||
#define IML_FILEERR_TOOMANYALARMITEM -38
|
||||
#define IML_FILEERR_SAMEALARMEXIST -39
|
||||
#define IML_FILEERR_ACCESSSWAPAREA -40
|
||||
#define IML_FILEERR_MULTIMEDIACARD -41
|
||||
#define IML_FILEERR_COPYPROTECTION -42
|
||||
#define IML_FILEERR_ILLEGALFILEDATA -43
|
||||
|
||||
// FILE_INFO.type
|
||||
#define DT_DIRECTORY 0x0000 // Directory
|
||||
#define DT_FILE 0x0001 // File
|
||||
#define DT_ADDIN_APP 0x0002 // Add-In application
|
||||
#define DT_EACT 0x0003 // eActivity
|
||||
#define DT_LANGUAGE 0x0004 // Language
|
||||
#define DT_BITMAP 0x0005 // Bitmap
|
||||
#define DT_MAINMEM 0x0006 // Main Memory data
|
||||
#define DT_TEMP 0x0007 // Temporary data
|
||||
#define DT_DOT 0x0008 // . (Current directory)
|
||||
#define DT_DOTDOT 0x0009 // .. (Parent directory)
|
||||
#define DT_VOLUME 0x000A // Volume label
|
||||
|
||||
|
||||
// Structs
|
||||
|
||||
typedef struct tag_FILE_INFO
|
||||
{
|
||||
unsigned short id;
|
||||
unsigned short type;
|
||||
unsigned long fsize; // File size
|
||||
unsigned long dsize; // Data size
|
||||
unsigned int property; // The file has not been completed, except when property is 0.
|
||||
unsigned long address;
|
||||
} FILE_INFO;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
100
debug/include/fxlib.h
Normal file
100
debug/include/fxlib.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*****************************************************************/
|
||||
/* */
|
||||
/* CASIO fx-9860G SDK Library */
|
||||
/* */
|
||||
/* File name : fxlib.h */
|
||||
/* */
|
||||
/* Copyright (c) 2006 CASIO COMPUTER CO., LTD. */
|
||||
/* */
|
||||
/*****************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __FXLIB_H__
|
||||
#define __FXLIB_H__
|
||||
|
||||
#include "dispbios.h"
|
||||
#include "filebios.h"
|
||||
#include "keybios.h"
|
||||
|
||||
|
||||
// Prototypes
|
||||
|
||||
void Bdisp_AllClr_DD(void);
|
||||
void Bdisp_AllClr_VRAM(void);
|
||||
void Bdisp_AllClr_DDVRAM(void);
|
||||
void Bdisp_AreaClr_DD(const DISPBOX *pArea);
|
||||
void Bdisp_AreaClr_VRAM(const DISPBOX *pArea);
|
||||
void Bdisp_AreaClr_DDVRAM(const DISPBOX *pArea);
|
||||
void Bdisp_AreaReverseVRAM(int x1, int y1, int x2, int y2);
|
||||
void Bdisp_GetDisp_DD(unsigned char *pData);
|
||||
void Bdisp_GetDisp_VRAM(unsigned char *pData);
|
||||
void Bdisp_PutDisp_DD(void);
|
||||
void Bdisp_PutDispArea_DD(const DISPBOX *PutDispArea);
|
||||
void Bdisp_SetPoint_DD(int x, int y, unsigned char point);
|
||||
void Bdisp_SetPoint_VRAM(int x, int y, unsigned char point);
|
||||
void Bdisp_SetPoint_DDVRAM(int x, int y, unsigned char point);
|
||||
int Bdisp_GetPoint_VRAM(int x, int y);
|
||||
void Bdisp_WriteGraph_DD(const DISPGRAPH *WriteGraph);
|
||||
void Bdisp_WriteGraph_VRAM(const DISPGRAPH *WriteGraph);
|
||||
void Bdisp_WriteGraph_DDVRAM(const DISPGRAPH *WriteGraph);
|
||||
void Bdisp_ReadArea_DD(const DISPBOX *ReadArea, unsigned char *ReadData);
|
||||
void Bdisp_ReadArea_VRAM(const DISPBOX *ReadArea, unsigned char *ReadData);
|
||||
void Bdisp_DrawLineVRAM(int x1, int y1, int x2, int y2);
|
||||
void Bdisp_ClearLineVRAM(int x1, int y1, int x2, int y2);
|
||||
|
||||
void locate(int x, int y);
|
||||
void Print(const unsigned char *str);
|
||||
void PrintRev(const unsigned char *str);
|
||||
void PrintC(const unsigned char *c);
|
||||
void PrintRevC(const unsigned char *str);
|
||||
void PrintLine(const unsigned char *str, int max);
|
||||
void PrintRLine(const unsigned char *str, int max);
|
||||
void PrintXY(int x, int y, const unsigned char *str, int type);
|
||||
int PrintMini(int x, int y, const unsigned char *str, int type);
|
||||
void SaveDisp(unsigned char num);
|
||||
void RestoreDisp(unsigned char num);
|
||||
void PopUpWin(int n);
|
||||
|
||||
int Bfile_OpenFile(const FONTCHARACTER *filename, int mode);
|
||||
int Bfile_OpenMainMemory(const unsigned char *name);
|
||||
int Bfile_ReadFile(int HANDLE, void *buf, int size, int readpos);
|
||||
int Bfile_WriteFile(int HANDLE, const void *buf, int size);
|
||||
int Bfile_SeekFile(int HANDLE, int pos);
|
||||
int Bfile_CloseFile(int HANDLE);
|
||||
int Bfile_GetMediaFree(enum DEVICE_TYPE devicetype, int *freebytes);
|
||||
int Bfile_GetFileSize(int HANDLE);
|
||||
int Bfile_CreateFile(const FONTCHARACTER *filename, int size);
|
||||
int Bfile_CreateDirectory(const FONTCHARACTER *pathname);
|
||||
int Bfile_CreateMainMemory(const unsigned char *name);
|
||||
int Bfile_RenameMainMemory(const unsigned char *oldname, const unsigned char *newname);
|
||||
int Bfile_DeleteFile(const FONTCHARACTER *filename);
|
||||
int Bfile_DeleteDirectory(const FONTCHARACTER *pathname);
|
||||
int Bfile_DeleteMainMemory(const unsigned char *name);
|
||||
int Bfile_FindFirst(const FONTCHARACTER *pathname, int *FindHandle, FONTCHARACTER *foundfile, FILE_INFO *fileinfo);
|
||||
int Bfile_FindNext(int FindHandle, FONTCHARACTER *foundfile, FILE_INFO *fileinfo);
|
||||
int Bfile_FindClose(int FindHandle);
|
||||
|
||||
void Bkey_Set_RepeatTime(long FirstCount, long NextCount);
|
||||
void Bkey_Get_RepeatTime(long *FirstCount, long *NextCount);
|
||||
void Bkey_Set_RepeatTime_Default(void);
|
||||
int GetKeyWait(int sel, int time, int menu, unsigned int *keycode);
|
||||
int IsKeyDown(int keycode);
|
||||
int IsKeyUp(int keycode);
|
||||
int GetKey(unsigned int *keycode);
|
||||
|
||||
int SetTimer(int ID, int elapse, void (*hander)(void));
|
||||
int KillTimer(int ID);
|
||||
void Sleep(int millisecond);
|
||||
|
||||
void SetQuitHandler(void (*callback)(void));
|
||||
int INIT_ADDIN_APPLICATION(int isAppli, unsigned short OptionNum);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
158
debug/include/keybios.h
Normal file
158
debug/include/keybios.h
Normal file
|
@ -0,0 +1,158 @@
|
|||
/*****************************************************************/
|
||||
/* */
|
||||
/* CASIO fx-9860G SDK Library */
|
||||
/* */
|
||||
/* File name : keybios.h */
|
||||
/* */
|
||||
/* Copyright (c) 2006 CASIO COMPUTER CO., LTD. */
|
||||
/* */
|
||||
/*****************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __KEYBIOS_H__
|
||||
#define __KEYBIOS_H__
|
||||
|
||||
|
||||
// Defines
|
||||
|
||||
// Character codes
|
||||
#define KEY_CHAR_0 0x30
|
||||
#define KEY_CHAR_1 0x31
|
||||
#define KEY_CHAR_2 0x32
|
||||
#define KEY_CHAR_3 0x33
|
||||
#define KEY_CHAR_4 0x34
|
||||
#define KEY_CHAR_5 0x35
|
||||
#define KEY_CHAR_6 0x36
|
||||
#define KEY_CHAR_7 0x37
|
||||
#define KEY_CHAR_8 0x38
|
||||
#define KEY_CHAR_9 0x39
|
||||
#define KEY_CHAR_DP 0x2e
|
||||
#define KEY_CHAR_EXP 0x0f
|
||||
#define KEY_CHAR_PMINUS 0x87
|
||||
#define KEY_CHAR_PLUS 0x89
|
||||
#define KEY_CHAR_MINUS 0x99
|
||||
#define KEY_CHAR_MULT 0xa9
|
||||
#define KEY_CHAR_DIV 0xb9
|
||||
#define KEY_CHAR_FRAC 0xbb
|
||||
#define KEY_CHAR_LPAR 0x28
|
||||
#define KEY_CHAR_RPAR 0x29
|
||||
#define KEY_CHAR_COMMA 0x2c
|
||||
#define KEY_CHAR_STORE 0x0e
|
||||
#define KEY_CHAR_LOG 0x95
|
||||
#define KEY_CHAR_LN 0x85
|
||||
#define KEY_CHAR_SIN 0x81
|
||||
#define KEY_CHAR_COS 0x82
|
||||
#define KEY_CHAR_TAN 0x83
|
||||
#define KEY_CHAR_SQUARE 0x8b
|
||||
#define KEY_CHAR_POW 0xa8
|
||||
#define KEY_CHAR_IMGNRY 0x7f50
|
||||
#define KEY_CHAR_LIST 0x7f51
|
||||
#define KEY_CHAR_MAT 0x7f40
|
||||
#define KEY_CHAR_EQUAL 0x3d
|
||||
#define KEY_CHAR_PI 0xd0
|
||||
#define KEY_CHAR_ANS 0xc0
|
||||
#define KEY_CHAR_LBRCKT 0x5b
|
||||
#define KEY_CHAR_RBRCKT 0x5d
|
||||
#define KEY_CHAR_LBRACE 0x7b
|
||||
#define KEY_CHAR_RBRACE 0x7d
|
||||
#define KEY_CHAR_CR 0x0d
|
||||
#define KEY_CHAR_CUBEROOT 0x96
|
||||
#define KEY_CHAR_RECIP 0x9b
|
||||
#define KEY_CHAR_ANGLE 0x7f54
|
||||
#define KEY_CHAR_EXPN10 0xb5
|
||||
#define KEY_CHAR_EXPN 0xa5
|
||||
#define KEY_CHAR_ASIN 0x91
|
||||
#define KEY_CHAR_ACOS 0x92
|
||||
#define KEY_CHAR_ATAN 0x93
|
||||
#define KEY_CHAR_ROOT 0x86
|
||||
#define KEY_CHAR_POWROOT 0xb8
|
||||
#define KEY_CHAR_SPACE 0x20
|
||||
#define KEY_CHAR_DQUATE 0x22
|
||||
#define KEY_CHAR_VALR 0xcd
|
||||
#define KEY_CHAR_THETA 0xce
|
||||
#define KEY_CHAR_A 0x41
|
||||
#define KEY_CHAR_B 0x42
|
||||
#define KEY_CHAR_C 0x43
|
||||
#define KEY_CHAR_D 0x44
|
||||
#define KEY_CHAR_E 0x45
|
||||
#define KEY_CHAR_F 0x46
|
||||
#define KEY_CHAR_G 0x47
|
||||
#define KEY_CHAR_H 0x48
|
||||
#define KEY_CHAR_I 0x49
|
||||
#define KEY_CHAR_J 0x4a
|
||||
#define KEY_CHAR_K 0x4b
|
||||
#define KEY_CHAR_L 0x4c
|
||||
#define KEY_CHAR_M 0x4d
|
||||
#define KEY_CHAR_N 0x4e
|
||||
#define KEY_CHAR_O 0x4f
|
||||
#define KEY_CHAR_P 0x50
|
||||
#define KEY_CHAR_Q 0x51
|
||||
#define KEY_CHAR_R 0x52
|
||||
#define KEY_CHAR_S 0x53
|
||||
#define KEY_CHAR_T 0x54
|
||||
#define KEY_CHAR_U 0x55
|
||||
#define KEY_CHAR_V 0x56
|
||||
#define KEY_CHAR_W 0x57
|
||||
#define KEY_CHAR_X 0x58
|
||||
#define KEY_CHAR_Y 0x59
|
||||
#define KEY_CHAR_Z 0x5a
|
||||
|
||||
|
||||
// Control codes
|
||||
#define KEY_CTRL_NOP 0
|
||||
#define KEY_CTRL_EXE 30004
|
||||
#define KEY_CTRL_DEL 30025
|
||||
#define KEY_CTRL_AC 30015
|
||||
#define KEY_CTRL_FD 30046
|
||||
#define KEY_CTRL_XTT 30001
|
||||
#define KEY_CTRL_EXIT 30002
|
||||
#define KEY_CTRL_SHIFT 30006
|
||||
#define KEY_CTRL_ALPHA 30007
|
||||
#define KEY_CTRL_OPTN 30008
|
||||
#define KEY_CTRL_VARS 30016
|
||||
#define KEY_CTRL_UP 30018
|
||||
#define KEY_CTRL_DOWN 30023
|
||||
#define KEY_CTRL_LEFT 30020
|
||||
#define KEY_CTRL_RIGHT 30021
|
||||
#define KEY_CTRL_F1 30009
|
||||
#define KEY_CTRL_F2 30010
|
||||
#define KEY_CTRL_F3 30011
|
||||
#define KEY_CTRL_F4 30012
|
||||
#define KEY_CTRL_F5 30013
|
||||
#define KEY_CTRL_F6 30014
|
||||
#define KEY_CTRL_CATALOG 30100
|
||||
#define KEY_CTRL_CAPTURE 30055
|
||||
#define KEY_CTRL_CLIP 30050
|
||||
#define KEY_CTRL_PASTE 30036
|
||||
#define KEY_CTRL_INS 30033
|
||||
#define KEY_CTRL_MIXEDFRAC 30054
|
||||
#define KEY_CTRL_FRACCNVRT 30026
|
||||
#define KEY_CTRL_QUIT 30029
|
||||
#define KEY_CTRL_PRGM 30028
|
||||
#define KEY_CTRL_SETUP 30037
|
||||
#define KEY_CTRL_PAGEUP 30052
|
||||
#define KEY_CTRL_PAGEDOWN 30053
|
||||
#define KEY_CTRL_MENU 30003
|
||||
#define KEY_CTRL_RESERVE1 30060
|
||||
#define KEY_CTRL_RESERVE2 30061
|
||||
#define KEY_CTRL_RESERVE3 30062
|
||||
|
||||
|
||||
// in Bkey_GetKeyWait function
|
||||
#define KEYWAIT_HALTON_TIMEROFF 0
|
||||
#define KEYWAIT_HALTOFF_TIMEROFF 1
|
||||
#define KEYWAIT_HALTON_TIMERON 2
|
||||
|
||||
#define KEYREP_NOEVENT 0
|
||||
#define KEYREP_KEYEVENT 1
|
||||
#define KEYREP_TIMEREVENT 2
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
31
debug/include/timer.h
Normal file
31
debug/include/timer.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*****************************************************************/
|
||||
/* */
|
||||
/* CASIO fx-9860G SDK Library */
|
||||
/* */
|
||||
/* File name : timer.h */
|
||||
/* */
|
||||
/* Copyright (c) 2006 CASIO COMPUTER CO., LTD. */
|
||||
/* */
|
||||
/*****************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __TIMER_H__
|
||||
#define __TIMER_H__
|
||||
|
||||
|
||||
// Defines
|
||||
|
||||
#define ID_USER_TIMER1 1
|
||||
#define ID_USER_TIMER2 2
|
||||
#define ID_USER_TIMER3 3
|
||||
#define ID_USER_TIMER4 4
|
||||
#define ID_USER_TIMER5 5
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
BIN
debug/libfx.a
Normal file
BIN
debug/libfx.a
Normal file
Binary file not shown.
160
debug/vsprintf.c
Normal file
160
debug/vsprintf.c
Normal file
|
@ -0,0 +1,160 @@
|
|||
//---
|
||||
// vsprintf()
|
||||
//
|
||||
// Unfortunately this function, which is part of fxlib, was broken by a
|
||||
// terribly un-professional port (incidentally, I am responsible for
|
||||
// this, so I can't complain). So we'll need something simple...
|
||||
//
|
||||
// Format Flags Character count
|
||||
// %d none no
|
||||
// %x 0 yes
|
||||
// %p none no
|
||||
// %c none no
|
||||
// %s none no
|
||||
//---
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void vsprintf_int(char **buffer_ptr, int n)
|
||||
{
|
||||
char *buffer = *buffer_ptr;
|
||||
if(!n)
|
||||
{
|
||||
*buffer++ = '0';
|
||||
*buffer_ptr = buffer;
|
||||
return;
|
||||
}
|
||||
if(n < 0)
|
||||
{
|
||||
*buffer++ = '-';
|
||||
n = -n;
|
||||
}
|
||||
|
||||
int digits = 0, x = n, copy;
|
||||
while(x) digits++, x /= 10;
|
||||
copy = digits;
|
||||
|
||||
while(digits)
|
||||
{
|
||||
buffer[--digits] = n % 10 + '0';
|
||||
n /= 10;
|
||||
}
|
||||
|
||||
*buffer_ptr = buffer + copy;
|
||||
}
|
||||
|
||||
void vsprintf_hexa(char **buffer_ptr, uint32_t val, int digits, int zero)
|
||||
{
|
||||
char *buffer = *buffer_ptr;
|
||||
if(!val)
|
||||
{
|
||||
while(digits-- > 1) *buffer++ = (zero) ? '0' : ' ';
|
||||
*buffer++ = '0';
|
||||
*buffer_ptr = buffer;
|
||||
return;
|
||||
}
|
||||
|
||||
if(digits <= 0)
|
||||
{
|
||||
uint32_t x = val;
|
||||
while(x) digits++, x >>= 4;
|
||||
}
|
||||
int copy = digits;
|
||||
|
||||
while(val && digits)
|
||||
{
|
||||
buffer[--digits] = (val & 15) + '0' + 39 * ((val & 15) > 9);
|
||||
val >>= 4;
|
||||
}
|
||||
while(digits)
|
||||
{
|
||||
buffer[--digits] = (zero) ? '0': ' ';
|
||||
}
|
||||
|
||||
*buffer_ptr = buffer + copy;
|
||||
}
|
||||
|
||||
void vsprintf_ptr(char **buffer_ptr, void *ptr)
|
||||
{
|
||||
vsprintf_hexa(buffer_ptr, (uint32_t)ptr, 8, 1);
|
||||
}
|
||||
|
||||
void vsprintf_char(char **buffer_ptr, int c)
|
||||
{
|
||||
char *buffer = *buffer_ptr;
|
||||
*buffer++ = c;
|
||||
*buffer_ptr = buffer;
|
||||
}
|
||||
|
||||
void vsprintf_str(char **buffer_ptr, const char *str)
|
||||
{
|
||||
char *buffer = *buffer_ptr;
|
||||
while(*str) *buffer++ = *str++;
|
||||
*buffer_ptr = buffer;
|
||||
}
|
||||
|
||||
int vsprintf(char *buffer, const char *format, va_list args)
|
||||
{
|
||||
char *save = buffer;
|
||||
int zero, count;
|
||||
|
||||
while(*format)
|
||||
{
|
||||
if(*format != '%')
|
||||
{
|
||||
*buffer++ = *format++;
|
||||
continue;
|
||||
}
|
||||
if(!*++format) break;
|
||||
|
||||
zero = 0;
|
||||
count = 0;
|
||||
|
||||
if(*format == '0') zero = 1, format++;
|
||||
while(*format >= '0' && *format <= '9')
|
||||
{
|
||||
count *= 10;
|
||||
count += (*format++ - '0');
|
||||
}
|
||||
if(!*format) break;
|
||||
|
||||
switch(*format)
|
||||
{
|
||||
case 'd':
|
||||
vsprintf_int(&buffer, va_arg(args, int));
|
||||
break;
|
||||
case 'x':
|
||||
vsprintf_hexa(&buffer, va_arg(args, uint32_t), count,
|
||||
zero);
|
||||
break;
|
||||
case 'p':
|
||||
vsprintf_ptr(&buffer, va_arg(args, void *));
|
||||
break;
|
||||
case 'c':
|
||||
vsprintf_char(&buffer, va_arg(args, int));
|
||||
break;
|
||||
case 's':
|
||||
vsprintf_str(&buffer, va_arg(args, const char *));
|
||||
break;
|
||||
default:
|
||||
*buffer++ = *format;
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
|
||||
*buffer = 0;
|
||||
return buffer - save;
|
||||
}
|
||||
|
||||
int sprintf(char *buffer, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int x = vsprintf(buffer, format, args);
|
||||
va_end(args);
|
||||
|
||||
return x;
|
||||
}
|
|
@ -341,7 +341,6 @@ void main_menu(int *category, int *app)
|
|||
//---
|
||||
|
||||
dclear();
|
||||
dupdate();
|
||||
|
||||
switch(tab)
|
||||
{
|
||||
|
@ -390,6 +389,7 @@ void main_menu(int *category, int *app)
|
|||
dreverse_area(0, 8 * (index - scroll) + 8, 127,
|
||||
8 * (index - scroll) + 15);
|
||||
}
|
||||
|
||||
dupdate();
|
||||
|
||||
//---
|
||||
|
@ -402,6 +402,9 @@ void main_menu(int *category, int *app)
|
|||
|
||||
switch(getkey())
|
||||
{
|
||||
// case KEY_7:
|
||||
// crt0_system_menu();
|
||||
// break;
|
||||
case KEY_F1:
|
||||
if(!tab) break;
|
||||
tab = 0;
|
||||
|
@ -499,37 +502,30 @@ int main(void)
|
|||
|
||||
switch((category << 8) | app)
|
||||
{
|
||||
case 0x0101:
|
||||
test_keyboard();
|
||||
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 0x0101: test_keyboard(); 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;
|
||||
case 0x0201: /* perf_bopti(); */ break;
|
||||
case 0x0202: /* perf_tales(); */ break;
|
||||
|
||||
case 0x0301:
|
||||
// if(isSH3()) debug_tlb();
|
||||
break;
|
||||
case 0x0301: /* if(isSH3()) debug_tlb(); */ break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
void crash(void)
|
||||
{
|
||||
__asm__(
|
||||
"mov #0, r0 \n\t"
|
||||
"ldc r0, vbr \n\t"
|
||||
"trapa #1 "
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -26,6 +26,8 @@ SECTIONS
|
|||
*/
|
||||
|
||||
.text : {
|
||||
_btext = . ;
|
||||
|
||||
/* Initialization code. */
|
||||
*(.pretext.entry)
|
||||
*(.pretext)
|
||||
|
@ -39,6 +41,8 @@ SECTIONS
|
|||
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
|
||||
_etext = . ;
|
||||
} > rom
|
||||
|
||||
.rodata : {
|
||||
|
@ -77,6 +81,7 @@ SECTIONS
|
|||
*(.eh_frame)
|
||||
*(.jcr)
|
||||
|
||||
. = ALIGN(4);
|
||||
_gint_data = _romdata + SIZEOF(.data) + SIZEOF(.cc) ;
|
||||
} > ram
|
||||
|
||||
|
@ -94,17 +99,14 @@ SECTIONS
|
|||
|
||||
/* Exception handler. */
|
||||
. = _gint_vbr + 0x100 ;
|
||||
*(.gint.exc.entry)
|
||||
*(.gint.exc)
|
||||
|
||||
/* TLB miss handler. */
|
||||
. = _gint_vbr + 0x400 ;
|
||||
*(.gint.tlb.entry)
|
||||
*(.gint.tlb)
|
||||
|
||||
/* Interrupt handler. */
|
||||
. = _gint_vbr + 0x600 ;
|
||||
*(.gint.int.entry)
|
||||
*(.gint.int)
|
||||
|
||||
_egint = . ;
|
||||
|
|
|
@ -95,10 +95,14 @@ static Image *select(Image *current)
|
|||
8 * i, 7, 7);
|
||||
if(i == row)
|
||||
{
|
||||
print(2, 2 + i + 1, "%08x", (unsigned int)
|
||||
images[i].img);
|
||||
/*
|
||||
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);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ void test_tales(void)
|
|||
for(int j = 0; j < 16; j++) str[j] = 32 + (i << 4) + j;
|
||||
str[16] = 0;
|
||||
|
||||
gtext(-10, 2 + i * height, str);
|
||||
gtext(2, 2 + i * height, str);
|
||||
}
|
||||
|
||||
gimage(0, 56, &res_opt_tales);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <rtc.h>
|
||||
|
||||
static void draw(int new_tab);
|
||||
static struct ClockConfig conf;
|
||||
static clock_config_t conf;
|
||||
|
||||
//---
|
||||
// Timer-RTC comparison.
|
||||
|
|
|
@ -11,17 +11,29 @@
|
|||
#define _CLOCK_H
|
||||
|
||||
//---
|
||||
// Some type declarations.
|
||||
// Sleep functions.
|
||||
//---
|
||||
|
||||
enum Clock
|
||||
{
|
||||
Clock_CKIO = 0, // SH7705
|
||||
Clock_RTCCLK = 1, // SH7305
|
||||
Clock_Bphi = 2,
|
||||
Clock_Iphi = 3,
|
||||
Clock_Pphi = 4,
|
||||
};
|
||||
/*
|
||||
sleep()
|
||||
Puts the processor to sleep until an interrupt request is issued.
|
||||
*/
|
||||
void sleep(void);
|
||||
|
||||
/*
|
||||
sleep_ms(), sleep_us()
|
||||
Sleeps for the given number of milliseconds / microseconds using the
|
||||
TIMER_USER timer. The actual sleep time will always be slightly less
|
||||
than requested.
|
||||
*/
|
||||
void sleep_ms(int ms_delay);
|
||||
void sleep_us(int us_delay);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Clock management.
|
||||
//---
|
||||
|
||||
enum ClockUnit
|
||||
{
|
||||
|
@ -34,7 +46,7 @@ enum ClockUnit
|
|||
Clock_MHz = 12,
|
||||
};
|
||||
|
||||
struct ClockConfig
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
|
@ -60,69 +72,23 @@ struct ClockConfig
|
|||
int Bphi_f;
|
||||
int Iphi_f;
|
||||
int Pphi_f;
|
||||
};
|
||||
|
||||
//---
|
||||
// Public API.
|
||||
//---
|
||||
|
||||
/*
|
||||
clock_frequency()
|
||||
Returns the approximate frequency, in Hz, of the given clock. The
|
||||
measurements need to have been done. Returns a negative number on
|
||||
error.
|
||||
*/
|
||||
int clock_frequency(enum Clock clock);
|
||||
} 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.
|
||||
Normally you need not use this function when setting up timers because
|
||||
timer_start() handles this conversion for you.
|
||||
*/
|
||||
int clock_setting(int duration, enum ClockUnit unit);
|
||||
|
||||
/*
|
||||
clock_config()
|
||||
Returns a copy of the clock configuration.
|
||||
Returns a copy of what the library knows about the clocks.
|
||||
*/
|
||||
struct ClockConfig clock_config(void);
|
||||
|
||||
/*
|
||||
sleep()
|
||||
Sleeps until an interrupt is accepted.
|
||||
*/
|
||||
void sleep(void);
|
||||
|
||||
/*
|
||||
sleep_us()
|
||||
Sleeps for the given number of us using the user timer. The result will
|
||||
always be slightly less than required.
|
||||
*/
|
||||
void sleep_us(int us_delay);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced for documentation purposes only. Do not use.
|
||||
//---
|
||||
|
||||
/*
|
||||
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);
|
||||
clock_config_t clock_config(void);
|
||||
|
||||
#endif // _CLOCK_H
|
||||
|
|
|
@ -62,7 +62,7 @@ __attribute__((always_inline)) static inline int isxdigit(int c) {
|
|||
}
|
||||
|
||||
__attribute__((always_inline)) static inline int isascii(int c) {
|
||||
return (c >= 0 && c <= 0x7f);
|
||||
return ((unsigned)c <= 0x7f);
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static inline int isblank(int c) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define _DISPLAY_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
//---
|
||||
|
|
376
include/gint.h
376
include/gint.h
|
@ -8,185 +8,221 @@
|
|||
//---
|
||||
|
||||
#ifndef _GINT_H
|
||||
#define _GINT_H 1
|
||||
#define _GINT_H
|
||||
|
||||
#define GINT_VERSION 0x01000000
|
||||
#define GINT_VERSION_STR "01.00"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define GINT_VERSION 0x000100a3
|
||||
#define GINT_VERSION_STR "00.01"
|
||||
|
||||
//---
|
||||
// Interrupt handler control.
|
||||
// System info provided by the library
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_getVBR()
|
||||
Returns the current vbr address.
|
||||
*/
|
||||
unsigned int gint_getVBR(void);
|
||||
|
||||
/*
|
||||
gint_systemVBR()
|
||||
Returns the vbr address used by the system (saved when execution
|
||||
starts).
|
||||
*/
|
||||
unsigned int gint_systemVBR(void);
|
||||
|
||||
/*
|
||||
gint_setDefaultHandler()
|
||||
In case gint receives an interrupt it doesn't recognize, it can fall
|
||||
back to a user-provided interrupt handler. Set it to NULL to disable
|
||||
this feature.
|
||||
Be aware that the event code passed to the default handler will either
|
||||
be INTEVT2 (SH7705) or INTEVT (SH7305), but its value for each
|
||||
interrupt source is completely platform-dependent. Remember to handle
|
||||
both platforms for increased portability, if possible.
|
||||
*/
|
||||
void gint_setDefaultHandler(void (*default_handler)(int event_code));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Register access.
|
||||
//---
|
||||
|
||||
/*
|
||||
enum Register
|
||||
Represents common registers. Used as identifiers to retrieve their
|
||||
values using gint_register().
|
||||
*/
|
||||
enum Register
|
||||
typedef struct
|
||||
{
|
||||
Register_EXPEVT,
|
||||
Register_MMUCR,
|
||||
Register_TEA,
|
||||
};
|
||||
/* 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 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).
|
||||
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(enum Register reg);
|
||||
|
||||
/*
|
||||
gint_strerror()
|
||||
Returns a string that describe the error set in EXPEVT in case of
|
||||
general exception of TLB miss exception. This string is platform-
|
||||
independent.
|
||||
Some exception codes represent different errors when invoked inside the
|
||||
general exception handler and the TLB error handler. Parameter 'is_tlb'
|
||||
should be set to zero for general exception meanings, and anything non-
|
||||
zero for TLB error meanings.
|
||||
*/
|
||||
const char *gint_strerror(int is_tlb);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced here for documentation purposes only.
|
||||
// Do NOT call these functions, you'll most probably screw up the whole
|
||||
// interrupt handling system.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_setVBR()
|
||||
Sets the vbr address and calls the configuration function while
|
||||
interrupts are disabled.
|
||||
*/
|
||||
void gint_setVBR(unsigned int new_vbr_address, void (*setup)(void));
|
||||
|
||||
/*
|
||||
gint_callDefaultHandler()
|
||||
Calls the user-provided default interrupt handler.
|
||||
*/
|
||||
void gint_callDefaultHandler(int event_code);
|
||||
|
||||
/*
|
||||
gint_init()
|
||||
Initializes gint. Loads the interrupt handler into the memory and sets
|
||||
the new vbr address.
|
||||
*/
|
||||
void gint_init(void);
|
||||
|
||||
/*
|
||||
gint_quit()
|
||||
Stops gint. Restores the system's configuration and vbr address.
|
||||
*/
|
||||
void gint_quit(void);
|
||||
|
||||
/*
|
||||
gint_setup()
|
||||
Configures interrupt priorities and some parameters to allow gint to
|
||||
take control of the interrupt flow.
|
||||
*/
|
||||
void gint_setup_7705(void);
|
||||
void gint_setup_7305(void);
|
||||
|
||||
/*
|
||||
gint_stop()
|
||||
Un-configures the interrupt flow to give back the interrupt control to
|
||||
the system.
|
||||
*/
|
||||
void gint_stop_7705(void);
|
||||
void gint_stop_7305(void);
|
||||
|
||||
/*
|
||||
gint_reg()
|
||||
gint_strerror()
|
||||
See "Register access" section.
|
||||
*/
|
||||
volatile void *gint_reg_7705(enum Register reg);
|
||||
volatile void *gint_reg_7305(enum Register reg);
|
||||
const char *gint_strerror_7705(int is_tlb);
|
||||
const char *gint_strerror_7305(void);
|
||||
|
||||
|
||||
//---
|
||||
// Exception handling.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_exc()
|
||||
Handles exceptions.
|
||||
*/
|
||||
void gint_exc(void) __attribute__((section(".gint.exc.entry"),
|
||||
interrupt_handler));
|
||||
void gint_exc_7705(void) __attribute__((section(".gint.exc")));
|
||||
void gint_exc_7305(void) __attribute__((section(".gint.exc")));
|
||||
|
||||
/*
|
||||
gint_tlb()
|
||||
Handles TLB misses.
|
||||
*/
|
||||
void gint_tlb(void) __attribute__((section(".gint.tlb.entry"),
|
||||
interrupt_handler));
|
||||
void gint_tlb_7705(void) __attribute__((section(".gint.tlb")));
|
||||
void gint_tlb_7305(void) __attribute__((section(".gint.tlb")));
|
||||
|
||||
/*
|
||||
gint_int()
|
||||
Handles interrupts.
|
||||
*/
|
||||
void gint_int(void) __attribute__((section(".gint.int.entry"),
|
||||
interrupt_handler));
|
||||
void gint_int_7705(void) __attribute__((section(".gint.int")));
|
||||
void gint_int_7305(void) __attribute__((section(".gint.int")));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal platform-independent definitions.
|
||||
//---
|
||||
|
||||
#define GINT_INTP_WDT 4
|
||||
#define GINT_INTP_RTC 12
|
||||
|
||||
#define GINT_INTP_GRAY 15
|
||||
#define GINT_INTP_KEY 8
|
||||
#define GINT_INTP_TIMER 10
|
||||
|
||||
|
||||
volatile void *gint_reg(gint_register_t reg);
|
||||
|
||||
#endif // _GINT_H
|
||||
|
|
|
@ -138,23 +138,4 @@ void gimage(int x, int y, struct Image *image);
|
|||
void gimage_part(int x, int y, struct Image *image, int left, int top,
|
||||
int width, int height);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced here for documentation purposes only. Do not call.
|
||||
//--
|
||||
|
||||
/*
|
||||
gray_interrupt()
|
||||
Answers a timer interrupt. Swaps the two buffers.
|
||||
*/
|
||||
void gray_interrupt(void) __attribute__((section(".gint.int")));
|
||||
|
||||
/*
|
||||
gray_init()
|
||||
Initializes the gray engine.
|
||||
*/
|
||||
void gray_init(void) __attribute__((constructor));
|
||||
|
||||
#endif // _GRAY_H
|
||||
|
|
21
include/internals/clock.h
Normal file
21
include/internals/clock.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#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
|
66
include/internals/exceptions.h
Normal file
66
include/internals/exceptions.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
#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,30 +1,184 @@
|
|||
#ifndef _INTERNALS_GINT_H
|
||||
#define _INTERNALS_GINT_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <gint.h>
|
||||
|
||||
//---
|
||||
// Exception code strings.
|
||||
// Interrupt handlers
|
||||
//---
|
||||
|
||||
extern const char *gint_str[];
|
||||
// General exception handler.
|
||||
void gint_exc(void);
|
||||
// TLB miss handler.
|
||||
void gint_tlb(void);
|
||||
// Interrupt handler.
|
||||
void gint_int(void);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Register access.
|
||||
// Assembler-level VBR management
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_spc()
|
||||
Returns the saved program counter, which is the last state of execution
|
||||
saved by interrupt processing.
|
||||
gint_getvbr()
|
||||
Retrieves the current VBR address.
|
||||
*/
|
||||
unsigned int gint_spc(void);
|
||||
uint32_t gint_getvbr(void);
|
||||
|
||||
/*
|
||||
gint_ssr()
|
||||
Returns the saved status register, which is the last configuration
|
||||
saved by interrupt processing.
|
||||
gint_setvbr()
|
||||
Sets the VBR address and calls the configuration function while
|
||||
interrupts are disabled.
|
||||
*/
|
||||
unsigned int gint_ssr(void);
|
||||
void gint_setvbr(uint32_t vbr, void (*setup)(void));
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Initialization and termination routines
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_init()
|
||||
Initializes gint. Loads the interrupt handler into the memory and sets
|
||||
the new vbr address.
|
||||
*/
|
||||
void gint_init(void);
|
||||
|
||||
/*
|
||||
gint_quit()
|
||||
Stops gint. Restores the system's configuration and vbr address.
|
||||
*/
|
||||
void gint_quit(void);
|
||||
|
||||
/*
|
||||
gint_save()
|
||||
Saves many registers into a buffer to ensure that the system is not
|
||||
upset by gint's configuration when the application ends.
|
||||
*/
|
||||
//void gint_save_7705(gint_save_buffer_t *buffer);
|
||||
//void gint_save_7305(gint_save_buffer_t *buffer);
|
||||
|
||||
/*
|
||||
gint_setup()
|
||||
Configures interrupt priorities and some parameters to allow gint to
|
||||
take control of the interrupt flow.
|
||||
*/
|
||||
void gint_setup_7705(void);
|
||||
void gint_setup_7305(void);
|
||||
|
||||
/*
|
||||
gint_restore()
|
||||
Restores the parameters saved in a save buffer to give back the
|
||||
interrupt control to the system.
|
||||
*/
|
||||
//void gint_restore_7705(gint_save_buffer_t *buffer);
|
||||
//void gint_restore_7305(gint_save_buffer_t *buffer);
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Diagnostics
|
||||
// When diagnostics are enabled, gint saves runtime information to a
|
||||
// buffer in RAM, which by chance is held if the application crashes (I
|
||||
// don't really know why). This allows deeper debugging.
|
||||
//---
|
||||
|
||||
#ifdef GINT_DIAGNOSTICS
|
||||
|
||||
#include <mpu.h>
|
||||
|
||||
// Determining whether the SaveDisp() buffer actually contains gint diagnostics
|
||||
// is performed by checking a magic number (1/256 chance of failure) and the
|
||||
// validity of all fields in the diagnostic information. Formally, a picture
|
||||
// taken by SaveDisp() could fool the checks but this is *very* unlikely and
|
||||
// the diagnostics should only be read just after gint crashes or stops anyway.
|
||||
#define GINT_DIAGNOSTICS_MAGIC 0xb7
|
||||
|
||||
typedef enum
|
||||
{
|
||||
stage_startup = 0,
|
||||
stage_sections = 1,
|
||||
stage_mmu = 2,
|
||||
stage_gint = 3,
|
||||
stage_clock = 4,
|
||||
stage_ctors = 5,
|
||||
stage_running = 6,
|
||||
stage_leaving = 7,
|
||||
stage_dtors = 8,
|
||||
stage_terminated = 9,
|
||||
|
||||
} gint_stage_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t address;
|
||||
uint32_t length;
|
||||
|
||||
} gint_memsection_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Magic number to check whether there is a diagnostic.
|
||||
uint8_t magic :8;
|
||||
// Unique counter that is incremented at each execution, allowing to
|
||||
// distinguish diagnostics output at different times if the application
|
||||
// crashes repeatedly.
|
||||
uint8_t counter :8;
|
||||
// How many work of initialization had been successfully done before
|
||||
// the application crashed.
|
||||
gint_stage_t stage :8;
|
||||
// What kind of MPU the library detected (undefined if the
|
||||
// initialization stage does not reach stage_gint).
|
||||
mpu_t mpu :8;
|
||||
|
||||
// Frequency of the main clocks, in MHz.
|
||||
uint8_t Bphi_f :8;
|
||||
uint8_t Iphi_f :8;
|
||||
uint8_t Pphi_f :8;
|
||||
|
||||
// What kind of exceptions occurred last.
|
||||
uint8_t excepts :8;
|
||||
uint8_t except_vect[12];
|
||||
// Last values held by registers SPC, SSR, EXPEVT / INTEVT2 / INTEVT,
|
||||
// and TEA.
|
||||
uint32_t spc;
|
||||
uint32_t ssr;
|
||||
uint32_t expevt;
|
||||
uint32_t tea;
|
||||
|
||||
// Gint version number, on the form 0xMMmmbbbb, where MM is the major
|
||||
// version, mm the minor version and bbbb the build number.
|
||||
uint32_t version;
|
||||
// Location of the VBR at the time of execution.
|
||||
uint32_t vbr_address;
|
||||
|
||||
// Memory map.
|
||||
uint32_t romdata;
|
||||
gint_memsection_t section_text;
|
||||
gint_memsection_t section_data;
|
||||
gint_memsection_t section_bss;
|
||||
gint_memsection_t section_gint;
|
||||
|
||||
} gint_diagnostics_t;
|
||||
|
||||
// This is somewhere inside the buffers of SaveDisp(), 3 bytes inside the first
|
||||
// buffer to be exact (that's to be 4-aligned).
|
||||
// This buffer is 1024-byte long so the logs must fit in 1021 bytes to be safe.
|
||||
// It looks like that this RAM area is generally not cleared when the
|
||||
// calculator reboots after a crash, even though it does not seem to work with
|
||||
// manual resets. Maybe it can provide useful information in some cases.
|
||||
#define gint_diagnostics() ((volatile gint_diagnostics_t *)0x88004d90)
|
||||
|
||||
#endif // GINT_DIAGNOSTICS
|
||||
|
||||
#endif // _INTERNALS_GINT_H
|
||||
|
|
100
include/internals/interrupt_maps.h
Normal file
100
include/internals/interrupt_maps.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
#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
|
18
include/internals/interrupts.h
Normal file
18
include/internals/interrupts.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#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
|
|
@ -2,6 +2,7 @@
|
|||
#define _INTERNALS_KEYBOARD_H
|
||||
|
||||
#include <keyboard.h>
|
||||
#include <clock.h>
|
||||
|
||||
// Keyboard variables.
|
||||
extern volatile unsigned char keyboard_state[10];
|
||||
|
@ -14,12 +15,6 @@ extern int last_key, last_repeats, last_events;
|
|||
// RTC callback id.
|
||||
extern unsigned cb_id;
|
||||
|
||||
/*
|
||||
sleep()
|
||||
Puts the CPU into sleep until an interrupt request is accepted.
|
||||
*/
|
||||
void sleep(void);
|
||||
|
||||
/*
|
||||
getPressedKey()
|
||||
Finds a pressed key in the keyboard state and returns it.
|
||||
|
|
|
@ -280,16 +280,14 @@ enum KeyType keytype(int key);
|
|||
Notifies the keyboard module that an interrupt request has been issued,
|
||||
and updates the keyboard state.
|
||||
*/
|
||||
void keyboard_interrupt(void) __attribute__((section(".gint.int")));
|
||||
void keyboard_interrupt(void);
|
||||
|
||||
/*
|
||||
keyboard_updateState()
|
||||
Updates the keyboard state.
|
||||
*/
|
||||
void keyboard_updateState_7705(volatile unsigned char *state)
|
||||
__attribute__((section(".gint.int")));
|
||||
void keyboard_updateState_7305(volatile unsigned char *state)
|
||||
__attribute__((section(".gint.int")));
|
||||
void keyboard_updateState_7705(volatile unsigned char *state);
|
||||
void keyboard_updateState_7305(volatile unsigned char *state);
|
||||
|
||||
/*
|
||||
keyboard_init()
|
||||
|
|
|
@ -4,15 +4,22 @@
|
|||
//
|
||||
// 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.
|
||||
// which is stored in a global variable MPU_CURRENT and determined at
|
||||
// startup.
|
||||
//
|
||||
// If you need to do MPU-dependant jobs, prefer the following alternative:
|
||||
// If you need to do MPU-dependant 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.
|
||||
//
|
||||
// In a general way, it is advised to always use the following
|
||||
// alternative (which gint does):
|
||||
//
|
||||
// if(isSH3())
|
||||
// {
|
||||
// ...
|
||||
// }
|
||||
// else
|
||||
// else
|
||||
// {
|
||||
// ...
|
||||
// }
|
||||
|
@ -23,29 +30,30 @@
|
|||
#define _MPU_H 1
|
||||
|
||||
/*
|
||||
enum MPU
|
||||
mpu_t
|
||||
This type holds information about the calculator's MPU.
|
||||
*/
|
||||
enum MPU
|
||||
typedef enum
|
||||
{
|
||||
MPU_Unknown = 0,
|
||||
mpu_unknown = 0,
|
||||
// fx-9860G SH3.
|
||||
MPU_SH7337 = 1,
|
||||
mpu_sh7337 = 1,
|
||||
// fx-9860G II SH3.
|
||||
MPU_SH7355 = 2,
|
||||
mpu_sh7355 = 2,
|
||||
// fx-9860G II SH4.
|
||||
MPU_SH7305 = 3,
|
||||
// Just for reference.
|
||||
MPU_SH7724 = 4
|
||||
};
|
||||
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 enum MPU MPU_CURRENT;
|
||||
extern 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 isSH3() (MPU_CURRENT == mpu_sh7337 || MPU_CURRENT == mpu_sh7355)
|
||||
#define isSH4() !isSH3()
|
||||
|
||||
|
||||
|
@ -58,19 +66,6 @@ extern enum MPU MPU_CURRENT;
|
|||
getMPU()
|
||||
Determines the MPU type and returns it. MPU_CURRENT is not updated.
|
||||
*/
|
||||
enum MPU getMPU(void);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Referenced here for documentation purposes only. Do not call.
|
||||
//---
|
||||
|
||||
/*
|
||||
mpu_init()
|
||||
Determines the MPU type and stores the result into MPU_CURRENT.
|
||||
*/
|
||||
void mpu_init(void) __attribute__((constructor));
|
||||
mpu_t getMPU(void);
|
||||
|
||||
#endif // _MPU_H
|
||||
|
|
|
@ -107,9 +107,9 @@ int rtc_cb_edit(int id, enum RTCFrequency new_freq,
|
|||
rtc_interrupt()
|
||||
Handles an RTC interrupt by calling the callback.
|
||||
*/
|
||||
void rtc_interrupt(void) __attribute__((section(".gint.int")));
|
||||
void rtc_interrupt_7705(void) __attribute__((section(".gint.int")));
|
||||
void rtc_interrupt_7305(void) __attribute__((section(".gint.int")));
|
||||
void rtc_interrupt(void);
|
||||
void rtc_interrupt_7705(void);
|
||||
void rtc_interrupt_7305(void);
|
||||
|
||||
/*
|
||||
rtc_cb_interrupt()
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <display.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
//---
|
||||
// Types and constants.
|
||||
|
|
|
@ -106,6 +106,6 @@ void timer_reload2(int timer, int new_delay);
|
|||
timer_interrupt()
|
||||
Handles the interrupt for the given timer.
|
||||
*/
|
||||
void timer_interrupt(int timer) __attribute__((section(".gint.int")));
|
||||
void timer_interrupt(int timer);
|
||||
|
||||
#endif // _TIMER_H
|
||||
|
|
|
@ -81,7 +81,7 @@ void bopti_grid_a32(const uint32_t *layer, int column_count, int height,
|
|||
{
|
||||
for(row = c->top; row < c->bottom; row++)
|
||||
{
|
||||
(*c->op)(vram_offset, layer[row], c);
|
||||
(c->op)(vram_offset, layer[row], c);
|
||||
vram_offset += 4;
|
||||
}
|
||||
|
||||
|
@ -108,8 +108,8 @@ void bopti_grid(const uint32_t *layer, int column_count, int height,
|
|||
int vram_column_offset = (c->y << 2) + (c->x >> 5) + (c->x < 0);
|
||||
int vram_offset = vram_column_offset;
|
||||
|
||||
int shift1 = 32 - (c->x & 31);
|
||||
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
|
||||
|
@ -138,7 +138,8 @@ void bopti_grid(const uint32_t *layer, int column_count, int height,
|
|||
l2 = (right_column < column_count) ? p2[line] : (0);
|
||||
|
||||
operator = (l1 << shift1) | (l2 >> shift2);
|
||||
(*c->op)(vram_offset, operator, c);
|
||||
(c->op)(vram_offset, operator, c);
|
||||
|
||||
vram_offset += 4;
|
||||
}
|
||||
|
||||
|
@ -199,7 +200,8 @@ void bopti_end_nover(const unsigned char *end, int size, struct Command *c)
|
|||
operator = (*get)(&end);
|
||||
operator <<= shift;
|
||||
|
||||
(*c->op)(vram_offset, operator, c);
|
||||
(c->op)(vram_offset, operator, c);
|
||||
|
||||
vram_offset += 4;
|
||||
}
|
||||
}
|
||||
|
@ -225,10 +227,12 @@ void bopti_end(const unsigned char *end, int size, struct Command *c)
|
|||
row_data = (*get)(&end);
|
||||
|
||||
operator = row_data >> shift1;
|
||||
(*c->op)(vram_offset, operator, c);
|
||||
(c->op)(vram_offset, operator, c);
|
||||
|
||||
|
||||
operator = row_data << shift2;
|
||||
(*c->op)(vram_offset + 1, operator, c);
|
||||
(c->op)(vram_offset + 1, operator, c);
|
||||
|
||||
|
||||
vram_offset += 4;
|
||||
}
|
||||
|
@ -288,8 +292,8 @@ void getStructure(struct Image *img, struct Structure *s)
|
|||
// Large images.
|
||||
if(!img->width && !img->height)
|
||||
{
|
||||
s->width = (img->data[0] << 8) | img->data[1];
|
||||
s->height = (img->data[2] << 8) | img->data[3];
|
||||
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;
|
||||
|
|
|
@ -2,10 +2,13 @@
|
|||
#include <internals/display.h>
|
||||
|
||||
/*
|
||||
dimage()
|
||||
Displays a monochrome image in the video ram.
|
||||
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(int x, int y, struct Image *img)
|
||||
void dimage_part(int x, int y, struct Image *img, int left, int top,
|
||||
int width, int height)
|
||||
{
|
||||
if(!img || img->magic != 0x01) return;
|
||||
|
||||
|
@ -16,18 +19,28 @@ void dimage(int x, int y, struct Image *img)
|
|||
|
||||
if(format != Format_Mono && format != Format_MonoAlpha) return;
|
||||
getStructure(img, &s);
|
||||
if(width < 0) width = s.width;
|
||||
if(height < 0) height = s.height;
|
||||
|
||||
//---
|
||||
// Adjusting image parameters.
|
||||
// Adjusting the bounding rectangle.
|
||||
//---
|
||||
|
||||
if(x + s.width < 0 || x > 127 || y + s.height < 0 || y > 63) return;
|
||||
// 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;
|
||||
|
||||
command.top = (y < 0) ? (-y) : (0);
|
||||
command.bottom = (y + s.height > 64) ? (64 - y) : (s.height);
|
||||
command.left = ((x < 0) ? (-x) : (0)) >> 5;
|
||||
actual_width = (x + s.width > 128) ? (128 - x) : (s.width);
|
||||
command.right = ((actual_width + 31) >> 5) - 1;
|
||||
if(x + left + width <= 0 || x > 127 || y + top + height <= 0 || y > 63)
|
||||
return;
|
||||
|
||||
command.top = (y < 0) ? (top - y) : top;
|
||||
command.bottom = top + ((y + height > 64) ? (64 - y) : height);
|
||||
command.left = ((x < 0) ? (left - x) : left) >> 5;
|
||||
actual_width = (x + width > 128) ? (128 - x) : width;
|
||||
command.right = ((left + actual_width + 31) >> 5) - 1;
|
||||
|
||||
command.op = bopti_op_mono;
|
||||
|
||||
|
@ -38,12 +51,10 @@ void dimage(int x, int y, struct Image *img)
|
|||
|
||||
while(format)
|
||||
{
|
||||
// Drawing every layer, in order of formats.
|
||||
if(format & 1)
|
||||
{
|
||||
// These members are modified by bopti()!
|
||||
command.x = x;
|
||||
command.y = y;
|
||||
command.x = x - left;
|
||||
command.y = y - top;
|
||||
command.channel = (1 << i);
|
||||
|
||||
bopti(s.data, &s, &command);
|
||||
|
@ -53,5 +64,13 @@ void dimage(int x, int y, struct Image *img)
|
|||
format >>= 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
dimage()
|
||||
Displays a monochrome image in the video ram.
|
||||
*/
|
||||
void dimage(int x, int y, struct Image *img)
|
||||
{
|
||||
dimage_part(x, y, img, 0, 0, -1, -1);
|
||||
}
|
||||
|
|
|
@ -1,65 +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, struct Image *img, int left, int top,
|
||||
int width, int height)
|
||||
{
|
||||
if(!img || img->magic != 0x01) return;
|
||||
|
||||
struct Structure s;
|
||||
struct Command command;
|
||||
int actual_width;
|
||||
int format = img->format, i = 0;
|
||||
|
||||
if(format != Format_Mono && format != Format_MonoAlpha) return;
|
||||
getStructure(img, &s);
|
||||
|
||||
//---
|
||||
// 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 + left + width <= 0 || x > 127 || y + top + height <= 0 || y > 63)
|
||||
return;
|
||||
|
||||
command.top = (y < 0) ? (top - y) : top;
|
||||
command.bottom = top + ((y + height > 64) ? (64 - y) : height);
|
||||
command.left = ((x < 0) ? (left - x) : left) >> 5;
|
||||
actual_width = (x + width > 128) ? (128 - x) : width;
|
||||
command.right = ((left + actual_width + 31) >> 5) - 1;
|
||||
|
||||
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();
|
||||
|
||||
while(format)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
format >>= 1;
|
||||
i++;
|
||||
}
|
||||
}
|
|
@ -3,10 +3,13 @@
|
|||
#include <gray.h>
|
||||
|
||||
/*
|
||||
gimage()
|
||||
Displays a gray image in the video ram.
|
||||
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(int x, int y, struct Image *img)
|
||||
void gimage_part(int x, int y, struct Image *img, int left, int top,
|
||||
int width, int height)
|
||||
{
|
||||
if(!img || img->magic != 0x01) return;
|
||||
|
||||
|
@ -16,18 +19,28 @@ void gimage(int x, int y, struct Image *img)
|
|||
int format = img->format, i = 0;
|
||||
|
||||
getStructure(img, &s);
|
||||
if(width < 0) width = s.width;
|
||||
if(height < 0) height = s.height;
|
||||
|
||||
//---
|
||||
// Adjusting image parameters.
|
||||
// Adjusting the bounding rectangle.
|
||||
//---
|
||||
|
||||
if(x + s.width <= 0 || x > 127 || y + s.height <= 0 || y > 63) return;
|
||||
// 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;
|
||||
|
||||
command.top = (y < 0) ? (-y) : (0);
|
||||
command.bottom = (y + s.height > 64) ? (64 - y) : (s.height);
|
||||
command.left = ((x < 0) ? (-x) : (0)) >> 5;
|
||||
actual_width = (x + s.width > 128) ? (128 - x) : (s.width);
|
||||
command.right = ((actual_width + 31) >> 5) - 1;
|
||||
if(x + left + width <= 0 || x > 127 || y + top + height <= 0 || y > 63)
|
||||
return;
|
||||
|
||||
command.top = (y < 0) ? (top - y) : top;
|
||||
command.bottom = top + ((y + height > 64) ? (64 - y) : height);
|
||||
command.left = ((x < 0) ? (left - x) : left) >> 5;
|
||||
actual_width = (x + width > 128) ? (128 - x) : width;
|
||||
command.right = ((left + actual_width + 31) >> 5) - 1;
|
||||
|
||||
command.op = bopti_op_gray;
|
||||
|
||||
|
@ -39,12 +52,10 @@ void gimage(int x, int y, struct Image *img)
|
|||
|
||||
while(format)
|
||||
{
|
||||
// Drawing every layer, in order of formats.
|
||||
if(format & 1)
|
||||
{
|
||||
// These members are modified by bopti()!
|
||||
command.x = x;
|
||||
command.y = y;
|
||||
command.x = x - left;
|
||||
command.y = y - top;
|
||||
command.channel = (1 << i);
|
||||
|
||||
bopti(s.data, &s, &command);
|
||||
|
@ -55,3 +66,12 @@ void gimage(int x, int y, struct Image *img)
|
|||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
gimage()
|
||||
Displays a gray image in the video ram.
|
||||
*/
|
||||
void gimage(int x, int y, struct Image *img)
|
||||
{
|
||||
gimage_part(x, y, img, 0, 0, -1, -1);
|
||||
}
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
#include <internals/bopti.h>
|
||||
#include <internals/display.h>
|
||||
#include <gray.h>
|
||||
|
||||
/*
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
struct Rect
|
||||
{
|
||||
int top, bottom;
|
||||
int left, right;
|
||||
};
|
||||
struct Rect intersect(struct Rect r1, struct Rect r2)
|
||||
{
|
||||
struct Rect result;
|
||||
result.top = max(r1.top, r2.top);
|
||||
result.bottom = min(r1.bottom, r2.bottom);
|
||||
result.left = max(r1.left, r2.left);
|
||||
result.right = min(r1.right, r2.right);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
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, struct Image *img, int left, int top,
|
||||
int width, int height)
|
||||
{
|
||||
if(!img || img->magic != 0x01) return;
|
||||
|
||||
struct Structure s;
|
||||
struct Command command;
|
||||
int actual_width;
|
||||
int format = img->format, i = 0;
|
||||
|
||||
getStructure(img, &s);
|
||||
|
||||
//---
|
||||
// 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 + left + width <= 0 || x > 127 || y + top + height <= 0 || y > 63)
|
||||
return;
|
||||
|
||||
command.top = (y < 0) ? (top - y) : top;
|
||||
command.bottom = top + ((y + height > 64) ? (64 - y) : height);
|
||||
command.left = ((x < 0) ? (left - x) : left) >> 5;
|
||||
actual_width = (x + width > 128) ? (128 - x) : width;
|
||||
command.right = ((left + actual_width + 31) >> 5) - 1;
|
||||
|
||||
command.op = bopti_op_gray;
|
||||
|
||||
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
|
||||
else getMasks(0, actual_width + x - 1, command.masks);
|
||||
|
||||
bopti_v1 = gray_lightVRAM();
|
||||
bopti_v2 = gray_darkVRAM();
|
||||
|
||||
while(format)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
format >>= 1;
|
||||
i++;
|
||||
}
|
||||
}
|
|
@ -5,39 +5,13 @@
|
|||
#include <stddef.h>
|
||||
#include <mpu.h>
|
||||
|
||||
static struct ClockConfig conf = {
|
||||
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_frequency()
|
||||
Returns the approximate frequency, in Hz, of the given clock. The
|
||||
measurements need to have been done. Returns a negative number on
|
||||
error.
|
||||
*/
|
||||
int clock_frequency(enum Clock clock)
|
||||
{
|
||||
switch(clock)
|
||||
{
|
||||
case Clock_CKIO:
|
||||
return conf.CKIO_f;
|
||||
case Clock_RTCCLK:
|
||||
return conf.RTCCLK_f;
|
||||
case Clock_Bphi:
|
||||
return conf.Bphi_f;
|
||||
case Clock_Iphi:
|
||||
return conf.Iphi_f;
|
||||
case Clock_Pphi:
|
||||
return conf.Pphi_f;
|
||||
|
||||
default:
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
clock_setting()
|
||||
Returns the P_phi / 4 timer setting that will last for the given time.
|
||||
|
@ -74,7 +48,7 @@ int clock_setting(int duration, enum ClockUnit unit)
|
|||
clock_config()
|
||||
Returns a copy of the clock configuration.
|
||||
*/
|
||||
struct ClockConfig clock_config(void)
|
||||
clock_config_t clock_config(void)
|
||||
{
|
||||
return conf;
|
||||
}
|
||||
|
@ -91,24 +65,28 @@ void sleep(void)
|
|||
}
|
||||
|
||||
/*
|
||||
sleep_us()
|
||||
Sleeps for the given number of us using the user timer. The result will
|
||||
always be slightly less than required.
|
||||
sleep_ms(), sleep_us()
|
||||
Sleeps for the given number of milliseconds / microseconds using the
|
||||
TIMER_USER timer. The actual sleep time will always be slightly less
|
||||
than requested.
|
||||
*/
|
||||
|
||||
static volatile int sleep_us_done = 0;
|
||||
|
||||
static void sleep_us_callback(void)
|
||||
static volatile int sleep_done = 0;
|
||||
static void sleep_callback(void)
|
||||
{
|
||||
sleep_us_done = 1;
|
||||
sleep_done = 1;
|
||||
}
|
||||
|
||||
void sleep_ms(int ms_delay)
|
||||
{
|
||||
sleep_us(1000 * ms_delay);
|
||||
}
|
||||
void sleep_us(int us_delay)
|
||||
{
|
||||
sleep_us_done = 0;
|
||||
timer_start(TIMER_USER, us_delay, Clock_us, sleep_us_callback, 1);
|
||||
sleep_done = 0;
|
||||
timer_start(TIMER_USER, us_delay, Clock_us, sleep_callback, 1);
|
||||
do sleep();
|
||||
while(!sleep_us_done);
|
||||
while(!sleep_done);
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,7 +104,12 @@ static void clock_compute_7305(void);
|
|||
|
||||
/*
|
||||
clock_measure()
|
||||
Measures or computes the clock frequencies.
|
||||
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)
|
||||
{
|
||||
|
|
137
src/core/crt0.c
137
src/core/crt0.c
|
@ -1,21 +1,27 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <gint.h>
|
||||
#include <clock.h>
|
||||
#include <internals/gint.h>
|
||||
#include <internals/mmu.h>
|
||||
#include <internals/clock.h>
|
||||
#include <clock.h>
|
||||
#include <gint.h>
|
||||
|
||||
int main(void);
|
||||
|
||||
static void init(void);
|
||||
static void fini(void);
|
||||
|
||||
// Symbols imported from the linker script.
|
||||
extern unsigned int
|
||||
romdata,
|
||||
bbss, ebss,
|
||||
bdata, edata;
|
||||
// Symbols provided by the linker script.
|
||||
extern uint32_t
|
||||
etext, btext, // Location of .text section
|
||||
bdata, edata, // Location of .data section
|
||||
bbss, ebss, // Location of .bss section
|
||||
bgint, egint, // Location of interrut handler and gint data
|
||||
gint_vbr, // VBR address
|
||||
romdata; // ROM address of .data section contents
|
||||
|
||||
// This variable should be overwritten before being returned, so the default
|
||||
// value doesn't matter much.
|
||||
|
@ -34,55 +40,133 @@ int atexit_index = 0;
|
|||
main(). Also prepares the execution environment by initializing all the
|
||||
modules.
|
||||
*/
|
||||
|
||||
int start(void)
|
||||
__attribute__((
|
||||
section(".pretext.entry")
|
||||
));
|
||||
|
||||
int start(void)
|
||||
__attribute__((section(".pretext.entry"))) int start(void)
|
||||
{
|
||||
// Linker symbols.
|
||||
unsigned int *bss = &bbss;
|
||||
unsigned int *data = &bdata, *src = &romdata;
|
||||
int x;
|
||||
#ifdef GINT_DIAGNOSTICS
|
||||
|
||||
// Ok, so fill as much information as possible so that in case anything
|
||||
// goes wrong we can try to analyze what's been going on.
|
||||
volatile gint_diagnostics_t *dg = gint_diagnostics();
|
||||
|
||||
// All that follows is "safe" information that can be saved immediately
|
||||
// because it will never change anyway.
|
||||
// Basic environment description.
|
||||
dg->magic = GINT_DIAGNOSTICS_MAGIC;
|
||||
dg->counter = dg->counter + 1;
|
||||
dg->mpu = mpu_unknown;
|
||||
dg->version = GINT_VERSION;
|
||||
dg->stage = stage_startup;
|
||||
|
||||
// Exception records: what kind of exceptions / TLB faults / interrupts
|
||||
// occured last to get some trace in case of crash.
|
||||
dg->excepts = 0;
|
||||
for(size_t i = 0; i < sizeof dg->except_vect; i++)
|
||||
dg->except_vect[i] = 0;
|
||||
dg->spc = 0x00000000;
|
||||
dg->ssr = 0x00000000;
|
||||
dg->expevt = 0x00000000;
|
||||
dg->tea = 0x00000000;
|
||||
|
||||
// Memory map: provides information about alignement and the relative
|
||||
// size and position of each section, as well as read-only / read-write
|
||||
// types of addresses.
|
||||
dg->section_text.address = (uint32_t)&btext;
|
||||
dg->section_text.length = (uint32_t)&etext - (uint32_t)&btext;
|
||||
dg->section_data.address = (uint32_t)&bdata;
|
||||
dg->section_data.length = (uint32_t)&edata - (uint32_t)&bdata;
|
||||
dg->section_bss.address = (uint32_t)&bbss;
|
||||
dg->section_bss.length = (uint32_t)&ebss - (uint32_t)&bbss;
|
||||
dg->romdata = (uint32_t)&romdata;
|
||||
|
||||
// Basic information about the running library.
|
||||
dg->vbr_address = (uint32_t)&gint_vbr;
|
||||
dg->section_gint.address = (uint32_t)&bgint;
|
||||
dg->section_gint.length = (uint32_t)&egint - (uint32_t)&bgint;
|
||||
#endif
|
||||
|
||||
// Clearing the .bss section.
|
||||
uint32_t *bss = &bbss;
|
||||
while(bss < &ebss) *bss++ = 0;
|
||||
|
||||
// Copying the .data section.
|
||||
uint32_t *data = &bdata, *src = &romdata;
|
||||
while(data < &edata) *data++ = *src++;
|
||||
|
||||
#ifdef GINT_DIAGNOSTICS
|
||||
dg->stage = stage_sections;
|
||||
#endif
|
||||
|
||||
// Trying to get the system to fill the TLB without editing it
|
||||
// directly, so that it does not go on rampage when finding out.
|
||||
mmu_pseudoTLBInit();
|
||||
|
||||
#ifdef GINT_DIAGNOSTICS
|
||||
// At this point it would be wise to include a copy of the TLB, but
|
||||
// it's already a huge array. Maybe later...
|
||||
/* TODO Debug TLB? */
|
||||
dg->stage = stage_mmu;
|
||||
#endif
|
||||
|
||||
// Initializing gint.
|
||||
gint_init();
|
||||
|
||||
// Measure clock frequencies.
|
||||
#ifdef GINT_DIAGNOSTICS
|
||||
dg->mpu = MPU_CURRENT;
|
||||
dg->stage = stage_gint;
|
||||
#endif
|
||||
|
||||
// Measuring clock frequencies.
|
||||
clock_measure();
|
||||
clock_measure_end();
|
||||
|
||||
#ifdef GINT_DIAGNOSTICS
|
||||
clock_config_t clock = clock_config();
|
||||
dg->Bphi_f = clock.Bphi_f / 1000000;
|
||||
dg->Iphi_f = clock.Iphi_f / 1000000;
|
||||
dg->Pphi_f = clock.Pphi_f / 1000000;
|
||||
dg->stage = stage_clock;
|
||||
#endif
|
||||
|
||||
// Calling global constructors.
|
||||
init();
|
||||
|
||||
#ifdef GINT_DIAGNOSTICS
|
||||
dg->stage = stage_ctors;
|
||||
dg->stage = stage_running;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Saving the execution state there.
|
||||
x = setjmp(env);
|
||||
int x = setjmp(env);
|
||||
// If the program has just started, executing main(). Otherwise, the
|
||||
// exit code has already been set by abort() or similar.
|
||||
if(!x) exit_code = main();
|
||||
|
||||
|
||||
#ifdef GINT_DIAGNOSTICS
|
||||
dg->stage = stage_leaving;
|
||||
#endif
|
||||
|
||||
// Remember to flush and close opened streams.
|
||||
/* TODO Flush and close opened streams. */
|
||||
|
||||
// Calling exit handlers.
|
||||
while(atexit_index > 0) (*atexit_handlers[--atexit_index])();
|
||||
|
||||
// Un-initializing everything.
|
||||
// Calling the destructors.
|
||||
fini();
|
||||
|
||||
#ifdef GINT_DIAGNOSTICS
|
||||
dg->stage = stage_dtors;
|
||||
#endif
|
||||
|
||||
// Un-initializing gint.
|
||||
gint_quit();
|
||||
|
||||
#ifdef GINT_DIAGNOSTICS
|
||||
dg->stage = stage_terminated;
|
||||
#endif
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
|
@ -166,3 +250,12 @@ int atexit(void (*function)(void))
|
|||
return 0;
|
||||
}
|
||||
|
||||
void crt0_system_menu(void)
|
||||
{
|
||||
fini();
|
||||
gint_quit();
|
||||
__system_menu();
|
||||
mmu_pseudoTLBInit();
|
||||
gint_init();
|
||||
init();
|
||||
}
|
||||
|
|
172
src/core/exceptions.c
Normal file
172
src/core/exceptions.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
#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" : "=rm"(spc));
|
||||
__asm__("stc ssr, %0" : "=rm"(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
|
368
src/core/gint.c
368
src/core/gint.c
|
@ -8,278 +8,182 @@
|
|||
//---
|
||||
|
||||
#include <internals/gint.h>
|
||||
#include <internals/interrupt_maps.h>
|
||||
#include <internals/exceptions.h>
|
||||
#include <internals/interrupts.h>
|
||||
#include <gint.h>
|
||||
#include <mpu.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static unsigned int
|
||||
new_vbr,
|
||||
sys_vbr;
|
||||
|
||||
static void (*default_handler)(int event_code) = NULL;
|
||||
// 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;
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Local functions.
|
||||
// Exception and interrupt handlers
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_setup()
|
||||
Configures interrupt priorities and some parameters to allow gint to
|
||||
take control of the interrupt flow.
|
||||
*/
|
||||
static void gint_setup(void)
|
||||
{
|
||||
if(isSH3())
|
||||
gint_setup_7705();
|
||||
else
|
||||
gint_setup_7305();
|
||||
}
|
||||
gint_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_stop()
|
||||
Un-configures the interrupt flow to give back the interrupt control to
|
||||
the system.
|
||||
gint_invoke()
|
||||
Invokes an interrupt or exception handler, given its type and subtype.
|
||||
*/
|
||||
static void gint_stop(void)
|
||||
void gint_invoke(uint8_t type, uint8_t subtype)
|
||||
{
|
||||
if(isSH3())
|
||||
gint_stop_7705();
|
||||
else
|
||||
gint_stop_7305();
|
||||
}
|
||||
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" : "=rm"(pc));
|
||||
tea = gint_reg(register_tea);
|
||||
tra = gint_reg(register_tra);
|
||||
tcpr_2 = (void *)0xfffffeb8;
|
||||
|
||||
//---
|
||||
// Public API.
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_systemVBR()
|
||||
Returns the vbr address used by the system (saved when execution
|
||||
starts).
|
||||
*/
|
||||
inline unsigned int gint_systemVBR(void)
|
||||
{
|
||||
return sys_vbr;
|
||||
}
|
||||
|
||||
/*
|
||||
gint_setDefaultHandler()
|
||||
In case gint receives an interrupt it doesn't recognize, it can fall
|
||||
back to a user-provided interrupt handler. Set it to NULL to disable
|
||||
this feature.
|
||||
Be aware that the event code passed to the default handler will either
|
||||
be INTEVT2 (SH7705) or INTEVT (SH7305), but its value for each
|
||||
interrupt case is completely platform-dependent. Remember to handle
|
||||
both platforms for increased portability, if possible.
|
||||
*/
|
||||
void gint_setDefaultHandler(void (*new_handler)(int event_code))
|
||||
{
|
||||
default_handler = new_handler;
|
||||
}
|
||||
|
||||
/*
|
||||
gint_init()
|
||||
Initializes gint. Loads the interrupt handler into the memory and sets
|
||||
the new vbr address.
|
||||
*/
|
||||
void gint_init(void)
|
||||
{
|
||||
// Linker script symbols -- gint.
|
||||
extern unsigned int
|
||||
gint_vbr,
|
||||
gint_data,
|
||||
bgint, egint;
|
||||
|
||||
unsigned int *ptr = &bgint;
|
||||
unsigned int *src = &gint_data;
|
||||
|
||||
// This initialization routine is usually called before any
|
||||
// constructor. We want to ensure that the MPU type is detected, but
|
||||
// mpu_init() hasn't been called yet.
|
||||
mpu_init();
|
||||
|
||||
// Loading the interrupt handler into the memory.
|
||||
while(ptr < &egint) *ptr++ = *src++;
|
||||
|
||||
sys_vbr = gint_getVBR();
|
||||
new_vbr = (unsigned int)&gint_vbr;
|
||||
|
||||
gint_setVBR(new_vbr, gint_setup);
|
||||
}
|
||||
|
||||
/*
|
||||
gint_quit()
|
||||
Stops gint. Restores the system's configuration and vbr address.
|
||||
*/
|
||||
void gint_quit(void)
|
||||
{
|
||||
gint_setVBR(sys_vbr, gint_stop);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// VBR space.
|
||||
//---
|
||||
|
||||
#include <display.h>
|
||||
#define print(str, x, y) dtext(6 * (x) - 5, 8 * (y) - 7, str)
|
||||
#define hexdigit(n) ((n) + '0' + 39 * ((n) > 9))
|
||||
|
||||
static void hex(unsigned int x, int digits, char *str)
|
||||
{
|
||||
str[0] = '0';
|
||||
str[1] = 'x';
|
||||
str[digits + 2] = 0;
|
||||
|
||||
while(digits)
|
||||
// Building up the argument list.
|
||||
for(int i = 0; i < 3; i++) switch(gint_handlers[type].args[i])
|
||||
{
|
||||
str[digits + 1] = hexdigit(x & 0xf);
|
||||
x >>= 4;
|
||||
digits--;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void reverse(void)
|
||||
{
|
||||
int *vram = display_getCurrentVRAM();
|
||||
int i;
|
||||
for(i = 0; i < 36; i++) vram[i] = ~vram[i];
|
||||
// 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_exc()
|
||||
Handles exceptions.
|
||||
gint_install()
|
||||
Installs an exception or interrupt handler for one of gint's recognized
|
||||
interrupts.
|
||||
*/
|
||||
void gint_exc(void)
|
||||
void gint_install(gint_interrupt_type_t type, void *function)
|
||||
{
|
||||
volatile unsigned int *expevt = gint_reg(Register_EXPEVT);
|
||||
volatile unsigned int *tea = gint_reg(Register_TEA);
|
||||
unsigned int spc;
|
||||
char str[11];
|
||||
|
||||
text_configure(NULL, Color_Black);
|
||||
|
||||
__asm__("\tstc spc, %0" : "=r"(spc));
|
||||
|
||||
dclear();
|
||||
print("Exception raised!", 3, 1);
|
||||
reverse();
|
||||
print(gint_strerror(0), 2, 3);
|
||||
|
||||
print("expevt", 2, 4);
|
||||
hex(*expevt, 3, str);
|
||||
print(str, 16, 4);
|
||||
|
||||
print("pc", 2, 5);
|
||||
hex(spc, 8, str);
|
||||
print(str, 11, 5);
|
||||
|
||||
print("tea", 2, 6);
|
||||
hex(*tea, 8, str);
|
||||
print(str, 11, 6);
|
||||
|
||||
print("Please reset.", 2, 7);
|
||||
dupdate();
|
||||
while(1);
|
||||
if((unsigned)type >= exc_type_max) return;
|
||||
gint_handlers[type].function = function;
|
||||
}
|
||||
|
||||
/*
|
||||
gint_tlb()
|
||||
Handles TLB misses.
|
||||
gint_uninstall()
|
||||
Uninstalls the exception or interrupt handler that was used for the
|
||||
given interrupt, falling back to gint's default handler.
|
||||
*/
|
||||
void gint_tlb(void)
|
||||
void gint_uninstall(gint_interrupt_type_t type)
|
||||
{
|
||||
volatile unsigned int *expevt = gint_reg(Register_EXPEVT);
|
||||
volatile unsigned int *tea = gint_reg(Register_TEA);
|
||||
unsigned int spc;
|
||||
char str[11];
|
||||
|
||||
text_configure(NULL, Color_Black);
|
||||
|
||||
__asm__("\tstc spc, %0" : "=r"(spc));
|
||||
|
||||
dclear();
|
||||
print("TLB error!", 6, 1);
|
||||
reverse();
|
||||
print(gint_strerror(1), 2, 3);
|
||||
|
||||
print("expevt", 2, 4);
|
||||
hex(*expevt, 3, str);
|
||||
print(str, 16, 4);
|
||||
|
||||
print("pc", 2, 5);
|
||||
hex(spc, 8, str);
|
||||
print(str, 11, 5);
|
||||
|
||||
print("tea", 2, 6);
|
||||
hex(*tea, 8, str);
|
||||
print(str, 11, 6);
|
||||
|
||||
print("Please reset.", 2, 7);
|
||||
dupdate();
|
||||
while(1);
|
||||
}
|
||||
|
||||
/*
|
||||
gint_int()
|
||||
Handles interrupts.
|
||||
*/
|
||||
void gint_int(void)
|
||||
{
|
||||
if(isSH3())
|
||||
gint_int_7705();
|
||||
else
|
||||
gint_int_7305();
|
||||
if((unsigned)type >= exc_type_max) return;
|
||||
gint_handlers[type].function = gint_handlers[type].default_function;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Internal API.
|
||||
// Register access
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_callDefaultHandler()
|
||||
Calls the user-provided default interrupt handler.
|
||||
*/
|
||||
void gint_callDefaultHandler(int event_code)
|
||||
{
|
||||
if(default_handler) default_handler(event_code);
|
||||
}
|
||||
|
||||
/*
|
||||
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).
|
||||
information.
|
||||
*/
|
||||
inline volatile void *gint_reg(enum Register reg)
|
||||
volatile void *gint_reg(gint_register_t reg)
|
||||
{
|
||||
if(isSH3())
|
||||
return gint_reg_7705(reg);
|
||||
else
|
||||
return gint_reg_7305(reg);
|
||||
}
|
||||
|
||||
/*
|
||||
gint_strerror()
|
||||
Returns a string that describe the error set in EXPEVT. This string is
|
||||
not platform-dependent.
|
||||
Some exception codes represent different errors when invoked inside the
|
||||
general exception handler and the TLB error handler. Parameter 'is_tlb'
|
||||
should be set to zero for general exception meanings, and anything non-
|
||||
zero for TLB error meanings.
|
||||
*/
|
||||
const char *gint_strerror(int is_tlb)
|
||||
{
|
||||
if(isSH3())
|
||||
return gint_strerror_7705(is_tlb);
|
||||
else
|
||||
return gint_strerror_7305();
|
||||
return isSH3() ? gint_reg_7705(reg) : gint_reg_7305(reg);
|
||||
}
|
||||
|
|
|
@ -15,52 +15,6 @@
|
|||
#include <7305.h>
|
||||
#include <rtc.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
//---
|
||||
// Interrupt codes.
|
||||
//---
|
||||
|
||||
#define IC_RTC_PRI 0xaa0
|
||||
#define IC_KEYSC 0xbe0
|
||||
#define IC_TMU0_TUNI0 0x400
|
||||
#define IC_TMU0_TUNI1 0x420
|
||||
#define IC_TMU0_TUNI2 0x440
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Exception handling.
|
||||
//---
|
||||
|
||||
void gint_int_7305(void)
|
||||
{
|
||||
volatile unsigned int *intevt = (unsigned int *)0xff000028;
|
||||
unsigned int code = *intevt;
|
||||
|
||||
switch(code)
|
||||
{
|
||||
case IC_RTC_PRI:
|
||||
rtc_interrupt();
|
||||
break;
|
||||
|
||||
case IC_TMU0_TUNI0:
|
||||
timer_interrupt(TIMER_TMU0);
|
||||
break;
|
||||
|
||||
case IC_TMU0_TUNI1:
|
||||
timer_interrupt(TIMER_TMU1);
|
||||
break;
|
||||
|
||||
case IC_TMU0_TUNI2:
|
||||
timer_interrupt(TIMER_TMU2);
|
||||
break;
|
||||
|
||||
default:
|
||||
gint_callDefaultHandler(code);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
gint_reg()
|
||||
Returns the address of a common register. All common registers exist
|
||||
|
@ -68,47 +22,19 @@ void gint_int_7305(void)
|
|||
information (f.i. EXPEVT may not return the same value for a given
|
||||
exception on both 7705 and 7305).
|
||||
*/
|
||||
volatile void *gint_reg_7305(enum Register reg)
|
||||
volatile void *gint_reg_7305(gint_register_t reg)
|
||||
{
|
||||
volatile unsigned int *expevt = (unsigned int *)0xff000024;
|
||||
volatile unsigned int *tea = (unsigned int *)0xff00000c;
|
||||
volatile unsigned int *mmucr = (unsigned int *)0xff000010;
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case Register_EXPEVT: return expevt;
|
||||
case Register_TEA: return tea;
|
||||
case Register_MMUCR: return mmucr;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
gint_strerror()
|
||||
Returns a string that describe the error set in EXPEVT. This string is
|
||||
not platform-dependent.
|
||||
*/
|
||||
const char *gint_strerror_7305(void)
|
||||
{
|
||||
volatile unsigned int *expevt = gint_reg_7305(Register_EXPEVT);
|
||||
|
||||
switch(*expevt)
|
||||
{
|
||||
case 0x1e0: return gint_str[3];
|
||||
case 0x0e0: return gint_str[8];
|
||||
case 0x040: return gint_str[14];
|
||||
case 0x0a0: return gint_str[17];
|
||||
case 0x180: return gint_str[6];
|
||||
case 0x1a0: return gint_str[7];
|
||||
case 0x100: return gint_str[9];
|
||||
case 0x060: return gint_str[15];
|
||||
case 0x0c0: return gint_str[18];
|
||||
case 0x080: return gint_str[20];
|
||||
case 0x160: return gint_str[21];
|
||||
}
|
||||
return gint_str[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
|
@ -164,10 +90,10 @@ static void gint_priority_lock_7305(void)
|
|||
// Allowing RTC. Keyboard analysis is done regularly using a RTC
|
||||
// because SH7305's special KEYSC interface does not allow us to clear
|
||||
// the keyboard interrupt flags.
|
||||
INTX.IPRK._RTC = GINT_INTP_RTC;
|
||||
INTX.IPRA.TMU0_0 = GINT_INTP_KEY;
|
||||
INTX.IPRA.TMU0_1 = GINT_INTP_GRAY;
|
||||
INTX.IPRA.TMU0_2 = GINT_INTP_TIMER;
|
||||
INTX.IPRK._RTC = 10;
|
||||
INTX.IPRA.TMU0_0 = 12;
|
||||
INTX.IPRA.TMU0_1 = 12;
|
||||
INTX.IPRA.TMU0_2 = 12;
|
||||
}
|
||||
|
||||
static void gint_priority_unlock_7305(void)
|
|
@ -15,52 +15,6 @@
|
|||
#include <7705.h>
|
||||
#include <rtc.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
//---
|
||||
// Interrupt codes.
|
||||
//---
|
||||
|
||||
#define IC_RTC_PRI 0x4a0
|
||||
#define IC_PINT07 0x700
|
||||
#define IC_TMU0_TUNI0 0x400
|
||||
#define IC_TMU1_TUNI1 0x420
|
||||
#define IC_TMU2_TUNI2 0x440
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Exception handling.
|
||||
//---
|
||||
|
||||
void gint_int_7705(void)
|
||||
{
|
||||
volatile unsigned int *intevt2 = (unsigned int *)0xa4000000;
|
||||
unsigned int code = *intevt2;
|
||||
|
||||
switch(code)
|
||||
{
|
||||
case IC_RTC_PRI:
|
||||
rtc_interrupt();
|
||||
break;
|
||||
|
||||
case IC_TMU0_TUNI0:
|
||||
timer_interrupt(TIMER_TMU0);
|
||||
break;
|
||||
|
||||
case IC_TMU1_TUNI1:
|
||||
timer_interrupt(TIMER_TMU1);
|
||||
break;
|
||||
|
||||
case IC_TMU2_TUNI2:
|
||||
timer_interrupt(TIMER_TMU2);
|
||||
break;
|
||||
|
||||
default:
|
||||
gint_callDefaultHandler(code);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
gint_reg()
|
||||
Returns the address of a common register. All common registers exist
|
||||
|
@ -68,52 +22,19 @@ void gint_int_7705(void)
|
|||
information (f.i. EXPEVT may not return the same value for a given
|
||||
exception on both 7705 and 7305).
|
||||
*/
|
||||
volatile void *gint_reg_7705(enum Register reg)
|
||||
volatile void *gint_reg_7705(gint_register_t reg)
|
||||
{
|
||||
volatile unsigned int *expevt = (unsigned int *)0xffffffd4;
|
||||
volatile unsigned int *mmucr = (unsigned int *)0xfffffff4;
|
||||
volatile unsigned int *tea = (unsigned int *)0xfffffffc;
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case Register_EXPEVT: return expevt;
|
||||
case Register_MMUCR: return mmucr;
|
||||
case Register_TEA: return tea;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
gint_strerror()
|
||||
Returns a string that describe the error set in EXPEVT. This string is
|
||||
not platform-dependent.
|
||||
Some exception codes represent different errors when invoked inside the
|
||||
general exception handler and the TLB error handler. Parameter 'is_tlb'
|
||||
should be set to zero for general exception meanings, and anything non-
|
||||
zero for TLB error meanings.
|
||||
*/
|
||||
const char *gint_strerror_7705(int is_tlb)
|
||||
{
|
||||
volatile unsigned int *expevt = gint_reg_7705(Register_EXPEVT);
|
||||
|
||||
switch(*expevt)
|
||||
{
|
||||
case 0x1e0: return gint_str[3];
|
||||
case 0x0e0: return gint_str[4];
|
||||
case 0x040: return gint_str[is_tlb ? 10 : 11];
|
||||
case 0x0a0: return gint_str[12];
|
||||
case 0x180: return gint_str[6];
|
||||
case 0x1a0: return gint_str[7];
|
||||
case 0x100: return gint_str[5];
|
||||
case 0x060: return gint_str[is_tlb ? 13 : 19];
|
||||
case 0x0c0: return gint_str[16];
|
||||
case 0x080: return gint_str[20];
|
||||
case 0x160: return gint_str[21];
|
||||
case 0x5c0: return gint_str[22];
|
||||
}
|
||||
return gint_str[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
|
@ -148,10 +69,10 @@ static void gint_priority_lock_7705(void)
|
|||
INTX.IPRH.WORD = 0x0000;
|
||||
|
||||
// Allowing RTC, which handles keyboard.
|
||||
INTC.IPRA.BIT._RTC = GINT_INTP_RTC;
|
||||
INTC.IPRA.BIT._TMU0 = GINT_INTP_KEY;
|
||||
INTC.IPRA.BIT._TMU1 = GINT_INTP_GRAY;
|
||||
INTC.IPRA.BIT._TMU2 = GINT_INTP_TIMER;
|
||||
INTC.IPRA.BIT._RTC = 10;
|
||||
INTC.IPRA.BIT._TMU0 = 12;
|
||||
INTC.IPRA.BIT._TMU1 = 12;
|
||||
INTC.IPRA.BIT._TMU2 = 12;
|
||||
}
|
||||
|
||||
static void gint_priority_unlock_7705(void)
|
|
@ -1,37 +0,0 @@
|
|||
#include <internals/gint.h>
|
||||
|
||||
const char *gint_str[] = {
|
||||
"Unknown",
|
||||
|
||||
// User breaks.
|
||||
"User break (before)",
|
||||
"User break (after)",
|
||||
"User breakpoint",
|
||||
|
||||
// General.
|
||||
"Inst. address error",
|
||||
"Data access error",
|
||||
"Illegal instruction",
|
||||
"Illegal slot",
|
||||
"Data address (r)",
|
||||
"Data address (w)",
|
||||
|
||||
// Instruction TLB.
|
||||
"Inst. TLB miss",
|
||||
"Inst. TLB invalid",
|
||||
"Inst. TLB protect.",
|
||||
|
||||
// Data TLB.
|
||||
"Data TLB miss",
|
||||
"Data TLB miss (r)",
|
||||
"Data TLB miss (w)",
|
||||
"Data TLB protection",
|
||||
"Data TLB prot. (r)",
|
||||
"Data TLB prot. (w)",
|
||||
"Data TLB invalid",
|
||||
|
||||
// Others.
|
||||
"Initial page write",
|
||||
"Trap",
|
||||
"DMA address error",
|
||||
};
|
|
@ -5,27 +5,27 @@
|
|||
address needs to be done in assembler.
|
||||
*/
|
||||
|
||||
.global _gint_getVBR
|
||||
.global _gint_setVBR
|
||||
.global _gint_getvbr
|
||||
.global _gint_setvbr
|
||||
|
||||
|
||||
|
||||
/*
|
||||
gint_getVBR()
|
||||
gint_getvbr()
|
||||
Returns the current vbr address.
|
||||
*/
|
||||
_gint_getVBR:
|
||||
_gint_getvbr:
|
||||
rts
|
||||
stc vbr, r0
|
||||
|
||||
|
||||
|
||||
/*
|
||||
gint_setVBR()
|
||||
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
|
||||
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.
|
||||
|
||||
|
@ -33,7 +33,7 @@ _gint_getVBR:
|
|||
having disabled all the interrupts in the status register. That's why
|
||||
this function takes as parameter the priority management function.
|
||||
*/
|
||||
_gint_setVBR:
|
||||
_gint_setvbr:
|
||||
sts.l pr, @-r15
|
||||
|
||||
/* Blocking all interrupts. */
|
||||
|
|
73
src/core/init_quit.c
Normal file
73
src/core/init_quit.c
Normal file
|
@ -0,0 +1,73 @@
|
|||
#include <internals/gint.h>
|
||||
#include <internals/interrupt_maps.h>
|
||||
#include <gint.h>
|
||||
#include <mpu.h>
|
||||
|
||||
gint_info_t gint;
|
||||
|
||||
//---
|
||||
// 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_setup_7705() : gint_setup_7305();
|
||||
}
|
||||
void gint_init(void)
|
||||
{
|
||||
// Linker script symbols -- gint.
|
||||
extern uint32_t
|
||||
gint_vbr,
|
||||
gint_data,
|
||||
bgint, egint;
|
||||
|
||||
uint32_t *ptr = &bgint;
|
||||
uint32_t *src = &gint_data;
|
||||
|
||||
// This initialization routine is usually called before any
|
||||
// constructor. We want to ensure that the MPU type is detected, but
|
||||
// mpu_init() hasn't been called yet.
|
||||
mpu_init();
|
||||
|
||||
// Loading the interrupt handler into the memory.
|
||||
while(ptr < &egint) *ptr++ = *src++;
|
||||
|
||||
// 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_stop_7705() : gint_stop_7305();
|
||||
}
|
||||
void gint_quit(void)
|
||||
{
|
||||
// Restoring the system's VBR.
|
||||
gint_setvbr(gint.system_vbr, stop);
|
||||
}
|
53
src/core/interrupt_maps_7305.c
Normal file
53
src/core/interrupt_maps_7305.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
#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;
|
||||
}
|
65
src/core/interrupt_maps_7705.c
Normal file
65
src/core/interrupt_maps_7705.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
#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;
|
||||
}
|
21
src/core/interrupts.c
Normal file
21
src/core/interrupts.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include <internals/interrupts.h>
|
||||
#include <timer.h>
|
||||
#include <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_interrupt();
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include <mpu.h>
|
||||
|
||||
enum MPU MPU_CURRENT;
|
||||
mpu_t MPU_CURRENT;
|
||||
|
||||
/*
|
||||
getMPU()
|
||||
|
@ -26,7 +26,7 @@ enum MPU MPU_CURRENT;
|
|||
Additionally, the CPU core ID register (CPIDR) at 0xff000048 returns 1
|
||||
on SH7305.
|
||||
*/
|
||||
enum MPU getMPU(void)
|
||||
mpu_t getMPU(void)
|
||||
{
|
||||
// Processor version register.
|
||||
volatile unsigned int *pvr = (unsigned int *)0xff000030;
|
||||
|
@ -46,26 +46,26 @@ enum MPU getMPU(void)
|
|||
*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;
|
||||
if(tested_plcr == 0x00ff) return mpu_sh7337;
|
||||
if(tested_plcr == 0x0fff) return mpu_sh7355;
|
||||
|
||||
// Looking for SH-4-based MPUs by testing the version registers. This
|
||||
// needs to have the three upper bytes of the processor version
|
||||
// register match 0x10300b :
|
||||
if((*pvr & 0xffffff00) != 0x10300b00) return MPU_Unknown;
|
||||
if((*pvr & 0xffffff00) != 0x10300b00) return mpu_unknown;
|
||||
|
||||
// Now that we have an SH-4-based MPU, checking whether it is SH7305 or
|
||||
// SH7724.
|
||||
switch(*prr & 0xfffffff0)
|
||||
{
|
||||
case 0x00002c00:
|
||||
return MPU_SH7305;
|
||||
return mpu_sh7305;
|
||||
case 0x00002200:
|
||||
return MPU_SH7724;
|
||||
return mpu_sh7724;
|
||||
}
|
||||
|
||||
// By default, the MPU is unknown.
|
||||
return MPU_Unknown;
|
||||
return mpu_unknown;
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,7 +74,7 @@ enum MPU getMPU(void)
|
|||
mpu_init()
|
||||
Determines the MPU type and stores the result into MPU_CURRENT.
|
||||
*/
|
||||
void mpu_init(void)
|
||||
__attribute__((constructor)) void mpu_init(void)
|
||||
{
|
||||
MPU_CURRENT = getMPU();
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
.global ___malloc
|
||||
.global ___free
|
||||
.global ___realloc
|
||||
.global ___system_menu
|
||||
|
||||
|
||||
|
||||
|
@ -34,8 +35,65 @@ ___realloc:
|
|||
nop
|
||||
1: .long 0xe6d
|
||||
|
||||
/*
|
||||
__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
|
||||
|
||||
/* 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 */
|
||||
mov #-5, r15
|
||||
mov r15, r1
|
||||
|
||||
mov #2, r6 /* type of waiting */
|
||||
mov #0, r7 /* timeout period */
|
||||
mov.l r1, @-r15 /* keycode pointer */
|
||||
mov #0, r2
|
||||
mov.l r2, @-r15 /* allow return to menu */
|
||||
|
||||
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
|
||||
.matrix_menu:
|
||||
.word 0x0308
|
||||
|
||||
|
||||
|
||||
.align 4
|
||||
|
||||
syscall_table:
|
||||
.long 0x80010070
|
||||
|
|
98
src/core/vbr_space.c
Normal file
98
src/core/vbr_space.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
#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,7 +1,6 @@
|
|||
#include <internals/display.h>
|
||||
#include <display.h>
|
||||
#include <screen.h>
|
||||
#include <gray.h>
|
||||
|
||||
/*
|
||||
dupdate()
|
||||
|
@ -9,6 +8,5 @@
|
|||
*/
|
||||
void dupdate(void)
|
||||
{
|
||||
if(gray_runs()) return;
|
||||
screen_display((const void *)vram);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,38 @@ static int runs = 0;
|
|||
|
||||
|
||||
|
||||
//---
|
||||
// Interrupt control and initialization.
|
||||
//---
|
||||
|
||||
/*
|
||||
gray_interrupt()
|
||||
Answers a timer interrupt. Swaps the buffers.
|
||||
*/
|
||||
void gray_interrupt(void)
|
||||
{
|
||||
timer_reload2(TIMER_GRAY, delays[(~current) & 1]);
|
||||
screen_display(vrams[current]);
|
||||
current ^= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
gray_init()
|
||||
Initializes the gray engine.
|
||||
*/
|
||||
__attribute__((constructor)) void gray_init(void)
|
||||
{
|
||||
vrams[0] = (const void *)display_getLocalVRAM();
|
||||
vrams[1] = (const void *)internal_vrams[0];
|
||||
vrams[2] = (const void *)internal_vrams[1];
|
||||
vrams[3] = (const void *)internal_vrams[2];
|
||||
|
||||
delays[0] = 912;
|
||||
delays[1] = 1343;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Engine control.
|
||||
//---
|
||||
|
@ -123,35 +155,3 @@ inline void gupdate(void)
|
|||
{
|
||||
current ^= 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Interrupt control and initialization.
|
||||
//---
|
||||
|
||||
/*
|
||||
gray_interrupt()
|
||||
Answers a timer interrupt. Swaps the buffers.
|
||||
*/
|
||||
void gray_interrupt(void)
|
||||
{
|
||||
timer_reload2(TIMER_GRAY, delays[(~current) & 1]);
|
||||
screen_display(vrams[current]);
|
||||
current ^= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
gray_init()
|
||||
Initializes the gray engine.
|
||||
*/
|
||||
void gray_init(void)
|
||||
{
|
||||
vrams[0] = (const void *)display_getLocalVRAM();
|
||||
vrams[1] = (const void *)internal_vrams[0];
|
||||
vrams[2] = (const void *)internal_vrams[1];
|
||||
vrams[3] = (const void *)internal_vrams[2];
|
||||
|
||||
delays[0] = 912;
|
||||
delays[1] = 1343;
|
||||
}
|
||||
|
|
|
@ -129,7 +129,8 @@ void rtc_cb_interrupt(void)
|
|||
// Adding to elapsed256 the number of 256-Hz ticks that correspond to
|
||||
// the current interrupt frequency, and rounding the result to a
|
||||
// multiple of this tick number.
|
||||
elapsed256 = (elapsed256 + scales[rtc_freq]) & ~(scales[rtc_freq] - 1);
|
||||
elapsed256 += scales[rtc_freq - 1];
|
||||
elapsed256 &= ~(scales[rtc_freq - 1] - 1);
|
||||
|
||||
for(n = 0; n < RTC_CB_ARRAY_SIZE; n++)
|
||||
{
|
||||
|
@ -139,7 +140,7 @@ void rtc_cb_interrupt(void)
|
|||
// Only execute callback when the number of elapsed 256-Hz
|
||||
// ticks reach a multiple that correspond to the callback
|
||||
// frequency.
|
||||
if(elapsed256 & (scales[cb->freq] - 1)) continue;
|
||||
if(elapsed256 & (scales[cb->freq - 1] - 1)) continue;
|
||||
|
||||
if(cb->callback) (*cb->callback)();
|
||||
if(cb->repeats)
|
||||
|
|
|
@ -16,18 +16,3 @@ void dprint(int x, int y, const char *format, ...)
|
|||
|
||||
dtext(x, y, __stdio_buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
gprint()
|
||||
Prints a formatted string. Works the same as printf().
|
||||
*/
|
||||
void gprint(int x, int y, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
__printf(0, format, args);
|
||||
va_end(args);
|
||||
|
||||
gtext(x, y, __stdio_buffer);
|
||||
}
|
|
@ -9,12 +9,3 @@ void dtext(int x, int y, const char *str)
|
|||
{
|
||||
render(x, y, str, operate_mono);
|
||||
}
|
||||
|
||||
/*
|
||||
gtext()
|
||||
Prints the given raw string.
|
||||
*/
|
||||
void gtext(int x, int y, const char *str)
|
||||
{
|
||||
render(x, y, str, operate_gray);
|
||||
}
|
18
src/tales/gprint.c
Normal file
18
src/tales/gprint.c
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <internals/tales.h>
|
||||
#include <internals/stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/*
|
||||
gprint()
|
||||
Prints a formatted string. Works the same as printf().
|
||||
*/
|
||||
void gprint(int x, int y, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
__printf(0, format, args);
|
||||
va_end(args);
|
||||
|
||||
gtext(x, y, __stdio_buffer);
|
||||
}
|
11
src/tales/gtext.c
Normal file
11
src/tales/gtext.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <internals/tales.h>
|
||||
#include <tales.h>
|
||||
|
||||
/*
|
||||
gtext()
|
||||
Prints the given raw string.
|
||||
*/
|
||||
void gtext(int x, int y, const char *str)
|
||||
{
|
||||
render(x, y, str, operate_gray);
|
||||
}
|
|
@ -132,8 +132,7 @@ void operate_mono(OPERATE_ARGS)
|
|||
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)
|
||||
int update(uint32_t *operators, int height, int available, uint32_t *glyph)
|
||||
{
|
||||
// Glyph width.
|
||||
int width = glyph[0] >> 24;
|
||||
|
|
Loading…
Reference in a new issue