Compare commits

..

84 Commits

Author SHA1 Message Date
jmle
c59cb6a828 Increase version number to 0.3.8 2019-02-20 00:10:02 +01:00
Simon Harms
06aaf5b571 Update README.rst
Add instructions to install on Arch Linux through AUR.
2019-02-14 18:03:28 -05:00
Antonio Niño Díaz
65d7909466 Merge pull request #319 from mid-kid/patch-317
Allow linker script to consider section attributes
2019-01-19 16:15:42 +00:00
Antonio Niño Díaz
861192c332 Merge pull request #318 from mid-kid/patch-316
Update a symbol's filename and line when defined
2019-01-19 16:14:11 +00:00
mid-kid
c63af05427 Allow linker script to consider section attributes
The linker script now allows you to assign a section with the same
attributes as in the source.
To do this, I've removed a check from AssignSectionAddressAndBankByName
that would never be triggered, due to that condition being checked
before. Shouldn't this and IsSectionSameTypeBankAndAttrs be condensed
into a single function?
2019-01-18 12:37:23 +01:00
mid-kid
d07ba6971b Update a symbol's filename and line when defined
Currently, all symbols are assigned a filename and line when they're
first encountered and added to the internal hash table. This is often
not expected and leads to erroneous error messages.
2019-01-12 12:57:58 +01:00
Antonio Niño Díaz
4b40d63dfd Merge pull request #311 from dbrotz/fix-222
Fix #222 and #255
2018-12-10 23:17:39 +00:00
Antonio Niño Díaz
a99b7f6902 Merge pull request #314 from dbrotz/fix-314
Fix #314
2018-12-10 23:09:39 +00:00
Antonio Niño Díaz
b3391f699f Merge pull request #310 from dbrotz/fix-302
Fix #302
2018-12-10 23:05:22 +00:00
dbrotz
5a3c12cc6b Add test for file ending with \ 2018-12-06 23:27:41 -08:00
dbrotz
a05fd9b818 Print full file path in error messages 2018-12-06 22:59:24 -08:00
dbrotz
6c1ec59a5b Use separate function to append newlines 2018-12-05 01:32:06 -08:00
Antonio Niño Díaz
e25a4b0abc Merge pull request #309 from dbrotz/master
Fix #308
2018-12-04 21:07:08 +00:00
dbrotz
a060f135b8 Only add newlines to file if necessary 2018-12-02 20:43:20 -08:00
dbrotz
f5d3087e9b Check if integer constants only contain radix prefix 2018-12-02 16:16:41 -08:00
dbrotz
2795404cd7 Add myself to contributors 2018-12-02 16:01:08 -08:00
Antonio Niño Díaz
16fac50db4 Fix clone of external repository
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-12-02 23:39:09 +00:00
dbrotz
3806eb3139 Fix ambiguity in const parsing 2018-12-02 13:49:12 -08:00
dbrotz
bad66e54fa Fix buffer overflow when file ends with \ 2018-12-01 07:21:25 -08:00
karas
5cb6c4af4b Fix typo in documentation
Signed-off-by: GwanYeong Kim <gy741.kim@gmail.com>
2018-08-30 18:53:44 +09:00
Antonio Niño Díaz
69f79f8598 Remove unused str2int()
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-08-18 00:19:48 +01:00
karas
573011a99e Remove dead code
Fixed: #301

Signed-off-by: GwanYeong Kim <gy741.kim@gmail.com>
2018-08-17 18:49:19 +09:00
Antonio Niño Díaz
d778b8e71c Update HTML documentation 2018-07-31 20:02:06 +01:00
Anthony J. Bentley
432a7574c9 Remove alphabetical list of keywords.
The original list only existed because the documentation was split
across multiple files. When all keywords are described in a single
document, Ctrl+F suffices to find them.
2018-07-28 02:05:52 -06:00
Anthony J. Bentley
4d2598e7bf Fix Bl -column widths: the arguments are strings as wide as the column. 2018-07-28 02:02:47 -06:00
Anthony J. Bentley
2e565bcb4e Escape some operators. 2018-07-28 01:55:38 -06:00
Anthony J. Bentley
62ecb6da0b Mark up #define with Fd. 2018-07-28 01:55:38 -06:00
Anthony J. Bentley
46fcebe2b5 Use .Fn for defining functions. 2018-07-28 01:55:35 -06:00
Anthony J. Bentley
ab1901eeac Remove excess tabs in column lists. 2018-07-28 01:55:35 -06:00
Anthony J. Bentley
29d2fc6ebc Cleanup "Sections" section. 2018-07-28 01:55:28 -06:00
Anthony J. Bentley
efe4599bd8 New sentence, new line. 2018-07-28 00:46:16 -06:00
Anthony J. Bentley
4fc1e41b16 @, &, $, {, and } don't need to be escaped. 2018-07-28 00:46:16 -06:00
Anthony J. Bentley
e771d60ec0 Eliminate \[dq] escapes and superfluous double quotes.
" can be used directly except in macro lines. Also in some situations
wrapping with a Dq or Ql macro can be more appropriate.
2018-07-28 00:45:54 -06:00
yenatch
e2de106d71 Use charmaps in const expressions. 2018-07-06 22:58:58 -04:00
Antonio Niño Díaz
adea89f3eb Merge pull request #294 from yenatch/utf-8
Fix UTF-8 characters with an even number of bytes.
2018-07-02 23:10:46 +01:00
yenatch
361015497c Remove signoff step from contributing guide. 2018-07-02 16:04:53 -04:00
yenatch
5e9c433a24 checkpatch: Don't expect Signed-off-by lines in commit messages 2018-07-01 00:05:11 -04:00
yenatch
587159448a Test binary output for rgbasm tests 2018-06-30 23:46:17 -04:00
yenatch
64158cf513 Run checkpatch in a separate build. 2018-06-30 21:58:05 -04:00
yenatch
a567365d7c unit test for db "é" 2018-06-30 21:57:34 -04:00
yenatch
57bf220e40 Fix formatting of utf8d table. 2018-06-30 20:07:23 -04:00
yenatch
e6e3cc474d Fix UTF-8 characters with an even number of bytes. 2018-06-30 19:41:46 -04:00
Antonio Niño Díaz
33c984e456 Merge pull request #287 from Ben10do/remove-dummymem
Two variables, pSection->Data and tSymbols, were previously set to
dummymem, a global variable that was otherwise not used.

As this can potentially cause alignment warnings on Clang, this commit
replaces that mechanism with a plain old NULL pointer, which is more
generally used as a dummy pointer value.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-06-10 22:54:16 +01:00
Antonio Niño Díaz
458f79f44f Fix test projects compilation in OS X
The tool md5sum is required by some of them.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-06-06 22:18:29 +01:00
Antonio Niño Díaz
34e04b0327 Re-enable OS X builds in Travis CI
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-06-06 22:10:21 +01:00
Antonio Niño Díaz
cf7bb9e99f Merge pull request #285 from Ben10do/allow-test-repos-to-be-kept
We no longer assume that the test repos don’t exist when we run
run-tests.sh. This allows developers to choose to keep them, to allow
them to run the tests more quickly.

- Add the test repos to the .gitignore.
- Check if the directory for each repo already exists, before trying to
  clone it.
- Do a git pull for each repo, to ensure that existing copies of repos
  are up-to-date.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-06-06 22:06:04 +01:00
Ben10do
1af5343e29 Use specific commits when running tests
This ensures that build breaks to any of the test projects don’t immediately cause rgbds tests to fail.

On clone, I’ve set it up to pull the commits since the day before the desired commit. Sadly, this will clone more recent commits that we’re not testing, but at least it ensures that the desired commit can be checked out. This is hopefully a good enough replacement for —depth=1.

Signed-off-by: Ben10do <Ben10do@users.noreply.github.com>
2018-06-06 22:00:45 +01:00
Ben10do
a5e3a7cbc9 Replace pointers to ‘dummymem’ with NULL
Two variables, pSection->Data and tSymbols, were previously set to ‘dummymem’, a global variable that was otherwise not used.

As this can potentially cause alignment warnings on Clang, this commit replaces that mechanism with a plain old NULL pointer, which is more generally used as a dummy pointer value.

Signed-off-by: Ben10do <Ben10do@users.noreply.github.com>
2018-06-06 21:16:53 +01:00
Antonio Niño Díaz
df065dbbcb Update html documentation
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-06-06 19:21:30 +01:00
Eldred Habert
fac7247483 Update descriptions of how flags are pushed/popped
Signed-off-by: ISSOtm <eldredhabert0@gmail.com>
2018-06-06 09:06:07 +02:00
Ben10do
60050af186 Allow test repos to be kept locally
We no longer assume that the test repos don’t exist when we run run-tests.sh. This allows developers to choose to keep them, to allow them to run the tests more quickly.

- Add the test repos to the .gitignore.
- Check if the directory for each repo already exists, before trying to clone it.
- Do a `git pull` for each repo, to ensure that existing copies of repos are up-to-date.

Signed-off-by: Ben10do <Ben10do@users.noreply.github.com>
2018-06-03 18:23:19 +01:00
Ben10do
11c47570ce Fix the global checksum calculation in rgbfix
A regression was spotted in rgbfix 0.3.7, where we would accidentally include the first byte of the existing checksum when calculating a global checksum. We now correctly ignore both of the existing checksum bytes.

This was spotted when running rgbfix on the Pokémon Gold/Silver betas, as they have a non-zero global checksum.

Fixes #280.

Signed-off-by: Ben10do <Ben10do@users.noreply.github.com>
2018-06-03 10:11:55 +01:00
Antonio Niño Díaz
f8b4cc52f6 rgbasm: Allow variations of 'ld [$FF00+c],a'
The following mnemonics are now valid:

    - ld
    - ldh
    - ldio

The following are valid as operands:

    - [$ff00+c]
    - [$ff00 + c]
    - [c]

This is done for consistency with 'ld [$FF00+n],a' and variations of it.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-05-20 21:04:47 +01:00
Antonio Niño Díaz
748943f6fc Increase version number to 0.3.7
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-05-02 20:04:00 +01:00
Antonio Niño Díaz
d945c5811c rgbasm: Check the values of operands in bit shifts
The tests are not exhaustive, there are some conditions that aren't
checked. The tests are based in the C standard rules about undefined
behaviour.

This is a compatibility break but, hopefully, all projects are using
sane values. If not, there is no guarantee that the projects will build
in any platform where RGBDS can be compiled, so it would be better to
fix them.

Even though, technically, the left shift of a negative value is always
undefined, some projects rely on its current behaviour. This is the
reason why this doesn't cause a fatal error.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-28 01:59:37 +01:00
Antonio Niño Díaz
6fe2741f2d Enable GCC options to detect undefined behaviour
GCC has an Undefined Behavior Sanitizer (ubsan), which enables run-time
checks of undefined behaviour. It has been enabled for the `develop`
build target.

A small bug detected with it has been fixed.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-28 00:57:25 +01:00
Antonio Niño Díaz
24d7cfe0f9 checkpatch: Ignore warnings about SPDX
The Linux kernel expects the SPDX license tag to be in the first line of
all source code files. The reason is that they have many different
license headers, and this simplifies the work for any tool that has to
determine the license of each file.

In this project, the license headers follow the same pattern, so it
isn't useful.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-27 23:00:29 +01:00
Antonio Niño Díaz
630933b148 rgbfix: Fix checkpatch issues
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-22 21:02:08 +01:00
Antonio Niño Díaz
e8a16c6f53 Don't generate output file if overlay isn't found
Previously, the output file was opened before trying to open the
overlay. Because of this, rgblink generated an empty output file if the
overlay couldn't be opened.

Now the overlay is opened (and checked) before the output file, so the
output file is only generated if the overlay is found.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-22 20:54:48 +01:00
Antonio Niño Díaz
2cb50730a1 Document Section ID == -1 in object files
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-22 20:21:45 +01:00
Antonio Niño Díaz
efae6c7fd2 Merge pull request #264 from inmemrgbfix
Rewrite rgbfix to perform most actions in memory.

Limit file operations to a small number that can be reasonably checked,
and do the majority of the actual work on a buffered header in memory
where operations won't fail.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-22 20:03:32 +01:00
Anthony J. Bentley
8a559beeb8 Rewrite rgbfix to perform most actions in memory.
Limit file operations to a small number that can be reasonably checked,
and do the majority of the actual work on a buffered header in memory
where operations won't fail.
2018-04-05 00:41:09 -06:00
Antonio Niño Díaz
7149fc1e39 tests: Update references
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-03 23:04:29 +01:00
Antonio Niño Díaz
2e695334c1 rgbfix: Add check to malloc()
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-03 22:41:51 +01:00
Antonio Niño Díaz
e2b4554a5c Replace tabs by spaces in fprintf()
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-03 22:41:44 +01:00
Antonio Niño Díaz
ef87dd5a6e rgbasm: Fix declaration of fatalerror()
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-03 22:41:37 +01:00
Antonio Niño Díaz
4f126b37d0 Merge pull request #261 from warnings
Enable a lot of GCC warnings and cleanup Makefile and compiler macros

Most of the warnings in the GCC documentation have been enabled. As the
build system was using `-Werror`, this made the new builds very
susceptible to any minor change in the compiler. To fix that, this
option has been removed from the default Makefile target and it is only
used when the code is compiled through `make develop`.

The file `stdnoreturn.h` has been modified to remove support for
compilers that aren't actually tested. It now has defines for
`__attribute__((unused))` and it has been renamed to `helpers.h`.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-03 19:57:04 +01:00
Antonio Niño Díaz
1b4187e51f Cleanup GCC compiler attributes
Added define 'unused_' for '__attribute__((unused))'. The oldest version
of GCC with online docs (GCC 2.95.3, released in March 16, 2001 [1])
already has support for this attribute, so it doesn't make sense to
check the version.

Renamed 'noreturn' to 'noreturn_' for consistency.

[1] https://gcc.gnu.org/onlinedocs/

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-03 19:52:50 +01:00
Antonio Niño Díaz
0daec91683 Check code style as part of the CI tests
If checkpatch.pl detects any ERROR in the new patches, the Travis CI
build will fail.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-03 00:02:17 +01:00
Antonio Niño Díaz
cbaaec98ca Simplify helpers.h
`__attribute__((noreturn))` has been supported since GCC 2.5, that was
released October 22, 1993. It doesn't make sense to check if the version
is at least that one, we are compiling for C99, that is more modern. [1]

Also, remove the MSVC check. This code is never compiled with it so
there may be problems that need to be solved to make it compile. All
releases cross-compiled from linux. If there is an actual need to
support MSVC, the compiler definitions can be added again.

Also, if the compiler is not supported, the compiler helpers default to
nothing, so the code can still compile.

[1] https://gcc.gnu.org/onlinedocs/

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-02 22:53:48 +01:00
Antonio Niño Díaz
895d1d5813 Remove check for C11 in helpers.h
The mandatory CFLAGS in the Makefile make the compiler use C99.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-02 22:53:48 +01:00
Antonio Niño Díaz
e99a651165 Create makefile target to check all warnings
Remove '-Werror' from the default make target to make it easy for
regular users of RGBDS to compile the source code. Only a few basic
warnings are left in that target.

All the warnings have been moved to a new target called 'develop'. This
target is now the one used in Travis CI to check for problems during
compilation.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-02 22:53:48 +01:00
Antonio Niño Díaz
0ae69b3114 Rename stdnoreturn.h to helpers.h
This file will contain more compiler-specific helpers.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-02 22:53:48 +01:00
Antonio Niño Díaz
95ccc48d0c Enable -Wundef
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-02 22:53:48 +01:00
Antonio Niño Díaz
29253046d5 Remove C++ check in stdnoreturn.h
This isn't a C++ project, only keep checks for C compilers.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-02 22:53:48 +01:00
Antonio Niño Díaz
340362d984 Enable a few warning flags
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-02 22:53:48 +01:00
Antonio Niño Díaz
85ece88268 Add default clauses to switch statements
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-02 22:53:43 +01:00
Antonio Niño Díaz
516e4578ea Enable more optional warnings
-Wformat-truncation is set to 1 instead of 2 because in some cases the
return value of snprintf is used to warn about truncations but GCC still
creates a warning for it, preventing the compilation from continuing.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-01 01:42:55 +01:00
Antonio Niño Díaz
9829be1045 Enable -Wextra
-Wsign-compare has been disabled because flex generates a comparison
that triggers a warning and cannot be fixed in the code.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-01 01:42:55 +01:00
Antonio Niño Díaz
b28a16c0da Enable -Wpedantic
Fix a few warnings related needed to build the source with this option.

Add new exception to .checkpatch.conf.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-04-01 00:56:00 +01:00
Antonio Niño Díaz
4d13d57491 Fix behaviour of '@'
When '@' is used as argument of any instruction (LD, JR, JP, etc), the
address it refers to is the address of the first byte of the
instruction. When '@' is used with DB/DW/DL, it refers to the same
address it is being placed at. This means that instructions need an
offset of 1 byte and others need an offset of 0 bytes.

The assembler doesn't evaluate anything related to '@' because it would
only work in sections with a fixed base address. It is left to the
linker. This means that the offset needs to be added to the RPN
expression of the patch that is saved in the linker. It isn't enough by
adding an offset to the final expresion. The following value wouldn't be
calculated correctly (even if it doesn't make sense):

    JP @ * @

The correct patch is `(@ - 1) * (@ - 1)`, not `(@ * @) - 1`.

This patch introduces an offset on 1 byte by default in every line, and
sets it to 0 only if a DB/DW/DL is detected.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-03-31 00:43:25 +01:00
Antonio Niño Díaz
be6bc7460b Don't save '@' in map and sym files
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-03-31 00:43:25 +01:00
Antonio Niño Díaz
efdd42c6a8 Simplify parsing of variable-length lists
This change removes 2 reduce/reduce conflicts in the parser while
preserving the behaviour of the rules.

Note that now each list with empty elements will only print a warning
per line.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-03-31 00:43:02 +01:00
Antonio Niño Díaz
c1a97f6541 Allow to JR to numeric constants
Previously, JR was only allowed to labels (in the same section, or
different sections). When trying to JR to an address specified as a
numeric value, rgbasm would fail to calculate the JR offset (as it
doesn't know the final address of the JR so it can't calculate the
difference).

This patch makes rgblink calculate the offset whenever there is a JR.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-03-29 23:38:54 +01:00
74 changed files with 1693 additions and 1173 deletions

View File

@@ -16,6 +16,12 @@
# Show file line, not input line
--showfile
# Don't expect SPDX tag in the first line of a file
--ignore SPDX_LICENSE_TAG
# Don't expect Signed-off-by lines in commit messages
--no-signoff
# List of ignored rules
# ---------------------
@@ -53,6 +59,9 @@
# Prefer stdint.h types over kernel types
--ignore PREFER_KERNEL_TYPES
# Don't ask to replace sscanf by kstrto
--ignore SSCANF_TO_KSTRTO
# Parentheses can make the code clearer
--ignore UNNECESSARY_PARENTHESES

4
.gitignore vendored
View File

@@ -5,3 +5,7 @@ rgbgfx
*.o
*.exe
.checkpatch-camelcase.*
test/pokecrystal/*
test/pokered/*
test/ucity/*

48
.travis-checkpatch.sh Executable file
View File

@@ -0,0 +1,48 @@
#!/bin/bash
echo "Checking code style..."
# Return failure as soon as a command fails to execute
set -e
# Download checkpatch.pl and related files
echo "Getting checkpatch.pl..."
mkdir checkpatchdir
wget https://raw.githubusercontent.com/torvalds/linux/master/scripts/checkpatch.pl
mv checkpatch.pl checkpatchdir/checkpatch.pl
chmod +x checkpatchdir/checkpatch.pl
touch checkpatchdir/const_structs.checkpatch
touch checkpatchdir/spelling.txt
# Run checkpatch.pl on the new commits
echo "Running checkpatch.pl..."
fname=$(mktemp)
rc=0
git remote set-branches --add origin develop
git fetch
make CHECKPATCH=checkpatchdir/checkpatch.pl checkpatch > $fname
cat $fname
if grep "ERROR" $fname; then
# At least one error found
echo "Code style errors have been found!"
rc=1
else
echo "No code style errors found, your patches are ready!"
fi
# Cleanup
rm -rf checkpatchdir
exit $rc

View File

@@ -2,7 +2,7 @@
if [ $TRAVIS_OS_NAME = "osx" ]; then
brew update
brew install libpng pkg-config
brew install libpng pkg-config md5sha1sum
else # linux
sudo apt-get -qq update
sudo apt-get install -y -q bison flex libpng-dev pkg-config

View File

@@ -6,9 +6,14 @@ install:
- sudo make install
os:
- linux
- osx
compiler:
- clang
- gcc
script:
- cd test
- ./run-tests.sh
- cd test && ./run-tests.sh
matrix:
include:
- env: _="checkpatch"
script:
- ./.travis-checkpatch.sh

View File

@@ -70,11 +70,14 @@ copyright and the reference to the MIT License.
3. Create a new branch to work on. You could still work on ``develop``, but it's
easier that way.
4. Sign off your commits: ``git commit -s``
4. Compile your changes with ``make develop`` instead of just ``make``. This
target checks for additional warnings. Your patches shouldn't introduce any
new warning (but it may be possible to remove some warning checks if it makes
the code much easier).
5. Follow the Linux kernel coding style, which can be found in the file
``Documentation/process/coding-style.rst`` in the Linux kernel repository.
Note that the coding style isn't writen on stone, if there is a good reason
Note that the coding style isn't written in stone, if there is a good reason
to deviate from it, it should be fine.
6. Download the files ``checkpatch.pl``, ``const_structs.checkpatch`` and
@@ -90,4 +93,4 @@ copyright and the reference to the MIT License.
8. Create a pull request against the branch ``develop``.
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/develop`` to modify chains of commits.

View File

@@ -28,6 +28,8 @@ Other contributors
- Christophe Staïesse <chastai@skynet.be>
- David Brotz <dbrotz007@gmail.com>
- The Musl C library <http://www.musl-libc.org>
- obskyr <powpowd@gmail.com>

View File

@@ -26,7 +26,7 @@ PNGLDLIBS := `${PKG_CONFIG} --static --libs-only-l libpng`
VERSION_STRING := `git describe --tags --dirty --always 2>/dev/null`
WARNFLAGS := -Wall -Werror
WARNFLAGS := -Wall
# Overridable CFLAGS
CFLAGS := -g
@@ -48,6 +48,7 @@ all: rgbasm rgblink rgbfix rgbgfx
rgbasm_obj := \
src/asm/asmy.o \
src/asm/charmap.o \
src/asm/constexpr.o \
src/asm/fstack.o \
src/asm/globlex.o \
src/asm/lexer.o \
@@ -61,7 +62,7 @@ rgbasm_obj := \
src/version.o
src/asm/asmy.h: src/asm/asmy.c
src/asm/locallex.o src/asm/globlex.o src/asm/lexer.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 := \
src/link/assign.o \
@@ -160,6 +161,7 @@ install: all
# Target used to check the coding style of the whole codebase. '.y' and '.l'
# files aren't checked, unfortunately...
checkcodebase:
$Qfor file in `git ls-files | grep -E '\.c|\.h' | grep -v '\.html'`; do \
${CHECKPATCH} -f "$$file"; \
@@ -169,6 +171,7 @@ checkcodebase:
# 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'
# files aren't checked, unfortunately...
checkpatch:
$Qeval COMMON_COMMIT=$$(git merge-base HEAD origin/develop); \
for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do \
@@ -193,6 +196,25 @@ wwwman:
$Qmandoc ${MANDOC} src/link/rgblink.5 > docs/rgblink.5.html
$Qmandoc ${MANDOC} src/gfx/rgbgfx.1 > docs/rgbgfx.1.html
# This target is used during development in order to prevent adding new issues
# to the source code. All warnings are treated as errors in order to block the
# compilation and make the continous integration infrastructure return failure.
develop:
$Qenv make -j WARNFLAGS="-Werror -Wall -Wextra -Wpedantic \
-Wno-sign-compare -Wchkp -Wformat=2 -Wformat-overflow=2 \
-Wformat-truncation=1 -Wformat-y2k -Wswitch-enum -Wunused \
-Wuninitialized -Wunknown-pragmas -Wstrict-overflow=5 \
-Wstringop-overflow=4 -Walloc-zero -Wduplicated-cond \
-Wfloat-equal -Wshadow -Wcast-qual -Wcast-align -Wlogical-op \
-Wnested-externs -Wno-aggressive-loop-optimizations -Winline \
-Wundef -Wstrict-prototypes -Wold-style-definition \
-fsanitize=shift -fsanitize=integer-divide-by-zero \
-fsanitize=unreachable -fsanitize=vla-bound \
-fsanitize=signed-integer-overflow -fsanitize=bounds \
-fsanitize=object-size -fsanitize=bool -fsanitize=enum \
-fsanitize=alignment -fsanitize=null"
# Targets for the project maintainer to easily create Windows exes.
# This is not for Windows users!
# If you're building on Windows with Cygwin or Mingw, just follow the Unix
@@ -200,7 +222,7 @@ wwwman:
mingw32:
$Qenv PKG_CONFIG_PATH=/usr/i686-w64-mingw32/sys-root/mingw/lib/pkgconfig/ \
make CC=i686-w64-mingw32-gcc YACC=bison WARNFLAGS= -j
make CC=i686-w64-mingw32-gcc YACC=bison -j
$Qmv rgbasm rgbasm.exe
$Qmv rgblink rgblink.exe
$Qmv rgbfix rgbfix.exe
@@ -208,7 +230,7 @@ mingw32:
mingw64:
$Qenv PKG_CONFIG_PATH=/usr/x86_64-w64-mingw32/sys-root/mingw/lib/pkgconfig/ \
make CC=x86_64-w64-mingw32-gcc YACC=bison WARNFLAGS= -j
make CC=x86_64-w64-mingw32-gcc YACC=bison -j
$Qmv rgbasm rgbasm.exe
$Qmv rgblink rgblink.exe
$Qmv rgbfix rgbfix.exe

View File

@@ -55,8 +55,17 @@ To install RGBDS with all of the current changes in development (as seen on the
.. code:: sh
brew install rgbds --HEAD
1.3 Arch Linux
~~~~~~~~~~~~~~
1.3 Other UNIX-like systems
To install RGBDS through the AUR run
.. code:: sh
yaourt -S rgbds
1.4 Other UNIX-like systems
~~~~~~~~~~~~~~~~~~~~~~~~~~~
No official binaries of RGBDS are distributed for these systems, you must follow

View File

@@ -1148,7 +1148,17 @@ Cycles: 3
<div class="Pp"></div>
Bytes: 1
<div class="Pp"></div>
Flags: None affected.
Flags:
<ul class="Bl-bullet Bl-compact">
<li class="It-bullet"><b class="Sy" title="Sy">Z</b>: Set from bit 7 of the
popped low byte.</li>
<li class="It-bullet"><b class="Sy" title="Sy">N</b>: Set from bit 6 of the
popped low byte.</li>
<li class="It-bullet"><b class="Sy" title="Sy">H</b>: Set from bit 5 of the
popped low byte.</li>
<li class="It-bullet"><b class="Sy" title="Sy">C</b>: Set from bit 4 of the
popped low byte.</li>
</ul>
<h2 class="Ss" title="Ss" id="POP_r16"><a class="selflink" href="#POP_r16">POP
r16</a></h2>
Pop register <var class="Ar" title="Ar">r16</var> from the stack.
@@ -1160,7 +1170,11 @@ Bytes: 1
Flags: None affected.
<h2 class="Ss" title="Ss" id="PUSH_AF"><a class="selflink" href="#PUSH_AF">PUSH
AF</a></h2>
Push register <b class="Sy" title="Sy">AF</b> into the stack.
Push register <b class="Sy" title="Sy">AF</b> into the stack. The low byte's bit
7 corresponds to the <b class="Sy" title="Sy">Z</b> flag, its bit 6 to the
<b class="Sy" title="Sy">N</b> flag, bit 5 to the
<b class="Sy" title="Sy">H</b> flag, and bit 4 to the
<b class="Sy" title="Sy">C</b> flag. Bits 3 to 0 are reset.
<div class="Pp"></div>
Cycles: 4
<div class="Pp"></div>

View File

@@ -49,10 +49,11 @@ All pseudo&#x2010;ops, mnemonics and registers (reserved keywords) are
<div class="Pp"></div>
There are two syntaxes for comments. In both cases, a comment ends at the end of
the line. The most common one is: anything that follows a semicolon
&quot;;&quot; (that isn't inside a string) is a comment. There is another
format: anything that follows a &quot;*&quot; that is placed right at the
start of a line is a comment. The assembler removes all comments from the code
before doing anything else.
&#x2018;<code class="Li">;</code>&#x2019; (that isn't inside a string) is a
comment. There is another format: anything that follows a
&#x2018;<code class="Li">*</code>&#x2019; that is placed right at the start of
a line is a comment. The assembler removes all comments from the code before
doing anything else.
<div class="Pp"></div>
Sometimes lines can be too long and it may be necessary to split them. The
syntax to do so is the following one:
@@ -65,7 +66,7 @@ Sometimes lines can be too long and it may be necessary to split them. The
</div>
<div class="Pp"></div>
This works anywhere in the code except inside of strings. To split strings it is
needed to use <b class="Sy" title="Sy">STRCAT</b> like this:
needed to use <b class="Fn" title="Fn">STRCAT</b>() like this:
<div class="Pp"></div>
<div class="Bd" style="margin-left: 5.00ex;">
<pre class="Li">
@@ -74,99 +75,140 @@ This works anywhere in the code except inside of strings. To split strings it is
</pre>
</div>
<h2 class="Ss" title="Ss" id="Sections"><a class="selflink" href="#Sections">Sections</a></h2>
<b class="Ic" title="Ic">SECTION</b> <var class="Ar" title="Ar">name</var>,
<var class="Ar" title="Ar">type</var>
<div class="Pp"></div>
<b class="Ic" title="Ic">SECTION</b> <var class="Ar" title="Ar">name</var>,
<var class="Ar" title="Ar">type</var>,
<var class="Ar" title="Ar">options</var>
<div class="Pp"></div>
<b class="Ic" title="Ic">SECTION</b> <var class="Ar" title="Ar">name</var>,
<var class="Ar" title="Ar">type</var>[<var class="Ar" title="Ar">addr</var>]
<div class="Pp"></div>
<b class="Ic" title="Ic">SECTION</b> <var class="Ar" title="Ar">name</var>,
<var class="Ar" title="Ar">type</var>[<var class="Ar" title="Ar">addr</var>],
<var class="Ar" title="Ar">options</var>
<div class="Pp"></div>
Before you can start writing code, you must define a section. This tells the
assembler what kind of information follows and, if it is code, where to put
it.
<div class="Pp"></div>
<div class="Bd" style="margin-left: 5.00ex;">
<pre class="Li">
SECTION &quot;CoolStuff&quot;,ROMX
</pre>
</div>
<var class="Ar" title="Ar">name</var> is a string enclosed in double quotes and
can be a new name or the name of an existing section. All sections assembled
at the same time that have the same name and type are considered to be the
same section, and their code is put together in the object file generated by
the assembler. All other sections must have a unique name, even in different
source files, or the linker will treat it as an error.
<div class="Pp"></div>
This switches to the section called &quot;CoolStuff&quot; (or creates it if it
doesn't already exist) and it defines it as a code section. All sections
assembled at the same time that have the same name, type, etc, are considered
to be the same one, and their code is put together in the object file
generated by the assembler. All other sections must have a unique name, even
in different source files, or the linker will treat it as an error.
<div class="Pp"></div>
Possible section types are as follows:
Possible section <var class="Ar" title="Ar">type</var>s are as follows:
<dl class="Bl-tag">
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><b class="Sy" title="Sy">ROM0</b></dt>
<dd class="It-tag">A ROM section. Mapped to memory at $0000&#x2013;$3FFF (or
$0000-$7FFF if tiny ROM mode is enabled in
<a class="Xr" title="Xr">rgblink(1)</a>).</dd>
<dt class="It-tag"><a class="selflink" href="#ROM0"><b class="Cm" title="Cm" id="ROM0">ROM0</b></a></dt>
<dd class="It-tag">A ROM section. <var class="Ar" title="Ar">addr</var> can
range from $0000&#x2013;$3FFF (or $0000&#x2013;$7FFF if tiny ROM mode is
enabled in <a class="Xr" title="Xr">rgblink(1)</a>).</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><b class="Sy" title="Sy">ROMX</b></dt>
<dd class="It-tag">A banked ROM section. Mapped to memory at
$4000&#x2013;$7FFF. Valid banks range from 1 to 511. Not available if tiny
ROM mode is enabled in <a class="Xr" title="Xr">rgblink(1)</a>.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><b class="Sy" title="Sy">VRAM</b></dt>
<dd class="It-tag">A banked video RAM section. Mapped to memory at
$8000&#x2013;$9FFF. Can only allocate memory, not fill it. Valid banks are
0 and 1 but bank 1 isn't available if DMG mode is enabled in
<dt class="It-tag"><a class="selflink" href="#ROMX"><b class="Cm" title="Cm" id="ROMX">ROMX</b></a></dt>
<dd class="It-tag">A banked ROM section. <var class="Ar" title="Ar">addr</var>
can range from $4000&#x2013;$7FFF. <var class="Ar" title="Ar">bank</var>
can range from 1 to 511. Not available if tiny ROM mode is enabled in
<a class="Xr" title="Xr">rgblink(1)</a>.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><b class="Sy" title="Sy">SRAM</b></dt>
<dd class="It-tag">A banked external (save) RAM section. Mapped to memory at
$A000&#x2013;$BFFF. Can only allocate memory, not fill it. Valid banks
range from 0 to 15.</dd>
<dt class="It-tag"><a class="selflink" href="#VRAM"><b class="Cm" title="Cm" id="VRAM">VRAM</b></a></dt>
<dd class="It-tag">A banked video RAM section.
<var class="Ar" title="Ar">addr</var> can range from $8000&#x2013;$9FFF.
<var class="Ar" title="Ar">bank</var> can be 0 or 1 but bank 1 is
unavailable if DMG mode is enabled in
<a class="Xr" title="Xr">rgblink(1)</a>. Memory in this section can only
be allocated with <b class="Sy" title="Sy">DS</b>, not filled with
data.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><b class="Sy" title="Sy">WRAM0</b></dt>
<dd class="It-tag">A general-purpose RAM section. Mapped to memory at
$C000&#x2013;$CFFF, or $C000-$DFFF if DMG mode is enabled in
<a class="Xr" title="Xr">rgblink(1)</a>. Can only allocate memory, not
fill it.</dd>
<dt class="It-tag"><a class="selflink" href="#SRAM"><b class="Cm" title="Cm" id="SRAM">SRAM</b></a></dt>
<dd class="It-tag">A banked external (save) RAM section.
<var class="Ar" title="Ar">addr</var> can range from $A000&#x2013;$BFFF.
<var class="Ar" title="Ar">bank</var> can range from 0 to 15. Memory in
this section can only be allocated with <b class="Sy" title="Sy">DS</b>,
not filled with data.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><b class="Sy" title="Sy">WRAMX</b></dt>
<dd class="It-tag">A banked general-purpose RAM section. Mapped to memory at
$D000&#x2013;$DFFF. Can only allocate memory, not fill it. Valid banks
range from 1 to 7. Not available if DMG mode is enabled in
<dt class="It-tag"><a class="selflink" href="#WRAM0"><b class="Cm" title="Cm" id="WRAM0">WRAM0</b></a></dt>
<dd class="It-tag">A general-purpose RAM section.
<var class="Ar" title="Ar">addr</var> can range from $C000&#x2013;$CFFF,
or $C000&#x2013;$DFFF if DMG mode is enabled in
<a class="Xr" title="Xr">rgblink(1)</a>. Memory in this section can only
be allocated with <b class="Sy" title="Sy">DS</b>, not filled with
data.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#WRAMX"><b class="Cm" title="Cm" id="WRAMX">WRAMX</b></a></dt>
<dd class="It-tag">A banked general-purpose RAM section.
<var class="Ar" title="Ar">addr</var> can range from $D000&#x2013;$DFFF.
<var class="Ar" title="Ar">bank</var> can range from 1 to 7. Memory in
this section can only be allocated with <b class="Sy" title="Sy">DS</b>,
not filled with data. Not available if DMG mode is enabled in
<a class="Xr" title="Xr">rgblink(1)</a>.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><b class="Sy" title="Sy">OAM</b></dt>
<dd class="It-tag">An object attributes RAM section. Mapped to memory at
$FE00-$FE9F. Can only allocate memory, not fill it.</dd>
<dt class="It-tag"><a class="selflink" href="#OAM"><b class="Cm" title="Cm" id="OAM">OAM</b></a></dt>
<dd class="It-tag">An object attributes RAM section.
<var class="Ar" title="Ar">addr</var> can range from $FE00-$FE9F. Memory
in this section can only be allocated with
<b class="Sy" title="Sy">DS</b>, not filled with data.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><b class="Sy" title="Sy">HRAM</b></dt>
<dd class="It-tag">A high RAM section. Mapped to memory at $FF80&#x2013;$FFFE.
Can only allocate memory, not fill it.
<dt class="It-tag"><a class="selflink" href="#HRAM"><b class="Cm" title="Cm" id="HRAM">HRAM</b></a></dt>
<dd class="It-tag">A high RAM section. <var class="Ar" title="Ar">addr</var>
can range from $FF80&#x2013;$FFFE. Memory in this section can only be
allocated with <b class="Sy" title="Sy">DS</b>, not filled with data.
<div class="Pp"></div>
NOTE: If you use this method of allocating HRAM the assembler will NOT
choose the short addressing mode in the LD instructions
<b class="Sy" title="Sy">LD [$FF00+n8],A</b> and
<b class="Sy" title="Sy">LD A,[$FF00+n8]</b> because the actual address
calculation is done by the linker. If you find this undesirable you can
use <b class="Ic" title="Ic">RSSET</b> <span class="No">/</span>
<b class="Ic" title="Ic">RB</b> <span class="No">/</span>
<b class="Ic" title="Ic">RW</b> instead or use the
<b class="Sy" title="Sy">LDH [$FF00+n8],A</b> and
<b class="Sy" title="Sy">Note</b>: If you use this method of allocating HRAM
the assembler will <i class="Em" title="Em">not</i> choose the short
addressing mode in the LD instructions <b class="Sy" title="Sy">LD
[$FF00+n8],A</b> and <b class="Sy" title="Sy">LD A,[$FF00+n8]</b> because
the actual address calculation is done by the linker. If you find this
undesirable you can use <b class="Ic" title="Ic">RSSET</b>,
<b class="Ic" title="Ic">RB</b>, or <b class="Ic" title="Ic">RW</b>
instead or use the <b class="Sy" title="Sy">LDH [$FF00+n8],A</b> and
<b class="Sy" title="Sy">LDH A,[$FF00+n8]</b> syntax instead. This forces
the assembler to emit the correct instruction and the linker to check if
the value is in the correct range. This optimization can be disabled by
passing the <b class="Fl" title="Fl">-L</b> flag to
<b class="Sy" title="Sy">rgbasm</b> as explained in
<a class="Xr" title="Xr">rgbasm(1)</a>.</dd>
</dl>
<div class="Pp"></div>
A section is usually defined as a floating one, but the code can restrict where
the linker can place it.
<var class="Ar" title="Ar">option</var>s are comma separated and may include:
<dl class="Bl-tag">
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#BANK"><b class="Cm" title="Cm" id="BANK">BANK</b></a>[<var class="Ar" title="Ar">bank</var>]</dt>
<dd class="It-tag">Specify which <var class="Ar" title="Ar">bank</var> for the
linker to place the section.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#ALIGN"><b class="Cm" title="Cm" id="ALIGN">ALIGN</b></a>[<var class="Ar" title="Ar">align</var>]</dt>
<dd class="It-tag">Place the section at an address whose
<var class="Ar" title="Ar">align</var> least&#x2010;significant bits are
zero. It is a syntax error to use this option with
<var class="Ar" title="Ar">addr</var>.</dd>
</dl>
<div class="Pp"></div>
If a section is defined with no indications, it is a floating section. The
linker will decide where to place it in the final binary and it has no
obligation to follow any specific rules. The following example defines a
section that can be placed anywhere in any ROMX bank:
If [<var class="Ar" title="Ar">addr</var>] is not specified, the section is
considered &#x201C;floating&#x201D;; the linker will automatically calculate
an appropriate address for the section. Similarly, if
<b class="Cm" title="Cm">BANK</b>[<var class="Ar" title="Ar">bank</var>] is
not specified, the linker will automatically find a bank with enough space.
<div class="Pp"></div>
Sections can also be placed by using a linkerscript file. The format is
described in <a class="Xr" title="Xr">rgblink(5)</a>. They allow the user to
place floating sections in the desired bank in the order specified in the
script. This is useful if the sections can't be placed at an address manually
because the size may change, but they have to be together.
<div class="Pp"></div>
Section examples:
<div class="Pp"></div>
<div class="Bd" style="margin-left: 5.00ex;">
<pre class="Li">
@@ -174,8 +216,19 @@ If a section is defined with no indications, it is a floating section. The
</pre>
</div>
<div class="Pp"></div>
If it is needed, the following syntax can be used to fix the base address of the
section:
This switches to the section called &#x201C;CoolStuff&#x201D; (or creates it if
it doesn't already exist) and defines it as a code section.
<div class="Pp"></div>
The following example defines a section that can be placed anywhere in any ROMX
bank:
<div class="Pp"></div>
<div class="Bd" style="margin-left: 5.00ex;">
<pre class="Li">
SECTION &quot;CoolStuff&quot;,ROMX
</pre>
</div>
<div class="Pp"></div>
If it is needed, the the base address of the section can be specified:
<div class="Pp"></div>
<div class="Bd" style="margin-left: 5.00ex;">
<pre class="Li">
@@ -183,8 +236,7 @@ If it is needed, the following syntax can be used to fix the base address of the
</pre>
</div>
<div class="Pp"></div>
It won't, however, fix the bank number, which is left to the linker. If you also
want to specify the bank you can do:
An example with a fixed bank:
<div class="Pp"></div>
<div class="Bd" style="margin-left: 5.00ex;">
<pre class="Li">
@@ -201,11 +253,7 @@ And if you only want to force the section into a certain bank, and not it's
</pre>
</div>
<div class="Pp"></div>
In addition, you can specify byte alignment for a section. This ensures that the
section starts at a memory address where the given number of least-significant
bits are 0. This can be used along with <b class="Ic" title="Ic">BANK</b>, if
desired. However, if an alignment is specified, the base address must be left
unassigned. This can be useful when using DMA to copy data or when it is
Alignment examples: one use could be when using DMA to copy data or when it is
needed to align the start of an array to 256 bytes to optimize the code that
accesses it.
<div class="Pp"></div>
@@ -217,26 +265,23 @@ In addition, you can specify byte alignment for a section. This ensures that the
</pre>
</div>
<div class="Pp"></div>
HINT: If you think this is a lot of typing for doing a simple
<b class="Ic" title="Ic">ORG</b> type thing you can quite easily write an
<b class="Sy" title="Sy">Hint</b>: If you think this is a lot of typing for
doing a simple &#x201C;org&#x201D; type thing you can quite easily write an
intelligent macro (called <b class="Ic" title="Ic">ORG</b> for example) that
uses <b class="Ic" title="Ic">@</b> for the section name and determines
correct section type etc as arguments for
<b class="Ic" title="Ic">SECTION</b>.
<div class="Pp"></div>
<h2 class="Ss" title="Ss" id="Section_Stack"><a class="selflink" href="#Section_Stack">Section
Stack</a></h2>
<b class="Ic" title="Ic">POPS</b> and <b class="Ic" title="Ic">PUSHS</b> provide
the interface to the section stack. <b class="Ic" title="Ic">PUSHS</b> will
push the current section context on the section stack.
<b class="Ic" title="Ic">POPS</b> can then later be used to restore it. Useful
for defining sections in included files when you don't want to destroy the
section context for the program that included your file. The number of entries
in the stack is limited only by the amount of memory in your machine.
the interface to the section stack.
<div class="Pp"></div>
Sections can also be placed by using a linkerscript file. The format is
described in <a class="Xr" title="Xr">rgblink(5)</a>. They allow the user to
place floating sections in the desired bank in the order specified in the
script. This is useful if the sections can't be placed at an address manually
because the size may change, but they have to be together.
<b class="Ic" title="Ic">PUSHS</b> will push the current section context on the
section stack. <b class="Ic" title="Ic">POPS</b> can then later be used to
restore it. Useful for defining sections in included files when you don't want
to destroy the section context for the program that included your file. The
number of entries in the stack is limited only by the amount of memory in your
machine.
<h1 class="Sh" title="Sh" id="SYMBOLS"><a class="selflink" href="#SYMBOLS">SYMBOLS</a></h1>
<h2 class="Ss" title="Ss" id="Symbols"><a class="selflink" href="#Symbols">Symbols</a></h2>
RGBDS supports several types of symbols:
@@ -254,7 +299,7 @@ RGBDS supports several types of symbols:
<dt class="It-hang"><b class="Sy" title="Sy">String equate</b>
(<b class="Sy" title="Sy">EQUS</b>)</dt>
<dd class="It-hang">Give a frequently used string a name. Can also be used as
a mini-macro, like #define in C.</dd>
a mini-macro, like <b class="Fd" title="Fd">#define</b> in C.</dd>
<dt class="It-hang"><b class="Sy" title="Sy">MACRO</b></dt>
<dd class="It-hang">A block of code or pseudo instructions that you invoke
like any other mnemonic. You can give them arguments too.</dd>
@@ -370,18 +415,14 @@ str_SIZEOF = 259
There are four commands in the RS group of commands:
<table class="Bl-column">
<colgroup>
<col style="width: 15.00ex;"/>
<col style="min-width: 10.00ex;"/>
<col style="min-width: 15.00ex;"/>
</colgroup>
<tr class="It-column">
<td class="It-column"><b class="Sy" title="Sy">Command</b></td>
<td class="It-column"></td>
<td class="It-column"></td>
<td class="It-column"><b class="Sy" title="Sy">Meaning</b></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#RSRESET"><b class="Ic" title="Ic" id="RSRESET">RSRESET</b></a></td>
<td class="It-column"></td>
<td class="It-column">Resets the _RS counter to zero.</td>
</tr>
<tr class="It-column">
@@ -425,7 +466,7 @@ str_SIZEOF = 259
<div class="Pp"></div>
EQUS is used to define string-symbols. Wherever the assembler meets a string
symbol its name is replaced with its value. If you are familiar with C you
can think of it as the same as #define.
can think of it as the same as <b class="Fd" title="Fd">#define .</b>
<div class="Pp"></div>
<div class="Bd" style="margin-left: 5.00ex;">
<pre class="Li">
@@ -604,11 +645,10 @@ ENDM
</div>
<div class="Pp"></div>
<b class="Ic" title="Ic">SHIFT</b> is a special command only available in
macros. Very useful in REPT-blocks. It will &quot;shift&quot; the
arguments by one &quot;to the left&quot;. <b class="Ic" title="Ic">\1</b>
will get the value of <b class="Ic" title="Ic">\2</b>,
<b class="Ic" title="Ic">\2</b> will get the value in
<b class="Ic" title="Ic">\3</b> and so forth.
macros. Very useful in REPT-blocks. It will shift the arguments by one to
the left. <b class="Ic" title="Ic">\1</b> will get the value of
<b class="Ic" title="Ic">\2</b>, <b class="Ic" title="Ic">\2</b> will get
the value in <b class="Ic" title="Ic">\3</b> and so forth.
<div class="Pp"></div>
This is the only way of accessing the value of arguments from 10 to
256.</dd>
@@ -658,62 +698,52 @@ Note that string symbols that are part of a <b class="Ic" title="Ic">PURGE</b>
The following symbols are defined by the assembler:
<table class="Bl-column" style="margin-left: 6.00ex;">
<colgroup>
<col style="width: 15.00ex;"/>
<col style="width: 15.00ex;"/>
<col style="min-width: 10.00ex;"/>
<col style="width: 7.80ex;"/>
<col style="min-width: 18.00ex;"/>
</colgroup>
<tr class="It-column">
<td class="It-column"><b class="Sy" title="Sy">Type</b></td>
<td class="It-column"><b class="Sy" title="Sy">Name</b></td>
<td class="It-column"></td>
<td class="It-column"><b class="Sy" title="Sy">Contents</b></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#@"><b class="Ic" title="Ic" id="@">@</b></a></td>
<td class="It-column"></td>
<td class="It-column">PC value</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#_PI"><b class="Ic" title="Ic" id="_PI">_PI</b></a></td>
<td class="It-column"></td>
<td class="It-column">Fixed point &#x03C0;</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#SET"><b class="Ic" title="Ic" id="SET">SET</b></a></td>
<td class="It-column"><a class="selflink" href="#_RS"><b class="Ic" title="Ic" id="_RS">_RS</b></a></td>
<td class="It-column"></td>
<td class="It-column">_RS Counter</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#_NARG"><b class="Ic" title="Ic" id="_NARG">_NARG</b></a></td>
<td class="It-column"></td>
<td class="It-column">Number of arguments passed to macro</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#__LINE__"><b class="Ic" title="Ic" id="__LINE__">__LINE__</b></a></td>
<td class="It-column"></td>
<td class="It-column">The current line number</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQUS"><b class="Ic" title="Ic" id="EQUS">EQUS</b></a></td>
<td class="It-column"><a class="selflink" href="#__FILE__"><b class="Ic" title="Ic" id="__FILE__">__FILE__</b></a></td>
<td class="It-column"></td>
<td class="It-column">The current filename</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQUS"><b class="Ic" title="Ic" id="EQUS">EQUS</b></a></td>
<td class="It-column"><a class="selflink" href="#__DATE__"><b class="Ic" title="Ic" id="__DATE__">__DATE__</b></a></td>
<td class="It-column"></td>
<td class="It-column">Today's date</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQUS"><b class="Ic" title="Ic" id="EQUS">EQUS</b></a></td>
<td class="It-column"><a class="selflink" href="#__TIME__"><b class="Ic" title="Ic" id="__TIME__">__TIME__</b></a></td>
<td class="It-column"></td>
<td class="It-column">The current time</td>
</tr>
<tr class="It-column">
@@ -729,55 +759,46 @@ The following symbols are defined by the assembler:
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#__UTC_YEAR__"><b class="Ic" title="Ic" id="__UTC_YEAR__">__UTC_YEAR__</b></a></td>
<td class="It-column"></td>
<td class="It-column">Today's year</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#__UTC_MONTH__"><b class="Ic" title="Ic" id="__UTC_MONTH__">__UTC_MONTH__</b></a></td>
<td class="It-column"></td>
<td class="It-column">Today's month number, 1-12</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#__UTC_DAY__"><b class="Ic" title="Ic" id="__UTC_DAY__">__UTC_DAY__</b></a></td>
<td class="It-column"></td>
<td class="It-column">Today's day of the month, 1-31</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#__UTC_HOUR__"><b class="Ic" title="Ic" id="__UTC_HOUR__">__UTC_HOUR__</b></a></td>
<td class="It-column"></td>
<td class="It-column">Current hour, 0-23</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#__UTC_MINUTE__"><b class="Ic" title="Ic" id="__UTC_MINUTE__">__UTC_MINUTE__</b></a></td>
<td class="It-column"></td>
<td class="It-column">Current minute, 0-59</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#__UTC_SECOND__"><b class="Ic" title="Ic" id="__UTC_SECOND__">__UTC_SECOND__</b></a></td>
<td class="It-column"></td>
<td class="It-column">Current second, 0-59</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#__RGBDS_MAJOR__"><b class="Ic" title="Ic" id="__RGBDS_MAJOR__">__RGBDS_MAJOR__</b></a></td>
<td class="It-column"></td>
<td class="It-column">Major version number of RGBDS.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#__RGBDS_MINOR__"><b class="Ic" title="Ic" id="__RGBDS_MINOR__">__RGBDS_MINOR__</b></a></td>
<td class="It-column"></td>
<td class="It-column">Minor version number of RGBDS.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#EQU"><b class="Ic" title="Ic" id="EQU">EQU</b></a></td>
<td class="It-column"><a class="selflink" href="#__RGBDS_PATCH__"><b class="Ic" title="Ic" id="__RGBDS_PATCH__">__RGBDS_PATCH__</b></a></td>
<td class="It-column"></td>
<td class="It-column">Patch version number of RGBDS.</td>
</tr>
</table>
@@ -1039,15 +1060,15 @@ A great number of operators you can use in expressions are available (listed in
order of precedence):
<table class="Bl-column" style="margin-left: 6.00ex;">
<colgroup>
<col style="width: 15.00ex;"/>
<col style="min-width: 10.00ex;"/>
<col style="min-width: 8.00ex;"/>
</colgroup>
<tr class="It-column">
<td class="It-column"><b class="Sy" title="Sy">Operator</b></td>
<td class="It-column"><b class="Sy" title="Sy">Meaning</b></td>
</tr>
<tr class="It-column">
<td class="It-column">()</td>
<td class="It-column"><a class="selflink" href="#(_)"><code class="Li" id="(_)">(
)</code></a></td>
<td class="It-column">Precedence override</td>
</tr>
<tr class="It-column">
@@ -1070,8 +1091,8 @@ A great number of operators you can use in expressions are available (listed in
<td class="It-column">Shift left/right</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#&amp;"><code class="Li" id="&amp;">&amp;</code></a>
| <a class="selflink" href="#^"><code class="Li" id="^">^</code></a></td>
<td class="It-column"><a class="selflink" href="#&amp;_|_^"><code class="Li" id="&amp;_|_^">&amp;
| ^</code></a></td>
<td class="It-column">Binary and/or/xor</td>
</tr>
<tr class="It-column">
@@ -1096,7 +1117,7 @@ A great number of operators you can use in expressions are available (listed in
<td class="It-column">Boolean and/or</td>
</tr>
<tr class="It-column">
<td class="It-column">!</td>
<td class="It-column"><a class="selflink" href="#!"><code class="Li" id="!">!</code></a></td>
<td class="It-column">Unary Boolean not</td>
</tr>
</table>
@@ -1127,57 +1148,90 @@ Some things are different for fixed-point math, though, which is why you have
the following functions to use:
<table class="Bl-column" style="margin-left: 6.00ex;">
<colgroup>
<col style="width: 15.00ex;"/>
<col style="min-width: 10.00ex;"/>
<col style="min-width: 11.00ex;"/>
</colgroup>
<tr class="It-column">
<td class="It-column"><b class="Sy" title="Sy">Name</b></td>
<td class="It-column"></td>
<td class="It-column"><b class="Sy" title="Sy">Operation</b></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#DIV(x,y)"><code class="Li" id="DIV(x,y)">DIV(x,y)</code></a></td>
<td class="It-column"></td>
<td class="It-column">x/y</td>
<td class="It-column"><b class="Fn" title="Fn">DIV</b>(<var class="Fa" title="Fa">x</var>,
<var class="Fa" title="Fa">y</var>)</td>
<td class="It-column">
<math class="eqn">
<mrow><mi>x</mi><mo>&#x00F7;</mo><mi>y</mi></mrow>
</math>
</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#MUL(x,y)"><code class="Li" id="MUL(x,y)">MUL(x,y)</code></a></td>
<td class="It-column"></td>
<td class="It-column">x*y</td>
<td class="It-column"><b class="Fn" title="Fn">MUL</b>(<var class="Fa" title="Fa">x</var>,
<var class="Fa" title="Fa">y</var>)</td>
<td class="It-column">
<math class="eqn">
<mrow><mi>x</mi><mo>&#x00D7;</mo><mi>y</mi></mrow>
</math>
</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#SIN(x)"><code class="Li" id="SIN(x)">SIN(x)</code></a></td>
<td class="It-column"></td>
<td class="It-column">sin(x)</td>
<td class="It-column"><b class="Fn" title="Fn">SIN</b>(<var class="Fa" title="Fa">x</var>)</td>
<td class="It-column">
<math class="eqn">
<mrow><mi>sin</mi><mo>(</mo><mi>x</mi><mo>)</mo></mrow>
</math>
</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#COS(x)"><code class="Li" id="COS(x)">COS(x)</code></a></td>
<td class="It-column"></td>
<td class="It-column">cos(x)</td>
<td class="It-column"><b class="Fn" title="Fn">COS</b>(<var class="Fa" title="Fa">x</var>)</td>
<td class="It-column">
<math class="eqn">
<mrow><mi>cos</mi><mo>(</mo><mi>x</mi><mo>)</mo></mrow>
</math>
</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#TAN(x)"><code class="Li" id="TAN(x)">TAN(x)</code></a></td>
<td class="It-column"></td>
<td class="It-column">tan(x)</td>
<td class="It-column"><b class="Fn" title="Fn">TAN</b>(<var class="Fa" title="Fa">x</var>)</td>
<td class="It-column">
<math class="eqn">
<mrow><mi>tan</mi><mo>(</mo><mi>x</mi><mo>)</mo></mrow>
</math>
</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#ASIN(x)"><code class="Li" id="ASIN(x)">ASIN(x)</code></a></td>
<td class="It-column"></td>
<td class="It-column">arcsin(x)</td>
<td class="It-column"><b class="Fn" title="Fn">ASIN</b>(<var class="Fa" title="Fa">x</var>)</td>
<td class="It-column">
<math class="eqn">
<mrow><mi>asin</mi><mo>(</mo><mi>x</mi><mo>)</mo></mrow>
</math>
</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#ACOS(x)"><code class="Li" id="ACOS(x)">ACOS(x)</code></a></td>
<td class="It-column"></td>
<td class="It-column">arccos(x)</td>
<td class="It-column"><b class="Fn" title="Fn">ACOS</b>(<var class="Fa" title="Fa">x</var>)</td>
<td class="It-column">
<math class="eqn">
<mrow><mi>acos</mi><mo>(</mo><mi>x</mi><mo>)</mo></mrow>
</math>
</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#ATAN(x)"><code class="Li" id="ATAN(x)">ATAN(x)</code></a></td>
<td class="It-column"></td>
<td class="It-column">arctan(x)</td>
<td class="It-column"><b class="Fn" title="Fn">ATAN</b>(<var class="Fa" title="Fa">x</var>)</td>
<td class="It-column">
<math class="eqn">
<mrow><mi>atan</mi><mo>(</mo><mi>x</mi><mo>)</mo></mrow>
</math>
</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#ATAN2(x,y)"><code class="Li" id="ATAN2(x,y)">ATAN2(x,y)</code></a></td>
<td class="It-column">Angle between (x,y) and (1,0)</td>
<td class="It-column"><b class="Fn" title="Fn">ATAN2</b>(<var class="Fa" title="Fa">x</var>,
<var class="Fa" title="Fa">y</var>)</td>
<td class="It-column">Angle between
<math class="eqn">
<mrow><mo>(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo>)</mo></mrow>
</math>
and
<math class="eqn">
<mrow><mo>(</mo><mn>1</mn><mo>,</mo><mn>0</mn><mo>)</mo></mrow>
</math>
</td>
</tr>
</table>
<div class="Pp"></div>
@@ -1203,8 +1257,7 @@ The most basic string expression is any number of characters contained in double
there are a number of commands you can use within a string:
<table class="Bl-column" style="margin-left: 6.00ex;">
<colgroup>
<col style="width: 15.00ex;"/>
<col style="min-width: 10.00ex;"/>
<col style="min-width: 6.00ex;"/>
</colgroup>
<tr class="It-column">
<td class="It-column"><b class="Sy" title="Sy">String</b></td>
@@ -1250,7 +1303,7 @@ The most basic string expression is any number of characters contained in double
</tr>
</table>
<div class="Pp"></div>
A funky feature is <b class="Sy" title="Sy">{symbol}</b> withing a string. This
A funky feature is <b class="Sy" title="Sy">{symbol}</b> within a string. 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 it's a
numeric symbol, the value is converted to hexadecimal notation and inserted as
@@ -1258,7 +1311,7 @@ A funky feature is <b class="Sy" title="Sy">{symbol}</b> withing a string. This
<div class="Pp"></div>
HINT: The <b class="Sy" title="Sy">{symbol}</b> construct can also be used
outside strings. The symbol's value is again inserted as a string. This is
just a short way of doing &quot;{symbol}&quot;.
just a short way of doing &#x201C;{symbol}&#x201D;.
<div class="Pp"></div>
Whenever the macro-language expects a string you can actually use a string
expression. This consists of one or more of these function (yes, you can nest
@@ -1266,45 +1319,47 @@ Whenever the macro-language expects a string you can actually use a string
used as part of an integer expression!
<table class="Bl-column">
<colgroup>
<col style="width: 15.00ex;"/>
<col style="min-width: 10.00ex;"/>
<col style="min-width: 20.00ex;"/>
</colgroup>
<tr class="It-column">
<td class="It-column"><b class="Sy" title="Sy">Name</b></td>
<td class="It-column"></td>
<td class="It-column"></td>
<td class="It-column"><b class="Sy" title="Sy">Operation</b></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#STRLEN(string)"><code class="Li" id="STRLEN(string)">STRLEN(string)</code></a></td>
<td class="It-column"><b class="Fn" title="Fn">STRLEN</b>(<var class="Fa" title="Fa">string</var>)</td>
<td class="It-column">Returns the number of characters in string</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#STRCAT(str1,str2)"><code class="Li" id="STRCAT(str1,str2)">STRCAT(str1,str2)</code></a></td>
<td class="It-column"><b class="Fn" title="Fn">STRCAT</b>(<var class="Fa" title="Fa">str1</var>,
<var class="Fa" title="Fa">str2</var>)</td>
<td class="It-column">Appends str2 to str1.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#STRCMP(str1,str2)"><code class="Li" id="STRCMP(str1,str2)">STRCMP(str1,str2)</code></a></td>
<td class="It-column"><b class="Fn" title="Fn">STRCMP</b>(<var class="Fa" title="Fa">str1</var>,
<var class="Fa" title="Fa">str2</var>)</td>
<td class="It-column">Returns negative if str1 is alphabetically lower than
str2, zero if they match, positive if str1 is greater than str2.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#STRIN(str1,str2)"><code class="Li" id="STRIN(str1,str2)">STRIN(str1,str2)</code></a></td>
<td class="It-column"><b class="Fn" title="Fn">STRIN</b>(<var class="Fa" title="Fa">str1</var>,
<var class="Fa" title="Fa">str2</var>)</td>
<td class="It-column">Returns the position of str2 in str1 or zero if it's
not present (first character is position 1).</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#STRSUB(str,pos,len)"><code class="Li" id="STRSUB(str,pos,len)">STRSUB(str,pos,len)</code></a></td>
<td class="It-column"><b class="Fn" title="Fn">STRSUB</b>(<var class="Fa" title="Fa">str</var>,
<var class="Fa" title="Fa">pos</var>,
<var class="Fa" title="Fa">len</var>)</td>
<td class="It-column">Returns a substring from str starting at pos (first
character is position 1) and with len characters.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#STRUPR(str)"><code class="Li" id="STRUPR(str)">STRUPR(str)</code></a></td>
<td class="It-column"><b class="Fn" title="Fn">STRUPR</b>(<var class="Fa" title="Fa">str</var>)</td>
<td class="It-column">Converts all characters in str to capitals and returns
the new string.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#STRLWR(str)"><code class="Li" id="STRLWR(str)">STRLWR(str)</code></a></td>
<td class="It-column"><b class="Fn" title="Fn">STRLWR</b>(<var class="Fa" title="Fa">str</var>)</td>
<td class="It-column">Converts all characters in str to lower case and
returns the new string.</td>
</tr>
@@ -1340,38 +1395,40 @@ CHARMAP &quot;A&quot;, 128
There are a few other functions that do various useful things:
<table class="Bl-column">
<colgroup>
<col style="width: 15.00ex;"/>
<col style="min-width: 10.00ex;"/>
<col style="min-width: 9.00ex;"/>
</colgroup>
<tr class="It-column">
<td class="It-column"><b class="Sy" title="Sy">Name</b></td>
<td class="It-column"></td>
<td class="It-column"></td>
<td class="It-column"><b class="Sy" title="Sy">Operation</b></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#BANK(@/str/lbl)"><code class="Li" id="BANK(@/str/lbl)">BANK(@/str/lbl)</code></a></td>
<td class="It-column">Returns a bank number. If the argument is the symbol
<b class="Ic" title="Ic">@,</b> this function returns the bank of the
current section. If the argument is a string, it returns the bank of the
section that has that name. If the argument is a label, it returns the
bank number the label is in. For labels, as the linker has to resolve
this, it can't be used when the expression has to be constant.</td>
<td class="It-column"><b class="Fn" title="Fn">BANK</b>(<var class="Fa" title="Fa">arg</var>)</td>
<td class="It-column">Returns a bank number. If
<var class="Ar" title="Ar">arg</var> is the symbol
<b class="Ic" title="Ic">@</b>, this function returns the bank of the
current section. If <var class="Ar" title="Ar">arg</var> is a string, it
returns the bank of the section that has that name. If
<var class="Ar" title="Ar">arg</var> is a label, it returns the bank
number the label is in. For labels, as the linker has to resolve this, it
can't be used when the expression has to be constant.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#DEF(label)"><code class="Li" id="DEF(label)">DEF(label)</code></a></td>
<td class="It-column">Returns TRUE if label has been defined.</td>
<td class="It-column"><b class="Fn" title="Fn">DEF</b>(<var class="Fa" title="Fa">label</var>)</td>
<td class="It-column">Returns TRUE if <var class="Ar" title="Ar">label</var>
has been defined.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#HIGH(r16/cnst/lbl)"><code class="Li" id="HIGH(r16/cnst/lbl)">HIGH(r16/cnst/lbl)</code></a></td>
<td class="It-column">Returns the top 8 bits of the operand if it is a label
or constant, or the top 8-bit register if it is a 16-bit register.</td>
<td class="It-column"><b class="Fn" title="Fn">HIGH</b>(<var class="Fa" title="Fa">arg</var>)</td>
<td class="It-column">Returns the top 8 bits of the operand if
<var class="Ar" title="Ar">arg</var> is a label or constant, or the top
8-bit register if it is a 16-bit register.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#LOW(r16/cnst/lbl)"><code class="Li" id="LOW(r16/cnst/lbl)">LOW(r16/cnst/lbl)</code></a></td>
<td class="It-column">Returns the bottom 8 bits of the operand if it is a
label or constant, or the bottom 8-bit register if it is a 16-bit register
(AF isn't a valid register for this function).</td>
<td class="It-column"><b class="Fn" title="Fn">LOW</b>(<var class="Fa" title="Fa">arg</var>)</td>
<td class="It-column">Returns the bottom 8 bits of the operand if
<var class="Ar" title="Ar">arg</var> is a label or constant, or the bottom
8-bit register if it is a 16-bit register (AF isn't a valid register for
this function).</td>
</tr>
</table>
<h1 class="Sh" title="Sh" id="MISCELLANEOUS"><a class="selflink" href="#MISCELLANEOUS">MISCELLANEOUS</a></h1>
@@ -1404,180 +1461,6 @@ The options that OPT can modify are currently: <b class="Sy" title="Sy">b</b>,
want to destroy the options set by the program that included your file. The
stacks number of entries is limited only by the amount of memory in your
machine.
<h1 class="Sh" title="Sh" id="ALPHABETICAL_LIST_OF_KEYWORDS"><a class="selflink" href="#ALPHABETICAL_LIST_OF_KEYWORDS">ALPHABETICAL
LIST OF KEYWORDS</a></h1>
<dl class="Bl-inset Bl-compact">
<dt class="It-inset"><a class="Sx" title="Sx" href="#@">@</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__DATE__">__DATE__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__FILE__">__FILE__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__ISO_8601_LOCAL__">__ISO_8601_LOCAL__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__ISO_8601_UTC__">__ISO_8601_UTC__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__LINE__">__LINE__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__TIME__">__TIME__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__RGBDS_MAJOR__">__RGBDS_MAJOR__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__RGBDS_MINOR__">__RGBDS_MINOR__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__RGBDS_PATCH__">__RGBDS_PATCH__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__UTC_YEAR__">__UTC_YEAR__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__UTC_MONTH__">__UTC_MONTH__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__UTC_DAY__">__UTC_DAY__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__UTC_HOUR__">__UTC_HOUR__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__UTC_MINUTE__">__UTC_MINUTE__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#__UTC_SECOND__">__UTC_SECOND__</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#_NARG">_NARG</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#_PI">_PI</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#_RS">_RS</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ACOS">ACOS</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ASIN">ASIN</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ATAN">ATAN</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ATAN2">ATAN2</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#BANK">BANK</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#CHARMAP">CHARMAP</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#COS">COS</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#DB">DB</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#DEF">DEF</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#DIV">DIV</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#DL">DL</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#DS">DS</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#DW">DW</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ELIF">ELIF</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ELSE">ELSE</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ENDC">ENDC</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ENDM">ENDM</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ENDR">ENDR</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#EQU">EQU</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#EQUS">EQUS</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#EXPORT">EXPORT</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#FAIL">FAIL</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#GLOBAL">GLOBAL</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#HIGH">HIGH</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#HRAM">HRAM</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#IF">IF</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#INCBIN">INCBIN</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#INCLUDE">INCLUDE</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#LOW">LOW</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#MACRO">MACRO</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#MUL">MUL</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#OPT">OPT</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#POPO">POPO</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#POPS">POPS</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#PRINTF">PRINTF</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#PRINTI">PRINTI</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#PRINTT">PRINTT</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#PRINTV">PRINTV</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#PURGE">PURGE</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#PUSHO">PUSHO</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#PUSHS">PUSHS</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#REPT">REPT</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#RB">RB</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#RL">RL</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ROM0">ROM0</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#ROMX">ROMX</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#RSRESET">RSRESET</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#RSSET">RSSET</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#RW">RW</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#SECTION">SECTION</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#SET">SET</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#SHIFT">SHIFT</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#SIN">SIN</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#SRAM">SRAM</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#STRCAT">STRCAT</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#STRCMP">STRCMP</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#STRIN">STRIN</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#STRLEN">STRLEN</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#STRLWR">STRLWR</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#STRSUB">STRSUB</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#STRUPR">STRUPR</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#TAN">TAN</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#VRAM">VRAM</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#WRAM0">WRAM0</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#WRAMX">WRAMX</a></dt>
<dd class="It-inset"></dd>
<dt class="It-inset"><a class="Sx" title="Sx" href="#WARN">WARN</a></dt>
<dd class="It-inset"></dd>
</dl>
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
ALSO</a></h1>
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(1)</a>,

View File

@@ -65,7 +65,9 @@ REPT NumberOfSymbols ; Number of symbols defined in this object file.
LONG LineNum ; Line number in the file where the symbol is defined.
LONG SectionID ; The section number (of this object file) in which
; this symbol is defined.
; this symbol is defined. If it doesn't belong to any
; specific section (like a constant), this field has
; the value -1.
LONG Value ; The symbols value. It's the offset into that
; symbol's section.

33
include/asm/constexpr.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_CONSTEXPR_H
#define RGBDS_ASM_CONSTEXPR_H
#include <stdint.h>
struct ConstExpression {
union {
int32_t nVal;
struct sSymbol *pSym;
} u;
uint32_t isSym;
};
void constexpr_Symbol(struct ConstExpression *expr, char *tzSym);
void constexpr_Number(struct ConstExpression *expr, int32_t i);
void constexpr_UnaryOp(struct ConstExpression *expr,
int32_t op,
const struct ConstExpression *src);
void constexpr_BinaryOp(struct ConstExpression *expr,
int32_t op,
const struct ConstExpression *src1,
const struct ConstExpression *src2);
int32_t constexpr_GetConstantValue(struct ConstExpression *expr);
#endif /* RGBDS_ASM_CONSTEXPR_H */

View File

@@ -42,7 +42,7 @@ void fstk_Dump(void);
void fstk_AddIncludePath(char *s);
uint32_t fstk_RunMacro(char *s);
void fstk_RunRept(uint32_t count);
FILE *fstk_FindFile(char *fname);
FILE *fstk_FindFile(char *fname, char **incPathUsed);
int32_t fstk_GetLine(void);
#endif /* RGBDS_ASM_FSTACK_H */

View File

@@ -12,7 +12,7 @@
#include <stdbool.h>
#include <stdint.h>
#include "extern/stdnoreturn.h"
#include "helpers.h"
struct sOptions {
char binary[2];
@@ -46,7 +46,7 @@ void opt_Parse(char *s);
* It is also used when the assembler goes into an invalid state (for example,
* when it fails to allocate memory).
*/
noreturn void fatalerror(const char *fmt, ...);
noreturn_ void fatalerror(const char *fmt, ...);
/*
* Used for errors that make it impossible to assemble correctly, but don't

10
include/extern/err.h vendored
View File

@@ -17,7 +17,7 @@
#include <stdarg.h>
#include "extern/stdnoreturn.h"
#include "helpers.h"
#define warn rgbds_warn
#define vwarn rgbds_vwarn
@@ -34,10 +34,10 @@ void vwarn(const char *fmt, va_list ap);
void warnx(const char *fmt, ...);
void vwarnx(const char *fmt, va_list ap);
noreturn void err(int status, const char *fmt, ...);
noreturn void verr(int status, const char *fmt, va_list ap);
noreturn void errx(int status, const char *fmt, ...);
noreturn void verrx(int status, const char *fmt, va_list ap);
noreturn_ void err(int status, const char *fmt, ...);
noreturn_ void verr(int status, const char *fmt, va_list ap);
noreturn_ void errx(int status, const char *fmt, ...);
noreturn_ void verrx(int status, const char *fmt, va_list ap);
#endif /* ERR_IN_LIBC */

View File

@@ -1,29 +0,0 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2014-2018, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef EXTERN_STDNORETURN_H
#define EXTERN_STDNORETURN_H
#if __STDC_VERSION__ >= 201112L
/* C11 or newer */
#define noreturn _Noreturn
#elif __cplusplus >= 201103L
/* C++11 or newer */
#define noreturn [[noreturn]]
#elif __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ >= 5))
/* GCC 2.5 or newer */
#define noreturn __attribute__ ((noreturn))
#elif _MSC_VER >= 1310
/* MS Visual Studio 2003/.NET Framework 1.1 or newer */
#define noreturn _declspec(noreturn)
#else
/* Unsupported, but no need to throw a fit */
#define noreturn
#endif
#endif /* EXTERN_STDNORETURN_H */

22
include/helpers.h Normal file
View File

@@ -0,0 +1,22 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2014-2018, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef HELPERS_H
#define HELPERS_H
#ifdef __GNUC__
/* GCC or compatible */
#define noreturn_ __attribute__ ((noreturn))
#define unused_ __attribute__ ((unused))
#else
/* Unsupported, but no need to throw a fit */
#define noreturn_
#define unused_
#endif
#endif /* HELPERS_H */

View File

@@ -36,8 +36,9 @@ void CreateSymbolTable(void);
struct sSection *GetSectionByName(const char *name);
int32_t IsSectionNameInUse(const char *name);
void SetLinkerscriptName(char *tzLinkerscriptFile);
int32_t IsSectionSameTypeBankAndFloating(const char *name,
enum eSectionType type, int32_t bank);
int32_t IsSectionSameTypeBankAndAttrs(const char *name,
enum eSectionType type, int32_t bank,
int32_t org, int32_t align);
uint32_t AssignSectionAddressAndBankByName(const char *name, uint32_t address,
int32_t bank);

View File

@@ -11,9 +11,9 @@
#include <stdint.h>
#include "extern/stdnoreturn.h"
#include "helpers.h"
noreturn void script_fatalerror(const char *fmt, ...);
noreturn_ void script_fatalerror(const char *fmt, ...);
void script_Parse(const char *path);

View File

@@ -11,7 +11,7 @@
#define PACKAGE_VERSION_MAJOR (0)
#define PACKAGE_VERSION_MINOR (3)
#define PACKAGE_VERSION_PATCH (6)
#define PACKAGE_VERSION_PATCH (8)
const char *get_package_version_string(void);

View File

@@ -17,6 +17,7 @@
#include "asm/asm.h"
#include "asm/charmap.h"
#include "asm/constexpr.h"
#include "asm/fstack.h"
#include "asm/lexer.h"
#include "asm/main.h"
@@ -28,8 +29,10 @@
#include "common.h"
#include "linkdefs.h"
uint32_t nListCountEmpty;
char *tzNewMacro;
uint32_t ulNewMacroSize;
int32_t nPCOffset;
static void bankrangecheck(char *name, uint32_t secttype, int32_t org,
int32_t bank)
@@ -104,18 +107,6 @@ size_t symvaluetostring(char *dest, size_t maxLength, char *sym)
return length;
}
static uint32_t str2int(char *s)
{
uint32_t r = 0;
while (*s) {
r <<= 8;
r |= (uint8_t)(*s++);
}
return r;
}
static uint32_t str2int2(char *s, int32_t length)
{
int32_t i;
@@ -339,8 +330,9 @@ static void if_skip_to_else(void)
break;
case '\"':
src++;
src += 2;
inString = false;
break;
default:
src++;
@@ -447,10 +439,11 @@ static void updateUnion(void)
char tzString[MAXSTRLEN + 1];
struct Expression sVal;
int32_t nConstValue;
struct ConstExpression sConstExpr;
}
%type <sVal> relocconst
%type <nConstValue> const
%type <sConstExpr> const
%type <nConstValue> uconst
%type <nConstValue> const_3bit
%type <sVal> const_8bit
@@ -462,38 +455,38 @@ static void updateUnion(void)
%token <nConstValue> T_NUMBER
%token <tzString> T_STRING
%left T_OP_LOGICNOT
%left T_OP_LOGICOR T_OP_LOGICAND T_OP_LOGICEQU
%left T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE
%left T_OP_ADD T_OP_SUB
%left T_OP_OR T_OP_XOR T_OP_AND
%left T_OP_SHL T_OP_SHR
%left T_OP_MUL T_OP_DIV T_OP_MOD
%left T_OP_NOT
%left T_OP_DEF
%left T_OP_BANK T_OP_ALIGN
%left T_OP_SIN
%left T_OP_COS
%left T_OP_TAN
%left T_OP_ASIN
%left T_OP_ACOS
%left T_OP_ATAN
%left T_OP_ATAN2
%left T_OP_FDIV
%left T_OP_FMUL
%left T_OP_ROUND
%left T_OP_CEIL
%left T_OP_FLOOR
%left <nConstValue> T_OP_LOGICNOT
%left <nConstValue> T_OP_LOGICOR T_OP_LOGICAND T_OP_LOGICEQU
%left <nConstValue> T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE
%left <nConstValue> T_OP_ADD T_OP_SUB
%left <nConstValue> T_OP_OR T_OP_XOR T_OP_AND
%left <nConstValue> T_OP_SHL T_OP_SHR
%left <nConstValue> T_OP_MUL T_OP_DIV T_OP_MOD
%left <nConstValue> T_OP_NOT
%left <nConstValue> T_OP_DEF
%left <nConstValue> T_OP_BANK T_OP_ALIGN
%left <nConstValue> T_OP_SIN
%left <nConstValue> T_OP_COS
%left <nConstValue> T_OP_TAN
%left <nConstValue> T_OP_ASIN
%left <nConstValue> T_OP_ACOS
%left <nConstValue> T_OP_ATAN
%left <nConstValue> T_OP_ATAN2
%left <nConstValue> T_OP_FDIV
%left <nConstValue> T_OP_FMUL
%left <nConstValue> T_OP_ROUND
%left <nConstValue> T_OP_CEIL
%left <nConstValue> T_OP_FLOOR
%token T_OP_HIGH T_OP_LOW
%token <nConstValue> T_OP_HIGH T_OP_LOW
%left T_OP_STRCMP
%left T_OP_STRIN
%left T_OP_STRSUB
%left T_OP_STRLEN
%left T_OP_STRCAT
%left T_OP_STRUPR
%left T_OP_STRLWR
%left <nConstValue> T_OP_STRCMP
%left <nConstValue> T_OP_STRIN
%left <nConstValue> T_OP_STRSUB
%left <nConstValue> T_OP_STRLEN
%left <nConstValue> T_OP_STRCAT
%left <nConstValue> T_OP_STRUPR
%left <nConstValue> T_OP_STRLWR
%left NEG /* negation -- unary minus */
@@ -579,10 +572,13 @@ asmfile : lines;
/* Note: The lexer adds '\n' at the end of the input */
lines : /* empty */
| lines line '\n' {
nLineNo += 1;
nTotalLines += 1;
}
| lines {
nListCountEmpty = 0;
nPCOffset = 1;
} line '\n' {
nLineNo += 1;
nTotalLines += 1;
}
;
line : label
@@ -655,9 +651,9 @@ simple_pseudoop : include
| import
| export
| global
| db
| dw
| dl
| { nPCOffset = 0; } db
| { nPCOffset = 0; } dw
| { nPCOffset = 0; } dl
| ds
| section
| rsreset
@@ -802,16 +798,28 @@ ds : T_POP_DS uconst
}
;
db : T_POP_DB constlist_8bit_entry comma constlist_8bit
| T_POP_DB constlist_8bit_entry_single
db : T_POP_DB constlist_8bit_entry comma constlist_8bit {
if ((nPass == 1) && (nListCountEmpty > 0)) {
warning("Empty entry in list of 8-bit elements (treated as 0).");
}
}
| T_POP_DB constlist_8bit_entry
;
dw : T_POP_DW constlist_16bit_entry comma constlist_16bit
| T_POP_DW constlist_16bit_entry_single
dw : T_POP_DW constlist_16bit_entry comma constlist_16bit {
if ((nPass == 1) && (nListCountEmpty > 0)) {
warning("Empty entry in list of 16-bit elements (treated as 0).");
}
}
| T_POP_DW constlist_16bit_entry
;
dl : T_POP_DL constlist_32bit_entry comma constlist_32bit
| T_POP_DL constlist_32bit_entry_single
dl : T_POP_DL constlist_32bit_entry comma constlist_32bit {
if ((nPass == 1) && (nListCountEmpty > 0)) {
warning("Empty entry in list of 32-bit elements (treated as 0).");
}
}
| T_POP_DL constlist_32bit_entry
;
purge : T_POP_PURGE {
@@ -877,13 +885,13 @@ global_list_entry : T_ID
equ : T_LABEL T_POP_EQU const
{
sym_AddEqu($1, $3);
sym_AddEqu($1, constexpr_GetConstantValue(&$3));
}
;
set : T_LABEL T_POP_SET const
{
sym_AddSet($1, $3);
sym_AddSet($1, constexpr_GetConstantValue(&$3));
}
;
@@ -912,7 +920,7 @@ charmap : T_POP_CHARMAP string comma string
}
| T_POP_CHARMAP string comma const
{
if (charmap_Add($2, $4 & 0xFF) == -1) {
if (charmap_Add($2, constexpr_GetConstantValue(&$4) & 0xFF) == -1) {
fprintf(stderr, "Error parsing charmap. Either you've added too many (%i), or the input character length is too long (%i)' : %s\n", MAXCHARMAPS, CHARMAPLENGTH, strerror(errno));
yyerror("Error parsing charmap.");
}
@@ -929,28 +937,28 @@ printt : T_POP_PRINTT string
printv : T_POP_PRINTV const
{
if (nPass == 1)
printf("$%X", $2);
printf("$%X", constexpr_GetConstantValue(&$2));
}
;
printi : T_POP_PRINTI const
{
if (nPass == 1)
printf("%d", $2);
printf("%d", constexpr_GetConstantValue(&$2));
}
;
printf : T_POP_PRINTF const
{
if (nPass == 1)
math_Print($2);
math_Print(constexpr_GetConstantValue(&$2));
}
;
if : T_POP_IF const
{
nIFDepth++;
if (!$2) {
if (!constexpr_GetConstantValue(&$2)) {
/*
* Continue parsing after ELSE, or at ELIF or
* ENDC keyword.
@@ -982,7 +990,7 @@ elif : T_POP_ELIF const
*/
skipElif = true;
if (!$2) {
if (!constexpr_GetConstantValue(&$2)) {
/*
* Continue parsing after ELSE, or at
* ELIF or ENDC keyword.
@@ -1014,10 +1022,11 @@ endc : T_POP_ENDC
const_3bit : const
{
if (($1 < 0) || ($1 > 7))
int32_t value = constexpr_GetConstantValue(&$1);
if ((value < 0) || (value > 7))
yyerror("Immediate value must be 3-bit");
else
$$ = $1 & 0x7;
$$ = value & 0x7;
}
;
@@ -1028,26 +1037,7 @@ constlist_8bit : constlist_8bit_entry
constlist_8bit_entry : /* empty */
{
out_Skip(1);
if (nPass == 1)
warning("Empty entry in list of 8-bit elements (treated as 0).");
}
| const_8bit
{
out_RelByte(&$1);
}
| string
{
char *s = $1;
int32_t length = charmap_Convert(&s);
out_AbsByteGroup(s, length);
free(s);
}
;
constlist_8bit_entry_single : /* empty */
{
out_Skip(1);
nListCountEmpty++;
}
| const_8bit
{
@@ -1070,18 +1060,7 @@ constlist_16bit : constlist_16bit_entry
constlist_16bit_entry : /* empty */
{
out_Skip(2);
if (nPass == 1)
warning("Empty entry in list of 16-bit elements (treated as 0).");
}
| const_16bit
{
out_RelWord(&$1);
}
;
constlist_16bit_entry_single : /* empty */
{
out_Skip(2);
nListCountEmpty++;
}
| const_16bit
{
@@ -1096,18 +1075,7 @@ constlist_32bit : constlist_32bit_entry
constlist_32bit_entry : /* empty */
{
out_Skip(4);
if (nPass == 1)
warning("Empty entry in list of 32-bit elements (treated as 0).");
}
| relocconst
{
out_RelLong(&$1);
}
;
constlist_32bit_entry_single : /* empty */
{
out_Skip(4);
nListCountEmpty++;
}
| relocconst
{
@@ -1134,8 +1102,39 @@ const_16bit : relocconst
relocconst : T_ID
{
rpn_Symbol(&$$, $1);
$$.nVal = sym_GetValue($1);
/*
* The value of @ needs to be evaluated by the linker,
* it can only be calculated by the assembler in very
* few cases (when the base address of a section is
* known).
*
* '@' is a bit special in that it means different
* things depending on when it is used:
*
* - JR/LD/ADD/etc: It refers to the first byte of the
* instruction (1 byte offset relative to the value
* stored in the ROM).
* - DB/DW/DL: It refers to the address of the value
* that is being saved (0 byte offset relative to the
* value stored in the ROM.
*
* This offset must be added whenever '@' is added to a
* RPN expression so that the linker can calculate the
* correct result of any expression that uses '@'.
*/
if ((strcmp($1, "@") == 0) && (nPCOffset != 0)) {
struct Expression sTemp, sOffset;
rpn_Symbol(&sTemp, $1);
sTemp.nVal = sym_GetValue($1);
rpn_Number(&sOffset, nPCOffset);
rpn_SUB(&$$, &sTemp, &sOffset);
} else {
rpn_Symbol(&$$, $1);
$$.nVal = sym_GetValue($1);
}
}
| T_NUMBER
{
@@ -1194,18 +1193,60 @@ relocconst : T_ID
rpn_Number(&$$, sym_isConstDefined($4));
oDontExpandStrings = false;
}
| T_OP_ROUND '(' const ')' { rpn_Number(&$$, math_Round($3)); }
| T_OP_CEIL '(' const ')' { rpn_Number(&$$, math_Ceil($3)); }
| T_OP_FLOOR '(' const ')' { rpn_Number(&$$, math_Floor($3)); }
| T_OP_FDIV '(' const comma const ')' { rpn_Number(&$$, math_Div($3, $5)); }
| T_OP_FMUL '(' const comma const ')' { rpn_Number(&$$, math_Mul($3, $5)); }
| T_OP_SIN '(' const ')' { rpn_Number(&$$, math_Sin($3)); }
| T_OP_COS '(' const ')' { rpn_Number(&$$, math_Cos($3)); }
| T_OP_TAN '(' const ')' { rpn_Number(&$$, math_Tan($3)); }
| T_OP_ASIN '(' const ')' { rpn_Number(&$$, math_ASin($3)); }
| T_OP_ACOS '(' const ')' { rpn_Number(&$$, math_ACos($3)); }
| T_OP_ATAN '(' const ')' { rpn_Number(&$$, math_ATan($3)); }
| T_OP_ATAN2 '(' const comma const ')' { rpn_Number(&$$, math_ATan2($3, $5)); }
| T_OP_ROUND '(' const ')'
{
rpn_Number(&$$, math_Round(constexpr_GetConstantValue(&$3)));
}
| T_OP_CEIL '(' const ')'
{
rpn_Number(&$$, math_Ceil(constexpr_GetConstantValue(&$3)));
}
| T_OP_FLOOR '(' const ')'
{
rpn_Number(&$$, math_Floor(constexpr_GetConstantValue(&$3)));
}
| T_OP_FDIV '(' const comma const ')'
{
rpn_Number(&$$,
math_Div(constexpr_GetConstantValue(&$3),
constexpr_GetConstantValue(&$5)));
}
| T_OP_FMUL '(' const comma const ')'
{
rpn_Number(&$$,
math_Mul(constexpr_GetConstantValue(&$3),
constexpr_GetConstantValue(&$5)));
}
| T_OP_SIN '(' const ')'
{
rpn_Number(&$$, math_Sin(constexpr_GetConstantValue(&$3)));
}
| T_OP_COS '(' const ')'
{
rpn_Number(&$$, math_Cos(constexpr_GetConstantValue(&$3)));
}
| T_OP_TAN '(' const ')'
{
rpn_Number(&$$, math_Tan(constexpr_GetConstantValue(&$3)));
}
| T_OP_ASIN '(' const ')'
{
rpn_Number(&$$, math_ASin(constexpr_GetConstantValue(&$3)));
}
| T_OP_ACOS '(' const ')'
{
rpn_Number(&$$, math_ACos(constexpr_GetConstantValue(&$3)));
}
| T_OP_ATAN '(' const ')'
{
rpn_Number(&$$, math_ATan(constexpr_GetConstantValue(&$3)));
}
| T_OP_ATAN2 '(' const comma const ')'
{
rpn_Number(&$$,
math_ATan2(constexpr_GetConstantValue(&$3),
constexpr_GetConstantValue(&$5)));
}
| T_OP_STRCMP '(' string comma string ')'
{
rpn_Number(&$$, strcmp($3, $5));
@@ -1225,88 +1266,79 @@ relocconst : T_ID
uconst : const
{
if ($1 < 0)
fatalerror("Constant mustn't be negative: %d", $1);
$$ = $1;
int32_t value = constexpr_GetConstantValue(&$1);
if (value < 0)
fatalerror("Constant mustn't be negative: %d", value);
$$ = value;
}
;
const : T_ID { $$ = sym_GetConstantValue($1); }
| T_NUMBER { $$ = $1; }
| T_OP_HIGH '(' const ')' { $$ = ($3 >> 8) & 0xFF; }
| T_OP_LOW '(' const ')' { $$ = $3 & 0xFF; }
| string { $$ = str2int($1); }
| T_OP_LOGICNOT const %prec NEG { $$ = !$2; }
| const T_OP_LOGICOR const { $$ = $1 || $3; }
| const T_OP_LOGICAND const { $$ = $1 && $3; }
| const T_OP_LOGICEQU const { $$ = $1 == $3; }
| const T_OP_LOGICGT const { $$ = $1 > $3; }
| const T_OP_LOGICLT const { $$ = $1 < $3; }
| const T_OP_LOGICGE const { $$ = $1 >= $3; }
| const T_OP_LOGICLE const { $$ = $1 <= $3; }
| const T_OP_LOGICNE const { $$ = $1 != $3; }
| const T_OP_ADD const { $$ = $1 + $3; }
| const T_OP_SUB const { $$ = $1 - $3; }
| T_ID T_OP_SUB T_ID
const : T_ID { constexpr_Symbol(&$$, $1); }
| T_NUMBER { constexpr_Number(&$$, $1); }
| T_OP_HIGH '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_LOW '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| string
{
if (sym_IsRelocDiffDefined($1, $3) == 0)
fatalerror("'%s - %s' not defined.", $1, $3);
$$ = sym_GetDefinedValue($1) - sym_GetDefinedValue($3);
char *s = $1;
int32_t length = charmap_Convert(&s);
constexpr_Number(&$$, str2int2(s, length));
free(s);
}
| const T_OP_XOR const { $$ = $1 ^ $3; }
| const T_OP_OR const { $$ = $1 | $3; }
| const T_OP_AND const { $$ = $1 & $3; }
| const T_OP_SHL const { $$ = $1 << $3; }
| const T_OP_SHR const { $$ = $1 >> $3; }
| const T_OP_MUL const { $$ = $1 * $3; }
| const T_OP_DIV const
{
if ($3 == 0)
fatalerror("division by zero");
$$ = $1 / $3;
}
| const T_OP_MOD const
{
if ($3 == 0)
fatalerror("division by zero");
$$ = $1 % $3;
}
| T_OP_ADD const %prec NEG { $$ = +$2; }
| T_OP_SUB const %prec NEG { $$ = -$2; }
| T_OP_NOT const %prec NEG { $$ = ~$2; }
| T_OP_ROUND '(' const ')' { $$ = math_Round($3); }
| T_OP_CEIL '(' const ')' { $$ = math_Ceil($3); }
| T_OP_FLOOR '(' const ')' { $$ = math_Floor($3); }
| T_OP_FDIV '(' const comma const ')' { $$ = math_Div($3,$5); }
| T_OP_FMUL '(' const comma const ')' { $$ = math_Mul($3,$5); }
| T_OP_SIN '(' const ')' { $$ = math_Sin($3); }
| T_OP_COS '(' const ')' { $$ = math_Cos($3); }
| T_OP_TAN '(' const ')' { $$ = math_Tan($3); }
| T_OP_ASIN '(' const ')' { $$ = math_ASin($3); }
| T_OP_ACOS '(' const ')' { $$ = math_ACos($3); }
| T_OP_ATAN '(' const ')' { $$ = math_ATan($3); }
| T_OP_ATAN2 '(' const comma const ')' { $$ = math_ATan2($3,$5); }
| T_OP_LOGICNOT const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
| const T_OP_LOGICOR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICAND const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICEQU const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICGT const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICLT const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICGE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICLE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICNE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_ADD const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_SUB const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_XOR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_OR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_AND const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_SHL const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_SHR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_MUL const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_DIV const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_MOD const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| T_OP_ADD const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
| T_OP_SUB const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
| T_OP_NOT const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
| T_OP_ROUND '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_CEIL '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_FLOOR '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_FDIV '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); }
| T_OP_FMUL '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); }
| T_OP_SIN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_COS '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_TAN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_ASIN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_ACOS '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_ATAN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_ATAN2 '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); }
| T_OP_DEF {
oDontExpandStrings = true;
} '(' T_ID ')'
{
$$ = sym_isConstDefined($4);
constexpr_Number(&$$, sym_isConstDefined($4));
oDontExpandStrings = false;
}
| T_OP_STRCMP '(' string comma string ')'
{
$$ = strcmp($3, $5);
constexpr_Number(&$$, strcmp($3, $5));
}
| T_OP_STRIN '(' string comma string ')'
{
char *p = strstr($3, $5);
if (p != NULL)
$$ = p - $3 + 1;
constexpr_Number(&$$, p - $3 + 1);
else
$$ = 0;
constexpr_Number(&$$, 0);
}
| T_OP_STRLEN '(' string ')' { $$ = strlen($3); }
| T_OP_STRLEN '(' string ')' { constexpr_Number(&$$, strlen($3)); }
| '(' const ')' { $$ = $2; }
;
@@ -1680,6 +1712,14 @@ z80_ldio : T_Z80_LDIO T_MODE_A comma op_mem_ind
$2.nVal &= 0xFF;
out_RelByte(&$2);
}
| T_Z80_LDIO T_MODE_A comma T_MODE_C_IND
{
out_AbsByte(0xF2);
}
| T_Z80_LDIO T_MODE_C_IND comma T_MODE_A
{
out_AbsByte(0xE2);
}
;
z80_ld : z80_ld_mem

View File

@@ -32,12 +32,10 @@ int32_t readUTF8Char(char *dest, char *src)
dest[i] = src[i];
i++;
if (state == 0) {
dest[i] = '\0';
dest[++i] = '\0';
return i;
}
dest[i] = src[i];
}
}

231
src/asm/constexpr.c Normal file
View File

@@ -0,0 +1,231 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "asm/asm.h"
#include "asm/constexpr.h"
#include "asm/lexer.h"
#include "asm/main.h"
#include "asm/mymath.h"
#include "asm/rpn.h"
#include "asm/symbol.h"
#include "asmy.h"
void constexpr_Symbol(struct ConstExpression *expr, char *tzSym)
{
if (!sym_isConstant(tzSym)) {
struct sSymbol *pSym = sym_FindSymbol(tzSym);
if (pSym != NULL) {
expr->u.pSym = pSym;
expr->isSym = 1;
} else {
fatalerror("'%s' not defined", tzSym);
}
} else {
constexpr_Number(expr, sym_GetConstantValue(tzSym));
}
}
void constexpr_Number(struct ConstExpression *expr, int32_t i)
{
expr->u.nVal = i;
expr->isSym = 0;
}
void constexpr_UnaryOp(struct ConstExpression *expr,
int32_t op,
const struct ConstExpression *src)
{
if (src->isSym)
fatalerror("Non-constant operand in constant expression");
int32_t value = src->u.nVal;
int32_t result = 0;
switch (op) {
case T_OP_HIGH:
result = (value >> 8) & 0xFF;
break;
case T_OP_LOW:
result = value & 0xFF;
break;
case T_OP_LOGICNOT:
result = !value;
break;
case T_OP_ADD:
result = value;
break;
case T_OP_SUB:
result = -value;
break;
case T_OP_NOT:
result = ~value;
break;
case T_OP_ROUND:
result = math_Round(value);
break;
case T_OP_CEIL:
result = math_Ceil(value);
break;
case T_OP_FLOOR:
result = math_Floor(value);
break;
case T_OP_SIN:
result = math_Sin(value);
break;
case T_OP_COS:
result = math_Cos(value);
break;
case T_OP_TAN:
result = math_Tan(value);
break;
case T_OP_ASIN:
result = math_ASin(value);
break;
case T_OP_ACOS:
result = math_ACos(value);
break;
case T_OP_ATAN:
result = math_ATan(value);
break;
default:
fatalerror("Unknown unary op");
}
constexpr_Number(expr, result);
}
void constexpr_BinaryOp(struct ConstExpression *expr,
int32_t op,
const struct ConstExpression *src1,
const struct ConstExpression *src2)
{
int32_t value1;
int32_t value2;
int32_t result = 0;
if (op == T_OP_SUB && src1->isSym && src2->isSym) {
char *symName1 = src1->u.pSym->tzName;
char *symName2 = src2->u.pSym->tzName;
if (!sym_IsRelocDiffDefined(symName1, symName2))
fatalerror("'%s - %s' not defined", symName1, symName2);
value1 = sym_GetDefinedValue(symName1);
value2 = sym_GetDefinedValue(symName2);
result = value1 - value2;
} else if (src1->isSym || src2->isSym) {
fatalerror("Non-constant operand in constant expression");
} else {
value1 = src1->u.nVal;
value2 = src2->u.nVal;
switch (op) {
case T_OP_LOGICOR:
result = value1 || value2;
break;
case T_OP_LOGICAND:
result = value1 && value2;
break;
case T_OP_LOGICEQU:
result = value1 == value2;
break;
case T_OP_LOGICGT:
result = value1 > value2;
break;
case T_OP_LOGICLT:
result = value1 < value2;
break;
case T_OP_LOGICGE:
result = value1 >= value2;
break;
case T_OP_LOGICLE:
result = value1 <= value2;
break;
case T_OP_LOGICNE:
result = value1 != value2;
break;
case T_OP_ADD:
result = value1 + value2;
break;
case T_OP_SUB:
result = value1 - value2;
break;
case T_OP_XOR:
result = value1 ^ value2;
break;
case T_OP_OR:
result = value1 | value2;
break;
case T_OP_AND:
result = value1 & value2;
break;
case T_OP_SHL:
if (value1 < 0)
warning("Left shift of negative value: %d",
value1);
if (value2 < 0)
fatalerror("Shift by negative value: %d",
value2);
else if (value2 >= 32)
fatalerror("Shift by too big value: %d",
value2);
result = value1 << value2;
break;
case T_OP_SHR:
if (value2 < 0)
fatalerror("Shift by negative value: %d",
value2);
else if (value2 >= 32)
fatalerror("Shift by too big value: %d",
value2);
result = value1 >> value2;
break;
case T_OP_MUL:
result = value1 * value2;
break;
case T_OP_DIV:
if (value2 == 0)
fatalerror("Division by zero");
result = value1 / value2;
break;
case T_OP_MOD:
if (value2 == 0)
fatalerror("Division by zero");
result = value1 % value2;
break;
case T_OP_FDIV:
result = math_Div(value1, value2);
break;
case T_OP_FMUL:
result = math_Mul(value1, value2);
break;
case T_OP_ATAN2:
result = math_ATan2(value1, value2);
break;
default:
fatalerror("Unknown binary op");
}
}
constexpr_Number(expr, result);
}
int32_t constexpr_GetConstantValue(struct ConstExpression *expr)
{
if (expr->isSym)
fatalerror("Non-constant expression");
return expr->u.nVal;
}

View File

@@ -87,6 +87,8 @@ static void pushcontext(void)
(*ppFileStack)->nREPTBlockSize = nCurrentREPTBlockSize;
(*ppFileStack)->nREPTBlockCount = nCurrentREPTBlockCount;
break;
default:
fatalerror("%s: Internal error.", __func__);
}
nLineNo = 0;
@@ -152,6 +154,8 @@ static int32_t popcontext(void)
nCurrentREPTBlockSize = pLastFile->nREPTBlockSize;
nCurrentREPTBlockCount = pLastFile->nREPTBlockCount;
break;
default:
fatalerror("%s: Internal error.", __func__);
}
free(*ppLastFile);
@@ -174,12 +178,13 @@ int32_t fstk_GetLine(void)
return nLineNo; /* ??? */
case STAT_isREPTBlock:
break; /* Peek top file of the stack */
default:
fatalerror("%s: Internal error.", __func__);
}
pLastFile = pFileStack;
if (pLastFile != NULL) {
ppLastFile = &pFileStack;
while (pLastFile->pNext) {
ppLastFile = &(pLastFile->pNext);
pLastFile = *ppLastFile;
@@ -229,7 +234,7 @@ void fstk_AddIncludePath(char *s)
fatalerror("Include path too long '%s'", s);
}
FILE *fstk_FindFile(char *fname)
FILE *fstk_FindFile(char *fname, char **incPathUsed)
{
char path[_MAX_PATH];
int32_t i;
@@ -257,8 +262,10 @@ FILE *fstk_FindFile(char *fname)
* space had been available. Thus, a return value of `size` or
* more means that the output was truncated.
*/
if (snprintf(path, sizeof(path), "%s%s", IncludePaths[i], fname)
>= sizeof(path))
int fullpathlen = snprintf(path, sizeof(path), "%s%s",
IncludePaths[i], fname);
if (fullpathlen >= (int)sizeof(path))
continue;
f = fopen(path, "rb");
@@ -268,6 +275,8 @@ FILE *fstk_FindFile(char *fname)
fprintf(dependfile, "%s: %s\n", tzObjectname,
path);
}
if (incPathUsed)
*incPathUsed = IncludePaths[i];
return f;
}
}
@@ -281,7 +290,8 @@ FILE *fstk_FindFile(char *fname)
*/
void fstk_RunInclude(char *tzFileName)
{
FILE *f = fstk_FindFile(tzFileName);
char *incPathUsed = "";
FILE *f = fstk_FindFile(tzFileName, &incPathUsed);
if (f == NULL)
err(1, "Unable to open included file '%s'", tzFileName);
@@ -289,7 +299,8 @@ void fstk_RunInclude(char *tzFileName)
pushcontext();
nLineNo = 1;
nCurrentStatus = STAT_isInclude;
strcpy(tzCurrentFileName, tzFileName);
snprintf(tzCurrentFileName, sizeof(tzCurrentFileName), "%s%s",
incPathUsed, tzFileName);
pCurrentFile = f;
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
yy_switch_to_buffer(CurrentFlexHandle);

View File

@@ -14,12 +14,15 @@
#include <string.h>
#include "asm/asm.h"
#include "asm/constexpr.h"
#include "asm/lexer.h"
#include "asm/main.h"
#include "asm/rpn.h"
#include "asm/symbol.h"
#include "asm/symbol.h"
#include "helpers.h"
#include "asmy.h"
bool oDontExpandStrings;
@@ -93,9 +96,18 @@ static int32_t ascii2bin(char *s)
s += 1;
convertfunc = binary2bin;
break;
default:
/* Handle below */
break;
}
if (radix == 4) {
if (*s == '\0') {
/*
* There are no digits after the radix prefix
* (or the string is empty, which shouldn't happen).
*/
yyerror("Invalid integer constant");
} else if (radix == 4) {
int32_t c;
while (*s != '\0') {
@@ -216,7 +228,7 @@ uint32_t PutMacroArg(char *src, uint32_t size)
return 0;
}
uint32_t PutUniqueArg(char *src, uint32_t size)
uint32_t PutUniqueArg(unused_ char *src, uint32_t size)
{
char *s;
@@ -307,6 +319,7 @@ const struct sLexInitString lexer_strings[] = {
{"sp", T_MODE_SP},
{"[c]", T_MODE_C_IND},
{"[$ff00+c]", T_MODE_C_IND},
{"[$ff00 + c]", T_MODE_C_IND},
{"a", T_TOKEN_A},
{"b", T_TOKEN_B},
@@ -579,7 +592,7 @@ void setup_lexer(void)
lex_FloatAddRange(id, '@', '@');
lex_FloatAddRange(id, '#', '#');
//@ID
// "@"
id = lex_FloatAlloc(&tIDToken);
lex_FloatAddFirstRange(id, '@', '@');

View File

@@ -6,6 +6,7 @@
* SPDX-License-Identifier: MIT
*/
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -14,6 +15,7 @@
#include <ctype.h>
#include "asm/asm.h"
#include "asm/constexpr.h"
#include "asm/fstack.h"
#include "asm/lexer.h"
#include "asm/main.h"
@@ -110,6 +112,21 @@ void yy_delete_buffer(YY_BUFFER_STATE buf)
free(buf);
}
/*
* Maintains the following invariants:
* 1. nBufferSize < capacity
* 2. The buffer is terminated with 0
* 3. nBufferSize is the size without the terminator
*/
static void yy_buffer_append(YY_BUFFER_STATE buf, uint32_t capacity, char c)
{
assert(buf->pBuffer[buf->nBufferSize] == 0);
assert(buf->nBufferSize + 1 < capacity);
buf->pBuffer[buf->nBufferSize++] = c;
buf->pBuffer[buf->nBufferSize] = 0;
}
YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size)
{
YY_BUFFER_STATE pBuffer = malloc(sizeof(struct yy_buffer_state));
@@ -145,7 +162,10 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f)
size = ftell(f);
fseek(f, 0, SEEK_SET);
pBuffer->pBufferRealStart = malloc(size + 2 + SAFETYMARGIN);
/* Give extra room for 2 newlines and terminator */
uint32_t capacity = size + 3;
pBuffer->pBufferRealStart = malloc(capacity + SAFETYMARGIN);
if (pBuffer->pBufferRealStart == NULL)
fatalerror("%s: Out of memory for buffer!", __func__);
@@ -155,9 +175,8 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f)
size = fread(pBuffer->pBuffer, sizeof(uint8_t), size, f);
pBuffer->pBuffer[size] = '\n';
pBuffer->pBuffer[size + 1] = 0;
pBuffer->nBufferSize = size + 1;
pBuffer->pBuffer[size] = 0;
pBuffer->nBufferSize = size;
/* Convert all line endings to LF and spaces */
@@ -218,6 +237,22 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f)
}
}
/* Add newline if file doesn't end with one */
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;
return pBuffer;
}
@@ -414,7 +449,7 @@ void yylex_GetFloatMaskAndFloatLen(uint32_t *pnFloatMask, uint32_t *pnFloatLen)
/*
* Gets the longest keyword/operator from the current position in the buffer.
*/
struct sLexString *yylex_GetLongestFixed()
struct sLexString *yylex_GetLongestFixed(void)
{
struct sLexString *pLongestFixed = NULL;
char *s = pLexBuffer;
@@ -640,7 +675,6 @@ scanagain:
/* Check for line continuation character */
if (*pLexBuffer == '\\') {
/*
* Look for line continuation character after a series of
* spaces. This is also useful for files that use Windows line
@@ -736,6 +770,7 @@ scanagain:
/* Longest match was a keyword or operator. */
pLexBuffer += pLongestFixed->nNameLength;
yylval.nConstValue = pLongestFixed->nToken;
return pLongestFixed->nToken;
}
@@ -851,7 +886,7 @@ uint32_t yylex(void)
return yylex_NORMAL();
case LEX_STATE_MACROARGS:
return yylex_MACROARGS();
default:
fatalerror("%s: Internal error.", __func__);
}
fatalerror("Internal error in %s", __func__);
}

View File

@@ -6,6 +6,7 @@
* SPDX-License-Identifier: MIT
*/
#include <float.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
@@ -23,6 +24,7 @@
#include "extern/err.h"
#include "helpers.h"
#include "version.h"
extern int yyparse(void);
@@ -147,10 +149,13 @@ void opt_Parse(char *s)
case 'z':
if (strlen(&s[1]) <= 2) {
int32_t result;
unsigned int fillchar;
result = sscanf(&s[1], "%x", &newopt.fillchar);
result = sscanf(&s[1], "%x", &fillchar);
if (!((result == EOF) || (result == 1)))
errx(1, "Invalid argument for option 'z'");
newopt.fillchar = fillchar;
} else {
errx(1, "Invalid argument for option 'z'");
}
@@ -222,7 +227,7 @@ void opt_AddDefine(char *s)
static void opt_ParseDefines(void)
{
int32_t i;
uint32_t i;
for (i = 0; i < cldefines_index; i += 2)
sym_AddString(cldefines[i], cldefines[i + 1]);
@@ -235,7 +240,7 @@ void verror(const char *fmt, va_list args)
{
fprintf(stderr, "ERROR: ");
fstk_Dump();
fprintf(stderr, ":\n\t");
fprintf(stderr, ":\n ");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
nErrors += 1;
@@ -250,7 +255,7 @@ void yyerror(const char *fmt, ...)
va_end(args);
}
void fatalerror(const char *fmt, ...)
noreturn_ void fatalerror(const char *fmt, ...)
{
va_list args;
@@ -272,7 +277,7 @@ void warning(const char *fmt, ...)
fprintf(stderr, "warning: ");
fstk_Dump();
fprintf(stderr, ":\n\t");
fprintf(stderr, ":\n ");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
@@ -480,7 +485,7 @@ int main(int argc, char *argv[])
if (CurrentOptions.verbose) {
printf("Success! %u lines in %d.%02d seconds ", nTotalLines,
(int)timespent, ((int)(timespent * 100.0)) % 100);
if (timespent == 0)
if (timespent < FLT_MIN_EXP)
printf("(INFINITY lines/minute)\n");
else
printf("(%d lines/minute)\n",

View File

@@ -882,24 +882,16 @@ void out_PCRelByte(struct Expression *expr)
{
checkcodesection();
checksectionoverflow(1);
if (rpn_isReloc(expr)) {
if (nPass == 2) {
pCurrentSection->tData[nPC] = 0;
createpatch(PATCH_BYTE_JR, expr);
}
pCurrentSection->nPC += 1;
nPC += 1;
pPCSymbol->nValue += 1;
} else {
int32_t b = expr->nVal;
b = (int16_t)((b & 0xFFFF) - (nPC + 1));
if (nPass == 2 && ((b < -128) || (b > 127)))
yyerror("PC-relative value must be 8-bit");
out_AbsByte(b & 0xFF);
/* Always let the linker calculate the offset. */
if (nPass == 2) {
pCurrentSection->tData[nPC] = 0;
createpatch(PATCH_BYTE_JR, expr);
}
pCurrentSection->nPC += 1;
nPC += 1;
pPCSymbol->nValue += 1;
rpn_Reset(expr);
}
@@ -910,7 +902,7 @@ void out_BinaryFile(char *s)
{
FILE *f;
f = fstk_FindFile(s);
f = fstk_FindFile(s, NULL);
if (f == NULL)
err(1, "Unable to open incbin file '%s'", s);
@@ -946,7 +938,7 @@ void out_BinaryFileSlice(char *s, int32_t start_pos, int32_t length)
if (length < 0)
fatalerror("Number of bytes to read must be greater than zero");
f = fstk_FindFile(s);
f = fstk_FindFile(s, NULL);
if (f == NULL)
err(1, "Unable to open included file '%s'", s);

View File

@@ -33,24 +33,28 @@ John: ld a,87 ;Weee
All pseudoops, mnemonics and registers (reserved keywords) are caseinsensitive
and all labels are casesensitive.
.Pp
There are two syntaxes for comments. In both cases, a comment ends at the end of
the line. The most common one is: anything that follows a semicolon
\[dq]\&;\[dq] (that isn't inside a string) is a comment. There is another
format: anything that follows a \[dq]*\[dq] that is placed right at the start of
a line is a comment. The assembler removes all comments from the code before
doing anything else.
There are two syntaxes for comments.
In both cases, a comment ends at the end of the line.
The most common one is: anything that follows a semicolon
.Ql \&;
(that isn't inside a string) is a comment.
There is another format: anything that follows a
.Ql *
that is placed right at the start of
a line is a comment.
The assembler removes all comments from the code before doing anything else.
.Pp
Sometimes lines can be too long and it may be necessary to split them. The
syntax to do so is the following one:
Sometimes lines can be too long and it may be necessary to split them.
The syntax to do so is the following one:
.Pp
.Bd -literal -offset indent
DB 1, 2, 3, 4 \[rs]
5, 6, 7, 8
.Ed
.Pp
This works anywhere in the code except inside of strings. To split strings it is
needed to use
.Sy STRCAT
This works anywhere in the code except inside of strings.
To split strings it is needed to use
.Fn STRCAT
like this:
.Pp
.Bd -literal -offset indent
@@ -59,162 +63,145 @@ like this:
.Ed
.Pp
.Ss Sections
.Ic SECTION Ar name , type
.Pp
.Ic SECTION Ar name , type , options
.Pp
.Ic SECTION Ar name , type Ns Bo Ar addr Bc
.Pp
.Ic SECTION Ar name , type Ns Bo Ar addr Bc , Ar options
.Pp
Before you can start writing code, you must define a section.
This tells the assembler what kind of information follows and, if it is code,
where to put it.
.Pp
.Bd -literal -offset indent
SECTION \[dq]CoolStuff\[dq],ROMX
.Ed
.Pp
This switches to the section called "CoolStuff" (or creates it if it doesn't
already exist) and it defines it as a code section.
All sections assembled at the same time that have the same name, type, etc, are
considered to be the same one, and their code is put together in the object file
generated by the assembler.
.Ar name
is a string enclosed in double quotes and can be a new name or the name of an
existing section.
All sections assembled at the same time that have the same name and type are
considered to be the same section, and their code is put together in the object
file generated by the assembler.
All other sections must have a unique name, even in different source files, or
the linker will treat it as an error.
.Pp
Possible section types are as follows:
Possible section
.Ar type Ns s
are as follows:
.Pp
.Bl -tag
.It Sy ROM0
.It Cm ROM0
A ROM section.
Mapped to memory at $0000$3FFF (or $0000-$7FFF if tiny ROM mode is enabled in
.Ar addr
can range from $0000$3FFF (or $0000$7FFF if tiny ROM mode is enabled in
.Xr rgblink 1 ) .
.It Sy ROMX
.It Cm ROMX
A banked ROM section.
Mapped to memory at $4000$7FFF.
Valid banks range from 1 to 511.
.Ar addr
can range from $4000$7FFF.
.Ar bank
can range from 1 to 511.
Not available if tiny ROM mode is enabled in
.Xr rgblink 1 .
.It Sy VRAM
.It Cm VRAM
A banked video RAM section.
Mapped to memory at $8000$9FFF.
Can only allocate memory, not fill it.
Valid banks are 0 and 1 but bank 1 isn't available if DMG mode is enabled in
.Ar addr
can range from $8000$9FFF.
.Ar bank
can be 0 or 1 but bank 1 is unavailable if DMG mode is enabled in
.Xr rgblink 1 .
.It Sy SRAM
Memory in this section can only be allocated with
.Sy DS ,
not filled with data.
.It Cm SRAM
A banked external (save) RAM section.
Mapped to memory at $A000$BFFF.
Can only allocate memory, not fill it.
Valid banks range from 0 to 15.
.It Sy WRAM0
.Ar addr
can range from $A000$BFFF.
.Ar bank
can range from 0 to 15.
Memory in this section can only be allocated with
.Sy DS ,
not filled with data.
.It Cm WRAM0
A general-purpose RAM section.
Mapped to memory at $C000$CFFF, or $C000-$DFFF if DMG mode is enabled in
.Ar addr
can range from $C000$CFFF, or $C000$DFFF if DMG mode is enabled in
.Xr rgblink 1 .
Can only allocate memory, not fill it.
.It Sy WRAMX
Memory in this section can only be allocated with
.Sy DS ,
not filled with data.
.It Cm WRAMX
A banked general-purpose RAM section.
Mapped to memory at $D000$DFFF.
Can only allocate memory, not fill it.
Valid banks range from 1 to 7.
.Ar addr
can range from $D000$DFFF.
.Ar bank
can range from 1 to 7.
Memory in this section can only be allocated with
.Sy DS ,
not filled with data.
Not available if DMG mode is enabled in
.Xr rgblink 1 .
.It Sy OAM
.It Cm OAM
An object attributes RAM section.
Mapped to memory at $FE00-$FE9F.
Can only allocate memory, not fill it.
.It Sy HRAM
.Ar addr
can range from $FE00-$FE9F.
Memory in this section can only be allocated with
.Sy DS ,
not filled with data.
.It Cm HRAM
A high RAM section.
Mapped to memory at $FF80$FFFE.
Can only allocate memory, not fill it.
.Ar addr
can range from $FF80$FFFE.
Memory in this section can only be allocated with
.Sy DS ,
not filled with data.
.Pp
NOTE: If you use this method of allocating HRAM the assembler will NOT choose
the short addressing mode in the LD instructions
.Sy Note :
If you use this method of allocating HRAM the assembler will
.Em not
choose the short addressing mode in the LD instructions
.Sy LD [$FF00+n8],A
and
.Sy LD A,[$FF00+n8]
because the actual address calculation is done by the linker.
If you find this undesirable you can use
.Ic RSSET No / Ic RB No / Ic RW
.Ic RSSET , RB ,
or
.Ic RW
instead or use the
.Sy LDH [$FF00+n8],A
and
.Sy LDH A,[$FF00+n8]
syntax instead.
This forces the assembler to emit the correct instruction and the linker to
check if the value is in the correct range. This optimization can be disabled
by passing the
check if the value is in the correct range.
This optimization can be disabled by passing the
.Fl L
flag to
.Sy rgbasm
as explained in
.Xr rgbasm 1 .
.El
.Pp
A section is usually defined as a floating one, but the code can restrict where
the linker can place it.
.Ar option Ns s are comma separated and may include:
.Bl -tag
.It Cm BANK Ns Bq Ar bank
Specify which
.Ar bank
for the linker to place the section.
.It Cm ALIGN Ns Bq Ar align
Place the section at an address whose
.Ar align
leastsignificant bits are zero.
It is a syntax error to use this option with
.Ar addr .
.El
.Pp
If a section is defined with no indications, it is a floating section.
The linker will decide where to place it in the final binary and it has no
obligation to follow any specific rules.
The following example defines a section that can be placed anywhere in any ROMX
bank:
.Pp
.Bd -literal -offset indent
SECTION \[dq]CoolStuff\[dq],ROMX
.Ed
.Pp
If it is needed, the following syntax can be used to fix the base address of the
section:
.Pp
.Bd -literal -offset indent
SECTION \[dq]CoolStuff\[dq],ROMX[$4567]
.Ed
.Pp
It won't, however, fix the bank number, which is left to the linker.
If you also want to specify the bank you can do:
.Pp
.Bd -literal -offset indent
SECTION \[dq]CoolStuff\[dq],ROMX[$4567],BANK[3]
.Ed
.Pp
And if you only want to force the section into a certain bank, and not it's
position within the bank, that's also possible:
.Pp
.Bd -literal -offset indent
SECTION \[dq]CoolStuff\[dq],ROMX,BANK[7]
.Ed
.Pp
In addition, you can specify byte alignment for a section.
This ensures that the section starts at a memory address where the given number
of least-significant bits are 0.
This can be used along with
.Ic BANK ,
if desired.
However, if an alignment is specified, the base address must be left unassigned.
This can be useful when using DMA to copy data or when it is needed to align the
start of an array to 256 bytes to optimize the code that accesses it.
.Pp
.Bd -literal -offset indent
SECTION \[dq]OAM Data\[dq],WRAM0,ALIGN[8] ; align to 256 bytes
SECTION \[dq]VRAM Data\[dq],ROMX,BANK[2],ALIGN[4] ; align to 16 bytes
.Ed
.Pp
HINT: If you think this is a lot of typing for doing a simple
.Ic ORG
type thing you can quite easily write an intelligent macro (called
.Ic ORG
for example) that uses
.Ic \@
for the section name and determines
correct section type etc as arguments for
.Ic SECTION .
.Pp
.Ic POPS
and
.Ic PUSHS
provide the interface to the section stack.
.Ic PUSHS
will push the current section context on the section stack.
.Ic POPS
can then later be used to restore it.
Useful for defining sections in included files when you don't want to destroy
the section context for the program that included your file.
The number of entries in the stack is limited only by the amount of memory in
your machine.
If
.Bq Ar addr
is not specified, the section is considered
.Dq floating ;
the linker will automatically calculate an appropriate address for the section.
Similarly, if
.Cm BANK Ns Bq Ar bank
is not specified, the linker will automatically find a bank with enough space.
.Pp
Sections can also be placed by using a linkerscript file.
The format is described in
@@ -224,6 +211,75 @@ specified in the script.
This is useful if the sections can't be placed at an address manually because
the size may change, but they have to be together.
.Pp
Section examples:
.Bd -literal -offset indent
SECTION "CoolStuff",ROMX
.Ed
.Pp
This switches to the section called
.Dq CoolStuff
(or creates it if it doesn't already exist) and defines it as a code section.
.Pp
The following example defines a section that can be placed anywhere in any ROMX
bank:
.Pp
.Bd -literal -offset indent
SECTION "CoolStuff",ROMX
.Ed
.Pp
If it is needed, the the base address of the section can be specified:
.Pp
.Bd -literal -offset indent
SECTION "CoolStuff",ROMX[$4567]
.Ed
.Pp
An example with a fixed bank:
.Pp
.Bd -literal -offset indent
SECTION "CoolStuff",ROMX[$4567],BANK[3]
.Ed
.Pp
And if you only want to force the section into a certain bank, and not it's
position within the bank, that's also possible:
.Pp
.Bd -literal -offset indent
SECTION "CoolStuff",ROMX,BANK[7]
.Ed
.Pp
Alignment examples:
one use could be when using DMA to copy data or when it is needed to align the
start of an array to 256 bytes to optimize the code that accesses it.
.Pp
.Bd -literal -offset indent
SECTION "OAM Data",WRAM0,ALIGN[8] ; align to 256 bytes
SECTION "VRAM Data",ROMX,BANK[2],ALIGN[4] ; align to 16 bytes
.Ed
.Pp
.Sy Hint :
If you think this is a lot of typing for doing a simple
.Dq org
type thing you can quite easily write an intelligent macro (called
.Ic ORG
for example) that uses
.Ic @
for the section name and determines
correct section type etc as arguments for
.Ic SECTION .
.Ss Section Stack
.Ic POPS
and
.Ic PUSHS
provide the interface to the section stack.
.Pp
.Ic PUSHS
will push the current section context on the section stack.
.Ic POPS
can then later be used to restore it.
Useful for defining sections in included files when you don't want to destroy
the section context for the program that included your file.
The number of entries in the stack is limited only by the amount of memory in
your machine.
.Sh SYMBOLS
.Pp
.Ss Symbols
@@ -241,7 +297,9 @@ assembling.
Define a structure easily.
.It Sy String equate Pq Sy EQUS
Give a frequently used string a name.
Can also be used as a mini-macro, like #define in C.
Can also be used as a mini-macro, like
.Fd #define
in C.
.It Sy MACRO
A block of code or pseudo instructions that you invoke like any other mnemonic.
You can give them arguments too.
@@ -341,9 +399,9 @@ str_SIZEOF = 259
.Pp
There are four commands in the RS group of commands:
.Pp
.Bl -column ".Sy String" ".Sy String"
.It Sy Command Ta Ta Ta Sy Meaning
.It Ic RSRESET Ta Ta Resets the _RS counter to zero.
.Bl -column "RSSET constexpr"
.It Sy Command Ta Sy Meaning
.It Ic RSRESET Ta Resets the _RS counter to zero.
.It Ic RSSET Ar constexpr Ta Sets the
.Ic _RS No counter to Ar constexpr .
.It Ic RB Ar constexpr Ta Sets the preceding symbol to
@@ -364,13 +422,14 @@ They don't change their value during the link process.
EQUS is used to define string-symbols.
Wherever the assembler meets a string symbol its name is replaced with its
value.
If you are familiar with C you can think of it as the same as #define.
If you are familiar with C you can think of it as the same as
.Fd #define .
.Pp
.Bd -literal -offset indent
COUNTREG EQUS "[hl+]"
ld a,COUNTREG
PLAYER_NAME EQUS \[dq]\[rs]\[dq]John\[rs]\[dq]\[dq]
PLAYER_NAME EQUS "\[rs]"John\[rs]""
db PLAYER_NAME
.Ed
.Pp
@@ -381,13 +440,13 @@ This will be interpreted as:
.Pp
.Bd -literal -offset indent
ld a,[hl+]
db \[dq]John\[dq]
db "John"
.Ed
.Pp
String-symbols can also be used to define small one-line macros:
.Pp
.Bd -literal -offset indent
PUSHA EQUS \[dq]push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n\[dq]
PUSHA EQUS "push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n"
.Ed
.Pp
Note that a colon (:) following the label-name is not allowed.
@@ -448,17 +507,17 @@ LoopyMacro: MACRO
This is fine.
That is, if you only use the macro once per scope.
To get around this problem there is a special label string equate called
.Ic \[rs]\@
.Ic \[rs]@
that you can append to your labels and it will then expand to a unique string.
.Pp
.Ic \[rs]\@
.Ic \[rs]@
also works in REPT-blocks should you have any loops there.
.Bd -literal -offset indent
LoopyMacro: MACRO
xor a,a
\&.loop\[rs]\@ ld [hl+],a
\&.loop\[rs]@ ld [hl+],a
dec c
jr nz,.loop\[rs]\@
jr nz,.loop\[rs]@
ENDM
.Ed
.Pp
@@ -491,9 +550,9 @@ LoopyMacro: MACRO
ld hl,\[rs]1
ld c,\[rs]2
xor a,a
\&.loop\[rs]\@ ld [hl+],a
\&.loop\[rs]@ ld [hl+],a
dec c
jr nz,.loop\[rs]\@
jr nz,.loop\[rs]@
ENDM
.Ed
.Pp
@@ -520,26 +579,27 @@ For instance, if you pass 1 + 2 as the first argument and then do
you will get the value 5 on screen and not 6 as you might have expected.
.Pp
In reality, up to 256 arguments can be passed to a macro, but you can only use
the first 9 like this. If you want to use the rest, you need to use the keyword
the first 9 like this.
If you want to use the rest, you need to use the keyword
.Ic SHIFT .
.Pp
Line continuations work as usual inside macros or lists of arguments of macros.
Strings, however, are a bit trickier. The following example shows how to use
strings as arguments for a macro:
Strings, however, are a bit trickier.
The following example shows how to use strings as arguments for a macro:
.Pp
.Bd -literal -offset indent
PrintMacro : MACRO
PRINTT \[rs]1
ENDM
PrintMacro STRCAT(\[rs]\[dq]Hello\[rs]\[dq]\[rs], \[rs]
\[rs]\[dq] world\[rs]\[rs]n\[rs]\[dq])
PrintMacro STRCAT(\[rs]"Hello\[rs]"\[rs], \[rs]
\[rs]" world\[rs]\[rs]n\[rs]")
.Ed
.Pp
.Ic SHIFT
is a special command only available in macros.
Very useful in REPT-blocks.
It will "shift" the arguments by one "to the left".
It will shift the arguments by one to the left.
.Ic \[rs]1
will get the value of
.Ic \[rs]2 ,
@@ -582,8 +642,8 @@ In fact, it's probably not even safe to purge anything other than string symbols
and macros.
.Pp
.Bd -literal -offset indent
Kamikaze EQUS \[dq]I don't want to live anymore\[dq]
AOLer EQUS \[dq]Me too\[dq]
Kamikaze EQUS "I don't want to live anymore"
AOLer EQUS "Me too"
PURGE Kamikaze, AOLer
.Ed
.Pp
@@ -593,27 +653,27 @@ command WILL NOT BE EXPANDED as the ONLY exception to this rule.
.Ss Predeclared Symbols
The following symbols are defined by the assembler:
.Pp
.Bl -column -offset indent ".Sy String" ".Sy String" ".Sy String"
.It Sy Type Ta Sy Name Ta Ta Sy Contents
.It Ic EQU Ta Ic \@ Ta Ta PC value
.It Ic EQU Ta Ic _PI Ta Ta Fixed point \[*p]
.It Ic SET Ta Ic _RS Ta Ta _RS Counter
.It Ic EQU Ta Ic _NARG Ta Ta Number of arguments passed to macro
.It Ic EQU Ta Ic __LINE__ Ta Ta The current line number
.It Ic EQUS Ta Ic __FILE__ Ta Ta The current filename
.It Ic EQUS Ta Ic __DATE__ Ta Ta Today's date
.It Ic EQUS Ta Ic __TIME__ Ta Ta The current time
.Bl -column -offset indent "EQUS" "__ISO_8601_LOCAL__"
.It Sy Type Ta Sy Name Ta Sy Contents
.It Ic EQU Ta Ic @ Ta PC value
.It Ic EQU Ta Ic _PI Ta Fixed point \[*p]
.It Ic SET Ta Ic _RS Ta _RS Counter
.It Ic EQU Ta Ic _NARG Ta Number of arguments passed to macro
.It Ic EQU Ta Ic __LINE__ Ta The current line number
.It Ic EQUS Ta Ic __FILE__ Ta The current filename
.It Ic EQUS Ta Ic __DATE__ Ta Today's date
.It Ic EQUS Ta Ic __TIME__ Ta The current time
.It Ic EQUS Ta Ic __ISO_8601_LOCAL__ Ta ISO 8601 timestamp (local)
.It Ic EQUS Ta Ic __ISO_8601_UTC__ Ta ISO 8601 timestamp (UTC)
.It Ic EQU Ta Ic __UTC_YEAR__ Ta Ta Today's year
.It Ic EQU Ta Ic __UTC_MONTH__ Ta Ta Today's month number, 1-12
.It Ic EQU Ta Ic __UTC_DAY__ Ta Ta Today's day of the month, 1-31
.It Ic EQU Ta Ic __UTC_HOUR__ Ta Ta Current hour, 0-23
.It Ic EQU Ta Ic __UTC_MINUTE__ Ta Ta Current minute, 0-59
.It Ic EQU Ta Ic __UTC_SECOND__ Ta Ta Current second, 0-59
.It Ic EQU Ta Ic __RGBDS_MAJOR__ Ta Ta Major version number of RGBDS.
.It Ic EQU Ta Ic __RGBDS_MINOR__ Ta Ta Minor version number of RGBDS.
.It Ic EQU Ta Ic __RGBDS_PATCH__ Ta Ta Patch version number of RGBDS.
.It Ic EQU Ta Ic __UTC_YEAR__ Ta Today's year
.It Ic EQU Ta Ic __UTC_MONTH__ Ta Today's month number, 1-12
.It Ic EQU Ta Ic __UTC_DAY__ Ta Today's day of the month, 1-31
.It Ic EQU Ta Ic __UTC_HOUR__ Ta Current hour, 0-23
.It Ic EQU Ta Ic __UTC_MINUTE__ Ta Current minute, 0-59
.It Ic EQU Ta Ic __UTC_SECOND__ Ta Current second, 0-59
.It Ic EQU Ta Ic __RGBDS_MAJOR__ Ta Major version number of RGBDS.
.It Ic EQU Ta Ic __RGBDS_MINOR__ Ta Minor version number of RGBDS.
.It Ic EQU Ta Ic __RGBDS_PATCH__ Ta Patch version number of RGBDS.
.El
.Pp
.Sh DEFINING DATA
@@ -623,7 +683,7 @@ defines a list of bytes that will be stored in the final image.
Ideal for tables and text (which is not zero-terminated).
.Pp
.Bd -literal -offset indent
DB 1,2,3,4,\[dq]This is a string\[dq]
DB 1,2,3,4,"This is a string"
.Ed
.Pp
Alternatively, you can use
@@ -681,9 +741,9 @@ If the file isn't found in the current directory, the include-path list passed
to the linker on the command line will be searched.
.Pp
.Bd -literal -offset indent
INCBIN \[dq]titlepic.bin\[dq]
INCBIN \[dq]sprites/hero.bin\[dq]\ ; UNIX
INCBIN \[dq]sprites\[rs]\[rs]hero.bin\[dq]\ ; Windows
INCBIN "titlepic.bin"
INCBIN "sprites/hero.bin"\ ; UNIX
INCBIN "sprites\[rs]\[rs]hero.bin"\ ; Windows
.Ed
.Pp
You can also include only part of a file with
@@ -691,7 +751,7 @@ You can also include only part of a file with
The example below includes 256 bytes from data.bin starting from byte 78.
.Pp
.Bd -literal -offset indent
INCBIN \[dq]data.bin\[dq],78,256
INCBIN "data.bin",78,256
.Ed
.Ss Unions
Unions allow multiple memory allocations to share the same space in memory,
@@ -736,7 +796,7 @@ Useful for debugging macros or wherever you may feel the need to tell yourself
some important information.
.Pp
.Bd -literal -offset indent
PRINTT \[dq]I'm the greatest programmer in the whole wide world\[rs]n\[dq]
PRINTT "I'm the greatest programmer in the whole wide world\[rs]n"
PRINTI (2 + 3) / 5
PRINTV $FF00 + $F0
PRINTF MUL(3.14, 3987.0)
@@ -747,7 +807,8 @@ PRINTF MUL(3.14, 3987.0)
prints out a string.
.It Ic PRINTV
prints out an integer value in hexadecimal or, as in the example, the result of
a calculation. Unsurprisingly, you can also print out a constant symbols value.
a calculation.
Unsurprisingly, you can also print out a constant symbols value.
.It Ic PRINTI
prints out a signed integer value.
.It Ic PRINTF
@@ -791,7 +852,7 @@ ANGLE SET ANGLE+256.0
.Ic REPT
is also very useful in recursive macros and, as in macros, you can also use the
special label operator
.Ic \[rs]\@ .
.Ic \[rs]@ .
REPT-blocks can be nested.
.Ss Aborting the assembly process
.Ic FAIL
@@ -821,7 +882,7 @@ You may nest
calls infinitely (or until you run out of memory, whichever comes first).
.Pp
.Bd -literal -offset indent
INCLUDE \[dq]irq.inc\[dq]
INCLUDE "irq.inc"
.Ed
.Pp
.Ss Conditional assembling
@@ -836,11 +897,11 @@ This is a powerful feature commonly used in macros.
.Pp
.Bd -literal -offset indent
IF NUM < 0
PRINTT \[dq]NUM < 0\[rs]n\[dq]
PRINTT "NUM < 0\[rs]n"
ELIF NUM == 0
PRINTT \[dq]NUM == 0\[rs]n\[dq]
PRINTT "NUM == 0\[rs]n"
ELSE
PRINTT \[dq]NUM > 0\[rs]n\[dq]
PRINTT "NUM > 0\[rs]n"
ENDC
.Ed
.Pp
@@ -879,17 +940,18 @@ There are a number of numeric formats.
.Pp
.Bl -dash -compact
.It
Hexadecimal: \(Do0123456789ABCDEF. Case-insensitive
Hexadecimal: $0123456789ABCDEF.
Case-insensitive
.It
Decimal: 0123456789
.It
Octal: \*(Am01234567
Octal: &01234567
.It
Binary: %01
.It
Fixedpoint (16.16): 01234.56789
.It
Character constant: \[dq]ABYZ\[dq]
Character constant: "ABYZ"
.It
Gameboy graphics: \`0123
.El
@@ -911,19 +973,19 @@ calculations between numbers.
A great number of operators you can use in expressions are available (listed in
order of precedence):
.Pp
.Bl -column -offset indent ".Sy String" ".Sy String"
.Bl -column -offset indent "Operator"
.It Sy Operator Ta Sy Meaning
.It Li ( ) Ta Precedence override
.It Li \&( \&) Ta Precedence override
.It Li FUNC() Ta Function call
.It Li ~ + - Ta Unary not/plus/minus
.It Li * / % Ta Multiply/divide/modulo
.It Li << >> Ta Shift left/right
.It Li & | ^ Ta Binary and/or/xor
.It Li & \&| ^ Ta Binary and/or/xor
.It Li + - Ta Add/subtract
.It Li != == <= Ta Boolean comparison
.It Li >= < > Ta Boolean comparison (Same precedence as the others)
.It Li && || Ta Boolean and/or
.It Li ! Ta Unary Boolean not
.It Li \&! Ta Unary Boolean not
.El
.Pp
The result of the boolean operators is zero if when FALSE and non-zero when
@@ -956,19 +1018,25 @@ it left.
.Pp
Some things are different for fixed-point math, though, which is why you have
the following functions to use:
.EQ
delim $$
.EN
.Pp
.Bl -column -offset indent ".Sy String" ".Sy String"
.It Sy Name Ta Ta Sy Operation
.It Li DIV(x,y) Ta Ta x/y
.It Li MUL(x,y) Ta Ta x*y
.It Li SIN(x) Ta Ta sin(x)
.It Li COS(x) Ta Ta cos(x)
.It Li TAN(x) Ta Ta tan(x)
.It Li ASIN(x) Ta Ta arcsin(x)
.It Li ACOS(x) Ta Ta arccos(x)
.It Li ATAN(x) Ta Ta arctan(x)
.It Li ATAN2(x,y) Ta Angle between (x,y) and (1,0)
.Bl -column -offset indent "ATAN2(x, y)"
.It Sy Name Ta Sy Operation
.It Fn DIV x y Ta $x \[di] y$
.It Fn MUL x y Ta $x \[mu] y$
.It Fn SIN x Ta $sin ( x )$
.It Fn COS x Ta $cos ( x )$
.It Fn TAN x Ta $tan ( x )$
.It Fn ASIN x Ta $asin ( x )$
.It Fn ACOS x Ta $acos ( x )$
.It Fn ATAN x Ta $atan ( x )$
.It Fn ATAN2 x y Ta Angle between $( x , y )$ and $( 1 , 0 )$
.El
.EQ
delim off
.EN
.Pp
These functions are extremely useful for automatic generation of various tables.
A circle has 65536.0 degrees.
@@ -988,36 +1056,37 @@ ANGLE SET ANGLE+256.0
.Pp
.Ss String Expressions
The most basic string expression is any number of characters contained in double
quotes (\[dq]for instance\[dq]).
quotes ("for instance").
Like in C, the escape character is \[rs], and there are a number of commands you
can use within a string:
.Pp
.Bl -column -offset indent ".Sy String" ".Sy String"
.Bl -column -offset indent "String"
.It Sy String Ta Sy Meaning
.It Li \[rs]\[rs] Ta Backslash
.It Li \[rs]\[dq] Ta Double quote
.It Li \[rs]" Ta Double quote
.It Li \[rs], Ta Comma
.It Li \[rs]\[lC] Ta Curly bracket left
.It Li \[rs]\[rC] Ta Curly bracket right
.It Li \[rs]{ Ta Curly bracket left
.It Li \[rs]} Ta Curly bracket right
.It Li \[rs]n Ta Newline ($0A)
.It Li \[rs]t Ta Tab ($09)
.It Li \[rs]1 - \[rs]9 Ta Macro argument (Only the body of a macros)
.It Li \[rs]\@ Ta Label name suffix (Only in the body of macros and repts)
.It Li \[rs]@ Ta Label name suffix (Only in the body of macros and repts)
.El
.Pp
A funky feature is
.Sy \[lC]symbol\[rC]
withing a string.
.Sy {symbol}
within a string.
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 it's a numeric symbol, the value is converted to hexadecimal notation and
inserted as a string.
.Pp
HINT: The
.Sy \[lC]symbol\[rC]
.Sy {symbol}
construct can also be used outside strings.
The symbol's value is again inserted as a string.
This is just a short way of doing \[dq]\[lC]symbol\[rC]\[dq].
This is just a short way of doing
.Dq {symbol} .
.Pp
Whenever the macro-language expects a string you can actually use a string
expression.
@@ -1025,19 +1094,19 @@ This consists of one or more of these function (yes, you can nest them).
Note that some of these functions actually return an integer and can be used as
part of an integer expression!
.Pp
.Bl -column ".Sy String" ".Sy String"
.It Sy Name Ta Ta Ta Sy Operation
.It Li STRLEN(string) Ta Returns the number of characters in string
.It Li STRCAT(str1,str2) Ta Appends str2 to str1.
.It Li STRCMP(str1,str2) Ta Returns negative if str1 is alphabetically lower
.Bl -column "STRSUB_str,_pos,_len"
.It Sy Name Ta Sy Operation
.It Fn STRLEN string Ta Returns the number of characters in string
.It Fn STRCAT str1 str2 Ta Appends str2 to str1.
.It Fn STRCMP str1 str2 Ta Returns negative if str1 is alphabetically lower
than str2, zero if they match, positive if str1 is greater than str2.
.It Li STRIN(str1,str2) Ta Returns the position of str2 in str1 or zero if it's
.It Fn STRIN str1 str2 Ta Returns the position of str2 in str1 or zero if it's
not present (first character is position 1).
.It Li STRSUB(str,pos,len) Ta Returns a substring from str starting at pos
.It Fn STRSUB str pos len Ta Returns a substring from str starting at pos
(first character is position 1) and with len characters.
.It Li STRUPR(str) Ta Converts all characters in str to capitals and returns the
.It Fn STRUPR str Ta Converts all characters in str to capitals and returns the
new string.
.It Li STRLWR(str) Ta Converts all characters in str to lower case and returns
.It Fn STRLWR str Ta Converts all characters in str to lower case and returns
the new string.
.El
.Pp
@@ -1072,23 +1141,32 @@ rest of it will be trimmed.
.Ss Other functions
There are a few other functions that do various useful things:
.Pp
.Bl -column ".Sy String" ".Sy String"
.It Sy Name Ta Ta Ta Sy Operation
.It Li BANK(\@/str/lbl) Ta Returns a bank number.
If the argument is the symbol
.Ic \@,
.Bl -column "BANK(arg)"
.It Sy Name Ta Sy Operation
.It Fn BANK arg Ta Returns a bank number.
If
.Ar arg
is the symbol
.Ic @ ,
this function returns the bank of the current section.
If the argument is a string, it returns the bank of the section that has that
name.
If the argument is a label, it returns the bank number the label is in.
If
.Ar arg
is a string, it returns the bank of the section that has that name.
If
.Ar arg
is a label, it returns the bank number the label is in.
For labels, as the linker has to resolve this, it can't be used when the
expression has to be constant.
.It Li DEF(label) Ta Returns TRUE if label has been defined.
.It Li HIGH(r16/cnst/lbl) Ta Returns the top 8 bits of the operand if it is a
label or constant, or the top 8-bit register if it is a 16-bit register.
.It Li LOW(r16/cnst/lbl) Ta Returns the bottom 8 bits of the operand if it is a
label or constant, or the bottom 8-bit register if it is a 16-bit register (AF
isn't a valid register for this function).
.It Fn DEF label Ta Returns TRUE if
.Ar label
has been defined.
.It Fn HIGH arg Ta Returns the top 8 bits of the operand if
.Ar arg
is a label or constant, or the top 8-bit register if it is a 16-bit register.
.It Fn LOW arg Ta Returns the bottom 8 bits of the operand if
.Ar arg
is a label or constant, or the bottom 8-bit register if it is a 16-bit register
(AF isn't a valid register for this function).
.El
.Pp
.Sh MISCELLANEOUS
@@ -1125,94 +1203,6 @@ Useful if you want to change some options in an include file and you don't want
to destroy the options set by the program that included your file.
The stacks number of entries is limited only by the amount of memory in your
machine.
.Sh ALPHABETICAL LIST OF KEYWORDS
.Bl -inset -compact
.It Sx @
.It Sx __DATE__
.It Sx __FILE__
.It Sx __ISO_8601_LOCAL__
.It Sx __ISO_8601_UTC__
.It Sx __LINE__
.It Sx __TIME__
.It Sx __RGBDS_MAJOR__
.It Sx __RGBDS_MINOR__
.It Sx __RGBDS_PATCH__
.It Sx __UTC_YEAR__
.It Sx __UTC_MONTH__
.It Sx __UTC_DAY__
.It Sx __UTC_HOUR__
.It Sx __UTC_MINUTE__
.It Sx __UTC_SECOND__
.It Sx _NARG
.It Sx _PI
.It Sx _RS
.It Sx ACOS
.It Sx ASIN
.It Sx ATAN
.It Sx ATAN2
.It Sx BANK
.It Sx CHARMAP
.It Sx COS
.It Sx DB
.It Sx DEF
.It Sx DIV
.It Sx DL
.It Sx DS
.It Sx DW
.It Sx ELIF
.It Sx ELSE
.It Sx ENDC
.It Sx ENDM
.It Sx ENDR
.It Sx EQU
.It Sx EQUS
.It Sx EXPORT
.It Sx FAIL
.It Sx GLOBAL
.It Sx HIGH
.It Sx HRAM
.It Sx IF
.It Sx INCBIN
.It Sx INCLUDE
.It Sx LOW
.It Sx MACRO
.It Sx MUL
.It Sx OPT
.It Sx POPO
.It Sx POPS
.It Sx PRINTF
.It Sx PRINTI
.It Sx PRINTT
.It Sx PRINTV
.It Sx PURGE
.It Sx PUSHO
.It Sx PUSHS
.It Sx REPT
.It Sx RB
.It Sx RL
.It Sx ROM0
.It Sx ROMX
.It Sx RSRESET
.It Sx RSSET
.It Sx RW
.It Sx SECTION
.It Sx SET
.It Sx SHIFT
.It Sx SIN
.It Sx SRAM
.It Sx STRCAT
.It Sx STRCMP
.It Sx STRIN
.It Sx STRLEN
.It Sx STRLWR
.It Sx STRSUB
.It Sx STRUPR
.It Sx TAN
.It Sx VRAM
.It Sx WRAM0
.It Sx WRAMX
.It Sx WARN
.El
.Sh SEE ALSO
.Xr rgbasm 1 ,
.Xr rgblink 1 ,

View File

@@ -330,6 +330,15 @@ void rpn_SHL(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
if (src1->nVal < 0)
warning("Left shift of negative value: %d", src1->nVal);
if (src2->nVal < 0)
fatalerror("Shift by negative value: %d", src2->nVal);
else if (src2->nVal >= 32)
fatalerror("Shift by too big value: %d", src2->nVal);
expr->nVal = (expr->nVal << src2->nVal);
pushbyte(expr, RPN_SHL);
}
@@ -338,6 +347,11 @@ void rpn_SHR(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
if (src2->nVal < 0)
fatalerror("Shift by negative value: %d", src2->nVal);
else if (src2->nVal >= 32)
fatalerror("Shift by too big value: %d", src2->nVal);
expr->nVal = (expr->nVal >> src2->nVal);
pushbyte(expr, RPN_SHR);
}
@@ -355,7 +369,7 @@ void rpn_DIV(struct Expression *expr, const struct Expression *src1,
{
joinexpr();
if (src2->nVal == 0)
fatalerror("division by zero");
fatalerror("Division by zero");
expr->nVal = (expr->nVal / src2->nVal);
pushbyte(expr, RPN_DIV);
@@ -366,7 +380,7 @@ void rpn_MOD(struct Expression *expr, const struct Expression *src1,
{
joinexpr();
if (src2->nVal == 0)
fatalerror("division by zero");
fatalerror("Division by zero");
expr->nVal = (expr->nVal % src2->nVal);
pushbyte(expr, RPN_MOD);

View File

@@ -25,6 +25,7 @@
#include "extern/err.h"
#include "helpers.h"
#include "version.h"
struct sSymbol *tHashedSymbols[HASHSIZE];
@@ -62,7 +63,7 @@ void helper_RemoveLeadingZeros(char *string)
memmove(string, new_beginning, strlen(new_beginning) + 1);
}
int32_t Callback_NARG(struct sSymbol *sym)
int32_t Callback_NARG(unused_ struct sSymbol *sym)
{
uint32_t i = 0;
@@ -72,7 +73,7 @@ int32_t Callback_NARG(struct sSymbol *sym)
return i;
}
int32_t Callback__LINE__(struct sSymbol __attribute__((unused)) *sym)
int32_t Callback__LINE__(unused_ struct sSymbol *sym)
{
return nLineNo;
}
@@ -101,6 +102,19 @@ uint32_t calchash(char *s)
return hash % HASHSIZE;
}
/*
* Update a symbol's definition filename and line
*/
void updateSymbolFilename(struct sSymbol *nsym)
{
if (snprintf(nsym->tzFileName, _MAX_PATH + 1, "%s",
tzCurrentFileName) > _MAX_PATH) {
fatalerror("%s: File name is too long: '%s'", __func__,
tzCurrentFileName);
}
nsym->nFileLine = fstk_GetLine();
}
/*
* Create a new symbol by name
*/
@@ -132,14 +146,7 @@ struct sSymbol *createsymbol(char *s)
(*ppsym)->pMacro = NULL;
(*ppsym)->pSection = NULL;
(*ppsym)->Callback = NULL;
if (snprintf((*ppsym)->tzFileName, _MAX_PATH + 1, "%s",
tzCurrentFileName) > _MAX_PATH) {
fatalerror("%s: File name is too long: '%s'", __func__,
tzCurrentFileName);
}
(*ppsym)->nFileLine = fstk_GetLine();
updateSymbolFilename(*ppsym);
return *ppsym;
}
@@ -559,6 +566,7 @@ void sym_AddEqu(char *tzSym, int32_t value)
nsym->nValue = value;
nsym->nType |= SYMF_EQU | SYMF_DEFINED | SYMF_CONST;
nsym->pScope = NULL;
updateSymbolFilename(nsym);
}
}
}
@@ -632,6 +640,7 @@ void sym_AddSet(char *tzSym, int32_t value)
nsym->nValue = value;
nsym->nType |= SYMF_SET | SYMF_DEFINED | SYMF_CONST;
nsym->pScope = NULL;
updateSymbolFilename(nsym);
}
}
@@ -673,7 +682,7 @@ void sym_AddReloc(char *tzSym)
struct sSymbol *parent = pScope->pScope ?
pScope->pScope : pScope;
int32_t parentLen = localPtr - tzSym;
uint32_t parentLen = localPtr - tzSym;
if (strchr(localPtr + 1, '.') != NULL) {
fatalerror("'%s' is a nonsensical reference to a nested local symbol",
@@ -709,6 +718,8 @@ void sym_AddReloc(char *tzSym)
nsym->pScope = scope;
nsym->pSection = pCurrentSection;
updateSymbolFilename(nsym);
}
}
pScope = findsymbol(tzSym, scope);
@@ -839,6 +850,7 @@ void sym_AddMacro(char *tzSym)
nsym->pScope = NULL;
nsym->ulMacroSize = ulNewMacroSize;
nsym->pMacro = tzNewMacro;
updateSymbolFilename(nsym);
}
}
}

8
src/extern/err.c vendored
View File

@@ -33,7 +33,7 @@ void rgbds_vwarnx(const char *fmt, va_list ap)
putc('\n', stderr);
}
noreturn void rgbds_verr(int status, const char *fmt, va_list ap)
noreturn_ void rgbds_verr(int status, const char *fmt, va_list ap)
{
fprintf(stderr, "error");
if (fmt) {
@@ -44,7 +44,7 @@ noreturn void rgbds_verr(int status, const char *fmt, va_list ap)
exit(status);
}
noreturn void rgbds_verrx(int status, const char *fmt, va_list ap)
noreturn_ void rgbds_verrx(int status, const char *fmt, va_list ap)
{
fprintf(stderr, "error");
if (fmt) {
@@ -73,7 +73,7 @@ void rgbds_warnx(const char *fmt, ...)
va_end(ap);
}
noreturn void rgbds_err(int status, const char *fmt, ...)
noreturn_ void rgbds_err(int status, const char *fmt, ...)
{
va_list ap;
@@ -82,7 +82,7 @@ noreturn void rgbds_err(int status, const char *fmt, ...)
va_end(ap);
}
noreturn void rgbds_errx(int status, const char *fmt, ...)
noreturn_ void rgbds_errx(int status, const char *fmt, ...)
{
va_list ap;

View File

@@ -11,34 +11,31 @@
#include <stdint.h>
static const uint8_t utf8d[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00..0f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10..1f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20..2f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30..3f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40..4f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50..5f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60..6f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70..7f */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80..8f */
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, /* 90..9f */
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* a0..af */
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* b0..bf */
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* c0..cf */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* d0..df */
0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, /* e0..e7 */
0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, /* e8..ef */
0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, /* f0..f7 */
0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, /* f8..ff */
0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, /* s0.. */
0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, /* ..s0 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s1 */
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, /* s1 */
1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, /* s3 */
1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, /* s4 */
1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, /* s5 */
1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s6 */
1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s7 */
1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00..0f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10..1f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20..2f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30..3f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40..4f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50..5f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60..6f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70..7f */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80..8f */
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, /* 90..9f */
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* a0..af */
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* b0..bf */
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* c0..cf */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* d0..df */
10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, /* e0..ef */
11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* f0..ff */
0, 1, 2, 3, 5, 8, 7, 1, 1, 1, 4, 6, 1, 1, 1, 1, /* s0 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s1 */
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, /* s1 */
1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, /* s3 */
1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, /* s4 */
1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, /* s5 */
1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s6 */
1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s7 */
1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s8 */
};
uint32_t decode(uint32_t *state, uint32_t *codep, uint32_t byte)

View File

@@ -207,9 +207,19 @@ int main(int argc, char *argv[])
err(1, "Error opening file %s", argv[argc - 1]);
/*
* Write changes to ROM
* Read ROM header
*
* Offsets in the buffer are 0x100 less than the equivalent in ROM.
*/
uint8_t header[0x50];
if (fseek(rom, 0x100, SEEK_SET) != 0)
err(1, "Could not locate ROM header");
if (fread(header, sizeof(uint8_t), sizeof(header), rom)
!= sizeof(header))
err(1, "Could not read ROM header");
if (fixlogo || trashlogo) {
/*
* Offset 0x1040x133: Nintendo Logo
@@ -232,12 +242,12 @@ int main(int argc, char *argv[])
0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E
};
if (trashlogo)
if (trashlogo) {
for (int i = 0; i < sizeof(ninlogo); i++)
ninlogo[i] = ~ninlogo[i];
}
fseek(rom, 0x104, SEEK_SET);
fwrite(ninlogo, 1, 48, rom);
memcpy(header + 0x04, ninlogo, sizeof(ninlogo));
}
if (settitle) {
@@ -258,11 +268,10 @@ int main(int argc, char *argv[])
* characters may conflict with the title.
*/
fseek(rom, 0x134, SEEK_SET);
fwrite(title, 1, strlen(title) + 1, rom);
int n = snprintf((char *)header + 0x34, 16, "%s", title);
while (ftell(rom) < 0x143)
fputc(0, rom);
for (int i = 16; i > n; i--)
header[0x34 + i] = '\0';
}
if (setid) {
@@ -272,8 +281,7 @@ int main(int argc, char *argv[])
* characters).
*/
fseek(rom, 0x13F, SEEK_SET);
fwrite(id, 1, 4, rom);
memcpy(header + 0x3F, id, 4);
}
if (colorcompatible) {
@@ -291,20 +299,12 @@ int main(int argc, char *argv[])
* may conflict.
*/
uint8_t byte;
fseek(rom, 0x143, SEEK_SET);
byte = fgetc(rom);
byte |= 1 << 7;
header[0x43] |= 1 << 7;
if (coloronly)
byte |= 1 << 6;
header[0x43] |= 1 << 6;
if (byte & 0x3F)
if (header[0x43] & 0x3F)
warnx("Color flag conflicts with game title");
fseek(rom, 0x143, SEEK_SET);
fputc(byte, rom);
}
if (setnewlicensee) {
@@ -320,8 +320,8 @@ int main(int argc, char *argv[])
* as a Super Game Boy flag.
*/
fseek(rom, 0x144, SEEK_SET);
fwrite(newlicensee, 1, 2, rom);
header[0x44] = newlicensee[0];
header[0x45] = newlicensee[1];
}
if (super) {
@@ -340,8 +340,7 @@ int main(int argc, char *argv[])
if (!setlicensee)
warnx("You should probably set both '-s' and '-l 0x33'");
fseek(rom, 0x146, SEEK_SET);
fputc(3, rom);
header[0x46] = 3;
}
if (setcartridge) {
@@ -351,8 +350,7 @@ int main(int argc, char *argv[])
* external RAM, timer, rumble, or battery.
*/
fseek(rom, 0x147, SEEK_SET);
fputc(cartridge, rom);
header[0x47] = cartridge;
}
if (resize) {
@@ -366,8 +364,13 @@ int main(int argc, char *argv[])
int headbyte;
uint8_t *buf;
fseek(rom, 0, SEEK_END);
if (fseek(rom, 0, SEEK_END) != 0)
err(1, "Could not pad ROM file");
romsize = ftell(rom);
if (romsize == -1)
err(1, "Could not pad ROM file");
newsize = 0x8000;
headbyte = 0;
@@ -380,11 +383,14 @@ int main(int argc, char *argv[])
warnx("ROM size is bigger than 8MiB");
buf = malloc(newsize - romsize);
memset(buf, padvalue, newsize - romsize);
fwrite(buf, 1, newsize - romsize, rom);
if (buf == NULL)
errx(1, "Couldn't allocate memory for padded ROM.");
fseek(rom, 0x148, SEEK_SET);
fputc(headbyte, rom);
memset(buf, padvalue, newsize - romsize);
if (fwrite(buf, 1, newsize - romsize, rom) != newsize - romsize)
err(1, "Could not pad ROM file");
header[0x48] = headbyte;
free(buf);
}
@@ -394,8 +400,7 @@ int main(int argc, char *argv[])
* Offset 0x149: RAM Size
*/
fseek(rom, 0x149, SEEK_SET);
fputc(ramsize, rom);
header[0x49] = ramsize;
}
if (nonjapan) {
@@ -403,8 +408,7 @@ int main(int argc, char *argv[])
* Offset 0x14A: Non-Japanese Region Flag
*/
fseek(rom, 0x14A, SEEK_SET);
fputc(1, rom);
header[0x4A] = 1;
}
if (setlicensee) {
@@ -420,8 +424,7 @@ int main(int argc, char *argv[])
* See also: the New Licensee ID at 0x1440x145.
*/
fseek(rom, 0x14B, SEEK_SET);
fputc(licensee, rom);
header[0x4B] = licensee;
}
if (setversion) {
@@ -430,8 +433,7 @@ int main(int argc, char *argv[])
* Which version of the ROM this is.
*/
fseek(rom, 0x14C, SEEK_SET);
fputc(version, rom);
header[0x4C] = version;
}
if (fixheadsum || trashheadsum) {
@@ -441,17 +443,27 @@ int main(int argc, char *argv[])
uint8_t headcksum = 0;
fseek(rom, 0x134, SEEK_SET);
for (int i = 0; i < (0x14D - 0x134); ++i)
headcksum = headcksum - fgetc(rom) - 1;
for (int i = 0x34; i < 0x4D; ++i)
headcksum = headcksum - header[i] - 1;
if (trashheadsum)
headcksum = ~headcksum;
fseek(rom, 0x14D, SEEK_SET);
fputc(headcksum, rom);
header[0x4D] = headcksum;
}
/*
* Before calculating the global checksum, we must write the modified
* header to the ROM.
*/
if (fseek(rom, 0x100, SEEK_SET) != 0)
err(1, "Could not locate header for writing");
if (fwrite(header, sizeof(uint8_t), sizeof(header), rom)
!= sizeof(header))
err(1, "Could not write modified ROM header");
if (fixglobalsum || trashglobalsum) {
/*
* Offset 0x14E0x14F: Global Checksum
@@ -459,15 +471,20 @@ int main(int argc, char *argv[])
uint16_t globalcksum = 0;
rewind(rom);
for (int i = 0; i < 0x14E; ++i)
globalcksum += fgetc(rom);
if (fseek(rom, 0, SEEK_SET) != 0)
err(1, "Could not start calculating global checksum");
int i = 0;
int byte;
fseek(rom, 0x150, SEEK_SET);
while ((byte = fgetc(rom)) != EOF)
globalcksum += byte;
while ((byte = fgetc(rom)) != EOF) {
if (i != 0x14E && i != 0x14F)
globalcksum += byte;
i++;
}
if (ferror(rom))
err(1, "Could not calculate global checksum");
if (trashglobalsum)
globalcksum = ~globalcksum;
@@ -475,9 +492,12 @@ int main(int argc, char *argv[])
fseek(rom, 0x14E, SEEK_SET);
fputc(globalcksum >> 8, rom);
fputc(globalcksum & 0xFF, rom);
if (ferror(rom))
err(1, "Could not write global checksum");
}
fclose(rom);
if (fclose(rom) != 0)
err(1, "Could not complete ROM write");
return 0;
}

View File

@@ -1105,7 +1105,21 @@ Cycles: 3
.Pp
Bytes: 1
.Pp
Flags: None affected.
Flags:
.Bl -bullet -compact
.It
.Sy Z :
Set from bit 7 of the popped low byte.
.It
.Sy N :
Set from bit 6 of the popped low byte.
.It
.Sy H :
Set from bit 5 of the popped low byte.
.It
.Sy C :
Set from bit 4 of the popped low byte.
.El
.Ss POP r16
Pop register
.Ar r16
@@ -1119,7 +1133,15 @@ Flags: None affected.
.Ss PUSH AF
Push register
.Sy AF
into the stack.
into the stack. The low byte's bit 7 corresponds to the
.Sy Z
flag, its bit 6 to the
.Sy N
flag, bit 5 to the
.Sy H
flag, and bit 4 to the
.Sy C
flag. Bits 3 to 0 are reset.
.Pp
Cycles: 4
.Pp

View File

@@ -53,6 +53,7 @@ int main(int argc, char *argv[])
break;
case 'F':
opts.hardfix = true;
/* fallthrough */
case 'f':
opts.fix = true;
break;

View File

@@ -317,9 +317,9 @@ static void rgba_png_palette(struct PNGImage *img,
png_color **palette_ptr_ptr, int *num_colors)
{
if (png_get_valid(img->png, img->info, PNG_INFO_PLTE))
return rgba_PLTE_palette(img, palette_ptr_ptr, num_colors);
rgba_PLTE_palette(img, palette_ptr_ptr, num_colors);
else
return rgba_build_palette(img, palette_ptr_ptr, num_colors);
rgba_build_palette(img, palette_ptr_ptr, num_colors);
}
static void rgba_PLTE_palette(struct PNGImage *img,
@@ -469,8 +469,10 @@ struct ColorWithLuminance {
static int compare_luminance(const void *a, const void *b)
{
struct ColorWithLuminance *x = (struct ColorWithLuminance *)a;
struct ColorWithLuminance *y = (struct ColorWithLuminance *)b;
const struct ColorWithLuminance *x, *y;
x = (const struct ColorWithLuminance *)a;
y = (const struct ColorWithLuminance *)b;
return y->luminance - x->luminance;
}

View File

@@ -74,6 +74,10 @@ static void do_max_bank(enum eSectionType Type, int32_t nBank)
if (nBank > MaxVBankUsed)
MaxVBankUsed = nBank;
break;
case SECT_ROM0:
case SECT_WRAM0:
case SECT_OAM:
case SECT_HRAM:
default:
break;
}
@@ -317,8 +321,9 @@ struct sSection *GetSectionByName(const char *name)
return NULL;
}
int32_t IsSectionSameTypeBankAndFloating(const char *name,
enum eSectionType type, int32_t bank)
int32_t IsSectionSameTypeBankAndAttrs(const char *name,
enum eSectionType type, int32_t bank,
int32_t org, int32_t align)
{
const struct sSection *pSection;
@@ -336,8 +341,9 @@ int32_t IsSectionSameTypeBankAndFloating(const char *name,
* mismatch or not.
*/
/* Section must be floating in source */
if (pSection->nOrg != -1 || pSection->nAlign != 1)
/* Section must have the same attributes or float */
if ((pSection->nOrg != -1 && pSection->nOrg != org) ||
(pSection->nAlign != 1 && pSection->nAlign != align))
return 0;
/* It must have the same type in source and linkerscript */
@@ -370,15 +376,6 @@ uint32_t AssignSectionAddressAndBankByName(const char *name, uint32_t address,
/* Section has been found. */
/*
* A section can be left as floating in the code if the location
* is assigned in the linkerscript.
*/
if (pSection->nOrg != -1 || pSection->nAlign != 1) {
errx(1, "Section \"%s\" from linkerscript isn't floating.\n",
name);
}
/* The bank can be left as unassigned or be the same */
if (pSection->nBank != -1 && pSection->nBank != bank) {
errx(1, "Section \"%s\" from linkerscript has different bank number than in the source.\n",
@@ -494,7 +491,6 @@ void SetLinkerscriptName(char *tzLinkerscriptFile)
void AssignSections(void)
{
int32_t i;
struct sSection *pSection;
MaxBankUsed = 0;
@@ -503,7 +499,7 @@ void AssignSections(void)
* Initialize the memory areas
*/
for (i = 0; i < BANK_INDEX_MAX; i += 1) {
for (int32_t i = 0; i < BANK_INDEX_MAX; i += 1) {
BankFree[i] = malloc(sizeof(*BankFree[i]));
if (!BankFree[i]) {
@@ -617,6 +613,9 @@ void AssignSections(void)
pSection->nOrg, pSection->nBank);
}
break;
default:
errx(1, "%s: Internal error: Type %d", __func__,
pSection->Type);
}
}
@@ -660,6 +659,10 @@ void AssignSections(void)
do_max_bank(pSection->Type, pSection->nBank);
break;
case SECT_ROM0:
case SECT_WRAM0:
case SECT_OAM:
case SECT_HRAM:
default: /* Handle other sections later */
break;
}

View File

@@ -23,7 +23,7 @@
#include "types.h"
extern int yyparse();
extern int yyparse(void);
/* File include stack. */
@@ -179,13 +179,13 @@ void script_PrintFileStack(void)
fprintf(stderr, "%s(%d)", linkerscript_path, include_line[i]);
}
noreturn void script_fatalerror(const char *fmt, ...)
noreturn_ void script_fatalerror(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, "error: ");
script_PrintFileStack();
fprintf(stderr, ":\n\t");
fprintf(stderr, ":\n ");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);

View File

@@ -120,6 +120,10 @@ void MapfileWriteSection(const struct sSection *pSect)
for (i = 0; i < pSect->nNumberOfSymbols; i += 1) {
const struct sSymbol *pSym = pSect->tSymbols[i];
/* Don't print '@' */
if (strcmp(pSym->pzName, "@") == 0)
continue;
if ((pSym->pSection == pSect) && (pSym->Type != SYM_IMPORT)) {
if (mf) {
fprintf(mf, " $%04X = %s\n",

View File

@@ -28,7 +28,6 @@
struct sSymbol **tSymbols;
struct sSection *pSections;
struct sSection *pLibSections;
uint8_t dummymem;
uint8_t oReadLib;
/*
@@ -36,14 +35,14 @@ uint8_t oReadLib;
*/
static int32_t readlong(FILE *f)
{
int32_t r;
uint32_t r;
r = fgetc(f);
r |= fgetc(f) << 8;
r |= fgetc(f) << 16;
r |= fgetc(f) << 24;
r = ((uint32_t)(uint8_t)fgetc(f));
r |= ((uint32_t)(uint8_t)fgetc(f)) << 8;
r |= ((uint32_t)(uint8_t)fgetc(f)) << 16;
r |= ((uint32_t)(uint8_t)fgetc(f)) << 24;
return r;
return (int32_t)r;
}
/*
@@ -209,7 +208,7 @@ struct sSection *obj_ReadRGBSection(FILE *f)
if (pSection->nByteSize == 0) {
/* Skip number of patches */
readlong(f);
pSection->pData = &dummymem;
pSection->pData = NULL;
return pSection;
}
@@ -283,7 +282,7 @@ void obj_ReadRGB(FILE *pObjfile, char *tzObjectfile)
for (i = 0; i < nNumberOfSymbols; i += 1)
tSymbols[i] = obj_ReadSymbol(pObjfile, tzObjectfile);
} else {
tSymbols = (struct sSymbol **)&dummymem;
tSymbols = NULL;
}
/* Next we have the sections */

View File

@@ -110,46 +110,53 @@ void Output(void)
FILE *f_overlay = NULL;
/*
* Apply overlay
* Load overlay
*/
if (tzOverlayname) {
f_overlay = fopen(tzOverlayname, "rb");
if (!f_overlay) {
errx(1, "Failed to open overlay file %s\n",
tzOverlayname);
}
fseek(f_overlay, 0, SEEK_END);
if (ftell(f_overlay) % 0x4000 != 0)
errx(1, "Overlay file must be aligned to 0x4000 bytes.");
MaxOverlayBank = (ftell(f_overlay) / 0x4000) - 1;
if (MaxOverlayBank < 1)
errx(1, "Overlay file must be at least 0x8000 bytes.");
if (MaxOverlayBank > MaxBankUsed)
MaxBankUsed = MaxOverlayBank;
}
/*
* Write ROM.
*/
f = fopen(tzOutname, "wb");
if (f != NULL) {
if (tzOverlayname) {
f_overlay = fopen(tzOverlayname, "rb");
if (!f_overlay) {
errx(1, "Failed to open overlay file %s\n",
tzOverlayname);
}
fseek(f_overlay, 0, SEEK_END);
if (ftell(f_overlay) % 0x4000 != 0)
errx(1, "Overlay file must be aligned to 0x4000 bytes.");
MaxOverlayBank = (ftell(f_overlay) / 0x4000) - 1;
if (MaxOverlayBank < 1)
errx(1, "Overlay file must be at least 0x8000 bytes.");
if (MaxOverlayBank > MaxBankUsed)
MaxBankUsed = MaxOverlayBank;
}
writehome(f, f_overlay);
for (i = 1; i <= MaxBankUsed; i += 1)
writebank(f, f_overlay, i);
fclose(f);
if (tzOverlayname)
fclose(f_overlay);
}
/*
* Add regular sections
* Close overlay
*/
if (tzOverlayname)
fclose(f_overlay);
/*
* Add regular sections to map and sym files.
*/
for (i = BANK_INDEX_WRAM0; i < BANK_INDEX_MAX; i++) {

View File

@@ -14,7 +14,7 @@
#include "link/script.h"
int yylex();
int yylex(void);
void yyerror(char *);
extern int yylineno;
@@ -107,8 +107,8 @@ statement:
%%
extern int yylex();
extern int yyparse();
extern int yylex(void);
extern int yyparse(void);
int yywrap(void)
{

View File

@@ -314,7 +314,7 @@ void Patch(void)
/* t contains the destination of the jump */
t = (int16_t)((t & 0xFFFF) - (nPatchOrg + 1));
if (t >= -128 && t <= 255) {
if (t >= -128 && t <= 127) {
t &= 0xFF;
pSect->pData[pPatch->nOffset] =
(uint8_t)t;
@@ -325,6 +325,8 @@ void Patch(void)
pPatch->nLineNo);
}
break;
default:
errx(1, "%s: Internal error.", __func__);
}
pPatch = pPatch->pNext;

View File

@@ -23,6 +23,10 @@ static struct {
static int32_t current_bank = -1; /* Bank as seen by the bank array */
static int32_t current_real_bank = -1; /* bank as seen by the GB */
/* Current section attributes */
static int32_t fix_org = -1;
static int32_t fix_align = 1;
void script_InitSections(void)
{
int32_t i;
@@ -85,59 +89,59 @@ void script_InitSections(void)
}
}
void script_SetCurrentSectionType(const char *type, uint32_t bank)
void script_SetCurrentSectionType(const char *type, uint32_t bank_num)
{
if (strcmp(type, "ROM0") == 0) {
if (bank != 0)
if (bank_num != 0)
errx(1, "Trying to assign a bank number to ROM0.\n");
current_bank = BANK_INDEX_ROM0;
current_real_bank = 0;
return;
} else if (strcmp(type, "ROMX") == 0) {
if (bank == 0)
if (bank_num == 0)
errx(1, "ROMX index can't be 0.\n");
if (bank > BANK_COUNT_ROMX) {
errx(1, "ROMX index too big (%d > %d).\n", bank,
if (bank_num > BANK_COUNT_ROMX) {
errx(1, "ROMX index too big (%d > %d).\n", bank_num,
BANK_COUNT_ROMX);
}
current_bank = BANK_INDEX_ROMX + bank - 1;
current_real_bank = bank;
current_bank = BANK_INDEX_ROMX + bank_num - 1;
current_real_bank = bank_num;
return;
} else if (strcmp(type, "VRAM") == 0) {
if (bank >= BANK_COUNT_VRAM) {
errx(1, "VRAM index too big (%d >= %d).\n", bank,
if (bank_num >= BANK_COUNT_VRAM) {
errx(1, "VRAM index too big (%d >= %d).\n", bank_num,
BANK_COUNT_VRAM);
}
current_bank = BANK_INDEX_VRAM + bank;
current_real_bank = bank;
current_bank = BANK_INDEX_VRAM + bank_num;
current_real_bank = bank_num;
return;
} else if (strcmp(type, "WRAM0") == 0) {
if (bank != 0)
if (bank_num != 0)
errx(1, "Trying to assign a bank number to WRAM0.\n");
current_bank = BANK_INDEX_WRAM0;
current_real_bank = 0;
return;
} else if (strcmp(type, "WRAMX") == 0) {
if (bank == 0)
if (bank_num == 0)
errx(1, "WRAMX index can't be 0.\n");
if (bank > BANK_COUNT_WRAMX) {
errx(1, "WRAMX index too big (%d > %d).\n", bank,
if (bank_num > BANK_COUNT_WRAMX) {
errx(1, "WRAMX index too big (%d > %d).\n", bank_num,
BANK_COUNT_WRAMX);
}
current_bank = BANK_INDEX_WRAMX + bank - 1;
current_real_bank = bank;
current_bank = BANK_INDEX_WRAMX + bank_num - 1;
current_real_bank = bank_num;
return;
} else if (strcmp(type, "SRAM") == 0) {
if (bank >= BANK_COUNT_SRAM) {
errx(1, "SRAM index too big (%d >= %d).\n", bank,
if (bank_num >= BANK_COUNT_SRAM) {
errx(1, "SRAM index too big (%d >= %d).\n", bank_num,
BANK_COUNT_SRAM);
}
current_bank = BANK_INDEX_SRAM + bank;
current_real_bank = bank;
current_bank = BANK_INDEX_SRAM + bank_num;
current_real_bank = bank_num;
return;
} else if (strcmp(type, "OAM") == 0) {
if (bank != 0) {
if (bank_num != 0) {
errx(1, "%s: Trying to assign a bank number to OAM.\n",
__func__);
}
@@ -145,7 +149,7 @@ void script_SetCurrentSectionType(const char *type, uint32_t bank)
current_real_bank = 0;
return;
} else if (strcmp(type, "HRAM") == 0) {
if (bank != 0) {
if (bank_num != 0) {
errx(1, "%s: Trying to assign a bank number to HRAM.\n",
__func__);
}
@@ -176,6 +180,8 @@ void script_SetAddress(uint32_t addr)
bank[current_bank].address,
bank[current_bank].top_address);
}
fix_org = addr;
}
void script_SetAlignment(uint32_t alignment)
@@ -200,6 +206,8 @@ void script_SetAlignment(uint32_t alignment)
bank[current_bank].address,
bank[current_bank].top_address);
}
fix_align = size;
}
void script_OutputSection(const char *section_name)
@@ -209,9 +217,11 @@ void script_OutputSection(const char *section_name)
section_name);
}
if (!IsSectionSameTypeBankAndFloating(section_name,
bank[current_bank].type,
current_real_bank)) {
if (!IsSectionSameTypeBankAndAttrs(section_name,
bank[current_bank].type,
current_real_bank,
fix_org,
fix_align)) {
errx(1, "Different attributes for \"%s\" in source and linkerscript\n",
section_name);
}
@@ -221,5 +231,7 @@ void script_OutputSection(const char *section_name)
AssignSectionAddressAndBankByName(section_name,
bank[current_bank].address,
current_real_bank);
}
fix_org = -1;
fix_align = 1;
}

View File

@@ -57,7 +57,9 @@ REPT NumberOfSymbols ; Number of symbols defined in this object file.
LONG LineNum ; Line number in the file where the symbol is defined.
LONG SectionID ; The section number (of this object file) in which
; this symbol is defined.
; this symbol is defined. If it doesn't belong to any
; specific section (like a constant), this field has
; the value -1.
LONG Value ; The symbols value. It's the offset into that
; symbol's section.

View File

@@ -1,2 +1,2 @@
ERROR: divzero-instr.asm(2):
division by zero
Division by zero

View File

@@ -1,2 +1,4 @@
ERROR: divzero-section-bank.asm(1):
division by zero
Invalid integer constant
ERROR: divzero-section-bank.asm(1):
Division by zero

4
test/asm/equ-charmap.asm Normal file
View File

@@ -0,0 +1,4 @@
SECTION "sec", ROM0
charmap "A", 1
_A_ EQU "A"
db _A_

0
test/asm/equ-charmap.out Normal file
View File

View File

@@ -0,0 +1 @@


View File

@@ -0,0 +1,7 @@
SECTION "sec", ROM0
dw Sym
m: MACRO
Sym::
ENDM
m
Sym::

View File

@@ -0,0 +1,3 @@
ERROR: label-redefinition.asm(7):
'Sym' already defined in m(6)
error: Assembly aborted in pass 1 (1 errors)!

View File

@@ -0,0 +1 @@
foo @bar\

View File

@@ -0,0 +1,2 @@
ERROR: line-continuation.asm(2) -> @(-1):
Macro '@' not defined

View File

@@ -1,3 +1,3 @@
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)!

View File

@@ -1,2 +1,2 @@
ERROR: macro-@.asm(1) -> @(-1):
Macro '@' not defined
Macro '@' not defined

View File

@@ -1,2 +1,2 @@
ERROR: null-in-macro.asm(1):
Unterminated MACRO definition.
Unterminated MACRO definition.

View File

@@ -1,2 +1,2 @@
ERROR: remote-local-noexist.asm(7):
'Parent.child.fail' is a nonsensical reference to a nested local symbol
'Parent.child.fail' is a nonsensical reference to a nested local symbol

View File

@@ -1,11 +1,24 @@
#!/bin/sh
fname=$(mktemp)
o=$(mktemp)
gb=$(mktemp)
before=$(mktemp)
after=$(mktemp)
rc=0
for i in *.asm; do
../../rgbasm $i >$fname 2>&1
diff -u $fname ${i%.asm}.out
../../rgbasm -o $o $i > $after 2>&1
diff -u ${i%.asm}.out $after
rc=$(($? || $rc))
bin=${i%.asm}.out.bin
if [ -f $bin ]; then
../../rgblink -o $gb $o > $after 2>&1
head -c $(wc -c < $bin) $gb > $after 2>&1
hexdump -C $after > $before && mv $before $after
hexdump -C $bin > $before
diff -u $before $after
rc=$(($? || $rc))
fi
done
rm -f $o $gb $before $after
exit $rc

View File

@@ -1,3 +1,3 @@
ERROR: undefined-dot.asm(3):
'.' not defined
'.' not defined
error: Assembly aborted in pass 2 (1 errors)!

View File

@@ -6,4 +6,5 @@ for i in *.asm; do
mv -f $fname ${i%.asm}.out
done
rm -f $fname
exit 0

2
test/asm/utf-8.asm Normal file
View File

@@ -0,0 +1,2 @@
SECTION "sec", ROM0
db "é"

0
test/asm/utf-8.out Normal file
View File

1
test/asm/utf-8.out.bin Normal file
View File

@@ -0,0 +1 @@
é

View File

@@ -0,0 +1,5 @@
ROM0
org $10
"sec"
org $20
"secfix"

View File

@@ -0,0 +1,2 @@
error: Different attributes for "sec" in source and linkerscript

View File

@@ -0,0 +1,2 @@
SECTION "sec",ROM0,ALIGN[4]
SECTION "secfix",ROM0[$20]

View File

@@ -0,0 +1,5 @@
ROM0
align 4
"sec"
org $20
"secfix"

View File

View File

@@ -16,6 +16,14 @@ head -c 20 $gbtemp > $otemp 2>&1
diff bank-numbers.out.bin $otemp
rc=$(($? || $rc))
$RGBASM -o $otemp section-attributes.asm
$RGBLINK -l section-attributes.link -o $gbtemp $otemp > $outtemp 2>&1
diff section-attributes.out $outtemp
rc=$(($? || $rc))
$RGBLINK -l section-attributes-mismatch.link -o $gbtemp $otemp > $outtemp 2>&1
diff section-attributes-mismatch.out $outtemp
rc=$(($? || $rc))
$RGBASM -o $otemp wramx-dmg-mode.asm
$RGBLINK -o $gbtemp $otemp > $outtemp 2>&1
diff wramx-dmg-mode-no-d.out $outtemp
@@ -60,4 +68,5 @@ $RGBLINK -o $gbtemp $otemp
diff all-instructions.out.bin $gbtemp
rc=$(($? || $rc))
rm -f $otemp $gbtemp $gbtemp2 $outtemp
exit $rc

View File

@@ -9,6 +9,12 @@ $RGBASM -o $otemp bank-numbers.asm
$RGBLINK -o $gbtemp $otemp > bank-numbers.out 2>&1
head -c 20 $gbtemp > bank-numbers.out.bin 2>&1
$RGBASM -o $otemp section-attributes.asm
$RGBLINK -l section-attributes.link \
-o $gbtemp $otemp > section-attributes.out 2>&1
$RGBLINK -l section-attributes-mismatch.link \
-o $gbtemp $otemp > section-attributes-mismatch.out 2>&1
$RGBASM -o $otemp wramx-dmg-mode.asm
$RGBLINK -o $gbtemp $otemp > wramx-dmg-mode-no-d.out 2>&1
$RGBLINK -d -o $gbtemp $otemp > wramx-dmg-mode-d.out 2>&1
@@ -28,4 +34,5 @@ $RGBLINK -t -o $gbtemp $otemp > romx-tiny-t.out 2>&1
$RGBASM -o $otemp all-instructions.asm
$RGBLINK -o all-instructions.out.bin $otemp 2>&1
rm -f $otemp $gbtemp
exit 0

View File

@@ -15,20 +15,33 @@ pushd link
popd
# Test some significant external projects that use RGBDS
# When adding new ones, don't forget to add them to the .gitignore!
git clone https://github.com/pret/pokecrystal.git --depth=1
if [ ! -d pokecrystal ]; then
git clone https://github.com/pret/pokecrystal.git --shallow-since=2018-06-04 --single-branch
fi
pushd pokecrystal
git fetch
git checkout 06e169d
make -j
make compare
popd
git clone --recursive https://github.com/pret/pokered.git --depth=1
if [ ! -d pokered ]; then
git clone --recursive https://github.com/pret/pokered.git --shallow-since=2018-03-23 --single-branch
fi
pushd pokered
git fetch
git checkout 98f09b6
make -j
make compare
popd
git clone https://github.com/AntonioND/ucity.git --depth=1
if [ ! -d ucity ]; then
git clone https://github.com/AntonioND/ucity.git --shallow-since=2017-07-13 --single-branch
fi
pushd ucity
git fetch
git checkout 3315601
make -j
popd