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