mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 10:42:07 +00:00
Compare commits
146 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
323738e7b8 | ||
|
|
a1d132cd35 | ||
|
|
e93d65d736 | ||
|
|
0f4d543aeb | ||
|
|
dab5f59ed9 | ||
|
|
22a6a82642 | ||
|
|
7b592eff8a | ||
|
|
4be81d9ffd | ||
|
|
55fbecee49 | ||
|
|
f36a3d5b2a | ||
|
|
c5e8e4ff83 | ||
|
|
ccc666c1e4 | ||
|
|
89eda89838 | ||
|
|
17b9838c8f | ||
|
|
889dd83798 | ||
|
|
38a372f25f | ||
|
|
2e6f5ac679 | ||
|
|
7a45fc68d9 | ||
|
|
1288737c0d | ||
|
|
5902306271 | ||
|
|
2fe4521a96 | ||
|
|
74673436a1 | ||
|
|
481748c279 | ||
|
|
9faa5c7a9e | ||
|
|
6fbb25c0da | ||
|
|
65fc42cce5 | ||
|
|
736b7727b6 | ||
|
|
fa920f8449 | ||
|
|
01aa56606f | ||
|
|
bddd5bc678 | ||
|
|
f6b7e39ce7 | ||
|
|
1363dd8f34 | ||
|
|
8214f0c09d | ||
|
|
ff7c46f5a6 | ||
|
|
b44f5825a5 | ||
|
|
631910bd67 | ||
|
|
37089ef940 | ||
|
|
4ef27a0d23 | ||
|
|
476ccc9f6b | ||
|
|
89dc14fcaf | ||
|
|
1ca2f12d24 | ||
|
|
20b2f5ee2f | ||
|
|
3cc67c48cf | ||
|
|
f9a04696f2 | ||
|
|
e0e8170fe6 | ||
|
|
9b40663d54 | ||
|
|
a517f900e4 | ||
|
|
350f40300c | ||
|
|
d3db5f0d76 | ||
|
|
7e3af4b3cd | ||
|
|
dfb3072381 | ||
|
|
02191135a0 | ||
|
|
dc2c97fe0c | ||
|
|
6068b565f5 | ||
|
|
a21cef7190 | ||
|
|
461ef6cea5 | ||
|
|
e05199ca1e | ||
|
|
12d82eb768 | ||
|
|
05becf3f4b | ||
|
|
3cc7981c82 | ||
|
|
8f287eeef9 | ||
|
|
ce05cb5683 | ||
|
|
17945a7377 | ||
|
|
3a1b47129e | ||
|
|
6ffa751090 | ||
|
|
c3641321d7 | ||
|
|
446173f0cb | ||
|
|
e27f381842 | ||
|
|
a3ee76dddd | ||
|
|
995265c549 | ||
|
|
03629b74d9 | ||
|
|
b069278e98 | ||
|
|
9738c88f95 | ||
|
|
a21ea30be0 | ||
|
|
64752da42d | ||
|
|
e3e18063c6 | ||
|
|
e400eac42b | ||
|
|
a6bf77718c | ||
|
|
c2787a9ea9 | ||
|
|
e33e6e2413 | ||
|
|
3cb56c5a2e | ||
|
|
91984cb7e7 | ||
|
|
b8d5dd1824 | ||
|
|
88b66f2941 | ||
|
|
3c7e59b9e1 | ||
|
|
c4471e3300 | ||
|
|
16111f46ef | ||
|
|
b019b03946 | ||
|
|
605acd24ba | ||
|
|
c8630eee95 | ||
|
|
4040555532 | ||
|
|
defb221c98 | ||
|
|
e7dc094e56 | ||
|
|
dfdb107105 | ||
|
|
9f598dfdb7 | ||
|
|
38110a833d | ||
|
|
484d15dbb2 | ||
|
|
1decf5d0d4 | ||
|
|
74e9de1b71 | ||
|
|
015d2b0830 | ||
|
|
c75a9539ba | ||
|
|
ca6149abcf | ||
|
|
b3120aea25 | ||
|
|
54e5bf0f0c | ||
|
|
847cae5b95 | ||
|
|
df15c97b6e | ||
|
|
0d97b58265 | ||
|
|
f7bc61e874 | ||
|
|
8d5a53f529 | ||
|
|
20f9492899 | ||
|
|
3cd1d46a1b | ||
|
|
88eceec257 | ||
|
|
d00ec024a2 | ||
|
|
0bcd53778a | ||
|
|
7592eaf42b | ||
|
|
12ed9e044a | ||
|
|
0a3af87aee | ||
|
|
4dee999f68 | ||
|
|
9a4941c794 | ||
|
|
2d0fd71159 | ||
|
|
327582be31 | ||
|
|
21aea281bd | ||
|
|
975f85260d | ||
|
|
f29d768989 | ||
|
|
9bd7ecad4c | ||
|
|
cc458a9693 | ||
|
|
d2bd9a2368 | ||
|
|
b909a5063a | ||
|
|
b2c1f6122e | ||
|
|
a761e98e18 | ||
|
|
e12e7b2acc | ||
|
|
f927c41abb | ||
|
|
249acace08 | ||
|
|
fa37922ca7 | ||
|
|
021990b8e0 | ||
|
|
540564694c | ||
|
|
8da4feb83c | ||
|
|
23f5e9dacc | ||
|
|
6ff9435e0a | ||
|
|
40006c6152 | ||
|
|
b256e4c2e3 | ||
|
|
a37a09c09c | ||
|
|
8ece231d8b | ||
|
|
e7de0745ad | ||
|
|
7af2d5dfe1 | ||
|
|
2f2f14bf80 |
@@ -67,3 +67,9 @@
|
|||||||
|
|
||||||
# Don't complain when files are modified in 'include/asm'
|
# Don't complain when files are modified in 'include/asm'
|
||||||
--ignore MODIFIED_INCLUDE_ASM
|
--ignore MODIFIED_INCLUDE_ASM
|
||||||
|
|
||||||
|
# Don't complain when bools are used in structs
|
||||||
|
--ignore BOOL_MEMBER
|
||||||
|
|
||||||
|
# Don't complain about initializing statics (this is specific to the kernel)
|
||||||
|
--ignore INITIALISED_STATIC
|
||||||
|
|||||||
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is part of RGBDS.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018-2019, Phil Smith and RGBDS contributors.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
.git
|
||||||
|
docs
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -6,6 +6,6 @@ rgbgfx
|
|||||||
*.exe
|
*.exe
|
||||||
.checkpatch-camelcase.*
|
.checkpatch-camelcase.*
|
||||||
|
|
||||||
test/pokecrystal/*
|
test/pokecrystal
|
||||||
test/pokered/*
|
test/pokered
|
||||||
test/ucity/*
|
test/ucity
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ echo "Running checkpatch.pl..."
|
|||||||
fname=$(mktemp)
|
fname=$(mktemp)
|
||||||
rc=0
|
rc=0
|
||||||
|
|
||||||
git remote set-branches --add origin develop
|
|
||||||
git fetch
|
|
||||||
|
|
||||||
make CHECKPATCH=checkpatchdir/checkpatch.pl checkpatch > $fname
|
make CHECKPATCH=checkpatchdir/checkpatch.pl checkpatch > $fname
|
||||||
|
|
||||||
cat $fname
|
cat $fname
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ language: c
|
|||||||
sudo: required
|
sudo: required
|
||||||
install:
|
install:
|
||||||
- ./.travis-deps.sh
|
- ./.travis-deps.sh
|
||||||
- make
|
- make Q=
|
||||||
- sudo make install
|
- sudo make install Q=
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
- osx
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ copyright and the reference to the MIT License.
|
|||||||
|
|
||||||
1. Fork this repository.
|
1. Fork this repository.
|
||||||
|
|
||||||
2. Checkout the ``develop`` branch.
|
2. Checkout the ``master`` branch.
|
||||||
|
|
||||||
3. Create a new branch to work on. You could still work on ``develop``, but it's
|
3. Create a new branch to work on. You could still work on ``master``, but it's
|
||||||
easier that way.
|
easier that way.
|
||||||
|
|
||||||
4. Compile your changes with ``make develop`` instead of just ``make``. This
|
4. Compile your changes with ``make develop`` instead of just ``make``. This
|
||||||
@@ -88,9 +88,9 @@ copyright and the reference to the MIT License.
|
|||||||
code. By default, the Makefile expects the script (and associate files) to be
|
code. By default, the Makefile expects the script (and associate files) to be
|
||||||
located in ``../linux/scripts/``, but you can place them anywhere you like as
|
located in ``../linux/scripts/``, but you can place them anywhere you like as
|
||||||
long as you specify it when executing the command:
|
long as you specify it when executing the command:
|
||||||
``CHECKPATCH=../path/to/folder make checkpatch``.
|
``make checkpatch CHECKPATCH=../path/to/folder``.
|
||||||
|
|
||||||
8. Create a pull request against the branch ``develop``.
|
8. Create a pull request against the branch ``master``.
|
||||||
|
|
||||||
9. Be prepared to get some comments about your code and to modify it. Tip: Use
|
9. Be prepared to get some comments about your code and to modify it. Tip: Use
|
||||||
``git rebase -i origin/develop`` to modify chains of commits.
|
``git rebase -i origin/master`` to modify chains of commits.
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Main contributors
|
|||||||
Other contributors
|
Other contributors
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
- Ben10do
|
- Ben Hetherington <dev@ben-h.uk>
|
||||||
|
|
||||||
- Björn Höhrmann <bjoern@hoehrmann.de>
|
- Björn Höhrmann <bjoern@hoehrmann.de>
|
||||||
|
|
||||||
@@ -30,14 +30,22 @@ Other contributors
|
|||||||
|
|
||||||
- David Brotz <dbrotz007@gmail.com>
|
- David Brotz <dbrotz007@gmail.com>
|
||||||
|
|
||||||
|
- Eldred Habert <eldredhabert0@gmail.com>
|
||||||
|
|
||||||
- The Musl C library <http://www.musl-libc.org>
|
- The Musl C library <http://www.musl-libc.org>
|
||||||
|
|
||||||
- obskyr <powpowd@gmail.com>
|
- obskyr <powpowd@gmail.com>
|
||||||
|
|
||||||
- The OpenBSD Project <http://www.openbsd.org>
|
- The OpenBSD Project <http://www.openbsd.org>
|
||||||
|
|
||||||
|
- Quint Guvernator <quint@guvernator.net>
|
||||||
|
|
||||||
- Sanqui <gsanky@gmail.com>
|
- Sanqui <gsanky@gmail.com>
|
||||||
|
|
||||||
- YamaArashi <shadow962@live.com>
|
- YamaArashi <shadow962@live.com>
|
||||||
|
|
||||||
- yenatch <yenatch@gmail.com>
|
- yenatch <yenatch@gmail.com>
|
||||||
|
|
||||||
|
- phs <phil@philhsmith.com>
|
||||||
|
|
||||||
|
- jidoc01 <jidoc01@naver.com>
|
||||||
|
|||||||
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# This file is part of RGBDS.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018-2019, Phil Smith and RGBDS contributors.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# docker build -t rgbds:vX.X.X-alpine
|
||||||
|
FROM alpine:latest
|
||||||
|
RUN apk add --update \
|
||||||
|
build-base \
|
||||||
|
byacc \
|
||||||
|
flex \
|
||||||
|
libpng-dev
|
||||||
|
COPY . /rgbds
|
||||||
|
WORKDIR /rgbds
|
||||||
|
RUN make Q='' all
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
RUN apk add --update \
|
||||||
|
libpng
|
||||||
|
COPY --from=0 \
|
||||||
|
/rgbds/rgbasm \
|
||||||
|
/rgbds/rgbfix \
|
||||||
|
/rgbds/rgblink \
|
||||||
|
/rgbds/rgbgfx \
|
||||||
|
/bin/
|
||||||
50
Makefile
50
Makefile
@@ -6,6 +6,9 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
#
|
#
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
.SUFFIXES: .h .l .y .c .o
|
||||||
|
|
||||||
# User-defined variables
|
# User-defined variables
|
||||||
|
|
||||||
Q := @
|
Q := @
|
||||||
@@ -33,6 +36,10 @@ CFLAGS := -g
|
|||||||
# Non-overridable CFLAGS
|
# Non-overridable CFLAGS
|
||||||
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=c99 -D_POSIX_C_SOURCE=200809L \
|
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=c99 -D_POSIX_C_SOURCE=200809L \
|
||||||
-Iinclude -DBUILD_VERSION_STRING=\"${VERSION_STRING}\"
|
-Iinclude -DBUILD_VERSION_STRING=\"${VERSION_STRING}\"
|
||||||
|
# Overridable LDFLAGS
|
||||||
|
LDFLAGS :=
|
||||||
|
# Non-overridable LDFLAGS
|
||||||
|
REALLDFLAGS := ${LDFLAGS} ${WARNFLAGS}
|
||||||
|
|
||||||
YFLAGS :=
|
YFLAGS :=
|
||||||
LFLAGS := --nounistd
|
LFLAGS := --nounistd
|
||||||
@@ -57,12 +64,12 @@ rgbasm_obj := \
|
|||||||
src/asm/output.o \
|
src/asm/output.o \
|
||||||
src/asm/rpn.o \
|
src/asm/rpn.o \
|
||||||
src/asm/symbol.o \
|
src/asm/symbol.o \
|
||||||
|
src/asm/util.o \
|
||||||
src/extern/err.o \
|
src/extern/err.o \
|
||||||
src/extern/utf8decoder.o \
|
src/extern/utf8decoder.o \
|
||||||
src/version.o
|
src/version.o
|
||||||
|
|
||||||
src/asm/asmy.h: src/asm/asmy.c
|
src/asm/globlex.o src/asm/lexer.o src/asm/constexpr.o: src/asm/asmy.h
|
||||||
src/asm/locallex.o src/asm/globlex.o src/asm/lexer.o src/asm/constexpr.o: src/asm/asmy.h
|
|
||||||
|
|
||||||
rgblink_obj := \
|
rgblink_obj := \
|
||||||
src/link/assign.o \
|
src/link/assign.o \
|
||||||
@@ -79,7 +86,6 @@ rgblink_obj := \
|
|||||||
src/extern/err.o \
|
src/extern/err.o \
|
||||||
src/version.o
|
src/version.o
|
||||||
|
|
||||||
src/link/parser.h: src/link/parser.c
|
|
||||||
src/link/lexer.o: src/link/parser.h
|
src/link/lexer.o: src/link/parser.h
|
||||||
|
|
||||||
rgbfix_obj := \
|
rgbfix_obj := \
|
||||||
@@ -95,27 +101,32 @@ rgbgfx_obj := \
|
|||||||
src/version.o
|
src/version.o
|
||||||
|
|
||||||
rgbasm: ${rgbasm_obj}
|
rgbasm: ${rgbasm_obj}
|
||||||
$Q${CC} ${REALCFLAGS} -o $@ ${rgbasm_obj} -lm
|
$Q${CC} ${REALLDFLAGS} -o $@ ${rgbasm_obj} -lm
|
||||||
|
|
||||||
rgblink: ${rgblink_obj}
|
rgblink: ${rgblink_obj}
|
||||||
$Q${CC} ${REALCFLAGS} -o $@ ${rgblink_obj}
|
$Q${CC} ${REALLDFLAGS} -o $@ ${rgblink_obj}
|
||||||
|
|
||||||
rgbfix: ${rgbfix_obj}
|
rgbfix: ${rgbfix_obj}
|
||||||
$Q${CC} ${REALCFLAGS} -o $@ ${rgbfix_obj}
|
$Q${CC} ${REALLDFLAGS} -o $@ ${rgbfix_obj}
|
||||||
|
|
||||||
rgbgfx: ${rgbgfx_obj}
|
rgbgfx: ${rgbgfx_obj}
|
||||||
$Q${CC} ${REALCFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${PNGLDLIBS}
|
$Q${CC} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${PNGLDLIBS}
|
||||||
|
|
||||||
# Rules to process files
|
# Rules to process files
|
||||||
|
|
||||||
|
# We want the yacc and lex invocations to pass through our rules
|
||||||
|
.y.o:
|
||||||
|
.l.o:
|
||||||
|
|
||||||
|
# yacc- and lex-generated C files have an accompanying header
|
||||||
|
.c.h:
|
||||||
|
$Qtouch $@
|
||||||
|
|
||||||
.y.c:
|
.y.c:
|
||||||
$Q${YACC} -d ${YFLAGS} -o $@ $<
|
$Q${YACC} -d ${YFLAGS} -o $@ $<
|
||||||
|
|
||||||
.l.o:
|
.l.c:
|
||||||
$Q${RM} $*.c
|
$Q${LEX} ${LFLAGS} -o $@ $<
|
||||||
$Q${LEX} ${LFLAGS} -o $*.c $<
|
|
||||||
$Q${CC} ${REALCFLAGS} -c -o $@ $*.c
|
|
||||||
$Q${RM} $*.c
|
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
$Q${CC} ${REALCFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
$Q${CC} ${REALCFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
||||||
@@ -124,10 +135,11 @@ rgbgfx: ${rgbgfx_obj}
|
|||||||
# for the html documentation.
|
# for the html documentation.
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$Q${RM} rgbasm rgbasm.exe ${rgbasm_obj}
|
$Q${RM} rgbasm rgbasm.exe
|
||||||
$Q${RM} rgblink rgblink.exe ${rgblink_obj}
|
$Q${RM} rgblink rgblink.exe
|
||||||
$Q${RM} rgbfix rgbfix.exe ${rgbfix_obj}
|
$Q${RM} rgbfix rgbfix.exe
|
||||||
$Q${RM} rgbgfx rgbgfx.exe ${rgbgfx_obj}
|
$Q${RM} rgbgfx rgbgfx.exe
|
||||||
|
$Qfind src/ -name "*.o" -exec rm {} \;
|
||||||
$Q${RM} src/asm/asmy.c src/asm/asmy.h
|
$Q${RM} src/asm/asmy.c src/asm/asmy.h
|
||||||
$Q${RM} src/link/lexer.c src/link/parser.c src/link/parser.h
|
$Q${RM} src/link/lexer.c src/link/parser.c src/link/parser.h
|
||||||
|
|
||||||
@@ -169,11 +181,11 @@ checkcodebase:
|
|||||||
|
|
||||||
# Target used to check the coding style of the patches from the upstream branch
|
# Target used to check the coding style of the patches from the upstream branch
|
||||||
# to the HEAD. Runs checkpatch once for each commit between the current HEAD and
|
# to the HEAD. Runs checkpatch once for each commit between the current HEAD and
|
||||||
# the first common commit between the HEAD and origin/develop. '.y' and '.l'
|
# the first common commit between the HEAD and origin/master. '.y' and '.l'
|
||||||
# files aren't checked, unfortunately...
|
# files aren't checked, unfortunately...
|
||||||
|
|
||||||
checkpatch:
|
checkpatch:
|
||||||
$Qeval COMMON_COMMIT=$$(git merge-base HEAD origin/develop); \
|
$Qeval COMMON_COMMIT=$$(git merge-base HEAD origin/master); \
|
||||||
for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do \
|
for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do \
|
||||||
echo "[*] Analyzing commit '$$commit'"; \
|
echo "[*] Analyzing commit '$$commit'"; \
|
||||||
git format-patch --stdout "$$commit~..$$commit" \
|
git format-patch --stdout "$$commit~..$$commit" \
|
||||||
@@ -202,7 +214,7 @@ wwwman:
|
|||||||
|
|
||||||
develop:
|
develop:
|
||||||
$Qenv make -j WARNFLAGS="-Werror -Wall -Wextra -Wpedantic \
|
$Qenv make -j WARNFLAGS="-Werror -Wall -Wextra -Wpedantic \
|
||||||
-Wno-sign-compare -Wchkp -Wformat=2 -Wformat-overflow=2 \
|
-Wno-sign-compare -Wformat=2 -Wformat-overflow=2 \
|
||||||
-Wformat-truncation=1 -Wformat-y2k -Wswitch-enum -Wunused \
|
-Wformat-truncation=1 -Wformat-y2k -Wswitch-enum -Wunused \
|
||||||
-Wuninitialized -Wunknown-pragmas -Wstrict-overflow=5 \
|
-Wuninitialized -Wunknown-pragmas -Wstrict-overflow=5 \
|
||||||
-Wstringop-overflow=4 -Walloc-zero -Wduplicated-cond \
|
-Wstringop-overflow=4 -Walloc-zero -Wduplicated-cond \
|
||||||
|
|||||||
@@ -24,13 +24,16 @@ found in this repository.
|
|||||||
1.1 Windows
|
1.1 Windows
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
|
||||||
Windows builds are available in the releases page on GitHub:
|
Windows builds are available in the releases page on GitHub
|
||||||
|
`here <https://github.com/rednex/rgbds/releases>`__.
|
||||||
|
|
||||||
|
Extract the zip and then add the executable directory to the path. For example:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
https://github.com/rednex/rgbds/releases
|
path %PATH%;C:\Programs\rgbds-0.3.8-win64\win64
|
||||||
|
|
||||||
Copy the ``.exe`` files to ``C:\Windows\`` or similar.
|
Alternatively, the RGBDS executables can be simply dropped in the folder of the project they're used in.
|
||||||
|
|
||||||
If you require the latest version in development, it should be possible to
|
If you require the latest version in development, it should be possible to
|
||||||
compile RGBDS with MinGW or Cygwin by following the instructions to build it on
|
compile RGBDS with MinGW or Cygwin by following the instructions to build it on
|
||||||
|
|||||||
2758
docs/gbz80.7.html
2758
docs/gbz80.7.html
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<!-- This is an automatically generated file. Do not edit.
|
||||||
|
This file is part of RGBDS.
|
||||||
|
|
||||||
|
Copyright (c) 2010-2019, Anthony J. Bentley and RGBDS contributors.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
||||||
<title>RGBASM(1)</title>
|
<title>RGBASM(1)</title>
|
||||||
</head>
|
</head>
|
||||||
@@ -20,136 +21,122 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="manual-text">
|
<div class="manual-text">
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
<section class="Sh">
|
||||||
<b class="Nm" title="Nm">rgbasm</b> — <span class="Nd" title="Nd">Game
|
<h1 class="Sh" id="NAME"><a class="permalink" href="#NAME">NAME</a></h1>
|
||||||
Boy assembler</span>
|
<code class="Nm">rgbasm</code> —
|
||||||
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
<div class="Nd">Game Boy assembler</div>
|
||||||
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SYNOPSIS"><a class="permalink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
||||||
<table class="Nm">
|
<table class="Nm">
|
||||||
<tr>
|
<tr>
|
||||||
<td><b class="Nm" title="Nm">rgbasm</b></td>
|
<td><code class="Nm">rgbasm</code></td>
|
||||||
<td>[<span class="Op"><b class="Fl" title="Fl">-EhLVvw</b></span>]
|
<td>[<code class="Fl">-EhLVvw</code>] [<code class="Fl">-b</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-b</b>
|
<var class="Ar">chars</var>] [<code class="Fl">-D</code>
|
||||||
<var class="Ar" title="Ar">chars</var></span>]
|
<var class="Ar">name</var>[=<var class="Ar">value</var>]]
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-D</b>
|
[<code class="Fl">-g</code> <var class="Ar">chars</var>]
|
||||||
<var class="Ar" title="Ar">name</var>[<span class="Op">=<var class="Ar" title="Ar">value</var></span>]</span>]
|
[<code class="Fl">-i</code> <var class="Ar">path</var>]
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-g</b>
|
[<code class="Fl">-M</code> <var class="Ar">dependfile</var>]
|
||||||
<var class="Ar" title="Ar">chars</var></span>]
|
[<code class="Fl">-o</code> <var class="Ar">outfile</var>]
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-i</b>
|
[<code class="Fl">-p</code> <var class="Ar">pad_value</var>]
|
||||||
<var class="Ar" title="Ar">path</var></span>]
|
[<code class="Fl">-r</code> <var class="Ar">recursion_depth</var>]
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-M</b>
|
<var class="Ar">file</var></td>
|
||||||
<var class="Ar" title="Ar">dependfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-o</b>
|
|
||||||
<var class="Ar" title="Ar">outfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-p</b>
|
|
||||||
<var class="Ar" title="Ar">pad_value</var></span>]
|
|
||||||
<var class="Ar" title="Ar">file</var></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
</section>
|
||||||
The <b class="Nm" title="Nm">rgbasm</b> program creates an object file from an
|
<section class="Sh">
|
||||||
assembly source file. Its arguments are as follows:
|
<h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
||||||
|
The <code class="Nm">rgbasm</code> program creates an object file from an
|
||||||
|
assembly source file. The input <var class="Ar">file</var> can be a file path,
|
||||||
|
or <code class="Cm">-</code> denoting <code class="Cm">stdin</code>. Its
|
||||||
|
arguments are as follows:
|
||||||
<dl class="Bl-tag">
|
<dl class="Bl-tag">
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#b"><code class="Fl" id="b">-b</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">chars</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#b"><b class="Fl" title="Fl" id="b">-b</b></a>
|
<dd>Change the two characters used for binary constants. The defaults are
|
||||||
<var class="Ar" title="Ar">chars</var></dt>
|
01.</dd>
|
||||||
<dd class="It-tag">Change the two characters used for binary constants. The
|
<dt><a class="permalink" href="#D"><code class="Fl" id="D">-D</code></a>
|
||||||
defaults are 01.</dd>
|
<var class="Ar">name</var>[=<var class="Ar">value</var>]</dt>
|
||||||
<dt class="It-tag"> </dt>
|
<dd>Add string symbol to the compiled source code. This is equivalent to
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">name</var> <code class="Cm">EQUS</code>
|
||||||
<dt class="It-tag"><a class="selflink" href="#D"><b class="Fl" title="Fl" id="D">-D</b></a>
|
“<var class="Ar">value</var>” in code. If a value is not
|
||||||
<var class="Ar" title="Ar">name</var>[<span class="Op">=<var class="Ar" title="Ar">value</var></span>]</dt>
|
specified, a value of 1 is given.</dd>
|
||||||
<dd class="It-tag">Add string symbol to the compiled source code. This is
|
<dt><a class="permalink" href="#E"><code class="Fl" id="E">-E</code></a></dt>
|
||||||
equivalent to <var class="Ar" title="Ar">name</var>
|
<dd>Export all labels, including unreferenced and local labels.</dd>
|
||||||
<b class="Cm" title="Cm">EQUS</b>
|
<dt><a class="permalink" href="#g"><code class="Fl" id="g">-g</code></a>
|
||||||
“<var class="Ar" title="Ar">value</var>” in code. If a value
|
<var class="Ar">chars</var></dt>
|
||||||
is not specified, a value of 1 is given.</dd>
|
<dd>Change the four characters used for binary constants. The defaults are
|
||||||
<dt class="It-tag"> </dt>
|
0123.</dd>
|
||||||
<dd class="It-tag"> </dd>
|
<dt><a class="permalink" href="#h"><code class="Fl" id="h">-h</code></a></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#E"><b class="Fl" title="Fl" id="E">-E</b></a></dt>
|
<dd>By default, <code class="Nm">rgbasm</code> inserts a ‘nop’
|
||||||
<dd class="It-tag">Export all labels, including unreferenced and local
|
instruction immediately after any ‘halt’ instruction. The
|
||||||
labels.</dd>
|
<code class="Fl">-h</code> option disables this behavior.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#i"><code class="Fl" id="i">-i</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">path</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#g"><b class="Fl" title="Fl" id="g">-g</b></a>
|
<dd>Add an include path.</dd>
|
||||||
<var class="Ar" title="Ar">chars</var></dt>
|
<dt><a class="permalink" href="#L"><code class="Fl" id="L">-L</code></a></dt>
|
||||||
<dd class="It-tag">Change the four characters used for binary constants. The
|
<dd>Disable the optimization that turns loads of the form <b class="Sy">LD
|
||||||
defaults are 0123.</dd>
|
[$FF00+n8],A</b> into the opcode <b class="Sy">LDH [$FF00+n8],A</b> in
|
||||||
<dt class="It-tag"> </dt>
|
order to have full control of the result in the final ROM.</dd>
|
||||||
<dd class="It-tag"> </dd>
|
<dt><a class="permalink" href="#M"><code class="Fl" id="M">-M</code></a>
|
||||||
<dt class="It-tag"><a class="selflink" href="#h"><b class="Fl" title="Fl" id="h">-h</b></a></dt>
|
<var class="Ar">dependfile</var></dt>
|
||||||
<dd class="It-tag">By default, <b class="Nm" title="Nm">rgbasm</b> inserts a
|
<dd>Print <a class="Xr">make(1)</a> dependencies to
|
||||||
‘nop’ instruction immediately after any ‘halt’
|
<var class="Ar">dependfile</var>.</dd>
|
||||||
instruction. The <b class="Fl" title="Fl">-h</b> option disables this
|
<dt><a class="permalink" href="#o"><code class="Fl" id="o">-o</code></a>
|
||||||
behavior.</dd>
|
<var class="Ar">outfile</var></dt>
|
||||||
<dt class="It-tag"> </dt>
|
<dd>Write an object file to the given filename.</dd>
|
||||||
<dd class="It-tag"> </dd>
|
<dt><a class="permalink" href="#p"><code class="Fl" id="p">-p</code></a>
|
||||||
<dt class="It-tag"><a class="selflink" href="#i"><b class="Fl" title="Fl" id="i">-i</b></a>
|
<var class="Ar">pad_value</var></dt>
|
||||||
<var class="Ar" title="Ar">path</var></dt>
|
<dd>When padding an image, pad with this value. The default is 0x00.</dd>
|
||||||
<dd class="It-tag">Add an include path.</dd>
|
<dt><a class="permalink" href="#r"><code class="Fl" id="r">-r</code></a>
|
||||||
<dt class="It-tag"> </dt>
|
<var class="Ar">recursion_depth</var></dt>
|
||||||
<dd class="It-tag"> </dd>
|
<dd>Specifies the recursion depth at which RGBASM will assume being in an
|
||||||
<dt class="It-tag"><a class="selflink" href="#L"><b class="Fl" title="Fl" id="L">-L</b></a></dt>
|
infinite loop.</dd>
|
||||||
<dd class="It-tag">Disable the optimization that turns loads of the form
|
<dt><a class="permalink" href="#V"><code class="Fl" id="V">-V</code></a></dt>
|
||||||
<b class="Sy" title="Sy">LD [$FF00+n8],A</b> into the opcode
|
<dd>Print the version of the program and exit.</dd>
|
||||||
<b class="Sy" title="Sy">LDH [$FF00+n8],A</b> in order to have full
|
<dt><a class="permalink" href="#v"><code class="Fl" id="v">-v</code></a></dt>
|
||||||
control of the result in the final ROM.</dd>
|
<dd>Be verbose.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#w"><code class="Fl" id="w">-w</code></a></dt>
|
||||||
<dd class="It-tag"> </dd>
|
<dd>Disable warning output.</dd>
|
||||||
<dt class="It-tag"><a class="selflink" href="#M"><b class="Fl" title="Fl" id="M">-M</b></a>
|
|
||||||
<var class="Ar" title="Ar">dependfile</var></dt>
|
|
||||||
<dd class="It-tag">Print <a class="Xr" title="Xr">make(1)</a> dependencies to
|
|
||||||
<var class="Ar" title="Ar">dependfile</var>.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#o"><b class="Fl" title="Fl" id="o">-o</b></a>
|
|
||||||
<var class="Ar" title="Ar">outfile</var></dt>
|
|
||||||
<dd class="It-tag">Write an object file to the given filename.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
|
|
||||||
<var class="Ar" title="Ar">pad_value</var></dt>
|
|
||||||
<dd class="It-tag">When padding an image, pad with this value. The default is
|
|
||||||
0x00.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
|
|
||||||
<dd class="It-tag">Print the version of the program and exit.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#v"><b class="Fl" title="Fl" id="v">-v</b></a></dt>
|
|
||||||
<dd class="It-tag">Be verbose.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#w"><b class="Fl" title="Fl" id="w">-w</b></a></dt>
|
|
||||||
<dd class="It-tag">Disable warning output.</dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
|
</section>
|
||||||
Assembling a basic source file is simple:
|
<section class="Sh">
|
||||||
<div class="Pp"></div>
|
<h1 class="Sh" id="EXAMPLES"><a class="permalink" href="#EXAMPLES">EXAMPLES</a></h1>
|
||||||
<div class="Bd" style="margin-left: 5.00ex;">
|
You can assemble a source file in two ways. Straight forward way:
|
||||||
<pre class="Li">
|
<div class="Bd Pp Bd-indent">
|
||||||
|
<pre>
|
||||||
$ rgbasm -o bar.o foo.asm
|
$ rgbasm -o bar.o foo.asm
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div class="Pp"></div>
|
<p class="Pp">Pipes way:</p>
|
||||||
The resulting object file is not yet a usable ROM image — it must first
|
<div class="Bd Pp Bd-indent">
|
||||||
be run through <a class="Xr" title="Xr">rgblink(1)</a> and
|
<pre>
|
||||||
<a class="Xr" title="Xr">rgbfix(1)</a>.
|
$ cat foo.asm | rgbasm -o bar.o -
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
$ rgbasm -o bar.o - < foo.asm
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
<p class="Pp">The resulting object file is not yet a usable ROM image —
|
||||||
|
it must first be run through <a class="Xr">rgblink(1)</a> and
|
||||||
|
<a class="Xr">rgbfix(1)</a>.</p>
|
||||||
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
|
||||||
ALSO</a></h1>
|
ALSO</a></h1>
|
||||||
<a class="Xr" title="Xr">rgbasm(5)</a>, <a class="Xr" title="Xr">rgbfix(1)</a>,
|
<a class="Xr">rgbasm(5)</a>, <a class="Xr">rgbfix(1)</a>,
|
||||||
<a class="Xr" title="Xr">rgblink(1)</a>,
|
<a class="Xr">rgblink(1)</a>, <a class="Xr">rgbds(5)</a>,
|
||||||
<a class="Xr" title="Xr">rgbds(5)</a>, <a class="Xr" title="Xr">rgbds(7)</a>,
|
<a class="Xr">rgbds(7)</a>, <a class="Xr">gbz80(7)</a>
|
||||||
<a class="Xr" title="Xr">gbz80(7)</a>
|
</section>
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
<section class="Sh">
|
||||||
<b class="Nm" title="Nm">rgbasm</b> was originally written by Carsten
|
<h1 class="Sh" id="HISTORY"><a class="permalink" href="#HISTORY">HISTORY</a></h1>
|
||||||
Sørensen as part of the ASMotor package, and was later packaged in
|
<code class="Nm">rgbasm</code> was originally written by Carsten Sørensen
|
||||||
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
as part of the ASMotor package, and was later packaged in RGBDS by Justin
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
Lloyd. It is now maintained by a number of contributors at
|
||||||
|
<a class="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
<table class="foot">
|
<table class="foot">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="foot-date">February 24, 2018</td>
|
<td class="foot-date">July 8, 2019</td>
|
||||||
<td class="foot-os">RGBDS Manual</td>
|
<td class="foot-os">RGBDS Manual</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
2034
docs/rgbasm.5.html
2034
docs/rgbasm.5.html
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<!-- This is an automatically generated file. Do not edit.
|
||||||
|
This file is part of RGBDS.
|
||||||
|
|
||||||
|
Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
||||||
<title>RGBDS(5)</title>
|
<title>RGBDS(5)</title>
|
||||||
</head>
|
</head>
|
||||||
@@ -20,27 +21,29 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="manual-text">
|
<div class="manual-text">
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
<section class="Sh">
|
||||||
<b class="Nm" title="Nm">rgbds</b> — <span class="Nd" title="Nd">object
|
<h1 class="Sh" id="NAME"><a class="permalink" href="#NAME">NAME</a></h1>
|
||||||
file format documentation</span>
|
<code class="Nm">rgbds</code> —
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
<div class="Nd">object file format documentation</div>
|
||||||
This is the description of the object files used by
|
</section>
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a> and
|
<section class="Sh">
|
||||||
<a class="Xr" title="Xr">rgblink(1)</a>. Please, note that the specifications
|
<h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
||||||
may change. This toolchain is in development and new features may require
|
This is the description of the object files used by <a class="Xr">rgbasm(1)</a>
|
||||||
adding more information to the current format, or modifying some fields, which
|
and <a class="Xr">rgblink(1)</a>. Please, note that the specifications may
|
||||||
would break compatibility with older versions.
|
change. This toolchain is in development and new features may require adding
|
||||||
<h1 class="Sh" title="Sh" id="FILE_STRUCTURE"><a class="selflink" href="#FILE_STRUCTURE">FILE
|
more information to the current format, or modifying some fields, which would
|
||||||
|
break compatibility with older versions.
|
||||||
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="FILE_STRUCTURE"><a class="permalink" href="#FILE_STRUCTURE">FILE
|
||||||
STRUCTURE</a></h1>
|
STRUCTURE</a></h1>
|
||||||
The following types are used:
|
The following types are used:
|
||||||
<div class="Pp"></div>
|
<p class="Pp"><var class="Ar">LONG</var> is a 32‐bit integer stored in
|
||||||
<var class="Ar" title="Ar">LONG</var> is a 32‐bit integer stored in
|
little‐endian format (Intel). <var class="Ar">BYTE</var> is an
|
||||||
little‐endian format (Intel). <var class="Ar" title="Ar">BYTE</var> is
|
8‐bit integer. <var class="Ar">STRING</var> is a 0‐terminated
|
||||||
an 8‐bit integer. <var class="Ar" title="Ar">STRING</var> is a
|
string of <var class="Ar">BYTE</var>.</p>
|
||||||
0‐terminated string of <var class="Ar" title="Ar">BYTE</var>.
|
<div class="Bd Pp">
|
||||||
<div class="Pp"></div>
|
<pre>
|
||||||
<div class="Bd" style="margin-left: 0.00ex;">
|
|
||||||
<pre class="Li">
|
|
||||||
; Header
|
; Header
|
||||||
|
|
||||||
BYTE ID[4] ; "RGB6"
|
BYTE ID[4] ; "RGB6"
|
||||||
@@ -55,7 +58,7 @@ REPT NumberOfSymbols ; Number of symbols defined in this object file.
|
|||||||
; as "Scope.Symbol".
|
; as "Scope.Symbol".
|
||||||
|
|
||||||
BYTE Type ; 0 = LOCAL symbol only used in this file.
|
BYTE Type ; 0 = LOCAL symbol only used in this file.
|
||||||
; 1 = IMPORT this symbol from elsewhere (unused).
|
; 1 = IMPORT this symbol from elsewhere
|
||||||
; 2 = EXPORT this symbol to other objects.
|
; 2 = EXPORT this symbol to other objects.
|
||||||
|
|
||||||
IF Type != 1 ; If symbol is defined in this object file.
|
IF Type != 1 ; If symbol is defined in this object file.
|
||||||
@@ -137,7 +140,8 @@ REPT NumberOfSections
|
|||||||
ENDR
|
ENDR
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="Ss" title="Ss" id="RPN_DATA"><a class="selflink" href="#RPN_DATA">RPN
|
<section class="Ss">
|
||||||
|
<h2 class="Ss" id="RPN_DATA"><a class="permalink" href="#RPN_DATA">RPN
|
||||||
DATA</a></h2>
|
DATA</a></h2>
|
||||||
Expressions in the object file are stored as RPN. This is an expression of the
|
Expressions in the object file are stored as RPN. This is an expression of the
|
||||||
form “2 5 +”. This will first push the value “2”
|
form “2 5 +”. This will first push the value “2”
|
||||||
@@ -146,159 +150,160 @@ Expressions in the object file are stored as RPN. This is an expression of the
|
|||||||
effectively replacing the two top arguments with their sum. In the RGB format,
|
effectively replacing the two top arguments with their sum. In the RGB format,
|
||||||
RPN expressions are stored as BYTEs with some bytes being special prefixes for
|
RPN expressions are stored as BYTEs with some bytes being special prefixes for
|
||||||
integers and symbols.
|
integers and symbols.
|
||||||
<table class="Bl-column" style="margin-left: 6.00ex;">
|
<table class="Bl-column Bd-indent">
|
||||||
<colgroup>
|
<tr>
|
||||||
<col style="width: 15.00ex;"/>
|
<td><b class="Sy">Value</b></td>
|
||||||
<col style="min-width: 10.00ex;"/>
|
<td><b class="Sy">Meaning</b></td>
|
||||||
</colgroup>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><b class="Sy" title="Sy">Value</b></td>
|
|
||||||
<td class="It-column"><b class="Sy" title="Sy">Meaning</b></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$00"><code class="Li" id="$00">$00</code></a></td>
|
<td><a class="permalink" href="#$00"><code class="Li" id="$00">$00</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#+_operator"><code class="Li" id="+_operator">+
|
<td><a class="permalink" href="#+_operator"><code class="Li" id="+_operator">+
|
||||||
operator</code></a></td>
|
operator</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$01"><code class="Li" id="$01">$01</code></a></td>
|
<td><a class="permalink" href="#$01"><code class="Li" id="$01">$01</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#-_operator"><code class="Li" id="-_operator">-
|
<td><a class="permalink" href="#-_operator"><code class="Li" id="-_operator">-
|
||||||
operator</code></a></td>
|
operator</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$02"><code class="Li" id="$02">$02</code></a></td>
|
<td><a class="permalink" href="#$02"><code class="Li" id="$02">$02</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#*_operator"><code class="Li" id="*_operator">*
|
<td><a class="permalink" href="#*_operator"><code class="Li" id="*_operator">*
|
||||||
operator</code></a></td>
|
operator</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$03"><code class="Li" id="$03">$03</code></a></td>
|
<td><a class="permalink" href="#$03"><code class="Li" id="$03">$03</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#/_operator"><code class="Li" id="/_operator">/
|
<td><a class="permalink" href="#/_operator"><code class="Li" id="/_operator">/
|
||||||
operator</code></a></td>
|
operator</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$04"><code class="Li" id="$04">$04</code></a></td>
|
<td><a class="permalink" href="#$04"><code class="Li" id="$04">$04</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#%_operator"><code class="Li" id="%_operator">%
|
<td><a class="permalink" href="#__operator"><code class="Li" id="__operator">%
|
||||||
operator</code></a></td>
|
operator</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$05"><code class="Li" id="$05">$05</code></a></td>
|
<td><a class="permalink" href="#$05"><code class="Li" id="$05">$05</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#unary_-"><code class="Li" id="unary_-">unary
|
<td><a class="permalink" href="#unary_-"><code class="Li" id="unary_-">unary
|
||||||
-</code></a></td>
|
-</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$10"><code class="Li" id="$10">$10</code></a></td>
|
<td><a class="permalink" href="#$10"><code class="Li" id="$10">$10</code></a></td>
|
||||||
<td class="It-column">|
|
<td>|
|
||||||
<a class="selflink" href="#operator"><code class="Li" id="operator">operator</code></a></td>
|
<a class="permalink" href="#operator"><code class="Li" id="operator">operator</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$11"><code class="Li" id="$11">$11</code></a></td>
|
<td><a class="permalink" href="#$11"><code class="Li" id="$11">$11</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#&_operator"><code class="Li" id="&_operator">&
|
<td><a class="permalink" href="#&_operator"><code class="Li" id="&_operator">&
|
||||||
operator</code></a></td>
|
operator</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$12"><code class="Li" id="$12">$12</code></a></td>
|
<td><a class="permalink" href="#$12"><code class="Li" id="$12">$12</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#^_operator"><code class="Li" id="^_operator">^
|
<td><a class="permalink" href="#__operator_2"><code class="Li" id="__operator_2">^
|
||||||
operator</code></a></td>
|
operator</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$13"><code class="Li" id="$13">$13</code></a></td>
|
<td><a class="permalink" href="#$13"><code class="Li" id="$13">$13</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#unary_~"><code class="Li" id="unary_~">unary
|
<td><a class="permalink" href="#unary_~"><code class="Li" id="unary_~">unary
|
||||||
~</code></a></td>
|
~</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$21"><code class="Li" id="$21">$21</code></a></td>
|
<td><a class="permalink" href="#$21"><code class="Li" id="$21">$21</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#&&_comparison"><code class="Li" id="&&_comparison">&&
|
<td><a class="permalink" href="#&&_comparison"><code class="Li" id="&&_comparison">&&
|
||||||
comparison</code></a></td>
|
comparison</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$22"><code class="Li" id="$22">$22</code></a></td>
|
<td><a class="permalink" href="#$22"><code class="Li" id="$22">$22</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#||_comparison"><code class="Li" id="||_comparison">||
|
<td><a class="permalink" href="#___comparison"><code class="Li" id="___comparison">||
|
||||||
comparison</code></a></td>
|
comparison</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$23"><code class="Li" id="$23">$23</code></a></td>
|
<td><a class="permalink" href="#$23"><code class="Li" id="$23">$23</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#unary"><code class="Li" id="unary">unary</code></a>!</td>
|
<td><a class="permalink" href="#unary"><code class="Li" id="unary">unary</code></a>!</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$30"><code class="Li" id="$30">$30</code></a></td>
|
<td><a class="permalink" href="#$30"><code class="Li" id="$30">$30</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#==_comparison"><code class="Li" id="==_comparison">==
|
<td><a class="permalink" href="#==_comparison"><code class="Li" id="==_comparison">==
|
||||||
comparison</code></a></td>
|
comparison</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$31"><code class="Li" id="$31">$31</code></a></td>
|
<td><a class="permalink" href="#$31"><code class="Li" id="$31">$31</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#!=_comparison"><code class="Li" id="!=_comparison">!=
|
<td><a class="permalink" href="#!=_comparison"><code class="Li" id="!=_comparison">!=
|
||||||
comparison</code></a></td>
|
comparison</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$32"><code class="Li" id="$32">$32</code></a></td>
|
<td><a class="permalink" href="#$32"><code class="Li" id="$32">$32</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#>_comparison"><code class="Li" id=">_comparison">>
|
<td><a class="permalink" href="#__comparison"><code class="Li" id="__comparison">>
|
||||||
comparison</code></a></td>
|
comparison</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$33"><code class="Li" id="$33">$33</code></a></td>
|
<td><a class="permalink" href="#$33"><code class="Li" id="$33">$33</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#<_comparison"><code class="Li" id="<_comparison"><
|
<td><a class="permalink" href="#__comparison_2"><code class="Li" id="__comparison_2"><
|
||||||
comparison</code></a></td>
|
comparison</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$34"><code class="Li" id="$34">$34</code></a></td>
|
<td><a class="permalink" href="#$34"><code class="Li" id="$34">$34</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#>=_comparison"><code class="Li" id=">=_comparison">>=
|
<td><a class="permalink" href="#_=_comparison"><code class="Li" id="_=_comparison">>=
|
||||||
comparison</code></a></td>
|
comparison</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$35"><code class="Li" id="$35">$35</code></a></td>
|
<td><a class="permalink" href="#$35"><code class="Li" id="$35">$35</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#<=_comparison"><code class="Li" id="<=_comparison"><=
|
<td><a class="permalink" href="#_=_comparison_2"><code class="Li" id="_=_comparison_2"><=
|
||||||
comparison</code></a></td>
|
comparison</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$40"><code class="Li" id="$40">$40</code></a></td>
|
<td><a class="permalink" href="#$40"><code class="Li" id="$40">$40</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#<<_comparison"><code class="Li" id="<<_comparison"><<
|
<td><a class="permalink" href="#___operator"><code class="Li" id="___operator"><<
|
||||||
comparison</code></a></td>
|
operator</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$41"><code class="Li" id="$41">$41</code></a></td>
|
<td><a class="permalink" href="#$41"><code class="Li" id="$41">$41</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#>>_comparison"><code class="Li" id=">>_comparison">>>
|
<td><a class="permalink" href="#___operator_2"><code class="Li" id="___operator_2">>>
|
||||||
comparison</code></a></td>
|
operator</code></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$50"><code class="Li" id="$50">$50</code></a></td>
|
<td><a class="permalink" href="#$50"><code class="Li" id="$50">$50</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#BANK(symbol),"><code class="Li" id="BANK(symbol),">BANK(symbol),</code></a>
|
<td><a class="permalink" href="#BANK(symbol),"><code class="Li" id="BANK(symbol),">BANK(symbol),</code></a>
|
||||||
a <var class="Ar" title="Ar">LONG</var> Symbol ID follows.</td>
|
a <var class="Ar">LONG</var> Symbol ID follows.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$51"><code class="Li" id="$51">$51</code></a></td>
|
<td><a class="permalink" href="#$51"><code class="Li" id="$51">$51</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#BANK(section_name),"><code class="Li" id="BANK(section_name),">BANK(section_name),</code></a>
|
<td><a class="permalink" href="#BANK(section_name),"><code class="Li" id="BANK(section_name),">BANK(section_name),</code></a>
|
||||||
a null-terminated string follows.</td>
|
a null-terminated string follows.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$52"><code class="Li" id="$52">$52</code></a></td>
|
<td><a class="permalink" href="#$52"><code class="Li" id="$52">$52</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#Current_BANK()"><code class="Li" id="Current_BANK()">Current
|
<td><a class="permalink" href="#Current_BANK()"><code class="Li" id="Current_BANK()">Current
|
||||||
BANK()</code></a>.</td>
|
BANK()</code></a>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$60"><code class="Li" id="$60">$60</code></a></td>
|
<td><a class="permalink" href="#$60"><code class="Li" id="$60">$60</code></a></td>
|
||||||
<td class="It-column"><a class="selflink" href="#HRAMCheck."><code class="Li" id="HRAMCheck.">HRAMCheck.</code></a>
|
<td><a class="permalink" href="#HRAMCheck."><code class="Li" id="HRAMCheck.">HRAMCheck.</code></a>
|
||||||
Check if the value is in HRAM, AND it with 0xFF.</td>
|
Check if the value is in HRAM, AND it with 0xFF.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$80"><code class="Li" id="$80">$80</code></a></td>
|
<td><a class="permalink" href="#$80"><code class="Li" id="$80">$80</code></a></td>
|
||||||
<td class="It-column"><var class="Ar" title="Ar">LONG</var> integer
|
<td><var class="Ar">LONG</var> integer follows.</td>
|
||||||
follows.</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="It-column">
|
<tr>
|
||||||
<td class="It-column"><a class="selflink" href="#$81"><code class="Li" id="$81">$81</code></a></td>
|
<td><a class="permalink" href="#$81"><code class="Li" id="$81">$81</code></a></td>
|
||||||
<td class="It-column"><var class="Ar" title="Ar">LONG</var> Symbol ID
|
<td><var class="Ar">LONG</var> Symbol ID follows.</td>
|
||||||
follows.</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
</section>
|
||||||
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
|
||||||
ALSO</a></h1>
|
ALSO</a></h1>
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(1)</a>,
|
<a class="Xr">rgbasm(1)</a>, <a class="Xr">rgblink(1)</a>,
|
||||||
<a class="Xr" title="Xr">rgbds(7)</a>, <a class="Xr" title="Xr">gbz80(7)</a>
|
<a class="Xr">rgbds(7)</a>, <a class="Xr">gbz80(7)</a>
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
</section>
|
||||||
<b class="Nm" title="Nm">rgbds</b> was originally written by Carsten
|
<section class="Sh">
|
||||||
Sørensen as part of the ASMotor package, and was later packaged in
|
<h1 class="Sh" id="HISTORY"><a class="permalink" href="#HISTORY">HISTORY</a></h1>
|
||||||
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
<code class="Nm">rgbds</code> was originally written by Carsten Sørensen
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
as part of the ASMotor package, and was later packaged in RGBDS by Justin
|
||||||
|
Lloyd. It is now maintained by a number of contributors at
|
||||||
|
<a class="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
<table class="foot">
|
<table class="foot">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="foot-date">January 26, 2018</td>
|
<td class="foot-date">January 26, 2018</td>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<!-- This is an automatically generated file. Do not edit.
|
||||||
|
This file is part of RGBDS.
|
||||||
|
|
||||||
|
Copyright (c) 2010-2018, Anthony J. Bentley and RGBDS contributors.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
||||||
<title>RGBDS(7)</title>
|
<title>RGBDS(7)</title>
|
||||||
</head>
|
</head>
|
||||||
@@ -20,46 +21,52 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="manual-text">
|
<div class="manual-text">
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
<section class="Sh">
|
||||||
<b class="Nm" title="Nm">rgbds</b> — <span class="Nd" title="Nd">Rednex
|
<h1 class="Sh" id="NAME"><a class="permalink" href="#NAME">NAME</a></h1>
|
||||||
Game Boy Development System</span>
|
<code class="Nm">rgbds</code> —
|
||||||
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
|
<div class="Nd">Rednex Game Boy Development System</div>
|
||||||
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="EXAMPLES"><a class="permalink" href="#EXAMPLES">EXAMPLES</a></h1>
|
||||||
To get a working ROM image from a single assembly source file:
|
To get a working ROM image from a single assembly source file:
|
||||||
<div class="Pp"></div>
|
<div class="Bd Pp Bd-indent">
|
||||||
<div class="Bd" style="margin-left: 5.00ex;">
|
<pre>
|
||||||
<pre class="Li">
|
|
||||||
$ rgbasm -o bar.o foo.asm
|
$ rgbasm -o bar.o foo.asm
|
||||||
$ rgblink -o baz.gb bar.o
|
$ rgblink -o baz.gb bar.o
|
||||||
$ rgbfix -v -p 0 baz.gb
|
$ rgbfix -v -p 0 baz.gb
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
|
||||||
ALSO</a></h1>
|
ALSO</a></h1>
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgbfix(1)</a>,
|
<a class="Xr">rgbasm(1)</a>, <a class="Xr">rgbfix(1)</a>,
|
||||||
<a class="Xr" title="Xr">rgblink(1)</a>,
|
<a class="Xr">rgblink(1)</a>, <a class="Xr">rgbds(5)</a>,
|
||||||
<a class="Xr" title="Xr">rgbds(5)</a>, <a class="Xr" title="Xr">gbz80(7)</a>
|
<a class="Xr">gbz80(7)</a>
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="HISTORY"><a class="permalink" href="#HISTORY">HISTORY</a></h1>
|
||||||
<dl class="Bl-ohang">
|
<dl class="Bl-ohang">
|
||||||
<dt class="It-ohang"></dt>
|
<dt></dt>
|
||||||
<dd class="It-ohang">1997, Carsten Sørensen (AKA SurfSmurf) writes
|
<dd>1997, Carsten Sørensen (AKA SurfSmurf) writes ASMotor as a
|
||||||
ASMotor as a general-purpose assembler/linker system for DOS/Win32.</dd>
|
general-purpose assembler/linker system for DOS/Win32.</dd>
|
||||||
<dt class="It-ohang"></dt>
|
<dt></dt>
|
||||||
<dd class="It-ohang">1999, Justin Lloyd (AKA Otaku no Zoku) adapts ASMotor to
|
<dd>1999, Justin Lloyd (AKA Otaku no Zoku) adapts ASMotor to read and produce
|
||||||
read and produce GBZ80 assembly/machine code, and releases this version as
|
GBZ80 assembly/machine code, and releases this version as RGBDS.</dd>
|
||||||
RGBDS.</dd>
|
<dt></dt>
|
||||||
<dt class="It-ohang"></dt>
|
<dd>2009, Vegard Nossum adapts the code to be more UNIX-like and releases this
|
||||||
<dd class="It-ohang">2009, Vegard Nossum adapts the code to be more UNIX-like
|
version as rgbds-linux on GitHub.</dd>
|
||||||
and releases this version as rgbds-linux on GitHub.</dd>
|
<dt></dt>
|
||||||
<dt class="It-ohang"></dt>
|
<dd>2010, Anthony J. Bentley forks that repository. The fork becomes the
|
||||||
<dd class="It-ohang">2010, Anthony J. Bentley forks that repository. The fork
|
reference implementation of rgbds.</dd>
|
||||||
becomes the reference implementation of rgbds.</dd>
|
<dt></dt>
|
||||||
<dt class="It-ohang"></dt>
|
<dd>2017, Bentley's repository is moved to a neutral name. It is now
|
||||||
<dd class="It-ohang">2017, Bentley's repository is moved to a neutral name. It
|
maintained by a number of contributors at
|
||||||
is now maintained by a number of contributors at
|
<a class="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</dd>
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</dd>
|
<dt></dt>
|
||||||
<dt class="It-ohang"></dt>
|
<dd>2018, codebase relicensed under the MIT license.</dd>
|
||||||
<dd class="It-ohang">2018, codebase relicensed under the MIT license.</dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<table class="foot">
|
<table class="foot">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<!-- This is an automatically generated file. Do not edit.
|
||||||
|
This file is part of RGBDS.
|
||||||
|
|
||||||
|
Copyright (c) 2010-2017, Anthony J. Bentley and RGBDS contributors.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
||||||
<title>RGBFIX(1)</title>
|
<title>RGBFIX(1)</title>
|
||||||
</head>
|
</head>
|
||||||
@@ -20,189 +21,158 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="manual-text">
|
<div class="manual-text">
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
<section class="Sh">
|
||||||
<b class="Nm" title="Nm">rgbfix</b> — <span class="Nd" title="Nd">Game
|
<h1 class="Sh" id="NAME"><a class="permalink" href="#NAME">NAME</a></h1>
|
||||||
Boy checksum fixer</span>
|
<code class="Nm">rgbfix</code> —
|
||||||
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
<div class="Nd">Game Boy checksum fixer</div>
|
||||||
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SYNOPSIS"><a class="permalink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
||||||
<table class="Nm">
|
<table class="Nm">
|
||||||
<tr>
|
<tr>
|
||||||
<td><b class="Nm" title="Nm">rgbfix</b></td>
|
<td><code class="Nm">rgbfix</code></td>
|
||||||
<td>[<span class="Op"><b class="Fl" title="Fl">-CcjsVv</b></span>]
|
<td>[<code class="Fl">-CcjsVv</code>] [<code class="Fl">-f</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-f</b>
|
<var class="Ar">fix_spec</var>] [<code class="Fl">-i</code>
|
||||||
<var class="Ar" title="Ar">fix_spec</var></span>]
|
<var class="Ar">game_id</var>] [<code class="Fl">-k</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-i</b>
|
<var class="Ar">licensee_str</var>] [<code class="Fl">-l</code>
|
||||||
<var class="Ar" title="Ar">game_id</var></span>]
|
<var class="Ar">licensee_id</var>] [<code class="Fl">-m</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-k</b>
|
<var class="Ar">mbc_type</var>] [<code class="Fl">-n</code>
|
||||||
<var class="Ar" title="Ar">licensee_str</var></span>]
|
<var class="Ar">rom_version</var>] [<code class="Fl">-p</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-l</b>
|
<var class="Ar">pad_value</var>] [<code class="Fl">-r</code>
|
||||||
<var class="Ar" title="Ar">licensee_id</var></span>]
|
<var class="Ar">ram_size</var>] [<code class="Fl">-t</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-m</b>
|
<var class="Ar">title_str</var>] <var class="Ar">file</var></td>
|
||||||
<var class="Ar" title="Ar">mbc_type</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-n</b>
|
|
||||||
<var class="Ar" title="Ar">rom_version</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-p</b>
|
|
||||||
<var class="Ar" title="Ar">pad_value</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-r</b>
|
|
||||||
<var class="Ar" title="Ar">ram_size</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-t</b>
|
|
||||||
<var class="Ar" title="Ar">title_str</var></span>]
|
|
||||||
<var class="Ar" title="Ar">file</var></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
</section>
|
||||||
The <b class="Nm" title="Nm">rgbfix</b> program changes headers of Game Boy ROM
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
||||||
|
The <code class="Nm">rgbfix</code> program changes headers of Game Boy ROM
|
||||||
images. It also performs other filetype operations, such as truncation. The
|
images. It also performs other filetype operations, such as truncation. The
|
||||||
arguments are as follows:
|
arguments are as follows:
|
||||||
<dl class="Bl-tag">
|
<dl class="Bl-tag">
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#C"><code class="Fl" id="C">-C</code></a></dt>
|
||||||
<dd class="It-tag"> </dd>
|
<dd>Set the Game Boy Color–only flag: <span class="Ad">0x143</span> =
|
||||||
<dt class="It-tag"><a class="selflink" href="#C"><b class="Fl" title="Fl" id="C">-C</b></a></dt>
|
0xC0. If both this and the <code class="Fl">-c</code> flag are set, this
|
||||||
<dd class="It-tag">Set the Game Boy Color–only flag:
|
takes precedence.</dd>
|
||||||
<i class="Ad">0x143</i> = 0xC0. If both this and the
|
<dt><a class="permalink" href="#c"><code class="Fl" id="c">-c</code></a></dt>
|
||||||
<b class="Fl" title="Fl">-c</b> flag are set, this takes precedence.</dd>
|
<dd>Set the Game Boy Color–compatible flag:
|
||||||
<dt class="It-tag"> </dt>
|
<span class="Ad">0x143</span> = 0x80. If both this and the
|
||||||
<dd class="It-tag"> </dd>
|
<code class="Fl">-C</code> flag are set, <code class="Fl">-C</code> takes
|
||||||
<dt class="It-tag"><a class="selflink" href="#c"><b class="Fl" title="Fl" id="c">-c</b></a></dt>
|
precedence.</dd>
|
||||||
<dd class="It-tag">Set the Game Boy Color–compatible flag:
|
<dt><a class="permalink" href="#f"><code class="Fl" id="f">-f</code></a>
|
||||||
<i class="Ad">0x143</i> = 0x80. If both this and the
|
<var class="Ar">fix_spec</var></dt>
|
||||||
<b class="Fl" title="Fl">-C</b> flag are set,
|
<dd>Fix certain header values that the Game Boy checks for correctness.
|
||||||
<b class="Fl" title="Fl">-C</b> takes precedence.</dd>
|
Alternatively, intentionally trash these values by writing their binary
|
||||||
<dt class="It-tag"> </dt>
|
inverse instead. <var class="Ar">fix_spec</var> is a string containing any
|
||||||
<dd class="It-tag"> </dd>
|
combination of the following characters:
|
||||||
<dt class="It-tag"><a class="selflink" href="#f"><b class="Fl" title="Fl" id="f">-f</b></a>
|
<p class="Pp"></p>
|
||||||
<var class="Ar" title="Ar">fix_spec</var></dt>
|
<dl class="Bl-tag Bl-compact">
|
||||||
<dd class="It-tag">Fix certain header values that the Game Boy checks for
|
<dt><a class="permalink" href="#l"><code class="Cm" id="l">l</code></a></dt>
|
||||||
correctness. Alternatively, intentionally trash these values by writing
|
<dd>Fix the Nintendo logo
|
||||||
their binary inverse instead. <var class="Ar" title="Ar">fix_spec</var> is
|
(<span class="Ad">0x104</span>–<span class="Ad">0x133</span>).</dd>
|
||||||
a string containing any combination of the following characters:
|
<dt><a class="permalink" href="#L"><code class="Cm" id="L">L</code></a></dt>
|
||||||
<div class="Pp"></div>
|
<dd>Trash the Nintendo logo.</dd>
|
||||||
<dl class="Bl-tag Bl-compact" style="margin-left: 5.40ex;">
|
<dt><a class="permalink" href="#h"><code class="Cm" id="h">h</code></a></dt>
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#l"><b class="Cm" title="Cm" id="l">l</b></a></dt>
|
<dd>Fix the header checksum (<span class="Ad">0x14D</span>).</dd>
|
||||||
<dd class="It-tag">Fix the Nintendo logo
|
<dt><a class="permalink" href="#H"><code class="Cm" id="H">H</code></a></dt>
|
||||||
(<i class="Ad">0x104</i>–<i class="Ad">0x133</i>).</dd>
|
<dd>Trash the header checksum.</dd>
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#L"><b class="Cm" title="Cm" id="L">L</b></a></dt>
|
<dt><a class="permalink" href="#g"><code class="Cm" id="g">g</code></a></dt>
|
||||||
<dd class="It-tag">Trash the Nintendo logo.</dd>
|
<dd>Fix the global checksum
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#h"><b class="Cm" title="Cm" id="h">h</b></a></dt>
|
(<span class="Ad">0x14E</span>–<span class="Ad">0x14F</span>).</dd>
|
||||||
<dd class="It-tag">Fix the header checksum (<i class="Ad">0x14D</i>).</dd>
|
<dt><a class="permalink" href="#G"><code class="Cm" id="G">G</code></a></dt>
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#H"><b class="Cm" title="Cm" id="H">H</b></a></dt>
|
<dd>Trash the global checksum.</dd>
|
||||||
<dd class="It-tag">Trash the header checksum.</dd>
|
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#g"><b class="Cm" title="Cm" id="g">g</b></a></dt>
|
|
||||||
<dd class="It-tag">Fix the global checksum
|
|
||||||
(<i class="Ad">0x14E</i>–<i class="Ad">0x14F</i>).</dd>
|
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#G"><b class="Cm" title="Cm" id="G">G</b></a></dt>
|
|
||||||
<dd class="It-tag">Trash the global checksum.</dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#i"><code class="Fl" id="i">-i</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">game_id</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#i"><b class="Fl" title="Fl" id="i">-i</b></a>
|
<dd>Set the game ID string
|
||||||
<var class="Ar" title="Ar">game_id</var></dt>
|
(<span class="Ad">0x13F</span>–<span class="Ad">0x142</span>) to a
|
||||||
<dd class="It-tag">Set the game ID string
|
given string of exactly 4 characters. If both this and the title are set,
|
||||||
(<i class="Ad">0x13F</i>–<i class="Ad">0x142</i>) to a given string
|
the game ID will overwrite the overlapping portion of the title.</dd>
|
||||||
of exactly 4 characters. If both this and the title are set, the game ID
|
<dt><a class="permalink" href="#j"><code class="Fl" id="j">-j</code></a></dt>
|
||||||
will overwrite the overlapping portion of the title.</dd>
|
<dd>Set the non-Japanese region flag: <span class="Ad">0x14A</span> = 1.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#k"><code class="Fl" id="k">-k</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">licensee_str</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#j"><b class="Fl" title="Fl" id="j">-j</b></a></dt>
|
<dd>Set the new licensee string
|
||||||
<dd class="It-tag">Set the non-Japanese region flag: <i class="Ad">0x14A</i> =
|
(<span class="Ad">0x144</span>–<span class="Ad">0x145</span>) to a
|
||||||
1.</dd>
|
given string, truncated to at most two characters.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#l_2"><code class="Fl" id="l_2">-l</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">licensee_id</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#k"><b class="Fl" title="Fl" id="k">-k</b></a>
|
<dd>Set the old licensee code, <span class="Ad">0x14B</span>, to a given value
|
||||||
<var class="Ar" title="Ar">licensee_str</var></dt>
|
from 0 to 0xFF. This value is deprecated and should be set to 0x33 in all
|
||||||
<dd class="It-tag">Set the new licensee string
|
new software.</dd>
|
||||||
(<i class="Ad">0x144</i>–<i class="Ad">0x145</i>) to a given
|
<dt><a class="permalink" href="#m"><code class="Fl" id="m">-m</code></a>
|
||||||
string, truncated to at most two characters.</dd>
|
<var class="Ar">mbc_type</var></dt>
|
||||||
<dt class="It-tag"> </dt>
|
<dd>Set the MBC type, <span class="Ad">0x147</span>, to a given value from 0
|
||||||
<dd class="It-tag"> </dd>
|
to 0xFF.</dd>
|
||||||
<dt class="It-tag"><a class="selflink" href="#l"><b class="Fl" title="Fl" id="l">-l</b></a>
|
<dt><a class="permalink" href="#n"><code class="Fl" id="n">-n</code></a>
|
||||||
<var class="Ar" title="Ar">licensee_id</var></dt>
|
<var class="Ar">rom_version</var></dt>
|
||||||
<dd class="It-tag">Set the old licensee code, <i class="Ad">0x14B</i>, to a
|
<dd>Set the ROM version, <span class="Ad">0x14C</span>, to a given value from
|
||||||
given value from 0 to 0xFF. This value is deprecated and should be set to
|
0 to 0xFF.</dd>
|
||||||
0x33 in all new software.</dd>
|
<dt><a class="permalink" href="#p"><code class="Fl" id="p">-p</code></a>
|
||||||
<dt class="It-tag"> </dt>
|
<var class="Ar">pad_value</var></dt>
|
||||||
<dd class="It-tag"> </dd>
|
<dd>Pad the image to a valid size with a given pad value from 0 to 0xFF.
|
||||||
<dt class="It-tag"><a class="selflink" href="#m"><b class="Fl" title="Fl" id="m">-m</b></a>
|
<code class="Nm">rgbfix</code> will automatically pick a size from 32KiB,
|
||||||
<var class="Ar" title="Ar">mbc_type</var></dt>
|
64KiB, 128KiB, ..., 8192KiB and give a warning thereafter. The cartridge
|
||||||
<dd class="It-tag">Set the MBC type, <i class="Ad">0x147</i>, to a given value
|
size byte (<span class="Ad">0x148</span>) will be changed to reflect this
|
||||||
from 0 to 0xFF.</dd>
|
new size.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#r"><code class="Fl" id="r">-r</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">ram_size</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#n"><b class="Fl" title="Fl" id="n">-n</b></a>
|
<dd>Set the RAM size, <span class="Ad">0x149</span>, to a given value from 0
|
||||||
<var class="Ar" title="Ar">rom_version</var></dt>
|
to 0xFF.</dd>
|
||||||
<dd class="It-tag">Set the ROM version, <i class="Ad">0x14C</i>, to a given
|
<dt><a class="permalink" href="#s"><code class="Fl" id="s">-s</code></a></dt>
|
||||||
value from 0 to 0xFF.</dd>
|
<dd>Set the SGB flag: <span class="Ad">0x146</span> = 3.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#t"><code class="Fl" id="t">-t</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">title</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
|
<dd>Set the title string
|
||||||
<var class="Ar" title="Ar">pad_value</var></dt>
|
(<span class="Ad">0x134</span>–<span class="Ad">0x143</span>) to a
|
||||||
<dd class="It-tag">Pad the image to a valid size with a given pad value from 0
|
given string, truncated to at most 16 characters. It is recommended to use
|
||||||
to 0xFF. <b class="Nm" title="Nm">rgbfix</b> will automatically pick a
|
15 characters instead, to avoid clashing with the CGB flag
|
||||||
size from 32KiB, 64KiB, 128KiB, ..., 8192KiB and give a warning
|
(<code class="Fl">-c</code> or <code class="Fl">-C</code>). If both this
|
||||||
thereafter. The cartridge size byte (<i class="Ad">0x148</i>) will be
|
and the game ID are set, the game ID will overwrite the overlapping
|
||||||
changed to reflect this new size.</dd>
|
portion of the title.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#V"><code class="Fl" id="V">-V</code></a></dt>
|
||||||
<dd class="It-tag"> </dd>
|
<dd>Print the version of the program and exit.</dd>
|
||||||
<dt class="It-tag"><a class="selflink" href="#r"><b class="Fl" title="Fl" id="r">-r</b></a>
|
<dt><a class="permalink" href="#v"><code class="Fl" id="v">-v</code></a></dt>
|
||||||
<var class="Ar" title="Ar">ram_size</var></dt>
|
<dd>Equivalent to <code class="Fl">-f</code> <code class="Cm">lhg</code>.</dd>
|
||||||
<dd class="It-tag">Set the RAM size, <i class="Ad">0x149</i>, to a given value
|
|
||||||
from 0 to 0xFF.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#s"><b class="Fl" title="Fl" id="s">-s</b></a></dt>
|
|
||||||
<dd class="It-tag">Set the SGB flag: <i class="Ad">0x146</i> = 3.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#t"><b class="Fl" title="Fl" id="t">-t</b></a>
|
|
||||||
<var class="Ar" title="Ar">title</var></dt>
|
|
||||||
<dd class="It-tag">Set the title string
|
|
||||||
(<i class="Ad">0x134</i>–<i class="Ad">0x143</i>) to a given
|
|
||||||
string, truncated to at most 16 characters. It is recommended to use 15
|
|
||||||
characters instead, to avoid clashing with the CGB flag
|
|
||||||
(<b class="Fl" title="Fl">-c</b> or <b class="Fl" title="Fl">-C</b>). If
|
|
||||||
both this and the game ID are set, the game ID will overwrite the
|
|
||||||
overlapping portion of the title.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
|
|
||||||
<dd class="It-tag">Print the version of the program and exit.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#v"><b class="Fl" title="Fl" id="v">-v</b></a></dt>
|
|
||||||
<dd class="It-tag">Equivalent to <b class="Fl" title="Fl">-f</b>
|
|
||||||
<b class="Cm" title="Cm">lhg</b>.</dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="EXAMPLES"><a class="permalink" href="#EXAMPLES">EXAMPLES</a></h1>
|
||||||
Most values in the ROM header are only cosmetic. The bare minimum requirements
|
Most values in the ROM header are only cosmetic. The bare minimum requirements
|
||||||
for a workable image are checksums, the Nintendo logo, and (if needed) the
|
for a workable image are checksums, the Nintendo logo, and (if needed) the
|
||||||
CGB/SGB flags. It is a good idea to pad the image to a valid size as well
|
CGB/SGB flags. It is a good idea to pad the image to a valid size as well
|
||||||
(“valid” meaning a multiple of 32KiB).
|
(“valid” meaning a multiple of 32KiB).
|
||||||
<div class="Pp"></div>
|
<p class="Pp">The following will make a plain, no-color Game Boy game without
|
||||||
The following will make a plain, no-color Game Boy game without checking for a
|
checking for a valid size:</p>
|
||||||
valid size:
|
<p class="Pp"></p>
|
||||||
<div class="Pp"></div>
|
<div class="Bd Bd-indent">$ rgbfix -v foo.gb</div>
|
||||||
<div class="D1">$ rgbfix -v foo.gb</div>
|
<p class="Pp">The following will make a SGB-enabled, color-enabled game with a
|
||||||
<div class="Pp"></div>
|
title of “foobar”, and pad it to a multiple of 32KiB. (The
|
||||||
The following will make a SGB-enabled, color-enabled game with a title of
|
Game Boy itself does not use the title, but some emulators or ROM managers
|
||||||
“foobar”, and pad it to a multiple of 32KiB. (The Game Boy
|
might.)</p>
|
||||||
itself does not use the title, but some emulators or ROM managers might.)
|
<p class="Pp"></p>
|
||||||
<div class="Pp"></div>
|
<div class="Bd Bd-indent">$ rgbfix -vcs -l 0x33 -p 0 -t foobar baz.gb</div>
|
||||||
<div class="D1">$ rgbfix -vcs -l 0x33 -p 0 -t foobar baz.gb</div>
|
<p class="Pp">The following will duplicate the header (sans global checksum) of
|
||||||
<div class="Pp"></div>
|
the game “Survival Kids”:</p>
|
||||||
The following will duplicate the header (sans global checksum) of the game
|
<p class="Pp"></p>
|
||||||
“Survival Kids”:
|
<div class="Bd Bd-indent">$ rgbfix -cjsv -k A4 -l 0x33 -m 0x1B -p 0xFF -r 3 -t
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="D1">$ rgbfix -cjsv -k A4 -l 0x33 -m 0x1B -p 0xFF -r 3 -t
|
|
||||||
SURVIVALKIDAVKE SurvivalKids.gbc</div>
|
SURVIVALKIDAVKE SurvivalKids.gbc</div>
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
|
||||||
ALSO</a></h1>
|
ALSO</a></h1>
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(1)</a>,
|
<a class="Xr">rgbasm(1)</a>, <a class="Xr">rgblink(1)</a>,
|
||||||
<a class="Xr" title="Xr">rgbds(7)</a>
|
<a class="Xr">rgbds(7)</a>
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
</section>
|
||||||
<b class="Nm" title="Nm">rgbfix</b> was originally released by Carsten
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="HISTORY"><a class="permalink" href="#HISTORY">HISTORY</a></h1>
|
||||||
|
<code class="Nm">rgbfix</code> was originally released by Carsten
|
||||||
Sørensen as a standalone program called gbfix, and was later packaged
|
Sørensen as a standalone program called gbfix, and was later packaged
|
||||||
in RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
in RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
<a class="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
<table class="foot">
|
<table class="foot">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="foot-date">March 11, 2018</td>
|
<td class="foot-date">March 11, 2018</td>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<!-- This is an automatically generated file. Do not edit.
|
||||||
|
This file is part of RGBDS.
|
||||||
|
|
||||||
|
Copyright (c) 2013-2018, stag019 and RGBDS contributors.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
||||||
<title>RGBGFX(1)</title>
|
<title>RGBGFX(1)</title>
|
||||||
</head>
|
</head>
|
||||||
@@ -20,151 +21,155 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="manual-text">
|
<div class="manual-text">
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
<section class="Sh">
|
||||||
<b class="Nm" title="Nm">rgbgfx</b> — <span class="Nd" title="Nd">Game
|
<h1 class="Sh" id="NAME"><a class="permalink" href="#NAME">NAME</a></h1>
|
||||||
Boy graphics converter</span>
|
<code class="Nm">rgbgfx</code> —
|
||||||
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
<div class="Nd">Game Boy graphics converter</div>
|
||||||
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SYNOPSIS"><a class="permalink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
||||||
<table class="Nm">
|
<table class="Nm">
|
||||||
<tr>
|
<tr>
|
||||||
<td><b class="Nm" title="Nm">rgbgfx</b></td>
|
<td><code class="Nm">rgbgfx</code></td>
|
||||||
<td>[<span class="Op"><b class="Fl" title="Fl">-DfFhPTVv</b></span>]
|
<td>[<code class="Fl">-ADfFhmPTuVv</code>] [<code class="Fl">-o</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-o</b>
|
<var class="Ar">outfile</var>] [<code class="Fl">-a</code>
|
||||||
<var class="Ar" title="Ar">outfile</var></span>]
|
<var class="Ar">attrmap</var>] [<code class="Fl">-d</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-d</b>
|
<var class="Ar">depth</var>] [<code class="Fl">-p</code>
|
||||||
<var class="Ar" title="Ar">depth</var></span>]
|
<var class="Ar">palfile</var>] [<code class="Fl">-t</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-p</b>
|
<var class="Ar">tilemap</var>] [<code class="Fl">-x</code>
|
||||||
<var class="Ar" title="Ar">palfile</var></span>]
|
<var class="Ar">tiles</var>] <var class="Ar">file</var></td>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-t</b>
|
|
||||||
<var class="Ar" title="Ar">mapfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-x</b>
|
|
||||||
<var class="Ar" title="Ar">tiles</var></span>]
|
|
||||||
<var class="Ar" title="Ar">file</var></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
</section>
|
||||||
The <b class="Nm" title="Nm">rgbgfx</b> program converts PNG images into the
|
<section class="Sh">
|
||||||
Nintendo Game Boy's planar tile format.
|
<h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
||||||
<div style="height: 1.00em;"> </div>
|
The <code class="Nm">rgbgfx</code> program converts PNG images into the Nintendo
|
||||||
The resulting colors and their palette indices are determined differently
|
Game Boy's planar tile format.
|
||||||
depending on the input PNG file:
|
<p class="Pp">The resulting colors and their palette indices are determined
|
||||||
|
differently depending on the input PNG file:</p>
|
||||||
<ul class="Bl-dash">
|
<ul class="Bl-dash">
|
||||||
<li class="It-dash">If the file has an embedded palette, that palette's color
|
<li>If the file has an embedded palette, that palette's color and order are
|
||||||
and order are used.</li>
|
used.</li>
|
||||||
<li class="It-dash">If not, and the image only contains shades of gray, rgbgfx
|
<li>If not, and the image only contains shades of gray, rgbgfx maps them to
|
||||||
maps them to the indices appropriate for each shade. Any undetermined
|
the indices appropriate for each shade. Any undetermined indices are set
|
||||||
indices are set to respective default shades of gray. For example: if the
|
to respective default shades of gray. For example: if the bit depth is 2
|
||||||
bit depth is 2 and the image contains light gray and black, they become
|
and the image contains light gray and black, they become the second and
|
||||||
the second and fourth colors - and the first and third colors get set to
|
fourth colors - and the first and third colors get set to default white
|
||||||
default white and dark gray. If the image has multiple shades that map to
|
and dark gray. If the image has multiple shades that map to the same
|
||||||
the same index, the palette is instead determined as if the image had
|
index, the palette is instead determined as if the image had color.</li>
|
||||||
color.</li>
|
<li>If the image has color (or the grayscale method failed), the colors are
|
||||||
<li class="It-dash">If the image has color (or the grayscale method failed),
|
sorted from lightest to darkest.</li>
|
||||||
the colors are sorted from lightest to darkest.</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<div style="height: 1.00em;"> </div>
|
<p class="Pp">The input image may not contain more colors than the selected bit
|
||||||
The input image may not contain more colors than the selected bit depth allows.
|
depth allows. Transparent pixels are set to palette index 0.</p>
|
||||||
Transparent pixels are set to palette index 0.
|
</section>
|
||||||
<h1 class="Sh" title="Sh" id="ARGUMENTS"><a class="selflink" href="#ARGUMENTS">ARGUMENTS</a></h1>
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="ARGUMENTS"><a class="permalink" href="#ARGUMENTS">ARGUMENTS</a></h1>
|
||||||
<dl class="Bl-tag">
|
<dl class="Bl-tag">
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#a"><code class="Fl" id="a">-a</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">attrmap</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#D"><b class="Fl" title="Fl" id="D">-D</b></a></dt>
|
<dd>Generate a file of tile mirroring attributes for OAM or (CGB-only)
|
||||||
<dd class="It-tag">Debug features are enabled.</dd>
|
background tiles. For each tile in the input file, a byte is written
|
||||||
<dt class="It-tag"> </dt>
|
representing the dimensions that the associated tile in the output file
|
||||||
<dd class="It-tag"> </dd>
|
should be mirrored. Useful in combination with <code class="Fl">-m</code>
|
||||||
<dt class="It-tag"><a class="selflink" href="#f"><b class="Fl" title="Fl" id="f">-f</b></a></dt>
|
to keep track the mirror direction of mirrored duplicate tiles.</dd>
|
||||||
<dd class="It-tag">Fix the input PNG file to be a correctly indexed
|
<dt><a class="permalink" href="#A"><code class="Fl" id="A">-A</code></a></dt>
|
||||||
image.</dd>
|
<dd>Same as <code class="Fl">-a</code>, but the attrmap file output name is
|
||||||
<dt class="It-tag"> </dt>
|
made by taking the input filename, removing the file extension, and
|
||||||
<dd class="It-tag"> </dd>
|
appending <span class="Pa">.attrmap</span>.</dd>
|
||||||
<dt class="It-tag"><a class="selflink" href="#F"><b class="Fl" title="Fl" id="F">-F</b></a></dt>
|
<dt><a class="permalink" href="#C"><code class="Fl" id="C">-C</code></a></dt>
|
||||||
<dd class="It-tag">Same as <b class="Fl" title="Fl">-f</b>, but additionally,
|
<dd>Use the color curve of the Game Boy Color when generating palettes.</dd>
|
||||||
the supplied command line parameters are saved within the PNG and will be
|
<dt><a class="permalink" href="#D"><code class="Fl" id="D">-D</code></a></dt>
|
||||||
loaded and automatically used next time.</dd>
|
<dd>Debug features are enabled.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#f"><code class="Fl" id="f">-f</code></a></dt>
|
||||||
<dd class="It-tag"> </dd>
|
<dd>Fix the input PNG file to be a correctly indexed image.</dd>
|
||||||
<dt class="It-tag"><a class="selflink" href="#d"><b class="Fl" title="Fl" id="d">-d</b></a>
|
<dt><a class="permalink" href="#F"><code class="Fl" id="F">-F</code></a></dt>
|
||||||
<var class="Ar" title="Ar">depth</var></dt>
|
<dd>Same as <code class="Fl">-f</code>, but additionally, the supplied command
|
||||||
<dd class="It-tag">The bit depth of the output image (either 1 or 2). By
|
line parameters are saved within the PNG and will be loaded and
|
||||||
default, the bit depth is 2 (two bits per pixel).</dd>
|
automatically used next time.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#d"><code class="Fl" id="d">-d</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">depth</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#h"><b class="Fl" title="Fl" id="h">-h</b></a></dt>
|
<dd>The bit depth of the output image (either 1 or 2). By default, the bit
|
||||||
<dd class="It-tag">Lay out tiles horizontally rather than vertically.</dd>
|
depth is 2 (two bits per pixel).</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#h"><code class="Fl" id="h">-h</code></a></dt>
|
||||||
<dd class="It-tag"> </dd>
|
<dd>Lay out tiles horizontally rather than vertically.</dd>
|
||||||
<dt class="It-tag"><a class="selflink" href="#o"><b class="Fl" title="Fl" id="o">-o</b></a>
|
<dt><a class="permalink" href="#m"><code class="Fl" id="m">-m</code></a></dt>
|
||||||
<var class="Ar" title="Ar">outfile</var></dt>
|
<dd>Truncate tiles by checking for tiles that are mirrored versions of others
|
||||||
<dd class="It-tag">The name of the output file.</dd>
|
and omitting these from the output file. Useful with tilemaps and attrmaps
|
||||||
<dt class="It-tag"> </dt>
|
together to keep track of the duplicated tiles and the dimension mirrored.
|
||||||
<dd class="It-tag"> </dd>
|
Tiles are checked for horizontal, vertical, and horizontal-vertical
|
||||||
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
|
mirroring. Implies <code class="Fl">-u</code>.</dd>
|
||||||
<var class="Ar" title="Ar">palfile</var></dt>
|
<dt><a class="permalink" href="#o"><code class="Fl" id="o">-o</code></a>
|
||||||
<dd class="It-tag">Output the image's palette in standard GBC palette format -
|
<var class="Ar">outfile</var></dt>
|
||||||
bytes (8 bytes for two bits per pixel, 4 bytes for one bit per pixel)
|
<dd>The name of the output file.</dd>
|
||||||
containing the RGB15 values in little-endian byte order. If the palette
|
<dt><a class="permalink" href="#p"><code class="Fl" id="p">-p</code></a>
|
||||||
contains too few colors, the remaining entries are set to black.</dd>
|
<var class="Ar">palfile</var></dt>
|
||||||
<dt class="It-tag"> </dt>
|
<dd>Output the image's palette in standard GBC palette format - bytes (8 bytes
|
||||||
<dd class="It-tag"> </dd>
|
for two bits per pixel, 4 bytes for one bit per pixel) containing the
|
||||||
<dt class="It-tag"><a class="selflink" href="#P"><b class="Fl" title="Fl" id="P">-P</b></a></dt>
|
RGB15 values in little-endian byte order. If the palette contains too few
|
||||||
<dd class="It-tag">Same as <b class="Fl" title="Fl">-p</b>, but the palette
|
colors, the remaining entries are set to black.</dd>
|
||||||
file output name is made by taking the input PNG file's filename, removing
|
<dt><a class="permalink" href="#P"><code class="Fl" id="P">-P</code></a></dt>
|
||||||
the file extension, and appending <i class="Pa" title="Pa">.pal</i>.</dd>
|
<dd>Same as <code class="Fl">-p</code>, but the palette file output name is
|
||||||
<dt class="It-tag"> </dt>
|
made by taking the input PNG file's filename, removing the file extension,
|
||||||
<dd class="It-tag"> </dd>
|
and appending <span class="Pa">.pal</span>.</dd>
|
||||||
<dt class="It-tag"><a class="selflink" href="#t"><b class="Fl" title="Fl" id="t">-t</b></a>
|
<dt><a class="permalink" href="#t"><code class="Fl" id="t">-t</code></a>
|
||||||
<var class="Ar" title="Ar">mapfile</var></dt>
|
<var class="Ar">tilemap</var></dt>
|
||||||
<dd class="It-tag">If any tiles are the same, don't place the repeat tiles in
|
<dd>Generate a file of tile indices. For each tile in the input file, a byte
|
||||||
the output file, and make a tilemap file.</dd>
|
is written representing the index of the associated tile in the output
|
||||||
<dt class="It-tag"> </dt>
|
file. Useful in combination with <code class="Fl">-u</code> or
|
||||||
<dd class="It-tag"> </dd>
|
<code class="Fl">-m</code> to keep track of duplicate tiles.</dd>
|
||||||
<dt class="It-tag"><a class="selflink" href="#T"><b class="Fl" title="Fl" id="T">-T</b></a></dt>
|
<dt><a class="permalink" href="#T"><code class="Fl" id="T">-T</code></a></dt>
|
||||||
<dd class="It-tag">Same as <b class="Fl" title="Fl">-t</b>, but the tilemap
|
<dd>Same as <code class="Fl">-t</code>, but the tilemap file output name is
|
||||||
file output name is made by taking the input filename, removing the file
|
made by taking the input filename, removing the file extension, and
|
||||||
extension, and appending <i class="Pa" title="Pa">.tilemap</i>.</dd>
|
appending <span class="Pa">.tilemap</span>.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#u"><code class="Fl" id="u">-u</code></a></dt>
|
||||||
<dd class="It-tag"> </dd>
|
<dd>Truncate tiles by checking for tiles that are exact duplicates of others
|
||||||
<dt class="It-tag"><a class="selflink" href="#u"><b class="Fl" title="Fl" id="u">-u</b></a></dt>
|
and omitting these from the output file. Useful with tilemaps to keep
|
||||||
<dd class="It-tag">Truncate repeated tiles. Useful with tilemaps.</dd>
|
track of the duplicated tiles.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#V"><code class="Fl" id="V">-V</code></a></dt>
|
||||||
<dd class="It-tag"> </dd>
|
<dd>Print the version of the program and exit.</dd>
|
||||||
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
|
<dt><a class="permalink" href="#v"><code class="Fl" id="v">-v</code></a></dt>
|
||||||
<dd class="It-tag">Print the version of the program and exit.</dd>
|
<dd>Verbose. Print errors when the command line parameters and the parameters
|
||||||
<dt class="It-tag"> </dt>
|
in the PNG file don't match.</dd>
|
||||||
<dd class="It-tag"> </dd>
|
<dt><a class="permalink" href="#x"><code class="Fl" id="x">-x</code></a>
|
||||||
<dt class="It-tag"><a class="selflink" href="#v"><b class="Fl" title="Fl" id="v">-v</b></a></dt>
|
<var class="Ar">tiles</var></dt>
|
||||||
<dd class="It-tag">Verbose. Print errors when the command line parameters and
|
<dd>Trim the end of the output file by this many tiles.</dd>
|
||||||
the parameters in the PNG file don't match.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#x"><b class="Fl" title="Fl" id="x">-x</b></a>
|
|
||||||
<var class="Ar" title="Ar">tiles</var></dt>
|
|
||||||
<dd class="It-tag">Trim the end of the output file by this many tiles.</dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="EXAMPLES"><a class="permalink" href="#EXAMPLES">EXAMPLES</a></h1>
|
||||||
The following will take a PNG file with a bit depth of 1, 2, or 8, and output
|
The following will take a PNG file with a bit depth of 1, 2, or 8, and output
|
||||||
planar 2bpp data:
|
planar 2bpp data:
|
||||||
<div class="Pp"></div>
|
<p class="Pp"></p>
|
||||||
<div class="D1">$ rgbgfx -o out.2bpp in.png</div>
|
<div class="Bd Bd-indent">$ rgbgfx -o out.2bpp in.png</div>
|
||||||
<div class="Pp"></div>
|
<p class="Pp">The following creates a planar 2bpp file with only unique tiles,
|
||||||
The following creates a planar 2bpp file with only unique tiles, and its tilemap
|
and its tilemap <span class="Pa">out.tilemap</span>:</p>
|
||||||
<i class="Pa" title="Pa">out.tilemap</i>:
|
<p class="Pp"></p>
|
||||||
<div class="Pp"></div>
|
<div class="Bd Bd-indent">$ rgbgfx -T -u -o out.2bpp in.png</div>
|
||||||
<div class="D1">$ rgbgfx -T -u -o out.2bpp in.png</div>
|
<p class="Pp">The following creates a planar 2bpp file with only unique tiles
|
||||||
<div class="Pp"></div>
|
(accounting for tile mirroring) and its associated tilemap
|
||||||
The following will do nothing:
|
<span class="Pa">out.tilemap</span> and attrmap
|
||||||
<div class="Pp"></div>
|
<span class="Pa">out.attrmap</span>:</p>
|
||||||
<div class="D1">$ rgbgfx in.png</div>
|
<p class="Pp"></p>
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
<div class="Bd Bd-indent">$ rgbgfx -A -T -m -o out.2bpp in.png</div>
|
||||||
|
<p class="Pp">The following will do nothing:</p>
|
||||||
|
<p class="Pp"></p>
|
||||||
|
<div class="Bd Bd-indent">$ rgbgfx in.png</div>
|
||||||
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
|
||||||
ALSO</a></h1>
|
ALSO</a></h1>
|
||||||
<a class="Xr" title="Xr">rgbds(7)</a>, <a class="Xr" title="Xr">rgbasm(1)</a>,
|
<a class="Xr">rgbds(7)</a>, <a class="Xr">rgbasm(1)</a>,
|
||||||
<a class="Xr" title="Xr">rgblink(1)</a>,
|
<a class="Xr">rgblink(1)</a>, <a class="Xr">rgbfix(1)</a>,
|
||||||
<a class="Xr" title="Xr">rgbfix(1)</a>, <a class="Xr" title="Xr">gbz80(7)</a>
|
<a class="Xr">gbz80(7)</a>
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
</section>
|
||||||
<b class="Nm" title="Nm">rgbgfx</b> was created by
|
<section class="Sh">
|
||||||
<span class="An" title="An">stag019</span> to be included in RGBDS. It is now
|
<h1 class="Sh" id="HISTORY"><a class="permalink" href="#HISTORY">HISTORY</a></h1>
|
||||||
maintained by a number of contributors at
|
<code class="Nm">rgbgfx</code> was created by <span class="An">stag019</span> to
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
be included in RGBDS. It is now maintained by a number of contributors at
|
||||||
|
<a class="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
<table class="foot">
|
<table class="foot">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="foot-date">January 26, 2018</td>
|
<td class="foot-date">January 26, 2018</td>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<!-- This is an automatically generated file. Do not edit.
|
||||||
|
This file is part of RGBDS.
|
||||||
|
|
||||||
|
Copyright (c) 2010-2018, Anthony J. Bentley and RGBDS contributors.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
||||||
<title>RGBLINK(1)</title>
|
<title>RGBLINK(1)</title>
|
||||||
</head>
|
</head>
|
||||||
@@ -20,137 +21,113 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="manual-text">
|
<div class="manual-text">
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
<section class="Sh">
|
||||||
<b class="Nm" title="Nm">rgblink</b> — <span class="Nd" title="Nd">Game
|
<h1 class="Sh" id="NAME"><a class="permalink" href="#NAME">NAME</a></h1>
|
||||||
Boy linker</span>
|
<code class="Nm">rgblink</code> —
|
||||||
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
<div class="Nd">Game Boy linker</div>
|
||||||
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SYNOPSIS"><a class="permalink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
||||||
<table class="Nm">
|
<table class="Nm">
|
||||||
<tr>
|
<tr>
|
||||||
<td><b class="Nm" title="Nm">rgblink</b></td>
|
<td><code class="Nm">rgblink</code></td>
|
||||||
<td>[<span class="Op"><b class="Fl" title="Fl">-dtVw</b></span>]
|
<td>[<code class="Fl">-dtVw</code>] [<code class="Fl">-m</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-m</b>
|
<var class="Ar">mapfile</var>] [<code class="Fl">-n</code>
|
||||||
<var class="Ar" title="Ar">mapfile</var></span>]
|
<var class="Ar">symfile</var>] [<code class="Fl">-O</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-n</b>
|
<var class="Ar">overlayfile</var>] [<code class="Fl">-o</code>
|
||||||
<var class="Ar" title="Ar">symfile</var></span>]
|
<var class="Ar">outfile</var>] [<code class="Fl">-p</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-O</b>
|
<var class="Ar">pad_value</var>] [<code class="Fl">-s</code>
|
||||||
<var class="Ar" title="Ar">overlayfile</var></span>]
|
<var class="Ar">symbol</var>] [<code class="Fl">-l</code>
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-o</b>
|
<var class="Ar">linkerscript</var>] <var class="Ar">file ...</var></td>
|
||||||
<var class="Ar" title="Ar">outfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-p</b>
|
|
||||||
<var class="Ar" title="Ar">pad_value</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-s</b>
|
|
||||||
<var class="Ar" title="Ar">symbol</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-l</b>
|
|
||||||
<var class="Ar" title="Ar">linkerscript</var></span>]
|
|
||||||
<var class="Ar" title="Ar">file ...</var></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
</section>
|
||||||
The <b class="Nm" title="Nm">rgblink</b> program links objects created by
|
<section class="Sh">
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a> into a single Game Boy ROM file.
|
<h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
||||||
<div class="Pp"></div>
|
The <code class="Nm">rgblink</code> program links objects created by
|
||||||
By default, ROM0 sections created by the assembler are placed in the 16KiB bank
|
<a class="Xr">rgbasm(1)</a> into a single Game Boy ROM file.
|
||||||
0, and ROMX sections are placed in any bank except bank 0. If your ROM will
|
<p class="Pp">By default, ROM0 sections created by the assembler are placed in
|
||||||
only be 32KiB, you can use the <b class="Fl" title="Fl">-t</b> option to
|
the 16KiB bank 0, and ROMX sections are placed in any bank except bank 0. If
|
||||||
override this.
|
your ROM will only be 32KiB, you can use the <code class="Fl">-t</code>
|
||||||
<div class="Pp"></div>
|
option to override this.</p>
|
||||||
Similarly, WRAM0 sections are placed in the first 4KiB of WRAM bank 0 and WRAMX
|
<p class="Pp">Similarly, WRAM0 sections are placed in the first 4KiB of WRAM
|
||||||
sections are placed in any bank except bank 0. If your ROM doesn't use banked
|
bank 0 and WRAMX sections are placed in any bank except bank 0. If your ROM
|
||||||
WRAM you can use option <b class="Fl" title="Fl">-w</b> option to override
|
doesn't use banked WRAM you can use option <code class="Fl">-w</code> option
|
||||||
this.
|
to override this.</p>
|
||||||
<div class="Pp"></div>
|
<p class="Pp">Also, if your ROM is designed for DMG, you can make sure that you
|
||||||
Also, if your ROM is designed for DMG, you can make sure that you don't use any
|
don't use any prohibited section by using the option
|
||||||
prohibited section by using the option <b class="Fl" title="Fl">-d</b>, which
|
<code class="Fl">-d</code>, which implies <code class="Fl">-w</code> but
|
||||||
implies <b class="Fl" title="Fl">-w</b> but also prohibits the use of VRAM
|
also prohibits the use of VRAM bank 1.</p>
|
||||||
bank 1.
|
<p class="Pp">The arguments are as follows:</p>
|
||||||
<div class="Pp"></div>
|
|
||||||
The arguments are as follows:
|
|
||||||
<dl class="Bl-tag">
|
<dl class="Bl-tag">
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#m"><code class="Fl" id="m">-m</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">mapfile</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#m"><b class="Fl" title="Fl" id="m">-m</b></a>
|
<dd>Write a mapfile to the given filename.</dd>
|
||||||
<var class="Ar" title="Ar">mapfile</var></dt>
|
<dt><a class="permalink" href="#n"><code class="Fl" id="n">-n</code></a>
|
||||||
<dd class="It-tag">Write a mapfile to the given filename.</dd>
|
<var class="Ar">symfile</var></dt>
|
||||||
<dt class="It-tag"> </dt>
|
<dd>Write a symbol file to the given filename.</dd>
|
||||||
<dd class="It-tag"> </dd>
|
<dt><a class="permalink" href="#O"><code class="Fl" id="O">-O</code></a>
|
||||||
<dt class="It-tag"><a class="selflink" href="#n"><b class="Fl" title="Fl" id="n">-n</b></a>
|
<var class="Ar">overlayfile</var></dt>
|
||||||
<var class="Ar" title="Ar">symfile</var></dt>
|
<dd>The ROM image to overlay sections over. When an overlay ROM is provided,
|
||||||
<dd class="It-tag">Write a symbol file to the given filename.</dd>
|
all sections must be fixed. This may be used to patch an existing
|
||||||
<dt class="It-tag"> </dt>
|
binary.</dd>
|
||||||
<dd class="It-tag"> </dd>
|
<dt><a class="permalink" href="#o"><code class="Fl" id="o">-o</code></a>
|
||||||
<dt class="It-tag"><a class="selflink" href="#O"><b class="Fl" title="Fl" id="O">-O</b></a>
|
<var class="Ar">outfile</var></dt>
|
||||||
<var class="Ar" title="Ar">overlayfile</var></dt>
|
<dd>Write ROM image to the given filename.</dd>
|
||||||
<dd class="It-tag">The ROM image to overlay sections over. When an overlay ROM
|
<dt><a class="permalink" href="#p"><code class="Fl" id="p">-p</code></a>
|
||||||
is provided, all sections must be fixed. This may be used to patch an
|
<var class="Ar">pad_value</var></dt>
|
||||||
existing binary.</dd>
|
<dd>When padding an image, pad with this value. The default is 0x00.</dd>
|
||||||
<dt class="It-tag"> </dt>
|
<dt><a class="permalink" href="#s"><code class="Fl" id="s">-s</code></a>
|
||||||
<dd class="It-tag"> </dd>
|
<var class="Ar">symbol</var></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#o"><b class="Fl" title="Fl" id="o">-o</b></a>
|
<dd>???</dd>
|
||||||
<var class="Ar" title="Ar">outfile</var></dt>
|
<dt><a class="permalink" href="#w"><code class="Fl" id="w">-w</code></a></dt>
|
||||||
<dd class="It-tag">Write ROM image to the given filename.</dd>
|
<dd>Expand the WRAM0 section size from 4KiB to the full 8KiB assigned to WRAM
|
||||||
<dt class="It-tag"> </dt>
|
and prohibit the use of WRAMX sections.</dd>
|
||||||
<dd class="It-tag"> </dd>
|
<dt><a class="permalink" href="#d"><code class="Fl" id="d">-d</code></a></dt>
|
||||||
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
|
<dd>Enable DMG mode. Prohibit the use of sections that doesn't exist on a DMG,
|
||||||
<var class="Ar" title="Ar">pad_value</var></dt>
|
such as WRAMX and VRAM bank 1. This option automatically enables
|
||||||
<dd class="It-tag">When padding an image, pad with this value. The default is
|
<code class="Fl">-w</code>.</dd>
|
||||||
0x00.</dd>
|
<dt><a class="permalink" href="#t"><code class="Fl" id="t">-t</code></a></dt>
|
||||||
<dt class="It-tag"> </dt>
|
<dd>Expand the ROM0 section size from 16KiB to the full 32KiB assigned to ROM
|
||||||
<dd class="It-tag"> </dd>
|
and prohibit the use of ROMX sections. Useful for ROMs that fit in 32
|
||||||
<dt class="It-tag"><a class="selflink" href="#s"><b class="Fl" title="Fl" id="s">-s</b></a>
|
KiB.</dd>
|
||||||
<var class="Ar" title="Ar">symbol</var></dt>
|
<dt><a class="permalink" href="#l"><code class="Fl" id="l">-l</code></a>
|
||||||
<dd class="It-tag">???</dd>
|
<var class="Ar">linkerscript</var></dt>
|
||||||
<dt class="It-tag"> </dt>
|
<dd>Specify a linkerscript file that tells the linker how sections must be
|
||||||
<dd class="It-tag"> </dd>
|
placed in the ROM. This file has priority over the attributes assigned in
|
||||||
<dt class="It-tag"><a class="selflink" href="#w"><b class="Fl" title="Fl" id="w">-w</b></a></dt>
|
the source code, but they have to be consistent. See
|
||||||
<dd class="It-tag">Expand the WRAM0 section size from 4KiB to the full 8KiB
|
<a class="Xr">rgblink(5)</a> for more information about its format.</dd>
|
||||||
assigned to WRAM and prohibit the use of WRAMX sections.</dd>
|
<dt><a class="permalink" href="#V"><code class="Fl" id="V">-V</code></a></dt>
|
||||||
<dt class="It-tag"> </dt>
|
<dd>Print the version of the program and exit.</dd>
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#d"><b class="Fl" title="Fl" id="d">-d</b></a></dt>
|
|
||||||
<dd class="It-tag">Enable DMG mode. Prohibit the use of sections that doesn't
|
|
||||||
exist on a DMG, such as WRAMX and VRAM bank 1. This option automatically
|
|
||||||
enables <b class="Fl" title="Fl">-w</b>.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#t"><b class="Fl" title="Fl" id="t">-t</b></a></dt>
|
|
||||||
<dd class="It-tag">Expand the ROM0 section size from 16KiB to the full 32KiB
|
|
||||||
assigned to ROM and prohibit the use of ROMX sections. Useful for ROMs
|
|
||||||
that fit in 32 KiB.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#l"><b class="Fl" title="Fl" id="l">-l</b></a>
|
|
||||||
<var class="Ar" title="Ar">linkerscript</var></dt>
|
|
||||||
<dd class="It-tag">Specify a linkerscript file that tells the linker how
|
|
||||||
sections must be placed in the ROM. This file has priority over the
|
|
||||||
attributes assigned in the source code, but they have to be consistent.
|
|
||||||
See <a class="Xr" title="Xr">rgblink(5)</a> for more information about its
|
|
||||||
format.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
|
|
||||||
<dd class="It-tag">Print the version of the program and exit.</dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="EXAMPLES"><a class="permalink" href="#EXAMPLES">EXAMPLES</a></h1>
|
||||||
All you need for a basic ROM is an object file, which can be made into a ROM
|
All you need for a basic ROM is an object file, which can be made into a ROM
|
||||||
image like so:
|
image like so:
|
||||||
<div class="Pp"></div>
|
<p class="Pp"></p>
|
||||||
<div class="D1">$ rgblink -o bar.gb foo.o</div>
|
<div class="Bd Bd-indent">$ rgblink -o bar.gb foo.o</div>
|
||||||
<div class="Pp"></div>
|
<p class="Pp">The resulting bar.gb will not have correct checksums (unless you
|
||||||
The resulting bar.gb will not have correct checksums (unless you put them in the
|
put them in the assembly source). You should use <a class="Xr">rgbfix(1)</a>
|
||||||
assembly source). You should use <a class="Xr" title="Xr">rgbfix(1)</a> to fix
|
to fix these so that the program will actually run in a Game Boy:</p>
|
||||||
these so that the program will actually run in a Game Boy:
|
<p class="Pp"></p>
|
||||||
<div class="Pp"></div>
|
<div class="Bd Bd-indent">$ rgbfix -v bar.gb</div>
|
||||||
<div class="D1">$ rgbfix -v bar.gb</div>
|
</section>
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
|
||||||
ALSO</a></h1>
|
ALSO</a></h1>
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(5)</a>,
|
<a class="Xr">rgbasm(1)</a>, <a class="Xr">rgblink(5)</a>,
|
||||||
<a class="Xr" title="Xr">rgbfix(1)</a>, <a class="Xr" title="Xr">rgbds(5)</a>,
|
<a class="Xr">rgbfix(1)</a>, <a class="Xr">rgbds(5)</a>,
|
||||||
<a class="Xr" title="Xr">rgbds(7)</a>
|
<a class="Xr">rgbds(7)</a>
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
</section>
|
||||||
<b class="Nm" title="Nm">rgblink</b> was originally written by Carsten
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="HISTORY"><a class="permalink" href="#HISTORY">HISTORY</a></h1>
|
||||||
|
<code class="Nm">rgblink</code> was originally written by Carsten
|
||||||
Sørensen as part of the ASMotor package, and was later packaged in
|
Sørensen as part of the ASMotor package, and was later packaged in
|
||||||
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
<a class="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
<table class="foot">
|
<table class="foot">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="foot-date">January 26, 2018</td>
|
<td class="foot-date">January 26, 2018</td>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<!-- This is an automatically generated file. Do not edit.
|
||||||
|
This file is part of RGBDS.
|
||||||
|
|
||||||
|
Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
||||||
<title>RGBLINK(5)</title>
|
<title>RGBLINK(5)</title>
|
||||||
</head>
|
</head>
|
||||||
@@ -20,23 +21,24 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="manual-text">
|
<div class="manual-text">
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
<section class="Sh">
|
||||||
<b class="Nm" title="Nm">rgblink</b> —
|
<h1 class="Sh" id="NAME"><a class="permalink" href="#NAME">NAME</a></h1>
|
||||||
<span class="Nd" title="Nd">linkerscript file format</span>
|
<code class="Nm">rgblink</code> —
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
<div class="Nd">linkerscript file format</div>
|
||||||
|
</section>
|
||||||
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
||||||
The linkerscript is an external file that allows the user to specify the order
|
The linkerscript is an external file that allows the user to specify the order
|
||||||
of sections without the need for doing so before assembling each object file.
|
of sections without the need for doing so before assembling each object file.
|
||||||
<div class="Pp"></div>
|
<p class="Pp">The placement of sections specified in the linkerscript is done
|
||||||
The placement of sections specified in the linkerscript is done before the
|
before the sections whose placement is defined in the source code.</p>
|
||||||
sections whose placement is defined in the source code.
|
<p class="Pp">A linkerscript consists on a series of banks followed by a list of
|
||||||
<div class="Pp"></div>
|
sections and, optionally, commands. They can be lowercase or uppercase, it
|
||||||
A linkerscript consists on a series of banks followed by a list of sections and,
|
is ignored. Any line can contain a comment starting with
|
||||||
optionally, commands. They can be lowercase or uppercase, it is ignored. Any
|
‘<code class="Li">;</code>’ that ends at the end of the
|
||||||
line can contain a comment starting with
|
line:</p>
|
||||||
‘<code class="Li">;</code>’ that ends at the end of the line:
|
<div class="Bd Pp Bd-indent">
|
||||||
<div class="Pp"></div>
|
<pre>
|
||||||
<div class="Bd" style="margin-left: 5.00ex;">
|
|
||||||
<pre class="Li">
|
|
||||||
ROMX $F ; This is a comment
|
ROMX $F ; This is a comment
|
||||||
"Functions to read array"
|
"Functions to read array"
|
||||||
ALIGN 8
|
ALIGN 8
|
||||||
@@ -46,55 +48,53 @@ WRAMX 2
|
|||||||
"Some variables"
|
"Some variables"
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div class="Pp"></div>
|
<p class="Pp">Numbers can be in decimal or hexadecimal format (the prefix is
|
||||||
Numbers can be in decimal or hexadecimal format (the prefix is
|
‘<code class="Li">$</code>’). It is an error if any section
|
||||||
‘<code class="Li">$</code>’). It is an error if any section name
|
name or command are found before setting a bank.</p>
|
||||||
or command are found before setting a bank.
|
<p class="Pp">Files can be included by using the <var class="Ar">INCLUDE</var>
|
||||||
<div class="Pp"></div>
|
|
||||||
Files can be included by using the <var class="Ar" title="Ar">INCLUDE</var>
|
|
||||||
keyword followed by a string with the path of the file that has to be
|
keyword followed by a string with the path of the file that has to be
|
||||||
included.
|
included.</p>
|
||||||
<div class="Pp"></div>
|
<p class="Pp">The possible bank types are: <b class="Sy">ROM0</b>,
|
||||||
The possible bank types are: <b class="Sy" title="Sy">ROM0</b>,
|
<b class="Sy">ROMX</b>, <b class="Sy">VRAM</b>, <b class="Sy">WRAM0</b>,
|
||||||
<b class="Sy" title="Sy">ROMX</b>, <b class="Sy" title="Sy">VRAM</b>,
|
<b class="Sy">WRAMX</b>, <b class="Sy">OAM</b> and <b class="Sy">HRAM</b>.
|
||||||
<b class="Sy" title="Sy">WRAM0</b>, <b class="Sy" title="Sy">WRAMX</b>,
|
Types <b class="Sy">ROMX</b>, <b class="Sy">VRAM</b>,
|
||||||
<b class="Sy" title="Sy">OAM</b> and <b class="Sy" title="Sy">HRAM</b>. Types
|
<b class="Sy">WRAMX</b> and <b class="Sy">SRAM</b> are banked, which means
|
||||||
<b class="Sy" title="Sy">ROMX</b>, <b class="Sy" title="Sy">VRAM</b>,
|
that it is needed to specify a bank after the type.</p>
|
||||||
<b class="Sy" title="Sy">WRAMX</b> and <b class="Sy" title="Sy">SRAM</b> are
|
<p class="Pp">When a new bank statement is found, sections found after it will
|
||||||
banked, which means that it is needed to specify a bank after the type.
|
be placed right from the beginning of that bank. If the linkerscript
|
||||||
<div class="Pp"></div>
|
switches to a different bank and then it comes back to the previous one it
|
||||||
When a new bank statement is found, sections found after it will be placed right
|
will continue from the last address that was used.</p>
|
||||||
from the beginning of that bank. If the linkerscript switches to a different
|
<p class="Pp">The only two commands are <var class="Ar">ORG</var> and
|
||||||
bank and then it comes back to the previous one it will continue from the last
|
<var class="Ar">ALIGN</var>:</p>
|
||||||
address that was used.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The only two commands are <var class="Ar" title="Ar">ORG</var> and
|
|
||||||
<var class="Ar" title="Ar">ALIGN</var>:
|
|
||||||
<ul class="Bl-bullet">
|
<ul class="Bl-bullet">
|
||||||
<li class="It-bullet"><var class="Ar" title="Ar">ORG</var> sets the address in
|
<li><var class="Ar">ORG</var> sets the address in which new sections will be
|
||||||
which new sections will be placed. It can not be lower than the current
|
placed. It can not be lower than the current address.</li>
|
||||||
address.</li>
|
<li><var class="Ar">ALIGN</var> will increase the address until it is aligned
|
||||||
<li class="It-bullet"><var class="Ar" title="Ar">ALIGN</var> will increase the
|
to the specified boundary (it tries to set to 0 the number of bits
|
||||||
address until it is aligned to the specified boundary (it tries to set to
|
specified after the command: <b class="Sy">ALIGN 8</b> will align to
|
||||||
0 the number of bits specified after the command:
|
$100).</li>
|
||||||
<b class="Sy" title="Sy">ALIGN 8</b> will align to $100).</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<div class="Pp"></div>
|
<p class="Pp">Note: The bank, alignment, address and type of sections can be
|
||||||
Note: The bank, alignment, address and type of sections can be specified both in
|
specified both in the source code and in the linkerscript. For a section to
|
||||||
the source code and in the linkerscript. For a section to be able to be placed
|
be able to be placed with the linkerscript the bank must be left unassigned
|
||||||
with the linkerscript the bank must be left unassigned in the source code or
|
in the source code or be the same as the one specified in the linkerscript.
|
||||||
be the same as the one specified in the linkerscript. The address and
|
The address and alignment musn't be set.</p>
|
||||||
alignment musn't be set.
|
</section>
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
|
||||||
ALSO</a></h1>
|
ALSO</a></h1>
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(1)</a>,
|
<a class="Xr">rgbasm(1)</a>, <a class="Xr">rgblink(1)</a>,
|
||||||
<a class="Xr" title="Xr">rgbfix(1)</a>, <a class="Xr" title="Xr">rgbds(5)</a>,
|
<a class="Xr">rgbfix(1)</a>, <a class="Xr">rgbds(5)</a>,
|
||||||
<a class="Xr" title="Xr">rgbds(7)</a>
|
<a class="Xr">rgbds(7)</a>
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
</section>
|
||||||
<b class="Nm" title="Nm">rgblink</b> was originally written by Carsten
|
<section class="Sh">
|
||||||
|
<h1 class="Sh" id="HISTORY"><a class="permalink" href="#HISTORY">HISTORY</a></h1>
|
||||||
|
<code class="Nm">rgblink</code> was originally written by Carsten
|
||||||
Sørensen as part of the ASMotor package, and was later packaged in
|
Sørensen as part of the ASMotor package, and was later packaged in
|
||||||
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
<a class="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
<table class="foot">
|
<table class="foot">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="foot-date">January 27, 2018</td>
|
<td class="foot-date">January 27, 2018</td>
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
extern int32_t nLineNo;
|
extern int32_t nLineNo;
|
||||||
extern uint32_t nTotalLines;
|
extern uint32_t nTotalLines;
|
||||||
extern uint32_t nPC;
|
extern uint32_t nPC;
|
||||||
extern uint32_t nPass;
|
|
||||||
extern uint32_t nIFDepth;
|
extern uint32_t nIFDepth;
|
||||||
extern bool skipElif;
|
extern bool skipElif;
|
||||||
extern uint32_t nUnionDepth;
|
extern uint32_t nUnionDepth;
|
||||||
@@ -40,6 +39,7 @@ extern struct sSymbol *tHashedSymbols[HASHSIZE];
|
|||||||
extern struct sSymbol *pPCSymbol;
|
extern struct sSymbol *pPCSymbol;
|
||||||
extern bool oDontExpandStrings;
|
extern bool oDontExpandStrings;
|
||||||
|
|
||||||
size_t symvaluetostring(char *dest, size_t maxLength, char *sym);
|
size_t symvaluetostring(char *dest, size_t maxLength, char *sym,
|
||||||
|
const char *mode);
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_ASM_H */
|
#endif /* RGBDS_ASM_ASM_H */
|
||||||
|
|||||||
@@ -13,14 +13,30 @@
|
|||||||
|
|
||||||
#define MAXCHARMAPS 512
|
#define MAXCHARMAPS 512
|
||||||
#define CHARMAPLENGTH 16
|
#define CHARMAPLENGTH 16
|
||||||
|
#define MAXCHARNODES (MAXCHARMAPS * CHARMAPLENGTH + 1)
|
||||||
|
|
||||||
struct Charmap {
|
/*
|
||||||
int32_t count;
|
* A node for trie structure.
|
||||||
char input[MAXCHARMAPS][CHARMAPLENGTH + 1];
|
*/
|
||||||
char output[MAXCHARMAPS];
|
struct Charnode {
|
||||||
|
uint8_t code; /* the value in a key-value pair. */
|
||||||
|
uint8_t isCode; /* has one if it's a code node, not just a bridge node. */
|
||||||
|
struct Charnode *next[256]; /* each index representing the next possible character from its current state. */
|
||||||
};
|
};
|
||||||
|
|
||||||
int32_t readUTF8Char(char *destination, char *source);
|
struct Charmap {
|
||||||
|
char name[MAXSYMLEN + 1];
|
||||||
|
int32_t charCount; /* user-side count. */
|
||||||
|
int32_t nodeCount; /* node-side count. */
|
||||||
|
struct Charnode nodes[MAXCHARNODES]; /* first node is reserved for the root node in charmap. */
|
||||||
|
struct Charmap *next; /* next charmap in hash table bucket */
|
||||||
|
};
|
||||||
|
|
||||||
|
void charmap_InitMain(void);
|
||||||
|
struct Charmap *charmap_New(const char *name, const char *baseName);
|
||||||
|
void charmap_Set(const char *name);
|
||||||
|
void charmap_Push(void);
|
||||||
|
void charmap_Pop(void);
|
||||||
int32_t charmap_Add(char *input, uint8_t output);
|
int32_t charmap_Add(char *input, uint8_t output);
|
||||||
int32_t charmap_Convert(char **input);
|
int32_t charmap_Convert(char **input);
|
||||||
|
|
||||||
|
|||||||
@@ -33,15 +33,20 @@ struct sContext {
|
|||||||
char *pREPTBlock;
|
char *pREPTBlock;
|
||||||
uint32_t nREPTBlockCount;
|
uint32_t nREPTBlockCount;
|
||||||
uint32_t nREPTBlockSize;
|
uint32_t nREPTBlockSize;
|
||||||
|
int32_t nREPTBodyFirstLine;
|
||||||
|
int32_t nREPTBodyLastLine;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern unsigned int nMaxRecursionDepth;
|
||||||
|
|
||||||
void fstk_RunInclude(char *tzFileName);
|
void fstk_RunInclude(char *tzFileName);
|
||||||
void fstk_RunMacroArg(int32_t s);
|
void fstk_RunMacroArg(int32_t s);
|
||||||
void fstk_Init(char *s);
|
void fstk_Init(char *s);
|
||||||
void fstk_Dump(void);
|
void fstk_Dump(void);
|
||||||
|
void fstk_DumpStringExpansions(void);
|
||||||
void fstk_AddIncludePath(char *s);
|
void fstk_AddIncludePath(char *s);
|
||||||
uint32_t fstk_RunMacro(char *s);
|
uint32_t fstk_RunMacro(char *s);
|
||||||
void fstk_RunRept(uint32_t count);
|
void fstk_RunRept(uint32_t count, int32_t nReptLineNo);
|
||||||
FILE *fstk_FindFile(char *fname, char **incPathUsed);
|
FILE *fstk_FindFile(char *fname, char **incPathUsed);
|
||||||
int32_t fstk_GetLine(void);
|
int32_t fstk_GetLine(void);
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ struct yy_buffer_state {
|
|||||||
/* Address where the data is initially written after a safety margin */
|
/* Address where the data is initially written after a safety margin */
|
||||||
char *pBufferStart;
|
char *pBufferStart;
|
||||||
char *pBuffer;
|
char *pBuffer;
|
||||||
uint32_t nBufferSize;
|
size_t nBufferSize;
|
||||||
uint32_t oAtLineStart;
|
uint32_t oAtLineStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,6 +40,13 @@ enum eLexerState {
|
|||||||
LEX_STATE_MACROARGS
|
LEX_STATE_MACROARGS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sStringExpansionPos {
|
||||||
|
char *tzName;
|
||||||
|
char *pBuffer;
|
||||||
|
char *pBufferPos;
|
||||||
|
struct sStringExpansionPos *pParent;
|
||||||
|
};
|
||||||
|
|
||||||
#define INITIAL 0
|
#define INITIAL 0
|
||||||
#define macroarg 3
|
#define macroarg 3
|
||||||
|
|
||||||
@@ -62,14 +69,16 @@ void lex_FloatDeleteSecondRange(uint32_t id, uint16_t start, uint16_t end);
|
|||||||
void lex_Init(void);
|
void lex_Init(void);
|
||||||
void lex_AddStrings(const struct sLexInitString *lex);
|
void lex_AddStrings(const struct sLexInitString *lex);
|
||||||
void lex_SetBuffer(char *buffer, uint32_t len);
|
void lex_SetBuffer(char *buffer, uint32_t len);
|
||||||
|
void lex_BeginStringExpansion(const char *tzName);
|
||||||
int yywrap(void);
|
int yywrap(void);
|
||||||
uint32_t yylex(void);
|
int yylex(void);
|
||||||
void yyunput(char c);
|
void yyunput(char c);
|
||||||
void yyunputstr(char *s);
|
void yyunputstr(const char *s);
|
||||||
void yyskipbytes(uint32_t count);
|
void yyskipbytes(uint32_t count);
|
||||||
void yyunputbytes(uint32_t count);
|
void yyunputbytes(uint32_t count);
|
||||||
|
|
||||||
extern YY_BUFFER_STATE pCurrentBuffer;
|
extern YY_BUFFER_STATE pCurrentBuffer;
|
||||||
|
extern struct sStringExpansionPos *pCurrentStringExpansion;
|
||||||
|
|
||||||
void upperstring(char *s);
|
void upperstring(char *s);
|
||||||
void lowerstring(char *s);
|
void lowerstring(char *s);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ void out_AbsByteGroup(char *s, int32_t length);
|
|||||||
void out_RelByte(struct Expression *expr);
|
void out_RelByte(struct Expression *expr);
|
||||||
void out_RelWord(struct Expression *expr);
|
void out_RelWord(struct Expression *expr);
|
||||||
void out_PCRelByte(struct Expression *expr);
|
void out_PCRelByte(struct Expression *expr);
|
||||||
|
void out_CheckErrors(void);
|
||||||
void out_WriteObject(void);
|
void out_WriteObject(void);
|
||||||
void out_Skip(int32_t skip);
|
void out_Skip(int32_t skip);
|
||||||
void out_BinaryFile(char *s);
|
void out_BinaryFile(char *s);
|
||||||
|
|||||||
@@ -11,17 +11,19 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define MAXRPNLEN 1048576
|
||||||
|
|
||||||
struct Expression {
|
struct Expression {
|
||||||
int32_t nVal;
|
int32_t nVal;
|
||||||
uint8_t tRPN[256];
|
uint8_t *tRPN;
|
||||||
|
uint32_t nRPNCapacity;
|
||||||
uint32_t nRPNLength;
|
uint32_t nRPNLength;
|
||||||
|
uint32_t nRPNPatchSize;
|
||||||
uint32_t nRPNOut;
|
uint32_t nRPNOut;
|
||||||
uint32_t isReloc;
|
uint32_t isReloc;
|
||||||
uint32_t isPCRel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t rpn_isReloc(const struct Expression *expr);
|
uint32_t rpn_isReloc(const struct Expression *expr);
|
||||||
uint32_t rpn_isPCRelative(const struct Expression *expr);
|
|
||||||
void rpn_Symbol(struct Expression *expr, char *tzSym);
|
void rpn_Symbol(struct Expression *expr, char *tzSym);
|
||||||
void rpn_Number(struct Expression *expr, uint32_t i);
|
void rpn_Number(struct Expression *expr, uint32_t i);
|
||||||
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
|
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
|
||||||
@@ -69,7 +71,8 @@ uint16_t rpn_PopByte(struct Expression *expr);
|
|||||||
void rpn_BankSymbol(struct Expression *expr, char *tzSym);
|
void rpn_BankSymbol(struct Expression *expr, char *tzSym);
|
||||||
void rpn_BankSection(struct Expression *expr, char *tzSectionName);
|
void rpn_BankSection(struct Expression *expr, char *tzSectionName);
|
||||||
void rpn_BankSelf(struct Expression *expr);
|
void rpn_BankSelf(struct Expression *expr);
|
||||||
void rpn_Reset(struct Expression *expr);
|
void rpn_Init(struct Expression *expr);
|
||||||
|
void rpn_Free(struct Expression *expr);
|
||||||
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
|
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_RPN_H */
|
#endif /* RGBDS_ASM_RPN_H */
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ struct sSymbol {
|
|||||||
#define SYMF_SET 0x004
|
#define SYMF_SET 0x004
|
||||||
/* Symbol should be exported */
|
/* Symbol should be exported */
|
||||||
#define SYMF_EXPORT 0x008
|
#define SYMF_EXPORT 0x008
|
||||||
/* Symbol is imported, it's value is unknown */
|
/* Symbol referenced in RPN expression */
|
||||||
#define SYMF_IMPORT 0x010
|
#define SYMF_REF 0x010
|
||||||
/* Symbol is a local symbol */
|
/* Symbol is a local symbol */
|
||||||
#define SYMF_LOCAL 0x020
|
#define SYMF_LOCAL 0x020
|
||||||
/* Symbol has been defined, not only referenced */
|
/* Symbol has been defined, not only referenced */
|
||||||
@@ -51,10 +51,8 @@ struct sSymbol {
|
|||||||
/* Symbol has a constant value, will not be changed during linking */
|
/* Symbol has a constant value, will not be changed during linking */
|
||||||
#define SYMF_CONST 0x200
|
#define SYMF_CONST 0x200
|
||||||
|
|
||||||
uint32_t calchash(char *s);
|
uint32_t sym_CalcHash(const char *s);
|
||||||
void sym_SetExportAll(uint8_t set);
|
void sym_SetExportAll(uint8_t set);
|
||||||
void sym_PrepPass1(void);
|
|
||||||
void sym_PrepPass2(void);
|
|
||||||
void sym_AddLocalReloc(char *tzSym);
|
void sym_AddLocalReloc(char *tzSym);
|
||||||
void sym_AddReloc(char *tzSym);
|
void sym_AddReloc(char *tzSym);
|
||||||
void sym_Export(char *tzSym);
|
void sym_Export(char *tzSym);
|
||||||
@@ -65,23 +63,21 @@ void sym_AddNewMacroArg(char *s);
|
|||||||
void sym_SaveCurrentMacroArgs(char *save[]);
|
void sym_SaveCurrentMacroArgs(char *save[]);
|
||||||
void sym_RestoreCurrentMacroArgs(char *save[]);
|
void sym_RestoreCurrentMacroArgs(char *save[]);
|
||||||
void sym_UseNewMacroArgs(void);
|
void sym_UseNewMacroArgs(void);
|
||||||
void sym_FreeCurrentMacroArgs(void);
|
|
||||||
void sym_AddEqu(char *tzSym, int32_t value);
|
void sym_AddEqu(char *tzSym, int32_t value);
|
||||||
void sym_AddSet(char *tzSym, int32_t value);
|
void sym_AddSet(char *tzSym, int32_t value);
|
||||||
void sym_Init(void);
|
void sym_Init(void);
|
||||||
uint32_t sym_GetConstantValue(char *s);
|
uint32_t sym_GetConstantValue(char *s);
|
||||||
uint32_t sym_isConstant(char *s);
|
uint32_t sym_isConstant(char *s);
|
||||||
struct sSymbol *sym_FindSymbol(char *tzName);
|
struct sSymbol *sym_FindSymbol(char *tzName);
|
||||||
void sym_Global(char *tzSym);
|
|
||||||
char *sym_FindMacroArg(int32_t i);
|
char *sym_FindMacroArg(int32_t i);
|
||||||
char *sym_GetStringValue(char *tzSym);
|
char *sym_GetStringValue(char *tzSym);
|
||||||
void sym_UseCurrentMacroArgs(void);
|
void sym_UseCurrentMacroArgs(void);
|
||||||
void sym_SetMacroArgID(uint32_t nMacroCount);
|
void sym_SetMacroArgID(uint32_t nMacroCount);
|
||||||
uint32_t sym_isString(char *tzSym);
|
uint32_t sym_isString(char *tzSym);
|
||||||
void sym_AddMacro(char *tzSym);
|
void sym_AddMacro(char *tzSym, int32_t nDefLineNo);
|
||||||
|
void sym_Ref(char *tzSym);
|
||||||
void sym_ShiftCurrentMacroArgs(void);
|
void sym_ShiftCurrentMacroArgs(void);
|
||||||
void sym_AddString(char *tzSym, char *tzValue);
|
void sym_AddString(char *tzSym, char *tzValue);
|
||||||
uint32_t sym_GetValue(char *s);
|
|
||||||
uint32_t sym_GetDefinedValue(char *s);
|
uint32_t sym_GetDefinedValue(char *s);
|
||||||
uint32_t sym_isDefined(char *tzName);
|
uint32_t sym_isDefined(char *tzName);
|
||||||
void sym_Purge(char *tzName);
|
void sym_Purge(char *tzName);
|
||||||
|
|||||||
17
include/asm/util.h
Normal file
17
include/asm/util.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGBDS_UTIL_H
|
||||||
|
#define RGBDS_UTIL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint32_t calchash(const char *s);
|
||||||
|
int32_t readUTF8Char(char *dest, char *src);
|
||||||
|
|
||||||
|
#endif /* RGBDS_UTIL_H */
|
||||||
@@ -12,14 +12,24 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "gfx/main.h"
|
#include "gfx/main.h"
|
||||||
|
|
||||||
|
#define XFLIP 0x40
|
||||||
|
#define YFLIP 0x20
|
||||||
|
|
||||||
void raw_to_gb(const struct RawIndexedImage *raw_image, struct GBImage *gb);
|
void raw_to_gb(const struct RawIndexedImage *raw_image, struct GBImage *gb);
|
||||||
void output_file(const struct Options *opts, const struct GBImage *gb);
|
void output_file(const struct Options *opts, const struct GBImage *gb);
|
||||||
int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
|
int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
|
||||||
int tile_size);
|
int tile_size);
|
||||||
void create_tilemap(const struct Options *opts, struct GBImage *gb,
|
uint8_t reverse_bits(uint8_t b);
|
||||||
struct Tilemap *tilemap);
|
void xflip(uint8_t *tile, uint8_t *tile_xflip, int tile_size);
|
||||||
|
void yflip(uint8_t *tile, uint8_t *tile_yflip, int tile_size);
|
||||||
|
int get_mirrored_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
|
||||||
|
int tile_size, int *flags);
|
||||||
|
void create_mapfiles(const struct Options *opts, struct GBImage *gb,
|
||||||
|
struct Mapfile *tilemap, struct Mapfile *attrmap);
|
||||||
void output_tilemap_file(const struct Options *opts,
|
void output_tilemap_file(const struct Options *opts,
|
||||||
const struct Tilemap *tilemap);
|
const struct Mapfile *tilemap);
|
||||||
|
void output_attrmap_file(const struct Options *opts,
|
||||||
|
const struct Mapfile *attrmap);
|
||||||
void output_palette_file(const struct Options *opts,
|
void output_palette_file(const struct Options *opts,
|
||||||
const struct RawIndexedImage *raw_image);
|
const struct RawIndexedImage *raw_image);
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,14 @@ struct Options {
|
|||||||
bool hardfix;
|
bool hardfix;
|
||||||
bool fix;
|
bool fix;
|
||||||
bool horizontal;
|
bool horizontal;
|
||||||
|
bool mirror;
|
||||||
bool unique;
|
bool unique;
|
||||||
|
bool colorcurve;
|
||||||
int trim;
|
int trim;
|
||||||
char *mapfile;
|
char *tilemapfile;
|
||||||
bool mapout;
|
bool tilemapout;
|
||||||
|
char *attrmapfile;
|
||||||
|
bool attrmapout;
|
||||||
char *palfile;
|
char *palfile;
|
||||||
bool palout;
|
bool palout;
|
||||||
char *outfile;
|
char *outfile;
|
||||||
@@ -40,8 +44,10 @@ struct RGBColor {
|
|||||||
struct ImageOptions {
|
struct ImageOptions {
|
||||||
bool horizontal;
|
bool horizontal;
|
||||||
int trim;
|
int trim;
|
||||||
char *mapfile;
|
char *tilemapfile;
|
||||||
bool mapout;
|
bool tilemapout;
|
||||||
|
char *attrmapfile;
|
||||||
|
bool attrmapout;
|
||||||
char *palfile;
|
char *palfile;
|
||||||
bool palout;
|
bool palout;
|
||||||
};
|
};
|
||||||
@@ -71,7 +77,7 @@ struct GBImage {
|
|||||||
int trim;
|
int trim;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Tilemap {
|
struct Mapfile {
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
int size;
|
int size;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ void sym_Init(void);
|
|||||||
void sym_CreateSymbol(char *tzName, int32_t nValue, int32_t nBank,
|
void sym_CreateSymbol(char *tzName, int32_t nValue, int32_t nBank,
|
||||||
char *tzObjFileName, char *tzFileName,
|
char *tzObjFileName, char *tzFileName,
|
||||||
uint32_t nFileLine);
|
uint32_t nFileLine);
|
||||||
int32_t sym_GetValue(char *tzName);
|
int32_t sym_GetValue(struct sPatch *pPatch, char *tzName);
|
||||||
int32_t sym_GetBank(char *tzName);
|
int32_t sym_GetBank(struct sPatch *pPatch, char *tzName);
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_SYMBOL_H */
|
#endif /* RGBDS_LINK_SYMBOL_H */
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#define PACKAGE_VERSION_MAJOR (0)
|
#define PACKAGE_VERSION_MAJOR (0)
|
||||||
#define PACKAGE_VERSION_MINOR (3)
|
#define PACKAGE_VERSION_MINOR (3)
|
||||||
#define PACKAGE_VERSION_PATCH (8)
|
#define PACKAGE_VERSION_PATCH (9)
|
||||||
|
|
||||||
const char *get_package_version_string(void);
|
const char *get_package_version_string(void);
|
||||||
|
|
||||||
|
|||||||
240
src/asm/asmy.y
240
src/asm/asmy.y
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
%{
|
%{
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -25,6 +26,9 @@
|
|||||||
#include "asm/output.h"
|
#include "asm/output.h"
|
||||||
#include "asm/rpn.h"
|
#include "asm/rpn.h"
|
||||||
#include "asm/symbol.h"
|
#include "asm/symbol.h"
|
||||||
|
#include "asm/util.h"
|
||||||
|
|
||||||
|
#include "extern/utf8decoder.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "linkdefs.h"
|
#include "linkdefs.h"
|
||||||
@@ -73,7 +77,8 @@ static void bankrangecheck(char *name, uint32_t secttype, int32_t org,
|
|||||||
out_NewAbsSection(name, secttype, org, bank);
|
out_NewAbsSection(name, secttype, org, bank);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t symvaluetostring(char *dest, size_t maxLength, char *sym)
|
size_t symvaluetostring(char *dest, size_t maxLength, char *sym,
|
||||||
|
const char *mode)
|
||||||
{
|
{
|
||||||
size_t length;
|
size_t length;
|
||||||
|
|
||||||
@@ -81,6 +86,9 @@ size_t symvaluetostring(char *dest, size_t maxLength, char *sym)
|
|||||||
char *src = sym_GetStringValue(sym);
|
char *src = sym_GetStringValue(sym);
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
if (mode)
|
||||||
|
yyerror("Print types are only allowed for numbers");
|
||||||
|
|
||||||
for (i = 0; src[i] != 0; i++) {
|
for (i = 0; src[i] != 0; i++) {
|
||||||
if (i >= maxLength)
|
if (i >= maxLength)
|
||||||
fatalerror("Symbol value too long to fit buffer");
|
fatalerror("Symbol value too long to fit buffer");
|
||||||
@@ -92,8 +100,25 @@ size_t symvaluetostring(char *dest, size_t maxLength, char *sym)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
uint32_t value = sym_GetConstantValue(sym);
|
uint32_t value = sym_GetConstantValue(sym);
|
||||||
int32_t fullLength = snprintf(dest, maxLength + 1, "$%X",
|
int32_t fullLength;
|
||||||
|
|
||||||
|
/* Special cheat for binary */
|
||||||
|
if (mode && !mode[0]) {
|
||||||
|
char binary[33]; /* 32 bits + 1 terminator */
|
||||||
|
char *write_ptr = binary + 32;
|
||||||
|
fullLength = 0;
|
||||||
|
binary[32] = 0;
|
||||||
|
do {
|
||||||
|
*(--write_ptr) = (value & 1) + '0';
|
||||||
|
value >>= 1;
|
||||||
|
fullLength++;
|
||||||
|
} while(value);
|
||||||
|
strncpy(dest, write_ptr, maxLength + 1);
|
||||||
|
} else {
|
||||||
|
fullLength = snprintf(dest, maxLength + 1,
|
||||||
|
mode ? : "$%X",
|
||||||
value);
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
if (fullLength < 0) {
|
if (fullLength < 0) {
|
||||||
fatalerror("snprintf encoding error");
|
fatalerror("snprintf encoding error");
|
||||||
@@ -249,14 +274,13 @@ static void copymacro(void)
|
|||||||
src = pCurrentBuffer->pBuffer;
|
src = pCurrentBuffer->pBuffer;
|
||||||
ulNewMacroSize = len;
|
ulNewMacroSize = len;
|
||||||
|
|
||||||
tzNewMacro = (char *)malloc(ulNewMacroSize+2);
|
tzNewMacro = (char *)malloc(ulNewMacroSize + 1);
|
||||||
if (tzNewMacro == NULL)
|
if (tzNewMacro == NULL)
|
||||||
fatalerror("Not enough memory for MACRO definition.");
|
fatalerror("Not enough memory for MACRO definition.");
|
||||||
|
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
tzNewMacro[ulNewMacroSize] = '\n';
|
tzNewMacro[ulNewMacroSize] = 0;
|
||||||
tzNewMacro[ulNewMacroSize+1] = 0;
|
|
||||||
for (i = 0; i < ulNewMacroSize; i += 1) {
|
for (i = 0; i < ulNewMacroSize; i += 1) {
|
||||||
tzNewMacro[i] = src[i];
|
tzNewMacro[i] = src[i];
|
||||||
if (src[i] == '\n')
|
if (src[i] == '\n')
|
||||||
@@ -266,16 +290,21 @@ static void copymacro(void)
|
|||||||
yyskipbytes(ulNewMacroSize + 4);
|
yyskipbytes(ulNewMacroSize + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool endsIf(char c)
|
||||||
|
{
|
||||||
|
return isWhiteSpace(c) || c == '(' || c == '{';
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t isIf(char *s)
|
static uint32_t isIf(char *s)
|
||||||
{
|
{
|
||||||
return (strncasecmp(s, "IF", 2) == 0)
|
return (strncasecmp(s, "IF", 2) == 0)
|
||||||
&& isWhiteSpace(s[-1]) && isWhiteSpace(s[2]);
|
&& isWhiteSpace(s[-1]) && endsIf(s[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t isElif(char *s)
|
static uint32_t isElif(char *s)
|
||||||
{
|
{
|
||||||
return (strncasecmp(s, "ELIF", 4) == 0)
|
return (strncasecmp(s, "ELIF", 4) == 0)
|
||||||
&& isWhiteSpace(s[-1]) && isWhiteSpace(s[4]);
|
&& isWhiteSpace(s[-1]) && endsIf(s[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t isElse(char *s)
|
static uint32_t isElse(char *s)
|
||||||
@@ -324,20 +353,14 @@ static void if_skip_to_else(void)
|
|||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (*src) {
|
if (*src == '\"') {
|
||||||
case '\\':
|
|
||||||
src += 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\"':
|
|
||||||
src += 2;
|
|
||||||
inString = false;
|
inString = false;
|
||||||
break;
|
} else if (*src == '\\') {
|
||||||
|
/* Escaped quotes don't end the string */
|
||||||
default:
|
if (*++src != '\"')
|
||||||
src++;
|
src--;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
src++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,21 +398,14 @@ static void if_skip_to_endc(void)
|
|||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (*src) {
|
if (*src == '\"') {
|
||||||
|
|
||||||
case '\\':
|
|
||||||
src += 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\"':
|
|
||||||
src++;
|
|
||||||
inString = false;
|
inString = false;
|
||||||
break;
|
} else if (*src == '\\') {
|
||||||
|
/* Escaped quotes don't end the string */
|
||||||
default:
|
if (*++src != '\"')
|
||||||
src++;
|
src--;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
src++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,6 +447,85 @@ static void updateUnion(void)
|
|||||||
pPCSymbol->nValue = unionStart[unionIndex];
|
pPCSymbol->nValue = unionStart[unionIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t strlenUTF8(const char *s)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
uint32_t state = 0;
|
||||||
|
uint32_t codep = 0;
|
||||||
|
|
||||||
|
while (*s) {
|
||||||
|
switch (decode(&state, &codep, (uint8_t)*s)) {
|
||||||
|
case 1:
|
||||||
|
fatalerror("STRLEN: Invalid UTF-8 character");
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
len++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for partial code point. */
|
||||||
|
if (state != 0)
|
||||||
|
fatalerror("STRLEN: Invalid UTF-8 character");
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len)
|
||||||
|
{
|
||||||
|
size_t srcIndex = 0;
|
||||||
|
size_t destIndex = 0;
|
||||||
|
uint32_t state = 0;
|
||||||
|
uint32_t codep = 0;
|
||||||
|
uint32_t curPos = 1;
|
||||||
|
uint32_t curLen = 0;
|
||||||
|
|
||||||
|
if (pos < 1) {
|
||||||
|
warning("STRSUB: Position starts at 1");
|
||||||
|
pos = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance to starting position in source string. */
|
||||||
|
while (src[srcIndex] && curPos < pos) {
|
||||||
|
switch (decode(&state, &codep, (uint8_t)src[srcIndex])) {
|
||||||
|
case 1:
|
||||||
|
fatalerror("STRSUB: Invalid UTF-8 character");
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
curPos++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
srcIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src[srcIndex])
|
||||||
|
warning("STRSUB: Position %lu is past the end of the string",
|
||||||
|
(unsigned long)pos);
|
||||||
|
|
||||||
|
/* Copy from source to destination. */
|
||||||
|
while (src[srcIndex] && destIndex < MAXSTRLEN && curLen < len) {
|
||||||
|
switch (decode(&state, &codep, (uint8_t)src[srcIndex])) {
|
||||||
|
case 1:
|
||||||
|
fatalerror("STRSUB: Invalid UTF-8 character");
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
curLen++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dest[destIndex++] = src[srcIndex++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curLen < len)
|
||||||
|
warning("STRSUB: Length too big: %lu", (unsigned long)len);
|
||||||
|
|
||||||
|
/* Check for partial code point. */
|
||||||
|
if (state != 0)
|
||||||
|
fatalerror("STRSUB: Invalid UTF-8 character");
|
||||||
|
|
||||||
|
dest[destIndex] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%union
|
%union
|
||||||
@@ -456,8 +551,8 @@ static void updateUnion(void)
|
|||||||
%token <tzString> T_STRING
|
%token <tzString> T_STRING
|
||||||
|
|
||||||
%left <nConstValue> T_OP_LOGICNOT
|
%left <nConstValue> T_OP_LOGICNOT
|
||||||
%left <nConstValue> T_OP_LOGICOR T_OP_LOGICAND T_OP_LOGICEQU
|
%left <nConstValue> T_OP_LOGICOR T_OP_LOGICAND
|
||||||
%left <nConstValue> T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE
|
%left <nConstValue> T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE T_OP_LOGICEQU
|
||||||
%left <nConstValue> T_OP_ADD T_OP_SUB
|
%left <nConstValue> T_OP_ADD T_OP_SUB
|
||||||
%left <nConstValue> T_OP_OR T_OP_XOR T_OP_AND
|
%left <nConstValue> T_OP_OR T_OP_XOR T_OP_AND
|
||||||
%left <nConstValue> T_OP_SHL T_OP_SHR
|
%left <nConstValue> T_OP_SHL T_OP_SHR
|
||||||
@@ -510,6 +605,10 @@ static void updateUnion(void)
|
|||||||
%token T_POP_UNION T_POP_NEXTU T_POP_ENDU
|
%token T_POP_UNION T_POP_NEXTU T_POP_ENDU
|
||||||
%token T_POP_INCBIN T_POP_REPT
|
%token T_POP_INCBIN T_POP_REPT
|
||||||
%token T_POP_CHARMAP
|
%token T_POP_CHARMAP
|
||||||
|
%token T_POP_NEWCHARMAP
|
||||||
|
%token T_POP_SETCHARMAP
|
||||||
|
%token T_POP_PUSHC
|
||||||
|
%token T_POP_POPC
|
||||||
%token T_POP_SHIFT
|
%token T_POP_SHIFT
|
||||||
%token T_POP_ENDR
|
%token T_POP_ENDR
|
||||||
%token T_POP_FAIL
|
%token T_POP_FAIL
|
||||||
@@ -663,6 +762,10 @@ simple_pseudoop : include
|
|||||||
| endu
|
| endu
|
||||||
| incbin
|
| incbin
|
||||||
| charmap
|
| charmap
|
||||||
|
| newcharmap
|
||||||
|
| setcharmap
|
||||||
|
| pushc
|
||||||
|
| popc
|
||||||
| rept
|
| rept
|
||||||
| shift
|
| shift
|
||||||
| fail
|
| fail
|
||||||
@@ -712,15 +815,17 @@ shift : T_POP_SHIFT { sym_ShiftCurrentMacroArgs(); }
|
|||||||
|
|
||||||
rept : T_POP_REPT uconst
|
rept : T_POP_REPT uconst
|
||||||
{
|
{
|
||||||
|
uint32_t nDefinitionLineNo = nLineNo;
|
||||||
copyrept();
|
copyrept();
|
||||||
fstk_RunRept($2);
|
fstk_RunRept($2, nDefinitionLineNo);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
macrodef : T_LABEL ':' T_POP_MACRO
|
macrodef : T_LABEL ':' T_POP_MACRO
|
||||||
{
|
{
|
||||||
|
int32_t nDefinitionLineNo = nLineNo;
|
||||||
copymacro();
|
copymacro();
|
||||||
sym_AddMacro($1);
|
sym_AddMacro($1, nDefinitionLineNo);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -799,7 +904,7 @@ ds : T_POP_DS uconst
|
|||||||
;
|
;
|
||||||
|
|
||||||
db : T_POP_DB constlist_8bit_entry comma constlist_8bit {
|
db : T_POP_DB constlist_8bit_entry comma constlist_8bit {
|
||||||
if ((nPass == 1) && (nListCountEmpty > 0)) {
|
if (nListCountEmpty > 0) {
|
||||||
warning("Empty entry in list of 8-bit elements (treated as 0).");
|
warning("Empty entry in list of 8-bit elements (treated as 0).");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -807,7 +912,7 @@ db : T_POP_DB constlist_8bit_entry comma constlist_8bit {
|
|||||||
;
|
;
|
||||||
|
|
||||||
dw : T_POP_DW constlist_16bit_entry comma constlist_16bit {
|
dw : T_POP_DW constlist_16bit_entry comma constlist_16bit {
|
||||||
if ((nPass == 1) && (nListCountEmpty > 0)) {
|
if (nListCountEmpty > 0) {
|
||||||
warning("Empty entry in list of 16-bit elements (treated as 0).");
|
warning("Empty entry in list of 16-bit elements (treated as 0).");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -815,7 +920,7 @@ dw : T_POP_DW constlist_16bit_entry comma constlist_16bit {
|
|||||||
;
|
;
|
||||||
|
|
||||||
dl : T_POP_DL constlist_32bit_entry comma constlist_32bit {
|
dl : T_POP_DL constlist_32bit_entry comma constlist_32bit {
|
||||||
if ((nPass == 1) && (nListCountEmpty > 0)) {
|
if (nListCountEmpty > 0) {
|
||||||
warning("Empty entry in list of 32-bit elements (treated as 0).");
|
warning("Empty entry in list of 32-bit elements (treated as 0).");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -852,7 +957,6 @@ import_list_entry : T_ID
|
|||||||
* This is done automatically if the label isn't found
|
* This is done automatically if the label isn't found
|
||||||
* in the list of defined symbols.
|
* in the list of defined symbols.
|
||||||
*/
|
*/
|
||||||
if (nPass == 1)
|
|
||||||
warning("IMPORT is a deprecated keyword with no effect: %s", $1);
|
warning("IMPORT is a deprecated keyword with no effect: %s", $1);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -879,7 +983,7 @@ global_list : global_list_entry
|
|||||||
|
|
||||||
global_list_entry : T_ID
|
global_list_entry : T_ID
|
||||||
{
|
{
|
||||||
sym_Global($1);
|
sym_Export($1);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -927,30 +1031,48 @@ charmap : T_POP_CHARMAP string comma string
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
newcharmap : T_POP_NEWCHARMAP T_ID
|
||||||
|
{
|
||||||
|
charmap_New($2, NULL);
|
||||||
|
}
|
||||||
|
| T_POP_NEWCHARMAP T_ID comma T_ID
|
||||||
|
{
|
||||||
|
charmap_New($2, $4);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
setcharmap : T_POP_SETCHARMAP T_ID
|
||||||
|
{
|
||||||
|
charmap_Set($2);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
pushc : T_POP_PUSHC { charmap_Push(); }
|
||||||
|
;
|
||||||
|
|
||||||
|
popc : T_POP_POPC { charmap_Pop(); }
|
||||||
|
;
|
||||||
|
|
||||||
printt : T_POP_PRINTT string
|
printt : T_POP_PRINTT string
|
||||||
{
|
{
|
||||||
if (nPass == 1)
|
|
||||||
printf("%s", $2);
|
printf("%s", $2);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
printv : T_POP_PRINTV const
|
printv : T_POP_PRINTV const
|
||||||
{
|
{
|
||||||
if (nPass == 1)
|
|
||||||
printf("$%X", constexpr_GetConstantValue(&$2));
|
printf("$%X", constexpr_GetConstantValue(&$2));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
printi : T_POP_PRINTI const
|
printi : T_POP_PRINTI const
|
||||||
{
|
{
|
||||||
if (nPass == 1)
|
|
||||||
printf("%d", constexpr_GetConstantValue(&$2));
|
printf("%d", constexpr_GetConstantValue(&$2));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
printf : T_POP_PRINTF const
|
printf : T_POP_PRINTF const
|
||||||
{
|
{
|
||||||
if (nPass == 1)
|
|
||||||
math_Print(constexpr_GetConstantValue(&$2));
|
math_Print(constexpr_GetConstantValue(&$2));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -1126,20 +1248,17 @@ relocconst : T_ID
|
|||||||
struct Expression sTemp, sOffset;
|
struct Expression sTemp, sOffset;
|
||||||
|
|
||||||
rpn_Symbol(&sTemp, $1);
|
rpn_Symbol(&sTemp, $1);
|
||||||
sTemp.nVal = sym_GetValue($1);
|
|
||||||
|
|
||||||
rpn_Number(&sOffset, nPCOffset);
|
rpn_Number(&sOffset, nPCOffset);
|
||||||
|
|
||||||
rpn_SUB(&$$, &sTemp, &sOffset);
|
rpn_SUB(&$$, &sTemp, &sOffset);
|
||||||
} else {
|
} else {
|
||||||
rpn_Symbol(&$$, $1);
|
rpn_Symbol(&$$, $1);
|
||||||
$$.nVal = sym_GetValue($1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| T_NUMBER
|
| T_NUMBER
|
||||||
{
|
{
|
||||||
rpn_Number(&$$, $1);
|
rpn_Number(&$$, $1);
|
||||||
$$.nVal = $1;
|
|
||||||
}
|
}
|
||||||
| string
|
| string
|
||||||
{
|
{
|
||||||
@@ -1149,7 +1268,6 @@ relocconst : T_ID
|
|||||||
|
|
||||||
free(s);
|
free(s);
|
||||||
rpn_Number(&$$, r);
|
rpn_Number(&$$, r);
|
||||||
$$.nVal = r;
|
|
||||||
}
|
}
|
||||||
| T_OP_LOGICNOT relocconst %prec NEG { rpn_LOGNOT(&$$, &$2); }
|
| T_OP_LOGICNOT relocconst %prec NEG { rpn_LOGNOT(&$$, &$2); }
|
||||||
| relocconst T_OP_LOGICOR relocconst { rpn_LOGOR(&$$, &$1, &$3); }
|
| relocconst T_OP_LOGICOR relocconst { rpn_LOGOR(&$$, &$1, &$3); }
|
||||||
@@ -1179,12 +1297,10 @@ relocconst : T_ID
|
|||||||
{
|
{
|
||||||
/* '@' is also a T_ID, it is handled here. */
|
/* '@' is also a T_ID, it is handled here. */
|
||||||
rpn_BankSymbol(&$$, $3);
|
rpn_BankSymbol(&$$, $3);
|
||||||
$$.nVal = 0;
|
|
||||||
}
|
}
|
||||||
| T_OP_BANK '(' string ')'
|
| T_OP_BANK '(' string ')'
|
||||||
{
|
{
|
||||||
rpn_BankSection(&$$, $3);
|
rpn_BankSection(&$$, $3);
|
||||||
$$.nVal = 0;
|
|
||||||
}
|
}
|
||||||
| T_OP_DEF {
|
| T_OP_DEF {
|
||||||
oDontExpandStrings = true;
|
oDontExpandStrings = true;
|
||||||
@@ -1260,7 +1376,7 @@ relocconst : T_ID
|
|||||||
else
|
else
|
||||||
rpn_Number(&$$, 0);
|
rpn_Number(&$$, 0);
|
||||||
}
|
}
|
||||||
| T_OP_STRLEN '(' string ')' { rpn_Number(&$$, strlen($3)); }
|
| T_OP_STRLEN '(' string ')' { rpn_Number(&$$, strlenUTF8($3)); }
|
||||||
| '(' relocconst ')' { $$ = $2; }
|
| '(' relocconst ')' { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -1338,7 +1454,7 @@ const : T_ID { constexpr_Symbol(&$$, $1); }
|
|||||||
else
|
else
|
||||||
constexpr_Number(&$$, 0);
|
constexpr_Number(&$$, 0);
|
||||||
}
|
}
|
||||||
| T_OP_STRLEN '(' string ')' { constexpr_Number(&$$, strlen($3)); }
|
| T_OP_STRLEN '(' string ')' { constexpr_Number(&$$, strlenUTF8($3)); }
|
||||||
| '(' const ')' { $$ = $2; }
|
| '(' const ')' { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -1349,14 +1465,7 @@ string : T_STRING
|
|||||||
}
|
}
|
||||||
| T_OP_STRSUB '(' string comma uconst comma uconst ')'
|
| T_OP_STRSUB '(' string comma uconst comma uconst ')'
|
||||||
{
|
{
|
||||||
uint32_t len = $7;
|
strsubUTF8($$, $3, $5, $7);
|
||||||
if (len > MAXSTRLEN) {
|
|
||||||
warning("STRSUB: Length too big: %u", len);
|
|
||||||
len = MAXSTRLEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snprintf($$, len + 1, "%s", $3 + $5 - 1) > MAXSTRLEN)
|
|
||||||
warning("STRSUB: String too long '%s'", $$);
|
|
||||||
}
|
}
|
||||||
| T_OP_STRCAT '(' string comma string ')'
|
| T_OP_STRCAT '(' string comma string ')'
|
||||||
{
|
{
|
||||||
@@ -1637,7 +1746,6 @@ z80_jp : T_Z80_JP const_16bit
|
|||||||
| T_Z80_JP T_MODE_HL_IND
|
| T_Z80_JP T_MODE_HL_IND
|
||||||
{
|
{
|
||||||
out_AbsByte(0xE9);
|
out_AbsByte(0xE9);
|
||||||
if (nPass == 1)
|
|
||||||
warning("'JP [HL]' is obsolete, use 'JP HL' instead.");
|
warning("'JP [HL]' is obsolete, use 'JP HL' instead.");
|
||||||
}
|
}
|
||||||
| T_Z80_JP T_MODE_HL
|
| T_Z80_JP T_MODE_HL
|
||||||
@@ -1665,7 +1773,6 @@ z80_ldi : T_Z80_LDI T_MODE_HL_IND comma T_MODE_A
|
|||||||
| T_Z80_LDI T_MODE_A comma T_MODE_HL
|
| T_Z80_LDI T_MODE_A comma T_MODE_HL
|
||||||
{
|
{
|
||||||
out_AbsByte(0x0A | (2 << 4));
|
out_AbsByte(0x0A | (2 << 4));
|
||||||
if (nPass == 1)
|
|
||||||
warning("'LDI A,HL' is obsolete, use 'LDI A,[HL]' or 'LD A,[HL+] instead.");
|
warning("'LDI A,HL' is obsolete, use 'LDI A,[HL]' or 'LD A,[HL+] instead.");
|
||||||
}
|
}
|
||||||
| T_Z80_LDI T_MODE_A comma T_MODE_HL_IND
|
| T_Z80_LDI T_MODE_A comma T_MODE_HL_IND
|
||||||
@@ -1681,7 +1788,6 @@ z80_ldd : T_Z80_LDD T_MODE_HL_IND comma T_MODE_A
|
|||||||
| T_Z80_LDD T_MODE_A comma T_MODE_HL
|
| T_Z80_LDD T_MODE_A comma T_MODE_HL
|
||||||
{
|
{
|
||||||
out_AbsByte(0x0A | (3 << 4));
|
out_AbsByte(0x0A | (3 << 4));
|
||||||
if (nPass == 1)
|
|
||||||
warning("'LDD A,HL' is obsolete, use 'LDD A,[HL]' or 'LD A,[HL-] instead.");
|
warning("'LDD A,HL' is obsolete, use 'LDD A,[HL]' or 'LD A,[HL-] instead.");
|
||||||
}
|
}
|
||||||
| T_Z80_LDD T_MODE_A comma T_MODE_HL_IND
|
| T_Z80_LDD T_MODE_A comma T_MODE_HL_IND
|
||||||
@@ -1772,6 +1878,7 @@ z80_ld_mem : T_Z80_LD op_mem_ind comma T_MODE_SP
|
|||||||
(!rpn_isReloc(&$2)) && ($2.nVal >= 0xFF00)) {
|
(!rpn_isReloc(&$2)) && ($2.nVal >= 0xFF00)) {
|
||||||
out_AbsByte(0xE0);
|
out_AbsByte(0xE0);
|
||||||
out_AbsByte($2.nVal & 0xFF);
|
out_AbsByte($2.nVal & 0xFF);
|
||||||
|
rpn_Free(&$2);
|
||||||
} else {
|
} else {
|
||||||
out_AbsByte(0xEA);
|
out_AbsByte(0xEA);
|
||||||
out_RelWord(&$2);
|
out_RelWord(&$2);
|
||||||
@@ -1826,12 +1933,14 @@ z80_ld_a : T_Z80_LD reg_r comma T_MODE_C_IND
|
|||||||
(!rpn_isReloc(&$4)) && ($4.nVal >= 0xFF00)) {
|
(!rpn_isReloc(&$4)) && ($4.nVal >= 0xFF00)) {
|
||||||
out_AbsByte(0xF0);
|
out_AbsByte(0xF0);
|
||||||
out_AbsByte($4.nVal & 0xFF);
|
out_AbsByte($4.nVal & 0xFF);
|
||||||
|
rpn_Free(&$4);
|
||||||
} else {
|
} else {
|
||||||
out_AbsByte(0xFA);
|
out_AbsByte(0xFA);
|
||||||
out_RelWord(&$4);
|
out_RelWord(&$4);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
yyerror("Destination operand must be A");
|
yyerror("Destination operand must be A");
|
||||||
|
rpn_Free(&$4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -1964,6 +2073,7 @@ z80_rst : T_Z80_RST const_8bit
|
|||||||
yyerror("Invalid address $%x for RST", $2.nVal);
|
yyerror("Invalid address $%x for RST", $2.nVal);
|
||||||
else
|
else
|
||||||
out_AbsByte(0xC7 | $2.nVal);
|
out_AbsByte(0xC7 | $2.nVal);
|
||||||
|
rpn_Free(&$2);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -15,134 +16,281 @@
|
|||||||
#include "asm/charmap.h"
|
#include "asm/charmap.h"
|
||||||
#include "asm/main.h"
|
#include "asm/main.h"
|
||||||
#include "asm/output.h"
|
#include "asm/output.h"
|
||||||
|
#include "asm/util.h"
|
||||||
|
|
||||||
#include "extern/utf8decoder.h"
|
#define CHARMAP_HASH_SIZE (1 << 9)
|
||||||
|
|
||||||
struct Charmap globalCharmap = {0};
|
struct CharmapStackEntry {
|
||||||
|
struct Charmap *charmap;
|
||||||
|
struct CharmapStackEntry *next;
|
||||||
|
};
|
||||||
|
|
||||||
int32_t readUTF8Char(char *dest, char *src)
|
static struct Charmap *tHashedCharmaps[CHARMAP_HASH_SIZE];
|
||||||
|
|
||||||
|
static struct Charmap *mainCharmap;
|
||||||
|
static struct Charmap *currentCharmap;
|
||||||
|
|
||||||
|
struct CharmapStackEntry *charmapStack;
|
||||||
|
|
||||||
|
static void warnSectionCharmap(void)
|
||||||
{
|
{
|
||||||
uint32_t state;
|
static bool warned = false;
|
||||||
uint32_t codep;
|
|
||||||
int32_t i;
|
|
||||||
|
|
||||||
for (i = 0, state = 0;; i++) {
|
if (warned)
|
||||||
if (decode(&state, &codep, (uint8_t)src[i]) == 1)
|
return;
|
||||||
fatalerror("invalid UTF-8 character");
|
|
||||||
|
|
||||||
dest[i] = src[i];
|
warning("Using 'charmap' within a section when the current charmap is 'main' is deprecated");
|
||||||
|
warned = true;
|
||||||
if (state == 0) {
|
|
||||||
dest[++i] = '\0';
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t charmap_CalcHash(const char *s)
|
||||||
|
{
|
||||||
|
return calchash(s) % CHARMAP_HASH_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct Charmap **charmap_Get(const char *name)
|
||||||
|
{
|
||||||
|
struct Charmap **ppCharmap = &tHashedCharmaps[charmap_CalcHash(name)];
|
||||||
|
|
||||||
|
while (*ppCharmap != NULL && strcmp((*ppCharmap)->name, name))
|
||||||
|
ppCharmap = &(*ppCharmap)->next;
|
||||||
|
|
||||||
|
return ppCharmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CopyNode(struct Charmap *dest,
|
||||||
|
const struct Charmap *src,
|
||||||
|
int nodeIdx)
|
||||||
|
{
|
||||||
|
dest->nodes[nodeIdx].code = src->nodes[nodeIdx].code;
|
||||||
|
dest->nodes[nodeIdx].isCode = src->nodes[nodeIdx].isCode;
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
if (src->nodes[nodeIdx].next[i])
|
||||||
|
dest->nodes[nodeIdx].next[i] = dest->nodes +
|
||||||
|
(src->nodes[nodeIdx].next[i] - src->nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Charmap *charmap_New(const char *name, const char *baseName)
|
||||||
|
{
|
||||||
|
struct Charmap *pBase = NULL;
|
||||||
|
|
||||||
|
if (baseName != NULL) {
|
||||||
|
struct Charmap **ppBase = charmap_Get(baseName);
|
||||||
|
|
||||||
|
if (*ppBase == NULL) {
|
||||||
|
yyerror("Base charmap '%s' doesn't exist", baseName);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pBase = *ppBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Charmap **ppCharmap = charmap_Get(name);
|
||||||
|
|
||||||
|
if (*ppCharmap != NULL) {
|
||||||
|
yyerror("Charmap '%s' already exists", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppCharmap = calloc(1, sizeof(struct Charmap));
|
||||||
|
|
||||||
|
if (*ppCharmap == NULL)
|
||||||
|
fatalerror("Not enough memory for charmap");
|
||||||
|
|
||||||
|
struct Charmap *pCharmap = *ppCharmap;
|
||||||
|
|
||||||
|
snprintf(pCharmap->name, sizeof(pCharmap->name), "%s", name);
|
||||||
|
|
||||||
|
if (pBase != NULL) {
|
||||||
|
pCharmap->charCount = pBase->charCount;
|
||||||
|
pCharmap->nodeCount = pBase->nodeCount;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAXCHARNODES; i++)
|
||||||
|
CopyNode(pCharmap, pBase, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCharmap = pCharmap;
|
||||||
|
|
||||||
|
return pCharmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void charmap_Set(const char *name)
|
||||||
|
{
|
||||||
|
struct Charmap **ppCharmap = charmap_Get(name);
|
||||||
|
|
||||||
|
if (*ppCharmap == NULL) {
|
||||||
|
yyerror("Charmap '%s' doesn't exist", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCharmap = *ppCharmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void charmap_Push(void)
|
||||||
|
{
|
||||||
|
struct CharmapStackEntry *stackEntry;
|
||||||
|
|
||||||
|
stackEntry = malloc(sizeof(struct CharmapStackEntry));
|
||||||
|
if (stackEntry == NULL)
|
||||||
|
fatalerror("No memory for charmap stack");
|
||||||
|
|
||||||
|
stackEntry->charmap = currentCharmap;
|
||||||
|
stackEntry->next = charmapStack;
|
||||||
|
|
||||||
|
charmapStack = stackEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void charmap_Pop(void)
|
||||||
|
{
|
||||||
|
if (charmapStack == NULL)
|
||||||
|
fatalerror("No entries in the charmap stack");
|
||||||
|
|
||||||
|
struct CharmapStackEntry *top = charmapStack;
|
||||||
|
|
||||||
|
currentCharmap = top->charmap;
|
||||||
|
charmapStack = top->next;
|
||||||
|
free(top);
|
||||||
|
}
|
||||||
|
|
||||||
|
void charmap_InitMain(void)
|
||||||
|
{
|
||||||
|
mainCharmap = charmap_New("main", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t charmap_Add(char *input, uint8_t output)
|
int32_t charmap_Add(char *input, uint8_t output)
|
||||||
{
|
{
|
||||||
int32_t i;
|
int32_t i;
|
||||||
size_t input_length;
|
uint8_t v;
|
||||||
char temp1i[CHARMAPLENGTH + 1], temp2i[CHARMAPLENGTH + 1];
|
|
||||||
char temp1o = 0, temp2o = 0;
|
|
||||||
|
|
||||||
struct Charmap *charmap;
|
struct Charmap *charmap;
|
||||||
|
struct Charnode *curr_node, *temp_node;
|
||||||
|
|
||||||
if (pCurrentSection) {
|
/*
|
||||||
|
* If the user tries to define a character mapping inside a section
|
||||||
|
* and the current global charmap is the "main" one, then a local
|
||||||
|
* section charmap will be created or modified instead of the global
|
||||||
|
* one. In other words, the local section charmap can override the
|
||||||
|
* main global one, but not the others.
|
||||||
|
*/
|
||||||
|
if (pCurrentSection && currentCharmap == mainCharmap) {
|
||||||
|
warnSectionCharmap();
|
||||||
if (pCurrentSection->charmap) {
|
if (pCurrentSection->charmap) {
|
||||||
charmap = pCurrentSection->charmap;
|
charmap = pCurrentSection->charmap;
|
||||||
} else {
|
} else {
|
||||||
charmap = calloc(1, sizeof(struct Charmap));
|
charmap = calloc(1, sizeof(struct Charmap));
|
||||||
if (charmap == NULL)
|
if (charmap == NULL)
|
||||||
fatalerror("Not enough memory for charmap");
|
fatalerror("Not enough memory for charmap");
|
||||||
|
|
||||||
pCurrentSection->charmap = charmap;
|
pCurrentSection->charmap = charmap;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
charmap = &globalCharmap;
|
charmap = currentCharmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nPass == 2)
|
if (charmap->charCount >= MAXCHARMAPS || strlen(input) > CHARMAPLENGTH)
|
||||||
return charmap->count;
|
|
||||||
|
|
||||||
if (charmap->count > MAXCHARMAPS || strlen(input) > CHARMAPLENGTH)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
input_length = strlen(input);
|
curr_node = &charmap->nodes[0];
|
||||||
if (input_length > 1) {
|
|
||||||
i = 0;
|
for (i = 0; (v = (uint8_t)input[i]); i++) {
|
||||||
while (i < charmap->count + 1) {
|
if (curr_node->next[v]) {
|
||||||
if (input_length > strlen(charmap->input[i])) {
|
curr_node = curr_node->next[v];
|
||||||
memcpy(temp1i, charmap->input[i],
|
|
||||||
CHARMAPLENGTH + 1);
|
|
||||||
memcpy(charmap->input[i], input, input_length);
|
|
||||||
temp1o = charmap->output[i];
|
|
||||||
charmap->output[i] = output;
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
while (i < charmap->count + 1) {
|
|
||||||
memcpy(temp2i, charmap->input[i], CHARMAPLENGTH + 1);
|
|
||||||
memcpy(charmap->input[i], temp1i, CHARMAPLENGTH + 1);
|
|
||||||
memcpy(temp1i, temp2i, CHARMAPLENGTH + 1);
|
|
||||||
temp2o = charmap->output[i];
|
|
||||||
charmap->output[i] = temp1o;
|
|
||||||
temp1o = temp2o;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
memcpy(charmap->input[charmap->count + 1], temp1i,
|
|
||||||
CHARMAPLENGTH + 1);
|
|
||||||
charmap->output[charmap->count + 1] = temp1o;
|
|
||||||
} else {
|
} else {
|
||||||
memcpy(charmap->input[charmap->count], input, input_length);
|
temp_node = &charmap->nodes[charmap->nodeCount + 1];
|
||||||
charmap->output[charmap->count] = output;
|
|
||||||
|
curr_node->next[v] = temp_node;
|
||||||
|
curr_node = temp_node;
|
||||||
|
|
||||||
|
++charmap->nodeCount;
|
||||||
}
|
}
|
||||||
return ++charmap->count;
|
}
|
||||||
|
|
||||||
|
/* prevent duplicated keys by accepting only first key-value pair. */
|
||||||
|
if (curr_node->isCode)
|
||||||
|
return charmap->charCount;
|
||||||
|
|
||||||
|
curr_node->code = output;
|
||||||
|
curr_node->isCode = 1;
|
||||||
|
|
||||||
|
return ++charmap->charCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t charmap_Convert(char **input)
|
int32_t charmap_Convert(char **input)
|
||||||
{
|
{
|
||||||
struct Charmap *charmap;
|
struct Charmap *charmap;
|
||||||
|
struct Charnode *charnode;
|
||||||
|
|
||||||
char outchar[CHARMAPLENGTH + 1];
|
char *output;
|
||||||
char *buffer;
|
char outchar[8];
|
||||||
int32_t i, j, length;
|
|
||||||
|
|
||||||
if (pCurrentSection && pCurrentSection->charmap)
|
int32_t i, match, length;
|
||||||
|
uint8_t v, foundCode;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is a local section charmap and the current global charmap
|
||||||
|
* is the "main" one, the local one is used. Otherwise, the global
|
||||||
|
* one is used. In other words, the local section charmap can override
|
||||||
|
* the main global one, but not the others.
|
||||||
|
*/
|
||||||
|
if (pCurrentSection &&
|
||||||
|
pCurrentSection->charmap &&
|
||||||
|
currentCharmap == mainCharmap)
|
||||||
charmap = pCurrentSection->charmap;
|
charmap = pCurrentSection->charmap;
|
||||||
else
|
else
|
||||||
charmap = &globalCharmap;
|
charmap = currentCharmap;
|
||||||
|
|
||||||
buffer = malloc(strlen(*input));
|
output = malloc(strlen(*input));
|
||||||
if (buffer == NULL)
|
if (output == NULL)
|
||||||
fatalerror("Not enough memory for buffer");
|
fatalerror("Not enough memory for buffer");
|
||||||
|
|
||||||
length = 0;
|
length = 0;
|
||||||
|
|
||||||
while (**input) {
|
while (**input) {
|
||||||
j = 0;
|
charnode = &charmap->nodes[0];
|
||||||
for (i = 0; i < charmap->count; i++) {
|
|
||||||
j = strlen(charmap->input[i]);
|
/*
|
||||||
if (memcmp(*input, charmap->input[i], j) == 0) {
|
* find the longest valid match which has been registered in charmap.
|
||||||
outchar[0] = charmap->output[i];
|
* note that there could be either multiple matches or no match.
|
||||||
outchar[1] = 0;
|
* and it possibly takes the longest match between them,
|
||||||
|
* which means that it ignores partial matches shorter than the longest one.
|
||||||
|
*/
|
||||||
|
for (i = match = 0; (v = (*input)[i]);) {
|
||||||
|
if (!charnode->next[v])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
charnode = charnode->next[v];
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (charnode->isCode) {
|
||||||
|
match = i;
|
||||||
|
foundCode = charnode->code;
|
||||||
}
|
}
|
||||||
j = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!j)
|
if (match) {
|
||||||
j = readUTF8Char(outchar, *input);
|
output[length] = foundCode;
|
||||||
|
|
||||||
if (!outchar[0]) {
|
length += 1;
|
||||||
buffer[length++] = 0;
|
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; outchar[i]; i++)
|
/*
|
||||||
buffer[length++] = outchar[i];
|
* put a utf-8 character
|
||||||
|
* if failed to find a match.
|
||||||
|
*/
|
||||||
|
match = readUTF8Char(outchar, *input);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
memcpy(output + length, *input, match);
|
||||||
|
} else {
|
||||||
|
output[length] = 0;
|
||||||
|
match = 1;
|
||||||
}
|
}
|
||||||
*input += j;
|
|
||||||
|
length += match;
|
||||||
}
|
}
|
||||||
*input = buffer;
|
|
||||||
|
*input += match;
|
||||||
|
}
|
||||||
|
|
||||||
|
*input = output;
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ void constexpr_UnaryOp(struct ConstExpression *expr,
|
|||||||
result = value;
|
result = value;
|
||||||
break;
|
break;
|
||||||
case T_OP_SUB:
|
case T_OP_SUB:
|
||||||
result = -value;
|
result = -(uint32_t)value;
|
||||||
break;
|
break;
|
||||||
case T_OP_NOT:
|
case T_OP_NOT:
|
||||||
result = ~value;
|
result = ~value;
|
||||||
@@ -155,10 +155,10 @@ void constexpr_BinaryOp(struct ConstExpression *expr,
|
|||||||
result = value1 != value2;
|
result = value1 != value2;
|
||||||
break;
|
break;
|
||||||
case T_OP_ADD:
|
case T_OP_ADD:
|
||||||
result = value1 + value2;
|
result = (uint32_t)value1 + (uint32_t)value2;
|
||||||
break;
|
break;
|
||||||
case T_OP_SUB:
|
case T_OP_SUB:
|
||||||
result = value1 - value2;
|
result = (uint32_t)value1 - (uint32_t)value2;
|
||||||
break;
|
break;
|
||||||
case T_OP_XOR:
|
case T_OP_XOR:
|
||||||
result = value1 ^ value2;
|
result = value1 ^ value2;
|
||||||
@@ -181,7 +181,7 @@ void constexpr_BinaryOp(struct ConstExpression *expr,
|
|||||||
fatalerror("Shift by too big value: %d",
|
fatalerror("Shift by too big value: %d",
|
||||||
value2);
|
value2);
|
||||||
|
|
||||||
result = value1 << value2;
|
result = (uint32_t)value1 << value2;
|
||||||
break;
|
break;
|
||||||
case T_OP_SHR:
|
case T_OP_SHR:
|
||||||
if (value2 < 0)
|
if (value2 < 0)
|
||||||
@@ -194,16 +194,24 @@ void constexpr_BinaryOp(struct ConstExpression *expr,
|
|||||||
result = value1 >> value2;
|
result = value1 >> value2;
|
||||||
break;
|
break;
|
||||||
case T_OP_MUL:
|
case T_OP_MUL:
|
||||||
result = value1 * value2;
|
result = (uint32_t)value1 * (uint32_t)value2;
|
||||||
break;
|
break;
|
||||||
case T_OP_DIV:
|
case T_OP_DIV:
|
||||||
if (value2 == 0)
|
if (value2 == 0)
|
||||||
fatalerror("Division by zero");
|
fatalerror("Division by zero");
|
||||||
|
if (value1 == INT32_MIN && value2 == -1) {
|
||||||
|
warning("Division of min value by -1");
|
||||||
|
result = INT32_MIN;
|
||||||
|
} else {
|
||||||
result = value1 / value2;
|
result = value1 / value2;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case T_OP_MOD:
|
case T_OP_MOD:
|
||||||
if (value2 == 0)
|
if (value2 == 0)
|
||||||
fatalerror("Division by zero");
|
fatalerror("Division by zero");
|
||||||
|
if (value1 == INT32_MIN && value2 == -1)
|
||||||
|
result = 0;
|
||||||
|
else
|
||||||
result = value1 % value2;
|
result = value1 % value2;
|
||||||
break;
|
break;
|
||||||
case T_OP_FDIV:
|
case T_OP_FDIV:
|
||||||
|
|||||||
118
src/asm/fstack.c
118
src/asm/fstack.c
@@ -28,6 +28,8 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
static struct sContext *pFileStack;
|
static struct sContext *pFileStack;
|
||||||
|
static unsigned int nFileStackDepth;
|
||||||
|
unsigned int nMaxRecursionDepth;
|
||||||
static struct sSymbol *pCurrentMacro;
|
static struct sSymbol *pCurrentMacro;
|
||||||
static YY_BUFFER_STATE CurrentFlexHandle;
|
static YY_BUFFER_STATE CurrentFlexHandle;
|
||||||
static FILE *pCurrentFile;
|
static FILE *pCurrentFile;
|
||||||
@@ -40,6 +42,8 @@ static uint32_t nMacroCount;
|
|||||||
static char *pCurrentREPTBlock;
|
static char *pCurrentREPTBlock;
|
||||||
static uint32_t nCurrentREPTBlockSize;
|
static uint32_t nCurrentREPTBlockSize;
|
||||||
static uint32_t nCurrentREPTBlockCount;
|
static uint32_t nCurrentREPTBlockCount;
|
||||||
|
static int32_t nCurrentREPTBodyFirstLine;
|
||||||
|
static int32_t nCurrentREPTBodyLastLine;
|
||||||
|
|
||||||
uint32_t ulMacroReturnValue;
|
uint32_t ulMacroReturnValue;
|
||||||
|
|
||||||
@@ -51,6 +55,8 @@ uint32_t ulMacroReturnValue;
|
|||||||
#define STAT_isMacroArg 2
|
#define STAT_isMacroArg 2
|
||||||
#define STAT_isREPTBlock 3
|
#define STAT_isREPTBlock 3
|
||||||
|
|
||||||
|
/* Max context stack size */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Context push and pop
|
* Context push and pop
|
||||||
*/
|
*/
|
||||||
@@ -58,6 +64,9 @@ static void pushcontext(void)
|
|||||||
{
|
{
|
||||||
struct sContext **ppFileStack;
|
struct sContext **ppFileStack;
|
||||||
|
|
||||||
|
if (++nFileStackDepth > nMaxRecursionDepth)
|
||||||
|
fatalerror("Recursion limit (%d) exceeded", nMaxRecursionDepth);
|
||||||
|
|
||||||
ppFileStack = &pFileStack;
|
ppFileStack = &pFileStack;
|
||||||
while (*ppFileStack)
|
while (*ppFileStack)
|
||||||
ppFileStack = &((*ppFileStack)->pNext);
|
ppFileStack = &((*ppFileStack)->pNext);
|
||||||
@@ -86,6 +95,8 @@ static void pushcontext(void)
|
|||||||
(*ppFileStack)->pREPTBlock = pCurrentREPTBlock;
|
(*ppFileStack)->pREPTBlock = pCurrentREPTBlock;
|
||||||
(*ppFileStack)->nREPTBlockSize = nCurrentREPTBlockSize;
|
(*ppFileStack)->nREPTBlockSize = nCurrentREPTBlockSize;
|
||||||
(*ppFileStack)->nREPTBlockCount = nCurrentREPTBlockCount;
|
(*ppFileStack)->nREPTBlockCount = nCurrentREPTBlockCount;
|
||||||
|
(*ppFileStack)->nREPTBodyFirstLine = nCurrentREPTBodyFirstLine;
|
||||||
|
(*ppFileStack)->nREPTBodyLastLine = nCurrentREPTBodyLastLine;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatalerror("%s: Internal error.", __func__);
|
fatalerror("%s: Internal error.", __func__);
|
||||||
@@ -100,6 +111,11 @@ static int32_t popcontext(void)
|
|||||||
|
|
||||||
if (nCurrentStatus == STAT_isREPTBlock) {
|
if (nCurrentStatus == STAT_isREPTBlock) {
|
||||||
if (--nCurrentREPTBlockCount) {
|
if (--nCurrentREPTBlockCount) {
|
||||||
|
char *pREPTIterationWritePtr;
|
||||||
|
unsigned long nREPTIterationNo;
|
||||||
|
int nNbCharsWritten;
|
||||||
|
int nNbCharsLeft;
|
||||||
|
|
||||||
yy_delete_buffer(CurrentFlexHandle);
|
yy_delete_buffer(CurrentFlexHandle);
|
||||||
CurrentFlexHandle =
|
CurrentFlexHandle =
|
||||||
yy_scan_bytes(pCurrentREPTBlock,
|
yy_scan_bytes(pCurrentREPTBlock,
|
||||||
@@ -108,6 +124,29 @@ static int32_t popcontext(void)
|
|||||||
sym_UseCurrentMacroArgs();
|
sym_UseCurrentMacroArgs();
|
||||||
sym_SetMacroArgID(nMacroCount++);
|
sym_SetMacroArgID(nMacroCount++);
|
||||||
sym_UseNewMacroArgs();
|
sym_UseNewMacroArgs();
|
||||||
|
|
||||||
|
/* Increment REPT count in file path */
|
||||||
|
pREPTIterationWritePtr =
|
||||||
|
strrchr(tzCurrentFileName, '~') + 1;
|
||||||
|
nREPTIterationNo =
|
||||||
|
strtoul(pREPTIterationWritePtr, NULL, 10);
|
||||||
|
nNbCharsLeft = sizeof(tzCurrentFileName)
|
||||||
|
- (pREPTIterationWritePtr - tzCurrentFileName);
|
||||||
|
nNbCharsWritten = snprintf(pREPTIterationWritePtr,
|
||||||
|
nNbCharsLeft, "%lu",
|
||||||
|
nREPTIterationNo + 1);
|
||||||
|
if (nNbCharsWritten >= nNbCharsLeft) {
|
||||||
|
/*
|
||||||
|
* The string is probably corrupted somehow,
|
||||||
|
* revert the change to avoid a bad error
|
||||||
|
* output.
|
||||||
|
*/
|
||||||
|
sprintf(pREPTIterationWritePtr, "%lu",
|
||||||
|
nREPTIterationNo);
|
||||||
|
fatalerror("Cannot write REPT count to file path");
|
||||||
|
}
|
||||||
|
|
||||||
|
nLineNo = nCurrentREPTBodyFirstLine;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,13 +167,9 @@ static int32_t popcontext(void)
|
|||||||
if (nCurrentStatus == STAT_isInclude)
|
if (nCurrentStatus == STAT_isInclude)
|
||||||
fclose(pCurrentFile);
|
fclose(pCurrentFile);
|
||||||
|
|
||||||
if (nCurrentStatus == STAT_isMacro) {
|
if (nCurrentStatus == STAT_isMacro
|
||||||
sym_FreeCurrentMacroArgs();
|
|| nCurrentStatus == STAT_isREPTBlock)
|
||||||
nLineNo += 1;
|
nLineNo++;
|
||||||
}
|
|
||||||
|
|
||||||
if (nCurrentStatus == STAT_isREPTBlock)
|
|
||||||
nLineNo += 1;
|
|
||||||
|
|
||||||
CurrentFlexHandle = pLastFile->FlexHandle;
|
CurrentFlexHandle = pLastFile->FlexHandle;
|
||||||
strcpy((char *)tzCurrentFileName, (char *)pLastFile->tzFileName);
|
strcpy((char *)tzCurrentFileName, (char *)pLastFile->tzFileName);
|
||||||
@@ -153,11 +188,16 @@ static int32_t popcontext(void)
|
|||||||
pCurrentREPTBlock = pLastFile->pREPTBlock;
|
pCurrentREPTBlock = pLastFile->pREPTBlock;
|
||||||
nCurrentREPTBlockSize = pLastFile->nREPTBlockSize;
|
nCurrentREPTBlockSize = pLastFile->nREPTBlockSize;
|
||||||
nCurrentREPTBlockCount = pLastFile->nREPTBlockCount;
|
nCurrentREPTBlockCount = pLastFile->nREPTBlockCount;
|
||||||
|
nCurrentREPTBodyFirstLine = pLastFile->nREPTBodyFirstLine;
|
||||||
|
/* + 1 to account for the `ENDR` line */
|
||||||
|
nLineNo = pLastFile->nREPTBodyLastLine + 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatalerror("%s: Internal error.", __func__);
|
fatalerror("%s: Internal error.", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nFileStackDepth--;
|
||||||
|
|
||||||
free(*ppLastFile);
|
free(*ppLastFile);
|
||||||
*ppLastFile = NULL;
|
*ppLastFile = NULL;
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
yy_switch_to_buffer(CurrentFlexHandle);
|
||||||
@@ -222,6 +262,20 @@ void fstk_Dump(void)
|
|||||||
fprintf(stderr, "%s(%d)", tzCurrentFileName, nLineNo);
|
fprintf(stderr, "%s(%d)", tzCurrentFileName, nLineNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump the string expansion stack to stderr
|
||||||
|
*/
|
||||||
|
void fstk_DumpStringExpansions(void)
|
||||||
|
{
|
||||||
|
const struct sStringExpansionPos *pExpansion = pCurrentStringExpansion;
|
||||||
|
|
||||||
|
while (pExpansion) {
|
||||||
|
fprintf(stderr, "while expanding symbol \"%s\"\n",
|
||||||
|
pExpansion->tzName);
|
||||||
|
pExpansion = pExpansion->pParent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extra includepath stuff
|
* Extra includepath stuff
|
||||||
*/
|
*/
|
||||||
@@ -317,19 +371,23 @@ void fstk_RunInclude(char *tzFileName)
|
|||||||
uint32_t fstk_RunMacro(char *s)
|
uint32_t fstk_RunMacro(char *s)
|
||||||
{
|
{
|
||||||
struct sSymbol *sym = sym_FindMacro(s);
|
struct sSymbol *sym = sym_FindMacro(s);
|
||||||
|
int nPrintedChars;
|
||||||
|
|
||||||
if (sym == NULL)
|
if (sym == NULL || sym->pMacro == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pushcontext();
|
pushcontext();
|
||||||
sym_SetMacroArgID(nMacroCount++);
|
sym_SetMacroArgID(nMacroCount++);
|
||||||
nLineNo = -1;
|
/* Minus 1 because there is a newline at the beginning of the buffer */
|
||||||
|
nLineNo = sym->nFileLine - 1;
|
||||||
sym_UseNewMacroArgs();
|
sym_UseNewMacroArgs();
|
||||||
nCurrentStatus = STAT_isMacro;
|
nCurrentStatus = STAT_isMacro;
|
||||||
strcpy(tzCurrentFileName, s);
|
nPrintedChars = snprintf(tzCurrentFileName, _MAX_PATH + 1,
|
||||||
|
"%s::%s", sym->tzFileName, s);
|
||||||
if (sym->pMacro == NULL)
|
if (nPrintedChars > _MAX_PATH) {
|
||||||
return 0;
|
popcontext();
|
||||||
|
fatalerror("File name + macro name is too large to fit into buffer");
|
||||||
|
}
|
||||||
|
|
||||||
pCurrentMacro = sym;
|
pCurrentMacro = sym;
|
||||||
CurrentFlexHandle = yy_scan_bytes(pCurrentMacro->pMacro,
|
CurrentFlexHandle = yy_scan_bytes(pCurrentMacro->pMacro,
|
||||||
@@ -385,17 +443,30 @@ void fstk_RunString(char *s)
|
|||||||
/*
|
/*
|
||||||
* Set up a repeat block for parsing
|
* Set up a repeat block for parsing
|
||||||
*/
|
*/
|
||||||
void fstk_RunRept(uint32_t count)
|
void fstk_RunRept(uint32_t count, int32_t nReptLineNo)
|
||||||
{
|
{
|
||||||
if (count) {
|
if (count) {
|
||||||
pushcontext();
|
static const char *tzReptStr = "::REPT~1";
|
||||||
|
|
||||||
|
/* For error printing to make sense, fake nLineNo */
|
||||||
|
nCurrentREPTBodyLastLine = nLineNo;
|
||||||
|
nLineNo = nReptLineNo;
|
||||||
sym_UseCurrentMacroArgs();
|
sym_UseCurrentMacroArgs();
|
||||||
|
pushcontext();
|
||||||
sym_SetMacroArgID(nMacroCount++);
|
sym_SetMacroArgID(nMacroCount++);
|
||||||
sym_UseNewMacroArgs();
|
sym_UseNewMacroArgs();
|
||||||
nCurrentREPTBlockCount = count;
|
nCurrentREPTBlockCount = count;
|
||||||
nCurrentStatus = STAT_isREPTBlock;
|
nCurrentStatus = STAT_isREPTBlock;
|
||||||
nCurrentREPTBlockSize = ulNewMacroSize;
|
nCurrentREPTBlockSize = ulNewMacroSize;
|
||||||
pCurrentREPTBlock = tzNewMacro;
|
pCurrentREPTBlock = tzNewMacro;
|
||||||
|
nCurrentREPTBodyFirstLine = nReptLineNo + 1;
|
||||||
|
nLineNo = nReptLineNo;
|
||||||
|
|
||||||
|
if (strlen(tzCurrentFileName) + strlen(tzReptStr) > _MAX_PATH)
|
||||||
|
fatalerror("Cannot append \"%s\" to file path",
|
||||||
|
tzReptStr);
|
||||||
|
strcat(tzCurrentFileName, tzReptStr);
|
||||||
|
|
||||||
CurrentFlexHandle =
|
CurrentFlexHandle =
|
||||||
yy_scan_bytes(pCurrentREPTBlock, nCurrentREPTBlockSize);
|
yy_scan_bytes(pCurrentREPTBlock, nCurrentREPTBlockSize);
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
yy_switch_to_buffer(CurrentFlexHandle);
|
||||||
@@ -405,23 +476,26 @@ void fstk_RunRept(uint32_t count)
|
|||||||
/*
|
/*
|
||||||
* Initialize the filestack routines
|
* Initialize the filestack routines
|
||||||
*/
|
*/
|
||||||
void fstk_Init(char *s)
|
void fstk_Init(char *pFileName)
|
||||||
{
|
{
|
||||||
char tzFileName[_MAX_PATH + 1];
|
|
||||||
char tzSymFileName[_MAX_PATH + 1 + 2];
|
char tzSymFileName[_MAX_PATH + 1 + 2];
|
||||||
|
|
||||||
snprintf(tzSymFileName, sizeof(tzSymFileName), "\"%s\"", s);
|
snprintf(tzSymFileName, sizeof(tzSymFileName), "\"%s\"", pFileName);
|
||||||
sym_AddString("__FILE__", tzSymFileName);
|
sym_AddString("__FILE__", tzSymFileName);
|
||||||
|
|
||||||
strcpy(tzFileName, s);
|
|
||||||
pFileStack = NULL;
|
pFileStack = NULL;
|
||||||
pCurrentFile = fopen(tzFileName, "rb");
|
if (strcmp(pFileName, "-") == 0) {
|
||||||
|
pCurrentFile = stdin;
|
||||||
|
} else {
|
||||||
|
pCurrentFile = fopen(pFileName, "rb");
|
||||||
if (pCurrentFile == NULL)
|
if (pCurrentFile == NULL)
|
||||||
err(1, "Unable to open file '%s'", tzFileName);
|
err(1, "Unable to open file '%s'", pFileName);
|
||||||
|
}
|
||||||
|
nFileStackDepth = 0;
|
||||||
|
|
||||||
nMacroCount = 0;
|
nMacroCount = 0;
|
||||||
nCurrentStatus = STAT_isInclude;
|
nCurrentStatus = STAT_isInclude;
|
||||||
snprintf(tzCurrentFileName, _MAX_PATH + 1, "%s", tzFileName);
|
snprintf(tzCurrentFileName, _MAX_PATH + 1, "%s", pFileName);
|
||||||
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
|
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
yy_switch_to_buffer(CurrentFlexHandle);
|
||||||
nLineNo = 1;
|
nLineNo = 1;
|
||||||
|
|||||||
@@ -71,8 +71,9 @@ typedef int32_t(*x2bin) (char ch);
|
|||||||
|
|
||||||
static int32_t ascii2bin(char *s)
|
static int32_t ascii2bin(char *s)
|
||||||
{
|
{
|
||||||
int32_t radix = 10;
|
char *start = s;
|
||||||
int32_t result = 0;
|
uint32_t radix = 10;
|
||||||
|
uint32_t result = 0;
|
||||||
x2bin convertfunc = char2bin;
|
x2bin convertfunc = char2bin;
|
||||||
|
|
||||||
switch (*s) {
|
switch (*s) {
|
||||||
@@ -101,6 +102,9 @@ static int32_t ascii2bin(char *s)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint32_t max_q = UINT32_MAX / radix;
|
||||||
|
const uint32_t max_r = UINT32_MAX % radix;
|
||||||
|
|
||||||
if (*s == '\0') {
|
if (*s == '\0') {
|
||||||
/*
|
/*
|
||||||
* There are no digits after the radix prefix
|
* There are no digits after the radix prefix
|
||||||
@@ -108,15 +112,39 @@ static int32_t ascii2bin(char *s)
|
|||||||
*/
|
*/
|
||||||
yyerror("Invalid integer constant");
|
yyerror("Invalid integer constant");
|
||||||
} else if (radix == 4) {
|
} else if (radix == 4) {
|
||||||
|
int32_t size = 0;
|
||||||
int32_t c;
|
int32_t c;
|
||||||
|
|
||||||
while (*s != '\0') {
|
while (*s != '\0') {
|
||||||
c = convertfunc(*s++);
|
c = convertfunc(*s++);
|
||||||
result = result * 2 + ((c & 2) << 7) + (c & 1);
|
result = result * 2 + ((c & 2) << 7) + (c & 1);
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extending a graphics constant longer than 8 pixels,
|
||||||
|
* the Game Boy tile width, produces a nonsensical result.
|
||||||
|
*/
|
||||||
|
if (size > 8) {
|
||||||
|
warning("Graphics constant '%s' is too long",
|
||||||
|
start);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (*s != '\0')
|
bool overflow = false;
|
||||||
result = result * radix + convertfunc(*s++);
|
|
||||||
|
while (*s != '\0') {
|
||||||
|
int32_t digit = convertfunc(*s++);
|
||||||
|
|
||||||
|
if (result > max_q
|
||||||
|
|| (result == max_q && digit > max_r)) {
|
||||||
|
overflow = true;
|
||||||
|
}
|
||||||
|
result = result * radix + digit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overflow)
|
||||||
|
warning("Integer constant '%s' is too large",
|
||||||
|
start);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -124,19 +152,19 @@ static int32_t ascii2bin(char *s)
|
|||||||
|
|
||||||
uint32_t ParseFixedPoint(char *s, uint32_t size)
|
uint32_t ParseFixedPoint(char *s, uint32_t size)
|
||||||
{
|
{
|
||||||
uint32_t i = 0, dot = 0;
|
uint32_t i;
|
||||||
|
uint32_t dot = 0;
|
||||||
|
|
||||||
while (size && dot != 2) {
|
for (i = 0; i < size; i++) {
|
||||||
if (s[i] == '.')
|
if (s[i] == '.') {
|
||||||
dot += 1;
|
dot++;
|
||||||
|
|
||||||
if (dot < 2) {
|
if (dot == 2)
|
||||||
size -= 1;
|
break;
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
yyunputbytes(size);
|
yyskipbytes(i);
|
||||||
|
|
||||||
yylval.nConstValue = (int32_t)(atof(s) * 65536);
|
yylval.nConstValue = (int32_t)(atof(s) * 65536);
|
||||||
|
|
||||||
@@ -147,66 +175,124 @@ uint32_t ParseNumber(char *s, uint32_t size)
|
|||||||
{
|
{
|
||||||
char dest[256];
|
char dest[256];
|
||||||
|
|
||||||
|
if (size > 255)
|
||||||
|
fatalerror("Number token too long");
|
||||||
|
|
||||||
strncpy(dest, s, size);
|
strncpy(dest, s, size);
|
||||||
dest[size] = 0;
|
dest[size] = 0;
|
||||||
yylval.nConstValue = ascii2bin(dest);
|
yylval.nConstValue = ascii2bin(dest);
|
||||||
|
|
||||||
|
yyskipbytes(size);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the symbol name ends before the end of the macro arg,
|
||||||
|
* return a pointer to the rest of the macro arg.
|
||||||
|
* Otherwise, return NULL.
|
||||||
|
*/
|
||||||
|
char *AppendMacroArg(char whichArg, char *dest, size_t *destIndex)
|
||||||
|
{
|
||||||
|
char *marg;
|
||||||
|
|
||||||
|
if (whichArg == '@')
|
||||||
|
marg = sym_FindMacroArg(-1);
|
||||||
|
else if (whichArg >= '1' && whichArg <= '9')
|
||||||
|
marg = sym_FindMacroArg(whichArg - '0');
|
||||||
|
else
|
||||||
|
fatalerror("Invalid macro argument '\\%c' in symbol", whichArg);
|
||||||
|
|
||||||
|
if (!marg)
|
||||||
|
fatalerror("Macro argument '\\%c' not defined", whichArg);
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
while ((ch = *marg) != 0) {
|
||||||
|
if ((ch >= 'a' && ch <= 'z')
|
||||||
|
|| (ch >= 'A' && ch <= 'Z')
|
||||||
|
|| (ch >= '0' && ch <= '9')
|
||||||
|
|| ch == '_'
|
||||||
|
|| ch == '@'
|
||||||
|
|| ch == '#'
|
||||||
|
|| ch == '.') {
|
||||||
|
if (*destIndex >= MAXSYMLEN)
|
||||||
|
fatalerror("Symbol too long");
|
||||||
|
|
||||||
|
dest[*destIndex] = ch;
|
||||||
|
(*destIndex)++;
|
||||||
|
} else {
|
||||||
|
return marg;
|
||||||
|
}
|
||||||
|
|
||||||
|
marg++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t ParseSymbol(char *src, uint32_t size)
|
uint32_t ParseSymbol(char *src, uint32_t size)
|
||||||
{
|
{
|
||||||
char dest[MAXSYMLEN + 1];
|
char dest[MAXSYMLEN + 1];
|
||||||
int32_t copied = 0, size_backup = size;
|
size_t srcIndex = 0;
|
||||||
|
size_t destIndex = 0;
|
||||||
|
char *rest = NULL;
|
||||||
|
|
||||||
while (size && copied < MAXSYMLEN) {
|
while (srcIndex < size) {
|
||||||
if (*src == '\\') {
|
char ch = src[srcIndex++];
|
||||||
char *marg;
|
|
||||||
|
|
||||||
src += 1;
|
if (ch == '\\') {
|
||||||
size -= 1;
|
/*
|
||||||
|
* We don't check if srcIndex is still less than size,
|
||||||
|
* but that can only fail to be true when the
|
||||||
|
* following char is neither '@' nor a digit.
|
||||||
|
* In that case, AppendMacroArg() will catch the error.
|
||||||
|
*/
|
||||||
|
ch = src[srcIndex++];
|
||||||
|
|
||||||
if (*src == '@') {
|
rest = AppendMacroArg(ch, dest, &destIndex);
|
||||||
marg = sym_FindMacroArg(-1);
|
/* If the symbol's end was in the middle of the token */
|
||||||
} else if (*src >= '0' && *src <= '9') {
|
if (rest)
|
||||||
marg = sym_FindMacroArg(*src - '0');
|
break;
|
||||||
} else {
|
} else {
|
||||||
fatalerror("Malformed ID");
|
if (destIndex >= MAXSYMLEN)
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
src += 1;
|
|
||||||
size -= 1;
|
|
||||||
|
|
||||||
if (marg) {
|
|
||||||
while (*marg)
|
|
||||||
dest[copied++] = *marg++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dest[copied++] = *src++;
|
|
||||||
size -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copied > MAXSYMLEN)
|
|
||||||
fatalerror("Symbol too long");
|
fatalerror("Symbol too long");
|
||||||
|
dest[destIndex++] = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dest[copied] = 0;
|
dest[destIndex] = 0;
|
||||||
|
|
||||||
|
/* Tell the lexer we read all bytes that we did */
|
||||||
|
yyskipbytes(srcIndex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If an escape's expansion left some chars after the symbol's end,
|
||||||
|
* such as the `::` in a `Backup\1` expanded to `BackupCamX::`,
|
||||||
|
* put those into the buffer.
|
||||||
|
* Note that this NEEDS to be done after the `yyskipbytes` above.
|
||||||
|
*/
|
||||||
|
if (rest)
|
||||||
|
yyunputstr(rest);
|
||||||
|
|
||||||
|
/* If the symbol is an EQUS, expand it */
|
||||||
if (!oDontExpandStrings && sym_isString(dest)) {
|
if (!oDontExpandStrings && sym_isString(dest)) {
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
yyskipbytes(size_backup);
|
lex_BeginStringExpansion(dest);
|
||||||
|
|
||||||
|
/* Feed the symbol's contents into the buffer */
|
||||||
yyunputstr(s = sym_GetStringValue(dest));
|
yyunputstr(s = sym_GetStringValue(dest));
|
||||||
|
|
||||||
|
/* Lines inserted this way shall not increase nLineNo */
|
||||||
while (*s) {
|
while (*s) {
|
||||||
if (*s++ == '\n')
|
if (*s++ == '\n')
|
||||||
nLineNo -= 1;
|
nLineNo--;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(yylval.tzString, dest);
|
strcpy(yylval.tzSym, dest);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,9 +307,9 @@ uint32_t PutMacroArg(char *src, uint32_t size)
|
|||||||
if (s != NULL)
|
if (s != NULL)
|
||||||
yyunputstr(s);
|
yyunputstr(s);
|
||||||
else
|
else
|
||||||
yyerror("Macro argument not defined");
|
yyerror("Macro argument '\\%c' not defined", src[1]);
|
||||||
} else {
|
} else {
|
||||||
yyerror("Invalid macro argument");
|
yyerror("Invalid macro argument '\\%c'", src[1]);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -401,6 +487,10 @@ const struct sLexInitString lexer_strings[] = {
|
|||||||
|
|
||||||
{"incbin", T_POP_INCBIN},
|
{"incbin", T_POP_INCBIN},
|
||||||
{"charmap", T_POP_CHARMAP},
|
{"charmap", T_POP_CHARMAP},
|
||||||
|
{"newcharmap", T_POP_NEWCHARMAP},
|
||||||
|
{"setcharmap", T_POP_SETCHARMAP},
|
||||||
|
{"pushc", T_POP_PUSHC},
|
||||||
|
{"popc", T_POP_POPC},
|
||||||
|
|
||||||
{"fail", T_POP_FAIL},
|
{"fail", T_POP_FAIL},
|
||||||
{"warn", T_POP_WARN},
|
{"warn", T_POP_WARN},
|
||||||
|
|||||||
307
src/asm/lexer.c
307
src/asm/lexer.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
@@ -38,6 +38,8 @@ struct sLexString {
|
|||||||
|
|
||||||
#define SAFETYMARGIN 1024
|
#define SAFETYMARGIN 1024
|
||||||
|
|
||||||
|
#define BOM_SIZE 3
|
||||||
|
|
||||||
struct sLexFloat tLexFloat[32];
|
struct sLexFloat tLexFloat[32];
|
||||||
struct sLexString *tLexHash[LEXHASHSIZE];
|
struct sLexString *tLexHash[LEXHASHSIZE];
|
||||||
YY_BUFFER_STATE pCurrentBuffer;
|
YY_BUFFER_STATE pCurrentBuffer;
|
||||||
@@ -49,6 +51,12 @@ uint32_t tFloatingChars[256];
|
|||||||
uint32_t nFloating;
|
uint32_t nFloating;
|
||||||
enum eLexerState lexerstate = LEX_STATE_NORMAL;
|
enum eLexerState lexerstate = LEX_STATE_NORMAL;
|
||||||
|
|
||||||
|
struct sStringExpansionPos *pCurrentStringExpansion;
|
||||||
|
static unsigned int nNbStringExpansions;
|
||||||
|
|
||||||
|
/* UTF-8 byte order mark */
|
||||||
|
static const unsigned char bom[BOM_SIZE] = { 0xEF, 0xBB, 0xBF };
|
||||||
|
|
||||||
void upperstring(char *s)
|
void upperstring(char *s)
|
||||||
{
|
{
|
||||||
while (*s) {
|
while (*s) {
|
||||||
@@ -83,17 +91,49 @@ void yyunput(char c)
|
|||||||
*(--pLexBuffer) = c;
|
*(--pLexBuffer) = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void yyunputstr(char *s)
|
void yyunputstr(const char *s)
|
||||||
{
|
{
|
||||||
int32_t i, len;
|
int32_t len;
|
||||||
|
|
||||||
len = strlen(s);
|
len = strlen(s);
|
||||||
|
|
||||||
if (pLexBuffer - len < pLexBufferRealStart)
|
/*
|
||||||
|
* It would be undefined behavior to subtract `len` from pLexBuffer and
|
||||||
|
* potentially have it point outside of pLexBufferRealStart's buffer,
|
||||||
|
* this is why the check is done this way.
|
||||||
|
* Refer to https://github.com/rednex/rgbds/pull/411#discussion_r319779797
|
||||||
|
*/
|
||||||
|
if (pLexBuffer - pLexBufferRealStart < len)
|
||||||
fatalerror("Buffer safety margin exceeded");
|
fatalerror("Buffer safety margin exceeded");
|
||||||
|
|
||||||
for (i = len - 1; i >= 0; i--)
|
pLexBuffer -= len;
|
||||||
*(--pLexBuffer) = s[i];
|
|
||||||
|
memcpy(pLexBuffer, s, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Marks that a new string expansion with name `tzName` ends here
|
||||||
|
* Enforces recursion depth
|
||||||
|
*/
|
||||||
|
void lex_BeginStringExpansion(const char *tzName)
|
||||||
|
{
|
||||||
|
if (++nNbStringExpansions > nMaxRecursionDepth)
|
||||||
|
fatalerror("Recursion limit (%d) exceeded", nMaxRecursionDepth);
|
||||||
|
|
||||||
|
struct sStringExpansionPos *pNewStringExpansion =
|
||||||
|
malloc(sizeof(*pNewStringExpansion));
|
||||||
|
char *tzNewExpansionName = strdup(tzName);
|
||||||
|
|
||||||
|
if (!pNewStringExpansion || !tzNewExpansionName)
|
||||||
|
fatalerror("Could not allocate memory to expand '%s'",
|
||||||
|
tzName);
|
||||||
|
|
||||||
|
pNewStringExpansion->tzName = tzNewExpansionName;
|
||||||
|
pNewStringExpansion->pBuffer = pLexBufferRealStart;
|
||||||
|
pNewStringExpansion->pBufferPos = pLexBuffer;
|
||||||
|
pNewStringExpansion->pParent = pCurrentStringExpansion;
|
||||||
|
|
||||||
|
pCurrentStringExpansion = pNewStringExpansion;
|
||||||
}
|
}
|
||||||
|
|
||||||
void yy_switch_to_buffer(YY_BUFFER_STATE buf)
|
void yy_switch_to_buffer(YY_BUFFER_STATE buf)
|
||||||
@@ -118,13 +158,34 @@ void yy_delete_buffer(YY_BUFFER_STATE buf)
|
|||||||
* 2. The buffer is terminated with 0
|
* 2. The buffer is terminated with 0
|
||||||
* 3. nBufferSize is the size without the terminator
|
* 3. nBufferSize is the size without the terminator
|
||||||
*/
|
*/
|
||||||
static void yy_buffer_append(YY_BUFFER_STATE buf, uint32_t capacity, char c)
|
static void yy_buffer_append(YY_BUFFER_STATE buf, size_t capacity, char c)
|
||||||
{
|
{
|
||||||
assert(buf->pBuffer[buf->nBufferSize] == 0);
|
assert(buf->pBufferStart[buf->nBufferSize] == 0);
|
||||||
assert(buf->nBufferSize + 1 < capacity);
|
assert(buf->nBufferSize + 1 < capacity);
|
||||||
|
|
||||||
buf->pBuffer[buf->nBufferSize++] = c;
|
buf->pBufferStart[buf->nBufferSize++] = c;
|
||||||
buf->pBuffer[buf->nBufferSize] = 0;
|
buf->pBufferStart[buf->nBufferSize] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void yy_buffer_append_newlines(YY_BUFFER_STATE buf, size_t capacity)
|
||||||
|
{
|
||||||
|
/* Add newline if file doesn't end with one */
|
||||||
|
if (buf->nBufferSize == 0
|
||||||
|
|| buf->pBufferStart[buf->nBufferSize - 1] != '\n')
|
||||||
|
yy_buffer_append(buf, capacity, '\n');
|
||||||
|
|
||||||
|
/* Add newline if \ will eat the last newline */
|
||||||
|
if (buf->nBufferSize >= 2) {
|
||||||
|
size_t pos = buf->nBufferSize - 2;
|
||||||
|
|
||||||
|
/* Skip spaces and tabs */
|
||||||
|
while (pos > 0 && (buf->pBufferStart[pos] == ' '
|
||||||
|
|| buf->pBufferStart[pos] == '\t'))
|
||||||
|
pos--;
|
||||||
|
|
||||||
|
if (buf->pBufferStart[pos] == '\\')
|
||||||
|
yy_buffer_append(buf, capacity, '\n');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size)
|
YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size)
|
||||||
@@ -134,7 +195,9 @@ YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size)
|
|||||||
if (pBuffer == NULL)
|
if (pBuffer == NULL)
|
||||||
fatalerror("%s: Out of memory!", __func__);
|
fatalerror("%s: Out of memory!", __func__);
|
||||||
|
|
||||||
pBuffer->pBufferRealStart = malloc(size + 1 + SAFETYMARGIN);
|
size_t capacity = size + 3; /* space for 2 newlines and terminator */
|
||||||
|
|
||||||
|
pBuffer->pBufferRealStart = malloc(capacity + SAFETYMARGIN);
|
||||||
|
|
||||||
if (pBuffer->pBufferRealStart == NULL)
|
if (pBuffer->pBufferRealStart == NULL)
|
||||||
fatalerror("%s: Out of memory for buffer!", __func__);
|
fatalerror("%s: Out of memory for buffer!", __func__);
|
||||||
@@ -142,9 +205,10 @@ YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size)
|
|||||||
pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN;
|
pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN;
|
||||||
pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN;
|
pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN;
|
||||||
memcpy(pBuffer->pBuffer, mem, size);
|
memcpy(pBuffer->pBuffer, mem, size);
|
||||||
pBuffer->nBufferSize = size;
|
|
||||||
pBuffer->oAtLineStart = 1;
|
|
||||||
pBuffer->pBuffer[size] = 0;
|
pBuffer->pBuffer[size] = 0;
|
||||||
|
pBuffer->nBufferSize = size;
|
||||||
|
yy_buffer_append_newlines(pBuffer, capacity);
|
||||||
|
pBuffer->oAtLineStart = 1;
|
||||||
|
|
||||||
return pBuffer;
|
return pBuffer;
|
||||||
}
|
}
|
||||||
@@ -156,71 +220,119 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f)
|
|||||||
if (pBuffer == NULL)
|
if (pBuffer == NULL)
|
||||||
fatalerror("%s: Out of memory!", __func__);
|
fatalerror("%s: Out of memory!", __func__);
|
||||||
|
|
||||||
uint32_t size;
|
size_t size = 0, capacity = -1;
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we can get the file size without implementation-defined
|
||||||
|
* behavior:
|
||||||
|
*
|
||||||
|
* From ftell(3p):
|
||||||
|
* [On error], ftell() and ftello() shall return −1, and set errno to
|
||||||
|
* indicate the error.
|
||||||
|
*
|
||||||
|
* The ftell() and ftello() functions shall fail if: [...]
|
||||||
|
* ESPIPE The file descriptor underlying stream is associated with a
|
||||||
|
* pipe, FIFO, or socket.
|
||||||
|
*
|
||||||
|
* From fseek(3p):
|
||||||
|
* The behavior of fseek() on devices which are incapable of seeking
|
||||||
|
* is implementation-defined.
|
||||||
|
*/
|
||||||
|
if (ftell(f) != -1) {
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
size = ftell(f);
|
capacity = ftell(f);
|
||||||
fseek(f, 0, SEEK_SET);
|
rewind(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If ftell errored or the block above wasn't executed
|
||||||
|
if (capacity == -1)
|
||||||
|
capacity = 4096;
|
||||||
|
// Handle 0-byte files gracefully
|
||||||
|
else if (capacity == 0)
|
||||||
|
capacity = 1;
|
||||||
|
|
||||||
|
while (!feof(f)) {
|
||||||
|
if (buf == NULL || size >= capacity) {
|
||||||
|
if (buf)
|
||||||
|
capacity *= 2;
|
||||||
/* Give extra room for 2 newlines and terminator */
|
/* Give extra room for 2 newlines and terminator */
|
||||||
uint32_t capacity = size + 3;
|
buf = realloc(buf, capacity + SAFETYMARGIN + 3);
|
||||||
|
|
||||||
pBuffer->pBufferRealStart = malloc(capacity + SAFETYMARGIN);
|
if (buf == NULL)
|
||||||
|
fatalerror("%s: Out of memory for buffer!",
|
||||||
|
__func__);
|
||||||
|
}
|
||||||
|
|
||||||
if (pBuffer->pBufferRealStart == NULL)
|
char *bufpos = buf + SAFETYMARGIN + size;
|
||||||
fatalerror("%s: Out of memory for buffer!", __func__);
|
size_t read_count = fread(bufpos, 1, capacity - size, f);
|
||||||
|
|
||||||
pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN;
|
if (read_count == 0 && !feof(f))
|
||||||
pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN;
|
fatalerror("%s: fread error", __func__);
|
||||||
|
|
||||||
size = fread(pBuffer->pBuffer, sizeof(uint8_t), size, f);
|
size += read_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
pBuffer->pBufferRealStart = buf;
|
||||||
|
pBuffer->pBufferStart = buf + SAFETYMARGIN;
|
||||||
|
pBuffer->pBuffer = buf + SAFETYMARGIN;
|
||||||
pBuffer->pBuffer[size] = 0;
|
pBuffer->pBuffer[size] = 0;
|
||||||
pBuffer->nBufferSize = size;
|
pBuffer->nBufferSize = size;
|
||||||
|
|
||||||
|
/* This is added here to make the buffer scaling above easy to express,
|
||||||
|
* while taking the newline space into account
|
||||||
|
* for the yy_buffer_append_newlines() call below.
|
||||||
|
*/
|
||||||
|
capacity += 3;
|
||||||
|
|
||||||
|
/* Skip UTF-8 byte order mark. */
|
||||||
|
if (pBuffer->nBufferSize >= BOM_SIZE
|
||||||
|
&& !memcmp(pBuffer->pBuffer, bom, BOM_SIZE))
|
||||||
|
pBuffer->pBuffer += BOM_SIZE;
|
||||||
|
|
||||||
/* Convert all line endings to LF and spaces */
|
/* Convert all line endings to LF and spaces */
|
||||||
|
|
||||||
char *mem = pBuffer->pBuffer;
|
char *mem = pBuffer->pBuffer;
|
||||||
uint32_t instring = 0;
|
int32_t lineCount = 0;
|
||||||
|
|
||||||
while (*mem) {
|
while (*mem) {
|
||||||
if (*mem == '\"')
|
|
||||||
instring = 1 - instring;
|
|
||||||
|
|
||||||
if ((mem[0] == '\\') && (mem[1] == '\"' || mem[1] == '\\')) {
|
if ((mem[0] == '\\') && (mem[1] == '\"' || mem[1] == '\\')) {
|
||||||
mem += 2;
|
mem += 2;
|
||||||
} else if (instring) {
|
|
||||||
mem += 1;
|
|
||||||
} else {
|
} else {
|
||||||
/* LF CR and CR LF */
|
/* LF CR and CR LF */
|
||||||
if (((mem[0] == 10) && (mem[1] == 13))
|
if (((mem[0] == '\n') && (mem[1] == '\r'))
|
||||||
|| ((mem[0] == 13) && (mem[1] == 10))) {
|
|| ((mem[0] == '\r') && (mem[1] == '\n'))) {
|
||||||
mem[0] = ' ';
|
*mem++ = ' ';
|
||||||
mem[1] = '\n';
|
*mem++ = '\n';
|
||||||
mem += 2;
|
lineCount++;
|
||||||
/* LF and CR */
|
/* LF and CR */
|
||||||
} else if ((mem[0] == 10) || (mem[0] == 13)) {
|
} else if ((mem[0] == '\n') || (mem[0] == '\r')) {
|
||||||
mem[0] = '\n';
|
*mem++ = '\n';
|
||||||
mem += 1;
|
lineCount++;
|
||||||
} else {
|
} else {
|
||||||
mem += 1;
|
mem++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mem != pBuffer->pBuffer + size) {
|
||||||
|
nLineNo = lineCount + 1;
|
||||||
|
fatalerror("Found null character");
|
||||||
|
}
|
||||||
|
|
||||||
/* Remove comments */
|
/* Remove comments */
|
||||||
|
|
||||||
mem = pBuffer->pBuffer;
|
mem = pBuffer->pBuffer;
|
||||||
instring = 0;
|
bool instring = false;
|
||||||
|
|
||||||
while (*mem) {
|
while (*mem) {
|
||||||
if (*mem == '\"')
|
if (*mem == '\"')
|
||||||
instring = 1 - instring;
|
instring = !instring;
|
||||||
|
|
||||||
if ((mem[0] == '\\') && (mem[1] == '\"' || mem[1] == '\\')) {
|
if ((mem[0] == '\\') && (mem[1] == '\"' || mem[1] == '\\')) {
|
||||||
mem += 2;
|
mem += 2;
|
||||||
} else if (instring) {
|
} else if (instring) {
|
||||||
mem += 1;
|
mem++;
|
||||||
} else {
|
} else {
|
||||||
/* Comments that start with ; anywhere in a line */
|
/* Comments that start with ; anywhere in a line */
|
||||||
if (*mem == ';') {
|
if (*mem == ';') {
|
||||||
@@ -228,31 +340,16 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f)
|
|||||||
*mem++ = ' ';
|
*mem++ = ' ';
|
||||||
/* Comments that start with * at the start of a line */
|
/* Comments that start with * at the start of a line */
|
||||||
} else if ((mem[0] == '\n') && (mem[1] == '*')) {
|
} else if ((mem[0] == '\n') && (mem[1] == '*')) {
|
||||||
mem += 1;
|
mem++;
|
||||||
while (!((*mem == '\n') || (*mem == '\0')))
|
while (!((*mem == '\n') || (*mem == '\0')))
|
||||||
*mem++ = ' ';
|
*mem++ = ' ';
|
||||||
} else {
|
} else {
|
||||||
mem += 1;
|
mem++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add newline if file doesn't end with one */
|
yy_buffer_append_newlines(pBuffer, capacity);
|
||||||
if (size == 0 || pBuffer->pBuffer[size - 1] != '\n')
|
|
||||||
yy_buffer_append(pBuffer, capacity, '\n');
|
|
||||||
|
|
||||||
/* Add newline if \ will eat the last newline */
|
|
||||||
if (pBuffer->nBufferSize >= 2) {
|
|
||||||
size_t pos = pBuffer->nBufferSize - 2;
|
|
||||||
|
|
||||||
/* Skip spaces */
|
|
||||||
while (pos > 0 && pBuffer->pBuffer[pos] == ' ')
|
|
||||||
pos--;
|
|
||||||
|
|
||||||
if (pBuffer->pBuffer[pos] == '\\')
|
|
||||||
yy_buffer_append(pBuffer, capacity, '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
pBuffer->oAtLineStart = 1;
|
pBuffer->oAtLineStart = 1;
|
||||||
return pBuffer;
|
return pBuffer;
|
||||||
}
|
}
|
||||||
@@ -376,6 +473,9 @@ void lex_Init(void)
|
|||||||
|
|
||||||
nLexMaxLength = 0;
|
nLexMaxLength = 0;
|
||||||
nFloating = 0;
|
nFloating = 0;
|
||||||
|
|
||||||
|
pCurrentStringExpansion = NULL;
|
||||||
|
nNbStringExpansions = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lex_AddStrings(const struct sLexInitString *lex)
|
void lex_AddStrings(const struct sLexInitString *lex)
|
||||||
@@ -428,17 +528,17 @@ void yylex_GetFloatMaskAndFloatLen(uint32_t *pnFloatMask, uint32_t *pnFloatLen)
|
|||||||
|
|
||||||
char *s = pLexBuffer;
|
char *s = pLexBuffer;
|
||||||
uint32_t nOldFloatMask = 0;
|
uint32_t nOldFloatMask = 0;
|
||||||
uint32_t nFloatMask = tFloatingFirstChar[(int32_t)*s];
|
uint32_t nFloatMask = tFloatingFirstChar[(uint8_t)*s];
|
||||||
|
|
||||||
if (nFloatMask != 0) {
|
if (nFloatMask != 0) {
|
||||||
s++;
|
s++;
|
||||||
nOldFloatMask = nFloatMask;
|
nOldFloatMask = nFloatMask;
|
||||||
nFloatMask &= tFloatingSecondChar[(int32_t)*s];
|
nFloatMask &= tFloatingSecondChar[(uint8_t)*s];
|
||||||
|
|
||||||
while (nFloatMask != 0) {
|
while (nFloatMask != 0) {
|
||||||
s++;
|
s++;
|
||||||
nOldFloatMask = nFloatMask;
|
nOldFloatMask = nFloatMask;
|
||||||
nFloatMask &= tFloatingChars[(int32_t)*s];
|
nFloatMask &= tFloatingChars[(uint8_t)*s];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,6 +652,7 @@ size_t yylex_ReadBracketedSymbol(char *dest, size_t index)
|
|||||||
char ch;
|
char ch;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
size_t length, maxLength;
|
size_t length, maxLength;
|
||||||
|
const char *mode = NULL;
|
||||||
|
|
||||||
for (ch = *pLexBuffer;
|
for (ch = *pLexBuffer;
|
||||||
ch != '}' && ch != '"' && ch != '\n';
|
ch != '}' && ch != '"' && ch != '\n';
|
||||||
@@ -565,16 +666,42 @@ size_t yylex_ReadBracketedSymbol(char *dest, size_t index)
|
|||||||
i += length;
|
i += length;
|
||||||
else
|
else
|
||||||
fatalerror("Illegal character escape '%c'", ch);
|
fatalerror("Illegal character escape '%c'", ch);
|
||||||
|
} else if (ch == ':' && !mode) { /* Only grab 1st colon */
|
||||||
|
/* Use a whitelist of modes, which does prevent the
|
||||||
|
* use of some features such as precision,
|
||||||
|
* but also avoids a security flaw
|
||||||
|
*/
|
||||||
|
const char *acceptedModes = "bxXd";
|
||||||
|
/* Binary isn't natively supported,
|
||||||
|
* so it's handled differently
|
||||||
|
*/
|
||||||
|
static const char * const formatSpecifiers[] = {
|
||||||
|
"", "%x", "%X", "%d"
|
||||||
|
};
|
||||||
|
/* Prevent reading out of bounds! */
|
||||||
|
const char *designatedMode;
|
||||||
|
|
||||||
|
if (i != 1)
|
||||||
|
fatalerror("Print types are exactly 1 character long");
|
||||||
|
|
||||||
|
designatedMode = strchr(acceptedModes, sym[i - 1]);
|
||||||
|
if (!designatedMode)
|
||||||
|
fatalerror("Illegal print type '%c'",
|
||||||
|
sym[i - 1]);
|
||||||
|
mode = formatSpecifiers[designatedMode - acceptedModes];
|
||||||
|
/* Begin writing the symbol again */
|
||||||
|
i = 0;
|
||||||
} else {
|
} else {
|
||||||
yylex_SymbolWriteChar(sym, i++, ch);
|
yylex_SymbolWriteChar(sym, i++, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Properly terminate the string */
|
||||||
yylex_SymbolWriteChar(sym, i, 0);
|
yylex_SymbolWriteChar(sym, i, 0);
|
||||||
|
|
||||||
/* It's assumed we're writing to a T_STRING */
|
/* It's assumed we're writing to a T_STRING */
|
||||||
maxLength = MAXSTRLEN - index;
|
maxLength = MAXSTRLEN - index;
|
||||||
length = symvaluetostring(&dest[index], maxLength, sym);
|
length = symvaluetostring(&dest[index], maxLength, sym, mode);
|
||||||
|
|
||||||
if (*pLexBuffer == '}')
|
if (*pLexBuffer == '}')
|
||||||
pLexBuffer++;
|
pLexBuffer++;
|
||||||
@@ -681,10 +808,10 @@ scanagain:
|
|||||||
* endings: "\r\n" is replaced by " \n" before the lexer has the
|
* endings: "\r\n" is replaced by " \n" before the lexer has the
|
||||||
* opportunity to see it.
|
* opportunity to see it.
|
||||||
*/
|
*/
|
||||||
if (pLexBuffer[1] == ' ') {
|
if (pLexBuffer[1] == ' ' || pLexBuffer[1] == '\t') {
|
||||||
pLexBuffer += 2;
|
pLexBuffer += 2;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (*pLexBuffer == ' ') {
|
if (*pLexBuffer == ' ' || *pLexBuffer == '\t') {
|
||||||
pLexBuffer++;
|
pLexBuffer++;
|
||||||
} else if (*pLexBuffer == '\n') {
|
} else if (*pLexBuffer == '\n') {
|
||||||
pLexBuffer++;
|
pLexBuffer++;
|
||||||
@@ -731,7 +858,9 @@ scanagain:
|
|||||||
return T_STRING;
|
return T_STRING;
|
||||||
} else if (*pLexBuffer == '{') {
|
} else if (*pLexBuffer == '{') {
|
||||||
pLexBuffer++;
|
pLexBuffer++;
|
||||||
yylex_ReadBracketedSymbol(yylval.tzString, 0);
|
size_t len = yylex_ReadBracketedSymbol(yylval.tzString,
|
||||||
|
0);
|
||||||
|
yylval.tzString[len] = 0;
|
||||||
return T_STRING;
|
return T_STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -740,10 +869,22 @@ scanagain:
|
|||||||
* numeric literal, string, or bracketed symbol, so just return
|
* numeric literal, string, or bracketed symbol, so just return
|
||||||
* the ASCII character.
|
* the ASCII character.
|
||||||
*/
|
*/
|
||||||
if (*pLexBuffer == '\n')
|
unsigned char ch = *pLexBuffer++;
|
||||||
|
|
||||||
|
if (ch == '\n')
|
||||||
AtLineStart = 1;
|
AtLineStart = 1;
|
||||||
|
|
||||||
return *pLexBuffer++;
|
/*
|
||||||
|
* Check for invalid unprintable characters.
|
||||||
|
* They may not be readily apparent in a text editor,
|
||||||
|
* so this is useful for identifying encoding problems.
|
||||||
|
*/
|
||||||
|
if (ch != 0
|
||||||
|
&& ch != '\n'
|
||||||
|
&& !(ch >= 0x20 && ch <= 0x7E))
|
||||||
|
fatalerror("Found garbage character: 0x%02X", ch);
|
||||||
|
|
||||||
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pLongestFixed == NULL || nFloatLen > pLongestFixed->nNameLength) {
|
if (pLongestFixed == NULL || nFloatLen > pLongestFixed->nNameLength) {
|
||||||
@@ -760,8 +901,6 @@ scanagain:
|
|||||||
goto scanagain;
|
goto scanagain;
|
||||||
}
|
}
|
||||||
|
|
||||||
pLexBuffer += nFloatLen;
|
|
||||||
|
|
||||||
if (token->nToken == T_ID && linestart)
|
if (token->nToken == T_ID && linestart)
|
||||||
return T_LABEL;
|
return T_LABEL;
|
||||||
else
|
else
|
||||||
@@ -811,6 +950,7 @@ static uint32_t yylex_MACROARGS(void)
|
|||||||
ch = '}';
|
ch = '}';
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
|
case '\t':
|
||||||
/*
|
/*
|
||||||
* Look for line continuation character after a
|
* Look for line continuation character after a
|
||||||
* series of spaces. This is also useful for
|
* series of spaces. This is also useful for
|
||||||
@@ -819,7 +959,8 @@ static uint32_t yylex_MACROARGS(void)
|
|||||||
* opportunity to see it.
|
* opportunity to see it.
|
||||||
*/
|
*/
|
||||||
while (1) {
|
while (1) {
|
||||||
if (*pLexBuffer == ' ') {
|
if (*pLexBuffer == ' '
|
||||||
|
|| *pLexBuffer == '\t') {
|
||||||
pLexBuffer++;
|
pLexBuffer++;
|
||||||
} else if (*pLexBuffer == '\n') {
|
} else if (*pLexBuffer == '\n') {
|
||||||
pLexBuffer++;
|
pLexBuffer++;
|
||||||
@@ -879,14 +1020,32 @@ static uint32_t yylex_MACROARGS(void)
|
|||||||
fatalerror("Internal error in %s", __func__);
|
fatalerror("Internal error in %s", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t yylex(void)
|
int yylex(void)
|
||||||
{
|
{
|
||||||
|
int returnedChar;
|
||||||
switch (lexerstate) {
|
switch (lexerstate) {
|
||||||
case LEX_STATE_NORMAL:
|
case LEX_STATE_NORMAL:
|
||||||
return yylex_NORMAL();
|
returnedChar = yylex_NORMAL();
|
||||||
|
break;
|
||||||
case LEX_STATE_MACROARGS:
|
case LEX_STATE_MACROARGS:
|
||||||
return yylex_MACROARGS();
|
returnedChar = yylex_MACROARGS();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fatalerror("%s: Internal error.", __func__);
|
fatalerror("%s: Internal error.", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if string expansions were fully read */
|
||||||
|
while (pCurrentStringExpansion
|
||||||
|
&& pCurrentStringExpansion->pBuffer == pLexBufferRealStart
|
||||||
|
&& pCurrentStringExpansion->pBufferPos <= pLexBuffer) {
|
||||||
|
struct sStringExpansionPos *pParent =
|
||||||
|
pCurrentStringExpansion->pParent;
|
||||||
|
free(pCurrentStringExpansion->tzName);
|
||||||
|
free(pCurrentStringExpansion);
|
||||||
|
|
||||||
|
pCurrentStringExpansion = pParent;
|
||||||
|
nNbStringExpansions--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnedChar;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "asm/lexer.h"
|
#include "asm/lexer.h"
|
||||||
#include "asm/output.h"
|
#include "asm/output.h"
|
||||||
#include "asm/main.h"
|
#include "asm/main.h"
|
||||||
|
#include "asm/charmap.h"
|
||||||
|
|
||||||
#include "extern/err.h"
|
#include "extern/err.h"
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ char **cldefines;
|
|||||||
|
|
||||||
clock_t nStartClock, nEndClock;
|
clock_t nStartClock, nEndClock;
|
||||||
int32_t nLineNo;
|
int32_t nLineNo;
|
||||||
uint32_t nTotalLines, nPass, nPC, nIFDepth, nUnionDepth, nErrors;
|
uint32_t nTotalLines, nPC, nIFDepth, nUnionDepth, nErrors;
|
||||||
bool skipElif;
|
bool skipElif;
|
||||||
uint32_t unionStart[128], unionSize[128];
|
uint32_t unionStart[128], unionSize[128];
|
||||||
|
|
||||||
@@ -238,12 +239,13 @@ static void opt_ParseDefines(void)
|
|||||||
*/
|
*/
|
||||||
void verror(const char *fmt, va_list args)
|
void verror(const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR: ");
|
fputs("ERROR: ", stderr);
|
||||||
fstk_Dump();
|
fstk_Dump();
|
||||||
fprintf(stderr, ":\n ");
|
fputs(":\n ", stderr);
|
||||||
vfprintf(stderr, fmt, args);
|
vfprintf(stderr, fmt, args);
|
||||||
fprintf(stderr, "\n");
|
fputc('\n', stderr);
|
||||||
nErrors += 1;
|
fstk_DumpStringExpansions();
|
||||||
|
nErrors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void yyerror(const char *fmt, ...)
|
void yyerror(const char *fmt, ...)
|
||||||
@@ -275,11 +277,12 @@ void warning(const char *fmt, ...)
|
|||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
|
||||||
fprintf(stderr, "warning: ");
|
fputs("warning: ", stderr);
|
||||||
fstk_Dump();
|
fstk_Dump();
|
||||||
fprintf(stderr, ":\n ");
|
fputs(":\n ", stderr);
|
||||||
vfprintf(stderr, fmt, args);
|
vfprintf(stderr, fmt, args);
|
||||||
fprintf(stderr, "\n");
|
fputc('\n', stderr);
|
||||||
|
fstk_DumpStringExpansions();
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
@@ -288,7 +291,8 @@ static void print_usage(void)
|
|||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
"usage: rgbasm [-EhLVvw] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
|
"usage: rgbasm [-EhLVvw] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
|
||||||
" [-M dependfile] [-o outfile] [-p pad_value] file.asm\n");
|
" [-M dependfile] [-o outfile] [-p pad_value]\n"
|
||||||
|
" [-r recursion_depth] file.asm\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,6 +319,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* yydebug=1; */
|
/* yydebug=1; */
|
||||||
|
|
||||||
|
nMaxRecursionDepth = 64;
|
||||||
|
|
||||||
DefaultOptions.gbgfx[0] = '0';
|
DefaultOptions.gbgfx[0] = '0';
|
||||||
DefaultOptions.gbgfx[1] = '1';
|
DefaultOptions.gbgfx[1] = '1';
|
||||||
DefaultOptions.gbgfx[2] = '2';
|
DefaultOptions.gbgfx[2] = '2';
|
||||||
@@ -332,7 +338,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
newopt = CurrentOptions;
|
newopt = CurrentOptions;
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "b:D:Eg:hi:LM:o:p:Vvw")) != -1) {
|
while ((ch = getopt(argc, argv, "b:D:Eg:hi:LM:o:p:r:Vvw")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'b':
|
case 'b':
|
||||||
if (strlen(optarg) == 2) {
|
if (strlen(optarg) == 2) {
|
||||||
@@ -386,6 +392,12 @@ int main(int argc, char *argv[])
|
|||||||
errx(1, "Argument for option 'p' must be between 0 and 0xFF");
|
errx(1, "Argument for option 'p' must be between 0 and 0xFF");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
nMaxRecursionDepth = strtoul(optarg, &ep, 0);
|
||||||
|
|
||||||
|
if (optarg[0] == '\0' || *ep != '\0')
|
||||||
|
errx(1, "Invalid argument for option 'r'");
|
||||||
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
printf("rgbasm %s\n", get_package_version_string());
|
printf("rgbasm %s\n", get_package_version_string());
|
||||||
exit(0);
|
exit(0);
|
||||||
@@ -432,21 +444,18 @@ int main(int argc, char *argv[])
|
|||||||
skipElif = true;
|
skipElif = true;
|
||||||
nUnionDepth = 0;
|
nUnionDepth = 0;
|
||||||
nPC = 0;
|
nPC = 0;
|
||||||
nPass = 1;
|
|
||||||
nErrors = 0;
|
nErrors = 0;
|
||||||
sym_PrepPass1();
|
sym_Init();
|
||||||
sym_SetExportAll(CurrentOptions.exportall);
|
sym_SetExportAll(CurrentOptions.exportall);
|
||||||
fstk_Init(tzMainfile);
|
fstk_Init(tzMainfile);
|
||||||
opt_ParseDefines();
|
opt_ParseDefines();
|
||||||
|
charmap_InitMain();
|
||||||
if (CurrentOptions.verbose)
|
|
||||||
printf("Pass 1...\n");
|
|
||||||
|
|
||||||
yy_set_state(LEX_STATE_NORMAL);
|
yy_set_state(LEX_STATE_NORMAL);
|
||||||
opt_SetCurrentOptions(&DefaultOptions);
|
opt_SetCurrentOptions(&DefaultOptions);
|
||||||
|
|
||||||
if (yyparse() != 0 || nErrors != 0)
|
if (yyparse() != 0 || nErrors != 0)
|
||||||
errx(1, "Assembly aborted in pass 1 (%ld errors)!", nErrors);
|
errx(1, "Assembly aborted (%ld errors)!", nErrors);
|
||||||
|
|
||||||
if (nIFDepth != 0)
|
if (nIFDepth != 0)
|
||||||
errx(1, "Unterminated IF construct (%ld levels)!", nIFDepth);
|
errx(1, "Unterminated IF construct (%ld levels)!", nIFDepth);
|
||||||
@@ -456,27 +465,6 @@ int main(int argc, char *argv[])
|
|||||||
nUnionDepth);
|
nUnionDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
nTotalLines = 0;
|
|
||||||
nLineNo = 1;
|
|
||||||
nIFDepth = 0;
|
|
||||||
skipElif = true;
|
|
||||||
nUnionDepth = 0;
|
|
||||||
nPC = 0;
|
|
||||||
nPass = 2;
|
|
||||||
nErrors = 0;
|
|
||||||
sym_PrepPass2();
|
|
||||||
out_PrepPass2();
|
|
||||||
fstk_Init(tzMainfile);
|
|
||||||
yy_set_state(LEX_STATE_NORMAL);
|
|
||||||
opt_SetCurrentOptions(&DefaultOptions);
|
|
||||||
opt_ParseDefines();
|
|
||||||
|
|
||||||
if (CurrentOptions.verbose)
|
|
||||||
printf("Pass 2...\n");
|
|
||||||
|
|
||||||
if (yyparse() != 0 || nErrors != 0)
|
|
||||||
errx(1, "Assembly aborted in pass 2 (%ld errors)!", nErrors);
|
|
||||||
|
|
||||||
double timespent;
|
double timespent;
|
||||||
|
|
||||||
nEndClock = clock();
|
nEndClock = clock();
|
||||||
@@ -491,6 +479,10 @@ int main(int argc, char *argv[])
|
|||||||
printf("(%d lines/minute)\n",
|
printf("(%d lines/minute)\n",
|
||||||
(int)(60 / timespent * nTotalLines));
|
(int)(60 / timespent * nTotalLines));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_CheckErrors();
|
||||||
|
/* If no path specified, don't write file */
|
||||||
|
if (tzObjectname != NULL)
|
||||||
out_WriteObject();
|
out_WriteObject();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
168
src/asm/output.c
168
src/asm/output.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
* Outputs an objectfile
|
* Outputs an objectfile
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -259,37 +260,37 @@ static void writesection(struct Section *pSect, FILE *f)
|
|||||||
*/
|
*/
|
||||||
static void writesymbol(struct sSymbol *pSym, FILE *f)
|
static void writesymbol(struct sSymbol *pSym, FILE *f)
|
||||||
{
|
{
|
||||||
char symname[MAXSYMLEN * 2 + 1];
|
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
int32_t sectid;
|
int32_t sectid;
|
||||||
|
|
||||||
if (pSym->nType & SYMF_IMPORT) {
|
if (!(pSym->nType & SYMF_DEFINED)) {
|
||||||
/* Symbol should be imported */
|
type = SYM_IMPORT;
|
||||||
strcpy(symname, pSym->tzName);
|
} else if (pSym->nType & SYMF_EXPORT) {
|
||||||
|
type = SYM_EXPORT;
|
||||||
|
} else {
|
||||||
|
type = SYM_LOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case SYM_LOCAL:
|
||||||
|
offset = pSym->nValue;
|
||||||
|
sectid = getsectid(pSym->pSection);
|
||||||
|
break;
|
||||||
|
case SYM_IMPORT:
|
||||||
offset = 0;
|
offset = 0;
|
||||||
sectid = -1;
|
sectid = -1;
|
||||||
type = SYM_IMPORT;
|
break;
|
||||||
} else {
|
case SYM_EXPORT:
|
||||||
strcpy(symname, pSym->tzName);
|
|
||||||
|
|
||||||
if (pSym->nType & SYMF_EXPORT) {
|
|
||||||
/* Symbol should be exported */
|
|
||||||
type = SYM_EXPORT;
|
|
||||||
offset = pSym->nValue;
|
offset = pSym->nValue;
|
||||||
if (pSym->nType & SYMF_CONST)
|
if (pSym->nType & SYMF_CONST)
|
||||||
sectid = -1;
|
sectid = -1;
|
||||||
else
|
else
|
||||||
sectid = getsectid(pSym->pSection);
|
sectid = getsectid(pSym->pSection);
|
||||||
} else {
|
break;
|
||||||
/* Symbol is local to this file */
|
|
||||||
type = SYM_LOCAL;
|
|
||||||
offset = pSym->nValue;
|
|
||||||
sectid = getsectid(pSym->pSection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fputstring(symname, f);
|
fputstring(pSym->tzName, f);
|
||||||
fputc(type, f);
|
fputc(type, f);
|
||||||
|
|
||||||
if (type != SYM_IMPORT) {
|
if (type != SYM_IMPORT) {
|
||||||
@@ -311,7 +312,7 @@ static uint32_t addsymbol(struct sSymbol *pSym)
|
|||||||
struct PatchSymbol *pPSym, **ppPSym;
|
struct PatchSymbol *pPSym, **ppPSym;
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
|
|
||||||
hash = calchash(pSym->tzName);
|
hash = sym_CalcHash(pSym->tzName);
|
||||||
ppPSym = &(tHashedPatchSymbols[hash]);
|
ppPSym = &(tHashedPatchSymbols[hash]);
|
||||||
|
|
||||||
while ((*ppPSym) != NULL) {
|
while ((*ppPSym) != NULL) {
|
||||||
@@ -383,10 +384,15 @@ void createpatch(uint32_t type, struct Expression *expr)
|
|||||||
{
|
{
|
||||||
struct Patch *pPatch;
|
struct Patch *pPatch;
|
||||||
uint16_t rpndata;
|
uint16_t rpndata;
|
||||||
uint8_t rpnexpr[2048];
|
uint8_t *rpnexpr;
|
||||||
char tzSym[512];
|
char tzSym[512];
|
||||||
uint32_t rpnptr = 0, symptr;
|
uint32_t rpnptr = 0, symptr;
|
||||||
|
|
||||||
|
rpnexpr = malloc(expr->nRPNPatchSize);
|
||||||
|
|
||||||
|
if (rpnexpr == NULL)
|
||||||
|
fatalerror("No memory for patch RPN expression");
|
||||||
|
|
||||||
pPatch = allocpatch();
|
pPatch = allocpatch();
|
||||||
pPatch->nType = type;
|
pPatch->nType = type;
|
||||||
strcpy(pPatch->tzFilename, tzCurrentFileName);
|
strcpy(pPatch->tzFilename, tzCurrentFileName);
|
||||||
@@ -468,12 +474,11 @@ void createpatch(uint32_t type, struct Expression *expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pPatch->pRPN = malloc(rpnptr);
|
assert(rpnptr == expr->nRPNPatchSize);
|
||||||
if (pPatch->pRPN != NULL) {
|
|
||||||
memcpy(pPatch->pRPN, rpnexpr, rpnptr);
|
pPatch->pRPN = rpnexpr;
|
||||||
pPatch->nRPNSize = rpnptr;
|
pPatch->nRPNSize = rpnptr;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A quick check to see if we have an initialized section
|
* A quick check to see if we have an initialized section
|
||||||
@@ -507,8 +512,9 @@ static void checksectionoverflow(uint32_t delta_size)
|
|||||||
{
|
{
|
||||||
uint32_t maxsize = getmaxsectionsize(pCurrentSection->nType,
|
uint32_t maxsize = getmaxsectionsize(pCurrentSection->nType,
|
||||||
pCurrentSection->pzName);
|
pCurrentSection->pzName);
|
||||||
|
uint32_t new_size = pCurrentSection->nPC + delta_size;
|
||||||
|
|
||||||
if (pCurrentSection->nPC + delta_size > maxsize) {
|
if (new_size > maxsize) {
|
||||||
/*
|
/*
|
||||||
* This check is here to trap broken code that generates
|
* This check is here to trap broken code that generates
|
||||||
* sections that are too big and to prevent the assembler from
|
* sections that are too big and to prevent the assembler from
|
||||||
@@ -516,8 +522,36 @@ static void checksectionoverflow(uint32_t delta_size)
|
|||||||
* memory.
|
* memory.
|
||||||
* The real check must be done at the linking stage.
|
* The real check must be done at the linking stage.
|
||||||
*/
|
*/
|
||||||
fatalerror("Section '%s' is too big (max size = 0x%X bytes).",
|
fatalerror("Section '%s' is too big (max size = 0x%X bytes, reached 0x%X).",
|
||||||
pCurrentSection->pzName, maxsize);
|
pCurrentSection->pzName, maxsize, new_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for errors that could happen while writing an object file
|
||||||
|
* This is important as out_WriteObject is skipped entirely when `-o` is omitted
|
||||||
|
* Therefore, errors such as memory allocations still should be handled in
|
||||||
|
* out_WriteObject and not here
|
||||||
|
*/
|
||||||
|
void out_CheckErrors(void)
|
||||||
|
{
|
||||||
|
/* Local symbols cannot be imported from elsewhere */
|
||||||
|
struct PatchSymbol *pSym = pPatchSymbols;
|
||||||
|
|
||||||
|
while (pSym) {
|
||||||
|
struct sSymbol *pSymbol = pSym->pSymbol;
|
||||||
|
|
||||||
|
if (!(pSymbol->nType & SYMF_DEFINED)
|
||||||
|
&& pSymbol->nType & SYMF_LOCAL) {
|
||||||
|
char *name = pSymbol->tzName;
|
||||||
|
char *localPtr = strchr(name, '.');
|
||||||
|
|
||||||
|
if (localPtr)
|
||||||
|
name = localPtr;
|
||||||
|
errx(1, "%s(%u) : '%s' not defined",
|
||||||
|
pSymbol->tzFileName, pSymbol->nFileLine, name);
|
||||||
|
}
|
||||||
|
pSym = pSym->pNext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,20 +561,15 @@ static void checksectionoverflow(uint32_t delta_size)
|
|||||||
void out_WriteObject(void)
|
void out_WriteObject(void)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
struct PatchSymbol *pSym;
|
||||||
|
struct Section *pSect;
|
||||||
|
|
||||||
addexports();
|
addexports();
|
||||||
|
|
||||||
/* If no path specified, don't write file */
|
|
||||||
if (tzObjectname == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
f = fopen(tzObjectname, "wb");
|
f = fopen(tzObjectname, "wb");
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
fatalerror("Couldn't write file '%s'\n", tzObjectname);
|
fatalerror("Couldn't write file '%s'\n", tzObjectname);
|
||||||
|
|
||||||
struct PatchSymbol *pSym;
|
|
||||||
struct Section *pSect;
|
|
||||||
|
|
||||||
fwrite(RGBDS_OBJECT_VERSION_STRING, 1,
|
fwrite(RGBDS_OBJECT_VERSION_STRING, 1,
|
||||||
strlen(RGBDS_OBJECT_VERSION_STRING), f);
|
strlen(RGBDS_OBJECT_VERSION_STRING), f);
|
||||||
|
|
||||||
@@ -562,22 +591,6 @@ void out_WriteObject(void)
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Prepare for pass #2
|
|
||||||
*/
|
|
||||||
void out_PrepPass2(void)
|
|
||||||
{
|
|
||||||
struct Section *pSect;
|
|
||||||
|
|
||||||
pSect = pSectionList;
|
|
||||||
while (pSect) {
|
|
||||||
pSect->nPC = 0;
|
|
||||||
pSect = pSect->pNext;
|
|
||||||
}
|
|
||||||
pCurrentSection = NULL;
|
|
||||||
pSectionStack = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the objectfilename
|
* Set the objectfilename
|
||||||
*/
|
*/
|
||||||
@@ -586,10 +599,6 @@ void out_SetFileName(char *s)
|
|||||||
tzObjectname = s;
|
tzObjectname = s;
|
||||||
if (CurrentOptions.verbose)
|
if (CurrentOptions.verbose)
|
||||||
printf("Output filename %s\n", s);
|
printf("Output filename %s\n", s);
|
||||||
|
|
||||||
pSectionList = NULL;
|
|
||||||
pCurrentSection = NULL;
|
|
||||||
pPatchSymbols = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -636,7 +645,6 @@ struct Section *out_FindSection(char *pzName, uint32_t secttype, int32_t org,
|
|||||||
pSect->pNext = NULL;
|
pSect->pNext = NULL;
|
||||||
pSect->pPatches = NULL;
|
pSect->pPatches = NULL;
|
||||||
pSect->charmap = NULL;
|
pSect->charmap = NULL;
|
||||||
pPatchSymbols = NULL;
|
|
||||||
|
|
||||||
/* It is only needed to allocate memory for ROM sections. */
|
/* It is only needed to allocate memory for ROM sections. */
|
||||||
if (secttype == SECT_ROM0 || secttype == SECT_ROMX) {
|
if (secttype == SECT_ROM0 || secttype == SECT_ROMX) {
|
||||||
@@ -662,7 +670,7 @@ void out_SetCurrentSection(struct Section *pSect)
|
|||||||
fatalerror("Cannot change the section within a UNION");
|
fatalerror("Cannot change the section within a UNION");
|
||||||
|
|
||||||
pCurrentSection = pSect;
|
pCurrentSection = pSect;
|
||||||
nPC = pSect->nPC;
|
nPC = (pSect != NULL) ? pSect->nPC : 0;
|
||||||
|
|
||||||
pPCSymbol->nValue = nPC;
|
pPCSymbol->nValue = nPC;
|
||||||
pPCSymbol->pSection = pCurrentSection;
|
pPCSymbol->pSection = pCurrentSection;
|
||||||
@@ -705,9 +713,7 @@ void out_AbsByteBypassCheck(int32_t b)
|
|||||||
{
|
{
|
||||||
checksectionoverflow(1);
|
checksectionoverflow(1);
|
||||||
b &= 0xFF;
|
b &= 0xFF;
|
||||||
if (nPass == 2)
|
|
||||||
pCurrentSection->tData[nPC] = b;
|
pCurrentSection->tData[nPC] = b;
|
||||||
|
|
||||||
pCurrentSection->nPC += 1;
|
pCurrentSection->nPC += 1;
|
||||||
nPC += 1;
|
nPC += 1;
|
||||||
pPCSymbol->nValue += 1;
|
pPCSymbol->nValue += 1;
|
||||||
@@ -772,17 +778,15 @@ void out_RelByte(struct Expression *expr)
|
|||||||
checkcodesection();
|
checkcodesection();
|
||||||
checksectionoverflow(1);
|
checksectionoverflow(1);
|
||||||
if (rpn_isReloc(expr)) {
|
if (rpn_isReloc(expr)) {
|
||||||
if (nPass == 2) {
|
|
||||||
pCurrentSection->tData[nPC] = 0;
|
pCurrentSection->tData[nPC] = 0;
|
||||||
createpatch(PATCH_BYTE, expr);
|
createpatch(PATCH_BYTE, expr);
|
||||||
}
|
|
||||||
pCurrentSection->nPC += 1;
|
pCurrentSection->nPC += 1;
|
||||||
nPC += 1;
|
nPC += 1;
|
||||||
pPCSymbol->nValue += 1;
|
pPCSymbol->nValue += 1;
|
||||||
} else {
|
} else {
|
||||||
out_AbsByte(expr->nVal);
|
out_AbsByte(expr->nVal);
|
||||||
}
|
}
|
||||||
rpn_Reset(expr);
|
rpn_Free(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -793,10 +797,8 @@ void out_AbsWord(int32_t b)
|
|||||||
checkcodesection();
|
checkcodesection();
|
||||||
checksectionoverflow(2);
|
checksectionoverflow(2);
|
||||||
b &= 0xFFFF;
|
b &= 0xFFFF;
|
||||||
if (nPass == 2) {
|
|
||||||
pCurrentSection->tData[nPC] = b & 0xFF;
|
pCurrentSection->tData[nPC] = b & 0xFF;
|
||||||
pCurrentSection->tData[nPC + 1] = b >> 8;
|
pCurrentSection->tData[nPC + 1] = b >> 8;
|
||||||
}
|
|
||||||
pCurrentSection->nPC += 2;
|
pCurrentSection->nPC += 2;
|
||||||
nPC += 2;
|
nPC += 2;
|
||||||
pPCSymbol->nValue += 2;
|
pPCSymbol->nValue += 2;
|
||||||
@@ -808,24 +810,19 @@ void out_AbsWord(int32_t b)
|
|||||||
*/
|
*/
|
||||||
void out_RelWord(struct Expression *expr)
|
void out_RelWord(struct Expression *expr)
|
||||||
{
|
{
|
||||||
uint32_t b;
|
|
||||||
|
|
||||||
checkcodesection();
|
checkcodesection();
|
||||||
checksectionoverflow(2);
|
checksectionoverflow(2);
|
||||||
b = expr->nVal & 0xFFFF;
|
|
||||||
if (rpn_isReloc(expr)) {
|
if (rpn_isReloc(expr)) {
|
||||||
if (nPass == 2) {
|
pCurrentSection->tData[nPC] = 0;
|
||||||
pCurrentSection->tData[nPC] = b & 0xFF;
|
pCurrentSection->tData[nPC + 1] = 0;
|
||||||
pCurrentSection->tData[nPC + 1] = b >> 8;
|
|
||||||
createpatch(PATCH_WORD_L, expr);
|
createpatch(PATCH_WORD_L, expr);
|
||||||
}
|
|
||||||
pCurrentSection->nPC += 2;
|
pCurrentSection->nPC += 2;
|
||||||
nPC += 2;
|
nPC += 2;
|
||||||
pPCSymbol->nValue += 2;
|
pPCSymbol->nValue += 2;
|
||||||
} else {
|
} else {
|
||||||
out_AbsWord(expr->nVal);
|
out_AbsWord(expr->nVal);
|
||||||
}
|
}
|
||||||
rpn_Reset(expr);
|
rpn_Free(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -835,12 +832,10 @@ void out_AbsLong(int32_t b)
|
|||||||
{
|
{
|
||||||
checkcodesection();
|
checkcodesection();
|
||||||
checksectionoverflow(sizeof(int32_t));
|
checksectionoverflow(sizeof(int32_t));
|
||||||
if (nPass == 2) {
|
|
||||||
pCurrentSection->tData[nPC] = b & 0xFF;
|
pCurrentSection->tData[nPC] = b & 0xFF;
|
||||||
pCurrentSection->tData[nPC + 1] = b >> 8;
|
pCurrentSection->tData[nPC + 1] = b >> 8;
|
||||||
pCurrentSection->tData[nPC + 2] = b >> 16;
|
pCurrentSection->tData[nPC + 2] = b >> 16;
|
||||||
pCurrentSection->tData[nPC + 3] = b >> 24;
|
pCurrentSection->tData[nPC + 3] = b >> 24;
|
||||||
}
|
|
||||||
pCurrentSection->nPC += 4;
|
pCurrentSection->nPC += 4;
|
||||||
nPC += 4;
|
nPC += 4;
|
||||||
pPCSymbol->nValue += 4;
|
pPCSymbol->nValue += 4;
|
||||||
@@ -852,26 +847,21 @@ void out_AbsLong(int32_t b)
|
|||||||
*/
|
*/
|
||||||
void out_RelLong(struct Expression *expr)
|
void out_RelLong(struct Expression *expr)
|
||||||
{
|
{
|
||||||
int32_t b;
|
|
||||||
|
|
||||||
checkcodesection();
|
checkcodesection();
|
||||||
checksectionoverflow(4);
|
checksectionoverflow(4);
|
||||||
b = expr->nVal;
|
|
||||||
if (rpn_isReloc(expr)) {
|
if (rpn_isReloc(expr)) {
|
||||||
if (nPass == 2) {
|
pCurrentSection->tData[nPC] = 0;
|
||||||
pCurrentSection->tData[nPC] = b & 0xFF;
|
pCurrentSection->tData[nPC + 1] = 0;
|
||||||
pCurrentSection->tData[nPC + 1] = b >> 8;
|
pCurrentSection->tData[nPC + 2] = 0;
|
||||||
pCurrentSection->tData[nPC + 2] = b >> 16;
|
pCurrentSection->tData[nPC + 3] = 0;
|
||||||
pCurrentSection->tData[nPC + 3] = b >> 24;
|
|
||||||
createpatch(PATCH_LONG_L, expr);
|
createpatch(PATCH_LONG_L, expr);
|
||||||
}
|
|
||||||
pCurrentSection->nPC += 4;
|
pCurrentSection->nPC += 4;
|
||||||
nPC += 4;
|
nPC += 4;
|
||||||
pPCSymbol->nValue += 4;
|
pPCSymbol->nValue += 4;
|
||||||
} else {
|
} else {
|
||||||
out_AbsLong(expr->nVal);
|
out_AbsLong(expr->nVal);
|
||||||
}
|
}
|
||||||
rpn_Reset(expr);
|
rpn_Free(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -884,15 +874,13 @@ void out_PCRelByte(struct Expression *expr)
|
|||||||
checksectionoverflow(1);
|
checksectionoverflow(1);
|
||||||
|
|
||||||
/* Always let the linker calculate the offset. */
|
/* Always let the linker calculate the offset. */
|
||||||
if (nPass == 2) {
|
|
||||||
pCurrentSection->tData[nPC] = 0;
|
pCurrentSection->tData[nPC] = 0;
|
||||||
createpatch(PATCH_BYTE_JR, expr);
|
createpatch(PATCH_BYTE_JR, expr);
|
||||||
}
|
|
||||||
pCurrentSection->nPC += 1;
|
pCurrentSection->nPC += 1;
|
||||||
nPC += 1;
|
nPC += 1;
|
||||||
pPCSymbol->nValue += 1;
|
pPCSymbol->nValue += 1;
|
||||||
|
|
||||||
rpn_Reset(expr);
|
rpn_Free(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -915,13 +903,12 @@ void out_BinaryFile(char *s)
|
|||||||
checkcodesection();
|
checkcodesection();
|
||||||
checksectionoverflow(fsize);
|
checksectionoverflow(fsize);
|
||||||
|
|
||||||
if (nPass == 2) {
|
|
||||||
int32_t dest = nPC;
|
int32_t dest = nPC;
|
||||||
int32_t todo = fsize;
|
int32_t todo = fsize;
|
||||||
|
|
||||||
while (todo--)
|
while (todo--)
|
||||||
pCurrentSection->tData[dest++] = fgetc(f);
|
pCurrentSection->tData[dest++] = fgetc(f);
|
||||||
}
|
|
||||||
pCurrentSection->nPC += fsize;
|
pCurrentSection->nPC += fsize;
|
||||||
nPC += fsize;
|
nPC += fsize;
|
||||||
pPCSymbol->nValue += fsize;
|
pPCSymbol->nValue += fsize;
|
||||||
@@ -958,13 +945,12 @@ void out_BinaryFileSlice(char *s, int32_t start_pos, int32_t length)
|
|||||||
checkcodesection();
|
checkcodesection();
|
||||||
checksectionoverflow(length);
|
checksectionoverflow(length);
|
||||||
|
|
||||||
if (nPass == 2) {
|
|
||||||
int32_t dest = nPC;
|
int32_t dest = nPC;
|
||||||
int32_t todo = length;
|
int32_t todo = length;
|
||||||
|
|
||||||
while (todo--)
|
while (todo--)
|
||||||
pCurrentSection->tData[dest++] = fgetc(f);
|
pCurrentSection->tData[dest++] = fgetc(f);
|
||||||
}
|
|
||||||
pCurrentSection->nPC += length;
|
pCurrentSection->nPC += length;
|
||||||
nPC += length;
|
nPC += length;
|
||||||
pPCSymbol->nValue += length;
|
pPCSymbol->nValue += length;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2010-2018, Anthony J. Bentley and RGBDS contributors.
|
.\" Copyright (c) 2010-2019, Anthony J. Bentley and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd February 24, 2018
|
.Dd July 8, 2019
|
||||||
.Dt RGBASM 1
|
.Dt RGBASM 1
|
||||||
.Os RGBDS Manual
|
.Os RGBDS Manual
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -21,11 +21,18 @@
|
|||||||
.Op Fl M Ar dependfile
|
.Op Fl M Ar dependfile
|
||||||
.Op Fl o Ar outfile
|
.Op Fl o Ar outfile
|
||||||
.Op Fl p Ar pad_value
|
.Op Fl p Ar pad_value
|
||||||
|
.Op Fl r Ar recursion_depth
|
||||||
.Ar file
|
.Ar file
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
program creates an object file from an assembly source file.
|
program creates an object file from an assembly source file.
|
||||||
|
The input
|
||||||
|
.Ar file
|
||||||
|
can be a file path, or
|
||||||
|
.Cm \-
|
||||||
|
denoting
|
||||||
|
.Cm stdin .
|
||||||
Its arguments are as follows:
|
Its arguments are as follows:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Fl b Ar chars
|
.It Fl b Ar chars
|
||||||
@@ -71,6 +78,8 @@ Write an object file to the given filename.
|
|||||||
.It Fl p Ar pad_value
|
.It Fl p 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.
|
||||||
|
.It Fl r Ar recursion_depth
|
||||||
|
Specifies the recursion depth at which RGBASM will assume being in an infinite loop.
|
||||||
.It Fl V
|
.It Fl V
|
||||||
Print the version of the program and exit.
|
Print the version of the program and exit.
|
||||||
.It Fl v
|
.It Fl v
|
||||||
@@ -79,12 +88,20 @@ Be verbose.
|
|||||||
Disable warning output.
|
Disable warning output.
|
||||||
.El
|
.El
|
||||||
.Sh EXAMPLES
|
.Sh EXAMPLES
|
||||||
Assembling a basic source file is simple:
|
You can assemble a source file in two ways.
|
||||||
|
Straight forward way:
|
||||||
.Pp
|
.Pp
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
$ rgbasm -o bar.o foo.asm
|
$ rgbasm -o bar.o foo.asm
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
|
Pipes way:
|
||||||
|
.Pp
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
$ cat foo.asm | rgbasm -o bar.o -
|
||||||
|
$ rgbasm -o bar.o - < foo.asm
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
The resulting object file is not yet a usable ROM image \(em it must first be
|
The resulting object file is not yet a usable ROM image \(em it must first be
|
||||||
run through
|
run through
|
||||||
.Xr rgblink 1
|
.Xr rgblink 1
|
||||||
|
|||||||
@@ -455,8 +455,7 @@ String equates can't be exported or imported.
|
|||||||
.Sy Important note :
|
.Sy Important note :
|
||||||
An EQUS can be expanded to a string that contains another EQUS
|
An EQUS can be expanded to a string that contains another EQUS
|
||||||
and it will be expanded as well.
|
and it will be expanded as well.
|
||||||
This means that, if you aren't careful, you may trap the assembler into an
|
If this creates an infinite loop, RGBASM will error out once a certain depth is reached. See the -r command-line option.
|
||||||
infinite loop if there's a circular dependency in the expansions.
|
|
||||||
Also, a MACRO can have inside an EQUS which references the same MACRO, which has
|
Also, a MACRO can have inside an EQUS which references the same MACRO, which has
|
||||||
the same problem.
|
the same problem.
|
||||||
.Pp
|
.Pp
|
||||||
@@ -584,16 +583,15 @@ If you want to use the rest, you need to use the keyword
|
|||||||
.Ic SHIFT .
|
.Ic SHIFT .
|
||||||
.Pp
|
.Pp
|
||||||
Line continuations work as usual inside macros or lists of arguments of macros.
|
Line continuations work as usual inside macros or lists of arguments of macros.
|
||||||
Strings, however, are a bit trickier.
|
However, some characters need to be escaped, as in the following example:
|
||||||
The following example shows how to use strings as arguments for a macro:
|
|
||||||
.Pp
|
.Pp
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
PrintMacro : MACRO
|
PrintMacro : MACRO
|
||||||
PRINTT \[rs]1
|
PRINTT \[rs]1
|
||||||
ENDM
|
ENDM
|
||||||
|
|
||||||
PrintMacro STRCAT(\[rs]"Hello\[rs]"\[rs], \[rs]
|
PrintMacro STRCAT("Hello"\[rs], \[rs]
|
||||||
\[rs]" world\[rs]\[rs]n\[rs]")
|
" world\[rs]\[rs]n")
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
.Ic SHIFT
|
.Ic SHIFT
|
||||||
@@ -1079,7 +1077,20 @@ within a string.
|
|||||||
This will examine the type of the symbol and insert its value accordingly.
|
This will examine the type of the symbol and insert its value accordingly.
|
||||||
If symbol is a string symbol, the symbols value is simply copied.
|
If symbol is a string symbol, the symbols value is simply copied.
|
||||||
If it's a numeric symbol, the value is converted to hexadecimal notation and
|
If it's a numeric symbol, the value is converted to hexadecimal notation and
|
||||||
inserted as a string.
|
inserted as a string with a dollar prepended.
|
||||||
|
.Pp
|
||||||
|
It's possible to change the way numeric symbols are converted by specifying
|
||||||
|
a print type like so:
|
||||||
|
.Sy {d:symbol}
|
||||||
|
Valid print types are:
|
||||||
|
.Bl -column -offset indent
|
||||||
|
.It Sy Print type Ta Sy Format Ta Sy Example
|
||||||
|
.It Li d Ta Decimal Ta 42
|
||||||
|
.It Li x Ta Lowercase hexadecimal Ta 2a
|
||||||
|
.It Li X Ta Uppercase hexadecimal Ta 2A
|
||||||
|
.It Li b Ta Binary Ta 101010
|
||||||
|
.Pp
|
||||||
|
Note that print types should only be used with numeric values, not strings.
|
||||||
.Pp
|
.Pp
|
||||||
HINT: The
|
HINT: The
|
||||||
.Sy {symbol}
|
.Sy {symbol}
|
||||||
@@ -1127,9 +1138,30 @@ CHARMAP "í", 20
|
|||||||
CHARMAP "A", 128
|
CHARMAP "A", 128
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
|
It is possible to create multiple character maps and then switch between them
|
||||||
|
as desired. This can be used to encode debug information in ASCII and use
|
||||||
|
a different encoding for other purposes, for example. Initially, there is
|
||||||
|
one character map called
|
||||||
|
.Sy main
|
||||||
|
and it is automatically selected as the current character map from the
|
||||||
|
beginning. There is also a character map stack that can be used to save and
|
||||||
|
restore which character map is currently active.
|
||||||
|
.Bl -column "NEWCHARMAP name, basename"
|
||||||
|
.It Sy Command Ta Sy Meaning
|
||||||
|
.It Ic NEWCHARMAP Ar name Ta Creates a new, empty character map called
|
||||||
|
.Ic name .
|
||||||
|
.It Ic NEWCHARMAP Ar name , basename Ta Creates a new character map called
|
||||||
|
. Ic name ,
|
||||||
|
copied from character map
|
||||||
|
.Ic basename .
|
||||||
|
.It Ic SETCHARMAP Ar name Ta Switch to character map Ic name .
|
||||||
|
.It Ic PUSHC Ta Push the current character map onto the stack.
|
||||||
|
.It Ic POPC Ta Pop a character map off the stack and switch to it.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
.Sy Note:
|
.Sy Note:
|
||||||
Character maps affect all strings in the file from the point in which they are
|
Character maps affect all strings in the file from the point in which they are
|
||||||
defined.
|
defined, until switching to a different character map.
|
||||||
This means that any string that the code may want to print as debug information
|
This means that any string that the code may want to print as debug information
|
||||||
will also be affected by it.
|
will also be affected by it.
|
||||||
.Pp
|
.Pp
|
||||||
|
|||||||
209
src/asm/rpn.c
209
src/asm/rpn.c
@@ -10,6 +10,7 @@
|
|||||||
* Controls RPN expressions for objectfiles
|
* Controls RPN expressions for objectfiles
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -24,12 +25,39 @@
|
|||||||
void mergetwoexpressions(struct Expression *expr, const struct Expression *src1,
|
void mergetwoexpressions(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
*expr = *src1;
|
assert(src1->tRPN != NULL && src2->tRPN != NULL);
|
||||||
memcpy(&(expr->tRPN[expr->nRPNLength]), src2->tRPN, src2->nRPNLength);
|
|
||||||
|
|
||||||
expr->nRPNLength += src2->nRPNLength;
|
if (src1->nRPNLength + src2->nRPNLength > MAXRPNLEN)
|
||||||
expr->isReloc |= src2->isReloc;
|
fatalerror("RPN expression is too large");
|
||||||
expr->isPCRel |= src2->isPCRel;
|
|
||||||
|
uint32_t len = src1->nRPNLength + src2->nRPNLength;
|
||||||
|
|
||||||
|
expr->nVal = 0;
|
||||||
|
expr->tRPN = src1->tRPN;
|
||||||
|
|
||||||
|
if (src1->nRPNCapacity >= len) {
|
||||||
|
expr->nRPNCapacity = src1->nRPNCapacity;
|
||||||
|
} else {
|
||||||
|
uint32_t cap1 = src1->nRPNCapacity;
|
||||||
|
uint32_t cap2 = src2->nRPNCapacity;
|
||||||
|
uint32_t cap = (cap1 > cap2) ? cap1 : cap2;
|
||||||
|
|
||||||
|
if (len > cap)
|
||||||
|
cap = (cap <= MAXRPNLEN / 2) ? cap * 2 : MAXRPNLEN;
|
||||||
|
|
||||||
|
expr->nRPNCapacity = cap;
|
||||||
|
expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity);
|
||||||
|
if (expr->tRPN == NULL)
|
||||||
|
fatalerror("No memory for RPN expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(expr->tRPN + src1->nRPNLength, src2->tRPN, src2->nRPNLength);
|
||||||
|
free(src2->tRPN);
|
||||||
|
|
||||||
|
expr->nRPNLength = len;
|
||||||
|
expr->nRPNPatchSize = src1->nRPNPatchSize + src2->nRPNPatchSize;
|
||||||
|
expr->nRPNOut = 0;
|
||||||
|
expr->isReloc = src1->isReloc || src2->isReloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define joinexpr() mergetwoexpressions(expr, src1, src2)
|
#define joinexpr() mergetwoexpressions(expr, src1, src2)
|
||||||
@@ -37,20 +65,46 @@ void mergetwoexpressions(struct Expression *expr, const struct Expression *src1,
|
|||||||
/*
|
/*
|
||||||
* Add a byte to the RPN expression
|
* Add a byte to the RPN expression
|
||||||
*/
|
*/
|
||||||
void pushbyte(struct Expression *expr, int b)
|
void pushbyte(struct Expression *expr, uint8_t b)
|
||||||
{
|
{
|
||||||
expr->tRPN[expr->nRPNLength++] = b & 0xFF;
|
if (expr->nRPNLength == expr->nRPNCapacity) {
|
||||||
|
if (expr->nRPNCapacity == 0)
|
||||||
|
expr->nRPNCapacity = 256;
|
||||||
|
else if (expr->nRPNCapacity == MAXRPNLEN)
|
||||||
|
fatalerror("RPN expression is too large");
|
||||||
|
else if (expr->nRPNCapacity > MAXRPNLEN / 2)
|
||||||
|
expr->nRPNCapacity = MAXRPNLEN;
|
||||||
|
else
|
||||||
|
expr->nRPNCapacity *= 2;
|
||||||
|
expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity);
|
||||||
|
|
||||||
|
if (expr->tRPN == NULL)
|
||||||
|
fatalerror("No memory for RPN expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
expr->tRPN[expr->nRPNLength++] = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset the RPN module
|
* Init the RPN expression
|
||||||
*/
|
*/
|
||||||
void rpn_Reset(struct Expression *expr)
|
void rpn_Init(struct Expression *expr)
|
||||||
{
|
{
|
||||||
|
expr->tRPN = NULL;
|
||||||
|
expr->nRPNCapacity = 0;
|
||||||
expr->nRPNLength = 0;
|
expr->nRPNLength = 0;
|
||||||
|
expr->nRPNPatchSize = 0;
|
||||||
expr->nRPNOut = 0;
|
expr->nRPNOut = 0;
|
||||||
expr->isReloc = 0;
|
expr->isReloc = 0;
|
||||||
expr->isPCRel = 0;
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the RPN expression
|
||||||
|
*/
|
||||||
|
void rpn_Free(struct Expression *expr)
|
||||||
|
{
|
||||||
|
free(expr->tRPN);
|
||||||
|
rpn_Init(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -72,45 +126,32 @@ uint32_t rpn_isReloc(const struct Expression *expr)
|
|||||||
return expr->isReloc;
|
return expr->isReloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine if the current expression can be pc-relative
|
|
||||||
*/
|
|
||||||
uint32_t rpn_isPCRelative(const struct Expression *expr)
|
|
||||||
{
|
|
||||||
return expr->isPCRel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add symbols, constants and operators to expression
|
* Add symbols, constants and operators to expression
|
||||||
*/
|
*/
|
||||||
void rpn_Number(struct Expression *expr, uint32_t i)
|
void rpn_Number(struct Expression *expr, uint32_t i)
|
||||||
{
|
{
|
||||||
rpn_Reset(expr);
|
rpn_Init(expr);
|
||||||
pushbyte(expr, RPN_CONST);
|
pushbyte(expr, RPN_CONST);
|
||||||
pushbyte(expr, i);
|
pushbyte(expr, i);
|
||||||
pushbyte(expr, i >> 8);
|
pushbyte(expr, i >> 8);
|
||||||
pushbyte(expr, i >> 16);
|
pushbyte(expr, i >> 16);
|
||||||
pushbyte(expr, i >> 24);
|
pushbyte(expr, i >> 24);
|
||||||
expr->nVal = i;
|
expr->nVal = i;
|
||||||
|
expr->nRPNPatchSize += 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_Symbol(struct Expression *expr, char *tzSym)
|
void rpn_Symbol(struct Expression *expr, char *tzSym)
|
||||||
{
|
{
|
||||||
if (!sym_isConstant(tzSym)) {
|
if (!sym_isConstant(tzSym)) {
|
||||||
const struct sSymbol *psym;
|
rpn_Init(expr);
|
||||||
|
sym_Ref(tzSym);
|
||||||
rpn_Reset(expr);
|
|
||||||
|
|
||||||
psym = sym_FindSymbol(tzSym);
|
|
||||||
|
|
||||||
if (psym == NULL || psym->pSection == pCurrentSection
|
|
||||||
|| psym->pSection == NULL)
|
|
||||||
expr->isPCRel = 1;
|
|
||||||
expr->isReloc = 1;
|
expr->isReloc = 1;
|
||||||
pushbyte(expr, RPN_SYM);
|
pushbyte(expr, RPN_SYM);
|
||||||
while (*tzSym)
|
while (*tzSym)
|
||||||
pushbyte(expr, *tzSym++);
|
pushbyte(expr, *tzSym++);
|
||||||
pushbyte(expr, 0);
|
pushbyte(expr, 0);
|
||||||
|
expr->nRPNPatchSize += 5;
|
||||||
} else {
|
} else {
|
||||||
rpn_Number(expr, sym_GetConstantValue(tzSym));
|
rpn_Number(expr, sym_GetConstantValue(tzSym));
|
||||||
}
|
}
|
||||||
@@ -118,7 +159,7 @@ void rpn_Symbol(struct Expression *expr, char *tzSym)
|
|||||||
|
|
||||||
void rpn_BankSelf(struct Expression *expr)
|
void rpn_BankSelf(struct Expression *expr)
|
||||||
{
|
{
|
||||||
rpn_Reset(expr);
|
rpn_Init(expr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This symbol is not really relocatable, but this makes the assembler
|
* This symbol is not really relocatable, but this makes the assembler
|
||||||
@@ -127,6 +168,7 @@ void rpn_BankSelf(struct Expression *expr)
|
|||||||
expr->isReloc = 1;
|
expr->isReloc = 1;
|
||||||
|
|
||||||
pushbyte(expr, RPN_BANK_SELF);
|
pushbyte(expr, RPN_BANK_SELF);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_BankSymbol(struct Expression *expr, char *tzSym)
|
void rpn_BankSymbol(struct Expression *expr, char *tzSym)
|
||||||
@@ -138,19 +180,14 @@ void rpn_BankSymbol(struct Expression *expr, char *tzSym)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!sym_isConstant(tzSym)) {
|
if (!sym_isConstant(tzSym)) {
|
||||||
rpn_Reset(expr);
|
rpn_Init(expr);
|
||||||
|
sym_Ref(tzSym);
|
||||||
/*
|
|
||||||
* Check that the symbol exists by evaluating and discarding the
|
|
||||||
* value.
|
|
||||||
*/
|
|
||||||
sym_GetValue(tzSym);
|
|
||||||
|
|
||||||
expr->isReloc = 1;
|
expr->isReloc = 1;
|
||||||
pushbyte(expr, RPN_BANK_SYM);
|
pushbyte(expr, RPN_BANK_SYM);
|
||||||
while (*tzSym)
|
while (*tzSym)
|
||||||
pushbyte(expr, *tzSym++);
|
pushbyte(expr, *tzSym++);
|
||||||
pushbyte(expr, 0);
|
pushbyte(expr, 0);
|
||||||
|
expr->nRPNPatchSize += 5;
|
||||||
} else {
|
} else {
|
||||||
yyerror("BANK argument must be a relocatable identifier");
|
yyerror("BANK argument must be a relocatable identifier");
|
||||||
}
|
}
|
||||||
@@ -158,7 +195,7 @@ void rpn_BankSymbol(struct Expression *expr, char *tzSym)
|
|||||||
|
|
||||||
void rpn_BankSection(struct Expression *expr, char *tzSectionName)
|
void rpn_BankSection(struct Expression *expr, char *tzSectionName)
|
||||||
{
|
{
|
||||||
rpn_Reset(expr);
|
rpn_Init(expr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This symbol is not really relocatable, but this makes the assembler
|
* This symbol is not really relocatable, but this makes the assembler
|
||||||
@@ -167,37 +204,48 @@ void rpn_BankSection(struct Expression *expr, char *tzSectionName)
|
|||||||
expr->isReloc = 1;
|
expr->isReloc = 1;
|
||||||
|
|
||||||
pushbyte(expr, RPN_BANK_SECT);
|
pushbyte(expr, RPN_BANK_SECT);
|
||||||
while (*tzSectionName)
|
expr->nRPNPatchSize++;
|
||||||
|
|
||||||
|
while (*tzSectionName) {
|
||||||
pushbyte(expr, *tzSectionName++);
|
pushbyte(expr, *tzSectionName++);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
|
}
|
||||||
|
|
||||||
pushbyte(expr, 0);
|
pushbyte(expr, 0);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
pushbyte(expr, RPN_HRAM);
|
pushbyte(expr, RPN_HRAM);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
|
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
|
expr->nVal = !expr->nVal;
|
||||||
pushbyte(expr, RPN_LOGUNNOT);
|
pushbyte(expr, RPN_LOGUNNOT);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGOR(struct Expression *expr, const struct Expression *src1,
|
void rpn_LOGOR(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal || src2->nVal);
|
expr->nVal = (src1->nVal || src2->nVal);
|
||||||
pushbyte(expr, RPN_LOGOR);
|
pushbyte(expr, RPN_LOGOR);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGAND(struct Expression *expr, const struct Expression *src1,
|
void rpn_LOGAND(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal && src2->nVal);
|
expr->nVal = (src1->nVal && src2->nVal);
|
||||||
pushbyte(expr, RPN_LOGAND);
|
pushbyte(expr, RPN_LOGAND);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_HIGH(struct Expression *expr, const struct Expression *src)
|
void rpn_HIGH(struct Expression *expr, const struct Expression *src)
|
||||||
@@ -221,6 +269,8 @@ void rpn_HIGH(struct Expression *expr, const struct Expression *src)
|
|||||||
pushbyte(expr, 0);
|
pushbyte(expr, 0);
|
||||||
|
|
||||||
pushbyte(expr, RPN_AND);
|
pushbyte(expr, RPN_AND);
|
||||||
|
|
||||||
|
expr->nRPNPatchSize += 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
||||||
@@ -236,94 +286,107 @@ void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
|||||||
pushbyte(expr, 0);
|
pushbyte(expr, 0);
|
||||||
|
|
||||||
pushbyte(expr, RPN_AND);
|
pushbyte(expr, RPN_AND);
|
||||||
|
|
||||||
|
expr->nRPNPatchSize += 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1,
|
void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal == src2->nVal);
|
expr->nVal = (src1->nVal == src2->nVal);
|
||||||
pushbyte(expr, RPN_LOGEQ);
|
pushbyte(expr, RPN_LOGEQ);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGGT(struct Expression *expr, const struct Expression *src1,
|
void rpn_LOGGT(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal > src2->nVal);
|
expr->nVal = (src1->nVal > src2->nVal);
|
||||||
pushbyte(expr, RPN_LOGGT);
|
pushbyte(expr, RPN_LOGGT);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGLT(struct Expression *expr, const struct Expression *src1,
|
void rpn_LOGLT(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal < src2->nVal);
|
expr->nVal = (src1->nVal < src2->nVal);
|
||||||
pushbyte(expr, RPN_LOGLT);
|
pushbyte(expr, RPN_LOGLT);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGGE(struct Expression *expr, const struct Expression *src1,
|
void rpn_LOGGE(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal >= src2->nVal);
|
expr->nVal = (src1->nVal >= src2->nVal);
|
||||||
pushbyte(expr, RPN_LOGGE);
|
pushbyte(expr, RPN_LOGGE);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGLE(struct Expression *expr, const struct Expression *src1,
|
void rpn_LOGLE(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal <= src2->nVal);
|
expr->nVal = (src1->nVal <= src2->nVal);
|
||||||
pushbyte(expr, RPN_LOGLE);
|
pushbyte(expr, RPN_LOGLE);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGNE(struct Expression *expr, const struct Expression *src1,
|
void rpn_LOGNE(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal != src2->nVal);
|
expr->nVal = (src1->nVal != src2->nVal);
|
||||||
pushbyte(expr, RPN_LOGNE);
|
pushbyte(expr, RPN_LOGNE);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_ADD(struct Expression *expr, const struct Expression *src1,
|
void rpn_ADD(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal + src2->nVal);
|
expr->nVal = ((uint32_t)src1->nVal + (uint32_t)src2->nVal);
|
||||||
pushbyte(expr, RPN_ADD);
|
pushbyte(expr, RPN_ADD);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_SUB(struct Expression *expr, const struct Expression *src1,
|
void rpn_SUB(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal - src2->nVal);
|
expr->nVal = ((uint32_t)src1->nVal - (uint32_t)src2->nVal);
|
||||||
pushbyte(expr, RPN_SUB);
|
pushbyte(expr, RPN_SUB);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_XOR(struct Expression *expr, const struct Expression *src1,
|
void rpn_XOR(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal ^ src2->nVal);
|
expr->nVal = (src1->nVal ^ src2->nVal);
|
||||||
pushbyte(expr, RPN_XOR);
|
pushbyte(expr, RPN_XOR);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_OR(struct Expression *expr, const struct Expression *src1,
|
void rpn_OR(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal | src2->nVal);
|
expr->nVal = (src1->nVal | src2->nVal);
|
||||||
pushbyte(expr, RPN_OR);
|
pushbyte(expr, RPN_OR);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_AND(struct Expression *expr, const struct Expression *src1,
|
void rpn_AND(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal & src2->nVal);
|
expr->nVal = (src1->nVal & src2->nVal);
|
||||||
pushbyte(expr, RPN_AND);
|
pushbyte(expr, RPN_AND);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_SHL(struct Expression *expr, const struct Expression *src1,
|
void rpn_SHL(struct Expression *expr, const struct Expression *src1,
|
||||||
@@ -331,6 +394,7 @@ void rpn_SHL(struct Expression *expr, const struct Expression *src1,
|
|||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
|
|
||||||
|
if (!expr->isReloc) {
|
||||||
if (src1->nVal < 0)
|
if (src1->nVal < 0)
|
||||||
warning("Left shift of negative value: %d", src1->nVal);
|
warning("Left shift of negative value: %d", src1->nVal);
|
||||||
|
|
||||||
@@ -339,58 +403,86 @@ void rpn_SHL(struct Expression *expr, const struct Expression *src1,
|
|||||||
else if (src2->nVal >= 32)
|
else if (src2->nVal >= 32)
|
||||||
fatalerror("Shift by too big value: %d", src2->nVal);
|
fatalerror("Shift by too big value: %d", src2->nVal);
|
||||||
|
|
||||||
expr->nVal = (expr->nVal << src2->nVal);
|
expr->nVal = ((uint32_t)src1->nVal << src2->nVal);
|
||||||
|
}
|
||||||
|
|
||||||
pushbyte(expr, RPN_SHL);
|
pushbyte(expr, RPN_SHL);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_SHR(struct Expression *expr, const struct Expression *src1,
|
void rpn_SHR(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
|
|
||||||
|
if (!expr->isReloc) {
|
||||||
if (src2->nVal < 0)
|
if (src2->nVal < 0)
|
||||||
fatalerror("Shift by negative value: %d", src2->nVal);
|
fatalerror("Shift by negative value: %d", src2->nVal);
|
||||||
else if (src2->nVal >= 32)
|
else if (src2->nVal >= 32)
|
||||||
fatalerror("Shift by too big value: %d", src2->nVal);
|
fatalerror("Shift by too big value: %d", src2->nVal);
|
||||||
|
|
||||||
expr->nVal = (expr->nVal >> src2->nVal);
|
expr->nVal = (src1->nVal >> src2->nVal);
|
||||||
|
}
|
||||||
|
|
||||||
pushbyte(expr, RPN_SHR);
|
pushbyte(expr, RPN_SHR);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_MUL(struct Expression *expr, const struct Expression *src1,
|
void rpn_MUL(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
expr->nVal = (expr->nVal * src2->nVal);
|
expr->nVal = ((uint32_t)src1->nVal * (uint32_t)src2->nVal);
|
||||||
pushbyte(expr, RPN_MUL);
|
pushbyte(expr, RPN_MUL);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_DIV(struct Expression *expr, const struct Expression *src1,
|
void rpn_DIV(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
|
|
||||||
|
if (!expr->isReloc) {
|
||||||
if (src2->nVal == 0)
|
if (src2->nVal == 0)
|
||||||
fatalerror("Division by zero");
|
fatalerror("Division by zero");
|
||||||
|
|
||||||
expr->nVal = (expr->nVal / src2->nVal);
|
if (src1->nVal == INT32_MIN && src2->nVal == -1) {
|
||||||
|
warning("Division of min value by -1");
|
||||||
|
expr->nVal = INT32_MIN;
|
||||||
|
} else {
|
||||||
|
expr->nVal = (src1->nVal / src2->nVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pushbyte(expr, RPN_DIV);
|
pushbyte(expr, RPN_DIV);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_MOD(struct Expression *expr, const struct Expression *src1,
|
void rpn_MOD(struct Expression *expr, const struct Expression *src1,
|
||||||
const struct Expression *src2)
|
const struct Expression *src2)
|
||||||
{
|
{
|
||||||
joinexpr();
|
joinexpr();
|
||||||
|
|
||||||
|
if (!expr->isReloc) {
|
||||||
if (src2->nVal == 0)
|
if (src2->nVal == 0)
|
||||||
fatalerror("Division by zero");
|
fatalerror("Division by zero");
|
||||||
|
|
||||||
expr->nVal = (expr->nVal % src2->nVal);
|
if (src1->nVal == INT32_MIN && src2->nVal == -1)
|
||||||
|
expr->nVal = 0;
|
||||||
|
else
|
||||||
|
expr->nVal = (src1->nVal % src2->nVal);
|
||||||
|
}
|
||||||
|
|
||||||
pushbyte(expr, RPN_MOD);
|
pushbyte(expr, RPN_MOD);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_UNNEG(struct Expression *expr, const struct Expression *src)
|
void rpn_UNNEG(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->nVal = -expr->nVal;
|
expr->nVal = -(uint32_t)expr->nVal;
|
||||||
pushbyte(expr, RPN_UNSUB);
|
pushbyte(expr, RPN_UNSUB);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
|
void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
|
||||||
@@ -398,4 +490,5 @@ void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
|
|||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->nVal = ~expr->nVal;
|
expr->nVal = ~expr->nVal;
|
||||||
pushbyte(expr, RPN_UNNOT);
|
pushbyte(expr, RPN_UNNOT);
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
}
|
}
|
||||||
|
|||||||
388
src/asm/symbol.c
388
src/asm/symbol.c
@@ -22,6 +22,7 @@
|
|||||||
#include "asm/main.h"
|
#include "asm/main.h"
|
||||||
#include "asm/mymath.h"
|
#include "asm/mymath.h"
|
||||||
#include "asm/output.h"
|
#include "asm/output.h"
|
||||||
|
#include "asm/util.h"
|
||||||
|
|
||||||
#include "extern/err.h"
|
#include "extern/err.h"
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ int32_t Callback_NARG(unused_ struct sSymbol *sym)
|
|||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
while (currentmacroargs[i] && i < MAXMACROARGS)
|
while (currentmacroargs[i] && i < MAXMACROARGS)
|
||||||
i += 1;
|
i++;
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@@ -90,16 +91,11 @@ static int32_t getvaluefield(struct sSymbol *sym)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the hash value for a string
|
* Calculate the hash value for a symbol name
|
||||||
*/
|
*/
|
||||||
uint32_t calchash(char *s)
|
uint32_t sym_CalcHash(const char *s)
|
||||||
{
|
{
|
||||||
uint32_t hash = 5381;
|
return calchash(s) % HASHSIZE;
|
||||||
|
|
||||||
while (*s != 0)
|
|
||||||
hash = (hash * 33) ^ (*s++);
|
|
||||||
|
|
||||||
return hash % HASHSIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -123,7 +119,7 @@ struct sSymbol *createsymbol(char *s)
|
|||||||
struct sSymbol **ppsym;
|
struct sSymbol **ppsym;
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
|
|
||||||
hash = calchash(s);
|
hash = sym_CalcHash(s);
|
||||||
ppsym = &(tHashedSymbols[hash]);
|
ppsym = &(tHashedSymbols[hash]);
|
||||||
|
|
||||||
while ((*ppsym) != NULL)
|
while ((*ppsym) != NULL)
|
||||||
@@ -154,12 +150,15 @@ struct sSymbol *createsymbol(char *s)
|
|||||||
* Creates the full name of a local symbol in a given scope, by prepending
|
* Creates the full name of a local symbol in a given scope, by prepending
|
||||||
* the name with the parent symbol's name.
|
* the name with the parent symbol's name.
|
||||||
*/
|
*/
|
||||||
static size_t fullSymbolName(char *output, size_t outputSize, char *localName,
|
static void fullSymbolName(char *output, size_t outputSize, char *localName,
|
||||||
const struct sSymbol *scope)
|
const struct sSymbol *scope)
|
||||||
{
|
{
|
||||||
const struct sSymbol *parent = scope->pScope ? scope->pScope : scope;
|
const struct sSymbol *parent = scope->pScope ? scope->pScope : scope;
|
||||||
|
int n = snprintf(output, outputSize, "%s%s", parent->tzName, localName);
|
||||||
|
|
||||||
return snprintf(output, outputSize, "%s%s", parent->tzName, localName);
|
if (n >= (int)outputSize)
|
||||||
|
fatalerror("Symbol name is too long: '%s%s'",
|
||||||
|
parent->tzName, localName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -184,7 +183,7 @@ struct sSymbol **findpsymbol(char *s, struct sSymbol *scope)
|
|||||||
s);
|
s);
|
||||||
}
|
}
|
||||||
|
|
||||||
hash = calchash(s);
|
hash = sym_CalcHash(s);
|
||||||
ppsym = &(tHashedSymbols[hash]);
|
ppsym = &(tHashedSymbols[hash]);
|
||||||
|
|
||||||
while ((*ppsym) != NULL) {
|
while ((*ppsym) != NULL) {
|
||||||
@@ -207,7 +206,7 @@ struct sSymbol *findsymbol(char *s, struct sSymbol *scope)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a symbol by name and scope
|
* Find a symbol by name, with automatically determined scope
|
||||||
*/
|
*/
|
||||||
struct sSymbol *sym_FindSymbol(char *tzName)
|
struct sSymbol *sym_FindSymbol(char *tzName)
|
||||||
{
|
{
|
||||||
@@ -256,14 +255,7 @@ void sym_Purge(char *tzName)
|
|||||||
*/
|
*/
|
||||||
uint32_t sym_isConstDefined(char *tzName)
|
uint32_t sym_isConstDefined(char *tzName)
|
||||||
{
|
{
|
||||||
struct sSymbol *psym, *pscope;
|
struct sSymbol *psym = sym_FindSymbol(tzName);
|
||||||
|
|
||||||
if (*tzName == '.')
|
|
||||||
pscope = pScope;
|
|
||||||
else
|
|
||||||
pscope = NULL;
|
|
||||||
|
|
||||||
psym = findsymbol(tzName, pscope);
|
|
||||||
|
|
||||||
if (psym && (psym->nType & SYMF_DEFINED)) {
|
if (psym && (psym->nType & SYMF_DEFINED)) {
|
||||||
uint32_t mask = SYMF_EQU | SYMF_SET | SYMF_MACRO | SYMF_STRING;
|
uint32_t mask = SYMF_EQU | SYMF_SET | SYMF_MACRO | SYMF_STRING;
|
||||||
@@ -280,19 +272,9 @@ uint32_t sym_isConstDefined(char *tzName)
|
|||||||
|
|
||||||
uint32_t sym_isDefined(char *tzName)
|
uint32_t sym_isDefined(char *tzName)
|
||||||
{
|
{
|
||||||
struct sSymbol *psym, *pscope;
|
struct sSymbol *psym = sym_FindSymbol(tzName);
|
||||||
|
|
||||||
if (*tzName == '.')
|
return (psym && (psym->nType & SYMF_DEFINED));
|
||||||
pscope = pScope;
|
|
||||||
else
|
|
||||||
pscope = NULL;
|
|
||||||
|
|
||||||
psym = findsymbol(tzName, pscope);
|
|
||||||
|
|
||||||
if (psym && (psym->nType & SYMF_DEFINED))
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -300,21 +282,9 @@ uint32_t sym_isDefined(char *tzName)
|
|||||||
*/
|
*/
|
||||||
uint32_t sym_isConstant(char *s)
|
uint32_t sym_isConstant(char *s)
|
||||||
{
|
{
|
||||||
struct sSymbol *psym, *pscope;
|
struct sSymbol *psym = sym_FindSymbol(s);
|
||||||
|
|
||||||
if (*s == '.')
|
return (psym && (psym->nType & SYMF_CONST));
|
||||||
pscope = pScope;
|
|
||||||
else
|
|
||||||
pscope = NULL;
|
|
||||||
|
|
||||||
psym = findsymbol(s, pscope);
|
|
||||||
|
|
||||||
if (psym != NULL) {
|
|
||||||
if (psym->nType & SYMF_CONST)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -337,14 +307,7 @@ char *sym_GetStringValue(char *tzSym)
|
|||||||
*/
|
*/
|
||||||
uint32_t sym_GetConstantValue(char *s)
|
uint32_t sym_GetConstantValue(char *s)
|
||||||
{
|
{
|
||||||
struct sSymbol *psym, *pscope;
|
struct sSymbol *psym = sym_FindSymbol(s);
|
||||||
|
|
||||||
if (*s == '.')
|
|
||||||
pscope = pScope;
|
|
||||||
else
|
|
||||||
pscope = NULL;
|
|
||||||
|
|
||||||
psym = findsymbol(s, pscope);
|
|
||||||
|
|
||||||
if (psym != NULL) {
|
if (psym != NULL) {
|
||||||
if (psym->nType & SYMF_CONST)
|
if (psym->nType & SYMF_CONST)
|
||||||
@@ -358,63 +321,12 @@ uint32_t sym_GetConstantValue(char *s)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Return a symbols value... "estimated" if not defined yet
|
|
||||||
*/
|
|
||||||
uint32_t sym_GetValue(char *s)
|
|
||||||
{
|
|
||||||
struct sSymbol *psym, *pscope;
|
|
||||||
|
|
||||||
if (*s == '.')
|
|
||||||
pscope = pScope;
|
|
||||||
else
|
|
||||||
pscope = NULL;
|
|
||||||
|
|
||||||
psym = findsymbol(s, pscope);
|
|
||||||
|
|
||||||
if (psym != NULL) {
|
|
||||||
if (psym->nType & SYMF_DEFINED) {
|
|
||||||
if (psym->nType & (SYMF_MACRO | SYMF_STRING))
|
|
||||||
yyerror("'%s' is a macro or string symbol", s);
|
|
||||||
|
|
||||||
return getvaluefield(psym);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nPass == 2) {
|
|
||||||
/*
|
|
||||||
* Assume undefined symbols are imported from
|
|
||||||
* somwehere else
|
|
||||||
*/
|
|
||||||
psym->nType |= SYMF_IMPORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 0x80 seems like a good default value... */
|
|
||||||
return 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nPass == 1) {
|
|
||||||
createsymbol(s);
|
|
||||||
return 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
yyerror("'%s' not defined", s);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return a defined symbols value... aborts if not defined yet
|
* Return a defined symbols value... aborts if not defined yet
|
||||||
*/
|
*/
|
||||||
uint32_t sym_GetDefinedValue(char *s)
|
uint32_t sym_GetDefinedValue(char *s)
|
||||||
{
|
{
|
||||||
struct sSymbol *psym, *pscope;
|
struct sSymbol *psym = sym_FindSymbol(s);
|
||||||
|
|
||||||
if (*s == '.')
|
|
||||||
pscope = pScope;
|
|
||||||
else
|
|
||||||
pscope = NULL;
|
|
||||||
|
|
||||||
psym = findsymbol(s, pscope);
|
|
||||||
|
|
||||||
if (psym != NULL) {
|
if (psym != NULL) {
|
||||||
if ((psym->nType & SYMF_DEFINED)) {
|
if ((psym->nType & SYMF_DEFINED)) {
|
||||||
@@ -448,7 +360,7 @@ void sym_ShiftCurrentMacroArgs(void)
|
|||||||
int32_t i;
|
int32_t i;
|
||||||
|
|
||||||
free(currentmacroargs[0]);
|
free(currentmacroargs[0]);
|
||||||
for (i = 0; i < MAXMACROARGS - 1; i += 1)
|
for (i = 0; i < MAXMACROARGS - 1; i++)
|
||||||
currentmacroargs[i] = currentmacroargs[i + 1];
|
currentmacroargs[i] = currentmacroargs[i + 1];
|
||||||
|
|
||||||
currentmacroargs[MAXMACROARGS - 1] = NULL;
|
currentmacroargs[MAXMACROARGS - 1] = NULL;
|
||||||
@@ -471,7 +383,8 @@ void sym_UseNewMacroArgs(void)
|
|||||||
{
|
{
|
||||||
int32_t i;
|
int32_t i;
|
||||||
|
|
||||||
for (i = 0; i <= MAXMACROARGS; i += 1) {
|
for (i = 0; i <= MAXMACROARGS; i++) {
|
||||||
|
free(currentmacroargs[i]);
|
||||||
currentmacroargs[i] = newmacroargs[i];
|
currentmacroargs[i] = newmacroargs[i];
|
||||||
newmacroargs[i] = NULL;
|
newmacroargs[i] = NULL;
|
||||||
}
|
}
|
||||||
@@ -481,25 +394,19 @@ void sym_SaveCurrentMacroArgs(char *save[])
|
|||||||
{
|
{
|
||||||
int32_t i;
|
int32_t i;
|
||||||
|
|
||||||
for (i = 0; i <= MAXMACROARGS; i += 1)
|
for (i = 0; i <= MAXMACROARGS; i++) {
|
||||||
save[i] = currentmacroargs[i];
|
save[i] = currentmacroargs[i];
|
||||||
|
currentmacroargs[i] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sym_RestoreCurrentMacroArgs(char *save[])
|
void sym_RestoreCurrentMacroArgs(char *save[])
|
||||||
{
|
{
|
||||||
int32_t i;
|
int32_t i;
|
||||||
|
|
||||||
for (i = 0; i <= MAXMACROARGS; i += 1)
|
for (i = 0; i <= MAXMACROARGS; i++) {
|
||||||
currentmacroargs[i] = save[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void sym_FreeCurrentMacroArgs(void)
|
|
||||||
{
|
|
||||||
int32_t i;
|
|
||||||
|
|
||||||
for (i = 0; i <= MAXMACROARGS; i += 1) {
|
|
||||||
free(currentmacroargs[i]);
|
free(currentmacroargs[i]);
|
||||||
currentmacroargs[i] = NULL;
|
currentmacroargs[i] = save[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,7 +415,7 @@ void sym_AddNewMacroArg(char *s)
|
|||||||
int32_t i = 0;
|
int32_t i = 0;
|
||||||
|
|
||||||
while (i < MAXMACROARGS && newmacroargs[i] != NULL)
|
while (i < MAXMACROARGS && newmacroargs[i] != NULL)
|
||||||
i += 1;
|
i++;
|
||||||
|
|
||||||
if (i < MAXMACROARGS) {
|
if (i < MAXMACROARGS) {
|
||||||
if (s)
|
if (s)
|
||||||
@@ -524,7 +431,7 @@ void sym_SetMacroArgID(uint32_t nMacroCount)
|
|||||||
{
|
{
|
||||||
char s[256];
|
char s[256];
|
||||||
|
|
||||||
snprintf(s, sizeof(s), "_%u", nMacroCount);
|
snprintf(s, sizeof(s) - 1, "_%u", nMacroCount);
|
||||||
newmacroargs[MAXMACROARGS] = strdup(s);
|
newmacroargs[MAXMACROARGS] = strdup(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,7 +439,7 @@ void sym_UseCurrentMacroArgs(void)
|
|||||||
{
|
{
|
||||||
int32_t i;
|
int32_t i;
|
||||||
|
|
||||||
for (i = 1; i <= MAXMACROARGS; i += 1)
|
for (i = 1; i <= MAXMACROARGS; i++)
|
||||||
sym_AddNewMacroArg(sym_FindMacroArg(i));
|
sym_AddNewMacroArg(sym_FindMacroArg(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,23 +452,36 @@ struct sSymbol *sym_FindMacro(char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add an equated symbol
|
* Create a symbol that will be non-relocatable and ensure that it
|
||||||
|
* hasn't already been defined or referenced in a context that would
|
||||||
|
* require that it be relocatable
|
||||||
*/
|
*/
|
||||||
void sym_AddEqu(char *tzSym, int32_t value)
|
static struct sSymbol *createNonrelocSymbol(char *tzSym)
|
||||||
{
|
{
|
||||||
if ((nPass == 1) || ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
|
|
||||||
/* only add equated symbols in pass 1 */
|
|
||||||
struct sSymbol *nsym = findsymbol(tzSym, NULL);
|
struct sSymbol *nsym = findsymbol(tzSym, NULL);
|
||||||
|
|
||||||
if (nsym != NULL) {
|
if (nsym != NULL) {
|
||||||
if (nsym->nType & SYMF_DEFINED) {
|
if (nsym->nType & SYMF_DEFINED) {
|
||||||
yyerror("'%s' already defined in %s(%d)", tzSym,
|
yyerror("'%s' already defined at %s(%u)",
|
||||||
nsym->tzFileName, nsym->nFileLine);
|
tzSym, nsym->tzFileName, nsym->nFileLine);
|
||||||
|
} else if (nsym->nType & SYMF_REF) {
|
||||||
|
yyerror("'%s' already referenced at %s(%u)",
|
||||||
|
tzSym, nsym->tzFileName, nsym->nFileLine);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nsym = createsymbol(tzSym);
|
nsym = createsymbol(tzSym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nsym;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add an equated symbol
|
||||||
|
*/
|
||||||
|
void sym_AddEqu(char *tzSym, int32_t value)
|
||||||
|
{
|
||||||
|
struct sSymbol *nsym = createNonrelocSymbol(tzSym);
|
||||||
|
|
||||||
if (nsym) {
|
if (nsym) {
|
||||||
nsym->nValue = value;
|
nsym->nValue = value;
|
||||||
nsym->nType |= SYMF_EQU | SYMF_DEFINED | SYMF_CONST;
|
nsym->nType |= SYMF_EQU | SYMF_DEFINED | SYMF_CONST;
|
||||||
@@ -569,7 +489,6 @@ void sym_AddEqu(char *tzSym, int32_t value)
|
|||||||
updateSymbolFilename(nsym);
|
updateSymbolFilename(nsym);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a string equated symbol.
|
* Add a string equated symbol.
|
||||||
@@ -585,16 +504,7 @@ void sym_AddEqu(char *tzSym, int32_t value)
|
|||||||
*/
|
*/
|
||||||
void sym_AddString(char *tzSym, char *tzValue)
|
void sym_AddString(char *tzSym, char *tzValue)
|
||||||
{
|
{
|
||||||
struct sSymbol *nsym = findsymbol(tzSym, NULL);
|
struct sSymbol *nsym = createNonrelocSymbol(tzSym);
|
||||||
|
|
||||||
if (nsym != NULL) {
|
|
||||||
if (nsym->nType & SYMF_DEFINED) {
|
|
||||||
yyerror("'%s' already defined in %s(%d)",
|
|
||||||
tzSym, nsym->tzFileName, nsym->nFileLine);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nsym = createsymbol(tzSym);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nsym) {
|
if (nsym) {
|
||||||
nsym->pMacro = malloc(strlen(tzValue) + 1);
|
nsym->pMacro = malloc(strlen(tzValue) + 1);
|
||||||
@@ -617,11 +527,7 @@ uint32_t sym_isString(char *tzSym)
|
|||||||
{
|
{
|
||||||
const struct sSymbol *pSym = findsymbol(tzSym, NULL);
|
const struct sSymbol *pSym = findsymbol(tzSym, NULL);
|
||||||
|
|
||||||
if (pSym != NULL) {
|
return (pSym && (pSym->nType & SYMF_STRING));
|
||||||
if (pSym->nType & SYMF_STRING)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -631,8 +537,25 @@ void sym_AddSet(char *tzSym, int32_t value)
|
|||||||
{
|
{
|
||||||
struct sSymbol *nsym = findsymbol(tzSym, NULL);
|
struct sSymbol *nsym = findsymbol(tzSym, NULL);
|
||||||
|
|
||||||
if (nsym == NULL) {
|
if (nsym != NULL) {
|
||||||
/* Symbol hasn been found, create */
|
if (nsym->nType & SYMF_DEFINED) {
|
||||||
|
if (!(nsym->nType & SYMF_CONST))
|
||||||
|
yyerror("'%s' already defined as non-constant at %s(%u)",
|
||||||
|
tzSym,
|
||||||
|
nsym->tzFileName,
|
||||||
|
nsym->nFileLine);
|
||||||
|
else if (!(nsym->nType & SYMF_SET))
|
||||||
|
yyerror("'%s' already defined as constant at %s(%u)",
|
||||||
|
tzSym,
|
||||||
|
nsym->tzFileName,
|
||||||
|
nsym->nFileLine);
|
||||||
|
} else if (nsym->nType & SYMF_REF) {
|
||||||
|
yyerror("'%s' already referenced at %s(%u)",
|
||||||
|
tzSym,
|
||||||
|
nsym->tzFileName,
|
||||||
|
nsym->nFileLine);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
nsym = createsymbol(tzSym);
|
nsym = createsymbol(tzSym);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,9 +573,6 @@ void sym_AddSet(char *tzSym, int32_t value)
|
|||||||
void sym_AddLocalReloc(char *tzSym)
|
void sym_AddLocalReloc(char *tzSym)
|
||||||
{
|
{
|
||||||
if (pScope) {
|
if (pScope) {
|
||||||
if (strlen(tzSym) + strlen(pScope->tzName) > MAXSYMLEN)
|
|
||||||
fatalerror("Symbol too long");
|
|
||||||
|
|
||||||
char fullname[MAXSYMLEN + 1];
|
char fullname[MAXSYMLEN + 1];
|
||||||
|
|
||||||
fullSymbolName(fullname, sizeof(fullname), tzSym, pScope);
|
fullSymbolName(fullname, sizeof(fullname), tzSym, pScope);
|
||||||
@@ -669,10 +589,6 @@ void sym_AddLocalReloc(char *tzSym)
|
|||||||
void sym_AddReloc(char *tzSym)
|
void sym_AddReloc(char *tzSym)
|
||||||
{
|
{
|
||||||
struct sSymbol *scope = NULL;
|
struct sSymbol *scope = NULL;
|
||||||
|
|
||||||
if ((nPass == 1)
|
|
||||||
|| ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
|
|
||||||
/* only add reloc symbols in pass 1 */
|
|
||||||
struct sSymbol *nsym;
|
struct sSymbol *nsym;
|
||||||
char *localPtr = strchr(tzSym, '.');
|
char *localPtr = strchr(tzSym, '.');
|
||||||
|
|
||||||
@@ -721,7 +637,7 @@ void sym_AddReloc(char *tzSym)
|
|||||||
|
|
||||||
updateSymbolFilename(nsym);
|
updateSymbolFilename(nsym);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
pScope = findsymbol(tzSym, scope);
|
pScope = findsymbol(tzSym, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,10 +650,6 @@ void sym_AddReloc(char *tzSym)
|
|||||||
*/
|
*/
|
||||||
int32_t sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2)
|
int32_t sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2)
|
||||||
{
|
{
|
||||||
/* Do nothing the first pass. */
|
|
||||||
if (nPass != 2)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
const struct sSymbol *nsym1 = sym_FindSymbol(tzSym1);
|
const struct sSymbol *nsym1 = sym_FindSymbol(tzSym1);
|
||||||
const struct sSymbol *nsym2 = sym_FindSymbol(tzSym2);
|
const struct sSymbol *nsym2 = sym_FindSymbol(tzSym2);
|
||||||
|
|
||||||
@@ -781,8 +693,6 @@ int32_t sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2)
|
|||||||
*/
|
*/
|
||||||
void sym_Export(char *tzSym)
|
void sym_Export(char *tzSym)
|
||||||
{
|
{
|
||||||
if (nPass == 1) {
|
|
||||||
/* only export symbols in pass 1 */
|
|
||||||
struct sSymbol *nsym = sym_FindSymbol(tzSym);
|
struct sSymbol *nsym = sym_FindSymbol(tzSym);
|
||||||
|
|
||||||
if (nsym == NULL)
|
if (nsym == NULL)
|
||||||
@@ -790,139 +700,69 @@ void sym_Export(char *tzSym)
|
|||||||
|
|
||||||
if (nsym)
|
if (nsym)
|
||||||
nsym->nType |= SYMF_EXPORT;
|
nsym->nType |= SYMF_EXPORT;
|
||||||
} else {
|
|
||||||
const struct sSymbol *nsym = sym_FindSymbol(tzSym);
|
|
||||||
|
|
||||||
if (nsym != NULL) {
|
|
||||||
if (nsym->nType & SYMF_DEFINED)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
yyerror("'%s' not defined", tzSym);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Globalize a symbol (export if defined, import if not)
|
|
||||||
*/
|
|
||||||
void sym_Global(char *tzSym)
|
|
||||||
{
|
|
||||||
if (nPass == 2) {
|
|
||||||
/* only globalize symbols in pass 2 */
|
|
||||||
struct sSymbol *nsym = sym_FindSymbol(tzSym);
|
|
||||||
|
|
||||||
if ((nsym == NULL) || ((nsym->nType & SYMF_DEFINED) == 0)) {
|
|
||||||
if (nsym == NULL)
|
|
||||||
nsym = createsymbol(tzSym);
|
|
||||||
|
|
||||||
if (nsym)
|
|
||||||
nsym->nType |= SYMF_IMPORT;
|
|
||||||
} else {
|
|
||||||
if (nsym)
|
|
||||||
nsym->nType |= SYMF_EXPORT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a macro definition
|
* Add a macro definition
|
||||||
*/
|
*/
|
||||||
void sym_AddMacro(char *tzSym)
|
void sym_AddMacro(char *tzSym, int32_t nDefLineNo)
|
||||||
{
|
{
|
||||||
if ((nPass == 1) || ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
|
struct sSymbol *nsym = createNonrelocSymbol(tzSym);
|
||||||
/* only add macros in pass 1 */
|
|
||||||
struct sSymbol *nsym;
|
|
||||||
|
|
||||||
nsym = findsymbol(tzSym, NULL);
|
|
||||||
|
|
||||||
if (nsym != NULL) {
|
|
||||||
if (nsym->nType & SYMF_DEFINED) {
|
|
||||||
yyerror("'%s' already defined in %s(%d)",
|
|
||||||
tzSym, nsym->tzFileName,
|
|
||||||
nsym->nFileLine);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nsym = createsymbol(tzSym);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nsym) {
|
if (nsym) {
|
||||||
nsym->nValue = nPC;
|
|
||||||
nsym->nType |= SYMF_MACRO | SYMF_DEFINED;
|
nsym->nType |= SYMF_MACRO | SYMF_DEFINED;
|
||||||
nsym->pScope = NULL;
|
nsym->pScope = NULL;
|
||||||
nsym->ulMacroSize = ulNewMacroSize;
|
nsym->ulMacroSize = ulNewMacroSize;
|
||||||
nsym->pMacro = tzNewMacro;
|
nsym->pMacro = tzNewMacro;
|
||||||
updateSymbolFilename(nsym);
|
updateSymbolFilename(nsym);
|
||||||
}
|
/*
|
||||||
|
* The symbol is created at the line after the `endm`,
|
||||||
|
* override this with the actual definition line
|
||||||
|
*/
|
||||||
|
nsym->nFileLine = nDefLineNo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set whether to export all relocable symbols by default
|
* Flag that a symbol is referenced in an RPN expression
|
||||||
|
* and create it if it doesn't exist yet
|
||||||
|
*/
|
||||||
|
void sym_Ref(char *tzSym)
|
||||||
|
{
|
||||||
|
struct sSymbol *nsym = sym_FindSymbol(tzSym);
|
||||||
|
|
||||||
|
if (nsym == NULL) {
|
||||||
|
char fullname[MAXSYMLEN + 1];
|
||||||
|
int isLocal = 0;
|
||||||
|
|
||||||
|
if (*tzSym == '.') {
|
||||||
|
if (!pScope)
|
||||||
|
fatalerror("Local label reference '%s' in main scope",
|
||||||
|
tzSym);
|
||||||
|
fullSymbolName(fullname, sizeof(fullname), tzSym,
|
||||||
|
pScope);
|
||||||
|
tzSym = fullname;
|
||||||
|
isLocal = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsym = createsymbol(tzSym);
|
||||||
|
|
||||||
|
if (nsym && isLocal)
|
||||||
|
nsym->nType |= SYMF_LOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nsym)
|
||||||
|
nsym->nType |= SYMF_REF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set whether to export all relocatable symbols by default
|
||||||
*/
|
*/
|
||||||
void sym_SetExportAll(uint8_t set)
|
void sym_SetExportAll(uint8_t set)
|
||||||
{
|
{
|
||||||
exportall = set;
|
exportall = set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Prepare for pass #1
|
|
||||||
*/
|
|
||||||
void sym_PrepPass1(void)
|
|
||||||
{
|
|
||||||
sym_Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prepare for pass #2
|
|
||||||
*/
|
|
||||||
void sym_PrepPass2(void)
|
|
||||||
{
|
|
||||||
int32_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < HASHSIZE; i += 1) {
|
|
||||||
struct sSymbol **ppSym = &(tHashedSymbols[i]);
|
|
||||||
|
|
||||||
while (*ppSym) {
|
|
||||||
uint32_t mask = SYMF_SET | SYMF_STRING | SYMF_EQU;
|
|
||||||
|
|
||||||
if ((*ppSym)->nType & mask) {
|
|
||||||
struct sSymbol *pTemp;
|
|
||||||
|
|
||||||
pTemp = (*ppSym)->pNext;
|
|
||||||
free(*ppSym);
|
|
||||||
*ppSym = pTemp;
|
|
||||||
} else {
|
|
||||||
ppSym = &((*ppSym)->pNext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pScope = NULL;
|
|
||||||
pPCSymbol->nValue = 0;
|
|
||||||
|
|
||||||
sym_AddString("__TIME__", SavedTIME);
|
|
||||||
sym_AddString("__DATE__", SavedDATE);
|
|
||||||
sym_AddString("__ISO_8601_LOCAL__", SavedTIMESTAMP_ISO8601_LOCAL);
|
|
||||||
sym_AddString("__ISO_8601_UTC__", SavedTIMESTAMP_ISO8601_UTC);
|
|
||||||
sym_AddString("__UTC_DAY__", SavedDAY);
|
|
||||||
sym_AddString("__UTC_MONTH__", SavedMONTH);
|
|
||||||
sym_AddString("__UTC_YEAR__", SavedYEAR);
|
|
||||||
sym_AddString("__UTC_HOUR__", SavedHOUR);
|
|
||||||
sym_AddString("__UTC_MINUTE__", SavedMINUTE);
|
|
||||||
sym_AddString("__UTC_SECOND__", SavedSECOND);
|
|
||||||
sym_AddEqu("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR);
|
|
||||||
sym_AddEqu("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR);
|
|
||||||
sym_AddEqu("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH);
|
|
||||||
sym_AddSet("_RS", 0);
|
|
||||||
|
|
||||||
sym_AddEqu("_NARG", 0);
|
|
||||||
p_NARGSymbol = findsymbol("_NARG", NULL);
|
|
||||||
p_NARGSymbol->Callback = Callback_NARG;
|
|
||||||
sym_AddEqu("__LINE__", 0);
|
|
||||||
p__LINE__Symbol = findsymbol("__LINE__", NULL);
|
|
||||||
p__LINE__Symbol->Callback = Callback__LINE__;
|
|
||||||
|
|
||||||
math_DefinePI();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the symboltable
|
* Initialize the symboltable
|
||||||
*/
|
*/
|
||||||
@@ -931,12 +771,12 @@ void sym_Init(void)
|
|||||||
int32_t i;
|
int32_t i;
|
||||||
time_t now;
|
time_t now;
|
||||||
|
|
||||||
for (i = 0; i < MAXMACROARGS; i += 1) {
|
for (i = 0; i < MAXMACROARGS; i++) {
|
||||||
currentmacroargs[i] = NULL;
|
currentmacroargs[i] = NULL;
|
||||||
newmacroargs[i] = NULL;
|
newmacroargs[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < HASHSIZE; i += 1)
|
for (i = 0; i < HASHSIZE; i++)
|
||||||
tHashedSymbols[i] = NULL;
|
tHashedSymbols[i] = NULL;
|
||||||
|
|
||||||
sym_AddReloc("@");
|
sym_AddReloc("@");
|
||||||
|
|||||||
46
src/asm/util.c
Normal file
46
src/asm/util.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "asm/main.h"
|
||||||
|
#include "asm/util.h"
|
||||||
|
|
||||||
|
#include "extern/utf8decoder.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the hash value for a string
|
||||||
|
*/
|
||||||
|
uint32_t calchash(const char *s)
|
||||||
|
{
|
||||||
|
uint32_t hash = 5381;
|
||||||
|
|
||||||
|
while (*s != 0)
|
||||||
|
hash = (hash * 33) ^ (*s++);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t readUTF8Char(char *dest, char *src)
|
||||||
|
{
|
||||||
|
uint32_t state;
|
||||||
|
uint32_t codep;
|
||||||
|
int32_t i;
|
||||||
|
|
||||||
|
for (i = 0, state = 0;; i++) {
|
||||||
|
if (decode(&state, &codep, (uint8_t)src[i]) == 1)
|
||||||
|
fatalerror("invalid UTF-8 character");
|
||||||
|
|
||||||
|
dest[i] = src[i];
|
||||||
|
|
||||||
|
if (state == 0) {
|
||||||
|
dest[++i] = '\0';
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -268,10 +268,7 @@ int main(int argc, char *argv[])
|
|||||||
* characters may conflict with the title.
|
* characters may conflict with the title.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int n = snprintf((char *)header + 0x34, 16, "%s", title);
|
strncpy((char *)header + 0x34, title, 16);
|
||||||
|
|
||||||
for (int i = 16; i > n; i--)
|
|
||||||
header[0x34 + i] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setid) {
|
if (setid) {
|
||||||
|
|||||||
177
src/gfx/gb.c
177
src/gfx/gb.c
@@ -85,8 +85,87 @@ int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles, int tile_size)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_tilemap(const struct Options *opts, struct GBImage *gb,
|
uint8_t reverse_bits(uint8_t b)
|
||||||
struct Tilemap *tilemap)
|
{
|
||||||
|
uint8_t rev = 0;
|
||||||
|
|
||||||
|
rev |= (b & 0x80) >> 7;
|
||||||
|
rev |= (b & 0x40) >> 5;
|
||||||
|
rev |= (b & 0x20) >> 3;
|
||||||
|
rev |= (b & 0x10) >> 1;
|
||||||
|
rev |= (b & 0x08) << 1;
|
||||||
|
rev |= (b & 0x04) << 3;
|
||||||
|
rev |= (b & 0x02) << 5;
|
||||||
|
rev |= (b & 0x01) << 7;
|
||||||
|
return rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xflip(uint8_t *tile, uint8_t *tile_xflip, int tile_size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < tile_size; i++)
|
||||||
|
tile_xflip[i] = reverse_bits(tile[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void yflip(uint8_t *tile, uint8_t *tile_yflip, int tile_size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < tile_size; i++)
|
||||||
|
tile_yflip[i] = tile[(tile_size - i - 1) ^ (depth - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_mirrored_tile_index looks for `tile` in tile array `tiles`, also
|
||||||
|
* checking x-, y-, and xy-mirrored versions of `tile`. If one is found,
|
||||||
|
* `*flags` is set according to the type of mirroring and the index of the
|
||||||
|
* matched tile is returned. If no match is found, -1 is returned.
|
||||||
|
*/
|
||||||
|
int get_mirrored_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
|
||||||
|
int tile_size, int *flags)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
uint8_t *tile_xflip;
|
||||||
|
uint8_t *tile_yflip;
|
||||||
|
|
||||||
|
index = get_tile_index(tile, tiles, num_tiles, tile_size);
|
||||||
|
if (index >= 0) {
|
||||||
|
*flags = 0;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile_yflip = malloc(tile_size);
|
||||||
|
yflip(tile, tile_yflip, tile_size);
|
||||||
|
index = get_tile_index(tile_yflip, tiles, num_tiles, tile_size);
|
||||||
|
if (index >= 0) {
|
||||||
|
*flags = YFLIP;
|
||||||
|
free(tile_yflip);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile_xflip = malloc(tile_size);
|
||||||
|
xflip(tile, tile_xflip, tile_size);
|
||||||
|
index = get_tile_index(tile_xflip, tiles, num_tiles, tile_size);
|
||||||
|
if (index >= 0) {
|
||||||
|
*flags = XFLIP;
|
||||||
|
free(tile_yflip);
|
||||||
|
free(tile_xflip);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
yflip(tile_xflip, tile_yflip, tile_size);
|
||||||
|
index = get_tile_index(tile_yflip, tiles, num_tiles, tile_size);
|
||||||
|
if (index >= 0)
|
||||||
|
*flags = XFLIP | YFLIP;
|
||||||
|
|
||||||
|
free(tile_yflip);
|
||||||
|
free(tile_xflip);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_mapfiles(const struct Options *opts, struct GBImage *gb,
|
||||||
|
struct Mapfile *tilemap, struct Mapfile *attrmap)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
int gb_i;
|
int gb_i;
|
||||||
@@ -94,6 +173,7 @@ void create_tilemap(const struct Options *opts, struct GBImage *gb,
|
|||||||
int max_tiles;
|
int max_tiles;
|
||||||
int num_tiles;
|
int num_tiles;
|
||||||
int index;
|
int index;
|
||||||
|
int flags;
|
||||||
int gb_size;
|
int gb_size;
|
||||||
uint8_t *tile;
|
uint8_t *tile;
|
||||||
uint8_t **tiles;
|
uint8_t **tiles;
|
||||||
@@ -109,19 +189,33 @@ void create_tilemap(const struct Options *opts, struct GBImage *gb,
|
|||||||
tiles = calloc(max_tiles, sizeof(uint8_t *));
|
tiles = calloc(max_tiles, sizeof(uint8_t *));
|
||||||
num_tiles = 0;
|
num_tiles = 0;
|
||||||
|
|
||||||
|
if (*opts->tilemapfile) {
|
||||||
tilemap->data = calloc(max_tiles, sizeof(uint8_t));
|
tilemap->data = calloc(max_tiles, sizeof(uint8_t));
|
||||||
tilemap->size = 0;
|
tilemap->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*opts->attrmapfile) {
|
||||||
|
attrmap->data = calloc(max_tiles, sizeof(uint8_t));
|
||||||
|
attrmap->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gb_i = 0;
|
gb_i = 0;
|
||||||
while (gb_i < gb_size) {
|
while (gb_i < gb_size) {
|
||||||
|
flags = 0;
|
||||||
tile = malloc(tile_size);
|
tile = malloc(tile_size);
|
||||||
for (i = 0; i < tile_size; i++) {
|
for (i = 0; i < tile_size; i++) {
|
||||||
tile[i] = gb->data[gb_i];
|
tile[i] = gb->data[gb_i];
|
||||||
gb_i++;
|
gb_i++;
|
||||||
}
|
}
|
||||||
if (opts->unique) {
|
if (opts->unique) {
|
||||||
|
if (opts->mirror) {
|
||||||
|
index = get_mirrored_tile_index(tile, tiles, num_tiles,
|
||||||
|
tile_size, &flags);
|
||||||
|
} else {
|
||||||
index = get_tile_index(tile, tiles, num_tiles,
|
index = get_tile_index(tile, tiles, num_tiles,
|
||||||
tile_size);
|
tile_size);
|
||||||
|
}
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
index = num_tiles;
|
index = num_tiles;
|
||||||
tiles[num_tiles] = tile;
|
tiles[num_tiles] = tile;
|
||||||
@@ -132,9 +226,15 @@ void create_tilemap(const struct Options *opts, struct GBImage *gb,
|
|||||||
tiles[num_tiles] = tile;
|
tiles[num_tiles] = tile;
|
||||||
num_tiles++;
|
num_tiles++;
|
||||||
}
|
}
|
||||||
|
if (*opts->tilemapfile) {
|
||||||
tilemap->data[tilemap->size] = index;
|
tilemap->data[tilemap->size] = index;
|
||||||
tilemap->size++;
|
tilemap->size++;
|
||||||
}
|
}
|
||||||
|
if (*opts->attrmapfile) {
|
||||||
|
attrmap->data[attrmap->size] = flags;
|
||||||
|
attrmap->size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (opts->unique) {
|
if (opts->unique) {
|
||||||
free(gb->data);
|
free(gb->data);
|
||||||
@@ -154,21 +254,61 @@ void create_tilemap(const struct Options *opts, struct GBImage *gb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void output_tilemap_file(const struct Options *opts,
|
void output_tilemap_file(const struct Options *opts,
|
||||||
const struct Tilemap *tilemap)
|
const struct Mapfile *tilemap)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
f = fopen(opts->mapfile, "wb");
|
f = fopen(opts->tilemapfile, "wb");
|
||||||
if (!f)
|
if (!f)
|
||||||
err(1, "Opening tilemap file '%s' failed", opts->mapfile);
|
err(1, "Opening tilemap file '%s' failed", opts->tilemapfile);
|
||||||
|
|
||||||
fwrite(tilemap->data, 1, tilemap->size, f);
|
fwrite(tilemap->data, 1, tilemap->size, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
if (opts->mapout)
|
if (opts->tilemapout)
|
||||||
free(opts->mapfile);
|
free(opts->tilemapfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void output_attrmap_file(const struct Options *opts,
|
||||||
|
const struct Mapfile *attrmap)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
f = fopen(opts->attrmapfile, "wb");
|
||||||
|
if (!f)
|
||||||
|
err(1, "Opening attrmap file '%s' failed", opts->attrmapfile);
|
||||||
|
|
||||||
|
fwrite(attrmap->data, 1, attrmap->size, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (opts->attrmapout)
|
||||||
|
free(opts->attrmapfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* based on the Gaussian-like curve used by SameBoy since commit
|
||||||
|
* 65dd02cc52f531dbbd3a7e6014e99d5b24e71a4c (Oct 2017)
|
||||||
|
* with ties resolved by comparing the difference of the squares.
|
||||||
|
*/
|
||||||
|
static int reverse_curve[] = {
|
||||||
|
0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4,
|
||||||
|
5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
|
||||||
|
10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||||
|
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
|
||||||
|
13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||||
|
14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||||
|
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17,
|
||||||
|
17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18,
|
||||||
|
18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||||
|
19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21,
|
||||||
|
21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||||
|
22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24,
|
||||||
|
24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
|
||||||
|
26, 27, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 30, 30, 31,
|
||||||
|
};
|
||||||
|
|
||||||
void output_palette_file(const struct Options *opts,
|
void output_palette_file(const struct Options *opts,
|
||||||
const struct RawIndexedImage *raw_image)
|
const struct RawIndexedImage *raw_image)
|
||||||
{
|
{
|
||||||
@@ -181,10 +321,25 @@ void output_palette_file(const struct Options *opts,
|
|||||||
err(1, "Opening palette file '%s' failed", opts->palfile);
|
err(1, "Opening palette file '%s' failed", opts->palfile);
|
||||||
|
|
||||||
for (i = 0; i < raw_image->num_colors; i++) {
|
for (i = 0; i < raw_image->num_colors; i++) {
|
||||||
color =
|
int r = raw_image->palette[i].red;
|
||||||
raw_image->palette[i].blue >> 3 << 10 |
|
int g = raw_image->palette[i].green;
|
||||||
raw_image->palette[i].green >> 3 << 5 |
|
int b = raw_image->palette[i].blue;
|
||||||
raw_image->palette[i].red >> 3;
|
|
||||||
|
if (opts->colorcurve) {
|
||||||
|
g = (g * 4 - b) / 3;
|
||||||
|
if (g < 0)
|
||||||
|
g = 0;
|
||||||
|
|
||||||
|
r = reverse_curve[r];
|
||||||
|
g = reverse_curve[g];
|
||||||
|
b = reverse_curve[b];
|
||||||
|
} else {
|
||||||
|
r >>= 3;
|
||||||
|
g >>= 3;
|
||||||
|
b >>= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
color = b << 10 | g << 5 | r;
|
||||||
cur_bytes[0] = color & 0xFF;
|
cur_bytes[0] = color & 0xFF;
|
||||||
cur_bytes[1] = color >> 8;
|
cur_bytes[1] = color >> 8;
|
||||||
fwrite(cur_bytes, 2, 1, f);
|
fwrite(cur_bytes, 2, 1, f);
|
||||||
|
|||||||
109
src/gfx/main.c
109
src/gfx/main.c
@@ -18,8 +18,8 @@
|
|||||||
static void print_usage(void)
|
static void print_usage(void)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
"usage: rgbgfx [-DFfhPTuVv] [-d #] [-o outfile] [-p palfile] [-t mapfile]\n"
|
"usage: rgbgfx [-ADFfhmPTuVv] [-o outfile] [-a attrmap] [-d #] [-p palfile]\n"
|
||||||
" [-x #] infile\n");
|
" [-t tilemap] [-x #] infile\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,21 +30,32 @@ int main(int argc, char *argv[])
|
|||||||
struct ImageOptions png_options = {0};
|
struct ImageOptions png_options = {0};
|
||||||
struct RawIndexedImage *raw_image;
|
struct RawIndexedImage *raw_image;
|
||||||
struct GBImage gb = {0};
|
struct GBImage gb = {0};
|
||||||
struct Tilemap tilemap = {0};
|
struct Mapfile tilemap = {0};
|
||||||
|
struct Mapfile attrmap = {0};
|
||||||
char *ext;
|
char *ext;
|
||||||
const char *errmsg = "Warning: The PNG's %s setting is not the same as the setting defined on the command line.";
|
const char *errmsg = "Warning: The PNG's %s setting is not the same as the setting defined on the command line.";
|
||||||
|
|
||||||
if (argc == 1)
|
if (argc == 1)
|
||||||
print_usage();
|
print_usage();
|
||||||
|
|
||||||
opts.mapfile = "";
|
opts.tilemapfile = "";
|
||||||
|
opts.attrmapfile = "";
|
||||||
opts.palfile = "";
|
opts.palfile = "";
|
||||||
opts.outfile = "";
|
opts.outfile = "";
|
||||||
|
|
||||||
depth = 2;
|
depth = 2;
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "Dd:Ffho:Tt:uPp:Vvx:")) != -1) {
|
while ((ch = getopt(argc, argv, "Aa:CDd:Ffhmo:Tt:uPp:Vvx:")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
|
case 'A':
|
||||||
|
opts.attrmapout = true;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
opts.attrmapfile = optarg;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
opts.colorcurve = true;
|
||||||
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
opts.debug = true;
|
opts.debug = true;
|
||||||
break;
|
break;
|
||||||
@@ -60,6 +71,10 @@ int main(int argc, char *argv[])
|
|||||||
case 'h':
|
case 'h':
|
||||||
opts.horizontal = true;
|
opts.horizontal = true;
|
||||||
break;
|
break;
|
||||||
|
case 'm':
|
||||||
|
opts.mirror = true;
|
||||||
|
opts.unique = true;
|
||||||
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
opts.outfile = optarg;
|
opts.outfile = optarg;
|
||||||
break;
|
break;
|
||||||
@@ -70,10 +85,10 @@ int main(int argc, char *argv[])
|
|||||||
opts.palfile = optarg;
|
opts.palfile = optarg;
|
||||||
break;
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
opts.mapout = true;
|
opts.tilemapout = true;
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
opts.mapfile = optarg;
|
opts.tilemapfile = optarg;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
opts.unique = true;
|
opts.unique = true;
|
||||||
@@ -107,7 +122,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
raw_image = input_png_file(&opts, &png_options);
|
raw_image = input_png_file(&opts, &png_options);
|
||||||
|
|
||||||
png_options.mapfile = "";
|
png_options.tilemapfile = "";
|
||||||
|
png_options.attrmapfile = "";
|
||||||
png_options.palfile = "";
|
png_options.palfile = "";
|
||||||
|
|
||||||
if (png_options.horizontal != opts.horizontal) {
|
if (png_options.horizontal != opts.horizontal) {
|
||||||
@@ -148,25 +164,45 @@ int main(int argc, char *argv[])
|
|||||||
(raw_image->width / 8) * (raw_image->height / 8) - 1);
|
(raw_image->width / 8) * (raw_image->height / 8) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(png_options.mapfile, opts.mapfile) != 0) {
|
if (strcmp(png_options.tilemapfile, opts.tilemapfile) != 0) {
|
||||||
if (opts.verbose)
|
if (opts.verbose)
|
||||||
warnx(errmsg, "tilemap file");
|
warnx(errmsg, "tilemap file");
|
||||||
|
|
||||||
if (opts.hardfix)
|
if (opts.hardfix)
|
||||||
png_options.mapfile = opts.mapfile;
|
png_options.tilemapfile = opts.tilemapfile;
|
||||||
}
|
}
|
||||||
if (!*opts.mapfile)
|
if (!*opts.tilemapfile)
|
||||||
opts.mapfile = png_options.mapfile;
|
opts.tilemapfile = png_options.tilemapfile;
|
||||||
|
|
||||||
if (png_options.mapout != opts.mapout) {
|
if (png_options.tilemapout != opts.tilemapout) {
|
||||||
if (opts.verbose)
|
if (opts.verbose)
|
||||||
warnx(errmsg, "tilemap file");
|
warnx(errmsg, "tilemap file");
|
||||||
|
|
||||||
if (opts.hardfix)
|
if (opts.hardfix)
|
||||||
png_options.mapout = opts.mapout;
|
png_options.tilemapout = opts.tilemapout;
|
||||||
}
|
}
|
||||||
if (png_options.mapout)
|
if (png_options.tilemapout)
|
||||||
opts.mapout = png_options.mapout;
|
opts.tilemapout = png_options.tilemapout;
|
||||||
|
|
||||||
|
if (strcmp(png_options.attrmapfile, opts.attrmapfile) != 0) {
|
||||||
|
if (opts.verbose)
|
||||||
|
warnx(errmsg, "attrmap file");
|
||||||
|
|
||||||
|
if (opts.hardfix)
|
||||||
|
png_options.attrmapfile = opts.attrmapfile;
|
||||||
|
}
|
||||||
|
if (!*opts.attrmapfile)
|
||||||
|
opts.attrmapfile = png_options.attrmapfile;
|
||||||
|
|
||||||
|
if (png_options.attrmapout != opts.attrmapout) {
|
||||||
|
if (opts.verbose)
|
||||||
|
warnx(errmsg, "attrmap file");
|
||||||
|
|
||||||
|
if (opts.hardfix)
|
||||||
|
png_options.attrmapout = opts.attrmapout;
|
||||||
|
}
|
||||||
|
if (png_options.attrmapout)
|
||||||
|
opts.attrmapout = png_options.attrmapout;
|
||||||
|
|
||||||
if (strcmp(png_options.palfile, opts.palfile) != 0) {
|
if (strcmp(png_options.palfile, opts.palfile) != 0) {
|
||||||
if (opts.verbose)
|
if (opts.verbose)
|
||||||
@@ -189,19 +225,35 @@ int main(int argc, char *argv[])
|
|||||||
if (png_options.palout)
|
if (png_options.palout)
|
||||||
opts.palout = png_options.palout;
|
opts.palout = png_options.palout;
|
||||||
|
|
||||||
if (!*opts.mapfile && opts.mapout) {
|
if (!*opts.tilemapfile && opts.tilemapout) {
|
||||||
ext = strrchr(opts.infile, '.');
|
ext = strrchr(opts.infile, '.');
|
||||||
|
|
||||||
if (ext != NULL) {
|
if (ext != NULL) {
|
||||||
size = ext - opts.infile + 9;
|
size = ext - opts.infile + 9;
|
||||||
opts.mapfile = malloc(size);
|
opts.tilemapfile = malloc(size);
|
||||||
strncpy(opts.mapfile, opts.infile, size);
|
strncpy(opts.tilemapfile, opts.infile, size);
|
||||||
*strrchr(opts.mapfile, '.') = '\0';
|
*strrchr(opts.tilemapfile, '.') = '\0';
|
||||||
strcat(opts.mapfile, ".tilemap");
|
strcat(opts.tilemapfile, ".tilemap");
|
||||||
} else {
|
} else {
|
||||||
opts.mapfile = malloc(strlen(opts.infile) + 9);
|
opts.tilemapfile = malloc(strlen(opts.infile) + 9);
|
||||||
strcpy(opts.mapfile, opts.infile);
|
strcpy(opts.tilemapfile, opts.infile);
|
||||||
strcat(opts.mapfile, ".tilemap");
|
strcat(opts.tilemapfile, ".tilemap");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*opts.attrmapfile && opts.attrmapout) {
|
||||||
|
ext = strrchr(opts.infile, '.');
|
||||||
|
|
||||||
|
if (ext != NULL) {
|
||||||
|
size = ext - opts.infile + 9;
|
||||||
|
opts.attrmapfile = malloc(size);
|
||||||
|
strncpy(opts.attrmapfile, opts.infile, size);
|
||||||
|
*strrchr(opts.attrmapfile, '.') = '\0';
|
||||||
|
strcat(opts.attrmapfile, ".attrmap");
|
||||||
|
} else {
|
||||||
|
opts.attrmapfile = malloc(strlen(opts.infile) + 9);
|
||||||
|
strcpy(opts.attrmapfile, opts.infile);
|
||||||
|
strcat(opts.attrmapfile, ".attrmap");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,17 +278,20 @@ int main(int argc, char *argv[])
|
|||||||
gb.trim = opts.trim;
|
gb.trim = opts.trim;
|
||||||
gb.horizontal = opts.horizontal;
|
gb.horizontal = opts.horizontal;
|
||||||
|
|
||||||
if (*opts.outfile || *opts.mapfile) {
|
if (*opts.outfile || *opts.tilemapfile || *opts.attrmapfile) {
|
||||||
raw_to_gb(raw_image, &gb);
|
raw_to_gb(raw_image, &gb);
|
||||||
create_tilemap(&opts, &gb, &tilemap);
|
create_mapfiles(&opts, &gb, &tilemap, &attrmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*opts.outfile)
|
if (*opts.outfile)
|
||||||
output_file(&opts, &gb);
|
output_file(&opts, &gb);
|
||||||
|
|
||||||
if (*opts.mapfile)
|
if (*opts.tilemapfile)
|
||||||
output_tilemap_file(&opts, &tilemap);
|
output_tilemap_file(&opts, &tilemap);
|
||||||
|
|
||||||
|
if (*opts.attrmapfile)
|
||||||
|
output_attrmap_file(&opts, &attrmap);
|
||||||
|
|
||||||
if (*opts.palfile)
|
if (*opts.palfile)
|
||||||
output_palette_file(&opts, raw_image);
|
output_palette_file(&opts, raw_image);
|
||||||
|
|
||||||
|
|||||||
@@ -199,8 +199,8 @@ static struct RawIndexedImage *indexed_png_to_raw(struct PNGImage *img)
|
|||||||
raw_image = create_raw_image(img->width, img->height, colors);
|
raw_image = create_raw_image(img->width, img->height, colors);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Transparent palette entries are removed, and the palette is collapsed.
|
* Transparent palette entries are removed, and the palette is
|
||||||
* Transparent pixels are then replaced with palette index 0.
|
* collapsed. Transparent pixels are then replaced with palette index 0.
|
||||||
* This way, an indexed PNG can contain transparent pixels in *addition*
|
* This way, an indexed PNG can contain transparent pixels in *addition*
|
||||||
* to 4 normal colors.
|
* to 4 normal colors.
|
||||||
*/
|
*/
|
||||||
@@ -649,10 +649,16 @@ static void get_text(const struct PNGImage *img,
|
|||||||
png_options->trim = strtoul(text[i].text, NULL, 0);
|
png_options->trim = strtoul(text[i].text, NULL, 0);
|
||||||
png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
|
png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
|
||||||
} else if (strcmp(text[i].key, "t") == 0) {
|
} else if (strcmp(text[i].key, "t") == 0) {
|
||||||
png_options->mapfile = text[i].text;
|
png_options->tilemapfile = text[i].text;
|
||||||
png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
|
png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
|
||||||
} else if (strcmp(text[i].key, "T") == 0 && !*text[i].text) {
|
} else if (strcmp(text[i].key, "T") == 0 && !*text[i].text) {
|
||||||
png_options->mapout = true;
|
png_options->tilemapout = true;
|
||||||
|
png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
|
||||||
|
} else if (strcmp(text[i].key, "a") == 0) {
|
||||||
|
png_options->attrmapfile = text[i].text;
|
||||||
|
png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
|
||||||
|
} else if (strcmp(text[i].key, "A") == 0 && !*text[i].text) {
|
||||||
|
png_options->attrmapout = true;
|
||||||
png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
|
png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
|
||||||
} else if (strcmp(text[i].key, "p") == 0) {
|
} else if (strcmp(text[i].key, "p") == 0) {
|
||||||
png_options->palfile = text[i].text;
|
png_options->palfile = text[i].text;
|
||||||
@@ -699,18 +705,30 @@ static void set_text(const struct PNGImage *img,
|
|||||||
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
|
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||||
png_set_text(img->png, img->info, text, 1);
|
png_set_text(img->png, img->info, text, 1);
|
||||||
}
|
}
|
||||||
if (*png_options->mapfile) {
|
if (*png_options->tilemapfile) {
|
||||||
text[0].key = "t";
|
text[0].key = "t";
|
||||||
text[0].text = "";
|
text[0].text = "";
|
||||||
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
|
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||||
png_set_text(img->png, img->info, text, 1);
|
png_set_text(img->png, img->info, text, 1);
|
||||||
}
|
}
|
||||||
if (png_options->mapout) {
|
if (png_options->tilemapout) {
|
||||||
text[0].key = "T";
|
text[0].key = "T";
|
||||||
text[0].text = "";
|
text[0].text = "";
|
||||||
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
|
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||||
png_set_text(img->png, img->info, text, 1);
|
png_set_text(img->png, img->info, text, 1);
|
||||||
}
|
}
|
||||||
|
if (*png_options->attrmapfile) {
|
||||||
|
text[0].key = "a";
|
||||||
|
text[0].text = "";
|
||||||
|
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||||
|
png_set_text(img->png, img->info, text, 1);
|
||||||
|
}
|
||||||
|
if (png_options->attrmapout) {
|
||||||
|
text[0].key = "A";
|
||||||
|
text[0].text = "";
|
||||||
|
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||||
|
png_set_text(img->png, img->info, text, 1);
|
||||||
|
}
|
||||||
if (*png_options->palfile) {
|
if (*png_options->palfile) {
|
||||||
text[0].key = "p";
|
text[0].key = "p";
|
||||||
text[0].text = "";
|
text[0].text = "";
|
||||||
|
|||||||
@@ -13,11 +13,12 @@
|
|||||||
.Nd Game Boy graphics converter
|
.Nd Game Boy graphics converter
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm rgbgfx
|
.Nm rgbgfx
|
||||||
.Op Fl DfFhPTVv
|
.Op Fl ADfFhmPTuVv
|
||||||
.Op Fl o Ar outfile
|
.Op Fl o Ar outfile
|
||||||
|
.Op Fl a Ar attrmap
|
||||||
.Op Fl d Ar depth
|
.Op Fl d Ar depth
|
||||||
.Op Fl p Ar palfile
|
.Op Fl p Ar palfile
|
||||||
.Op Fl t Ar mapfile
|
.Op Fl t Ar tilemap
|
||||||
.Op Fl x Ar tiles
|
.Op Fl x Ar tiles
|
||||||
.Ar file
|
.Ar file
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
@@ -47,6 +48,21 @@ The input image may not contain more colors than the selected bit depth
|
|||||||
allows. Transparent pixels are set to palette index 0.
|
allows. Transparent pixels are set to palette index 0.
|
||||||
.Sh ARGUMENTS
|
.Sh ARGUMENTS
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
|
.It Fl a Ar attrmap
|
||||||
|
Generate a file of tile mirroring attributes for OAM or (CGB-only) background
|
||||||
|
tiles. For each tile in the input file, a byte is written representing the
|
||||||
|
dimensions that the associated tile in the output file should be mirrored.
|
||||||
|
Useful in combination with
|
||||||
|
.Fl m
|
||||||
|
to keep track the mirror direction of mirrored duplicate tiles.
|
||||||
|
.It Fl A
|
||||||
|
Same as
|
||||||
|
.Fl a ,
|
||||||
|
but the attrmap file output name is made by taking the input filename, removing
|
||||||
|
the file extension, and appending
|
||||||
|
.Pa .attrmap .
|
||||||
|
.It Fl C
|
||||||
|
Use the color curve of the Game Boy Color when generating palettes.
|
||||||
.It Fl D
|
.It Fl D
|
||||||
Debug features are enabled.
|
Debug features are enabled.
|
||||||
.It Fl f
|
.It Fl f
|
||||||
@@ -61,6 +77,12 @@ The bit depth of the output image (either 1 or 2).
|
|||||||
By default, the bit depth is 2 (two bits per pixel).
|
By default, the bit depth is 2 (two bits per pixel).
|
||||||
.It Fl h
|
.It Fl h
|
||||||
Lay out tiles horizontally rather than vertically.
|
Lay out tiles horizontally rather than vertically.
|
||||||
|
.It Fl m
|
||||||
|
Truncate tiles by checking for tiles that are mirrored versions of others and
|
||||||
|
omitting these from the output file. Useful with tilemaps and attrmaps together
|
||||||
|
to keep track of the duplicated tiles and the dimension mirrored. Tiles are
|
||||||
|
checked for horizontal, vertical, and horizontal-vertical mirroring. Implies
|
||||||
|
.Fl u .
|
||||||
.It Fl o Ar outfile
|
.It Fl o Ar outfile
|
||||||
The name of the output file.
|
The name of the output file.
|
||||||
.It Fl p Ar palfile
|
.It Fl p Ar palfile
|
||||||
@@ -74,17 +96,24 @@ Same as
|
|||||||
but the palette file output name is made by taking the input PNG file's
|
but the palette file output name is made by taking the input PNG file's
|
||||||
filename, removing the file extension, and appending
|
filename, removing the file extension, and appending
|
||||||
.Pa .pal .
|
.Pa .pal .
|
||||||
.It Fl t Ar mapfile
|
.It Fl t Ar tilemap
|
||||||
If any tiles are the same, don't place the repeat tiles in the output file, and
|
Generate a file of tile indices. For each tile in the input file, a byte is
|
||||||
make a tilemap file.
|
written representing the index of the associated tile in the output file.
|
||||||
|
Useful in combination with
|
||||||
|
.Fl u
|
||||||
|
or
|
||||||
|
.Fl m
|
||||||
|
to keep track of duplicate tiles.
|
||||||
.It Fl T
|
.It Fl T
|
||||||
Same as
|
Same as
|
||||||
.Fl t ,
|
.Fl t ,
|
||||||
but the tilemap file output name is made by taking the input filename,
|
but the tilemap file output name is made by taking the input filename, removing
|
||||||
removing the file extension, and appending
|
the file extension, and appending
|
||||||
.Pa .tilemap .
|
.Pa .tilemap .
|
||||||
.It Fl u
|
.It Fl u
|
||||||
Truncate repeated tiles. Useful with tilemaps.
|
Truncate tiles by checking for tiles that are exact duplicates of others and
|
||||||
|
omitting these from the output file. Useful with tilemaps to keep track of the
|
||||||
|
duplicated tiles.
|
||||||
.It Fl V
|
.It Fl V
|
||||||
Print the version of the program and exit.
|
Print the version of the program and exit.
|
||||||
.It Fl v
|
.It Fl v
|
||||||
@@ -105,6 +134,14 @@ The following creates a planar 2bpp file with only unique tiles, and its tilemap
|
|||||||
.Pp
|
.Pp
|
||||||
.D1 $ rgbgfx -T -u -o out.2bpp in.png
|
.D1 $ rgbgfx -T -u -o out.2bpp in.png
|
||||||
.Pp
|
.Pp
|
||||||
|
The following creates a planar 2bpp file with only unique tiles (accounting for
|
||||||
|
tile mirroring) and its associated tilemap
|
||||||
|
.Pa out.tilemap
|
||||||
|
and attrmap
|
||||||
|
.Pa out.attrmap :
|
||||||
|
.Pp
|
||||||
|
.D1 $ rgbgfx -A -T -m -o out.2bpp in.png
|
||||||
|
.Pp
|
||||||
The following will do nothing:
|
The following will do nothing:
|
||||||
.Pp
|
.Pp
|
||||||
.D1 $ rgbgfx in.png
|
.D1 $ rgbgfx in.png
|
||||||
|
|||||||
2
src/link/.gitignore
vendored
2
src/link/.gitignore
vendored
@@ -1,2 +1,4 @@
|
|||||||
parser.c
|
parser.c
|
||||||
parser.h
|
parser.h
|
||||||
|
lexer.c
|
||||||
|
lexer.h
|
||||||
|
|||||||
@@ -155,6 +155,11 @@ int32_t area_Avail(int32_t bank)
|
|||||||
|
|
||||||
int32_t area_doAlloc(struct sFreeArea *pArea, int32_t org, int32_t size)
|
int32_t area_doAlloc(struct sFreeArea *pArea, int32_t org, int32_t size)
|
||||||
{
|
{
|
||||||
|
if (size == 0) {
|
||||||
|
/* 0-byte SECTIONs don't take any room, they can go anywhere */
|
||||||
|
return org;
|
||||||
|
}
|
||||||
|
|
||||||
if ((org >= pArea->nOrg)
|
if ((org >= pArea->nOrg)
|
||||||
&& ((org + size) <= (pArea->nOrg + pArea->nSize))) {
|
&& ((org + size) <= (pArea->nOrg + pArea->nSize))) {
|
||||||
|
|
||||||
@@ -695,24 +700,24 @@ void CreateSymbolTable(void)
|
|||||||
if ((tSymbol->Type == SYM_EXPORT) &&
|
if ((tSymbol->Type == SYM_EXPORT) &&
|
||||||
((tSymbol->pSection == pSect) ||
|
((tSymbol->pSection == pSect) ||
|
||||||
(tSymbol->pSection == NULL))) {
|
(tSymbol->pSection == NULL))) {
|
||||||
if (tSymbol->pSection == NULL)
|
if (tSymbol->pSection == NULL) {
|
||||||
sym_CreateSymbol(
|
sym_CreateSymbol(tSymbol->pzName,
|
||||||
tSymbol->pzName,
|
|
||||||
tSymbol->nOffset,
|
tSymbol->nOffset,
|
||||||
-1,
|
-1,
|
||||||
tSymbol->pzObjFileName,
|
tSymbol->pzObjFileName,
|
||||||
tSymbol->pzFileName,
|
tSymbol->pzFileName,
|
||||||
tSymbol->nFileLine);
|
tSymbol->nFileLine);
|
||||||
else
|
} else {
|
||||||
sym_CreateSymbol(
|
sym_CreateSymbol(tSymbol->pzName,
|
||||||
tSymbol->pzName,
|
pSect->nOrg +
|
||||||
pSect->nOrg + tSymbol->nOffset,
|
tSymbol->nOffset,
|
||||||
pSect->nBank,
|
pSect->nBank,
|
||||||
tSymbol->pzObjFileName,
|
tSymbol->pzObjFileName,
|
||||||
tSymbol->pzFileName,
|
tSymbol->pzFileName,
|
||||||
tSymbol->nFileLine);
|
tSymbol->nFileLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pSect = pSect->pNext;
|
pSect = pSect->pNext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,18 @@
|
|||||||
#include "link/mylink.h"
|
#include "link/mylink.h"
|
||||||
#include "link/symbol.h"
|
#include "link/symbol.h"
|
||||||
|
|
||||||
|
#define RPN_STACK_SIZE 256
|
||||||
|
|
||||||
static struct sSection *pCurrentSection;
|
static struct sSection *pCurrentSection;
|
||||||
static int32_t rpnstack[256];
|
static int32_t rpnstack[RPN_STACK_SIZE];
|
||||||
static int32_t rpnp;
|
static int32_t rpnp;
|
||||||
int32_t nPC;
|
int32_t nPC;
|
||||||
|
|
||||||
static void rpnpush(int32_t i)
|
static void rpnpush(int32_t i)
|
||||||
{
|
{
|
||||||
|
if (rpnp >= RPN_STACK_SIZE)
|
||||||
|
errx(1, "RPN stack overflow");
|
||||||
|
|
||||||
rpnstack[rpnp] = i;
|
rpnstack[rpnp] = i;
|
||||||
rpnp++;
|
rpnp++;
|
||||||
}
|
}
|
||||||
@@ -35,13 +40,13 @@ static int32_t rpnpop(void)
|
|||||||
return rpnstack[rpnp];
|
return rpnstack[rpnp];
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t getsymvalue(int32_t symid)
|
static int32_t getsymvalue(struct sPatch *pPatch, int32_t symid)
|
||||||
{
|
{
|
||||||
const struct sSymbol *tSymbol = pCurrentSection->tSymbols[symid];
|
const struct sSymbol *tSymbol = pCurrentSection->tSymbols[symid];
|
||||||
|
|
||||||
switch (tSymbol->Type) {
|
switch (tSymbol->Type) {
|
||||||
case SYM_IMPORT:
|
case SYM_IMPORT:
|
||||||
return sym_GetValue(tSymbol->pzName);
|
return sym_GetValue(pPatch, tSymbol->pzName);
|
||||||
|
|
||||||
case SYM_EXPORT:
|
case SYM_EXPORT:
|
||||||
case SYM_LOCAL:
|
case SYM_LOCAL:
|
||||||
@@ -75,14 +80,14 @@ static int32_t getrealbankfrominternalbank(int32_t n)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t getsymbank(int32_t symid)
|
static int32_t getsymbank(struct sPatch *pPatch, int32_t symid)
|
||||||
{
|
{
|
||||||
int32_t nBank;
|
int32_t nBank;
|
||||||
const struct sSymbol *tSymbol = pCurrentSection->tSymbols[symid];
|
const struct sSymbol *tSymbol = pCurrentSection->tSymbols[symid];
|
||||||
|
|
||||||
switch (tSymbol->Type) {
|
switch (tSymbol->Type) {
|
||||||
case SYM_IMPORT:
|
case SYM_IMPORT:
|
||||||
nBank = sym_GetBank(tSymbol->pzName);
|
nBank = sym_GetBank(pPatch, tSymbol->pzName);
|
||||||
break;
|
break;
|
||||||
case SYM_EXPORT:
|
case SYM_EXPORT:
|
||||||
case SYM_LOCAL:
|
case SYM_LOCAL:
|
||||||
@@ -209,8 +214,8 @@ int32_t calcrpn(struct sPatch *pPatch)
|
|||||||
t |= (*rpn++) << 8;
|
t |= (*rpn++) << 8;
|
||||||
t |= (*rpn++) << 16;
|
t |= (*rpn++) << 16;
|
||||||
t |= (*rpn++) << 24;
|
t |= (*rpn++) << 24;
|
||||||
rpnpush(getsymvalue(t));
|
rpnpush(getsymvalue(pPatch, t));
|
||||||
pPatch->oRelocPatch |= (getsymbank(t) != -1);
|
pPatch->oRelocPatch |= (getsymbank(pPatch, t) != -1);
|
||||||
size -= 4;
|
size -= 4;
|
||||||
break;
|
break;
|
||||||
case RPN_BANK_SYM:
|
case RPN_BANK_SYM:
|
||||||
@@ -219,7 +224,7 @@ int32_t calcrpn(struct sPatch *pPatch)
|
|||||||
t |= (*rpn++) << 8;
|
t |= (*rpn++) << 8;
|
||||||
t |= (*rpn++) << 16;
|
t |= (*rpn++) << 16;
|
||||||
t |= (*rpn++) << 24;
|
t |= (*rpn++) << 24;
|
||||||
rpnpush(getsymbank(t));
|
rpnpush(getsymbank(pPatch, t));
|
||||||
size -= 4;
|
size -= 4;
|
||||||
break;
|
break;
|
||||||
case RPN_BANK_SECT:
|
case RPN_BANK_SECT:
|
||||||
@@ -229,7 +234,9 @@ int32_t calcrpn(struct sPatch *pPatch)
|
|||||||
struct sSection *pSection = GetSectionByName(name);
|
struct sSection *pSection = GetSectionByName(name);
|
||||||
|
|
||||||
if (pSection == NULL) {
|
if (pSection == NULL) {
|
||||||
errx(1, "Requested BANK() of section \"%s\", which was not found.\n",
|
errx(1,
|
||||||
|
"%s(%ld) : Requested BANK() of section \"%s\", which was not found.\n",
|
||||||
|
pPatch->pzFilename, pPatch->nLineNo,
|
||||||
name);
|
name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "link/main.h"
|
#include "link/main.h"
|
||||||
#include "link/patch.h"
|
#include "link/patch.h"
|
||||||
|
#include "link/mylink.h"
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ void sym_Init(void)
|
|||||||
tHash[i] = NULL;
|
tHash[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t sym_GetValue(char *tzName)
|
int32_t sym_GetValue(struct sPatch *pPatch, char *tzName)
|
||||||
{
|
{
|
||||||
if (strcmp(tzName, "@") == 0)
|
if (strcmp(tzName, "@") == 0)
|
||||||
return nPC;
|
return nPC;
|
||||||
@@ -68,10 +69,13 @@ int32_t sym_GetValue(char *tzName)
|
|||||||
return ((*ppSym)->nValue);
|
return ((*ppSym)->nValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
errx(1, "Unknown symbol '%s'", tzName);
|
errx(1,
|
||||||
|
"%s(%ld) : Unknown symbol '%s'",
|
||||||
|
pPatch->pzFilename, pPatch->nLineNo,
|
||||||
|
tzName);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t sym_GetBank(char *tzName)
|
int32_t sym_GetBank(struct sPatch *pPatch, char *tzName)
|
||||||
{
|
{
|
||||||
struct ISymbol **ppSym;
|
struct ISymbol **ppSym;
|
||||||
|
|
||||||
@@ -83,7 +87,10 @@ int32_t sym_GetBank(char *tzName)
|
|||||||
return ((*ppSym)->nBank);
|
return ((*ppSym)->nBank);
|
||||||
}
|
}
|
||||||
|
|
||||||
errx(1, "Unknown symbol '%s'", tzName);
|
errx(1,
|
||||||
|
"%s(%ld) : Unknown symbol '%s'",
|
||||||
|
pPatch->pzFilename, pPatch->nLineNo,
|
||||||
|
tzName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sym_CreateSymbol(char *tzName, int32_t nValue, int32_t nBank,
|
void sym_CreateSymbol(char *tzName, int32_t nValue, int32_t nBank,
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ REPT NumberOfSymbols ; Number of symbols defined in this object file.
|
|||||||
; as "Scope.Symbol".
|
; as "Scope.Symbol".
|
||||||
|
|
||||||
BYTE Type ; 0 = LOCAL symbol only used in this file.
|
BYTE Type ; 0 = LOCAL symbol only used in this file.
|
||||||
; 1 = IMPORT this symbol from elsewhere (unused).
|
; 1 = IMPORT this symbol from elsewhere
|
||||||
; 2 = EXPORT this symbol to other objects.
|
; 2 = EXPORT this symbol to other objects.
|
||||||
|
|
||||||
IF Type != 1 ; If symbol is defined in this object file.
|
IF Type != 1 ; If symbol is defined in this object file.
|
||||||
@@ -164,8 +164,8 @@ special prefixes for integers and symbols.
|
|||||||
.It Li $33 Ta Li < comparison
|
.It Li $33 Ta Li < comparison
|
||||||
.It Li $34 Ta Li >= comparison
|
.It Li $34 Ta Li >= comparison
|
||||||
.It Li $35 Ta Li <= comparison
|
.It Li $35 Ta Li <= comparison
|
||||||
.It Li $40 Ta Li << comparison
|
.It Li $40 Ta Li << operator
|
||||||
.It Li $41 Ta Li >> comparison
|
.It Li $41 Ta Li >> operator
|
||||||
.It Li $50 Ta Li BANK(symbol),
|
.It Li $50 Ta Li BANK(symbol),
|
||||||
a
|
a
|
||||||
.Ar LONG
|
.Ar LONG
|
||||||
|
|||||||
20
test/asm/bracketed-symbols.asm
Normal file
20
test/asm/bracketed-symbols.asm
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
X = 42
|
||||||
|
PRINTT "{X}\n"
|
||||||
|
PRINTT "{x:X}\n"
|
||||||
|
PRINTT "{X:X}\n"
|
||||||
|
PRINTT "{d:X}\n"
|
||||||
|
PRINTT "{b:X}\n"
|
||||||
|
|
||||||
|
Y equ 1337
|
||||||
|
PRINTT "{b:Y}\n"
|
||||||
|
|
||||||
|
rsreset
|
||||||
|
R rb 0
|
||||||
|
PRINTT "{d:R}\n"
|
||||||
|
|
||||||
|
S equs "You can't format me!"
|
||||||
|
PRINTT "{X:S}\n"
|
||||||
|
|
||||||
|
SECTION "Test", ROM0
|
||||||
|
Label:
|
||||||
|
PRINTT "{x:Label}\n"
|
||||||
12
test/asm/bracketed-symbols.out
Normal file
12
test/asm/bracketed-symbols.out
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
ERROR: bracketed-symbols.asm(16):
|
||||||
|
Print types are only allowed for numbers
|
||||||
|
ERROR: bracketed-symbols.asm(20):
|
||||||
|
Expression must have a constant value
|
||||||
|
$2A
|
||||||
|
2a
|
||||||
|
2A
|
||||||
|
42
|
||||||
|
101010
|
||||||
|
10100111001
|
||||||
|
0
|
||||||
|
You can't format me!
|
||||||
11
test/asm/correct-line-number.asm
Normal file
11
test/asm/correct-line-number.asm
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
IF 0
|
||||||
|
"\
|
||||||
|
"
|
||||||
|
ELIF 1
|
||||||
|
WARN "Am I geting ahead of myself?"
|
||||||
|
ELSE
|
||||||
|
"\
|
||||||
|
"
|
||||||
|
ENDC
|
||||||
|
|
||||||
|
WARN "Hopefully not."
|
||||||
4
test/asm/correct-line-number.out
Normal file
4
test/asm/correct-line-number.out
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
warning: correct-line-number.asm(5):
|
||||||
|
Am I geting ahead of myself?
|
||||||
|
warning: correct-line-number.asm(11):
|
||||||
|
Hopefully not.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
SECTION "sec", ROM0
|
|
||||||
charmap "A", 1
|
charmap "A", 1
|
||||||
|
SECTION "sec", ROM0[0]
|
||||||
_A_ EQU "A"
|
_A_ EQU "A"
|
||||||
db _A_
|
db _A_
|
||||||
|
|||||||
2
test/asm/equs-recursion.asm
Normal file
2
test/asm/equs-recursion.asm
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
recurse EQUS "recurse"
|
||||||
|
recurse
|
||||||
66
test/asm/equs-recursion.out
Normal file
66
test/asm/equs-recursion.out
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
ERROR: equs-recursion.asm(2):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
|
while expanding symbol "recurse"
|
||||||
1
test/asm/garbage_char.asm
Normal file
1
test/asm/garbage_char.asm
Normal file
@@ -0,0 +1 @@
|
|||||||
|
x<EFBFBD>
|
||||||
2
test/asm/garbage_char.out
Normal file
2
test/asm/garbage_char.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: garbage_char.asm(1):
|
||||||
|
Found garbage character: 0xFF
|
||||||
1
test/asm/include-recursion.asm
Normal file
1
test/asm/include-recursion.asm
Normal file
@@ -0,0 +1 @@
|
|||||||
|
INCLUDE "include-recursion.asm"
|
||||||
2
test/asm/include-recursion.out
Normal file
2
test/asm/include-recursion.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
45
test/asm/label-macro-arg.asm
Normal file
45
test/asm/label-macro-arg.asm
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
print: MACRO
|
||||||
|
printv \1
|
||||||
|
printt "\n"
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
|
||||||
|
m1: MACRO
|
||||||
|
x\1
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
S EQUS "y"
|
||||||
|
S2 EQUS "yy"
|
||||||
|
|
||||||
|
m2: MACRO
|
||||||
|
S\1
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
m1 = 5
|
||||||
|
m2 = 6
|
||||||
|
m1 x = 7
|
||||||
|
m2 2 = 8
|
||||||
|
|
||||||
|
print x
|
||||||
|
print y
|
||||||
|
print xx
|
||||||
|
print yy
|
||||||
|
|
||||||
|
|
||||||
|
test_char: MACRO
|
||||||
|
VAR_DEF equs "sizeof_\1something = 0"
|
||||||
|
VAR_DEF
|
||||||
|
sizeof_\1something = 1
|
||||||
|
PURGE VAR_DEF
|
||||||
|
|
||||||
|
VAR_PRINT equs "printt \"sizeof_\1something equals {sizeof_\1something}\\n\""
|
||||||
|
VAR_PRINT
|
||||||
|
PURGE VAR_PRINT
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
test_char _
|
||||||
|
test_char @
|
||||||
|
test_char #
|
||||||
|
test_char .
|
||||||
|
|
||||||
|
test_char :
|
||||||
10
test/asm/label-macro-arg.out
Normal file
10
test/asm/label-macro-arg.out
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
ERROR: label-macro-arg.asm(45) -> label-macro-arg.asm::test_char(31):
|
||||||
|
Macro 'something' not defined
|
||||||
|
$5
|
||||||
|
$6
|
||||||
|
$7
|
||||||
|
$8
|
||||||
|
sizeof__something equals $1
|
||||||
|
sizeof_@something equals $1
|
||||||
|
sizeof_#something equals $1
|
||||||
|
sizeof_.something equals $1
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: label-redefinition.asm(7):
|
ERROR: label-redefinition.asm(7):
|
||||||
'Sym' already defined in m(6)
|
'Sym' already defined in label-redefinition.asm::m(6)
|
||||||
error: Assembly aborted in pass 1 (1 errors)!
|
error: Assembly aborted (1 errors)!
|
||||||
|
|||||||
7
test/asm/line-continuation-macro.asm
Normal file
7
test/asm/line-continuation-macro.asm
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
m: MACRO
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
m2: MACRO
|
||||||
|
m \ ENDM
|
||||||
|
|
||||||
|
m2
|
||||||
0
test/asm/line-continuation-macro.out
Normal file
0
test/asm/line-continuation-macro.out
Normal file
8
test/asm/line-continuation-rept.asm
Normal file
8
test/asm/line-continuation-rept.asm
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
m: MACRO
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
REPT 1
|
||||||
|
m ENDR
|
||||||
|
|
||||||
|
REPT 1
|
||||||
|
m \ ENDR
|
||||||
0
test/asm/line-continuation-rept.out
Normal file
0
test/asm/line-continuation-rept.out
Normal file
7
test/asm/line-continuation-whitespace.asm
Normal file
7
test/asm/line-continuation-whitespace.asm
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
; Test that \ followed by whitespace after a macro invocation at the end of the
|
||||||
|
; file doesn't cause a segfault.
|
||||||
|
|
||||||
|
bar: MACRO
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
foo bar baz\
|
||||||
0
test/asm/line-continuation-whitespace.out
Normal file
0
test/asm/line-continuation-whitespace.out
Normal file
@@ -1 +1,7 @@
|
|||||||
foo @bar\
|
; Test that \ after a macro invocation at the end of the file doesn't
|
||||||
|
; cause a segfault.
|
||||||
|
|
||||||
|
bar: MACRO
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
foo bar baz\
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ERROR: line-continuation.asm(2) -> @(-1):
|
|
||||||
Macro '@' not defined
|
|
||||||
|
|||||||
3
test/asm/local-ref-without-parent.asm
Normal file
3
test/asm/local-ref-without-parent.asm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
SECTION "sec", ROM0
|
||||||
|
|
||||||
|
dw .test
|
||||||
2
test/asm/local-ref-without-parent.out
Normal file
2
test/asm/local-ref-without-parent.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: local-ref-without-parent.asm(3):
|
||||||
|
Local label reference '.test' in main scope
|
||||||
2
test/asm/local-without-parent.asm
Normal file
2
test/asm/local-without-parent.asm
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
SECTION "Test", ROM0
|
||||||
|
.test:
|
||||||
2
test/asm/local-without-parent.out
Normal file
2
test/asm/local-without-parent.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: local-without-parent.asm(2):
|
||||||
|
Local label in main scope
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: local-wrong-parent.asm(5):
|
ERROR: local-wrong-parent.asm(5):
|
||||||
Not currently in the scope of 'WrongParent'
|
Not currently in the scope of 'WrongParent'
|
||||||
error: Assembly aborted in pass 1 (1 errors)!
|
error: Assembly aborted (1 errors)!
|
||||||
|
|||||||
33
test/asm/long-rpn-expression.asm
Normal file
33
test/asm/long-rpn-expression.asm
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
SECTION "sec", ROM0
|
||||||
|
|
||||||
|
X0 EQUS "0"
|
||||||
|
|
||||||
|
m: MACRO
|
||||||
|
\1 EQUS STRCAT("{X\2}", "+0")
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
|
||||||
|
REPT $7E
|
||||||
|
n1 = n + 1
|
||||||
|
NSTR EQUS STRSUB("{n}", 2, STRLEN("{n}") - 1)
|
||||||
|
N1STR EQUS STRSUB("{n1}", 2, STRLEN("{n1}") - 1)
|
||||||
|
XN1 EQUS STRCAT("X", "{N1STR}")
|
||||||
|
m XN1, {NSTR}
|
||||||
|
PURGE NSTR, N1STR, XN1
|
||||||
|
n = n + 1
|
||||||
|
ENDR
|
||||||
|
|
||||||
|
; string of 127 zeros separated by plus signs
|
||||||
|
X EQUS "{X7E}"
|
||||||
|
|
||||||
|
db x+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+\
|
||||||
|
X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+\
|
||||||
|
X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+\
|
||||||
|
X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+\
|
||||||
|
X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+\
|
||||||
|
X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+\
|
||||||
|
X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+\
|
||||||
|
X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X
|
||||||
|
|
||||||
|
x db 0
|
||||||
0
test/asm/long-rpn-expression.out
Normal file
0
test/asm/long-rpn-expression.out
Normal file
@@ -1,2 +1,2 @@
|
|||||||
ERROR: macro-@.asm(1) -> @(-1):
|
ERROR: macro-@.asm(1):
|
||||||
Macro '@' not defined
|
Macro '@' not defined
|
||||||
|
|||||||
4
test/asm/macro-recursion.asm
Normal file
4
test/asm/macro-recursion.asm
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
recurse: MACRO
|
||||||
|
recurse
|
||||||
|
ENDM
|
||||||
|
recurse
|
||||||
2
test/asm/macro-recursion.out
Normal file
2
test/asm/macro-recursion.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: macro-recursion.asm(4) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2) -> macro-recursion.asm::recurse(2):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
104
test/asm/multiple-charmaps.asm
Normal file
104
test/asm/multiple-charmaps.asm
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
new_: MACRO
|
||||||
|
IF _NARG > 1
|
||||||
|
printt "newcharmap \1, \2\n"
|
||||||
|
newcharmap \1, \2
|
||||||
|
ELSE
|
||||||
|
printt "newcharmap \1\n"
|
||||||
|
newcharmap \1
|
||||||
|
ENDC
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
set_: MACRO
|
||||||
|
printt "setcharmap \1\n"
|
||||||
|
setcharmap \1
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
push_: MACRO
|
||||||
|
printt "pushc\n"
|
||||||
|
pushc
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
pop_: MACRO
|
||||||
|
printt "popc\n"
|
||||||
|
popc
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
print: MACRO
|
||||||
|
x = \1
|
||||||
|
printt "{x}\n"
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
printt "main charmap\n"
|
||||||
|
|
||||||
|
charmap "ab", $0
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
|
||||||
|
new_ map1
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
|
||||||
|
new_ map2, main
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
|
||||||
|
set_ map1
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
|
||||||
|
new_ map3
|
||||||
|
|
||||||
|
charmap "ab", $1
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
|
||||||
|
new_ map4, map3
|
||||||
|
|
||||||
|
charmap "ab", $1
|
||||||
|
charmap "cd", $2
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
print "cd"
|
||||||
|
|
||||||
|
set_ map3
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
print "cd"
|
||||||
|
|
||||||
|
set_ main
|
||||||
|
|
||||||
|
SECTION "sec0", ROM0
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
|
||||||
|
printt "override main charmap\n"
|
||||||
|
charmap "ef", $3
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
print "ef"
|
||||||
|
|
||||||
|
set_ map1
|
||||||
|
|
||||||
|
push_
|
||||||
|
set_ map2
|
||||||
|
push_
|
||||||
|
|
||||||
|
set_ map3
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
print "cd"
|
||||||
|
print "ef"
|
||||||
|
|
||||||
|
pop_
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
|
||||||
|
pop_
|
||||||
|
|
||||||
|
print "ab"
|
||||||
|
|
||||||
|
new_ map1
|
||||||
|
|
||||||
|
set_ map5
|
||||||
|
|
||||||
|
pop_
|
||||||
44
test/asm/multiple-charmaps.out
Normal file
44
test/asm/multiple-charmaps.out
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
warning: multiple-charmaps.asm(75):
|
||||||
|
Using 'charmap' within a section when the current charmap is 'main' is deprecated
|
||||||
|
ERROR: multiple-charmaps.asm(100) -> multiple-charmaps.asm::new_(7):
|
||||||
|
Charmap 'map1' already exists
|
||||||
|
ERROR: multiple-charmaps.asm(102) -> multiple-charmaps.asm::set_(13):
|
||||||
|
Charmap 'map5' doesn't exist
|
||||||
|
ERROR: multiple-charmaps.asm(104) -> multiple-charmaps.asm::pop_(23):
|
||||||
|
No entries in the charmap stack
|
||||||
|
main charmap
|
||||||
|
$0
|
||||||
|
newcharmap map1
|
||||||
|
$6162
|
||||||
|
newcharmap map2, main
|
||||||
|
$0
|
||||||
|
setcharmap map1
|
||||||
|
$6162
|
||||||
|
newcharmap map3
|
||||||
|
$1
|
||||||
|
newcharmap map4, map3
|
||||||
|
$1
|
||||||
|
$2
|
||||||
|
setcharmap map3
|
||||||
|
$1
|
||||||
|
$6364
|
||||||
|
setcharmap main
|
||||||
|
$0
|
||||||
|
override main charmap
|
||||||
|
$6162
|
||||||
|
$3
|
||||||
|
setcharmap map1
|
||||||
|
pushc
|
||||||
|
setcharmap map2
|
||||||
|
pushc
|
||||||
|
setcharmap map3
|
||||||
|
$1
|
||||||
|
$6364
|
||||||
|
$6566
|
||||||
|
popc
|
||||||
|
$0
|
||||||
|
popc
|
||||||
|
$6162
|
||||||
|
newcharmap map1
|
||||||
|
setcharmap map5
|
||||||
|
popc
|
||||||
14
test/asm/narg-decreases-after-shift.asm
Normal file
14
test/asm/narg-decreases-after-shift.asm
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
testing: MACRO
|
||||||
|
db _NARG
|
||||||
|
shift
|
||||||
|
db _NARG
|
||||||
|
shift
|
||||||
|
db _NARG
|
||||||
|
shift
|
||||||
|
db _NARG
|
||||||
|
shift
|
||||||
|
db _NARG
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
SECTION "Test output", ROM0[0]
|
||||||
|
testing 1, 2, 3
|
||||||
0
test/asm/narg-decreases-after-shift.out
Normal file
0
test/asm/narg-decreases-after-shift.out
Normal file
BIN
test/asm/narg-decreases-after-shift.out.bin
Normal file
BIN
test/asm/narg-decreases-after-shift.out.bin
Normal file
Binary file not shown.
18
test/asm/nested-if.asm
Normal file
18
test/asm/nested-if.asm
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
if 0
|
||||||
|
if(1)
|
||||||
|
endc
|
||||||
|
if 1
|
||||||
|
endc
|
||||||
|
if{x}
|
||||||
|
endc
|
||||||
|
endc
|
||||||
|
|
||||||
|
if 1
|
||||||
|
else
|
||||||
|
if(1)
|
||||||
|
endc
|
||||||
|
if 1
|
||||||
|
endc
|
||||||
|
if{x}
|
||||||
|
endc
|
||||||
|
endc
|
||||||
0
test/asm/nested-if.out
Normal file
0
test/asm/nested-if.out
Normal file
@@ -1,2 +1,2 @@
|
|||||||
ERROR: null-in-macro.asm(1):
|
ERROR: null-in-macro.asm(2):
|
||||||
Unterminated MACRO definition.
|
Found null character
|
||||||
|
|||||||
7
test/asm/operator-precedence.asm
Normal file
7
test/asm/operator-precedence.asm
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
print: MACRO
|
||||||
|
printv \1
|
||||||
|
printt "\n"
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
print 1 == 1 || 1 == 2
|
||||||
|
print (1 == 1) || (1 == 2)
|
||||||
2
test/asm/operator-precedence.out
Normal file
2
test/asm/operator-precedence.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
$1
|
||||||
|
$1
|
||||||
42
test/asm/overflow.asm
Normal file
42
test/asm/overflow.asm
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
SECTION "sec", ROM0
|
||||||
|
|
||||||
|
print_x: MACRO
|
||||||
|
printv x
|
||||||
|
printt "\n"
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
x = 2147483647
|
||||||
|
x = x + 1
|
||||||
|
dl 2147483647+1
|
||||||
|
print_x
|
||||||
|
|
||||||
|
x = -2147483648
|
||||||
|
x = x - 1
|
||||||
|
dl -2147483648-1
|
||||||
|
print_x
|
||||||
|
|
||||||
|
x = -2147483648
|
||||||
|
x = x * -1
|
||||||
|
dl -2147483648 * -1
|
||||||
|
print_x
|
||||||
|
|
||||||
|
x = -2147483648
|
||||||
|
x = x / -1
|
||||||
|
dl -2147483648 / -1
|
||||||
|
print_x
|
||||||
|
|
||||||
|
x = -2147483648
|
||||||
|
x = x % -1
|
||||||
|
dl -2147483648 % -1
|
||||||
|
print_x
|
||||||
|
|
||||||
|
x = -1
|
||||||
|
x = x << 1
|
||||||
|
dl -1 << 1
|
||||||
|
print_x
|
||||||
|
|
||||||
|
x = 4294967295
|
||||||
|
x = 4294967296
|
||||||
|
|
||||||
|
x = `33333333
|
||||||
|
x = `333333333
|
||||||
18
test/asm/overflow.out
Normal file
18
test/asm/overflow.out
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
warning: overflow.asm(24):
|
||||||
|
Division of min value by -1
|
||||||
|
warning: overflow.asm(25):
|
||||||
|
Division of min value by -1
|
||||||
|
warning: overflow.asm(34):
|
||||||
|
Left shift of negative value: -1
|
||||||
|
warning: overflow.asm(35):
|
||||||
|
Left shift of negative value: -1
|
||||||
|
warning: overflow.asm(39):
|
||||||
|
Integer constant '4294967296' is too large
|
||||||
|
warning: overflow.asm(42):
|
||||||
|
Graphics constant '`333333333' is too long
|
||||||
|
$80000000
|
||||||
|
$7FFFFFFF
|
||||||
|
$80000000
|
||||||
|
$80000000
|
||||||
|
$0
|
||||||
|
$FFFFFFFE
|
||||||
1
test/asm/pops-no-pushed-sections.asm
Normal file
1
test/asm/pops-no-pushed-sections.asm
Normal file
@@ -0,0 +1 @@
|
|||||||
|
POPS
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user