Huh... debug app for crashes & whole new interrupt system. Minor edits.

This commit is contained in:
lephe 2017-02-25 19:02:07 +01:00
parent 49df2a5fb4
commit d852bc3310
66 changed files with 2883 additions and 1187 deletions

3
.gitignore vendored
View file

@ -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
View file

@ -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

View file

@ -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
View file

@ -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
View file

@ -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
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

97
debug/include/dispbios.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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

Binary file not shown.

160
debug/vsprintf.c Normal file
View 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;
}

View file

@ -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 "
);
}
*/

View file

@ -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 = . ;

View file

@ -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);
*/
}
}

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -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) {

View file

@ -10,6 +10,7 @@
#define _DISPLAY_H 1
#include <stdint.h>
#include <stddef.h>
//---

View file

@ -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

View file

@ -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
View 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

View 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

View file

@ -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

View 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

View 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

View file

@ -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.

View file

@ -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()

View file

@ -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

View file

@ -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()

View file

@ -12,6 +12,7 @@
#include <display.h>
#include <stdint.h>
#include <stddef.h>
//---
// Types and constants.

View file

@ -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

View file

@ -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;

View file

@ -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);
}

View file

@ -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++;
}
}

View file

@ -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);
}

View file

@ -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++;
}
}

View file

@ -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)
{

View file

@ -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
View 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

View file

@ -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);
}

View file

@ -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)

View file

@ -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)

View file

@ -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",
};

View file

@ -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
View 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);
}

View 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;
}

View 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
View 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();
}

View file

@ -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();
}

View file

@ -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
View 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

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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);
}

View file

@ -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
View 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
View 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);
}

View file

@ -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;