mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 10:42:07 +00:00
Compare commits
80 Commits
v0.5.0-rc1
...
v0.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
432c769d60 | ||
|
|
9923fa3eee | ||
|
|
750e93be3d | ||
|
|
ee5da4468d | ||
|
|
503c3b5364 | ||
|
|
992be3fd9b | ||
|
|
c755fa3469 | ||
|
|
e78a1d5bfd | ||
|
|
d2f6def2eb | ||
|
|
1ffd7cb5bb | ||
|
|
215e26b478 | ||
|
|
8885f7bcf6 | ||
|
|
5334fc334e | ||
|
|
f97663aa37 | ||
|
|
08bdbd1949 | ||
|
|
5c852c7651 | ||
|
|
6be3584467 | ||
|
|
8c90d9d2d7 | ||
|
|
f69e666b00 | ||
|
|
eba06404f0 | ||
|
|
9558ccea1b | ||
|
|
260d372acd | ||
|
|
4e1b0ce793 | ||
|
|
363ee9578c | ||
|
|
8fa5a4255e | ||
|
|
b3312886fb | ||
|
|
7fc8a65d0a | ||
|
|
c278a361da | ||
|
|
a2f52867ad | ||
|
|
ab79e6bede | ||
|
|
850c78aaf4 | ||
|
|
c08cf783c8 | ||
|
|
25a8518fbf | ||
|
|
49174f4486 | ||
|
|
81327b0d99 | ||
|
|
c0859e64f7 | ||
|
|
3e0b7d428f | ||
|
|
ba3428314b | ||
|
|
bcb78f5d18 | ||
|
|
de7d1facf3 | ||
|
|
310d34c655 | ||
|
|
39c38f9838 | ||
|
|
576b063519 | ||
|
|
596e17ee61 | ||
|
|
363b3d0134 | ||
|
|
c7ed9a275e | ||
|
|
49aac2961d | ||
|
|
3741bd4617 | ||
|
|
937c9888a4 | ||
|
|
61a9bfd33c | ||
|
|
d08bcc455d | ||
|
|
aaa92659ea | ||
|
|
be877134e5 | ||
|
|
d05703c692 | ||
|
|
5dbfafcc55 | ||
|
|
a265b85d9d | ||
|
|
28abf03c0a | ||
|
|
7e7f92f18c | ||
|
|
7461170956 | ||
|
|
57d966d6e0 | ||
|
|
17752d7094 | ||
|
|
4216f0a9b0 | ||
|
|
e3fde986ad | ||
|
|
aa99ed056c | ||
|
|
46d6652df1 | ||
|
|
5406674cdd | ||
|
|
5d2e2e2182 | ||
|
|
a929f36bc5 | ||
|
|
bdb84a901f | ||
|
|
093631ca0b | ||
|
|
7e127a4e52 | ||
|
|
b8093847dc | ||
|
|
8d1b56bcf5 | ||
|
|
5fb7fcf461 | ||
|
|
ee900ae7a3 | ||
|
|
3ca58e13dc | ||
|
|
aaa4e17454 | ||
|
|
a81d383f75 | ||
|
|
60019cf476 | ||
|
|
5a6a44cbc1 |
9
.editorconfig
Normal file
9
.editorconfig
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[*]
|
||||||
|
root = true
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = tab
|
||||||
|
tab_width = 8
|
||||||
|
charset = utf-8
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
end_of_line = lf
|
||||||
8
.github/actions/get-pages.sh
vendored
8
.github/actions/get-pages.sh
vendored
@@ -53,8 +53,8 @@ PAGES=(
|
|||||||
WWWPATH="/docs"
|
WWWPATH="/docs"
|
||||||
mkdir -p "$1/_documentation/$2"
|
mkdir -p "$1/_documentation/$2"
|
||||||
|
|
||||||
# `mandoc` uses a different format for referring to man pages present in the **current** directory
|
# `mandoc` uses a different format for referring to man pages present in the **current** directory.
|
||||||
# We want that format for RGBDS man pages, and the other one for the t=rest;
|
# We want that format for RGBDS man pages, and the other one for the rest;
|
||||||
# we thus need to copy all pages to a temporary directory, and process them there.
|
# we thus need to copy all pages to a temporary directory, and process them there.
|
||||||
|
|
||||||
# Copy all pages to current dir
|
# Copy all pages to current dir
|
||||||
@@ -77,6 +77,7 @@ EOF
|
|||||||
options+=,toc
|
options+=,toc
|
||||||
fi
|
fi
|
||||||
mandoc -Thtml -I os=Linux -O$options "${PAGES[$page]##*/}" | .github/actions/doc_postproc.awk >> "$1/_documentation/$2/$page"
|
mandoc -Thtml -I os=Linux -O$options "${PAGES[$page]##*/}" | .github/actions/doc_postproc.awk >> "$1/_documentation/$2/$page"
|
||||||
|
groff -Tpdf -mdoc -wall "${PAGES[$page]##*/}" >"$1/_documentation/$2/$stem.pdf"
|
||||||
if [ $is_release -ne 0 ]; then
|
if [ $is_release -ne 0 ]; then
|
||||||
cat - >"$1/_documentation/$page" <<EOF
|
cat - >"$1/_documentation/$page" <<EOF
|
||||||
---
|
---
|
||||||
@@ -88,6 +89,7 @@ description: RGBDS latest stable — $descr
|
|||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
cat - >"$1/_documentation/$2/index.html" <<EOF
|
cat - >"$1/_documentation/$2/index.html" <<EOF
|
||||||
---
|
---
|
||||||
layout: doc_index
|
layout: doc_index
|
||||||
@@ -97,6 +99,7 @@ description: RGBDS $2 - Online manual
|
|||||||
---
|
---
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
||||||
# If making a release, add a new entry right after `master`
|
# If making a release, add a new entry right after `master`
|
||||||
if [ $is_release -ne 0 ]; then
|
if [ $is_release -ne 0 ]; then
|
||||||
awk '{ print }
|
awk '{ print }
|
||||||
@@ -105,5 +108,6 @@ if [ $is_release -ne 0 ]; then
|
|||||||
mv "$1/_data/doc.json"{.tmp,}
|
mv "$1/_data/doc.json"{.tmp,}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Clean up
|
# Clean up
|
||||||
rm "${PAGES[@]##*/}"
|
rm "${PAGES[@]##*/}"
|
||||||
|
|||||||
4
.github/workflows/create-release-docs.yml
vendored
4
.github/workflows/create-release-docs.yml
vendored
@@ -18,10 +18,10 @@ jobs:
|
|||||||
repository: ${{ github.repository_owner }}/rgbds-www
|
repository: ${{ github.repository_owner }}/rgbds-www
|
||||||
path: rgbds-www
|
path: rgbds-www
|
||||||
# `-O toc` was added in 1.14.5, but the repos only have 1.14.4
|
# `-O toc` was added in 1.14.5, but the repos only have 1.14.4
|
||||||
- name: Build and install mandoc
|
- name: Build and install mandoc + install groff
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -qq update
|
sudo apt-get -qq update
|
||||||
sudo apt-get install -yq zlib1g-dev
|
sudo apt-get install -yq groff zlib1g-dev
|
||||||
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
|
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
|
||||||
tar xf mandoc-1.14.5.tar.gz
|
tar xf mandoc-1.14.5.tar.gz
|
||||||
cd mandoc-1.14.5
|
cd mandoc-1.14.5
|
||||||
|
|||||||
6
.github/workflows/update-master-docs.yml
vendored
6
.github/workflows/update-master-docs.yml
vendored
@@ -31,10 +31,10 @@ jobs:
|
|||||||
repository: gbdev/rgbds-www
|
repository: gbdev/rgbds-www
|
||||||
ref: master
|
ref: master
|
||||||
path: rgbds-www
|
path: rgbds-www
|
||||||
- name: Build and install mandoc
|
- name: Build and install mandoc + install groff
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -qq update
|
sudo apt-get -qq update
|
||||||
sudo apt-get install -yq zlib1g-dev
|
sudo apt-get install -yq groff zlib1g-dev
|
||||||
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
|
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
|
||||||
tar xf mandoc-1.14.5.tar.gz
|
tar xf mandoc-1.14.5.tar.gz
|
||||||
cd mandoc-1.14.5
|
cd mandoc-1.14.5
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
- name: Update pages
|
- name: Update pages
|
||||||
working-directory: rgbds
|
working-directory: rgbds
|
||||||
run: |
|
run: |
|
||||||
./.github/actions/get-pages.sh ../rgbds-www/_documentation master
|
./.github/actions/get-pages.sh ../rgbds-www master
|
||||||
- name: Push new pages
|
- name: Push new pages
|
||||||
working-directory: rgbds-www
|
working-directory: rgbds-www
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
Contributing
|
Contributing
|
||||||
============
|
============
|
||||||
|
|
||||||
RGBDS was created in the late 90's and has received contributions from several
|
RGBDS was created in the late '90s and has received contributions from several
|
||||||
developers since then. It wouldn't have been possible to get to this point
|
developers since then. It wouldn't have been possible to get to this point
|
||||||
without their work and, for that reason, it is always open to the contributions
|
without their work, and it is always open to the contributions of other people.
|
||||||
of other people.
|
|
||||||
|
|
||||||
Reporting Bugs
|
Reporting Bugs
|
||||||
--------------
|
--------------
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ The documentation of this toolchain can be viewed online
|
|||||||
`here <https://rgbds.gbdev.io/docs/>`__, it is generated from the man pages
|
`here <https://rgbds.gbdev.io/docs/>`__, it is generated from the man pages
|
||||||
found in this repository.
|
found in this repository.
|
||||||
|
|
||||||
|
If you want to contribute or maintain RGBDS, and have questions regarding the code, its organisation, etc. you can find me `on GBDev <https://gbdev.io/chat>`__ or via mail at ``rgbds at eldred dot fr``.
|
||||||
|
|
||||||
1. Installing RGBDS
|
1. Installing RGBDS
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
|||||||
65
RELEASE.rst
Normal file
65
RELEASE.rst
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
Releasing
|
||||||
|
=========
|
||||||
|
|
||||||
|
This describes for the maintainers of RGBDS how to publish a new release on
|
||||||
|
GitHub.
|
||||||
|
|
||||||
|
1. Update, commit, and push `include/version.h <include/version.h>`__ with
|
||||||
|
values for ``PACKAGE_VERSION_MAJOR``, ``PACKAGE_VERSION_MINOR``,
|
||||||
|
``PACKAGE_VERSION_PATCH``, and ``PACKAGE_VERSION_RC``. Only define
|
||||||
|
``PACKAGE_VERSION_RC`` if you are publishing a release candidate! You can
|
||||||
|
use ``git commit -m "Release <version>"`` and ``git push origin master``.
|
||||||
|
|
||||||
|
2. Create a Git tag formatted as ``v<MAJOR>.<MINOR>.<PATCH>``, or
|
||||||
|
``v<MAJOR>.<MINOR>.<PATCH>-rc<RC>`` for a release candidate. ``MAJOR``,
|
||||||
|
``MINOR``, ``PATCH``, and ``RC`` should match their values from
|
||||||
|
`include/version.h <include/version.h>`__. You can use ``git tag <tag>``.
|
||||||
|
|
||||||
|
3. Push the tag to GitHub. You can use ``git push origin <tag>``.
|
||||||
|
|
||||||
|
GitHub Actions will run the `create-release-artifacts.yaml
|
||||||
|
<.github/workflows/create-release-artifacts.yaml>`__ workflow to detect the
|
||||||
|
tag starting with "``v[0-9]``" and automatically do the following:
|
||||||
|
|
||||||
|
1. Build 32-bit and 64-bit RGBDS binaries for Windows with ``cmake``.
|
||||||
|
|
||||||
|
2. Package the binaries into zip files.
|
||||||
|
|
||||||
|
3. Package the source code into a tar.gz file with ``make dist``.
|
||||||
|
|
||||||
|
4. Create a draft GitHub release for the tag, attaching the three
|
||||||
|
packaged files. It will be a prerelease if the tag contains "``-rc``".
|
||||||
|
|
||||||
|
If an error occurred in the above steps, delete the tag and restart the
|
||||||
|
procedure. You can use ``git push --delete origin <tag>`` and
|
||||||
|
``git tag --delete <tag>``.
|
||||||
|
|
||||||
|
4. GitHub Actions will run the `create-release-docs.yml
|
||||||
|
<.github/workflows/create-release-docs.yml>`__ workflow to add the release
|
||||||
|
documentation to `rgbds-www <https://github.com/gbdev/rgbds-www>`__.
|
||||||
|
|
||||||
|
For a release candidate, which creates a prerelease, you will have to
|
||||||
|
take these steps yourself.
|
||||||
|
|
||||||
|
1. Clone `rgbds-www <https://github.com/gbdev/rgbds-www>`__. You can use
|
||||||
|
``git clone https://github.com/gbdev/rgbds-www.git``.
|
||||||
|
|
||||||
|
2. Make sure that you have installed ``groff`` and ``mandoc``. You will
|
||||||
|
need ``mandoc`` 1.14.5 or later to support ``-O toc``.
|
||||||
|
|
||||||
|
3. Run ``.github/actions/get-pages.sh -r <path/to/rgbds-www> <tag>``. This
|
||||||
|
will render the RGBDS documentation as HTML and PDF and copy it to
|
||||||
|
``rgbds-www``.
|
||||||
|
|
||||||
|
If you do not have ``groff`` installed, you can change
|
||||||
|
``groff -Tpdf -mdoc -wall`` to ``mandoc -Tpdf -I os=Linux`` in
|
||||||
|
`.github/actions/get-pages.sh <.github/actions/get-pages.sh>`__ and it
|
||||||
|
will suffice.
|
||||||
|
|
||||||
|
4. Commit and push the documentation. You can use ``git commit -m
|
||||||
|
"Create RGBDS <tag> documentation"`` and ``git push origin master``
|
||||||
|
(within the ``rgbds-www`` directory, not RGBDS).
|
||||||
|
|
||||||
|
5. Write a changelog in the GitHub draft release.
|
||||||
|
|
||||||
|
6. Click the "Publish release" button to publish it!
|
||||||
@@ -28,9 +28,9 @@ struct FormatSpec {
|
|||||||
bool prefix;
|
bool prefix;
|
||||||
bool alignLeft;
|
bool alignLeft;
|
||||||
bool padZero;
|
bool padZero;
|
||||||
uint8_t width;
|
size_t width;
|
||||||
bool hasFrac;
|
bool hasFrac;
|
||||||
uint8_t fracWidth;
|
size_t fracWidth;
|
||||||
int type;
|
int type;
|
||||||
bool valid;
|
bool valid;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ static inline bool sym_IsConstant(struct Symbol const *sym)
|
|||||||
if (sym->type == SYM_LABEL) {
|
if (sym->type == SYM_LABEL) {
|
||||||
struct Section const *sect = sym_GetSection(sym);
|
struct Section const *sect = sym_GetSection(sym);
|
||||||
|
|
||||||
return sect && sect->org != -1;
|
return sect && sect->org != (uint32_t)-1;
|
||||||
}
|
}
|
||||||
return sym->type == SYM_EQU || sym->type == SYM_SET;
|
return sym->type == SYM_EQU || sym->type == SYM_SET;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
uint32_t calchash(const char *s);
|
char const *printChar(int c);
|
||||||
char const *print(int c);
|
|
||||||
/*
|
/*
|
||||||
* @return The number of bytes read, or 0 if invalid data was found
|
* @return The number of bytes read, or 0 if invalid data was found
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ extern unsigned int nbErrors;
|
|||||||
|
|
||||||
enum WarningID {
|
enum WarningID {
|
||||||
WARNING_ASSERT, /* Assertions */
|
WARNING_ASSERT, /* Assertions */
|
||||||
|
WARNING_BACKWARDS_FOR, /* `for` loop with backwards range */
|
||||||
WARNING_BUILTIN_ARG, /* Invalid args to builtins */
|
WARNING_BUILTIN_ARG, /* Invalid args to builtins */
|
||||||
WARNING_CHARMAP_REDEF, /* Charmap entry re-definition */
|
WARNING_CHARMAP_REDEF, /* Charmap entry re-definition */
|
||||||
WARNING_DIV, /* Division undefined behavior */
|
WARNING_DIV, /* Division undefined behavior */
|
||||||
|
|||||||
@@ -29,19 +29,9 @@ typedef struct HashMapEntry *HashMap[HASHMAP_NB_BUCKETS];
|
|||||||
* @param map The HashMap to add the element to
|
* @param map The HashMap to add the element to
|
||||||
* @param key The key with which the element will be stored and retrieved
|
* @param key The key with which the element will be stored and retrieved
|
||||||
* @param element The element to add
|
* @param element The element to add
|
||||||
* @return True if a collision occurred (for statistics)
|
* @return A pointer to the pointer to the element.
|
||||||
*/
|
*/
|
||||||
bool hash_AddElement(HashMap map, char const *key, void *element);
|
void **hash_AddElement(HashMap map, char const *key, void *element);
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces an element with an already-present key in a hashmap.
|
|
||||||
* @warning Inserting a NULL will make `hash_GetElement`'s return ambiguous!
|
|
||||||
* @param map The HashMap to replace the element in
|
|
||||||
* @param key The key with which the element will be stored and retrieved
|
|
||||||
* @param element The element to replace
|
|
||||||
* @return True if the element was found and replaced
|
|
||||||
*/
|
|
||||||
bool hash_ReplaceElement(HashMap const map, char const *key, void *element);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes an element from a hashmap.
|
* Removes an element from a hashmap.
|
||||||
@@ -51,6 +41,14 @@ bool hash_ReplaceElement(HashMap const map, char const *key, void *element);
|
|||||||
*/
|
*/
|
||||||
bool hash_RemoveElement(HashMap map, char const *key);
|
bool hash_RemoveElement(HashMap map, char const *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds an element in a hashmap, and returns a pointer to its value field.
|
||||||
|
* @param map The map to consider the elements of
|
||||||
|
* @param key The key to search an element for
|
||||||
|
* @return A pointer to the pointer to the element, or NULL if not found.
|
||||||
|
*/
|
||||||
|
void **hash_GetNode(HashMap const map, char const *key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds an element in a hashmap.
|
* Finds an element in a hashmap.
|
||||||
* @param map The map to consider the elements of
|
* @param map The map to consider the elements of
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ struct AttachedSymbol {
|
|||||||
struct Patch {
|
struct Patch {
|
||||||
struct FileStackNode const *src;
|
struct FileStackNode const *src;
|
||||||
uint32_t lineNo;
|
uint32_t lineNo;
|
||||||
int32_t offset;
|
uint32_t offset;
|
||||||
uint32_t pcSectionID;
|
uint32_t pcSectionID;
|
||||||
uint32_t pcOffset;
|
uint32_t pcOffset;
|
||||||
enum PatchType type;
|
enum PatchType type;
|
||||||
int32_t rpnSize;
|
uint32_t rpnSize;
|
||||||
uint8_t *rpnExpression;
|
uint8_t *rpnExpression;
|
||||||
|
|
||||||
struct Section const *pcSection;
|
struct Section const *pcSection;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
|
* Copyright (c) 2017-2021, Antonio Nino Diaz and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
@@ -12,7 +12,6 @@
|
|||||||
#define PACKAGE_VERSION_MAJOR 0
|
#define PACKAGE_VERSION_MAJOR 0
|
||||||
#define PACKAGE_VERSION_MINOR 5
|
#define PACKAGE_VERSION_MINOR 5
|
||||||
#define PACKAGE_VERSION_PATCH 0
|
#define PACKAGE_VERSION_PATCH 0
|
||||||
#define PACKAGE_VERSION_RC 1
|
|
||||||
|
|
||||||
const char *get_package_version_string(void);
|
const char *get_package_version_string(void);
|
||||||
|
|
||||||
|
|||||||
@@ -44,32 +44,35 @@ struct Charmap {
|
|||||||
|
|
||||||
static HashMap charmaps;
|
static HashMap charmaps;
|
||||||
|
|
||||||
static struct Charmap *currentCharmap;
|
/*
|
||||||
|
* Store pointers to hashmap nodes, so that there is only one pointer to the memory block
|
||||||
|
* that gets reallocated.
|
||||||
|
*/
|
||||||
|
static struct Charmap **currentCharmap;
|
||||||
|
|
||||||
struct CharmapStackEntry {
|
struct CharmapStackEntry {
|
||||||
struct Charmap *charmap;
|
struct Charmap **charmap;
|
||||||
struct CharmapStackEntry *next;
|
struct CharmapStackEntry *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharmapStackEntry *charmapStack;
|
struct CharmapStackEntry *charmapStack;
|
||||||
|
|
||||||
static inline struct Charmap *charmap_Get(const char *name)
|
static struct Charmap *charmap_Get(const char *name)
|
||||||
{
|
{
|
||||||
return hash_GetElement(charmaps, name);
|
return hash_GetElement(charmaps, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct Charmap *resizeCharmap(struct Charmap *map, size_t capacity)
|
static void resizeCharmap(struct Charmap **map, size_t capacity)
|
||||||
{
|
{
|
||||||
struct Charmap *new = realloc(map, sizeof(*map) + sizeof(*map->nodes) * capacity);
|
*map = realloc(*map, sizeof(**map) + sizeof(*(*map)->nodes) * capacity);
|
||||||
|
|
||||||
if (!new)
|
if (!*map)
|
||||||
fatalerror("Failed to %s charmap: %s\n",
|
fatalerror("Failed to %s charmap: %s\n",
|
||||||
map ? "create" : "resize", strerror(errno));
|
*map ? "create" : "resize", strerror(errno));
|
||||||
new->capacity = capacity;
|
(**map).capacity = capacity;
|
||||||
return new;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void initNode(struct Charnode *node)
|
static void initNode(struct Charnode *node)
|
||||||
{
|
{
|
||||||
node->isTerminal = false;
|
node->isTerminal = false;
|
||||||
memset(node->next, 0, sizeof(node->next));
|
memset(node->next, 0, sizeof(node->next));
|
||||||
@@ -95,19 +98,18 @@ struct Charmap *charmap_New(const char *name, const char *baseName)
|
|||||||
|
|
||||||
/* Init the new charmap's fields */
|
/* Init the new charmap's fields */
|
||||||
if (base) {
|
if (base) {
|
||||||
charmap = resizeCharmap(NULL, base->capacity);
|
resizeCharmap(&charmap, base->capacity);
|
||||||
charmap->usedNodes = base->usedNodes;
|
charmap->usedNodes = base->usedNodes;
|
||||||
|
|
||||||
memcpy(charmap->nodes, base->nodes, sizeof(base->nodes[0]) * charmap->usedNodes);
|
memcpy(charmap->nodes, base->nodes, sizeof(base->nodes[0]) * charmap->usedNodes);
|
||||||
} else {
|
} else {
|
||||||
charmap = resizeCharmap(NULL, INITIAL_CAPACITY);
|
resizeCharmap(&charmap, INITIAL_CAPACITY);
|
||||||
charmap->usedNodes = 1;
|
charmap->usedNodes = 1;
|
||||||
initNode(&charmap->nodes[0]); /* Init the root node */
|
initNode(&charmap->nodes[0]); /* Init the root node */
|
||||||
}
|
}
|
||||||
charmap->name = strdup(name);
|
charmap->name = strdup(name);
|
||||||
|
|
||||||
hash_AddElement(charmaps, charmap->name, charmap);
|
currentCharmap = (struct Charmap **)hash_AddElement(charmaps, charmap->name, charmap);
|
||||||
currentCharmap = charmap;
|
|
||||||
|
|
||||||
return charmap;
|
return charmap;
|
||||||
}
|
}
|
||||||
@@ -120,7 +122,7 @@ void charmap_Delete(struct Charmap *charmap)
|
|||||||
|
|
||||||
void charmap_Set(const char *name)
|
void charmap_Set(const char *name)
|
||||||
{
|
{
|
||||||
struct Charmap *charmap = charmap_Get(name);
|
struct Charmap **charmap = (struct Charmap **)hash_GetNode(charmaps, name);
|
||||||
|
|
||||||
if (charmap == NULL)
|
if (charmap == NULL)
|
||||||
error("Charmap '%s' doesn't exist\n", name);
|
error("Charmap '%s' doesn't exist\n", name);
|
||||||
@@ -158,25 +160,26 @@ void charmap_Pop(void)
|
|||||||
|
|
||||||
void charmap_Add(char *mapping, uint8_t value)
|
void charmap_Add(char *mapping, uint8_t value)
|
||||||
{
|
{
|
||||||
struct Charnode *node = ¤tCharmap->nodes[0];
|
struct Charmap *charmap = *currentCharmap;
|
||||||
|
struct Charnode *node = &charmap->nodes[0];
|
||||||
|
|
||||||
for (uint8_t c; *mapping; mapping++) {
|
for (uint8_t c; *mapping; mapping++) {
|
||||||
c = *mapping - 1;
|
c = *mapping - 1;
|
||||||
|
|
||||||
if (node->next[c]) {
|
if (node->next[c]) {
|
||||||
node = ¤tCharmap->nodes[node->next[c]];
|
node = &charmap->nodes[node->next[c]];
|
||||||
} else {
|
} else {
|
||||||
/* Register next available node */
|
/* Register next available node */
|
||||||
node->next[c] = currentCharmap->usedNodes;
|
node->next[c] = charmap->usedNodes;
|
||||||
/* If no more nodes are available, get new ones */
|
/* If no more nodes are available, get new ones */
|
||||||
if (currentCharmap->usedNodes == currentCharmap->capacity) {
|
if (charmap->usedNodes == charmap->capacity) {
|
||||||
currentCharmap->capacity *= 2;
|
charmap->capacity *= 2;
|
||||||
currentCharmap = resizeCharmap(currentCharmap, currentCharmap->capacity);
|
resizeCharmap(currentCharmap, charmap->capacity);
|
||||||
hash_ReplaceElement(charmaps, currentCharmap->name, currentCharmap);
|
charmap = *currentCharmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Switch to and init new node */
|
/* Switch to and init new node */
|
||||||
node = ¤tCharmap->nodes[currentCharmap->usedNodes++];
|
node = &charmap->nodes[charmap->usedNodes++];
|
||||||
initNode(node);
|
initNode(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,7 +200,8 @@ size_t charmap_Convert(char const *input, uint8_t *output)
|
|||||||
* If no match, read a UTF-8 codepoint and output that.
|
* If no match, read a UTF-8 codepoint and output that.
|
||||||
*/
|
*/
|
||||||
size_t outputLen = 0;
|
size_t outputLen = 0;
|
||||||
struct Charnode const *node = ¤tCharmap->nodes[0];
|
struct Charmap const *charmap = *currentCharmap;
|
||||||
|
struct Charnode const *node = &charmap->nodes[0];
|
||||||
struct Charnode const *match = NULL;
|
struct Charnode const *match = NULL;
|
||||||
size_t rewindDistance = 0;
|
size_t rewindDistance = 0;
|
||||||
|
|
||||||
@@ -209,7 +213,7 @@ size_t charmap_Convert(char const *input, uint8_t *output)
|
|||||||
input++; /* Consume that char */
|
input++; /* Consume that char */
|
||||||
rewindDistance++;
|
rewindDistance++;
|
||||||
|
|
||||||
node = ¤tCharmap->nodes[node->next[c]];
|
node = &charmap->nodes[node->next[c]];
|
||||||
if (node->isTerminal) {
|
if (node->isTerminal) {
|
||||||
match = node;
|
match = node;
|
||||||
rewindDistance = 0; /* Rewind from after the match */
|
rewindDistance = 0; /* Rewind from after the match */
|
||||||
@@ -218,7 +222,7 @@ size_t charmap_Convert(char const *input, uint8_t *output)
|
|||||||
} else {
|
} else {
|
||||||
input -= rewindDistance; /* Rewind */
|
input -= rewindDistance; /* Rewind */
|
||||||
rewindDistance = 0;
|
rewindDistance = 0;
|
||||||
node = ¤tCharmap->nodes[0];
|
node = &charmap->nodes[0];
|
||||||
|
|
||||||
if (match) { /* Arrived at a dead end with a match found */
|
if (match) { /* Arrived at a dead end with a match found */
|
||||||
*output++ = match->value;
|
*output++ = match->value;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -148,20 +149,24 @@ void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, cha
|
|||||||
size_t len = strlen(value);
|
size_t len = strlen(value);
|
||||||
size_t totalLen = fmt->width > len ? fmt->width : len;
|
size_t totalLen = fmt->width > len ? fmt->width : len;
|
||||||
|
|
||||||
if (totalLen + 1 > bufLen) /* bufLen includes terminator */
|
if (totalLen > bufLen - 1) { /* bufLen includes terminator */
|
||||||
error("Formatted string value too long\n");
|
error("Formatted string value too long\n");
|
||||||
|
totalLen = bufLen - 1;
|
||||||
|
if (len > totalLen)
|
||||||
|
len = totalLen;
|
||||||
|
}
|
||||||
|
assert(len < bufLen && totalLen < bufLen && len <= totalLen);
|
||||||
|
|
||||||
size_t padLen = fmt->width > len ? fmt->width - len : 0;
|
size_t padLen = totalLen - len;
|
||||||
|
|
||||||
if (fmt->alignLeft) {
|
if (fmt->alignLeft) {
|
||||||
strncpy(buf, value, len < bufLen ? len : bufLen);
|
memcpy(buf, value, len);
|
||||||
for (size_t i = 0; i < totalLen && len + i < bufLen; i++)
|
for (size_t i = len; i < totalLen; i++)
|
||||||
buf[len + i] = ' ';
|
|
||||||
} else {
|
|
||||||
for (size_t i = 0; i < padLen && i < bufLen; i++)
|
|
||||||
buf[i] = ' ';
|
buf[i] = ' ';
|
||||||
if (bufLen > padLen)
|
} else {
|
||||||
strncpy(buf + padLen, value, bufLen - padLen - 1);
|
for (size_t i = 0; i < padLen; i++)
|
||||||
|
buf[i] = ' ';
|
||||||
|
memcpy(buf + padLen, value, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[totalLen] = '\0';
|
buf[totalLen] = '\0';
|
||||||
@@ -221,12 +226,18 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
|||||||
/* Special case for fixed-point */
|
/* Special case for fixed-point */
|
||||||
|
|
||||||
/* Default fractional width (C's is 6 for "%f"; here 5 is enough) */
|
/* Default fractional width (C's is 6 for "%f"; here 5 is enough) */
|
||||||
uint8_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
|
size_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
|
||||||
|
|
||||||
if (fracWidth) {
|
if (fracWidth) {
|
||||||
|
if (fracWidth > 255) {
|
||||||
|
error("Fractional width %zu too long, limiting to 255\n",
|
||||||
|
fracWidth);
|
||||||
|
fracWidth = 255;
|
||||||
|
}
|
||||||
|
|
||||||
char spec[16]; /* Max "%" + 5-char PRIu32 + ".%0255.f" + terminator */
|
char spec[16]; /* Max "%" + 5-char PRIu32 + ".%0255.f" + terminator */
|
||||||
|
|
||||||
snprintf(spec, sizeof(spec), "%%" PRIu32 ".%%0%d.f", fracWidth);
|
snprintf(spec, sizeof(spec), "%%" PRIu32 ".%%0%zu.f", fracWidth);
|
||||||
snprintf(valueBuf, sizeof(valueBuf), spec, value >> 16,
|
snprintf(valueBuf, sizeof(valueBuf), spec, value >> 16,
|
||||||
(value % 65536) / 65536.0 * pow(10, fracWidth) + 0.5);
|
(value % 65536) / 65536.0 * pow(10, fracWidth) + 0.5);
|
||||||
} else {
|
} else {
|
||||||
@@ -244,55 +255,49 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t len = strlen(valueBuf);
|
size_t len = strlen(valueBuf);
|
||||||
size_t numLen = len;
|
size_t numLen = !!sign + !!prefix + len;
|
||||||
|
|
||||||
if (sign)
|
|
||||||
numLen++;
|
|
||||||
if (prefix)
|
|
||||||
numLen++;
|
|
||||||
|
|
||||||
size_t totalLen = fmt->width > numLen ? fmt->width : numLen;
|
size_t totalLen = fmt->width > numLen ? fmt->width : numLen;
|
||||||
|
|
||||||
if (totalLen + 1 > bufLen) /* bufLen includes terminator */
|
if (totalLen > bufLen - 1) { /* bufLen includes terminator */
|
||||||
error("Formatted numeric value too long\n");
|
error("Formatted numeric value too long\n");
|
||||||
|
totalLen = bufLen - 1;
|
||||||
|
if (numLen > totalLen) {
|
||||||
|
len -= numLen - totalLen;
|
||||||
|
numLen = totalLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(numLen < bufLen && totalLen < bufLen && numLen <= totalLen && len <= numLen);
|
||||||
|
|
||||||
size_t padLen = fmt->width > numLen ? fmt->width - numLen : 0;
|
size_t padLen = totalLen - numLen;
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
if (fmt->alignLeft) {
|
if (fmt->alignLeft) {
|
||||||
size_t pos = 0;
|
if (sign)
|
||||||
|
|
||||||
if (sign && pos < bufLen)
|
|
||||||
buf[pos++] = sign;
|
buf[pos++] = sign;
|
||||||
if (prefix && pos < bufLen)
|
if (prefix)
|
||||||
buf[pos++] = prefix;
|
buf[pos++] = prefix;
|
||||||
|
memcpy(buf + pos, valueBuf, len);
|
||||||
strcpy(buf + pos, valueBuf);
|
for (size_t i = pos + len; i < totalLen; i++)
|
||||||
pos += len;
|
buf[i] = ' ';
|
||||||
|
|
||||||
for (size_t i = 0; i < totalLen && pos + i < bufLen; i++)
|
|
||||||
buf[pos + i] = ' ';
|
|
||||||
} else {
|
} else {
|
||||||
size_t pos = 0;
|
|
||||||
|
|
||||||
if (fmt->padZero) {
|
if (fmt->padZero) {
|
||||||
/* sign, then prefix, then zero padding */
|
/* sign, then prefix, then zero padding */
|
||||||
if (sign && pos < bufLen)
|
if (sign)
|
||||||
buf[pos++] = sign;
|
buf[pos++] = sign;
|
||||||
if (prefix && pos < bufLen)
|
if (prefix)
|
||||||
buf[pos++] = prefix;
|
buf[pos++] = prefix;
|
||||||
for (size_t i = 0; i < padLen && pos < bufLen; i++)
|
for (size_t i = 0; i < padLen; i++)
|
||||||
buf[pos++] = '0';
|
buf[pos++] = '0';
|
||||||
} else {
|
} else {
|
||||||
/* space padding, then sign, then prefix */
|
/* space padding, then sign, then prefix */
|
||||||
for (size_t i = 0; i < padLen && pos < bufLen; i++)
|
for (size_t i = 0; i < padLen; i++)
|
||||||
buf[pos++] = ' ';
|
buf[pos++] = ' ';
|
||||||
if (sign && pos < bufLen)
|
if (sign)
|
||||||
buf[pos++] = sign;
|
buf[pos++] = sign;
|
||||||
if (prefix && pos < bufLen)
|
if (prefix)
|
||||||
buf[pos++] = prefix;
|
buf[pos++] = prefix;
|
||||||
}
|
}
|
||||||
if (bufLen > pos)
|
memcpy(buf + pos, valueBuf, len);
|
||||||
strcpy(buf + pos, valueBuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[totalLen] = '\0';
|
buf[totalLen] = '\0';
|
||||||
|
|||||||
@@ -175,8 +175,14 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
|
|||||||
char const *incPath = i ? includePaths[i - 1] : "";
|
char const *incPath = i ? includePaths[i - 1] : "";
|
||||||
int len = snprintf(*fullPath, *size, "%s%s", incPath, path);
|
int len = snprintf(*fullPath, *size, "%s%s", incPath, path);
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
error("snprintf error during include path search: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Oh how I wish `asnprintf` was standard... */
|
/* Oh how I wish `asnprintf` was standard... */
|
||||||
if (len >= *size) { /* `len` doesn't include the terminator, `size` does */
|
if ((size_t)len >= *size) { /* `len` doesn't include the terminator, `size` does */
|
||||||
*size = len + 1;
|
*size = len + 1;
|
||||||
*fullPath = realloc(*fullPath, *size);
|
*fullPath = realloc(*fullPath, *size);
|
||||||
if (!*fullPath) {
|
if (!*fullPath) {
|
||||||
@@ -185,12 +191,14 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
len = sprintf(*fullPath, "%s%s", incPath, path);
|
len = sprintf(*fullPath, "%s%s", incPath, path);
|
||||||
|
if (len < 0) {
|
||||||
|
error("sprintf error during include path search: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < 0) {
|
if (isPathValid(*fullPath)) {
|
||||||
error("snprintf error during include path search: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
} else if (isPathValid(*fullPath)) {
|
|
||||||
printDep(*fullPath);
|
printDep(*fullPath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -314,10 +322,14 @@ void fstk_RunInclude(char const *path)
|
|||||||
|
|
||||||
if (!fstk_FindFile(path, &fullPath, &size)) {
|
if (!fstk_FindFile(path, &fullPath, &size)) {
|
||||||
free(fullPath);
|
free(fullPath);
|
||||||
if (oGeneratedMissingIncludes)
|
if (oGeneratedMissingIncludes) {
|
||||||
|
if (verbose)
|
||||||
|
printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n",
|
||||||
|
path, strerror(errno));
|
||||||
oFailedOnMissingInclude = true;
|
oFailedOnMissingInclude = true;
|
||||||
else
|
} else {
|
||||||
error("Unable to open included file '%s': %s\n", path, strerror(errno));
|
error("Unable to open included file '%s': %s\n", path, strerror(errno));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dbgPrint("Full path: \"%s\"\n", fullPath);
|
dbgPrint("Full path: \"%s\"\n", fullPath);
|
||||||
@@ -480,6 +492,10 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
|
|||||||
else if (step == 0)
|
else if (step == 0)
|
||||||
error("FOR cannot have a step value of 0\n");
|
error("FOR cannot have a step value of 0\n");
|
||||||
|
|
||||||
|
if ((step > 0 && start > stop) || (step < 0 && start < stop))
|
||||||
|
warning(WARNING_BACKWARDS_FOR, "FOR goes backwards from %d to %d by %d\n",
|
||||||
|
start, stop, step);
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
if (!newReptContext(reptLineNo, body, size))
|
if (!newReptContext(reptLineNo, body, size))
|
||||||
@@ -532,6 +548,7 @@ void fstk_Init(char const *mainPath, size_t maxRecursionDepth)
|
|||||||
context->fileInfo = (struct FileStackNode *)fileInfo;
|
context->fileInfo = (struct FileStackNode *)fileInfo;
|
||||||
/* lineNo and reptIter are unused on the top-level context */
|
/* lineNo and reptIter are unused on the top-level context */
|
||||||
context->fileInfo->parent = NULL;
|
context->fileInfo->parent = NULL;
|
||||||
|
context->fileInfo->lineNo = 0; // This still gets written to the object file, so init it
|
||||||
context->fileInfo->referenced = false;
|
context->fileInfo->referenced = false;
|
||||||
context->fileInfo->type = NODE_FILE;
|
context->fileInfo->type = NODE_FILE;
|
||||||
memcpy(fileInfo->name, fileName, len + 1);
|
memcpy(fileInfo->name, fileName, len + 1);
|
||||||
|
|||||||
737
src/asm/lexer.c
737
src/asm/lexer.c
File diff suppressed because it is too large
Load Diff
@@ -170,12 +170,12 @@ void macro_ShiftCurrentArgs(int32_t count)
|
|||||||
{
|
{
|
||||||
if (!macroArgs) {
|
if (!macroArgs) {
|
||||||
error("Cannot shift macro arguments outside of a macro\n");
|
error("Cannot shift macro arguments outside of a macro\n");
|
||||||
} else if (count > 0 && (count > macroArgs->nbArgs
|
} else if (count > 0 && ((uint32_t)count > macroArgs->nbArgs
|
||||||
|| macroArgs->shift > macroArgs->nbArgs - count)) {
|
|| macroArgs->shift > macroArgs->nbArgs - count)) {
|
||||||
warning(WARNING_MACRO_SHIFT,
|
warning(WARNING_MACRO_SHIFT,
|
||||||
"Cannot shift macro arguments past their end\n");
|
"Cannot shift macro arguments past their end\n");
|
||||||
macroArgs->shift = macroArgs->nbArgs;
|
macroArgs->shift = macroArgs->nbArgs;
|
||||||
} else if (count < 0 && macroArgs->shift < -count) {
|
} else if (count < 0 && macroArgs->shift < (uint32_t)-count) {
|
||||||
warning(WARNING_MACRO_SHIFT,
|
warning(WARNING_MACRO_SHIFT,
|
||||||
"Cannot shift macro arguments past their beginning\n");
|
"Cannot shift macro arguments past their beginning\n");
|
||||||
macroArgs->shift = 0;
|
macroArgs->shift = 0;
|
||||||
|
|||||||
@@ -353,7 +353,8 @@ int main(int argc, char *argv[])
|
|||||||
sect_CheckUnionClosed();
|
sect_CheckUnionClosed();
|
||||||
|
|
||||||
if (nbErrors != 0)
|
if (nbErrors != 0)
|
||||||
errx(1, "Assembly aborted (%u errors)!", nbErrors);
|
errx(1, "Assembly aborted (%u error%s)!", nbErrors,
|
||||||
|
nbErrors == 1 ? "" : "s");
|
||||||
|
|
||||||
// If parse aborted due to missing an include, and `-MG` was given, exit normally
|
// If parse aborted due to missing an include, and `-MG` was given, exit normally
|
||||||
if (oFailedOnMissingInclude)
|
if (oFailedOnMissingInclude)
|
||||||
|
|||||||
@@ -136,9 +136,9 @@ static uint32_t getNbFileStackNodes(void)
|
|||||||
void out_RegisterNode(struct FileStackNode *node)
|
void out_RegisterNode(struct FileStackNode *node)
|
||||||
{
|
{
|
||||||
/* If node is not already registered, register it (and parents), and give it a unique ID */
|
/* If node is not already registered, register it (and parents), and give it a unique ID */
|
||||||
while (node->ID == -1) {
|
while (node->ID == (uint32_t)-1) {
|
||||||
node->ID = getNbFileStackNodes();
|
node->ID = getNbFileStackNodes();
|
||||||
if (node->ID == -1)
|
if (node->ID == (uint32_t)-1)
|
||||||
fatalerror("Reached too many file stack nodes; try splitting the file up\n");
|
fatalerror("Reached too many file stack nodes; try splitting the file up\n");
|
||||||
node->next = fileStackNodes;
|
node->next = fileStackNodes;
|
||||||
fileStackNodes = node;
|
fileStackNodes = node;
|
||||||
@@ -266,7 +266,7 @@ static void registerSymbol(struct Symbol *sym)
|
|||||||
*objectSymbolsTail = sym;
|
*objectSymbolsTail = sym;
|
||||||
objectSymbolsTail = &sym->next;
|
objectSymbolsTail = &sym->next;
|
||||||
out_RegisterNode(sym->src);
|
out_RegisterNode(sym->src);
|
||||||
if (nbSymbols == -1)
|
if (nbSymbols == (uint32_t)-1)
|
||||||
fatalerror("Registered too many symbols (%" PRIu32
|
fatalerror("Registered too many symbols (%" PRIu32
|
||||||
"); try splitting up your files\n", (uint32_t)-1);
|
"); try splitting up your files\n", (uint32_t)-1);
|
||||||
sym->ID = nbSymbols++;
|
sym->ID = nbSymbols++;
|
||||||
@@ -278,7 +278,7 @@ static void registerSymbol(struct Symbol *sym)
|
|||||||
*/
|
*/
|
||||||
static uint32_t getSymbolID(struct Symbol *sym)
|
static uint32_t getSymbolID(struct Symbol *sym)
|
||||||
{
|
{
|
||||||
if (sym->ID == -1 && !sym_IsPC(sym))
|
if (sym->ID == (uint32_t)-1 && !sym_IsPC(sym))
|
||||||
registerSymbol(sym);
|
registerSymbol(sym);
|
||||||
return sym->ID;
|
return sym->ID;
|
||||||
}
|
}
|
||||||
@@ -474,7 +474,7 @@ static void registerUnregisteredSymbol(struct Symbol *symbol, void *arg)
|
|||||||
(void)arg; // sym_ForEach requires a void* parameter, but we are not using it.
|
(void)arg; // sym_ForEach requires a void* parameter, but we are not using it.
|
||||||
|
|
||||||
// Check for symbol->src, to skip any built-in symbol from rgbasm
|
// Check for symbol->src, to skip any built-in symbol from rgbasm
|
||||||
if (symbol->src && symbol->ID == -1) {
|
if (symbol->src && symbol->ID == (uint32_t)-1) {
|
||||||
registerSymbol(symbol);
|
registerSymbol(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
186
src/asm/parser.y
186
src/asm/parser.y
@@ -176,7 +176,9 @@ static void strrpl(char *dest, size_t destLen, char const *src, char const *old,
|
|||||||
|
|
||||||
for (char const *next = strstr(src, old); next && *next; next = strstr(src, old)) {
|
for (char const *next = strstr(src, old); next && *next; next = strstr(src, old)) {
|
||||||
// Copy anything before the substring to replace
|
// Copy anything before the substring to replace
|
||||||
memcpy(dest + i, src, next - src < destLen - i ? next - src : destLen - i);
|
unsigned int lenBefore = next - src;
|
||||||
|
|
||||||
|
memcpy(dest + i, src, lenBefore < destLen - i ? lenBefore : destLen - i);
|
||||||
i += next - src;
|
i += next - src;
|
||||||
if (i >= destLen)
|
if (i >= destLen)
|
||||||
break;
|
break;
|
||||||
@@ -333,7 +335,7 @@ static void freeDsArgList(struct DsArgList *args)
|
|||||||
free(args->args);
|
free(args->args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void failAssert(enum AssertionType type)
|
static void failAssert(enum AssertionType type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ASSERT_FATAL:
|
case ASSERT_FATAL:
|
||||||
@@ -347,7 +349,7 @@ static inline void failAssert(enum AssertionType type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void failAssertMsg(enum AssertionType type, char const *msg)
|
static void failAssertMsg(enum AssertionType type, char const *msg)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ASSERT_FATAL:
|
case ASSERT_FATAL:
|
||||||
@@ -390,6 +392,7 @@ enum {
|
|||||||
REG_BC = 0,
|
REG_BC = 0,
|
||||||
REG_DE = 1,
|
REG_DE = 1,
|
||||||
REG_HL = 2,
|
REG_HL = 2,
|
||||||
|
// LD/INC/ADD/DEC allow SP, PUSH/POP allow AF
|
||||||
REG_SP = 3,
|
REG_SP = 3,
|
||||||
REG_AF = 3
|
REG_AF = 3
|
||||||
};
|
};
|
||||||
@@ -504,6 +507,8 @@ enum {
|
|||||||
%token <tzSym> T_ID "identifier"
|
%token <tzSym> T_ID "identifier"
|
||||||
%token <tzSym> T_LOCAL_ID "local identifier"
|
%token <tzSym> T_LOCAL_ID "local identifier"
|
||||||
%token <tzSym> T_ANON "anonymous label"
|
%token <tzSym> T_ANON "anonymous label"
|
||||||
|
%type <tzSym> def_id
|
||||||
|
%type <tzSym> redef_id
|
||||||
%type <tzSym> scoped_id
|
%type <tzSym> scoped_id
|
||||||
%type <tzSym> scoped_anon_id
|
%type <tzSym> scoped_anon_id
|
||||||
%token T_POP_EQU "EQU"
|
%token T_POP_EQU "EQU"
|
||||||
@@ -594,7 +599,6 @@ enum {
|
|||||||
%type <nConstValue> ccode
|
%type <nConstValue> ccode
|
||||||
%type <sVal> op_a_n
|
%type <sVal> op_a_n
|
||||||
%type <nConstValue> op_a_r
|
%type <nConstValue> op_a_r
|
||||||
%type <nConstValue> op_hl_ss
|
|
||||||
%type <sVal> op_mem_ind
|
%type <sVal> op_mem_ind
|
||||||
%type <assertType> assert_type
|
%type <assertType> assert_type
|
||||||
|
|
||||||
@@ -692,6 +696,22 @@ endc : T_POP_ENDC {
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
def_id : T_OP_DEF {
|
||||||
|
lexer_ToggleStringExpansion(false);
|
||||||
|
} T_ID {
|
||||||
|
lexer_ToggleStringExpansion(true);
|
||||||
|
strcpy($$, $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
redef_id : T_POP_REDEF {
|
||||||
|
lexer_ToggleStringExpansion(false);
|
||||||
|
} T_ID {
|
||||||
|
lexer_ToggleStringExpansion(true);
|
||||||
|
strcpy($$, $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
scoped_id : T_ID | T_LOCAL_ID;
|
scoped_id : T_ID | T_LOCAL_ID;
|
||||||
scoped_anon_id : scoped_id | T_ANON;
|
scoped_anon_id : scoped_id | T_ANON;
|
||||||
|
|
||||||
@@ -773,8 +793,14 @@ directive : include
|
|||||||
| fail
|
| fail
|
||||||
| warn
|
| warn
|
||||||
| assert
|
| assert
|
||||||
|
| def_equ
|
||||||
|
| def_set
|
||||||
|
| def_rb
|
||||||
|
| def_rw
|
||||||
|
| def_rl
|
||||||
|
| def_equs
|
||||||
|
| redef_equs
|
||||||
| purge
|
| purge
|
||||||
| redef
|
|
||||||
| pops
|
| pops
|
||||||
| pushs
|
| pushs
|
||||||
| popo
|
| popo
|
||||||
@@ -786,6 +812,36 @@ directive : include
|
|||||||
trailing_comma : %empty | T_COMMA
|
trailing_comma : %empty | T_COMMA
|
||||||
;
|
;
|
||||||
|
|
||||||
|
equ : T_LABEL T_POP_EQU const { sym_AddEqu($1, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
set_or_equal : T_POP_SET | T_POP_EQUAL
|
||||||
|
;
|
||||||
|
|
||||||
|
set : T_LABEL set_or_equal const { sym_AddSet($1, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
equs : T_LABEL T_POP_EQUS string { sym_AddString($1, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
rb : T_LABEL T_POP_RB rs_uconst {
|
||||||
|
sym_AddEqu($1, sym_GetConstantValue("_RS"));
|
||||||
|
sym_AddSet("_RS", sym_GetConstantValue("_RS") + $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rw : T_LABEL T_POP_RW rs_uconst {
|
||||||
|
sym_AddEqu($1, sym_GetConstantValue("_RS"));
|
||||||
|
sym_AddSet("_RS", sym_GetConstantValue("_RS") + 2 * $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rl : T_LABEL T_Z80_RL rs_uconst {
|
||||||
|
sym_AddEqu($1, sym_GetConstantValue("_RS"));
|
||||||
|
sym_AddSet("_RS", sym_GetConstantValue("_RS") + 4 * $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
align : T_OP_ALIGN uconst {
|
align : T_OP_ALIGN uconst {
|
||||||
if ($2 > 16)
|
if ($2 > 16)
|
||||||
error("Alignment must be between 0 and 16, not %u\n", $2);
|
error("Alignment must be between 0 and 16, not %u\n", $2);
|
||||||
@@ -893,10 +949,14 @@ rept : T_POP_REPT uconst T_NEWLINE {
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
for : T_POP_FOR T_ID T_COMMA for_args T_NEWLINE {
|
for : T_POP_FOR {
|
||||||
|
lexer_ToggleStringExpansion(false);
|
||||||
|
} T_ID {
|
||||||
|
lexer_ToggleStringExpansion(true);
|
||||||
|
} T_COMMA for_args T_NEWLINE {
|
||||||
lexer_CaptureRept(&captureBody);
|
lexer_CaptureRept(&captureBody);
|
||||||
} T_NEWLINE {
|
} T_NEWLINE {
|
||||||
fstk_RunFor($2, $4.start, $4.stop, $4.step, captureBody.lineNo,
|
fstk_RunFor($3, $6.start, $6.stop, $6.step, captureBody.lineNo,
|
||||||
captureBody.body, captureBody.size);
|
captureBody.body, captureBody.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -923,10 +983,14 @@ break : T_POP_BREAK T_NEWLINE {
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
macrodef : T_POP_MACRO T_ID T_NEWLINE {
|
macrodef : T_POP_MACRO {
|
||||||
|
lexer_ToggleStringExpansion(false);
|
||||||
|
} T_ID {
|
||||||
|
lexer_ToggleStringExpansion(true);
|
||||||
|
} T_NEWLINE {
|
||||||
lexer_CaptureMacroBody(&captureBody);
|
lexer_CaptureMacroBody(&captureBody);
|
||||||
} T_NEWLINE {
|
} T_NEWLINE {
|
||||||
sym_AddMacro($2, captureBody.lineNo, captureBody.body, captureBody.size);
|
sym_AddMacro($3, captureBody.lineNo, captureBody.body, captureBody.size);
|
||||||
}
|
}
|
||||||
| T_LABEL T_COLON T_POP_MACRO T_NEWLINE {
|
| T_LABEL T_COLON T_POP_MACRO T_NEWLINE {
|
||||||
lexer_CaptureMacroBody(&captureBody);
|
lexer_CaptureMacroBody(&captureBody);
|
||||||
@@ -935,9 +999,6 @@ macrodef : T_POP_MACRO T_ID T_NEWLINE {
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
equs : T_LABEL T_POP_EQUS string { sym_AddString($1, $3); }
|
|
||||||
;
|
|
||||||
|
|
||||||
rsset : T_POP_RSSET uconst { sym_AddSet("_RS", $2); }
|
rsset : T_POP_RSSET uconst { sym_AddSet("_RS", $2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -950,24 +1011,6 @@ rs_uconst : %empty {
|
|||||||
| uconst
|
| uconst
|
||||||
;
|
;
|
||||||
|
|
||||||
rl : T_LABEL T_Z80_RL rs_uconst {
|
|
||||||
sym_AddEqu($1, sym_GetConstantValue("_RS"));
|
|
||||||
sym_AddSet("_RS", sym_GetConstantValue("_RS") + 4 * $3);
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
rw : T_LABEL T_POP_RW rs_uconst {
|
|
||||||
sym_AddEqu($1, sym_GetConstantValue("_RS"));
|
|
||||||
sym_AddSet("_RS", sym_GetConstantValue("_RS") + 2 * $3);
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
rb : T_LABEL T_POP_RB rs_uconst {
|
|
||||||
sym_AddEqu($1, sym_GetConstantValue("_RS"));
|
|
||||||
sym_AddSet("_RS", sym_GetConstantValue("_RS") + $3);
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
union : T_POP_UNION { sect_StartUnion(); }
|
union : T_POP_UNION { sect_StartUnion(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -1010,6 +1053,47 @@ dl : T_POP_DL { out_Skip(4, false); }
|
|||||||
| T_POP_DL constlist_32bit trailing_comma
|
| T_POP_DL constlist_32bit trailing_comma
|
||||||
;
|
;
|
||||||
|
|
||||||
|
def_equ : def_id T_POP_EQU const {
|
||||||
|
sym_AddEqu($1, $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
def_set : def_id set_or_equal const {
|
||||||
|
sym_AddSet($1, $3);
|
||||||
|
}
|
||||||
|
| redef_id set_or_equal const {
|
||||||
|
sym_AddSet($1, $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
def_rb : def_id T_POP_RB rs_uconst {
|
||||||
|
sym_AddEqu($1, sym_GetConstantValue("_RS"));
|
||||||
|
sym_AddSet("_RS", sym_GetConstantValue("_RS") + $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
def_rw : def_id T_POP_RW rs_uconst {
|
||||||
|
sym_AddEqu($1, sym_GetConstantValue("_RS"));
|
||||||
|
sym_AddSet("_RS", sym_GetConstantValue("_RS") + 2 * $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
def_rl : def_id T_Z80_RL rs_uconst {
|
||||||
|
sym_AddEqu($1, sym_GetConstantValue("_RS"));
|
||||||
|
sym_AddSet("_RS", sym_GetConstantValue("_RS") + 4 * $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
def_equs : def_id T_POP_EQUS string {
|
||||||
|
sym_AddString($1, $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
redef_equs : redef_id T_POP_EQUS string {
|
||||||
|
sym_RedefString($1, $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
purge : T_POP_PURGE {
|
purge : T_POP_PURGE {
|
||||||
lexer_ToggleStringExpansion(false);
|
lexer_ToggleStringExpansion(false);
|
||||||
} purge_list trailing_comma {
|
} purge_list trailing_comma {
|
||||||
@@ -1017,15 +1101,6 @@ purge : T_POP_PURGE {
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
redef : T_POP_REDEF {
|
|
||||||
lexer_ToggleStringExpansion(false);
|
|
||||||
} scoped_id {
|
|
||||||
lexer_ToggleStringExpansion(true);
|
|
||||||
} T_POP_EQUS string {
|
|
||||||
sym_RedefString($3, $6);
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
purge_list : purge_list_entry
|
purge_list : purge_list_entry
|
||||||
| purge_list T_COMMA purge_list_entry
|
| purge_list T_COMMA purge_list_entry
|
||||||
;
|
;
|
||||||
@@ -1043,13 +1118,6 @@ export_list : export_list_entry
|
|||||||
export_list_entry : scoped_id { sym_Export($1); }
|
export_list_entry : scoped_id { sym_Export($1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
equ : T_LABEL T_POP_EQU const { sym_AddEqu($1, $3); }
|
|
||||||
;
|
|
||||||
|
|
||||||
set : T_LABEL T_POP_SET const { sym_AddSet($1, $3); }
|
|
||||||
| T_LABEL T_POP_EQUAL const { sym_AddSet($1, $3); }
|
|
||||||
;
|
|
||||||
|
|
||||||
include : T_POP_INCLUDE string {
|
include : T_POP_INCLUDE string {
|
||||||
fstk_RunInclude($2);
|
fstk_RunInclude($2);
|
||||||
if (oFailedOnMissingInclude)
|
if (oFailedOnMissingInclude)
|
||||||
@@ -1097,8 +1165,14 @@ popc : T_POP_POPC { charmap_Pop(); }
|
|||||||
print : T_POP_PRINT print_exprs trailing_comma
|
print : T_POP_PRINT print_exprs trailing_comma
|
||||||
;
|
;
|
||||||
|
|
||||||
println : T_POP_PRINTLN { putchar('\n'); }
|
println : T_POP_PRINTLN {
|
||||||
| T_POP_PRINTLN print_exprs trailing_comma { putchar('\n'); }
|
putchar('\n');
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
| T_POP_PRINTLN print_exprs trailing_comma {
|
||||||
|
putchar('\n');
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
print_exprs : print_expr
|
print_exprs : print_expr
|
||||||
@@ -1437,7 +1511,11 @@ string : T_STRING
|
|||||||
|
|
||||||
strcat_args : string
|
strcat_args : string
|
||||||
| strcat_args T_COMMA string {
|
| strcat_args T_COMMA string {
|
||||||
if (snprintf($$, sizeof($$), "%s%s", $1, $3) >= sizeof($$))
|
int ret = snprintf($$, sizeof($$), "%s%s", $1, $3);
|
||||||
|
|
||||||
|
if (ret == -1)
|
||||||
|
fatalerror("snprintf error in STRCAT: %s\n", strerror(errno));
|
||||||
|
else if ((unsigned int)ret >= sizeof($$))
|
||||||
warning(WARNING_LONG_STR, "STRCAT: String too long '%s%s'\n",
|
warning(WARNING_LONG_STR, "STRCAT: String too long '%s%s'\n",
|
||||||
$1, $3);
|
$1, $3);
|
||||||
}
|
}
|
||||||
@@ -1590,7 +1668,7 @@ z80_add : T_Z80_ADD op_a_n {
|
|||||||
out_RelByte(&$2, 1);
|
out_RelByte(&$2, 1);
|
||||||
}
|
}
|
||||||
| T_Z80_ADD op_a_r { out_AbsByte(0x80 | $2); }
|
| T_Z80_ADD op_a_r { out_AbsByte(0x80 | $2); }
|
||||||
| T_Z80_ADD op_hl_ss { out_AbsByte(0x09 | ($2 << 4)); }
|
| T_Z80_ADD T_MODE_HL T_COMMA reg_ss { out_AbsByte(0x09 | ($4 << 4)); }
|
||||||
| T_Z80_ADD T_MODE_SP T_COMMA reloc_8bit {
|
| T_Z80_ADD T_MODE_SP T_COMMA reloc_8bit {
|
||||||
out_AbsByte(0xE8);
|
out_AbsByte(0xE8);
|
||||||
out_RelByte(&$4, 1);
|
out_RelByte(&$4, 1);
|
||||||
@@ -1731,9 +1809,9 @@ z80_ld : z80_ld_mem
|
|||||||
| z80_ld_a
|
| z80_ld_a
|
||||||
;
|
;
|
||||||
|
|
||||||
z80_ld_hl : T_Z80_LD T_MODE_HL T_COMMA T_MODE_SP reloc_8bit {
|
z80_ld_hl : T_Z80_LD T_MODE_HL T_COMMA T_MODE_SP T_OP_ADD reloc_8bit {
|
||||||
out_AbsByte(0xF8);
|
out_AbsByte(0xF8);
|
||||||
out_RelByte(&$5, 1);
|
out_RelByte(&$6, 1);
|
||||||
}
|
}
|
||||||
| T_Z80_LD T_MODE_HL T_COMMA reloc_16bit {
|
| T_Z80_LD T_MODE_HL T_COMMA reloc_16bit {
|
||||||
out_AbsByte(0x01 | (REG_HL << 4));
|
out_AbsByte(0x01 | (REG_HL << 4));
|
||||||
@@ -1975,10 +2053,6 @@ z80_xor : T_Z80_XOR op_a_n {
|
|||||||
op_mem_ind : T_LBRACK reloc_16bit T_RBRACK { $$ = $2; }
|
op_mem_ind : T_LBRACK reloc_16bit T_RBRACK { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
op_hl_ss : reg_ss
|
|
||||||
| T_MODE_HL T_COMMA reg_ss { $$ = $3; }
|
|
||||||
;
|
|
||||||
|
|
||||||
op_a_r : reg_r
|
op_a_r : reg_r
|
||||||
| T_MODE_A T_COMMA reg_r { $$ = $3; }
|
| T_MODE_A T_COMMA reg_r { $$ = $3; }
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2010-2019, Anthony J. Bentley and RGBDS contributors.
|
.\" Copyright (c) 2010-2021, Anthony J. Bentley and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd July 8, 2019
|
.Dd March 28, 2021
|
||||||
.Dt RGBASM 1
|
.Dt RGBASM 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -189,7 +189,7 @@ Ignoring the
|
|||||||
prefix, entries are listed alphabetically.
|
prefix, entries are listed alphabetically.
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Fl Wno-assert
|
.It Fl Wno-assert
|
||||||
Warns when
|
Warn when
|
||||||
.Ic WARN Ns No -type
|
.Ic WARN Ns No -type
|
||||||
assertions fail. (See
|
assertions fail. (See
|
||||||
.Dq Aborting the assembly process
|
.Dq Aborting the assembly process
|
||||||
@@ -197,6 +197,12 @@ in
|
|||||||
.Xr rgbasm 5
|
.Xr rgbasm 5
|
||||||
for
|
for
|
||||||
.Ic ASSERT ) .
|
.Ic ASSERT ) .
|
||||||
|
.It Fl Wbackwards-for
|
||||||
|
Warn when
|
||||||
|
.Ic FOR
|
||||||
|
loops have their start and stop values switched according to the step value.
|
||||||
|
This warning is enabled by
|
||||||
|
.Fl Wall .
|
||||||
.It Fl Wbuiltin-args
|
.It Fl Wbuiltin-args
|
||||||
Warn about incorrect arguments to built-in functions, such as
|
Warn about incorrect arguments to built-in functions, such as
|
||||||
.Fn STRSUB
|
.Fn STRSUB
|
||||||
@@ -239,7 +245,7 @@ constant or
|
|||||||
directive are encountered.
|
directive are encountered.
|
||||||
.It Fl Wshift
|
.It Fl Wshift
|
||||||
Warn when shifting right a negative value.
|
Warn when shifting right a negative value.
|
||||||
Use a division by 2^N instead.
|
Use a division by 2**N instead.
|
||||||
.It Fl Wshift-amount
|
.It Fl Wshift-amount
|
||||||
Warn when a shift's operand is negative or greater than 32.
|
Warn when a shift's operand is negative or greater than 32.
|
||||||
.It Fl Wno-truncation
|
.It Fl Wno-truncation
|
||||||
|
|||||||
218
src/asm/rgbasm.5
218
src/asm/rgbasm.5
@@ -1,11 +1,11 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
|
.\" Copyright (c) 2017-2021, Antonio Nino Diaz and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd December 5, 2019
|
.Dd March 28, 2021
|
||||||
.Dt RGBASM 5
|
.Dt RGBASM 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -25,11 +25,11 @@ Generally,
|
|||||||
.Dq the linker
|
.Dq the linker
|
||||||
will refer to
|
will refer to
|
||||||
.Xr rgblink 1 ,
|
.Xr rgblink 1 ,
|
||||||
but any program that processes RGB object files (described in
|
but any program that processes RGBDS object files (described in
|
||||||
.Xr rgbds 5 )
|
.Xr rgbds 5 )
|
||||||
can be used in its place.
|
can be used in its place.
|
||||||
.Sh SYNTAX
|
.Sh SYNTAX
|
||||||
The syntax is line‐based, just as in any other assembler, meaning that you do one instruction or directive per line:
|
The syntax is line-based, just as in any other assembler, meaning that you do one instruction or directive per line:
|
||||||
.Pp
|
.Pp
|
||||||
.Dl Oo Ar label Oc Oo Ar instruction Oc Oo Ar ;\ comment Oc
|
.Dl Oo Ar label Oc Oo Ar instruction Oc Oo Ar ;\ comment Oc
|
||||||
.Pp
|
.Pp
|
||||||
@@ -38,7 +38,7 @@ Example:
|
|||||||
John: ld a,87 ;Weee
|
John: ld a,87 ;Weee
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
All reserved keywords (directives, mnemonics, registers, etc.) are case‐insensitive;
|
All reserved keywords (directives, mnemonics, registers, etc.) are case-insensitive;
|
||||||
all identifiers (symbol names) are case-sensitive.
|
all identifiers (symbol names) are case-sensitive.
|
||||||
.Pp
|
.Pp
|
||||||
Comments are used to give humans information about the code, such as explanations.
|
Comments are used to give humans information about the code, such as explanations.
|
||||||
@@ -177,8 +177,8 @@ and
|
|||||||
.Pp
|
.Pp
|
||||||
.Ic \&!
|
.Ic \&!
|
||||||
returns 1 if the operand was 0, and 0 otherwise.
|
returns 1 if the operand was 0, and 0 otherwise.
|
||||||
.Ss Fixed‐point Expressions
|
.Ss Fixed-point Expressions
|
||||||
Fixed-point numbers are basically normal (32-bit) integers, which count 65536th's instead of entire units, offering better precision than integers but limiting the range of values.
|
Fixed-point numbers are basically normal (32-bit) integers, which count 65536ths instead of entire units, offering better precision than integers but limiting the range of values.
|
||||||
The upper 16 bits are used for the integer part and the lower 16 bits are used for the fraction (65536ths).
|
The upper 16 bits are used for the integer part and the lower 16 bits are used for the fraction (65536ths).
|
||||||
Since they are still akin to integers, you can use them in normal integer expressions, and some integer operators like
|
Since they are still akin to integers, you can use them in normal integer expressions, and some integer operators like
|
||||||
.Sq +
|
.Sq +
|
||||||
@@ -266,21 +266,37 @@ A funky feature is
|
|||||||
.Ql {symbol}
|
.Ql {symbol}
|
||||||
within a string, called
|
within a string, called
|
||||||
.Dq symbol interpolation .
|
.Dq symbol interpolation .
|
||||||
This will paste
|
This will paste the contents of
|
||||||
.Ar symbol Ap s
|
.Ql symbol
|
||||||
contents as a string.
|
as if they were part of the source file.
|
||||||
If it's a string symbol, the string is simply inserted.
|
If it's a string symbol, its characters are simply inserted.
|
||||||
If it's a numeric symbol, its value is converted to hexadecimal notation with a dollar sign
|
If it's a numerical symbol, its value is converted to hexadecimal notation with a dollar sign
|
||||||
.Sq $
|
.Sq $
|
||||||
prepended.
|
prepended.
|
||||||
.Bd -literal -offset indent
|
.Pp
|
||||||
TOPIC equs "life, the universe, and \[rs]"everything\[rs]""
|
Symbols can be
|
||||||
ANSWER = 42
|
.Em interpolated
|
||||||
;\ Prints "The answer to life, the universe, and "everything" is $2A"
|
even in the contexts that disable
|
||||||
PRINTLN "The answer to {TOPIC} is {ANSWER}"
|
.Em expansion
|
||||||
.Ed
|
of string equates:
|
||||||
|
.Ql DEF({name}) ,
|
||||||
|
.Ql DEF {name} EQU/SET/EQUS/etc ... ,
|
||||||
|
.Ql PURGE {name} ,
|
||||||
|
and
|
||||||
|
.Ql MACRO {name}
|
||||||
|
will all interpolate the contents of
|
||||||
|
.Ql {name} .
|
||||||
.Pp
|
.Pp
|
||||||
Symbol interpolations can be nested, too!
|
Symbol interpolations can be nested, too!
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
DEF topic EQUS "life, the universe, and \[rs]"everything\[rs]""
|
||||||
|
DEF meaning EQUS "answer"
|
||||||
|
;\ Defines answer = 42
|
||||||
|
DEF {meaning} = 42
|
||||||
|
;\ Prints "The answer to life, the universe, and "everything" is 42"
|
||||||
|
PRINTLN "The {meaning} to {topic} is {d:{meaning}}"
|
||||||
|
PURGE topic, meaning, {meaning}
|
||||||
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
It's possible to change the way symbols are converted by specifying a print format like so:
|
It's possible to change the way symbols are converted by specifying a print format like so:
|
||||||
.Ql {fmt:symbol} .
|
.Ql {fmt:symbol} .
|
||||||
@@ -321,7 +337,7 @@ followed by one or more
|
|||||||
\[en]
|
\[en]
|
||||||
.Ql 9 .
|
.Ql 9 .
|
||||||
If specified, prints this many digits of a fixed-point fraction.
|
If specified, prints this many digits of a fixed-point fraction.
|
||||||
Defaults to 5 digits.
|
Defaults to 5 digits, maximum 255 digits.
|
||||||
.It Ql <type> Ta Specifies the type of value.
|
.It Ql <type> Ta Specifies the type of value.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
@@ -355,14 +371,14 @@ HINT: The
|
|||||||
construct can also be used outside strings.
|
construct can also be used outside strings.
|
||||||
The symbol's value is again inserted directly.
|
The symbol's value is again inserted directly.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
NAME equs "ITEM"
|
def NAME equs "ITEM"
|
||||||
FMT equs "d"
|
def FMT equs "d"
|
||||||
ZERO_NUM equ 0
|
def ZERO_NUM equ 0
|
||||||
ZERO_STR equs "0"
|
def ZERO_STR equs "0"
|
||||||
;\ Defines INDEX as 100
|
;\ Defines INDEX as 100
|
||||||
INDEX = 1{ZERO_STR}{{FMT}:ZERO_NUM}
|
INDEX = 1{ZERO_STR}{{FMT}:ZERO_NUM}
|
||||||
;\ Defines ITEM_100 as "\[rs]"hundredth\[rs]""
|
;\ Defines ITEM_100 as "\[rs]"hundredth\[rs]""
|
||||||
{NAME}_{d:INDEX} equs "\[rs]"hundredth\[rs]""
|
def {NAME}_{d:INDEX} equs "\[rs]"hundredth\[rs]""
|
||||||
;\ Prints "ITEM_100 is hundredth"
|
;\ Prints "ITEM_100 is hundredth"
|
||||||
PRINTLN STRCAT("{NAME}_{d:INDEX} is ", {NAME}_{d:INDEX})
|
PRINTLN STRCAT("{NAME}_{d:INDEX} is ", {NAME}_{d:INDEX})
|
||||||
;\ Purges ITEM_100
|
;\ Purges ITEM_100
|
||||||
@@ -446,7 +462,7 @@ is able to compute it.
|
|||||||
.It Fn DEF symbol Ta Returns TRUE (1) if
|
.It Fn DEF symbol Ta Returns TRUE (1) if
|
||||||
.Ar symbol
|
.Ar symbol
|
||||||
has been defined, FALSE (0) otherwise.
|
has been defined, FALSE (0) otherwise.
|
||||||
String symbols are not expanded within the parentheses.
|
String equates are not expanded within the parentheses.
|
||||||
.It Fn HIGH arg Ta Returns the top 8 bits of the operand if Ar arg No is a label or constant, or the top 8-bit register if it is a 16-bit register.
|
.It Fn HIGH arg Ta Returns the top 8 bits of the operand if Ar arg No 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 No is a label or constant, or the bottom 8-bit register if it is a 16-bit register Pq Cm AF No isn't a valid register for this function .
|
.It Fn LOW arg Ta Returns the bottom 8 bits of the operand if Ar arg No is a label or constant, or the bottom 8-bit register if it is a 16-bit register Pq Cm AF No isn't a valid register for this function .
|
||||||
.It Fn ISCONST arg Ta Returns 1 if Ar arg Ap s value is known by RGBASM (e.g. if it can be an argument to
|
.It Fn ISCONST arg Ta Returns 1 if Ar arg Ap s value is known by RGBASM (e.g. if it can be an argument to
|
||||||
@@ -590,7 +606,7 @@ depending on
|
|||||||
.It Ic ALIGN Ns Bq Ar align , offset
|
.It Ic ALIGN Ns Bq Ar align , offset
|
||||||
Place the section at an address whose
|
Place the section at an address whose
|
||||||
.Ar align
|
.Ar align
|
||||||
least‐significant bits are equal to
|
least-significant bits are equal to
|
||||||
.Ar offset .
|
.Ar offset .
|
||||||
(Note that
|
(Note that
|
||||||
.Ic ALIGN Ns Bq Ar align
|
.Ic ALIGN Ns Bq Ar align
|
||||||
@@ -853,16 +869,7 @@ Periods
|
|||||||
.Sq \&.
|
.Sq \&.
|
||||||
are allowed exclusively in labels, as described below.
|
are allowed exclusively in labels, as described below.
|
||||||
A symbol cannot have the same name as a reserved keyword.
|
A symbol cannot have the same name as a reserved keyword.
|
||||||
.Pp
|
.Ss Label declaration
|
||||||
Constants and string equates
|
|
||||||
.Em must not
|
|
||||||
have any whitespace before their name when they are defined;
|
|
||||||
otherwise
|
|
||||||
.Nm
|
|
||||||
will treat them as a macro invocation.
|
|
||||||
Label and macro definitions may have whitespace before them, since a leading period or a following colon distinguishes them from invoking a macro.
|
|
||||||
.Bl -tag -width indent
|
|
||||||
.It Sy Label declaration
|
|
||||||
One of the assembler's main tasks is to keep track of addresses for you, so you can work with meaningful names instead of "magic" numbers.
|
One of the assembler's main tasks is to keep track of addresses for you, so you can work with meaningful names instead of "magic" numbers.
|
||||||
.Pp
|
.Pp
|
||||||
This can be done in a number of ways:
|
This can be done in a number of ways:
|
||||||
@@ -937,56 +944,57 @@ However, if the section in which the label is declared has a fixed base address,
|
|||||||
.Pp
|
.Pp
|
||||||
.Nm
|
.Nm
|
||||||
is able to compute the subtraction of two labels either if both are constant as described above, or if both belong to the same section.
|
is able to compute the subtraction of two labels either if both are constant as described above, or if both belong to the same section.
|
||||||
.It Ic EQU
|
.Ss Immutable constants
|
||||||
.Ic EQU
|
.Ic EQU
|
||||||
allows defining constant symbols.
|
is used to define numerical constant symbols.
|
||||||
Unlike
|
Unlike
|
||||||
.Ic SET
|
.Ic SET
|
||||||
below, constants defined this way cannot be redefined.
|
below, constants defined this way cannot be redefined.
|
||||||
They can, for example, be used for things such as bit definitions of hardware registers.
|
They can, for example, be used for things such as bit definitions of hardware registers.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
SCREEN_WIDTH equ 160 ;\ In pixels
|
def SCREEN_WIDTH equ 160 ;\ In pixels
|
||||||
SCREEN_HEIGHT equ 144
|
def SCREEN_HEIGHT equ 144
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Note that colons
|
Note that colons
|
||||||
.Ql \&:
|
.Ql \&:
|
||||||
following the name are not allowed.
|
following the name are not allowed.
|
||||||
.It Ic SET
|
.Ss Mutable constants
|
||||||
.Ic SET ,
|
.Ic SET ,
|
||||||
or its synonym
|
or its synonym
|
||||||
.Ic = ,
|
.Ic = ,
|
||||||
defines constant symbols like
|
is used to define numerical symbols like
|
||||||
.Ic EQU ,
|
.Ic EQU ,
|
||||||
but those constants can be redefined.
|
but these symbols can be redefined.
|
||||||
This is useful for variables in macros, for counters, etc.
|
This is useful for variables in macros, for counters, etc.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
ARRAY_SIZE EQU 4
|
DEF ARRAY_SIZE EQU 4
|
||||||
COUNT SET 2
|
DEF COUNT SET 2
|
||||||
COUNT SET ARRAY_SIZE+COUNT
|
DEF COUNT SET 3
|
||||||
;\ COUNT now has the value 6
|
REDEF COUNT SET ARRAY_SIZE+COUNT
|
||||||
COUNT = COUNT + 1
|
COUNT = COUNT*2
|
||||||
|
;\ COUNT now has the value 14
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Note that colons
|
Note that colons
|
||||||
.Ql \&:
|
.Ql \&:
|
||||||
following the name are not allowed.
|
following the name are not allowed.
|
||||||
.It Ic RSSET , RSRESET , RB , RW
|
.Ss Offset constants
|
||||||
The RS group of commands is a handy way of defining structures:
|
The RS group of commands is a handy way of defining structure offsets:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
RSRESET
|
RSRESET
|
||||||
str_pStuff RW 1
|
DEF str_pStuff RW 1
|
||||||
str_tData RB 256
|
DEF str_tData RB 256
|
||||||
str_bCount RB 1
|
DEF str_bCount RB 1
|
||||||
str_SIZEOF RB 0
|
DEF str_SIZEOF RB 0
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
The example defines four constants as if by:
|
The example defines four constants as if by:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
str_pStuff EQU 0
|
DEF str_pStuff EQU 0
|
||||||
str_tData EQU 2
|
DEF str_tData EQU 2
|
||||||
str_bCount EQU 258
|
DEF str_bCount EQU 258
|
||||||
str_SIZEOF EQU 259
|
DEF str_SIZEOF EQU 259
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
There are five commands in the RS group of commands:
|
There are five commands in the RS group of commands:
|
||||||
@@ -1008,17 +1016,26 @@ is omitted, it's assumed to be 1.
|
|||||||
Note that colons
|
Note that colons
|
||||||
.Ql \&:
|
.Ql \&:
|
||||||
following the name are not allowed.
|
following the name are not allowed.
|
||||||
.It Ic EQUS
|
.Ss String equates
|
||||||
.Ic EQUS
|
.Ic EQUS
|
||||||
is used to define string symbols.
|
is used to define string equate symbols.
|
||||||
Wherever the assembler meets a string symbol its name is replaced with its value.
|
Wherever the assembler reads a string equate, it gets
|
||||||
If you are familiar with C you can think of it as similar to
|
.Em expanded :
|
||||||
|
the symbol's name is replaced with its contents.
|
||||||
|
If you are familiar with C, you can think of it as similar to
|
||||||
.Fd #define .
|
.Fd #define .
|
||||||
|
This expansion is disabled in a few contexts:
|
||||||
|
.Ql DEF(name) ,
|
||||||
|
.Ql DEF name EQU/SET/EQUS/etc ... ,
|
||||||
|
.Ql PURGE name ,
|
||||||
|
and
|
||||||
|
.Ql MACRO name
|
||||||
|
will not expand string equates in their names.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
COUNTREG EQUS "[hl+]"
|
DEF COUNTREG EQUS "[hl+]"
|
||||||
ld a,COUNTREG
|
ld a,COUNTREG
|
||||||
|
|
||||||
PLAYER_NAME EQUS "\[rs]"John\[rs]""
|
DEF PLAYER_NAME EQUS "\[rs]"John\[rs]""
|
||||||
db PLAYER_NAME
|
db PLAYER_NAME
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1028,9 +1045,9 @@ This will be interpreted as:
|
|||||||
db "John"
|
db "John"
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
String symbols can also be used to define small one-line macros:
|
String equates can also be used to define small one-line macros:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
pusha EQUS "push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n"
|
DEF pusha EQUS "push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n"
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Note that colons
|
Note that colons
|
||||||
@@ -1047,7 +1064,7 @@ However, the
|
|||||||
keyword will define or redefine a string symbol.
|
keyword will define or redefine a string symbol.
|
||||||
For example:
|
For example:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
s EQUS "Hello, "
|
DEF s EQUS "Hello, "
|
||||||
REDEF s EQUS "{s}world!"
|
REDEF s EQUS "{s}world!"
|
||||||
; prints "Hello, world!"
|
; prints "Hello, world!"
|
||||||
PRINTT "{s}\n"
|
PRINTT "{s}\n"
|
||||||
@@ -1070,7 +1087,47 @@ command-line option in
|
|||||||
Also, a macro can contain an
|
Also, a macro can contain an
|
||||||
.Ic EQUS
|
.Ic EQUS
|
||||||
which calls the same macro, which causes the same problem.
|
which calls the same macro, which causes the same problem.
|
||||||
.It Ic MACRO
|
.Pp
|
||||||
|
The examples above for
|
||||||
|
.Ql EQU ,
|
||||||
|
.Ql SET
|
||||||
|
or
|
||||||
|
.Ql = ,
|
||||||
|
.Ql RB ,
|
||||||
|
.Ql RW ,
|
||||||
|
.Ql RL ,
|
||||||
|
and
|
||||||
|
.Ql EQUS
|
||||||
|
all start with
|
||||||
|
.Ql DEF .
|
||||||
|
(A
|
||||||
|
.Ql SET
|
||||||
|
or
|
||||||
|
.Ql =
|
||||||
|
definition may start with
|
||||||
|
.Ql REDEF
|
||||||
|
instead, since they are redefinable.)
|
||||||
|
You may use the older syntax without
|
||||||
|
.Ql DEF ,
|
||||||
|
but then the name being defined
|
||||||
|
.Em must not
|
||||||
|
have any whitespace before it;
|
||||||
|
otherwise
|
||||||
|
.Nm
|
||||||
|
will treat it as a macro invocation.
|
||||||
|
Furthermore, without the
|
||||||
|
.Ql DEF
|
||||||
|
keyword,
|
||||||
|
string equates may be expanded for the name.
|
||||||
|
This can lead to surprising results:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
X EQUS "Y"
|
||||||
|
; this defines Y, not X!
|
||||||
|
X EQU 42
|
||||||
|
; prints "Y $2A"
|
||||||
|
PRINTLN "{X} {Y}"
|
||||||
|
.Ed
|
||||||
|
.Ss Macros
|
||||||
One of the best features of an assembler is the ability to write macros for it.
|
One of the best features of an assembler is the ability to write macros for it.
|
||||||
Macros can be called with arguments, and can react depending on input using
|
Macros can be called with arguments, and can react depending on input using
|
||||||
.Ic IF
|
.Ic IF
|
||||||
@@ -1085,6 +1142,7 @@ ENDM
|
|||||||
The example above defines
|
The example above defines
|
||||||
.Ql MyMacro
|
.Ql MyMacro
|
||||||
as a new macro.
|
as a new macro.
|
||||||
|
String equates are not expanded within the name of the macro.
|
||||||
You may use the older syntax
|
You may use the older syntax
|
||||||
.Ql MyMacro: MACRO
|
.Ql MyMacro: MACRO
|
||||||
instead of
|
instead of
|
||||||
@@ -1092,6 +1150,8 @@ instead of
|
|||||||
with a single colon
|
with a single colon
|
||||||
.Ql \&:
|
.Ql \&:
|
||||||
following the macro's name.
|
following the macro's name.
|
||||||
|
With the older syntax, string equates may be expanded for the name.
|
||||||
|
.Pp
|
||||||
Macros can't be exported or imported.
|
Macros can't be exported or imported.
|
||||||
.Pp
|
.Pp
|
||||||
Plainly nesting macro definitions is not allowed, but this can be worked around using
|
Plainly nesting macro definitions is not allowed, but this can be worked around using
|
||||||
@@ -1108,12 +1168,11 @@ ENDM
|
|||||||
But this will:
|
But this will:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
MACRO outer
|
MACRO outer
|
||||||
definition EQUS "MACRO inner\[rs]nPRINTLN \[rs]"Hello!\[rs]"\[rs]nENDM"
|
DEF definition EQUS "MACRO inner\[rs]nPRINTLN \[rs]"Hello!\[rs]"\[rs]nENDM"
|
||||||
definition
|
definition
|
||||||
PURGE definition
|
PURGE definition
|
||||||
ENDM
|
ENDM
|
||||||
.Ed
|
.Ed
|
||||||
.El
|
|
||||||
.Pp
|
.Pp
|
||||||
Macro arguments support all the escape sequences of strings, as well as
|
Macro arguments support all the escape sequences of strings, as well as
|
||||||
.Ql \[rs],
|
.Ql \[rs],
|
||||||
@@ -1184,15 +1243,12 @@ I can't stress this enough,
|
|||||||
DON'T purge a symbol that you use in expressions the linker needs to calculate.
|
DON'T purge a symbol that you use in expressions the linker needs to calculate.
|
||||||
When not sure, it's probably not safe to purge anything other than string symbols, macros, and constants.
|
When not sure, it's probably not safe to purge anything other than string symbols, macros, and constants.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
Kamikaze EQUS "I don't want to live anymore"
|
DEF Kamikaze EQUS "I don't want to live anymore"
|
||||||
AOLer EQUS "Me too"
|
DEF AOLer EQUS "Me too"
|
||||||
PURGE Kamikaze, AOLer
|
PURGE Kamikaze, AOLer
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Note that, as an exception, string symbols in the argument list of a
|
String equates are not expanded within the symbol names.
|
||||||
.Ic PURGE
|
|
||||||
command
|
|
||||||
.Em will not be expanded .
|
|
||||||
.Ss Predeclared Symbols
|
.Ss Predeclared Symbols
|
||||||
The following symbols are defined by the assembler:
|
The following symbols are defined by the assembler:
|
||||||
.Bl -column -offset indent "EQUS" "__ISO_8601_LOCAL__"
|
.Bl -column -offset indent "EQUS" "__ISO_8601_LOCAL__"
|
||||||
@@ -1216,6 +1272,7 @@ The following symbols are defined by the assembler:
|
|||||||
.It Dv __RGBDS_MINOR__ Ta Ic EQU Ta Minor version number of RGBDS
|
.It Dv __RGBDS_MINOR__ Ta Ic EQU Ta Minor version number of RGBDS
|
||||||
.It Dv __RGBDS_PATCH__ Ta Ic EQU Ta Patch version number of RGBDS
|
.It Dv __RGBDS_PATCH__ Ta Ic EQU Ta Patch version number of RGBDS
|
||||||
.It Dv __RGBDS_RC__ Ta Ic EQU Ta Release candidate ID of RGBDS, not defined for final releases
|
.It Dv __RGBDS_RC__ Ta Ic EQU Ta Release candidate ID of RGBDS, not defined for final releases
|
||||||
|
.It Dv __RGBDS_VERSION__ Ta Ic EQUS Ta Version of RGBDS, as printed by Ql rgbasm --version
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The current time values will be taken from the
|
The current time values will be taken from the
|
||||||
@@ -1458,7 +1515,7 @@ MACRO LoopyMacro
|
|||||||
ENDM
|
ENDM
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Now I can call the macro specifying two arguments, the first being the address and the second being a byte count.
|
Now you can call the macro specifying two arguments, the first being the address and the second being a byte count.
|
||||||
The generated code will then reset all bytes in this range.
|
The generated code will then reset all bytes in this range.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
LoopyMacro MyVars,54
|
LoopyMacro MyVars,54
|
||||||
@@ -1598,6 +1655,7 @@ Everything between
|
|||||||
and the matching
|
and the matching
|
||||||
.Ic ENDR
|
.Ic ENDR
|
||||||
will be repeated for each value of a given symbol.
|
will be repeated for each value of a given symbol.
|
||||||
|
String equates are not expanded within the symbol name.
|
||||||
For example, this code will produce a table of squared values from 0 to 255:
|
For example, this code will produce a table of squared values from 0 to 255:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
FOR N, 256
|
FOR N, 256
|
||||||
@@ -1624,9 +1682,9 @@ You can customize the range of
|
|||||||
values:
|
values:
|
||||||
.Bl -column "FOR V, start, stop, step"
|
.Bl -column "FOR V, start, stop, step"
|
||||||
.It Sy Code Ta Sy Range
|
.It Sy Code Ta Sy Range
|
||||||
.It Ic FOR Ar V , stop Ta Ar V No increments from 0 to Ar stop No
|
.It Ic FOR Ar V , stop Ta Ar V No increments from 0 to Ar stop
|
||||||
.It Ic FOR Ar V , start , stop Ta Ar V No increments from Ar start No to Ar stop No
|
.It Ic FOR Ar V , start , stop Ta Ar V No increments from Ar start No to Ar stop
|
||||||
.It Ic FOR Ar V , start , stop , step Ta Ar V No goes from Ar start No to Ar stop No by Ar step No
|
.It Ic FOR Ar V , start , stop , step Ta Ar V No goes from Ar start No to Ar stop No by Ar step
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ void rpn_BankSelf(struct Expression *expr)
|
|||||||
if (!pCurrentSection) {
|
if (!pCurrentSection) {
|
||||||
error("PC has no bank outside a section\n");
|
error("PC has no bank outside a section\n");
|
||||||
expr->nVal = 1;
|
expr->nVal = 1;
|
||||||
} else if (pCurrentSection->bank == -1) {
|
} else if (pCurrentSection->bank == (uint32_t)-1) {
|
||||||
makeUnknown(expr, "Current section's bank is not known");
|
makeUnknown(expr, "Current section's bank is not known");
|
||||||
expr->nRPNPatchSize++;
|
expr->nRPNPatchSize++;
|
||||||
*reserveSpace(expr, 1) = RPN_BANK_SELF;
|
*reserveSpace(expr, 1) = RPN_BANK_SELF;
|
||||||
@@ -165,7 +165,7 @@ void rpn_BankSymbol(struct Expression *expr, char const *tzSym)
|
|||||||
sym = sym_Ref(tzSym);
|
sym = sym_Ref(tzSym);
|
||||||
assert(sym); // If the symbol didn't exist, it should have been created
|
assert(sym); // If the symbol didn't exist, it should have been created
|
||||||
|
|
||||||
if (sym_GetSection(sym) && sym_GetSection(sym)->bank != -1) {
|
if (sym_GetSection(sym) && sym_GetSection(sym)->bank != (uint32_t)-1) {
|
||||||
/* Symbol's section is known and bank is fixed */
|
/* Symbol's section is known and bank is fixed */
|
||||||
expr->nVal = sym_GetSection(sym)->bank;
|
expr->nVal = sym_GetSection(sym)->bank;
|
||||||
} else {
|
} else {
|
||||||
@@ -186,7 +186,7 @@ void rpn_BankSection(struct Expression *expr, char const *tzSectionName)
|
|||||||
|
|
||||||
struct Section *pSection = out_FindSectionByName(tzSectionName);
|
struct Section *pSection = out_FindSectionByName(tzSectionName);
|
||||||
|
|
||||||
if (pSection && pSection->bank != -1) {
|
if (pSection && pSection->bank != (uint32_t)-1) {
|
||||||
expr->nVal = pSection->bank;
|
expr->nVal = pSection->bank;
|
||||||
} else {
|
} else {
|
||||||
makeUnknown(expr, "Section \"%s\"'s bank is not known",
|
makeUnknown(expr, "Section \"%s\"'s bank is not known",
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ struct UnionStackEntry {
|
|||||||
/*
|
/*
|
||||||
* A quick check to see if we have an initialized section
|
* A quick check to see if we have an initialized section
|
||||||
*/
|
*/
|
||||||
static inline void checksection(void)
|
static void checksection(void)
|
||||||
{
|
{
|
||||||
if (pCurrentSection == NULL)
|
if (pCurrentSection == NULL)
|
||||||
fatalerror("Code generation before SECTION directive\n");
|
fatalerror("Code generation before SECTION directive\n");
|
||||||
@@ -51,7 +51,7 @@ static inline void checksection(void)
|
|||||||
* A quick check to see if we have an initialized section that can contain
|
* A quick check to see if we have an initialized section that can contain
|
||||||
* this much initialized data
|
* this much initialized data
|
||||||
*/
|
*/
|
||||||
static inline void checkcodesection(void)
|
static void checkcodesection(void)
|
||||||
{
|
{
|
||||||
checksection();
|
checksection();
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ static inline void checkcodesection(void)
|
|||||||
pCurrentSection->name);
|
pCurrentSection->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void checkSectionSize(struct Section const *sect, uint32_t size)
|
static void checkSectionSize(struct Section const *sect, uint32_t size)
|
||||||
{
|
{
|
||||||
uint32_t maxSize = maxsize[sect->type];
|
uint32_t maxSize = maxsize[sect->type];
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ static inline void checkSectionSize(struct Section const *sect, uint32_t size)
|
|||||||
/*
|
/*
|
||||||
* Check if the section has grown too much.
|
* Check if the section has grown too much.
|
||||||
*/
|
*/
|
||||||
static inline void reserveSpace(uint32_t delta_size)
|
static void reserveSpace(uint32_t delta_size)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This check is here to trap broken code that generates sections that
|
* This check is here to trap broken code that generates sections that
|
||||||
@@ -114,9 +114,9 @@ static unsigned int mergeSectUnion(struct Section *sect, enum SectionType type,
|
|||||||
if (sect_HasData(type))
|
if (sect_HasData(type))
|
||||||
fail("Cannot declare ROM sections as UNION\n");
|
fail("Cannot declare ROM sections as UNION\n");
|
||||||
|
|
||||||
if (org != -1) {
|
if (org != (uint32_t)-1) {
|
||||||
/* If both are fixed, they must be the same */
|
/* If both are fixed, they must be the same */
|
||||||
if (sect->org != -1 && sect->org != org)
|
if (sect->org != (uint32_t)-1 && sect->org != org)
|
||||||
fail("Section already declared as fixed at different address $%04"
|
fail("Section already declared as fixed at different address $%04"
|
||||||
PRIx32 "\n", sect->org);
|
PRIx32 "\n", sect->org);
|
||||||
else if (sect->align != 0 && (mask(sect->align) & (org - sect->alignOfs)))
|
else if (sect->align != 0 && (mask(sect->align) & (org - sect->alignOfs)))
|
||||||
@@ -128,7 +128,7 @@ static unsigned int mergeSectUnion(struct Section *sect, enum SectionType type,
|
|||||||
|
|
||||||
} else if (alignment != 0) {
|
} else if (alignment != 0) {
|
||||||
/* Make sure any fixed address given is compatible */
|
/* Make sure any fixed address given is compatible */
|
||||||
if (sect->org != -1) {
|
if (sect->org != (uint32_t)-1) {
|
||||||
if ((sect->org - alignOffset) & mask(alignment))
|
if ((sect->org - alignOffset) & mask(alignment))
|
||||||
fail("Section already declared as fixed at incompatible address $%04"
|
fail("Section already declared as fixed at incompatible address $%04"
|
||||||
PRIx32 "\n", sect->org);
|
PRIx32 "\n", sect->org);
|
||||||
@@ -160,11 +160,11 @@ static unsigned int mergeFragments(struct Section *sect, enum SectionType type,
|
|||||||
* combination of both.
|
* combination of both.
|
||||||
* The merging is however performed at the *end* of the original section!
|
* The merging is however performed at the *end* of the original section!
|
||||||
*/
|
*/
|
||||||
if (org != -1) {
|
if (org != (uint32_t)-1) {
|
||||||
uint16_t curOrg = org - sect->size;
|
uint16_t curOrg = org - sect->size;
|
||||||
|
|
||||||
/* If both are fixed, they must be the same */
|
/* If both are fixed, they must be the same */
|
||||||
if (sect->org != -1 && sect->org != curOrg)
|
if (sect->org != (uint32_t)-1 && sect->org != curOrg)
|
||||||
fail("Section already declared as fixed at incompatible address $%04"
|
fail("Section already declared as fixed at incompatible address $%04"
|
||||||
PRIx32 " (cur addr = %04" PRIx32 ")\n",
|
PRIx32 " (cur addr = %04" PRIx32 ")\n",
|
||||||
sect->org, sect->org + sect->size);
|
sect->org, sect->org + sect->size);
|
||||||
@@ -182,7 +182,7 @@ static unsigned int mergeFragments(struct Section *sect, enum SectionType type,
|
|||||||
curOfs += 1U << alignment;
|
curOfs += 1U << alignment;
|
||||||
|
|
||||||
/* Make sure any fixed address given is compatible */
|
/* Make sure any fixed address given is compatible */
|
||||||
if (sect->org != -1) {
|
if (sect->org != (uint32_t)-1) {
|
||||||
if ((sect->org - curOfs) & mask(alignment))
|
if ((sect->org - curOfs) & mask(alignment))
|
||||||
fail("Section already declared as fixed at incompatible address $%04"
|
fail("Section already declared as fixed at incompatible address $%04"
|
||||||
PRIx32 "\n", sect->org);
|
PRIx32 "\n", sect->org);
|
||||||
@@ -221,10 +221,10 @@ static void mergeSections(struct Section *sect, enum SectionType type, uint32_t
|
|||||||
// Common checks
|
// Common checks
|
||||||
|
|
||||||
/* If the section's bank is unspecified, override it */
|
/* If the section's bank is unspecified, override it */
|
||||||
if (sect->bank == -1)
|
if (sect->bank == (uint32_t)-1)
|
||||||
sect->bank = bank;
|
sect->bank = bank;
|
||||||
/* If both specify a bank, it must be the same one */
|
/* If both specify a bank, it must be the same one */
|
||||||
else if (bank != -1 && sect->bank != bank)
|
else if (bank != (uint32_t)-1 && sect->bank != bank)
|
||||||
fail("Section already declared with different bank %" PRIu32 "\n",
|
fail("Section already declared with different bank %" PRIu32 "\n",
|
||||||
sect->bank);
|
sect->bank);
|
||||||
break;
|
break;
|
||||||
@@ -296,7 +296,7 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
|
|||||||
|
|
||||||
// First, validate parameters, and normalize them if applicable
|
// First, validate parameters, and normalize them if applicable
|
||||||
|
|
||||||
if (bank != -1) {
|
if (bank != (uint32_t)-1) {
|
||||||
if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM
|
if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM
|
||||||
&& type != SECTTYPE_SRAM && type != SECTTYPE_WRAMX)
|
&& type != SECTTYPE_SRAM && type != SECTTYPE_WRAMX)
|
||||||
error("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections\n");
|
error("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections\n");
|
||||||
@@ -316,7 +316,7 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
|
|||||||
alignOffset = 0;
|
alignOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (org != -1) {
|
if (org != (uint32_t)-1) {
|
||||||
if (org < startaddr[type] || org > endaddr(type))
|
if (org < startaddr[type] || org > endaddr(type))
|
||||||
error("Section \"%s\"'s fixed address %#" PRIx32
|
error("Section \"%s\"'s fixed address %#" PRIx32
|
||||||
" is outside of range [%#" PRIx16 "; %#" PRIx16 "]\n",
|
" is outside of range [%#" PRIx16 "; %#" PRIx16 "]\n",
|
||||||
@@ -331,7 +331,7 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
|
|||||||
/* It doesn't make sense to have both alignment and org set */
|
/* It doesn't make sense to have both alignment and org set */
|
||||||
uint32_t mask = mask(alignment);
|
uint32_t mask = mask(alignment);
|
||||||
|
|
||||||
if (org != -1) {
|
if (org != (uint32_t)-1) {
|
||||||
if ((org - alignOffset) & mask)
|
if ((org - alignOffset) & mask)
|
||||||
error("Section \"%s\"'s fixed address doesn't match its alignment\n",
|
error("Section \"%s\"'s fixed address doesn't match its alignment\n",
|
||||||
name);
|
name);
|
||||||
@@ -339,6 +339,8 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
|
|||||||
} else if (startaddr[type] & mask) {
|
} else if (startaddr[type] & mask) {
|
||||||
error("Section \"%s\"'s alignment cannot be attained in %s\n",
|
error("Section \"%s\"'s alignment cannot be attained in %s\n",
|
||||||
name, typeNames[type]);
|
name, typeNames[type]);
|
||||||
|
alignment = 0; /* Ignore it if it's unattainable */
|
||||||
|
org = 0;
|
||||||
} else if (alignment == 16) {
|
} else if (alignment == 16) {
|
||||||
// Treat an alignment of 16 as being fixed at address 0
|
// Treat an alignment of 16 as being fixed at address 0
|
||||||
alignment = 0;
|
alignment = 0;
|
||||||
@@ -453,7 +455,7 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset)
|
|||||||
struct Section *sect = sect_GetSymbolSection();
|
struct Section *sect = sect_GetSymbolSection();
|
||||||
uint16_t alignSize = 1 << alignment; // Size of an aligned "block"
|
uint16_t alignSize = 1 << alignment; // Size of an aligned "block"
|
||||||
|
|
||||||
if (sect->org != -1) {
|
if (sect->org != (uint32_t)-1) {
|
||||||
if ((sym_GetPCValue() - offset) % alignSize)
|
if ((sym_GetPCValue() - offset) % alignSize)
|
||||||
error("Section's fixed address fails required alignment (PC = $%04" PRIx32
|
error("Section's fixed address fails required alignment (PC = $%04" PRIx32
|
||||||
")\n", sym_GetPCValue());
|
")\n", sym_GetPCValue());
|
||||||
@@ -472,7 +474,7 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void growSection(uint32_t growth)
|
static void growSection(uint32_t growth)
|
||||||
{
|
{
|
||||||
curOffset += growth;
|
curOffset += growth;
|
||||||
if (curOffset + loadOffset > pCurrentSection->size)
|
if (curOffset + loadOffset > pCurrentSection->size)
|
||||||
@@ -481,19 +483,19 @@ static inline void growSection(uint32_t growth)
|
|||||||
currentLoadSection->size = curOffset;
|
currentLoadSection->size = curOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void writebyte(uint8_t byte)
|
static void writebyte(uint8_t byte)
|
||||||
{
|
{
|
||||||
pCurrentSection->data[sect_GetOutputOffset()] = byte;
|
pCurrentSection->data[sect_GetOutputOffset()] = byte;
|
||||||
growSection(1);
|
growSection(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void writeword(uint16_t b)
|
static void writeword(uint16_t b)
|
||||||
{
|
{
|
||||||
writebyte(b & 0xFF);
|
writebyte(b & 0xFF);
|
||||||
writebyte(b >> 8);
|
writebyte(b >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void writelong(uint32_t b)
|
static void writelong(uint32_t b)
|
||||||
{
|
{
|
||||||
writebyte(b & 0xFF);
|
writebyte(b & 0xFF);
|
||||||
writebyte(b >> 8);
|
writebyte(b >> 8);
|
||||||
@@ -501,8 +503,7 @@ static inline void writelong(uint32_t b)
|
|||||||
writebyte(b >> 24);
|
writebyte(b >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void createPatch(enum PatchType type, struct Expression const *expr,
|
static void createPatch(enum PatchType type, struct Expression const *expr, uint32_t pcShift)
|
||||||
uint32_t pcShift)
|
|
||||||
{
|
{
|
||||||
out_CreatePatch(type, expr, sect_GetOutputOffset(), pcShift);
|
out_CreatePatch(type, expr, sect_GetOutputOffset(), pcShift);
|
||||||
}
|
}
|
||||||
@@ -761,6 +762,8 @@ void out_BinaryFile(char const *s, int32_t startPos)
|
|||||||
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
if (oGeneratedMissingIncludes) {
|
if (oGeneratedMissingIncludes) {
|
||||||
|
if (verbose)
|
||||||
|
printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", s, strerror(errno));
|
||||||
oFailedOnMissingInclude = true;
|
oFailedOnMissingInclude = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -777,8 +780,7 @@ void out_BinaryFile(char const *s, int32_t startPos)
|
|||||||
|
|
||||||
if (startPos > fsize) {
|
if (startPos > fsize) {
|
||||||
error("Specified start position is greater than length of file\n");
|
error("Specified start position is greater than length of file\n");
|
||||||
fclose(f);
|
goto cleanup;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(f, startPos, SEEK_SET);
|
fseek(f, startPos, SEEK_SET);
|
||||||
@@ -801,6 +803,7 @@ void out_BinaryFile(char const *s, int32_t startPos)
|
|||||||
if (ferror(f))
|
if (ferror(f))
|
||||||
error("Error reading INCBIN file '%s': %s\n", s, strerror(errno));
|
error("Error reading INCBIN file '%s': %s\n", s, strerror(errno));
|
||||||
|
|
||||||
|
cleanup:
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -824,14 +827,16 @@ void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
|
|||||||
|
|
||||||
if (fstk_FindFile(s, &fullPath, &size))
|
if (fstk_FindFile(s, &fullPath, &size))
|
||||||
f = fopen(fullPath, "rb");
|
f = fopen(fullPath, "rb");
|
||||||
|
free(fullPath);
|
||||||
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
free(fullPath);
|
|
||||||
if (oGeneratedMissingIncludes) {
|
if (oGeneratedMissingIncludes) {
|
||||||
|
if (verbose)
|
||||||
|
printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", s, strerror(errno));
|
||||||
oFailedOnMissingInclude = true;
|
oFailedOnMissingInclude = true;
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
error("Error opening INCBIN file '%s': %s\n", s, strerror(errno));
|
error("Error opening INCBIN file '%s': %s\n", s, strerror(errno));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -845,13 +850,13 @@ void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
|
|||||||
|
|
||||||
if (start_pos > fsize) {
|
if (start_pos > fsize) {
|
||||||
error("Specified start position is greater than length of file\n");
|
error("Specified start position is greater than length of file\n");
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((start_pos + length) > fsize) {
|
if ((start_pos + length) > fsize) {
|
||||||
error("Specified range in INCBIN is out of bounds (%" PRIu32 " + %" PRIu32
|
error("Specified range in INCBIN is out of bounds (%" PRIu32 " + %" PRIu32
|
||||||
" > %" PRIu32 ")\n", start_pos, length, fsize);
|
" > %" PRIu32 ")\n", start_pos, length, fsize);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(f, start_pos, SEEK_SET);
|
fseek(f, start_pos, SEEK_SET);
|
||||||
@@ -879,8 +884,8 @@ void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
fclose(f);
|
fclose(f);
|
||||||
free(fullPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -43,12 +43,6 @@ static char savedTIME[256];
|
|||||||
static char savedDATE[256];
|
static char savedDATE[256];
|
||||||
static char savedTIMESTAMP_ISO8601_LOCAL[256];
|
static char savedTIMESTAMP_ISO8601_LOCAL[256];
|
||||||
static char savedTIMESTAMP_ISO8601_UTC[256];
|
static char savedTIMESTAMP_ISO8601_UTC[256];
|
||||||
static char savedDAY[3];
|
|
||||||
static char savedMONTH[3];
|
|
||||||
static char savedYEAR[20];
|
|
||||||
static char savedHOUR[3];
|
|
||||||
static char savedMINUTE[3];
|
|
||||||
static char savedSECOND[3];
|
|
||||||
static bool exportall;
|
static bool exportall;
|
||||||
|
|
||||||
bool sym_IsPC(struct Symbol const *sym)
|
bool sym_IsPC(struct Symbol const *sym)
|
||||||
@@ -179,7 +173,7 @@ static void updateSymbolFilename(struct Symbol *sym)
|
|||||||
|
|
||||||
setSymbolFilename(sym);
|
setSymbolFilename(sym);
|
||||||
/* If the old node was referenced, ensure the new one is */
|
/* If the old node was referenced, ensure the new one is */
|
||||||
if (oldSrc && oldSrc->referenced && oldSrc->ID != -1)
|
if (oldSrc && oldSrc->referenced && oldSrc->ID != (uint32_t)-1)
|
||||||
out_RegisterNode(sym->src);
|
out_RegisterNode(sym->src);
|
||||||
/* TODO: unref the old node, and use `out_ReplaceNode` instead if deleting it */
|
/* TODO: unref the old node, and use `out_ReplaceNode` instead if deleting it */
|
||||||
}
|
}
|
||||||
@@ -275,9 +269,9 @@ struct Symbol const *sym_GetPC(void)
|
|||||||
return PCSymbol;
|
return PCSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isReferenced(struct Symbol const *sym)
|
static bool isReferenced(struct Symbol const *sym)
|
||||||
{
|
{
|
||||||
return sym->ID != -1;
|
return sym->ID != (uint32_t)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -315,7 +309,7 @@ uint32_t sym_GetPCValue(void)
|
|||||||
|
|
||||||
if (!sect)
|
if (!sect)
|
||||||
error("PC has no value outside a section\n");
|
error("PC has no value outside a section\n");
|
||||||
else if (sect->org == -1)
|
else if (sect->org == (uint32_t)-1)
|
||||||
error("Expected constant PC but section is not fixed\n");
|
error("Expected constant PC but section is not fixed\n");
|
||||||
else
|
else
|
||||||
return CallbackPC();
|
return CallbackPC();
|
||||||
@@ -379,6 +373,7 @@ static struct Symbol *createNonrelocSymbol(char const *symbolName, bool numeric)
|
|||||||
error("'%s' already defined at ", symbolName);
|
error("'%s' already defined at ", symbolName);
|
||||||
dumpFilename(symbol);
|
dumpFilename(symbol);
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
|
return NULL; // Don't allow overriding the symbol, that'd be bad!
|
||||||
} else if (!numeric) {
|
} else if (!numeric) {
|
||||||
// The symbol has already been referenced, but it's not allowed
|
// The symbol has already been referenced, but it's not allowed
|
||||||
error("'%s' already referenced at ", symbolName);
|
error("'%s' already referenced at ", symbolName);
|
||||||
@@ -439,6 +434,10 @@ struct Symbol *sym_RedefString(char const *symName, char const *value)
|
|||||||
error("'%s' already defined as non-EQUS at ", symName);
|
error("'%s' already defined as non-EQUS at ", symName);
|
||||||
dumpFilename(sym);
|
dumpFilename(sym);
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
|
return NULL;
|
||||||
|
} else if (sym->isBuiltin) {
|
||||||
|
error("Built-in symbol '%s' cannot be redefined\n", symName);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -681,18 +680,7 @@ void sym_SetExportAll(bool set)
|
|||||||
exportall = set;
|
exportall = set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static struct Symbol *createBuiltinSymbol(char const *name)
|
||||||
* Returns a pointer to the first non-zero character in a string
|
|
||||||
* Non-'0', not non-'\0'.
|
|
||||||
*/
|
|
||||||
static inline char const *removeLeadingZeros(char const *ptr)
|
|
||||||
{
|
|
||||||
while (*ptr == '0')
|
|
||||||
ptr++;
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct Symbol *createBuiltinSymbol(char const *name)
|
|
||||||
{
|
{
|
||||||
struct Symbol *sym = createsymbol(name);
|
struct Symbol *sym = createsymbol(name);
|
||||||
|
|
||||||
@@ -722,13 +710,18 @@ void sym_Init(time_t now)
|
|||||||
__LINE__Symbol->numCallback = Callback__LINE__;
|
__LINE__Symbol->numCallback = Callback__LINE__;
|
||||||
__FILE__Symbol->type = SYM_EQUS;
|
__FILE__Symbol->type = SYM_EQUS;
|
||||||
__FILE__Symbol->strCallback = Callback__FILE__;
|
__FILE__Symbol->strCallback = Callback__FILE__;
|
||||||
|
|
||||||
sym_AddSet("_RS", 0)->isBuiltin = true;
|
sym_AddSet("_RS", 0)->isBuiltin = true;
|
||||||
|
|
||||||
sym_AddEqu("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR)->isBuiltin = true;
|
#define addNumber(name, val) sym_AddEqu(name, val)->isBuiltin = true
|
||||||
sym_AddEqu("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR)->isBuiltin = true;
|
#define addString(name, val) sym_AddString(name, val)->isBuiltin = true
|
||||||
sym_AddEqu("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH)->isBuiltin = true;
|
|
||||||
|
addString("__RGBDS_VERSION__", get_package_version_string());
|
||||||
|
addNumber("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR);
|
||||||
|
addNumber("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR);
|
||||||
|
addNumber("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH);
|
||||||
#ifdef PACKAGE_VERSION_RC
|
#ifdef PACKAGE_VERSION_RC
|
||||||
sym_AddEqu("__RGBDS_RC__", PACKAGE_VERSION_RC)->isBuiltin = true;
|
addNumber("__RGBDS_RC__", PACKAGE_VERSION_RC);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (now == (time_t)-1) {
|
if (now == (time_t)-1) {
|
||||||
@@ -750,25 +743,19 @@ void sym_Init(time_t now)
|
|||||||
sizeof(savedTIMESTAMP_ISO8601_UTC), "\"%Y-%m-%dT%H:%M:%SZ\"",
|
sizeof(savedTIMESTAMP_ISO8601_UTC), "\"%Y-%m-%dT%H:%M:%SZ\"",
|
||||||
time_utc);
|
time_utc);
|
||||||
|
|
||||||
strftime(savedYEAR, sizeof(savedYEAR), "%Y", time_utc);
|
|
||||||
strftime(savedMONTH, sizeof(savedMONTH), "%m", time_utc);
|
|
||||||
strftime(savedDAY, sizeof(savedDAY), "%d", time_utc);
|
|
||||||
strftime(savedHOUR, sizeof(savedHOUR), "%H", time_utc);
|
|
||||||
strftime(savedMINUTE, sizeof(savedMINUTE), "%M", time_utc);
|
|
||||||
strftime(savedSECOND, sizeof(savedSECOND), "%S", time_utc);
|
|
||||||
|
|
||||||
#define addString(name, val) sym_AddString(name, val)->isBuiltin = true
|
|
||||||
addString("__TIME__", savedTIME);
|
addString("__TIME__", savedTIME);
|
||||||
addString("__DATE__", savedDATE);
|
addString("__DATE__", savedDATE);
|
||||||
addString("__ISO_8601_LOCAL__", savedTIMESTAMP_ISO8601_LOCAL);
|
addString("__ISO_8601_LOCAL__", savedTIMESTAMP_ISO8601_LOCAL);
|
||||||
addString("__ISO_8601_UTC__", savedTIMESTAMP_ISO8601_UTC);
|
addString("__ISO_8601_UTC__", savedTIMESTAMP_ISO8601_UTC);
|
||||||
/* This cannot start with zeros */
|
|
||||||
addString("__UTC_YEAR__", savedYEAR);
|
addNumber("__UTC_YEAR__", time_utc->tm_year + 1900);
|
||||||
addString("__UTC_MONTH__", removeLeadingZeros(savedMONTH));
|
addNumber("__UTC_MONTH__", time_utc->tm_mon + 1);
|
||||||
addString("__UTC_DAY__", removeLeadingZeros(savedDAY));
|
addNumber("__UTC_DAY__", time_utc->tm_mday);
|
||||||
addString("__UTC_HOUR__", removeLeadingZeros(savedHOUR));
|
addNumber("__UTC_HOUR__", time_utc->tm_hour);
|
||||||
addString("__UTC_MINUTE__", removeLeadingZeros(savedMINUTE));
|
addNumber("__UTC_MINUTE__", time_utc->tm_min);
|
||||||
addString("__UTC_SECOND__", removeLeadingZeros(savedSECOND));
|
addNumber("__UTC_SECOND__", time_utc->tm_sec);
|
||||||
|
|
||||||
|
#undef addNumber
|
||||||
#undef addString
|
#undef addString
|
||||||
|
|
||||||
labelScope = NULL;
|
labelScope = NULL;
|
||||||
|
|||||||
@@ -15,52 +15,45 @@
|
|||||||
|
|
||||||
#include "extern/utf8decoder.h"
|
#include "extern/utf8decoder.h"
|
||||||
|
|
||||||
/*
|
char const *printChar(int c)
|
||||||
* Calculate the hash value for a string.
|
|
||||||
* Uses the djb2 algorithm (xor version).
|
|
||||||
* http://www.cse.yorku.ca/~oz/hash.html
|
|
||||||
*/
|
|
||||||
uint32_t calchash(const char *s)
|
|
||||||
{
|
{
|
||||||
uint32_t hash = 5381;
|
// "'A'" + '\0': 4 bytes
|
||||||
|
// "'\\n'" + '\0': 5 bytes
|
||||||
while (*s != 0)
|
// "0xFF" + '\0': 5 bytes
|
||||||
hash = (hash * 33) ^ (*s++);
|
static char buf[5];
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
char const *print(int c)
|
|
||||||
{
|
|
||||||
static char buf[5]; /* '\xNN' + '\0' */
|
|
||||||
|
|
||||||
if (c == EOF)
|
if (c == EOF)
|
||||||
return "EOF";
|
return "EOF";
|
||||||
|
|
||||||
if (isprint(c)) {
|
if (isprint(c)) {
|
||||||
buf[0] = c;
|
buf[0] = '\'';
|
||||||
buf[1] = '\0';
|
buf[1] = c;
|
||||||
|
buf[2] = '\'';
|
||||||
|
buf[3] = '\0';
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[0] = '\\';
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\n':
|
case '\n':
|
||||||
buf[1] = 'n';
|
buf[2] = 'n';
|
||||||
break;
|
break;
|
||||||
case '\r':
|
case '\r':
|
||||||
buf[1] = 'r';
|
buf[2] = 'r';
|
||||||
break;
|
break;
|
||||||
case '\t':
|
case '\t':
|
||||||
buf[1] = 't';
|
buf[2] = 't';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: /* Print as hex */
|
default: /* Print as hex */
|
||||||
|
buf[0] = '0';
|
||||||
buf[1] = 'x';
|
buf[1] = 'x';
|
||||||
sprintf(&buf[2], "%02hhx", c);
|
snprintf(&buf[2], 3, "%02hhX", (uint8_t)c); // includes the '\0'
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
buf[2] = '\0';
|
buf[0] = '\'';
|
||||||
|
buf[1] = '\\';
|
||||||
|
buf[3] = '\'';
|
||||||
|
buf[4] = '\0';
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ enum WarningState {
|
|||||||
|
|
||||||
static enum WarningState const defaultWarnings[NB_WARNINGS] = {
|
static enum WarningState const defaultWarnings[NB_WARNINGS] = {
|
||||||
[WARNING_ASSERT] = WARNING_ENABLED,
|
[WARNING_ASSERT] = WARNING_ENABLED,
|
||||||
|
[WARNING_BACKWARDS_FOR] = WARNING_DISABLED,
|
||||||
[WARNING_BUILTIN_ARG] = WARNING_DISABLED,
|
[WARNING_BUILTIN_ARG] = WARNING_DISABLED,
|
||||||
[WARNING_CHARMAP_REDEF] = WARNING_DISABLED,
|
[WARNING_CHARMAP_REDEF] = WARNING_DISABLED,
|
||||||
[WARNING_DIV] = WARNING_DISABLED,
|
[WARNING_DIV] = WARNING_DISABLED,
|
||||||
@@ -72,6 +73,7 @@ static enum WarningState warningState(enum WarningID id)
|
|||||||
|
|
||||||
static char const *warningFlags[NB_WARNINGS_ALL] = {
|
static char const *warningFlags[NB_WARNINGS_ALL] = {
|
||||||
"assert",
|
"assert",
|
||||||
|
"backwards-for",
|
||||||
"builtin-args",
|
"builtin-args",
|
||||||
"charmap-redef",
|
"charmap-redef",
|
||||||
"div",
|
"div",
|
||||||
@@ -100,6 +102,7 @@ enum MetaWarningCommand {
|
|||||||
|
|
||||||
/* Warnings that probably indicate an error */
|
/* Warnings that probably indicate an error */
|
||||||
static uint8_t const _wallCommands[] = {
|
static uint8_t const _wallCommands[] = {
|
||||||
|
WARNING_BACKWARDS_FOR,
|
||||||
WARNING_BUILTIN_ARG,
|
WARNING_BUILTIN_ARG,
|
||||||
WARNING_CHARMAP_REDEF,
|
WARNING_CHARMAP_REDEF,
|
||||||
WARNING_EMPTY_DATA_DIRECTIVE,
|
WARNING_EMPTY_DATA_DIRECTIVE,
|
||||||
@@ -119,6 +122,7 @@ static uint8_t const _wextraCommands[] = {
|
|||||||
|
|
||||||
/* Literally everything. Notably useful for testing */
|
/* Literally everything. Notably useful for testing */
|
||||||
static uint8_t const _weverythingCommands[] = {
|
static uint8_t const _weverythingCommands[] = {
|
||||||
|
WARNING_BACKWARDS_FOR,
|
||||||
WARNING_BUILTIN_ARG,
|
WARNING_BUILTIN_ARG,
|
||||||
WARNING_DIV,
|
WARNING_DIV,
|
||||||
WARNING_EMPTY_DATA_DIRECTIVE,
|
WARNING_EMPTY_DATA_DIRECTIVE,
|
||||||
|
|||||||
@@ -870,11 +870,13 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
|||||||
|
|
||||||
// Output ROMX if it was buffered
|
// Output ROMX if it was buffered
|
||||||
if (romx) {
|
if (romx) {
|
||||||
|
// The value returned is either -1, or smaller than `totalRomxLen`,
|
||||||
|
// so it's fine to cast to `size_t`
|
||||||
writeLen = writeBytes(output, romx, totalRomxLen);
|
writeLen = writeBytes(output, romx, totalRomxLen);
|
||||||
if (writeLen == -1) {
|
if (writeLen == -1) {
|
||||||
report("FATAL: Failed to write \"%s\"'s ROMX: %s\n", name, strerror(errno));
|
report("FATAL: Failed to write \"%s\"'s ROMX: %s\n", name, strerror(errno));
|
||||||
goto free_romx;
|
goto free_romx;
|
||||||
} else if (writeLen < totalRomxLen) {
|
} else if ((size_t)writeLen < totalRomxLen) {
|
||||||
report("FATAL: Could only write %ld of \"%s\"'s %ld ROMX bytes\n",
|
report("FATAL: Could only write %ld of \"%s\"'s %ld ROMX bytes\n",
|
||||||
writeLen, name, totalRomxLen);
|
writeLen, name, totalRomxLen);
|
||||||
goto free_romx;
|
goto free_romx;
|
||||||
@@ -898,7 +900,9 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
|||||||
size_t thisLen = len > sizeof(bank) ? sizeof(bank) : len;
|
size_t thisLen = len > sizeof(bank) ? sizeof(bank) : len;
|
||||||
ssize_t ret = writeBytes(output, bank, thisLen);
|
ssize_t ret = writeBytes(output, bank, thisLen);
|
||||||
|
|
||||||
if (ret != thisLen) {
|
// The return value is either -1, or at most `thisLen`,
|
||||||
|
// so it's fine to cast to `size_t`
|
||||||
|
if ((size_t)ret != thisLen) {
|
||||||
report("FATAL: Failed to write \"%s\"'s padding: %s\n",
|
report("FATAL: Failed to write \"%s\"'s padding: %s\n",
|
||||||
name, strerror(errno));
|
name, strerror(errno));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2010-2017, Anthony J. Bentley and RGBDS contributors.
|
.\" Copyright (c) 2010-2021, Anthony J. Bentley and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd December 5, 2019
|
.Dd March 28, 2021
|
||||||
.Dt RGBFIX 1
|
.Dt RGBFIX 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
|||||||
40
src/gbz80.7
40
src/gbz80.7
@@ -1,11 +1,11 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
|
.\" Copyright (c) 2017-2021, Antonio Nino Diaz and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd February 23, 2018
|
.Dd March 28, 2021
|
||||||
.Dt GBZ80 7
|
.Dt GBZ80 7
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -879,9 +879,9 @@ Bytes: 2
|
|||||||
Flags: None affected.
|
Flags: None affected.
|
||||||
.Pp
|
.Pp
|
||||||
This is sometimes written as
|
This is sometimes written as
|
||||||
.Ql ldio [n16], a ,
|
.Ql LDIO [n16],A ,
|
||||||
or
|
or
|
||||||
.Ql ld [$ff00+n8], a .
|
.Ql LD [$FF00+n8],A .
|
||||||
.Ss LDH [C],A
|
.Ss LDH [C],A
|
||||||
Store value in register
|
Store value in register
|
||||||
.Sy A
|
.Sy A
|
||||||
@@ -895,9 +895,9 @@ Bytes: 1
|
|||||||
Flags: None affected.
|
Flags: None affected.
|
||||||
.Pp
|
.Pp
|
||||||
This is sometimes written as
|
This is sometimes written as
|
||||||
.Ql ldio [c], a ,
|
.Ql LDIO [C],A ,
|
||||||
or
|
or
|
||||||
.Ql ld [$ff00+c], a .
|
.Ql LD [$FF00+C],A .
|
||||||
.Ss LD A,[r16]
|
.Ss LD A,[r16]
|
||||||
Load value in register
|
Load value in register
|
||||||
.Sy A
|
.Sy A
|
||||||
@@ -937,9 +937,9 @@ Bytes: 2
|
|||||||
Flags: None affected.
|
Flags: None affected.
|
||||||
.Pp
|
.Pp
|
||||||
This is sometimes written as
|
This is sometimes written as
|
||||||
.Ql ldio a, [n16] ,
|
.Ql LDIO A,[n16] ,
|
||||||
or
|
or
|
||||||
.Ql ld a, [$ff00+n8] .
|
.Ql LD A,[$FF00+n8] .
|
||||||
.Ss LDH A,[C]
|
.Ss LDH A,[C]
|
||||||
Load value in register
|
Load value in register
|
||||||
.Sy A
|
.Sy A
|
||||||
@@ -953,9 +953,9 @@ Bytes: 1
|
|||||||
Flags: None affected.
|
Flags: None affected.
|
||||||
.Pp
|
.Pp
|
||||||
This is sometimes written as
|
This is sometimes written as
|
||||||
.Ql ldio a, [c] ,
|
.Ql LDIO A,[C] ,
|
||||||
or
|
or
|
||||||
.Ql ld a, [$ff00+c] .
|
.Ql LD A,[$FF00+C] .
|
||||||
.Ss LD [HLI],A
|
.Ss LD [HLI],A
|
||||||
Store value in register
|
Store value in register
|
||||||
.Sy A
|
.Sy A
|
||||||
@@ -970,6 +970,11 @@ Cycles: 2
|
|||||||
Bytes: 1
|
Bytes: 1
|
||||||
.Pp
|
.Pp
|
||||||
Flags: None affected.
|
Flags: None affected.
|
||||||
|
.Pp
|
||||||
|
This is sometimes written as
|
||||||
|
.Ql LD [HL+],A ,
|
||||||
|
or
|
||||||
|
.Ql LDI [HL],A .
|
||||||
.Ss LD [HLD],A
|
.Ss LD [HLD],A
|
||||||
Store value in register
|
Store value in register
|
||||||
.Sy A
|
.Sy A
|
||||||
@@ -984,6 +989,11 @@ Cycles: 2
|
|||||||
Bytes: 1
|
Bytes: 1
|
||||||
.Pp
|
.Pp
|
||||||
Flags: None affected.
|
Flags: None affected.
|
||||||
|
.Pp
|
||||||
|
This is sometimes written as
|
||||||
|
.Ql LD [HL-],A ,
|
||||||
|
or
|
||||||
|
.Ql LDD [HL],A .
|
||||||
.Ss LD A,[HLD]
|
.Ss LD A,[HLD]
|
||||||
Load value into register
|
Load value into register
|
||||||
.Sy A
|
.Sy A
|
||||||
@@ -998,6 +1008,11 @@ Cycles: 2
|
|||||||
Bytes: 1
|
Bytes: 1
|
||||||
.Pp
|
.Pp
|
||||||
Flags: None affected.
|
Flags: None affected.
|
||||||
|
.Pp
|
||||||
|
This is sometimes written as
|
||||||
|
.Ql LD A,[HL-] ,
|
||||||
|
or
|
||||||
|
.Ql LDD A,[HL] .
|
||||||
.Ss LD A,[HLI]
|
.Ss LD A,[HLI]
|
||||||
Load value into register
|
Load value into register
|
||||||
.Sy A
|
.Sy A
|
||||||
@@ -1012,6 +1027,11 @@ Cycles: 2
|
|||||||
Bytes: 1
|
Bytes: 1
|
||||||
.Pp
|
.Pp
|
||||||
Flags: None affected.
|
Flags: None affected.
|
||||||
|
.Pp
|
||||||
|
This is sometimes written as
|
||||||
|
.Ql LD A,[HL+], ,
|
||||||
|
or
|
||||||
|
.Ql LDI A,[HL] .
|
||||||
.Ss LD SP,n16
|
.Ss LD SP,n16
|
||||||
Load value
|
Load value
|
||||||
.Ar n16
|
.Ar n16
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2013-2018, stag019 and RGBDS contributors.
|
.\" Copyright (c) 2013-2021, stag019 and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd December 5, 2019
|
.Dd March 28, 2021
|
||||||
.Dt RGBGFX 1
|
.Dt RGBGFX 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -78,7 +78,8 @@ Same as
|
|||||||
.Fl f ,
|
.Fl f ,
|
||||||
but additionally, the supplied command line parameters are saved within the PNG and will be loaded and automatically used next time.
|
but additionally, the supplied command line parameters are saved within the PNG and will be loaded and automatically used next time.
|
||||||
.It Fl h , Fl Fl horizontal
|
.It Fl h , Fl Fl horizontal
|
||||||
Lay out tiles horizontally rather than vertically.
|
Lay out tiles in column-major order (column by column), instead of the default row-major order (line by line).
|
||||||
|
Especially useful for "8x16" OBJ mode, if the input image is 16 pixels tall.
|
||||||
.It Fl m , Fl Fl mirror-tiles
|
.It Fl m , Fl Fl mirror-tiles
|
||||||
Truncate tiles by checking for tiles that are mirrored versions of others and omitting these from the output file.
|
Truncate tiles by checking for tiles that are mirrored versions of others and omitting these from the output file.
|
||||||
Useful with tilemaps and attrmaps together to keep track of the duplicated tiles and the dimension mirrored.
|
Useful with tilemaps and attrmaps together to keep track of the duplicated tiles and the dimension mirrored.
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ static HashType hash(char const *str)
|
|||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hash_AddElement(HashMap map, char const *key, void *element)
|
void **hash_AddElement(HashMap map, char const *key, void *element)
|
||||||
{
|
{
|
||||||
HashType hashedKey = hash(key);
|
HashType hashedKey = hash(key);
|
||||||
HalfHashType index = hashedKey;
|
HalfHashType index = hashedKey;
|
||||||
@@ -61,23 +61,7 @@ bool hash_AddElement(HashMap map, char const *key, void *element)
|
|||||||
newEntry->next = map[index];
|
newEntry->next = map[index];
|
||||||
map[index] = newEntry;
|
map[index] = newEntry;
|
||||||
|
|
||||||
return newEntry->next != NULL;
|
return &newEntry->content;
|
||||||
}
|
|
||||||
|
|
||||||
bool hash_ReplaceElement(HashMap const map, char const *key, void *element)
|
|
||||||
{
|
|
||||||
HashType hashedKey = hash(key);
|
|
||||||
struct HashMapEntry *ptr = map[(HalfHashType)hashedKey];
|
|
||||||
|
|
||||||
while (ptr) {
|
|
||||||
if (hashedKey >> HALF_HASH_NB_BITS == ptr->hash
|
|
||||||
&& !strcmp(ptr->key, key)) {
|
|
||||||
ptr->content = element;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ptr = ptr->next;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hash_RemoveElement(HashMap map, char const *key)
|
bool hash_RemoveElement(HashMap map, char const *key)
|
||||||
@@ -99,7 +83,7 @@ bool hash_RemoveElement(HashMap map, char const *key)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hash_GetElement(HashMap const map, char const *key)
|
void **hash_GetNode(HashMap const map, char const *key)
|
||||||
{
|
{
|
||||||
HashType hashedKey = hash(key);
|
HashType hashedKey = hash(key);
|
||||||
struct HashMapEntry *ptr = map[(HalfHashType)hashedKey];
|
struct HashMapEntry *ptr = map[(HalfHashType)hashedKey];
|
||||||
@@ -107,13 +91,20 @@ void *hash_GetElement(HashMap const map, char const *key)
|
|||||||
while (ptr) {
|
while (ptr) {
|
||||||
if (hashedKey >> HALF_HASH_NB_BITS == ptr->hash
|
if (hashedKey >> HALF_HASH_NB_BITS == ptr->hash
|
||||||
&& !strcmp(ptr->key, key)) {
|
&& !strcmp(ptr->key, key)) {
|
||||||
return ptr->content;
|
return &ptr->content;
|
||||||
}
|
}
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *hash_GetElement(HashMap const map, char const *key)
|
||||||
|
{
|
||||||
|
void **node = hash_GetNode(map, key);
|
||||||
|
|
||||||
|
return node ? *node : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg)
|
void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < HASHMAP_NB_BUCKETS; i++) {
|
for (size_t i = 0; i < HASHMAP_NB_BUCKETS; i++) {
|
||||||
|
|||||||
@@ -106,12 +106,18 @@ static void processLinkerScript(void)
|
|||||||
* @param section The section to assign
|
* @param section The section to assign
|
||||||
* @param location The location to assign the section to
|
* @param location The location to assign the section to
|
||||||
*/
|
*/
|
||||||
static inline void assignSection(struct Section *section,
|
static void assignSection(struct Section *section, struct MemoryLocation const *location)
|
||||||
struct MemoryLocation const *location)
|
|
||||||
{
|
{
|
||||||
section->org = location->address;
|
section->org = location->address;
|
||||||
section->bank = location->bank;
|
section->bank = location->bank;
|
||||||
|
|
||||||
|
// Propagate the assigned location to all UNIONs/FRAGMENTs
|
||||||
|
// so `jr` patches in them will have the correct offset
|
||||||
|
for (struct Section *next = section->nextu; next != NULL; next = next->nextu) {
|
||||||
|
next->org = section->org;
|
||||||
|
next->bank = section->bank;
|
||||||
|
}
|
||||||
|
|
||||||
nbSectionsToAssign--;
|
nbSectionsToAssign--;
|
||||||
|
|
||||||
out_AddSection(section);
|
out_AddSection(section);
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ static void cleanup(void)
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int optionChar;
|
int optionChar;
|
||||||
char *endptr; /* For error checking with `strtol` */
|
char *endptr; /* For error checking with `strtoul` */
|
||||||
unsigned long value; /* For storing `strtoul`'s return value */
|
unsigned long value; /* For storing `strtoul`'s return value */
|
||||||
|
|
||||||
/* Parse options */
|
/* Parse options */
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ static void readFileStackNode(FILE *file, struct FileStackNode fileNodes[], uint
|
|||||||
|
|
||||||
tryReadlong(parentID, file,
|
tryReadlong(parentID, file,
|
||||||
"%s: Cannot read node #%" PRIu32 "'s parent ID: %s", fileName, i);
|
"%s: Cannot read node #%" PRIu32 "'s parent ID: %s", fileName, i);
|
||||||
fileNodes[i].parent = parentID == -1 ? NULL : &fileNodes[parentID];
|
fileNodes[i].parent = parentID == (uint32_t)-1 ? NULL : &fileNodes[parentID];
|
||||||
tryReadlong(fileNodes[i].lineNo, file,
|
tryReadlong(fileNodes[i].lineNo, file,
|
||||||
"%s: Cannot read node #%" PRIu32 "'s line number: %s", fileName, i);
|
"%s: Cannot read node #%" PRIu32 "'s line number: %s", fileName, i);
|
||||||
tryGetc(fileNodes[i].type, file, "%s: Cannot read node #%" PRIu32 "'s type: %s",
|
tryGetc(fileNodes[i].type, file, "%s: Cannot read node #%" PRIu32 "'s type: %s",
|
||||||
@@ -261,7 +261,7 @@ static void readSymbol(FILE *file, struct Symbol *symbol,
|
|||||||
* @param i The number of the patch to report in errors
|
* @param i The number of the patch to report in errors
|
||||||
*/
|
*/
|
||||||
static void readPatch(FILE *file, struct Patch *patch, char const *fileName, char const *sectName,
|
static void readPatch(FILE *file, struct Patch *patch, char const *fileName, char const *sectName,
|
||||||
uint32_t i, struct Section *fileSections[], struct FileStackNode fileNodes[])
|
uint32_t i, struct FileStackNode fileNodes[])
|
||||||
{
|
{
|
||||||
uint32_t nodeID;
|
uint32_t nodeID;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@@ -279,7 +279,6 @@ static void readPatch(FILE *file, struct Patch *patch, char const *fileName, cha
|
|||||||
tryReadlong(patch->pcSectionID, file,
|
tryReadlong(patch->pcSectionID, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s",
|
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s",
|
||||||
fileName, sectName, i);
|
fileName, sectName, i);
|
||||||
patch->pcSection = patch->pcSectionID == -1 ? NULL : fileSections[patch->pcSectionID];
|
|
||||||
tryReadlong(patch->pcOffset, file,
|
tryReadlong(patch->pcOffset, file,
|
||||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s",
|
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s",
|
||||||
fileName, sectName, i);
|
fileName, sectName, i);
|
||||||
@@ -304,6 +303,16 @@ static void readPatch(FILE *file, struct Patch *patch, char const *fileName, cha
|
|||||||
feof(file) ? "Unexpected end of file" : strerror(errno));
|
feof(file) ? "Unexpected end of file" : strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a patch's pcSection from its pcSectionID.
|
||||||
|
* @param patch The struct to fix
|
||||||
|
*/
|
||||||
|
static void linkPatchToPCSect(struct Patch *patch, struct Section *fileSections[])
|
||||||
|
{
|
||||||
|
patch->pcSection = patch->pcSectionID == (uint32_t)-1 ? NULL
|
||||||
|
: fileSections[patch->pcSectionID];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a section from a file.
|
* Reads a section from a file.
|
||||||
* @param file The file to read from
|
* @param file The file to read from
|
||||||
@@ -311,7 +320,7 @@ static void readPatch(FILE *file, struct Patch *patch, char const *fileName, cha
|
|||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
*/
|
*/
|
||||||
static void readSection(FILE *file, struct Section *section, char const *fileName,
|
static void readSection(FILE *file, struct Section *section, char const *fileName,
|
||||||
struct Section *fileSections[], struct FileStackNode fileNodes[])
|
struct FileStackNode fileNodes[])
|
||||||
{
|
{
|
||||||
int32_t tmp;
|
int32_t tmp;
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
@@ -388,12 +397,9 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
|
|||||||
malloc(sizeof(*patches) * section->nbPatches + 1);
|
malloc(sizeof(*patches) * section->nbPatches + 1);
|
||||||
|
|
||||||
if (!patches)
|
if (!patches)
|
||||||
err(1, "%s: Unable to read \"%s\"'s patches", fileName,
|
err(1, "%s: Unable to read \"%s\"'s patches", fileName, section->name);
|
||||||
section->name);
|
for (uint32_t i = 0; i < section->nbPatches; i++)
|
||||||
for (uint32_t i = 0; i < section->nbPatches; i++) {
|
readPatch(file, &patches[i], fileName, section->name, i, fileNodes);
|
||||||
readPatch(file, &patches[i], fileName, section->name,
|
|
||||||
i, fileSections, fileNodes);
|
|
||||||
}
|
|
||||||
section->patches = patches;
|
section->patches = patches;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -435,18 +441,18 @@ static void linkSymToSect(struct Symbol const *symbol, struct Section *section)
|
|||||||
*/
|
*/
|
||||||
static void readAssertion(FILE *file, struct Assertion *assert,
|
static void readAssertion(FILE *file, struct Assertion *assert,
|
||||||
char const *fileName, uint32_t i,
|
char const *fileName, uint32_t i,
|
||||||
struct Section *fileSections[], struct FileStackNode fileNodes[])
|
struct FileStackNode fileNodes[])
|
||||||
{
|
{
|
||||||
char assertName[sizeof("Assertion #4294967295")]; // UINT32_MAX
|
char assertName[sizeof("Assertion #4294967295")]; // UINT32_MAX
|
||||||
|
|
||||||
snprintf(assertName, sizeof(assertName), "Assertion #%" PRIu32, i);
|
snprintf(assertName, sizeof(assertName), "Assertion #%" PRIu32, i);
|
||||||
|
|
||||||
readPatch(file, &assert->patch, fileName, assertName, 0, fileSections, fileNodes);
|
readPatch(file, &assert->patch, fileName, assertName, 0, fileNodes);
|
||||||
tryReadstr(assert->message, file, "%s: Cannot read assertion's message: %s",
|
tryReadstr(assert->message, file, "%s: Cannot read assertion's message: %s",
|
||||||
fileName);
|
fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct Section *getMainSection(struct Section *section)
|
static struct Section *getMainSection(struct Section *section)
|
||||||
{
|
{
|
||||||
if (section->modifier != SECTION_NORMAL)
|
if (section->modifier != SECTION_NORMAL)
|
||||||
section = sect_GetSection(section->name);
|
section = sect_GetSection(section->name);
|
||||||
@@ -549,7 +555,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
err(1, "%s: Couldn't create new section", fileName);
|
err(1, "%s: Couldn't create new section", fileName);
|
||||||
|
|
||||||
fileSections[i]->nextu = NULL;
|
fileSections[i]->nextu = NULL;
|
||||||
readSection(file, fileSections[i], fileName, fileSections, nodes[fileID].nodes);
|
readSection(file, fileSections[i], fileName, nodes[fileID].nodes);
|
||||||
fileSections[i]->fileSymbols = fileSymbols;
|
fileSections[i]->fileSymbols = fileSymbols;
|
||||||
if (nbSymPerSect[i]) {
|
if (nbSymPerSect[i]) {
|
||||||
fileSections[i]->symbols = malloc(nbSymPerSect[i]
|
fileSections[i]->symbols = malloc(nbSymPerSect[i]
|
||||||
@@ -567,7 +573,15 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
|
|
||||||
free(nbSymPerSect);
|
free(nbSymPerSect);
|
||||||
|
|
||||||
/* Give symbols pointers to their sections */
|
/* Give patches' PC section pointers to their sections */
|
||||||
|
for (uint32_t i = 0; i < nbSections; i++) {
|
||||||
|
if (sect_HasData(fileSections[i]->type)) {
|
||||||
|
for (uint32_t j = 0; j < fileSections[i]->nbPatches; j++)
|
||||||
|
linkPatchToPCSect(&fileSections[i]->patches[j], fileSections);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Give symbols' section pointers to their sections */
|
||||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||||
int32_t sectionID = fileSymbols[i]->sectionID;
|
int32_t sectionID = fileSymbols[i]->sectionID;
|
||||||
|
|
||||||
@@ -599,7 +613,8 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
|
|
||||||
if (!assertion)
|
if (!assertion)
|
||||||
err(1, "%s: Couldn't create new assertion", fileName);
|
err(1, "%s: Couldn't create new assertion", fileName);
|
||||||
readAssertion(file, assertion, fileName, i, fileSections, nodes[fileID].nodes);
|
readAssertion(file, assertion, fileName, i, nodes[fileID].nodes);
|
||||||
|
linkPatchToPCSect(&assertion->patch, fileSections);
|
||||||
assertion->fileSymbols = fileSymbols;
|
assertion->fileSymbols = fileSymbols;
|
||||||
assertion->next = assertions;
|
assertion->next = assertions;
|
||||||
assertions = assertion;
|
assertions = assertion;
|
||||||
@@ -635,7 +650,7 @@ static void freeSection(struct Section *section, void *arg)
|
|||||||
free(section->name);
|
free(section->name);
|
||||||
if (sect_HasData(section->type)) {
|
if (sect_HasData(section->type)) {
|
||||||
free(section->data);
|
free(section->data);
|
||||||
for (int32_t i = 0; i < section->nbPatches; i++)
|
for (uint32_t i = 0; i < section->nbPatches; i++)
|
||||||
free(section->patches[i].rpnExpression);
|
free(section->patches[i].rpnExpression);
|
||||||
free(section->patches);
|
free(section->patches);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ static void writeSymBank(struct SortedSections const *bankSections)
|
|||||||
/**
|
/**
|
||||||
* Write a bank's contents to the map file
|
* Write a bank's contents to the map file
|
||||||
* @param bankSections The bank's sections
|
* @param bankSections The bank's sections
|
||||||
* @return The bank's slack space
|
* @return The bank's used space
|
||||||
*/
|
*/
|
||||||
static uint16_t writeMapBank(struct SortedSections const *sectList,
|
static uint16_t writeMapBank(struct SortedSections const *sectList,
|
||||||
enum SectionType type, uint32_t bank)
|
enum SectionType type, uint32_t bank)
|
||||||
@@ -350,14 +350,14 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
|||||||
fprintf(mapFile, "%s bank #%" PRIu32 ":\n", typeNames[type],
|
fprintf(mapFile, "%s bank #%" PRIu32 ":\n", typeNames[type],
|
||||||
bank + bankranges[type][0]);
|
bank + bankranges[type][0]);
|
||||||
|
|
||||||
uint16_t slack = maxsize[type];
|
uint16_t used = 0;
|
||||||
|
|
||||||
while (section || zeroLenSection) {
|
while (section || zeroLenSection) {
|
||||||
struct SortedSection const **pickedSection =
|
struct SortedSection const **pickedSection =
|
||||||
nextSection(§ion, &zeroLenSection);
|
nextSection(§ion, &zeroLenSection);
|
||||||
struct Section const *sect = (*pickedSection)->section;
|
struct Section const *sect = (*pickedSection)->section;
|
||||||
|
|
||||||
slack -= sect->size;
|
used += sect->size;
|
||||||
|
|
||||||
if (sect->size != 0)
|
if (sect->size != 0)
|
||||||
fprintf(mapFile, " SECTION: $%04" PRIx16 "-$%04" PRIx16 " ($%04" PRIx16 " byte%s) [\"%s\"]\n",
|
fprintf(mapFile, " SECTION: $%04" PRIx16 "-$%04" PRIx16 " ($%04" PRIx16 " byte%s) [\"%s\"]\n",
|
||||||
@@ -368,44 +368,54 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
|||||||
fprintf(mapFile, " SECTION: $%04" PRIx16 " (0 bytes) [\"%s\"]\n",
|
fprintf(mapFile, " SECTION: $%04" PRIx16 " (0 bytes) [\"%s\"]\n",
|
||||||
sect->org, sect->name);
|
sect->org, sect->name);
|
||||||
|
|
||||||
|
uint16_t org = sect->org;
|
||||||
|
|
||||||
|
while (sect) {
|
||||||
for (size_t i = 0; i < sect->nbSymbols; i++)
|
for (size_t i = 0; i < sect->nbSymbols; i++)
|
||||||
fprintf(mapFile, " $%04" PRIx32 " = %s\n",
|
fprintf(mapFile, " $%04" PRIx32 " = %s\n",
|
||||||
sect->symbols[i]->offset + sect->org,
|
sect->symbols[i]->offset + org,
|
||||||
sect->symbols[i]->name);
|
sect->symbols[i]->name);
|
||||||
|
|
||||||
|
sect = sect->nextu; // Also print symbols in the following "pieces"
|
||||||
|
}
|
||||||
|
|
||||||
*pickedSection = (*pickedSection)->next;
|
*pickedSection = (*pickedSection)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slack == maxsize[type])
|
|
||||||
|
if (used == 0) {
|
||||||
fputs(" EMPTY\n\n", mapFile);
|
fputs(" EMPTY\n\n", mapFile);
|
||||||
else
|
} else {
|
||||||
|
uint16_t slack = maxsize[type] - used;
|
||||||
|
|
||||||
fprintf(mapFile, " SLACK: $%04" PRIx16 " byte%s\n\n", slack,
|
fprintf(mapFile, " SLACK: $%04" PRIx16 " byte%s\n\n", slack,
|
||||||
slack == 1 ? "" : "s");
|
slack == 1 ? "" : "s");
|
||||||
|
}
|
||||||
|
|
||||||
return slack;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the total slack space by section type to the map file
|
* Write the total used space by section type to the map file
|
||||||
* @param slackMap The total slack space by section type
|
* @param usedMap The total used space by section type
|
||||||
*/
|
*/
|
||||||
static void writeMapSlack(uint32_t slackMap[MIN_NB_ELMS(SECTTYPE_INVALID)])
|
static void writeMapUsed(uint32_t usedMap[MIN_NB_ELMS(SECTTYPE_INVALID)])
|
||||||
{
|
{
|
||||||
if (!mapFile)
|
if (!mapFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fputs("FREE:\n", mapFile);
|
fputs("USED:\n", mapFile);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < SECTTYPE_INVALID; i++) {
|
for (uint8_t i = 0; i < SECTTYPE_INVALID; i++) {
|
||||||
enum SectionType type = typeMap[i];
|
enum SectionType type = typeMap[i];
|
||||||
|
|
||||||
// Do not output slack space for VRAM or OAM
|
// Do not output used space for VRAM or OAM
|
||||||
if (type == SECTTYPE_VRAM || type == SECTTYPE_OAM)
|
if (type == SECTTYPE_VRAM || type == SECTTYPE_OAM)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sections[type].nbBanks > 0) {
|
if (sections[type].nbBanks > 0) {
|
||||||
fprintf(mapFile, " %s: $%04" PRIx32 " byte%s in %" PRIu32 " bank%s\n",
|
fprintf(mapFile, " %s: $%04" PRIx32 " byte%s in %" PRIu32 " bank%s\n",
|
||||||
typeNames[type], slackMap[type], slackMap[type] == 1 ? "" : "s",
|
typeNames[type], usedMap[type], usedMap[type] == 1 ? "" : "s",
|
||||||
sections[type].nbBanks, sections[type].nbBanks == 1 ? "" : "s");
|
sections[type].nbBanks, sections[type].nbBanks == 1 ? "" : "s");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -419,7 +429,7 @@ static void writeSymAndMap(void)
|
|||||||
if (!symFileName && !mapFileName)
|
if (!symFileName && !mapFileName)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t slackMap[SECTTYPE_INVALID] = {0};
|
uint32_t usedMap[SECTTYPE_INVALID] = {0};
|
||||||
|
|
||||||
symFile = openFile(symFileName, "w");
|
symFile = openFile(symFileName, "w");
|
||||||
mapFile = openFile(mapFileName, "w");
|
mapFile = openFile(mapFileName, "w");
|
||||||
@@ -434,11 +444,11 @@ static void writeSymAndMap(void)
|
|||||||
struct SortedSections const *sect = §ions[type].banks[bank];
|
struct SortedSections const *sect = §ions[type].banks[bank];
|
||||||
|
|
||||||
writeSymBank(sect);
|
writeSymBank(sect);
|
||||||
slackMap[type] += writeMapBank(sect, type, bank);
|
usedMap[type] += writeMapBank(sect, type, bank);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeMapSlack(slackMap);
|
writeMapUsed(usedMap);
|
||||||
|
|
||||||
closeFile(symFile);
|
closeFile(symFile);
|
||||||
closeFile(mapFile);
|
closeFile(mapFile);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ struct RPNStack {
|
|||||||
size_t capacity;
|
size_t capacity;
|
||||||
} stack;
|
} stack;
|
||||||
|
|
||||||
static inline void initRPNStack(void)
|
static void initRPNStack(void)
|
||||||
{
|
{
|
||||||
stack.capacity = 64;
|
stack.capacity = 64;
|
||||||
stack.values = malloc(sizeof(*stack.values) * stack.capacity);
|
stack.values = malloc(sizeof(*stack.values) * stack.capacity);
|
||||||
@@ -46,7 +46,7 @@ static inline void initRPNStack(void)
|
|||||||
err(1, "Failed to init RPN stack");
|
err(1, "Failed to init RPN stack");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void clearRPNStack(void)
|
static void clearRPNStack(void)
|
||||||
{
|
{
|
||||||
stack.size = 0;
|
stack.size = 0;
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ static int32_t popRPN(struct FileStackNode const *node, uint32_t lineNo)
|
|||||||
return stack.values[stack.size];
|
return stack.values[stack.size];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void freeRPNStack(void)
|
static void freeRPNStack(void)
|
||||||
{
|
{
|
||||||
free(stack.values);
|
free(stack.values);
|
||||||
free(stack.errorFlags);
|
free(stack.errorFlags);
|
||||||
@@ -400,7 +400,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
|
|
||||||
void patch_CheckAssertions(struct Assertion *assert)
|
void patch_CheckAssertions(struct Assertion *assert)
|
||||||
{
|
{
|
||||||
verbosePrint("Checking assertions...");
|
verbosePrint("Checking assertions...\n");
|
||||||
initRPNStack();
|
initRPNStack();
|
||||||
|
|
||||||
while (assert) {
|
while (assert) {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2010-2019, Anthony J. Bentley and RGBDS contributors.
|
.\" Copyright (c) 2010-2021, Anthony J. Bentley and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd November 26, 2019
|
.Dd March 28, 2021
|
||||||
.Dt RGBLINK 1
|
.Dt RGBLINK 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
|
.\" Copyright (c) 2017-2021, Antonio Nino Diaz and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd November 26, 2019
|
.Dd March 28, 2021
|
||||||
.Dt RGBLINK 5
|
.Dt RGBLINK 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
|||||||
@@ -78,12 +78,12 @@ static bool popFile(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isWhiteSpace(int c)
|
static bool isWhiteSpace(int c)
|
||||||
{
|
{
|
||||||
return c == ' ' || c == '\t';
|
return c == ' ' || c == '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isNewline(int c)
|
static bool isNewline(int c)
|
||||||
{
|
{
|
||||||
return c == '\r' || c == '\n';
|
return c == '\r' || c == '\n';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,11 +194,7 @@ void sect_AddSection(struct Section *section)
|
|||||||
section->name, typeNames[section->type]);
|
section->name, typeNames[section->type]);
|
||||||
} else {
|
} else {
|
||||||
/* If not, add it */
|
/* If not, add it */
|
||||||
bool collided = hash_AddElement(sections, section->name,
|
hash_AddElement(sections, section->name, section);
|
||||||
section);
|
|
||||||
|
|
||||||
if (beVerbose && collided)
|
|
||||||
warnx("Section hashmap collision occurred!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +244,7 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
|||||||
* Check if alignment is reasonable, this is important to avoid UB
|
* Check if alignment is reasonable, this is important to avoid UB
|
||||||
* An alignment of zero is equivalent to no alignment, basically
|
* An alignment of zero is equivalent to no alignment, basically
|
||||||
*/
|
*/
|
||||||
if (section->isAlignFixed && section->alignMask == 1)
|
if (section->isAlignFixed && section->alignMask == 0)
|
||||||
section->isAlignFixed = false;
|
section->isAlignFixed = false;
|
||||||
|
|
||||||
/* Too large an alignment may not be satisfiable */
|
/* Too large an alignment may not be satisfiable */
|
||||||
|
|||||||
@@ -54,10 +54,7 @@ void sym_AddSymbol(struct Symbol *symbol)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If not, add it */
|
/* If not, add it */
|
||||||
bool collided = hash_AddElement(symbols, symbol->name, symbol);
|
hash_AddElement(symbols, symbol->name, symbol);
|
||||||
|
|
||||||
if (beVerbose && collided)
|
|
||||||
warnx("Symbol hashmap collision occurred!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol *sym_GetSymbol(char const *name)
|
struct Symbol *sym_GetSymbol(char const *name)
|
||||||
|
|||||||
10
src/rgbds.5
10
src/rgbds.5
@@ -1,11 +1,11 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2017-2020, Antonio Nino Diaz and RGBDS contributors.
|
.\" Copyright (c) 2017-2021, Antonio Nino Diaz and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 26, 2018
|
.Dd March 28, 2021
|
||||||
.Dt RGBDS 5
|
.Dt RGBDS 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -22,11 +22,11 @@ This toolchain is in development and new features may require adding more inform
|
|||||||
The following types are used:
|
The following types are used:
|
||||||
.Pp
|
.Pp
|
||||||
.Ar LONG
|
.Ar LONG
|
||||||
is a 32‐bit integer stored in little‐endian format.
|
is a 32-bit integer stored in little-endian format.
|
||||||
.Ar BYTE
|
.Ar BYTE
|
||||||
is an 8‐bit integer.
|
is an 8-bit integer.
|
||||||
.Ar STRING
|
.Ar STRING
|
||||||
is a 0‐terminated string of
|
is a 0-terminated string of
|
||||||
.Ar BYTE .
|
.Ar BYTE .
|
||||||
.Bd -literal
|
.Bd -literal
|
||||||
; Header
|
; Header
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2010-2018, Anthony J. Bentley and RGBDS contributors.
|
.\" Copyright (c) 2010-2021, Anthony J. Bentley and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd March 7, 2018
|
.Dd March 28, 2021
|
||||||
.Dt RGBDS 7
|
.Dt RGBDS 7
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: align-large-ofs.asm(2):
|
ERROR: align-large-ofs.asm(2):
|
||||||
Alignment offset (2) must be smaller than alignment size (2)
|
Alignment offset (2) must be smaller than alignment size (2)
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
3
test/asm/align-unattainable.asm
Normal file
3
test/asm/align-unattainable.asm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
SECTION UNION "X", WRAM0
|
||||||
|
|
||||||
|
SECTION UNION "X", WRAM0, ALIGN[16]
|
||||||
3
test/asm/align-unattainable.err
Normal file
3
test/asm/align-unattainable.err
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ERROR: align-unattainable.asm(3):
|
||||||
|
Section "X"'s alignment cannot be attained in WRAM0
|
||||||
|
error: Assembly aborted (1 error)!
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: assert-nosect-bank.asm(1):
|
ERROR: assert-nosect-bank.asm(1):
|
||||||
PC has no bank outside a section
|
PC has no bank outside a section
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: assert@-no-sect.asm(1):
|
ERROR: assert@-no-sect.asm(1):
|
||||||
PC has no value outside a section
|
PC has no value outside a section
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
43
test/asm/builtin-overwrite.asm
Normal file
43
test/asm/builtin-overwrite.asm
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
macro tickle
|
||||||
|
; There once was a bug where overwriting worked only on the second try, so
|
||||||
|
; try everything twice for good measure
|
||||||
|
|
||||||
|
; Skip this syntax for EQUS, as it is invalid
|
||||||
|
IF \2
|
||||||
|
\1 = 0
|
||||||
|
\1 = 0
|
||||||
|
PRINTLN \1
|
||||||
|
|
||||||
|
\1 EQU 0
|
||||||
|
\1 EQU 0
|
||||||
|
PRINTLN \1
|
||||||
|
ENDC
|
||||||
|
|
||||||
|
PURGE \1
|
||||||
|
PURGE \1
|
||||||
|
PRINTLN \1
|
||||||
|
|
||||||
|
DEF \1 EQU 0
|
||||||
|
DEF \1 EQU 0
|
||||||
|
PRINTLN \1
|
||||||
|
|
||||||
|
DEF \1 = 0
|
||||||
|
DEF \1 = 0
|
||||||
|
PRINTLN \1
|
||||||
|
|
||||||
|
DEF \1 EQUS "hello"
|
||||||
|
DEF \1 EQUS "hello"
|
||||||
|
PRINTLN \1
|
||||||
|
|
||||||
|
REDEF \1 = 0
|
||||||
|
REDEF \1 = 0
|
||||||
|
PRINTLN \1
|
||||||
|
|
||||||
|
REDEF \1 EQUS "hello"
|
||||||
|
REDEF \1 EQUS "hello"
|
||||||
|
PRINTLN \1
|
||||||
|
endm
|
||||||
|
|
||||||
|
; Representative numeric and string builtins
|
||||||
|
tickle __LINE__, 1
|
||||||
|
tickle __FILE__, 0
|
||||||
57
test/asm/builtin-overwrite.err
Normal file
57
test/asm/builtin-overwrite.err
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(7):
|
||||||
|
'__LINE__' already defined as constant at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(8):
|
||||||
|
'__LINE__' already defined as constant at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(11):
|
||||||
|
'__LINE__' already defined at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(12):
|
||||||
|
'__LINE__' already defined at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(16):
|
||||||
|
Built-in symbol '__LINE__' cannot be purged
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(17):
|
||||||
|
Built-in symbol '__LINE__' cannot be purged
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(20):
|
||||||
|
'__LINE__' already defined at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(21):
|
||||||
|
'__LINE__' already defined at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(24):
|
||||||
|
'__LINE__' already defined as constant at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(25):
|
||||||
|
'__LINE__' already defined as constant at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(28):
|
||||||
|
'__LINE__' already defined at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(29):
|
||||||
|
'__LINE__' already defined at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(32):
|
||||||
|
'__LINE__' already defined as constant at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(33):
|
||||||
|
'__LINE__' already defined as constant at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(36):
|
||||||
|
'__LINE__' already defined as non-EQUS at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(37):
|
||||||
|
'__LINE__' already defined as non-EQUS at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(16):
|
||||||
|
Built-in symbol '__FILE__' cannot be purged
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(17):
|
||||||
|
Built-in symbol '__FILE__' cannot be purged
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(20):
|
||||||
|
'__FILE__' already defined at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(21):
|
||||||
|
'__FILE__' already defined at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(24):
|
||||||
|
'__FILE__' already defined as constant at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(25):
|
||||||
|
'__FILE__' already defined as constant at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(28):
|
||||||
|
'__FILE__' already defined at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(29):
|
||||||
|
'__FILE__' already defined at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(32):
|
||||||
|
'__FILE__' already defined as constant at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(33):
|
||||||
|
'__FILE__' already defined as constant at <builtin>
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(36):
|
||||||
|
Built-in symbol '__FILE__' cannot be redefined
|
||||||
|
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(37):
|
||||||
|
Built-in symbol '__FILE__' cannot be redefined
|
||||||
|
error: Assembly aborted (28 errors)!
|
||||||
14
test/asm/builtin-overwrite.out
Normal file
14
test/asm/builtin-overwrite.out
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
$9
|
||||||
|
$D
|
||||||
|
$12
|
||||||
|
$16
|
||||||
|
$1A
|
||||||
|
$1E
|
||||||
|
$22
|
||||||
|
$26
|
||||||
|
builtin-overwrite.asm
|
||||||
|
builtin-overwrite.asm
|
||||||
|
builtin-overwrite.asm
|
||||||
|
builtin-overwrite.asm
|
||||||
|
builtin-overwrite.asm
|
||||||
|
builtin-overwrite.asm
|
||||||
29
test/asm/def.asm
Normal file
29
test/asm/def.asm
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
def variable = 1
|
||||||
|
println variable
|
||||||
|
def variable set 2
|
||||||
|
println variable
|
||||||
|
redef variable = 3
|
||||||
|
println variable
|
||||||
|
redef variable set 4
|
||||||
|
println variable
|
||||||
|
|
||||||
|
DEF constant EQU 42
|
||||||
|
println constant
|
||||||
|
|
||||||
|
DEF string EQUS "here"
|
||||||
|
println "{string}"
|
||||||
|
|
||||||
|
rsreset
|
||||||
|
def _x rb
|
||||||
|
def _y rw 2
|
||||||
|
def _z rl
|
||||||
|
def _size rb 0
|
||||||
|
println "{_x} {_y} {_z} {_size}"
|
||||||
|
|
||||||
|
def constant equ 6*7 ; fails
|
||||||
|
println constant
|
||||||
|
|
||||||
|
redef string equs "there"
|
||||||
|
println "{string}"
|
||||||
|
|
||||||
|
redef constant equ 6*9 ; syntax error
|
||||||
5
test/asm/def.err
Normal file
5
test/asm/def.err
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
ERROR: def.asm(23):
|
||||||
|
'constant' already defined at def.asm(10)
|
||||||
|
ERROR: def.asm(29):
|
||||||
|
syntax error, unexpected EQU, expecting SET or = or EQUS
|
||||||
|
error: Assembly aborted (2 errors)!
|
||||||
9
test/asm/def.out
Normal file
9
test/asm/def.out
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
$1
|
||||||
|
$2
|
||||||
|
$3
|
||||||
|
$4
|
||||||
|
$2A
|
||||||
|
here
|
||||||
|
$0 $1 $5 $9
|
||||||
|
$2A
|
||||||
|
there
|
||||||
5
test/asm/def.simple.err
Normal file
5
test/asm/def.simple.err
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
ERROR: def.asm(23):
|
||||||
|
'constant' already defined at def.asm(10)
|
||||||
|
ERROR: def.asm(29):
|
||||||
|
syntax error
|
||||||
|
error: Assembly aborted (2 errors)!
|
||||||
@@ -2,4 +2,4 @@ warning: deprecated-pi.asm(2): [-Wobsolete]
|
|||||||
`_PI` is deprecated; use 3.14159
|
`_PI` is deprecated; use 3.14159
|
||||||
ERROR: deprecated-pi.asm(3):
|
ERROR: deprecated-pi.asm(3):
|
||||||
Built-in symbol '_PI' cannot be purged
|
Built-in symbol '_PI' cannot be purged
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,36 +1,62 @@
|
|||||||
_ASM equ 0
|
def _ASM equ 0
|
||||||
|
|
||||||
test: MACRO
|
test: MACRO
|
||||||
; Test RGBASM
|
; Test RGBASM
|
||||||
V equs "_ASM +"
|
redef V equs "_ASM +"
|
||||||
static_assert \#
|
static_assert \#
|
||||||
PURGE V
|
; Test RGBLINK
|
||||||
; Test RGBLINK
|
redef V equs "_LINK +"
|
||||||
V equs "_LINK +"
|
|
||||||
assert \#
|
assert \#
|
||||||
PURGE V
|
|
||||||
ENDM
|
ENDM
|
||||||
|
|
||||||
for x, -300, 301
|
test_mod: MACRO
|
||||||
for y, -x - 1, x + 2
|
def x = \1 ; dividend
|
||||||
if y != 0
|
def y = \2 ; divisor
|
||||||
q = x / y
|
shift 2
|
||||||
r = x % y
|
def q = x / y ; quotient
|
||||||
|
def r = x % y ; remainder
|
||||||
|
; identity laws
|
||||||
test (V (q * y + r)) == (V x)
|
test (V (q * y + r)) == (V x)
|
||||||
test (V (x + y) % y) == (V r)
|
test (V (x + y) % y) == (V r)
|
||||||
test (V (x - y) % y) == (V r)
|
test (V (x - y) % y) == (V r)
|
||||||
endc
|
ENDM
|
||||||
endr
|
|
||||||
endr
|
|
||||||
|
|
||||||
for x, -300, 301
|
test_each_mod: MACRO
|
||||||
for p, 31
|
test_mod (\1), (\2)
|
||||||
y = 2 ** p
|
test_mod (\1), -(\2)
|
||||||
r = x % y
|
test_mod -(\1), (\2)
|
||||||
m = x & (y - 1)
|
test_mod -(\1), -(\2)
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
test_pow: MACRO
|
||||||
|
def x = \1 ; dividend
|
||||||
|
def y = 2 ** \2 ; divisor
|
||||||
|
def r = x % y ; remainder
|
||||||
|
def m = x & (y - 1) ; mask
|
||||||
|
; identity law
|
||||||
test (V r) == (V m)
|
test (V r) == (V m)
|
||||||
endr
|
ENDM
|
||||||
endr
|
|
||||||
|
test_each_pow: MACRO
|
||||||
|
test_pow (\1), (\2)
|
||||||
|
test_pow -(\1), (\2)
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
test_each_mod 0, 1
|
||||||
|
test_each_mod 7, 5
|
||||||
|
test_each_mod 42, 256
|
||||||
|
test_each_mod 567, 256
|
||||||
|
test_each_mod 256, 512
|
||||||
|
test_each_mod 1, 65535
|
||||||
|
test_each_mod 100, 65535
|
||||||
|
test_each_mod 10000, 65535
|
||||||
|
test_each_mod 1000000, 65535
|
||||||
|
|
||||||
|
test_each_pow 5, 1
|
||||||
|
test_each_pow 42, 8
|
||||||
|
test_each_pow 567, 8
|
||||||
|
test_each_pow 12345, 16
|
||||||
|
test_each_pow 99999, 16
|
||||||
|
|
||||||
SECTION "LINK", ROM0
|
SECTION "LINK", ROM0
|
||||||
_LINK::
|
_LINK::
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ ERROR: ds-bad.asm(3):
|
|||||||
Expected constant expression: 'unknown' is not constant at assembly time
|
Expected constant expression: 'unknown' is not constant at assembly time
|
||||||
warning: ds-bad.asm(4): [-Wtruncation]
|
warning: ds-bad.asm(4): [-Wtruncation]
|
||||||
Expression must be 8-bit
|
Expression must be 8-bit
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
23
test/asm/elif-after-taken-if.asm
Normal file
23
test/asm/elif-after-taken-if.asm
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
if 1
|
||||||
|
println "taken if"
|
||||||
|
elif 2 / 0 ; avoided fatal "Division by zero" error
|
||||||
|
println "untaken elif"
|
||||||
|
elif 3 / 0 ; avoided fatal "Division by zero" error
|
||||||
|
println "untaken after untaken"
|
||||||
|
endc
|
||||||
|
|
||||||
|
if 0
|
||||||
|
println "untaken if"
|
||||||
|
elif 1
|
||||||
|
println "taken elif"
|
||||||
|
elif !@#$ ; avoided fatal syntax error
|
||||||
|
println "untaken elif"
|
||||||
|
elif %^&* ; avoided fatal syntax error
|
||||||
|
println "untaken after untaken"
|
||||||
|
endc
|
||||||
|
|
||||||
|
if 0
|
||||||
|
println "untaken if"
|
||||||
|
elif 1 / 0 ; fatal "Division by zero" error
|
||||||
|
println "unreached elif"
|
||||||
|
endc
|
||||||
2
test/asm/elif-after-taken-if.err
Normal file
2
test/asm/elif-after-taken-if.err
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
FATAL: elif-after-taken-if.asm(21):
|
||||||
|
Division by zero
|
||||||
2
test/asm/elif-after-taken-if.out
Normal file
2
test/asm/elif-after-taken-if.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
taken if
|
||||||
|
taken elif
|
||||||
@@ -3,5 +3,6 @@ warning: equs-newline.asm(3): [-Wuser]
|
|||||||
while expanding symbol "ACT"
|
while expanding symbol "ACT"
|
||||||
warning: equs-newline.asm(3): [-Wuser]
|
warning: equs-newline.asm(3): [-Wuser]
|
||||||
Second
|
Second
|
||||||
|
while expanding symbol "ACT"
|
||||||
warning: equs-newline.asm(4): [-Wuser]
|
warning: equs-newline.asm(4): [-Wuser]
|
||||||
Third
|
Third
|
||||||
|
|||||||
@@ -1,6 +1,2 @@
|
|||||||
recurse EQUS "recurse "
|
recurse EQUS "recurse"
|
||||||
recurse
|
recurse
|
||||||
|
|
||||||
; FIXME: also handle the following:
|
|
||||||
; recurse EQUS "recurse"
|
|
||||||
; recurse
|
|
||||||
|
|||||||
6
test/asm/expand-empty-string.asm
Normal file
6
test/asm/expand-empty-string.asm
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
test: MACRO
|
||||||
|
v equs "X"
|
||||||
|
X equs "" ; should not be expanded
|
||||||
|
\1
|
||||||
|
ENDM
|
||||||
|
test v 0
|
||||||
3
test/asm/expand-empty-string.err
Normal file
3
test/asm/expand-empty-string.err
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ERROR: expand-empty-string.asm(6) -> expand-empty-string.asm::test(4):
|
||||||
|
syntax error, unexpected number
|
||||||
|
error: Assembly aborted (1 error)!
|
||||||
0
test/asm/expand-empty-string.out
Normal file
0
test/asm/expand-empty-string.out
Normal file
3
test/asm/expand-empty-string.simple.err
Normal file
3
test/asm/expand-empty-string.simple.err
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ERROR: expand-empty-string.asm(6) -> expand-empty-string.asm::test(4):
|
||||||
|
syntax error
|
||||||
|
error: Assembly aborted (1 error)!
|
||||||
5
test/asm/ff00-plus-c.asm
Normal file
5
test/asm/ff00-plus-c.asm
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
SECTION "test", ROM0[0]
|
||||||
|
ld [ $ff00 + c ], a
|
||||||
|
; 257 spaces exceeds both LEXER_BUF_SIZE (42) and uint8_t limit (255)
|
||||||
|
ld [ $ff00 + c ], a
|
||||||
|
ld [ $ff00 + c ], a
|
||||||
0
test/asm/ff00-plus-c.err
Normal file
0
test/asm/ff00-plus-c.err
Normal file
0
test/asm/ff00-plus-c.out
Normal file
0
test/asm/ff00-plus-c.out
Normal file
1
test/asm/ff00-plus-c.out.bin
Normal file
1
test/asm/ff00-plus-c.out.bin
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<EFBFBD><EFBFBD><EFBFBD>
|
||||||
@@ -8,13 +8,17 @@ for v, 0
|
|||||||
endr
|
endr
|
||||||
|
|
||||||
for v, 2, 1
|
for v, 2, 1
|
||||||
print "unreached"
|
print "backwards"
|
||||||
endr
|
endr
|
||||||
|
|
||||||
for v, 1, 2, 0
|
for v, 1, 2, 0
|
||||||
print "unreached"
|
print "unreached"
|
||||||
endr
|
endr
|
||||||
|
|
||||||
|
for v, 1, 2, -1
|
||||||
|
print "backwards"
|
||||||
|
endr
|
||||||
|
|
||||||
for x, 1, 5+1
|
for x, 1, 5+1
|
||||||
print "{d:x} "
|
print "{d:x} "
|
||||||
endr
|
endr
|
||||||
@@ -33,7 +37,7 @@ endr
|
|||||||
println "-> {d:q}"
|
println "-> {d:q}"
|
||||||
|
|
||||||
s EQUS "x"
|
s EQUS "x"
|
||||||
for s, 3, 30, 3
|
for {s}, 3, 30, 3
|
||||||
print "{d:x} "
|
print "{d:x} "
|
||||||
endr
|
endr
|
||||||
println "-> {d:x}"
|
println "-> {d:x}"
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
warning: for.asm(12): [-Wbackwards-for]
|
||||||
|
FOR goes backwards from 2 to 1 by 1
|
||||||
ERROR: for.asm(16):
|
ERROR: for.asm(16):
|
||||||
FOR cannot have a step value of 0
|
FOR cannot have a step value of 0
|
||||||
ERROR: for.asm(41) -> for.asm::REPT~4(47):
|
warning: for.asm(20): [-Wbackwards-for]
|
||||||
'v' already defined as constant at for.asm(41) -> for.asm::REPT~4(45)
|
FOR goes backwards from 1 to 2 by -1
|
||||||
FATAL: for.asm(41) -> for.asm::REPT~4(47):
|
ERROR: for.asm(45) -> for.asm::REPT~4(51):
|
||||||
|
'v' already defined as constant at for.asm(45) -> for.asm::REPT~4(49)
|
||||||
|
FATAL: for.asm(45) -> for.asm::REPT~4(51):
|
||||||
Failed to update FOR symbol value
|
Failed to update FOR symbol value
|
||||||
|
|||||||
15
test/asm/format-truncation.asm
Normal file
15
test/asm/format-truncation.asm
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
num equ 42
|
||||||
|
fix equ 123.0
|
||||||
|
str equs "hello"
|
||||||
|
|
||||||
|
println "{#0260x:num}"
|
||||||
|
println "{#-260x:num}"
|
||||||
|
println "{0280.260f:fix}"
|
||||||
|
println "{260s:str}"
|
||||||
|
println "{-260s:str}"
|
||||||
|
|
||||||
|
println "<{#0260x:num}>"
|
||||||
|
println "<{#-260x:num}>"
|
||||||
|
println "<{0280.260f:fix}>"
|
||||||
|
println "<{260s:str}>"
|
||||||
|
println "<{-260s:str}>"
|
||||||
35
test/asm/format-truncation.err
Normal file
35
test/asm/format-truncation.err
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
ERROR: format-truncation.asm(5):
|
||||||
|
Formatted numeric value too long
|
||||||
|
ERROR: format-truncation.asm(6):
|
||||||
|
Formatted numeric value too long
|
||||||
|
ERROR: format-truncation.asm(7):
|
||||||
|
Fractional width 260 too long, limiting to 255
|
||||||
|
ERROR: format-truncation.asm(7):
|
||||||
|
Formatted numeric value too long
|
||||||
|
ERROR: format-truncation.asm(8):
|
||||||
|
Formatted string value too long
|
||||||
|
ERROR: format-truncation.asm(9):
|
||||||
|
Formatted string value too long
|
||||||
|
ERROR: format-truncation.asm(11):
|
||||||
|
Formatted numeric value too long
|
||||||
|
warning: format-truncation.asm(11): [-Wlong-string]
|
||||||
|
String constant too long
|
||||||
|
ERROR: format-truncation.asm(12):
|
||||||
|
Formatted numeric value too long
|
||||||
|
warning: format-truncation.asm(12): [-Wlong-string]
|
||||||
|
String constant too long
|
||||||
|
ERROR: format-truncation.asm(13):
|
||||||
|
Fractional width 260 too long, limiting to 255
|
||||||
|
ERROR: format-truncation.asm(13):
|
||||||
|
Formatted numeric value too long
|
||||||
|
warning: format-truncation.asm(13): [-Wlong-string]
|
||||||
|
String constant too long
|
||||||
|
ERROR: format-truncation.asm(14):
|
||||||
|
Formatted string value too long
|
||||||
|
warning: format-truncation.asm(14): [-Wlong-string]
|
||||||
|
String constant too long
|
||||||
|
ERROR: format-truncation.asm(15):
|
||||||
|
Formatted string value too long
|
||||||
|
warning: format-truncation.asm(15): [-Wlong-string]
|
||||||
|
String constant too long
|
||||||
|
error: Assembly aborted (12 errors)!
|
||||||
10
test/asm/format-truncation.out
Normal file
10
test/asm/format-truncation.out
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
$0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a
|
||||||
|
$2a
|
||||||
|
123.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
hello
|
||||||
|
hello
|
||||||
|
<$0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
|
||||||
|
<$2a
|
||||||
|
<123.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
< hell
|
||||||
|
<hello
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: fragment-align.asm(25):
|
ERROR: fragment-align.asm(25):
|
||||||
Section's alignment fails required alignment (offset from section start = $0004)
|
Section's alignment fails required alignment (offset from section start = $0004)
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: garbage_char.asm(1):
|
ERROR: garbage_char.asm(1):
|
||||||
Unknown character 0xFF
|
Unknown character 0xFF
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: if@-no-sect.asm(1):
|
ERROR: if@-no-sect.asm(1):
|
||||||
PC has no value outside a section
|
PC has no value outside a section
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: incbin-empty-bad.asm(3):
|
ERROR: incbin-empty-bad.asm(3):
|
||||||
Specified range in INCBIN is out of bounds (0 + 1 > 0)
|
Specified range in INCBIN is out of bounds (0 + 1 > 0)
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: incbin-end-bad.asm(3):
|
ERROR: incbin-end-bad.asm(3):
|
||||||
Specified range in INCBIN is out of bounds (123 + 1 > 123)
|
Specified range in INCBIN is out of bounds (123 + 1 > 123)
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
4
test/asm/interpolation-overflow.asm
Normal file
4
test/asm/interpolation-overflow.asm
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
; It seems that \1 was the easiest way to notice the memory corruption that
|
||||||
|
; resulted from this overflow
|
||||||
|
x = 0
|
||||||
|
{.99999999f:x}\1
|
||||||
9
test/asm/interpolation-overflow.err
Normal file
9
test/asm/interpolation-overflow.err
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
ERROR: interpolation-overflow.asm(4):
|
||||||
|
Fractional width 99999999 too long, limiting to 255
|
||||||
|
ERROR: interpolation-overflow.asm(4):
|
||||||
|
Formatted numeric value too long
|
||||||
|
warning: interpolation-overflow.asm(4): [-Wlarge-constant]
|
||||||
|
Precision of fixed-point constant is too large
|
||||||
|
while expanding symbol "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
FATAL: interpolation-overflow.asm(4):
|
||||||
|
Macro argument '\1' not defined
|
||||||
0
test/asm/interpolation-overflow.out
Normal file
0
test/asm/interpolation-overflow.out
Normal file
2
test/asm/interpolation-recursion.asm
Normal file
2
test/asm/interpolation-recursion.asm
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
recurse EQUS "\{recurse\}"
|
||||||
|
{recurse}
|
||||||
67
test/asm/interpolation-recursion.err
Normal file
67
test/asm/interpolation-recursion.err
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
FATAL: interpolation-recursion.asm(2):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
|
while expanding symbol "{recurse}"
|
||||||
0
test/asm/interpolation-recursion.out
Normal file
0
test/asm/interpolation-recursion.out
Normal file
@@ -1,3 +1,3 @@
|
|||||||
ERROR: label-outside-section.asm(1):
|
ERROR: label-outside-section.asm(1):
|
||||||
Label "bad" created outside of a SECTION
|
Label "bad" created outside of a SECTION
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: label-redefinition.asm(7):
|
ERROR: label-redefinition.asm(7):
|
||||||
'Sym' already defined at label-redefinition.asm(6) -> label-redefinition.asm::m(4)
|
'Sym' already defined at label-redefinition.asm(6) -> label-redefinition.asm::m(4)
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: line-continuation-whitespace.asm(7):
|
ERROR: line-continuation-whitespace.asm(7):
|
||||||
Label "foo" created outside of a SECTION
|
Label "foo" created outside of a SECTION
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: line-continuation.asm(7):
|
ERROR: line-continuation.asm(7):
|
||||||
Label "foo" created outside of a SECTION
|
Label "foo" created outside of a SECTION
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: load-rom.asm(3):
|
ERROR: load-rom.asm(3):
|
||||||
`LOAD` blocks cannot create a ROM section
|
`LOAD` blocks cannot create a ROM section
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
ERROR: local-purge.asm(8):
|
ERROR: local-purge.asm(8):
|
||||||
Interpolated symbol ".loc" does not exist
|
Interpolated symbol ".loc" does not exist
|
||||||
error: Assembly aborted (1 errors)!
|
error: Assembly aborted (1 error)!
|
||||||
|
|||||||
11
test/asm/local-truncated.asm
Normal file
11
test/asm/local-truncated.asm
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
SECTION "Test", ROM0
|
||||||
|
|
||||||
|
MACRO a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
|
||||||
|
println "truncated :("
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
a012:
|
||||||
|
a012.local
|
||||||
|
|
||||||
|
a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012:
|
||||||
|
a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012.local
|
||||||
7
test/asm/local-truncated.err
Normal file
7
test/asm/local-truncated.err
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
warning: local-truncated.asm(10): [-Wlong-string]
|
||||||
|
Symbol name too long, got truncated
|
||||||
|
ERROR: local-truncated.asm(10):
|
||||||
|
'a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' already defined at local-truncated.asm(3)
|
||||||
|
warning: local-truncated.asm(11): [-Wlong-string]
|
||||||
|
Symbol name too long, got truncated
|
||||||
|
error: Assembly aborted (1 error)!
|
||||||
1
test/asm/local-truncated.out
Normal file
1
test/asm/local-truncated.out
Normal file
@@ -0,0 +1 @@
|
|||||||
|
truncated :(
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user