mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Compare commits
53 Commits
v0.5.0-rcC
...
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 |
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
|
||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 2
|
|
||||||
|
|
||||||
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';
|
||||||
|
|||||||
@@ -191,6 +191,11 @@ 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 (isPathValid(*fullPath)) {
|
if (isPathValid(*fullPath)) {
|
||||||
@@ -487,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))
|
||||||
|
|||||||
830
src/asm/lexer.c
830
src/asm/lexer.c
File diff suppressed because it is too large
Load Diff
977
src/asm/parser.y
977
src/asm/parser.y
File diff suppressed because it is too large
Load Diff
@@ -83,7 +83,7 @@ Add an include path.
|
|||||||
Disable the optimization that turns loads of the form
|
Disable the optimization that turns loads of the form
|
||||||
.Ic LD [$FF00+n8],A
|
.Ic LD [$FF00+n8],A
|
||||||
into the opcode
|
into the opcode
|
||||||
.Ic LD [H $FF00+n8],A
|
.Ic LDH [$FF00+n8],A
|
||||||
in order to have full control of the result in the final ROM.
|
in order to have full control of the result in the final ROM.
|
||||||
.It Fl M Ar depend_file , Fl Fl dependfile Ar depend_file
|
.It Fl M Ar depend_file , Fl Fl dependfile Ar depend_file
|
||||||
Print
|
Print
|
||||||
@@ -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,12 +245,12 @@ 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
|
||||||
Warn when an implicit truncation (for example,
|
Warn when an implicit truncation (for example,
|
||||||
.Ic LD [B @] )
|
.Ic db )
|
||||||
loses some bits.
|
loses some bits.
|
||||||
.It Fl Wno-user
|
.It Fl Wno-user
|
||||||
Warn when the
|
Warn when the
|
||||||
|
|||||||
202
src/asm/rgbasm.5
202
src/asm/rgbasm.5
@@ -63,9 +63,9 @@ X = /* the value of x
|
|||||||
Sometimes lines can be too long and it may be necessary to split them.
|
Sometimes lines can be too long and it may be necessary to split them.
|
||||||
To do so, put a backslash at the end of the line:
|
To do so, put a backslash at the end of the line:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
LD [B @:...], 1, 2, 3,\ \[rs]
|
DB 1, 2, 3,\ \[rs]
|
||||||
4, 5, 6,\ \[rs]\ ;\ Put it before any comments
|
4, 5, 6,\ \[rs]\ ;\ Put it before any comments
|
||||||
7, 8, 9
|
7, 8, 9
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
This works anywhere in the code except inside of strings.
|
This works anywhere in the code except inside of strings.
|
||||||
@@ -73,8 +73,8 @@ To split strings it is needed to use
|
|||||||
.Fn STRCAT
|
.Fn STRCAT
|
||||||
like this:
|
like this:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
LD [B @:], STRCAT("Hello ",\ \[rs]
|
db STRCAT("Hello ",\ \[rs]
|
||||||
"world!")
|
"world!")
|
||||||
.Ed
|
.Ed
|
||||||
.Sh EXPRESSIONS
|
.Sh EXPRESSIONS
|
||||||
An expression can be composed of many things.
|
An expression can be composed of many things.
|
||||||
@@ -226,7 +226,7 @@ For example:
|
|||||||
; (shifted and scaled from the range [-1.0, 1.0])
|
; (shifted and scaled from the range [-1.0, 1.0])
|
||||||
ANGLE = 0.0
|
ANGLE = 0.0
|
||||||
REPT 256
|
REPT 256
|
||||||
ld [b @], (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
|
db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
|
||||||
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
|
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
|
||||||
ENDR
|
ENDR
|
||||||
.Ed
|
.Ed
|
||||||
@@ -337,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
|
||||||
@@ -417,9 +417,9 @@ CHARMAP "í", 20
|
|||||||
CHARMAP "A", 128
|
CHARMAP "A", 128
|
||||||
.Ed
|
.Ed
|
||||||
This would result in
|
This would result in
|
||||||
.Ql ld [b @:...], \(dqAmen<LF>\(dq
|
.Ql db \(dqAmen<LF>\(dq
|
||||||
being equivalent to
|
being equivalent to
|
||||||
.Ql ld [b @:...], 128, 109, 101, 110, 10 .
|
.Ql db 128, 109, 101, 110, 10 .
|
||||||
.Pp
|
.Pp
|
||||||
Any characters in a string without defined mappings will be copied directly, using the source file's encoding of characters to bytes.
|
Any characters in a string without defined mappings will be copied directly, using the source file's encoding of characters to bytes.
|
||||||
.Pp
|
.Pp
|
||||||
@@ -574,15 +574,15 @@ While
|
|||||||
will automatically optimize
|
will automatically optimize
|
||||||
.Ic ld
|
.Ic ld
|
||||||
instructions to the smaller and faster
|
instructions to the smaller and faster
|
||||||
.Ic ld\ h
|
.Ic ldh
|
||||||
(see
|
(see
|
||||||
.Xr gbz80 7 )
|
.Xr gbz80 7 )
|
||||||
whenever possible, it is generally unable to do so when a label is involved.
|
whenever possible, it is generally unable to do so when a label is involved.
|
||||||
Using the
|
Using the
|
||||||
.Ic ld\ h
|
.Ic ldh
|
||||||
instruction directly is recommended.
|
instruction directly is recommended.
|
||||||
This forces the assembler to emit a
|
This forces the assembler to emit a
|
||||||
.Ic ld\ h
|
.Ic ldh
|
||||||
instruction and the linker to check if the value is in the correct range.
|
instruction and the linker to check if the value is in the correct range.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
@@ -699,11 +699,11 @@ CopyCode:
|
|||||||
ld c, RAMLocation.end - RAMLocation
|
ld c, RAMLocation.end - RAMLocation
|
||||||
\&.loop
|
\&.loop
|
||||||
ld a, [de]
|
ld a, [de]
|
||||||
ld de+
|
inc de
|
||||||
ld [hli], a
|
ld [hli], a
|
||||||
ld c-
|
dec c
|
||||||
ld nz pc, b .loop
|
jr nz, .loop
|
||||||
ld pc,[sp++]
|
ret
|
||||||
|
|
||||||
RAMCode:
|
RAMCode:
|
||||||
LOAD "RAM code", WRAM0
|
LOAD "RAM code", WRAM0
|
||||||
@@ -713,13 +713,13 @@ RAMLocation:
|
|||||||
\&.copy
|
\&.copy
|
||||||
ld a, [hli]
|
ld a, [hli]
|
||||||
ld [de], a
|
ld [de], a
|
||||||
ld de+
|
inc de
|
||||||
ld a,a&a
|
and a
|
||||||
ld nz pc, b .copy
|
jr nz, .copy
|
||||||
ld pc,[sp++]
|
ret
|
||||||
|
|
||||||
\&.string
|
\&.string
|
||||||
ld [b @:...], "Hello World!", 0
|
db "Hello World!", 0
|
||||||
\&.end
|
\&.end
|
||||||
ENDL
|
ENDL
|
||||||
.Ed
|
.Ed
|
||||||
@@ -929,14 +929,14 @@ references the one before the expression;
|
|||||||
and so on.
|
and so on.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
ld hl, :++
|
ld hl, :++
|
||||||
: ld a, [hli] ; referenced by "ld nz pc"
|
: ld a, [hli] ; referenced by "jr nz"
|
||||||
ld [h c], a
|
ldh [c], a
|
||||||
ld c-
|
dec c
|
||||||
ld nz pc,b :-
|
jr nz, :-
|
||||||
ld pc,[sp++]
|
ret
|
||||||
|
|
||||||
: ; referenced by "ld hl"
|
: ; referenced by "ld hl"
|
||||||
ld [w @:], $7FFF, $1061, $03E0, $58A5
|
dw $7FFF, $1061, $03E0, $58A5
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
A label's location (and thus value) is usually not determined until the linking stage, so labels usually cannot be used as constants.
|
A label's location (and thus value) is usually not determined until the linking stage, so labels usually cannot be used as constants.
|
||||||
@@ -1036,18 +1036,18 @@ DEF COUNTREG EQUS "[hl+]"
|
|||||||
ld a,COUNTREG
|
ld a,COUNTREG
|
||||||
|
|
||||||
DEF PLAYER_NAME EQUS "\[rs]"John\[rs]""
|
DEF PLAYER_NAME EQUS "\[rs]"John\[rs]""
|
||||||
ld [b @:], PLAYER_NAME
|
db PLAYER_NAME
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
This will be interpreted as:
|
This will be interpreted as:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
ld a,[hl+]
|
ld a,[hl+]
|
||||||
ld [b @:], "John"
|
db "John"
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
String equates 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
|
||||||
DEF ld_de_hl EQUS "ld d,h\[rs]n ld e,l\[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
|
||||||
@@ -1135,7 +1135,7 @@ constructs.
|
|||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
MACRO MyMacro
|
MACRO MyMacro
|
||||||
ld a, 80
|
ld a, 80
|
||||||
ld[--sp],pc, MyFunc
|
call MyFunc
|
||||||
ENDM
|
ENDM
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1208,9 +1208,9 @@ ExportedLabelB2:
|
|||||||
.Ql c.asm :
|
.Ql c.asm :
|
||||||
.Bd -literal -compact
|
.Bd -literal -compact
|
||||||
SECTION "C", ROM0[0]
|
SECTION "C", ROM0[0]
|
||||||
ld [w @], LabelA
|
dw LabelA
|
||||||
ld [w @], ExportedLabelB1
|
dw ExportedLabelB1
|
||||||
ld [w @], ExportedLabelB2
|
dw ExportedLabelB2
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Then
|
Then
|
||||||
@@ -1272,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
|
||||||
@@ -1281,20 +1282,18 @@ Refer to the spec at
|
|||||||
.Lk https://reproducible-builds.org/docs/source-date-epoch/ .
|
.Lk https://reproducible-builds.org/docs/source-date-epoch/ .
|
||||||
.Sh DEFINING DATA
|
.Sh DEFINING DATA
|
||||||
.Ss Declaring variables in a RAM section
|
.Ss Declaring variables in a RAM section
|
||||||
.Ic LD [B @:<len>]
|
.Ic DS
|
||||||
allocates a number of empty bytes.
|
allocates a number of empty bytes.
|
||||||
This is the preferred method of allocating space in a RAM section.
|
This is the preferred method of allocating space in a RAM section.
|
||||||
You can also use
|
You can also use
|
||||||
.Ic LD [B @] , LD [W @]
|
.Ic DB , DW
|
||||||
and
|
and
|
||||||
.Ic LD [L @]
|
.Ic DL
|
||||||
with
|
without any arguments instead (see
|
||||||
.Ql \&?
|
|
||||||
instead (see
|
|
||||||
.Sx Defining constant data
|
.Sx Defining constant data
|
||||||
below).
|
below).
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
LD [B @:42], ? ;\ Allocates 42 bytes
|
DS 42 ;\ Allocates 42 bytes
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Empty space in RAM sections will not be initialized.
|
Empty space in RAM sections will not be initialized.
|
||||||
@@ -1303,24 +1302,17 @@ In ROM sections, it will be filled with the value passed to the
|
|||||||
command-line option, except when using overlays with
|
command-line option, except when using overlays with
|
||||||
.Fl O .
|
.Fl O .
|
||||||
.Ss Defining constant data
|
.Ss Defining constant data
|
||||||
.Ic LD [B @]
|
.Ic DB
|
||||||
defines a list of bytes that will be stored in the final image.
|
defines a list of bytes that will be stored in the final image.
|
||||||
Ideal for tables and text.
|
Ideal for tables and text.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
LD [B @:...], 1,2,3,4,"This is a string"
|
DB 1,2,3,4,"This is a string"
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Python slice syntax is used: for a single byte, close the brackets immediately after
|
|
||||||
.Ql @ ;
|
|
||||||
if more than one entry follows, a colon must be added after the
|
|
||||||
.Ql @ ,
|
|
||||||
optionally followed by an ellipsis
|
|
||||||
.Ql ... .
|
|
||||||
.Pp
|
|
||||||
Alternatively, you can use
|
Alternatively, you can use
|
||||||
.Ic LD [W @]
|
.Ic DW
|
||||||
to store a list of words (16-bit) or
|
to store a list of words (16-bit) or
|
||||||
.Ic LD [L @]
|
.Ic DL
|
||||||
to store a list of double-words/longs (32-bit).
|
to store a list of double-words/longs (32-bit).
|
||||||
.Pp
|
.Pp
|
||||||
Strings are handled a little specially: they first undergo charmap conversion (see
|
Strings are handled a little specially: they first undergo charmap conversion (see
|
||||||
@@ -1328,42 +1320,36 @@ Strings are handled a little specially: they first undergo charmap conversion (s
|
|||||||
then each resulting character is output individually.
|
then each resulting character is output individually.
|
||||||
For example, under the default charmap, the following two lines are identical:
|
For example, under the default charmap, the following two lines are identical:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
LD [W @:], "Hello!"
|
DW "Hello!"
|
||||||
LD [W @:], "H", "e", "l", "l", "o", "!"
|
DW "H", "e", "l", "l", "o", "!"
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Note that strings require a colon after the
|
|
||||||
.Ql @
|
|
||||||
in the directive.
|
|
||||||
.Pp
|
|
||||||
If you do not want this special handling, enclose the string in parentheses.
|
If you do not want this special handling, enclose the string in parentheses.
|
||||||
.Pp
|
.Pp
|
||||||
.Ic LD [B @:<len>]
|
.Ic DS
|
||||||
can also be used to fill a region of memory with some repeated values.
|
can also be used to fill a region of memory with some repeated values.
|
||||||
For example:
|
For example:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
; outputs 3 bytes: $AA, $AA, $AA
|
; outputs 3 bytes: $AA, $AA, $AA
|
||||||
LD [B @:3], $AA
|
DS 3, $AA
|
||||||
; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB
|
; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB
|
||||||
LD [B @:7], $BB, $CC
|
DS 7, $BB, $CC
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
You can also use
|
You can also use
|
||||||
.Ic LD [B @] , LD [W @]
|
.Ic DB , DW
|
||||||
and
|
and
|
||||||
.Ic LD [L @]
|
.Ic DL
|
||||||
with
|
without arguments.
|
||||||
.Ql \&?
|
|
||||||
as its sole argument (in which case neither the colon nor an ellipsis may be present).
|
|
||||||
This works exactly like
|
This works exactly like
|
||||||
.Ic LD [B @:1] , LD [B @:2]
|
.Ic DS 1 , DS 2
|
||||||
and
|
and
|
||||||
.Ic LD [B @:4]
|
.Ic DS 4
|
||||||
respectively.
|
respectively.
|
||||||
Consequently, these forms of
|
Consequently, no-argument
|
||||||
.Ic LD [B @] , LD [W @]
|
.Ic DB , DW
|
||||||
and
|
and
|
||||||
.Ic LD [L @]
|
.Ic DL
|
||||||
can be used in a
|
can be used in a
|
||||||
.Ic WRAM0
|
.Ic WRAM0
|
||||||
/
|
/
|
||||||
@@ -1378,25 +1364,23 @@ section.
|
|||||||
.Ss Including binary files
|
.Ss Including binary files
|
||||||
You probably have some graphics, level data, etc. you'd like to include.
|
You probably have some graphics, level data, etc. you'd like to include.
|
||||||
Use
|
Use
|
||||||
.Ic LD [B @:...] =
|
.Ic INCBIN
|
||||||
to include a raw binary file as it is.
|
to include a raw binary file as it is.
|
||||||
.Pq The ellipsis are optional.
|
|
||||||
If the file isn't found in the current directory, the include-path list passed to
|
If the file isn't found in the current directory, the include-path list passed to
|
||||||
.Xr rgbasm 1
|
.Xr rgbasm 1
|
||||||
(see the
|
(see the
|
||||||
.Fl i
|
.Fl i
|
||||||
option) on the command line will be searched.
|
option) on the command line will be searched.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
LD [B @:] = "titlepic.bin"
|
INCBIN "titlepic.bin"
|
||||||
LD [B @:...] = "sprites/hero.bin"
|
INCBIN "sprites/hero.bin"
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
You can also include only part of a file with
|
You can also include only part of a file with
|
||||||
.Ic LD [B @:] .
|
.Ic INCBIN .
|
||||||
The examples below include 256 bytes from data.bin, starting from byte 78.
|
The example below includes 256 bytes from data.bin, starting from byte 78.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
LD [B @:] = "data.bin"[78:256]
|
INCBIN "data.bin",78,256
|
||||||
LD [B @:256] = "data.bin"[78:]
|
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
The length argument is optional.
|
The length argument is optional.
|
||||||
@@ -1416,19 +1400,19 @@ separates each block of allocations, and you may use it as many times within a u
|
|||||||
; Let's say PC = $C0DE here
|
; Let's say PC = $C0DE here
|
||||||
UNION
|
UNION
|
||||||
; Here, PC = $C0DE
|
; Here, PC = $C0DE
|
||||||
Name: ld [b @:8], ?
|
Name: ds 8
|
||||||
; PC = $C0E6
|
; PC = $C0E6
|
||||||
Nickname: ld [b @:8], ?
|
Nickname: ds 8
|
||||||
; PC = $C0EE
|
; PC = $C0EE
|
||||||
NEXTU
|
NEXTU
|
||||||
; PC is back to $C0DE
|
; PC is back to $C0DE
|
||||||
Health: ld [w @], ?
|
Health: dw
|
||||||
; PC = $C0E0
|
; PC = $C0E0
|
||||||
Something: ld [b @:6], ?
|
Something: ds 6
|
||||||
; And so on
|
; And so on
|
||||||
Lives: ld [b @], ?
|
Lives: db
|
||||||
NEXTU
|
NEXTU
|
||||||
VideoBuffer: ld [b @:19], ?
|
VideoBuffer: ds 19
|
||||||
ENDU
|
ENDU
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1448,17 +1432,17 @@ The size of this union is 19 bytes, as this is the size of the largest block (th
|
|||||||
Nesting unions is possible, with each inner union's size being considered as described above.
|
Nesting unions is possible, with each inner union's size being considered as described above.
|
||||||
.Pp
|
.Pp
|
||||||
Unions may be used in any section, but inside them may only be
|
Unions may be used in any section, but inside them may only be
|
||||||
.Ic LD\ [B\ @],\ ? Ns - Ns
|
.Ic DS -
|
||||||
like commands (see
|
like commands (see
|
||||||
.Sx Declaring variables in a RAM section ) .
|
.Sx Declaring variables in a RAM section ) .
|
||||||
.Sh THE MACRO LANGUAGE
|
.Sh THE MACRO LANGUAGE
|
||||||
.Ss Invoking macros
|
.Ss Invoking macros
|
||||||
You execute the macro by inserting its name.
|
You execute the macro by inserting its name.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
ld a,a+b
|
add a,b
|
||||||
ld sp,hl
|
ld sp,hl
|
||||||
MyMacro ;\ This will be expanded
|
MyMacro ;\ This will be expanded
|
||||||
ld a,a-87
|
sub a,87
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
It's valid to call a macro from a macro (yes, even the same one).
|
It's valid to call a macro from a macro (yes, even the same one).
|
||||||
@@ -1475,10 +1459,10 @@ it will insert the macro definition (the code enclosed in
|
|||||||
Suppose your macro contains a loop.
|
Suppose your macro contains a loop.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
MACRO LoopyMacro
|
MACRO LoopyMacro
|
||||||
ld a,a^a
|
xor a,a
|
||||||
\&.loop ld [hl+],a
|
\&.loop ld [hl+],a
|
||||||
ld c-
|
dec c
|
||||||
ld nz pc,b .loop
|
jr nz,.loop
|
||||||
ENDM
|
ENDM
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1493,10 +1477,10 @@ also works in
|
|||||||
blocks.
|
blocks.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
MACRO LoopyMacro
|
MACRO LoopyMacro
|
||||||
ld a,a^a
|
xor a,a
|
||||||
\&.loop\[rs]@ ld [hl+],a
|
\&.loop\[rs]@ ld [hl+],a
|
||||||
ld c-
|
dec c
|
||||||
ld nz pc,b .loop\[rs]@
|
jr nz,.loop\[rs]@
|
||||||
ENDM
|
ENDM
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1524,10 +1508,10 @@ being the first argument specified on the macro invocation.
|
|||||||
MACRO LoopyMacro
|
MACRO LoopyMacro
|
||||||
ld hl,\[rs]1
|
ld hl,\[rs]1
|
||||||
ld c,\[rs]2
|
ld c,\[rs]2
|
||||||
ld a,a^a
|
xor a,a
|
||||||
\&.loop\[rs]@ ld [hl+],a
|
\&.loop\[rs]@ ld [hl+],a
|
||||||
ld c-
|
dec c
|
||||||
ld nz pc,b .loop\[rs]@
|
jr nz,.loop\[rs]@
|
||||||
ENDM
|
ENDM
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1639,7 +1623,7 @@ The following example will assemble
|
|||||||
four times:
|
four times:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
REPT 4
|
REPT 4
|
||||||
ld a,a+c
|
add a,c
|
||||||
ENDR
|
ENDR
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1651,7 +1635,7 @@ to generate tables on the fly:
|
|||||||
; (shifted and scaled from the range [-1.0, 1.0])
|
; (shifted and scaled from the range [-1.0, 1.0])
|
||||||
ANGLE = 0.0
|
ANGLE = 0.0
|
||||||
REPT 256
|
REPT 256
|
||||||
ld [b @], (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
|
db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
|
||||||
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
|
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
|
||||||
ENDR
|
ENDR
|
||||||
.Ed
|
.Ed
|
||||||
@@ -1675,21 +1659,21 @@ 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
|
||||||
ld [w @], N * N
|
dw N * N
|
||||||
ENDR
|
ENDR
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
It acts just as if you had done:
|
It acts just as if you had done:
|
||||||
.Bd -literal -offset ident
|
.Bd -literal -offset ident
|
||||||
N = 0
|
N = 0
|
||||||
ld [w @], N * N
|
dw N * N
|
||||||
N = 1
|
N = 1
|
||||||
ld [w @], N * N
|
dw N * N
|
||||||
N = 2
|
N = 2
|
||||||
ld [w @], N * N
|
dw N * N
|
||||||
; ...
|
; ...
|
||||||
N = 255
|
N = 255
|
||||||
ld [w @], N * N
|
dw N * N
|
||||||
N = 256
|
N = 256
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@@ -1780,18 +1764,18 @@ and
|
|||||||
Syntax examples are given below:
|
Syntax examples are given below:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
Function:
|
Function:
|
||||||
ld a,a^a
|
xor a
|
||||||
ASSERT LOW(Variable) == 0
|
ASSERT LOW(Variable) == 0
|
||||||
ld h, HIGH(Variable)
|
ld h, HIGH(Variable)
|
||||||
ld l, a
|
ld l, a
|
||||||
ld a, [hli]
|
ld a, [hli]
|
||||||
; You can also indent this!
|
; You can also indent this!
|
||||||
ASSERT BANK(OtherFunction) == BANK(Function)
|
ASSERT BANK(OtherFunction) == BANK(Function)
|
||||||
ld [--sp], pc,OtherFunction
|
call OtherFunction
|
||||||
; Lowercase also works
|
; Lowercase also works
|
||||||
assert Variable + 1 == OtherVariable
|
assert Variable + 1 == OtherVariable
|
||||||
ld c, [hl]
|
ld c, [hl]
|
||||||
ld pc,[sp++]
|
ret
|
||||||
\&.end
|
\&.end
|
||||||
; If you specify one, a message will be printed
|
; If you specify one, a message will be printed
|
||||||
STATIC_ASSERT .end - Function < 256, "Function is too large!"
|
STATIC_ASSERT .end - Function < 256, "Function is too large!"
|
||||||
@@ -1900,9 +1884,9 @@ takes a comma-separated list of options as its argument:
|
|||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
PUSHO
|
PUSHO
|
||||||
OPT g.oOX ;Set the GB graphics constants to use these characters
|
OPT g.oOX ;Set the GB graphics constants to use these characters
|
||||||
LD [W @], `..ooOOXX
|
DW `..ooOOXX
|
||||||
POPO
|
POPO
|
||||||
LD [W @], `00112233
|
DW `00112233
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
The options that OPT can modify are currently:
|
The options that OPT can modify are currently:
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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;
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -779,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);
|
||||||
@@ -803,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,16 +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)
|
if (verbose)
|
||||||
printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", s, strerror(errno));
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -849,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);
|
||||||
@@ -883,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)
|
||||||
@@ -275,7 +269,7 @@ 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 != (uint32_t)-1;
|
return sym->ID != (uint32_t)-1;
|
||||||
}
|
}
|
||||||
@@ -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", (uint8_t)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,
|
||||||
|
|||||||
559
src/gbz80.7
559
src/gbz80.7
File diff suppressed because it is too large
Load Diff
@@ -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,8 +106,7 @@ 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;
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ static void readAssertion(FILE *file, struct Assertion *assert,
|
|||||||
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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
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)!
|
||||||
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
|
||||||
@@ -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
|
||||||
test (V (q * y + r)) == (V x)
|
def r = x % y ; remainder
|
||||||
test (V (x + y) % y) == (V r)
|
; identity laws
|
||||||
test (V (x - y) % y) == (V r)
|
test (V (q * y + r)) == (V x)
|
||||||
endc
|
test (V (x + y) % y) == (V r)
|
||||||
endr
|
test (V (x - y) % y) == (V r)
|
||||||
endr
|
ENDM
|
||||||
|
|
||||||
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)
|
||||||
test (V r) == (V m)
|
ENDM
|
||||||
endr
|
|
||||||
endr
|
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)
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
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::
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
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
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 :(
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
_NARG = 0
|
|
||||||
_NARG = 0
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
ERROR: narg-overwrite.asm(1):
|
|
||||||
'_NARG' already defined as constant at <builtin>
|
|
||||||
ERROR: narg-overwrite.asm(2):
|
|
||||||
'_NARG' already defined as constant at <builtin>
|
|
||||||
error: Assembly aborted (2 errors)!
|
|
||||||
6
test/asm/nested-expansions.asm
Normal file
6
test/asm/nested-expansions.asm
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
def foo equs "bar"
|
||||||
|
def bar equs "qux"
|
||||||
|
MACRO test
|
||||||
|
\1
|
||||||
|
ENDM
|
||||||
|
test foo 0
|
||||||
3
test/asm/nested-expansions.err
Normal file
3
test/asm/nested-expansions.err
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ERROR: nested-expansions.asm(6) -> nested-expansions.asm::test(4):
|
||||||
|
Macro "qux" not defined
|
||||||
|
error: Assembly aborted (1 error)!
|
||||||
0
test/asm/nested-expansions.out
Normal file
0
test/asm/nested-expansions.out
Normal file
3
test/asm/nested-interpolation-recursion.asm
Normal file
3
test/asm/nested-interpolation-recursion.asm
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
def s equs "s"
|
||||||
|
; 65 nested {}s, recursion limit is 64
|
||||||
|
println "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{s}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}"
|
||||||
2
test/asm/nested-interpolation-recursion.err
Normal file
2
test/asm/nested-interpolation-recursion.err
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
FATAL: nested-interpolation-recursion.asm(3):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
0
test/asm/nested-interpolation-recursion.out
Normal file
0
test/asm/nested-interpolation-recursion.out
Normal file
6
test/asm/pushc-without-switch.asm
Normal file
6
test/asm/pushc-without-switch.asm
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
; Triggering a charmap realloc while the charmap has been pushed onto the stack used
|
||||||
|
; to induce a use-after-free.
|
||||||
|
pushc
|
||||||
|
charmap "000000000000000000000000000000000",12
|
||||||
|
popc
|
||||||
|
charmap "000000000000000000000000000000000",34
|
||||||
0
test/asm/pushc-without-switch.err
Normal file
0
test/asm/pushc-without-switch.err
Normal file
0
test/asm/pushc-without-switch.out
Normal file
0
test/asm/pushc-without-switch.out
Normal file
@@ -1,13 +1,13 @@
|
|||||||
N:MACRO
|
MACRO N
|
||||||
FOR I,_NARG
|
FOR I,_NARG
|
||||||
SHIFT I
|
PRINT STRSUB("\n\"\\ INRST1,ABCDEFGHMnOPU_+-()",\1+1,1)
|
||||||
PRINT STRSUB("\n\"\\ INRT1,ABCDEFGHMOPSUn_(+-:)",\1+1,1)
|
SHIFT
|
||||||
SHIFT-I
|
|
||||||
ENDR
|
ENDR
|
||||||
REPT _NARG-1
|
SHIFT-I
|
||||||
|
REPT I-1
|
||||||
PRINT"\1,"
|
PRINT"\1,"
|
||||||
SHIFT
|
SHIFT
|
||||||
ENDR
|
ENDR
|
||||||
PRINT"\1\n"
|
PRINT"\1\n"
|
||||||
ENDM
|
ENDM
|
||||||
N 5,28,18,10,12,6,19,0,15,19,6,3,4,9,24,5,10,6,16,0,21,17,4,15,7,3,4,0,20,6,4,5,7,3,21,7,6,21,22,11,25,1,2,23,2,1,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,1,9,2,8,26,8,9,8,29,0,21,17,4,15,7,27,4,0,14,5,13,6,0,6,14,20,7,3,24,5,10,6,16,27,8,0,20,6,4,5,7,1,2,8,9,1,0,21,17,4,15,7,0,14,5,13,6,0,20,6,4,5,7,1,2,8,2,23,1,0,14,5,13,18,0,3,5,3
|
N 19,11,13,6,21,3,5,0,16,21,6,3,4,10,24,5,11,6,17,0,22,6,4,5,8,3,7,8,6,7,23,12,27,1,2,20,2,1,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,1,10,2,9,25,9,10,9,28,0,7,18,4,16,8,0,15,5,14,6,0,7,18,4,16,8,26,4,0,6,15,22,8,3,4,26,9,0,22,6,4,5,8,1,2,9,10,1,0,7,18,4,16,8,0,15,5,14,6,0,22,6,4,5,8,1,2,9,2,20,1,0,15,5,14,19,0,3,5,3
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
N:MACRO
|
MACRO N
|
||||||
FOR I,_NARG
|
FOR I,_NARG
|
||||||
SHIFT I
|
PRINT STRSUB("\n\"\\ INRST1,ABCDEFGHMnOPU_+-()",\1+1,1)
|
||||||
PRINT STRSUB("\n\"\\ INRT1,ABCDEFGHMOPSUn_(+-:)",\1+1,1)
|
SHIFT
|
||||||
SHIFT-I
|
|
||||||
ENDR
|
ENDR
|
||||||
REPT _NARG-1
|
SHIFT-I
|
||||||
|
REPT I-1
|
||||||
PRINT"\1,"
|
PRINT"\1,"
|
||||||
SHIFT
|
SHIFT
|
||||||
ENDR
|
ENDR
|
||||||
PRINT"\1\n"
|
PRINT"\1\n"
|
||||||
ENDM
|
ENDM
|
||||||
N 5,28,18,10,12,6,19,0,15,19,6,3,4,9,24,5,10,6,16,0,21,17,4,15,7,3,4,0,20,6,4,5,7,3,21,7,6,21,22,11,25,1,2,23,2,1,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,1,9,2,8,26,8,9,8,29,0,21,17,4,15,7,27,4,0,14,5,13,6,0,6,14,20,7,3,24,5,10,6,16,27,8,0,20,6,4,5,7,1,2,8,9,1,0,21,17,4,15,7,0,14,5,13,6,0,20,6,4,5,7,1,2,8,2,23,1,0,14,5,13,18,0,3,5,3
|
N 19,11,13,6,21,3,5,0,16,21,6,3,4,10,24,5,11,6,17,0,22,6,4,5,8,3,7,8,6,7,23,12,27,1,2,20,2,1,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,1,10,2,9,25,9,10,9,28,0,7,18,4,16,8,0,15,5,14,6,0,7,18,4,16,8,26,4,0,6,15,22,8,3,4,26,9,0,22,6,4,5,8,1,2,9,10,1,0,7,18,4,16,8,0,15,5,14,6,0,22,6,4,5,8,1,2,9,2,20,1,0,15,5,14,19,0,3,5,3
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
q:macro
|
macro q
|
||||||
println\1,"\1"
|
println\1,"\1"
|
||||||
endm
|
endm
|
||||||
q"q:macro\nprintln\\1,\"\\1\"\nendm\n q"
|
q"macro q\nprintln\\1,\"\\1\"\nendm\n q"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
q:macro
|
macro q
|
||||||
println\1,"\1"
|
println\1,"\1"
|
||||||
endm
|
endm
|
||||||
q"q:macro\nprintln\\1,\"\\1\"\nendm\n q"
|
q"macro q\nprintln\\1,\"\\1\"\nendm\n q"
|
||||||
|
|||||||
@@ -16,12 +16,8 @@ SECTION "calls", ROM0[0]
|
|||||||
|
|
||||||
|
|
||||||
defRST: MACRO
|
defRST: MACRO
|
||||||
; FIXME: This is required, otherwise the lexer does not paste the two tokens
|
SECTION "rst\1", ROM0[$\1]
|
||||||
ADDR equs "$\1"
|
rst\1:
|
||||||
SECTION "rst\1", ROM0[ADDR]
|
|
||||||
|
|
||||||
rst\1:
|
|
||||||
PURGE ADDR
|
|
||||||
ENDM
|
ENDM
|
||||||
defRST 00
|
defRST 00
|
||||||
defRST 08
|
defRST 08
|
||||||
|
|||||||
@@ -38,12 +38,14 @@ tryCmp () {
|
|||||||
|
|
||||||
# Add the version constants test, outputting the closest tag to the HEAD
|
# Add the version constants test, outputting the closest tag to the HEAD
|
||||||
if git describe --tags --abbrev=0 > version.out; then
|
if git describe --tags --abbrev=0 > version.out; then
|
||||||
|
$RGBASM --version >> version.out
|
||||||
cat > version.asm <<EOF
|
cat > version.asm <<EOF
|
||||||
IF !DEF(__RGBDS_RC__)
|
IF !DEF(__RGBDS_RC__)
|
||||||
PRINTLN "v{d:__RGBDS_MAJOR__}.{d:__RGBDS_MINOR__}.{d:__RGBDS_PATCH__}"
|
PRINTLN "v{d:__RGBDS_MAJOR__}.{d:__RGBDS_MINOR__}.{d:__RGBDS_PATCH__}"
|
||||||
ELSE
|
ELSE
|
||||||
PRINTLN "v{d:__RGBDS_MAJOR__}.{d:__RGBDS_MINOR__}.{d:__RGBDS_PATCH__}-rc{d:__RGBDS_RC__}"
|
PRINTLN "v{d:__RGBDS_MAJOR__}.{d:__RGBDS_MINOR__}.{d:__RGBDS_PATCH__}-rc{d:__RGBDS_RC__}"
|
||||||
ENDC
|
ENDC
|
||||||
|
PRINTLN "rgbasm {__RGBDS_VERSION__}"
|
||||||
EOF
|
EOF
|
||||||
else
|
else
|
||||||
echo "${bold}${orange}Warning: cannot run version test!${rescolors}${resbold}"
|
echo "${bold}${orange}Warning: cannot run version test!${rescolors}${resbold}"
|
||||||
@@ -60,6 +62,7 @@ EOF
|
|||||||
cat > quote\"file.err <<EOF
|
cat > quote\"file.err <<EOF
|
||||||
warning: quote"file.asm(1): [-Wuser]
|
warning: quote"file.asm(1): [-Wuser]
|
||||||
quote"file.asm
|
quote"file.asm
|
||||||
|
while expanding symbol "__FILE__"
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,27 @@
|
|||||||
warning: unique-id.asm(12) -> unique-id.asm::m(4): [-Wuser]
|
warning: unique-id.asm(12) -> unique-id.asm::m(4): [-Wuser]
|
||||||
_u1
|
_u1
|
||||||
|
while expanding symbol "warn_unique"
|
||||||
warning: unique-id.asm(12) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~1(6): [-Wuser]
|
warning: unique-id.asm(12) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~1(6): [-Wuser]
|
||||||
_u2
|
_u2
|
||||||
|
while expanding symbol "warn_unique"
|
||||||
warning: unique-id.asm(12) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~2(6): [-Wuser]
|
warning: unique-id.asm(12) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~2(6): [-Wuser]
|
||||||
_u3
|
_u3
|
||||||
|
while expanding symbol "warn_unique"
|
||||||
warning: unique-id.asm(12) -> unique-id.asm::m(8): [-Wuser]
|
warning: unique-id.asm(12) -> unique-id.asm::m(8): [-Wuser]
|
||||||
_u1
|
_u1
|
||||||
|
while expanding symbol "warn_unique"
|
||||||
warning: unique-id.asm(14) -> unique-id.asm::m(4): [-Wuser]
|
warning: unique-id.asm(14) -> unique-id.asm::m(4): [-Wuser]
|
||||||
_u4
|
_u4
|
||||||
|
while expanding symbol "warn_unique"
|
||||||
warning: unique-id.asm(14) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~1(6): [-Wuser]
|
warning: unique-id.asm(14) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~1(6): [-Wuser]
|
||||||
_u5
|
_u5
|
||||||
|
while expanding symbol "warn_unique"
|
||||||
warning: unique-id.asm(14) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~2(6): [-Wuser]
|
warning: unique-id.asm(14) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~2(6): [-Wuser]
|
||||||
_u6
|
_u6
|
||||||
|
while expanding symbol "warn_unique"
|
||||||
warning: unique-id.asm(14) -> unique-id.asm::m(8): [-Wuser]
|
warning: unique-id.asm(14) -> unique-id.asm::m(8): [-Wuser]
|
||||||
_u4
|
_u4
|
||||||
|
while expanding symbol "warn_unique"
|
||||||
FATAL: unique-id.asm(15):
|
FATAL: unique-id.asm(15):
|
||||||
Macro argument '\@' not defined
|
Macro argument '\@' not defined
|
||||||
while expanding symbol "warn_unique"
|
while expanding symbol "warn_unique"
|
||||||
|
|||||||
14
test/asm/utc-time.asm
Normal file
14
test/asm/utc-time.asm
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
MACRO between
|
||||||
|
assert (\1) <= (\2) && (\2) <= (\3)
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
between 0, __UTC_YEAR__, 9999 ; Y10K problem...
|
||||||
|
between 1, __UTC_MONTH__, 12
|
||||||
|
between 1, __UTC_DAY__, 31
|
||||||
|
between 0, __UTC_HOUR__, 23
|
||||||
|
between 0, __UTC_MINUTE__, 59
|
||||||
|
between 0, __UTC_SECOND__, 60 ; leap seconds!
|
||||||
|
|
||||||
|
UTC_TIME EQUS STRCAT("{04d:__UTC_YEAR__}-{02d:__UTC_MONTH__}-{02d:__UTC_DAY__}T", \
|
||||||
|
"{02d:__UTC_HOUR__}:{02d:__UTC_MINUTE__}:{02d:__UTC_SECOND__}Z")
|
||||||
|
assert !STRCMP("{UTC_TIME}", __ISO_8601_UTC__)
|
||||||
0
test/asm/utc-time.err
Normal file
0
test/asm/utc-time.err
Normal file
0
test/asm/utc-time.out
Normal file
0
test/asm/utc-time.out
Normal file
@@ -14,12 +14,8 @@ SECTION "calls", ROM0[0]
|
|||||||
|
|
||||||
|
|
||||||
defRST: MACRO
|
defRST: MACRO
|
||||||
; FIXME: This is required, otherwise the lexer does not paste the two tokens
|
SECTION "rst\1", ROM0[$\1]
|
||||||
ADDR equs "$\1"
|
rst\1:
|
||||||
SECTION "rst\1", ROM0[ADDR]
|
|
||||||
|
|
||||||
rst\1:
|
|
||||||
PURGE ADDR
|
|
||||||
ENDM
|
ENDM
|
||||||
defRST 00
|
defRST 00
|
||||||
defRST 08
|
defRST 08
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
export LC_ALL=C
|
export LC_ALL=C
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Return failure as soon as a command fails to execute
|
# Return failure as soon as a command fails to execute
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user