mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Compare commits
35 Commits
v0.6.0-rc2
...
v0.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f90857032c | ||
|
|
1653a9a3f2 | ||
|
|
3c049983f1 | ||
|
|
8553b61a94 | ||
|
|
ab12c474d2 | ||
|
|
8ccbd9dc36 | ||
|
|
b8307432b8 | ||
|
|
80a62a8a03 | ||
|
|
bbe28faab4 | ||
|
|
106ad30e5a | ||
|
|
a1107fc5cf | ||
|
|
969412af24 | ||
|
|
c10345f26d | ||
|
|
6fd5c94b27 | ||
|
|
ddb1d0b6aa | ||
|
|
08545643cf | ||
|
|
140c6b169e | ||
|
|
d86d24bdc1 | ||
|
|
a1a919579c | ||
|
|
a47da5f71f | ||
|
|
68ad926279 | ||
|
|
dec4133e84 | ||
|
|
c35cb6ac32 | ||
|
|
023884d2b0 | ||
|
|
3567faf395 | ||
|
|
6502ed3919 | ||
|
|
b1a241233e | ||
|
|
f88968ec20 | ||
|
|
5ad8a8c958 | ||
|
|
2827374505 | ||
|
|
b8385a50e3 | ||
|
|
02923a67f3 | ||
|
|
f5b1990604 | ||
|
|
0794da22bc | ||
|
|
6df75f7af3 |
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -1,2 +1,6 @@
|
|||||||
# Shell scripts need Unix line endings (see https://github.com/gbdev/rgbds/issues/841)
|
# Shell scripts need Unix line endings (see https://github.com/gbdev/rgbds/issues/841)
|
||||||
*.sh text eol=lf
|
*.sh text eol=lf
|
||||||
|
*.bash text eol=lf
|
||||||
|
|
||||||
|
# Flags also need Unix line endings (see https://github.com/gbdev/rgbds/issues/955)
|
||||||
|
*.flags text eol=lf
|
||||||
|
|||||||
17
.github/actions/mingw-configure.sh
vendored
17
.github/actions/mingw-configure.sh
vendored
@@ -1,17 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
source mingw-env @TRIPLE@
|
|
||||||
echo LAST IS: $last
|
|
||||||
|
|
||||||
# check if last arg is a path to configure, else use parent
|
|
||||||
for last; do true; done
|
|
||||||
if test -x "${last}/configure"; then
|
|
||||||
config_path="$last"
|
|
||||||
else
|
|
||||||
config_path=".."
|
|
||||||
fi
|
|
||||||
|
|
||||||
${config_path}/configure \
|
|
||||||
--host=@TRIPLE@ --target=@TRIPLE@ --build="$CHOST" \
|
|
||||||
--prefix=/usr/@TRIPLE@ --libdir=/usr/@TRIPLE@/lib --includedir=/usr/@TRIPLE@/include \
|
|
||||||
--enable-shared --enable-static "$@"
|
|
||||||
16
.github/actions/mingw-env.sh
vendored
16
.github/actions/mingw-env.sh
vendored
@@ -1,16 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
_arch=$1
|
|
||||||
|
|
||||||
default_mingw_pp_flags="-D_FORTIFY_SOURCE=2"
|
|
||||||
default_mingw_compiler_flags="$default_mingw_pp_flags -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4"
|
|
||||||
default_mingw_linker_flags="-Wl,-O1,--sort-common,--as-needed -fstack-protector"
|
|
||||||
|
|
||||||
export CPPFLAGS="${MINGW_CPPFLAGS:-$default_mingw_pp_flags $CPPFLAGS}"
|
|
||||||
export CFLAGS="${MINGW_CFLAGS:-$default_mingw_compiler_flags $CFLAGS}"
|
|
||||||
export CXXFLAGS="${MINGW_CXXFLAGS:-$default_mingw_compiler_flags $CXXFLAGS}"
|
|
||||||
export LDFLAGS="${MINGW_LDFLAGS:-$default_mingw_linker_flags $LDFLAGS}"
|
|
||||||
|
|
||||||
mingw_prefix=/usr/${_arch}
|
|
||||||
export PKG_CONFIG_SYSROOT_DIR="${mingw_prefix}"
|
|
||||||
export PKG_CONFIG_LIBDIR="${mingw_prefix}/lib/pkgconfig:${mingw_prefix}/share/pkgconfig"
|
|
||||||
44
.github/actions/mingw-w64-libpng-dev.sh
vendored
44
.github/actions/mingw-w64-libpng-dev.sh
vendored
@@ -1,44 +1,34 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
# This script was written by ISSOtm while looking at Arch Linux's PKGBUILD for
|
|
||||||
# the corresponding package. (And its dependencies)
|
|
||||||
# https://aur.archlinux.org/packages/mingw-w64-libpng/
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
pngver=1.6.37
|
pngver=1.6.37
|
||||||
_apngver=$pngver
|
arch="$1"
|
||||||
_arch="$1"
|
|
||||||
|
|
||||||
|
|
||||||
## Install mingw-configure and mingw-env (both build dependencies)
|
|
||||||
|
|
||||||
install -m 755 .github/actions/mingw-env.sh /usr/bin/mingw-env
|
|
||||||
|
|
||||||
sed "s|@TRIPLE@|${_arch}|g" .github/actions/mingw-configure.sh > ${_arch}-configure
|
|
||||||
install -m 755 ${_arch}-configure /usr/bin/
|
|
||||||
|
|
||||||
|
|
||||||
## Grab sources and check them
|
## Grab sources and check them
|
||||||
|
|
||||||
wget http://downloads.sourceforge.net/sourceforge/libpng/libpng-$pngver.tar.xz
|
wget http://downloads.sourceforge.net/project/libpng/libpng16/$pngver/libpng-$pngver.tar.xz
|
||||||
wget http://downloads.sourceforge.net/project/apng/libpng/libpng16/libpng-$_apngver-apng.patch.gz
|
wget http://downloads.sourceforge.net/project/apng/libpng/libpng16/libpng-$pngver-apng.patch.gz
|
||||||
sha256sum -c .github/actions/mingw-w64-libpng-dev.sha256sums
|
sha256sum -c .github/actions/mingw-w64-libpng-dev.sha256sums
|
||||||
|
|
||||||
## Extract sources
|
## Extract sources and patch them
|
||||||
|
|
||||||
tar -xf libpng-$pngver.tar.xz
|
tar -xf libpng-$pngver.tar.xz
|
||||||
gunzip libpng-$_apngver-apng.patch.gz
|
gunzip libpng-$pngver-apng.patch.gz
|
||||||
|
|
||||||
|
# Patch in apng support
|
||||||
|
env -C libpng-$pngver patch -p0 ../libpng-$pngver-apng.patch
|
||||||
|
|
||||||
## Start building!
|
## Start building!
|
||||||
|
|
||||||
cd libpng-$pngver
|
mkdir -p build
|
||||||
# Patch in apng support
|
cd build
|
||||||
patch -p0 ../libpng-$_apngver-apng.patch
|
../libpng-$pngver/configure \
|
||||||
|
--host="$arch" --target="$arch" \
|
||||||
mkdir -p build-${_arch}
|
--prefix="/usr/$arch" \
|
||||||
cd build-${_arch}
|
--enable-shared --disable-static \
|
||||||
${_arch}-configure LDFLAGS=-static-libgcc
|
CPPFLAGS="-D_FORTIFY_SOURCE=2" \
|
||||||
make
|
CFLAGS="-O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4" \
|
||||||
|
LDFLAGS="-Wl,-O1,--sort-common,--as-needed -fstack-protector"
|
||||||
|
make -kj
|
||||||
make install
|
make install
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
windows:
|
windows:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2022
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Get version from tag
|
- name: Get version from tag
|
||||||
|
|||||||
13
.github/workflows/create-release-docs.yml
vendored
13
.github/workflows/create-release-docs.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: github.repository_owner == 'gbdev'
|
if: github.repository_owner == 'gbdev'
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout rgbds@release
|
- name: Checkout rgbds@release
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -18,17 +18,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repository: ${{ github.repository_owner }}/rgbds-www
|
repository: ${{ github.repository_owner }}/rgbds-www
|
||||||
path: rgbds-www
|
path: rgbds-www
|
||||||
# `-O toc` was added in 1.14.5, but the repos only have 1.14.4
|
- name: Install groff and mandoc
|
||||||
- name: Build and install mandoc + install groff
|
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -qq update
|
sudo apt-get -qq update
|
||||||
sudo apt-get install -yq groff zlib1g-dev
|
sudo apt-get install -yq groff mandoc
|
||||||
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.6.tar.gz'
|
|
||||||
tar xf mandoc-1.14.6.tar.gz
|
|
||||||
cd mandoc-1.14.6
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
- name: Update pages
|
- name: Update pages
|
||||||
working-directory: rgbds/man
|
working-directory: rgbds/man
|
||||||
run: | # The ref appears to be in the format "refs/tags/<version>", so strip that
|
run: | # The ref appears to be in the format "refs/tags/<version>", so strip that
|
||||||
|
|||||||
34
.github/workflows/testing.yml
vendored
34
.github/workflows/testing.yml
vendored
@@ -7,14 +7,14 @@ jobs:
|
|||||||
unix-testing:
|
unix-testing:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-20.04, ubuntu-18.04, macos-11.0, macos-10.15]
|
os: [ubuntu-20.04, ubuntu-22.04, macos-11, macos-12]
|
||||||
cc: [gcc, clang]
|
cc: [gcc, clang]
|
||||||
buildsys: [make, cmake]
|
buildsys: [make, cmake]
|
||||||
exclude:
|
exclude:
|
||||||
# `gcc` is just an alias to `clang` on macOS, don't bother
|
# `gcc` is just an alias to `clang` on macOS, don't bother
|
||||||
- os: macos-10.15
|
- os: macos-11
|
||||||
cc: gcc
|
cc: gcc
|
||||||
- os: macos-11.0
|
- os: macos-12
|
||||||
cc: gcc
|
cc: gcc
|
||||||
include:
|
include:
|
||||||
- cc: gcc
|
- cc: gcc
|
||||||
@@ -64,6 +64,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
bits: [32, 64]
|
bits: [32, 64]
|
||||||
|
os: [windows-2019, windows-2022]
|
||||||
include:
|
include:
|
||||||
- bits: 32
|
- bits: 32
|
||||||
arch: x86
|
arch: x86
|
||||||
@@ -72,7 +73,7 @@ jobs:
|
|||||||
arch: x86_x64
|
arch: x86_x64
|
||||||
platform: x64
|
platform: x64
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
runs-on: windows-2019
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Get zlib, libpng and bison
|
- name: Get zlib, libpng and bison
|
||||||
@@ -149,7 +150,6 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
bits: [32, 64]
|
bits: [32, 64]
|
||||||
os: [ubuntu-18.04]
|
|
||||||
include:
|
include:
|
||||||
- bits: 32
|
- bits: 32
|
||||||
arch: i686
|
arch: i686
|
||||||
@@ -158,7 +158,7 @@ jobs:
|
|||||||
arch: x86-64
|
arch: x86-64
|
||||||
triplet: x86_64-w64-mingw32
|
triplet: x86_64-w64-mingw32
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ubuntu-22.04
|
||||||
env:
|
env:
|
||||||
DIST_DIR: win${{ matrix.bits }}
|
DIST_DIR: win${{ matrix.bits }}
|
||||||
steps:
|
steps:
|
||||||
@@ -168,8 +168,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./.github/actions/install_deps.sh ${{ matrix.os }}
|
./.github/actions/install_deps.sh ${{ matrix.os }}
|
||||||
- name: Install MinGW
|
- name: Install MinGW
|
||||||
run: |
|
run: | # dpkg-dev is apparently required for pkg-config for cross-building
|
||||||
sudo apt-get install {gcc,g++}-mingw-w64-${{ matrix.arch }} mingw-w64-tools libz-mingw-w64-dev
|
sudo apt-get install {gcc,g++}-mingw-w64-${{ matrix.arch }}-win32 mingw-w64-tools libz-mingw-w64-dev dpkg-dev
|
||||||
- name: Install libpng dev headers for MinGW
|
- name: Install libpng dev headers for MinGW
|
||||||
run: |
|
run: |
|
||||||
sudo ./.github/actions/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
|
sudo ./.github/actions/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
|
||||||
@@ -177,17 +177,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make mingw${{ matrix.bits }} -j Q=
|
make mingw${{ matrix.bits }} -j Q=
|
||||||
- name: Package binaries
|
- name: Package binaries
|
||||||
run: |
|
run: | # DLL dependencies can be figured out using e.g. Dependency Walker
|
||||||
mkdir bins
|
mkdir bins
|
||||||
mv rgbasm bins/rgbasm.exe
|
mv -v rgb{asm,link,fix,gfx}.exe bins/
|
||||||
mv rgblink bins/rgblink.exe
|
cp -v /usr/${{ matrix.triplet }}/lib/zlib1.dll bins
|
||||||
mv rgbfix bins/rgbfix.exe
|
cp -v /usr/${{ matrix.triplet }}/bin/libpng16-16.dll bins
|
||||||
mv rgbgfx bins/rgbgfx.exe
|
[ "${{ matrix.bits }}" -ne 32 ] || cp -v /usr/lib/gcc/${{ matrix.triplet }}/10-win32/lib{gcc_s_dw2-1,ssp-0,stdc++-6}.dll bins
|
||||||
cp /usr/${{ matrix.triplet }}/lib/zlib1.dll bins
|
|
||||||
cp /usr/${{ matrix.triplet }}/bin/libpng16-16.dll bins
|
|
||||||
if [ ${{ matrix.bits }} -eq 32 ]; then cp /usr/lib/gcc/${{ matrix.triplet }}/7.3-win32/lib{gcc_s_sjlj-1,stdc++-6}.dll bins; fi
|
|
||||||
mv test/gfx/randtilegen{,.exe}
|
|
||||||
mv test/gfx/rgbgfx_test{,.exe}
|
|
||||||
- name: Upload Windows binaries
|
- name: Upload Windows binaries
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
@@ -205,9 +200,10 @@ jobs:
|
|||||||
needs: windows-xbuild
|
needs: windows-xbuild
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
os: [windows-2019, windows-2022]
|
||||||
bits: [32, 64]
|
bits: [32, 64]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
runs-on: windows-2019
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Retrieve binaries
|
- name: Retrieve binaries
|
||||||
|
|||||||
12
.github/workflows/update-master-docs.yml
vendored
12
.github/workflows/update-master-docs.yml
vendored
@@ -17,7 +17,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: github.repository_owner == 'gbdev'
|
if: github.repository_owner == 'gbdev'
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout rgbds@master
|
- name: Checkout rgbds@master
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -31,16 +31,10 @@ jobs:
|
|||||||
repository: gbdev/rgbds-www
|
repository: gbdev/rgbds-www
|
||||||
ref: master
|
ref: master
|
||||||
path: rgbds-www
|
path: rgbds-www
|
||||||
- name: Build and install mandoc + install groff
|
- name: Install groff and mandoc
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -qq update
|
sudo apt-get -qq update
|
||||||
sudo apt-get install -yq groff zlib1g-dev
|
sudo apt-get install -yq groff mandoc
|
||||||
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.6.tar.gz'
|
|
||||||
tar xf mandoc-1.14.6.tar.gz
|
|
||||||
cd mandoc-1.14.6
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
- name: Update pages
|
- name: Update pages
|
||||||
working-directory: rgbds/man
|
working-directory: rgbds/man
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
18
Makefile
18
Makefile
@@ -9,6 +9,8 @@
|
|||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.SUFFIXES: .h .y .c .cpp .o
|
.SUFFIXES: .h .y .c .cpp .o
|
||||||
|
|
||||||
|
.PHONY: all clean install checkcodebase checkpatch checkdiff develop debug mingw32 mingw64 wine-shim dist
|
||||||
|
|
||||||
# User-defined variables
|
# User-defined variables
|
||||||
|
|
||||||
Q := @
|
Q := @
|
||||||
@@ -33,8 +35,8 @@ VERSION_STRING := `git describe --tags --dirty --always 2>/dev/null`
|
|||||||
WARNFLAGS := -Wall -pedantic
|
WARNFLAGS := -Wall -pedantic
|
||||||
|
|
||||||
# Overridable CFLAGS
|
# Overridable CFLAGS
|
||||||
CFLAGS ?= -O3 -flto -DNDEBUG
|
CFLAGS ?= -O3 -flto=auto -DNDEBUG
|
||||||
CXXFLAGS ?= -O3 -flto -DNDEBUG
|
CXXFLAGS ?= -O3 -flto=auto -DNDEBUG
|
||||||
# Non-overridable CFLAGS
|
# Non-overridable CFLAGS
|
||||||
# _ISOC11_SOURCE is required on certain platforms to get C11 on top of the C99-based POSIX 2008
|
# _ISOC11_SOURCE is required on certain platforms to get C11 on top of the C99-based POSIX 2008
|
||||||
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=gnu11 -I include \
|
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=gnu11 -I include \
|
||||||
@@ -95,6 +97,7 @@ rgblink_obj := \
|
|||||||
src/link/section.o \
|
src/link/section.o \
|
||||||
src/link/symbol.o \
|
src/link/symbol.o \
|
||||||
src/extern/getopt.o \
|
src/extern/getopt.o \
|
||||||
|
src/extern/utf8decoder.o \
|
||||||
src/error.o \
|
src/error.o \
|
||||||
src/hashmap.o \
|
src/hashmap.o \
|
||||||
src/linkdefs.o \
|
src/linkdefs.o \
|
||||||
@@ -249,6 +252,13 @@ develop:
|
|||||||
CFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls" \
|
CFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls" \
|
||||||
CXXFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
CXXFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||||
|
|
||||||
|
# This target is used during development in order to more easily debug with gdb.
|
||||||
|
|
||||||
|
debug:
|
||||||
|
$Qenv ${MAKE} \
|
||||||
|
CFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls" \
|
||||||
|
CXXFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||||
|
|
||||||
# Targets for the project maintainer to easily create Windows exes.
|
# Targets for the project maintainer to easily create Windows exes.
|
||||||
# This is not for Windows users!
|
# This is not for Windows users!
|
||||||
# If you're building on Windows with Cygwin or Mingw, just follow the Unix
|
# If you're building on Windows with Cygwin or Mingw, just follow the Unix
|
||||||
@@ -257,12 +267,12 @@ develop:
|
|||||||
mingw32:
|
mingw32:
|
||||||
$Q${MAKE} all test/gfx/randtilegen test/gfx/rgbgfx_test \
|
$Q${MAKE} all test/gfx/randtilegen test/gfx/rgbgfx_test \
|
||||||
CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ \
|
CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ \
|
||||||
BISON=bison PKG_CONFIG=i686-w64-mingw32-pkg-config -j
|
BISON=bison PKG_CONFIG="PKG_CONFIG_SYSROOT_DIR=/usr/i686-w64-mingw32 pkg-config"
|
||||||
|
|
||||||
mingw64:
|
mingw64:
|
||||||
$Q${MAKE} all test/gfx/randtilegen test/gfx/rgbgfx_test \
|
$Q${MAKE} all test/gfx/randtilegen test/gfx/rgbgfx_test \
|
||||||
CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ \
|
CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ \
|
||||||
BISON=bison PKG_CONFIG=x86_64-w64-mingw32-pkg-config -j
|
BISON=bison PKG_CONFIG="PKG_CONFIG_SYSROOT_DIR=/usr/x86_64-w64-mingw32 pkg-config"
|
||||||
|
|
||||||
wine-shim:
|
wine-shim:
|
||||||
$Qecho '#!/bin/bash' > rgbshim.sh
|
$Qecho '#!/bin/bash' > rgbshim.sh
|
||||||
|
|||||||
@@ -35,9 +35,10 @@ _rgbasm_completions() {
|
|||||||
[b]="binary-digits:unk"
|
[b]="binary-digits:unk"
|
||||||
[D]="define:unk"
|
[D]="define:unk"
|
||||||
[g]="gfx-chars:unk"
|
[g]="gfx-chars:unk"
|
||||||
[i]="include:dir"
|
[I]="include:dir"
|
||||||
[M]="dependfile:glob-*.mk *.d"
|
[M]="dependfile:glob-*.mk *.d"
|
||||||
[o]="output:glob-*.o"
|
[o]="output:glob-*.o"
|
||||||
|
[P]="preinclude:glob-*.asm *.inc"
|
||||||
[p]="pad-value:unk"
|
[p]="pad-value:unk"
|
||||||
[Q]="q-precision:unk"
|
[Q]="q-precision:unk"
|
||||||
[r]="recursion-depth:unk"
|
[r]="recursion-depth:unk"
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ _rgbasm_warnings() {
|
|||||||
'user:Warn when executing the WARN built-in'
|
'user:Warn when executing the WARN built-in'
|
||||||
)
|
)
|
||||||
# TODO: handle `no-` and `error=` somehow?
|
# TODO: handle `no-` and `error=` somehow?
|
||||||
# TODO: handle `=0|1|2` levels for `numeric-string` and `truncation`?
|
# TODO: handle `=0|1|2` levels for `numeric-string`, `truncation`, and `unmapped-char`?
|
||||||
_describe warning warnings
|
_describe warning warnings
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,13 +48,14 @@ local args=(
|
|||||||
'(-b --binary-digits)'{-b,--binary-digits}'+[Change chars for binary constants]:digit spec:'
|
'(-b --binary-digits)'{-b,--binary-digits}'+[Change chars for binary constants]:digit spec:'
|
||||||
'*'{-D,--define}'+[Define a string symbol]:name + value (default 1):'
|
'*'{-D,--define}'+[Define a string symbol]:name + value (default 1):'
|
||||||
'(-g --gfx-chars)'{-g,--gfx-chars}'+[Change chars for gfx constants]:chars spec:'
|
'(-g --gfx-chars)'{-g,--gfx-chars}'+[Change chars for gfx constants]:chars spec:'
|
||||||
'(-i --include)'{-i,--include}'+[Add an include directory]:include path:_files -/'
|
'(-I --include)'{-I,--include}'+[Add an include directory]:include path:_files -/'
|
||||||
'(-M --dependfile)'{-M,--dependfile}"+[List deps in make format]:output file:_files -g '*.{d,mk}'"
|
'(-M --dependfile)'{-M,--dependfile}"+[List deps in make format]:output file:_files -g '*.{d,mk}'"
|
||||||
-MG'[Assume missing files should be generated]'
|
-MG'[Assume missing files should be generated]'
|
||||||
-MP'[Add phony targets to all deps]'
|
-MP'[Add phony targets to all deps]'
|
||||||
'*'-MT"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
|
'*'-MT"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
|
||||||
'*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
|
'*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
|
||||||
'(-o --output)'{-o,--output}'+[Output file]:output file:_files'
|
'(-o --output)'{-o,--output}'+[Output file]:output file:_files'
|
||||||
|
'(-P --preinclude)'{-P,--preinclude}"+[Pre-include a file]:include file:_files -g '*.{asm,inc}'"
|
||||||
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
|
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
|
||||||
'(-Q --q-precision)'{-Q,--q-precision}'+[Set fixed-point precision]:precision:'
|
'(-Q --q-precision)'{-Q,--q-precision}'+[Set fixed-point precision]:precision:'
|
||||||
'(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:'
|
'(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:'
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define DEFAULT_CHARMAP_NAME "main"
|
||||||
|
|
||||||
struct Charmap *charmap_New(char const *name, char const *baseName);
|
struct Charmap *charmap_New(char const *name, char const *baseName);
|
||||||
void charmap_Delete(struct Charmap *charmap);
|
void charmap_Delete(struct Charmap *charmap);
|
||||||
void charmap_Set(char const *name);
|
void charmap_Set(char const *name);
|
||||||
|
|||||||
@@ -13,22 +13,22 @@
|
|||||||
|
|
||||||
extern uint8_t fixPrecision;
|
extern uint8_t fixPrecision;
|
||||||
|
|
||||||
|
uint8_t fix_Precision(void);
|
||||||
double fix_PrecisionFactor(void);
|
double fix_PrecisionFactor(void);
|
||||||
void fix_Print(int32_t i);
|
int32_t fix_Sin(int32_t i, int32_t q);
|
||||||
int32_t fix_Sin(int32_t i);
|
int32_t fix_Cos(int32_t i, int32_t q);
|
||||||
int32_t fix_Cos(int32_t i);
|
int32_t fix_Tan(int32_t i, int32_t q);
|
||||||
int32_t fix_Tan(int32_t i);
|
int32_t fix_ASin(int32_t i, int32_t q);
|
||||||
int32_t fix_ASin(int32_t i);
|
int32_t fix_ACos(int32_t i, int32_t q);
|
||||||
int32_t fix_ACos(int32_t i);
|
int32_t fix_ATan(int32_t i, int32_t q);
|
||||||
int32_t fix_ATan(int32_t i);
|
int32_t fix_ATan2(int32_t i, int32_t j, int32_t q);
|
||||||
int32_t fix_ATan2(int32_t i, int32_t j);
|
int32_t fix_Mul(int32_t i, int32_t j, int32_t q);
|
||||||
int32_t fix_Mul(int32_t i, int32_t j);
|
int32_t fix_Mod(int32_t i, int32_t j, int32_t q);
|
||||||
int32_t fix_Mod(int32_t i, int32_t j);
|
int32_t fix_Div(int32_t i, int32_t j, int32_t q);
|
||||||
int32_t fix_Div(int32_t i, int32_t j);
|
int32_t fix_Pow(int32_t i, int32_t j, int32_t q);
|
||||||
int32_t fix_Pow(int32_t i, int32_t j);
|
int32_t fix_Log(int32_t i, int32_t j, int32_t q);
|
||||||
int32_t fix_Log(int32_t i, int32_t j);
|
int32_t fix_Round(int32_t i, int32_t q);
|
||||||
int32_t fix_Round(int32_t i);
|
int32_t fix_Ceil(int32_t i, int32_t q);
|
||||||
int32_t fix_Ceil(int32_t i);
|
int32_t fix_Floor(int32_t i, int32_t q);
|
||||||
int32_t fix_Floor(int32_t i);
|
|
||||||
|
|
||||||
#endif // RGBDS_ASM_FIXPOINT_H
|
#endif // RGBDS_ASM_FIXPOINT_H
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ struct FileStackNode *fstk_GetFileStack(void);
|
|||||||
char const *fstk_GetFileName(void);
|
char const *fstk_GetFileName(void);
|
||||||
|
|
||||||
void fstk_AddIncludePath(char const *s);
|
void fstk_AddIncludePath(char const *s);
|
||||||
|
void fstk_SetPreIncludeFile(char const *s);
|
||||||
/*
|
/*
|
||||||
* @param path The user-provided file name
|
* @param path The user-provided file name
|
||||||
* @param fullPath The address of a pointer, which will be made to point at the full path
|
* @param fullPath The address of a pointer, which will be made to point at the full path
|
||||||
|
|||||||
@@ -127,6 +127,8 @@ struct Symbol *sym_FindExactSymbol(char const *symName);
|
|||||||
struct Symbol *sym_FindUnscopedSymbol(char const *symName);
|
struct Symbol *sym_FindUnscopedSymbol(char const *symName);
|
||||||
// Find a symbol, possibly scoped, by name
|
// Find a symbol, possibly scoped, by name
|
||||||
struct Symbol *sym_FindScopedSymbol(char const *symName);
|
struct Symbol *sym_FindScopedSymbol(char const *symName);
|
||||||
|
// Find a scoped symbol by name; do not return `@` or `_NARG` when they have no value
|
||||||
|
struct Symbol *sym_FindScopedValidSymbol(char const *symName);
|
||||||
struct Symbol const *sym_GetPC(void);
|
struct Symbol const *sym_GetPC(void);
|
||||||
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
|
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
|
||||||
struct Symbol *sym_Ref(char const *symName);
|
struct Symbol *sym_Ref(char const *symName);
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ enum WarningID {
|
|||||||
WARNING_OBSOLETE, // Obsolete things
|
WARNING_OBSOLETE, // Obsolete things
|
||||||
WARNING_SHIFT, // Shifting undefined behavior
|
WARNING_SHIFT, // Shifting undefined behavior
|
||||||
WARNING_SHIFT_AMOUNT, // Strange shift amount
|
WARNING_SHIFT_AMOUNT, // Strange shift amount
|
||||||
WARNING_UNMAPPED_CHAR, // Character without charmap entry
|
|
||||||
WARNING_USER, // User warnings
|
WARNING_USER, // User warnings
|
||||||
|
|
||||||
NB_PLAIN_WARNINGS,
|
NB_PLAIN_WARNINGS,
|
||||||
@@ -49,6 +48,9 @@ enum WarningID {
|
|||||||
// Implicit truncation loses some bits
|
// Implicit truncation loses some bits
|
||||||
WARNING_TRUNCATION_1,
|
WARNING_TRUNCATION_1,
|
||||||
WARNING_TRUNCATION_2,
|
WARNING_TRUNCATION_2,
|
||||||
|
// Character without charmap entry
|
||||||
|
WARNING_UNMAPPED_CHAR_1,
|
||||||
|
WARNING_UNMAPPED_CHAR_2,
|
||||||
|
|
||||||
NB_PLAIN_AND_PARAM_WARNINGS,
|
NB_PLAIN_AND_PARAM_WARNINGS,
|
||||||
#define NB_PARAM_WARNINGS (NB_PLAIN_AND_PARAM_WARNINGS - PARAM_WARNINGS_START)
|
#define NB_PARAM_WARNINGS (NB_PLAIN_AND_PARAM_WARNINGS - PARAM_WARNINGS_START)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#ifndef RGBDS_LINK_SECTION_H
|
#ifndef RGBDS_LINK_SECTION_H
|
||||||
#define RGBDS_LINK_SECTION_H
|
#define RGBDS_LINK_SECTION_H
|
||||||
|
|
||||||
// GUIDELINE: external code MUST NOT BE AWARE of the data structure used!!
|
// GUIDELINE: external code MUST NOT BE AWARE of the data structure used!
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#ifndef RGBDS_LINK_SYMBOL_H
|
#ifndef RGBDS_LINK_SYMBOL_H
|
||||||
#define RGBDS_LINK_SYMBOL_H
|
#define RGBDS_LINK_SYMBOL_H
|
||||||
|
|
||||||
// GUIDELINE: external code MUST NOT BE AWARE of the data structure used!!
|
// GUIDELINE: external code MUST NOT BE AWARE of the data structure used!
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ extern "C" {
|
|||||||
#define PACKAGE_VERSION_MAJOR 0
|
#define PACKAGE_VERSION_MAJOR 0
|
||||||
#define PACKAGE_VERSION_MINOR 6
|
#define PACKAGE_VERSION_MINOR 6
|
||||||
#define PACKAGE_VERSION_PATCH 0
|
#define PACKAGE_VERSION_PATCH 0
|
||||||
#define PACKAGE_VERSION_RC 2
|
|
||||||
|
|
||||||
char const *get_package_version_string(void);
|
char const *get_package_version_string(void);
|
||||||
|
|
||||||
|
|||||||
50
man/rgbasm.1
50
man/rgbasm.1
@@ -17,28 +17,28 @@
|
|||||||
.Op Fl b Ar chars
|
.Op Fl b Ar chars
|
||||||
.Op Fl D Ar name Ns Op = Ns Ar value
|
.Op Fl D Ar name Ns Op = Ns Ar value
|
||||||
.Op Fl g Ar chars
|
.Op Fl g Ar chars
|
||||||
.Op Fl i Ar path
|
.Op Fl I Ar path
|
||||||
.Op Fl M Ar depend_file
|
.Op Fl M Ar depend_file
|
||||||
.Op Fl MG
|
.Op Fl MG
|
||||||
.Op Fl MP
|
.Op Fl MP
|
||||||
.Op Fl MT Ar target_file
|
.Op Fl MT Ar target_file
|
||||||
.Op Fl MQ Ar target_file
|
.Op Fl MQ Ar target_file
|
||||||
.Op Fl o Ar out_file
|
.Op Fl o Ar out_file
|
||||||
|
.Op Fl P Ar include_file
|
||||||
.Op Fl p Ar pad_value
|
.Op Fl p Ar pad_value
|
||||||
.Op Fl Q Ar fix_precision
|
.Op Fl Q Ar fix_precision
|
||||||
.Op Fl r Ar recursion_depth
|
.Op Fl r Ar recursion_depth
|
||||||
.Op Fl W Ar warning
|
.Op Fl W Ar warning
|
||||||
.Ar
|
.Ar asmfile
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
program creates an RGB object file from an assembly source file.
|
program creates an RGB object file from an assembly source file.
|
||||||
The input
|
The input
|
||||||
.Ar file
|
.Ar asmfile
|
||||||
can be a file path, or
|
can be a path to a file, or
|
||||||
.Cm \-
|
.Cm \-
|
||||||
denoting
|
to read from standard input.
|
||||||
.Cm stdin .
|
|
||||||
.Pp
|
.Pp
|
||||||
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
||||||
.Fl Fl verb
|
.Fl Fl verb
|
||||||
@@ -86,8 +86,20 @@ Disables inserting a
|
|||||||
instruction immediately after any
|
instruction immediately after any
|
||||||
.Ic halt
|
.Ic halt
|
||||||
instruction.
|
instruction.
|
||||||
.It Fl i Ar path , Fl Fl include Ar path
|
.It Fl I Ar path , Fl Fl include Ar path
|
||||||
Add an include path.
|
Add a new
|
||||||
|
.Dq include path ; Ar path
|
||||||
|
must point to a directory.
|
||||||
|
When a
|
||||||
|
.Ic INCLUDE
|
||||||
|
.Pq including the implicit one from Fl P
|
||||||
|
or
|
||||||
|
.Ic INCBIN
|
||||||
|
is attempted,
|
||||||
|
.Nm
|
||||||
|
first looks up the provided path from its working directory; if this fails, it tries again from each of the
|
||||||
|
.Dq include path
|
||||||
|
directories, in the order they were provided.
|
||||||
.It Fl L , Fl Fl preserve-ld
|
.It Fl L , Fl Fl preserve-ld
|
||||||
By default,
|
By default,
|
||||||
.Nm
|
.Nm
|
||||||
@@ -116,6 +128,7 @@ This makes
|
|||||||
.Nm
|
.Nm
|
||||||
assume that missing files are auto-generated: when
|
assume that missing files are auto-generated: when
|
||||||
.Ic INCLUDE
|
.Ic INCLUDE
|
||||||
|
.Pq including the implicit one from Fl P
|
||||||
or
|
or
|
||||||
.Ic INCBIN
|
.Ic INCBIN
|
||||||
is attempted on a non-existent file, it is added as a dependency, then
|
is attempted on a non-existent file, it is added as a dependency, then
|
||||||
@@ -146,6 +159,12 @@ characters, essentially
|
|||||||
.Sq $ .
|
.Sq $ .
|
||||||
.It Fl o Ar out_file , Fl Fl output Ar out_file
|
.It Fl o Ar out_file , Fl Fl output Ar out_file
|
||||||
Write an object file to the given filename.
|
Write an object file to the given filename.
|
||||||
|
.It Fl P Ar include_file , Fl Fl preinclude Ar include_file
|
||||||
|
Pre-include a file.
|
||||||
|
This acts as if a
|
||||||
|
.Ql Ic INCLUDE Qq Ar include_file
|
||||||
|
was read before the input
|
||||||
|
.Ar asmfile .
|
||||||
.It Fl p Ar pad_value , Fl Fl pad-value Ar pad_value
|
.It Fl p Ar pad_value , Fl Fl pad-value Ar pad_value
|
||||||
When padding an image, pad with this value.
|
When padding an image, pad with this value.
|
||||||
The default is 0x00.
|
The default is 0x00.
|
||||||
@@ -301,12 +320,19 @@ warns when an N-bit value's absolute value is 2**N or greater.
|
|||||||
or just
|
or just
|
||||||
.Fl Wtruncation
|
.Fl Wtruncation
|
||||||
also warns when an N-bit value is less than -2**(N-1), which will not fit in two's complement encoding.
|
also warns when an N-bit value is less than -2**(N-1), which will not fit in two's complement encoding.
|
||||||
.It Fl Wunmapped-char
|
.It Fl Wunmapped-char=
|
||||||
Warn when a character goes through charmap conversion but has no defined mapping.
|
Warn when a character goes through charmap conversion but has no defined mapping.
|
||||||
This warning is always disabled if the active charmap is empty, and/or is the default charmap
|
.Fl Wunmapped-char=0
|
||||||
|
or
|
||||||
|
.Fl Wunmapped-char
|
||||||
|
disables this warning.
|
||||||
|
.Fl Wunmapped-char=1
|
||||||
|
or just
|
||||||
|
.Fl Wunmapped-char
|
||||||
|
only warns if the active charmap is not empty.
|
||||||
|
.Fl Wunmapped-char=2
|
||||||
|
warns if the active charmap is empty, and/or is not the default charmap
|
||||||
.Sq main .
|
.Sq main .
|
||||||
This warning is enabled by
|
|
||||||
.Fl Wall .
|
|
||||||
.It Fl Wno-user
|
.It Fl Wno-user
|
||||||
Warn when the
|
Warn when the
|
||||||
.Ic WARN
|
.Ic WARN
|
||||||
|
|||||||
204
man/rgbasm.5
204
man/rgbasm.5
@@ -18,7 +18,7 @@ This is the full description of the language used by
|
|||||||
The description of the instructions supported by the Game Boy CPU is in
|
The description of the instructions supported by the Game Boy CPU is in
|
||||||
.Xr gbz80 7 .
|
.Xr gbz80 7 .
|
||||||
.Pp
|
.Pp
|
||||||
It is strongly recommended to have some familiarity with the Game Boy hardware before reading this document.
|
It is advisable to have some familiarity with the Game Boy hardware before reading this document.
|
||||||
RGBDS is specifically targeted at the Game Boy, and thus a lot of its features tie directly to its concepts.
|
RGBDS is specifically targeted at the Game Boy, and thus a lot of its features tie directly to its concepts.
|
||||||
This document is not intended to be a Game Boy hardware reference.
|
This document is not intended to be a Game Boy hardware reference.
|
||||||
.Pp
|
.Pp
|
||||||
@@ -57,27 +57,25 @@ and ending with
|
|||||||
.Ql */ .
|
.Ql */ .
|
||||||
It can be split across multiple lines, or occur in the middle of an expression:
|
It can be split across multiple lines, or occur in the middle of an expression:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
X = /* the value of x
|
DEF X = /* the value of x
|
||||||
should be 3 */ 3
|
should be 3 */ 3
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Sometimes lines can be too long and it may be necessary to split them.
|
Sometimes lines can be too long and it may be necessary to split them.
|
||||||
To do so, put a backslash at the end of the line:
|
To do so, put a backslash at the end of the line:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
DB 1, 2, 3,\ \[rs]
|
DB 1, 2, 3,\ \e
|
||||||
4, 5, 6,\ \[rs]\ ;\ Put it before any comments
|
4, 5, 6,\ \e\ ;\ Put it before any comments
|
||||||
7, 8, 9
|
7, 8, 9
|
||||||
DB "Hello,\ \[rs]\ \ ;\ Space before the \[rs] is included
|
DB "Hello,\ \e\ \ ;\ Space before the \e is included
|
||||||
world!"\ \ \ \ \ \ \ \ \ \ \ ;\ Any leading space is included
|
world!"\ \ \ \ \ \ \ \ \ \ \ ;\ Any leading space is included
|
||||||
.Ed
|
.Ed
|
||||||
.Ss Symbol interpolation
|
.Ss Symbol interpolation
|
||||||
A funky feature is
|
A funky feature is writing a symbol between
|
||||||
.Ql {symbol}
|
.Ql {braces} ,
|
||||||
within a string, called
|
called
|
||||||
.Dq symbol interpolation .
|
.Dq symbol interpolation .
|
||||||
This will paste the contents of
|
This will paste the symbol's contents as if they were part of the source file.
|
||||||
.Ql symbol
|
|
||||||
as if they were part of the source file.
|
|
||||||
If it is a string symbol, its characters are simply inserted as-is.
|
If it is a string symbol, its characters are simply inserted as-is.
|
||||||
If it is a numeric symbol, its value is converted to hexadecimal notation with a dollar sign
|
If it is a numeric symbol, its value is converted to hexadecimal notation with a dollar sign
|
||||||
.Sq $
|
.Sq $
|
||||||
@@ -85,7 +83,7 @@ prepended.
|
|||||||
.Pp
|
.Pp
|
||||||
Symbol interpolations can be nested, too!
|
Symbol interpolations can be nested, too!
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
DEF topic EQUS "life, the universe, and \[rs]"everything\[rs]""
|
DEF topic EQUS "life, the universe, and \e"everything\e""
|
||||||
DEF meaning EQUS "answer"
|
DEF meaning EQUS "answer"
|
||||||
;\ Defines answer = 42
|
;\ Defines answer = 42
|
||||||
DEF {meaning} = 42
|
DEF {meaning} = 42
|
||||||
@@ -170,20 +168,20 @@ Valid print types are:
|
|||||||
Examples:
|
Examples:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
SECTION "Test", ROM0[2]
|
SECTION "Test", ROM0[2]
|
||||||
X: ;\ This works with labels **whose address is known**
|
X: ;\ This works with labels **whose address is known**
|
||||||
Y = 3 ;\ This also works with variables
|
DEF Y = 3 ;\ This also works with variables
|
||||||
SUM equ X + Y ;\ And likewise with numeric constants
|
DEF SUM EQU X + Y ;\ And likewise with numeric constants
|
||||||
; Prints "%0010 + $3 == 5"
|
; Prints "%0010 + $3 == 5"
|
||||||
PRINTLN "{#05b:X} + {#x:Y} == {d:SUM}"
|
PRINTLN "{#05b:X} + {#x:Y} == {d:SUM}"
|
||||||
|
|
||||||
rsset 32
|
rsset 32
|
||||||
PERCENT rb 1 ;\ Same with offset constants
|
DEF PERCENT rb 1 ;\ Same with offset constants
|
||||||
VALUE = 20
|
DEF VALUE = 20
|
||||||
RESULT = MUL(20.0, 0.32)
|
DEF RESULT = MUL(20.0, 0.32)
|
||||||
; Prints "32% of 20 = 6.40"
|
; Prints "32% of 20 = 6.40"
|
||||||
PRINTLN "{d:PERCENT}% of {d:VALUE} = {f:RESULT}"
|
PRINTLN "{d:PERCENT}% of {d:VALUE} = {f:RESULT}"
|
||||||
|
|
||||||
WHO equs STRLWR("WORLD")
|
DEF WHO EQUS STRLWR("WORLD")
|
||||||
; Prints "Hello world!"
|
; Prints "Hello world!"
|
||||||
PRINTLN "Hello {s:WHO}!"
|
PRINTLN "Hello {s:WHO}!"
|
||||||
.Ed
|
.Ed
|
||||||
@@ -348,44 +346,53 @@ delim $$
|
|||||||
delim off
|
delim off
|
||||||
.EN
|
.EN
|
||||||
.Pp
|
.Pp
|
||||||
|
All of these fixed-point functions can take an optional final argument, which is the precision to use.
|
||||||
|
For example,
|
||||||
|
.Ql MUL(6.0q8, 7.0q8, 8)
|
||||||
|
will evaluate to
|
||||||
|
.Ql 42.0q8
|
||||||
|
no matter what value is set as the current
|
||||||
|
.Cm Q
|
||||||
|
option.
|
||||||
|
.Pp
|
||||||
The trigonometry functions (
|
The trigonometry functions (
|
||||||
.Ic SIN ,
|
.Ic SIN ,
|
||||||
.Ic COS ,
|
.Ic COS ,
|
||||||
.Ic TAN ,
|
.Ic TAN ,
|
||||||
etc) are defined in terms of a circle divided into 65535.0 degrees.
|
etc) are defined in terms of a circle divided into 1.0 "turns" (equal to 2pi radians or 360 degrees).
|
||||||
.Pp
|
.Pp
|
||||||
These functions are useful for automatic generation of various tables.
|
These functions are useful for automatic generation of various tables.
|
||||||
For example:
|
For example:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
; Generate a 256-byte sine table with values in the range [0, 128]
|
; Generate a table of sine values from sin(0.0) to sin(1.0), with
|
||||||
; (shifted and scaled from the range [-1.0, 1.0])
|
; amplitude scaled from [-1.0, 1.0] to [0.0, 128.0]
|
||||||
ANGLE = 0.0
|
DEF turns = 0.0
|
||||||
REPT 256
|
REPT 256
|
||||||
db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
|
db MUL(64.0, SIN(turns) + 1.0) >> 16
|
||||||
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
|
DEF turns += 1.0 / 256
|
||||||
ENDR
|
ENDR
|
||||||
.Ed
|
.Ed
|
||||||
.Ss String expressions
|
.Ss String expressions
|
||||||
The most basic string expression is any number of characters contained in double quotes
|
The most basic string expression is any number of characters contained in double quotes
|
||||||
.Pq Ql \&"for instance" .
|
.Pq Ql \&"for instance" .
|
||||||
The backslash character
|
The backslash character
|
||||||
.Ql \[rs]
|
.Ql \e
|
||||||
is special in that it causes the character following it to be
|
is special in that it causes the character following it to be
|
||||||
.Dq escaped ,
|
.Dq escaped ,
|
||||||
meaning that it is treated differently from normal.
|
meaning that it is treated differently from normal.
|
||||||
There are a number of escape sequences you can use within a string:
|
There are a number of escape sequences you can use within a string:
|
||||||
.Bl -column -offset indent "Qo \[rs]1 Qc \[en] Qo \[rs]9 Qc"
|
.Bl -column -offset indent "Qo \e1 Qc \[en] Qo \e9 Qc"
|
||||||
.It Sy String Ta Sy Meaning
|
.It Sy String Ta Sy Meaning
|
||||||
.It Ql \[rs]\[rs] Ta Produces a backslash
|
.It Ql \e\e Ta Produces a backslash
|
||||||
.It Ql \[rs]" Ta Produces a double quote without terminating
|
.It Ql \e" Ta Produces a double quote without terminating
|
||||||
.It Ql \[rs]{ Ta Curly bracket left
|
.It Ql \e{ Ta Curly bracket left
|
||||||
.It Ql \[rs]} Ta Curly bracket right
|
.It Ql \e} Ta Curly bracket right
|
||||||
.It Ql \[rs]n Ta Newline ($0A)
|
.It Ql \en Ta Newline ($0A)
|
||||||
.It Ql \[rs]r Ta Carriage return ($0D)
|
.It Ql \er Ta Carriage return ($0D)
|
||||||
.It Ql \[rs]t Ta Tab ($09)
|
.It Ql \et Ta Tab ($09)
|
||||||
.It Qo \[rs]1 Qc \[en] Qo \[rs]9 Qc Ta Macro argument (Only in the body of a macro; see Sx Invoking macros )
|
.It Qo \e1 Qc \[en] Qo \e9 Qc Ta Macro argument (Only in the body of a macro; see Sx Invoking macros )
|
||||||
.It Ql \[rs]# Ta All Dv _NARG No macro arguments, separated by commas (Only in the body of a macro)
|
.It Ql \e# Ta All Dv _NARG No macro arguments, separated by commas (Only in the body of a macro)
|
||||||
.It Ql \[rs]@ Ta Label name suffix (Only in the body of a macro or a Ic REPT No block)
|
.It Ql \e@ Ta Label name suffix (Only in the body of a macro or a Ic REPT No block)
|
||||||
.El
|
.El
|
||||||
(Note that some of those can be used outside of strings, when noted further in this document.)
|
(Note that some of those can be used outside of strings, when noted further in this document.)
|
||||||
.Pp
|
.Pp
|
||||||
@@ -393,9 +400,9 @@ Multi-line strings are contained in triple quotes
|
|||||||
.Pq Ql \&"\&"\&"for instance\&"\&"\&" .
|
.Pq Ql \&"\&"\&"for instance\&"\&"\&" .
|
||||||
Escape sequences work the same way in multi-line strings; however, literal newline
|
Escape sequences work the same way in multi-line strings; however, literal newline
|
||||||
characters will be included as-is, without needing to escape them with
|
characters will be included as-is, without needing to escape them with
|
||||||
.Ql \[rs]r
|
.Ql \er
|
||||||
or
|
or
|
||||||
.Ql \[rs]n .
|
.Ql \en .
|
||||||
.Pp
|
.Pp
|
||||||
The following functions operate on string expressions.
|
The following functions operate on string expressions.
|
||||||
Most of them return a string, however some of these functions actually return an integer and can be used as part of an integer expression!
|
Most of them return a string, however some of these functions actually return an integer and can be used as part of an integer expression!
|
||||||
@@ -474,6 +481,11 @@ is a label, it returns the bank number the label is in.
|
|||||||
The result may be constant if
|
The result may be constant if
|
||||||
.Nm
|
.Nm
|
||||||
is able to compute it.
|
is able to compute it.
|
||||||
|
.It Fn SECTION symbol Ta Returns the name of the section that
|
||||||
|
.Ar symbol
|
||||||
|
is in.
|
||||||
|
.Ar symbol
|
||||||
|
must have been defined already.
|
||||||
.It Fn SIZEOF arg Ta Returns the size of the section named
|
.It Fn SIZEOF arg Ta Returns the size of the section named
|
||||||
.Ar arg .
|
.Ar arg .
|
||||||
The result is not constant, since only RGBLINK can compute its value.
|
The result is not constant, since only RGBLINK can compute its value.
|
||||||
@@ -1013,7 +1025,7 @@ DEF ARRAY_SIZE EQU 4
|
|||||||
DEF COUNT = 2
|
DEF COUNT = 2
|
||||||
DEF COUNT = 3
|
DEF COUNT = 3
|
||||||
DEF COUNT = ARRAY_SIZE + COUNT
|
DEF COUNT = ARRAY_SIZE + COUNT
|
||||||
COUNT = COUNT*2
|
DEF COUNT *= 2
|
||||||
;\ COUNT now has the value 14
|
;\ COUNT now has the value 14
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1066,7 +1078,7 @@ This can be used, for example, to update a constant using a macro, without makin
|
|||||||
def NUM_ITEMS equ 0
|
def NUM_ITEMS equ 0
|
||||||
MACRO add_item
|
MACRO add_item
|
||||||
redef NUM_ITEMS equ NUM_ITEMS + 1
|
redef NUM_ITEMS equ NUM_ITEMS + 1
|
||||||
def ITEM_{02x:NUM_ITEMS} equ \[rs]1
|
def ITEM_{02x:NUM_ITEMS} equ \e1
|
||||||
ENDM
|
ENDM
|
||||||
add_item 1
|
add_item 1
|
||||||
add_item 4
|
add_item 4
|
||||||
@@ -1131,7 +1143,7 @@ will not expand string constants in their names.
|
|||||||
DEF COUNTREG EQUS "[hl+]"
|
DEF COUNTREG EQUS "[hl+]"
|
||||||
ld a,COUNTREG
|
ld a,COUNTREG
|
||||||
|
|
||||||
DEF PLAYER_NAME EQUS "\[rs]"John\[rs]""
|
DEF PLAYER_NAME EQUS "\e"John\e""
|
||||||
db PLAYER_NAME
|
db PLAYER_NAME
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1143,7 +1155,7 @@ This will be interpreted as:
|
|||||||
.Pp
|
.Pp
|
||||||
String constants can also be used to define small one-line macros:
|
String constants can also be used to define small one-line macros:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
DEF pusha EQUS "push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n"
|
DEF pusha EQUS "push af\enpush bc\enpush de\enpush hl\en"
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Note that colons
|
Note that colons
|
||||||
@@ -1252,18 +1264,18 @@ ENDM
|
|||||||
But this will:
|
But this will:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
MACRO outer
|
MACRO outer
|
||||||
DEF definition EQUS "MACRO inner\[rs]nPRINTLN \[rs]"Hello!\[rs]"\[rs]nENDM"
|
DEF definition EQUS "MACRO inner\enPRINTLN \e"Hello!\e"\enENDM"
|
||||||
definition
|
definition
|
||||||
PURGE definition
|
PURGE definition
|
||||||
ENDM
|
ENDM
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Macro arguments support all the escape sequences of strings, as well as
|
Macro arguments support all the escape sequences of strings, as well as
|
||||||
.Ql \[rs],
|
.Ql \e,
|
||||||
to escape commas, as well as
|
to escape commas, as well as
|
||||||
.Ql \[rs](
|
.Ql \e(
|
||||||
and
|
and
|
||||||
.Ql \[rs])
|
.Ql \e)
|
||||||
to escape parentheses, since those otherwise separate and enclose arguments, respectively.
|
to escape parentheses, since those otherwise separate and enclose arguments, respectively.
|
||||||
.Ss Exporting and importing symbols
|
.Ss Exporting and importing symbols
|
||||||
Importing and exporting of symbols is a feature that is very useful when your project spans many source files and, for example, you need to jump to a routine defined in another file.
|
Importing and exporting of symbols is a feature that is very useful when your project spans many source files and, for example, you need to jump to a routine defined in another file.
|
||||||
@@ -1324,7 +1336,7 @@ Note also that only exported symbols will appear in symbol and map files produce
|
|||||||
.Ss Purging symbols
|
.Ss Purging symbols
|
||||||
.Ic PURGE
|
.Ic PURGE
|
||||||
allows you to completely remove a symbol from the symbol table as if it had never existed.
|
allows you to completely remove a symbol from the symbol table as if it had never existed.
|
||||||
.Em USE WITH EXTREME CAUTION!!!
|
.Em USE WITH EXTREME CAUTION!
|
||||||
I can't stress this enough,
|
I can't stress this enough,
|
||||||
.Sy you seriously need to know what you are doing .
|
.Sy you seriously need to know what you are doing .
|
||||||
DON'T purge a symbol that you use in expressions the linker needs to calculate.
|
DON'T purge a symbol that you use in expressions the linker needs to calculate.
|
||||||
@@ -1343,8 +1355,6 @@ The following symbols are defined by the assembler:
|
|||||||
.It Dv @ Ta Ic EQU Ta PC value (essentially, the current memory address)
|
.It Dv @ Ta Ic EQU Ta PC value (essentially, the current memory address)
|
||||||
.It Dv _RS Ta Ic = Ta _RS Counter
|
.It Dv _RS Ta Ic = Ta _RS Counter
|
||||||
.It Dv _NARG Ta Ic EQU Ta Number of arguments passed to macro, updated by Ic SHIFT
|
.It Dv _NARG Ta Ic EQU Ta Number of arguments passed to macro, updated by Ic SHIFT
|
||||||
.It Dv __LINE__ Ta Ic EQU Ta The current line number
|
|
||||||
.It Dv __FILE__ Ta Ic EQUS Ta The current filename
|
|
||||||
.It Dv __DATE__ Ta Ic EQUS Ta Today's date
|
.It Dv __DATE__ Ta Ic EQUS Ta Today's date
|
||||||
.It Dv __TIME__ Ta Ic EQUS Ta The current time
|
.It Dv __TIME__ Ta Ic EQUS Ta The current time
|
||||||
.It Dv __ISO_8601_LOCAL__ Ta Ic EQUS Ta ISO 8601 timestamp (local)
|
.It Dv __ISO_8601_LOCAL__ Ta Ic EQUS Ta ISO 8601 timestamp (local)
|
||||||
@@ -1561,19 +1571,19 @@ ENDM
|
|||||||
.Pp
|
.Pp
|
||||||
This is fine, but only if you use the macro no more than once per scope.
|
This is fine, but only if you use the macro no more than once per scope.
|
||||||
To get around this problem, there is the escape sequence
|
To get around this problem, there is the escape sequence
|
||||||
.Ic \[rs]@
|
.Ic \e@
|
||||||
that expands to a unique string.
|
that expands to a unique string.
|
||||||
.Pp
|
.Pp
|
||||||
.Ic \[rs]@
|
.Ic \e@
|
||||||
also works in
|
also works in
|
||||||
.Ic REPT
|
.Ic REPT
|
||||||
blocks.
|
blocks.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
MACRO LoopyMacro
|
MACRO LoopyMacro
|
||||||
xor a,a
|
xor a,a
|
||||||
\&.loop\[rs]@ ld [hl+],a
|
\&.loop\e@ ld [hl+],a
|
||||||
dec c
|
dec c
|
||||||
jr nz,.loop\[rs]@
|
jr nz,.loop\e@
|
||||||
ENDM
|
ENDM
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1593,18 +1603,18 @@ which references the same macro, which has the same problem.
|
|||||||
.Pp
|
.Pp
|
||||||
It's possible to pass arguments to macros as well!
|
It's possible to pass arguments to macros as well!
|
||||||
You retrieve the arguments by using the escape sequences
|
You retrieve the arguments by using the escape sequences
|
||||||
.Ic \[rs]1
|
.Ic \e1
|
||||||
through
|
through
|
||||||
.Ic \[rs]9 , \[rs]1
|
.Ic \e9 , \e1
|
||||||
being the first argument specified on the macro invocation.
|
being the first argument specified on the macro invocation.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
MACRO LoopyMacro
|
MACRO LoopyMacro
|
||||||
ld hl,\[rs]1
|
ld hl,\e1
|
||||||
ld c,\[rs]2
|
ld c,\e2
|
||||||
xor a,a
|
xor a,a
|
||||||
\&.loop\[rs]@ ld [hl+],a
|
\&.loop\e@ ld [hl+],a
|
||||||
dec c
|
dec c
|
||||||
jr nz,.loop\[rs]@
|
jr nz,.loop\e@
|
||||||
ENDM
|
ENDM
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1617,14 +1627,14 @@ LoopyMacro MyVars,54
|
|||||||
Arguments are passed as string constants, although there's no need to enclose them in quotes.
|
Arguments are passed as string constants, although there's no need to enclose them in quotes.
|
||||||
Thus, an expression will not be evaluated first but kind of copy-pasted.
|
Thus, an expression will not be evaluated first but kind of copy-pasted.
|
||||||
This means that it's probably a very good idea to use brackets around
|
This means that it's probably a very good idea to use brackets around
|
||||||
.Ic \[rs]1
|
.Ic \e1
|
||||||
to
|
to
|
||||||
.Ic \[rs]9
|
.Ic \e9
|
||||||
if you perform further calculations on them.
|
if you perform further calculations on them.
|
||||||
For instance, consider the following:
|
For instance, consider the following:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
MACRO print_double
|
MACRO print_double
|
||||||
PRINTLN \[rs]1 * 2
|
PRINTLN \e1 * 2
|
||||||
ENDM
|
ENDM
|
||||||
print_double 1 + 2
|
print_double 1 + 2
|
||||||
.Ed
|
.Ed
|
||||||
@@ -1639,15 +1649,15 @@ Line continuations work as usual inside macros or lists of macro arguments.
|
|||||||
However, some characters need to be escaped, as in the following example:
|
However, some characters need to be escaped, as in the following example:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
MACRO PrintMacro1
|
MACRO PrintMacro1
|
||||||
PRINTLN STRCAT(\[rs]1)
|
PRINTLN STRCAT(\e1)
|
||||||
ENDM
|
ENDM
|
||||||
PrintMacro1 "Hello "\[rs], \[rs]
|
PrintMacro1 "Hello "\e, \e
|
||||||
"world"
|
"world"
|
||||||
MACRO PrintMacro2
|
MACRO PrintMacro2
|
||||||
PRINT \[rs]1
|
PRINT \e1
|
||||||
ENDM
|
ENDM
|
||||||
PrintMacro2 STRCAT("Hello ", \[rs]
|
PrintMacro2 STRCAT("Hello ", \e
|
||||||
"world\[rs]n")
|
"world\en")
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
The comma in
|
The comma in
|
||||||
@@ -1657,34 +1667,34 @@ The comma in
|
|||||||
.Ql PrintMacro2
|
.Ql PrintMacro2
|
||||||
does not need escaping because it is inside parentheses, similar to macro arguments in C.
|
does not need escaping because it is inside parentheses, similar to macro arguments in C.
|
||||||
The backslash in
|
The backslash in
|
||||||
.Ql \[rs]n
|
.Ql \en
|
||||||
also does not need escaping because string literals work as usual inside macro arguments.
|
also does not need escaping because string literals work as usual inside macro arguments.
|
||||||
.Pp
|
.Pp
|
||||||
Since there are only nine digits, you can only access the first nine macro arguments like this.
|
Since there are only nine digits, you can only access the first nine macro arguments like this.
|
||||||
To use the rest, you need to put the multi-digit argument number in angle brackets, like
|
To use the rest, you need to put the multi-digit argument number in angle brackets, like
|
||||||
.Ql \[rs]<10> .
|
.Ql \e<10> .
|
||||||
This bracketed syntax supports decimal numbers and numeric constant symbols.
|
This bracketed syntax supports decimal numbers and numeric constant symbols.
|
||||||
For example,
|
For example,
|
||||||
.Ql \[rs]<_NARG>
|
.Ql \e<_NARG>
|
||||||
will get the last argument.
|
will get the last argument.
|
||||||
.Pp
|
.Pp
|
||||||
Other macro arguments and symbol interpolations will be expanded inside the angle brackets.
|
Other macro arguments and symbol interpolations will be expanded inside the angle brackets.
|
||||||
For example, if
|
For example, if
|
||||||
.Ql \[rs]1
|
.Ql \e1
|
||||||
is
|
is
|
||||||
.Ql 13 ,
|
.Ql 13 ,
|
||||||
then
|
then
|
||||||
.Ql \[rs]<\[rs]1>
|
.Ql \e<\e1>
|
||||||
will expand to
|
will expand to
|
||||||
.Ql \[rs]<13> .
|
.Ql \e<13> .
|
||||||
Or if
|
Or if
|
||||||
.Ql v10 = 42
|
.Ql v10 = 42
|
||||||
and
|
and
|
||||||
.Ql x = 10 ,
|
.Ql x = 10 ,
|
||||||
then
|
then
|
||||||
.Ql \[rs]<v{d:x}>
|
.Ql \e<v{d:x}>
|
||||||
will expand to
|
will expand to
|
||||||
.Ql \[rs]<42> .
|
.Ql \e<42> .
|
||||||
.Pp
|
.Pp
|
||||||
Another way to access more than nine macro arguments is the
|
Another way to access more than nine macro arguments is the
|
||||||
.Ic SHIFT
|
.Ic SHIFT
|
||||||
@@ -1692,11 +1702,11 @@ command, a special command only available in macros.
|
|||||||
It will shift the arguments by one to the left, and decrease
|
It will shift the arguments by one to the left, and decrease
|
||||||
.Dv _NARG
|
.Dv _NARG
|
||||||
by 1.
|
by 1.
|
||||||
.Ic \[rs]1
|
.Ic \e1
|
||||||
will get the value of
|
will get the value of
|
||||||
.Ic \[rs]2 , \[rs]2
|
.Ic \e2 , \e2
|
||||||
will get the value of
|
will get the value of
|
||||||
.Ic \[rs]3 ,
|
.Ic \e3 ,
|
||||||
and so forth.
|
and so forth.
|
||||||
.Pp
|
.Pp
|
||||||
.Ic SHIFT
|
.Ic SHIFT
|
||||||
@@ -1715,9 +1725,9 @@ and
|
|||||||
commands print text and values to the standard output.
|
commands print text and values to the standard output.
|
||||||
Useful for debugging macros, or wherever you may feel the need to tell yourself some important information.
|
Useful for debugging macros, or wherever you may feel the need to tell yourself some important information.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
PRINT "Hello world!\[rs]n"
|
PRINT "Hello world!\en"
|
||||||
PRINTLN "Hello world!"
|
PRINTLN "Hello world!"
|
||||||
PRINT _NARG, " arguments\[rs]n"
|
PRINT _NARG, " arguments\en"
|
||||||
PRINTLN "sum: ", 2+3, " product: ", 2*3
|
PRINTLN "sum: ", 2+3, " product: ", 2*3
|
||||||
PRINTLN "Line #", __LINE__
|
PRINTLN "Line #", __LINE__
|
||||||
PRINTLN STRFMT("E = %f", 2.718)
|
PRINTLN STRFMT("E = %f", 2.718)
|
||||||
@@ -1731,7 +1741,7 @@ For different formats, use
|
|||||||
.Ic STRFMT .
|
.Ic STRFMT .
|
||||||
.It Ic PRINTLN
|
.It Ic PRINTLN
|
||||||
prints out each of its comma-separated arguments, if any, followed by a line feed
|
prints out each of its comma-separated arguments, if any, followed by a line feed
|
||||||
.Pq Ql \[rs]n .
|
.Pq Ql \en .
|
||||||
.El
|
.El
|
||||||
.Ss Automatically repeating blocks of code
|
.Ss Automatically repeating blocks of code
|
||||||
Suppose you want to unroll a time consuming loop without copy-pasting it.
|
Suppose you want to unroll a time consuming loop without copy-pasting it.
|
||||||
@@ -1755,17 +1765,16 @@ You can also use
|
|||||||
.Ic REPT
|
.Ic REPT
|
||||||
to generate tables on the fly:
|
to generate tables on the fly:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
; Generate a 256-byte sine table with values in the range [0, 128]
|
; Generate a table of square values from 0**2 = 0 to 100**2 = 10000
|
||||||
; (shifted and scaled from the range [-1.0, 1.0])
|
DEF x = 0
|
||||||
ANGLE = 0.0
|
REPT 101
|
||||||
REPT 256
|
dw x * x
|
||||||
db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
|
DEF x += 1
|
||||||
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
|
ENDR
|
||||||
ENDR
|
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
As in macros, you can also use the escape sequence
|
As in macros, you can also use the escape sequence
|
||||||
.Ic \[rs]@ .
|
.Ic \e@ .
|
||||||
.Ic REPT
|
.Ic REPT
|
||||||
blocks can be nested.
|
blocks can be nested.
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1853,7 +1862,7 @@ This will print:
|
|||||||
Just like with
|
Just like with
|
||||||
.Ic REPT
|
.Ic REPT
|
||||||
blocks, you can use the escape sequence
|
blocks, you can use the escape sequence
|
||||||
.Ic \[rs]@
|
.Ic \e@
|
||||||
inside of
|
inside of
|
||||||
.Ic FOR
|
.Ic FOR
|
||||||
blocks, and they can be nested.
|
blocks, and they can be nested.
|
||||||
@@ -1974,6 +1983,13 @@ calls infinitely (or until you run out of memory, whichever comes first).
|
|||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
INCLUDE "irq.inc"
|
INCLUDE "irq.inc"
|
||||||
.Ed
|
.Ed
|
||||||
|
.Pp
|
||||||
|
You may also implicitly
|
||||||
|
.Ic INCLUDE
|
||||||
|
a file before the source file with the
|
||||||
|
.Fl P
|
||||||
|
option of
|
||||||
|
.Xr rgbasm 1 .
|
||||||
.Ss Conditional assembling
|
.Ss Conditional assembling
|
||||||
The four commands
|
The four commands
|
||||||
.Ic IF , ELIF , ELSE ,
|
.Ic IF , ELIF , ELSE ,
|
||||||
|
|||||||
51
man/rgbgfx.1
51
man/rgbgfx.1
@@ -14,7 +14,6 @@
|
|||||||
.Nd Game Boy graphics converter
|
.Nd Game Boy graphics converter
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl r Ar stride
|
|
||||||
.Op Fl CmuVZ
|
.Op Fl CmuVZ
|
||||||
.Op Fl v Op Fl v No ...
|
.Op Fl v Op Fl v No ...
|
||||||
.Op Fl a Ar attrmap | Fl A
|
.Op Fl a Ar attrmap | Fl A
|
||||||
@@ -27,6 +26,7 @@
|
|||||||
.Op Fl o Ar out_file
|
.Op Fl o Ar out_file
|
||||||
.Op Fl p Ar pal_file | Fl P
|
.Op Fl p Ar pal_file | Fl P
|
||||||
.Op Fl q Ar pal_map | Fl Q
|
.Op Fl q Ar pal_map | Fl Q
|
||||||
|
.Op Fl r Ar stride
|
||||||
.Op Fl s Ar nb_colors
|
.Op Fl s Ar nb_colors
|
||||||
.Op Fl t Ar tilemap | Fl T
|
.Op Fl t Ar tilemap | Fl T
|
||||||
.Op Fl x Ar quantity
|
.Op Fl x Ar quantity
|
||||||
@@ -321,7 +321,22 @@ any command-line argument that begins with an at sign
|
|||||||
.Pq Ql @
|
.Pq Ql @
|
||||||
is interpreted as one.
|
is interpreted as one.
|
||||||
The rest of the argument (without the @, that is) is interpreted as the path to a file, whose contents are interpreted as if given on the command line.
|
The rest of the argument (without the @, that is) is interpreted as the path to a file, whose contents are interpreted as if given on the command line.
|
||||||
At-files can be stored right next to the corresponding image, for example.
|
At-files can be stored right next to the corresponding image, for example:
|
||||||
|
.Pp
|
||||||
|
.Dl $ rgbgfx -o image.2bpp -t image.tilemap @image.flags image.png
|
||||||
|
.Pp
|
||||||
|
This will read additional flags from file
|
||||||
|
.Ql image.flags ,
|
||||||
|
which could contains for example
|
||||||
|
.Ql -b 128
|
||||||
|
to specify a base offset for the image's tiles.
|
||||||
|
The above command could be generated from the following
|
||||||
|
.Xr make 1
|
||||||
|
rule, for example:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
%.2bpp %.tilemap: %.flags %.png
|
||||||
|
rgbgfx -o $*.2bpp -t $*.tilemap @$*.flags $*.png
|
||||||
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Since the contents of at-files are interpreted by
|
Since the contents of at-files are interpreted by
|
||||||
.Nm ,
|
.Nm ,
|
||||||
@@ -336,17 +351,19 @@ optionally preceded by whitespace, are considered comments and also ignored.
|
|||||||
Each line can contain any number of arguments, which are separated by whitespace.
|
Each line can contain any number of arguments, which are separated by whitespace.
|
||||||
.Pq \&No quoting feature to prevent this is provided.
|
.Pq \&No quoting feature to prevent this is provided.
|
||||||
.Pp
|
.Pp
|
||||||
Note that this special meaning given to arguments has less precedence than option arguments, and that the standard
|
Note that a leading
|
||||||
|
.Ql @
|
||||||
|
has no special meaning on option arguments, and that the standard
|
||||||
.Ql --
|
.Ql --
|
||||||
to stop option processing also disables at-file processing.
|
to stop option processing also disables at-file processing.
|
||||||
For example, the following command line processes
|
For example, the following command line reads command-line options from
|
||||||
.Ql @tilesets/town.png ,
|
|
||||||
outputs tile data to
|
|
||||||
.Ql @tilesets/town.2bpp ,
|
|
||||||
and reads command-line options from
|
|
||||||
.Ql tilesets/town.flags
|
.Ql tilesets/town.flags
|
||||||
then
|
then
|
||||||
.Ql tilesets.flags :
|
.Ql tilesets.flags ,
|
||||||
|
but processes
|
||||||
|
.Ql @tilesets/town.png
|
||||||
|
as the input image and outputs tile data to
|
||||||
|
.Ql @tilesets/town.2bpp :
|
||||||
.Pp
|
.Pp
|
||||||
.Dl $ rgbgfx -o @tilesets/town.2bpp @tilesets/town.flags @tilesets.flags -- @tilesets/town.png
|
.Dl $ rgbgfx -o @tilesets/town.2bpp @tilesets/town.flags @tilesets.flags -- @tilesets/town.png
|
||||||
.Pp
|
.Pp
|
||||||
@@ -357,11 +374,21 @@ can be used in an at-file (with identical semantics), it is only effective insid
|
|||||||
.Sh PALETTE SPECIFICATION FORMATS
|
.Sh PALETTE SPECIFICATION FORMATS
|
||||||
The following formats are supported:
|
The following formats are supported:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Sy act
|
.It Cm act
|
||||||
.Lk https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1070626 Adobe Photoshop color table .
|
.Lk https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1070626 Adobe Photoshop color table .
|
||||||
.It Sy aco
|
.It Cm aco
|
||||||
.Lk https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1055819 Adobe Photoshop color swatch .
|
.Lk https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1055819 Adobe Photoshop color swatch .
|
||||||
.It Sy psp
|
.It Cm gbc
|
||||||
|
A GBC palette memory dump, as emitted by
|
||||||
|
.Nm Fl p .
|
||||||
|
Useful to force several images to share the same palette.
|
||||||
|
.It Cm gpl
|
||||||
|
.Lk https://docs.gimp.org/2.10/en/gimp-concepts-palettes.html GIMP palette .
|
||||||
|
.It Cm hex
|
||||||
|
Plaintext lines of hexadecimal colors in
|
||||||
|
.Ql rrggbb
|
||||||
|
format.
|
||||||
|
.It Cm psp
|
||||||
.Lk https://www.selapa.net/swatches/colors/fileformats.php#psp_pal Paint Shop Pro palette .
|
.Lk https://www.selapa.net/swatches/colors/fileformats.php#psp_pal Paint Shop Pro palette .
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
|
|||||||
@@ -54,12 +54,12 @@ it is needed to specify a bank number after the type.
|
|||||||
Section names in double quotes support the same character escape sequences as strings in
|
Section names in double quotes support the same character escape sequences as strings in
|
||||||
.Xr rgbasm 5 ,
|
.Xr rgbasm 5 ,
|
||||||
specifically
|
specifically
|
||||||
.Ql \[rs]\[rs] ,
|
.Ql \e\e ,
|
||||||
.Ql \[rs]" ,
|
.Ql \e" ,
|
||||||
.Ql \[rs]n ,
|
.Ql \en ,
|
||||||
.Ql \[rs]r ,
|
.Ql \er ,
|
||||||
and
|
and
|
||||||
.Ql \[rs]t .
|
.Ql \et .
|
||||||
Other backslash escape sequences in
|
Other backslash escape sequences in
|
||||||
.Xr rgbasm 5
|
.Xr rgbasm 5
|
||||||
are only relevant to assembly code and do not apply in section names.
|
are only relevant to assembly code and do not apply in section names.
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ set(rgblink_src
|
|||||||
"link/sdas_obj.c"
|
"link/sdas_obj.c"
|
||||||
"link/section.c"
|
"link/section.c"
|
||||||
"link/symbol.c"
|
"link/symbol.c"
|
||||||
|
"extern/utf8decoder.c"
|
||||||
"hashmap.c"
|
"hashmap.c"
|
||||||
"linkdefs.c"
|
"linkdefs.c"
|
||||||
"opmath.c"
|
"opmath.c"
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
struct Charnode {
|
struct Charnode {
|
||||||
bool isTerminal; // Whether there exists a mapping that ends here
|
bool isTerminal; // Whether there exists a mapping that ends here
|
||||||
uint8_t value; // If the above is true, its corresponding value
|
uint8_t value; // If the above is true, its corresponding value
|
||||||
// This MUST be indexes and not pointers, because pointers get invalidated by `realloc`!!
|
// This MUST be indexes and not pointers, because pointers get invalidated by `realloc`!
|
||||||
size_t next[255]; // Indexes of where to go next, 0 = nowhere
|
size_t next[255]; // Indexes of where to go next, 0 = nowhere
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -249,11 +249,14 @@ size_t charmap_ConvertNext(char const **input, uint8_t **output)
|
|||||||
if (output)
|
if (output)
|
||||||
*output += codepointLen;
|
*output += codepointLen;
|
||||||
|
|
||||||
// Check if the character map is not the default "main" one, or if
|
// Warn if this character is not mapped but any others are
|
||||||
// it has any mappings defined
|
if (charmap->usedNodes > 1)
|
||||||
if (strcmp(charmap->name, "main") || charmap->usedNodes > 1)
|
warning(WARNING_UNMAPPED_CHAR_1,
|
||||||
warning(WARNING_UNMAPPED_CHAR,
|
|
||||||
"Unmapped character %s\n", printChar(firstChar));
|
"Unmapped character %s\n", printChar(firstChar));
|
||||||
|
else if (strcmp(charmap->name, DEFAULT_CHARMAP_NAME))
|
||||||
|
warning(WARNING_UNMAPPED_CHAR_2,
|
||||||
|
"Unmapped character %s not in " DEFAULT_CHARMAP_NAME
|
||||||
|
" charmap\n", printChar(firstChar));
|
||||||
|
|
||||||
return codepointLen;
|
return codepointLen;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "asm/fixpoint.h"
|
#include "asm/fixpoint.h"
|
||||||
#include "asm/symbol.h"
|
#include "asm/symbol.h"
|
||||||
@@ -21,105 +20,96 @@
|
|||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define fix2double(i) ((double)((i) / fix_PrecisionFactor()))
|
#define fix2double(i, q) ((double)((i) / pow(2.0, q)))
|
||||||
#define double2fix(d) ((int32_t)round((d) * fix_PrecisionFactor()))
|
#define double2fix(d, q) ((int32_t)round((d) * pow(2.0, q)))
|
||||||
|
|
||||||
// pi*2 radians == 2**fixPrecision fixed-point "degrees"
|
// 2*pi radians == 1 turn
|
||||||
#define fdeg2rad(f) ((f) * (M_PI * 2) / fix_PrecisionFactor())
|
#define turn2rad(f) ((f) * (M_PI * 2))
|
||||||
#define rad2fdeg(r) ((r) * fix_PrecisionFactor() / (M_PI * 2))
|
#define rad2turn(r) ((r) / (M_PI * 2))
|
||||||
|
|
||||||
uint8_t fixPrecision;
|
uint8_t fixPrecision;
|
||||||
|
|
||||||
|
uint8_t fix_Precision(void)
|
||||||
|
{
|
||||||
|
return fixPrecision;
|
||||||
|
}
|
||||||
|
|
||||||
double fix_PrecisionFactor(void)
|
double fix_PrecisionFactor(void)
|
||||||
{
|
{
|
||||||
return pow(2.0, fixPrecision);
|
return pow(2.0, fixPrecision);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fix_Print(int32_t i)
|
int32_t fix_Sin(int32_t i, int32_t q)
|
||||||
{
|
{
|
||||||
uint32_t u = i;
|
return double2fix(sin(turn2rad(fix2double(i, q))), q);
|
||||||
char const *sign = "";
|
|
||||||
|
|
||||||
if (i < 0) {
|
|
||||||
u = -u;
|
|
||||||
sign = "-";
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%s%" PRIu32 ".%05" PRIu32, sign, u >> fixPrecision,
|
|
||||||
((uint32_t)(fix2double(u) * 100000 + 0.5)) % 100000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Sin(int32_t i)
|
int32_t fix_Cos(int32_t i, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(sin(fdeg2rad(fix2double(i))));
|
return double2fix(cos(turn2rad(fix2double(i, q))), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Cos(int32_t i)
|
int32_t fix_Tan(int32_t i, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(cos(fdeg2rad(fix2double(i))));
|
return double2fix(tan(turn2rad(fix2double(i, q))), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Tan(int32_t i)
|
int32_t fix_ASin(int32_t i, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(tan(fdeg2rad(fix2double(i))));
|
return double2fix(rad2turn(asin(fix2double(i, q))), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_ASin(int32_t i)
|
int32_t fix_ACos(int32_t i, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(rad2fdeg(asin(fix2double(i))));
|
return double2fix(rad2turn(acos(fix2double(i, q))), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_ACos(int32_t i)
|
int32_t fix_ATan(int32_t i, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(rad2fdeg(acos(fix2double(i))));
|
return double2fix(rad2turn(atan(fix2double(i, q))), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_ATan(int32_t i)
|
int32_t fix_ATan2(int32_t i, int32_t j, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(rad2fdeg(atan(fix2double(i))));
|
return double2fix(rad2turn(atan2(fix2double(i, q), fix2double(j, q))), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_ATan2(int32_t i, int32_t j)
|
int32_t fix_Mul(int32_t i, int32_t j, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(rad2fdeg(atan2(fix2double(i), fix2double(j))));
|
return double2fix(fix2double(i, q) * fix2double(j, q), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Mul(int32_t i, int32_t j)
|
int32_t fix_Div(int32_t i, int32_t j, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(fix2double(i) * fix2double(j));
|
return double2fix(fix2double(i, q) / fix2double(j, q), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Div(int32_t i, int32_t j)
|
int32_t fix_Mod(int32_t i, int32_t j, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(fix2double(i) / fix2double(j));
|
return double2fix(fmod(fix2double(i, q), fix2double(j, q)), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Mod(int32_t i, int32_t j)
|
int32_t fix_Pow(int32_t i, int32_t j, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(fmod(fix2double(i), fix2double(j)));
|
return double2fix(pow(fix2double(i, q), fix2double(j, q)), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Pow(int32_t i, int32_t j)
|
int32_t fix_Log(int32_t i, int32_t j, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(pow(fix2double(i), fix2double(j)));
|
return double2fix(log(fix2double(i, q)) / log(fix2double(j, q)), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Log(int32_t i, int32_t j)
|
int32_t fix_Round(int32_t i, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(log(fix2double(i)) / log(fix2double(j)));
|
return double2fix(round(fix2double(i, q)), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Round(int32_t i)
|
int32_t fix_Ceil(int32_t i, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(round(fix2double(i)));
|
return double2fix(ceil(fix2double(i, q)), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Ceil(int32_t i)
|
int32_t fix_Floor(int32_t i, int32_t q)
|
||||||
{
|
{
|
||||||
return double2fix(ceil(fix2double(i)));
|
return double2fix(floor(fix2double(i, q)), q);
|
||||||
}
|
|
||||||
|
|
||||||
int32_t fix_Floor(int32_t i)
|
|
||||||
{
|
|
||||||
return double2fix(floor(fix2double(i)));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t len = strlen(valueBuf);
|
size_t len = strlen(valueBuf);
|
||||||
size_t numLen = !!sign + !!prefix + len;
|
size_t numLen = (sign != 0) + (prefix != 0) + len;
|
||||||
size_t totalLen = fmt->width > numLen ? fmt->width : numLen;
|
size_t totalLen = fmt->width > numLen ? fmt->width : numLen;
|
||||||
|
|
||||||
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "asm/main.h"
|
#include "asm/main.h"
|
||||||
#include "asm/symbol.h"
|
#include "asm/symbol.h"
|
||||||
#include "asm/warning.h"
|
#include "asm/warning.h"
|
||||||
|
#include "error.h"
|
||||||
#include "platform.h" // S_ISDIR (stat macro)
|
#include "platform.h" // S_ISDIR (stat macro)
|
||||||
|
|
||||||
#define MAXINCPATHS 128
|
#define MAXINCPATHS 128
|
||||||
@@ -42,6 +43,8 @@ size_t maxRecursionDepth;
|
|||||||
static unsigned int nbIncPaths = 0;
|
static unsigned int nbIncPaths = 0;
|
||||||
static char const *includePaths[MAXINCPATHS];
|
static char const *includePaths[MAXINCPATHS];
|
||||||
|
|
||||||
|
static const char *preIncludeName;
|
||||||
|
|
||||||
static const char *dumpNodeAndParents(struct FileStackNode const *node)
|
static const char *dumpNodeAndParents(struct FileStackNode const *node)
|
||||||
{
|
{
|
||||||
char const *name;
|
char const *name;
|
||||||
@@ -133,6 +136,15 @@ void fstk_AddIncludePath(char const *path)
|
|||||||
includePaths[nbIncPaths++] = str;
|
includePaths[nbIncPaths++] = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fstk_SetPreIncludeFile(char const *path)
|
||||||
|
{
|
||||||
|
if (preIncludeName)
|
||||||
|
warnx("Overriding pre-included filename %s", preIncludeName);
|
||||||
|
preIncludeName = path;
|
||||||
|
if (verbose)
|
||||||
|
printf("Pre-included filename %s\n", preIncludeName);
|
||||||
|
}
|
||||||
|
|
||||||
static void printDep(char const *path)
|
static void printDep(char const *path)
|
||||||
{
|
{
|
||||||
if (dependfile) {
|
if (dependfile) {
|
||||||
@@ -274,11 +286,12 @@ bool yywrap(void)
|
|||||||
|
|
||||||
lexer_SetState(contextStack->lexerState);
|
lexer_SetState(contextStack->lexerState);
|
||||||
macro_SetUniqueID(contextStack->uniqueID);
|
macro_SetUniqueID(contextStack->uniqueID);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure not to switch the lexer state before calling this, so the saved line no is correct.
|
// Make sure not to switch the lexer state before calling this, so the saved line no is correct.
|
||||||
// BE CAREFUL!! This modifies the file stack directly, you should have set up the file info first.
|
// BE CAREFUL! This modifies the file stack directly, you should have set up the file info first.
|
||||||
// Callers should set contextStack->lexerState after this so it is not NULL.
|
// Callers should set contextStack->lexerState after this so it is not NULL.
|
||||||
static void newContext(struct FileStackNode *fileInfo)
|
static void newContext(struct FileStackNode *fileInfo)
|
||||||
{
|
{
|
||||||
@@ -300,7 +313,7 @@ static void newContext(struct FileStackNode *fileInfo)
|
|||||||
context->forName = NULL;
|
context->forName = NULL;
|
||||||
|
|
||||||
// Link new entry to its parent so it's reachable later
|
// Link new entry to its parent so it's reachable later
|
||||||
// ERRORS SHOULD NOT OCCUR AFTER THIS!!
|
// ERRORS SHOULD NOT OCCUR AFTER THIS!
|
||||||
context->parent = contextStack;
|
context->parent = contextStack;
|
||||||
contextStack = context;
|
contextStack = context;
|
||||||
}
|
}
|
||||||
@@ -342,6 +355,41 @@ void fstk_RunInclude(char const *path)
|
|||||||
contextStack->uniqueID = macro_UndefUniqueID();
|
contextStack->uniqueID = macro_UndefUniqueID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Similar to `fstk_RunInclude`, but not subject to `-MG`, and
|
||||||
|
// calling `lexer_SetState` instead of `lexer_SetStateAtEOL`.
|
||||||
|
static void runPreIncludeFile(void)
|
||||||
|
{
|
||||||
|
if (!preIncludeName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char *fullPath = NULL;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
if (!fstk_FindFile(preIncludeName, &fullPath, &size)) {
|
||||||
|
free(fullPath);
|
||||||
|
error("Unable to open included file '%s': %s\n", preIncludeName, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FileStackNamedNode *fileInfo = malloc(sizeof(*fileInfo) + size);
|
||||||
|
|
||||||
|
if (!fileInfo) {
|
||||||
|
error("Failed to alloc file info for pre-include: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fileInfo->node.type = NODE_FILE;
|
||||||
|
strcpy(fileInfo->name, fullPath);
|
||||||
|
free(fullPath);
|
||||||
|
|
||||||
|
newContext((struct FileStackNode *)fileInfo);
|
||||||
|
contextStack->lexerState = lexer_OpenFile(fileInfo->name);
|
||||||
|
if (!contextStack->lexerState)
|
||||||
|
fatalerror("Failed to set up lexer for file include\n");
|
||||||
|
lexer_SetState(contextStack->lexerState);
|
||||||
|
// We're back at top-level, so most things are reset
|
||||||
|
contextStack->uniqueID = macro_UndefUniqueID();
|
||||||
|
}
|
||||||
|
|
||||||
void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
||||||
{
|
{
|
||||||
struct Symbol *macro = sym_FindExactSymbol(macroName);
|
struct Symbol *macro = sym_FindExactSymbol(macroName);
|
||||||
@@ -563,4 +611,6 @@ void fstk_Init(char const *mainPath, size_t maxDepth)
|
|||||||
// Make sure that the default of 64 is OK, though
|
// Make sure that the default of 64 is OK, though
|
||||||
assert(DEPTH_LIMIT >= DEFAULT_MAX_DEPTH);
|
assert(DEPTH_LIMIT >= DEFAULT_MAX_DEPTH);
|
||||||
#undef DEPTH_LIMIT
|
#undef DEPTH_LIMIT
|
||||||
|
|
||||||
|
runPreIncludeFile();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -733,7 +733,7 @@ static uint32_t readBracketedMacroArgNum(void)
|
|||||||
}
|
}
|
||||||
symName[i] = '\0';
|
symName[i] = '\0';
|
||||||
|
|
||||||
struct Symbol const *sym = sym_FindScopedSymbol(symName);
|
struct Symbol const *sym = sym_FindScopedValidSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
error("Bracketed symbol \"%s\" does not exist\n", symName);
|
error("Bracketed symbol \"%s\" does not exist\n", symName);
|
||||||
@@ -1179,7 +1179,7 @@ static uint32_t readFractionalPart(uint32_t integer)
|
|||||||
precision = fixPrecision;
|
precision = fixPrecision;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (integer >= ((uint32_t)1 << (precision - 1)))
|
if (integer >= ((uint64_t)1 << (32 - precision)))
|
||||||
warning(WARNING_LARGE_CONSTANT, "Magnitude of fixed-point constant is too large\n");
|
warning(WARNING_LARGE_CONSTANT, "Magnitude of fixed-point constant is too large\n");
|
||||||
|
|
||||||
// Cast to unsigned avoids undefined overflow behavior
|
// Cast to unsigned avoids undefined overflow behavior
|
||||||
@@ -1400,7 +1400,7 @@ static char const *readInterpolation(size_t depth)
|
|||||||
|
|
||||||
static char buf[MAXSTRLEN + 1];
|
static char buf[MAXSTRLEN + 1];
|
||||||
|
|
||||||
struct Symbol const *sym = sym_FindScopedSymbol(symName);
|
struct Symbol const *sym = sym_FindScopedValidSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
error("Interpolated symbol \"%s\" does not exist\n", symName);
|
error("Interpolated symbol \"%s\" does not exist\n", symName);
|
||||||
|
|||||||
@@ -53,11 +53,11 @@ char const *__asan_default_options(void) { return "detect_leaks=0"; }
|
|||||||
// Unfortunately, macOS still ships 2.3, which is from 2008...
|
// Unfortunately, macOS still ships 2.3, which is from 2008...
|
||||||
int yyparse(void);
|
int yyparse(void);
|
||||||
|
|
||||||
FILE * dependfile;
|
FILE *dependfile = NULL;
|
||||||
bool generatedMissingIncludes;
|
bool generatedMissingIncludes = false;
|
||||||
bool failedOnMissingInclude;
|
bool failedOnMissingInclude = false;
|
||||||
bool generatePhonyDeps;
|
bool generatePhonyDeps = false;
|
||||||
char *targetFileName;
|
char *targetFileName = NULL;
|
||||||
|
|
||||||
bool haltnop;
|
bool haltnop;
|
||||||
bool warnOnHaltNop;
|
bool warnOnHaltNop;
|
||||||
@@ -87,7 +87,7 @@ static char *make_escape(char const *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Short options
|
// Short options
|
||||||
static const char *optstring = "b:D:Eg:Hhi:LlM:o:p:Q:r:VvW:w";
|
static const char *optstring = "b:D:Eg:Hhi:I:LlM:o:P:p:Q:r:VvW:w";
|
||||||
|
|
||||||
// Variables for the long-only options
|
// Variables for the long-only options
|
||||||
static int depType; // Variants of `-M`
|
static int depType; // Variants of `-M`
|
||||||
@@ -107,7 +107,7 @@ static struct option const longopts[] = {
|
|||||||
{ "gfx-chars", required_argument, NULL, 'g' },
|
{ "gfx-chars", required_argument, NULL, 'g' },
|
||||||
{ "nop-after-halt", no_argument, NULL, 'H' },
|
{ "nop-after-halt", no_argument, NULL, 'H' },
|
||||||
{ "halt-without-nop", no_argument, NULL, 'h' },
|
{ "halt-without-nop", no_argument, NULL, 'h' },
|
||||||
{ "include", required_argument, NULL, 'i' },
|
{ "include", required_argument, NULL, 'I' },
|
||||||
{ "preserve-ld", no_argument, NULL, 'L' },
|
{ "preserve-ld", no_argument, NULL, 'L' },
|
||||||
{ "auto-ldh", no_argument, NULL, 'l' },
|
{ "auto-ldh", no_argument, NULL, 'l' },
|
||||||
{ "dependfile", required_argument, NULL, 'M' },
|
{ "dependfile", required_argument, NULL, 'M' },
|
||||||
@@ -116,6 +116,7 @@ static struct option const longopts[] = {
|
|||||||
{ "MT", required_argument, &depType, 'T' },
|
{ "MT", required_argument, &depType, 'T' },
|
||||||
{ "MQ", required_argument, &depType, 'Q' },
|
{ "MQ", required_argument, &depType, 'Q' },
|
||||||
{ "output", required_argument, NULL, 'o' },
|
{ "output", required_argument, NULL, 'o' },
|
||||||
|
{ "preinclude", required_argument, NULL, 'P' },
|
||||||
{ "pad-value", required_argument, NULL, 'p' },
|
{ "pad-value", required_argument, NULL, 'p' },
|
||||||
{ "q-precision", required_argument, NULL, 'Q' },
|
{ "q-precision", required_argument, NULL, 'Q' },
|
||||||
{ "recursion-depth", required_argument, NULL, 'r' },
|
{ "recursion-depth", required_argument, NULL, 'r' },
|
||||||
@@ -128,10 +129,10 @@ static struct option const longopts[] = {
|
|||||||
static void print_usage(void)
|
static void print_usage(void)
|
||||||
{
|
{
|
||||||
fputs(
|
fputs(
|
||||||
"Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-i path]\n"
|
"Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-I path]\n"
|
||||||
" [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n"
|
" [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n"
|
||||||
" [-o out_file] [-p pad_value] [-Q precision] [-r depth]\n"
|
" [-o out_file] [-P include_file] [-p pad_value] [-Q precision]\n"
|
||||||
" [-W warning] <file>\n"
|
" [-r depth] [-W warning] <file>\n"
|
||||||
"Useful options:\n"
|
"Useful options:\n"
|
||||||
" -E, --export-all export all labels\n"
|
" -E, --export-all export all labels\n"
|
||||||
" -M, --dependfile <path> set the output dependency file\n"
|
" -M, --dependfile <path> set the output dependency file\n"
|
||||||
@@ -147,9 +148,6 @@ static void print_usage(void)
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int ch;
|
|
||||||
char *ep;
|
|
||||||
|
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH");
|
char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH");
|
||||||
|
|
||||||
@@ -158,18 +156,11 @@ int main(int argc, char *argv[])
|
|||||||
if (sourceDateEpoch)
|
if (sourceDateEpoch)
|
||||||
now = (time_t)strtoul(sourceDateEpoch, NULL, 0);
|
now = (time_t)strtoul(sourceDateEpoch, NULL, 0);
|
||||||
|
|
||||||
dependfile = NULL;
|
|
||||||
|
|
||||||
// Perform some init for below
|
// Perform some init for below
|
||||||
sym_Init(now);
|
sym_Init(now);
|
||||||
|
|
||||||
// Set defaults
|
// Set defaults
|
||||||
|
|
||||||
generatePhonyDeps = false;
|
|
||||||
generatedMissingIncludes = false;
|
|
||||||
failedOnMissingInclude = false;
|
|
||||||
targetFileName = NULL;
|
|
||||||
|
|
||||||
opt_B("01");
|
opt_B("01");
|
||||||
opt_G("0123");
|
opt_G("0123");
|
||||||
opt_P(0);
|
opt_P(0);
|
||||||
@@ -182,13 +173,16 @@ int main(int argc, char *argv[])
|
|||||||
warnings = true;
|
warnings = true;
|
||||||
sym_SetExportAll(false);
|
sym_SetExportAll(false);
|
||||||
uint32_t maxDepth = DEFAULT_MAX_DEPTH;
|
uint32_t maxDepth = DEFAULT_MAX_DEPTH;
|
||||||
|
char *dependFileName = NULL;
|
||||||
size_t targetFileNameLen = 0;
|
size_t targetFileNameLen = 0;
|
||||||
|
|
||||||
|
int ch;
|
||||||
|
char *ep;
|
||||||
while ((ch = musl_getopt_long_only(argc, argv, optstring, longopts, NULL)) != -1) {
|
while ((ch = musl_getopt_long_only(argc, argv, optstring, longopts, NULL)) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'b':
|
case 'b':
|
||||||
if (strlen(musl_optarg) == 2)
|
if (strlen(musl_optarg) == 2)
|
||||||
opt_B(&musl_optarg[1]);
|
opt_B(musl_optarg);
|
||||||
else
|
else
|
||||||
errx("Must specify exactly 2 characters for option 'b'");
|
errx("Must specify exactly 2 characters for option 'b'");
|
||||||
break;
|
break;
|
||||||
@@ -210,7 +204,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
case 'g':
|
case 'g':
|
||||||
if (strlen(musl_optarg) == 4)
|
if (strlen(musl_optarg) == 4)
|
||||||
opt_G(&musl_optarg[1]);
|
opt_G(musl_optarg);
|
||||||
else
|
else
|
||||||
errx("Must specify exactly 4 characters for option 'g'");
|
errx("Must specify exactly 4 characters for option 'g'");
|
||||||
break;
|
break;
|
||||||
@@ -226,6 +220,10 @@ int main(int argc, char *argv[])
|
|||||||
haltnop = false;
|
haltnop = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// `-i` was the only short option for `--include` until `-I` was
|
||||||
|
// introduced to better match the `-I dir` option of gcc and clang.
|
||||||
|
// `-i` is now undocumented but still supported for now.
|
||||||
|
case 'I':
|
||||||
case 'i':
|
case 'i':
|
||||||
fstk_AddIncludePath(musl_optarg);
|
fstk_AddIncludePath(musl_optarg);
|
||||||
break;
|
break;
|
||||||
@@ -242,18 +240,27 @@ int main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'M':
|
case 'M':
|
||||||
if (!strcmp("-", musl_optarg))
|
if (dependfile)
|
||||||
|
warnx("Overriding dependfile %s", dependFileName);
|
||||||
|
if (!strcmp("-", musl_optarg)) {
|
||||||
dependfile = stdout;
|
dependfile = stdout;
|
||||||
else
|
dependFileName = "<stdout>";
|
||||||
|
} else {
|
||||||
dependfile = fopen(musl_optarg, "w");
|
dependfile = fopen(musl_optarg, "w");
|
||||||
|
dependFileName = musl_optarg;
|
||||||
|
}
|
||||||
if (dependfile == NULL)
|
if (dependfile == NULL)
|
||||||
err("Could not open dependfile %s", musl_optarg);
|
err("Could not open dependfile %s", dependFileName);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
out_SetFileName(musl_optarg);
|
out_SetFileName(musl_optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'P':
|
||||||
|
fstk_SetPreIncludeFile(musl_optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
unsigned long padByte;
|
unsigned long padByte;
|
||||||
case 'p':
|
case 'p':
|
||||||
padByte = strtoul(musl_optarg, &ep, 0);
|
padByte = strtoul(musl_optarg, &ep, 0);
|
||||||
@@ -371,7 +378,7 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(dependfile, "%s: %s\n", targetFileName, mainFileName);
|
fprintf(dependfile, "%s: %s\n", targetFileName, mainFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
charmap_New("main", NULL);
|
charmap_New(DEFAULT_CHARMAP_NAME, NULL);
|
||||||
|
|
||||||
// Init lexer and file stack, providing file info
|
// Init lexer and file stack, providing file info
|
||||||
lexer_Init();
|
lexer_Init();
|
||||||
|
|||||||
@@ -492,7 +492,7 @@ void out_WriteObject(void)
|
|||||||
if (strcmp(objectName, "-") != 0)
|
if (strcmp(objectName, "-") != 0)
|
||||||
f = fopen(objectName, "wb");
|
f = fopen(objectName, "wb");
|
||||||
else
|
else
|
||||||
f = fdopen(1, "wb");
|
f = fdopen(STDOUT_FILENO, "wb");
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
err("Couldn't write file '%s'", objectName);
|
err("Couldn't write file '%s'", objectName);
|
||||||
@@ -540,7 +540,9 @@ void out_WriteObject(void)
|
|||||||
// Set the objectfilename
|
// Set the objectfilename
|
||||||
void out_SetFileName(char *s)
|
void out_SetFileName(char *s)
|
||||||
{
|
{
|
||||||
|
if (objectName)
|
||||||
|
warnx("Overriding output filename %s", objectName);
|
||||||
objectName = s;
|
objectName = s;
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf("Output filename %s\n", s);
|
printf("Output filename %s\n", objectName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -550,6 +550,7 @@ enum {
|
|||||||
%token T_OP_BANK "BANK"
|
%token T_OP_BANK "BANK"
|
||||||
%token T_OP_ALIGN "ALIGN"
|
%token T_OP_ALIGN "ALIGN"
|
||||||
%token T_OP_SIZEOF "SIZEOF" T_OP_STARTOF "STARTOF"
|
%token T_OP_SIZEOF "SIZEOF" T_OP_STARTOF "STARTOF"
|
||||||
|
|
||||||
%token T_OP_SIN "SIN" T_OP_COS "COS" T_OP_TAN "TAN"
|
%token T_OP_SIN "SIN" T_OP_COS "COS" T_OP_TAN "TAN"
|
||||||
%token T_OP_ASIN "ASIN" T_OP_ACOS "ACOS" T_OP_ATAN "ATAN" T_OP_ATAN2 "ATAN2"
|
%token T_OP_ASIN "ASIN" T_OP_ACOS "ACOS" T_OP_ATAN "ATAN" T_OP_ATAN2 "ATAN2"
|
||||||
%token T_OP_FDIV "FDIV"
|
%token T_OP_FDIV "FDIV"
|
||||||
@@ -559,6 +560,7 @@ enum {
|
|||||||
%token T_OP_LOG "LOG"
|
%token T_OP_LOG "LOG"
|
||||||
%token T_OP_ROUND "ROUND"
|
%token T_OP_ROUND "ROUND"
|
||||||
%token T_OP_CEIL "CEIL" T_OP_FLOOR "FLOOR"
|
%token T_OP_CEIL "CEIL" T_OP_FLOOR "FLOOR"
|
||||||
|
%type <constValue> opt_q_arg
|
||||||
|
|
||||||
%token T_OP_HIGH "HIGH" T_OP_LOW "LOW"
|
%token T_OP_HIGH "HIGH" T_OP_LOW "LOW"
|
||||||
%token T_OP_ISCONST "ISCONST"
|
%token T_OP_ISCONST "ISCONST"
|
||||||
@@ -1462,56 +1464,54 @@ relocexpr_no_str : scoped_anon_id { rpn_Symbol(&$$, $1); }
|
|||||||
| T_OP_DEF {
|
| T_OP_DEF {
|
||||||
lexer_ToggleStringExpansion(false);
|
lexer_ToggleStringExpansion(false);
|
||||||
} T_LPAREN scoped_anon_id T_RPAREN {
|
} T_LPAREN scoped_anon_id T_RPAREN {
|
||||||
struct Symbol const *sym = sym_FindScopedSymbol($4);
|
rpn_Number(&$$, sym_FindScopedValidSymbol($4) != NULL);
|
||||||
|
|
||||||
rpn_Number(&$$, !!sym);
|
|
||||||
|
|
||||||
lexer_ToggleStringExpansion(true);
|
lexer_ToggleStringExpansion(true);
|
||||||
}
|
}
|
||||||
| T_OP_ROUND T_LPAREN const T_RPAREN {
|
| T_OP_ROUND T_LPAREN const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Round($3));
|
rpn_Number(&$$, fix_Round($3, $4));
|
||||||
}
|
}
|
||||||
| T_OP_CEIL T_LPAREN const T_RPAREN {
|
| T_OP_CEIL T_LPAREN const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Ceil($3));
|
rpn_Number(&$$, fix_Ceil($3, $4));
|
||||||
}
|
}
|
||||||
| T_OP_FLOOR T_LPAREN const T_RPAREN {
|
| T_OP_FLOOR T_LPAREN const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Floor($3));
|
rpn_Number(&$$, fix_Floor($3, $4));
|
||||||
}
|
}
|
||||||
| T_OP_FDIV T_LPAREN const T_COMMA const T_RPAREN {
|
| T_OP_FDIV T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Div($3, $5));
|
rpn_Number(&$$, fix_Div($3, $5, $6));
|
||||||
}
|
}
|
||||||
| T_OP_FMUL T_LPAREN const T_COMMA const T_RPAREN {
|
| T_OP_FMUL T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Mul($3, $5));
|
rpn_Number(&$$, fix_Mul($3, $5, $6));
|
||||||
}
|
}
|
||||||
| T_OP_FMOD T_LPAREN const T_COMMA const T_RPAREN {
|
| T_OP_FMOD T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Mod($3, $5));
|
rpn_Number(&$$, fix_Mod($3, $5, $6));
|
||||||
}
|
}
|
||||||
| T_OP_POW T_LPAREN const T_COMMA const T_RPAREN {
|
| T_OP_POW T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Pow($3, $5));
|
rpn_Number(&$$, fix_Pow($3, $5, $6));
|
||||||
}
|
}
|
||||||
| T_OP_LOG T_LPAREN const T_COMMA const T_RPAREN {
|
| T_OP_LOG T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Log($3, $5));
|
rpn_Number(&$$, fix_Log($3, $5, $6));
|
||||||
}
|
}
|
||||||
| T_OP_SIN T_LPAREN const T_RPAREN {
|
| T_OP_SIN T_LPAREN const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Sin($3));
|
rpn_Number(&$$, fix_Sin($3, $4));
|
||||||
}
|
}
|
||||||
| T_OP_COS T_LPAREN const T_RPAREN {
|
| T_OP_COS T_LPAREN const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Cos($3));
|
rpn_Number(&$$, fix_Cos($3, $4));
|
||||||
}
|
}
|
||||||
| T_OP_TAN T_LPAREN const T_RPAREN {
|
| T_OP_TAN T_LPAREN const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_Tan($3));
|
rpn_Number(&$$, fix_Tan($3, $4));
|
||||||
}
|
}
|
||||||
| T_OP_ASIN T_LPAREN const T_RPAREN {
|
| T_OP_ASIN T_LPAREN const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_ASin($3));
|
rpn_Number(&$$, fix_ASin($3, $4));
|
||||||
}
|
}
|
||||||
| T_OP_ACOS T_LPAREN const T_RPAREN {
|
| T_OP_ACOS T_LPAREN const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_ACos($3));
|
rpn_Number(&$$, fix_ACos($3, $4));
|
||||||
}
|
}
|
||||||
| T_OP_ATAN T_LPAREN const T_RPAREN {
|
| T_OP_ATAN T_LPAREN const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_ATan($3));
|
rpn_Number(&$$, fix_ATan($3, $4));
|
||||||
}
|
}
|
||||||
| T_OP_ATAN2 T_LPAREN const T_COMMA const T_RPAREN {
|
| T_OP_ATAN2 T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||||
rpn_Number(&$$, fix_ATan2($3, $5));
|
rpn_Number(&$$, fix_ATan2($3, $5, $6));
|
||||||
}
|
}
|
||||||
| T_OP_STRCMP T_LPAREN string T_COMMA string T_RPAREN {
|
| T_OP_STRCMP T_LPAREN string T_COMMA string T_RPAREN {
|
||||||
rpn_Number(&$$, strcmp($3, $5));
|
rpn_Number(&$$, strcmp($3, $5));
|
||||||
@@ -1538,7 +1538,7 @@ relocexpr_no_str : scoped_anon_id { rpn_Symbol(&$$, $1); }
|
|||||||
uconst : const {
|
uconst : const {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
if ($$ < 0)
|
if ($$ < 0)
|
||||||
fatalerror("Constant mustn't be negative: %d\n", $1);
|
fatalerror("Constant must not be negative: %d\n", $1);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -1551,6 +1551,17 @@ const_no_str : relocexpr_no_str { $$ = rpn_GetConstVal(&$1); }
|
|||||||
const_8bit : reloc_8bit { $$ = rpn_GetConstVal(&$1); }
|
const_8bit : reloc_8bit { $$ = rpn_GetConstVal(&$1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
opt_q_arg : %empty { $$ = fix_Precision(); }
|
||||||
|
| T_COMMA const {
|
||||||
|
if ($2 >= 1 && $2 <= 31) {
|
||||||
|
$$ = $2;
|
||||||
|
} else {
|
||||||
|
error("Fixed-point precision must be between 1 and 31\n");
|
||||||
|
$$ = fix_Precision();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
string : T_STRING
|
string : T_STRING
|
||||||
| T_OP_STRSUB T_LPAREN string T_COMMA const T_COMMA uconst T_RPAREN {
|
| T_OP_STRSUB T_LPAREN string T_COMMA const T_COMMA uconst T_RPAREN {
|
||||||
size_t len = strlenUTF8($3);
|
size_t len = strlenUTF8($3);
|
||||||
@@ -1589,6 +1600,19 @@ string : T_STRING
|
|||||||
strfmt($$, sizeof($$), $3.format, $3.nbArgs, $3.args);
|
strfmt($$, sizeof($$), $3.format, $3.nbArgs, $3.args);
|
||||||
freeStrFmtArgList(&$3);
|
freeStrFmtArgList(&$3);
|
||||||
}
|
}
|
||||||
|
| T_POP_SECTION T_LPAREN scoped_anon_id T_RPAREN {
|
||||||
|
struct Symbol *sym = sym_FindScopedValidSymbol($3);
|
||||||
|
|
||||||
|
if (!sym)
|
||||||
|
fatalerror("Unknown symbol \"%s\"\n", $3);
|
||||||
|
struct Section const *section = sym_GetSection(sym);
|
||||||
|
|
||||||
|
if (!section)
|
||||||
|
fatalerror("\"%s\" does not belong to any section\n", sym->name);
|
||||||
|
// Section names are capped by rgbasm's maximum string length,
|
||||||
|
// so this currently can't overflow.
|
||||||
|
strcpy($$, section->name);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
strcat_args : string
|
strcat_args : string
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ HashMap symbols;
|
|||||||
|
|
||||||
static const char *labelScope; // Current section's label scope
|
static const char *labelScope; // Current section's label scope
|
||||||
static struct Symbol *PCSymbol;
|
static struct Symbol *PCSymbol;
|
||||||
|
static struct Symbol *_NARGSymbol;
|
||||||
static char savedTIME[256];
|
static char savedTIME[256];
|
||||||
static char savedDATE[256];
|
static char savedDATE[256];
|
||||||
static char savedTIMESTAMP_ISO8601_LOCAL[256];
|
static char savedTIMESTAMP_ISO8601_LOCAL[256];
|
||||||
@@ -78,12 +79,15 @@ static int32_t Callback_NARG(void)
|
|||||||
|
|
||||||
static int32_t Callback__LINE__(void)
|
static int32_t Callback__LINE__(void)
|
||||||
{
|
{
|
||||||
|
warning(WARNING_OBSOLETE, "`__LINE__` is deprecated\n");
|
||||||
|
|
||||||
return lexer_GetLineNo();
|
return lexer_GetLineNo();
|
||||||
}
|
}
|
||||||
|
|
||||||
static char const *Callback__FILE__(void)
|
static char const *Callback__FILE__(void)
|
||||||
{
|
{
|
||||||
// FIXME: this is dangerous, and here's why this is CURRENTLY okay. It's still bad, fix it.
|
warning(WARNING_OBSOLETE, "`__FILE__` is deprecated\n");
|
||||||
|
|
||||||
// There are only two call sites for this; one copies the contents directly, the other is
|
// There are only two call sites for this; one copies the contents directly, the other is
|
||||||
// EQUS expansions, which cannot straddle file boundaries. So this should be fine.
|
// EQUS expansions, which cannot straddle file boundaries. So this should be fine.
|
||||||
static char *buf = NULL;
|
static char *buf = NULL;
|
||||||
@@ -97,7 +101,7 @@ static char const *Callback__FILE__(void)
|
|||||||
// Account for the extra backslash inserted below
|
// Account for the extra backslash inserted below
|
||||||
if (fileName[i] == '"')
|
if (fileName[i] == '"')
|
||||||
j++;
|
j++;
|
||||||
// Ensure there will be enough room; DO NOT PRINT ANYTHING ABOVE THIS!!
|
// Ensure there will be enough room; DO NOT PRINT ANYTHING ABOVE THIS!
|
||||||
if (j + 2 >= bufsize) { // Always keep room for 2 tail chars
|
if (j + 2 >= bufsize) { // Always keep room for 2 tail chars
|
||||||
bufsize = bufsize ? bufsize * 2 : 64;
|
bufsize = bufsize ? bufsize * 2 : 64;
|
||||||
buf = realloc(buf, bufsize);
|
buf = realloc(buf, bufsize);
|
||||||
@@ -247,6 +251,21 @@ struct Symbol *sym_FindScopedSymbol(char const *symName)
|
|||||||
return sym_FindExactSymbol(symName);
|
return sym_FindExactSymbol(symName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Symbol *sym_FindScopedValidSymbol(char const *symName)
|
||||||
|
{
|
||||||
|
struct Symbol *sym = sym_FindScopedSymbol(symName);
|
||||||
|
|
||||||
|
// `@` has no value outside a section
|
||||||
|
if (sym == PCSymbol && !sect_GetSymbolSection()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// `_NARG` has no value outside a macro
|
||||||
|
if (sym == _NARGSymbol && !macro_GetCurrentArgs()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
|
||||||
struct Symbol const *sym_GetPC(void)
|
struct Symbol const *sym_GetPC(void)
|
||||||
{
|
{
|
||||||
return PCSymbol;
|
return PCSymbol;
|
||||||
@@ -260,7 +279,7 @@ static bool isReferenced(struct Symbol const *sym)
|
|||||||
// Purge a symbol
|
// Purge a symbol
|
||||||
void sym_Purge(char const *symName)
|
void sym_Purge(char const *symName)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = sym_FindScopedSymbol(symName);
|
struct Symbol *sym = sym_FindScopedValidSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
error("'%s' not defined\n", symName);
|
error("'%s' not defined\n", symName);
|
||||||
@@ -571,7 +590,7 @@ struct Symbol *sym_AddAnonLabel(void)
|
|||||||
}
|
}
|
||||||
char name[MAXSYMLEN + 1];
|
char name[MAXSYMLEN + 1];
|
||||||
|
|
||||||
sym_WriteAnonLabelName(name, 0, true); // The direction is important!!
|
sym_WriteAnonLabelName(name, 0, true); // The direction is important!
|
||||||
anonLabelID++;
|
anonLabelID++;
|
||||||
return addLabel(name);
|
return addLabel(name);
|
||||||
}
|
}
|
||||||
@@ -679,8 +698,10 @@ static struct Symbol *createBuiltinSymbol(char const *symName)
|
|||||||
void sym_Init(time_t now)
|
void sym_Init(time_t now)
|
||||||
{
|
{
|
||||||
PCSymbol = createBuiltinSymbol("@");
|
PCSymbol = createBuiltinSymbol("@");
|
||||||
struct Symbol *_NARGSymbol = createBuiltinSymbol("_NARG");
|
_NARGSymbol = createBuiltinSymbol("_NARG");
|
||||||
|
// __LINE__ is deprecated
|
||||||
struct Symbol *__LINE__Symbol = createBuiltinSymbol("__LINE__");
|
struct Symbol *__LINE__Symbol = createBuiltinSymbol("__LINE__");
|
||||||
|
// __FILE__ is deprecated
|
||||||
struct Symbol *__FILE__Symbol = createBuiltinSymbol("__FILE__");
|
struct Symbol *__FILE__Symbol = createBuiltinSymbol("__FILE__");
|
||||||
|
|
||||||
PCSymbol->type = SYM_LABEL;
|
PCSymbol->type = SYM_LABEL;
|
||||||
|
|||||||
@@ -38,13 +38,14 @@ static const enum WarningState defaultWarnings[ARRAY_SIZE(warningStates)] = {
|
|||||||
[WARNING_OBSOLETE] = WARNING_ENABLED,
|
[WARNING_OBSOLETE] = WARNING_ENABLED,
|
||||||
[WARNING_SHIFT] = WARNING_DISABLED,
|
[WARNING_SHIFT] = WARNING_DISABLED,
|
||||||
[WARNING_SHIFT_AMOUNT] = WARNING_DISABLED,
|
[WARNING_SHIFT_AMOUNT] = WARNING_DISABLED,
|
||||||
[WARNING_UNMAPPED_CHAR] = WARNING_ENABLED,
|
|
||||||
[WARNING_USER] = WARNING_ENABLED,
|
[WARNING_USER] = WARNING_ENABLED,
|
||||||
|
|
||||||
[WARNING_NUMERIC_STRING_1] = WARNING_ENABLED,
|
[WARNING_NUMERIC_STRING_1] = WARNING_ENABLED,
|
||||||
[WARNING_NUMERIC_STRING_2] = WARNING_DISABLED,
|
[WARNING_NUMERIC_STRING_2] = WARNING_DISABLED,
|
||||||
[WARNING_TRUNCATION_1] = WARNING_ENABLED,
|
[WARNING_TRUNCATION_1] = WARNING_ENABLED,
|
||||||
[WARNING_TRUNCATION_2] = WARNING_DISABLED,
|
[WARNING_TRUNCATION_2] = WARNING_DISABLED,
|
||||||
|
[WARNING_UNMAPPED_CHAR_1] = WARNING_ENABLED,
|
||||||
|
[WARNING_UNMAPPED_CHAR_2] = WARNING_DISABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum WarningState warningStates[ARRAY_SIZE(warningStates)];
|
enum WarningState warningStates[ARRAY_SIZE(warningStates)];
|
||||||
@@ -86,7 +87,6 @@ static const char * const warningFlags[NB_WARNINGS] = {
|
|||||||
"obsolete",
|
"obsolete",
|
||||||
"shift",
|
"shift",
|
||||||
"shift-amount",
|
"shift-amount",
|
||||||
"unmapped-char",
|
|
||||||
"user",
|
"user",
|
||||||
|
|
||||||
// Parametric warnings
|
// Parametric warnings
|
||||||
@@ -94,6 +94,8 @@ static const char * const warningFlags[NB_WARNINGS] = {
|
|||||||
"numeric-string",
|
"numeric-string",
|
||||||
"truncation",
|
"truncation",
|
||||||
"truncation",
|
"truncation",
|
||||||
|
"unmapped-char",
|
||||||
|
"unmapped-char",
|
||||||
|
|
||||||
// Meta warnings
|
// Meta warnings
|
||||||
"all",
|
"all",
|
||||||
@@ -108,6 +110,7 @@ static const struct {
|
|||||||
} paramWarnings[] = {
|
} paramWarnings[] = {
|
||||||
{ "numeric-string", 2, 1 },
|
{ "numeric-string", 2, 1 },
|
||||||
{ "truncation", 2, 2 },
|
{ "truncation", 2, 2 },
|
||||||
|
{ "unmapped-char", 2, 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool tryProcessParamWarning(char const *flag, uint8_t param, enum WarningState state)
|
static bool tryProcessParamWarning(char const *flag, uint8_t param, enum WarningState state)
|
||||||
@@ -162,8 +165,8 @@ static uint8_t const _wallCommands[] = {
|
|||||||
WARNING_LONG_STR,
|
WARNING_LONG_STR,
|
||||||
WARNING_NESTED_COMMENT,
|
WARNING_NESTED_COMMENT,
|
||||||
WARNING_OBSOLETE,
|
WARNING_OBSOLETE,
|
||||||
WARNING_UNMAPPED_CHAR,
|
|
||||||
WARNING_NUMERIC_STRING_1,
|
WARNING_NUMERIC_STRING_1,
|
||||||
|
WARNING_UNMAPPED_CHAR_1,
|
||||||
META_WARNING_DONE
|
META_WARNING_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -176,6 +179,8 @@ static uint8_t const _wextraCommands[] = {
|
|||||||
WARNING_NUMERIC_STRING_2,
|
WARNING_NUMERIC_STRING_2,
|
||||||
WARNING_TRUNCATION_1,
|
WARNING_TRUNCATION_1,
|
||||||
WARNING_TRUNCATION_2,
|
WARNING_TRUNCATION_2,
|
||||||
|
WARNING_UNMAPPED_CHAR_1,
|
||||||
|
WARNING_UNMAPPED_CHAR_2,
|
||||||
META_WARNING_DONE
|
META_WARNING_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -194,11 +199,12 @@ static uint8_t const _weverythingCommands[] = {
|
|||||||
WARNING_OBSOLETE,
|
WARNING_OBSOLETE,
|
||||||
WARNING_SHIFT,
|
WARNING_SHIFT,
|
||||||
WARNING_SHIFT_AMOUNT,
|
WARNING_SHIFT_AMOUNT,
|
||||||
WARNING_UNMAPPED_CHAR,
|
|
||||||
WARNING_NUMERIC_STRING_1,
|
WARNING_NUMERIC_STRING_1,
|
||||||
WARNING_NUMERIC_STRING_2,
|
WARNING_NUMERIC_STRING_2,
|
||||||
WARNING_TRUNCATION_1,
|
WARNING_TRUNCATION_1,
|
||||||
WARNING_TRUNCATION_2,
|
WARNING_TRUNCATION_2,
|
||||||
|
WARNING_UNMAPPED_CHAR_1,
|
||||||
|
WARNING_UNMAPPED_CHAR_2,
|
||||||
// WARNING_USER,
|
// WARNING_USER,
|
||||||
META_WARNING_DONE
|
META_WARNING_DONE
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -337,6 +337,8 @@ static char *parseArgv(int argc, char **argv, bool &autoAttrmap, bool &autoTilem
|
|||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
autoAttrmap = false;
|
autoAttrmap = false;
|
||||||
|
if (!options.attrmap.empty())
|
||||||
|
warning("Overriding attrmap file %s", options.attrmap.c_str());
|
||||||
options.attrmap = musl_optarg;
|
options.attrmap = musl_optarg;
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
@@ -479,6 +481,8 @@ static char *parseArgv(int argc, char **argv, bool &autoAttrmap, bool &autoTilem
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
|
if (!options.output.empty())
|
||||||
|
warning("Overriding tile data file %s", options.output.c_str());
|
||||||
options.output = musl_optarg;
|
options.output = musl_optarg;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
@@ -486,6 +490,8 @@ static char *parseArgv(int argc, char **argv, bool &autoAttrmap, bool &autoTilem
|
|||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
autoPalettes = false;
|
autoPalettes = false;
|
||||||
|
if (!options.palettes.empty())
|
||||||
|
warning("Overriding palettes file %s", options.palettes.c_str());
|
||||||
options.palettes = musl_optarg;
|
options.palettes = musl_optarg;
|
||||||
break;
|
break;
|
||||||
case 'Q':
|
case 'Q':
|
||||||
@@ -493,6 +499,8 @@ static char *parseArgv(int argc, char **argv, bool &autoAttrmap, bool &autoTilem
|
|||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
autoPalmap = false;
|
autoPalmap = false;
|
||||||
|
if (!options.palmap.empty())
|
||||||
|
warning("Overriding palette map file %s", options.palmap.c_str());
|
||||||
options.palmap = musl_optarg;
|
options.palmap = musl_optarg;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
@@ -520,6 +528,8 @@ static char *parseArgv(int argc, char **argv, bool &autoAttrmap, bool &autoTilem
|
|||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
autoTilemap = false;
|
autoTilemap = false;
|
||||||
|
if (!options.tilemap.empty())
|
||||||
|
warning("Overriding tilemap file %s", options.tilemap.c_str());
|
||||||
options.tilemap = musl_optarg;
|
options.tilemap = musl_optarg;
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
|
|||||||
@@ -28,31 +28,6 @@ void indexed(std::vector<Palette> &palettes, int palSize, png_color const *palRG
|
|||||||
return Rgba(c.red, c.green, c.blue, palAlpha ? palAlpha[index] : 0xFF);
|
return Rgba(c.red, c.green, c.blue, palAlpha ? palAlpha[index] : 0xFF);
|
||||||
};
|
};
|
||||||
|
|
||||||
// HACK: for compatibility with old versions, add unused colors if:
|
|
||||||
// - there is only one palette, and
|
|
||||||
// - only some of the first N colors are being used
|
|
||||||
if (palettes.size() == 1) {
|
|
||||||
Palette &palette = palettes[0];
|
|
||||||
// Build our candidate array of colors
|
|
||||||
decltype(palette.colors) colors{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
|
|
||||||
for (int i = 0; i < options.maxOpaqueColors(); ++i) {
|
|
||||||
colors[i + options.hasTransparentPixels] = pngToRgb(i).cgbColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the palette only uses those colors
|
|
||||||
if (std::all_of(palette.begin(), palette.end(), [&colors](uint16_t color) {
|
|
||||||
return std::find(colors.begin(), colors.end(), color) != colors.end();
|
|
||||||
})) {
|
|
||||||
if (palette.size() != options.maxOpaqueColors()) {
|
|
||||||
warning("Unused color in PNG embedded palette was re-added; please use `-c "
|
|
||||||
"embedded` to get this in future versions");
|
|
||||||
}
|
|
||||||
// Overwrite the palette, and return with that (it's already sorted)
|
|
||||||
palette.colors = colors;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Palette &pal : palettes) {
|
for (Palette &pal : palettes) {
|
||||||
std::sort(pal.begin(), pal.end(), [&](uint16_t lhs, uint16_t rhs) {
|
std::sort(pal.begin(), pal.end(), [&](uint16_t lhs, uint16_t rhs) {
|
||||||
// Iterate through the PNG's palette, looking for either of the two
|
// Iterate through the PNG's palette, looking for either of the two
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <limits>
|
||||||
|
#include <optional>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <streambuf>
|
#include <streambuf>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -53,7 +55,7 @@ constexpr uint8_t singleToHex(char c) {
|
|||||||
|
|
||||||
template<typename Str> // Should be std::string or std::string_view
|
template<typename Str> // Should be std::string or std::string_view
|
||||||
static void skipWhitespace(Str const &str, typename Str::size_type &pos) {
|
static void skipWhitespace(Str const &str, typename Str::size_type &pos) {
|
||||||
pos = std::min(str.find_first_not_of(" \t", pos), str.length());
|
pos = std::min(str.find_first_not_of(" \t"sv, pos), str.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseInlinePalSpec(char const * const rawArg) {
|
void parseInlinePalSpec(char const * const rawArg) {
|
||||||
@@ -191,6 +193,15 @@ static T readBE(U const *bytes) {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
static T readLE(U const *bytes) {
|
||||||
|
T val = 0;
|
||||||
|
for (size_t i = 0; i < sizeof(val); ++i) {
|
||||||
|
val |= static_cast<uint8_t>(bytes[i]) << (i * 8);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* **Appends** the first line read from `file` to the end of the provided `buffer`.
|
* **Appends** the first line read from `file` to the end of the provided `buffer`.
|
||||||
*/
|
*/
|
||||||
@@ -217,13 +228,53 @@ static void readLine(std::filebuf &file, std::string &buffer) {
|
|||||||
/*
|
/*
|
||||||
* Parses the initial part of a string_view, advancing the "read index" as it does
|
* Parses the initial part of a string_view, advancing the "read index" as it does
|
||||||
*/
|
*/
|
||||||
static uint16_t parseDec(std::string const &str, std::string::size_type &n) {
|
template<typename U> // Should be uint*_t
|
||||||
uint32_t value = 0; // Use a larger type to handle overflow more easily
|
static std::optional<U> parseDec(std::string const &str, std::string::size_type &n) {
|
||||||
for (auto end = std::min(str.length(), str.find_first_not_of("0123456789", n)); n < end; ++n) {
|
std::string::size_type start = n;
|
||||||
value = std::min<uint32_t>(value * 10 + (str[n] - '0'), UINT16_MAX);
|
|
||||||
|
uintmax_t value = 0; // Use a larger type to handle overflow more easily
|
||||||
|
for (auto end = std::min(str.length(), str.find_first_not_of("0123456789"sv, n)); n < end;
|
||||||
|
++n) {
|
||||||
|
value = std::min(value * 10 + (str[n] - '0'), (uintmax_t)std::numeric_limits<U>::max);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return n > start ? std::optional<U>{value} : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::optional<Rgba> parseColor(std::string const &str, std::string::size_type &n,
|
||||||
|
uint16_t i) {
|
||||||
|
std::optional<uint8_t> r = parseDec<uint8_t>(str, n);
|
||||||
|
if (!r) {
|
||||||
|
error("Failed to parse color #%" PRIu16 " (\"%s\"): invalid red component", i + 1,
|
||||||
|
str.c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
skipWhitespace(str, n);
|
||||||
|
if (n == str.length()) {
|
||||||
|
error("Failed to parse color #%" PRIu16 " (\"%s\"): missing green component", i + 1,
|
||||||
|
str.c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
std::optional<uint8_t> g = parseDec<uint8_t>(str, n);
|
||||||
|
if (!g) {
|
||||||
|
error("Failed to parse color #%" PRIu16 " (\"%s\"): invalid green component", i + 1,
|
||||||
|
str.c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
skipWhitespace(str, n);
|
||||||
|
if (n == str.length()) {
|
||||||
|
error("Failed to parse color #%" PRIu16 " (\"%s\"): missing blue component", i + 1,
|
||||||
|
str.c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
std::optional<uint8_t> b = parseDec<uint8_t>(str, n);
|
||||||
|
if (!b) {
|
||||||
|
error("Failed to parse color #%" PRIu16 " (\"%s\"): invalid blue component", i + 1,
|
||||||
|
str.c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::optional<Rgba>{Rgba(*r, *g, *b, 0xFF)};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parsePSPFile(std::filebuf &file) {
|
static void parsePSPFile(std::filebuf &file) {
|
||||||
@@ -246,41 +297,30 @@ static void parsePSPFile(std::filebuf &file) {
|
|||||||
line.clear();
|
line.clear();
|
||||||
readLine(file, line);
|
readLine(file, line);
|
||||||
std::string::size_type n = 0;
|
std::string::size_type n = 0;
|
||||||
uint16_t nbColors = parseDec(line, n);
|
std::optional<uint16_t> nbColors = parseDec<uint16_t>(line, n);
|
||||||
if (n != line.length()) {
|
if (!nbColors || n != line.length()) {
|
||||||
error("Invalid \"number of colors\" line in PSP file (%s)", line.c_str());
|
error("Invalid \"number of colors\" line in PSP file (%s)", line.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nbColors > options.nbColorsPerPal * options.nbPalettes) {
|
if (*nbColors > options.nbColorsPerPal * options.nbPalettes) {
|
||||||
warning("PSP file contains %" PRIu16 " colors, but there can only be %" PRIu16
|
warning("PSP file contains %" PRIu16 " colors, but there can only be %" PRIu16
|
||||||
"; ignoring extra",
|
"; ignoring extra",
|
||||||
nbColors, options.nbColorsPerPal * options.nbPalettes);
|
*nbColors, options.nbColorsPerPal * options.nbPalettes);
|
||||||
nbColors = options.nbColorsPerPal * options.nbPalettes;
|
nbColors = options.nbColorsPerPal * options.nbPalettes;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.palSpec.clear();
|
options.palSpec.clear();
|
||||||
|
|
||||||
for (uint16_t i = 0; i < nbColors; ++i) {
|
for (uint16_t i = 0; i < *nbColors; ++i) {
|
||||||
line.clear();
|
line.clear();
|
||||||
readLine(file, line);
|
readLine(file, line);
|
||||||
n = 0;
|
|
||||||
|
|
||||||
uint8_t r = parseDec(line, n);
|
n = 0;
|
||||||
skipWhitespace(line, n);
|
std::optional<Rgba> color = parseColor(line, n, i + 1);
|
||||||
if (n == line.length()) {
|
if (!color) {
|
||||||
error("Failed to parse color #%" PRIu16 " (\"%s\"): missing green component", i + 1,
|
|
||||||
line.c_str());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint8_t g = parseDec(line, n);
|
|
||||||
if (n == line.length()) {
|
|
||||||
error("Failed to parse color #%" PRIu16 " (\"%s\"): missing green component", i + 1,
|
|
||||||
line.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
skipWhitespace(line, n);
|
|
||||||
uint8_t b = parseDec(line, n);
|
|
||||||
if (n != line.length()) {
|
if (n != line.length()) {
|
||||||
error("Failed to parse color #%" PRIu16
|
error("Failed to parse color #%" PRIu16
|
||||||
" (\"%s\"): trailing characters after blue component",
|
" (\"%s\"): trailing characters after blue component",
|
||||||
@@ -291,11 +331,98 @@ static void parsePSPFile(std::filebuf &file) {
|
|||||||
if (i % options.nbColorsPerPal == 0) {
|
if (i % options.nbColorsPerPal == 0) {
|
||||||
options.palSpec.emplace_back();
|
options.palSpec.emplace_back();
|
||||||
}
|
}
|
||||||
options.palSpec.back()[i % options.nbColorsPerPal] = Rgba(r, g, b, 0xFF);
|
options.palSpec.back()[i % options.nbColorsPerPal] = *color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseACTFile(std::filebuf &file) {
|
static void parseGPLFile(std::filebuf &file) {
|
||||||
|
// https://gitlab.gnome.org/GNOME/gimp/-/blob/gimp-2-10/app/core/gimppalette-load.c#L39
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
readLine(file, line);
|
||||||
|
// FIXME: C++20 will allow `!line.starts_with` instead of `line.rfind` with 0
|
||||||
|
if (line.rfind("GIMP Palette", 0)) {
|
||||||
|
error("Palette file does not appear to be a GPL palette file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t nbColors = 0;
|
||||||
|
uint16_t maxNbColors = options.nbColorsPerPal * options.nbPalettes;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
line.clear();
|
||||||
|
readLine(file, line);
|
||||||
|
if (!line.length()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: C++20 will allow `line.starts_with` instead of `!line.rfind` with 0
|
||||||
|
if (!line.rfind("#", 0) || !line.rfind("Name:", 0) || !line.rfind("Column:", 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string::size_type n = 0;
|
||||||
|
std::optional<Rgba> color = parseColor(line, n, nbColors + 1);
|
||||||
|
if (!color) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
++nbColors;
|
||||||
|
if (nbColors < maxNbColors) {
|
||||||
|
if (nbColors % options.nbColorsPerPal == 1) {
|
||||||
|
options.palSpec.emplace_back();
|
||||||
|
}
|
||||||
|
options.palSpec.back()[nbColors % options.nbColorsPerPal] = *color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbColors > maxNbColors) {
|
||||||
|
warning("GPL file contains %" PRIu16 " colors, but there can only be %" PRIu16
|
||||||
|
"; ignoring extra",
|
||||||
|
nbColors, maxNbColors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseHEXFile(std::filebuf &file) {
|
||||||
|
// https://lospec.com/palette-list/tag/gbc
|
||||||
|
|
||||||
|
uint16_t nbColors = 0;
|
||||||
|
uint16_t maxNbColors = options.nbColorsPerPal * options.nbPalettes;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
std::string line;
|
||||||
|
readLine(file, line);
|
||||||
|
if (!line.length()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.length() != 6
|
||||||
|
|| line.find_first_not_of("0123456789ABCDEFabcdef"sv) != std::string::npos) {
|
||||||
|
error("Failed to parse color #%" PRIu16 " (\"%s\"): invalid \"rrggbb\" line",
|
||||||
|
nbColors + 1, line.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rgba color =
|
||||||
|
Rgba(toHex(line[0], line[1]), toHex(line[2], line[3]), toHex(line[4], line[5]), 0xFF);
|
||||||
|
|
||||||
|
++nbColors;
|
||||||
|
if (nbColors < maxNbColors) {
|
||||||
|
if (nbColors % options.nbColorsPerPal == 1) {
|
||||||
|
options.palSpec.emplace_back();
|
||||||
|
}
|
||||||
|
options.palSpec.back()[nbColors % options.nbColorsPerPal] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbColors > maxNbColors) {
|
||||||
|
warning("HEX file contains %" PRIu16 " colors, but there can only be %" PRIu16
|
||||||
|
"; ignoring extra",
|
||||||
|
nbColors, maxNbColors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseACTFile(std::filebuf &file) {
|
||||||
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1070626
|
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1070626
|
||||||
|
|
||||||
std::array<char, 772> buf;
|
std::array<char, 772> buf;
|
||||||
@@ -344,8 +471,8 @@ void parseACTFile(std::filebuf &file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseACOFile(std::filebuf &file) {
|
static void parseACOFile(std::filebuf &file) {
|
||||||
// rhttps://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1055819
|
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1055819
|
||||||
// http://www.nomodes.com/aco.html
|
// http://www.nomodes.com/aco.html
|
||||||
|
|
||||||
char buf[10];
|
char buf[10];
|
||||||
@@ -412,6 +539,29 @@ void parseACOFile(std::filebuf &file) {
|
|||||||
// `codecvt` can be used to convert from UTF-16 to UTF-8
|
// `codecvt` can be used to convert from UTF-16 to UTF-8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parseGBCFile(std::filebuf &file) {
|
||||||
|
// This only needs to be able to read back files generated by `rgbgfx -p`
|
||||||
|
options.palSpec.clear();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
char buf[2 * 4];
|
||||||
|
auto len = file.sgetn(buf, sizeof(buf));
|
||||||
|
if (len == 0) {
|
||||||
|
break;
|
||||||
|
} else if (len != sizeof(buf)) {
|
||||||
|
error("GBC palette dump contains %zu 8-byte palette%s, plus %zu byte%s",
|
||||||
|
options.palSpec.size(), options.palSpec.size() == 1 ? "" : "s", len,
|
||||||
|
len == 1 ? "" : "s");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.palSpec.push_back({Rgba::fromCGBColor(readLE<uint16_t>(&buf[0])),
|
||||||
|
Rgba::fromCGBColor(readLE<uint16_t>(&buf[2])),
|
||||||
|
Rgba::fromCGBColor(readLE<uint16_t>(&buf[4])),
|
||||||
|
Rgba::fromCGBColor(readLE<uint16_t>(&buf[6]))});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void parseExternalPalSpec(char const *arg) {
|
void parseExternalPalSpec(char const *arg) {
|
||||||
// `fmt:path`, parse the file according to the given format
|
// `fmt:path`, parse the file according to the given format
|
||||||
|
|
||||||
@@ -425,8 +575,11 @@ void parseExternalPalSpec(char const *arg) {
|
|||||||
|
|
||||||
static std::array parsers{
|
static std::array parsers{
|
||||||
std::tuple{"PSP", &parsePSPFile, std::ios::in },
|
std::tuple{"PSP", &parsePSPFile, std::ios::in },
|
||||||
|
std::tuple{"GPL", &parseGPLFile, std::ios::in },
|
||||||
|
std::tuple{"HEX", &parseHEXFile, std::ios::in },
|
||||||
std::tuple{"ACT", &parseACTFile, std::ios::binary},
|
std::tuple{"ACT", &parseACTFile, std::ios::binary},
|
||||||
std::tuple{"ACO", &parseACOFile, std::ios::binary},
|
std::tuple{"ACO", &parseACOFile, std::ios::binary},
|
||||||
|
std::tuple{"GBC", &parseGBCFile, std::ios::binary},
|
||||||
};
|
};
|
||||||
|
|
||||||
auto iter = std::find_if(parsers.begin(), parsers.end(),
|
auto iter = std::find_if(parsers.begin(), parsers.end(),
|
||||||
|
|||||||
@@ -997,7 +997,7 @@ void process() {
|
|||||||
* protoPalettes.erase(protoPalettes.begin() + i);
|
* protoPalettes.erase(protoPalettes.begin() + i);
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
case ProtoPalette::THEY_BIGGER:
|
case ProtoPalette::THEY_BIGGER:
|
||||||
|
|||||||
@@ -154,9 +154,9 @@ FILE *openFile(char const *fileName, char const *mode)
|
|||||||
if (strcmp(fileName, "-") != 0)
|
if (strcmp(fileName, "-") != 0)
|
||||||
file = fopen(fileName, mode);
|
file = fopen(fileName, mode);
|
||||||
else if (mode[0] == 'r')
|
else if (mode[0] == 'r')
|
||||||
file = fdopen(0, mode);
|
file = fdopen(STDIN_FILENO, mode);
|
||||||
else
|
else
|
||||||
file = fdopen(1, mode);
|
file = fdopen(STDOUT_FILENO, mode);
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
err("Could not open file \"%s\"", fileName);
|
err("Could not open file \"%s\"", fileName);
|
||||||
@@ -369,21 +369,31 @@ int main(int argc, char *argv[])
|
|||||||
isWRA0Mode = true;
|
isWRA0Mode = true;
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
|
if (linkerScriptName)
|
||||||
|
warnx("Overriding linkerscript %s", musl_optarg);
|
||||||
linkerScriptName = musl_optarg;
|
linkerScriptName = musl_optarg;
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
noSymInMap = true;
|
noSymInMap = true;
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
|
if (mapFileName)
|
||||||
|
warnx("Overriding mapfile %s", musl_optarg);
|
||||||
mapFileName = musl_optarg;
|
mapFileName = musl_optarg;
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
|
if (symFileName)
|
||||||
|
warnx("Overriding symfile %s", musl_optarg);
|
||||||
symFileName = musl_optarg;
|
symFileName = musl_optarg;
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
|
if (overlayFileName)
|
||||||
|
warnx("Overriding overlay file %s", musl_optarg);
|
||||||
overlayFileName = musl_optarg;
|
overlayFileName = musl_optarg;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
|
if (outputFileName)
|
||||||
|
warnx("Overriding output file %s", musl_optarg);
|
||||||
outputFileName = musl_optarg;
|
outputFileName = musl_optarg;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
|
|||||||
@@ -459,7 +459,12 @@ static struct Section *getMainSection(struct Section *section)
|
|||||||
|
|
||||||
void obj_ReadFile(char const *fileName, unsigned int fileID)
|
void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||||
{
|
{
|
||||||
FILE *file = strcmp("-", fileName) ? fopen(fileName, "rb") : stdin;
|
FILE *file;
|
||||||
|
|
||||||
|
if (strcmp("-", fileName) != 0)
|
||||||
|
file = fopen(fileName, "rb");
|
||||||
|
else
|
||||||
|
file = fdopen(STDIN_FILENO, "rb"); // `stdin` is in text mode by default
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
err("Could not open file %s", fileName);
|
err("Could not open file %s", fileName);
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#include "link/section.h"
|
#include "link/section.h"
|
||||||
#include "link/symbol.h"
|
#include "link/symbol.h"
|
||||||
|
|
||||||
|
#include "extern/utf8decoder.h"
|
||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "linkdefs.h"
|
#include "linkdefs.h"
|
||||||
#include "platform.h" // MIN_NB_ELMS
|
#include "platform.h" // MIN_NB_ELMS
|
||||||
@@ -273,6 +275,55 @@ static struct SortedSection const **nextSection(struct SortedSection const **s1,
|
|||||||
return (*s1)->section->org < (*s2)->section->org ? s1 : s2;
|
return (*s1)->section->org < (*s2)->section->org ? s1 : s2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks whether this character is legal as the first character of a symbol's name in a sym file
|
||||||
|
static bool canStartSymName(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether this character is legal in a symbol's name in a sym file
|
||||||
|
static bool isLegalForSymName(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
||||||
|
c == '_' || c == '@' || c == '#' || c == '$' || c == '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a symbol's name to `symFile`, assuming that the first character is legal.
|
||||||
|
// Illegal characters are UTF-8-decoded (errors are replaced by U+FFFD) and emitted as `\u`/`\U`.
|
||||||
|
static void printSymName(char const *name)
|
||||||
|
{
|
||||||
|
for (char const *ptr = name; *ptr != '\0'; ) {
|
||||||
|
char c = *ptr;
|
||||||
|
|
||||||
|
if (isLegalForSymName(c)) {
|
||||||
|
// Output legal ASCII characters as-is
|
||||||
|
fputc(c, symFile);
|
||||||
|
++ptr;
|
||||||
|
} else {
|
||||||
|
// Output illegal characters using Unicode escapes
|
||||||
|
// Decode the UTF-8 codepoint; or at least attempt to
|
||||||
|
uint32_t state = 0, codepoint;
|
||||||
|
|
||||||
|
do {
|
||||||
|
decode(&state, &codepoint, *ptr);
|
||||||
|
if (state == 1) {
|
||||||
|
// This sequence was invalid; emit a U+FFFD, and recover
|
||||||
|
codepoint = 0xFFFD;
|
||||||
|
// Skip continuation bytes
|
||||||
|
// A NUL byte does not qualify, so we're good
|
||||||
|
while ((*ptr & 0xC0) == 0x80)
|
||||||
|
++ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++ptr;
|
||||||
|
} while (state != 0);
|
||||||
|
|
||||||
|
fprintf(symFile, codepoint <= 0xFFFF ? "\\u%04" PRIx32 : "\\U%08" PRIx32,
|
||||||
|
codepoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Comparator function for `qsort` to sort symbols
|
// Comparator function for `qsort` to sort symbols
|
||||||
// Symbols are ordered by address, or else by original index for a stable sort
|
// Symbols are ordered by address, or else by original index for a stable sort
|
||||||
static int compareSymbols(void const *a, void const *b)
|
static int compareSymbols(void const *a, void const *b)
|
||||||
@@ -296,16 +347,22 @@ static void writeSymBank(struct SortedSections const *bankSections,
|
|||||||
if (!symFile)
|
if (!symFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#define forEachSortedSection(sect, ...) do { \
|
||||||
|
for (struct SortedSection const *ssp = bankSections->zeroLenSections; ssp; ssp = ssp->next) { \
|
||||||
|
for (struct Section const *sect = ssp->section; sect; sect = sect->nextu) \
|
||||||
|
__VA_ARGS__ \
|
||||||
|
} \
|
||||||
|
for (struct SortedSection const *ssp = bankSections->sections; ssp; ssp = ssp->next) { \
|
||||||
|
for (struct Section const *sect = ssp->section; sect; sect = sect->nextu) \
|
||||||
|
__VA_ARGS__ \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
uint32_t nbSymbols = 0;
|
uint32_t nbSymbols = 0;
|
||||||
|
|
||||||
for (struct SortedSection const *ptr = bankSections->zeroLenSections; ptr; ptr = ptr->next) {
|
forEachSortedSection(sect, {
|
||||||
for (struct Section const *sect = ptr->section; sect; sect = sect->nextu)
|
nbSymbols += sect->nbSymbols;
|
||||||
nbSymbols += sect->nbSymbols;
|
});
|
||||||
}
|
|
||||||
for (struct SortedSection const *ptr = bankSections->sections; ptr; ptr = ptr->next) {
|
|
||||||
for (struct Section const *sect = ptr->section; sect; sect = sect->nextu)
|
|
||||||
nbSymbols += sect->nbSymbols;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nbSymbols)
|
if (!nbSymbols)
|
||||||
return;
|
return;
|
||||||
@@ -315,29 +372,21 @@ static void writeSymBank(struct SortedSections const *bankSections,
|
|||||||
if (!symList)
|
if (!symList)
|
||||||
err("Failed to allocate symbol list");
|
err("Failed to allocate symbol list");
|
||||||
|
|
||||||
uint32_t idx = 0;
|
nbSymbols = 0;
|
||||||
|
|
||||||
for (struct SortedSection const *ptr = bankSections->zeroLenSections; ptr; ptr = ptr->next) {
|
forEachSortedSection(sect, {
|
||||||
for (struct Section const *sect = ptr->section; sect; sect = sect->nextu) {
|
for (uint32_t i = 0; i < sect->nbSymbols; i++) {
|
||||||
for (uint32_t i = 0; i < sect->nbSymbols; i++) {
|
if (!canStartSymName(sect->symbols[i]->name[0]))
|
||||||
symList[idx].idx = idx;
|
// Don't output symbols that begin with an illegal character
|
||||||
symList[idx].sym = sect->symbols[i];
|
continue;
|
||||||
symList[idx].addr = symList[idx].sym->offset + sect->org;
|
symList[nbSymbols].idx = nbSymbols;
|
||||||
idx++;
|
symList[nbSymbols].sym = sect->symbols[i];
|
||||||
}
|
symList[nbSymbols].addr = symList[nbSymbols].sym->offset + sect->org;
|
||||||
|
nbSymbols++;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
for (struct SortedSection const *ptr = bankSections->sections; ptr; ptr = ptr->next) {
|
|
||||||
for (struct Section const *sect = ptr->section; sect; sect = sect->nextu) {
|
#undef forEachSortedSection
|
||||||
for (uint32_t i = 0; i < sect->nbSymbols; i++) {
|
|
||||||
symList[idx].idx = idx;
|
|
||||||
symList[idx].sym = sect->symbols[i];
|
|
||||||
symList[idx].addr = symList[idx].sym->offset + sect->org;
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(idx == nbSymbols);
|
|
||||||
|
|
||||||
qsort(symList, nbSymbols, sizeof(*symList), compareSymbols);
|
qsort(symList, nbSymbols, sizeof(*symList), compareSymbols);
|
||||||
|
|
||||||
@@ -346,11 +395,13 @@ static void writeSymBank(struct SortedSections const *bankSections,
|
|||||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||||
struct SortedSymbol *sym = &symList[i];
|
struct SortedSymbol *sym = &symList[i];
|
||||||
|
|
||||||
fprintf(symFile, "%02" PRIx32 ":%04" PRIx16 " %s\n",
|
fprintf(symFile, "%02" PRIx32 ":%04" PRIx16 " ", symBank, sym->addr);
|
||||||
symBank, sym->addr, sym->sym->name);
|
printSymName(sym->sym->name);
|
||||||
|
fputc('\n', symFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(symList);
|
free(symList);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -384,20 +435,20 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
|||||||
if (prevEndAddr < sect->org) {
|
if (prevEndAddr < sect->org) {
|
||||||
uint16_t empty = sect->org - prevEndAddr;
|
uint16_t empty = sect->org - prevEndAddr;
|
||||||
|
|
||||||
fprintf(mapFile, " EMPTY: $%04" PRIx16 " byte%s\n", empty,
|
fprintf(mapFile, "\tEMPTY: $%04" PRIx16 " byte%s\n", empty,
|
||||||
empty == 1 ? "" : "s");
|
empty == 1 ? "" : "s");
|
||||||
}
|
}
|
||||||
|
|
||||||
prevEndAddr = sect->org + sect->size;
|
prevEndAddr = sect->org + sect->size;
|
||||||
|
|
||||||
if (sect->size != 0)
|
if (sect->size != 0)
|
||||||
fprintf(mapFile, " SECTION: $%04" PRIx16 "-$%04x ($%04" PRIx16
|
fprintf(mapFile, "\tSECTION: $%04" PRIx16 "-$%04x ($%04" PRIx16
|
||||||
" byte%s) [\"%s\"]\n",
|
" byte%s) [\"%s\"]\n",
|
||||||
sect->org, prevEndAddr - 1,
|
sect->org, prevEndAddr - 1,
|
||||||
sect->size, sect->size == 1 ? "" : "s",
|
sect->size, sect->size == 1 ? "" : "s",
|
||||||
sect->name);
|
sect->name);
|
||||||
else
|
else
|
||||||
fprintf(mapFile, " SECTION: $%04" PRIx16 " (0 bytes) [\"%s\"]\n",
|
fprintf(mapFile, "\tSECTION: $%04" PRIx16 " (0 bytes) [\"%s\"]\n",
|
||||||
sect->org, sect->name);
|
sect->org, sect->name);
|
||||||
|
|
||||||
if (!noSymInMap) {
|
if (!noSymInMap) {
|
||||||
@@ -405,11 +456,12 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
|||||||
|
|
||||||
while (sect) {
|
while (sect) {
|
||||||
if (sect->modifier == SECTION_UNION)
|
if (sect->modifier == SECTION_UNION)
|
||||||
fprintf(mapFile, " ; New union\n");
|
fprintf(mapFile, "\t\t; New union\n");
|
||||||
else if (sect->modifier == SECTION_FRAGMENT)
|
else if (sect->modifier == SECTION_FRAGMENT)
|
||||||
fprintf(mapFile, " ; New fragment\n");
|
fprintf(mapFile, "\t\t; New fragment\n");
|
||||||
for (size_t i = 0; i < sect->nbSymbols; i++)
|
for (size_t i = 0; i < sect->nbSymbols; i++)
|
||||||
fprintf(mapFile, " $%04" PRIx32 " = %s\n",
|
// "\tSECTION: $xxxx ..."
|
||||||
|
fprintf(mapFile, "\t $%04" PRIx32 " = %s\n",
|
||||||
sect->symbols[i]->offset + org,
|
sect->symbols[i]->offset + org,
|
||||||
sect->symbols[i]->name);
|
sect->symbols[i]->name);
|
||||||
|
|
||||||
@@ -425,7 +477,7 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
|||||||
if (prevEndAddr < bankEndAddr) {
|
if (prevEndAddr < bankEndAddr) {
|
||||||
uint16_t empty = bankEndAddr - prevEndAddr;
|
uint16_t empty = bankEndAddr - prevEndAddr;
|
||||||
|
|
||||||
fprintf(mapFile, " EMPTY: $%04" PRIx16 " byte%s\n", empty,
|
fprintf(mapFile, "\tEMPTY: $%04" PRIx16 " byte%s\n", empty,
|
||||||
empty == 1 ? "" : "s");
|
empty == 1 ? "" : "s");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,7 +486,7 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
|||||||
} else {
|
} else {
|
||||||
uint16_t slack = sectionTypeInfo[type].size - used;
|
uint16_t slack = sectionTypeInfo[type].size - used;
|
||||||
|
|
||||||
fprintf(mapFile, " SLACK: $%04" PRIx16 " byte%s\n\n", slack,
|
fprintf(mapFile, "\tSLACK: $%04" PRIx16 " byte%s\n\n", slack,
|
||||||
slack == 1 ? "" : "s");
|
slack == 1 ? "" : "s");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,15 +494,15 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write the total used space by section type to the map file
|
* Write the total used and free space by section type to the map file
|
||||||
* @param usedMap The total used space by section type
|
* @param usedMap The total used space by section type
|
||||||
*/
|
*/
|
||||||
static void writeMapUsed(uint32_t usedMap[MIN_NB_ELMS(SECTTYPE_INVALID)])
|
static void writeMapSummary(uint32_t usedMap[MIN_NB_ELMS(SECTTYPE_INVALID)])
|
||||||
{
|
{
|
||||||
if (!mapFile)
|
if (!mapFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fputs("USED:\n", mapFile);
|
fputs("SUMMARY:\n", mapFile);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < SECTTYPE_INVALID; i++) {
|
for (uint8_t i = 0; i < SECTTYPE_INVALID; i++) {
|
||||||
enum SectionType type = typeMap[i];
|
enum SectionType type = typeMap[i];
|
||||||
@@ -459,11 +511,18 @@ static void writeMapUsed(uint32_t usedMap[MIN_NB_ELMS(SECTTYPE_INVALID)])
|
|||||||
if (type == SECTTYPE_VRAM || type == SECTTYPE_OAM)
|
if (type == SECTTYPE_VRAM || type == SECTTYPE_OAM)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sections[type].nbBanks > 0) {
|
// Do not output unused section types
|
||||||
fprintf(mapFile, " %s: $%04" PRIx32 " byte%s in %" PRIu32 " bank%s\n",
|
if (sections[type].nbBanks == 0)
|
||||||
sectionTypeInfo[type].name, usedMap[type], usedMap[type] == 1 ? "" : "s",
|
continue;
|
||||||
sections[type].nbBanks, sections[type].nbBanks == 1 ? "" : "s");
|
|
||||||
}
|
fprintf(mapFile, "\t%s: %" PRId32 " byte%s used / %" PRId32 " free",
|
||||||
|
sectionTypeInfo[type].name, usedMap[type], usedMap[type] == 1 ? "" : "s",
|
||||||
|
sections[type].nbBanks * sectionTypeInfo[type].size - usedMap[type]);
|
||||||
|
if (sectionTypeInfo[type].firstBank != sectionTypeInfo[type].lastBank ||
|
||||||
|
sections[type].nbBanks > 1)
|
||||||
|
fprintf(mapFile, " in %d bank%s", sections[type].nbBanks,
|
||||||
|
sections[type].nbBanks == 1 ? "" : "s");
|
||||||
|
fputc('\n', mapFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,7 +551,7 @@ static void writeSymAndMap(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeMapUsed(usedMap);
|
writeMapSummary(usedMap);
|
||||||
|
|
||||||
closeFile(symFile);
|
closeFile(symFile);
|
||||||
closeFile(mapFile);
|
closeFile(mapFile);
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
isError = false;
|
isError = false;
|
||||||
|
|
||||||
// Be VERY careful with two `popRPN` in the same expression.
|
// Be VERY careful with two `popRPN` in the same expression.
|
||||||
// C does not guarantee order of evaluation of operands!!
|
// C does not guarantee order of evaluation of operands!
|
||||||
// So, if there are two `popRPN` in the same expression, make
|
// So, if there are two `popRPN` in the same expression, make
|
||||||
// sure the operation is commutative.
|
// sure the operation is commutative.
|
||||||
switch (command) {
|
switch (command) {
|
||||||
|
|||||||
@@ -39,5 +39,6 @@ PRINTLN \1
|
|||||||
endm
|
endm
|
||||||
|
|
||||||
; Representative numeric and string builtins
|
; Representative numeric and string builtins
|
||||||
tickle __LINE__, 1
|
; (SOURCE_DATE_EPOCH in test.sh makes this reproducible)
|
||||||
tickle __FILE__, 0
|
tickle __UTC_YEAR__, 1
|
||||||
|
tickle __ISO_8601_UTC__, 0
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(7):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(7):
|
||||||
'__LINE__' already defined as constant at <builtin>
|
'__UTC_YEAR__' already defined as constant at <command-line>
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(8):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(8):
|
||||||
'__LINE__' already defined as constant at <builtin>
|
'__UTC_YEAR__' already defined as constant at <command-line>
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(11):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(11):
|
||||||
'__LINE__' already defined at <builtin>
|
'__UTC_YEAR__' already defined at <command-line>
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(12):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(12):
|
||||||
'__LINE__' already defined at <builtin>
|
'__UTC_YEAR__' already defined at <command-line>
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(16):
|
|
||||||
Built-in symbol '__LINE__' cannot be purged
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(17):
|
|
||||||
Built-in symbol '__LINE__' cannot be purged
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(20):
|
|
||||||
'__LINE__' already defined at <builtin>
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(21):
|
|
||||||
'__LINE__' already defined at <builtin>
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(24):
|
|
||||||
'__LINE__' already defined as constant at <builtin>
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(25):
|
|
||||||
'__LINE__' already defined as constant at <builtin>
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(28):
|
|
||||||
'__LINE__' already defined at <builtin>
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(29):
|
|
||||||
'__LINE__' already defined at <builtin>
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(32):
|
|
||||||
'__LINE__' already defined as constant at <builtin>
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(33):
|
|
||||||
'__LINE__' already defined as constant at <builtin>
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(36):
|
|
||||||
'__LINE__' already defined as non-EQUS at <builtin>
|
|
||||||
error: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(37):
|
|
||||||
'__LINE__' already defined as non-EQUS at <builtin>
|
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(16):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(16):
|
||||||
Built-in symbol '__FILE__' cannot be purged
|
Built-in symbol '__UTC_YEAR__' cannot be purged
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(17):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(17):
|
||||||
Built-in symbol '__FILE__' cannot be purged
|
Built-in symbol '__UTC_YEAR__' cannot be purged
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(20):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(20):
|
||||||
'__FILE__' already defined at <builtin>
|
'__UTC_YEAR__' already defined at <command-line>
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(21):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(21):
|
||||||
'__FILE__' already defined at <builtin>
|
'__UTC_YEAR__' already defined at <command-line>
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(24):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(24):
|
||||||
'__FILE__' already defined as constant at <builtin>
|
'__UTC_YEAR__' already defined as constant at <command-line>
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(25):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(25):
|
||||||
'__FILE__' already defined as constant at <builtin>
|
'__UTC_YEAR__' already defined as constant at <command-line>
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(28):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(28):
|
||||||
'__FILE__' already defined at <builtin>
|
'__UTC_YEAR__' already defined at <command-line>
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(29):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(29):
|
||||||
'__FILE__' already defined at <builtin>
|
'__UTC_YEAR__' already defined at <command-line>
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(32):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(32):
|
||||||
'__FILE__' already defined as constant at <builtin>
|
'__UTC_YEAR__' already defined as constant at <command-line>
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(33):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(33):
|
||||||
'__FILE__' already defined as constant at <builtin>
|
'__UTC_YEAR__' already defined as constant at <command-line>
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(36):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(36):
|
||||||
Built-in symbol '__FILE__' cannot be redefined
|
'__UTC_YEAR__' already defined as non-EQUS at <command-line>
|
||||||
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(37):
|
error: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(37):
|
||||||
Built-in symbol '__FILE__' cannot be redefined
|
'__UTC_YEAR__' already defined as non-EQUS at <command-line>
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(16):
|
||||||
|
Built-in symbol '__ISO_8601_UTC__' cannot be purged
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(17):
|
||||||
|
Built-in symbol '__ISO_8601_UTC__' cannot be purged
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(20):
|
||||||
|
'__ISO_8601_UTC__' already defined at <command-line>
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(21):
|
||||||
|
'__ISO_8601_UTC__' already defined at <command-line>
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(24):
|
||||||
|
'__ISO_8601_UTC__' already defined as constant at <command-line>
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(25):
|
||||||
|
'__ISO_8601_UTC__' already defined as constant at <command-line>
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(28):
|
||||||
|
'__ISO_8601_UTC__' already defined at <command-line>
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(29):
|
||||||
|
'__ISO_8601_UTC__' already defined at <command-line>
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(32):
|
||||||
|
'__ISO_8601_UTC__' already defined as constant at <command-line>
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(33):
|
||||||
|
'__ISO_8601_UTC__' already defined as constant at <command-line>
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(36):
|
||||||
|
Built-in symbol '__ISO_8601_UTC__' cannot be redefined
|
||||||
|
error: builtin-overwrite.asm(44) -> builtin-overwrite.asm::tickle(37):
|
||||||
|
Built-in symbol '__ISO_8601_UTC__' cannot be redefined
|
||||||
error: Assembly aborted (28 errors)!
|
error: Assembly aborted (28 errors)!
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
$9
|
$7C5
|
||||||
$D
|
$7C5
|
||||||
$12
|
$7C5
|
||||||
$16
|
$7C5
|
||||||
$1A
|
$7C5
|
||||||
$1E
|
$7C5
|
||||||
$22
|
$7C5
|
||||||
$26
|
$7C5
|
||||||
builtin-overwrite.asm
|
1989-04-21T12:34:56Z
|
||||||
builtin-overwrite.asm
|
1989-04-21T12:34:56Z
|
||||||
builtin-overwrite.asm
|
1989-04-21T12:34:56Z
|
||||||
builtin-overwrite.asm
|
1989-04-21T12:34:56Z
|
||||||
builtin-overwrite.asm
|
1989-04-21T12:34:56Z
|
||||||
builtin-overwrite.asm
|
1989-04-21T12:34:56Z
|
||||||
|
|||||||
@@ -33,8 +33,5 @@ endm
|
|||||||
_RS += 100
|
_RS += 100
|
||||||
println _RS
|
println _RS
|
||||||
|
|
||||||
__LINE__ *= 200
|
|
||||||
println __LINE__
|
|
||||||
|
|
||||||
UnDeFiNeD ^= 300
|
UnDeFiNeD ^= 300
|
||||||
println UnDeFiNeD
|
println UnDeFiNeD
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
error: compound-assignment.asm(36):
|
error: compound-assignment.asm(36):
|
||||||
'__LINE__' already defined as constant at <builtin>
|
|
||||||
error: compound-assignment.asm(39):
|
|
||||||
Expected constant expression: 'UnDeFiNeD' is not constant at assembly time
|
Expected constant expression: 'UnDeFiNeD' is not constant at assembly time
|
||||||
error: Assembly aborted (2 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -35,5 +35,4 @@ $5
|
|||||||
$14
|
$14
|
||||||
$A
|
$A
|
||||||
$64
|
$64
|
||||||
$25
|
|
||||||
$0
|
$0
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
warning: file-sym.asm(1): [-Wobsolete]
|
||||||
|
`__FILE__` is deprecated
|
||||||
|
|||||||
19
test/asm/fixed-point-magnitude.asm
Normal file
19
test/asm/fixed-point-magnitude.asm
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
for precision, 1, 32
|
||||||
|
opt Q{d:precision}
|
||||||
|
def magnitude = 32 - precision
|
||||||
|
|
||||||
|
def maxInt = 1 << magnitude - 1
|
||||||
|
redef defMaxValue equs "def maxValue = {d:maxInt}.0"
|
||||||
|
{defMaxValue}
|
||||||
|
println "Q.{2d:precision}: max ok = 1 << {2d:magnitude} - 1 = {11d:maxInt}.0 = {#09x:maxValue}"
|
||||||
|
|
||||||
|
def minBadInt = maxInt + 1
|
||||||
|
redef defMinBadValue equs "def minBadValue = {d:minBadInt}.0"
|
||||||
|
{defMinBadValue}
|
||||||
|
println "Q.{2d:precision}: min bad = 1 << {2d:magnitude} = {11d:minBadInt}.0 = {#09x:minBadValue}"
|
||||||
|
|
||||||
|
def worseInt = minBadInt + 42
|
||||||
|
redef defWorseValue equs "def worseValue = {d:worseInt}.0"
|
||||||
|
{defWorseValue}
|
||||||
|
println "Q.{2d:precision}: worse = 1 << {2d:magnitude} + 42 = {11d:worseInt}.0 = {#09x:worseValue}"
|
||||||
|
endr
|
||||||
183
test/asm/fixed-point-magnitude.err
Normal file
183
test/asm/fixed-point-magnitude.err
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~1(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = -2147483648.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~2(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 1073741824.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~2(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 1073741866.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~3(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 536870912.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~3(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 536870954.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~4(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 268435456.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~4(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 268435498.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~5(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 134217728.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~5(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 134217770.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~6(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 67108864.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~6(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 67108906.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~7(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 33554432.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~7(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 33554474.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~8(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 16777216.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~8(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 16777258.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~9(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 8388608.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~9(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 8388650.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~10(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 4194304.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~10(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 4194346.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~11(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 2097152.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~11(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 2097194.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~12(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 1048576.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~12(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 1048618.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~13(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 524288.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~13(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 524330.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~14(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 262144.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~14(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 262186.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~15(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 131072.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~15(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 131114.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~16(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 65536.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~16(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 65578.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~17(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 32768.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~17(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 32810.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~18(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 16384.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~18(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 16426.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~19(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 8192.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~19(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 8234.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~20(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 4096.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~20(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 4138.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~21(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 2048.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~21(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 2090.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~22(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 1024.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~22(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 1066.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~23(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 512.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~23(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 554.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~24(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 256.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~24(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 298.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~25(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 128.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~25(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 170.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~26(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 64.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~26(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 106.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~27(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 32.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~27(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 74.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~28(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 16.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~28(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 58.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~29(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 8.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~29(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 50.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~30(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 4.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~30(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 46.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~31(12): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def minBadValue = 2.0"
|
||||||
|
warning: fixed-point-magnitude.asm(1) -> fixed-point-magnitude.asm::REPT~31(17): [-Wlarge-constant]
|
||||||
|
Magnitude of fixed-point constant is too large
|
||||||
|
while expanding symbol "def worseValue = 44.0"
|
||||||
93
test/asm/fixed-point-magnitude.out
Normal file
93
test/asm/fixed-point-magnitude.out
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
Q. 1: max ok = 1 << 31 - 1 = 2147483647.0 = $fffffffe
|
||||||
|
Q. 1: min bad = 1 << 31 = -2147483648.0 = $00000000
|
||||||
|
Q. 1: worse = 1 << 31 + 42 = -2147483606.0 = $00000054
|
||||||
|
Q. 2: max ok = 1 << 30 - 1 = 1073741823.0 = $fffffffc
|
||||||
|
Q. 2: min bad = 1 << 30 = 1073741824.0 = $00000000
|
||||||
|
Q. 2: worse = 1 << 30 + 42 = 1073741866.0 = $000000a8
|
||||||
|
Q. 3: max ok = 1 << 29 - 1 = 536870911.0 = $fffffff8
|
||||||
|
Q. 3: min bad = 1 << 29 = 536870912.0 = $00000000
|
||||||
|
Q. 3: worse = 1 << 29 + 42 = 536870954.0 = $00000150
|
||||||
|
Q. 4: max ok = 1 << 28 - 1 = 268435455.0 = $fffffff0
|
||||||
|
Q. 4: min bad = 1 << 28 = 268435456.0 = $00000000
|
||||||
|
Q. 4: worse = 1 << 28 + 42 = 268435498.0 = $000002a0
|
||||||
|
Q. 5: max ok = 1 << 27 - 1 = 134217727.0 = $ffffffe0
|
||||||
|
Q. 5: min bad = 1 << 27 = 134217728.0 = $00000000
|
||||||
|
Q. 5: worse = 1 << 27 + 42 = 134217770.0 = $00000540
|
||||||
|
Q. 6: max ok = 1 << 26 - 1 = 67108863.0 = $ffffffc0
|
||||||
|
Q. 6: min bad = 1 << 26 = 67108864.0 = $00000000
|
||||||
|
Q. 6: worse = 1 << 26 + 42 = 67108906.0 = $00000a80
|
||||||
|
Q. 7: max ok = 1 << 25 - 1 = 33554431.0 = $ffffff80
|
||||||
|
Q. 7: min bad = 1 << 25 = 33554432.0 = $00000000
|
||||||
|
Q. 7: worse = 1 << 25 + 42 = 33554474.0 = $00001500
|
||||||
|
Q. 8: max ok = 1 << 24 - 1 = 16777215.0 = $ffffff00
|
||||||
|
Q. 8: min bad = 1 << 24 = 16777216.0 = $00000000
|
||||||
|
Q. 8: worse = 1 << 24 + 42 = 16777258.0 = $00002a00
|
||||||
|
Q. 9: max ok = 1 << 23 - 1 = 8388607.0 = $fffffe00
|
||||||
|
Q. 9: min bad = 1 << 23 = 8388608.0 = $00000000
|
||||||
|
Q. 9: worse = 1 << 23 + 42 = 8388650.0 = $00005400
|
||||||
|
Q.10: max ok = 1 << 22 - 1 = 4194303.0 = $fffffc00
|
||||||
|
Q.10: min bad = 1 << 22 = 4194304.0 = $00000000
|
||||||
|
Q.10: worse = 1 << 22 + 42 = 4194346.0 = $0000a800
|
||||||
|
Q.11: max ok = 1 << 21 - 1 = 2097151.0 = $fffff800
|
||||||
|
Q.11: min bad = 1 << 21 = 2097152.0 = $00000000
|
||||||
|
Q.11: worse = 1 << 21 + 42 = 2097194.0 = $00015000
|
||||||
|
Q.12: max ok = 1 << 20 - 1 = 1048575.0 = $fffff000
|
||||||
|
Q.12: min bad = 1 << 20 = 1048576.0 = $00000000
|
||||||
|
Q.12: worse = 1 << 20 + 42 = 1048618.0 = $0002a000
|
||||||
|
Q.13: max ok = 1 << 19 - 1 = 524287.0 = $ffffe000
|
||||||
|
Q.13: min bad = 1 << 19 = 524288.0 = $00000000
|
||||||
|
Q.13: worse = 1 << 19 + 42 = 524330.0 = $00054000
|
||||||
|
Q.14: max ok = 1 << 18 - 1 = 262143.0 = $ffffc000
|
||||||
|
Q.14: min bad = 1 << 18 = 262144.0 = $00000000
|
||||||
|
Q.14: worse = 1 << 18 + 42 = 262186.0 = $000a8000
|
||||||
|
Q.15: max ok = 1 << 17 - 1 = 131071.0 = $ffff8000
|
||||||
|
Q.15: min bad = 1 << 17 = 131072.0 = $00000000
|
||||||
|
Q.15: worse = 1 << 17 + 42 = 131114.0 = $00150000
|
||||||
|
Q.16: max ok = 1 << 16 - 1 = 65535.0 = $ffff0000
|
||||||
|
Q.16: min bad = 1 << 16 = 65536.0 = $00000000
|
||||||
|
Q.16: worse = 1 << 16 + 42 = 65578.0 = $002a0000
|
||||||
|
Q.17: max ok = 1 << 15 - 1 = 32767.0 = $fffe0000
|
||||||
|
Q.17: min bad = 1 << 15 = 32768.0 = $00000000
|
||||||
|
Q.17: worse = 1 << 15 + 42 = 32810.0 = $00540000
|
||||||
|
Q.18: max ok = 1 << 14 - 1 = 16383.0 = $fffc0000
|
||||||
|
Q.18: min bad = 1 << 14 = 16384.0 = $00000000
|
||||||
|
Q.18: worse = 1 << 14 + 42 = 16426.0 = $00a80000
|
||||||
|
Q.19: max ok = 1 << 13 - 1 = 8191.0 = $fff80000
|
||||||
|
Q.19: min bad = 1 << 13 = 8192.0 = $00000000
|
||||||
|
Q.19: worse = 1 << 13 + 42 = 8234.0 = $01500000
|
||||||
|
Q.20: max ok = 1 << 12 - 1 = 4095.0 = $fff00000
|
||||||
|
Q.20: min bad = 1 << 12 = 4096.0 = $00000000
|
||||||
|
Q.20: worse = 1 << 12 + 42 = 4138.0 = $02a00000
|
||||||
|
Q.21: max ok = 1 << 11 - 1 = 2047.0 = $ffe00000
|
||||||
|
Q.21: min bad = 1 << 11 = 2048.0 = $00000000
|
||||||
|
Q.21: worse = 1 << 11 + 42 = 2090.0 = $05400000
|
||||||
|
Q.22: max ok = 1 << 10 - 1 = 1023.0 = $ffc00000
|
||||||
|
Q.22: min bad = 1 << 10 = 1024.0 = $00000000
|
||||||
|
Q.22: worse = 1 << 10 + 42 = 1066.0 = $0a800000
|
||||||
|
Q.23: max ok = 1 << 9 - 1 = 511.0 = $ff800000
|
||||||
|
Q.23: min bad = 1 << 9 = 512.0 = $00000000
|
||||||
|
Q.23: worse = 1 << 9 + 42 = 554.0 = $15000000
|
||||||
|
Q.24: max ok = 1 << 8 - 1 = 255.0 = $ff000000
|
||||||
|
Q.24: min bad = 1 << 8 = 256.0 = $00000000
|
||||||
|
Q.24: worse = 1 << 8 + 42 = 298.0 = $2a000000
|
||||||
|
Q.25: max ok = 1 << 7 - 1 = 127.0 = $fe000000
|
||||||
|
Q.25: min bad = 1 << 7 = 128.0 = $00000000
|
||||||
|
Q.25: worse = 1 << 7 + 42 = 170.0 = $54000000
|
||||||
|
Q.26: max ok = 1 << 6 - 1 = 63.0 = $fc000000
|
||||||
|
Q.26: min bad = 1 << 6 = 64.0 = $00000000
|
||||||
|
Q.26: worse = 1 << 6 + 42 = 106.0 = $a8000000
|
||||||
|
Q.27: max ok = 1 << 5 - 1 = 31.0 = $f8000000
|
||||||
|
Q.27: min bad = 1 << 5 = 32.0 = $00000000
|
||||||
|
Q.27: worse = 1 << 5 + 42 = 74.0 = $50000000
|
||||||
|
Q.28: max ok = 1 << 4 - 1 = 15.0 = $f0000000
|
||||||
|
Q.28: min bad = 1 << 4 = 16.0 = $00000000
|
||||||
|
Q.28: worse = 1 << 4 + 42 = 58.0 = $a0000000
|
||||||
|
Q.29: max ok = 1 << 3 - 1 = 7.0 = $e0000000
|
||||||
|
Q.29: min bad = 1 << 3 = 8.0 = $00000000
|
||||||
|
Q.29: worse = 1 << 3 + 42 = 50.0 = $40000000
|
||||||
|
Q.30: max ok = 1 << 2 - 1 = 3.0 = $c0000000
|
||||||
|
Q.30: min bad = 1 << 2 = 4.0 = $00000000
|
||||||
|
Q.30: worse = 1 << 2 + 42 = 46.0 = $80000000
|
||||||
|
Q.31: max ok = 1 << 1 - 1 = 1.0 = $80000000
|
||||||
|
Q.31: min bad = 1 << 1 = 2.0 = $00000000
|
||||||
|
Q.31: worse = 1 << 1 + 42 = 44.0 = $00000000
|
||||||
27
test/asm/fixed-point-specific.asm
Normal file
27
test/asm/fixed-point-specific.asm
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
MACRO compare
|
||||||
|
print "\3: "
|
||||||
|
if _NARG == 4
|
||||||
|
def v1 = \3(\4q\1, \1)
|
||||||
|
def v2 = \3(\4q\2, \2)
|
||||||
|
elif _NARG == 5
|
||||||
|
def v1 = \3(\4q\1, \5q\1, \1)
|
||||||
|
def v2 = \3(\4q\2, \5q\2, \2)
|
||||||
|
endc
|
||||||
|
opt Q\1
|
||||||
|
print "{.4f:v1} == "
|
||||||
|
opt Q\2
|
||||||
|
println "{.4f:v2}"
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
compare 8, 16, mul, 6.0, 7.0
|
||||||
|
compare 12, 24, div, 115.625, 9.25
|
||||||
|
compare 7, 14, pow, 3.5, 5.5
|
||||||
|
|
||||||
|
compare 4, 8, sin, 0.25
|
||||||
|
compare 5, 9, cos, 0.75
|
||||||
|
compare 6, 10, asin, 1.0
|
||||||
|
compare 7, 11, acos, 0.0
|
||||||
|
|
||||||
|
compare 3, 6, round, 1.75
|
||||||
|
compare 10, 20, ceil, 123.4
|
||||||
|
compare 13, 17, floor, 567.8
|
||||||
10
test/asm/fixed-point-specific.out
Normal file
10
test/asm/fixed-point-specific.out
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
mul: 42.0000 == 42.0000
|
||||||
|
div: 12.5000 == 12.5000
|
||||||
|
pow: 982.5938 == 982.5943
|
||||||
|
sin: 1.0000 == 1.0000
|
||||||
|
cos: 0.0000 == 0.0000
|
||||||
|
asin: 0.2500 == 0.2500
|
||||||
|
acos: 0.2500 == 0.2500
|
||||||
|
round: 2.0000 == 2.0000
|
||||||
|
ceil: 124.0000 == 124.0000
|
||||||
|
floor: 567.0000 == 567.0000
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
if "{@}"
|
|
||||||
endc
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
error: if@-no-sect.asm(1):
|
|
||||||
PC has no value outside a section
|
|
||||||
warning: if@-no-sect.asm(1): [-Wnumeric-string]
|
|
||||||
Treating 2-character string as a number
|
|
||||||
error: Assembly aborted (1 error)!
|
|
||||||
2
test/asm/long-section-name.asm
Normal file
2
test/asm/long-section-name.asm
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
SECTION "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit", ROM0[0]
|
||||||
|
println "This is section ", SECTION(@)
|
||||||
2
test/asm/long-section-name.err
Normal file
2
test/asm/long-section-name.err
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
warning: long-section-name.asm(1): [-Wlong-string]
|
||||||
|
String constant too long
|
||||||
1
test/asm/long-section-name.out
Normal file
1
test/asm/long-section-name.out
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This is section Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor i
|
||||||
@@ -1 +0,0 @@
|
|||||||
PRINTLN "{_NARG}"
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
error: narg-nosect.asm(1):
|
|
||||||
_NARG does not make sense outside of a macro
|
|
||||||
error: Assembly aborted (1 error)!
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
$0
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
warning: opt-Q.asm(10) -> opt-Q.asm::REPT~1(12) -> opt-Q.asm::test(5): [-Wlarge-constant]
|
|
||||||
Magnitude of fixed-point constant is too large
|
|
||||||
error: opt-Q.asm(17) -> opt-Q.asm::test(3):
|
error: opt-Q.asm(17) -> opt-Q.asm::test(3):
|
||||||
Argument for option 'Q' must be between 1 and 31
|
Argument for option 'Q' must be between 1 and 31
|
||||||
error: opt-Q.asm(18) -> opt-Q.asm::test(3):
|
error: opt-Q.asm(18) -> opt-Q.asm::test(3):
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
|
PRINTLN %Oo_Oo_Oo
|
||||||
|
|
||||||
OPT b.X
|
OPT b.X
|
||||||
PRINTLN %..X.X.X.
|
PRINTLN %..X._X.X.
|
||||||
|
|||||||
1
test/asm/opt-b.flags
Normal file
1
test/asm/opt-b.flags
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-Weverything -b oO
|
||||||
@@ -1 +1,2 @@
|
|||||||
$2A
|
$2A
|
||||||
|
$2A
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
|
PRINTLN `pqpq_rsrs
|
||||||
|
|
||||||
OPT g.x0X
|
OPT g.x0X
|
||||||
PRINTLN `.x.x0X0X
|
PRINTLN `.x.x_0X0X
|
||||||
|
|||||||
1
test/asm/opt-g.flags
Normal file
1
test/asm/opt-g.flags
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-Weverything -g pqrs
|
||||||
@@ -1 +1,2 @@
|
|||||||
$F55
|
$F55
|
||||||
|
$F55
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
IF DEF(@)
|
|
||||||
PRINTLN "defined"
|
|
||||||
ELSE
|
|
||||||
PRINTLN "not defined"
|
|
||||||
ENDC
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
defined
|
|
||||||
3
test/asm/preinclude.asm
Normal file
3
test/asm/preinclude.asm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
warn "main file"
|
||||||
|
def v3 = v1 + v2
|
||||||
|
println "{d:v1} + {d:v2} = {d:v3}"
|
||||||
4
test/asm/preinclude.err
Normal file
4
test/asm/preinclude.err
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
warning: preinclude.asm(0) -> preinclude.inc(1): [-Wuser]
|
||||||
|
pre-included file
|
||||||
|
warning: preinclude.asm(1): [-Wuser]
|
||||||
|
main file
|
||||||
1
test/asm/preinclude.flags
Normal file
1
test/asm/preinclude.flags
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-Weverything -P preinclude.inc
|
||||||
11
test/asm/preinclude.inc
Normal file
11
test/asm/preinclude.inc
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
warn "pre-included file"
|
||||||
|
|
||||||
|
def v1 = 12
|
||||||
|
rept 3
|
||||||
|
println "rept 3"
|
||||||
|
endr
|
||||||
|
|
||||||
|
def v2 = 34
|
||||||
|
for i, 3
|
||||||
|
println "for {d:i}/3"
|
||||||
|
endr
|
||||||
7
test/asm/preinclude.out
Normal file
7
test/asm/preinclude.out
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
rept 3
|
||||||
|
rept 3
|
||||||
|
rept 3
|
||||||
|
for 0/3
|
||||||
|
for 1/3
|
||||||
|
for 2/3
|
||||||
|
12 + 34 = 46
|
||||||
7
test/asm/section-name-invalid.asm
Normal file
7
test/asm/section-name-invalid.asm
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
SECTION "test", ROM0
|
||||||
|
|
||||||
|
Label:
|
||||||
|
println SECTION(Label) ; OK
|
||||||
|
|
||||||
|
DEF Value EQU 42
|
||||||
|
println SECTION(Value) ; not OK
|
||||||
2
test/asm/section-name-invalid.err
Normal file
2
test/asm/section-name-invalid.err
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
FATAL: section-name-invalid.asm(7):
|
||||||
|
"Value" does not belong to any section
|
||||||
1
test/asm/section-name-invalid.out
Normal file
1
test/asm/section-name-invalid.out
Normal file
@@ -0,0 +1 @@
|
|||||||
|
test
|
||||||
19
test/asm/section-name.asm
Normal file
19
test/asm/section-name.asm
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
SECTION "aaa", ROM0[5]
|
||||||
|
println SECTION(@)
|
||||||
|
Label1: println SECTION(Label1)
|
||||||
|
dw STARTOF(SECTION(@))
|
||||||
|
|
||||||
|
SECTION UNION "bbb", WRAM0
|
||||||
|
println SECTION(@)
|
||||||
|
Label2:
|
||||||
|
.local1: println SECTION(Label2.local1)
|
||||||
|
.local2: println SECTION(.local2)
|
||||||
|
|
||||||
|
SECTION FRAGMENT "ccc", HRAM
|
||||||
|
println SECTION(@)
|
||||||
|
: println SECTION(:-)
|
||||||
|
|
||||||
|
PUSHS
|
||||||
|
SECTION "ddd", ROMX
|
||||||
|
println SECTION(@)
|
||||||
|
POPS
|
||||||
0
test/asm/section-name.err
Normal file
0
test/asm/section-name.err
Normal file
8
test/asm/section-name.out
Normal file
8
test/asm/section-name.out
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
aaa
|
||||||
|
aaa
|
||||||
|
bbb
|
||||||
|
bbb
|
||||||
|
bbb
|
||||||
|
ccc
|
||||||
|
ccc
|
||||||
|
ddd
|
||||||
BIN
test/asm/section-name.out.bin
Normal file
BIN
test/asm/section-name.out.bin
Normal file
Binary file not shown.
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
export LC_ALL=C
|
export LC_ALL=C
|
||||||
|
|
||||||
|
# Game Boy release date, 1989-04-21T12:34:56Z (for reproducible test results)
|
||||||
|
export SOURCE_DATE_EPOCH=609165296
|
||||||
|
|
||||||
o="$(mktemp)"
|
o="$(mktemp)"
|
||||||
gb="$(mktemp)"
|
gb="$(mktemp)"
|
||||||
input="$(mktemp)"
|
input="$(mktemp)"
|
||||||
@@ -52,20 +55,6 @@ else
|
|||||||
rm -f version.asm
|
rm -f version.asm
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add the quote test, except on Windows
|
|
||||||
if uname | grep -viq mingw; then
|
|
||||||
cat > quote\"file.asm <<EOF
|
|
||||||
WARN __FILE__
|
|
||||||
EOF
|
|
||||||
cat > quote\"file.out <<EOF
|
|
||||||
EOF
|
|
||||||
cat > quote\"file.err <<EOF
|
|
||||||
warning: quote"file.asm(1): [-Wuser]
|
|
||||||
quote"file.asm
|
|
||||||
while expanding symbol "__FILE__"
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check whether to use '.simple.err' files if they exist
|
# Check whether to use '.simple.err' files if they exist
|
||||||
# (rgbasm with pre-3.0 Bison just reports "syntax error")
|
# (rgbasm with pre-3.0 Bison just reports "syntax error")
|
||||||
$RGBASM -Weverything -o $o syntax-error.asm > $output 2> $errput
|
$RGBASM -Weverything -o $o syntax-error.asm > $output 2> $errput
|
||||||
@@ -76,6 +65,11 @@ if ! diff --strip-trailing-cr syntax-error.err $errput; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
for i in *.asm; do
|
for i in *.asm; do
|
||||||
|
flags=${i%.asm}.flags
|
||||||
|
RGBASMFLAGS=-Weverything
|
||||||
|
if [ -f $flags ]; then
|
||||||
|
RGBASMFLAGS="$(head -n 1 "$flags")" # Allow other lines to serve as comments
|
||||||
|
fi
|
||||||
for variant in '' '.pipe'; do
|
for variant in '' '.pipe'; do
|
||||||
echo "${bold}${green}${i%.asm}${variant}...${rescolors}${resbold}"
|
echo "${bold}${green}${i%.asm}${variant}...${rescolors}${resbold}"
|
||||||
desired_errname=${i%.asm}.err
|
desired_errname=${i%.asm}.err
|
||||||
@@ -83,7 +77,7 @@ for i in *.asm; do
|
|||||||
desired_errname=${i%.asm}.simple.err
|
desired_errname=${i%.asm}.simple.err
|
||||||
fi
|
fi
|
||||||
if [ -z "$variant" ]; then
|
if [ -z "$variant" ]; then
|
||||||
$RGBASM -Weverything -o $o $i > $output 2> $errput
|
$RGBASM $RGBASMFLAGS -o $o $i > $output 2> $errput
|
||||||
desired_output=${i%.asm}.out
|
desired_output=${i%.asm}.out
|
||||||
desired_errput=$desired_errname
|
desired_errput=$desired_errname
|
||||||
else
|
else
|
||||||
@@ -97,7 +91,7 @@ for i in *.asm; do
|
|||||||
# stdin redirection makes the input an unseekable pipe - a scenario
|
# stdin redirection makes the input an unseekable pipe - a scenario
|
||||||
# that's harder to deal with and was broken when the feature was
|
# that's harder to deal with and was broken when the feature was
|
||||||
# first implemented.
|
# first implemented.
|
||||||
cat $i | $RGBASM -Weverything -o $o - > $output 2> $errput
|
cat $i | $RGBASM $RGBASMFLAGS -o $o - > $output 2> $errput
|
||||||
|
|
||||||
# Use two otherwise unused files for temp storage
|
# Use two otherwise unused files for temp storage
|
||||||
desired_output=$input
|
desired_output=$input
|
||||||
|
|||||||
38
test/asm/trigonometry.asm
Normal file
38
test/asm/trigonometry.asm
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
for Q, 2, 31
|
||||||
|
OPT Q.{d:Q}
|
||||||
|
|
||||||
|
assert sin(0.25) == 1.0
|
||||||
|
assert asin(1.0) == 0.25
|
||||||
|
|
||||||
|
assert sin(0.0) == 0.0
|
||||||
|
assert asin(0.0) == 0.0
|
||||||
|
|
||||||
|
assert cos(0.0) == 1.0
|
||||||
|
assert acos(1.0) == 0.0
|
||||||
|
|
||||||
|
if Q > 2 ; can't represent 0.125 in Q.2
|
||||||
|
assert tan(0.125) == 1.0
|
||||||
|
assert atan(1.0) == 0.125
|
||||||
|
else
|
||||||
|
assert tan(0.0) == 0.0
|
||||||
|
assert atan(0.0) == 0.0
|
||||||
|
endc
|
||||||
|
endr
|
||||||
|
|
||||||
|
SECTION "sine", ROM0[0]
|
||||||
|
OPT Q.16
|
||||||
|
; Generate a table of sine values from sin(0.0) to sin(1.0), with
|
||||||
|
; amplitude scaled from [-1.0, 1.0] to [0.0, 128.0]
|
||||||
|
DEF turns = 0.0
|
||||||
|
REPT 256
|
||||||
|
db MUL(64.0, SIN(turns) + 1.0) >> 16
|
||||||
|
DEF turns += 1.0 / 256
|
||||||
|
ENDR
|
||||||
|
|
||||||
|
|
||||||
|
SECTION "cosine", ROM0[256]
|
||||||
|
OPT Q.8
|
||||||
|
; 32 samples of cos(x) from x=0 to x=pi radians=0.5 turns
|
||||||
|
for x, 0.0, 0.5, 0.5 / 32
|
||||||
|
dw cos(x)
|
||||||
|
endr
|
||||||
0
test/asm/trigonometry.err
Normal file
0
test/asm/trigonometry.err
Normal file
0
test/asm/trigonometry.out
Normal file
0
test/asm/trigonometry.out
Normal file
BIN
test/asm/trigonometry.out.bin
Normal file
BIN
test/asm/trigonometry.out.bin
Normal file
Binary file not shown.
21
test/asm/undefined-builtins.asm
Normal file
21
test/asm/undefined-builtins.asm
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
; not inside a section
|
||||||
|
assert !DEF(@)
|
||||||
|
println @
|
||||||
|
println "{@}?"
|
||||||
|
|
||||||
|
; not inside a macro
|
||||||
|
assert !DEF(_NARG)
|
||||||
|
println _NARG
|
||||||
|
println "{_NARG}?"
|
||||||
|
|
||||||
|
SECTION "s", ROM0[$42]
|
||||||
|
assert DEF(@)
|
||||||
|
println @
|
||||||
|
println "{@}!"
|
||||||
|
|
||||||
|
MACRO m
|
||||||
|
assert DEF(_NARG)
|
||||||
|
println _NARG
|
||||||
|
println "{_NARG}!"
|
||||||
|
ENDM
|
||||||
|
m 1, 2, 3
|
||||||
9
test/asm/undefined-builtins.err
Normal file
9
test/asm/undefined-builtins.err
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
error: undefined-builtins.asm(3):
|
||||||
|
PC has no value outside a section
|
||||||
|
error: undefined-builtins.asm(4):
|
||||||
|
Interpolated symbol "@" does not exist
|
||||||
|
error: undefined-builtins.asm(8):
|
||||||
|
_NARG does not make sense outside of a macro
|
||||||
|
error: undefined-builtins.asm(9):
|
||||||
|
Interpolated symbol "_NARG" does not exist
|
||||||
|
error: Assembly aborted (4 errors)!
|
||||||
8
test/asm/undefined-builtins.out
Normal file
8
test/asm/undefined-builtins.out
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
$0
|
||||||
|
?
|
||||||
|
$0
|
||||||
|
?
|
||||||
|
$42
|
||||||
|
$42!
|
||||||
|
$3
|
||||||
|
$3!
|
||||||
@@ -1,10 +1,18 @@
|
|||||||
|
opt Wunmapped-char=1 ; non-default empty charmaps can have unmapped chars
|
||||||
|
|
||||||
SECTION "test", ROM0
|
SECTION "test", ROM0
|
||||||
|
|
||||||
db "A" ; OK, default empty charmap
|
db "A" ; OK, default empty charmap
|
||||||
|
|
||||||
pushc
|
pushc
|
||||||
newcharmap custom
|
newcharmap custom
|
||||||
db "A" ; unmapped in non-default charmap
|
db "A" ; OK, unmapped in non-default empty charmap
|
||||||
|
pusho
|
||||||
|
opt Wunmapped-char=2
|
||||||
|
db "A" ; unmapped in non-default empty charmap
|
||||||
|
popo
|
||||||
|
charmap "C", $99
|
||||||
|
db "A" ; unmapped in non-empty charmap
|
||||||
popc
|
popc
|
||||||
|
|
||||||
db "A" ; OK, default empty charmap again
|
db "A" ; OK, default empty charmap again
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
warning: unmapped-char.asm(7): [-Wunmapped-char]
|
warning: unmapped-char.asm(12): [-Wunmapped-char]
|
||||||
|
Unmapped character 'A' not in main charmap
|
||||||
|
warning: unmapped-char.asm(15): [-Wunmapped-char]
|
||||||
Unmapped character 'A'
|
Unmapped character 'A'
|
||||||
warning: unmapped-char.asm(13): [-Wunmapped-char]
|
warning: unmapped-char.asm(21): [-Wunmapped-char]
|
||||||
Unmapped character 'A'
|
Unmapped character 'A'
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
AAAAA
|
AAAAAAA
|
||||||
41
test/patches/pokecrystal.patch
Normal file
41
test/patches/pokecrystal.patch
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
diff --git a/Makefile b/Makefile
|
||||||
|
index bf54eb4ce..d75f86aae 100644
|
||||||
|
--- a/Makefile
|
||||||
|
+++ b/Makefile
|
||||||
|
@@ -104,7 +104,7 @@ tools:
|
||||||
|
$(MAKE) -C tools/
|
||||||
|
|
||||||
|
|
||||||
|
-RGBASMFLAGS = -L -Weverything -Wnumeric-string=2 -Wtruncation=1
|
||||||
|
+RGBASMFLAGS = -L -Weverything -Wnumeric-string=2 -Wtruncation=1 -Q8
|
||||||
|
# Create a sym/map for debug purposes if `make` run with `DEBUG=1`
|
||||||
|
ifeq ($(DEBUG),1)
|
||||||
|
RGBASMFLAGS += -E
|
||||||
|
@@ -208,9 +208,11 @@ gfx/pokemon/girafarig/front.animated.tilemap: gfx/pokemon/girafarig/front.2bpp g
|
||||||
|
|
||||||
|
### Misc file-specific graphics rules
|
||||||
|
|
||||||
|
-gfx/pokemon/%/back.2bpp: rgbgfx += -h
|
||||||
|
+gfx/pokemon/%/back.2bpp: rgbgfx += -h -c embedded
|
||||||
|
+gfx/pokemon/%/front.2bpp: rgbgfx += -c embedded
|
||||||
|
+gfx/pokemon/unown_%/front.2bpp: rgbgfx =
|
||||||
|
|
||||||
|
-gfx/trainers/%.2bpp: rgbgfx += -h
|
||||||
|
+gfx/trainers/%.2bpp: rgbgfx += -h -c embedded
|
||||||
|
|
||||||
|
gfx/pokemon/egg/unused_front.2bpp: rgbgfx += -h
|
||||||
|
|
||||||
|
diff --git a/macros/data.asm b/macros/data.asm
|
||||||
|
index c2686c9f4..4dac70f3a 100644
|
||||||
|
--- a/macros/data.asm
|
||||||
|
+++ b/macros/data.asm
|
||||||
|
@@ -97,7 +97,7 @@ MACRO sine_table
|
||||||
|
; \1 samples of sin(x) from x=0 to x<32768 (pi radians)
|
||||||
|
DEF x = 0
|
||||||
|
rept \1
|
||||||
|
- dw (sin(x) + (sin(x) & $ff)) >> 8 ; round up
|
||||||
|
- DEF x += DIV(32768, \1) ; a circle has 65536 "degrees"
|
||||||
|
+ dw sin(x)
|
||||||
|
+ DEF x += 0.5 / (\1)
|
||||||
|
endr
|
||||||
|
ENDM
|
||||||
@@ -25,32 +25,20 @@ done
|
|||||||
# When updating subprojects, change the commit being checked out, and set the `shallow-since`
|
# When updating subprojects, change the commit being checked out, and set the `shallow-since`
|
||||||
# to the day before, to reduce the amount of refs being transferred and thus speed up CI.
|
# to the day before, to reduce the amount of refs being transferred and thus speed up CI.
|
||||||
|
|
||||||
if [ ! -d pokecrystal ]; then
|
test_downstream() { # owner/repo shallow-since commit make-target
|
||||||
git clone https://github.com/pret/pokecrystal.git --shallow-since=2022-03-12 --single-branch
|
if [ ! -d ${1##*/} ]; then
|
||||||
fi
|
git clone https://github.com/$1.git --shallow-since=$2 --single-branch
|
||||||
pushd pokecrystal
|
fi
|
||||||
git fetch
|
pushd ${1##*/}
|
||||||
git checkout a3e31d6463e6313aed12ebc733b3f772f2fc78d7
|
git checkout -f $3
|
||||||
make clean
|
if [ -f ../patches/${1##*/}.patch ]; then
|
||||||
make -j4 compare RGBDS=../../
|
git apply --ignore-whitespace ../patches/${1##*/}.patch
|
||||||
popd
|
fi
|
||||||
|
make clean
|
||||||
|
make -j4 $4 RGBDS=../../
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
if [ ! -d pokered ]; then
|
test_downstream pret/pokecrystal 2022-09-29 70a3ec1accb6de1c1c273470af0ddfa2edc1b0a9 compare
|
||||||
git clone https://github.com/pret/pokered.git --shallow-since=2022-03-07 --single-branch
|
test_downstream pret/pokered 2022-09-29 2b52ceb718b55dce038db24d177715ae4281d065 compare
|
||||||
fi
|
test_downstream AntonioND/ucity 2022-04-20 d8878233da7a6569f09f87b144cb5bf140146a0f ''
|
||||||
pushd pokered
|
|
||||||
git fetch
|
|
||||||
git checkout a75dd222709c92ae136d835ff2451391d5a88e45
|
|
||||||
make clean
|
|
||||||
make -j4 compare RGBDS=../../
|
|
||||||
popd
|
|
||||||
|
|
||||||
if [ ! -d ucity ]; then
|
|
||||||
git clone https://github.com/AntonioND/ucity.git --shallow-since=2020-11-01 --single-branch
|
|
||||||
fi
|
|
||||||
pushd ucity
|
|
||||||
git fetch
|
|
||||||
git checkout d8878233da7a6569f09f87b144cb5bf140146a0f
|
|
||||||
make clean
|
|
||||||
make -j4 RGBDS=../../
|
|
||||||
popd
|
|
||||||
|
|||||||
Reference in New Issue
Block a user