decompile libraries (#6)

This commit is contained in:
jiangzhengwenjz 2020-01-13 14:05:03 +08:00
parent cbd9351e32
commit cac5bd8be6
47 changed files with 17624 additions and 24743 deletions

2
.gitignore vendored
View File

@ -48,7 +48,7 @@ tools/agbcc
tools/binutils
types_*.taghl
*.zip
!.travis/calcrom/calcrom.pl
!calcrom.pl
!sound/programmable_wave_samples/*.pcm
_Deparsed_XSubs.pm
*.py

View File

@ -1,3 +1,5 @@
First, you must put a Kirby & the Amazing Mirror (U) ROM (with SHA1: `274b102b6d940f46861a92b4e65f89a51815c12c`) in the root directory of the repository and name it `baserom.gba`.
## Prerequisites
| Linux | macOS | Windows 10 (build 18917+) | Windows 10 (1709+) | Windows 8, 8.1, and 10 (1507, 1511, 1607, 1703)
@ -15,18 +17,24 @@ Make sure that the `build-essential`, `git`, and `libpng-dev` packages are insta
In the case of Cygwin, [include](https://cygwin.com/cygwin-ug-net/setup-net.html#setup-packages) the `make`, `git`, `gcc-core`, `gcc-g++`, and `libpng-devel` packages.
Install the **devkitARM** toolchain of [devkitPro](https://devkitpro.org/wiki/Getting_Started) and add its environment variables. For Windows versions without the Linux subsystem, the devkitPro [graphical installer](https://github.com/devkitPro/installer/releases) includes a preconfigured MSYS2 environment, thus the steps below are not required.
sudo (dkp-)pacman -S gba-dev
export DEVKITPRO=/opt/devkitpro
echo "export DEVKITPRO=$DEVKITPRO" >> ~/.bashrc
export DEVKITARM=$DEVKITPRO/devkitARM
echo "export DEVKITARM=$DEVKITARM" >> ~/.bashrc
## Installation
To set up the repository:
git clone https://github.com/jiangzhengwenjz/kirbyamazingmirror
git clone https://github.com/luckytyphlosion/agbcc -b new_layout_with_libs
git clone https://github.com/jiangzhengwenjz/agbcc -b new_newlib_pret
cd ./agbcc
make
make install prefix=../kirbyamazingmirror
make install-sdk prefix=../kirbyamazingmirror
sh build.sh
sh install.sh ../kirbyamazingmirror
cd ../kirbyamazingmirror
@ -43,3 +51,15 @@ If only `.c` or `.s` files were changed, turn off the dependency scanning tempor
make -j$(nproc) NODEP=1
**Note:** If the build command is not recognized on Linux, including the Linux environment used within Windows, run `nproc` and replace `$(nproc)` with the returned value (e.g.: `make -j4`). Because `nproc` is not available on macOS, the alternative is `sysctl -n hw.ncpu`.
### Note for Mac users
The BSD make that comes with Mac XCode can be buggy, so obtain GNU make and sed using [Homebrew](https://brew.sh):
brew install make gnu-sed
When compiling agbcc, substitute the `build.sh` line for
gsed 's/^make/gmake/g' build.sh | sh
Finally, use `gmake` instead of `make` to compile the ROM(s).

View File

@ -1,9 +1,9 @@
include $(DEVKITARM)/base_tools
COMPARE ?= 0
AS := tools/binutils/bin/arm-none-eabi-as
CPP := $(CC) -E
LD := tools/binutils/bin/arm-none-eabi-ld
OBJCOPY := tools/binutils/bin/arm-none-eabi-objcopy
LD := $(DEVKITARM)/bin/arm-none-eabi-ld
GAME_VERSION := AMAZINGMIRROR
REVISION := 0
@ -48,7 +48,7 @@ CPPFLAGS := -I tools/agbcc -I tools/agbcc/include -iquote include -nostdinc -und
LDFLAGS = -Map ../../$(MAP)
LIB := #-L ../../tools/agbcc/lib -lgcc -lc
LIB := -L ../../tools/agbcc/lib -lgcc -lc
SHA1 := $(shell { command -v sha1sum || command -v shasum; } 2>/dev/null) -c
GFX := tools/gbagfx/gbagfx
@ -157,6 +157,12 @@ sound/%.bin: sound/%.aif ; $(AIF) $< $@
sound/songs/%.s: sound/songs/%.mid
cd $(@D) && ../../$(MID) $(<F)
$(C_BUILDDIR)/m4a.o: CC1 := tools/agbcc/bin/old_agbcc
$(C_BUILDDIR)/powf_error_handler.o: CC1 := tools/agbcc/bin/old_agbcc
$(C_BUILDDIR)/powf_error_handler.o: override CFLAGS := -Wimplicit -Wparentheses -Werror -O2 -fhex-asm
$(C_BUILDDIR)/agb_sram.o: CFLAGS := -mthumb-interwork -Wimplicit -Wparentheses -Werror -O1
$(C_BUILDDIR)/agb_sram.o: CC1 := tools/agbcc/bin/old_agbcc
ifeq ($(NODEP),1)
$(C_BUILDDIR)/%.o: c_dep :=
else
@ -170,7 +176,7 @@ endif
$(C_BUILDDIR)/%.o : $(C_SUBDIR)/%.c $$(c_dep)
@$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i
@$(PREPROC) $(C_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(C_BUILDDIR)/$*.s
@echo -e "\t.text\n\t.align\t2, 0\n" >> $(C_BUILDDIR)/$*.s
@echo -e "\t.text\n\t.align\t2, 0 @ Don't pad with nop\n" >> $(C_BUILDDIR)/$*.s
$(AS) $(ASFLAGS) -o $@ $(C_BUILDDIR)/$*.s
ifeq ($(NODEP),1)
@ -195,7 +201,7 @@ $(SONG_BUILDDIR)/%.o: $(SONG_SUBDIR)/%.s
$(AS) $(ASFLAGS) -I sound -o $@ $<
$(ELF): $(OBJS) linker.ld
cd $(OBJ_DIR) && ../../$(LD) $(LDFLAGS) -T ../../linker.ld -o ../../$@ $(LIB)
cd $(OBJ_DIR) && $(LD) $(LDFLAGS) -T ../../linker.ld -o ../../$@ $(LIB)
$(FIX) $@ -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(REVISION) --silent
$(ROM): $(ELF)

View File

@ -1,227 +0,0 @@
.include "asm/macros.inc"
.include "constants/constants.inc"
.syntax unified
.text
thumb_func_start sub_08159158
sub_08159158: @ 0x08159158
push {r4, lr}
adds r4, r0, #0
subs r3, r2, #1
cmp r2, #0
beq _08159174
movs r2, #1
rsbs r2, r2, #0
_08159166:
ldrb r0, [r4]
strb r0, [r1]
adds r4, #1
adds r1, #1
subs r3, #1
cmp r3, r2
bne _08159166
_08159174:
pop {r4}
pop {r0}
bx r0
.align 2, 0
thumb_func_start sub_0815917C
sub_0815917C: @ 0x0815917C
push {r4, r5, r6, lr}
sub sp, #0x80
adds r4, r0, #0
adds r5, r1, #0
adds r6, r2, #0
ldr r2, _081591A8 @ =0x04000204
ldrh r0, [r2]
ldr r1, _081591AC @ =0x0000FFFC
ands r0, r1
movs r1, #3
orrs r0, r1
strh r0, [r2]
ldr r3, _081591B0 @ =sub_08159158
movs r0, #1
bics r3, r0
mov r2, sp
ldr r0, _081591B4 @ =sub_0815917C
ldr r1, _081591B0 @ =sub_08159158
subs r0, r0, r1
lsls r0, r0, #0xf
b _081591C4
.align 2, 0
_081591A8: .4byte 0x04000204
_081591AC: .4byte 0x0000FFFC
_081591B0: .4byte sub_08159158
_081591B4: .4byte sub_0815917C
_081591B8:
ldrh r0, [r3]
strh r0, [r2]
adds r3, #2
adds r2, #2
subs r0, r1, #1
lsls r0, r0, #0x10
_081591C4:
lsrs r1, r0, #0x10
cmp r1, #0
bne _081591B8
mov r3, sp
adds r3, #1
adds r0, r4, #0
adds r1, r5, #0
adds r2, r6, #0
bl _call_via_r3
add sp, #0x80
pop {r4, r5, r6}
pop {r0}
bx r0
thumb_func_start sub_081591E0
sub_081591E0: @ 0x081591E0
push {r4, r5, lr}
adds r5, r0, #0
adds r4, r1, #0
adds r3, r2, #0
ldr r2, _08159218 @ =0x04000204
ldrh r0, [r2]
ldr r1, _0815921C @ =0x0000FFFC
ands r0, r1
movs r1, #3
orrs r0, r1
strh r0, [r2]
subs r3, #1
movs r0, #1
rsbs r0, r0, #0
cmp r3, r0
beq _08159210
adds r1, r0, #0
_08159202:
ldrb r0, [r5]
strb r0, [r4]
adds r5, #1
adds r4, #1
subs r3, #1
cmp r3, r1
bne _08159202
_08159210:
pop {r4, r5}
pop {r0}
bx r0
.align 2, 0
_08159218: .4byte 0x04000204
_0815921C: .4byte 0x0000FFFC
thumb_func_start sub_08159220
sub_08159220: @ 0x08159220
push {r4, r5, lr}
adds r5, r0, #0
adds r3, r1, #0
subs r4, r2, #1
cmp r2, #0
beq _08159246
movs r2, #1
rsbs r2, r2, #0
_08159230:
ldrb r1, [r3]
ldrb r0, [r5]
adds r5, #1
adds r3, #1
cmp r1, r0
beq _08159240
subs r0, r3, #1
b _08159248
_08159240:
subs r4, #1
cmp r4, r2
bne _08159230
_08159246:
movs r0, #0
_08159248:
pop {r4, r5}
pop {r1}
bx r1
.align 2, 0
thumb_func_start sub_08159250
sub_08159250: @ 0x08159250
push {r4, r5, r6, lr}
sub sp, #0xc0
adds r4, r0, #0
adds r5, r1, #0
adds r6, r2, #0
ldr r2, _0815927C @ =0x04000204
ldrh r0, [r2]
ldr r1, _08159280 @ =0x0000FFFC
ands r0, r1
movs r1, #3
orrs r0, r1
strh r0, [r2]
ldr r3, _08159284 @ =sub_08159220
movs r0, #1
bics r3, r0
mov r2, sp
ldr r0, _08159288 @ =sub_08159250
ldr r1, _08159284 @ =sub_08159220
subs r0, r0, r1
lsls r0, r0, #0xf
b _08159298
.align 2, 0
_0815927C: .4byte 0x04000204
_08159280: .4byte 0x0000FFFC
_08159284: .4byte sub_08159220
_08159288: .4byte sub_08159250
_0815928C:
ldrh r0, [r3]
strh r0, [r2]
adds r3, #2
adds r2, #2
subs r0, r1, #1
lsls r0, r0, #0x10
_08159298:
lsrs r1, r0, #0x10
cmp r1, #0
bne _0815928C
mov r3, sp
adds r3, #1
adds r0, r4, #0
adds r1, r5, #0
adds r2, r6, #0
bl _call_via_r3
add sp, #0xc0
pop {r4, r5, r6}
pop {r1}
bx r1
thumb_func_start sub_081592B4
sub_081592B4: @ 0x081592B4
push {r4, r5, r6, r7, lr}
adds r6, r0, #0
adds r5, r1, #0
adds r4, r2, #0
movs r7, #0
b _081592C6
_081592C0:
adds r0, r7, #1
lsls r0, r0, #0x18
lsrs r7, r0, #0x18
_081592C6:
cmp r7, #2
bhi _081592E4
adds r0, r6, #0
adds r1, r5, #0
adds r2, r4, #0
bl sub_081591E0
adds r0, r6, #0
adds r1, r5, #0
adds r2, r4, #0
bl sub_08159250
adds r3, r0, #0
cmp r3, #0
bne _081592C0
_081592E4:
adds r0, r3, #0
pop {r4, r5, r6, r7}
pop {r1}
bx r1

View File

@ -22388,7 +22388,7 @@ _0800AA6C:
mov r0, sp
adds r1, r5, #0
movs r2, #8
bl sub_081592B4
bl WriteSramEx
cmp r0, #0
bne _0800AA58
adds r5, #8
@ -22418,7 +22418,7 @@ _0800AA9E:
_0800AAB0:
adds r0, r1, #0
adds r1, r5, #0
bl sub_081592B4
bl WriteSramEx
cmp r0, #0
bne _0800AA58
ldr r0, [r4, #4]
@ -22515,7 +22515,7 @@ _0800AB58:
adds r0, r5, #0
mov r1, sp
movs r2, #8
bl sub_0815917C
bl ReadSram
adds r5, #8
cmp r7, #0
beq _0800AB72
@ -22542,7 +22542,7 @@ _0800AB7E:
adds r6, r0, #0
_0800AB90:
adds r0, r5, #0
bl sub_0815917C
bl ReadSram
ldr r0, [r4, #4]
adds r5, r5, r0
adds r4, #8
@ -55836,14 +55836,14 @@ _0801A66A:
ldr r6, _0801A6B8 @ =gUnk_03002490
ldrb r2, [r2]
adds r1, r6, #0
bl sub_08157308
bl MultiSioMain
str r0, [r4]
adds r4, r5, #0
adds r4, #0xa4
ldr r0, [r4]
cmp r0, #0
bne _0801A690
bl sub_081576A0
bl MultiSioStart
movs r0, #1
str r0, [r4]
_0801A690:
@ -55906,12 +55906,12 @@ _0801A6E6:
adds r0, r0, r2
ldr r4, [r0]
_0801A6FC:
bl sub_081576BC
bl MultiSioStop
ldr r2, _0801A730 @ =0x04000208
movs r0, #0
strh r0, [r2]
ldr r1, _0801A734 @ =gUnk_030017B0
ldr r0, _0801A738 @ =sub_08158038
ldr r1, _0801A734 @ =gIntrTable
ldr r0, _0801A738 @ =Sio32MultiLoadIntr
str r0, [r1]
movs r0, #1
strh r0, [r2]
@ -55920,7 +55920,7 @@ _0801A6FC:
movs r1, #0x80
ands r0, r1
adds r1, r4, #0
bl sub_08158100
bl Sio32MultiLoadInit
ldr r0, _0801A740 @ =sub_0801A8C4
str r0, [r5, #0x14]
pop {r4, r5}
@ -55930,8 +55930,8 @@ _0801A6FC:
_0801A728: .4byte gUnk_082DE308
_0801A72C: .4byte gUnk_08D60A80
_0801A730: .4byte 0x04000208
_0801A734: .4byte gUnk_030017B0
_0801A738: .4byte sub_08158038
_0801A734: .4byte gIntrTable
_0801A738: .4byte Sio32MultiLoadIntr
_0801A73C: .4byte gUnk_03002554
_0801A740: .4byte sub_0801A8C4
@ -56126,7 +56126,7 @@ sub_0801A884: @ 0x0801A884
bl sub_0801E754
adds r0, r4, #0
bl sub_0801A908
bl sub_081576A0
bl MultiSioStart
ldr r0, _0801A8C0 @ =sub_0801A618
str r0, [r4, #0x14]
_0801A8B4:
@ -56145,7 +56145,7 @@ sub_0801A8C4: @ 0x0801A8C4
movs r0, #0
str r0, [sp]
mov r0, sp
bl sub_08157E54
bl Sio32MultiLoadMain
cmp r0, #0
beq _0801A8DC
ldr r0, _0801A8E4 @ =sub_0801AA40
@ -56181,8 +56181,8 @@ sub_0801A908: @ 0x0801A908
ldr r2, _0801A940 @ =0x04000208
movs r6, #0
strh r6, [r2]
ldr r1, _0801A944 @ =gUnk_030017B0
ldr r0, _0801A948 @ =gUnk_030068E0
ldr r1, _0801A944 @ =gIntrTable
ldr r0, _0801A948 @ =gMultiSioIntrFuncBuf
str r0, [r1]
movs r0, #1
strh r0, [r2]
@ -56192,7 +56192,7 @@ sub_0801A908: @ 0x0801A908
lsls r1, r1, #4
ands r0, r1
lsrs r0, r0, #8
bl sub_08157210
bl MultiSioInit
adds r0, r4, #0
adds r0, #0xa8
movs r1, #0
@ -56205,8 +56205,8 @@ sub_0801A908: @ 0x0801A908
bx r0
.align 2, 0
_0801A940: .4byte 0x04000208
_0801A944: .4byte gUnk_030017B0
_0801A948: .4byte gUnk_030068E0
_0801A944: .4byte gIntrTable
_0801A948: .4byte gMultiSioIntrFuncBuf
_0801A94C: .4byte gUnk_03002554
thumb_func_start sub_0801A950
@ -101110,7 +101110,7 @@ sub_0803024C: @ 0x0803024C
ldr r0, _080302D4 @ =0x0400012A
strh r3, [r0]
ldr r2, _080302D8 @ =gUnk_03000470
ldr r1, _080302DC @ =gUnk_030017B0
ldr r1, _080302DC @ =gIntrTable
ldr r0, [r1, #0x1c]
str r0, [r2]
ldr r2, _080302E0 @ =gUnk_03000484
@ -101139,7 +101139,7 @@ _080302CC: .4byte 0x04000128
_080302D0: .4byte 0x00004003
_080302D4: .4byte 0x0400012A
_080302D8: .4byte gUnk_03000470
_080302DC: .4byte gUnk_030017B0
_080302DC: .4byte gIntrTable
_080302E0: .4byte gUnk_03000484
_080302E4: .4byte sub_08030898
_080302E8: .4byte 0x04000200
@ -102251,7 +102251,7 @@ sub_08030B38: @ 0x08030B38
ldr r2, _08030B9C @ =0x00008F52
adds r0, r2, #0
strh r0, [r1]
ldr r1, _08030BA0 @ =gUnk_030017B0
ldr r1, _08030BA0 @ =gIntrTable
ldr r0, _08030BA4 @ =gUnk_03000470
ldr r0, [r0]
str r0, [r1, #0x1c]
@ -102281,7 +102281,7 @@ _08030B90: .4byte 0x04000128
_08030B94: .4byte 0x0000BFFF
_08030B98: .4byte 0x0400012A
_08030B9C: .4byte 0x00008F52
_08030BA0: .4byte gUnk_030017B0
_08030BA0: .4byte gIntrTable
_08030BA4: .4byte gUnk_03000470
_08030BA8: .4byte gUnk_03000484
_08030BAC: .4byte gUnk_03000490
@ -102324,7 +102324,7 @@ sub_08030BB8: @ 0x08030BB8
mov r1, r8
strb r1, [r0]
adds r0, r5, #0
bl sub_08157DDC
bl MultiBootInit
add sp, #4
pop {r3, r4}
mov r8, r3
@ -102429,7 +102429,7 @@ sub_08030C94: @ 0x08030C94
adds r1, r4, #0
bl CpuSet
strh r5, [r4, #4]
bl sub_081576A0
bl MultiSioStart
ldr r0, _08030D0C @ =sub_0803149C
str r5, [sp]
movs r1, #0x20
@ -106963,14 +106963,14 @@ _08032F98:
str r4, [r3]
strb r4, [r5]
movs r0, #0
bl sub_08157210
bl MultiSioInit
bl sub_08031BFC
bl m4aMPlayAllStop
ldr r0, _08032FFC @ =0x04000208
strh r4, [r0]
movs r2, #0
ldr r4, _08033000 @ =gUnk_030017B0
ldr r3, _08033004 @ =gUnk_08D5FD9C
ldr r4, _08033000 @ =gIntrTable
ldr r3, _08033004 @ =gIntrTableTemplate
_08032FB6:
lsls r0, r2, #2
adds r1, r0, r4
@ -107000,8 +107000,8 @@ _08032FF0: .4byte 0x85000014
_08032FF4: .4byte gUnk_03002554
_08032FF8: .4byte gUnk_03002558
_08032FFC: .4byte 0x04000208
_08033000: .4byte gUnk_030017B0
_08033004: .4byte gUnk_08D5FD9C
_08033000: .4byte gIntrTable
_08033004: .4byte gIntrTableTemplate
thumb_func_start sub_08033008
sub_08033008: @ 0x08033008

File diff suppressed because it is too large Load Diff

9543
asm/code_08152A18.s Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,429 +5,6 @@
.text
thumb_func_start sub_08157E54
sub_08157E54: @ 0x08157E54
push {r4, r5, r6, r7, lr}
adds r2, r0, #0
ldr r0, _08157E70 @ =gUnk_03006C90
ldrb r1, [r0, #1]
adds r5, r0, #0
cmp r1, #4
bls _08157E64
b _0815802A
_08157E64:
lsls r0, r1, #2
ldr r1, _08157E74 @ =_08157E78
adds r0, r0, r1
ldr r0, [r0]
mov pc, r0
.align 2, 0
_08157E70: .4byte gUnk_03006C90
_08157E74: .4byte _08157E78
_08157E78: @ jump table
.4byte _08157E8C @ case 0
.4byte _08157EA4 @ case 1
.4byte _08157F40 @ case 2
.4byte _08157FB2 @ case 3
.4byte _08158020 @ case 4
_08157E8C:
ldr r0, [r5]
ldr r1, _08157EA0 @ =0x00FF00FF
ands r0, r1
cmp r0, #0
bne _08157E98
b _0815802A
_08157E98:
movs r0, #1
strb r0, [r5, #1]
b _0815802A
.align 2, 0
_08157EA0: .4byte 0x00FF00FF
_08157EA4:
ldrb r0, [r5]
cmp r0, #1
bne _08157EB4
ldrb r0, [r5, #2]
cmp r0, #5
bhi _08157EB2
b _0815802A
_08157EB2:
b _08157EBE
_08157EB4:
ldr r1, _08157EF4 @ =0x04000128
movs r2, #0x80
lsls r2, r2, #5
adds r0, r2, #0
strh r0, [r1]
_08157EBE:
ldr r0, _08157EF8 @ =0x04000120
movs r6, #0
str r6, [r0]
ldr r1, _08157EFC @ =0x04000202
movs r0, #0xc0
strh r0, [r1]
ldrb r4, [r5]
cmp r4, #1
bne _08157F0C
ldr r2, _08157EF4 @ =0x04000128
ldrh r0, [r2]
movs r1, #0x80
orrs r0, r1
strh r0, [r2]
ldr r1, _08157F00 @ =0x0400010C
ldr r0, _08157F04 @ =0x00C0F318
str r0, [r1]
ldr r3, _08157F08 @ =0x04000208
strh r6, [r3]
adds r2, #0xd8
ldrh r0, [r2]
movs r1, #0x40
orrs r0, r1
strh r0, [r2]
strh r4, [r3]
b _08157F2C
.align 2, 0
_08157EF4: .4byte 0x04000128
_08157EF8: .4byte 0x04000120
_08157EFC: .4byte 0x04000202
_08157F00: .4byte 0x0400010C
_08157F04: .4byte 0x00C0F318
_08157F08: .4byte 0x04000208
_08157F0C:
ldr r2, _08157F38 @ =0x04000128
ldrh r0, [r2]
movs r3, #0x81
lsls r3, r3, #7
adds r1, r3, #0
orrs r0, r1
strh r0, [r2]
ldr r3, _08157F3C @ =0x04000208
strh r6, [r3]
adds r2, #0xd8
ldrh r0, [r2]
movs r1, #0x80
orrs r0, r1
strh r0, [r2]
movs r0, #1
strh r0, [r3]
_08157F2C:
movs r0, #0
strb r0, [r5, #2]
movs r0, #2
strb r0, [r5, #1]
b _0815802A
.align 2, 0
_08157F38: .4byte 0x04000128
_08157F3C: .4byte 0x04000208
_08157F40:
ldr r6, [r5, #8]
adds r4, r6, #0
movs r0, #0x80
lsls r0, r0, #6
cmp r6, r0
ble _08157F50
adds r4, r0, #0
b _08157F56
_08157F50:
cmp r6, #0
bge _08157F56
movs r4, #0
_08157F56:
cmp r2, #0
beq _08157F5C
str r4, [r2]
_08157F5C:
ldrb r0, [r5]
cmp r0, #1
beq _08157F9E
ldr r0, [r5, #0x14]
cmp r0, r4
bge _08157F82
adds r3, r5, #0
ldr r7, [r5, #4]
_08157F6C:
ldr r2, [r3, #0x14]
lsls r0, r2, #2
adds r0, r0, r7
ldr r1, [r3, #0x10]
ldr r0, [r0]
adds r1, r1, r0
str r1, [r3, #0x10]
adds r2, #1
str r2, [r3, #0x14]
cmp r2, r4
blt _08157F6C
_08157F82:
movs r0, #0x80
lsls r0, r0, #6
cmp r6, r0
ble _08157FA6
ldr r0, [r5, #0xc]
ldr r1, [r5, #0x10]
adds r0, r0, r1
str r0, [r5, #0xc]
movs r1, #1
rsbs r1, r1, #0
cmp r0, r1
bne _08157F9E
movs r0, #1
strb r0, [r5, #3]
_08157F9E:
movs r0, #0x80
lsls r0, r0, #6
cmp r6, r0
bgt _08157FAC
_08157FA6:
ldrb r0, [r5, #2]
cmp r0, #0x8c
bne _0815802A
_08157FAC:
movs r0, #3
strb r0, [r5, #1]
b _0815802A
_08157FB2:
ldr r3, _08158004 @ =0x04000208
movs r4, #0
strh r4, [r3]
ldr r2, _08158008 @ =0x04000200
ldrh r1, [r2]
ldr r0, _0815800C @ =0x0000FF3F
ands r0, r1
strh r0, [r2]
movs r0, #1
strh r0, [r3]
ldr r1, _08158010 @ =0x04000128
movs r2, #0x80
lsls r2, r2, #5
adds r0, r2, #0
strh r0, [r1]
movs r0, #0x80
lsls r0, r0, #6
str r0, [r1]
adds r0, #3
str r0, [r1]
ldr r2, _08158014 @ =0x04000120
movs r0, #0
movs r1, #0
str r0, [r2]
str r1, [r2, #4]
ldrb r0, [r5]
cmp r0, #0
beq _08157FF0
ldr r1, _08158018 @ =0x0400010C
movs r0, #0
str r0, [r1]
_08157FF0:
ldr r0, _0815801C @ =0x04000202
movs r1, #0xc0
strh r1, [r0]
ldrb r0, [r5]
cmp r0, #0
beq _08158026
strb r4, [r5, #2]
movs r0, #4
strb r0, [r5, #1]
b _0815802A
.align 2, 0
_08158004: .4byte 0x04000208
_08158008: .4byte 0x04000200
_0815800C: .4byte 0x0000FF3F
_08158010: .4byte 0x04000128
_08158014: .4byte 0x04000120
_08158018: .4byte 0x0400010C
_0815801C: .4byte 0x04000202
_08158020:
ldrb r0, [r5, #2]
cmp r0, #2
bls _0815802A
_08158026:
movs r0, #1
b _08158032
_0815802A:
ldrb r0, [r5, #2]
adds r0, #1
strb r0, [r5, #2]
movs r0, #0
_08158032:
pop {r4, r5, r6, r7}
pop {r1}
bx r1
thumb_func_start sub_08158038
sub_08158038: @ 0x08158038
push {r4, r5, lr}
ldr r2, _0815805C @ =0x04000120
ldr r3, [r2]
ldr r5, _08158060 @ =gUnk_03006C90
ldrb r0, [r5]
adds r4, r5, #0
cmp r0, #1
beq _08158068
ldr r0, _08158064 @ =0x04000128
ldrh r1, [r0]
movs r2, #0x80
orrs r1, r2
strh r1, [r0]
ldr r2, [r4, #8]
cmp r2, #0
bge _081580B4
b _081580A2
.align 2, 0
_0815805C: .4byte 0x04000120
_08158060: .4byte gUnk_03006C90
_08158064: .4byte 0x04000128
_08158068:
ldr r1, _0815807C @ =0x0400010E
movs r0, #0
strh r0, [r1]
ldr r1, [r4, #8]
cmp r1, #0
bge _08158084
ldr r0, _08158080 @ =0xFEFEFEFE
str r0, [r2]
b _081580CA
.align 2, 0
_0815807C: .4byte 0x0400010E
_08158080: .4byte 0xFEFEFEFE
_08158084:
ldr r0, _08158098 @ =0x00001FFF
cmp r1, r0
bgt _0815809C
ldr r0, [r4, #4]
lsls r1, r1, #2
adds r1, r1, r0
ldr r0, [r1]
str r0, [r2]
b _081580CA
.align 2, 0
_08158098: .4byte 0x00001FFF
_0815809C:
ldr r0, [r4, #0xc]
str r0, [r2]
b _081580CA
_081580A2:
ldr r0, _081580B0 @ =0xFEFEFEFE
cmp r3, r0
beq _081580CA
subs r0, r2, #1
str r0, [r5, #8]
b _081580CA
.align 2, 0
_081580B0: .4byte 0xFEFEFEFE
_081580B4:
ldr r0, _081580C4 @ =0x00001FFF
cmp r2, r0
bgt _081580C8
ldr r1, [r4, #4]
lsls r0, r2, #2
adds r0, r0, r1
str r3, [r0]
b _081580CA
.align 2, 0
_081580C4: .4byte 0x00001FFF
_081580C8:
str r3, [r4, #0xc]
_081580CA:
ldr r1, [r4, #8]
ldr r0, _081580F4 @ =0x00002002
cmp r1, r0
bgt _081580EC
adds r0, r1, #1
str r0, [r4, #8]
ldrb r0, [r4]
cmp r0, #1
bne _081580EC
ldr r2, _081580F8 @ =0x04000128
ldrh r0, [r2]
movs r1, #0x80
orrs r0, r1
strh r0, [r2]
ldr r1, _081580FC @ =0x0400010E
movs r0, #0xc0
strh r0, [r1]
_081580EC:
pop {r4, r5}
pop {r0}
bx r0
.align 2, 0
_081580F4: .4byte 0x00002002
_081580F8: .4byte 0x04000128
_081580FC: .4byte 0x0400010E
thumb_func_start sub_08158100
sub_08158100: @ 0x08158100
push {r4, r5, r6, r7, lr}
mov r7, r8
push {r7}
sub sp, #4
adds r5, r0, #0
adds r7, r1, #0
movs r6, #0
ldr r3, _0815817C @ =0x04000208
strh r6, [r3]
ldr r2, _08158180 @ =0x04000200
ldrh r1, [r2]
ldr r0, _08158184 @ =0x0000FF3F
ands r0, r1
strh r0, [r2]
movs r0, #1
mov r8, r0
strh r0, [r3]
str r6, [sp]
ldr r4, _08158188 @ =gUnk_03006C90
ldr r2, _0815818C @ =0x05000006
mov r0, sp
adds r1, r4, #0
bl CpuSet
ldr r1, _08158190 @ =0x04000128
ldr r0, _08158194 @ =0x00002003
str r0, [r1]
str r7, [r4, #4]
movs r0, #1
rsbs r0, r0, #0
str r0, [r4, #8]
cmp r5, #0
beq _0815816E
ldr r0, _08158198 @ =0x0400010C
str r6, [r0]
mov r2, r8
strb r2, [r4]
adds r1, r7, #0
movs r2, #0x80
lsls r2, r2, #6
_08158150:
ldm r1!, {r0}
adds r6, r6, r0
subs r2, #1
cmp r2, #0
bne _08158150
mvns r0, r6
str r0, [r4, #0xc]
ldr r1, _08158190 @ =0x04000128
movs r2, #0x80
lsls r2, r2, #5
adds r0, r2, #0
strh r0, [r1]
adds r2, #1
adds r0, r2, #0
strh r0, [r1]
_0815816E:
add sp, #4
pop {r3}
mov r8, r3
pop {r4, r5, r6, r7}
pop {r0}
bx r0
.align 2, 0
_0815817C: .4byte 0x04000208
_08158180: .4byte 0x04000200
_08158184: .4byte 0x0000FF3F
_08158188: .4byte gUnk_03006C90
_0815818C: .4byte 0x05000006
_08158190: .4byte 0x04000128
_08158194: .4byte 0x00002003
_08158198: .4byte 0x0400010C
thumb_func_start sub_0815819C
sub_0815819C: @ 0x0815819C
ldr r1, _081581A4 @ =gUnk_03006CB0
@ -901,30 +478,30 @@ _081584FE:
movs r1, #0
ldrsh r4, [r7, r1]
adds r0, r4, #0
bl __floatsidf
bl __floatsisf
adds r6, r0, #0
mov r8, r5
cmp r4, #0
bge _08158520
ldr r1, _08158558 @ =0x47800000
bl __adddf3
bl __addsf3
adds r6, r0, #0
_08158520:
mov r2, sl
movs r0, #0
ldrsb r0, [r2, r0]
bl __floatsidf
bl __floatsisf
adds r4, r0, #0
ldr r1, _0815855C @ =0x41800000
bl __adddf3
bl __addsf3
ldr r1, _08158560 @ =0x3D800000
bl __muldf3
bl __mulsf3
adds r1, r0, #0
adds r0, r6, #0
bl __muldf3
bl __mulsf3
adds r1, r4, #0
bl __subdf3
bl __fixdfsi
bl __subsf3
bl __fixsfsi
cmp r0, #0
bge _08158564
movs r0, #0
@ -946,23 +523,23 @@ _0815856A:
adds r6, r1, r0
ldrh r0, [r6]
lsrs r0, r0, #5
bl __floatsidf
bl __floatsisf
adds r5, r0, #0
mov r2, sl
movs r0, #1
ldrsb r0, [r2, r0]
bl __floatsidf
bl __floatsisf
adds r4, r0, #0
ldr r1, _081585B0 @ =0x41800000
bl __adddf3
bl __addsf3
ldr r1, _081585B4 @ =0x3D800000
bl __muldf3
bl __mulsf3
adds r1, r0, #0
adds r0, r5, #0
bl __muldf3
bl __mulsf3
adds r1, r4, #0
bl __subdf3
bl __fixdfsi
bl __subsf3
bl __fixsfsi
cmp r0, #0
bge _081585B8
movs r0, #0
@ -990,23 +567,23 @@ _081585CC:
adds r6, r1, r0
ldrh r0, [r6]
lsrs r0, r0, #0xa
bl __floatsidf
bl __floatsisf
adds r5, r0, #0
mov r2, sl
movs r0, #2
ldrsb r0, [r2, r0]
bl __floatsidf
bl __floatsisf
adds r4, r0, #0
ldr r1, _08158614 @ =0x41800000
bl __adddf3
bl __addsf3
ldr r1, _08158618 @ =0x3D800000
bl __muldf3
bl __mulsf3
adds r1, r0, #0
adds r0, r5, #0
bl __muldf3
bl __mulsf3
adds r1, r4, #0
bl __subdf3
bl __fixdfsi
bl __subsf3
bl __fixsfsi
cmp r0, #0
bge _0815861C
movs r0, #0
@ -1068,20 +645,20 @@ _0815866A:
movs r0, #0
ldrsh r4, [r6, r0]
adds r0, r4, #0
bl __floatsidf
bl __floatsisf
cmp r4, #0
bge _08158686
ldr r1, _081586B0 @ =0x47800000
bl __adddf3
bl __addsf3
_08158686:
adds r1, r7, #0
bl __divdf3
bl __divsf3
mov r2, r8
ldr r1, [r2]
bl sub_08159350
bl powferrorhandler
adds r1, r7, #0
bl __muldf3
bl __fixdfsi
bl __mulsf3
bl __fixsfsi
cmp r0, #0
bge _081586B4
movs r0, #0
@ -1100,15 +677,15 @@ _081586BA:
adds r4, r5, r0
ldrh r0, [r4]
lsrs r0, r0, #5
bl __floatsidf
bl __floatsisf
adds r1, r7, #0
bl __divdf3
bl __divsf3
mov r2, r8
ldr r1, [r2, #4]
bl sub_08159350
bl powferrorhandler
adds r1, r7, #0
bl __muldf3
bl __fixdfsi
bl __mulsf3
bl __fixsfsi
cmp r0, #0
bge _081586EC
movs r0, #0
@ -1129,15 +706,15 @@ _081586F8:
adds r5, r5, r0
ldrh r0, [r5]
lsrs r0, r0, #0xa
bl __floatsidf
bl __floatsisf
adds r1, r7, #0
bl __divdf3
bl __divsf3
mov r2, r8
ldr r1, [r2, #8]
bl sub_08159350
bl powferrorhandler
adds r1, r7, #0
bl __muldf3
bl __fixdfsi
bl __mulsf3
bl __fixsfsi
cmp r0, #0
bge _0815872C
movs r0, #0
@ -1455,7 +1032,7 @@ sub_08158934: @ 0x08158934
ldr r0, _08158988 @ =gUnk_03002558
strb r2, [r0]
movs r0, #0
bl sub_08157210
bl MultiSioInit
add sp, #4
pop {r0}
bx r0
@ -1489,12 +1066,12 @@ sub_0815898C: @ 0x0815898C
movs r2, #1
strh r2, [r3]
strh r4, [r3]
ldr r1, _081589DC @ =gUnk_030017B0
ldr r0, _081589E0 @ =gUnk_030068E0
ldr r1, _081589DC @ =gIntrTable
ldr r0, _081589E0 @ =gMultiSioIntrFuncBuf
str r0, [r1]
strh r2, [r3]
movs r0, #0
bl sub_08157210
bl MultiSioInit
_081589C0:
ldr r1, _081589E4 @ =gUnk_03002558
movs r0, #1
@ -1507,8 +1084,8 @@ _081589CC: .4byte gUnk_03002440
_081589D0: .4byte 0x04000208
_081589D4: .4byte 0x04000200
_081589D8: .4byte 0x0000FFBF
_081589DC: .4byte gUnk_030017B0
_081589E0: .4byte gUnk_030068E0
_081589DC: .4byte gIntrTable
_081589E0: .4byte gMultiSioIntrFuncBuf
_081589E4: .4byte gUnk_03002558
thumb_func_start sub_081589E8
@ -1522,9 +1099,9 @@ sub_081589E8: @ 0x081589E8
ldr r1, _08158A24 @ =0xFFEFFFFF
ands r0, r1
str r0, [r4]
bl sub_081576BC
bl MultiSioStop
movs r0, #0
bl sub_08157210
bl MultiSioInit
ldr r0, [r4]
movs r1, #0x80
lsls r1, r1, #0xc
@ -1741,12 +1318,12 @@ _08158BD0:
cmp r0, #3
bhi _08158BE4
lsls r0, r0, #1
ldr r1, _08158BE0 @ =gUnk_08D60898
ldr r1, _08158BE0 @ =gAgbSramLibVer
adds r0, r0, r1
ldrh r0, [r0]
b _08158BE8
.align 2, 0
_08158BE0: .4byte gUnk_08D60898
_08158BE0: .4byte gAgbSramLibVer
_08158BE4:
movs r0, #0x80
lsls r0, r0, #8
@ -2112,8 +1689,8 @@ _08158E9A:
.align 2, 0
_08158EA4: .4byte 0x10000010
thumb_func_start sub_08158EA8
sub_08158EA8: @ 0x08158EA8
thumb_func_start Timer3Intr
Timer3Intr: @ 0x08158EA8
push {r4, r5, lr}
ldr r3, _08158EE8 @ =0x04000208
movs r4, #0

View File

@ -1,108 +0,0 @@
.include "asm/macros.inc"
.include "constants/constants.inc"
.syntax unified
.text
arm_func_start sub_08158F14
sub_08158F14: @ 0x08158F14
push {r4, r5, r6, r7, r8, sb, sl, fp}
mov ip, #0x4000000
ldr fp, _08158F50 @ =gUnk_03006A60
add sl, fp, #0x40
mov sb, #1
mov r8, #0
strb r8, [ip, #0x208]
ldm sl, {r0, r1, r2, r3, r4, r5, r6, r7}
stm sl!, {r4, r5, r6, r7}
stm sl!, {r0, r1, r2, r3}
ldr r0, [fp, #4]
str r8, [fp, #4]
strb sb, [ip, #0x208]
pop {r4, r5, r6, r7, r8, sb, sl, fp}
bx lr
.align 2, 0
_08158F50: .4byte gUnk_03006A60
arm_func_start sub_08158F54
sub_08158F54: @ 0x08158F54
mov ip, #0x4000000
add ip, ip, #0x120
ldm ip, {r0, r1}
push {r7, r8, sb, sl, fp}
ldr fp, _0815906C @ =gUnk_03006A60
mov sb, #0xfe
add sb, sb, #0xfe00
ldrh r3, [ip, #8]
and r3, r3, #0x40
strb r3, [fp, #9]
ldr sl, [fp, #0x14]
adds r3, sl, #1
blt _08158FB0
bne _08158FA4
strh sb, [ip, #0xa]
add r8, fp, #0x28
ldm r8, {r2, r3}
mov r7, r2
stm r8, {r3, r7}
b _08158FB0
_08158FA4:
ldr r3, [fp, #0x2c]
ldr r2, [r3, sl, lsl #1]
strh r2, [ip, #0xa]
_08158FB0:
cmp sl, #0xd
addlt sl, sl, #1
strlt sl, [fp, #0x14]
push {r0, r1, r5, r6}
mov r6, #3
_08158FC4:
add r8, fp, #0x18
add r8, r8, r6, lsl #2
ldr sl, [r8]
lsl r3, r6, #1
ldrh r5, [sp, r3]
cmp r5, sb
bne _08158FF4
cmp sl, #0xb
ble _08158FF4
mov r0, #1
sub sl, r0, #2
b _08159020
_08158FF4:
ldr r0, [r8, #0x18]
lsl r3, sl, #1
strh r5, [r0, r3]
cmp sl, #0xb
bne _08159020
ldr r1, [r8, #0x28]
str r0, [r8, #0x28]
str r1, [r8, #0x18]
add r3, fp, #4
mov r0, #1
strb r0, [r3, r6]
_08159020:
cmp sl, #0xd
addlt sl, sl, #1
str sl, [r8]
subs r6, r6, #1
bge _08158FC4
ldrb r0, [fp]
cmp r0, #0
beq _08159060
ldr r7, _08159070 @ =0x0400010E
mov r0, #0
strh r0, [r7]
ldrh r0, [ip, #8]
orr r0, r0, #0x80
strh r0, [ip, #8]
mov r0, #0xc0
strh r0, [r7]
_08159060:
add sp, sp, #8
pop {r5, r6, r7, r8, sb, sl, fp}
bx lr
.align 2, 0
_0815906C: .4byte gUnk_03006A60
_08159070: .4byte 0x0400010E

File diff suppressed because it is too large Load Diff

View File

@ -10,82 +10,81 @@ __start:
arm_func_start sub_08000000
sub_08000000: @ 0x08000000
b _080000C0
_08000004:
.include "asm/rom_header.inc"
_080000C0:
mov r0, #0x12
mov r0, #PSR_IRQ_MODE
msr cpsr_fc, r0
ldr sp, _080000F8 @ =gUnk_03007FA0
mov r0, #0x1f
ldr sp, sp_irq
mov r0, #PSR_SYS_MODE
msr cpsr_fc, r0
ldr sp, _080000F4 @ =gUnk_03007E80
ldr r1, _080001C0 @ =gUnk_03007FFC
add r0, pc, #0x18 @ =sub_080000FC
ldr sp, sp_usr
ldr r1, _080001C0 @ =INTR_VECTOR
add r0, pc, #0x18 @ =IntrMain
str r0, [r1]
ldr r1, _080001C4 @ =sub_08152A04
ldr r1, _080001C4 @ =AgbMain
mov lr, pc
bx r1
_080000F0:
b _080000C0
_080000F4: .4byte gUnk_03007E80
_080000F8: .4byte gUnk_03007FA0
sp_usr: .4byte IWRAM_END - 0x180
sp_irq: .4byte IWRAM_END - 0x60
arm_func_start sub_080000FC
sub_080000FC: @ 0x080000FC
arm_func_start IntrMain
IntrMain: @ 0x080000FC
mov r3, #0x4000000
add r3, r3, #0x200
ldr r2, [r3]
and r1, r2, r2, lsr #16
mov r2, #0
ands r0, r1, #0x2000
ands r0, r1, #INTR_FLAG_GAMEPAK
strbne r0, [r3, #-0x17c]
_08000118:
bne _08000118
ands r0, r1, #0xc0
ands r0, r1, #INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL
bne _080001AC
add r2, r2, #4
ands r0, r1, #1
ands r0, r1, #INTR_FLAG_VBLANK
bne _080001AC
add r2, r2, #4
ands r0, r1, #2
ands r0, r1, #INTR_FLAG_HBLANK
bne _080001AC
add r2, r2, #4
ands r0, r1, #4
ands r0, r1, #INTR_FLAG_VCOUNT
bne _080001AC
add r2, r2, #4
ands r0, r1, #8
ands r0, r1, #INTR_FLAG_TIMER0
bne _080001AC
add r2, r2, #4
ands r0, r1, #0x10
ands r0, r1, #INTR_FLAG_TIMER1
bne _080001AC
add r2, r2, #4
ands r0, r1, #0x20
ands r0, r1, #INTR_FLAG_TIMER2
bne _080001AC
add r2, r2, #4
ands r0, r1, #0x40
ands r0, r1, #INTR_FLAG_TIMER3
bne _080001AC
add r2, r2, #4
ands r0, r1, #0x100
ands r0, r1, #INTR_FLAG_DMA0
bne _080001AC
add r2, r2, #4
ands r0, r1, #0x200
ands r0, r1, #INTR_FLAG_DMA1
bne _080001AC
add r2, r2, #4
ands r0, r1, #0x400
ands r0, r1, #INTR_FLAG_DMA2
bne _080001AC
add r2, r2, #4
ands r0, r1, #0x800
ands r0, r1, #INTR_FLAG_DMA3
bne _080001AC
add r2, r2, #4
_080001AC:
strh r0, [r3, #2]
ldr r1, _080001C8 @ =gUnk_030017B0
ldr r1, _080001C8 @ =gIntrTable
add r1, r1, r2
ldr r0, [r1]
bx r0
.align 2, 0
_080001C0: .4byte gUnk_03007FFC
_080001C4: .4byte sub_08152A04
_080001C8: .4byte gUnk_030017B0
_080001C0: .4byte INTR_VECTOR
_080001C4: .4byte AgbMain
_080001C8: .4byte gIntrTable

View File

@ -73,15 +73,15 @@ SoftReset: @ 0x0815931C
_0815932C: .4byte 0x04000208
_08159330: .4byte gUnk_03007F00
thumb_func_start SoundBiasLevel000
SoundBiasLevel000: @ 0x08159334
thumb_func_start SoundBiasReset
SoundBiasReset: @ 0x08159334
movs r0, #0
svc #0x19
bx lr
.align 2, 0
thumb_func_start SoundBiasLevel200
SoundBiasLevel200: @ 0x0815933C
thumb_func_start SoundBiasSet
SoundBiasSet: @ 0x0815933C
movs r0, #1
svc #0x19
bx lr

View File

@ -1,113 +0,0 @@
.include "asm/macros.inc"
.include "constants/constants.inc"
.syntax unified
.text
thumb_func_start memcpy
memcpy: @ 0x0815BD24
push {r4, r5, lr}
adds r5, r0, #0
adds r4, r5, #0
adds r3, r1, #0
cmp r2, #0xf
bls _0815BD64
adds r0, r3, #0
orrs r0, r5
movs r1, #3
ands r0, r1
cmp r0, #0
bne _0815BD64
adds r1, r5, #0
_0815BD3E:
ldm r3!, {r0}
stm r1!, {r0}
ldm r3!, {r0}
stm r1!, {r0}
ldm r3!, {r0}
stm r1!, {r0}
ldm r3!, {r0}
stm r1!, {r0}
subs r2, #0x10
cmp r2, #0xf
bhi _0815BD3E
cmp r2, #3
bls _0815BD62
_0815BD58:
ldm r3!, {r0}
stm r1!, {r0}
subs r2, #4
cmp r2, #3
bhi _0815BD58
_0815BD62:
adds r4, r1, #0
_0815BD64:
subs r2, #1
movs r0, #1
rsbs r0, r0, #0
cmp r2, r0
beq _0815BD7E
adds r1, r0, #0
_0815BD70:
ldrb r0, [r3]
strb r0, [r4]
adds r3, #1
adds r4, #1
subs r2, #1
cmp r2, r1
bne _0815BD70
_0815BD7E:
adds r0, r5, #0
pop {r4, r5, pc}
.align 2, 0
thumb_func_start memset
memset: @ 0x0815BD84
push {r4, r5, lr}
adds r5, r0, #0
adds r4, r1, #0
adds r3, r5, #0
cmp r2, #3
bls _0815BDCA
movs r0, #3
ands r0, r5
cmp r0, #0
bne _0815BDCA
adds r1, r5, #0
movs r0, #0xff
ands r4, r0
lsls r3, r4, #8
orrs r3, r4
lsls r0, r3, #0x10
orrs r3, r0
cmp r2, #0xf
bls _0815BDBE
_0815BDAA:
stm r1!, {r3}
stm r1!, {r3}
stm r1!, {r3}
stm r1!, {r3}
subs r2, #0x10
cmp r2, #0xf
bhi _0815BDAA
b _0815BDBE
_0815BDBA:
stm r1!, {r3}
subs r2, #4
_0815BDBE:
cmp r2, #3
bhi _0815BDBA
adds r3, r1, #0
b _0815BDCA
_0815BDC6:
strb r4, [r3]
adds r3, #1
_0815BDCA:
adds r0, r2, #0
subs r2, #1
cmp r0, #0
bne _0815BDC6
adds r0, r5, #0
pop {r4, r5, pc}
.align 2, 0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

12411
asm/main.s

File diff suppressed because it is too large Load Diff

220
asm/multi_sio_asm.s Normal file
View File

@ -0,0 +1,220 @@
.include "asm/macros.inc"
.include "constants/constants.inc"
.syntax unified
.text
.ifdef MULTI_SIO_DI_FUNC_FAST
@--------------------------------------------------------------------
@- Update Receive Data/Check Buffer Routine -
@--------------------------------------------------------------------
arm_func_start MultiSioRecvBufChange
MultiSioRecvBufChange: @ 0x08158F14
stmfd sp!, {r4-r11}
mov r12, #REG_BASE @ r12: REG_BASE
ldr r11, =gMultiSioArea @ r11: &gMultiSioArea
add r10, r11, #OFS_MS_LAST_RECV_BUF_P @ r10: &gMultiSioArea.lastRecvBufp[0]
mov r9, #1 @ r9: 1
mov r8, #0 @ r8: 0
@ *(vu8 *)REG_ADDR_IME = 0 Disable Interrupt (29 Clocks)
strb r8, [r12, #OFFSET_REG_IME]
@ gMultiSioArea.recvCheckBufp[i] <--> gMultiSioArea.lastRecvBufp[i] Update Receive Buffer
ldmia r10, {r0-r7}
stmia r10!, {r4-r7}
stmia r10!, {r0-r3}
@ syncRecvFlagBak[i] = gMultiSioArea.syncRecvFlag[i]
@ gMultiSioArea.syncRecvFlag[i] = 0
ldr r0, [r11, #OFS_MS_SYNC_RECV_FLAG]
str r8, [r11, #OFS_MS_SYNC_RECV_FLAG]
@ *(vu8 *)REG_IME = 1 Enable Interrupt
strb r9, [r12, #OFFSET_REG_IME]
@ return gMultiSioArea.syncRecvFlag[i]
ldmfd sp!, {r4-r11}
bx lr
.ltorg
arm_func_end MultiSioRecvBufChange
@--------------------------------------------------------------------
@- Multi-play Interrupt Routine -
@--------------------------------------------------------------------
arm_func_start MultiSioIntr
MultiSioIntr: @ 0x08158F54
@ Save Receive Data
@ *(u64 *)recvTmp = *(u64 *)REG_ADDR_SIOMLT_RECV
mov r12, #REG_BASE @ r12: REG_SIOMLT_RECV
add r12, r12, #OFFSET_REG_SIOMLT_RECV
ldmia r12, {r0-r1}
@ Save Register to Stack
stmfd sp!, {r7-r11}
ldr r11, =gMultiSioArea @ r11: &gMultiSioArea
mov r9, #MULTI_SIO_SYNC_DATA & 0x00ff @ r9: MULTI_SIO_SYNC_DATA
add r9, r9, #MULTI_SIO_SYNC_DATA & 0xff00
/* FIXME: What does these mean? */
ldrh r3, [r12, #8]
and r3, r3, #0x40
@ hardError
strb r3, [r11, #9]
@ Send Data Processing
@ if (gMultiSioArea.sendBufCounter == -1) {
ldr r10, [r11, #OFS_MS_SEND_BUF_COUNTER] @ r10: gMultiSioArea.sendBufCounter
adds r3, r10, #1
blt 3f
bne 2f
@ REG_SIOCNT->data = MULTI_SIO_SYNC_DATA Set Synchronization Data
strh r9, [r12, #REG_SIOMLT_SEND - REG_SIOMLT_RECV]
@ gMultiSioArea.currentSendBufp <--> gMultiSioArea.nextSendBufp Change Send Buffer
add r8, r11, #OFS_MS_NEXT_SEND_BUF_P
ldmia r8, {r2,r3}
mov r7, r2
stmia r8, {r3,r7}
b 3f
2:
@ } else if (gMultiSioArea.sendBufCounter >= 0) {
@ REG_SIOCNT->data = gMultiSioArea.currentSendBufp[gMultiSioArea.sendBufCounter]
@ Set Send Data
ldr r3, [r11, #OFS_MS_CURRENT_SEND_BUF_P]
ldr r2, [r3, r10, lsl #1]
strh r2, [r12, #REG_SIOMLT_SEND - REG_SIOMLT_RECV]
3:
@ }
@ if (gMultiSioArea.sendBufCounter < sizeof(struct MultiSioPacket) / 2 - 1)
@ gMultiSioArea.sendBufCounter++;
cmp r10, #MULTI_SIO_PACKET_SIZE / 2 - 1
addlt r10, r10, #1
strlt r10, [r11, #OFS_MS_SEND_BUF_COUNTER]
@ Save Receive Data & Register to Stack
stmfd sp!, {r0-r1, r5-r6}
@ Receive Data Processing (Max. Approx. 160 Clocks/Included in Wait Period)
@ for (i = 0; i < MULTI_SIO_PLAYERS_MAX; i++) {
mov r6, #MULTI_SIO_PLAYERS_MAX - 1 @ r6: i
4:
add r8, r11, #OFS_MS_RECV_BUF_COUNTER @ r8: &gMultiSioArea.recvBufCounter[i]
add r8, r8, r6, lsl #2
ldr r10, [r8, #0] @ r10: gMultiSioArea.recvBufCounter[i]
mov r3, r6, lsl #1 @ r5: RecvTmp[i]
ldrh r5, [sp, r3]
@ if ( recvTmp[i] == MULTI_SIO_SYNC_DATA
@ && gMultiSioArea.recvBufCounter[i] > sizeof(struct MultiSioPacket) / 2 - 3) {
cmp r5, r9
bne 6f
cmp r10, #MULTI_SIO_PACKET_SIZE / 2 - 3
ble 6f
@ gMultiSioArea.recvBufCounter[i] = -1
mov r0, #1
sub r10, r0, #2
b 7f
6:
@ } else {
@ gMultiSioArea.currentRecvBufp[i][gMultiSioArea.recvBufCounter[i]] = recvTmp[i]
@ Store Receive Data
ldr r0, [r8, #OFS_MS_CURRENT_RECV_BUF_P - OFS_MS_RECV_BUF_COUNTER]
mov r3, r10, lsl #1
strh r5, [r0, r3]
@ if (gMultiSioArea.recvBufCounter[i] == sizeof(struct MultiSioPacket) / 2 - 3)
cmp r10, #MULTI_SIO_PACKET_SIZE / 2 - 3
bne 7f
@ gMultiSioArea.currentRecvBufp[i] <--> gMultiSioArea.lastRecvBufp[i] Change Receive Buffer
ldr r1, [r8, #OFS_MS_LAST_RECV_BUF_P - OFS_MS_RECV_BUF_COUNTER]
str r0, [r8, #OFS_MS_LAST_RECV_BUF_P - OFS_MS_RECV_BUF_COUNTER]
str r1, [r8, #OFS_MS_CURRENT_RECV_BUF_P - OFS_MS_RECV_BUF_COUNTER]
@ gMultiSioArea.syncRecvFlag[i] = 1; Receive Completion Flag
add r3, r11, #OFS_MS_SYNC_RECV_FLAG
mov r0, #1
strb r0, [r3, r6]
7:
@ }
@ if (gMultiSioArea.recvBufCounter[i] < sizeof(struct MultiSioPacket) / 2 - 1)
@ gMultiSioArea.recvBufCounter[i]++;
cmp r10, #MULTI_SIO_PACKET_SIZE / 2 - 1
addlt r10, r10, #1
str r10, [r8, #0]
subs r6, r6, #1
bge 4b
@ }
@ Start Master Send
@ if (gMultiSioArea.type == SIO_MULTI_PARENT)
ldrb r0, [r11,#OFS_MS_TYPE]
cmp r0, #0
beq 11f
@ *(vu16 *)REG_ADDR_MULTI_SIO_TIMER_H = 0; Stop Timer
ldr r7, =REG_MULTI_SIO_TIMER_H @ r7: REG_MULTI_SIO_TIMER_H
mov r0, #0
strh r0, [r7, #0]
@ REG_SIOCNT |= SIO_ENABLE; Restart Send
ldrh r0, [r12, #REG_SIOCNT - REG_SIOMLT_RECV]
orr r0, r0, #SIO_ENABLE
strh r0, [r12, #REG_SIOCNT - REG_SIOMLT_RECV]
@ *(vu16 *)REG_ADDR_MULTI_SIO_TIMER_H Restart Timer
@ = (TIMER_1CLK | TIMER_INTR_ENABLE | TIMER_ENABLE);
mov r0, #0xC0
strh r0, [r7, #0]
11:
add sp, sp, #8
ldmfd sp!, {r5-r11}
bx lr
arm_func_end MultiSioIntr
.endif

File diff suppressed because it is too large Load Diff

10
asmdiff.sh Normal file
View File

@ -0,0 +1,10 @@
#!/bin/bash
buildname=kirbyamazingmirror
baserom=baserom
OBJDUMP="$DEVKITARM/bin/arm-none-eabi-objdump -D -bbinary -marmv4t -Mforce-thumb"
OPTIONS="--start-address=$(($1)) --stop-address=$(($1 + $2))"
$OBJDUMP $OPTIONS ${baserom}.gba > ${baserom}.dump || exit 1
$OBJDUMP $OPTIONS ${buildname}.gba > ${buildname}.dump
diff -u ${baserom}.dump ${buildname}.dump

142
calcrom.pl Normal file
View File

@ -0,0 +1,142 @@
#!/usr/bin/perl
use IPC::Cmd qw[ run ];
(@ARGV == 1)
or die "ERROR: no map file specified.\n";
open(my $file, $ARGV[0])
or die "ERROR: could not open file '$ARGV[0]'.\n";
my $src = 0;
my $asm = 0;
my $srcdata = 0;
my $data = 0;
while (my $line = <$file>)
{
if ($line =~ /^ \.(\w+)\s+0x[0-9a-f]+\s+(0x[0-9a-f]+) (\w+)\/.+\.o/)
{
my $section = $1;
my $size = hex($2);
my $dir = $3;
if ($size & 3)
{
$size += 4 - ($size % 3);
}
if ($section =~ /text/)
{
if ($dir eq 'src')
{
$src += $size;
}
elsif ($dir eq 'asm')
{
$asm += $size;
}
}
elsif ($section =~ /rodata/)
{
if ($dir eq 'src')
{
$srcdata += $size;
}
elsif ($dir eq 'data')
{
$data += $size;
}
}
}
}
# Note that the grep filters out all branch labels. It also requires a minimum
# line length of 5, to filter out a ton of generated symbols (like AcCn). No
# settings to nm seem to remove these symbols. Finally, nm prints out a separate
# entry for whenever a name appears in a file, not just where it's defined. uniq
# removes all the duplicate entries.
#
#
# You'd expect this to take a while, because of uniq. It runs in under a second,
# though. Uniq is pretty fast!
my $base_cmd = "nm kirbyamazingmirror.elf | awk '{print \$3}' | grep '^[^_].\\{4\\}' | uniq";
# This looks for Unk_, unk_, or sub_, followed by just numbers. Note that
# it matches even if stuff precedes the unk, like sUnk/gUnk.
my $undoc_cmd = "grep '[Uu]nk_[0-9a-fA-F]*\\|sub_[0-9a-fA-F]*'";
# This looks for every symbol with an address at the end of it. Some things are
# given a name based on their type / location, but still have an unknown purpose.
# For example, FooMap_EventScript_FFFFFFF.
my $count_cmd = "wc -l";
# It sucks that we have to run this three times, but I can't figure out how to get
# stdin working for subcommands in perl while still having a timeout. It's decently
# fast anyway.
my $total_syms_as_string;
(run (
command => "$base_cmd | $count_cmd",
buffer => \$total_syms_as_string,
timeout => 60
))
or die "ERROR: Error while getting all symbols: $?";
my $undocumented_as_string;
(run (
command => "$base_cmd | $undoc_cmd | $count_cmd",
buffer => \$undocumented_as_string,
timeout => 60
))
or die "ERROR: Error while filtering for undocumented symbols: $?";
# Performing addition on a string converts it to a number. Any string that fails
# to convert to a number becomes 0. So if our converted number is 0, but our string
# is nonzero, then the conversion was an error.
my $undocumented = $undocumented_as_string + 0;
(($undocumented != 0) and ($undocumented_as_string ne "0"))
or die "ERROR: Cannot convert string to num: '$undocumented_as_string'";
my $total_syms = $total_syms_as_string + 0;
(($total_syms != 0) and ($total_syms_as_string ne "0"))
or die "ERROR: Cannot convert string to num: '$total_syms_as_string'";
($total_syms != 0)
or die "ERROR: No symbols found.";
my $total = $src + $asm;
my $srcPct = sprintf("%.4f", 100 * $src / $total);
my $asmPct = sprintf("%.4f", 100 * $asm / $total);
my $documented = $total_syms - ($undocumented);
my $docPct = sprintf("%.4f", 100 * $documented / $total_syms);
my $undocPct = sprintf("%.4f", 100 * $undocumented / $total_syms);
print "$total total bytes of code\n";
print "$src bytes of code in src ($srcPct%)\n";
print "$asm bytes of code in asm ($asmPct%)\n";
print "\n";
print "$total_syms total symbols\n";
print "$documented symbols documented ($docPct%)\n";
print "$undocumented symbols undocumented ($undocPct%)\n";
my $foundLines = `git grep '\.incbin "baserom\.gba"' data/`;
my @allLines = split('\n', $foundLines);
my $incbinTotal = 0;
my $incbinNum = 0;
foreach my $line (@allLines)
{
if ($line =~ /\.incbin\s+"baserom\.gba",\s*0x\w+,\s*(.+?)\s*(\@.*)?$/)
{
my $size = hex($1);
$incbinTotal += $size;
$incbinNum++;
}
}
print "\n";
my $dataTotal = $srcdata + $data;
my $srcDataPct = sprintf("%.4f", 100 * $srcdata / $dataTotal);
my $dataPct = sprintf("%.4f", 100 * $data / $dataTotal);
my $incbinTotalPct = sprintf("%.4f", 100 * $incbinTotal / $dataTotal);
print "$dataTotal total bytes of data\n";
print "$srcdata bytes of data in src ($srcDataPct%)\n";
print "$data bytes of data in data ($dataPct%)\n";
print "$incbinNum baserom incbins with a combined $incbinTotal bytes ($incbinTotalPct%)\n";

View File

@ -1,2 +1,3 @@
.include "constants/gba_constants.inc"
.include "constants/misc_constants.inc"
.include "constants/multi_sio_constants.inc"

View File

@ -10,9 +10,9 @@
.set PSR_F_BIT, 0x00000040
.set PSR_I_BIT, 0x00000080
.set EWRAM_START, gUnk_02000000
.set EWRAM_START, 0x2000000
.set EWRAM_END, EWRAM_START + 0x40000
.set IWRAM_START, 0x03000000
.set IWRAM_START, 0x3000000
.set IWRAM_END, IWRAM_START + 0x8000
.set PLTT, 0x5000000
@ -488,3 +488,7 @@
.set OAM_SIZE_8x32, OAM_SIZE_1 | OAM_V_RECTANGLE
.set OAM_SIZE_16x32, OAM_SIZE_2 | OAM_V_RECTANGLE
.set OAM_SIZE_32x64, OAM_SIZE_3 | OAM_V_RECTANGLE
@ SIO constants
.set SIO_ENABLE, 0x80

View File

@ -0,0 +1,64 @@
@ Optimize the following settings based on the software specifications
MULTI_SIO_BLOCK_SIZE = 20 @ Communication Data Block Size (Max. 24 Bytes)
MULTI_SIO_PLAYERS_MAX = 4 @ Maximum Number of Players
MULTI_SIO_SYNC_DATA = 0xfefe @ Synchronized Data (0x0000/0xfffa~0xffff prohibited)
@ Comment out if no space in CPU internal Work RAM
MULTI_SIO_DI_FUNC_FAST: @ SIO Interrupt Prohibit Function High Speed Flag (CPU Internal RAM Execution)
MULTI_SIO_TIMER_NO = 3 @ Timer No.
MULTI_SIO_TIMER_INTR_FLAG = (INTR_FLAG_TIMER0 << MULTI_SIO_TIMER_NO)
@ Timer Interrupt Flag
REG_MULTI_SIO_TIMER = (REG_TM0CNT + MULTI_SIO_TIMER_NO * 4)
REG_MULTI_SIO_TIMER_L = REG_MULTI_SIO_TIMER
REG_MULTI_SIO_TIMER_H = (REG_MULTI_SIO_TIMER + 2)
@ Timer Register
@ Multi-play Communication Packet Structure Offset
OFS_MSP_FRAME_COUNTER = 0 @ Frame Counter
OFS_MSP_RECV_ERROR_FLAGS = 1 @ Receive Error Flag
OFS_MSP_CHECK_SUM = 2 @ Checksum
OFS_MSP_DATA = 4 @ Communication Data
OFS_MSP_OVERRUN_CATCH = (OFS_MSP_DATA + MULTI_SIO_BLOCK_SIZE)
@ Overrun Protect Area
MULTI_SIO_PACKET_SIZE = (OFS_MSP_OVERRUN_CATCH + 4)
@ Structure Size
@ Multi-play Communication Work Area Structure Offset
OFS_MS_TYPE = 0 @ Connection (Master/Slave)
OFS_MS_STATE = 1 @ Communication Function State
OFS_MS_CONNECTED_FLAG = 2 @ Connection History Flag
OFS_MS_RECV_SUCCESS_FLAGS = 3 @ Receive Success Flag
OFS_MS_SYNC_RECV_FLAG = 4 @ Synchronized Data Receive Confirmation Flag
OFS_MS_SYNC_RECV_ADJUST_COUNTER = 8 @ Synchronization Adjustment Counter
OFS_MS_SEND_BUF_COUNTER_INIT = 10 @ Send Buffer Counter Initialization
OFS_MS_SYNC_SEND_FRAME_COUNTER = 11 @ Send Frame Counter
OFS_MS_SYNC_RECV_FRAME_COUNTER = 12 @ Receive Frame Counter
OFS_MS_SEND_BUF_COUNTER = 20 @ Send Buffer Counter
OFS_MS_RECV_BUF_COUNTER = 24 @ Receive Buffer Counter
OFS_MS_NEXT_SEND_BUF_P = 40 @ Send Buffer Pointer
OFS_MS_CURRENT_SEND_BUF_P = 44
OFS_MS_CURRENT_RECV_BUF_P = 48 @ Receive Buffer Pointer
OFS_MS_LAST_RECV_BUF_P = 64
OFS_MS_RECV_CHECK_BUF_P = 80
OFS_MS_SEND_BUF = 96 @ Send Buffer (Double Buffer)
OFS_MS_RECV_BUF = (OFS_MS_SEND_BUF + MULTI_SIO_PACKET_SIZE * 2)
@ Receive Buffer (Triple Buffer)
MULTI_SIO_AREA_SIZE = (OFS_MS_RECV_BUF + MULTI_SIO_PACKET_SIZE * 3 * MULTI_SIO_PLAYERS_MAX)
@ Structure Size

File diff suppressed because it is too large Load Diff

1385
data/data_2.s Normal file

File diff suppressed because it is too large Load Diff

7
data/data_3.s Normal file
View File

@ -0,0 +1,7 @@
.include "asm/macros.inc"
.include "constants/constants.inc"
.section .rodata
gUnk_08D6096C:: @ 08D6096C
.incbin "baserom.gba", 0xD6096C, 0x0000010

View File

@ -4,7 +4,10 @@
.section .rodata
gUnk_08D72194:: @ 08D72194
.incbin "baserom.gba", 0xD72194, 0x01C0F10
.incbin "baserom.gba", 0xD72194, 0x01C0C00
gUnk_08F330A4:: @ 08F330A4
.incbin "baserom.gba", 0xF330A4, 0x0000004
gUnk_08F32D94:: @ 08F32D94
.incbin "baserom.gba", 0xF32D94, 0x0000008
gUnk_08F32D9C:: @ 08F32D9C
.incbin "baserom.gba", 0xF32D9C, 0x000001C

100
include/agb_sram.h Normal file
View File

@ -0,0 +1,100 @@
#ifndef GUARD_AGB_SRAM_H
#define GUARD_AGB_SRAM_H
#include "global.h"
#define SRAM 0x0E000000
#ifndef __SRAM_DEBUG
#define SRAM_ADR 0x0e000000 // SRAM Start Address
#define SRAM_SIZE_256K 0x00008000 // 256KSRAM
#define SRAM_SIZE_512K 0x00010000 // 512KSRAM
#else
#define SRAM_ADR 0x02018000
#define SRAM_SIZE_256K 0x00000400
#define SRAM_SIZE_512K 0x00000800
#endif
#define SRAM_RETRY_MAX 3 // Maximum retry number for the
// WriteSramEx function
/*------------------------------------------------------------------
The function group in this header file was also used in the old version.
The static variable area of the main unit WRAM is not used, but please
note that compared to the function group AgbSramFast.h, access to
SRAM is slower.
--------------------------------------------------------------------*/
/*------------------------------------------------------------------*/
/* Read Data */
/*------------------------------------------------------------------*/
extern void ReadSram(const u8 *src,u8 *dst,u32 size) ;
/* From the SRAM address specified by the argument, read "size"
byte of data to area starting from "dst" address in Work.
<Arguments>
const u8 *src : Read source SRAM address (Address on AGB memory map)
u8 *dst : Address of work area where read data is stored
(Address on AGB memory map)
u32 size : Read size in bytes
<Return Values>
None
*/
/*------------------------------------------------------------------*/
/* Write Data */
/*------------------------------------------------------------------*/
extern void WriteSram(const u8 *src,u8 *dst,u32 size) ;
/* From the work area address specified by the argument, write "size"
byte data to area starting from 'dst' address in SRAM.
<Arguments>
const u8 *src : Write source work area address
u8 *dst : Write destination SRAM address
(Address on AGB memory map)
u32 size : Write size in bytes
<Return Values>
None
*/
/*------------------------------------------------------------------*/
/* Verify Data */
/*------------------------------------------------------------------*/
extern u32 VerifySram(const u8 *src,u8 *tgt,u32 size) ;
/* Verify "size" byte of data from "src" address in the work area
and "tgt" address in SRAM.
If verify ends normally this function returns 0, if a verify error
occurs and the address where the error occurred is returned.
<Arguments>
const u8 *src : Pointer to verify source work area address (original data)
u8 *tgt : Pointer to verify target SRAM address
(write destination data, address on AGB memory map)
u32 size : Verify size in bytes
<Return Values>
u32 errorAdr : Normal end => 0
Verify error => Error address on device side
*/
/*------------------------------------------------------------------*/
/* Write data & Verify */
/*------------------------------------------------------------------*/
extern u32 WriteSramEx(const u8 *src, u8 *dst, u32 size) ;
/* This function writes internally using WriteSram and then verifies using VerifySram.
In case of an error, it retries a maximum of SRAM_RETRY_MAX times (defined by AgbSram.h).
<Argument>
const u8 *src : Work area address of write source
u8 *dst : SRAM address of write destination (address on AGB memory map)
u32 size : Write size in number of bytes
<Return value>
u32 errorAdr : Normal end => 0
Verify error => Error address on device side
*/
#endif // GUARD_AGB_SRAM_H

View File

@ -14,6 +14,9 @@
#define EWRAM_DATA __attribute__((section("ewram_data")))
#endif
#define NAKED __attribute__((naked))
#define UNUSED __attribute__((unused))
#define ALIGNED(n) __attribute__((aligned(n)))
#define SOUND_INFO_PTR (*(struct SoundInfo **)0x3007FF0)
@ -86,7 +89,6 @@
#define RGB_CYAN RGB(0, 31, 31)
#define RGB_WHITEALPHA (RGB_WHITE | 0x8000)
#define NAKED __attribute__((naked))
#define UNUSED __attribute__((unused))
#define SYSTEM_CLOCK (16 * 1024 * 1024) // System Clock
#endif // GUARD_GBA_DEFINES

View File

@ -5,7 +5,7 @@
#include "defines.h"
#include "io_reg.h"
#include "types.h"
#include "multiboot.h"
#include "multi_boot.h"
#include "syscall.h"
#include "macro.h"
#include "isagbprint.h"

View File

@ -667,20 +667,40 @@
#define SIO_MULTI_MODE 0x2000 // Multi-player communication mode
#define SIO_UART_MODE 0x3000 // UART communication mode
#define SIO_9600_BPS 0x0000 // baud rate 9600 bps
#define SIO_38400_BPS 0x0001 // 38400 bps
#define SIO_57600_BPS 0x0002 // 57600 bps
#define SIO_115200_BPS 0x0003 // 115200 bps
#define SIO_SCK_OUT 0x0000 // Select external clock
#define SIO_SCK_IN 0x0001 // Select internal clock
#define SIO_IN_SCK_256K 0x0000 // Select internal clock 256KHz
#define SIO_IN_SCK_2M 0x0002 // Select 2MHz
#define SIO_ACK_RECV 0x0004 // Request transfer
#define SIO_ACK_SEND 0x0008 // Enable transfer
#define SIO_9600_BPS 0x0000 // baud rate 9600 bps
#define SIO_38400_BPS 0x0001 // 38400 bps
#define SIO_57600_BPS 0x0002 // 57600 bps
#define SIO_115200_BPS 0x0003 // 115200 bps
#define SIO_MULTI_SI 0x0004 // Multi-player communication SI terminal
#define SIO_MULTI_SD 0x0008 // SD terminal
#define SIO_MULTI_BUSY 0x0080
#define SIO_MULTI_CONNECT 0x0004 // Connecting multi-play communication
#define SIO_MULTI_DISCONNECT 0x0000 // Disconnect
#define SIO_MULTI_PARENT 0x0008 // Multi-play communication Connect master
#define SIO_MULTI_CHILD 0x0000 // Connect slave
#define SIO_MULTI_SI 0x0004 // Multi-play communication SI terminal
#define SIO_MULTI_SD 0x0008 // SD terminal
#define SIO_MULTI_BUSY 0x0080 // Multi-play communicating
#define SIO_CTS_ENABLE 0x0004 // Enable UART send enable signal
#define SIO_UART_7BIT 0x0000 // UART communication data length 7 bit
#define SIO_UART_8BIT 0x0080 // 8 bit
#define SIO_ERROR 0x0040 // Detect error
#define SIO_START 0x0080 // Start transfer
#define SIO_ENABLE 0x0080 // Enable SIO
#define SIO_INTR_ENABLE 0x4000
#define SIO_PARITY_ENABLE 0x0200 // Enable parity
#define SIO_PARITY_EVEN 0x0000 // Even parity
#define SIO_PARITY_ODD 0x0008 // Odd parity
#define SIO_TRANS_ENABLE 0x0400 // Enable transmitter
#define SIO_TRANS_DATA_FULL 0x0010 // Transmitted data full
#define SIO_RECV_ENABLE 0x0800 // Enable receiver
#define SIO_RECV_DATA_EMPTY 0x0020 // No data received
#define SIO_IF_ENABLE 0x4000 // Enable interrupt request
#define SIO_MULTI_SI_SHIFT 2
#define SIO_MULTI_SI_MASK 0x1

View File

@ -100,7 +100,7 @@ struct CgbChannel
u8 le;
u8 sw;
u32 fr;
u32 * wp;
u32 *wp;
u32 cp;
u32 tp;
u32 pp;
@ -182,8 +182,8 @@ struct SoundInfo
void (*CgbOscOff)(u8);
u32 (*MidiKeyToCgbFreq)(u8, u8, u8);
u32 MPlayJumpTable;
u32 plynote;
u32 ExtVolPit;
void *plynote;
void (*ExtVolPit)(void);
u8 gap2[16];
struct SoundChannel chans[MAX_DIRECTSOUND_CHANNELS];
s8 pcmBuffer[PCM_DMA_BUF_SIZE * 2];
@ -199,38 +199,6 @@ struct SongHeader
u8 *part[1];
};
struct PokemonCrySong
{
u8 trackCount;
u8 blockCount;
u8 priority;
u8 reverb;
struct ToneData *tone;
u8 *part[2];
u8 gap;
u8 part0; // 0x11
u8 tuneValue; // 0x12
u8 gotoCmd; // 0x13
u32 gotoTarget; // 0x14
u8 part1; // 0x18
u8 tuneValue2; // 0x19
u8 cont[2]; // 0x1A
u8 volCmd; // 0x1C
u8 volumeValue; // 0x1D
u8 unkCmd0D[2]; // 0x1E
u32 unkCmd0DParam; // 0x20
u8 xreleCmd[2]; // 0x24
u8 releaseValue; // 0x26
u8 panCmd;
u8 panValue; // 0x28
u8 tieCmd; // 0x29
u8 tieKeyValue; // 0x2A
u8 tieVelocityValue; // 0x2B
u8 unkCmd0C[2]; // 0x2C
u16 unkCmd0CParam; // 0x2E
u8 end[2]; // 0x30
};
#define MPT_FLG_VOLSET 0x01
#define MPT_FLG_VOLCHG 0x03
#define MPT_FLG_PITSET 0x04
@ -334,21 +302,10 @@ struct Song
extern const struct MusicPlayer gMPlayTable[];
extern const struct Song gSongTable[];
extern u8 gMPlayMemAccArea[];
//u8 gPokemonCrySong[52];
//u8 gPokemonCrySongs[52 * MAX_POKEMON_CRIES];
#define MAX_POKEMON_CRIES 2
extern struct PokemonCrySong gPokemonCrySong;
extern struct PokemonCrySong gPokemonCrySongs[];
extern struct MusicPlayerInfo gPokemonCryMusicPlayers[];
extern struct MusicPlayerTrack gPokemonCryTracks[];
extern char SoundMainRAM[];
extern void *gMPlayJumpTable[];
@ -357,6 +314,7 @@ typedef void (*XcmdFunc)(struct MusicPlayerInfo *, struct MusicPlayerTrack *);
extern const XcmdFunc gXcmdTable[];
extern struct CgbChannel gCgbChans[];
extern const u8 gCgb3Vol[];
extern const u8 gScaleTable[];
extern const u32 gFreqTable[];
@ -366,10 +324,6 @@ extern const u8 gCgbScaleTable[];
extern const s16 gCgbFreqTable[];
extern const u8 gNoiseTable[];
extern const struct PokemonCrySong gPokemonCrySongTemplate;
extern const struct ToneData voicegroup000;
extern char gNumMusicPlayers[];
extern char gMaxLines[];
@ -398,7 +352,7 @@ void MPlayOpen(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track
void CgbSound(void);
void CgbOscOff(u8);
u32 MidiKeyToCgbFreq(u8, u8, u8);
void DummyFunc(void);
void nullsub_141(void);
void MPlayJumpTableCopy(void **mplayJumpTable);
void SampleFreqSet(u32 freq);
void m4aSoundVSyncOn(void);
@ -412,18 +366,6 @@ void ClearModM(struct MusicPlayerTrack *track);
void m4aMPlayModDepthSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 modDepth);
void m4aMPlayLFOSpeedSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 lfoSpeed);
struct MusicPlayerInfo *SetPokemonCryTone(struct ToneData *tone);
void SetPokemonCryVolume(u8 val);
void SetPokemonCryPanpot(s8 val);
void SetPokemonCryPitch(s16 val);
void SetPokemonCryLength(u16 val);
void SetPokemonCryRelease(u8 val);
void SetPokemonCryProgress(u32 val);
int IsPokemonCryPlaying(struct MusicPlayerInfo *mplayInfo);
void SetPokemonCryChorus(s8 val);
void SetPokemonCryStereo(u32 val);
void SetPokemonCryPriority(u8 val);
// sound command handler functions
void ply_fine(struct MusicPlayerInfo *, struct MusicPlayerTrack *);
void ply_goto(struct MusicPlayerInfo *, struct MusicPlayerTrack *);

106
include/gba/multi_boot.h Normal file
View File

@ -0,0 +1,106 @@
#ifndef GUARD_GBA_MULTI_BOOT_H
#define GUARD_GBA_MULTI_BOOT_H
#define MULTIBOOT_NCHILD 3 // Maximum number of slaves
#define MULTIBOOT_HEADER_SIZE 0xc0 // Header size
#define MULTIBOOT_SEND_SIZE_MIN 0x100 // Minimum transmission size
#define MULTIBOOT_SEND_SIZE_MAX 0x40000 // Maximum transmission size
struct MultiBootParam
{
u32 system_work[5]; // Can be rewritten within system call.
// Used with library also.
u8 handshake_data; // Handshake data from client
u8 padding;
u16 handshake_timeout; // Handshake timeout check counter
u8 probe_count; // If not 0, during client recognition or
// boot program transfer
u8 client_data[MULTIBOOT_NCHILD]; // Handshake data from client
u8 palette_data; // Palette's flashing parameter during load
// for client
u8 response_bit; // When high probability that slave
// connected, 4P-2P: d3-d1 is 1.
u8 client_bit; // For slave distinguished as client,
// 4P-2P: d3-d1 is 1.
u8 reserved1; // Reserved
const u8 *boot_srcp; // Boot program start (after header)
const u8 *boot_endp; // Boot program end pointer
const u8 *masterp; // Pointer to header referenced and output
// by master
u8 *reserved2[MULTIBOOT_NCHILD]; // Reserved
u32 system_work2[4]; // Can be rewritten within system call.
u8 sendflag; // If SC7=1 and during send, not 0
u8 probe_target_bit; // If target recognized with client,
// 4P-2P: d3-d1 is 1.
u8 check_wait; // Wait frame until recoginition with client
u8 server_type; // client recognize method 0= Low Speed
// 1= High Speed
};
/* Error Code
* If value returned by MultiBootMain() is not 0, an error listed
* below has occurred. However, there is no need to have separate error
* messages for all error code types.
* "Communication Error. Please check connection. Retry with START."
* "Turn off power, check connection, and turn on again."
* "Slave is not connected."
* "Cannot recognize the slave."
* ,etc. Messages easy for the player to understand are good.
* NO_PROBE_TARGET: When recognizing client all machines returned
* abnormal data and there is no target.
* NO_DLREADY: client did not return a download preparations
* possible message.
* BOOT_FAILURE: MultiBoot() system call returned an error.
* HANDSHAKE_FAILURE: Failed to do handshake with master which should
* occur immediately after boot of slave.
* (Slave may be in infinite loop, request that power be turned off
* and on again.)
*/
#define MULTIBOOT_ERROR_04 0x04
#define MULTIBOOT_ERROR_08 0x08
#define MULTIBOOT_ERROR_0c 0x0c
#define MULTIBOOT_ERROR_40 0x40
#define MULTIBOOT_ERROR_44 0x44
#define MULTIBOOT_ERROR_48 0x48
#define MULTIBOOT_ERROR_4c 0x4c
#define MULTIBOOT_ERROR_80 0x80
#define MULTIBOOT_ERROR_84 0x84
#define MULTIBOOT_ERROR_88 0x88
#define MULTIBOOT_ERROR_8c 0x8c
#define MULTIBOOT_ERROR_NO_PROBE_TARGET 0x50
#define MULTIBOOT_ERROR_NO_DLREADY 0x60
#define MULTIBOOT_ERROR_BOOT_FAILURE 0x70
#define MULTIBOOT_ERROR_HANDSHAKE_FAILURE 0x71
/* After an error, or when a value other than 0xffff is returned,
* the avoid chattering wait(frames) until redo connection check.
* The client timeout is about 11 frames so use value sufficiently
* longer than this.
* Usually during this time the MASTER_INFO is sent, but when there
* is a system call error, nothing is sent at this time and it waits.
* Then, during this time period MASTER_INFO is sent.
*/
#define MULTIBOOT_CONNECTION_CHECK_WAIT 15
/* Recognition of Slave
* Value set in MultiBootParam structure member server_type
* MULTIBOOT_SERVER_TYPE_NORMAL: Slow speed recognition mode
* The MultiBootMain() function communicates 2 bytes with one call.
* Therefore, processing returns from MultiBootMain() function
* in short time.
* MULTIBOOT_SERVER_TYPE_QUICK: High speed recognition mode
* In MultiBootMain() function as many consecutive communications
* are done as possible.
* Therefore, processing may not return from MultiBootMain() for
* several dozen frames.
* During this time, there is no problem if processing for sound and
* display cannot be done. If processing for sound and display is
* done with timer interrupt processing, you can use.
*/
#define MULTIBOOT_SERVER_TYPE_NORMAL 0
#define MULTIBOOT_SERVER_TYPE_QUICK 1
/* Timeout for slave's final start up check 400 frames */
#define MULTIBOOT_HANDSHAKE_TIMEOUT 400
#endif // GUARD_GBA_MULTI_BOOT_H

View File

@ -1,55 +0,0 @@
#ifndef GUARD_GBA_MULTIBOOT_H
#define GUARD_GBA_MULTIBOOT_H
#define MULTIBOOT_NCHILD 3 // Maximum number of slaves
#define MULTIBOOT_HEADER_SIZE 0xc0 // Header size
#define MULTIBOOT_SEND_SIZE_MIN 0x100 // Minimum transmission size
#define MULTIBOOT_SEND_SIZE_MAX 0x40000 // Maximum transmission size
struct MultiBootParam
{
u32 system_work[5];
u8 handshake_data;
u8 padding;
u16 handshake_timeout;
u8 probe_count;
u8 client_data[MULTIBOOT_NCHILD];
u8 palette_data;
u8 response_bit;
u8 client_bit;
u8 reserved1;
const u8 *boot_srcp;
const u8 *boot_endp;
const u8 *masterp;
u8 *reserved2[MULTIBOOT_NCHILD];
u32 system_work2[4];
u8 sendflag;
u8 probe_target_bit;
u8 check_wait;
u8 server_type;
};
#define MULTIBOOT_ERROR_04 0x04
#define MULTIBOOT_ERROR_08 0x08
#define MULTIBOOT_ERROR_0c 0x0c
#define MULTIBOOT_ERROR_40 0x40
#define MULTIBOOT_ERROR_44 0x44
#define MULTIBOOT_ERROR_48 0x48
#define MULTIBOOT_ERROR_4c 0x4c
#define MULTIBOOT_ERROR_80 0x80
#define MULTIBOOT_ERROR_84 0x84
#define MULTIBOOT_ERROR_88 0x88
#define MULTIBOOT_ERROR_8c 0x8c
#define MULTIBOOT_ERROR_NO_PROBE_TARGET 0x50
#define MULTIBOOT_ERROR_NO_DLREADY 0x60
#define MULTIBOOT_ERROR_BOOT_FAILURE 0x70
#define MULTIBOOT_ERROR_HANDSHAKE_FAILURE 0x71
#define MULTIBOOT_CONNECTION_CHECK_WAIT 15
#define MULTIBOOT_SERVER_TYPE_NORMAL 0
#define MULTIBOOT_SERVER_TYPE_QUICK 1
#define MULTIBOOT_HANDSHAKE_TIMEOUT 400
#endif // GUARD_GBA_MULTIBOOT_H

View File

@ -142,6 +142,31 @@ struct ObjAffineSrcData
u16 rotation;
};
// Normal SIO Control Structure
struct SioNormalCnt
{
u16 sck_I_O:1; // Clock I/O Select
u16 sck:1; // Internal Clock Select
u16 ackRecv:1; // Transfer Enable Flag Receive
u16 ackSend:1; // Transfer Enable Flag Send
u16 unused_6_4:3;
u16 enable:1; // SIO Enable
u16 unused_11_8:4;
u16 mode:2; // Communication Mode Select
u16 ifEnable:1; // Interrupt Request Enable
u16 unused_15:1;
u8 data; // Data
u8 unused_31_24;
};
#define ST_SIO_8BIT_MODE 0 // Normal 8-bit communication mode
#define ST_SIO_32BIT_MODE 1 // Normal 32-bit communication mode
#define ST_SIO_SCK_OUT 0 // Select external clock
#define ST_SIO_SCK_IN 1 // Select internal clock
#define ST_SIO_IN_SCK_256K 0 // Select internal clock 256KHz
#define ST_SIO_IN_SCK_2M 1 // Select 2MHz
// Multi-player SIO Control Structure
struct SioMultiCnt
{
@ -153,17 +178,91 @@ struct SioMultiCnt
u16 enable:1; // SIO enable
u16 unused_11_8:4;
u16 mode:2; // communication mode (should equal 2)
u16 intrEnable:1; // IRQ enable
u16 ifEnable:1; // IRQ enable
u16 unused_15:1;
u16 data; // data
};
#define ST_SIO_MULTI_MODE 2 // Multi-player communication mode
#define ST_SIO_MULTI_MODE 2 // Multi-play communication mode
// baud rate
#define ST_SIO_9600_BPS 0 // 9600 bps
#define ST_SIO_38400_BPS 1 // 38400 bps
#define ST_SIO_57600_BPS 2 // 57600 bps
#define ST_SIO_115200_BPS 3 // 115200 bps
#define ST_SIO_9600_BPS 0 // Baud rate 9600 bps
#define ST_SIO_38400_BPS 1 // 38400 bps
#define ST_SIO_57600_BPS 2 // 57600 bps
#define ST_SIO_115200_BPS 3 // 115200 bps
#define ST_SIO_MULTI_PARENT 1 // Multi-play communication Connect master
#define ST_SIO_MULTI_CHILD 0 // Connect slave
// UART - SIO Control Structure
struct SioUartCnt
{
u16 baudRate:2; // Baud Rate
u16 ctsEnable:1; // Send Signal Enable
u16 paritySelect:1; // Parity Even/Odd
u16 transDataFull:1; // Transmit Data Full
u16 recvDataEmpty:1; // Receive Data Empty
u16 error:1; // Error Detect
u16 length:1; // Data Length
u16 fifoEnable:1; // FIFO Enable
u16 parityEnable:1; // Parity Enable
u16 transEnable:1; // Transmitter Enable
u16 recvEnable:1; // Receiver Enable
u16 mode:2; // Communication Mode Select
u16 ifEnable:1; // Interrupt Request Enable
u16 unused_15:1;
u8 data; // Data
u8 unused_31_24;
};
#define ST_SIO_UART_MODE 3 // UART communication mode
#define ST_SIO_UART_7BIT 0 // UART communication data length 7 bits
#define ST_SIO_UART_8BIT 1 // 8 bits
#define ST_SIO_PARITY_EVEN 0 // Even parity
#define ST_SIO_PARITY_ODD 1 // Odd parity
// JOY Bus Communication Control Structure
struct JoyCnt
{
u8 ifReset:1; // JOY Bus Reset Interrupt Request
u8 ifRecv:1; // JOY Bus Received Interrupt Request
u8 ifSend:1; // JOY Bus Sent Interrupt Request
u8 unused_5_3:3;
u8 ifEnable:1; // Interrupt Request Enable
u8 unused_7:1;
};
// JOY Bus Communication Status Structure
struct JoyStat
{
u8 unused_0:1;
u8 recv:1; // Receive Status
u8 unused_2:1;
u8 send:1; // Send Status
u8 flags:2; // General Flag
u8 unused_7_6:2;
};
// General Input/Output Control Structure
struct RCnt
{
u8 sc:1; // Data
u8 sd:1;
u8 si:1;
u8 so:1;
u8 sc_i_o:1; // I/O Select
u8 sd_i_o:1;
u8 si_i_o:1;
u8 so_i_o:1;
u8 ifEnable:1; // Interrupt Request Enable
u8 unused_13_9:5;
u8 sioModeMaster:2; // SIO Mode Master
};
#define ST_R_SIO_MASTER_MODE 0 // SIO master mode
#define ST_R_DIRECT_MODE 2 // General input/output communication mode
#define ST_R_JOY_MODE 3 // JOY communication mode
#define ST_R_IN 0 // Select input
#define ST_R_OUT 1 // Select output
#endif // GUARD_GBA_TYPES_H

99
include/multi_boot.h Normal file
View File

@ -0,0 +1,99 @@
#ifndef GUARD_MULTI_BOOT_H
#define GUARD_MULTI_BOOT_H
#include "global.h"
/* From MASTER_INFO to MASTER_START_DL are upper values.
* From MASTER_REQUEST_CRC to MASTER_VERIFY_CRC are lower values (Upper=0)
*/
#define MULTIBOOT_MASTER_INFO 0x62
#define MULTIBOOT_CLIENT_INFO 0x72
#define MULTIBOOT_MASTER_START_PROBE 0x61
#define MULTIBOOT_MASTER_REQUEST_DLREADY 0x63
#define MULTIBOOT_CLIENT_DLREADY 0x73
#define MULTIBOOT_MASTER_START_DL 0x64
#define MULTIBOOT_MASTER_REQUEST_CRC 0x65
#define MULTIBOOT_CLIENT_CALC_CRC 0x74
#define MULTIBOOT_CLIENT_CRCREADY 0x75
#define MULTIBOOT_MASTER_VERIFY_CRC 0x66
/*------------------------------------------------------------------*/
/* Initialize Multi-play Boot */
/*------------------------------------------------------------------*/
extern void MultiBootInit(struct MultiBootParam *mp);
//* Sets serial communication mode as multi-play mode.
//* Basically, SIO_INTR_FLAG of IE is cleared, however it is acceptable to use SIO interrupt.
//
//* does not set mp -> masterp.
// Make sure to set up before calling this initialization function.
/*------------------------------------------------------------------*/
/* Multi-play Boot Main */
/*------------------------------------------------------------------*/
extern s32 MultiBootMain(struct MultiBootParam *mp);
//* Basically, call it once per frame.
// However, if there is a wait long enough, it is acceptable to call it multiple times per frame.
// The safe length of wait time depends on the application.
// (It is necessary to make the wait longer than the time it takes to process the interrupts of long period of time,
// including V-Blank interrupts.)
//
//* Returns 0 in normal completion.
//
//* Returns 0 when transfer ends (successfully) and a value of MultiBootCheckComplete() other than 0.
//
//* Once it is in the transfer end status, it simply returns 0 immediately.
// In order to cancel this status, call MultiBootInit().
// It is acceptable to call MultiBootStartProbe() or MultiBootStartMaster(), however, they are internally
// calling MultiBootInit().
/*------------------------------------------------------------------*/
/* Starts Client Recognition */
/*------------------------------------------------------------------*/
extern void MultiBootStartProbe(struct MultiBootParam *mp);
// After calling this, the client's recognition processing is done with // MultiBootMain().
// Call after verifying mp -> probe_count is 0.
/*------------------------------------------------------------------*/
/* Starts Transfer from Master Server */
/*------------------------------------------------------------------*/
extern void MultiBootStartMaster(struct MultiBootParam *mp, const u8 *srcp, s32 length, u8 palette_color, s8 palette_speed);
//* Among the units connected by multi-play communication cable, only those units with game pak inserted
// can become master server.
//
// srcp Pointer for the program that you want to boot
// (requires 4-byte alignment)
// For clients, it is downloaded immediately after the header.
// length Transfer byte count of program.
// MULTIBOOT_SEND_SIZE_MIN (0x100) bytes or more and
// MULTIBOOT_SEND_SIZE_MAX (0x40000) bytes or less.
// "palette_color" and "palette_speed" are palette flash parameters of client while loading.
// palette_color uses 0 to 6 to specify the basic palettes (7 types)
// With "palette_speed", it flashes in reversal order from -4 to -1 (-4 being the fastest) and it flashes in normal
// from +1 to +4 (+4 being the fastest)
// Palette is fixed (no flash) at 0.
// Do not specify any values other than listed above.
/*------------------------------------------------------------------*/
/* Check Transfer Completion */
/*------------------------------------------------------------------*/
extern s32 MultiBootCheckComplete(struct MultiBootParam *mp);
//* Check if transfer has completed.
//
//* Returns a value other than 0 if transfer has completed (successfully).
// Returns 0 if it is still recognizing, has not started transfer, or transfer has failed.
//
//* Calling any one of MultiBootInit(), MultiBootStartProbe() or MultiBootStartMaster()
// cancels the transfer completion status.
#endif // GUARD_MULTI_BOOT_H

264
include/multi_sio.h Normal file
View File

@ -0,0 +1,264 @@
#ifndef GUARD_MULTI_SIO_H
#define GUARD_MULTI_SIO_H
#include "global.h"
// Optimize the following settings based on the software specifications
#define MULTI_SIO_BLOCK_SIZE 20 // Communication Data Block Size (Max. 24 Bytes)
#define MULTI_SIO_PLAYERS_MAX 4 // Maximum Number of Players
#define MULTI_SIO_SYNC_DATA 0xfefe // Synchronized Data (0x0000/0xfffa~0xffff prohibited)
// Comment out if no space in CPU internal Work RAM
#define MULTI_SIO_DI_FUNC_FAST // SIO Interrupt Prohibit Function High Speed Flag (CPU Internal RAM Execution)
// Update if maximum delay for communication interrupt is larger than following.
#define MULTI_SIO_INTR_DELAY_MAX 2000 // Communication Interrupt Allowed Delay Clocks
#ifdef MULTI_SIO_DI_FUNC_FAST
#define MULTI_SIO_INTR_CLOCK_MAX 400 // Communication Interrupt Processing Maximum Clocks
#else
#define MULTI_SIO_INTR_CLOCK_MAX 1000
#endif
#define MULTI_SIO_1P_SEND_CLOCKS 3000 // Communication Time for 1 unit
#if MULTI_SIO_PLAYERS_MAX == 4
#define MULTI_SIO_START_BIT_WAIT 0 // Start Bit Wait Time
#else
#define MULTI_SIO_START_BIT_WAIT 512
#endif
// During development set NDEBUG to undefined and value below to 0,
// define with last check and confirm operation with changed to 600.
// (Even if increase setting the communication interval increases, but
// processing doesn't slow).
//#define NDEBUG // Can define with Makefile (MakefileDemo)
#ifdef NDEBUG
#define MULTI_SIO_INTR_MARGIN 600 // Communication Interrupt Error Guarantee Value
#else
#define MULTI_SIO_INTR_MARGIN 0
#endif
#define MULTI_SIO_BAUD_RATE 115200 // Baud Rate
#define MULTI_SIO_BAUD_RATE_NO SIO_115200_BPS // Baud Rate No.
#define MULTI_SIO_TIMER_NO 3 // Timer No.
#define MULTI_SIO_TIMER_INTR_FLAG (INTR_FLAG_TIMER0 << MULTI_SIO_TIMER_NO)
#define REG_MULTI_SIO_TIMER (*(vu32 *)(REG_ADDR_TMCNT + (MULTI_SIO_TIMER_NO * 4)))
#define REG_MULTI_SIO_TIMER_L (*(vu16 *)(REG_ADDR_TMCNT_L + (MULTI_SIO_TIMER_NO * 4)))
#define REG_MULTI_SIO_TIMER_H (*(vu16 *)(REG_ADDR_TMCNT_H + (MULTI_SIO_TIMER_NO * 4)))
// Timer Register
// Timer count number is calculated from communication data block size.
#define MULTI_SIO_TIMER_COUNT_TMP (SYSTEM_CLOCK / 60 / ((2 + 4 + MULTI_SIO_BLOCK_SIZE + 6) / (16 / 8)))
// Timer Count Temporary Value
#define MULTI_SIO_TIMER_COUNT_MIN ( MULTI_SIO_1P_SEND_CLOCKS * MULTI_SIO_PLAYERS_MAX \
+ MULTI_SIO_START_BIT_WAIT + MULTI_SIO_INTR_MARGIN \
+ MULTI_SIO_INTR_DELAY_MAX + MULTI_SIO_INTR_CLOCK_MAX)
// Timer Count Minimum Value
#define MULTI_SIO_TIMER_COUNT_MAX 0x10000 // Timer Count Maximum Value
#define MULTI_SIO_TIMER_COUNT (MULTI_SIO_TIMER_COUNT_MAX - MULTI_SIO_TIMER_COUNT_TMP)
// Timer Count
// Timer Count Setting Error
#if MULTI_SIO_TIMER_COUNT_TMP < MULTI_SIO_TIMER_COUNT_MIN
#error MULTI_SIO_TIMER_COUNT is too short,
#error because MULTI_SIO_BLOCK_SIZE or MULTI_SIO_INTR_DELAY_MAX is too large.
#elif MULTI_SIO_TIMER_COUNT_TMP > MULTI_SIO_TIMER_COUNT_MAX
#error MULTI_SIO_TIMER_COUNT is too long.
#endif
// Multi-play Communication Packet Structure
struct MultiSioPacket
{
u8 frameCounter; // Frame Counter
u8 recvErrorFlags:4; // Receive Error Flag
u8 loadRequest:1; // Load Request
u8 downloadSuccessFlag:1; // Download Success Flag
u8 loadSuccessFlag:1; // Load Success
u8 reserved_0:1; // Reserved
u16 checkSum; // Checksum
u16 data[MULTI_SIO_BLOCK_SIZE / 2]; // Communication Data
u16 overrunCatch[2]; // Overrun Protect Area
};
// Multi-play Communication Work Area Structure
struct MultiSioArea
{
u8 type; // Connection (Master/Slave)
u8 state; // Communication Function State
u8 connectedFlags; // Connection History Flag
u8 recvSuccessFlags; // Receive Success Flag
u8 syncRecvFlag[4]; // Receive Confirmation Flag
u8 downloadSuccessFlags:4; // Download Success Flag
u8 loadEnable:1; // Enable Load
u8 loadRequest:1; // Load Request
u8 loadSuccessFlag:1; // Load Success
u8 startFlag:1; // Communication Start Flag
u8 hardError; // Hard error
u8 recvFlagsAvailableCounter; // Receiving success flag validation counter
u8 sendFrameCounter; // Send Frame Counter
u8 recvFrameCounter[4][2]; // Receive Frame Counter
s32 sendBufCounter; // Send Buffer Counter
s32 recvBufCounter[4]; // Receive Buffer Counter
u16 *nextSendBufp; // Send Buffer Pointer
u16 *currentSendBufp;
u16 *currentRecvBufp[4]; // Receive Buffer Pointer
u16 *lastRecvBufp[4];
u16 *recvCheckBufp[4];
struct MultiSioPacket sendBuf[2]; // Send Buffer (Double Buffer)
struct MultiSioPacket recvBuf[MULTI_SIO_PLAYERS_MAX][3];
// Receive Buffer (Triple Buffer)
};
extern u32 gMultiSioRecvFuncBuf[0x40 / 4]; // Receive Data/Check Buffer Change Routine RAM Execution Buffer
extern u32 gMultiSioIntrFuncBuf[0x180 / 4]; // Interrupt Routine RAM Execution Buffer
extern struct MultiSioArea gMultiSioArea; // Multi-play Communication Work Area
/*------------------------------------------------------------------*/
/* Multi-play Communication Initialization */
/*------------------------------------------------------------------*/
extern void MultiSioInit(u32 connectedFlags);
//* Set serial communication mode to multi-play mode.
//* Initialize register and buffer.
//* Arguments:
// u32 connectedFlags Set appropriate flag if a unit recognized as connected
/*------------------------------------------------------------------*/
/* Start Multi-play Communication */
/*------------------------------------------------------------------*/
void MultiSioStart(void);
//* If following master recognition set flag to start send.
//* If slave or prior to master recognition do nothing.
/*------------------------------------------------------------------*/
/* Stop Multi-play Communication */
/*------------------------------------------------------------------*/
void MultiSioStop(void);
//* Stop Communication
/*------------------------------------------------------------------*/
/* Multi-play Communication Main */
/*------------------------------------------------------------------*/
extern u32 MultiSioMain(void *sendp, void *recvp, u32 loadRequest);
//* First determine if master or slave. If master recognized, initialize
// timer.
//* Call MultiSioSendDataSet() and set send data.
//* Call MultiSioRecvDataCheck() and check if normal receive done,
// and copy receive data to Recvp.
//
//* Set so called with as close a timing as possible within 1 frame.
//* Safer not to send data that matches flag data (SIO_SYNC_DATA) prior
// to connection determination.
//
//* Arguments:
// void *sendp User Send Buffer Pointer
// void *recvp User Receive Buffer Pointer
// u32 loadRequest Load Request
//* Return Value:
#define MULTI_SIO_RECV_ID_MASK 0x000f // Receive Success Flag
#define MULTI_SIO_CONNECTED_ID_MASK 0x0f00 // Connection History Flag
#define MULTI_SIO_RECV_ID0 0x0001 // Receive Success Flag Master
#define MULTI_SIO_RECV_ID1 0x0002 // Slave 1
#define MULTI_SIO_RECV_ID2 0x0004 // Slave 2
#define MULTI_SIO_RECV_ID3 0x0008 // Slave 3
#define MULTI_SIO_LD_ENABLE 0x0010 // Enable Load
#define MULTI_SIO_LD_REQUEST 0x0020 // Load Request
#define MULTI_SIO_LD_SUCCESS 0x0040 // Load Success
#define MULTI_SIO_TYPE 0x0080 // Connection (Master/Slave)
#define MULTI_SIO_PARENT 0x0080 // Master Connection
#define MULTI_SIO_CHILD 0x0000 // Slave Connection
#define MULTI_SIO_CONNECTED_ID0 0x0100 // Connection History Flag Master
#define MULTI_SIO_CONNECTED_ID1 0x0200 // Slave 1
#define MULTI_SIO_CONNECTED_ID2 0x0400 // Slave 2
#define MULTI_SIO_CONNECTED_ID3 0x0800 // Slave 3
#define MULTI_SIO_UNK_x1000 0x1000
#define MULTI_SIO_UNK_x2000 0x2000
// Return Value Structure
struct MultiSioReturn
{
u32 recvSuccessFlags:4; // Receive Success Flag
u32 loadEnable:1; // Enable Load
u32 loadRequest:1; // Load Request
u32 loadSuccessFlag:1; // Load Success
u32 type:1; // Connection (Master/Slave)
u32 connectedFlags:4; // Connection History Flag
u32 multisioreturn_unk00_0c:1;
u32 multisioreturn_unk00_0d:1;
};
/*------------------------------------------------------------------*/
/* Multi-play Communication Interrupt */
/*------------------------------------------------------------------*/
extern void MultiSioIntr(void);
//* During communication interrupt, store receive data from each unit
// in each receive buffer and set the send buffer data to the register.
//* If master, reset timer and restart send.
//
//* Program so slave is called with communication interrupt and master
// is called with timer interrupt.
//* Adjust setting so 1 packet (Except for OverRunCatch[]) can be
// transfered with 1 frame.
/*------------------------------------------------------------------*/
/* Set Send Data */
/*------------------------------------------------------------------*/
extern void MultiSioSendDataSet(void *sendp, u32 loadReq);
//* Set the user send buffer data to send buffer.
//
//* Called from MultiSioMain().
//* Not necessary to call directly.
//
//* Arguments:
// void *sendp User Send Buffer Pointer
// u32 loadReq Load Request
/*------------------------------------------------------------------*/
/* Check Receive Data */
/*------------------------------------------------------------------*/
extern u32 MultiSioRecvDataCheck(void *recvp);
//* Check if receive done normally. If normal, copy the receive data
// to the user receive buffer.
//
//* Called from MultiSioMain().
//* Do not need to call directly.
//
//* Arguments:
// void *recvp User Receive Buffer Pointer
#endif // GUARD_MULTI_SIO_H

View File

@ -1,17 +0,0 @@
#ifndef GUARD_MULTIBOOT_H
#define GUARD_MULTIBOOT_H
#include "global.h"
#define MULTIBOOT_MASTER_INFO 0x62
#define MULTIBOOT_CLIENT_INFO 0x72
#define MULTIBOOT_MASTER_START_PROBE 0x61
#define MULTIBOOT_MASTER_REQUEST_DLREADY 0x63
#define MULTIBOOT_CLIENT_DLREADY 0x73
#define MULTIBOOT_MASTER_START_DL 0x64
#define MULTIBOOT_MASTER_REQUEST_CRC 0x65
#define MULTIBOOT_CLIENT_CALC_CRC 0x74
#define MULTIBOOT_CLIENT_CRCREADY 0x75
#define MULTIBOOT_MASTER_VERIFY_CRC 0x66
#endif // GUARD_MULTIBOOT_H

141
include/sio32_multi_load.h Normal file
View File

@ -0,0 +1,141 @@
#ifndef GUARD_SIO32_MULTI_LOAD_H
#define GUARD_SIO32_MULTI_LOAD_H
#include "multi_sio.h"
// Optimize the following settings based on the software specifications
#define SIO32ML_BLOCK_SIZE 0x8000 // Communication Data Block Size
// Update if maximum delay for communication interrupt is larger than following.
#define SIO32ML_INTR_DELAY_MAX 1000 // Communication Interrupt Allowed Delay Clocks
#define SIO32ML_INTR_CLOCK_MAX 256 // Communication Interrupt Processing Maximum Clocks
#define SIO32ML_SYNC_DATA 0xfefefefe // Synchronized Data (0x00000000and 0xffffffff prohibited)
#define SIO32ML_SYSTEM_CLOCK (16 * 1024 * 1024)// System Clock
#define SIO32ML_SHIFT_CLOCK (256 * 1024) // Shift Clock
#define SIO32ML_LINE_CLOCKS 1232 // Line Clocks
// Comment out if no space in CPU internal Work RAM
#ifdef MULTI_SIO_DI_FUNC_FAST
// #define SIO32ML_DI_FUNC_FAST // SIO Interrupt Prohibit Function High Speed Flag (CPU Internal RAM Execution)
#endif
#define SIO32ML_TIMER_NO 3 // Timer No.
#define SIO32ML_TIMER_INTR_FLAG (INTR_FLAG_TIMER0 << SIO32ML_TIMER_NO)
// Timer Interrupt Flag
#define REG_SIO32ML_TIMER (*(vu32 *)(REG_ADDR_TMCNT + (SIO32ML_TIMER_NO * 4)))
#define REG_SIO32ML_TIMER_L (*(vu16 *)(REG_ADDR_TMCNT_L + (SIO32ML_TIMER_NO * 4)))
#define REG_SIO32ML_TIMER_H (*(vu16 *)(REG_ADDR_TMCNT_H + (SIO32ML_TIMER_NO * 4)))
// Timer Register
// Timer count temporary value is calculated from communication data block size.
#define SIO32ML_TIMER_COUNT_TMP (SIO32ML_SYSTEM_CLOCK / SIO32ML_SHIFT_CLOCK * 32 \
+ SIO32ML_INTR_DELAY_MAX + SIO32ML_INTR_CLOCK_MAX)
// Timer Count Temporary Value
#define SIO32ML_TIMER_COUNT_MAX 0x10000 // Timer Count Maximum Value
#define SIO32ML_TIMER_COUNT ((SIO32ML_TIMER_COUNT_TMP > SIO32ML_TIMER_COUNT_MAX) \
? SIO32ML_TIMER_COUNT_MAX - SIO32ML_TIMER_COUNT_MAX \
: SIO32ML_TIMER_COUNT_MAX - SIO32ML_TIMER_COUNT_TMP)
// Timer Count
// Load timeout frames is calculated from above values.
#define SIO32ML_MODE_WAIT_FRAMES 6 // SIO Mode Switch Wait Frames
#define SIO32ML_LD_TIMEOUT_FRAMES (((SIO32ML_TIMER_COUNT_MAX - SIO32ML_TIMER_COUNT \
+ SIO32ML_INTR_DELAY_MAX + SIO32ML_INTR_CLOCK_MAX) \
* (SIO32ML_BLOCK_SIZE / 4)) / (SIO32ML_LINE_CLOCKS * 228) \
+ SIO32ML_MODE_WAIT_FRAMES + 2)
// Load timeout frames
// 32bit Serial Communication Multi-load Work Area Structure
struct Sio32MultiLoadArea
{
u8 type; // Connection (Master/Slave)
u8 state; // Communication Function State
u8 frameCounter; // Frame Counter
u8 downloadSuccessFlag; // Download Success Flag
u32 *datap; // Data Pointer
s32 dataCounter; // Data Counter
u32 checkSum; // Checksum
u32 checkSumTmp;
s32 checkSumCounter; // Checksum Counter
};
extern struct Sio32MultiLoadArea gSio32MultiLoadArea; // 32bit Serial Communication Multi-load Work Area
/*------------------------------------------------------------------*/
/* 32bit Serial Communication Multi-load Intialization */
/*------------------------------------------------------------------*/
extern void Sio32MultiLoadInit(u32 type, void *datap);
//* Initialize register and buffer.
//* To avoid problem with shift clock synchronization set master to 256Kbps
// 32 bit serial communication mode first.
//
//* 2Mbps communication with a cable is not guaranteed so do not set up.
//* Set already connection already determined with multi-play communication
// to Type.
//* Do not pass VRAM address to Datap during display.
// May fail with checksum of stored data.
// Copy to VRAM after storing to work RAM once.
// After this, possible overwrite program data to work RAM.
//
//* Arguments:
// u32 type Connection (Master = Not 0/ Slave = 0)
// void *datap Data Pointer (Master = Send Data/ Slave= Receive Buffer)
/*------------------------------------------------------------------*/
/* 32bit Serial Communication Multi-load Main */
/*------------------------------------------------------------------*/
extern u32 Sio32MultiLoadMain(u32 *progressCounterp);
//* After 1 frame wait, set the slave to 256Kbps 32bit serial communication
// mode. Also, until the slave's SIO mode is determined the waits and then
// communication is started.
//* Slave successively calculates receive data checksum, and checks when
// receive complete.
//* If receive is not completed at time when should be, end receive forcibly.
//* After communication ends prohibit communication interrupts, and return
// to multi-play communication mode.
//
//* Arguments:
// u32 *progressCounterp Progress Counter Pointer
// (Disabled when 0 specified)
//* Return Value:
// During communication = 0/ End = Not 0
/*------------------------------------------------------------------*/
/* 32bit Serial Communication Multi-load Interrupt Routine */
/*------------------------------------------------------------------*/
extern void Sio32MultiLoadIntr(void);
//* Master does only send and slave only receive.
//* Master resets timer during send.
//* Slave stores receive data in order to receive buffer during
// communication interrupt.
// Lastly it stores checksum to work area.
//
//* Program so slave is called with communication interrupt and master
// is called with timer interrupt.
//* Data is passed with pipeline operation so delayed with slave with
// large ID and then received. Therefore at a minimum need to send
// two (8 Bytes) extra times.
//
//* Example:
// ID 0 1 2 3
// Data 0 -> 0 -> 0 -> 0
// 1 -> 0 -> 0 -> 0
// 2 -> 1 -> 0 -> 0
// 3 -> 2 -> 1 -> 0
// 4 -> 3 -> 2 -> 1
#endif // GUARD_SIO32_MULTI_LOAD_H

View File

@ -1,5 +1,6 @@
gNumMusicPlayers = 4;
gMaxLines = 0;
gUnk_02000000 = 0x2000000;
ENTRY(__start)
@ -11,7 +12,6 @@ MEMORY {
SECTIONS {
ewram (NOLOAD) : ALIGN(4) {
. = 0x00000000; gUnk_02000000 = .;
. = 0x00000140; gUnk_02000140 = .;
. = 0x00000F40; gUnk_02000F40 = .;
. = 0x00008300; gUnk_02008300 = .;
@ -116,15 +116,18 @@ SECTIONS {
. = 0x00000008; gUnk_03000008 = .;
. = 0x0000000C; gUnk_0300000C = .;
. = 0x00000010; gUnk_03000010 = .;
. = 0x00000014; gUnk_03000014 = .;
. = 0x00000014; src/multi_boot.o(.bss);
. = ALIGN(16);
. = 0x00000020; gUnk_03000020 = .;
. = 0x0000002C; gUnk_0300002C = .;
. = 0x00000030; gUnk_03000030 = .;
. = 0x00000034; gUnk_03000034 = .;
. = 0x00000038; gUnk_03000038 = .;
. = 0x00000050; gUnk_03000050 = .;
. += 4; . = ALIGN(4);
*libgcc.a:dp-bit.o(.bss);
. = ALIGN(4);
*libgcc.a:fp-bit.o(.bss);
. = ALIGN(4);
. = 0x00000060; SoundMainRAM_Buffer = .;
. = 0x00000061; gUnk_03000061 = .;
. = 0x00000470; gUnk_03000470 = .;
. = 0x00000478; gUnk_03000478 = .;
. = 0x00000480; gUnk_03000480 = .;
@ -151,7 +154,7 @@ SECTIONS {
. = 0x00001760; gMPlayMemAccArea = .;
. = 0x00001760; gUnk_03001760 = .;
. = 0x00001770; gUnk_03001770 = .;
. = 0x000017B0; gUnk_030017B0 = .;
. = 0x000017B0; gIntrTable = .;
. = 0x000017F0; gUnk_030017F0 = .;
. = 0x000019F0; gUnk_030019F0 = .;
. = 0x000023F0; gUnk_030023F0 = .;
@ -258,42 +261,72 @@ SECTIONS {
. = 0x000068D0; gUnk_030068D0 = .;
. = 0x000068D4; gUnk_030068D4 = .;
. = 0x000068D8; gUnk_030068D8 = .;
. = 0x000068E0; gUnk_030068E0 = .;
. = 0x00006A60; gUnk_03006A60 = .;
. = 0x00006C50; gUnk_03006C50 = .;
. = 0x00006C90; gUnk_03006C90 = .;
. = 0x000068E0; gMultiSioIntrFuncBuf = .;
. = 0x00006A60; gMultiSioArea = .;
. = 0x00006C50; gMultiSioRecvFuncBuf = .;
. = 0x00006C90; gSio32MultiLoadArea = .;
. = 0x00006CB0; gUnk_03006CB0 = .;
. = 0x00006CBC; gUnk_03006CBC = .;
. = 0x00006CC0; gUnk_03006CC0 = .;
. = 0x00006CC4; gUnk_03006CC4 = .;
. = 0x00007E80; gUnk_03007E80 = .;
. = 0x00007F00; gUnk_03007F00 = .;
. = 0x00007FA0; gUnk_03007FA0 = .;
. = 0x00007FF0; SOUND_INFO_PTR = .;
. = 0x00007FF8; gUnk_03007FF8 = .;
. = 0x00007FFC; gUnk_03007FFC = .;
. = 0x00008000;
} >iwram
rom : ALIGN(4) {
asm/crt0.o(.text);
asm/code.o(.text);
asm/libm4a_1.o(.text);
asm/libm4a_2.o(.text);
asm/code_0815158C.o(.text);
asm/m4a_asm.o(.text);
src/m4a.o(.text);
asm/main.o(.text);
asm/multiboot.o(.text);
asm/code_08157E54.o(.text);
asm/code_08158F14.o(.text);
asm/code_08152A18.o(.text);
src/multi_sio.o(.text);
src/multi_boot.o(.text);
src/sio32_multi_load.o(.text);
asm/code_0815819C.o(.text);
asm/multi_sio_asm.o(.text);
asm/code_08159074.o(.text);
asm/agb_flash.o(.text); /* TODO: is it? */
src/agb_sram.o(.text);
asm/libagbsyscall.o(.text);
asm/code_08159350.o(.text);
asm/libgcc.o(.text);
asm/libc.o(.text);
src/powf_error_handler.o(.text);
*libc.a:ef_pow.o(.text);
*libc.a:ef_sqrt.o(.text);
*libc.a:s_matherr.o(.text);
*libc.a:s_rint.o(.text);
*libc.a:sf_fabs.o(.text);
*libc.a:sf_finite.o(.text);
*libc.a:sf_isnan.o(.text);
*libc.a:sf_scalbn.o(.text);
*libc.a:sf_copysign.o(.text);
*libgcc.a:_call_via_rX.o(.text);
*libgcc.a:_divsi3.o(.text);
*libgcc.a:_dvmd_tls.o(.text);
*libgcc.a:_modsi3.o(.text);
*libgcc.a:_udivsi3.o(.text);
*libgcc.a:_umodsi3.o(.text);
*libgcc.a:dp-bit.o(.text);
*libgcc.a:fp-bit.o(.text);
*libgcc.a:_lshrdi3.o(.text);
*libgcc.a:_muldi3.o(.text);
*libgcc.a:_negdi2.o(.text);
*libc.a:errno.o(.text);
*libc.a:memcpy.o(.text);
*libc.a:memset.o(.text);
data/data_1.o(.rodata);
src/multi_sio.o(.rodata);
src/sio32_multi_load.o(.rodata);
src/agb_sram.o(.rodata);
src/powf_error_handler.o(.rodata);
*libc.a:ef_pow.o(.rodata);
*libc.a:ef_sqrt.o(.rodata);
src/powf_error_handler.o(.data);
*libc.a:s_rint.o(.rodata);
data/data_3.o(.rodata);
*libc.a:impure.o(.rodata);
data/data_2.o(.rodata);
/* stuff below are mislinked into the binary? */
data/data_unk.o(.rodata);
*libc.a:impure.o(.data);
} >rom
/* DWARF 2 sections */

80
src/agb_sram.c Normal file
View File

@ -0,0 +1,80 @@
#include "agb_sram.h"
const char gAgbSramLibVer[] = "NINTENDOSRAM_V113";
static void ReadSram_Core(const u8 *src, u8 *dest, u32 size)
{
while (--size != -1)
*dest++ = *src++;
}
void ReadSram(const u8 *src, u8 *dest, u32 size)
{
const u16 *s;
u16 *d;
u16 readSramFast_Work[64];
u16 size_;
REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
s = (void *)((uintptr_t)ReadSram_Core);
s = (void *)((uintptr_t)s & ~1);
d = readSramFast_Work;
size_ = ((uintptr_t)ReadSram - (uintptr_t)ReadSram_Core) / 2;
while (size_ != 0)
{
*d++ = *s++;
--size_;
}
((void (*)(const u8 *, u8 *, u32))readSramFast_Work + 1)(src, dest, size);
}
void WriteSram(const u8 *src, u8 *dest, u32 size)
{
REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
while (--size != -1)
*dest++ = *src++;
}
static u32 VerifySram_Core(const u8 *src, u8 *dest, u32 size)
{
while (--size != -1)
if (*dest++ != *src++)
return (u32)(dest - 1);
return 0;
}
u32 VerifySram(const u8 *src, u8 *dest, u32 size)
{
const u16 *s;
u16 *d;
u16 verifySramFast_Work[96];
u16 size_;
REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
s = (void *)((uintptr_t)VerifySram_Core);
s = (void *)((uintptr_t)s & ~1);
d = verifySramFast_Work;
size_ = ((uintptr_t)VerifySram - (uintptr_t)VerifySram_Core) / 2;
while (size_ != 0)
{
*d++ = *s++;
--size_;
}
return ((u32 (*)(const u8 *, u8 *, u32))verifySramFast_Work + 1)(src, dest, size);
}
u32 WriteSramEx(const u8 *src, u8 *dest, u32 size)
{
u8 i;
u32 errorAddr;
// try writing and verifying the data 3 times
for (i = 0; i < SRAM_RETRY_MAX; ++i)
{
WriteSram(src, dest, size);
errorAddr = VerifySram(src, dest, size);
if (errorAddr == 0)
break;
}
return errorAddr;
}

1428
src/m4a.c Normal file

File diff suppressed because it is too large Load Diff

637
src/multi_boot.c Normal file
View File

@ -0,0 +1,637 @@
#include "multi_boot.h"
static s32 MultiBootSend(struct MultiBootParam *mp, u16 data);
static s32 MultiBootHandShake(struct MultiBootParam *mp);
static void MultiBootWaitSendDone(void);
static u16 sMultiBootRequiredData[MULTIBOOT_NCHILD];
/*------------------------------------------------------------------*/
/* Multi-play Boot Main */
/*------------------------------------------------------------------*/
s32 MultiBootMain(struct MultiBootParam *mp)
{
s32 i, j, k;
if (MultiBootCheckComplete(mp))
/* Transfer is complete so no other processing done */
return 0;
if (mp->check_wait > MULTIBOOT_CONNECTION_CHECK_WAIT)
{
/* After system call error, do not send anything,
* and wait for client to have timeout error.
*/
--mp->check_wait;
return 0;
}
output_burst:
if (mp->sendflag)
{
mp->sendflag = 0;
/* There is a problem if SC7, SC6 is on at this point.
* There may be a problem with the connection(connected to JOY) and
* communication does not have timeout error.
* When the connection ID is not 00 or there is a problem with the SD or SI terminals an error occurs.
*/
i = REG_SIOCNT & (SIO_MULTI_BUSY | SIO_ERROR | SIO_ID | SIO_MULTI_SD | SIO_MULTI_SI);
if (i != SIO_MULTI_SD)
{
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
return i ^ SIO_MULTI_SD;
}
}
if (mp->probe_count >= 0xe0)
{
/* Check(handshake) to see if all slaves booted properly. */
i = MultiBootHandShake(mp);
if (i)
return i;
/* If Low speed recognition mode, handshake also 2bytes communication, call
* If High speed recognition mode, handshake also high speed communication.
*/
if (mp->probe_count > 0xe1
&& MultiBootCheckComplete(mp) == 0)
{
MultiBootWaitSendDone();
goto output_burst;
}
/* Timeout check */
if (MultiBootCheckComplete(mp) == 0)
{
if (mp->handshake_timeout == 0)
{
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
return MULTIBOOT_ERROR_HANDSHAKE_FAILURE;
}
--mp->handshake_timeout;
}
return 0;
}
switch (mp->probe_count)
{
case 0:
/* client not doing recognition
* Value should be CLIENT_INFO 000 0 ccc 0
* First, check if some kind of response(other than 0xffff)
* from machine.
*/
k = 0x0e;
for (i = MULTIBOOT_NCHILD; i != 0; --i)
{
if (*(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2) != 0xffff)
{ // braces are required to match on my machine, but works fine on SBird's CE :/
break;
}
k >>= 1;
}
k &= 0x0e; /* 4P-2P: d3-d1 is 1 */
mp->response_bit = k;
/* Machine recognized as client,
* must be CLIENT_INFO 000 0 ccc 0.
*/
for (i = MULTIBOOT_NCHILD; i != 0; --i)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if (mp->client_bit & (1 << i))
{
if (j != ((MULTIBOOT_CLIENT_INFO << 8) | (1 << i)))
{
/* Need to do recognition processing again */
k = 0;
mp->response_bit = 0;
break;
}
}
}
mp->client_bit &= k;
if (k == 0)
/* From client, until at least one returns value other than
* 0xffff, maintain fixed time until redo of recognition processing
*/
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
if (mp->check_wait)
{
--mp->check_wait;
}
else
{
/* If machine with response and client status do not match up,
* do recognition processing again.
*/
if (mp->response_bit != mp->client_bit)
{
MultiBootStartProbe(mp);
goto case_1;
}
}
output_master_info:
/* Output MASTER_INFO 000 0 ccc 0. */
return MultiBootSend(mp, (MULTIBOOT_MASTER_INFO << 8) | mp->client_bit);
case 1:
case_1:
/* Start recognition.
* Those where in data is CLIENT_INFO 000 0 ccc 0
* are recognized.
*/
mp->probe_target_bit = 0;
for (i = MULTIBOOT_NCHILD; i != 0; --i)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if ((j >> 8) == MULTIBOOT_CLIENT_INFO)
{
/* Check validity of 000 0 ccc 0.
* If 4P, 0x08
* If 3P, 0x04
* If 2P, 0x02
* If not so, invalid.
*/
sMultiBootRequiredData[i - 1] = j; /* During processing next time must be same value */
j &= 0xff;
if (j == (1 << i))
mp->probe_target_bit |= j;
}
}
if (mp->response_bit != mp->probe_target_bit)
goto output_master_info;
/* Send MASTER_START_PROBE 000 0 ccc 0.
* Here the recognized bits are 000, ccc.
* If not possible that 000 or ccc, not recognized by master.
*/
mp->probe_count = 2;
return MultiBootSend(mp, (MULTIBOOT_MASTER_START_PROBE << 8) | mp->probe_target_bit);
case 2:
/* Must be CLIENT_INFO 000 0 ccc 0.
* Output header +0, +1 bytes.
*/
for (i = MULTIBOOT_NCHILD; i != 0; --i)
{
if (mp->probe_target_bit & (1 << i))
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if (j != sMultiBootRequiredData[i - 1])
/* Problem with client recognition */
mp->probe_target_bit ^= 1 << i;
}
}
goto output_header;
case 0xd0:
/* Request for start of master server.
* If CLIENT_INFO 000 0 ccc 0, not ready
* to download client.
* If all clients CLIENT_DLREADY, call system
* call and transfer boot program.
*/
k = 1; /* Okay to go to download start? */
for (i = MULTIBOOT_NCHILD; i != 0; --i)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
/* handshake data from client
* Regardless of recognition, save for all machines
*/
mp->client_data[i - 1] = j;
if (mp->probe_target_bit & (1 << i))
{
if ((j >> 8) != MULTIBOOT_CLIENT_INFO
&& (j >> 8) != MULTIBOOT_CLIENT_DLREADY)
{
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
return MULTIBOOT_ERROR_NO_DLREADY; /* No response saying ready to do download */
}
if (j == sMultiBootRequiredData[i - 1])
/* CLIENT_INFO 000 0 ccc 0
* Was at least one machine not ready for download,
* so not start download yet.
*/
k = 0;
}
}
if (k == 0)
/* Not start download yet.
* Send request for download preparation
*/
return MultiBootSend(mp, (MULTIBOOT_MASTER_REQUEST_DLREADY << 8) | mp->palette_data);
/* All machines ready to download */
mp->probe_count = 0xd1;
k = 0x11;
for (i = MULTIBOOT_NCHILD; i != 0; --i)
/* handshake data */
k += mp->client_data[i - 1];
mp->handshake_data = k;
return MultiBootSend(mp, (MULTIBOOT_MASTER_START_DL << 8) | (k & 0xff));
case 0xd1:
/* Send MASTER_START_DL
* Should be CLIENT_DLREADY.
*/
for (i = MULTIBOOT_NCHILD; i != 0; --i)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if (mp->probe_target_bit & (1 << i))
{
if ((j >> 8) != MULTIBOOT_CLIENT_DLREADY)
{
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
return MULTIBOOT_ERROR_NO_DLREADY; /* No response saying ready to do download */
}
}
}
i = MultiBoot(mp);
if (i == 0)
{
/* complete
* Make mp -> probe_count into 0xe0(request for handshake start).
*/
mp->probe_count = 0xe0;
mp->handshake_timeout = MULTIBOOT_HANDSHAKE_TIMEOUT;
return 0;
}
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
/* With system call failure, possible that client still in
* receive data status.
* Therefore, until retry, do not send anything including MASTER_INFO,
* during time for "Client has timeout error".
*/
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT * 2;
return MULTIBOOT_ERROR_BOOT_FAILURE; /* Transfer failed */
default:
/* 4-...: Doing recognition processing
* 4 -> +0,1 byte
* 6 -> +2,3
* 8 -> +4,5
* :
* 0xc2 -> +0xbe, 0xbf byte
* Output header data.
*/
/* When client is being recognized,
* value is MASTER_START_PROBE - 1, ..-2, ..., 0
* 0x61 - 1, 0x5f
* lower bytes are 000 0 ccc 0
*/
for (i = MULTIBOOT_NCHILD; i != 0; --i)
{
if (mp->probe_target_bit & (1 << i))
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if ((j >> 8) != (MULTIBOOT_MASTER_START_PROBE + 1 - (mp->probe_count >> 1))
|| ((j & 0xff) != (1 << i)))
/* Problem with client recognition */
mp->probe_target_bit ^= 1 << i;
}
}
if (mp->probe_count == 0xc4)
{
/* From recognized, those leftover last are
* qualified as client.
*/
mp->client_bit = mp->probe_target_bit & 0x0e;
mp->probe_count = 0;
goto output_master_info;
}
output_header:
/* If no target, ends with error in middle. */
if (mp->probe_target_bit == 0)
{
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
return MULTIBOOT_ERROR_NO_PROBE_TARGET; /* No recognized target */
}
mp->probe_count += 2;
if (mp->probe_count == 0xc4)
/* When getting final data, send MASTER_INFO 000 0 ccc 0.
* If do not problem with timing.
*/
goto output_master_info;
i = MultiBootSend(mp,
(mp->masterp[mp->probe_count - 4 + 1] << 8)
| mp->masterp[mp->probe_count - 4]);
if (i)
return i;
/* If Low speed recognition mode, for each frame of call, 2 bytes of
* communication.
* If High speed recognition mode,
* (time to end of communication + sufficient time for slave
* interrupt processing)
* Wait, continued communication.
*/
if (mp->server_type == MULTIBOOT_SERVER_TYPE_QUICK)
{
MultiBootWaitSendDone();
goto output_burst;
}
return 0;
}
/* never comes here */
}
/*------------------------------------------------------------------*/
/* Send Data */
/*------------------------------------------------------------------*/
/*
* If connection has problem, non-0
*/
static s32 MultiBootSend(struct MultiBootParam *mp, u16 data)
{
s32 i;
/* If SC7 is on, problem has occurred.
* There may be a problem with the connection(connected to JOY) and
* communication does not have timeout error.
* (reconnect cable) May be first communication so no check for
* SC6, connection ID.
*/
i = REG_SIOCNT & (SIO_MULTI_BUSY | SIO_MULTI_SD | SIO_MULTI_SI);
if (i != SIO_MULTI_SD)
{
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
return i ^ SIO_MULTI_SD;
}
REG_SIODATA8 = data;
REG_SIOCNT |= SIO_START;
mp->sendflag = 1;
return 0;
}
/*------------------------------------------------------------------*/
/* Start recognition of client */
/*------------------------------------------------------------------*/
void MultiBootStartProbe(struct MultiBootParam *mp)
{
if (mp->probe_count != 0)
{
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
return;
}
mp->check_wait = 0;
mp->client_bit = 0;
mp->probe_count = 1;
}
/*------------------------------------------------------------------*/
/* Start send from master server */
/*------------------------------------------------------------------*/
void MultiBootStartMaster(struct MultiBootParam *mp, const u8 *srcp, s32 length, u8 palette_color, s8 palette_speed)
{
s32 i;
if (mp->probe_count != 0
|| mp->client_bit == 0
|| mp->check_wait != 0)
{
/* Recognition processing, cannot do processing */
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
return;
}
mp->boot_srcp = srcp;
length = (length + 15) & ~15; /* 16 byte units */
if (length < MULTIBOOT_SEND_SIZE_MIN || length > MULTIBOOT_SEND_SIZE_MAX)
{
/* More than number or transfer bytes */
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
return;
}
mp->boot_endp = srcp + length;
switch (palette_speed)
{
case -4:
case -3:
case -2:
case -1:
i = (palette_color << 3) | (3 - palette_speed);
break;
case 0:
i = 0x38 | palette_color;
break;
case 1:
case 2:
case 3:
case 4:
i = (palette_color << 3) | (palette_speed - 1);
break;
}
mp->palette_data = ((i & 0x3f) << 1) | 0x81;
mp->probe_count = 0xd0;
}
/*------------------------------------------------------------------*/
/* Handshake (final confirmation of boot) */
/*------------------------------------------------------------------*/
static s32 MultiBootHandShake(struct MultiBootParam *mp)
{
s32 i, j;
#define send_data (mp->system_work[0])
#define must_data (mp->system_work[1])
switch (mp->probe_count)
{
case 0xe0:
case_0xe0:
/* Master sends 0x0000. */
mp->probe_count = 0xe1;
must_data = 0x0000;
send_data = 0x100000; /* Right before next send >>5 */
return MultiBootSend(mp, 0x0000);
default:
/* 0xe1-0xe6
* If expected data does not come, do again from case_0xe0.
* 0xe1: After master sends 0x0000. All slaves must be 0x0000.
* 0xe2: After master sends 0x8000. All slaves must be 0x0000.
* 0xe3: 0x0400 0x8000
* 0xe4: 0x0020 0x0400
* 0xe5: 0x0001 0x0020
* 0xe6: 0x0000 0x0001
*/
for (i = MULTIBOOT_NCHILD; i != 0; --i)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if ((mp->client_bit & (1 << i))
&& j != must_data)
/* Expected data still hasn't come from all slaves. */
goto case_0xe0;
}
++mp->probe_count;
must_data = send_data & 0xffff;
if (send_data == 0x0000)
{
/* This time send initial code low. */
must_data = mp->masterp[0xac] | (mp->masterp[0xad] << 8);
send_data = must_data << 5; /* right before sending >>5 */
}
send_data >>= 5;
output_common:
return MultiBootSend(mp, send_data);
case 0xe7: /* Master sent initial code, low. All slaves must be same. */
case 0xe8: /* Master sent initial code, high. All slaves must be same. */
for (i = MULTIBOOT_NCHILD; i != 0; --i)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if ((mp->client_bit & (1 << i)) && j != must_data)
{
/* Desired data did not come from all slaves.
* If reach this point and have error, stop(infinite loop) slave,
* and no retry by master.
* On master's screen display,
* "Communicsation failure. Turn off power and check connection.
* Turn on power again."
*/
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
return MULTIBOOT_ERROR_HANDSHAKE_FAILURE;
}
}
++mp->probe_count;
if (mp->probe_count == 0xe9)
/* Handshake Success! */
return 0;
/* This time send the initial code, high. */
send_data = mp->masterp[0xae] | (mp->masterp[0xaf] << 8);
must_data = send_data;
goto output_common;
}
#undef send_data
#undef must_data
}
/*------------------------------------------------------------------*/
/* Multi-play Boot Initialization */
/*------------------------------------------------------------------*/
void MultiBootInit(struct MultiBootParam *mp)
{
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
}
/*------------------------------------------------------------------*/
/* Check transfer completion */
/*------------------------------------------------------------------*/
s32 MultiBootCheckComplete(struct MultiBootParam *mp)
{
if (mp->probe_count == 0xe9)
/* Transfer complete status */
return 1;
/* middle of recognition, haven't started transfer, or transfer failure */
return 0;
}
/*------------------------------------------------------------------*/
/* Wait Cycle */
/*------------------------------------------------------------------*/
static inline void MultiBootWaitCycles(u32 cycles)
{
/* Depending on if this is in CPU internal working, CPU external
* working, ROM, the CPU cycles used for one of this function's wait
* loops is different.
* CPU External Working (0x02XXXXXX) ... 12 cycles/loop
* ROM (0x08XXXXXX) ... 13 cycles/loop
* (Have prefetch Setup maximum speed)
* CPU Internal Working (0x03XXXXXX) ... 4 cycles/loop
* If address area other than above, temporarily use 4 cycles/loop.
* If set up lower cycles/loop than actual,
* can get specified cycle number wait.
*
* Use AGB system clock 16.78MHz as hint for argument, cycles.
* If use 0x1000000 (16777216) with cycles approximately 1 second wait.
* (If V blank interrupt is processed during this, actual wait is longer)
*/
asm("mov r2, pc");
asm("lsr r2, #24");
asm("mov r1, #12");
asm("cmp r2, #0x02");
asm("beq MultiBootWaitCyclesLoop");
asm("mov r1, #13");
asm("cmp r2, #0x08");
asm("beq MultiBootWaitCyclesLoop");
asm("mov r1, #4");
asm("MultiBootWaitCyclesLoop:");
asm("sub r0, r1");
asm("bgt MultiBootWaitCyclesLoop");
}
/*------------------------------------------------------------------*/
/* Check if communication completed within fixed time */
/*------------------------------------------------------------------*/
static void MultiBootWaitSendDone(void)
{
s32 i;
/* If cannot detect communication end within fixed time(1 frame),
* remove loop.
* Even if fast this loop takes 9 cycles/loop,
* (ldr=3, and=1, branch skip=1, i++=1, branch=3)
* try loop for 1 frame.
* Number of times do loop is,
* 0x1000000 (16.78MHz=cycles/sec) / 60 (frames/sec) / 9 (cycles/loop)
* = approximately 31069 (loops/frame)
*/
for (i = 0; i < 31069; ++i)
if ((REG_SIOCNT & SIO_START) == 0)
break;
/* Sufficient time for slave's interrupt processing */
MultiBootWaitCycles(600);
}

279
src/multi_sio.c Normal file
View File

@ -0,0 +1,279 @@
#include "sio32_multi_load.h"
static const u8 sMultiSioLibVer[] = "MultiSio4Sio32Load020820";
// COMMON
// struct MultiSioArea gMultiSioArea; // Multi-play Communication Work Area
#ifdef MULTI_SIO_DI_FUNC_FAST
// u32 gMultiSioRecvFuncBuf[0x40 / 4]; // Receive Data/Check Buffer Change Routine RAM Execution Buffer
// u32 gMultiSioIntrFuncBuf[0x180 / 4]; // Interrupt Routine RAM Execution Buffer
#endif
/*------------------------------------------------------------------*/
/* Multi-play Communication Initialization */
/*------------------------------------------------------------------*/
extern u32 MultiSioRecvBufChange(void);
void MultiSioInit(u32 connectedFlags)
{
s32 i;
REG_IME = 0;
REG_IE &= ~(INTR_FLAG_SERIAL // Disable SIO & Timer Interrupt
| MULTI_SIO_TIMER_INTR_FLAG);
REG_IME = 1;
REG_RCNT = ST_R_SIO_MASTER_MODE;
*(vu32 *)REG_ADDR_SIOCNT = SIO_MULTI_MODE;
REG_SIOCNT |= SIO_IF_ENABLE | MULTI_SIO_BAUD_RATE_NO;
CpuFill32(0, &gMultiSioArea, sizeof(struct MultiSioArea)); // Clear Multi-play Communication Work Area
#ifdef MULTI_SIO_DI_FUNC_FAST // Copy Function
CpuCopy32(MultiSioRecvBufChange, gMultiSioRecvFuncBuf, sizeof(gMultiSioRecvFuncBuf));
CpuCopy32(MultiSioIntr, gMultiSioIntrFuncBuf, sizeof(gMultiSioIntrFuncBuf));
#endif
gMultiSioArea.connectedFlags = connectedFlags;
gMultiSioArea.sendBufCounter = -1;
gMultiSioArea.nextSendBufp = (u16 *)&gMultiSioArea.sendBuf[0]; // Set Send Buffer Pointer
gMultiSioArea.currentSendBufp = (u16 *)&gMultiSioArea.sendBuf[1];
for (i = 0; i < 4; ++i)
{ // Set Receive Buffer Pointer
gMultiSioArea.currentRecvBufp[i] = (u16 *)&gMultiSioArea.recvBuf[i][0];
gMultiSioArea.lastRecvBufp[i] = (u16 *)&gMultiSioArea.recvBuf[i][1];
gMultiSioArea.recvCheckBufp[i] = (u16 *)&gMultiSioArea.recvBuf[i][2];
}
REG_IME = 0;
REG_IE |= INTR_FLAG_SERIAL; // Enable SIO Interrupt
REG_IME = 1;
}
/*------------------------------------------------------------------*/
/* Multi-play Communication Main */
/*------------------------------------------------------------------*/
u32 MultiSioMain(void *sendp, void *recvp, u32 loadRequest)
{
struct SioMultiCnt sioCntBak;
UNUSED s32 i, ii; // declared in SDK
sioCntBak = *(struct SioMultiCnt *)REG_ADDR_SIOCNT; // Check Connection
switch (gMultiSioArea.state)
{
case 0:
if (!sioCntBak.id)
{
if (!sioCntBak.sd || sioCntBak.enable)
break;
if (!sioCntBak.si && gMultiSioArea.sendBufCounter == -1)
{
REG_IME = 0;
REG_IE &= ~INTR_FLAG_SERIAL; // Disable SIO Interrupt
REG_IE |= MULTI_SIO_TIMER_INTR_FLAG; // Enable Timer Interrupt
REG_IME = 1;
((struct SioMultiCnt *)REG_ADDR_SIOCNT)->ifEnable = 0; // Reset SIO-IFE
REG_IF = INTR_FLAG_SERIAL | MULTI_SIO_TIMER_INTR_FLAG;
REG_MULTI_SIO_TIMER = MULTI_SIO_TIMER_COUNT; // Timer Initialization
gMultiSioArea.type = SIO_MULTI_PARENT;
((struct SioMultiCnt *)REG_ADDR_SIOCNT)->enable = 1; // Start Send
}
}
gMultiSioArea.state = 1;
// fallthrough
case 1:
if (gMultiSioArea.connectedFlags && !gMultiSioArea.loadSuccessFlag)
{
if (gMultiSioArea.recvFlagsAvailableCounter < 8) // Waiting period to stabilize communication in initialization
++gMultiSioArea.recvFlagsAvailableCounter;
else
gMultiSioArea.state = 2;
}
// fallthrough
case 2:
MultiSioRecvDataCheck(recvp); // Check Receive Data
MultiSioSendDataSet(sendp, loadRequest); // Set Send Data
break;
}
++gMultiSioArea.sendFrameCounter;
return gMultiSioArea.recvSuccessFlags
| gMultiSioArea.loadEnable << 4
| gMultiSioArea.loadRequest << 5
| gMultiSioArea.loadSuccessFlag << 6
| (gMultiSioArea.type == SIO_MULTI_PARENT) << 7
| gMultiSioArea.connectedFlags << 8
| (gMultiSioArea.hardError != 0) << 12
| (sioCntBak.id >= MULTI_SIO_PLAYERS_MAX) << 13
| (gMultiSioArea.recvFlagsAvailableCounter >> 3) << 15;
}
/*------------------------------------------------------------------*/
/* Set Send Data */
/*------------------------------------------------------------------*/
void MultiSioSendDataSet(void *sendp, u32 loadRequest)
{
s32 checkSum = 0;
s32 i;
((struct MultiSioPacket *)gMultiSioArea.nextSendBufp)->loadRequest = loadRequest;
((struct MultiSioPacket *)gMultiSioArea.nextSendBufp)->downloadSuccessFlag = gSio32MultiLoadArea.downloadSuccessFlag;
((struct MultiSioPacket *)gMultiSioArea.nextSendBufp)->loadSuccessFlag = gMultiSioArea.loadSuccessFlag;
((struct MultiSioPacket *)gMultiSioArea.nextSendBufp)->frameCounter = (u8)gMultiSioArea.sendFrameCounter;
((struct MultiSioPacket *)gMultiSioArea.nextSendBufp)->recvErrorFlags = gMultiSioArea.connectedFlags ^ gMultiSioArea.recvSuccessFlags;
((struct MultiSioPacket *)gMultiSioArea.nextSendBufp)->checkSum = 0;
CpuCopy32(sendp, &gMultiSioArea.nextSendBufp[2], MULTI_SIO_BLOCK_SIZE); // Set Send Data
for (i = 0; i < sizeof(struct MultiSioPacket) / 2 - 2; ++i) // Calculate Checksum Send Data
checkSum += gMultiSioArea.nextSendBufp[i];
((struct MultiSioPacket *)gMultiSioArea.nextSendBufp)->checkSum = ~checkSum - 14;
if (gMultiSioArea.type)
REG_MULTI_SIO_TIMER_H = 0; // Stop Timer
gMultiSioArea.sendBufCounter = -1;
if (gMultiSioArea.type && gMultiSioArea.startFlag)
REG_MULTI_SIO_TIMER_H = TIMER_1CLK | TIMER_INTR_ENABLE | TIMER_ENABLE; // Start Timer
}
/*------------------------------------------------------------------*/
/* Check Receive Data */
/*------------------------------------------------------------------*/
u32 MultiSioRecvDataCheck(void *recvp)
{
u32 (*multiSioRecvBufChangeOnRam)(void) = (u32 (*)(void))gMultiSioRecvFuncBuf;
s32 checkSum;
vu32 recvCheck = 0;
u8 syncRecvFlagBak[4];
u8 counterDiff;
u16 *bufpTmp;
s32 i, ii;
#ifdef MULTI_SIO_DI_FUNC_FAST // Update Receive Data/Check Buffer
*(u32 *)syncRecvFlagBak = multiSioRecvBufChangeOnRam();
#else
REG_IME = 0; // Disable Interrupt (Approx. 80 Clocks)
for (i = 0; i < 4; ++i)
{
bufpTmp = gMultiSioArea.recvCheckBufp[i]; // Update Receive Data/Check Buffer
gMultiSioArea.recvCheckBufp[i] = gMultiSioArea.lastRecvBufp[i];
gMultiSioArea.lastRecvBufp[i] = bufpTmp;
}
REG_IME = 1; // Enable Interrupt
#endif
gMultiSioArea.recvSuccessFlags = 0;
gMultiSioArea.loadSuccessFlag = 0;
for (i = 0; i < 4; ++i)
{
checkSum = 0; // Calculate Checksum Receive Data
for (ii = 0; ii < sizeof(struct MultiSioPacket) / 2 - 2; ++ii)
checkSum += gMultiSioArea.recvCheckBufp[i][ii];
if (syncRecvFlagBak[i]) // Receive Success Confirmation
if ((s16)checkSum == -15)
{
gMultiSioArea.recvSuccessFlags |= 1 << i;
gMultiSioArea.downloadSuccessFlags |= ((struct MultiSioPacket *)gMultiSioArea.recvCheckBufp[i])->downloadSuccessFlag << i;
CpuCopy32(&((u8 *)gMultiSioArea.recvCheckBufp[i])[4], &((u8 *)recvp)[i * MULTI_SIO_BLOCK_SIZE], MULTI_SIO_BLOCK_SIZE);
}
CpuFill32(0, &((u8 *)gMultiSioArea.recvCheckBufp[i])[4], MULTI_SIO_BLOCK_SIZE);
}
gMultiSioArea.connectedFlags |= gMultiSioArea.recvSuccessFlags; // Set Connect Complete Flag
if (gMultiSioArea.recvSuccessFlags & 1)
{
if (gMultiSioArea.type == SIO_MULTI_PARENT)
{
if (gMultiSioArea.recvSuccessFlags & 0x3) // Enable Load
if (gMultiSioArea.recvSuccessFlags == gMultiSioArea.connectedFlags)
gMultiSioArea.loadEnable = 1;
if ((gMultiSioArea.downloadSuccessFlags & 0xe) == (gMultiSioArea.connectedFlags & 0xe)) // Check Load
gMultiSioArea.loadSuccessFlag = 1;
}
else
gMultiSioArea.loadSuccessFlag = ((struct MultiSioPacket *)gMultiSioArea.recvCheckBufp[0])->loadSuccessFlag;
gMultiSioArea.loadRequest = ((struct MultiSioPacket *)gMultiSioArea.recvCheckBufp[0])->loadRequest; // Request Load
}
return gMultiSioArea.recvSuccessFlags;
}
/*------------------------------------------------------------------*/
/* Start Multi-play Communication */
/*------------------------------------------------------------------*/
void MultiSioStart(void)
{
if (gMultiSioArea.type)
gMultiSioArea.startFlag = 1; // Set Start Flag
}
/*------------------------------------------------------------------*/
/* Stop Multi-play Communication */
/*------------------------------------------------------------------*/
void MultiSioStop(void)
{
REG_IME = 0;
REG_IE &= ~(INTR_FLAG_SERIAL | MULTI_SIO_TIMER_INTR_FLAG); // Disable SIO & Timer Interrupt
REG_IME = 1;
REG_SIOCNT = SIO_MULTI_MODE | MULTI_SIO_BAUD_RATE_NO; // Stop SIO
REG_MULTI_SIO_TIMER = MULTI_SIO_TIMER_COUNT; // Stop Timer
REG_IF = INTR_FLAG_SERIAL | MULTI_SIO_TIMER_INTR_FLAG; // Reset IF
gMultiSioArea.startFlag = 0; // Reset Start Flag
}
/*==================================================================*/
/* Multi-play Communication Interrupt Routine */
/*==================================================================*/
#ifndef MULTI_SIO_DI_FUNC_FAST
void MultiSioIntr(void)
{
u16 recvTmp[4];
u16 *bufpTmp;
s32 i;
UNUSED s32 ii; // declared in SDK
// Save Receive Data
*(u64 *)recvTmp = *(u64 *)REG_ADDR_SIOMLT_RECV;
// Detect hard error
gMultiSioArea.hardError = ((struct SioMultiCnt *)REG_ADDR_SIOCNT)->error;
// Send Data Processing
if (gMultiSioArea.sendBufCounter == -1)
{ // Set Synchronized Data
((struct SioMultiCnt *)REG_ADDR_SIOCNT)->data = MULTI_SIO_SYNC_DATA;
bufpTmp = gMultiSioArea.currentSendBufp; // Change Send Buffer
gMultiSioArea.currentSendBufp = gMultiSioArea.nextSendBufp;
gMultiSioArea.nextSendBufp = bufpTmp;
}
else if (gMultiSioArea.sendBufCounter >= 0)
{ // Set Send Data
((struct SioMultiCnt *)REG_ADDR_SIOCNT)->data = gMultiSioArea.currentSendBufp[gMultiSioArea.sendBufCounter];
}
if (gMultiSioArea.sendBufCounter < (s32)(sizeof(struct MultiSioPacket) / 2 - 1))
++gMultiSioArea.sendBufCounter;
// Receive Data Processing (Max. Approx. 350 Clocks/Included in wait period)
for (i = 0; i < 4; ++i)
{
if (recvTmp[i] == MULTI_SIO_SYNC_DATA
&& gMultiSioArea.recvBufCounter[i] > (s32)(sizeof(struct MultiSioPacket) / 2 - 3))
{
gMultiSioArea.recvBufCounter[i] = -1;
}
else
{
gMultiSioArea.currentRecvBufp[i][gMultiSioArea.recvBufCounter[i]] = recvTmp[i];
// Store Receive Data
if (gMultiSioArea.recvBufCounter[i] == (s32)(sizeof(struct MultiSioPacket) / 2 - 3))
{
bufpTmp = gMultiSioArea.lastRecvBufp[i]; // Change Receive Buffer
gMultiSioArea.lastRecvBufp[i] = gMultiSioArea.currentRecvBufp[i];
gMultiSioArea.currentRecvBufp[i] = bufpTmp;
gMultiSioArea.syncRecvFlag[i] = 1; // Receive Complete Flag
}
}
if (gMultiSioArea.recvBufCounter[i] < (s32)(sizeof(struct MultiSioPacket) / 2 - 1))
++gMultiSioArea.recvBufCounter[i];
}
// Start Master Send
if (gMultiSioArea.type == SIO_MULTI_PARENT)
{
REG_MULTI_SIO_TIMER_H = 0; // Stop Timer
REG_SIOCNT |= SIO_ENABLE; // Restart Send
REG_MULTI_SIO_TIMER_H = TIMER_1CLK | TIMER_INTR_ENABLE | TIMER_ENABLE; // Restart Timer
}
}
#endif

215
src/powf_error_handler.c Normal file
View File

@ -0,0 +1,215 @@
#include "global.h"
// lib function but doesn't match any known signature.
// fdlibm.h
#define HUGE ((float)3.40282346638528860e+38)
// math.h
union __dmath {
__uint32_t i[2];
double d;
};
#define DOMAIN 1
#define SING 2
#define OVERFLOW 3
#define UNDERFLOW 4
#define TLOSS 5
#define PLOSS 6
extern const union __dmath __infinity;
#define HUGE_VAL (__infinity.d)
struct exception
{
int type;
const char *name;
double arg1;
double arg2;
double retval;
int err;
};
float __ieee754_powf (float, float);
int isnanf(float x);
int matherr(struct exception *exc);
int finitef(float x);
double rint(double x);
// sys/errno.h
#define EDOM 33 /* Math arg out of domain of func */
#define ERANGE 34 /* Math result not representable */
int *__errno(void);
// mislinked data section - -
union __dmath gUnk_08D60950 = { .i = {0x7ff00000, 0} }; // infinity
s32 gUnk_08D60958 = 1;
static const char gUnk_08D608BC[] = "powf";
f32 powferrorhandler(f32 x, f32 y)
{
struct exception e;
union __dmath sp24;
f32 r4 = __ieee754_powf(x, y);
s32 r9 = gUnk_08D60958;
if (r9 == -1)
return r4;
if (isnanf(y) != 0)
return r4;
if (isnanf(x) != 0)
{
if (y == 0.0f)
{
e.type = DOMAIN;
e.name = gUnk_08D608BC;
e.err = 0;
e.arg1 = x;
e.arg2 = y;
e.retval = x;
if (r9 == 2)
e.retval = 1.0;
else
{
if (matherr(&e) == 0)
*__errno() = EDOM;
}
if (e.err != 0)
*__errno() = e.err;
return e.retval;
}
}
else
{
if (x == 0.0f)
{
if (y == 0.0f)
{
e.type = DOMAIN;
e.name = gUnk_08D608BC;
e.err = 0;
e.arg1 = x;
e.arg2 = y;
e.retval = 0.0;
if (r9 != 0)
e.retval = 1.0;
else
{
if (matherr(&e) == 0)
*__errno() = EDOM;
}
if (e.err != 0)
*__errno() = e.err;
return e.retval;
}
else
{
// _08159468
if (finitef(y) == 0)
return r4;
if (y < 0.0f)
{
e.type = DOMAIN;
e.name = gUnk_08D608BC;
e.err = 0;
e.arg1 = x;
e.arg2 = y;
if (r9 == 0)
e.retval = 0.0;
else
e.retval = -gUnk_08D60950.d;
if (gUnk_08D60958 == 2 || matherr(&e) == 0)
*__errno() = EDOM;
if (e.err != 0)
*__errno() = e.err;
return e.retval;
}
else
return r4;
}
}
else
{
if (finitef(r4) == 0 && finitef(x) != 0 && finitef(y) != 0)
{
if (isnanf(r4) != 0)
{
e.type = 1;
e.name = gUnk_08D608BC;
e.err = 0;
e.arg1 = x;
e.arg2 = y;
if (r9 == 0)
e.retval = 0.0;
else
{
union __d_math_2
{
f64 d;
s64 i;
};
e.retval = ((union __d_math_2)((s64)0xFFFFFFFF7FFFFFFF)).d;
}
if (gUnk_08D60958 == 2 || matherr(&e) == 0)
*__errno() = EDOM;
if (e.err != 0)
*__errno() = e.err;
return e.retval;
}
else
{
e.type = OVERFLOW;
e.name = gUnk_08D608BC;
e.err = 0;
e.arg1 = x;
e.arg2 = y;
if (r9 == 0)
{
e.retval = HUGE;
y *= 5e-1;
if (x < 0.0)
{
if(rint(y) != y)
e.retval = -HUGE;
}
}
else
{
sp24 = gUnk_08D60950;
e.retval = sp24.d;
y *= 5e-1;
if (x < 0.0)
{
if(rint(y) != y)
e.retval = -sp24.d;
}
}
}
}
else
{
if (r4 == 0.0f && finitef(x) != 0 && finitef(y) != 0)
{
e.type = UNDERFLOW;
e.name = gUnk_08D608BC;
e.err = 0;
e.arg1 = x;
e.arg2 = y;
e.retval = 0.0;
}
else
return r4;
}
if (gUnk_08D60958 == 2 || matherr(&e) == 0)
*__errno() = ERANGE;
if (e.err != 0)
*__errno() = e.err;
return e.retval;
}
}
return r4;
}

176
src/sio32_multi_load.c Normal file
View File

@ -0,0 +1,176 @@
#include "sio32_multi_load.h"
static const u8 sMultiSioLibVer[] = "Sio32MultiLoad010214";
// COMMON
// struct Sio32MultiLoadArea gSio32MultiLoadArea; // 32bit serial communication multi-load work area
/*------------------------------------------------------------------*/
/* 32bit serial communication multi-load main */
/*------------------------------------------------------------------*/
u32 Sio32MultiLoadMain(u32 *progressCounterp)
{
s32 dataCounter, dataCounterBak;
UNUSED s32 i, ii; // declared in SDK
switch (gSio32MultiLoadArea.state)
{
case 0:
if (gSio32MultiLoadArea.type || gSio32MultiLoadArea.frameCounter) // Slave SIO Mode switch delay wait
gSio32MultiLoadArea.state = 1;
break;
case 1:
if (gSio32MultiLoadArea.type == SIO_SCK_IN)
{
if (gSio32MultiLoadArea.frameCounter < SIO32ML_MODE_WAIT_FRAMES) // Master wait
break;
}
else // Slave
REG_SIOCNT = SIO_32BIT_MODE; // Switches to SIO mode
REG_SIODATA32 = 0; // Clears data registery
REG_IF = INTR_FLAG_SERIAL | SIO32ML_TIMER_INTR_FLAG; // Resets IF
if (gSio32MultiLoadArea.type == SIO_SCK_IN)
{ // Sets Master
REG_SIOCNT |= SIO_ENABLE; // Starts communication
REG_SIO32ML_TIMER = SIO32ML_TIMER_COUNT | ((TIMER_1CLK | TIMER_INTR_ENABLE | TIMER_ENABLE) << 16); // Starts timer
REG_IME = 0;
REG_IE |= SIO32ML_TIMER_INTR_FLAG; // Enables timer interrupt
REG_IME = 1;
}
else
{ // Sets Slave
REG_SIOCNT |= SIO_IF_ENABLE | SIO_ENABLE; // Starts communication
REG_IME = 0;
REG_IE |= INTR_FLAG_SERIAL; // Enables SIO interrupt
REG_IME = 1;
}
gSio32MultiLoadArea.frameCounter = 0;
gSio32MultiLoadArea.state = 2;
break;
case 2:
dataCounter = gSio32MultiLoadArea.dataCounter;
dataCounterBak = dataCounter;
if (dataCounter > SIO32ML_BLOCK_SIZE / 4)
dataCounter = SIO32ML_BLOCK_SIZE / 4;
else if (dataCounter < 0)
dataCounter = 0;
if (progressCounterp)
*progressCounterp = dataCounter; // Set progress counter
if (gSio32MultiLoadArea.type != SIO_SCK_IN)
{ // Slave
while (gSio32MultiLoadArea.checkSumCounter < dataCounter) // Receiving data sum check
gSio32MultiLoadArea.checkSumTmp += ((s32 *)gSio32MultiLoadArea.datap)[gSio32MultiLoadArea.checkSumCounter++];
if (dataCounterBak > SIO32ML_BLOCK_SIZE / 4)
if ((gSio32MultiLoadArea.checkSum += gSio32MultiLoadArea.checkSumTmp) == -1)
gSio32MultiLoadArea.downloadSuccessFlag = 1; // Succeeds download
}
if (dataCounterBak > SIO32ML_BLOCK_SIZE / 4 // Complete communication
|| gSio32MultiLoadArea.frameCounter == 0x8C) // SIO32ML_LD_TIMEOUT_FRAMES in SDK doesn't match
gSio32MultiLoadArea.state = 3; // Load time out
break;
case 3:
REG_IME = 0;
REG_IE &= ~(INTR_FLAG_SERIAL | SIO32ML_TIMER_INTR_FLAG); // Disables SIO and timer interrupt
REG_IME = 1;
REG_SIOCNT = SIO_32BIT_MODE; // Stops SIO32
*(vu32 *)REG_ADDR_SIOCNT = SIO_MULTI_MODE; // Switches to SIO mode
*(vu32 *)REG_ADDR_SIOCNT = SIO_MULTI_MODE | MULTI_SIO_BAUD_RATE_NO;
*(vu64 *)REG_ADDR_SIODATA32 = 0; // Clears data register
if (gSio32MultiLoadArea.type) // Master
REG_SIO32ML_TIMER = 0; // Resets timer
REG_IF = INTR_FLAG_SERIAL | SIO32ML_TIMER_INTR_FLAG; // Resets IF
if (!gSio32MultiLoadArea.type)
return 1; // Slave comes back first
gSio32MultiLoadArea.frameCounter = 0;
gSio32MultiLoadArea.state = 4;
break;
case 4:
if (gSio32MultiLoadArea.frameCounter >= 3) // Master comes back later
return 1;
break;
}
++gSio32MultiLoadArea.frameCounter;
return 0;
}
/*==================================================================*/
/* 32bit Serial Communication Multi-load Interrupt Routine */
/*==================================================================*/
void Sio32MultiLoadIntr(void)
{
u32 recvTmp;
u32 *bufpTmp;
// Saves received data
recvTmp = REG_SIODATA32;
// Slave prepares to receive
if (gSio32MultiLoadArea.type != SIO_SCK_IN)
REG_SIOCNT |= SIO_ENABLE;
if (gSio32MultiLoadArea.type == SIO_SCK_IN)
{
REG_SIO32ML_TIMER_H = 0; // Stops timer
// Process sending data
if (gSio32MultiLoadArea.dataCounter < 0) // Sets synchronous data
REG_SIODATA32 = SIO32ML_SYNC_DATA;
else if (gSio32MultiLoadArea.dataCounter < SIO32ML_BLOCK_SIZE / 4) // Sets sending data
REG_SIODATA32 = gSio32MultiLoadArea.datap[gSio32MultiLoadArea.dataCounter];
else
REG_SIODATA32 = gSio32MultiLoadArea.checkSum; // Sets check sum
}
else
{
// Process receiving data
if (gSio32MultiLoadArea.dataCounter < 0)
{ // Checks synchronous data
if (recvTmp != SIO32ML_SYNC_DATA)
--gSio32MultiLoadArea.dataCounter;
}
else if (gSio32MultiLoadArea.dataCounter < SIO32ML_BLOCK_SIZE / 4) // Saves receiving data
gSio32MultiLoadArea.datap[gSio32MultiLoadArea.dataCounter] = recvTmp;
else
gSio32MultiLoadArea.checkSum = recvTmp; // Saves check sum
}
if (gSio32MultiLoadArea.dataCounter < SIO32ML_BLOCK_SIZE / 4 + 3)
{
++gSio32MultiLoadArea.dataCounter;
// Master starts to sending
if (gSio32MultiLoadArea.type == SIO_SCK_IN)
{
REG_SIOCNT |= SIO_ENABLE; // Restarts sending
REG_SIO32ML_TIMER_H = TIMER_1CLK | TIMER_INTR_ENABLE | TIMER_ENABLE; // Restarts timer
}
}
}
/*------------------------------------------------------------------*/
/* 32bit Serial communication multi-load initialization */
/*------------------------------------------------------------------*/
void Sio32MultiLoadInit(u32 type, void *datap)
{
s32 checkSum = 0;
UNUSED s32 i; // declared in SDK
REG_IME = 0;
REG_IE &= ~(INTR_FLAG_SERIAL | SIO32ML_TIMER_INTR_FLAG); // Disables SIO and timer interrupt
REG_IME = 1;
CpuFill32(0, &gSio32MultiLoadArea, sizeof(gSio32MultiLoadArea)); // Clears 32bit serial communication work area
#ifdef SIO32ML_DI_FUNC_FAST // Copies function
CpuCopy32(Sio32MultiLoadIntr, gMultiSioIntrFuncBuf, sizeof(gMultiSioIntrFuncBuf));
#endif
*(vu32 *)REG_ADDR_SIOCNT = SIO_MULTI_MODE | MULTI_SIO_BAUD_RATE_NO; // Stops multi-play communication
gSio32MultiLoadArea.datap = datap; // Sets data pointer
gSio32MultiLoadArea.dataCounter = -1;
if (type)
{ // Sets Master
REG_SIO32ML_TIMER = 0; // Resets timer
gSio32MultiLoadArea.type = SIO_SCK_IN;
for (i = 0; i < SIO32ML_BLOCK_SIZE / 4; ++i) // Calculates sending data check sum
checkSum += ((s32 *)datap)[i];
gSio32MultiLoadArea.checkSum = ~checkSum;
REG_SIOCNT = SIO_32BIT_MODE; // Switches to SIO mode (preceding code)
REG_SIOCNT = SIO_32BIT_MODE | SIO_SCK_IN | SIO_IN_SCK_256K;
}
}