diff --git a/.gitignore b/.gitignore index 06e0ba1..9a73a45 100644 --- a/.gitignore +++ b/.gitignore @@ -9,12 +9,13 @@ build/** *.o # Some notes. -LIBC +notes/** # Output files libc.a libgint.a gintdemo.g1a +gintdbg.g1a # Configuration files gcc.cfg diff --git a/Makefile b/Makefile index ab90ea1..3c2f7a8 100755 --- a/Makefile +++ b/Makefile @@ -1,25 +1,25 @@ #! /usr/bin/make -f -#--- # -# gint project Makefile. +# gint project Makefile # #--- include Makefile.cfg #--- -# Project variables. +# Project variables #--- # Modules -modules-gint = core clock keyboard mmu mpu rtc screen timer \ - bopti display gray tales events -modules-libc = setjmp string stdio stdlib time +modules-gint = bopti clock core display events gray keyboard mmu rtc \ + screen tales timer +modules-libc = setjmp stdio stdlib string time # Targets -target-g1a = gintdemo.g1a target-lib = libgint.a target-std = libc.a +target-g1a = gintdemo.g1a +target-dbg = gintdbg.g1a # Tools cc = sh3eb-elf-gcc @@ -28,27 +28,40 @@ ar = sh3eb-elf-ar ob = sh3eb-elf-objcopy wr = g1a-wrapper -# Flags -cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \ - -W -Wall -Wextra -pedantic @gcc.cfg +# Flags for gint +lib-cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \ + -Wall -Wextra @gcc.cfg # Demo application (could be done better) demo-src = $(notdir $(wildcard demo/*.[cs])) demo-dep = $(wildcard demo/*.h) -demo-ld = demo/gintdemo.ld demo-icon = demo/icon.bmp demo-res = $(notdir $(wildcard demo/resources/*)) demo-obj = $(patsubst %,build/demo_%.o,$(demo-src) $(demo-res)) demo-elf = build/gintdemo.elf demo-bin = build/gintdemo.bin -demo-libs = -L. -lgint -lc -lgcc +demo-ldflags = $(demo-cflags) -T demo/gintdemo.ld -L. -lgint -lc -lgcc +demo-cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \ + -Wall -Wextra + +# Debugger application (displays past diagnostics without running gint) +debug-src = $(notdir $(wildcard debug/*.[cs])) +debug-dep = $(wildcard debug/*.h) +debug-icon = debug/icon.bmp +debug-obj = $(debug-src:%=build/debug_%.o) +debug-elf = build/gintdbg.elf +debug-bin = build/gintdbg.bin +debug-ldflags = $(debug-cflags) -T debug/addin.ld -L debug -lfx -lgcc +debug-cflags = -m3 -mb -nostdlib -ffreestanding -I debug/include -I \ + include -std=c11 -Os -Wall -Wextra # Specific objects -obj-lib-spec = build/display_font_system.bmp.o +obj-lib-spec = build/display_font_system.bmp.o \ + build/display_font_terminal.bmp.o obj-std-spec = # Configuration files -config = gcc.cfg +config = gcc.cfg ifeq ($(wildcard $(config)),) $(error "Configuration files are missing. Did you ./configure ?") endif @@ -63,7 +76,7 @@ endif #--- -# Automatic variables. +# Automatic variables #--- # Modules are subfolders of src/. @@ -86,7 +99,7 @@ $(foreach mod, $(modules), $(eval \ obj-std = $(foreach mod,$(modules-libc),$(mod-$(mod)-obj)) $(obj-std-spec) obj-lib = $(foreach mod,$(modules-gint),$(mod-$(mod)-obj)) $(obj-lib-spec) -# Dependencies +# Dependencies. hdr-dep = $(wildcard include/*.h include/internals/*.h) @@ -95,11 +108,6 @@ hdr-dep = $(wildcard include/*.h include/internals/*.h) # Rule templates. #--- -#ifndef VERBOSE -#$(note "default full log") -#VERBOSE = -#endif - # C source file template: # $1 module name # $2 filename @@ -107,10 +115,10 @@ hdr-dep = $(wildcard include/*.h include/internals/*.h) define rule-c-source build/$1_$2.o: src/$1/$2 $3 $(config) $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $$<\n') - $(if $(VERBOSE),,@) $(cc) -c $$< -o $$@ $(cflags) -I src/$1 + $(if $(VERBOSE),,@) $(cc) -c $$< -o $$@ $(lib-cflags) endef -# asm source file template: +# Asm source file template: # $1 module name # $2 filename define rule-asm-source @@ -127,8 +135,9 @@ endef # Generic rules -all: $(config) $(target-std) $(target-lib) $(target-g1a) - @ printf '\e[32;1mmsg \u00bb\e[0m All done!\n' +all-lib: $(config) $(target-std) $(target-lib) + +all: $(config) $(target-std) $(target-lib) $(target-g1a) $(target-dbg) build: $(if $(VERBOSE),,@ printf '\e[35;1mdir \u00bb\e[0m mkdir $@\n') @@ -152,7 +161,7 @@ $(target-lib): $(config) $(target-std) $(obj-lib) $(target-g1a): $(config) $(target-std) $(target-lib) $(demo-obj) $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m ld -o $(demo-elf)\n') - $(if $(VERBOSE),,@) $(cc) -o $(demo-elf) $(cflags) -T $(demo-ld) $(demo-obj) $(demo-libs) + $(if $(VERBOSE),,@) $(cc) -o $(demo-elf) $(demo-obj) $(demo-ldflags) $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m objcopy -o $(demo-bin)\n') $(if $(VERBOSE),,@) $(ob) -R .comment -R .bss -O binary $(demo-elf) $(demo-bin) $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m g1a-wrapper -o $@\n') @@ -161,6 +170,17 @@ $(target-g1a): $(config) $(target-std) $(target-lib) $(demo-obj) @ printf $$(stat -c %s $@) @ printf ' bytes)\n\n' +$(target-dbg): $(config) $(debug-obj) + $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m ld -o $(debug-elf)\n') + $(if $(VERBOSE),,@) $(cc) -o $(debug-elf) $(debug-obj) $(debug-ldflags) + $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m objcopy -o $(debug-bin)\n') + $(if $(VERBOSE),,@) $(ob) -R .comment -R .bss -O binary $(debug-elf) $(debug-bin) + $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m g1a-wrapper -o $@\n') + $(if $(VERBOSE),,@) $(wr) $(debug-bin) -o $@ -i $(debug-icon) + @ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built debug application (' + @ printf $$(stat -c %s $@) + @ printf ' bytes)\n\n' + # Automated rules $(foreach mod,$(modules), \ @@ -172,21 +192,19 @@ $(foreach mod,$(modules), \ # Specific rules -# This one should not be optimized. It makes __attribute__((interrupt_handler)) -# buggy... maybe. Anyway there's some bug in this file that I can't fix now. -build/core_gint.c.o: src/core/gint.c $(mod-core-dep) $(config) - $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n') - $(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(cflags) -I src/core -O0 +# Optimizing this one makes the interrupt handler raise illegal slot exception +# on rte; lds.l @r15+, mach. This is totally weird but I haven't understood +# why for now. -build/display_font_system.bmp.o: src/display/font_system.bmp +build/display_font_%.bmp.o: src/display/font_%.bmp $(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n') - $(if $(VERBOSE),,@) fxconv $< -o $@ --font -n gint_font_system + $(if $(VERBOSE),,@) fxconv $< -o $@ --font -n $(<:src/display/font_%.bmp=gint_font_%) # Demo application build/demo_%.c.o: demo/%.c $(hdr-dep) $(demo-dep) $(config) $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n') - $(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(cflags) + $(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(demo-cflags) build/demo_font_%.bmp.o: demo/resources/font_%.bmp $(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n') @@ -196,10 +214,20 @@ build/demo_%.bmp.o: demo/resources/%.bmp $(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n') $(if $(VERBOSE),,@) fxconv $< -o $@ -n $(patsubst demo/resources/%.bmp,res_%,$<) +# Debug application + +build/debug_%.s.o: debug/%.s $(config) + $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m as $<\n') + $(if $(VERBOSE),,@) $(as) -c $< -o $@ + +build/debug_%.c.o: debug/%.c $(hdr-dep) $(debug-dep) $(config) + $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n') + $(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(debug-cflags) + #--- -# Cleaning and others. +# Cleaning and install #--- clean: @@ -222,7 +250,11 @@ ifdef config_ext endif @ printf '\e[32;1mmsg \u00bb\e[0m All installed!\n' -install_demo: +install-demo: p7 send -f $(target-g1a) +install-debug: + p7 send -f $(target-dbg) -.PHONY: all clean mrproper distclean install install_demo help +.PHONY: all-lib all help +.PHONY: clean mrproper distclean +.PHONY: install install-demo install-debug diff --git a/README.md b/README.md index 64a94c6..79e9845 100644 --- a/README.md +++ b/README.md @@ -59,13 +59,14 @@ The classical way to build gint is to enter a terminal and use the usual: $ make # make install -This will build and install the following components in the storage folder of -the fxSDK: +This will build the `all-lib` target and install the following components in +the storage folder of the fxSDK: * `libgint.a`, the gint library * `libc.a`, the partial standard library * The libgint headers for development -The following additional files will be generated in the working directory: +When explicitly running target `all`, the following additional files will be +generated in the working directory: * `gintdemo.g1a`, a test application The usual `clean`, `mrproper`, and `distclean` rules will clean the directory. @@ -79,8 +80,8 @@ allocation...). Source organization ------------------- -gint is made of *modules*. Each module may have any of the following -components: +gint is made of *modules*. Each module has one or more of the following +component files: * A header file in `/include` * An internal header file in `/include/internals` * Single-function source files in `/src/module`: to avoid linking against the @@ -91,4 +92,4 @@ components: often begin with `module_`. * Other files in `/src/module`: the `display` module contains a font. -The demo application is in the `demo` directory. +The demo application is in the `demo` folder. diff --git a/TODO b/TODO index a4ed30e..3f7b8de 100644 --- a/TODO +++ b/TODO @@ -9,30 +9,28 @@ Simple improvements: - demo: Try 284x124 at (-60, -28) (all disadvantages) - display: Rectangle-based drawing functions - time: Compute CLOCKS_PER_SEC -- core: Add VBR handlers debugging information (if possible) - events: Introduce KeyRepeat events -- library: Implement C99's inttypes.h for Cake's UpdateExe - string: Use cmp/str to implement memchr() (assembler examples) - string: Do some tests for memcmp() +- core: Register more interrupts (and understand their parameters) +- rtc: Take care of carry when reading time Larger improvements: - errno: Introduce errno and use it more or less everywhere - bopti: Monochrome bitmaps blending modes - bopti: Handle partial transparency - core: Implement all callbacks and a complete user API -Other whole modules: -- Serial communication through 3-pin -- USB communication -- Sound playback and synthesizing (if possible) -- Overclock (relaunch clocks when overclocking) +* core: Better save registers +* core: Allow return to menu +- serial: Implement a driver +- usb: Implement a driver +- esper: Cleaner playback, synthetizing +- clock: Handle overclocking (relaunch clocks when overclocking) Things to investigate: - Packed bit fields alignment - Registers that may need to be saved within setjmp() - Registers that may need to be saved and restored by gint -- Possible bug when optimizing __attribute__((interrupt_handler)) - -Configuration: -- ATEXIT_MAX (16) -- RTC_CB_ARRAY_SIZE (5) -- EVENTS_QUEUE_SIZE (64) -- GINT_NO_SYSCALLS (undefined) +- Optimizing core/gint.c leads to raising of an illegal slot exception when + running the interrupt handler, although it ends on rte; lds.l @r15+, mach, + which is totally not an illegal slot. +- Check version registers on SH7705 diff --git a/configure b/configure index 8fb9110..5bd34db 100755 --- a/configure +++ b/configure @@ -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$C0 [default:$Cp 16$C0] - Number of exit handlers that can be registered by atexit(). - $Cr--rtc-callbacks=$C0$Cg$C0 [default:$Cp 5$C0] - Number of RTC callbacks that can be registered. - $Cr--events-queue-size=$C0$Cg$C0 [default:$Cp 64$C0] - Number of events simultaneously stored in the event queue. + $Cr--atexit-max$C0=$Cy$Cg [default:$Cp 16$Cg]$C0 + Number of exit handlers that can be registered by atexit(). + $Cr--rtc-callbacks$C0=$Cy$Cg [default:$Cp 5$Cg]$C0 + Number of RTC callbacks that can be registered. + $Cr--events-queue-size$C0=$Cy$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 diff --git a/debug/addin.ld b/debug/addin.ld new file mode 100644 index 0000000..b712b1d --- /dev/null +++ b/debug/addin.ld @@ -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 +} diff --git a/debug/crt0.s b/debug/crt0.s new file mode 100644 index 0000000..93000cf --- /dev/null +++ b/debug/crt0.s @@ -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 diff --git a/debug/gintdbg.c b/debug/gintdbg.c new file mode 100644 index 0000000..61c70af --- /dev/null +++ b/debug/gintdbg.c @@ -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 +#include + +#include +#include +#include + +// 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; +} diff --git a/debug/icon.bmp b/debug/icon.bmp new file mode 100644 index 0000000..6240f61 Binary files /dev/null and b/debug/icon.bmp differ diff --git a/debug/include/dispbios.h b/debug/include/dispbios.h new file mode 100644 index 0000000..7b2bdc6 --- /dev/null +++ b/debug/include/dispbios.h @@ -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 diff --git a/debug/include/endian.h b/debug/include/endian.h new file mode 100644 index 0000000..0a4be82 --- /dev/null +++ b/debug/include/endian.h @@ -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 diff --git a/debug/include/filebios.h b/debug/include/filebios.h new file mode 100644 index 0000000..276d9ce --- /dev/null +++ b/debug/include/filebios.h @@ -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 diff --git a/debug/include/fxlib.h b/debug/include/fxlib.h new file mode 100644 index 0000000..dc4534a --- /dev/null +++ b/debug/include/fxlib.h @@ -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 diff --git a/debug/include/keybios.h b/debug/include/keybios.h new file mode 100644 index 0000000..848fa5f --- /dev/null +++ b/debug/include/keybios.h @@ -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 diff --git a/debug/include/timer.h b/debug/include/timer.h new file mode 100644 index 0000000..286f665 --- /dev/null +++ b/debug/include/timer.h @@ -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 diff --git a/debug/libfx.a b/debug/libfx.a new file mode 100644 index 0000000..5ef92aa Binary files /dev/null and b/debug/libfx.a differ diff --git a/debug/vsprintf.c b/debug/vsprintf.c new file mode 100644 index 0000000..ad18ba3 --- /dev/null +++ b/debug/vsprintf.c @@ -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 +#include + +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; +} diff --git a/demo/gintdemo.c b/demo/gintdemo.c index de90854..b9b92f6 100644 --- a/demo/gintdemo.c +++ b/demo/gintdemo.c @@ -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 " + ); +} +*/ diff --git a/demo/gintdemo.ld b/demo/gintdemo.ld index 1947163..9111fcc 100644 --- a/demo/gintdemo.ld +++ b/demo/gintdemo.ld @@ -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 = . ; diff --git a/demo/test_bopti.c b/demo/test_bopti.c index f769365..818bdb6 100644 --- a/demo/test_bopti.c +++ b/demo/test_bopti.c @@ -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); +*/ } } diff --git a/demo/test_tales.c b/demo/test_tales.c index 1a64352..644fc23 100644 --- a/demo/test_tales.c +++ b/demo/test_tales.c @@ -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); diff --git a/demo/test_timer.c b/demo/test_timer.c index 2f634d3..d8158b5 100644 --- a/demo/test_timer.c +++ b/demo/test_timer.c @@ -12,7 +12,7 @@ #include static void draw(int new_tab); -static struct ClockConfig conf; +static clock_config_t conf; //--- // Timer-RTC comparison. diff --git a/include/clock.h b/include/clock.h index 58e5c30..65ed96b 100644 --- a/include/clock.h +++ b/include/clock.h @@ -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 diff --git a/include/ctype.h b/include/ctype.h index a325f23..23ceac4 100644 --- a/include/ctype.h +++ b/include/ctype.h @@ -62,7 +62,7 @@ __attribute__((always_inline)) static inline int isxdigit(int c) { } __attribute__((always_inline)) static inline int isascii(int c) { - return (c >= 0 && c <= 0x7f); + return ((unsigned)c <= 0x7f); } __attribute__((always_inline)) static inline int isblank(int c) { diff --git a/include/display.h b/include/display.h index 5112f86..c5dba6e 100644 --- a/include/display.h +++ b/include/display.h @@ -10,6 +10,7 @@ #define _DISPLAY_H 1 #include +#include //--- diff --git a/include/gint.h b/include/gint.h index c49cb5f..85fc84f 100644 --- a/include/gint.h +++ b/include/gint.h @@ -8,185 +8,221 @@ //--- #ifndef _GINT_H -#define _GINT_H 1 +#define _GINT_H -#define GINT_VERSION 0x01000000 -#define GINT_VERSION_STR "01.00" +#include +#include + +#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 diff --git a/include/gray.h b/include/gray.h index e18a20a..bbae4f0 100644 --- a/include/gray.h +++ b/include/gray.h @@ -138,23 +138,4 @@ void gimage(int x, int y, struct Image *image); void gimage_part(int x, int y, struct Image *image, int left, int top, int width, int height); - - -//--- -// Internal API. -// Referenced here for documentation purposes only. Do not call. -//-- - -/* - gray_interrupt() - Answers a timer interrupt. Swaps the two buffers. -*/ -void gray_interrupt(void) __attribute__((section(".gint.int"))); - -/* - gray_init() - Initializes the gray engine. -*/ -void gray_init(void) __attribute__((constructor)); - #endif // _GRAY_H diff --git a/include/internals/clock.h b/include/internals/clock.h new file mode 100644 index 0000000..6de2c43 --- /dev/null +++ b/include/internals/clock.h @@ -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 diff --git a/include/internals/exceptions.h b/include/internals/exceptions.h new file mode 100644 index 0000000..80b4b38 --- /dev/null +++ b/include/internals/exceptions.h @@ -0,0 +1,66 @@ +#ifndef _INTERNALS_EXCEPTIONS_H +#define _INTERNALS_EXCEPTIONS_H + +#include + +/* + 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 diff --git a/include/internals/gint.h b/include/internals/gint.h index 4f038d2..91a07a7 100644 --- a/include/internals/gint.h +++ b/include/internals/gint.h @@ -1,30 +1,184 @@ #ifndef _INTERNALS_GINT_H #define _INTERNALS_GINT_H 1 +#include +#include + //--- -// 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 + +// 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 diff --git a/include/internals/interrupt_maps.h b/include/internals/interrupt_maps.h new file mode 100644 index 0000000..ac66baf --- /dev/null +++ b/include/internals/interrupt_maps.h @@ -0,0 +1,100 @@ +#ifndef _INTERRUPT_MAPS +#define _INTERRUPT_MAPS + +#include +#include + +//--- +// 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 diff --git a/include/internals/interrupts.h b/include/internals/interrupts.h new file mode 100644 index 0000000..0957d11 --- /dev/null +++ b/include/internals/interrupts.h @@ -0,0 +1,18 @@ +#ifndef _INTERNALS_INTERRUPTS_H +#define _INTERNALS_INTERRUPTS_H + +#include + +/* + 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 diff --git a/include/internals/keyboard.h b/include/internals/keyboard.h index f982fcf..2824893 100644 --- a/include/internals/keyboard.h +++ b/include/internals/keyboard.h @@ -2,6 +2,7 @@ #define _INTERNALS_KEYBOARD_H #include +#include // 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. diff --git a/include/keyboard.h b/include/keyboard.h index a1b101b..4bb2483 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -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() diff --git a/include/mpu.h b/include/mpu.h index fd4a498..e789cdd 100644 --- a/include/mpu.h +++ b/include/mpu.h @@ -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 diff --git a/include/rtc.h b/include/rtc.h index 805c91d..48f72e9 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -107,9 +107,9 @@ int rtc_cb_edit(int id, enum RTCFrequency new_freq, rtc_interrupt() Handles an RTC interrupt by calling the callback. */ -void rtc_interrupt(void) __attribute__((section(".gint.int"))); -void rtc_interrupt_7705(void) __attribute__((section(".gint.int"))); -void rtc_interrupt_7305(void) __attribute__((section(".gint.int"))); +void rtc_interrupt(void); +void rtc_interrupt_7705(void); +void rtc_interrupt_7305(void); /* rtc_cb_interrupt() diff --git a/include/tales.h b/include/tales.h index e1304c3..501e263 100644 --- a/include/tales.h +++ b/include/tales.h @@ -12,6 +12,7 @@ #include #include +#include //--- // Types and constants. diff --git a/include/timer.h b/include/timer.h index 34fe987..1b5cb7d 100644 --- a/include/timer.h +++ b/include/timer.h @@ -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 diff --git a/src/bopti/bopti_internals.c b/src/bopti/bopti_internals.c index acdf435..4b6503f 100644 --- a/src/bopti/bopti_internals.c +++ b/src/bopti/bopti_internals.c @@ -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; diff --git a/src/bopti/dimage.c b/src/bopti/dimage.c index 4033398..104aee8 100644 --- a/src/bopti/dimage.c +++ b/src/bopti/dimage.c @@ -2,10 +2,13 @@ #include /* - 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); } diff --git a/src/bopti/dimage_part.c b/src/bopti/dimage_part.c deleted file mode 100644 index 4af879f..0000000 --- a/src/bopti/dimage_part.c +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -/* - 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++; - } -} diff --git a/src/bopti/gimage.c b/src/bopti/gimage.c index e010f20..1bd4b5c 100644 --- a/src/bopti/gimage.c +++ b/src/bopti/gimage.c @@ -3,10 +3,13 @@ #include /* - 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); +} diff --git a/src/bopti/gimage_part.c b/src/bopti/gimage_part.c deleted file mode 100644 index 7c3314f..0000000 --- a/src/bopti/gimage_part.c +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include -#include - -/* -#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++; - } -} diff --git a/src/clock/clock.c b/src/clock/clock.c index 28230be..a88a216 100644 --- a/src/clock/clock.c +++ b/src/clock/clock.c @@ -5,39 +5,13 @@ #include #include -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) { diff --git a/src/core/crt0.c b/src/core/crt0.c index d22de28..19cf44d 100644 --- a/src/core/crt0.c +++ b/src/core/crt0.c @@ -1,21 +1,27 @@ #include #include #include +#include -#include -#include +#include #include +#include +#include +#include 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(); +} diff --git a/src/core/exceptions.c b/src/core/exceptions.c new file mode 100644 index 0000000..ca57cc0 --- /dev/null +++ b/src/core/exceptions.c @@ -0,0 +1,172 @@ +#include +#include +#include + +//--- +// 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 diff --git a/src/core/gint.c b/src/core/gint.c index 28de9f2..608bce5 100644 --- a/src/core/gint.c +++ b/src/core/gint.c @@ -8,278 +8,182 @@ //--- #include +#include +#include +#include #include #include -#include -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 -#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); } diff --git a/src/mpu/gint_sh7305.c b/src/core/gint_sh7305.c similarity index 66% rename from src/mpu/gint_sh7305.c rename to src/core/gint_sh7305.c index 7327a38..7410084 100644 --- a/src/mpu/gint_sh7305.c +++ b/src/core/gint_sh7305.c @@ -15,52 +15,6 @@ #include <7305.h> #include -#include - -//--- -// 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) diff --git a/src/mpu/gint_sh7705.c b/src/core/gint_sh7705.c similarity index 51% rename from src/mpu/gint_sh7705.c rename to src/core/gint_sh7705.c index a1c19aa..9f5ac26 100644 --- a/src/mpu/gint_sh7705.c +++ b/src/core/gint_sh7705.c @@ -15,52 +15,6 @@ #include <7705.h> #include -#include - -//--- -// 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) diff --git a/src/core/gint_str.c b/src/core/gint_str.c deleted file mode 100644 index c7e9957..0000000 --- a/src/core/gint_str.c +++ /dev/null @@ -1,37 +0,0 @@ -#include - -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", -}; diff --git a/src/core/gint_vbr.s b/src/core/gint_vbr.s index 488be1b..7253a91 100644 --- a/src/core/gint_vbr.s +++ b/src/core/gint_vbr.s @@ -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. */ diff --git a/src/core/init_quit.c b/src/core/init_quit.c new file mode 100644 index 0000000..8ecea6b --- /dev/null +++ b/src/core/init_quit.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include + +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); +} diff --git a/src/core/interrupt_maps_7305.c b/src/core/interrupt_maps_7305.c new file mode 100644 index 0000000..bf76fa9 --- /dev/null +++ b/src/core/interrupt_maps_7305.c @@ -0,0 +1,53 @@ +#include +#include + +//--- +// 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; +} diff --git a/src/core/interrupt_maps_7705.c b/src/core/interrupt_maps_7705.c new file mode 100644 index 0000000..d471d0a --- /dev/null +++ b/src/core/interrupt_maps_7705.c @@ -0,0 +1,65 @@ +#include +#include + +//--- +// 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; +} diff --git a/src/core/interrupts.c b/src/core/interrupts.c new file mode 100644 index 0000000..d056774 --- /dev/null +++ b/src/core/interrupts.c @@ -0,0 +1,21 @@ +#include +#include +#include + +/* + 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(); +} diff --git a/src/mpu/mpu.c b/src/core/mpu.c similarity index 85% rename from src/mpu/mpu.c rename to src/core/mpu.c index f4c7dc6..13f621c 100644 --- a/src/mpu/mpu.c +++ b/src/core/mpu.c @@ -8,7 +8,7 @@ #include -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(); } diff --git a/src/core/syscalls.s b/src/core/syscalls.s index e4dd817..0fdb38d 100644 --- a/src/core/syscalls.s +++ b/src/core/syscalls.s @@ -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 diff --git a/src/core/vbr_space.c b/src/core/vbr_space.c new file mode 100644 index 0000000..2344854 --- /dev/null +++ b/src/core/vbr_space.c @@ -0,0 +1,98 @@ +#include +#include +#include + +// 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 diff --git a/src/display/dupdate.c b/src/display/dupdate.c index 6ca42f8..a6c92c9 100644 --- a/src/display/dupdate.c +++ b/src/display/dupdate.c @@ -1,7 +1,6 @@ #include #include #include -#include /* dupdate() @@ -9,6 +8,5 @@ */ void dupdate(void) { - if(gray_runs()) return; screen_display((const void *)vram); } diff --git a/src/gray/gray_engine.c b/src/gray/gray_engine.c index 893897f..9c1071f 100644 --- a/src/gray/gray_engine.c +++ b/src/gray/gray_engine.c @@ -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; -} diff --git a/src/rtc/rtc_callback.c b/src/rtc/rtc_callback.c index 3a69a95..635eafc 100644 --- a/src/rtc/rtc_callback.c +++ b/src/rtc/rtc_callback.c @@ -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) diff --git a/src/tales/tales_print.c b/src/tales/dprint.c similarity index 56% rename from src/tales/tales_print.c rename to src/tales/dprint.c index be3d107..cf3c4e8 100644 --- a/src/tales/tales_print.c +++ b/src/tales/dprint.c @@ -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); -} diff --git a/src/tales/tales_text.c b/src/tales/dtext.c similarity index 60% rename from src/tales/tales_text.c rename to src/tales/dtext.c index 3729f7d..22e7b59 100644 --- a/src/tales/tales_text.c +++ b/src/tales/dtext.c @@ -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); -} diff --git a/src/tales/gprint.c b/src/tales/gprint.c new file mode 100644 index 0000000..8f58f29 --- /dev/null +++ b/src/tales/gprint.c @@ -0,0 +1,18 @@ +#include +#include +#include + +/* + 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); +} diff --git a/src/tales/gtext.c b/src/tales/gtext.c new file mode 100644 index 0000000..118aafd --- /dev/null +++ b/src/tales/gtext.c @@ -0,0 +1,11 @@ +#include +#include + +/* + gtext() + Prints the given raw string. +*/ +void gtext(int x, int y, const char *str) +{ + render(x, y, str, operate_gray); +} diff --git a/src/tales/tales_internals.c b/src/tales/tales_internals.c index d0a2483..c12d2c5 100644 --- a/src/tales/tales_internals.c +++ b/src/tales/tales_internals.c @@ -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;