From d122624c56157039685a3594ea2ef04c3f313e2b Mon Sep 17 00:00:00 2001 From: lephe Date: Wed, 6 Jul 2016 11:28:51 +0200 Subject: [PATCH] Re-structured files. Minor name changes. No code changed in this falsely huge commit. --- Makefile | 148 +---- Makefile.old | 141 +++++ README.md | 16 + TODO | 2 + ginttest.c => demo/gintdemo.c | 2 +- ginttest.ld => demo/gintdemo.ld | 0 icon.bmp => demo/icon.bmp | Bin {resources => demo/resources}/bitmap_opt.bmp | Bin {resources => demo/resources}/font.bmp | Bin .../resources}/illustration.bmp | Bin {resources => demo/resources}/sprites.bmp | Bin {resources => demo/resources}/swords.bmp | Bin {resources => demo/resources}/symbol.bmp | Bin {resources => demo/resources}/symbol2.bmp | Bin ginttest.g1a | Bin 20136 -> 0 bytes include/gint.h | 44 +- include/keyboard.h | 50 +- include/mpu.h | 34 +- include/screen.h | 19 +- include/tales.h | 30 +- include/timer.h | 43 +- libc.a | Bin 1770 -> 1770 bytes libgint.a | Bin 30732 -> 30732 bytes src/{bopti.c => bopti/bopti_internals.c} | 143 +---- src/bopti/bopti_internals.h | 127 ++++ src/bopti/dimage.c | 38 ++ src/bopti/gimage.c | 37 ++ src/{ => core}/crt0.c | 26 +- src/{ => core}/gint.c | 56 +- src/core/gint_callback.c | 40 ++ src/{ => core}/gint_vbr.s | 5 - src/{ => core}/syscalls.s | 6 +- src/display.c | 473 --------------- src/display/adjustRectangle.c | 24 + src/display/dclear.c | 12 + src/display/dclear_area.c | 21 + src/display/display_internals.h | 52 ++ src/display/display_vram.c | 43 ++ src/display/dline.c | 116 ++++ src/display/dpixel.c | 32 + src/display/dreverse_area.c | 21 + src/display/dupdate.c | 14 + src/display/getMasks.c | 34 ++ src/gint_7305.c | 313 ---------- src/gint_7705.c | 276 --------- src/gray/gclear.c | 14 + src/gray/gclear_area.c | 15 + src/gray/gline.c | 20 + src/gray/gpixel.c | 47 ++ src/{gray.c => gray/gray_engine.c} | 176 ++---- src/gray/greverse_area.c | 15 + src/keyboard.c | 502 ---------------- src/keyboard/getPressedKey.c | 24 + src/keyboard/getPressedKeys.c | 54 ++ src/keyboard/getkey.c | 113 ++++ src/keyboard/keyboard_config.c | 26 + src/keyboard/keyboard_internals.h | 34 ++ src/keyboard/keyboard_interrupt.c | 56 ++ src/keyboard/keyboard_misc.c | 25 + src/keyboard/keyboard_sh7305.c | 146 +++++ src/keyboard/keyboard_sh7705.c | 139 +++++ src/keyboard/keychar.c | 36 ++ src/keyboard/keyid.c | 17 + src/keyboard/keytype.c | 17 + src/keyboard/multigetkey.c | 46 ++ src/keyboard/sleep.c | 13 + src/mpu/gint_sh7305.c | 159 +++++ src/mpu/gint_sh7705.c | 125 ++++ src/{ => mpu}/mpu.c | 21 +- src/mpu/various_7305.c | 27 + src/mpu/various_7705.c | 27 + src/{screen.c => screen/screen_display.c} | 18 +- src/{ => setjmp}/setjmp.s | 19 +- src/{string.c => string/memcpy.c} | 58 -- src/string/memset.c | 48 ++ src/tales.c | 290 --------- src/tales/dtext.c | 88 +++ src/tales/tales_configuration.c | 11 + src/tales/tales_internals.c | 164 +++++ src/tales/tales_internals.h | 47 ++ src/timer.c | 201 ------- src/timer/timer_get.c | 25 + src/timer/timer_internals.h | 54 ++ src/timer/timer_interrupt.c | 27 + src/timer/timer_reload.c | 22 + src/timer/timer_start.c | 38 ++ src/timer/timer_stop.c | 18 + syscall_0x24a.txt | 190 ------ syscall_0x24a_7705.txt | 558 ------------------ syscall_0x24b.txt | 91 --- 90 files changed, 2713 insertions(+), 3586 deletions(-) create mode 100644 Makefile.old rename ginttest.c => demo/gintdemo.c (99%) rename ginttest.ld => demo/gintdemo.ld (100%) rename icon.bmp => demo/icon.bmp (100%) rename {resources => demo/resources}/bitmap_opt.bmp (100%) rename {resources => demo/resources}/font.bmp (100%) rename {resources => demo/resources}/illustration.bmp (100%) rename {resources => demo/resources}/sprites.bmp (100%) rename {resources => demo/resources}/swords.bmp (100%) rename {resources => demo/resources}/symbol.bmp (100%) rename {resources => demo/resources}/symbol2.bmp (100%) delete mode 100644 ginttest.g1a rename src/{bopti.c => bopti/bopti_internals.c} (67%) create mode 100644 src/bopti/bopti_internals.h create mode 100644 src/bopti/dimage.c create mode 100644 src/bopti/gimage.c rename src/{ => core}/crt0.c (83%) rename src/{ => core}/gint.c (58%) create mode 100644 src/core/gint_callback.c rename src/{ => core}/gint_vbr.s (92%) rename src/{ => core}/syscalls.s (82%) delete mode 100644 src/display.c create mode 100644 src/display/adjustRectangle.c create mode 100644 src/display/dclear.c create mode 100644 src/display/dclear_area.c create mode 100644 src/display/display_internals.h create mode 100644 src/display/display_vram.c create mode 100644 src/display/dline.c create mode 100644 src/display/dpixel.c create mode 100644 src/display/dreverse_area.c create mode 100644 src/display/dupdate.c create mode 100644 src/display/getMasks.c delete mode 100644 src/gint_7305.c delete mode 100644 src/gint_7705.c create mode 100644 src/gray/gclear.c create mode 100644 src/gray/gclear_area.c create mode 100644 src/gray/gline.c create mode 100644 src/gray/gpixel.c rename src/{gray.c => gray/gray_engine.c} (52%) create mode 100644 src/gray/greverse_area.c delete mode 100644 src/keyboard.c create mode 100644 src/keyboard/getPressedKey.c create mode 100644 src/keyboard/getPressedKeys.c create mode 100644 src/keyboard/getkey.c create mode 100644 src/keyboard/keyboard_config.c create mode 100644 src/keyboard/keyboard_internals.h create mode 100644 src/keyboard/keyboard_interrupt.c create mode 100644 src/keyboard/keyboard_misc.c create mode 100644 src/keyboard/keyboard_sh7305.c create mode 100644 src/keyboard/keyboard_sh7705.c create mode 100644 src/keyboard/keychar.c create mode 100644 src/keyboard/keyid.c create mode 100644 src/keyboard/keytype.c create mode 100644 src/keyboard/multigetkey.c create mode 100644 src/keyboard/sleep.c create mode 100644 src/mpu/gint_sh7305.c create mode 100644 src/mpu/gint_sh7705.c rename src/{ => mpu}/mpu.c (82%) create mode 100644 src/mpu/various_7305.c create mode 100644 src/mpu/various_7705.c rename src/{screen.c => screen/screen_display.c} (60%) rename src/{ => setjmp}/setjmp.s (65%) rename src/{string.c => string/memcpy.c} (55%) create mode 100644 src/string/memset.c delete mode 100644 src/tales.c create mode 100644 src/tales/dtext.c create mode 100644 src/tales/tales_configuration.c create mode 100644 src/tales/tales_internals.c create mode 100644 src/tales/tales_internals.h delete mode 100644 src/timer.c create mode 100644 src/timer/timer_get.c create mode 100644 src/timer/timer_internals.h create mode 100644 src/timer/timer_interrupt.c create mode 100644 src/timer/timer_reload.c create mode 100644 src/timer/timer_start.c create mode 100644 src/timer/timer_stop.c delete mode 100644 syscall_0x24a.txt delete mode 100644 syscall_0x24a_7705.txt delete mode 100644 syscall_0x24b.txt diff --git a/Makefile b/Makefile index ea3834a..ee6613f 100644 --- a/Makefile +++ b/Makefile @@ -1,141 +1,11 @@ -#! /usr/bin/make -f +## Temporary things there -#--- -# fx-9860g lib Makefile. -#--- +# C source file template: +# $1 module name +# $2 file base name +define rule-c-source +build/$1_$2.c.o: src/$1/$2.c + $(cc) $(cflags) -c $$< -o $$@ +endef - - -# -# Variables and configuration. -# - -# Tools -cc = sh3eb-elf-gcc -as = sh3eb-elf-as -ar = sh3eb-elf-ar -ob = sh3eb-elf-objcopy -wr = g1a-wrapper - -# Output files -g1a = ginttest.g1a -bin = build/ginttest.bin -elf = build/ginttest.elf - -# Command-line options -cflags = -m3 -mb -nostdlib -ffreestanding -W -Wall \ - -I . -isystem include -lib = -lgcc -L. -lgint -lc - - - -# -# Source and object files. -# - -# Gint library. -src-lib = crt0.c syscalls.s \ - gint.c gint_vbr.s gint_7705.c gint_7305.c \ - mpu.c keyboard.c screen.c display.c gray.c timer.c tales.c \ - bopti.c -hea-lib = 7305.h 7705.h gint.h \ - stdlib.h \ - mpu.h keyboard.h screen.h display.h gray.h timer.h tales.h -obj-lib = $(patsubst %, build/%.o, $(src-lib)) -hdr-lib = $(patsubst %, include/%, $(hea-lib)) - -# Standard library. -src-std = setjmp.s string.c -hea-std = setjmp.h string.h ctype.h -obj-std = $(patsubst %, build/%.o, $(src-std)) -hdr-std = $(patsubst %, include/%, $(hea-str)) - -# Test application. -src-app = ginttest.c -img-app = bitmap_opt.bmp swords.bmp sprites.bmp symbol.bmp symbol2.bmp \ - illustration.bmp -res-app = $(patsubst %, build/%.o, $(img-app)) build/font.o - - -# -# Building rules. -# - -all: build libgint.a libc.a ginttest.g1a - -build: - mkdir -p build - -libgint.a: $(obj-lib) - $(ar) rcs libgint.a $(obj-lib) - @ echo "\033[32;1mLibrary file size: "`stat -c %s libgint.a` \ - "bytes\033[0m" - -libc.a: $(obj-std) - $(ar) rcs libc.a $(obj-std) - @ echo "\033[32;1mStandard file size: "`stat -c %s libc.a` \ - "bytes\033[0m" - -$(g1a): libgint.a $(src-app) $(res-app) - $(cc) $(src-app) $(res-app) -T ginttest.ld -o $(elf) $(cflags) $(lib) - $(ob) -R .comment -R .bss -O binary $(elf) $(bin) - $(wr) $(bin) -o ginttest.g1a -i icon.bmp - @ echo "\033[32;1mBinary file size: "`stat -c %s $(bin)`" bytes\033[0m" - @ sh3eb-elf-objdump -h build/ginttest.elf - - - -# -# Resource management. -# - -build/%.c.o: src/%.c $(hdr-lib) $(hdr-std) - $(cc) $(cflags) -O2 -c $< -o $@ - -build/%.s.o: src/%.s - $(as) -c $^ -o $@ - -build/%.bmp.o: resources/%.bmp - fxconv $^ -o $@ --preview - -build/font.o: resources/font.bmp - fxconv --font $^ -o $@ - -# File gint.c should not be optimized... looks like attribute((interrupt_ -# handler)) doesn't like it. (It could be a gint bug also, I should check.) -build/gint.c.o: src/gint.c $(hdr-lib) $(hdr-std) - $(cc) $(cflags) -c $< -o $@ - -%.c.o: %.c $(hdr-lib) $(hdr-std) - $(cc) $(cflags) -c $< -o $@ -%.s.o: %.s - $(as) -c $^ -o $@ - - - -# -# Cleaning rules. -# - -clean: - @ rm -f $(obj-lib) $(obj-std) $(obj-app) $(res-app) - @ rm -f $(bin) $(elf) -mrproper: clean - @ rm -f build/* - @ rm -f ginttest.g1a libc.a libgint.a -distclean: mrproper - -re: distclean all - - - -# -# Installing shorthand. -# - -install: - usb-connector SEND ginttest.g1a ginttest.g1a fls0 - - - -.PHONY: all clean mrproper distclean re install +$(eval $(call rule-c-source,display,area)) diff --git a/Makefile.old b/Makefile.old new file mode 100644 index 0000000..ea3834a --- /dev/null +++ b/Makefile.old @@ -0,0 +1,141 @@ +#! /usr/bin/make -f + +#--- +# fx-9860g lib Makefile. +#--- + + + +# +# Variables and configuration. +# + +# Tools +cc = sh3eb-elf-gcc +as = sh3eb-elf-as +ar = sh3eb-elf-ar +ob = sh3eb-elf-objcopy +wr = g1a-wrapper + +# Output files +g1a = ginttest.g1a +bin = build/ginttest.bin +elf = build/ginttest.elf + +# Command-line options +cflags = -m3 -mb -nostdlib -ffreestanding -W -Wall \ + -I . -isystem include +lib = -lgcc -L. -lgint -lc + + + +# +# Source and object files. +# + +# Gint library. +src-lib = crt0.c syscalls.s \ + gint.c gint_vbr.s gint_7705.c gint_7305.c \ + mpu.c keyboard.c screen.c display.c gray.c timer.c tales.c \ + bopti.c +hea-lib = 7305.h 7705.h gint.h \ + stdlib.h \ + mpu.h keyboard.h screen.h display.h gray.h timer.h tales.h +obj-lib = $(patsubst %, build/%.o, $(src-lib)) +hdr-lib = $(patsubst %, include/%, $(hea-lib)) + +# Standard library. +src-std = setjmp.s string.c +hea-std = setjmp.h string.h ctype.h +obj-std = $(patsubst %, build/%.o, $(src-std)) +hdr-std = $(patsubst %, include/%, $(hea-str)) + +# Test application. +src-app = ginttest.c +img-app = bitmap_opt.bmp swords.bmp sprites.bmp symbol.bmp symbol2.bmp \ + illustration.bmp +res-app = $(patsubst %, build/%.o, $(img-app)) build/font.o + + +# +# Building rules. +# + +all: build libgint.a libc.a ginttest.g1a + +build: + mkdir -p build + +libgint.a: $(obj-lib) + $(ar) rcs libgint.a $(obj-lib) + @ echo "\033[32;1mLibrary file size: "`stat -c %s libgint.a` \ + "bytes\033[0m" + +libc.a: $(obj-std) + $(ar) rcs libc.a $(obj-std) + @ echo "\033[32;1mStandard file size: "`stat -c %s libc.a` \ + "bytes\033[0m" + +$(g1a): libgint.a $(src-app) $(res-app) + $(cc) $(src-app) $(res-app) -T ginttest.ld -o $(elf) $(cflags) $(lib) + $(ob) -R .comment -R .bss -O binary $(elf) $(bin) + $(wr) $(bin) -o ginttest.g1a -i icon.bmp + @ echo "\033[32;1mBinary file size: "`stat -c %s $(bin)`" bytes\033[0m" + @ sh3eb-elf-objdump -h build/ginttest.elf + + + +# +# Resource management. +# + +build/%.c.o: src/%.c $(hdr-lib) $(hdr-std) + $(cc) $(cflags) -O2 -c $< -o $@ + +build/%.s.o: src/%.s + $(as) -c $^ -o $@ + +build/%.bmp.o: resources/%.bmp + fxconv $^ -o $@ --preview + +build/font.o: resources/font.bmp + fxconv --font $^ -o $@ + +# File gint.c should not be optimized... looks like attribute((interrupt_ +# handler)) doesn't like it. (It could be a gint bug also, I should check.) +build/gint.c.o: src/gint.c $(hdr-lib) $(hdr-std) + $(cc) $(cflags) -c $< -o $@ + +%.c.o: %.c $(hdr-lib) $(hdr-std) + $(cc) $(cflags) -c $< -o $@ +%.s.o: %.s + $(as) -c $^ -o $@ + + + +# +# Cleaning rules. +# + +clean: + @ rm -f $(obj-lib) $(obj-std) $(obj-app) $(res-app) + @ rm -f $(bin) $(elf) +mrproper: clean + @ rm -f build/* + @ rm -f ginttest.g1a libc.a libgint.a +distclean: mrproper + +re: distclean all + + + +# +# Installing shorthand. +# + +install: + usb-connector SEND ginttest.g1a ginttest.g1a fls0 + + + +.PHONY: all clean mrproper distclean re install diff --git a/README.md b/README.md index 4a94658..847a24b 100644 --- a/README.md +++ b/README.md @@ -44,3 +44,19 @@ This will build the following components : * `ginttest.g1a`, a test application The common `clean`, `mrproper`, and `distclean` rules will clean the directory. + + + +Source organization +------------------- + +gint is made of *modules*. Each module has its own source directory (which is +`/src/module`), and its associated header file in `/include`. A module folder +contains three types of files : +* Internal headers: shared only among the files of a module +* Single-function source files: to avoid linking against the whole library, + some functions have their own object files. Their names are the function + names. +* Other source files: contain multiple functions that always work together, or + are lightweight enough not to be separated. Their names often begin with + `module_`. diff --git a/TODO b/TODO index 1c84e6c..9f62af2 100644 --- a/TODO +++ b/TODO @@ -12,6 +12,8 @@ @ vram overflow @ keyboard test threading interface ++ use alloca() for tales ++ call exit handlers + compute frequencies + gray text + effective rtc callback diff --git a/ginttest.c b/demo/gintdemo.c similarity index 99% rename from ginttest.c rename to demo/gintdemo.c index 9e54fd0..c357690 100644 --- a/ginttest.c +++ b/demo/gintdemo.c @@ -1,11 +1,11 @@ #include #include + #include #include #include #include #include -#include #include #include <7305.h> diff --git a/ginttest.ld b/demo/gintdemo.ld similarity index 100% rename from ginttest.ld rename to demo/gintdemo.ld diff --git a/icon.bmp b/demo/icon.bmp similarity index 100% rename from icon.bmp rename to demo/icon.bmp diff --git a/resources/bitmap_opt.bmp b/demo/resources/bitmap_opt.bmp similarity index 100% rename from resources/bitmap_opt.bmp rename to demo/resources/bitmap_opt.bmp diff --git a/resources/font.bmp b/demo/resources/font.bmp similarity index 100% rename from resources/font.bmp rename to demo/resources/font.bmp diff --git a/resources/illustration.bmp b/demo/resources/illustration.bmp similarity index 100% rename from resources/illustration.bmp rename to demo/resources/illustration.bmp diff --git a/resources/sprites.bmp b/demo/resources/sprites.bmp similarity index 100% rename from resources/sprites.bmp rename to demo/resources/sprites.bmp diff --git a/resources/swords.bmp b/demo/resources/swords.bmp similarity index 100% rename from resources/swords.bmp rename to demo/resources/swords.bmp diff --git a/resources/symbol.bmp b/demo/resources/symbol.bmp similarity index 100% rename from resources/symbol.bmp rename to demo/resources/symbol.bmp diff --git a/resources/symbol2.bmp b/demo/resources/symbol2.bmp similarity index 100% rename from resources/symbol2.bmp rename to demo/resources/symbol2.bmp diff --git a/ginttest.g1a b/ginttest.g1a deleted file mode 100644 index 5542edb849a37d9e4404701f6f6d54892e631ece..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20136 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 F{{!FYJr!oC~qTBKHax04Fs>e*gdg delta 221 zcmeDAz}WMFae^$XiMgSX$wsC1tSlhboJia|da5jNuJ~qIV+VdXS8Q{I(@um@ j;+uV4efS` -#include -#include - - -//--- -// Heading declarations. -//--- - -/* - enum Channel - Determines the kind of information written into a layer. Every image is - made of one or more channels. -*/ -enum Channel -{ - Channel_Mono = 0x01, - Channel_Light = 0x02, - Channel_Dark = 0x04, - - Channel_FullAlpha = 0x08, - Channel_LightAlpha = 0x10, - Channel_DarkAlpha = 0x20, -}; - -/* - enum Format - Describes the various combination of channels allowed by bopti. -*/ -enum Format -{ - Format_Mono = Channel_Mono, - Format_MonoAlpha = Format_Mono | Channel_FullAlpha, - Format_Gray = Channel_Light | Channel_Dark, - Format_GrayAlpha = Format_Gray | Channel_FullAlpha, - Format_GreaterAlpha = Format_Mono | Channel_LightAlpha | - Channel_DarkAlpha -}; - -// These pointers are set by dimage() to avoid having to repeatedly determine -// which video ram to use. -static int *vram, *v1, *v2; -// The following variables refer to parameters that do not change during the -// drawing operation (at least for the time of a layer). They could be passed -// on by every function from the module, but this would be heavy and useless. -static enum Channel channel; -static int height; -static void (*op)(int offset, uint32_t operator, uint32_t op_mask); - - - -//--- -// Drawing operation. -//--- +#include /* bopti_op() @@ -306,7 +237,6 @@ static void bopti_end(const unsigned char *end, int x, int y, int width) bopti() Draws a layer in the video ram. */ - static void bopti(const unsigned char *layer, int x, int y, int columns, int end_size) { @@ -360,74 +290,3 @@ static void getStructure(struct Image *img, int *width, int *height, if(end_size) *end_size = end; if(layer_size) *layer_size = layer; } - -/* - dimage() - Displays a monochrome image in the video ram. -*/ -void dimage(struct Image *img, int x, int y) -{ - int width, layer_size, columns, end; - int format = img->format, i = 0; - const unsigned char *data; - - if(img->magic != 0xb7) return; - if(img->format != Format_Mono && img->format != Format_MonoAlpha) - return; - op = bopti_op_mono; - - // 'height' refers to a static variable for this file. - getStructure(img, &width, &height, &layer_size, &data, &columns, &end); - - vram = display_getCurrentVRAM(); - - while(format) - { - // Drawing every layer, in order of formats. - if(format & 1) - { - channel = (1 << i); - bopti(data, x, y, columns, end); - data += layer_size; - } - - format >>= 1; - i++; - } - -} - -/* - gimage() - Displays a gray image in the video ram. -*/ -void gimage(struct Image *img, int x, int y) -{ - int width, layer_size, columns, end; - int format = img->format, i = 0; - const unsigned char *data; - - if(img->magic != 0xb7) return; - op = bopti_op_gray; - - // 'height' refers to a static variable for this file. - getStructure(img, &width, &height, &layer_size, &data, &columns, &end); - - v1 = gray_lightVRAM(); - v2 = gray_darkVRAM(); - - while(format) - { - // Drawing every layer, in order of formats. - if(format & 1) - { - channel = (1 << i); - bopti(data, x, y, columns, end); - data += layer_size; - } - - format >>= 1; - i++; - } - -} diff --git a/src/bopti/bopti_internals.h b/src/bopti/bopti_internals.h new file mode 100644 index 0000000..99a40a2 --- /dev/null +++ b/src/bopti/bopti_internals.h @@ -0,0 +1,127 @@ +//--- +// +// gint drawing module: bopti +// +// bopti does every job related to display images. There is only one +// public function, but there are lots of internal optimizations. +// +// Some bit-manipulation expressions may look written out of nowhere. The +// idea is always the same: get a part of the image in an 'operator', +// which is a 32-bit variable, shift this operator so that its bits +// correspond to the desired position for the bitmap on the screen, and +// edit the video-ram long entry which correspond to this position using +// a 'mask' that indicates which bits of the operator contain information. +// +//--- + +#ifndef _BOPTI_INTERNALS_H +#define _BOPTI_INTERNALS_H 1 + +#include + +/* + enum Channel + Determines the kind of information written into a layer. Every image is + made of one or more channels. +*/ +enum Channel +{ + Channel_Mono = 0x01, + Channel_Light = 0x02, + Channel_Dark = 0x04, + + Channel_FullAlpha = 0x08, + Channel_LightAlpha = 0x10, + Channel_DarkAlpha = 0x20, +}; + +/* + enum Format + Describes the various combination of channels allowed by bopti. +*/ +enum Format +{ + Format_Mono = Channel_Mono, + Format_MonoAlpha = Format_Mono | Channel_FullAlpha, + Format_Gray = Channel_Light | Channel_Dark, + Format_GrayAlpha = Format_Gray | Channel_FullAlpha, + Format_GreaterAlpha = Format_Mono | Channel_LightAlpha | + Channel_DarkAlpha +}; + +// The following variables refer to parameters that do not change during the +// drawing operation (at least for the time of a layer). They could be passed +// on by every function from the module, but this would be heavy and useless. +// Using global variables is not really a proper solution but it does simplify +// code much. +extern int *vram, *v1, *v2; +extern enum Channel channel; +extern int height; +extern void (*op)(int offset, uint32_t operator, uint32_t op_mask); + + + +//--- +// Some bopti routines. +//--- + +/* + bopti_op() + Operates on a vram long. The operator will often not contain 32 bits of + image information. Since neutral bits are not the same for all + operations, the op_mask argument indicates which bits should be used + for the operation. Which operation has to be done is determined by the + channel setting. +*/ +void bopti_op_mono(int offset, uint32_t operator, uint32_t op_mask); +void bopti_op_gray(int offset, uint32_t operator, uint32_t op_mask); + +/* + bopti_grid() -- general form + bopti_grid_a32() -- when x is a multiple of 32 + + Draws the grid at the beginning of a layer's data. The length of this + grid is always a multiple of 32. + The need for bopti_grid_a32() is not only linked to optimization, + because bopti_grid() will perform a 32-bit shift when x is a multiple + of 32, which is undefined behavior. +*/ +void bopti_grid_a32(const uint32_t *layer, int x, int y, int column_count); +void bopti_grid(const uint32_t *layer, int x, int y, int column_count); + +/* + bopti_end_get() + Returns an operator for the end of a line, whose width is lower than 32 + (by design: otherwise, it would have been a column). The given pointer + is read and updated so that it points to the next line at the end of + the operation. +*/ +uint32_t bopti_end_get1(const unsigned char **data); +uint32_t bopti_end_get2(const unsigned char **data); + +/* + bopti_rest() -- general form + bopti_rest_nover() -- when the end does not overlap two vram longs + + Draws the end of a layer, which can be considered as a whole layer + whose with is lower than 32. (Actually is it lower or equal to 16; + otherwise it would have been a column and the end would be empty). +*/ +void bopti_end_nover(const unsigned char *end, int x, int y, int width); +void bopti_end(const unsigned char *end, int x, int y, int width); + +/* + bopti() + Draws a layer in the video ram. +*/ +void bopti(const unsigned char *layer, int x, int y, int columns, + int end_size); + +/* + getStructure() + Determines the image size and data pointer. +*/ +void getStructure(struct Image *img, int *width, int *height, int *layer_size, + const unsigned char **data, int *columns, int *end_size); + +#endif // _BOPTI_INTERNALS_H diff --git a/src/bopti/dimage.c b/src/bopti/dimage.c new file mode 100644 index 0000000..f0df4b5 --- /dev/null +++ b/src/bopti/dimage.c @@ -0,0 +1,38 @@ +#include +#include + +/* + dimage() + Displays a monochrome image in the video ram. +*/ +void dimage(struct Image *img, int x, int y) +{ + int width, layer_size, columns, end; + int format = img->format, i = 0; + const unsigned char *data; + + if(img->magic != 0xb7) return; + if(img->format != Format_Mono && img->format != Format_MonoAlpha) + return; + op = bopti_op_mono; + + // 'height' refers to a static variable for this file. + getStructure(img, &width, &height, &layer_size, &data, &columns, &end); + + vram = display_getCurrentVRAM(); + + while(format) + { + // Drawing every layer, in order of formats. + if(format & 1) + { + channel = (1 << i); + bopti(data, x, y, columns, end); + data += layer_size; + } + + format >>= 1; + i++; + } + +} diff --git a/src/bopti/gimage.c b/src/bopti/gimage.c new file mode 100644 index 0000000..d9904af --- /dev/null +++ b/src/bopti/gimage.c @@ -0,0 +1,37 @@ +#include +#include + +/* + gimage() + Displays a gray image in the video ram. +*/ +void gimage(struct Image *img, int x, int y) +{ + int width, layer_size, columns, end; + int format = img->format, i = 0; + const unsigned char *data; + + if(img->magic != 0xb7) return; + op = bopti_op_gray; + + // 'height' refers to a static variable for this file. + getStructure(img, &width, &height, &layer_size, &data, &columns, &end); + + v1 = gray_lightVRAM(); + v2 = gray_darkVRAM(); + + while(format) + { + // Drawing every layer, in order of formats. + if(format & 1) + { + channel = (1 << i); + bopti(data, x, y, columns, end); + data += layer_size; + } + + format >>= 1; + i++; + } + +} diff --git a/src/crt0.c b/src/core/crt0.c similarity index 83% rename from src/crt0.c rename to src/core/crt0.c index bbb3383..a323234 100644 --- a/src/crt0.c +++ b/src/core/crt0.c @@ -1,19 +1,12 @@ -// Used by the exit()-family functions to save and restore the execution state. -#include -static jmp_buf env; -// Provides EXIT_SUCCESS and EXIT_FAILURE. #include -// Provides gint initialization functionalities. #include -// Provides memset() and memcpy(). #include +#include -// Some syscall prototypes. void __Hmem_SetMMU(unsigned int, unsigned int, int); void __GLibAddinAplExecutionCheck(int, int, int); int main(void); -// Local functions. static void init(void); static void fini(void); @@ -26,17 +19,15 @@ extern unsigned int // This variable should be overwritten before being returned, so the default // value doesn't matter much. static int exit_code = EXIT_SUCCESS; +static jmp_buf env; /* start() - Program entry point. Loads the data section into the memory and invokes main(). Also prepares the execution environment by initializing all the modules. - - @return Execution status returned to the OS. */ int start(void) @@ -118,7 +109,6 @@ static void fini(void) /* abort() - Immediately ends the program without invoking the exit handlers. */ @@ -130,11 +120,13 @@ void abort(void) /* exit() - - Ends the program and returns the given exit code status. - Calls exit handlers before returning. - - @arg status Exit status. + Ends the program and returns the given exit code status. Calls exit + handlers before returning. + Usually exit() would ask the operating system to stop the process but + the fx-9860G executes only one program at a time and calls it as a + function. Reaching the program end point is therefore an efficient way + of achieving this goal while minimizing interaction with the operating + system. */ void exit(int status) diff --git a/src/gint.c b/src/core/gint.c similarity index 58% rename from src/gint.c rename to src/core/gint.c index e63596b..b7c9c45 100644 --- a/src/gint.c +++ b/src/core/gint.c @@ -1,18 +1,20 @@ +//--- +// +// gint core module: interrupt handler +// +// Central point of the library. Controls the interrupt handler and +// defines a few functions to configure callbacks for some interrupts. +// +//--- + #include #include -#include #include -//--- -// Local variables. -//--- - static unsigned int new_vbr, sys_vbr; -static void (*rtc_callback)(void) = NULL; - //--- @@ -55,50 +57,12 @@ static void gint_stop(void) gint_systemVBR() Returns the vbr address used by the system (saved when execution starts). - - @return vbr address used by the system. */ -unsigned int gint_systemVBR(void) +inline unsigned int gint_systemVBR(void) { return sys_vbr; } -/* - gint_setRTCCallback() - Sets the callback function for the real-time clock interrupt. If - frequency is non-NULL, the clock frequency is set to the given value. - - @arg callback Callback function. - @arg frequency Interrupt frequency. -*/ -void gint_setRTCCallback(void (*callback)(void), enum RTCFrequency frequency) -{ - if(frequency < 1 || frequency > 7) return; - rtc_callback = callback; - - if(isSH3()) - gint_setRTCFrequency_7705(frequency); - else - gint_setRTCFrequency_7305(frequency); -} - -/* - gint_getRTCCallback() - Returns the callback function. If frequency is non-NULL, it is set to - the current frequency value. -*/ -void (*gint_getRTCCallback(enum RTCFrequency *frequency))(void) -{ - if(!frequency) return rtc_callback; - - if(isSH3()) - *frequency = gint_getRTCFrequency_7705(); - else - *frequency = gint_getRTCFrequency_7305(); - - return rtc_callback; -} - /* gint() Handles interrupts. diff --git a/src/core/gint_callback.c b/src/core/gint_callback.c new file mode 100644 index 0000000..e90e4c2 --- /dev/null +++ b/src/core/gint_callback.c @@ -0,0 +1,40 @@ +#include +#include + +static void (*rtc_callback)(void) = NULL; + +/* + gint_setRTCCallback() + Sets the callback function for the real-time clock interrupt. If + frequency is non-NULL, the clock frequency is set to the given value. + + @arg callback Callback function. + @arg frequency Interrupt frequency. +*/ +void gint_setRTCCallback(void (*callback)(void), enum RTCFrequency frequency) +{ + if(frequency < 1 || frequency > 7) return; + rtc_callback = callback; + + if(isSH3()) + gint_setRTCFrequency_7705(frequency); + else + gint_setRTCFrequency_7305(frequency); +} + +/* + gint_getRTCCallback() + Returns the callback function. If frequency is non-NULL, it is set to + the current frequency value. +*/ +void (*gint_getRTCCallback(enum RTCFrequency *frequency))(void) +{ + if(!frequency) return rtc_callback; + + if(isSH3()) + *frequency = gint_getRTCFrequency_7705(); + else + *frequency = gint_getRTCFrequency_7305(); + + return rtc_callback; +} diff --git a/src/gint_vbr.s b/src/core/gint_vbr.s similarity index 92% rename from src/gint_vbr.s rename to src/core/gint_vbr.s index 92a8a29..488be1b 100644 --- a/src/gint_vbr.s +++ b/src/core/gint_vbr.s @@ -13,8 +13,6 @@ /* gint_getVBR() Returns the current vbr address. - - @return vbr address currently in use. */ _gint_getVBR: rts @@ -34,9 +32,6 @@ _gint_getVBR: Therefore, we must set vbr *and* change interrupt priorities while having disabled all the interrupts in the status register. That's why this function takes as parameter the priority management function. - - @arg New vbr address. - @arg Priority management function. */ _gint_setVBR: sts.l pr, @-r15 diff --git a/src/syscalls.s b/src/core/syscalls.s similarity index 82% rename from src/syscalls.s rename to src/core/syscalls.s index c2a3e1c..5e67fa9 100644 --- a/src/syscalls.s +++ b/src/core/syscalls.s @@ -1,6 +1,8 @@ /* - This file contains all the system calls used by the library. Maybe one - day we won't need them anymore ? + gint core module: syscalls + + All the system calls used by the library. Let's hope one day we won't + depend on them anymore. */ .global ___Hmem_SetMMU diff --git a/src/display.c b/src/display.c deleted file mode 100644 index 2fa046f..0000000 --- a/src/display.c +++ /dev/null @@ -1,473 +0,0 @@ -//--- -// -// gint drawing module: display -// -// Handles vram manipulation and drawing. -// -// -// :: Rectangle masks -// -// The concept of 'rectangle masks' is used several times in this module. -// It is based on the fact that an operation that affects a rectangle acts -// the same on all its lines. Therefore the behavior of the operation is -// determined by its behavior on a single line, which is represented using -// 'masks' whose bits indicate whether a pixel is affected (1) or not (0). -// -// For example when clearing the screen rectangle (16, 16, 112, 48), the -// masks will represent information '16 to 112 on x-axis', and will hold -// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These -// masks can then be used by setting vram[offset] &= ~masks[i]. This -// appears to be very flexible : for instance, vram[offset] ^= masks[i] -// will reverse the pixels in the same rectangle. -// -// This technique can also be used in more subtle cases with more complex -// patterns, but within this module it is unlikely to happen. -// -//--- - -#include -#include -#include -#include -#include - -// Program video ram. It resides in .bss section, therefore it is cleared at -// program initialization and stripped from the executable file. -static int local_vram[256]; -static int *vram = local_vram; - -#define sgn(x) ((x) < 0 ? -1 : 1) -#define abs(x) ((x) < 0 ? -(x) : (x)) -#define rnd(x) ((int)((x) + 0.5)) - - - -//--- -// Local functions. -//--- - -/* - adjust() - Adjusts the given rectangle coordinates to ensure that : - - the rectangle is entirely contained in the screen - - x1 < x2 - - y1 < y2 - which is needed when working with screen rectangles. -*/ -static void adjust(int *x1, int *y1, int *x2, int *y2) -{ - #define swap(a, b) tmp = a, a = b, b = tmp - int tmp; - - if(*x2 < *x1) swap(*x1, *x2); - if(*y2 < *y1) swap(*y1, *y2); - - if(*x1 < 0) *x1 = 0; - if(*y1 < 0) *y1 = 0; - if(*x2 > 127) *x2 = 127; - if(*y2 > 63) *y2 = 63; - #undef swap -} - -/* - getmasks() - - Computes the rectangle masks needed to affect pixels located between x1 - and x2 (both included). The four masks are stored in the third argument - (seen as an array). -*/ -static void getmasks(int x1, int x2, unsigned int *masks) -{ - // Indexes of the first and last longs that are non-blank. - int l1 = x1 >> 5; - int l2 = x2 >> 5; - int i = 0; - - // Setting the base masks. Those are the final values, except for the - // longs with indexes l1 and l2, that still need to be adjusted. - while(i < l1) masks[i++] = 0x00000000; - while(i <= l2) masks[i++] = 0xffffffff; - while(i < 4) masks[i++] = 0x00000000; - - // Removing the long number information in x1 and x2 (that is, the - // multiples of 32) to keep only the interesting information -- the - // number of null bits to add in l1 and l2. - x1 &= 31; - // Inverting x2 is here the same as computing 32 - x, since 32 is a - // power of 2 (positive bits at the left are removed by the mask). - x2 = ~x2 & 31; - - // Setting the first and last masks. - masks[l1] &= (0xffffffff >> x1); - masks[l2] &= (0xffffffff << x2); -} - - - -//--- -// Generic functions. -//--- - -/* - display_getLocalVRAM() - Returns the local video ram address. This function always return the - same address. - The buffer returned by this function should not be used directly when - running the gray engine. -*/ -inline void *display_getLocalVRAM(void) -{ - return (void *)local_vram; -} - -/* - display_getCurrentVRAM() - Returns the current video ram. This function usually returns the - parameter of the last call to display_useVRAM(), unless the gray engine - is running (in which case the result is undefined). Returns the local - vram address by default. -*/ -inline void *display_getCurrentVRAM(void) -{ - return (void *)vram; -} - -/* - display_useVRAM() - Changes the current video ram address. The argument MUST be a 4- - aligned 1024-byte buffer ; otherwise any drawing operation will crash - the program. - This function will most likely have no effect when running the gray - engine. -*/ -inline void display_useVRAM(void *ptr) -{ - vram = (int *)ptr; -} - - - -//--- -// Global drawing functions. -//--- - -/* - dupdate() - Displays the vram on the physical screen. -*/ -void dupdate(void) -{ - if(gray_runs()) return; - screen_display((const void *)local_vram); -} - -/* - dclear() - Clears the whole vram. -*/ -void dclear(void) -{ - int i; - for(i = 0; i < 256; i++) vram[i] = 0; -} - -/* - dclear_area() - Clears an area of the vram using rectangle masks. Both (x1, y1) and - (x2, y2) are cleared. -*/ -void dclear_area(int x1, int y1, int x2, int y2) -{ - unsigned int masks[4]; - adjust(&x1, &y1, &x2, &y2); - getmasks(x1, x2, masks); - - int begin = y1 << 2; - int end = (y2 + 1) << 2; - int i; - - for(i = 0; i < 4; i++) masks[i] = ~masks[i]; - for(i = begin; i < end; i++) vram[i] &= masks[i & 3]; -} - -/* - dreverse_area() - Reverses an area of the vram. This function is a simple application of - the rectangle masks concept. (x1, y1) and (x2, y2) are reversed as - well. -*/ -void dreverse_area(int x1, int y1, int x2, int y2) -{ - unsigned int masks[4]; - adjust(&x1, &y1, &x2, &y2); - getmasks(x1, x2, masks); - - int begin = y1 << 2; - int end = (y2 + 1) << 2; - int i; - - if(gray_runs()) - { - int *v1 = gray_lightVRAM(); - int *v2 = gray_darkVRAM(); - - for(i = begin; i < end; i++) - { - v1[i] ^= masks[i & 3]; - v2[i] ^= masks[i & 3]; - } - } - else for(i = begin; i < end; i++) - { - vram[i] ^= masks[i & 3]; - } -} - - - -//--- -// Local drawing functions. -//--- - -/* - dpixel() - Puts a pixel in the vram. -*/ -void dpixel(int x, int y, enum Color color) -{ - if((unsigned int)x > 127 || (unsigned int)y > 63) return; - - int offset = (y << 2) + (x >> 5); - int mask = 0x80000000 >> (x & 31); - - switch(color) - { - case Color_White: - vram[offset] &= ~mask; - break; - - case Color_Black: - vram[offset] |= mask; - break; - - case Color_Invert: - vram[offset] ^= mask; - break; - - default: - break; - } -} - -/* - dline() - Draws a line on the screen. Automatically optimizes horizontal and - vertical lines. -*/ - -static void dhline(int x1, int x2, int y, enum Color color) -{ - unsigned int masks[4]; - int offset = y << 2; - int i; - - // Swapping x1 and x2 if needed. - if(x1 > x2) x1 ^= x2, x2 ^= x1, x1 ^= x2; - getmasks(x1, x2, masks); - - int *v1 = gray_lightVRAM(); - int *v2 = gray_darkVRAM(); - - if(gray_runs()) switch(color) - { - case Color_White: - for(i = 0; i < 4; i++) - { - v1[offset + i] &= ~masks[i]; - v2[offset + i] &= ~masks[i]; - } - break; - - case Color_Light: - for(i = 0; i < 4; i++) - { - v1[offset + i] |= masks[i]; - v2[offset + i] &= ~masks[i]; - } - break; - - case Color_Dark: - for(i = 0; i < 4; i++) - { - v1[offset + i] &= ~masks[i]; - v2[offset + i] |= masks[i]; - } - break; - - case Color_Black: - for(i = 0; i < 4; i++) - { - v1[offset + i] |= masks[i]; - v2[offset + i] |= masks[i]; - } - break; - - case Color_Invert: - for(i = 0; i < 4; i++) - { - v1[offset + i] ^= masks[i]; - v2[offset + i] ^= masks[i]; - } - break; - - default: - break; - } - - else switch(color) - { - case Color_White: - for(i = 0; i < 4; i++) vram[offset + i] &= ~masks[i]; - break; - - case Color_Black: - for(i = 0; i < 4; i++) vram[offset + i] |= masks[i]; - break; - - case Color_Invert: - for(i = 0; i < 4; i++) vram[offset + i] ^= masks[i]; - break; - - default: - break; - } -} - -static void dvline(int y1, int y2, int x, enum Color color) -{ - int offset = (y1 << 2) + (x >> 5); - int end = (y2 << 2) + (x >> 5); - int mask = 0x80000000 >> (x & 31); - - int *v1 = gray_lightVRAM(); - int *v2 = gray_darkVRAM(); - - if(gray_runs()) switch(color) - { - case Color_White: - while(offset <= end) - { - v1[offset] &= ~mask; - v2[offset] &= ~mask; - offset += 4; - } - break; - - case Color_Light: - while(offset <= end) - { - v1[offset] |= mask; - v2[offset] &= ~mask; - offset += 4; - } - break; - - case Color_Dark: - while(offset <= end) - { - v1[offset] &= ~mask; - v2[offset] |= mask; - offset += 4; - } - break; - - case Color_Black: - while(offset <= end) - { - v1[offset] |= mask; - v2[offset] |= mask; - offset += 4; - } - break; - - case Color_Invert: - while(offset <= end) - { - v1[offset] ^= mask; - v2[offset] ^= mask; - offset += 4; - } - break; - - default: - break; - } - - else switch(color) - { - case Color_White: - while(offset <= end) vram[offset] &= ~mask, offset += 4; - break; - - case Color_Black: - while(offset <= end) vram[offset] |= mask, offset += 4; - break; - - case Color_Invert: - while(offset <= end) vram[offset] ^= mask, offset += 4; - break; - - default: - break; - } -} - -void dline(int x1, int y1, int x2, int y2, enum Color color) -{ - adjust(&x1, &y1, &x2, &y2); - - // Possible optimizations. - if(y1 == y2) - { - dhline(x1, x2, y1, color); - return; - } - if(x1 == x2) - { - dvline(y1, y2, x1, color); - return; - } - - int i, x = x1, y = y1, cumul; - int dx = x2 - x1, dy = y2 - y1; - int sx = sgn(dx), sy = sgn(dy); - - dx = abs(dx), dy = abs(dy); - - dpixel(x1, y1, color); - - if(dx >= dy) - { - cumul = dx >> 1; - for(i = 1; i < dx; i++) - { - x += sx; - cumul += dy; - if(cumul > dx) cumul -= dx, y += sy; - dpixel(x, y, color); - } - } - else - { - cumul = dy >> 1; - for(i = 1; i < dy; i++) - { - y += sy; - cumul += dx; - if(cumul > dy) cumul -= dy, x += sx; - dpixel(x, y, color); - } - } - - dpixel(x2, y2, color); -} diff --git a/src/display/adjustRectangle.c b/src/display/adjustRectangle.c new file mode 100644 index 0000000..3b5b237 --- /dev/null +++ b/src/display/adjustRectangle.c @@ -0,0 +1,24 @@ +#include + +/* + adjustRectangle() + Adjusts the given rectangle coordinates to ensure that : + - the rectangle is entirely contained in the screen + - x1 < x2 + - y1 < y2 + which is needed when working with screen rectangles. +*/ +void adjustRectangle(int *x1, int *y1, int *x2, int *y2) +{ + #define swap(a, b) tmp = a, a = b, b = tmp + int tmp; + + if(*x2 < *x1) swap(*x1, *x2); + if(*y2 < *y1) swap(*y1, *y2); + + if(*x1 < 0) *x1 = 0; + if(*y1 < 0) *y1 = 0; + if(*x2 > 127) *x2 = 127; + if(*y2 > 63) *y2 = 63; + #undef swap +} diff --git a/src/display/dclear.c b/src/display/dclear.c new file mode 100644 index 0000000..d33503b --- /dev/null +++ b/src/display/dclear.c @@ -0,0 +1,12 @@ +#include +#include + +/* + dclear() + Clears the whole vram. +*/ +void dclear(void) +{ + int i; + for(i = 0; i < 256; i++) vram[i] = 0; +} diff --git a/src/display/dclear_area.c b/src/display/dclear_area.c new file mode 100644 index 0000000..0b9aadb --- /dev/null +++ b/src/display/dclear_area.c @@ -0,0 +1,21 @@ +#include +#include + +/* + dclear_area() + Clears an area of the vram using rectangle masks. Both (x1, y1) and + (x2, y2) are cleared. +*/ +void dclear_area(int x1, int y1, int x2, int y2) +{ + unsigned int masks[4]; + adjustRectangle(&x1, &y1, &x2, &y2); + getMasks(x1, x2, masks); + + int begin = y1 << 2; + int end = (y2 + 1) << 2; + int i; + + for(i = 0; i < 4; i++) masks[i] = ~masks[i]; + for(i = begin; i < end; i++) vram[i] &= masks[i & 3]; +} diff --git a/src/display/display_internals.h b/src/display/display_internals.h new file mode 100644 index 0000000..7c3471a --- /dev/null +++ b/src/display/display_internals.h @@ -0,0 +1,52 @@ +//--- +// +// gint drawing module: display +// +// Handles vram manipulation and drawing. +// +// +// :: Rectangle masks +// +// The concept of 'rectangle masks' is used several times in this module. +// It is based on the fact that an operation that affects a rectangle acts +// the same on all its lines. Therefore the behavior of the operation is +// determined by its behavior on a single line, which is represented using +// 'masks' whose bits indicate whether a pixel is affected (1) or not (0). +// +// For example when clearing the screen rectangle (16, 16, 112, 48), the +// masks will represent information '16 to 112 on x-axis', and will hold +// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These +// masks can then be used by setting vram[offset] &= ~masks[i]. This +// appears to be very flexible : for instance, vram[offset] ^= masks[i] +// will reverse the pixels in the same rectangle. +// +// This technique can also be used in more subtle cases with more complex +// patterns, but within this module it is unlikely to happen. +// +//--- + +#ifndef _DISPLAY_INTERNALS_H +#define _DISPLAY_INTERNALS_H + +extern int *vram; + +/* + adjustRectangle() + Adjusts the given rectangle coordinates to ensure that : + - the rectangle is entirely contained in the screen + - x1 < x2 + - y1 < y2 + which is needed when working with screen rectangles. +*/ +static void adjustRectangle(int *x1, int *y1, int *x2, int *y2); + +/* + getMasks() + Computes the rectangle masks needed to affect pixels located between x1 + and x2 (both included). The four masks are stored in the third argument + (seen as an array). + See this module's internals header file for more information. +*/ +static void getMasks(int x1, int x2, unsigned int *masks); + +#endif // _DISPLAY_INTERNALS_H diff --git a/src/display/display_vram.c b/src/display/display_vram.c new file mode 100644 index 0000000..2dc3763 --- /dev/null +++ b/src/display/display_vram.c @@ -0,0 +1,43 @@ +#include + +// Program video ram. It resides in .bss section, therefore it is cleared at +// program initialization and stripped from the executable file. +static int local_vram[256]; +int *vram = local_vram; + +/* + display_getLocalVRAM() + Returns the local video ram address. This function always return the + same address. + The buffer returned by this function should not be used directly when + running the gray engine. +*/ +inline void *display_getLocalVRAM(void) +{ + return (void *)local_vram; +} + +/* + display_getCurrentVRAM() + Returns the current video ram. This function usually returns the + parameter of the last call to display_useVRAM(), unless the gray engine + is running (in which case the result is undefined). Returns the local + vram address by default. +*/ +inline void *display_getCurrentVRAM(void) +{ + return (void *)vram; +} + +/* + display_useVRAM() + Changes the current video ram address. The argument MUST be a 4- + aligned 1024-byte buffer ; otherwise any drawing operation will crash + the program. + This function will most likely have no effect when running the gray + engine. +*/ +inline void display_useVRAM(void *ptr) +{ + vram = (int *)ptr; +} diff --git a/src/display/dline.c b/src/display/dline.c new file mode 100644 index 0000000..3f90483 --- /dev/null +++ b/src/display/dline.c @@ -0,0 +1,116 @@ +#include +#include + +#define sgn(x) ((x) < 0 ? -1 : 1) +#define abs(x) ((x) < 0 ? -(x) : (x)) +#define rnd(x) ((int)((x) + 0.5)) + +/* + dline() + Draws a line on the screen. Automatically optimizes horizontal and + vertical lines. +*/ + +static void dhline(int x1, int x2, int y, enum Color color) +{ + unsigned int masks[4]; + int offset = y << 2; + int i; + + // Swapping x1 and x2 if needed. + if(x1 > x2) x1 ^= x2, x2 ^= x1, x1 ^= x2; + getMasks(x1, x2, masks); + + switch(color) + { + case Color_White: + for(i = 0; i < 4; i++) vram[offset + i] &= ~masks[i]; + break; + + case Color_Black: + for(i = 0; i < 4; i++) vram[offset + i] |= masks[i]; + break; + + case Color_Invert: + for(i = 0; i < 4; i++) vram[offset + i] ^= masks[i]; + break; + + default: + break; + } +} + +static void dvline(int y1, int y2, int x, enum Color color) +{ + int offset = (y1 << 2) + (x >> 5); + int end = (y2 << 2) + (x >> 5); + int mask = 0x80000000 >> (x & 31); + + switch(color) + { + case Color_White: + while(offset <= end) vram[offset] &= ~mask, offset += 4; + break; + + case Color_Black: + while(offset <= end) vram[offset] |= mask, offset += 4; + break; + + case Color_Invert: + while(offset <= end) vram[offset] ^= mask, offset += 4; + break; + + default: + break; + } +} + +void dline(int x1, int y1, int x2, int y2, enum Color color) +{ + adjustRectangle(&x1, &y1, &x2, &y2); + + // Possible optimizations. + if(y1 == y2) + { + dhline(x1, x2, y1, color); + return; + } + if(x1 == x2) + { + dvline(y1, y2, x1, color); + return; + } + + int i, x = x1, y = y1, cumul; + int dx = x2 - x1, dy = y2 - y1; + int sx = sgn(dx), sy = sgn(dy); + + dx = abs(dx), dy = abs(dy); + + dpixel(x1, y1, color); + + if(dx >= dy) + { + cumul = dx >> 1; + for(i = 1; i < dx; i++) + { + x += sx; + cumul += dy; + if(cumul > dx) cumul -= dx, y += sy; + dpixel(x, y, color); + } + } + else + { + cumul = dy >> 1; + for(i = 1; i < dy; i++) + { + y += sy; + cumul += dx; + if(cumul > dy) cumul -= dy, x += sx; + dpixel(x, y, color); + } + } + + dpixel(x2, y2, color); +} diff --git a/src/display/dpixel.c b/src/display/dpixel.c new file mode 100644 index 0000000..c5bfb9a --- /dev/null +++ b/src/display/dpixel.c @@ -0,0 +1,32 @@ +#include +#include + +/* + dpixel() + Puts a pixel in the vram. +*/ +void dpixel(int x, int y, enum Color color) +{ + if((unsigned int)x > 127 || (unsigned int)y > 63) return; + + int offset = (y << 2) + (x >> 5); + int mask = 0x80000000 >> (x & 31); + + switch(color) + { + case Color_White: + vram[offset] &= ~mask; + break; + + case Color_Black: + vram[offset] |= mask; + break; + + case Color_Invert: + vram[offset] ^= mask; + break; + + default: + break; + } +} diff --git a/src/display/dreverse_area.c b/src/display/dreverse_area.c new file mode 100644 index 0000000..f3c48fe --- /dev/null +++ b/src/display/dreverse_area.c @@ -0,0 +1,21 @@ +#include +#include + +/* + dreverse_area() + Reverses an area of the vram. This function is a simple application of + the rectangle masks concept. (x1, y1) and (x2, y2) are reversed as + well. +*/ +void dreverse_area(int x1, int y1, int x2, int y2) +{ + unsigned int masks[4]; + adjustRectangle(&x1, &y1, &x2, &y2); + getMasks(x1, x2, masks); + + int begin = y1 << 2; + int end = (y2 + 1) << 2; + int i; + + for(i = begin; i < end; i++) vram[i] ^= masks[i & 3]; +} diff --git a/src/display/dupdate.c b/src/display/dupdate.c new file mode 100644 index 0000000..6942c60 --- /dev/null +++ b/src/display/dupdate.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +/* + dupdate() + Displays the vram on the physical screen. +*/ +void dupdate(void) +{ + if(gray_runs()) return; + screen_display((const void *)vram); +} diff --git a/src/display/getMasks.c b/src/display/getMasks.c new file mode 100644 index 0000000..bb2b32f --- /dev/null +++ b/src/display/getMasks.c @@ -0,0 +1,34 @@ +#include + +/* + getMasks() + Computes the rectangle masks needed to affect pixels located between x1 + and x2 (both included). The four masks are stored in the third argument + (seen as an array). + See this module's internals header file for more information. +*/ +void getMasks(int x1, int x2, unsigned int *masks) +{ + // Indexes of the first and last longs that are non-blank. + int l1 = x1 >> 5; + int l2 = x2 >> 5; + int i = 0; + + // Setting the base masks. Those are the final values, except for the + // longs with indexes l1 and l2, that still need to be adjusted. + while(i < l1) masks[i++] = 0x00000000; + while(i <= l2) masks[i++] = 0xffffffff; + while(i < 4) masks[i++] = 0x00000000; + + // Removing the long number information in x1 and x2 (that is, the + // multiples of 32) to keep only the interesting information -- the + // number of null bits to add in l1 and l2. + x1 &= 31; + // Inverting x2 is here the same as computing 32 - x, since 32 is a + // power of 2 (positive bits at the left are removed by the mask). + x2 = ~x2 & 31; + + // Setting the first and last masks. + masks[l1] &= (0xffffffff >> x1); + masks[l2] &= (0xffffffff << x2); +} diff --git a/src/gint_7305.c b/src/gint_7305.c deleted file mode 100644 index d103920..0000000 --- a/src/gint_7305.c +++ /dev/null @@ -1,313 +0,0 @@ -#include -#include -#include -#include <7305.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 - - - -//--- -// Various MPU-dependent procedures. -//--- - -/* - gint_setRTCFrequency() - Sets the RTC interrupt frequency and enables interrupts. - - @arg frequency -*/ -void gint_setRTCFrequency_7305(enum RTCFrequency frequency) -{ - if(frequency < 1 || frequency > 7) return; - RTC.RCR2.BYTE = (frequency << 4) | 0x09; -} - -/* - gint_getRTCFrequency() - Returns the RTC interrupt frequency. - - @return RTC interrupt frequency. -*/ -enum RTCFrequency gint_getRTCFrequency_7305(void) -{ - return (RTC.RCR2.BYTE & 0x70) >> 4; -} - - - -//--- -// Keyboard management. -//--- - -/* - kdelay() - Should sleep during a few milliseconds. Well... - This delay has a great influence on key detection. Here are a few - observations of what happens with common numbers of "nop" (without - overclock). Take care of the effect of overclock ! - - Column effects - May have something to do with register HIZCRB not being used here. When - many keys on the same column are pressed, other keys of the same column - may be triggered. - - - Less Bad key detection. - - 8 Very few column effects. Most often, three keys may be pressed - simultaneously. However, [UP] has latencies and is globally not - detected. - - 12 Seems best. Every individual key is detected well. No column - effect observed before four keys. - - 16 Every single key is detected correctly. Pressing two keys on a - same column does not usually create a column effect. Three keys - almost always. - - More Does not improve single key detection, and increase column - effects. At 256 every single key press create a whole column - effect. -*/ -static void kdelay(void) -{ - #define r4(str) str str str str - - __asm__ - ( - r4("nop\n\t") - r4("nop\n\t") - r4("nop\n\t") - ); - - #undef r4 -} - -/* - krow() - Reads a keyboard row. Works like krow() for SH7705. See gint_7705.c for - more details. -*/ -static int krow(int row) -{ - volatile unsigned short *injector1 = (unsigned short *)0xa4050116; - volatile unsigned char *data1 = (unsigned char *)0xa4050136; - - volatile unsigned short *injector2 = (unsigned short *)0xa4050118; - volatile unsigned char *data2 = (unsigned char *)0xa4050138; - - volatile unsigned short *detector = (unsigned short *)0xa405014c; - volatile unsigned char *keys = (unsigned char *)0xa405016c; - - volatile unsigned char *key_register = (unsigned char *)0xa40501c6; -// volatile unsigned short *hizcrb = (unsigned short *)0xa405015a; - - unsigned short smask; - unsigned char cmask; - int result = 0; - - if(row < 0 || row > 9) return 0; - - // Additional configuration for SH7305. - *detector = 0xaaaa; - *key_register = 0xff; - *injector1 = (*injector1 & 0xf000) | 0x0555; - *injector2 = (*injector2 & 0xf000) | 0x0555; - *data1 |= 0x3f; - *data2 |= 0x3f; - kdelay(); - - if(row < 6) - { - smask = 0x0003 << (row * 2); - cmask = ~(1 << row); - - *injector1 = ((*injector1 & 0xf000) | 0x0aaa) ^ smask; - *injector2 = (*injector2 & 0xf000) | 0x0aaa; - kdelay(); - - *data1 = (*data1 & 0xc0) | cmask; - *data2 |= 0x3f; - kdelay(); - } - else - { - smask = 0x0003 << ((row - 6) * 2); - cmask = ~(1 << (row - 6)); - - *injector1 = (*injector1 & 0xf000) | 0x0aaa; - *injector2 = ((*injector2 & 0xf000) | 0x0aaa) ^ smask; - kdelay(); - - *data1 |= 0x3f; - *data2 = (*data2 & 0xc0) | cmask; - kdelay(); - } - - // Reading the keyboard row. - result = ~*keys; - kdelay(); - - // Re-initializing the port configuration and data. - *injector1 = (*injector1 & 0xf000) | 0x0aaa; - *injector2 = (*injector2 & 0xf000) | 0x0aaa; - kdelay(); - *injector1 = (*injector1 & 0xf000) | 0x0555; - *injector2 = (*injector2 & 0xf000) | 0x0555; - kdelay(); - *data1 &= 0xc0; - *data2 &= 0xc0; - - return result; -} - -/* - keyboard_updateState() - Updates the keyboard state. -*/ -void keyboard_updateState_7305(volatile unsigned char *keyboard_state) -{ - int i; - - for(i = 0; i < 10; i++) keyboard_state[i] = krow(i); -} - - - -//--- -// Interrupt handler. -//--- - -void gint_7305(void) -{ - volatile unsigned int *intevt = (unsigned int *)0xff000028; - unsigned int code = *intevt; - - switch(code) - { - case IC_RTC_PRI: - RTC.RCR2.PEF = 0; - 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; - } -} - - - -//--- -// Setup. -//--- - -static unsigned short ipr[12]; -static unsigned char rcr2; -// Saves of the keyboard registres. Could be better. -static unsigned short inj1, inj2, det; -static unsigned char data1, data2, keys, reg; - -static void gint_priority_lock_7305(void) -{ - // Saving the current interrupt priorities. - ipr[0] = INTX.IPRA.WORD; - ipr[1] = INTX.IPRB.WORD; - ipr[2] = INTX.IPRC.WORD; - ipr[3] = INTX.IPRD.WORD; - ipr[4] = INTX.IPRE.WORD; - ipr[5] = INTX.IPRF.WORD; - ipr[6] = INTX.IPRG.WORD; - ipr[7] = INTX.IPRH.WORD; - ipr[8] = INTX.IPRI.WORD; - ipr[9] = INTX.IPRJ.WORD; - ipr[10] = INTX.IPRK.WORD; - ipr[11] = INTX.IPRL.WORD; - - // Disabling everything by default to avoid freezing on unhandled - // interrupts. - INTX.IPRA.WORD = 0x0000; - INTX.IPRB.WORD = 0x0000; - INTX.IPRC.WORD = 0x0000; - INTX.IPRD.WORD = 0x0000; - INTX.IPRE.WORD = 0x0000; - INTX.IPRF.WORD = 0x0000; - INTX.IPRG.WORD = 0x0000; - INTX.IPRH.WORD = 0x0000; - INTX.IPRI.WORD = 0x0000; - INTX.IPRJ.WORD = 0x0000; - INTX.IPRK.WORD = 0x0000; - INTX.IPRL.WORD = 0x0000; - - // Saving keyboard registers. - inj1 = *((volatile unsigned short *)0xa4050116); - data1 = *((volatile unsigned char *)0xa4050136); - inj2 = *((volatile unsigned short *)0xa4050118); - data2 = *((volatile unsigned char *)0xa4050138); - det = *((volatile unsigned short *)0xa405014c); - keys = *((volatile unsigned char *)0xa405016c); - reg = *((volatile unsigned char *)0xa40501c6); - - // Allowing RTC. Keyboard analysis is done regularly using a RTC - // because SH7305's special KEYSC interface does not allow us to clear - // the keyboard interrupt flags. - INTX.IPRK._RTC = GINT_INTP_RTC; - INTX.IPRA.TMU0_0 = GINT_INTP_KEY; - INTX.IPRA.TMU0_1 = GINT_INTP_GRAY; - INTX.IPRA.TMU0_2 = GINT_INTP_TIMER; -} - -static void gint_priority_unlock_7305(void) -{ - // Restoring the interrupt priorities. - INTX.IPRA.WORD = ipr[0]; - INTX.IPRB.WORD = ipr[1]; - INTX.IPRC.WORD = ipr[2]; - INTX.IPRD.WORD = ipr[3]; - INTX.IPRE.WORD = ipr[4]; - INTX.IPRF.WORD = ipr[5]; - INTX.IPRG.WORD = ipr[6]; - INTX.IPRH.WORD = ipr[7]; - INTX.IPRI.WORD = ipr[8]; - INTX.IPRJ.WORD = ipr[9]; - INTX.IPRK.WORD = ipr[10]; - INTX.IPRL.WORD = ipr[11]; - - // Restoring keyboard registers. - *((volatile unsigned short *)0xa4050116) = inj1; - *((volatile unsigned char *)0xa4050136) = data1; - *((volatile unsigned short *)0xa4050118) = inj2; - *((volatile unsigned char *)0xa4050138) = data2; - *((volatile unsigned short *)0xa405014c) = det; - *((volatile unsigned char *)0xa405016c) = keys; - *((volatile unsigned char *)0xa40501c6) = reg; -} - -void gint_setup_7305(void) -{ - gint_priority_lock_7305(); - - // Saving the RTC configuration. - rcr2 = RTC.RCR2.BYTE; - // Disabling RTC interrupts by default. - RTC.RCR2.BYTE = 0x09; -} - -void gint_stop_7305(void) -{ - gint_priority_unlock_7305(); - - // Restoring the RTC configuration. - RTC.RCR2.BYTE = rcr2; -} diff --git a/src/gint_7705.c b/src/gint_7705.c deleted file mode 100644 index 253a174..0000000 --- a/src/gint_7705.c +++ /dev/null @@ -1,276 +0,0 @@ -#include -#include -#include -#include <7705.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 - - - -//--- -// Various MPU-dependent procedures. -//--- - -/* - gint_setRTCFrequency() - Sets the RTC interrupt frequency and enables interrupts. - - @arg frequency -*/ -void gint_setRTCFrequency_7705(enum RTCFrequency frequency) -{ - if(frequency < 1 || frequency > 7) return; - RTC.RCR2.BYTE = (frequency << 4) | 0x09; -} - -/* - gint_getRTCFrequency() - Returns the RTC interrupt frequency. - - @return RTC interrupt frequency. -*/ -enum RTCFrequency gint_getRTCFrequency_7705(void) -{ - return (RTC.RCR2.BYTE & 0x70) >> 4; -} - - - -//--- -// Keyboard management. -//--- - -/* - kdelay() - Used to be a low-level sleep using the watchdog, as in the system. This - way seems OK at least, and it doesn't create column effects as for - SH7305. -*/ -static void kdelay(void) -{ - #define r4(str) str str str str - - __asm__ - ( - r4("nop\n\t") - r4("nop\n\t") - r4("nop\n\t") - ); - - #undef r4 - - /* Watchdog version. - const int delay = 0xf4; - - // Disabling the watchdog timer interrupt and resetting the - // configuration. Setting the delay. - INTC.IPRB.BIT._WDT = 0; - WDT.WTCSR.WRITE = 0xa500; - WDT.WTCNT.WRITE = 0x5a00 | (delay & 0xff); - - // Counting on Po/256. - WDT.WTCSR.WRITE = 0xa505; - // Starting the timer (sets again to Po/256). - WDT.WTCSR.WRITE = 0xa585; - - // Waiting until it overflows (delaying), then clearing the overflow - // flag. - while((WDT.WTCSR.READ.BYTE & 0x08) == 0); - WDT.WTCSR.WRITE = 0xa500 | (WDT.WTCSR.READ.BYTE & 0xf7); - - // Resetting the configuration and the counter. - WDT.WTCSR.WRITE = 0xa500; - WDT.WTCSR.WRITE = 0x5a00; - - // Enabling back the watchdog timer interrupt. - INTC.IPRB.BIT._WDT = GINT_INTP_WDT; - */ -} - -/* - krow() - Reads a keyboard row. - - @arg row Row to check (0 <= row <= 9). - - @return Bit-based representation of pressed keys in the checked row. -*/ -static int krow(int row) -{ - // '11' on the active row, '00' everywhere else. - unsigned short smask = 0x0003 << ((row % 8) * 2); - // '0' on the active row, '1' everywhere else. - unsigned char cmask = ~(1 << (row % 8)); - // Line results. - int result = 0; - - if(row < 0 || row > 9) return 0; - - // Initial configuration. - PFC.PBCR.WORD = 0xaaaa; - PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x0055; - kdelay(); - - if(row < 8) - { - // Configuring port B/M as input except for the row to check, - // which has to be an output. This sets '01' (output) on the - // active row, '10' (input) everywhere else. - PFC.PBCR.WORD = 0xaaaa ^ smask; - PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x00aa; - kdelay(); - - // Every bit set to 1 except the active row bit. - PB.DR.BYTE = cmask; - PM.DR.BYTE = (PM.DR.BYTE & 0xf0) | 0x0f; - kdelay(); - } - else - { - // The same, but deals with port M. - PFC.PBCR.WORD = 0xaaaa; - PFC.PMCR.WORD = ((PFC.PMCR.WORD & 0xff00) | 0x00aa) ^ smask; - kdelay(); - - PB.DR.BYTE = 0xff; - PM.DR.BYTE = (PM.DR.BYTE & 0xf0) | cmask; - kdelay(); - } - - // Reading the keyboard row. - result = ~PA.DR.BYTE; - kdelay(); - - // Re-initializing the port configuration and data. - PFC.PBCR.WORD = 0xaaaa; - PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x00aa; - kdelay(); - PFC.PBCR.WORD = 0x5555; - PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x0055; - kdelay(); - PB.DR.BYTE = 0x00; - PM.DR.BYTE &= 0xf0; - - return result; -} - -/* - keyboard_updateState() - Updates the keyboard state. -*/ -void keyboard_updateState_7705(volatile unsigned char *keyboard_state) -{ - int i; - - for(i = 0; i < 10; i++) keyboard_state[i] = krow(i); -} - - - -//--- -// Interrupt handler. -//--- - -void gint_7705(void) -{ - volatile unsigned int *intevt2 = (unsigned int *)0xa4000000; - unsigned int code = *intevt2; - - switch(code) - { - case IC_RTC_PRI: - RTC.RCR2.BIT.PEF = 0; - 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; - } -} - - - -//--- -// Setup. -//--- - -static unsigned short iprs[8]; -static unsigned char rcr2; - -static void gint_priority_lock_7705(void) -{ - // Saving the interrupt masks from registers IPRA to IPRH. - iprs[0] = INTC.IPRA.WORD; - iprs[1] = INTC.IPRB.WORD; - iprs[2] = INTX.IPRC.WORD; - iprs[3] = INTX.IPRD.WORD; - iprs[4] = INTX.IPRE.WORD; - iprs[5] = INTX.IPRF.WORD; - iprs[6] = INTX.IPRG.WORD; - iprs[7] = INTX.IPRH.WORD; - - // Disabling everything by default to avoid receiving an interrupt that - // the handler doesn't handle, which would cause the user program to - // freeze. - INTC.IPRA.WORD = 0x0000; - INTC.IPRB.WORD = 0x0000; - INTX.IPRC.WORD = 0x0000; - INTX.IPRD.WORD = 0x0000; - INTX.IPRE.WORD = 0x0000; - INTX.IPRF.WORD = 0x0000; - INTX.IPRG.WORD = 0x0000; - INTX.IPRH.WORD = 0x0000; - - // Allowing RTC, which handles keyboard. - INTC.IPRA.BIT._RTC = GINT_INTP_RTC; - INTC.IPRA.BIT._TMU0 = GINT_INTP_KEY; - INTC.IPRA.BIT._TMU1 = GINT_INTP_GRAY; - INTC.IPRA.BIT._TMU2 = GINT_INTP_TIMER; -} - -static void gint_priority_unlock_7705(void) -{ - // Restoring the saved states. - INTC.IPRA.WORD = iprs[0]; - INTC.IPRB.WORD = iprs[1]; - INTX.IPRC.WORD = iprs[2]; - INTX.IPRD.WORD = iprs[3]; - INTX.IPRE.WORD = iprs[4]; - INTX.IPRF.WORD = iprs[5]; - INTX.IPRG.WORD = iprs[6]; - INTX.IPRH.WORD = iprs[7]; -} - -void gint_setup_7705(void) -{ - gint_priority_lock_7705(); - - // Saving the RTC configuration. - rcr2 = RTC.RCR2.BYTE; - // Disabling RTC interrupts by default. - RTC.RCR2.BYTE = 0x09; -} - -void gint_stop_7705(void) -{ - gint_priority_unlock_7705(); - - // Restoring the RTC configuration. - RTC.RCR2.BYTE = rcr2; -} diff --git a/src/gray/gclear.c b/src/gray/gclear.c new file mode 100644 index 0000000..e3beb21 --- /dev/null +++ b/src/gray/gclear.c @@ -0,0 +1,14 @@ +#include + +/* + gclear() + Clears the video ram. +*/ +void gclear(void) +{ + int *v1 = gray_lightVRAM(); + int *v2 = gray_darkVRAM(); + int i; + + for(i = 0; i < 256; i++) v1[i] = v2[i] = 0; +} diff --git a/src/gray/gclear_area.c b/src/gray/gclear_area.c new file mode 100644 index 0000000..42c3f29 --- /dev/null +++ b/src/gray/gclear_area.c @@ -0,0 +1,15 @@ +#include +#include + +/* + gclear_area() + Clears an area of the video ram. End points (x1, y1) and (x2, y2) are + included. +*/ +void gclear_area(int x1, int y1, int x2, int y2) +{ + display_useVRAM(gray_lightVRAM()); + dclear_area(x1, y1, x2, y2); + display_useVRAM(gray_darkVRAM()); + dclear_area(x1, y1, x2, y2); +} diff --git a/src/gray/gline.c b/src/gray/gline.c new file mode 100644 index 0000000..bd7cadd --- /dev/null +++ b/src/gray/gline.c @@ -0,0 +1,20 @@ +#include +#include + +/* + gline() + Draws a line in the vram. Automatically optimizes special cases. +*/ +void gline(int x1, int y1, int x2, int y2, enum Color color) +{ + enum Color c1, c2; + + if(color == Color_None) return; + else if(color == Color_Invert) c1 = c2 = Color_Invert; + else c1 = color & 1, c2 = color >> 1; + + display_useVRAM(gray_lightVRAM()); + dline(x1, y1, x2, y2, c1); + display_useVRAM(gray_darkVRAM()); + dline(x1, y1, x2, y2, c2); +} diff --git a/src/gray/gpixel.c b/src/gray/gpixel.c new file mode 100644 index 0000000..be44071 --- /dev/null +++ b/src/gray/gpixel.c @@ -0,0 +1,47 @@ +#include + +/* + gpixel() + Puts a pixel in the vram. +*/ +void gpixel(int x, int y, enum Color color) +{ + if((unsigned int)x > 127 || (unsigned int)y > 63) return; + + int offset = (y << 2) + (x >> 5); + int mask = 0x80000000 >> (x & 31); + + int *v1 = gray_lightVRAM(); + int *v2 = gray_lightVRAM(); + + switch(color) + { + case Color_White: + v1[offset] &= ~mask; + v2[offset] &= ~mask; + break; + + case Color_Light: + v1[offset] |= mask; + v2[offset] &= ~mask; + break; + + case Color_Dark: + v1[offset] &= ~mask; + v2[offset] |= mask; + break; + + case Color_Black: + v1[offset] |= mask; + v2[offset] |= mask; + break; + + case Color_Invert: + v1[offset] ^= mask; + v2[offset] ^= mask; + break; + + default: + break; + } +} diff --git a/src/gray.c b/src/gray/gray_engine.c similarity index 52% rename from src/gray.c rename to src/gray/gray_engine.c index 3e86b2e..12015df 100644 --- a/src/gray.c +++ b/src/gray/gray_engine.c @@ -6,7 +6,6 @@ // //--- -#include #include #include #include @@ -27,15 +26,6 @@ static int runs = 0; // Engine control. //--- -/* - gray_runs() - Returns 1 if the gray engine is running, 0 otherwise. -*/ -inline int gray_runs(void) -{ - return runs; -} - /* gray_start() Starts the gray engine. The control of the screen is transferred to the @@ -60,6 +50,31 @@ void gray_stop(void) display_useVRAM(display_getLocalVRAM()); } +/* + gray_setDelays() + Changes the gray engine delays. +*/ +void gray_setDelays(int light, int dark) +{ + delays[0] = light; + delays[1] = dark; +} + + + +//--- +// Engine information. +//--- + +/* + gray_runs() + Returns 1 if the gray engine is running, 0 otherwise. +*/ +inline int gray_runs(void) +{ + return runs; +} + /* gray_lightVRAM() Returns the module's gray vram address. @@ -88,20 +103,25 @@ void gray_getDelays(int *light, int *dark) if(dark) *dark = delays[1]; } + + +//--- +// Drawing. +//--- + /* - gray_setDelays() - Changes the gray engine delays. + gupdate() + Swaps the vram buffer sets. */ -void gray_setDelays(int light, int dark) +inline void gupdate(void) { - delays[0] = light; - delays[1] = dark; + current ^= 2; } //--- -// Internal API. +// Interrupt control and initialization. //--- /* @@ -129,127 +149,3 @@ void gray_init(void) delays[0] = 900; delays[1] = 1000; } - - - -//--- -// Global drawing functions -//--- - -/* - gupdate() - Swaps the vram buffer sets. -*/ -inline void gupdate(void) -{ - current ^= 2; -} - -/* - gclear() - Clears the video ram. -*/ -void gclear(void) -{ - int *v1 = gray_lightVRAM(); - int *v2 = gray_darkVRAM(); - int i; - - for(i = 0; i < 256; i++) v1[i] = v2[i] = 0; -} - -/* - gclear_area() - Clears an area of the video ram. End points (x1, y1) and (x2, y2) are - included. -*/ -void gclear_area(int x1, int y1, int x2, int y2) -{ - display_useVRAM(gray_lightVRAM()); - dclear_area(x1, y1, x2, y2); - display_useVRAM(gray_darkVRAM()); - dclear_area(x1, y1, x2, y2); -} - -/* - greverse_area() - Reverses an area of the vram. End points (x1, y1) and (x2, y2) are - included. -*/ -void greverse_area(int x1, int y1, int x2, int y2) -{ - display_useVRAM(gray_lightVRAM()); - dreverse_area(x1, y1, x2, y2); - display_useVRAM(gray_darkVRAM()); - dreverse_area(x1, y1, x2, y2); -} - - - -//--- -// Local drawing functions. -//--- - -/* - gpixel() - Puts a pixel in the vram. -*/ -void gpixel(int x, int y, enum Color color) -{ - if((unsigned int)x > 127 || (unsigned int)y > 63) return; - - int offset = (y << 2) + (x >> 5); - int mask = 0x80000000 >> (x & 31); - - int *v1 = gray_lightVRAM(); - int *v2 = gray_lightVRAM(); - - switch(color) - { - case Color_White: - v1[offset] &= ~mask; - v2[offset] &= ~mask; - break; - - case Color_Light: - v1[offset] |= mask; - v2[offset] &= ~mask; - break; - - case Color_Dark: - v1[offset] &= ~mask; - v2[offset] |= mask; - break; - - case Color_Black: - v1[offset] |= mask; - v2[offset] |= mask; - break; - - case Color_Invert: - v1[offset] ^= mask; - v2[offset] ^= mask; - break; - - default: - break; - } -} - -/* - gline() - Draws a line in the vram. Automatically optimizes special cases. -*/ -void gline(int x1, int y1, int x2, int y2, enum Color color) -{ - enum Color c1, c2; - - if(color == Color_None) return; - else if(color == Color_Invert) c1 = c2 = Color_Invert; - else c1 = color & 1, c2 = color >> 1; - - display_useVRAM(gray_lightVRAM()); - dline(x1, y1, x2, y2, c1); - display_useVRAM(gray_darkVRAM()); - dline(x1, y1, x2, y2, c2); -} diff --git a/src/gray/greverse_area.c b/src/gray/greverse_area.c new file mode 100644 index 0000000..7a3fccd --- /dev/null +++ b/src/gray/greverse_area.c @@ -0,0 +1,15 @@ +#include +#include + +/* + greverse_area() + Reverses an area of the vram. End points (x1, y1) and (x2, y2) are + included. +*/ +void greverse_area(int x1, int y1, int x2, int y2) +{ + display_useVRAM(gray_lightVRAM()); + dreverse_area(x1, y1, x2, y2); + display_useVRAM(gray_darkVRAM()); + dreverse_area(x1, y1, x2, y2); +} diff --git a/src/keyboard.c b/src/keyboard.c deleted file mode 100644 index f3a8c2c..0000000 --- a/src/keyboard.c +++ /dev/null @@ -1,502 +0,0 @@ -#include -#include -#include - -//--- -// Keyboard variables. -//--- - -// These ones get modified by interrupts. -static volatile unsigned char keyboard_state[10] = { 0 }; -static volatile int interrupt_flag = 0; - -// Key statistics. -static int repeat_first = 10, repeat_next = 2; -static int last_key = KEY_NONE, last_repeats = 0, last_events = 0; - - - -//--- -// Auxiliary functions. -//--- - -/* - sleep() - Puts the CPU to sleep and waits for an interrupt. -*/ -static void sleep(void) -{ - __asm__ - ( - "sleep\n\t" - ); -} - -/* - getPressedKey() - Finds a pressed key in the keyboard state and returns it. - - @return A pressed key. -*/ -static int getPressedKey(void) -{ - int row = 1, column = 0; - int state; - if(keyboard_state[0] & 1) return KEY_AC_ON; - - while(row <= 9 && !keyboard_state[row]) row++; - if(row > 9) return KEY_NONE; - - state = keyboard_state[row]; - while(!(state & 1)) - { - state >>= 1; - column++; - } - - return (column << 4) | row; -} - -/* - getPressedKeys() - Find 'count' pressed keys in the keyboard state. - - @arg keys Will be filled. - @arg count Size of array. - - @return Number of actual pressed keys found. -*/ -static int getPressedKeys(int *keys, int count) -{ - int row = 1, column; - int found = 0, actually_pressed; - int state; - if(count <= 0) return 0; - - if(keyboard_state[0] & 1) - { - keys[found++] = KEY_AC_ON; - count--; - } - - while(count && row <= 9) - { - while(row <= 9 && !keyboard_state[row]) row++; - if(row > 9) break; - - state = keyboard_state[row]; - column = 0; - - while(count && column < 8) - { - if(state & 1) - { - keys[found++] = (column << 4) | row; - count--; - } - - state >>= 1; - column++; - } - - row++; - } - - actually_pressed = found; - - while(count) - { - keys[found++] = KEY_NONE; - count--; - } - - return actually_pressed; -} - - - -//--- -// Interrupt management. -//--- - -/* - keyboard_interrupt() - Callback for keyboard update. Allows keyboard analysis functions to - wake only when keyboard interrupts happen. -*/ -void keyboard_interrupt(void) -{ - if(isSH3()) - keyboard_updateState_7705(keyboard_state); - else - keyboard_updateState_7305(keyboard_state); - - interrupt_flag = 1; -} - -/* - keyboard_init() - Starts the keyboard timer. -*/ -void keyboard_init(void) -{ - timer_start(TIMER_KEYBOARD, 1700, TIMER_Po_256, keyboard_interrupt, - 0); -} - -/* - keyboard_quit() - Stops the keyboard timer. -*/ -void keyboard_quit(void) -{ - timer_stop(TIMER_KEYBOARD); -} - - - -//--- -// Keyboard configuration. -//--- - -/* - keyboard_setFrequency() - Sets the keyboard frequency. - - @arg frequency In Hz. -*/ -void keyboard_setFrequency(int frequency) -{ -} - -/* - keyboard_setRepeatRate() - Sets the default repeat rate for key events. The unit for the argument - is the keyboard period. - For example at 16 Hz, values of (10, 2) will imitate the system - default. - - @arg first Delay before first repeat, in keyboard period units. - @arg next Delay before following repeats, in keyboard period - units. -*/ -void keyboard_setRepeatRate(int first, int next) -{ - if(first < 0) first = 0; - if(next < 0) next = 0; - - repeat_first = first; - repeat_next = next; -} - - - -//--- -// Keyboard access. -//--- - -/* - keylast() - Returns the matrix code of the last pressed key. If repeat_count is - non-NULL, it is set to the number of repetitions. - - @arg repeat_count - - @return Key matrix code. -*/ -int keylast(int *repeat_count) -{ - if(repeat_count) *repeat_count = last_repeats; - return last_key; -} - - - -/* - keystate() - Returns the address of the keyboard state array. The returned address - is the handler's buffer, therefore it contains volatile data. - - @return 10-byte keyboard state buffer. -*/ -volatile unsigned char *keystate(void) -{ - return keyboard_state; -} - - - - -/* - getkey() - Blocking function with auto-repeat and SHIFT modifying functionalities. - Roughly reproduces the behavior of the system's GetKey(). - - @return Pressed key matrix code. -*/ -int getkey(void) -{ - return getkey_opt( - Getkey_ShiftModifier | - Getkey_AlphaModifier | - - Getkey_RepeatArrowKeys, - - 0 - ); -} - - - -/* - getkey_opt() - Enhances getkey() with most general functionalities. - If max_cycles is non-zero and positive, getkey_opt() will return - KEY_NOEVENT if no event occurs during max_cycle analysis. - - @arg options OR-combination of GetkeyOpt values. - @arg max_cycles - - @return Pressed key matrix code. -*/ -int getkey_opt(enum GetkeyOpt options, int max_cycles) -{ - int key; - enum KeyType type; - int modifier = 0, last_modifier = KEY_NONE; - int r; - - if(!max_cycles) max_cycles = -1; - - while(max_cycles != 0) - { - while(!interrupt_flag) sleep(); - interrupt_flag = 0; - if(max_cycles > 0) max_cycles--; - - // Getting key and adding modifiers. - key = getPressedKey(); - - // Handling "no_key" event; - if(key == KEY_NONE) - { - // Condition for returning. - r = (last_key != KEY_NONE && - options & Getkey_ReleaseEvent); - - last_key = KEY_NONE; - last_modifier = KEY_NONE; - last_repeats = 0; - last_events = 0; - - if(r) return KEY_NONE; - } - - // Handling "new key" events. - else if(key != last_key) - { - if(options & Getkey_ShiftModifier && key == KEY_SHIFT) - { - if(last_modifier != KEY_SHIFT) - modifier ^= MOD_SHIFT; - last_modifier = KEY_SHIFT; - - continue; - } - if(options & Getkey_AlphaModifier && key == KEY_ALPHA) - { - if(last_modifier != KEY_ALPHA) - modifier ^= MOD_ALPHA; - last_modifier = KEY_ALPHA; - - continue; - } - - last_key = key; - last_repeats = 0; - last_events = 0; - - return key | modifier; - } - - // Handling key repetitions. - else - { - type = keytype(key); - - // Checking whether this key type is repeated. - if(options & (type << 4)) - { - last_events++; - r = last_repeats ? repeat_next : repeat_first; - - if(last_events >= r) - { - last_repeats++; - last_events = 0; - - return key; - } - } - } - } - - // When no key was pressed during the given delay... - return KEY_NOEVENT; -} - -/* - multigetkey() - Listens the keyboard for simultaneous key hits. Uses the same options - as getkey_opt(). - multigetkey() fills the 'keys' array with 'count' key codes, adding - KEY_NOKEY if less than 'count' keys are pressed. - Be aware that rectangle and column effects can make multigetkey() read - unpressed keys as pressed (see documentation for more information). - Setting count = 3 is generally safe. - - @arg keys Key code array. - @arg count Maximum number of keys that will be read. - @arg max_cycles -*/ -void multigetkey(int *keys, int count, int max_cycles) -{ - int number; - - if(!max_cycles) max_cycles = -1; - - while(max_cycles != 0) - { - while(!interrupt_flag) sleep(); - interrupt_flag = 0; - if(max_cycles > 0) max_cycles--; - - number = getPressedKeys(keys, count); - - // We need to update the last key data, in case multigetkey() - // returns a single key, and getkey() is called a short time - // after. Otherwise getkey() could re-send an event for this - // key. - if(number == 1) - { - last_key = keys[0]; - last_repeats = 0; - last_events = 0; - } - - if(number) return; - - // Handle key repetitions. -/* - else - { - type = keytype(key); - - // Checking whether this key type is repeated. - if(options & (type << 4)) - { - last_events++; - r = last_repeats ? repeat_next : repeat_first; - - if(last_events >= r) - { - last_repeats++; - last_events = 0; - - return key; - } - } - } -*/ - } - - // When no key was pressed during the given delay... (no need to fill - // the array, it has already been done by getPressedKeys()). - return; -} - - - -//--- -// Key analysis. -//--- - -/* - keyid() - Returns a non-matrix key code that can be used for array subscript. - Ignores modifiers. - - @arg key - - @return Modified keycode. -*/ -int keyid(int key) -{ - if(key < 0) return -1; - key &= MOD_CLEAR; - - int row = 9 - (key & 0x0f); - int column = 6 - ((key & 0xf0) >> 4); - - return 6 * row + column; -} - -/* - keychar() - Returns the ASCII character associated with a key, or 0 for control - keys. - - @arg key - - @return Associated character. -*/ -int keychar(int key) -{ - char flat[] = { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, '2', '^', 0x0, 0x0, 0x0, - 'X', 'l', 'l', 's', 'c', 't', - 0x0, 0x0, '(', ')', ',', '>', - '7', '8', '9', 0x0, 0x0, 0x0, - '4', '5', '6', '*', '/', 0x0, - '1', '2', '3', '+', '-', 0x0, - '0', '.', 'e', '-', 0x0, 0x0 - }; - char alpha[] = { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 'r', 'o', 0x0, 0x0, 0x0, - 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'I', 'J', 'K', 'L', - 'M', 'N', 'O', 0x0, 0x0, 0x0, - 'P', 'Q', 'R', 'S', 'T', 0x0, - 'U', 'V', 'W', 'X', 'Y', 0x0, - 'Z', ' ', '"', 0x0, 0x0, 0x0 - }; - - int id = keyid(key); - - if(key & MOD_ALPHA) return alpha[id]; - return flat[id]; -} - -/* - keytype() - Returns a key's type. Ignores modifiers. - - @arg key - - @return Key type. -*/ -enum KeyType keytype(int key) -{ - key &= MOD_CLEAR; - - if(key == KEY_UP || key == KEY_RIGHT || key == KEY_DOWN || - key == KEY_LEFT) return KeyType_Arrow; - - if((key & 0x0f) == 0x09) return KeyType_Function; - - return keychar(key) ? KeyType_Character : KeyType_Control; -} diff --git a/src/keyboard/getPressedKey.c b/src/keyboard/getPressedKey.c new file mode 100644 index 0000000..5e53a01 --- /dev/null +++ b/src/keyboard/getPressedKey.c @@ -0,0 +1,24 @@ +#include + +/* + getPressedKey() + Finds a pressed key in the keyboard state and returns it. +*/ +int getPressedKey(volatile unsigned char *keyboard_state) +{ + int row = 1, column = 0; + int state; + if(keyboard_state[0] & 1) return KEY_AC_ON; + + while(row <= 9 && !keyboard_state[row]) row++; + if(row > 9) return KEY_NONE; + + state = keyboard_state[row]; + while(!(state & 1)) + { + state >>= 1; + column++; + } + + return (column << 4) | row; +} diff --git a/src/keyboard/getPressedKeys.c b/src/keyboard/getPressedKeys.c new file mode 100644 index 0000000..20f52dc --- /dev/null +++ b/src/keyboard/getPressedKeys.c @@ -0,0 +1,54 @@ +#include + +/* + getPressedKeys() + Find 'count' pressed keys in the keyboard state and fills the 'keys' + array. Returns the number of actually-pressed keys found. +*/ +int getPressedKeys(volatile unsigned char *keyboard_state, int *keys, + int count) +{ + int row = 1, column; + int found = 0, actually_pressed; + int state; + if(count <= 0) return 0; + + if(keyboard_state[0] & 1) + { + keys[found++] = KEY_AC_ON; + count--; + } + + while(count && row <= 9) + { + while(row <= 9 && !keyboard_state[row]) row++; + if(row > 9) break; + + state = keyboard_state[row]; + column = 0; + + while(count && column < 8) + { + if(state & 1) + { + keys[found++] = (column << 4) | row; + count--; + } + + state >>= 1; + column++; + } + + row++; + } + + actually_pressed = found; + + while(count) + { + keys[found++] = KEY_NONE; + count--; + } + + return actually_pressed; +} diff --git a/src/keyboard/getkey.c b/src/keyboard/getkey.c new file mode 100644 index 0000000..faf9853 --- /dev/null +++ b/src/keyboard/getkey.c @@ -0,0 +1,113 @@ +#include +#include + +/* + getkey() + Blocking function with auto-repeat and SHIFT modifying functionalities. + Roughly reproduces the behavior of the system's GetKey(). +*/ +int getkey(void) +{ + return getkey_opt( + Getkey_ShiftModifier | + Getkey_AlphaModifier | + + Getkey_RepeatArrowKeys, + + 0 + ); +} + + + +/* + getkey_opt() + Enhances getkey() with most general functionalities. + If max_cycles is non-zero and positive, getkey_opt() will return + KEY_NOEVENT if no event occurs during max_cycle analysis. +*/ +int getkey_opt(enum GetkeyOpt options, int max_cycles) +{ + int key; + enum KeyType type; + int modifier = 0, last_modifier = KEY_NONE; + int r; + + if(!max_cycles) max_cycles = -1; + + while(max_cycles != 0) + { + while(!interrupt_flag) sleep(); + interrupt_flag = 0; + if(max_cycles > 0) max_cycles--; + + // Getting key and adding modifiers. + key = getPressedKey(keyboard_state); + + // Handling "no_key" event; + if(key == KEY_NONE) + { + // Condition for returning. + r = (last_key != KEY_NONE && + options & Getkey_ReleaseEvent); + + last_key = KEY_NONE; + last_modifier = KEY_NONE; + last_repeats = 0; + last_events = 0; + + if(r) return KEY_NONE; + } + + // Handling "new key" events. + else if(key != last_key) + { + if(options & Getkey_ShiftModifier && key == KEY_SHIFT) + { + if(last_modifier != KEY_SHIFT) + modifier ^= MOD_SHIFT; + last_modifier = KEY_SHIFT; + + continue; + } + if(options & Getkey_AlphaModifier && key == KEY_ALPHA) + { + if(last_modifier != KEY_ALPHA) + modifier ^= MOD_ALPHA; + last_modifier = KEY_ALPHA; + + continue; + } + + last_key = key; + last_repeats = 0; + last_events = 0; + + return key | modifier; + } + + // Handling key repetitions. + else + { + type = keytype(key); + + // Checking whether this key type is repeated. + if(options & (type << 4)) + { + last_events++; + r = last_repeats ? repeat_next : repeat_first; + + if(last_events >= r) + { + last_repeats++; + last_events = 0; + + return key; + } + } + } + } + + // When no key was pressed during the given delay... + return KEY_NOEVENT; +} diff --git a/src/keyboard/keyboard_config.c b/src/keyboard/keyboard_config.c new file mode 100644 index 0000000..909952d --- /dev/null +++ b/src/keyboard/keyboard_config.c @@ -0,0 +1,26 @@ +#include +#include + +/* + keyboard_setFrequency() + Sets the keyboard frequency (in Hz). +*/ +void keyboard_setFrequency(int frequency) +{ +} + +/* + keyboard_setRepeatRate() + Sets the default repeat rate for key events. The unit for the argument + is the keyboard period. + For example at 32 Hz, values of (20, 4) will imitate the system + default. +*/ +void keyboard_setRepeatRate(int first, int next) +{ + if(first < 0) first = 0; + if(next < 0) next = 0; + + repeat_first = first; + repeat_next = next; +} diff --git a/src/keyboard/keyboard_internals.h b/src/keyboard/keyboard_internals.h new file mode 100644 index 0000000..b4a5b2c --- /dev/null +++ b/src/keyboard/keyboard_internals.h @@ -0,0 +1,34 @@ +#ifndef _KEYBOARD_INTERNALS_H +#define _KEYBOARD_INTERNALS_H 1 + +#include + +// Keyboard variables. +extern volatile unsigned char keyboard_state[10]; +extern volatile int interrupt_flag = 0; + +// Key statistics. +extern int repeat_first, repeat_next; +extern int last_key, last_repeats, last_events; + +/* + sleep() + Puts the CPU into sleep until an interrupt request is accepted. +*/ +void sleep(void); + +/* + getPressedKey() + Finds a pressed key in the keyboard state and returns it. +*/ +int getPressedKey(volatile unsigned char *keyboard_state); + +/* + getPressedKeys() + Find 'count' pressed keys in the keyboard state and fills the 'keys' + array. Returns the number of actually-pressed keys found. +*/ +int getPressedKeys(volatile unsigned char *keyboard_state, int *keys, + int count); + +#endif // _KEYBOARD_INTERNALS_H diff --git a/src/keyboard/keyboard_interrupt.c b/src/keyboard/keyboard_interrupt.c new file mode 100644 index 0000000..4bf12ae --- /dev/null +++ b/src/keyboard/keyboard_interrupt.c @@ -0,0 +1,56 @@ +#include +#include +#include + +#include + +//--- +// Keyboard variables. +//--- + +// These ones get modified by interrupts. +volatile unsigned char keyboard_state[10] = { 0 }; +volatile int interrupt_flag = 0; + +// Key statistics. +int repeat_first = 10, repeat_next = 2; +int last_key = KEY_NONE, last_repeats = 0, last_events = 0; + + +//--- +// Interrupt management. +//--- + +/* + keyboard_interrupt() + Callback for keyboard update. Allows keyboard analysis functions to + wake only when keyboard interrupts happen. +*/ +void keyboard_interrupt(void) +{ + if(isSH3()) + keyboard_updateState_7705(keyboard_state); + else + keyboard_updateState_7305(keyboard_state); + + interrupt_flag = 1; +} + +/* + keyboard_init() + Starts the keyboard timer. +*/ +void keyboard_init(void) +{ + timer_start(TIMER_KEYBOARD, 1700, TIMER_Po_256, keyboard_interrupt, + 0); +} + +/* + keyboard_quit() + Stops the keyboard timer. +*/ +void keyboard_quit(void) +{ + timer_stop(TIMER_KEYBOARD); +} diff --git a/src/keyboard/keyboard_misc.c b/src/keyboard/keyboard_misc.c new file mode 100644 index 0000000..4837c8b --- /dev/null +++ b/src/keyboard/keyboard_misc.c @@ -0,0 +1,25 @@ +#include +#include + +/* + keylast() + Returns the matrix code of the last pressed key. If repeat_count is + non-NULL, it is set to the number of repetitions. +*/ +int keylast(int *repeat_count) +{ + if(repeat_count) *repeat_count = last_repeats; + return last_key; +} + + + +/* + keystate() + Returns the address of the keyboard state array. The returned address + is the handler's buffer, therefore it contains volatile data. +*/ +volatile unsigned char *keystate(void) +{ + return keyboard_state; +} diff --git a/src/keyboard/keyboard_sh7305.c b/src/keyboard/keyboard_sh7305.c new file mode 100644 index 0000000..2df0ec6 --- /dev/null +++ b/src/keyboard/keyboard_sh7305.c @@ -0,0 +1,146 @@ +//--- +// +// gint core module: keyboard analyzer +// +// Probably the most difficult hardware interaction. There is very few +// documentation on how the system actually analyzes the keyboard. While +// disassembling syscalls reveals the following procedure (which was +// already documented by SimonLothar), there is nothing about the +// detection problems of the multi-getkey system. +// +//--- + +#include +#include <7305.h> + +//--- +// Keyboard management. +//--- + +/* + kdelay() + Should sleep during a few milliseconds. Well... + This delay has a great influence on key detection. Here are a few + observations of what happens with common numbers of "nop" (without + overclock). Take care of the effect of overclock ! + + Column effects + May have something to do with register HIZCRB not being used here. When + many keys on the same column are pressed, other keys of the same column + may be triggered. + + - Less Bad key detection. + - 8 Very few column effects. Most often, three keys may be pressed + simultaneously. However, [UP] has latencies and is globally not + detected. + - 12 Seems best. Every individual key is detected well. No column + effect observed before four keys. + - 16 Every single key is detected correctly. Pressing two keys on a + same column does not usually create a column effect. Three keys + almost always. + - More Does not improve single key detection, and increase column + effects. At 256 every single key press create a whole column + effect. +*/ +static void kdelay(void) +{ + #define r4(str) str str str str + + __asm__ + ( + r4("nop\n\t") + r4("nop\n\t") + r4("nop\n\t") + ); + + #undef r4 +} + +/* + krow() + Reads a keyboard row. Works like krow() for SH7705. See gint_7705.c for + more details. +*/ +static int krow(int row) +{ + volatile unsigned short *injector1 = (unsigned short *)0xa4050116; + volatile unsigned char *data1 = (unsigned char *)0xa4050136; + + volatile unsigned short *injector2 = (unsigned short *)0xa4050118; + volatile unsigned char *data2 = (unsigned char *)0xa4050138; + + volatile unsigned short *detector = (unsigned short *)0xa405014c; + volatile unsigned char *keys = (unsigned char *)0xa405016c; + + volatile unsigned char *key_register = (unsigned char *)0xa40501c6; +// volatile unsigned short *hizcrb = (unsigned short *)0xa405015a; + + unsigned short smask; + unsigned char cmask; + int result = 0; + + if(row < 0 || row > 9) return 0; + + // Additional configuration for SH7305. + *detector = 0xaaaa; + *key_register = 0xff; + *injector1 = (*injector1 & 0xf000) | 0x0555; + *injector2 = (*injector2 & 0xf000) | 0x0555; + *data1 |= 0x3f; + *data2 |= 0x3f; + kdelay(); + + if(row < 6) + { + smask = 0x0003 << (row * 2); + cmask = ~(1 << row); + + *injector1 = ((*injector1 & 0xf000) | 0x0aaa) ^ smask; + *injector2 = (*injector2 & 0xf000) | 0x0aaa; + kdelay(); + + *data1 = (*data1 & 0xc0) | cmask; + *data2 |= 0x3f; + kdelay(); + } + else + { + smask = 0x0003 << ((row - 6) * 2); + cmask = ~(1 << (row - 6)); + + *injector1 = (*injector1 & 0xf000) | 0x0aaa; + *injector2 = ((*injector2 & 0xf000) | 0x0aaa) ^ smask; + kdelay(); + + *data1 |= 0x3f; + *data2 = (*data2 & 0xc0) | cmask; + kdelay(); + } + + // Reading the keyboard row. + result = ~*keys; + kdelay(); + + // Re-initializing the port configuration and data. + *injector1 = (*injector1 & 0xf000) | 0x0aaa; + *injector2 = (*injector2 & 0xf000) | 0x0aaa; + kdelay(); + *injector1 = (*injector1 & 0xf000) | 0x0555; + *injector2 = (*injector2 & 0xf000) | 0x0555; + kdelay(); + *data1 &= 0xc0; + *data2 &= 0xc0; + + return result; +} + +/* + keyboard_updateState() + Updates the keyboard state. +*/ +void keyboard_updateState_7305(volatile unsigned char *keyboard_state) +{ + int i; + + for(i = 0; i < 10; i++) keyboard_state[i] = krow(i); +} diff --git a/src/keyboard/keyboard_sh7705.c b/src/keyboard/keyboard_sh7705.c new file mode 100644 index 0000000..4f3b27a --- /dev/null +++ b/src/keyboard/keyboard_sh7705.c @@ -0,0 +1,139 @@ +//--- +// +// gint core module: keyboard analyzer +// +// Probably the most difficult hardware interaction. There is very few +// documentation on how the system actually analyzes the keyboard. While +// disassembling syscalls reveals the following procedure (which was +// already documented by SimonLothar), there is nothing about the +// detection problems of the multi-getkey system. +// +//--- + +#include +#include <7705.h> + +//--- +// Keyboard management. +//--- + +/* + kdelay() + Used to be a low-level sleep using the watchdog, as in the system. This + way seems OK at least, and it doesn't create column effects as for + SH7305. +*/ +static void kdelay(void) +{ + #define r4(str) str str str str + + __asm__ + ( + r4("nop\n\t") + r4("nop\n\t") + r4("nop\n\t") + ); + + #undef r4 + + /* Watchdog delay version. + const int delay = 0xf4; + + // Disabling the watchdog timer interrupt and resetting the + // configuration. Setting the delay. + INTC.IPRB.BIT._WDT = 0; + WDT.WTCSR.WRITE = 0xa500; + WDT.WTCNT.WRITE = 0x5a00 | (delay & 0xff); + + // Counting on Po/256. + WDT.WTCSR.WRITE = 0xa505; + // Starting the timer (sets again to Po/256). + WDT.WTCSR.WRITE = 0xa585; + + // Waiting until it overflows (delaying), then clearing the overflow + // flag. + while((WDT.WTCSR.READ.BYTE & 0x08) == 0); + WDT.WTCSR.WRITE = 0xa500 | (WDT.WTCSR.READ.BYTE & 0xf7); + + // Resetting the configuration and the counter. + WDT.WTCSR.WRITE = 0xa500; + WDT.WTCSR.WRITE = 0x5a00; + + // Enabling back the watchdog timer interrupt. + INTC.IPRB.BIT._WDT = GINT_INTP_WDT; + */ +} + +/* + krow() + Reads a keyboard row. +*/ +static int krow(int row) +{ + // '11' on the active row, '00' everywhere else. + unsigned short smask = 0x0003 << ((row % 8) * 2); + // '0' on the active row, '1' everywhere else. + unsigned char cmask = ~(1 << (row % 8)); + // Line results. + int result = 0; + + if(row < 0 || row > 9) return 0; + + // Initial configuration. + PFC.PBCR.WORD = 0xaaaa; + PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x0055; + kdelay(); + + if(row < 8) + { + // Configuring port B/M as input except for the row to check, + // which has to be an output. This sets '01' (output) on the + // active row, '10' (input) everywhere else. + PFC.PBCR.WORD = 0xaaaa ^ smask; + PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x00aa; + kdelay(); + + // Every bit set to 1 except the active row bit. + PB.DR.BYTE = cmask; + PM.DR.BYTE = (PM.DR.BYTE & 0xf0) | 0x0f; + kdelay(); + } + else + { + // The same, but deals with port M. + PFC.PBCR.WORD = 0xaaaa; + PFC.PMCR.WORD = ((PFC.PMCR.WORD & 0xff00) | 0x00aa) ^ smask; + kdelay(); + + PB.DR.BYTE = 0xff; + PM.DR.BYTE = (PM.DR.BYTE & 0xf0) | cmask; + kdelay(); + } + + // Reading the keyboard row. + result = ~PA.DR.BYTE; + kdelay(); + + // Re-initializing the port configuration and data. + PFC.PBCR.WORD = 0xaaaa; + PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x00aa; + kdelay(); + PFC.PBCR.WORD = 0x5555; + PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x0055; + kdelay(); + PB.DR.BYTE = 0x00; + PM.DR.BYTE &= 0xf0; + + return result; +} + +/* + keyboard_updateState() + Updates the keyboard state. +*/ +void keyboard_updateState_7705(volatile unsigned char *keyboard_state) +{ + int i; + + for(i = 0; i < 10; i++) keyboard_state[i] = krow(i); +} diff --git a/src/keyboard/keychar.c b/src/keyboard/keychar.c new file mode 100644 index 0000000..bd9e9cc --- /dev/null +++ b/src/keyboard/keychar.c @@ -0,0 +1,36 @@ +#include + +/* + keychar() + Returns the ASCII character associated with a key, or 0 for control + keys. +*/ +int keychar(int key) +{ + char flat[] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, '2', '^', 0x0, 0x0, 0x0, + 'X', 'L', 'l', 's', 'c', 't', + 0x0, 0x0, '(', ')', ',', '>', + '7', '8', '9', 0x0, 0x0, 0x0, + '4', '5', '6', '*', '/', 0x0, + '1', '2', '3', '+', '-', 0x0, + '0', '.', 'e', '_', 0x0, 0x0 + }; + char alpha[] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 'r', 'o', 0x0, 0x0, 0x0, + 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 0x0, 0x0, 0x0, + 'P', 'Q', 'R', 'S', 'T', 0x0, + 'U', 'V', 'W', 'X', 'Y', 0x0, + 'Z', ' ', '"', 0x0, 0x0, 0x0 + }; + + int id = keyid(key); + + return (key & MOD_ALPHA) ? alpha[id] : flat[id]; +} diff --git a/src/keyboard/keyid.c b/src/keyboard/keyid.c new file mode 100644 index 0000000..c4ed014 --- /dev/null +++ b/src/keyboard/keyid.c @@ -0,0 +1,17 @@ +#include + +/* + keyid() + Returns a non-matrix key code that can be used for array subscript. + Ignores modifiers. +*/ +int keyid(int key) +{ + if(key < 0) return -1; + key &= MOD_CLEAR; + + int row = 9 - (key & 0x0f); + int column = 6 - ((key & 0xf0) >> 4); + + return 6 * row + column; +} diff --git a/src/keyboard/keytype.c b/src/keyboard/keytype.c new file mode 100644 index 0000000..9e3c0c9 --- /dev/null +++ b/src/keyboard/keytype.c @@ -0,0 +1,17 @@ +#include + +/* + keytype() + Returns a key's type. Ignores modifiers. +*/ +enum KeyType keytype(int key) +{ + key &= MOD_CLEAR; + + if(key == KEY_UP || key == KEY_RIGHT || key == KEY_DOWN || + key == KEY_LEFT) return KeyType_Arrow; + + if((key & 0x0f) == 0x09) return KeyType_Function; + + return keychar(key) ? KeyType_Character : KeyType_Control; +} diff --git a/src/keyboard/multigetkey.c b/src/keyboard/multigetkey.c new file mode 100644 index 0000000..fb7d355 --- /dev/null +++ b/src/keyboard/multigetkey.c @@ -0,0 +1,46 @@ +#include +#include + +/* + multigetkey() + Listens the keyboard for simultaneous key hits. Uses the same options + as getkey_opt(). + multigetkey() fills the 'keys' array with 'count' key codes, adding + KEY_NOKEY if less than 'count' keys are pressed. + Be aware that rectangle and column effects can make multigetkey() read + unpressed keys as pressed (see documentation for more information). + Setting count = 3 is generally safe. + The function returns after 'max_cycles' if no key is pressed. +*/ +void multigetkey(int *keys, int count, int max_cycles) +{ + int number; + + if(!max_cycles) max_cycles = -1; + + while(max_cycles != 0) + { + while(!interrupt_flag) sleep(); + interrupt_flag = 0; + if(max_cycles > 0) max_cycles--; + + number = getPressedKeys(keyboard_state, keys, count); + + // We need to update the last key data, in case multigetkey() + // returns a single key, and getkey() is called a short time + // after. Otherwise getkey() could re-send an event for this + // key. + if(number == 1) + { + last_key = keys[0]; + last_repeats = 0; + last_events = 0; + } + + if(number) return; + } + + // When no key was pressed during the given delay... (no need to fill + // the array, it has already been done by getPressedKeys()). + return; +} diff --git a/src/keyboard/sleep.c b/src/keyboard/sleep.c new file mode 100644 index 0000000..92ae174 --- /dev/null +++ b/src/keyboard/sleep.c @@ -0,0 +1,13 @@ +#include + +/* + sleep() + Puts the CPU to sleep and waits for an interrupt. +*/ +void sleep(void) +{ + __asm__ + ( + "sleep\n\t" + ); +} diff --git a/src/mpu/gint_sh7305.c b/src/mpu/gint_sh7305.c new file mode 100644 index 0000000..f5e8c85 --- /dev/null +++ b/src/mpu/gint_sh7305.c @@ -0,0 +1,159 @@ +//--- +// +// gint core module: sh7305 interrupt handler +// +// Of course all the work related to interrupts is heavily platform- +// dependent. This module handles interrupts and configures the MPU to +// save and restore the system's configuration when execution ends. +// +//--- + +#include +#include +#include <7305.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 + + + +//--- +// Interrupt handler. +//--- + +void gint_7305(void) +{ + volatile unsigned int *intevt = (unsigned int *)0xff000028; + unsigned int code = *intevt; + + switch(code) + { + case IC_RTC_PRI: + RTC.RCR2.PEF = 0; + 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; + } +} + + + +//--- +// Setup. +//--- + +static unsigned short ipr[12]; +static unsigned char rcr2; +// Saves of the keyboard registers. Could be better. +static unsigned short inj1, inj2, det; +static unsigned char data1, data2, keys, reg; + +static void gint_priority_lock_7305(void) +{ + // Saving the current interrupt priorities. + ipr[0] = INTX.IPRA.WORD; + ipr[1] = INTX.IPRB.WORD; + ipr[2] = INTX.IPRC.WORD; + ipr[3] = INTX.IPRD.WORD; + ipr[4] = INTX.IPRE.WORD; + ipr[5] = INTX.IPRF.WORD; + ipr[6] = INTX.IPRG.WORD; + ipr[7] = INTX.IPRH.WORD; + ipr[8] = INTX.IPRI.WORD; + ipr[9] = INTX.IPRJ.WORD; + ipr[10] = INTX.IPRK.WORD; + ipr[11] = INTX.IPRL.WORD; + + // Disabling everything by default to avoid freezing on non-handled + // interrupts. + INTX.IPRA.WORD = 0x0000; + INTX.IPRB.WORD = 0x0000; + INTX.IPRC.WORD = 0x0000; + INTX.IPRD.WORD = 0x0000; + INTX.IPRE.WORD = 0x0000; + INTX.IPRF.WORD = 0x0000; + INTX.IPRG.WORD = 0x0000; + INTX.IPRH.WORD = 0x0000; + INTX.IPRI.WORD = 0x0000; + INTX.IPRJ.WORD = 0x0000; + INTX.IPRK.WORD = 0x0000; + INTX.IPRL.WORD = 0x0000; + + // Saving keyboard registers. + inj1 = *((volatile unsigned short *)0xa4050116); + data1 = *((volatile unsigned char *)0xa4050136); + inj2 = *((volatile unsigned short *)0xa4050118); + data2 = *((volatile unsigned char *)0xa4050138); + det = *((volatile unsigned short *)0xa405014c); + keys = *((volatile unsigned char *)0xa405016c); + reg = *((volatile unsigned char *)0xa40501c6); + + // Allowing RTC. Keyboard analysis is done regularly using a RTC + // because SH7305's special KEYSC interface does not allow us to clear + // the keyboard interrupt flags. + INTX.IPRK._RTC = GINT_INTP_RTC; + INTX.IPRA.TMU0_0 = GINT_INTP_KEY; + INTX.IPRA.TMU0_1 = GINT_INTP_GRAY; + INTX.IPRA.TMU0_2 = GINT_INTP_TIMER; +} + +static void gint_priority_unlock_7305(void) +{ + // Restoring the interrupt priorities. + INTX.IPRA.WORD = ipr[0]; + INTX.IPRB.WORD = ipr[1]; + INTX.IPRC.WORD = ipr[2]; + INTX.IPRD.WORD = ipr[3]; + INTX.IPRE.WORD = ipr[4]; + INTX.IPRF.WORD = ipr[5]; + INTX.IPRG.WORD = ipr[6]; + INTX.IPRH.WORD = ipr[7]; + INTX.IPRI.WORD = ipr[8]; + INTX.IPRJ.WORD = ipr[9]; + INTX.IPRK.WORD = ipr[10]; + INTX.IPRL.WORD = ipr[11]; + + // Restoring keyboard registers. + *((volatile unsigned short *)0xa4050116) = inj1; + *((volatile unsigned char *)0xa4050136) = data1; + *((volatile unsigned short *)0xa4050118) = inj2; + *((volatile unsigned char *)0xa4050138) = data2; + *((volatile unsigned short *)0xa405014c) = det; + *((volatile unsigned char *)0xa405016c) = keys; + *((volatile unsigned char *)0xa40501c6) = reg; +} + +void gint_setup_7305(void) +{ + gint_priority_lock_7305(); + + // Saving the RTC configuration. + rcr2 = RTC.RCR2.BYTE; + // Disabling RTC interrupts by default. + RTC.RCR2.BYTE = 0x09; +} + +void gint_stop_7305(void) +{ + gint_priority_unlock_7305(); + + // Restoring the RTC configuration. + RTC.RCR2.BYTE = rcr2; +} diff --git a/src/mpu/gint_sh7705.c b/src/mpu/gint_sh7705.c new file mode 100644 index 0000000..f17aafb --- /dev/null +++ b/src/mpu/gint_sh7705.c @@ -0,0 +1,125 @@ +//--- +// +// gint core module: sh7705 interrupt handler +// +// Of course all the work related to interrupts is heavily platform- +// dependent. This module handles interrupts and configures the MPU to +// save and restore the system's configuration when execution ends. +// +//--- + +#include +#include +#include <7705.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 + + + +//--- +// Interrupt handler. +//--- + +void gint_7705(void) +{ + volatile unsigned int *intevt2 = (unsigned int *)0xa4000000; + unsigned int code = *intevt2; + + switch(code) + { + case IC_RTC_PRI: + RTC.RCR2.BIT.PEF = 0; + 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; + } +} + + + +//--- +// Setup. +//--- + +static unsigned short iprs[8]; +static unsigned char rcr2; + +static void gint_priority_lock_7705(void) +{ + // Saving the interrupt masks from registers IPRA to IPRH. + iprs[0] = INTC.IPRA.WORD; + iprs[1] = INTC.IPRB.WORD; + iprs[2] = INTX.IPRC.WORD; + iprs[3] = INTX.IPRD.WORD; + iprs[4] = INTX.IPRE.WORD; + iprs[5] = INTX.IPRF.WORD; + iprs[6] = INTX.IPRG.WORD; + iprs[7] = INTX.IPRH.WORD; + + // Disabling everything by default to avoid receiving an interrupt that + // the handler doesn't handle, which would cause the user program to + // freeze. + INTC.IPRA.WORD = 0x0000; + INTC.IPRB.WORD = 0x0000; + INTX.IPRC.WORD = 0x0000; + INTX.IPRD.WORD = 0x0000; + INTX.IPRE.WORD = 0x0000; + INTX.IPRF.WORD = 0x0000; + INTX.IPRG.WORD = 0x0000; + INTX.IPRH.WORD = 0x0000; + + // Allowing RTC, which handles keyboard. + INTC.IPRA.BIT._RTC = GINT_INTP_RTC; + INTC.IPRA.BIT._TMU0 = GINT_INTP_KEY; + INTC.IPRA.BIT._TMU1 = GINT_INTP_GRAY; + INTC.IPRA.BIT._TMU2 = GINT_INTP_TIMER; +} + +static void gint_priority_unlock_7705(void) +{ + // Restoring the saved states. + INTC.IPRA.WORD = iprs[0]; + INTC.IPRB.WORD = iprs[1]; + INTX.IPRC.WORD = iprs[2]; + INTX.IPRD.WORD = iprs[3]; + INTX.IPRE.WORD = iprs[4]; + INTX.IPRF.WORD = iprs[5]; + INTX.IPRG.WORD = iprs[6]; + INTX.IPRH.WORD = iprs[7]; +} + +void gint_setup_7705(void) +{ + gint_priority_lock_7705(); + + // Saving the RTC configuration. + rcr2 = RTC.RCR2.BYTE; + // Disabling RTC interrupts by default. + RTC.RCR2.BYTE = 0x09; +} + +void gint_stop_7705(void) +{ + gint_priority_unlock_7705(); + + // Restoring the RTC configuration. + RTC.RCR2.BYTE = rcr2; +} diff --git a/src/mpu.c b/src/mpu/mpu.c similarity index 82% rename from src/mpu.c rename to src/mpu/mpu.c index fa5fbea..f4c7dc6 100644 --- a/src/mpu.c +++ b/src/mpu/mpu.c @@ -1,3 +1,11 @@ +//--- +// +// gint core module: mpu +// +// Determines which kind of MPU is running the program. +// +//--- + #include enum MPU MPU_CURRENT; @@ -6,21 +14,18 @@ enum MPU MPU_CURRENT; getMPU() Returns the MPU identifier of the calculator. - Thanks to SimonLothar for this function and related informations. + Thanks to SimonLothar for this function and related information. Processor version register (PVR) and product control register (PRR) - hold information about the MPU version but are only accessible for + hold information about the MPU version, they but are only accessible on SH-4-based MPUs. - Therefore, this function uses port L control register (PLCR), whose - bits 8 to 15 cannot be set with SH7337 where bits 8 to 11 can be set - with SH7355. + To detect SH-3-based MPUs, this function uses port L control register + (PLCR), whose bits 8 to 15 cannot be set with SH7337 where bits 8 to 11 + can be set with SH7355. Additionally, the CPU core ID register (CPIDR) at 0xff000048 returns 1 on SH7305. - - @return MPU identifier as integer value. */ - enum MPU getMPU(void) { // Processor version register. diff --git a/src/mpu/various_7305.c b/src/mpu/various_7305.c new file mode 100644 index 0000000..6182968 --- /dev/null +++ b/src/mpu/various_7305.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include <7305.h> + +//--- +// Various MPU-dependent procedures. +//--- + +/* + gint_setRTCFrequency() + Sets the RTC interrupt frequency and enables interrupts. +*/ +void gint_setRTCFrequency_7305(enum RTCFrequency frequency) +{ + if(frequency < 1 || frequency > 7) return; + RTC.RCR2.BYTE = (frequency << 4) | 0x09; +} + +/* + gint_getRTCFrequency() + Returns the RTC interrupt frequency. +*/ +enum RTCFrequency gint_getRTCFrequency_7305(void) +{ + return (RTC.RCR2.BYTE & 0x70) >> 4; +} diff --git a/src/mpu/various_7705.c b/src/mpu/various_7705.c new file mode 100644 index 0000000..c046813 --- /dev/null +++ b/src/mpu/various_7705.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include <7705.h> + +//--- +// Various MPU-dependent procedures. +//--- + +/* + gint_setRTCFrequency() + Sets the RTC interrupt frequency and enables interrupts. +*/ +void gint_setRTCFrequency_7705(enum RTCFrequency frequency) +{ + if(frequency < 1 || frequency > 7) return; + RTC.RCR2.BYTE = (frequency << 4) | 0x09; +} + +/* + gint_getRTCFrequency() + Returns the RTC interrupt frequency. +*/ +enum RTCFrequency gint_getRTCFrequency_7705(void) +{ + return (RTC.RCR2.BYTE & 0x70) >> 4; +} diff --git a/src/screen.c b/src/screen/screen_display.c similarity index 60% rename from src/screen.c rename to src/screen/screen_display.c index e3ac5e6..c04d7d8 100644 --- a/src/screen.c +++ b/src/screen/screen_display.c @@ -1,27 +1,11 @@ -/* - screen.c - - This module is in charge of interaction with the physical screen. See - module 'display' for video ram management and drawing. - - The screen basically has two input values, which are a register - selector and the selected register's value. What this module does is - essentially selecting registers by setting *selector and assigning them - values by setting *data. -*/ - #include - - /* screen_display() Displays the given vram on the screen. Only bytes can be transferred through the screen registers, which is unfortunate because most of the - vram-related operations use longword-base computations. - - @arg vram 1024-byte video buffer. + vram-related operations use longword-base operations. */ void screen_display(const void *ptr) { diff --git a/src/setjmp.s b/src/setjmp/setjmp.s similarity index 65% rename from src/setjmp.s rename to src/setjmp/setjmp.s index 27a070e..81a053a 100644 --- a/src/setjmp.s +++ b/src/setjmp/setjmp.s @@ -1,16 +1,13 @@ /* - This file implements long jumps. An example of their use is with crt0.c - and exit()-family functions that use them to restore the execution - state when leaving the program from an unknown location. + gint standard module: setjmp - The register contents are saved in a buffer when setjmp() is called and - restored at any time when longjmp() performs the jump, through an - exit() or abort() call, for instance. + Long jumps. The register contents are saved in a buffer when setjmp() + is called and restored at any time when longjmp() performs the jump. - This is actually a question of playing with pr ; the user program is - resumed after the setjmp() call when longjmp() is invoked but setjmp() - has nothing to do with this operation. longjmp() restores the pr value - that was saved by setjmp() and performs an rts instruction. + This is based on a trick that uses pr ; the user program is resumed + after the setjmp() call when longjmp() is invoked but this is not + setjmp() that returns. longjmp() restores the pr value that was saved + by setjmp() and performs an rts instruction. setjmp() returns 0 when called to set up the jump point and a non-zero value when invoked through a long jump. If 0 is given as return value @@ -54,7 +51,7 @@ _setjmp: _longjmp: /* Restoring the system and control registers. Restoring pr is actually - what performs the jump -- and makes the user program thinks that + what performs the jump -- and makes the user program think that setjmp() has returned. */ lds.l @r4+, pr lds.l @r4+, macl diff --git a/src/string.c b/src/string/memcpy.c similarity index 55% rename from src/string.c rename to src/string/memcpy.c index 6edd334..d78d1f6 100644 --- a/src/string.c +++ b/src/string/memcpy.c @@ -1,17 +1,9 @@ #include #include -//--- -// Memory manipulation. -//--- - /* memcpy() Copies a memory area. A smart copy is performed if possible. - - @arg destination - @arg source - @arg byte_number */ void *memcpy(void *d, const void *s, size_t n) { @@ -82,53 +74,3 @@ void *memcpy(void *d, const void *s, size_t n) return d; } - -/* - memset() - Sets the contents of a memory area. A smart copy is performed. - - @arg area - @arg byte Byte to write in the area. - @arg byte_number -*/ -void *memset(void *d, int byte, size_t byte_number) -{ - uint8_t *dest = (uint8_t *)d; - unsigned short word = (byte << 8) | byte; - unsigned int longword = (word << 16) | word; - - // When the area is small, simply copying using byte operations. The - // minimum length used for long operations must be at least 3. - if(byte_number < 8) - { - while(byte_number) - { - *dest++ = byte; - byte_number--; - } - - return d; - } - - // Reaching a long offset. - while((intptr_t)dest & 3) - { - *dest++ = byte; - byte_number--; - } - // Copying using long operations. - while(byte_number >= 4) - { - *((uint32_t *)dest) = longword; - dest += 4; - byte_number -= 4; - } - // Ending the copy. - while(byte_number) - { - *dest++ = byte; - byte_number--; - } - - return d; -} diff --git a/src/string/memset.c b/src/string/memset.c new file mode 100644 index 0000000..7236516 --- /dev/null +++ b/src/string/memset.c @@ -0,0 +1,48 @@ +#include +#include + +/* + memset() + Sets the contents of a memory area. A smart copy is performed. +*/ +void *memset(void *d, int byte, size_t byte_number) +{ + uint8_t *dest = (uint8_t *)d; + unsigned short word = (byte << 8) | byte; + unsigned int longword = (word << 16) | word; + + // When the area is small, simply copying using byte operations. The + // minimum length used for long operations must be at least 3. + if(byte_number < 8) + { + while(byte_number) + { + *dest++ = byte; + byte_number--; + } + + return d; + } + + // Reaching a long offset. + while((intptr_t)dest & 3) + { + *dest++ = byte; + byte_number--; + } + // Copying using long operations. + while(byte_number >= 4) + { + *((uint32_t *)dest) = longword; + dest += 4; + byte_number -= 4; + } + // Ending the copy. + while(byte_number) + { + *dest++ = byte; + byte_number--; + } + + return d; +} diff --git a/src/tales.c b/src/tales.c deleted file mode 100644 index 777134e..0000000 --- a/src/tales.c +++ /dev/null @@ -1,290 +0,0 @@ -#include -#include -#include -#include - -#include - -static struct Font *font; - -//--- -// Local functions. -//--- - -/* - getCharacterIndex() - Returns the index of a character in a font data area depending on the - font format and the size of the characters. - - @arg character - - @return Index in data area (as long array). Returns -1 when the - character does not belong to the font format set. -*/ -static int getCharacterIndex(int c) -{ - const char *data = (const char *)&font->glyphs; - int index, current; - int offset; - int width, bits; - - c &= 0x7f; - - - - // Getting the character index in the glyph array. - - if(font->format == FontFormat_Ascii) index = c; - else if(font->format == FontFormat_Print) index = c - 32; - - else switch(font->format) - { - case FontFormat_Numeric: - if(!isdigit(c)) return -1; - index = c - '0'; - break; - case FontFormat_LowerCase: - if(!islower(c)) return -1; - index = c - 'a'; - break; - case FontFormat_UpperCase: - if(!isupper(c)) return -1; - index = c - 'A'; - break; - case FontFormat_Letters: - if(!isalpha(c)) return -1; - index = c - 'A' - ('a' - 'z') * (c >= 'a'); - break; - case FontFormat_Common: - if(!isalnum(c)) return -1; - index = c - '0' - ('A' - '9') * (c >= 'A') - - ('a' - 'z') * (c >= 'a'); - break; - case FontFormat_Unknown: - default: - return -1; - } - - - - // Reaching the character offset. - - current = index & ~7; - offset = font->index[current >> 3]; - - while(current < index) - { - width = data[offset << 2]; - bits = font->data_height * width + 8; - - offset += (bits + 31) >> 5; - current++; - } - - return offset; -} - -/* - operate() - Operates on the vram using the given operators. The x-coordinate should - be a multiple of 32. - - @arg operators Operator array. - @arg height Number of operators (height of text). - @arg x - @arg y -*/ -static void operate(uint32_t *operators, int height, int x, int y) -{ - int *vram = display_getCurrentVRAM(); - int vram_offset = (x >> 5) + (y << 2); - int i; - - for(i = 0; i < height; i++) - { - // TODO BLENDING MODES // - vram[vram_offset] |= operators[i]; - - vram_offset += 4; - } -} - -/* - update() - Updates the operators using the given glyph. The operation will not be - complete if there are not enough bits available in the operator data. - In this case the offset will become negative, which means that the - calling procedure has to call operate() and re-call update(). - - @arg operators Operator array. - @arg height Number of operators. - @arg available Number of free bits in the operators (lower - bits). - @arg glyph Glyph data, including meta-data. - - @return Number of bits available after the operation. May be negative: - in this case, call operate() and update() again. -*/ -static int update(uint32_t *operators, int height, int available, - uint32_t *glyph) -{ - // Glyph width. - int width = glyph[0] >> 24; - int i; - - // The glyph mask extracts 'width' bits at the left. The partial mask - // is used when there are less than 'width' bits available in the - // current data longword. - uint32_t glyph_mask = 0xffffffff << (32 - width); - uint32_t partial_mask; - - int shift; - uint32_t line; - - // Current data longword, next data array index, and number of bits - // still available in 'data'. - uint32_t data = glyph[0] << 8; - int data_index = 1; - int bits_available = 24; - - for(i = 0; i < height; i++) - { - shift = 32 - available; - - // Getting the next 'width' bits. In some cases these bits will - // intersect two different longs. - line = data & glyph_mask; - line = (shift >= 0) ? (line >> shift) : (line << -shift); - operators[i] |= line; - - data <<= width; - bits_available -= width; - - // Continue until they do. - if(bits_available >= 0) continue; - - // Computing a special mask that extracts just the number of - // bits missing, and loading a new data longword. - partial_mask = 0xffffffff << (32 + bits_available); - data = glyph[data_index++]; - shift += width + bits_available; - - if(shift <= 31) - { - line = data & partial_mask; - line = (shift >= 0) ? (line >> shift) : - (line << -shift); - operators[i] |= line; - } - - data <<= -bits_available; - bits_available += 32; - } - - return available - width; -} - - - -//--- -// Public API. -//--- - -/* - print_configure() - Sets the font and mode to use for the following print operations. - - @arg font - @arg mode -*/ -void print_configure(struct Font *next_font) -{ - font = next_font; -} - -/* - print_raw() - Prints the given string, without any analysis. - - @arg str - @arg x - @arg y -*/ -void print_raw(const char *str, int x, int y) -{ - // Operator data, and number of available bits in the operators (which - // is the same for all operators, since they are treated equally). - uint32_t *operators; - int available; - - // Raw glyph data, each glyph being represented by one or several - // longwords, and an index in this array. - uint32_t *data = (uint32_t *)font->glyphs; - int index; - - // Height of each glyph. This value is constant because the storage - // format requires it: it allows greater optimization. - int height; - - - - if(!font) return; - - // Allocating data. There will be one operator for each line. - height = font->data_height; - if(x > 127 || y > 63 || y <= -height) return; - - operators = calloc(height, sizeof(uint32_t)); - if(!operators) return; - - // Computing the initial operator offset to have 32-aligned operators. - // This allows to write directly video ram longs instead of having to - // shift operators, and do all the vram operation twice. - available = 32 - (x & 31); - x &= ~31; - - // Displaying character after another. - while(*str) - { - index = getCharacterIndex(*str++); - if(index < 0) continue; - - // Updating the operators. - available = update(operators, height, available, data + index); - - // Continue until operators are full (this includes an - // additional bit to add a space between each character). - if(available > 1) - { - available--; - continue; - } - - // When operators are full, updating the video ram and - // preparing the operators for another row. - - operate(operators, height, x, y); - x += 32; - if(x > 96) break; - - memset(operators, 0, height << 2); - if(available >= 0) - { - available = 31 + available; - continue; - } - - // Finishing update, in case it has been only partially done, - // because there was not enough bits available to fit all the - // information. Also adding a space, assuming that characters - // aren't more than 30 bits wide. - available += 32 + (data[index] >> 24); - available = update(operators, height, available, data + index); - available--; - } - - // Final operation. - if(x <= 96 && available < 32) operate(operators, height, x, y); - - free(operators); -} diff --git a/src/tales/dtext.c b/src/tales/dtext.c new file mode 100644 index 0000000..7f52aaa --- /dev/null +++ b/src/tales/dtext.c @@ -0,0 +1,88 @@ +#include +#include + +#include +#include + +/* + dtext() + Prints the given string, without any analysis. +*/ +void dtext(const char *str, int x, int y) +{ + // Operator data, and number of available bits in the operators (which + // is the same for all operators, since they are treated equally). + uint32_t *operators; + int available; + + // Raw glyph data, each glyph being represented by one or several + // longwords, and an index in this array. + uint32_t *data = (uint32_t *)font->glyphs; + int index; + + // Height of each glyph. This value is constant because the storage + // format requires it: it allows greater optimization. + int height; + + + + if(!font) return; + + // Allocating data. There will be one operator for each line. + height = font->data_height; + if(x > 127 || y > 63 || y <= -height) return; + + operators = calloc(height, sizeof(uint32_t)); + if(!operators) return; + + // Computing the initial operator offset to have 32-aligned operators. + // This allows to write directly video ram longs instead of having to + // shift operators, and do all the vram operation twice. + available = 32 - (x & 31); + x &= ~31; + + // Displaying character after another. + while(*str) + { + index = getCharacterIndex(*str++); + if(index < 0) continue; + + // Updating the operators. + available = update(operators, height, available, data + index); + + // Continue until operators are full (this includes an + // additional bit to add a space between each character). + if(available > 1) + { + available--; + continue; + } + + // When operators are full, updating the video ram and + // preparing the operators for another row. + + operate(operators, height, x, y); + x += 32; + if(x > 96) break; + + memset(operators, 0, height << 2); + if(available >= 0) + { + available = 31 + available; + continue; + } + + // Finishing update, in case it has been only partially done, + // because there was not enough bits available to fit all the + // information. Also adding a space, assuming that characters + // aren't more than 30 bits wide. + available += 32 + (data[index] >> 24); + available = update(operators, height, available, data + index); + available--; + } + + // Final operation. + if(x <= 96 && available < 32) operate(operators, height, x, y); + + free(operators); +} diff --git a/src/tales/tales_configuration.c b/src/tales/tales_configuration.c new file mode 100644 index 0000000..be38c33 --- /dev/null +++ b/src/tales/tales_configuration.c @@ -0,0 +1,11 @@ +#include +#include + +/* + text_configure() + Sets the font and mode to use for the following print operations. +*/ +void text_configure(struct Font *font) +{ + font = next_font; +} diff --git a/src/tales/tales_internals.c b/src/tales/tales_internals.c new file mode 100644 index 0000000..8470254 --- /dev/null +++ b/src/tales/tales_internals.c @@ -0,0 +1,164 @@ +#include +#include + +struct Font *font; + +/* + getCharacterIndex() + Returns the index of a character in a font data area depending on the + font format and the size of the characters. Returns the index in the + data area, as long array, or -1 when the character does not belong to + the font format set. +*/ +int getCharacterIndex(int c) +{ + const char *data = (const char *)&font->glyphs; + int index, current; + int offset; + int width, bits; + + c &= 0x7f; + + + + // Getting the character index in the glyph array. + + if(font->format == FontFormat_Ascii) index = c; + else if(font->format == FontFormat_Print) index = c - 32; + + else switch(font->format) + { + case FontFormat_Numeric: + if(!isdigit(c)) return -1; + index = c - '0'; + break; + case FontFormat_LowerCase: + if(!islower(c)) return -1; + index = c - 'a'; + break; + case FontFormat_UpperCase: + if(!isupper(c)) return -1; + index = c - 'A'; + break; + case FontFormat_Letters: + if(!isalpha(c)) return -1; + index = c - 'A' - ('a' - 'z') * (c >= 'a'); + break; + case FontFormat_Common: + if(!isalnum(c)) return -1; + index = c - '0' - ('A' - '9') * (c >= 'A') - + ('a' - 'z') * (c >= 'a'); + break; + case FontFormat_Unknown: + default: + return -1; + } + + + + // Reaching the character offset. + + current = index & ~7; + offset = font->index[current >> 3]; + + while(current < index) + { + width = data[offset << 2]; + bits = font->data_height * width + 8; + + offset += (bits + 31) >> 5; + current++; + } + + return offset; +} + +/* + operate() + Operates on the vram using the given operators. The x-coordinate should + be a multiple of 32. There should be `height` operators. +*/ +void operate(uint32_t *operators, int height, int x, int y) +{ + int *vram = display_getCurrentVRAM(); + int vram_offset = (x >> 5) + (y << 2); + int i; + + for(i = 0; i < height; i++) + { + // TODO BLENDING MODES // + vram[vram_offset] |= operators[i]; + + vram_offset += 4; + } +} + +/* + update() + Updates the operators using the given glyph. The operation will not be + complete if there are not enough bits available in the operator data. + In this case the offset will become negative, which means that the + calling procedure has to call operate() and re-call update(). + `available` represents the number of free bits in the operators (lower + bits). + Returns the number of bits available after the operation. If it's + negative, call operate() and update() again. +*/ +int update(uint32_t *operators, int height, int available, + uint32_t *glyph) +{ + // Glyph width. + int width = glyph[0] >> 24; + int i; + + // The glyph mask extracts 'width' bits at the left. The partial mask + // is used when there are less than 'width' bits available in the + // current data longword. + uint32_t glyph_mask = 0xffffffff << (32 - width); + uint32_t partial_mask; + + int shift; + uint32_t line; + + // Current data longword, next data array index, and number of bits + // still available in 'data'. + uint32_t data = glyph[0] << 8; + int data_index = 1; + int bits_available = 24; + + for(i = 0; i < height; i++) + { + shift = 32 - available; + + // Getting the next 'width' bits. In some cases these bits will + // intersect two different longs. + line = data & glyph_mask; + line = (shift >= 0) ? (line >> shift) : (line << -shift); + operators[i] |= line; + + data <<= width; + bits_available -= width; + + // Continue until they do. + if(bits_available >= 0) continue; + + // Computing a special mask that extracts just the number of + // bits missing, and loading a new data longword. + partial_mask = 0xffffffff << (32 + bits_available); + data = glyph[data_index++]; + shift += width + bits_available; + + if(shift <= 31) + { + line = data & partial_mask; + line = (shift >= 0) ? (line >> shift) : + (line << -shift); + operators[i] |= line; + } + + data <<= -bits_available; + bits_available += 32; + } + + return available - width; +} diff --git a/src/tales/tales_internals.h b/src/tales/tales_internals.h new file mode 100644 index 0000000..4908aaf --- /dev/null +++ b/src/tales/tales_internals.h @@ -0,0 +1,47 @@ +//--- +// +// gint drawing module: tales +// +// Text displaying. Does some good optimization, though requires dynamic +// allocation. +// +//--- + +#ifndef _TALES_INTERNALS_H +#define _TALES_INTERNALS_H 1 + +#include +#include + +extern struct Font *font; + +/* + getCharacterIndex() + Returns the index of a character in a font data area depending on the + font format and the size of the characters. Returns the index in the + data area, as long array, or -1 when the character does not belong to + the font format set. +*/ +int getCharacterIndex(int c); + +/* + operate() + Operates on the vram using the given operators. The x-coordinate should + be a multiple of 32. There should be `height` operators. +*/ +void operate(uint32_t *operators, int height, int x, int y); + +/* + update() + Updates the operators using the given glyph. The operation will not be + complete if there are not enough bits available in the operator data. + In this case the offset will become negative, which means that the + calling procedure has to call operate() and re-call update(). + `available` represents the number of free bits in the operators (lower + bits). + Returns the number of bits available after the operation. If it's + negative, call operate() and update() again. +*/ +int update(uint32_t *operators, int height, int available, uint32_t *glyph); + +#endif // _TALES_INTERNALS_H diff --git a/src/timer.c b/src/timer.c deleted file mode 100644 index 5988b8e..0000000 --- a/src/timer.c +++ /dev/null @@ -1,201 +0,0 @@ -#include -#include -#include - -//--- -// Internal declarations. -// Timer structure and running information (callbacks, repeats etc.) -//--- - -/* - struct Timer - This structure holds information for a running timer. -*/ -struct Timer -{ - void (*callback)(void); - int repetitions; -}; - -// Static timers. -static struct Timer timers[3] = { { NULL, 0 }, { NULL, 0 }, { NULL, 0 } }; - -/* - struct mod_tmu - This structure holds information about the timer unit (peripheral - module) registers. -*/ -struct mod_tmu -{ - // Timer constant register. - unsigned int TCOR; - // Timer counter. - unsigned int TCNT; - - // Timer control register. - union - { - unsigned short WORD; - struct - { - unsigned :7; - // Underflow flag. - unsigned UNF :1; - unsigned :2; - // Underflow interrupt enable. - unsigned UNIE :1; - // Clock edge, reserved on SH7305. - unsigned CKEG :2; - // Timer prescaler. - unsigned TPSC :3; - }; - } TCR; -}; - - - -//--- -// Internal API. -//--- - -/* - timer_get() - - Returns the timer and TSTR register addresses. - - @arg timer Timer id. - @arg tmu mod_tmu structure pointer address. - @arg tstr mod_tstr structure pointer address. -*/ -static void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr) -{ - // Using SH7705 information for SH-3-based MPUs. - if(MPU_CURRENT == MPU_SH7337 || MPU_CURRENT == MPU_SH7355) - { - if(tstr) *tstr = (unsigned char *)0xfffffe92; - if(tmu) *tmu = (struct mod_tmu *)0xfffffe94; - } - // Assuming SH7305 by default. - else - { - if(tstr) *tstr = (unsigned char *)0xa4490004; - if(tmu) *tmu = (struct mod_tmu *)0xa4490008; - } - - // Shifting tmu value to get to the timer-nth timer in the unit. - if(tmu) *tmu += timer; -} - -/* - timer_interrupt() - Handles the interrupt for the given timer. - - @timer Timer that generated the interrupt. -*/ -void timer_interrupt(int timer) -{ - // Getting the timer address. - struct mod_tmu *tmu; - timer_get(timer, &tmu, NULL); - - // Resetting the interrupt flag. - (*tmu).TCR.UNF = 0; - - // Calling the callback function. - if(timers[timer].callback) timers[timer].callback(); - - // Reducing the number of repetitions left, if not infinite. - if(!timers[timer].repetitions) return; - // And stopping it if necessary. - if(timers[timer].repetitions == 1) timer_stop(timer); - else timers[timer].repetitions--; -} - - - -//--- -// Public API. -//--- - -/* - timer_start() - Configures and starts a timer. - - @arg timer Timer identifier. - @arg delay Delay before expiration. - @arg prescaler Clock prescaler value. - @arg callback Callback function. - @arg repetitions Number of repetitions, 0 for infinite. -*/ -void timer_start(int timer, int delay, int prescaler, void (*callback)(void), - int repetitions) -{ - // Getting the timer address. Using a byte to alter TSTR. - struct mod_tmu *tmu; - unsigned char *tstr; - int byte = (1 << timer); - timer_get(timer, &tmu, &tstr); - - // Setting the constant register. - (*tmu).TCOR = delay; - // Loading the delay in the counter. - (*tmu).TCNT = delay; - - // Resetting underflow flag. - (*tmu).TCR.UNF = 0; - // Enabling interruptions on underflow. - (*tmu).TCR.UNIE = 1; - // Counting on rising edge. On SH7305 these two bits are reserved but - // writing 0 is ignored. - (*tmu).TCR.CKEG = 0; - // Setting the prescaler. - (*tmu).TCR.TPSC = prescaler; - - // Loading the structure information. - timers[timer].callback = callback; - timers[timer].repetitions = repetitions; - - // Starting the timer and returning. - *tstr |= byte; -} - -/* - timer_stop() - Stops the given timer. This function may be called even if the timer is - not running. - - @arg timer Timer to stop. -*/ -void timer_stop(int timer) -{ - // Getting TSTR address and the corresponding byte. - unsigned char *tstr; - int byte = (1 << timer); - timer_get(timer, NULL, &tstr); - - // Stopping the timer. - *tstr &= ~byte; -} - -/* - timer_reload() - Reloads the given timer with the given constant. Starts the timer if - it was stopped. - - @arg timer Timer identifier. - @arg new_delay -*/ -void timer_reload(int timer, int new_delay) -{ - struct mod_tmu *tmu; - unsigned char *tstr; - int byte = (1 << timer); - timer_get(timer, &tmu, &tstr); - - // Setting the constant and the delay. - (*tmu).TCOR = new_delay; - (*tmu).TCNT = new_delay; - - // Starting the timer. - *tstr |= byte; -} diff --git a/src/timer/timer_get.c b/src/timer/timer_get.c new file mode 100644 index 0000000..c3ab7f0 --- /dev/null +++ b/src/timer/timer_get.c @@ -0,0 +1,25 @@ +#include +#include + +/* + timer_get() + Returns the timer and TSTR register addresses. +*/ +void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr) +{ + // Using SH7705 information for SH-3-based MPUs. + if(isSH3()) + { + if(tstr) *tstr = (unsigned char *)0xfffffe92; + if(tmu) *tmu = (struct mod_tmu *)0xfffffe94; + } + // Assuming SH7305 by default. + else + { + if(tstr) *tstr = (unsigned char *)0xa4490004; + if(tmu) *tmu = (struct mod_tmu *)0xa4490008; + } + + // Shifting tmu value to get to the timer-nth timer in the unit. + if(tmu) *tmu += timer; +} diff --git a/src/timer/timer_internals.h b/src/timer/timer_internals.h new file mode 100644 index 0000000..4cc9e5d --- /dev/null +++ b/src/timer/timer_internals.h @@ -0,0 +1,54 @@ +#ifndef _TIMER_INTERNALS_H +#define _TIMER_INTERNALS_H + +/* + struct Timer + This structure holds information for a running timer. +*/ +struct Timer +{ + void (*callback)(void); + int repeats; +}; + +extern struct Timer timers[3]; + +/* + struct mod_tmu + This structure holds information about the timer unit (peripheral + module) registers. +*/ +struct mod_tmu +{ + // Timer constant register. + unsigned int TCOR; + // Timer counter. + unsigned int TCNT; + + // Timer control register. + union + { + unsigned short WORD; + struct + { + unsigned :7; + // Underflow flag. + unsigned UNF :1; + unsigned :2; + // Underflow interrupt enable. + unsigned UNIE :1; + // Clock edge, reserved on SH7305. + unsigned CKEG :2; + // Timer prescaler. + unsigned TPSC :3; + }; + } TCR; +}; + +/* + timer_get() + Returns the timer and TSTR register addresses. +*/ +void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr); + +#endif // _TIMER_INTERNALS_H diff --git a/src/timer/timer_interrupt.c b/src/timer/timer_interrupt.c new file mode 100644 index 0000000..182ea9c --- /dev/null +++ b/src/timer/timer_interrupt.c @@ -0,0 +1,27 @@ +#include +#include + +struct Timer timers[3] = { { NULL, 0 }, { NULL, 0 }, { NULL, 0 } }; + +/* + timer_interrupt() + Handles the interrupt for the given timer. +*/ +void timer_interrupt(int timer) +{ + // Getting the timer address. + struct mod_tmu *tmu; + timer_get(timer, &tmu, NULL); + + // Resetting the interrupt flag. + (*tmu).TCR.UNF = 0; + + // Calling the callback function. + if(timers[timer].callback) timers[timer].callback(); + + // Reducing the number of repetitions left, if not infinite. + if(!timers[timer].repeats) return; + // And stopping it if necessary. + if(timers[timer].repeats == 1) timer_stop(timer); + else timers[timer].repeats--; +} diff --git a/src/timer/timer_reload.c b/src/timer/timer_reload.c new file mode 100644 index 0000000..6d9112c --- /dev/null +++ b/src/timer/timer_reload.c @@ -0,0 +1,22 @@ +#include +#include + +/* + timer_reload() + Reloads the given timer with the given constant. Starts the timer if + it was stopped. +*/ +void timer_reload(int timer, int new_delay) +{ + struct mod_tmu *tmu; + unsigned char *tstr; + int byte = (1 << timer); + timer_get(timer, &tmu, &tstr); + + // Setting the constant and the delay. + (*tmu).TCOR = new_delay; + (*tmu).TCNT = new_delay; + + // Starting the timer. + *tstr |= byte; +} diff --git a/src/timer/timer_start.c b/src/timer/timer_start.c new file mode 100644 index 0000000..f753e5d --- /dev/null +++ b/src/timer/timer_start.c @@ -0,0 +1,38 @@ +#include +#include + +/* + timer_start() + Configures and starts a timer. +*/ +void timer_start(int timer, int delay, int prescaler, void (*callback)(void), + int repeats) +{ + // Getting the timer address. Using a byte to alter TSTR. + struct mod_tmu *tmu; + unsigned char *tstr; + int byte = (1 << timer); + timer_get(timer, &tmu, &tstr); + + // Setting the constant register. + (*tmu).TCOR = delay; + // Loading the delay in the counter. + (*tmu).TCNT = delay; + + // Resetting underflow flag. + (*tmu).TCR.UNF = 0; + // Enabling interruptions on underflow. + (*tmu).TCR.UNIE = 1; + // Counting on rising edge. On SH7305 these two bits are reserved but + // writing 0 is ignored. + (*tmu).TCR.CKEG = 0; + // Setting the prescaler. + (*tmu).TCR.TPSC = prescaler; + + // Loading the structure information. + timers[timer].callback = callback; + timers[timer].repeats = repeats; + + // Starting the timer and returning. + *tstr |= byte; +} diff --git a/src/timer/timer_stop.c b/src/timer/timer_stop.c new file mode 100644 index 0000000..ab58f1e --- /dev/null +++ b/src/timer/timer_stop.c @@ -0,0 +1,18 @@ +#include +#include + +/* + timer_stop() + Stops the given timer. This function may be called even if the timer is + not running. +*/ +void timer_stop(int timer) +{ + // Getting TSTR address and the corresponding byte. + unsigned char *tstr; + int byte = (1 << timer); + timer_get(timer, NULL, &tstr); + + // Stopping the timer. + *tstr &= ~byte; +} diff --git a/syscall_0x24a.txt b/syscall_0x24a.txt deleted file mode 100644 index a85e926..0000000 --- a/syscall_0x24a.txt +++ /dev/null @@ -1,190 +0,0 @@ - ------------------------------------ -Syscall information ------------------------------------ - - Syscall id: 0x24a - Syscall address: 0x8003fc48 - - r4 {short *matrixcode} - - Syscall 0x24a redirects to 8003 f9d6. - - - ------------------------------------ -Stack ------------------------------------ - - ------ Pointer sent at <3f9fe> (also as first parameter) and <3fa12> - (12) Data from a44b 0000 - ------ Pointer sent at <3f9de> - (4) {short *matrixcode} at <3f9fe> - pr - r14 - ------ Bottom - - - ------------------------------------ -Syscall code ------------------------------------ - -# Saves some data. - 3f9d6: 2fe6 mov.l r14, @-r15 - 3f9d8: 4f22 sts.l pr, @-r15 - 3f9da: 7ff0 add #-16, r15 - -# First subroutine call: disables keyboard interrupts. -# Also pushes {short *matrixcode} on the stack. - 3f9dc: d128 mov.l #0x8003e264, r1 - 3f9de: 410b jsr @r1 - 3f9e0: 1f43 mov.l r4, @(12, r15) - -# Loads KEYSC data to the stack. -# Second subroutine call, with parameters : stack top and {short *matrixcode}. -# Checks whether the key given in the matrixcode was pressed. - 3f9e2: d528 mov.l #0xa44b0000, r5 - 3f9e4: 6451 mov.w @r5, r4 - 3f9e6: 2f41 mov.w r4, @r15 - 3f9e8: 64f3 mov r15, r4 - 3f9ea: 8551 mov.w @(2, r5), r0 - 3f9ec: 81f1 mov.w r0, @(2, r15) - 3f9ee: 8552 mov.w @(4, r5), r0 - 3f9f0: 81f2 mov.w r0, @(4, r15) - 3f9f2: 8553 mov.w @(6, r5), r0 - 3f9f4: 81f3 mov.w r0, @(6, r15) - 3f9f6: 8554 mov.w @(8, r5), r0 - 3f9f8: 81f4 mov.w r0, @(8, r15) - 3f9fa: 8555 mov.w @(10, r5), r0 - 3f9fc: 81f5 mov.w r0, @(10, r15) - 3f9fe: bd30 bsr <3f462> - 3fa00: 55f3 mov.l @(12, r15), r5 - -# Loads IPRF address to r6, sets the keyboard interrupt priority to 13 and -# performs a third subroutine call : enables keyboard interrupts (curiously -# the interrupt priority is set two times). -# Also saves the last subroutine result (key pressed) to r14. - 3fa02: d621 mov.l <3fa88>(#0xa4080014), r6 - 3fa04: 9113 mov.w <3fa2e>(#0x0fff), r1 - 3fa06: 9213 mov.w <3fa30>(#0xd000), r2 - 3fa08: 6e03 mov r0, r14 - 3fa0a: 6761 mov.w @r6, r7 - 3fa0c: 2719 and r1, r7 - 3fa0e: 272b or r2, r7 - 3fa10: d212 mov.l #0x8003e26c, r2 - 3fa12: 420b jsr @r2 - 3fa14: 2671 mov.w r7, @r6 - -# Restores the 'key pressed' result to r0, restores saved data and returns. - 3fa16: 60e3 mov r14, r0 - 3fa18: 7f10 add #16, r15 - 3fa1a: 4f26 lds.l @r15+, pr - 3fa1c: 000b rts - 3fa1e: 6ef6 mov.l @r15+, r14 - - - ------------------------------------ -Subroutine call at <3f9de> -- Denies keyboard interrupt in IMR5. -- Disables keyboard interrupt in IPRF. ------------------------------------ - - Call redirects to 8003 e278. - -# Loads IMR5 address to r4. - 3e278: d478 mov.l <3e45c>(#0xa4080094), r4 - 3e27a: e180 mov #-128, r1 - 3e27c: 955b mov.w <3e336>(#0x0fff), r5 -# Writes 0x80 to IMR5. - 3e27e: 2410 mov.b r1, @r4 - -# Loads IPRF address to r4. - 3e280: 7480 add #-128, r4 -# Sets the four upper bits of IPRF to 0. - 3e282: 6241 mov.w @r4, r2 - 3e284: 2259 and r5, r2 - 3e286: 000b rts - 3e288: 2421 mov.w r2, @r4 - - - ------------------------------------ -Subroutine call at <3f9fe> -- Detects whether a specific key is pressed using the KEYSC data loaded onto - the stack. -- Returns 1 if the key is pressed, 0 otherwise. ------------------------------------ - -Stack: - r4 (bottom stack address) - {short *matrixcode} - ------ Bottom stack address. - -# Pushes {short *matrixcode} on the stack and on top, pushes r4. -# Loads the key column to r2 and replaces r5 by #1 (r5 will then be shifted to -# be used as a mask in a KEYSC word). - 3f462: 7ff8 add #-8, r15 - 3f464: 1f51 mov.l r5, @(4, r15) - 3f466: 6250 mov.b @r5, r2 - 3f468: e501 mov #1, r5 - 3f46a: 51f1 mov.l @(4, r15), r1 - 3f46c: 622c extu.b r2, r2 - 3f46e: 2f42 mov.l r4, @r15 - -# Loads the key row to r0. - 3f470: 8411 mov.b @(1, r1), r0 - 3f472: 600c extu.b r0, r0 -# Shifts it right within r6 and tests the row's lower bit. - 3f474: 6603 mov r0, r6 - 3f476: 4621 shar r6 - 3f478: c801 tst #1, r0 - -# Shift r5 by its column number. -# If the row's lower bit was 1, then also shift r5 by 8 (because there are two -# rows for each word). - 3f47a: 8d01 bt/s <3f480> - 3f47c: 452d shld r2, r5 - 3f47e: 4518 shll8 r5 - -# Loads the bottom stack address to r1. - 3f480: 61f2 mov.l @r15, r1 -# Erases the even/odd bit of the row in r6 (because the KEYSC data is read in -# words so we don't want to get on a byte offset, and the lower bit has -# already been handled when shifting r5). - 3f482: 4600 shll r6 - -# Loads the final mask into r2. - 3f484: 625d extu.w r5, r2 - 3f486: 6063 mov r6, r0 -# Tests whether the key represented by the parameter matrixcode is pressed. - 3f488: 041d mov.w @(r0, r1), r4 - 3f48a: 2428 tst r2, r4 -# Returns the KEYSC bit, that is 1 if the key was pressed, 0 otherwise. - 3f48c: 0029 movt r0 - 3f48e: ca01 xor #1, r0 - 3f490: 000b rts - 3f492: 7f08 add #8, r15 - - - ------------------------------------ -Subroutine call at <3fa12> -- Sets the keyboard interrupt priority to 13. -- Clears the keyboard interrupt mask. ------------------------------------ - - Calls redirects to 8003 e28a. - - 3e28a: d475 mov.l #0xa4080014, r4 - 3e28c: 9753 mov.w #0x0fff, r7 - 3e28e: 9253 mov.w #0xd000, r2 - 3e290: e580 mov #-128, r5 - 3e292: 6141 mov.w @r4, r1 - 3e294: 2179 and r7, r1 - 3e296: 212b or r2, r1 - 3e298: 2411 mov.w r1, @r4 - 3e29a: d472 mov.l <3e464>(#0xa40800d4), r4 - 3e29c: 000b rts - 3e29e: 2450 mov.b r5, @r4 diff --git a/syscall_0x24a_7705.txt b/syscall_0x24a_7705.txt deleted file mode 100644 index e1edb3b..0000000 --- a/syscall_0x24a_7705.txt +++ /dev/null @@ -1,558 +0,0 @@ - ------------------------------------ -Syscall information ------------------------------------ - - Syscall id: 0x24a - Syscall address: 0x8003fa28 - - r4 {short *matrixcode} - - - ------------------------------------ -Stack ------------------------------------ - - #1 - pr - r8 - r9 - r10 - r11 - r12 - r13 - r14 - ------ Bottom - - - ------------------------------------ -Variables ------------------------------------ - - r14 Current row - r13 - r12 - r11 Delay routine address - r10 1 << r14 ? Could be the data register mask. - r9 Current column. - r8 {short *matrixcode} - - - ------------------------------------ -Syscall code ------------------------------------ - -# Saves r8-r14 to the stack. Loads data: -# r13 = 8, r12 = 1, r11 = 8003 e47a, r10 = 1, r9 = 0, r8 = {short *matrixcode}. - 3fa28: 2fe6 mov.l r14, @-r15 - 3fa2a: 2fd6 mov.l r13, @-r15 - 3fa2c: 2fc6 mov.l r12, @-r15 - 3fa2e: ed08 mov #8, r13 - 3fa30: 2fb6 mov.l r11, @-r15 - 3fa32: ec01 mov #1, r12 - 3fa34: 2fa6 mov.l r10, @-r15 - 3fa36: 6ac3 mov r12, r10 - 3fa38: 2f96 mov.l r9, @-r15 - 3fa3a: e900 mov #0, r9 - 3fa3c: db22 mov.l #0x8003e47a, r11 - 3fa3e: 2f86 mov.l r8, @-r15 - 3fa40: 4f22 sts.l pr, @-r15 - 3fa42: 6843 mov r4, r8 - -# r14 = 0, pushes #1 on the stack and branches to <3fb1a>. This branch does -# nothing if r14 is lower than 12 (thus here it does nothing). - 3fa44: 7ffc add #-4, r15 - 3fa46: 2fc2 mov.l r12, @r15 - 3fa48: a067 bra <3fb1a> - 3fa4a: 6e93 mov r9, r14 - -# Sets gbr = a400 0100: area where the port control registers are located. - 3fa4c: d21f mov.l #0xa4000100, r2 - 3fa4e: 421e ldc r2, gbr - -# B_CTRL = h'aaaa - 3fa50: d01f mov.l #0x0000aaaa, r0 - 3fa52: c101 mov.w r0, @(2, gbr) - -# M_CTRL = h'__55 - 3fa54: c50c mov.w @(24, gbr), r0 - 3fa56: d31f mov.l #0x0000ff00, r3 - 3fa58: 2039 and r3, r0 - 3fa5a: cbaa or #0x55, r0 - 3fa5c: c10c mov.w r0, @(24, gbr) - -# Delay. - 3fa5e: 4b0b jsr @r11 - 3fa60: e402 mov #2, r4 - -# Loads 801b e65c as a data segment base. It contains words in this order: -# aaa9 aaa6 aa9a aa6a ... 9aaa 6aaa 00a9 00a6 009a 006a. -# These words are the B_CTRL/M_CTRL values. -# Loads the r14-th word into B_CTRL (r14 <= 8) or the lowest byte of M_CTRL -# (r14 > 8). The row-to-check pin is configured as output, and all the others -# are configured as inputs. - 3fa62: 3ed3 cmp/ge r13, r14 - 3fa64: d41c mov.l #0x801be65c, r4 - 3fa66: 8904 bt <3fa72> - 3fa68: 60e3 mov r14, r0 - 3fa6a: 4000 shll r0 - 3fa6c: 004d mov.w @(r0, r4), r0 - 3fa6e: a009 bra <3fa84> - 3fa70: c101 mov.w r0, @(2, gbr) - 3fa72: 60e3 mov r14, r0 - 3fa74: 4000 shll r0 - 3fa76: 004d mov.w @(r0, r4), r0 - 3fa78: 6203 mov r0, r2 - 3fa7a: c50c mov.w @(24, gbr), r0 - 3fa7c: d315 mov.l #0x0000ff00, r3 - 3fa7e: 2039 and r3, r0 - 3fa80: 202b or r2, r0 - 3fa82: c10c mov.w r0, @(24, gbr) - -# Delay. - 3fa84: 4b0b jsr @r11 - 3fa86: e402 mov #2, r4 - -# Loads the port data registers section into gbr. - 3fa88: d314 mov.l #0xa4000120, r3 - 3fa8a: 431e ldc r3, gbr - 3fa8c: 3ed3 cmp/ge r13, r14 - 3fa8e: 8d27 bt/s <3fae0> - -# When the row-to-check is lower than or equal to 8. -# Writes ~r10 to B_DATA. Sets M_DATA to 0x-f. - 3fa90: 64a7 not r10, r4 - 3fa92: 6043 mov r4, r0 - 3fa94: c002 mov.b r0, @(2, gbr) - 3fa96: c418 mov.b @(24, gbr), r0 - 3fa98: c9f0 and #0xf0, r0 - 3fa9a: a026 bra <3faea> - 3fa9c: cb0f or #15, r0 - - 3fa9e: 0000 .word 0x0000 - 3faa0: 801b mov.b r0, @(11, r1) - 3faa2: e6dc mov #-36, r6 - 3faa4: 8006 mov.b r0, @(6, r0) - 3faa6: 9088 mov.w <3fbba>(#0xc10c), r0 - 3faa8: 8002 mov.b r0, @(2, r0) - 3faaa: 4e4e ldc r14, spc - 3faac: 8800 cmp/eq #0, r0 - 3faae: 77ed add #-19, r7 - 3fab0: 8003 mov.b r0, @(3, r0) - 3fab2: d446 mov.l <3fbcc>(#0x004da007), r4 - 3fab4: 8003 mov.b r0, @(3, r0) - 3fab6: da54 mov.l <3fc08>(#0x0000aaaa), r10 - 3fab8: 8003 mov.b r0, @(3, r0) - 3faba: de9c mov.l <3fd2c>(#0xee00eb0a), r14 - 3fabc: 8006 mov.b r0, @(6, r0) - 3fabe: 90d8 mov.w <3fc72>(#0x421e), r0 - 3fac0: 8006 mov.b r0, @(6, r0) - 3fac2: 2ed8 tst r13, r14 - 3fac4: 8800 cmp/eq #0, r0 - 3fac6: 7054 add #84, r0 - -# Data segment. - 3fac8: 8003 e47a - 3facc: a400 0100 - 3fad0: 0000 aaaa - 3fad4: 0000 ff00 - 3fad8: 801b e65c - 3fadc: a400 0120 - -# When the row-to-check is strictly greater than 8. -# Writes 0xff to B_DATA, and ~r10 to M_DATA. - 3fae0: 908e mov.w <3fc00>(#0x00ff), r0 - 3fae2: c002 mov.b r0, @(2, gbr) - 3fae4: c418 mov.b @(24, gbr), r0 - 3fae6: c9f0 and #0xf0, r0 - 3fae8: 204b or r4, r0 - -# Delay. - 3faea: c018 mov.b r0, @(24, gbr) - 3faec: 4b0b jsr @r11 - 3faee: e402 mov #2, r4 - -# Loads result in r5, as ~A_DATA. - 3faf0: c400 mov.b @(0, gbr), r0 - 3faf2: 6507 not r0, r5 - -# r9 = 0 the first time. Compares r12 with the result. If none of the bits of -# r12 are set in checked row, branches to <3fb04>. - 3faf4: 6493 mov r9, r4 - 3faf6: 635c extu.b r5, r3 - 3faf8: 23c8 tst r12, r3 - 3fafa: 8903 bt <3fb04> - -# r9 seems to be the key column and r14 the row. - 3fafc: 2840 mov.b r4, @r8 - 3fafe: 60e3 mov r14, r0 - 3fb00: a00f bra <3fb22> - 3fb02: 8081 mov.b r0, @(1, r8) - - 3fb04: 655c extu.b r5, r5 - 3fb06: 4501 shlr r5 - 3fb08: 7401 add #1, r4 - 3fb0a: 34d3 cmp/ge r13, r4 - 3fb0c: 8bf3 bf <3faf6> - 3fb0e: 4a00 shll r10 - 3fb10: 60e3 mov r14, r0 - 3fb12: 8807 cmp/eq #7, r0 - 3fb14: 8f01 bf/s <3fb1a> - 3fb16: 7e01 add #1, r14 - 3fb18: 6ac3 mov r12, r10 - 3fb1a: e30c mov #12, r3 - 3fb1c: 3e33 cmp/ge r3, r14 - 3fb1e: 8b95 bf <3fa4c> - 3fb20: 2f92 mov.l r9, @r15 - -# Ends the procedure and restores everything ? - -# B_CTRL = 0xaaaa. M_CTRL = 0x--aa. Delay. - 3fb22: d338 mov.l <3fc04>(#0xa4000100), r3 - 3fb24: d038 mov.l <3fc08>(#0x0000aaaa), r0 - 3fb26: 431e ldc r3, gbr - 3fb28: c101 mov.w r0, @(2, gbr) - 3fb2a: c50c mov.w @(24, gbr), r0 - 3fb2c: d237 mov.l <3fc0c>(#0x0000ff00), r2 - 3fb2e: 2029 and r2, r0 - 3fb30: cbaa or #0xaa, r0 - 3fb32: c10c mov.w r0, @(24, gbr) - 3fb34: 4b0b jsr @r11 - 3fb36: e402 mov #2, r4 - -# B_CTRL = 0x5555. M_CTRL = 0x--55. Delay. - 3fb38: 9063 mov.w <3fc02>(#0x5555), r0 - 3fb3a: c101 mov.w r0, @(2, gbr) - 3fb3c: c50c mov.w @(24, gbr), r0 - 3fb3e: d333 mov.l <3fc0c>(#0x0000ff00), r3 - 3fb40: 2039 and r3, r0 - 3fb42: cb55 or #0x55, r0 - 3fb44: c10c mov.w r0, @(24, gbr) - 3fb46: 4b0b jsr @r11 - 3fb48: e402 mov #2, r4 - -# B_DATA = 0x00. M_DATA = 0x-0. - 3fb4a: e000 mov #0, r0 - 3fb4c: d230 mov.l <3fc10>(#0xa4000120), r2 - 3fb4e: 421e ldc r2, gbr - 3fb50: c002 mov.b r0, @(2, gbr) - 3fb52: c418 mov.b @(24, gbr), r0 - 3fb54: c9f0 and #0xf0, r0 - 3fb56: c018 mov.b r0, @(24, gbr) - -# Returns the value at the top of the stack (originally 1). - 3fb58: 60f2 mov.l @r15, r0 - 3fb5a: 7f04 add #4, r15 - 3fb5c: 4f26 lds.l @r15+, pr - 3fb5e: 68f6 mov.l @r15+, r8 - 3fb60: 69f6 mov.l @r15+, r9 - 3fb62: 6af6 mov.l @r15+, r10 - 3fb64: 6bf6 mov.l @r15+, r11 - 3fb66: 6cf6 mov.l @r15+, r12 - 3fb68: 6df6 mov.l @r15+, r13 - 3fb6a: 000b rts - 3fb6c: 6ef6 mov.l @r15+, r14 - - - ------------------------------------ -First subroutine ------------------------------------ - -# Go back to <3fa4c> (first call to this subroutine) until r14 reaches 12. - 3fb1a: e30c mov #12, r3 - 3fb1c: 3e33 cmp/ge r3, r14 - 3fb1e: 8b95 bf <3fa4c> - - 3fb20: 2f92 mov.l r9, @r15 - 3fb22: d338 mov.l <3fc04>(#0xa4000100), r3 - 3fb24: d038 mov.l <3fc08>(#0x0000aaaa), r0 - 3fb26: 431e ldc r3, gbr - 3fb28: c101 mov.w r0, @(2, gbr) - 3fb2a: c50c mov.w @(24, gbr), r0 - 3fb2c: d237 mov.l <3fc0c>(#0x0000ff00), r2 - 3fb2e: 2029 and r2, r0 - 3fb30: cbaa or #-86, r0 - 3fb32: c10c mov.w r0, @(24, gbr) - 3fb34: 4b0b jsr @r11 - 3fb36: e402 mov #2, r4 - 3fb38: 9063 mov.w <3fc02>(#0x5555), r0 - 3fb3a: c101 mov.w r0, @(2, gbr) - 3fb3c: c50c mov.w @(24, gbr), r0 - 3fb3e: d333 mov.l <3fc0c>(#0x0000ff00), r3 - 3fb40: 2039 and r3, r0 - 3fb42: cb55 or #85, r0 - 3fb44: c10c mov.w r0, @(24, gbr) - 3fb46: 4b0b jsr @r11 - 3fb48: e402 mov #2, r4 - 3fb4a: e000 mov #0, r0 - 3fb4c: d230 mov.l <3fc10>(#0xa4000120), r2 - 3fb4e: 421e ldc r2, gbr - 3fb50: c002 mov.b r0, @(2, gbr) - 3fb52: c418 mov.b @(24, gbr), r0 - 3fb54: c9f0 and #-16, r0 - 3fb56: c018 mov.b r0, @(24, gbr) - 3fb58: 60f2 mov.l @r15, r0 - 3fb5a: 7f04 add #4, r15 - 3fb5c: 4f26 lds.l @r15+, pr - 3fb5e: 68f6 mov.l @r15+, r8 - 3fb60: 69f6 mov.l @r15+, r9 - 3fb62: 6af6 mov.l @r15+, r10 - 3fb64: 6bf6 mov.l @r15+, r11 - 3fb66: 6cf6 mov.l @r15+, r12 - 3fb68: 6df6 mov.l @r15+, r13 - 3fb6a: 000b rts - 3fb6c: 6ef6 mov.l @r15+, r14 - - - ------------------------------------ -Second subroutine -Just a delay ! If also configures IRQ0. ------------------------------------ - -Stack: - gbr - macl - pr - r14 - ------ Bottom - -# Saves r14, pr, macl and gbr to the stack. Saves parameter (r4 = 2) to r14. -# Loads data: r2 = 8006 31dc, r5 = 1 (parameter 'set' for syscall 0x3ed). - 3e47a: 0312 stc gbr, r3 - 3e47c: d235 mov.l <3e554>(#0x800631dc), r2 - 3e47e: e501 mov #1, r5 - 3e480: 2fe6 mov.l r14, @-r15 - 3e482: 6e43 mov r4, r14 - 3e484: 4f22 sts.l pr, @-r15 - 3e486: 4f12 sts.l macl, @-r15 - 3e488: 7ffc add #-4, r15 - 3e48a: 2f32 mov.l r3, @r15 - -# Sets the "watchdog occupied" status in the RAM interrupt status byte. - 3e48c: 420b jsr @r2 - 3e48e: e410 mov #16, r4 - -# Ensures 1 <= r14 <= 40 by setting r14 = 1 or 40 if needed. -# Here r14 is always 2. - 3e490: 4e15 cmp/pl r14 - 3e492: 8d01 bt/s <3e498> - 3e494: e428 mov #40, r4 - 3e496: ee01 mov #1, r14 - 3e498: 3e47 cmp/gt r4, r14 - 3e49a: 8b00 bf <3e49e> - 3e49c: 6e43 mov r4, r14 - -# r4 = ~((r14 * 92) >> 4) on a single byte, which is 244 when r14 = 2. -# 256 - r4 will be used as a delay for the watchdog timer. -# Sets gbr to 0xfffffee0 and disables the watchdog interrupt. - 3e49e: e45c mov #92, r4 - 3e4a0: 924b mov.w <3e53a>(#0xfee0), r2 - 3e4a2: e3fc mov #-4, r3 - 3e4a4: 0e47 mul.l r4, r14 - 3e4a6: 421e ldc r2, gbr - 3e4a8: 041a sts macl, r4 - 3e4aa: 443c shad r3, r4 - 3e4ac: 6447 not r4, r4 - 3e4ae: 644c extu.b r4, r4 - 3e4b0: c502 mov.w @(4, gbr), r0 - 3e4b2: 9343 mov.w <3e53c>(#0x0fff), r3 - 3e4b4: 2039 and r3, r0 - 3e4b6: c102 mov.w r0, @(4, gbr) - -# Loads the watchdog module base address into gbr. Resets everything in the -# watchdog configuration. Then loads r4 (here 244) to the counter, sets the -# frequency at Po/256, starts the timer and waits until it overflows. -# This is probably just a way of delaying port usage. - 3e4b8: d027 mov.l <3e558>(#0x0000a500), r0 - 3e4ba: e180 mov #-128, r1 - 3e4bc: 411e ldc r1, gbr - 3e4be: c103 mov.w r0, @(6, gbr) - 3e4c0: 903d mov.w <3e53e>(#0x5a00), r0 - 3e4c2: 204b or r4, r0 - 3e4c4: c102 mov.w r0, @(4, gbr) - 3e4c6: d025 mov.l <3e55c>(#0x0000a505), r0 - 3e4c8: c103 mov.w r0, @(6, gbr) - 3e4ca: d025 mov.l <3e560>(#0x0000a585), r0 - 3e4cc: c103 mov.w r0, @(6, gbr) - 3e4ce: e408 mov #8, r4 - 3e4d0: c406 mov.b @(6, gbr), r0 - 3e4d2: 600c extu.b r0, r0 - 3e4d4: 2048 tst r4, r0 - 3e4d6: 89fb bt <3e4d0> - -# Resets the overflow flag, then resets the whole configuration. - 3e4d8: c406 mov.b @(6, gbr), r0 - 3e4da: 600c extu.b r0, r0 - 3e4dc: d31e mov.l <3e558>(#0x0000a500), r3 - 3e4de: c9f7 and #0xf7, r0 - 3e4e0: 203b or r3, r0 - 3e4e2: c103 mov.w r0, @(6, gbr) - 3e4e4: 6033 mov r3, r0 - 3e4e6: c103 mov.w r0, @(6, gbr) - -# Resets the counter. - 3e4e8: 9029 mov.w <3e53e>(#0x5a00), r0 - 3e4ea: c102 mov.w r0, @(4, gbr) - -# Unsets the "watchdog occupied" bit in the RAM interrupt status byte. - 3e4ec: d219 mov.l <3e554>(#0x800631dc), r2 - 3e4ee: e500 mov #0, r5 - 3e4f0: 420b jsr @r2 - 3e4f2: e410 mov #16, r4 - -# Configures IRQ0 if possible (that is, if both the watchdog and the SD card -# are idle). - 3e4f4: d31b mov.l <3e564>(#0x8003dbec), r3 - 3e4f6: 430b jsr @r3 - 3e4f8: 0009 nop - -# Un-stacks everything and returns. - 3e4fa: 62f2 mov.l @r15, r2 - 3e4fc: 421e ldc r2, gbr - 3e4fe: 7f04 add #4, r15 - 3e500: 4f16 lds.l @r15+, macl - 3e502: 4f26 lds.l @r15+, pr - 3e504: 000b rts - 3e506: 6ef6 mov.l @r15+, r14 - - - ------------------------------------ -Third subroutine ------------------------------------ - -# Erases the lowest bit in an unknown byte (probably an extension of the -# interrupt status byte). Returns if this bit was 0. - 3dbec: 4f22 sts.l pr, @-r15 - 3dbee: e501 mov #1, r5 - 3dbf0: d349 mov.l <3dd18>(#0x80063236), r3 - 3dbf2: 430b jsr @r3 - 3dbf4: 6453 mov r5, r4 - 3dbf6: 8801 cmp/eq #1, r0 - 3dbf8: 8b07 bf <3dc0a> - -# Checks if the watchdog timer is occupied, or if the SD-card is busy (?). -# If any of them is in use, aborts. Otherwise controls is transferred to the -# extract below, as if called directly. -# Probably the SD-card has something to do with generating IRQ0 interrupts. - 3dbfa: e500 mov #0, r5 - 3dbfc: d347 mov.l <3dd1c>(#0x800631f6), r3 - 3dbfe: 430b jsr @r3 - 3dc00: e418 mov #24, r4 - 3dc02: 2008 tst r0, r0 - 3dc04: 8b01 bf <3dc0a> - 3dc06: af82 bra <3db0e> - 3dc08: 4f26 lds.l @r15+, pr - -# Returns. - 3dc0a: 4f26 lds.l @r15+, pr - 3dc0c: 000b rts - 3dc0e: 0009 nop - - Here's the extract of code that takes control when the interrupt conditions - required by the main procedure are fulfilled. - It configures IRQ0 interrupts. - -# Disables IRQ0 interrupt in IPRC. - 3db0e: d32d mov.l <3dbc4>(#0xa4000000), r3 - 3db10: 431e ldc r3, gbr - 3db12: c50b mov.w @(22, gbr), r0 - 3db14: d22e mov.l <3dbd0>(#0x0000fff0), r2 - 3db16: 2029 and r2, r0 - 3db18: c10b mov.w r0, @(22, gbr) - -# Sets PTH0 to 'other functions' mode, which is IRQ0 and IRL0 input for the -# interrupt controller. - 3db1a: d12e mov.l <3dbd4>(#0xa4000100), r1 - 3db1c: 411e ldc r1, gbr - 3db1e: c507 mov.w @(14, gbr), r0 - 3db20: d32d mov.l <3dbd8>(#0x0000fffc), r3 - 3db22: 2039 and r3, r0 - 3db24: c107 mov.w r0, @(14, gbr) - -# Sets IRQ0 detection mode to low level input in ICR1. - 3db26: d227 mov.l <3dbc4>(#0xa4000000), r2 - 3db28: 421e ldc r2, gbr - 3db2a: c508 mov.w @(16, gbr), r0 - 3db2c: 2039 and r3, r0 - 3db2e: cb02 or #2, r0 - 3db30: c108 mov.w r0, @(16, gbr) - -# Clears the IRQ0 interrupt flag. - 3db32: c404 mov.b @(4, gbr), r0 - 3db34: c9fe and #-2, r0 - 3db36: c004 mov.b r0, @(4, gbr) - -# Enables IRQ0 interrupts with priority 13 in IPRC. - 3db38: c50b mov.w @(22, gbr), r0 - 3db3a: d125 mov.l <3dbd0>(#0x0000fff0), r1 - 3db3c: 2019 and r1, r0 - 3db3e: cb0d or #13, r0 - 3db40: c10b mov.w r0, @(22, gbr) - -# Returns 1. - 3db42: 000b rts - 3db44: e001 mov #1, r0 - - Here is the first subroutine, that handles an unknown byte at 0x8800713d. - This byte may be an extension of the interrupt status byte. - - Returns 1 if a bit in the unknown byte matches the mask r4. - Also, if r5 = 1, erases the bits according to the mask. - -# Sets r6 to 1 if a bit in the mask is set in the unknown byte, 0 otherwise. -# Also sets r0 = r5. - 63236: 624c extu.b r4, r2 - 63238: d72a mov.l <632e4>(#0x8800713d), r7 - 6323a: 6370 mov.b @r7, r3 - 6323c: 633c extu.b r3, r3 - 6323e: 2328 tst r2, r3 - 63240: 8f02 bf/s <63248> - 63242: 6053 mov r5, r0 - 63244: a001 bra <6324a> - 63246: e600 mov #0, r6 - 63248: e601 mov #1, r6 - -# Uses the mask comparison result as return value. If the operation is 0, then -# stop there. - 6324a: 8801 cmp/eq #1, r0 - 6324c: 8f04 bf/s <63258> - 6324e: 6063 mov r6, r0 - -# Otherwise, erase the mask in the unknown byte. - 63250: 6370 mov.b @r7, r3 - 63252: 6447 not r4, r4 - 63254: 2349 and r4, r3 - 63256: 2730 mov.b r3, @r7 - 63258: 000b rts - 6325a: 0009 nop - - Here is the second subroutine. - It does exactly the same as the first, except that it uses the common - interrupt status byte at 0x8800713c. - It's the syscall 0x3ee. - - 631f6: 624c extu.b r4, r2 - 631f8: d739 mov.l <632e0>(#0x8800713c), r7 - 631fa: 6370 mov.b @r7, r3 - 631fc: 633c extu.b r3, r3 - 631fe: 2328 tst r2, r3 - 63200: 8f02 bf/s <63208> - 63202: 6053 mov r5, r0 - 63204: a001 bra <6320a> - 63206: e600 mov #0, r6 - 63208: e601 mov #1, r6 - 6320a: 8801 cmp/eq #1, r0 - 6320c: 8f04 bf/s <63218> - 6320e: 6063 mov r6, r0 - 63210: 6370 mov.b @r7, r3 - 63212: 6447 not r4, r4 - 63214: 2349 and r4, r3 - 63216: 2730 mov.b r3, @r7 - 63218: 000b rts - 6321a: 0009 nop diff --git a/syscall_0x24b.txt b/syscall_0x24b.txt deleted file mode 100644 index 035600b..0000000 --- a/syscall_0x24b.txt +++ /dev/null @@ -1,91 +0,0 @@ -fxos lephe$ fxos disasm -s 0x24b sh7305.fls -l 200 -Syscall table: 0x801cdd84 -Syscall id: 0x24b -Syscall address: 0x4cfc0380 - -=================================== - -Stack state: -r4 s1: Parameter of call located at -pr -r14 -r13 ------- Bottom - -=================================== - -Missing information: - -- Function of (negative offset relative to ) -- Function of (negative offset relative to <3e>, does not seem to be - the same as , curiously) -- Function of <8003e8c8> (probably syscall, but not found) - -=================================== - -# -# Initialization. -# - -# Saves the registers. - 0: 2fd6 mov.l r13, @-r15 - 2: 2fe6 mov.l r14, @-r15 - 4: 4f22 sts.l pr, @-r15 - 6: 7ffc add #-4, r15 - 8: 2f42 mov.l r4, @r15 - -# Loads 1 into r13. If jump at <16> is performed, r13 is changed to 0. - a: ed01 mov #1, r13 -# r14 gets decremented whenever call at is looped (considering the -# documentation, it is probably the number of tries before the function -# gives up). - c: ee05 mov #5, r14 - - - -# -# Main loop, calls . No more than initial_r14 turns. -# - -# Calls (r4). - e: bf19 bsr - 10: 64f2 mov.l @r15, r4 - -# If result != 0, then <1a>, else <24>. - 12: 2008 tst r0, r0 - 14: 8b01 bf <1a> - 16: a005 bra <24> - 18: ed00 mov #0, r13 - - - -# -# When returns non-zero, calls <8003e8c8>, decrements r14 and -# loops. -# - -# Call returned non-zero (r13 = 1). -# Calls <8003e8c8>(10). - 1a: d22d mov.l (0x8003e8c8), r2 - 1c: 420b jsr @r2 - 1e: e40a mov #10, r4 -# Decrementing the number of tries before returning, and looping to if the -# number of tries has not been exceeded. - 20: 4e10 dt r14 - 22: 8bf4 bf - - - -# -# When returns zero or the number of tries has been exceeded, -# return from the function with the correct value. -# - -# Call returned zero (r13 = 0). Ends the function and returns 1 if -# the key is pressed, 0 otherwise. - 24: 60d3 mov r13, r0 - 26: 7f04 add #4, r15 - 28: 4f26 lds.l @r15+, pr - 2a: 6ef6 mov.l @r15+, r14 - 2c: 000b rts - 2e: 6df6 mov.l @r15+, r13