Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
95682ef709 | |||
5381563d11 | |||
450335c79a | |||
3359073498 | |||
2675aa13c9 | |||
86006fde68 | |||
908f950ff0 | |||
dd5d9d0bc0 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,6 +4,7 @@
|
|||||||
*.o
|
*.o
|
||||||
*.bin
|
*.bin
|
||||||
*.dfs
|
*.dfs
|
||||||
|
*/target/
|
||||||
|
|
||||||
## OSX junk
|
## OSX junk
|
||||||
.DS_Store
|
.DS_Store
|
||||||
@ -17,3 +18,4 @@
|
|||||||
*properties.json
|
*properties.json
|
||||||
/.vs
|
/.vs
|
||||||
/.vscode
|
/.vscode
|
||||||
|
*/.idea/
|
||||||
|
52
Makefile
52
Makefile
@ -15,13 +15,28 @@ HEADERTITLE = "EverDrive OS"
|
|||||||
SRCDIR = ./src
|
SRCDIR = ./src
|
||||||
INCDIR = ./inc
|
INCDIR = ./inc
|
||||||
RESDIR = ./res
|
RESDIR = ./res
|
||||||
OBJDIR = ./obj
|
BINDIR = ./target
|
||||||
BINDIR = ./bin
|
OBJDIR = $(BINDIR)/obj
|
||||||
TOOLSDIR = ./tools
|
TOOLSDIR = ./tools
|
||||||
|
|
||||||
LINK_FLAGS = -O1 -L$(ROOTDIR)/lib -L$(ROOTDIR)/mips64-elf/lib -ldragon -lmad -lyaml -lc -lm -ldragonsys -lnosys $(LIBS) -Tn64ld.x
|
RUST_DIR = ./rust
|
||||||
PROG_NAME = OS64P
|
RUST_TARGET_DIR = target/mips-nintendo64-none/release
|
||||||
CFLAGS = -std=gnu99 -march=vr4300 -mtune=vr4300 -O1 -I$(INCDIR) -I$(ROOTDIR)/include -I$(ROOTDIR)/mips64-elf/include -lpthread -lrt -D_REENTRANT -DUSE_TRUETYPE $(SET_DEBUG)
|
RUST_FULL_TARGET_DIR = $(RUST_DIR)/$(RUST_TARGET_DIR)
|
||||||
|
RUST_DEPS := $(wildcard $(RUST_DIR)/src/*) $(wildcard $(RUST_DIR)/Cargo.*)
|
||||||
|
RUST_BIN_DEPS := $(RUST_DEPS) $(RUST_DIR)/mips-nintendo64-none.json
|
||||||
|
RUST_H_DEPS := $(RUST_DEPS) $(RUST_DIR)/cbindgen.toml
|
||||||
|
|
||||||
|
CFLAGS = -std=gnu99 -march=vr4300 -mtune=vr4300 -O1 -I$(INCDIR) -I$(ROOTDIR)/include -I$(ROOTDIR)/mips64-elf/include -I$(RUST_FULL_TARGET_DIR) -lpthread -lrt -D_REENTRANT -DUSE_TRUETYPE $(SET_DEBUG)
|
||||||
|
|
||||||
|
ifdef USE_YAML
|
||||||
|
CFLAGS += -DUSE_YAML
|
||||||
|
LIBS += -lyaml
|
||||||
|
else
|
||||||
|
endif
|
||||||
|
LIBS += -laltra64
|
||||||
|
|
||||||
|
LINK_FLAGS = -O1 -L$(ROOTDIR)/lib -L$(ROOTDIR)/mips64-elf/lib -L$(RUST_FULL_TARGET_DIR) -ldragon -lmad $(LIBS) -lc -lm -ldragonsys -lnosys -Tn64ld.x
|
||||||
|
PROG_NAME = $(BINDIR)/OS64P
|
||||||
ASFLAGS = -mtune=vr4300 -march=vr4300
|
ASFLAGS = -mtune=vr4300 -march=vr4300
|
||||||
CC = $(GCCN64PREFIX)gcc
|
CC = $(GCCN64PREFIX)gcc
|
||||||
AS = $(GCCN64PREFIX)as
|
AS = $(GCCN64PREFIX)as
|
||||||
@ -31,17 +46,23 @@ OBJCOPY = $(GCCN64PREFIX)objcopy
|
|||||||
SOURCES := $(wildcard $(SRCDIR)/*.c)
|
SOURCES := $(wildcard $(SRCDIR)/*.c)
|
||||||
OBJECTS = $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
|
OBJECTS = $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
|
||||||
|
|
||||||
$(PROG_NAME).v64: $ $(PROG_NAME).elf $(PROG_NAME).dfs
|
$(PROG_NAME).v64: $(PROG_NAME).elf $(PROG_NAME).dfs
|
||||||
$(OBJCOPY) $(BINDIR)/$(PROG_NAME).elf $(BINDIR)/$(PROG_NAME).bin -O binary
|
$(OBJCOPY) $(PROG_NAME).elf $(PROG_NAME).bin -O binary
|
||||||
rm -f $(BINDIR)/$(PROG_NAME).v64
|
rm -f $(PROG_NAME).v64
|
||||||
$(N64TOOL) -l 4M -t $(HEADERTITLE) -h $(RESDIR)/$(HEADERNAME) -o $(BINDIR)/$(PROG_NAME).v64 $(BINDIR)/$(PROG_NAME).bin -s 1M $(BINDIR)/$(PROG_NAME).dfs
|
$(N64TOOL) -l 4M -t $(HEADERTITLE) -h $(RESDIR)/$(HEADERNAME) -o $(PROG_NAME).v64 $(PROG_NAME).bin -s 1M $(PROG_NAME).dfs
|
||||||
$(CHKSUM64PATH) $(BINDIR)/$(PROG_NAME).v64
|
$(CHKSUM64PATH) $(PROG_NAME).v64
|
||||||
|
|
||||||
$(PROG_NAME).elf : $(OBJECTS)
|
$(RUST_FULL_TARGET_DIR)/libaltra64.a: $(RUST_BIN_DEPS)
|
||||||
|
cd $(RUST_DIR) && cargo build --release --verbose --target mips-nintendo64-none.json -Z build-std=core && touch $(RUST_TARGET_DIR)/libaltra64.a
|
||||||
|
|
||||||
|
$(RUST_FULL_TARGET_DIR)/altra64.h: $(RUST_H_DEPS)
|
||||||
|
cd $(RUST_DIR) && cbindgen -o $(RUST_TARGET_DIR)/altra64.h && touch $(RUST_TARGET_DIR)/altra64.h
|
||||||
|
|
||||||
|
$(PROG_NAME).elf : $(OBJECTS) $(RUST_FULL_TARGET_DIR)/libaltra64.a
|
||||||
@mkdir -p $(BINDIR)
|
@mkdir -p $(BINDIR)
|
||||||
$(LD) -o $(BINDIR)/$(PROG_NAME).elf $(OBJECTS) $(LINK_FLAGS)
|
$(LD) -o $(PROG_NAME).elf $(OBJECTS) $(LINK_FLAGS)
|
||||||
|
|
||||||
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
|
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c $(RUST_FULL_TARGET_DIR)/altra64.h
|
||||||
@mkdir -p $(OBJDIR)
|
@mkdir -p $(OBJDIR)
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
@ -49,7 +70,8 @@ copy: $(PROG_NAME).v64
|
|||||||
sh $(TOOLSDIR)/upload.sh
|
sh $(TOOLSDIR)/upload.sh
|
||||||
|
|
||||||
$(PROG_NAME).dfs:
|
$(PROG_NAME).dfs:
|
||||||
$(MKDFSPATH) $(BINDIR)/$(PROG_NAME).dfs $(RESDIR)/filesystem/
|
@mkdir -p $(BINDIR)
|
||||||
|
$(MKDFSPATH) $(PROG_NAME).dfs $(RESDIR)/filesystem/
|
||||||
|
|
||||||
all: $(PROG_NAME).v64
|
all: $(PROG_NAME).v64
|
||||||
|
|
||||||
@ -58,4 +80,4 @@ debug: $(PROG_NAME).v64
|
|||||||
debug: SET_DEBUG=-DDEBUG
|
debug: SET_DEBUG=-DDEBUG
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(BINDIR)/*.v64 $(BINDIR)/*.elf $(OBJDIR)/*.o $(BINDIR)/*.bin $(BINDIR)/*.dfs
|
rm -rf ./target ./rust/target
|
||||||
|
@ -14,7 +14,7 @@ The original version overwrote 1 save file per game on system reset, but if you
|
|||||||
|
|
||||||
If you want to build the menu, you need an n64 toolchain. This is terrible to build, I ended up creating a Dockerfile in the docker folder, instructions included in it.
|
If you want to build the menu, you need an n64 toolchain. This is terrible to build, I ended up creating a Dockerfile in the docker folder, instructions included in it.
|
||||||
|
|
||||||
Or if you trust me, you can use the one I built and pushed to docker hub, [moparisthebest/altra64-dev](https://hub.docker.com/r/moparisthebest/altra64-dev)
|
Or if you trust me, you can use the one I built and pushed to docker hub, [moparisthebest/altra64-rust-dev](https://hub.docker.com/r/moparisthebest/altra64-rust-dev)
|
||||||
|
|
||||||
|
|
||||||
### Build `Altra64`
|
### Build `Altra64`
|
||||||
@ -23,7 +23,7 @@ To build the Rom
|
|||||||
|
|
||||||
from the projects root directory, with docker installed
|
from the projects root directory, with docker installed
|
||||||
```
|
```
|
||||||
$ docker run --rm -v "$(pwd):/build" moparisthebest/altra64-dev make
|
$ docker run --rm -v "$HOME/.cargo/registry:/root/.cargo/registry" -v "$(pwd):/build" moparisthebest/altra64-rust-dev make
|
||||||
```
|
```
|
||||||
If it all worked, you will find `OS64.v64` in the `bin` directory.
|
If it all worked, you will find `OS64.v64` in the `bin` directory.
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ Finally, we can clean the build objects from the project
|
|||||||
|
|
||||||
from the projects root directory
|
from the projects root directory
|
||||||
```
|
```
|
||||||
$ docker run --rm -v "$(pwd):/build" moparisthebest/altra64-dev make clean
|
$ docker run --rm -v "$(pwd):/build" moparisthebest/altra64-rust-dev make clean
|
||||||
```
|
```
|
||||||
|
|
||||||
Enjoy!
|
Enjoy!
|
||||||
|
165
docker/setup-linux-32bittoolchain.sh
Executable file
165
docker/setup-linux-32bittoolchain.sh
Executable file
@ -0,0 +1,165 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 The Altra64 project contributors
|
||||||
|
# See LICENSE file in the project root for full license information.
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euxo pipefail
|
||||||
|
|
||||||
|
# Download and install latest updates for the system [sudo req.]
|
||||||
|
apt-get update
|
||||||
|
apt-get -y upgrade
|
||||||
|
|
||||||
|
# Install essential packages [sudo req.]
|
||||||
|
apt-get -y install wget build-essential git texinfo libc6 libgmp-dev libmpfr-dev libmpc-dev libpng-dev zlib1g-dev libtool autoconf
|
||||||
|
|
||||||
|
# change to the users root directory
|
||||||
|
cd ~/
|
||||||
|
|
||||||
|
# add a system variable and make it perminent
|
||||||
|
# echo 'N64_INST=/usr/local/libdragon' >> /etc/environment
|
||||||
|
# echo 'export N64_INST=/usr/local/libdragon' >> ~/.bashrc
|
||||||
|
export N64_INST=/usr/local/libdragon
|
||||||
|
|
||||||
|
# EDIT THIS LINE TO CHANGE YOUR INSTALL PATH!
|
||||||
|
export INSTALL_PATH=/usr/local/libdragon
|
||||||
|
|
||||||
|
# Set up path for newlib to compile later
|
||||||
|
export PATH=$PATH:$INSTALL_PATH/bin
|
||||||
|
|
||||||
|
# Versions
|
||||||
|
export BINUTILS_V=2.27
|
||||||
|
export GCC_V=6.2.0
|
||||||
|
export NEWLIB_V=2.4.0
|
||||||
|
|
||||||
|
|
||||||
|
export BINUTILS_V=2.37
|
||||||
|
#export GCC_V=11.2.0
|
||||||
|
#export NEWLIB_V=4.1.0
|
||||||
|
|
||||||
|
|
||||||
|
export GCC_V=4.6.4
|
||||||
|
|
||||||
|
# make a build folder for libdragon
|
||||||
|
mkdir build_gcc
|
||||||
|
cd build_gcc
|
||||||
|
|
||||||
|
# Download stage
|
||||||
|
#wget -c ftp://sourceware.org/pub/binutils/releases/binutils-$BINUTILS_V.tar.bz2
|
||||||
|
wget -c https://sourceware.org/pub/binutils/releases/binutils-$BINUTILS_V.tar.xz
|
||||||
|
wget -c https://sourceware.org/pub/gcc/releases/gcc-$GCC_V/gcc-$GCC_V.tar.bz2
|
||||||
|
#wget -c https://sourceware.org/pub/gcc/releases/gcc-$GCC_V/gcc-$GCC_V.tar.xz
|
||||||
|
wget -c https://sourceware.org/pub/newlib/newlib-$NEWLIB_V.tar.gz
|
||||||
|
|
||||||
|
# Extract stage
|
||||||
|
test -d binutils-$BINUTILS_V || tar -xvJf binutils-$BINUTILS_V.tar.xz || tar -xvjf binutils-$BINUTILS_V.tar.bz2
|
||||||
|
test -d gcc-$GCC_V || tar -xvJf gcc-$GCC_V.tar.xz || tar -xvjf gcc-$GCC_V.tar.bz2
|
||||||
|
test -d newlib-$NEWLIB_V || tar -xvzf newlib-$NEWLIB_V.tar.gz
|
||||||
|
|
||||||
|
# Binutils and newlib support compiling in source directory, GCC does not
|
||||||
|
|
||||||
|
# Compile binutils
|
||||||
|
cd binutils-$BINUTILS_V
|
||||||
|
./configure --prefix=${INSTALL_PATH} --target=mips64-elf --with-cpu=mips64vr4300 --disable-werror
|
||||||
|
make -j9
|
||||||
|
make install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Compile gcc (pass 1)
|
||||||
|
rm -rf gcc_compile
|
||||||
|
mkdir gcc_compile
|
||||||
|
cd gcc_compile
|
||||||
|
CFLAGS_FOR_TARGET="-G0 -mabi=32 -march=vr4300 -mtune=vr4300 -O2" ../gcc-$GCC_V/configure --prefix=${INSTALL_PATH} --target=mips64-elf --enable-languages=c --without-headers --with-newlib --with-system-zlib --disable-libssp --enable-multilib --disable-shared --with-gcc --with-gnu-ld --with-gnu-as --disable-threads --disable-win32-registry --disable-nls --disable-debug --disable-libmudflap --disable-werror
|
||||||
|
make -j9
|
||||||
|
make install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# hacky hack hack
|
||||||
|
mv /usr/local/libdragon/bin/mips64-elf-gcc /usr/local/libdragon/bin/mips64-elf-gcc.orig
|
||||||
|
cat > /usr/local/libdragon/bin/mips64-elf-gcc <<EOF
|
||||||
|
#!/bin/bash
|
||||||
|
set +x
|
||||||
|
exec /usr/local/libdragon/bin/mips64-elf-gcc.orig -mabi=32 -mtune=vr4300 -march=vr4300 "\$@"
|
||||||
|
EOF
|
||||||
|
chmod +x /usr/local/libdragon/bin/mips64-elf-gcc
|
||||||
|
|
||||||
|
# Compile newlib
|
||||||
|
cd newlib-$NEWLIB_V
|
||||||
|
CFLAGS_FOR_TARGET="-G0 -march=vr4300 -mtune=vr4300 -O2" CFLAGS="-O2" CXXFLAGS="-O2" ./configure --target=mips64-elf --prefix=${INSTALL_PATH} --with-cpu=mips64vr4300 --disable-threads --disable-libssp --disable-werror
|
||||||
|
make -j9
|
||||||
|
make install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Compile gcc (pass 2)
|
||||||
|
#rm -rf gcc_compile
|
||||||
|
#mkdir gcc_compile
|
||||||
|
#cd gcc_compile
|
||||||
|
#CFLAGS_FOR_TARGET="-G0 -mabi=32 -march=vr4300 -mtune=vr4300 -O2" CXXFLAGS_FOR_TARGET="-G0 -mabi=32 -march=vr4300 -mtune=vr4300 -O2" ../gcc-#$GCC_V/configure --prefix=${INSTALL_PATH} --target=mips64-elf --enable-languages=c,c++ --with-newlib --with-system-zlib --disable-libssp --#enable-multilib --disable-shared --with-gcc --with-gnu-ld --with-gnu-as --disable-threads --disable-win32-registry --disable-nls --disable-#debug --disable-libmudflap
|
||||||
|
#make -j9
|
||||||
|
#make install
|
||||||
|
#cd ..
|
||||||
|
|
||||||
|
export CFLAGS="-std=gnu99 -mabi=32 -march=vr4300 -mtune=vr4300"
|
||||||
|
|
||||||
|
export CFLAGS="-std=gnu99 -march=vr4300 -mtune=vr4300"
|
||||||
|
|
||||||
|
# Pull the latest libdragon source code and make a build directory
|
||||||
|
git clone https://github.com/dragonminded/libdragon.git
|
||||||
|
# set to correct commit
|
||||||
|
cd libdragon
|
||||||
|
git checkout -f b26fce6
|
||||||
|
|
||||||
|
# fix issues with the build scripts
|
||||||
|
sed -i -- 's|${N64_INST:-/usr/local}|/usr/local/libdragon|g' tools/build
|
||||||
|
sed -i -- 's|--with-newlib|--with-newlib --with-system-zlib|g' tools/build
|
||||||
|
|
||||||
|
sed -i -- 's| -lpng|\nLDLIBS = -lpng|g' tools/mksprite/Makefile
|
||||||
|
sed -i -- 's| -Werror| -w|g' tools/mksprite/Makefile
|
||||||
|
# run the install script
|
||||||
|
#find -type f -name Makefile -print0 | xargs -0 sed -i 's/ -mtune=vr4300 / -mabi=32 -mtune=vr4300 /'
|
||||||
|
make -j9
|
||||||
|
make install
|
||||||
|
make -j9 tools
|
||||||
|
make tools-install
|
||||||
|
|
||||||
|
export LDFLAGS="-L$N64_INST/lib -Tn64ld.x"
|
||||||
|
export LIBS="-ldragon -lc -ldragonsys -lnosys"
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
# install libmikmod (custom version)
|
||||||
|
git clone https://github.com/n64-tools/libmikmod
|
||||||
|
cd libmikmod/n64
|
||||||
|
make -j9
|
||||||
|
make install
|
||||||
|
cd .. # we have are in a subfolder, this is not a duplicate...
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
# install libyaml
|
||||||
|
git clone https://github.com/yaml/libyaml
|
||||||
|
cd libyaml
|
||||||
|
./bootstrap
|
||||||
|
./configure --host=mips64-elf --prefix=$N64_INST
|
||||||
|
make -j9
|
||||||
|
make install
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
# install libmad (custom version)
|
||||||
|
git clone https://github.com/n64-tools/libmad
|
||||||
|
cd libmad
|
||||||
|
./configure --host=mips64-elf --prefix=$N64_INST
|
||||||
|
# needed for GCC 4.6.4
|
||||||
|
sed -i 's/-fforce-mem//' Makefile
|
||||||
|
make -j9
|
||||||
|
make install
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Perform cleanup
|
||||||
|
apt-get -y autoremove
|
||||||
|
apt-get autoclean
|
||||||
|
|
||||||
|
find /usr/local/libdragon/bin /usr/local/libdragon/mips64-elf/bin /usr/local/libdragon/libexec/gcc/mips64-elf -type f -print0 | xargs -0 strip || true
|
||||||
|
|
||||||
|
# these are ENV in Dockerfile now
|
||||||
|
#echo 'export N64_INST=/usr/local/libdragon' >> ~/.bashrc
|
||||||
|
#echo 'export PATH="$PATH:$N64_INST/bin"' >> ~/.bashrc
|
7
rust/Cargo.lock
generated
Normal file
7
rust/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "altra64"
|
||||||
|
version = "0.1.0"
|
25
rust/Cargo.toml
Normal file
25
rust/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "altra64"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["moparisthebest <admin@moparisthebest.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
#libc = {version = "0.2", default-features = false}
|
||||||
|
#no-std-compat = { version = "0.4.1", features = [ "alloc" ] }
|
||||||
|
#libdragon-bindings = { git = "https://github.com/DagothBob/libdragon-bindings" }
|
||||||
|
#cstr_core = {version = "0.2", default-features = false}
|
||||||
|
|
||||||
|
# the profile used for `cargo build`
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort" # disable stack unwinding on panic
|
||||||
|
lto = "off"
|
||||||
|
|
||||||
|
# the profile used for `cargo build --release`
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort" # disable stack unwinding on panic
|
||||||
|
lto = "off"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "altra64"
|
||||||
|
crate-type = ["staticlib"]
|
16
rust/Dockerfile
Normal file
16
rust/Dockerfile
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
# to build and test:
|
||||||
|
# docker build -t altra64-rust-dev . && docker run --rm -v "$HOME/.cargo/registry:/root/.cargo/registry" -v "$(pwd):/build" -it altra64-rust-dev
|
||||||
|
|
||||||
|
# to use to compile altra64 (or other n64 stuff I guess)
|
||||||
|
# docker run --rm -v "$HOME/.cargo/registry:/root/.cargo/registry" -v "$(pwd):/build" -it altra64-rust-dev ./build.sh
|
||||||
|
|
||||||
|
FROM moparisthebest/altra64-dev
|
||||||
|
|
||||||
|
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/libdragon/bin:/root/.cargo/bin
|
||||||
|
|
||||||
|
RUN apt-get -y install curl && \
|
||||||
|
curl https://sh.rustup.rs -sSf | sh -s -- -y --no-modify-path --profile minimal --default-toolchain nightly --component rust-src && \
|
||||||
|
apt-get -y purge curl && \
|
||||||
|
cargo install cbindgen && \
|
||||||
|
rm -rf ~/.cargo/registry/
|
19
rust/cbindgen.toml
Normal file
19
rust/cbindgen.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# This is a template cbindgen.toml file with all of the default values.
|
||||||
|
# Some values are commented out because their absence is the real default.
|
||||||
|
#
|
||||||
|
# See https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml
|
||||||
|
# for detailed documentation of every option here.
|
||||||
|
|
||||||
|
language = "C"
|
||||||
|
|
||||||
|
############## Options for Wrapping the Contents of the Header #################
|
||||||
|
|
||||||
|
# header = "/* Text to put at the beginning of the generated file. Probably a license. */"
|
||||||
|
# trailer = "/* Text to put at the end of the generated file */"
|
||||||
|
include_guard = "ALTRA64_H"
|
||||||
|
#pragma_once = true
|
||||||
|
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
|
||||||
|
include_version = false
|
||||||
|
|
||||||
|
[export]
|
||||||
|
exclude = ["strtoul", "screen_text", "test_c_print", "screen_text_num", "screen_text_ptr"]
|
25
rust/mips-nintendo64-none.json
Normal file
25
rust/mips-nintendo64-none.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"arch": "mips",
|
||||||
|
"cpu": "mips3",
|
||||||
|
"data-layout": "E-m:m-p:64:64-i8:8:32-i16:16:32-i64:64-n64-S64",
|
||||||
|
"disable-redzone": true,
|
||||||
|
"env": "unknown",
|
||||||
|
"executables": true,
|
||||||
|
"features": "+mips3,+gp64,+noabicalls",
|
||||||
|
"linker": "rust-lld",
|
||||||
|
"linker-flavor": "ld.lld",
|
||||||
|
"llvm-target": "mips-unknown-unknown",
|
||||||
|
"llvm-abiname": "n64",
|
||||||
|
"os": "none",
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
"pre-link-args": {
|
||||||
|
"ld.lld": [
|
||||||
|
"--script={}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"relocation-model": "static",
|
||||||
|
"target-c-int-width": "64",
|
||||||
|
"target-endian": "big",
|
||||||
|
"target-pointer-width": "64",
|
||||||
|
"vendor": "nintendo64"
|
||||||
|
}
|
453
rust/src/lib.rs
Normal file
453
rust/src/lib.rs
Normal file
@ -0,0 +1,453 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![allow(dead_code,unused_variables)]
|
||||||
|
|
||||||
|
use core::slice;
|
||||||
|
use core::iter::Iterator;
|
||||||
|
|
||||||
|
const WHITESPACE: &[u8] = b" \t\n\r";
|
||||||
|
|
||||||
|
pub trait SliceSubsequence<T> {
|
||||||
|
fn trim_start(&self, needle: &[T]) -> &[T];
|
||||||
|
fn trim_end(&self, needle: &[T]) -> &[T];
|
||||||
|
fn first_index_of(&self, needle: &[T]) -> Option<usize>;
|
||||||
|
//fn extract_between(&self, before: &[T], after: &[T]) -> Option<&[T]>;
|
||||||
|
fn lines<'a>(&'a self, needle: &'a [T]) -> LineIterator<'a, T>;
|
||||||
|
|
||||||
|
fn trim(&self, needle: &[T]) -> &[T];
|
||||||
|
|
||||||
|
fn contains_seq(&self, needle: &[T]) -> bool {
|
||||||
|
self.first_index_of(needle).is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LineIterator<'a, T> {
|
||||||
|
inner: &'a [T],
|
||||||
|
needle: &'a [T],
|
||||||
|
pos: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: PartialEq> Iterator for LineIterator<'a, T> {
|
||||||
|
type Item = &'a [T];
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.pos == self.inner.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let search = &self.inner[self.pos..];
|
||||||
|
match search.first_index_of(self.needle) {
|
||||||
|
None => {
|
||||||
|
let pos = self.pos;
|
||||||
|
self.pos = self.inner.len();
|
||||||
|
Some(&self.inner[pos..])
|
||||||
|
}
|
||||||
|
Some(idx) => {
|
||||||
|
self.pos += idx + self.needle.len();
|
||||||
|
Some(&search[..idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last_index_of<T: PartialEq>(s: &[T], needle: &[T]) -> usize {
|
||||||
|
let mut len = 0;
|
||||||
|
for i in s {
|
||||||
|
if needle.contains(i) {
|
||||||
|
len += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last_index_of_rev<T: PartialEq>(s: &[T], needle: &[T]) -> usize {
|
||||||
|
let mut len = s.len();
|
||||||
|
for i in s.iter().rev() {
|
||||||
|
if needle.contains(i) {
|
||||||
|
len -= 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq> SliceSubsequence<T> for &[T] {
|
||||||
|
fn trim_start(&self, needle: &[T]) -> &[T] {
|
||||||
|
&self[last_index_of(self, needle)..]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trim_end(&self, needle: &[T]) -> &[T] {
|
||||||
|
&self[..last_index_of_rev(self, needle)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first_index_of(&self, needle: &[T]) -> Option<usize> {
|
||||||
|
if self.len() >= needle.len() {
|
||||||
|
for i in 0..self.len() - needle.len() + 1 {
|
||||||
|
if self[i..i + needle.len()] == needle[..] {
|
||||||
|
return Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lines<'a>(&'a self, needle: &'a [T]) -> LineIterator<'a, T> {
|
||||||
|
LineIterator {
|
||||||
|
inner: self,
|
||||||
|
needle,
|
||||||
|
pos: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trim(&self, needle: &[T]) -> &[T] {
|
||||||
|
let start = last_index_of(self, needle);
|
||||||
|
let end = last_index_of_rev(self, needle);
|
||||||
|
if start >= end {
|
||||||
|
// empty
|
||||||
|
&self[0..0]
|
||||||
|
} else {
|
||||||
|
&self[start..end]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// for some reason, passing actual pointers like this freezes the n64
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn parse_cheats_ffi(
|
||||||
|
cheat_file: *mut u8, cheat_file_len: usize,
|
||||||
|
boot_cheats: *mut u32, boot_cheats_len: usize,
|
||||||
|
in_game_cheats: *mut u32, in_game_cheats_len: usize,
|
||||||
|
) -> u8 {
|
||||||
|
let cheat_file = unsafe { slice::from_raw_parts(cheat_file, cheat_file_len) };
|
||||||
|
let boot_cheats = unsafe { slice::from_raw_parts_mut(boot_cheats, boot_cheats_len) };
|
||||||
|
let in_game_cheats = unsafe { slice::from_raw_parts_mut(in_game_cheats, in_game_cheats_len) };
|
||||||
|
|
||||||
|
parse_cheats(cheat_file, boot_cheats, in_game_cheats)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// in C world, usize is actually u32, no idea why but that's a problem for another day...
|
||||||
|
// but if we put u32 here it crashes, can only send usize
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn parse_cheats_ffi(
|
||||||
|
cheat_file: usize, cheat_file_len: usize,
|
||||||
|
boot_cheats: usize, boot_cheats_len: usize,
|
||||||
|
in_game_cheats: usize, in_game_cheats_len: usize,
|
||||||
|
) -> u8 {
|
||||||
|
|
||||||
|
/*
|
||||||
|
unsafe {
|
||||||
|
let cheat_file = cheat_file as *mut u8;
|
||||||
|
let cheat_file = slice::from_raw_parts_mut(cheat_file, 4);
|
||||||
|
cheat_file[1] = b'a';
|
||||||
|
0
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
//unsafe { screen_text_ptr(b"from rust woot" as *const u8 as u32); }
|
||||||
|
|
||||||
|
//let cheat_file = unsafe { slice::from_raw_parts(cheat_file as *const u8, cheat_file_len as usize) };
|
||||||
|
let cheat_file = unsafe { slice::from_raw_parts_mut(cheat_file as *mut u8, cheat_file_len as usize) };
|
||||||
|
let boot_cheats = unsafe { slice::from_raw_parts_mut(boot_cheats as *mut u32, boot_cheats_len as usize) };
|
||||||
|
let in_game_cheats = unsafe { slice::from_raw_parts_mut(in_game_cheats as *mut u32, in_game_cheats_len as usize) };
|
||||||
|
|
||||||
|
dbg(100);
|
||||||
|
|
||||||
|
//cheat_file[1] = b'a';
|
||||||
|
|
||||||
|
//0
|
||||||
|
|
||||||
|
parse_cheats(cheat_file, boot_cheats, in_game_cheats)
|
||||||
|
}
|
||||||
|
|
||||||
|
const SUCCESS: u8 = 0;
|
||||||
|
const INVALID_CODE_LINE: u8 = 1;
|
||||||
|
const INVALID_LINE: u8 = 2;
|
||||||
|
|
||||||
|
pub fn parse_cheats(cheat_file: &[u8], boot_cheats: &mut [u32], in_game_cheats: &mut [u32]) -> u8 {
|
||||||
|
dbg(101);
|
||||||
|
let mut repeater = false;
|
||||||
|
let mut boot_cheats_idx = 0;
|
||||||
|
let mut in_game_cheats_idx = 0;
|
||||||
|
dbg(102);
|
||||||
|
for line in cheat_file.lines(b"\n") {
|
||||||
|
dbg(200);
|
||||||
|
let line = line.trim(WHITESPACE);
|
||||||
|
if line.is_empty() || line.starts_with(b"#") || line == b"---" {
|
||||||
|
continue; // empty or comment or whatever the starting thing is
|
||||||
|
} else if line.ends_with(b":") {
|
||||||
|
repeater = false;
|
||||||
|
} else if line.starts_with(b"- ") {
|
||||||
|
// we found the start of a code
|
||||||
|
let line = line.trim_start(b"- ");
|
||||||
|
let line = line.trim(WHITESPACE);
|
||||||
|
let mut line = line.lines(b" ");
|
||||||
|
match (line.next(), line.next(), line.next()) {
|
||||||
|
(Some(address), Some(value), None) => {
|
||||||
|
// proper line
|
||||||
|
let address = hex_to_u32(address.trim(WHITESPACE));
|
||||||
|
let value = hex_to_u32(value.trim(WHITESPACE));
|
||||||
|
//println!("address: {:X}, value: {:X}", address, value);
|
||||||
|
//println!("dec address: {}, value: {}", address, value);
|
||||||
|
|
||||||
|
// Do not check code types within "repeater data"
|
||||||
|
if repeater {
|
||||||
|
repeater = false;
|
||||||
|
in_game_cheats[in_game_cheats_idx] = address;
|
||||||
|
in_game_cheats_idx += 1;
|
||||||
|
in_game_cheats[in_game_cheats_idx] = value;
|
||||||
|
in_game_cheats_idx += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//println!("address >> 24: {:X}", address >> 24);
|
||||||
|
// Determine destination cheat_list for the code type
|
||||||
|
match address >> 24
|
||||||
|
{
|
||||||
|
// Uncessary code types
|
||||||
|
0x20 | // Clear code list
|
||||||
|
0xCC | // Exception Handler Selection
|
||||||
|
0xDE => // Entry Point
|
||||||
|
continue,
|
||||||
|
|
||||||
|
// Boot-time cheats
|
||||||
|
0xEE | // Disable Expansion Pak
|
||||||
|
0xF0 | // 8-bit Boot-Time Write
|
||||||
|
0xF1 | // 16-bit Boot-Time Write
|
||||||
|
0xFF => { // Cheat Engine Location
|
||||||
|
boot_cheats[boot_cheats_idx] = address;
|
||||||
|
boot_cheats_idx += 1;
|
||||||
|
boot_cheats[boot_cheats_idx] = value;
|
||||||
|
boot_cheats_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In-game cheats
|
||||||
|
0x50 => { // Repeater/Patch
|
||||||
|
// Validate repeater count
|
||||||
|
if (address & 0x0000FF00) == 0 {
|
||||||
|
repeater = true;
|
||||||
|
in_game_cheats[in_game_cheats_idx] = address;
|
||||||
|
in_game_cheats_idx += 1;
|
||||||
|
in_game_cheats[in_game_cheats_idx] = value;
|
||||||
|
in_game_cheats_idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// todo: was fallthrough from default in C, does that even work?
|
||||||
|
0xD0 | // 8-bit Equal-To Conditional
|
||||||
|
0xD1 | // 16-bit Equal-To Conditional
|
||||||
|
0xD2 | // 8-bit Not-Equal-To Conditional
|
||||||
|
0xD3 => { // 16-bit Not-Equal-To Conditional
|
||||||
|
// Validate 16-bit codes
|
||||||
|
if (address & 0x01000001) == 0x01000001 {
|
||||||
|
continue; // todo: or error
|
||||||
|
}
|
||||||
|
|
||||||
|
in_game_cheats[in_game_cheats_idx] = address;
|
||||||
|
in_game_cheats_idx += 1;
|
||||||
|
in_game_cheats[in_game_cheats_idx] = value;
|
||||||
|
in_game_cheats_idx += 1;
|
||||||
|
}
|
||||||
|
// Everything else
|
||||||
|
_ => {
|
||||||
|
if address != 0
|
||||||
|
{
|
||||||
|
// TODO: Support special code types! :)
|
||||||
|
}
|
||||||
|
// Validate 16-bit codes
|
||||||
|
if (address & 0x01000001) == 0x01000001 {
|
||||||
|
continue; // todo: or error
|
||||||
|
}
|
||||||
|
|
||||||
|
in_game_cheats[in_game_cheats_idx] = address;
|
||||||
|
in_game_cheats_idx += 1;
|
||||||
|
in_game_cheats[in_game_cheats_idx] = value;
|
||||||
|
in_game_cheats_idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return INVALID_CODE_LINE,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//println!("bad line: '{}'", String::from_utf8_lossy(line));
|
||||||
|
return INVALID_LINE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dbg(103);
|
||||||
|
SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function is called on panic.
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hex_to_u32(str: &[u8]) -> u32 {
|
||||||
|
use core::ptr::null_mut;
|
||||||
|
unsafe { strtoul(str.as_ptr(), null_mut(), 16) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn test_rust_print() {
|
||||||
|
//unsafe { test_c_print(); }
|
||||||
|
//unsafe { screen_text_num(9); }
|
||||||
|
// sent 18446744073709551515 = 4294967195 = FFFF_FF9B
|
||||||
|
// sent 0xffff_ffff_ffff_ffff = 4294967295 = FFFF_FFFF
|
||||||
|
unsafe { screen_text_num(0xffff_ffff_ffff_ffff); }
|
||||||
|
//unsafe { screen_text(b"rust test\0".as_ptr()); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rust_call_test(num: usize) {
|
||||||
|
unsafe { screen_text_num(num); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rust_call_test_ptr(num: usize) -> u8 {
|
||||||
|
unsafe {
|
||||||
|
let cheat_file = num as *mut u8;
|
||||||
|
let cheat_file = slice::from_raw_parts_mut(cheat_file, 4);
|
||||||
|
cheat_file[1] = b'a';
|
||||||
|
//screen_text_num(cheat_file[0].into());
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dbg(num: usize) {
|
||||||
|
#[cfg(not(test))]
|
||||||
|
unsafe { screen_text_num(num); }
|
||||||
|
#[cfg(test)]
|
||||||
|
println!("dbg: {}", num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rust_call_test_bla() {
|
||||||
|
//rust_call_test(b"c rust test\0".as_ptr());
|
||||||
|
rust_call_test([99, 32, 114, 117, 115, 116, 32, 116, 101, 115, 116, 0].as_ptr());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn strtoul(s: *const u8, endp: *mut *mut u8, base: i32) -> u32; // todo: is base i32 ?
|
||||||
|
fn screen_text(msg: *const u8);
|
||||||
|
fn screen_text_num(num: usize);
|
||||||
|
fn screen_text_ptr(ptr: u32);
|
||||||
|
fn test_c_print();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hex_to_u32() {
|
||||||
|
println!("i: {:?}", b"c rust test\0");
|
||||||
|
assert_eq!(hex_to_u32(b"0x09"), 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trim_start() {
|
||||||
|
let buf = &b" bla"[..];
|
||||||
|
let buf = buf.trim_start(WHITESPACE);
|
||||||
|
assert_eq!(buf, b"bla");
|
||||||
|
|
||||||
|
let buf = &b"\n\t\r \rbla"[..];
|
||||||
|
let buf = buf.trim_start(WHITESPACE);
|
||||||
|
assert_eq!(buf, b"bla");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trim_end() {
|
||||||
|
let buf = &b"bla "[..];
|
||||||
|
let buf = buf.trim_end(WHITESPACE);
|
||||||
|
assert_eq!(buf, b"bla");
|
||||||
|
|
||||||
|
let buf = &b"bla\n\t\r \r"[..];
|
||||||
|
let buf = buf.trim_end(WHITESPACE);
|
||||||
|
assert_eq!(buf, b"bla");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trim() {
|
||||||
|
let buf = &b" bla "[..];
|
||||||
|
let buf = buf.trim(WHITESPACE);
|
||||||
|
assert_eq!(buf, b"bla");
|
||||||
|
|
||||||
|
let buf = &b"\n\t\r \rbla\n\t\r \r"[..];
|
||||||
|
let buf = buf.trim(WHITESPACE);
|
||||||
|
assert_eq!(buf, b"bla");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lines() {
|
||||||
|
let lines = &b"\
|
||||||
|
line1
|
||||||
|
line2\r
|
||||||
|
line3
|
||||||
|
"[..];
|
||||||
|
let mut lines = lines.lines(b"\n");
|
||||||
|
assert_eq!(lines.next(), Some(&b"line1"[..]));
|
||||||
|
assert_eq!(lines.next(), Some(&b"line2\r"[..]));
|
||||||
|
assert_eq!(lines.next(), Some(&b"line3"[..]));
|
||||||
|
assert_eq!(lines.next(), None);
|
||||||
|
assert_eq!(lines.next(), None);
|
||||||
|
|
||||||
|
let lines = &b"F10004E4 2400"[..];
|
||||||
|
let mut lines = lines.lines(b" ");
|
||||||
|
assert_eq!(lines.next(), Some(&b"F10004E4"[..]));
|
||||||
|
assert_eq!(lines.next(), Some(&b"2400"[..]));
|
||||||
|
assert_eq!(lines.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_cheats() {
|
||||||
|
let cheats_file = &b"\
|
||||||
|
---
|
||||||
|
|
||||||
|
A:
|
||||||
|
- F10004E4 2400
|
||||||
|
- EE000000 0000
|
||||||
|
|
||||||
|
B:
|
||||||
|
- 8138EDA0 2400
|
||||||
|
|
||||||
|
"[..];
|
||||||
|
let mut boot_cheats = [0u32; 6];
|
||||||
|
let mut in_game_cheats = [0u32; 6];
|
||||||
|
let ok = parse_cheats(cheats_file, &mut boot_cheats, &mut in_game_cheats);
|
||||||
|
assert_eq!(ok, SUCCESS);
|
||||||
|
assert_eq!(boot_cheats, [0xF10004E4, 0x2400, 0xEE000000, 0x0000, 0, 0]);
|
||||||
|
assert_eq!(in_game_cheats, [0x8138EDA0, 0x2400, 0, 0, 0, 0]);
|
||||||
|
|
||||||
|
|
||||||
|
let cheats_file = &b"\
|
||||||
|
---
|
||||||
|
# Legend of Zelda, The - Ocarina of Time (USA) (Rev 2)
|
||||||
|
|
||||||
|
Master Code:
|
||||||
|
- F10004E4 2400
|
||||||
|
- EE000000 0000
|
||||||
|
|
||||||
|
In Health (ASM):
|
||||||
|
- 8138EDA0 2400
|
||||||
|
"[..];
|
||||||
|
let mut boot_cheats = [0u32; 6];
|
||||||
|
let mut in_game_cheats = [0u32; 6];
|
||||||
|
let ok = parse_cheats(cheats_file, &mut boot_cheats, &mut in_game_cheats);
|
||||||
|
assert_eq!(ok, SUCCESS);
|
||||||
|
assert_eq!(boot_cheats, [0xF10004E4, 0x2400, 0xEE000000, 0x0000, 0, 0]);
|
||||||
|
assert_eq!(in_game_cheats, [0x8138EDA0, 0x2400, 0, 0, 0, 0]);
|
||||||
|
|
||||||
|
let cheats_file = &b"wootwootwootwootwootwootwootwoot\0"[..];
|
||||||
|
let cheats_file = &b"wootwootwootwootwootwootwootwoot"[..];
|
||||||
|
let mut boot_cheats = [0u32; 6];
|
||||||
|
let mut in_game_cheats = [0u32; 6];
|
||||||
|
let ok = parse_cheats(cheats_file, &mut boot_cheats, &mut in_game_cheats);
|
||||||
|
assert_eq!(ok, INVALID_LINE);
|
||||||
|
assert_eq!(boot_cheats, [0, 0, 0, 0, 0, 0]);
|
||||||
|
assert_eq!(in_game_cheats, [0, 0, 0, 0, 0, 0]);
|
||||||
|
}
|
||||||
|
}
|
266
src/main.c
266
src/main.c
@ -37,8 +37,13 @@
|
|||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "mp3.h"
|
#include "mp3.h"
|
||||||
|
|
||||||
|
#ifdef USE_YAML
|
||||||
// YAML parser
|
// YAML parser
|
||||||
#include <yaml.h>
|
#include <yaml.h>
|
||||||
|
#else
|
||||||
|
#endif /* USE_YAML */
|
||||||
|
|
||||||
|
#include <altra64.h>
|
||||||
|
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -56,6 +61,10 @@
|
|||||||
|
|
||||||
#define MAX_LIST 20
|
#define MAX_LIST 20
|
||||||
|
|
||||||
|
uint8_t get_c_u8(void) {
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
|
||||||
struct glyph
|
struct glyph
|
||||||
{
|
{
|
||||||
int xoff;
|
int xoff;
|
||||||
@ -249,6 +258,50 @@ int page = 0;
|
|||||||
int cursor = 0;
|
int cursor = 0;
|
||||||
direntry_t *list;
|
direntry_t *list;
|
||||||
|
|
||||||
|
display_context_t global_disp_ctx;
|
||||||
|
|
||||||
|
void screen_text(u8 *msg) {
|
||||||
|
printText(msg, 3, -1, global_disp_ctx);
|
||||||
|
display_show(global_disp_ctx);
|
||||||
|
sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void screen_text_num(size_t num) {
|
||||||
|
char num_str[64];
|
||||||
|
|
||||||
|
sprintf(num_str, "dbg: %u", num);
|
||||||
|
screen_text(num_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void screen_text_ptr(size_t ptr) {
|
||||||
|
u8 *msg = (u8*)ptr;
|
||||||
|
screen_text(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void call_test(size_t num) {
|
||||||
|
screen_text_num(num);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
00006644 <call_test>:
|
||||||
|
6644: 27bdffd8 addiu sp,sp,-40
|
||||||
|
6648: ffbf0020 sd ra,32(sp)
|
||||||
|
664c: 0c000000 jal 0 <ttULONG>
|
||||||
|
6650: 00000000 nop
|
||||||
|
6654: dfbf0020 ld ra,32(sp)
|
||||||
|
6658: 03e00008 jr ra
|
||||||
|
665c: 27bd0028 addiu sp,sp,40
|
||||||
|
*/
|
||||||
|
|
||||||
|
void call_test_bla() {
|
||||||
|
call_test(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_c_print() {
|
||||||
|
screen_text("c rust test");
|
||||||
|
screen_text_num(5);
|
||||||
|
screen_text("c rust test2");
|
||||||
|
}
|
||||||
|
|
||||||
int filesize(FILE *pFile)
|
int filesize(FILE *pFile)
|
||||||
{
|
{
|
||||||
fseek(pFile, 0, SEEK_END);
|
fseek(pFile, 0, SEEK_END);
|
||||||
@ -1751,9 +1804,9 @@ int saveTypeToSd(display_context_t disp, char *rom_name, int stype)
|
|||||||
if (result == FR_OK)
|
if (result == FR_OK)
|
||||||
{
|
{
|
||||||
//for savegame
|
//for savegame
|
||||||
uint8_t cartsave_data[size]; //TODO: bring back old initialisation if this doesn't work
|
uint8_t cartsave_data[size];
|
||||||
|
// zero the memory so we can detect+abort if we can't get a save from the cart
|
||||||
|
memset(cartsave_data, 0, size * sizeof(cartsave_data[0]));
|
||||||
|
|
||||||
TRACEF(disp, "cartsave_data=%p", &cartsave_data);
|
TRACEF(disp, "cartsave_data=%p", &cartsave_data);
|
||||||
|
|
||||||
@ -2022,13 +2075,9 @@ void readSDcard(display_context_t disp, char *directory)
|
|||||||
display_dir(list, cursor, page, MAX_LIST, count, disp);
|
display_dir(list, cursor, page, MAX_LIST, count, disp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
#ifdef USE_YAML
|
||||||
* Returns two cheat lists:
|
int parse_cheats_yaml(char *cheatfile, u32 *list1, u32 *list2) {
|
||||||
* - One for the "at boot" cheats
|
|
||||||
* - Another for the "in-game" cheats
|
|
||||||
*/
|
|
||||||
int readCheatFile(TCHAR *filename, u32 *cheat_lists[2])
|
|
||||||
{
|
|
||||||
// YAML parser
|
// YAML parser
|
||||||
yaml_parser_t parser;
|
yaml_parser_t parser;
|
||||||
yaml_event_t event;
|
yaml_event_t event;
|
||||||
@ -2037,61 +2086,14 @@ int readCheatFile(TCHAR *filename, u32 *cheat_lists[2])
|
|||||||
int is_code = 0;
|
int is_code = 0;
|
||||||
int code_on = 1;
|
int code_on = 1;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
u32 *list1;
|
|
||||||
u32 *list2;
|
|
||||||
char *next;
|
|
||||||
|
|
||||||
int repeater = 0;
|
|
||||||
u32 address;
|
u32 address;
|
||||||
u32 value;
|
u32 value;
|
||||||
|
|
||||||
|
char *next;
|
||||||
|
|
||||||
|
int repeater = 0;
|
||||||
|
|
||||||
yaml_parser_initialize(&parser);
|
yaml_parser_initialize(&parser);
|
||||||
|
|
||||||
|
|
||||||
FRESULT result;
|
|
||||||
FIL file;
|
|
||||||
UINT bytesread;
|
|
||||||
result = f_open(&file, filename, FA_READ);
|
|
||||||
|
|
||||||
if (result == FR_OK)
|
|
||||||
{
|
|
||||||
int fsize = f_size(&file);
|
|
||||||
|
|
||||||
char *cheatfile = malloc(fsize);
|
|
||||||
if (!cheatfile)
|
|
||||||
{
|
|
||||||
return -2; // Out of memory
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Size of the cheat list can never be more than half the size of the YAML
|
|
||||||
* Minimum YAML example:
|
|
||||||
* A:-80001234 FFFF
|
|
||||||
* Which is exactly 16 bytes.
|
|
||||||
* The cheat list in this case fits into exactly 8 bytes (2 words):
|
|
||||||
* 0x80001234, 0x0000FFFF
|
|
||||||
*/
|
|
||||||
list1 = calloc(1, fsize + 2 * sizeof(u32)); // Plus 2 words to be safe
|
|
||||||
if (!list1)
|
|
||||||
{
|
|
||||||
// Free
|
|
||||||
free(cheatfile);
|
|
||||||
return -2; // Out of memory
|
|
||||||
}
|
|
||||||
list2 = &list1[fsize / sizeof(u32) / 2];
|
|
||||||
cheat_lists[0] = list1;
|
|
||||||
cheat_lists[1] = list2;
|
|
||||||
|
|
||||||
result =
|
|
||||||
f_read (
|
|
||||||
&file, /* [IN] File object */
|
|
||||||
cheatfile, /* [OUT] Buffer to store read data */
|
|
||||||
fsize, /* [IN] Number of bytes to read */
|
|
||||||
&bytesread /* [OUT] Number of bytes read */
|
|
||||||
);
|
|
||||||
|
|
||||||
f_close(&file);
|
|
||||||
|
|
||||||
yaml_parser_set_input_string(&parser, cheatfile, strlen(cheatfile));
|
yaml_parser_set_input_string(&parser, cheatfile, strlen(cheatfile));
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -2101,11 +2103,6 @@ int readCheatFile(TCHAR *filename, u32 *cheat_lists[2])
|
|||||||
// Free
|
// Free
|
||||||
yaml_parser_delete(&parser);
|
yaml_parser_delete(&parser);
|
||||||
yaml_event_delete(&event);
|
yaml_event_delete(&event);
|
||||||
free(cheatfile);
|
|
||||||
free(cheat_lists[0]);
|
|
||||||
cheat_lists[0] = 0;
|
|
||||||
cheat_lists[1] = 0;
|
|
||||||
|
|
||||||
return -3; // Parse error
|
return -3; // Parse error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2217,7 +2214,89 @@ int readCheatFile(TCHAR *filename, u32 *cheat_lists[2])
|
|||||||
|
|
||||||
// Free
|
// Free
|
||||||
yaml_parser_delete(&parser);
|
yaml_parser_delete(&parser);
|
||||||
|
|
||||||
|
return repeater;
|
||||||
|
}
|
||||||
|
#endif /* USE_YAML */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns two cheat lists:
|
||||||
|
* - One for the "at boot" cheats
|
||||||
|
* - Another for the "in-game" cheats
|
||||||
|
*/
|
||||||
|
int readCheatFile(TCHAR *filename, u32 *cheat_lists[2])
|
||||||
|
{
|
||||||
|
u32 *list1;
|
||||||
|
u32 *list2;
|
||||||
|
|
||||||
|
int repeater = 0;
|
||||||
|
|
||||||
|
FRESULT result;
|
||||||
|
FIL file;
|
||||||
|
UINT bytesread;
|
||||||
|
result = f_open(&file, filename, FA_READ);
|
||||||
|
|
||||||
|
screen_text("in readCheatFile");
|
||||||
|
screen_text_num(0xffffffffffffffff);
|
||||||
|
test_rust_print();
|
||||||
|
screen_text("called rust");
|
||||||
|
|
||||||
|
if (result == FR_OK)
|
||||||
|
{
|
||||||
|
int fsize = f_size(&file);
|
||||||
|
|
||||||
|
char *cheatfile = malloc(fsize);
|
||||||
|
if (!cheatfile)
|
||||||
|
{
|
||||||
|
return -2; // Out of memory
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size of the cheat list can never be more than half the size of the YAML
|
||||||
|
* Minimum YAML example:
|
||||||
|
* A:-80001234 FFFF
|
||||||
|
* Which is exactly 16 bytes.
|
||||||
|
* The cheat list in this case fits into exactly 8 bytes (2 words):
|
||||||
|
* 0x80001234, 0x0000FFFF
|
||||||
|
*/
|
||||||
|
size_t both_list_sizes = fsize + 2 * sizeof(u32);
|
||||||
|
list1 = calloc(1, both_list_sizes); // Plus 2 words to be safe
|
||||||
|
if (!list1)
|
||||||
|
{
|
||||||
|
// Free
|
||||||
free(cheatfile);
|
free(cheatfile);
|
||||||
|
return -2; // Out of memory
|
||||||
|
}
|
||||||
|
size_t list2_size = fsize / sizeof(u32) / 2;
|
||||||
|
list2 = &list1[list2_size];
|
||||||
|
cheat_lists[0] = list1;
|
||||||
|
cheat_lists[1] = list2;
|
||||||
|
|
||||||
|
result =
|
||||||
|
f_read (
|
||||||
|
&file, /* [IN] File object */
|
||||||
|
cheatfile, /* [OUT] Buffer to store read data */
|
||||||
|
fsize, /* [IN] Number of bytes to read */
|
||||||
|
&bytesread /* [OUT] Number of bytes read */
|
||||||
|
);
|
||||||
|
|
||||||
|
f_close(&file);
|
||||||
|
|
||||||
|
#ifdef USE_YAML
|
||||||
|
repeater = parse_cheats_yaml(cheatfile, list1, list2);
|
||||||
|
#else
|
||||||
|
// use rust
|
||||||
|
size_t list1_size = both_list_sizes - list2_size;
|
||||||
|
repeater = parse_cheats_ffi((size_t)cheatfile, fsize, (size_t)list1, list1_size, (size_t)list2, list2_size);
|
||||||
|
#endif /* USE_YAML */
|
||||||
|
|
||||||
|
free(cheatfile);
|
||||||
|
if (repeater != 0) {
|
||||||
|
// this is what original yaml code did
|
||||||
|
free(cheat_lists[0]);
|
||||||
|
cheat_lists[0] = 0;
|
||||||
|
cheat_lists[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return repeater; // Ok or repeater error
|
return repeater; // Ok or repeater error
|
||||||
|
|
||||||
@ -2242,10 +2321,12 @@ void bootRom(display_context_t disp, int silent)
|
|||||||
char cheat_filename[64];
|
char cheat_filename[64];
|
||||||
sprintf(cheat_filename, "/"ED64_FIRMWARE_PATH"/CHEATS/%s.yml", rom_filename);
|
sprintf(cheat_filename, "/"ED64_FIRMWARE_PATH"/CHEATS/%s.yml", rom_filename);
|
||||||
|
|
||||||
|
global_disp_ctx = disp;
|
||||||
int ok = readCheatFile(cheat_filename, cheat_lists);
|
int ok = readCheatFile(cheat_filename, cheat_lists);
|
||||||
if (ok == 0)
|
if (ok == 0)
|
||||||
{
|
{
|
||||||
printText("cheats found...", 3, -1, disp);
|
printText("cheats found...", 3, -1, disp);
|
||||||
|
sleep(10000);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -4560,6 +4641,59 @@ int main(void)
|
|||||||
drawBg(disp); //new
|
drawBg(disp); //new
|
||||||
drawBoxNumber(disp, 1); //new
|
drawBoxNumber(disp, 1); //new
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
global_disp_ctx = disp;
|
||||||
|
screen_text("in MAIN");
|
||||||
|
screen_text_num(SIZE_MAX);
|
||||||
|
screen_text("in MAIN2");
|
||||||
|
screen_text_num((size_t)-1);
|
||||||
|
screen_text("in MAIN3");
|
||||||
|
screen_text_num(0xffffffffffffffff);
|
||||||
|
test_rust_print();
|
||||||
|
screen_text_ptr((size_t)"called rust");
|
||||||
|
rust_call_test(SIZE_MAX);
|
||||||
|
screen_text_ptr((size_t)"called rust2");
|
||||||
|
char* woot = "wootwootwootwootwootwootwootwoot";
|
||||||
|
size_t fsize = 32;
|
||||||
|
|
||||||
|
//u8 repeater = rust_call_test_ptr((size_t) woot);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
u32 *list1;
|
||||||
|
u32 *list2;
|
||||||
|
size_t both_list_sizes = fsize + 2 * sizeof(u32);
|
||||||
|
list1 = calloc(1, both_list_sizes); // Plus 2 words to be safe
|
||||||
|
if (!list1)
|
||||||
|
{
|
||||||
|
screen_text("oom");
|
||||||
|
while(true) { sleep(1000); }
|
||||||
|
}
|
||||||
|
size_t list2_size = fsize / sizeof(u32) / 2;
|
||||||
|
list2 = &list1[list2_size];
|
||||||
|
//cheat_lists[0] = list1;
|
||||||
|
//cheat_lists[1] = list2;
|
||||||
|
|
||||||
|
size_t list1_size = both_list_sizes - list2_size;
|
||||||
|
|
||||||
|
screen_text_num(list1_size);
|
||||||
|
screen_text_num(list2_size);
|
||||||
|
screen_text_ptr((size_t)"called rust2.5");
|
||||||
|
|
||||||
|
u8 repeater = parse_cheats_ffi((size_t)woot, fsize
|
||||||
|
, (size_t)list1, list1_size
|
||||||
|
, (size_t)list2, list2_size
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
screen_text("called rust3");
|
||||||
|
screen_text(woot);
|
||||||
|
screen_text("called rust4");
|
||||||
|
while(true) { sleep(1000); }
|
||||||
|
|
||||||
uint32_t *buffer = (uint32_t *)__get_buffer(disp); //fg disp = 2
|
uint32_t *buffer = (uint32_t *)__get_buffer(disp); //fg disp = 2
|
||||||
|
|
||||||
display_show(disp); //new
|
display_show(disp); //new
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
#include <libdragon.h>
|
#include <libdragon.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user