mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 02:32:06 +00:00
Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c0adb63a1 | ||
|
|
f5b0c701a6 | ||
|
|
874bd92604 | ||
|
|
69a8c62863 | ||
|
|
5481af5093 | ||
|
|
6355d0598b | ||
|
|
1145d10996 | ||
|
|
32231e3f7e | ||
|
|
29314f76f7 | ||
|
|
8e92383fa3 | ||
|
|
e51701acaa | ||
|
|
0793e9effe | ||
|
|
c25b0be085 | ||
|
|
1f2f797cb9 | ||
|
|
aca00e4fce | ||
|
|
cf80293d9b | ||
|
|
6d53753c66 | ||
|
|
79f293c3d7 | ||
|
|
8c765883fb | ||
|
|
83aa456d05 | ||
|
|
819c36943e | ||
|
|
8b60efa149 | ||
|
|
240fca0861 | ||
|
|
f996186fae | ||
|
|
69a41d8ef9 | ||
|
|
b958820bce | ||
|
|
7624bd524c | ||
|
|
663f0ca3b0 | ||
|
|
f88d9e728d | ||
|
|
71fa62c9d1 | ||
|
|
5c6069dbe9 | ||
|
|
d517d2d6b4 | ||
|
|
80218fa109 | ||
|
|
fee8a58b77 | ||
|
|
fd52a6f046 | ||
|
|
89fb372326 | ||
|
|
a828f82414 | ||
|
|
4d0d6664d7 | ||
|
|
5c24de3dc4 | ||
|
|
363458c3bc | ||
|
|
b299f6fb3b | ||
|
|
645473e336 | ||
|
|
bdf397bba7 | ||
|
|
781a65ee49 | ||
|
|
c135e2c6a0 | ||
|
|
12693081c9 | ||
|
|
7c22954fd5 | ||
|
|
8958e352df | ||
|
|
573003113b | ||
|
|
8b1351fc3e | ||
|
|
106ef895ee | ||
|
|
7f9bd12f76 | ||
|
|
5fe3a0adb6 | ||
|
|
cdb4c5f553 | ||
|
|
57639f3765 | ||
|
|
9bec983923 | ||
|
|
2220f19fa7 | ||
|
|
2a734ecba2 | ||
|
|
d21015e34a | ||
|
|
023a3c037f | ||
|
|
828edb7403 | ||
|
|
a034ce0478 | ||
|
|
d6cd5823e3 | ||
|
|
5dd941b311 | ||
|
|
f9f27d6f5a | ||
|
|
5ea8490e2b | ||
|
|
5863cd10b8 | ||
|
|
40f8e33e6c | ||
|
|
0157ba63d3 | ||
|
|
9e3d8b22cb | ||
|
|
665412c073 | ||
|
|
2b0c34ecb5 | ||
|
|
b0ec8468e6 | ||
|
|
e82ad21704 | ||
|
|
e098bf47ba | ||
|
|
190678107b | ||
|
|
9f82fa4cf7 | ||
|
|
562835308b | ||
|
|
927c65e863 | ||
|
|
5b6c1569a4 | ||
|
|
65121e6d5d | ||
|
|
82e0e4ffaf | ||
|
|
ffb199a26a | ||
|
|
175933d2b1 | ||
|
|
c86e6fef0a | ||
|
|
1e3ce2a36f | ||
|
|
153915dc2f | ||
|
|
ced38bc6ee |
2
.github/workflows/testing.yml
vendored
2
.github/workflows/testing.yml
vendored
@@ -5,7 +5,7 @@ jobs:
|
||||
unix-testing:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-18.04, ubuntu-16.04, macos-10.15]
|
||||
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04, macos-10.15]
|
||||
cc: [gcc, clang]
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,6 +6,9 @@ rgbshim.sh
|
||||
*.o
|
||||
*.exe
|
||||
.checkpatch-camelcase.*
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
cmake_install.cmake
|
||||
|
||||
test/pokecrystal
|
||||
test/pokered
|
||||
|
||||
71
CMakeLists.txt
Normal file
71
CMakeLists.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
#
|
||||
# This file is part of RGBDS.
|
||||
#
|
||||
# Copyright (c) 2020 RGBDS contributors.
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
|
||||
set(RGBDS_VER 0.4.1)
|
||||
set(RGBDS_DESC "Rednex Game Boy Development System")
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.0)
|
||||
project(rgbds C)
|
||||
set(PROJECT_VERSION "${RGBDS_VER}")
|
||||
else()
|
||||
if(CMAKE_VERSION VERSION_LESS 3.9)
|
||||
project(rgbds VERSION "${RGBDS_VER}"
|
||||
LANGUAGES C)
|
||||
else()
|
||||
project(rgbds VERSION "${RGBDS_VER}"
|
||||
DESCRIPTION "${RGBDS_DESC}"
|
||||
LANGUAGES C)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.9)
|
||||
set(PROJECT_DESCRIPTION "${RGBDS_DESC}")
|
||||
endif()
|
||||
|
||||
set(DEFAULT_BUILD_TYPE "Release")
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}")
|
||||
endif()
|
||||
|
||||
# get real path of source and binary directories
|
||||
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
|
||||
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
|
||||
|
||||
# reject in-source builds, may conflict with Makefile
|
||||
if(srcdir STREQUAL bindir)
|
||||
message("RGBDS should not be built in the source directory.")
|
||||
message("Instead, create a separate build directory and specify to CMake the path to the source directory.")
|
||||
message(FATAL_ERROR "Terminating configuration")
|
||||
endif()
|
||||
|
||||
find_package(PNG 1.2 REQUIRED)
|
||||
find_package(BISON REQUIRED)
|
||||
find_package(FLEX)
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W1 /MP -D_CRT_SECURE_NO_WARNINGS")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic")
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.12)
|
||||
add_definitions(-DBUILD_VERSION_STRING="${PROJECT_VERSION}")
|
||||
else()
|
||||
add_compile_definitions(BUILD_VERSION_STRING="${PROJECT_VERSION}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED True)
|
||||
|
||||
add_subdirectory(src)
|
||||
17
Makefile
17
Makefile
@@ -14,10 +14,10 @@
|
||||
Q := @
|
||||
PREFIX := /usr/local
|
||||
bindir := ${PREFIX}/bin
|
||||
mandir := ${PREFIX}/man
|
||||
mandir := ${PREFIX}/share/man
|
||||
STRIP := -s
|
||||
BINMODE := 555
|
||||
MANMODE := 444
|
||||
BINMODE := 755
|
||||
MANMODE := 644
|
||||
CHECKPATCH := ../linux/scripts/checkpatch.pl
|
||||
|
||||
# Other variables
|
||||
@@ -34,8 +34,8 @@ WARNFLAGS := -Wall
|
||||
# Overridable CFLAGS
|
||||
CFLAGS := -O3
|
||||
# Non-overridable CFLAGS
|
||||
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=c11 -D_POSIX_C_SOURCE=200809L \
|
||||
-D_DEFAULT_SOURCE -Iinclude
|
||||
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=gnu11 -D_POSIX_C_SOURCE=200809L \
|
||||
-Iinclude
|
||||
# Overridable LDFLAGS
|
||||
LDFLAGS :=
|
||||
# Non-overridable LDFLAGS
|
||||
@@ -247,3 +247,10 @@ wine-shim:
|
||||
$Qln -s rgbshim.sh rgblink
|
||||
$Qln -s rgbshim.sh rgbfix
|
||||
$Qln -s rgbshim.sh rgbgfx
|
||||
|
||||
# Target for the project maintainer to produce distributable release tarballs
|
||||
# of the source code.
|
||||
|
||||
dist:
|
||||
$Qgit ls-files | sed s~^~$${PWD##*/}/~ \
|
||||
| tar -czf rgbds-`git describe --tags | cut -c 2-`.tar.gz -C .. -T -
|
||||
|
||||
@@ -147,7 +147,7 @@ This is the complete list of user-defined variables:
|
||||
``${PREFIX}/bin``.
|
||||
|
||||
- ``mandir``: Location where the manpages will be installed. Defaults to
|
||||
``${PREFIX}/man``.
|
||||
``${PREFIX}/share/man``.
|
||||
|
||||
- ``DESTDIR``: This is prepended to all paths during the installation. It is
|
||||
mainly used for packaging.
|
||||
@@ -158,9 +158,9 @@ This is the complete list of user-defined variables:
|
||||
- ``STRIP``: Whether to strip the installed binaries of debug symbols or not.
|
||||
Defaults to ``-s``.
|
||||
|
||||
- ``BINMODE``: Permissions of the installed binaries. Defaults to ``555``.
|
||||
- ``BINMODE``: Permissions of the installed binaries. Defaults to ``755``.
|
||||
|
||||
- ``MANMODE``: Permissions of the installed manpages. Defaults to ``444``.
|
||||
- ``MANMODE``: Permissions of the installed manpages. Defaults to ``644``.
|
||||
|
||||
- ``CHECKPATCH``: Path of the script ``checkpatch.pl`` of the Linux kernel.
|
||||
Defaults to ``../linux/scripts/checkpatch.pl``.
|
||||
|
||||
@@ -1064,10 +1064,10 @@ Pop register <b class="Sy">AF</b> from the stack. This is roughly equivalent to
|
||||
the following <i class="Em">imaginary</i> instructions:
|
||||
<div class="Bd Pp Bd-indent">
|
||||
<pre>
|
||||
ld f, [sp] ; See below for individual flags
|
||||
inc sp
|
||||
ld a, [sp]
|
||||
inc sp
|
||||
ld f, [sp] ; See below for individual flags
|
||||
</pre>
|
||||
</div>
|
||||
<p class="Pp">Cycles: 3</p>
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
[<code class="Fl"><a href="#g">-g</a></code> <var class="Ar">chars</var>]
|
||||
[<code class="Fl"><a href="#i">-i</a></code> <var class="Ar">path</var>]
|
||||
[<code class="Fl"><a href="#M">-M</a></code> <var class="Ar">depend_file</var>]
|
||||
[<code class="Fl"><a href="#M">-M</a><a href="#G">G</a></code>] [<code class="Fl"><a href="#M">-M</a><a href="#P">P</a></code>]
|
||||
[<code class="Fl"><a href="#M">-M</a><a href="#T">T</a></code> <var class="Ar">target_file</var>]
|
||||
[<code class="Fl"><a href="#M">-M</a><a href="#Q">Q</a></code> <var class="Ar">target_file</var>]
|
||||
[<code class="Fl"><a href="#o">-o</a></code> <var class="Ar">out_file</var>]
|
||||
[<code class="Fl"><a href="#p">-p</a></code> <var class="Ar">pad_value</var>]
|
||||
[<code class="Fl"><a href="#r">-r</a></code> <var class="Ar">recursion_depth</var>]
|
||||
@@ -107,6 +110,35 @@ The <code class="Nm">rgbasm</code> program creates an RGB object file from an
|
||||
<var class="Ar">depend_file</var></dt>
|
||||
<dd>Print <a class="Xr">make(1)</a> dependencies to
|
||||
<var class="Ar">depend_file</var>.</dd>
|
||||
<dt><a class="permalink" href="#MG"><code class="Fl" id="MG">-MG</code></a></dt>
|
||||
<dd>To be used in conjunction with <code class="Fl">-M</code>. This makes
|
||||
<code class="Nm">rgbasm</code> assume that missing files are
|
||||
auto-generated: when <code class="Ic">INCLUDE</code> or
|
||||
<code class="Ic">INCBIN</code> is attempted on a non-existent file, it is
|
||||
added as a dependency, then <code class="Nm">rgbasm</code> exits normally
|
||||
instead of erroring out. This feature is used in automatic updating of
|
||||
makefiles.</dd>
|
||||
<dt><a class="permalink" href="#MP"><code class="Fl" id="MP">-MP</code></a></dt>
|
||||
<dd>When enabled, this causes a phony target to be added for each dependency
|
||||
other than the main file. This prevents <a class="Xr">make(1)</a> from
|
||||
erroring out when dependency files are deleted.</dd>
|
||||
<dt><a class="permalink" href="#MT"><code class="Fl" id="MT">-MT</code></a>
|
||||
<var class="Ar">target_file</var></dt>
|
||||
<dd>Add a target to the rules emitted by <code class="Fl">-M</code>. The exact
|
||||
string provided will be written, including spaces and special characters.
|
||||
<div class="Bd Bd-indent"><code class="Li"><code class="Fl">-MT</code>
|
||||
<code class="Fl">-fileA</code> <code class="Fl">-MT</code>
|
||||
<code class="Fl">-fileB</code></code></div>
|
||||
is equivalent to
|
||||
<div class="Bd Bd-indent"><code class="Li"><code class="Fl">-MT</code>
|
||||
<code class="Fl">-'fileA</code>
|
||||
<code class="Fl">-fileB'</code>.</code></div>
|
||||
If neither this nor <code class="Fl">-MQ</code> is specified, the output
|
||||
file name is used.</dd>
|
||||
<dt><a class="permalink" href="#MQ"><code class="Fl" id="MQ">-MQ</code></a>
|
||||
<var class="Ar">target_file</var></dt>
|
||||
<dd>Same as <code class="Fl">-MT</code>, but additionally escapes any special
|
||||
<a class="Xr">make(1)</a> characters, essentially ‘$’.</dd>
|
||||
<dt><a class="permalink" href="#o"><code class="Fl" id="o">-o</code></a>
|
||||
<var class="Ar">out_file</var>,
|
||||
<code class="Fl">--output</code>
|
||||
@@ -200,10 +232,10 @@ Warnings are diagnostic messages that indicate possibly erroneous behavior that
|
||||
<dt><a class="permalink" href="#Wlong-string"><code class="Fl" id="Wlong-string">-Wlong-string</code></a></dt>
|
||||
<dd>Warn when a string too long to fit in internal buffers is encountered.
|
||||
This warning is enabled by <code class="Fl">-Wall</code>.</dd>
|
||||
<dt><a class="permalink" href="#Wobsolete"><code class="Fl" id="Wobsolete">-Wobsolete</code></a></dt>
|
||||
<dt><a class="permalink" href="#Wno-obsolete"><code class="Fl" id="Wno-obsolete">-Wno-obsolete</code></a></dt>
|
||||
<dd>Warn when obsolete constructs such as the <code class="Ic">jp [hl]</code>
|
||||
instruction or <code class="Ic">HOME</code> section type are encountered.
|
||||
This warning is enabled by <code class="Fl">-Wextra</code>.</dd>
|
||||
instruction or <code class="Ic">HOME</code> section type are
|
||||
encountered.</dd>
|
||||
<dt><a class="permalink" href="#Wshift"><code class="Fl" id="Wshift">-Wshift</code></a></dt>
|
||||
<dd>Warn when shifting right a negative value. Use a division by 2^N
|
||||
instead.</dd>
|
||||
|
||||
@@ -232,7 +232,7 @@ A great number of operators you can use in expressions are available (listed
|
||||
<p class="Pp">Unlike in a lot of languages, and for technical reasons,
|
||||
<code class="Nm">rgbasm</code> still evaluates both operands of
|
||||
‘&&’ and ‘||’.</p>
|
||||
<p class="Pp">! returns 1 if the operand was 0, and 1 otherwise.</p>
|
||||
<p class="Pp">! returns 1 if the operand was 0, and 0 otherwise.</p>
|
||||
</section>
|
||||
<section class="Ss">
|
||||
<h2 class="Ss" id="Fixed__u2010_point_Expressions"><a class="permalink" href="#Fixed__u2010_point_Expressions">Fixed‐point
|
||||
@@ -639,12 +639,9 @@ Before you can start writing code, you must define a section. This tells the
|
||||
<var class="Ar">type</var>[<var class="Ar">addr</var>],
|
||||
<var class="Ar">options</var></code></div>
|
||||
<p class="Pp"><var class="Ar">name</var> is a string enclosed in double quotes,
|
||||
and can be a new name or the name of an existing section. All sections
|
||||
assembled at the same time that have the same name are considered to be the
|
||||
same section, and their code is put together in the object file generated by
|
||||
the assembler. If the type doesn't match, an error occurs. All other
|
||||
sections must have a unique name, even in different source files, or the
|
||||
linker will treat it as an error.</p>
|
||||
and can be a new name or the name of an existing section. If the type
|
||||
doesn't match, an error occurs. All other sections must have a unique name,
|
||||
even in different source files, or the linker will treat it as an error.</p>
|
||||
<p class="Pp">Possible section <var class="Ar">type</var>s are as follows:</p>
|
||||
<dl class="Bl-tag">
|
||||
<dt><a class="permalink" href="#ROM0"><code class="Ic" id="ROM0">ROM0</code></a></dt>
|
||||
@@ -703,11 +700,17 @@ Before you can start writing code, you must define a section. This tells the
|
||||
<dd>Specify which <var class="Ar">bank</var> for the linker to place the
|
||||
section in. See above for possible values for <var class="Ar">bank</var>,
|
||||
depending on <var class="Ar">type</var>.</dd>
|
||||
<dt><a class="permalink" href="#ALIGN"><code class="Ic" id="ALIGN">ALIGN</code></a>[<var class="Ar">align</var>]</dt>
|
||||
<dt><a class="permalink" href="#ALIGN"><code class="Ic" id="ALIGN">ALIGN</code></a>[<var class="Ar">align</var>,
|
||||
<var class="Ar">offset</var>]</dt>
|
||||
<dd>Place the section at an address whose <var class="Ar">align</var>
|
||||
least‐significant bits are zero. This option can be used with
|
||||
<var class="Ar">addr</var>, as long as they don't contradict
|
||||
eachother.</dd>
|
||||
least‐significant bits are equal to <var class="Ar">offset</var>.
|
||||
(Note that <code class="Ic">ALIGN</code>[<var class="Ar">align</var>] is a
|
||||
shorthand for <code class="Ic">ALIGN</code>[<var class="Ar">align</var>,
|
||||
<span class="No">0</span>]). This option can be used with
|
||||
[<var class="Ar">addr</var>], as long as they don't contradict eachother.
|
||||
It's also possible to request alignment in the middle of a section, see
|
||||
<a class="Sx" href="#Requesting_alignment">Requesting alignment</a>
|
||||
below.</dd>
|
||||
</dl>
|
||||
<p class="Pp">If [<var class="Ar">addr</var>] is not specified, the section is
|
||||
considered “floating”; the linker will automatically calculate
|
||||
@@ -724,7 +727,7 @@ Before you can start writing code, you must define a section. This tells the
|
||||
<li>
|
||||
<div class="Bd Pp Bd-indent">
|
||||
<pre>
|
||||
SECTION "CoolStuff",ROMX
|
||||
SECTION "Cool Stuff",ROMX
|
||||
</pre>
|
||||
</div>
|
||||
This switches to the section called “CoolStuff”, creating it
|
||||
@@ -733,14 +736,14 @@ SECTION "CoolStuff",ROMX
|
||||
<li>If it is needed, the the base address of the section can be specified:
|
||||
<div class="Bd Pp Bd-indent">
|
||||
<pre>
|
||||
SECTION "CoolStuff",ROMX[$4567]
|
||||
SECTION "Cool Stuff",ROMX[$4567]
|
||||
</pre>
|
||||
</div>
|
||||
</li>
|
||||
<li>An example with a fixed bank:
|
||||
<div class="Bd Pp Bd-indent">
|
||||
<pre>
|
||||
SECTION "CoolStuff",ROMX[$4567],BANK[3]
|
||||
SECTION "Cool Stuff",ROMX[$4567],BANK[3]
|
||||
</pre>
|
||||
</div>
|
||||
</li>
|
||||
@@ -748,7 +751,7 @@ SECTION "CoolStuff",ROMX[$4567],BANK[3]
|
||||
within the bank, that's also possible:
|
||||
<div class="Bd Pp Bd-indent">
|
||||
<pre>
|
||||
SECTION "CoolStuff",ROMX,BANK[7]
|
||||
SECTION "Cool Stuff",ROMX,BANK[7]
|
||||
</pre>
|
||||
</div>
|
||||
</li>
|
||||
@@ -848,7 +851,8 @@ When you're tight on RAM, you may want to define overlapping blocks of
|
||||
several times per <code class="Nm">rgbasm</code> invocation, and across
|
||||
several invocations. Different declarations are treated and merged
|
||||
identically whether within the same invocation, or different ones.</li>
|
||||
<li>A section cannot be declared both as unionized or non-unionized.</li>
|
||||
<li>If one section has been declared as unionized, all sections with the same
|
||||
name must be declared unionized as well.</li>
|
||||
<li>All declarations must have the same type. For example, even if
|
||||
<a class="Xr" href="rgblink.1.html">rgblink(1)</a>'s <code class="Fl">-w</code> flag is used,
|
||||
<code class="Ic">WRAM0</code> and <code class="Ic">WRAMX</code> types are
|
||||
@@ -865,6 +869,43 @@ When you're tight on RAM, you may want to define overlapping blocks of
|
||||
<a class="Sx" href="#Unions">Unions</a>. Similarly, the size of an unionized
|
||||
section is the largest of all its declarations.</p>
|
||||
</section>
|
||||
<section class="Ss">
|
||||
<h2 class="Ss" id="Section_Fragments"><a class="permalink" href="#Section_Fragments">Section
|
||||
Fragments</a></h2>
|
||||
Section fragments are sections with a small twist: when several of the same name
|
||||
are encountered, they are concatenated instead of producing an error. This
|
||||
works within the same file (paralleling the behavior "plain"
|
||||
sections has in previous versions), but also across object files. However,
|
||||
similarly to <a class="Sx" href="#Unionized_Sections">Unionized Sections</a>,
|
||||
some rules must be followed:
|
||||
<ul class="Bl-bullet Bd-indent">
|
||||
<li>If one section has been declared as fragment, all sections with the same
|
||||
name must be declared fragments as well.</li>
|
||||
<li>All declarations must have the same type. For example, even if
|
||||
<a class="Xr" href="rgblink.1.html">rgblink(1)</a>'s <code class="Fl">-w</code> flag is used,
|
||||
<code class="Ic">WRAM0</code> and <code class="Ic">WRAMX</code> types are
|
||||
still considered different.</li>
|
||||
<li>Different constraints (alignment, bank, etc.) can be specified for each
|
||||
unionized section declaration, but they must all be compatible. For
|
||||
example, alignment must be compatible with any fixed address, all
|
||||
specified banks must be the same, etc.</li>
|
||||
<li>A section fragment may not be unionized; after all, that wouldn't make
|
||||
much sense.</li>
|
||||
</ul>
|
||||
<p class="Pp">When RGBASM merges two fragments, the one encountered later is
|
||||
appended to the one encountered earlier.</p>
|
||||
<p class="Pp">When RGBLINK merges two fragments, the one whose file was
|
||||
specified last is appended to the one whose file was specified first. For
|
||||
example, assuming ‘<code class="Li">bar.o</code>’,
|
||||
‘<code class="Li">baz.o</code>’, and
|
||||
‘<code class="Li">foo.o</code>’ all contain a fragment with
|
||||
the same name, the command</p>
|
||||
<div class="Bd Bd-indent"><code class="Li">rgblink -o rom.gb baz.o foo.o
|
||||
bar.o</code></div>
|
||||
would produce the fragment from ‘<code class="Li">baz.o</code>’
|
||||
first, followed by the one from ‘<code class="Li">foo.o</code>’,
|
||||
and the one from ‘<code class="Li">bar.o</code>’ last.
|
||||
</section>
|
||||
</section>
|
||||
<section class="Sh">
|
||||
<h1 class="Sh" id="SYMBOLS"><a class="permalink" href="#SYMBOLS">SYMBOLS</a></h1>
|
||||
@@ -919,6 +960,8 @@ ThisWillBeExported.too::
|
||||
‘<code class="Li">.local:</code>’. If the former notation
|
||||
is used, then ‘<code class="Li">scope</code>’ must be the
|
||||
actual current scope.</p>
|
||||
<p class="Pp">Local labels may have whitespace before their declaration as
|
||||
the only exception to the rule.</p>
|
||||
<p class="Pp">A label's location (and thus value) is usually not determined
|
||||
until the linking stage, so labels usually cannot be used as constants.
|
||||
However, if the section in which the label is declared has a fixed base
|
||||
@@ -1665,6 +1708,23 @@ DW `00112233
|
||||
number of entries is limited only by the amount of memory in your
|
||||
machine.</p>
|
||||
</section>
|
||||
<section class="Ss">
|
||||
<h2 class="Ss" id="Requesting_alignment"><a class="permalink" href="#Requesting_alignment">Requesting
|
||||
alignment</a></h2>
|
||||
While <code class="Ic">ALIGN</code> as presented in
|
||||
<a class="Sx" href="#SECTIONS">SECTIONS</a> is often useful as-is, sometimes
|
||||
you instead want a particular piece of data (or code) in the middle of the
|
||||
section to be aligned. This is made easier through the use of mid-section
|
||||
<code class="Ic">align</code> <var class="Ar">align</var>,
|
||||
<var class="Ar">offset</var>. It will alter the section's attributes to ensure
|
||||
that the location the <code class="Ic">align</code> directive is at, has its
|
||||
<var class="Ar">align</var> lower bits equal to <var class="Ar">offset</var>.
|
||||
<p class="Pp">If the constraint cannot be met (for example because the section
|
||||
is fixed at an incompatible address), and error is produced. Note that
|
||||
<code class="Ic">align</code> <var class="Ar">align</var> is a shorthand for
|
||||
<code class="Ic">align</code> <var class="Ar">align</var>,
|
||||
<span class="No">0</span>.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section class="Sh">
|
||||
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
|
||||
|
||||
@@ -107,8 +107,10 @@ REPT NumberOfSections
|
||||
; decide (floating bank). This field is only valid for ROMX,
|
||||
; VRAM, WRAMX and SRAM sections.
|
||||
|
||||
LONG Align ; Alignment of this section, expressed as 1 << align. 1 if
|
||||
; not specified.
|
||||
BYTE Align ; Alignment of this section, as N bits. 0 when not specified.
|
||||
|
||||
LONG Ofs ; Offset relative to the alignment specified above.
|
||||
; Must be below 1 << Align.
|
||||
|
||||
IF (Type == ROMX) || (Type == ROM0) ; Sections that can contain data.
|
||||
|
||||
@@ -116,8 +118,6 @@ REPT NumberOfSections
|
||||
|
||||
LONG NumberOfPatches ; Number of patches to apply.
|
||||
|
||||
; These types of sections may have patches
|
||||
|
||||
REPT NumberOfPatches
|
||||
|
||||
STRING SourceFile ; Name of the source file (for printing error
|
||||
@@ -126,6 +126,16 @@ REPT NumberOfSections
|
||||
LONG Offset ; Offset into the section where patch should
|
||||
; be applied (in bytes).
|
||||
|
||||
LONG PCSectionID ; Index within the file of the section in which
|
||||
; PC is located.
|
||||
; This is usually the same section that the
|
||||
; patch should be applied into, except e.g.
|
||||
; with LOAD blocks.
|
||||
|
||||
LONG PCOffset ; PC's offset into the above section.
|
||||
; Used because the section may be floating, so
|
||||
; PC's value is not known to RGBASM.
|
||||
|
||||
BYTE Type ; 0 = BYTE patch.
|
||||
; 1 = little endian WORD patch.
|
||||
; 2 = little endian LONG patch.
|
||||
@@ -152,6 +162,13 @@ REPT NumberOfAssertions
|
||||
|
||||
LONG Offset ; Offset into the section where the assertion is located.
|
||||
|
||||
LONG SectionID ; Index within the file of the section in which PC is
|
||||
; located, or -1 if defined outside a section.
|
||||
|
||||
LONG PCOffset ; PC's offset into the above section.
|
||||
; Used because the section may be floating, so PC's value
|
||||
; is not known to RGBASM.
|
||||
|
||||
BYTE Type ; 0 = Prints the message but allows linking to continue
|
||||
; 1 = Prints the message and evaluates other assertions,
|
||||
; but linking fails afterwards
|
||||
@@ -161,10 +178,6 @@ REPT NumberOfAssertions
|
||||
|
||||
BYTE RPN[RPNSize] ; RPN expression, same as patches. Assert fails if == 0.
|
||||
|
||||
LONG SectionID ; The section number (of this object file) in which this
|
||||
; assert is defined. If it doesn't belong to any specific
|
||||
; section (like a constant), this field has the value -1.
|
||||
|
||||
STRING Message ; A message displayed when the assert fails. If set to
|
||||
; the empty string, a generic message is printed instead.
|
||||
|
||||
@@ -248,7 +261,7 @@ Expressions in the object file are stored as RPN. This is an expression of the
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="permalink" href="#$23"><code class="Li" id="$23">$23</code></a></td>
|
||||
<td><a class="permalink" href="#unary"><code class="Li" id="unary">unary</code></a>!</td>
|
||||
<td><a class="permalink" href="#unary__!"><code class="Li" id="unary__!">unary !</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="permalink" href="#$30"><code class="Li" id="$30">$30</code></a></td>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<table class="Nm">
|
||||
<tr>
|
||||
<td><code class="Nm">rgblink</code></td>
|
||||
<td>[<code class="Fl"><a href="#d">-d</a><a href="#t">t</a><a href="#V">V</a><a href="#v">v</a><a href="#w">w</a></code>] [<code class="Fl"><a href="#l">-l</a></code>
|
||||
<td>[<code class="Fl"><a href="#d">-d</a><a href="#t">t</a><a href="#V">V</a><a href="#v">v</a><a href="#w">w</a><a href="#x">x</a></code>] [<code class="Fl"><a href="#l">-l</a></code>
|
||||
<var class="Ar">linker_script</var>] [<code class="Fl"><a href="#m">-m</a></code>
|
||||
<var class="Ar">map_file</var>] [<code class="Fl"><a href="#n">-n</a></code>
|
||||
<var class="Ar">sym_file</var>] [<code class="Fl"><a href="#O">-O</a></code>
|
||||
@@ -71,7 +71,7 @@ The <code class="Nm">rgblink</code> program links RGB object files, typically
|
||||
<dt><a class="permalink" href="#d"><code class="Fl" id="d">-d</code></a>,
|
||||
<code class="Fl">--dmg</code></dt>
|
||||
<dd>Enable DMG mode. Prohibit the use of sections that doesn't exist on a DMG,
|
||||
such as WRAMX and VRAM bank 1. This option automatically enables
|
||||
such as VRAM bank 1. This option automatically enables
|
||||
<code class="Fl">-w</code>.</dd>
|
||||
<dt><a class="permalink" href="#l"><code class="Fl" id="l">-l</code></a>
|
||||
<var class="Ar">linker_script,</var>
|
||||
@@ -122,7 +122,8 @@ The <code class="Nm">rgblink</code> program links RGB object files, typically
|
||||
<dt><a class="permalink" href="#t"><code class="Fl" id="t">-t</code></a>,
|
||||
<code class="Fl">--tiny</code></dt>
|
||||
<dd>Expand the ROM0 section size from 16 KiB to the full 32 KiB assigned to
|
||||
ROM and prohibit the use of ROMX sections. Useful for ROMs that fit in 32
|
||||
ROM. ROMX sections that are fixed to a bank other than 1 become errors,
|
||||
other ROMX sections are treated as ROM0. Useful for ROMs that fit in 32
|
||||
KiB.</dd>
|
||||
<dt><a class="permalink" href="#V"><code class="Fl" id="V">-V</code></a>,
|
||||
<code class="Fl">--version</code></dt>
|
||||
@@ -133,7 +134,15 @@ The <code class="Nm">rgblink</code> program links RGB object files, typically
|
||||
<dt><a class="permalink" href="#w"><code class="Fl" id="w">-w</code></a>,
|
||||
<code class="Fl">--wramx</code></dt>
|
||||
<dd>Expand the WRAM0 section size from 4 KiB to the full 8 KiB assigned to
|
||||
WRAM and prohibit the use of WRAMX sections.</dd>
|
||||
WRAM. WRAMX sections that are fixed to a bank other than 1 become errors,
|
||||
other WRAMX sections are treated as WRAM0.</dd>
|
||||
<dt><a class="permalink" href="#x"><code class="Fl" id="x">-x</code></a>,
|
||||
<code class="Fl">--nopad</code></dt>
|
||||
<dd>Disables padding the end of the final file. This option automatically
|
||||
enables <code class="Fl">-t</code>. You can use this when not not making a
|
||||
ROM. When making a ROM, be careful that not using this is not a
|
||||
replacement for <a class="Xr" href="rgbfix.1.html">rgbfix(1)</a>'s <code class="Fl">-p</code>
|
||||
option!</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section class="Sh">
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "asm/symbol.h"
|
||||
|
||||
#define MAXUNIONS 128
|
||||
#define MAXMACROARGS 256
|
||||
#define MAXMACROARGS 99999
|
||||
#define MAXINCPATHS 128
|
||||
|
||||
extern int32_t nLineNo;
|
||||
@@ -34,7 +34,6 @@ extern uint32_t unionStart[MAXUNIONS];
|
||||
extern uint32_t unionSize[MAXUNIONS];
|
||||
extern char tzCurrentFileName[_MAX_PATH + 1];
|
||||
extern struct Section *pCurrentSection;
|
||||
extern struct sSymbol *pPCSymbol;
|
||||
extern bool oDontExpandStrings;
|
||||
|
||||
size_t symvaluetostring(char *dest, size_t maxLength, char *sym,
|
||||
|
||||
@@ -25,7 +25,7 @@ struct MacroArgs;
|
||||
|
||||
struct sContext {
|
||||
YY_BUFFER_STATE FlexHandle;
|
||||
struct sSymbol *pMacro;
|
||||
struct Symbol const *pMacro;
|
||||
struct sContext *pNext;
|
||||
char tzFileName[_MAX_PATH + 1];
|
||||
struct MacroArgs *macroArgs;
|
||||
@@ -48,7 +48,7 @@ void fstk_Dump(void);
|
||||
void fstk_DumpToStr(char *buf, size_t len);
|
||||
void fstk_DumpStringExpansions(void);
|
||||
void fstk_AddIncludePath(char *s);
|
||||
bool fstk_RunMacro(char *s, struct MacroArgs *args);
|
||||
void fstk_RunMacro(char *s, struct MacroArgs *args);
|
||||
void fstk_RunRept(uint32_t count, int32_t nReptLineNo);
|
||||
FILE *fstk_FindFile(char const *fname, char **incPathUsed);
|
||||
int32_t fstk_GetLine(void);
|
||||
|
||||
@@ -56,7 +56,7 @@ void setup_lexer(void);
|
||||
|
||||
void yy_set_state(enum eLexerState i);
|
||||
YY_BUFFER_STATE yy_create_buffer(FILE *f);
|
||||
YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size);
|
||||
YY_BUFFER_STATE yy_scan_bytes(char const *mem, uint32_t size);
|
||||
void yy_delete_buffer(YY_BUFFER_STATE buf);
|
||||
void yy_switch_to_buffer(YY_BUFFER_STATE buf);
|
||||
uint32_t lex_FloatAlloc(const struct sLexFloat *tok);
|
||||
|
||||
@@ -20,7 +20,7 @@ struct MacroArgs;
|
||||
|
||||
struct MacroArgs *macro_GetCurrentArgs(void);
|
||||
struct MacroArgs *macro_NewArgs(void);
|
||||
void macro_AppendArg(struct MacroArgs *args, char *s);
|
||||
void macro_AppendArg(struct MacroArgs **args, char *s);
|
||||
void macro_UseNewArgs(struct MacroArgs *args);
|
||||
void macro_FreeArgs(struct MacroArgs *args);
|
||||
char const *macro_GetArg(uint32_t i);
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
struct sOptions {
|
||||
char binary[2];
|
||||
char gbgfx[4];
|
||||
bool exportall;
|
||||
int32_t fillchar;
|
||||
bool haltnop;
|
||||
bool optimizeloads;
|
||||
bool verbose;
|
||||
bool warnings; /* True to enable warnings, false to disable them. */
|
||||
};
|
||||
|
||||
extern char *tzNewMacro;
|
||||
@@ -35,6 +30,10 @@ extern uint32_t curOffset; /* Offset into the current section */
|
||||
|
||||
extern struct sOptions DefaultOptions;
|
||||
extern struct sOptions CurrentOptions;
|
||||
extern bool haltnop;
|
||||
extern bool optimizeloads;
|
||||
extern bool verbose;
|
||||
extern bool warnings; /* True to enable warnings, false to disable them. */
|
||||
|
||||
extern FILE *dependfile;
|
||||
extern char *tzTargetFileName;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define RGBDS_SECTION_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "linkdefs.h"
|
||||
|
||||
@@ -18,11 +19,12 @@ struct Expression;
|
||||
struct Section {
|
||||
char *pzName;
|
||||
enum SectionType nType;
|
||||
bool isUnion;
|
||||
enum SectionModifier modifier;
|
||||
uint32_t size;
|
||||
uint32_t nOrg;
|
||||
uint32_t nBank;
|
||||
uint32_t nAlign;
|
||||
uint8_t nAlign;
|
||||
uint16_t alignOfs;
|
||||
struct Section *pNext;
|
||||
struct Patch *pPatches;
|
||||
uint8_t *tData;
|
||||
@@ -30,22 +32,25 @@ struct Section {
|
||||
|
||||
struct SectionSpec {
|
||||
uint32_t bank;
|
||||
uint32_t alignment;
|
||||
uint8_t alignment;
|
||||
uint16_t alignOfs;
|
||||
};
|
||||
|
||||
struct Section *out_FindSectionByName(const char *pzName);
|
||||
void out_NewSection(char const *pzName, uint32_t secttype, uint32_t org,
|
||||
struct SectionSpec const *attributes, bool isUnion);
|
||||
struct SectionSpec const *attributes,
|
||||
enum SectionModifier mod);
|
||||
void out_SetLoadSection(char const *name, uint32_t secttype, uint32_t org,
|
||||
struct SectionSpec const *attributes);
|
||||
void out_EndLoadSection(void);
|
||||
|
||||
struct Section *sect_GetSymbolSection(void);
|
||||
uint32_t sect_GetOutputOffset(void);
|
||||
void sect_AlignPC(uint8_t alignment, uint16_t offset);
|
||||
|
||||
void out_AbsByte(uint8_t b);
|
||||
void out_AbsByteGroup(uint8_t const *s, int32_t length);
|
||||
void out_Skip(int32_t skip);
|
||||
void out_Skip(int32_t skip, bool ds);
|
||||
void out_String(char const *s);
|
||||
void out_RelByte(struct Expression *expr);
|
||||
void out_RelBytes(struct Expression *expr, uint32_t n);
|
||||
|
||||
@@ -29,53 +29,70 @@ enum SymbolType {
|
||||
SYM_REF // Forward reference to a label
|
||||
};
|
||||
|
||||
struct sSymbol {
|
||||
char tzName[MAXSYMLEN + 1];
|
||||
struct Symbol {
|
||||
char name[MAXSYMLEN + 1];
|
||||
enum SymbolType type;
|
||||
bool isExported; /* Whether the symbol is to be exported */
|
||||
bool isBuiltin; /* Whether the symbol is a built-in */
|
||||
struct sSymbol *pScope;
|
||||
struct Section *pSection;
|
||||
int32_t nValue;
|
||||
uint32_t ulMacroSize;
|
||||
char *pMacro;
|
||||
int32_t (*Callback)(struct sSymbol const *self);
|
||||
char tzFileName[_MAX_PATH + 1]; /* File where the symbol was defined. */
|
||||
uint32_t nFileLine; /* Line where the symbol was defined. */
|
||||
struct Symbol const *scope;
|
||||
struct Section *section;
|
||||
char fileName[_MAX_PATH + 1]; /* File where the symbol was defined. */
|
||||
uint32_t fileLine; /* Line where the symbol was defined. */
|
||||
|
||||
union {
|
||||
struct { /* If sym_IsNumeric */
|
||||
int32_t value;
|
||||
int32_t (*callback)(void);
|
||||
};
|
||||
struct { /* For SYM_MACRO */
|
||||
uint32_t macroSize;
|
||||
char *macro;
|
||||
};
|
||||
};
|
||||
|
||||
uint32_t ID; /* ID of the symbol in the object file (-1 if none) */
|
||||
struct sSymbol *next; /* Next object to output in the object file */
|
||||
struct Symbol *next; /* Next object to output in the object file */
|
||||
};
|
||||
|
||||
static inline bool sym_IsDefined(struct sSymbol const *sym)
|
||||
bool sym_IsPC(struct Symbol const *sym);
|
||||
|
||||
static inline bool sym_IsDefined(struct Symbol const *sym)
|
||||
{
|
||||
return sym->type != SYM_REF;
|
||||
}
|
||||
|
||||
static inline bool sym_IsConstant(struct sSymbol const *sym)
|
||||
static inline struct Section *sym_GetSection(struct Symbol const *sym)
|
||||
{
|
||||
return sym->type == SYM_EQU || sym->type == SYM_SET
|
||||
|| (sym->type == SYM_LABEL && sym->pSection
|
||||
&& sym->pSection->nOrg != -1);
|
||||
return sym_IsPC(sym) ? sect_GetSymbolSection() : sym->section;
|
||||
}
|
||||
|
||||
static inline bool sym_IsNumeric(struct sSymbol const *sym)
|
||||
static inline bool sym_IsConstant(struct Symbol const *sym)
|
||||
{
|
||||
if (sym->type == SYM_LABEL) {
|
||||
struct Section const *sect = sym_GetSection(sym);
|
||||
|
||||
return sect && sect->nOrg != -1;
|
||||
}
|
||||
return sym->type == SYM_EQU || sym->type == SYM_SET;
|
||||
}
|
||||
|
||||
static inline bool sym_IsNumeric(struct Symbol const *sym)
|
||||
{
|
||||
return sym->type == SYM_LABEL || sym->type == SYM_EQU
|
||||
|| sym->type == SYM_SET;
|
||||
}
|
||||
|
||||
static inline bool sym_IsLabel(struct sSymbol const *sym)
|
||||
static inline bool sym_IsLabel(struct Symbol const *sym)
|
||||
{
|
||||
return sym->type == SYM_LABEL || sym->type == SYM_REF;
|
||||
}
|
||||
|
||||
static inline bool sym_IsLocal(struct sSymbol const *sym)
|
||||
static inline bool sym_IsLocal(struct Symbol const *sym)
|
||||
{
|
||||
return sym_IsLabel(sym) && strchr(sym->tzName, '.');
|
||||
return sym_IsLabel(sym) && strchr(sym->name, '.');
|
||||
}
|
||||
|
||||
static inline bool sym_IsExported(struct sSymbol const *sym)
|
||||
static inline bool sym_IsExported(struct Symbol const *sym)
|
||||
{
|
||||
return sym->isExported;
|
||||
}
|
||||
@@ -83,33 +100,32 @@ static inline bool sym_IsExported(struct sSymbol const *sym)
|
||||
/*
|
||||
* Get a string equate's value
|
||||
*/
|
||||
static inline char *sym_GetStringValue(struct sSymbol const *sym)
|
||||
static inline char const *sym_GetStringValue(struct Symbol const *sym)
|
||||
{
|
||||
return sym->pMacro;
|
||||
return sym->macro;
|
||||
}
|
||||
|
||||
void sym_ForEach(void (*func)(struct sSymbol *, void *), void *arg);
|
||||
void sym_ForEach(void (*func)(struct Symbol *, void *), void *arg);
|
||||
|
||||
int32_t sym_GetValue(struct sSymbol const *sym);
|
||||
int32_t sym_GetValue(struct Symbol const *sym);
|
||||
void sym_SetExportAll(bool set);
|
||||
struct sSymbol *sym_AddLocalReloc(char const *tzSym);
|
||||
struct sSymbol *sym_AddReloc(char const *tzSym);
|
||||
void sym_Export(char const *tzSym);
|
||||
struct sSymbol *sym_FindMacro(char const *s);
|
||||
struct sSymbol *sym_AddEqu(char const *tzSym, int32_t value);
|
||||
struct sSymbol *sym_AddSet(char const *tzSym, int32_t value);
|
||||
void sym_Init(void);
|
||||
struct Symbol *sym_AddLocalReloc(char const *symName);
|
||||
struct Symbol *sym_AddReloc(char const *symName);
|
||||
void sym_Export(char const *symName);
|
||||
struct Symbol *sym_AddEqu(char const *symName, int32_t value);
|
||||
struct Symbol *sym_AddSet(char const *symName, int32_t value);
|
||||
uint32_t sym_GetPCValue(void);
|
||||
uint32_t sym_GetConstantValue(char const *s);
|
||||
struct sSymbol *sym_FindSymbol(char const *tzName);
|
||||
char *sym_GetStringValue(struct sSymbol const *sym);
|
||||
struct sSymbol *sym_AddMacro(char const *tzSym, int32_t nDefLineNo);
|
||||
struct sSymbol *sym_Ref(char const *tzSym);
|
||||
struct sSymbol *sym_AddString(char const *tzSym, char const *tzValue);
|
||||
struct Symbol *sym_FindSymbol(char const *symName);
|
||||
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo);
|
||||
struct Symbol *sym_Ref(char const *symName);
|
||||
struct Symbol *sym_AddString(char const *symName, char const *value);
|
||||
uint32_t sym_GetDefinedValue(char const *s);
|
||||
void sym_Purge(char const *tzName);
|
||||
void sym_Purge(char const *symName);
|
||||
void sym_Init(void);
|
||||
|
||||
/* Functions to save and restore the current symbol scope. */
|
||||
struct sSymbol *sym_GetCurrentSymbolScope(void);
|
||||
void sym_SetCurrentSymbolScope(struct sSymbol *pNewScope);
|
||||
struct Symbol *sym_GetCurrentSymbolScope(void);
|
||||
void sym_SetCurrentSymbolScope(struct Symbol *newScope);
|
||||
|
||||
#endif /* RGBDS_SYMBOL_H */
|
||||
|
||||
@@ -17,6 +17,7 @@ enum WarningID {
|
||||
WARNING_ASSERT,
|
||||
WARNING_BUILTIN_ARG,
|
||||
WARNING_DIV,
|
||||
WARNING_EMPTY_DATA_DIRECTIVE,
|
||||
WARNING_EMPTY_ENTRY,
|
||||
WARNING_LARGE_CONSTANT,
|
||||
WARNING_LONG_STR,
|
||||
|
||||
6
include/extern/getopt.h
vendored
6
include/extern/getopt.h
vendored
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2005-2019 Rich Felker, et al.
|
||||
* Copyright © 2005-2020 Rich Felker, et al.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@@ -23,8 +23,8 @@
|
||||
|
||||
/* This implementation was taken from musl and modified for RGBDS */
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
#define _GETOPT_H
|
||||
#ifndef RGBDS_EXTERN_GETOPT_H
|
||||
#define RGBDS_EXTERN_GETOPT_H
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind, opterr, optopt, optreset;
|
||||
|
||||
@@ -83,7 +83,7 @@ struct Mapfile {
|
||||
int size;
|
||||
};
|
||||
|
||||
int depth, colors;
|
||||
extern int depth, colors;
|
||||
|
||||
#include "gfx/makepng.h"
|
||||
#include "gfx/gb.h"
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
#define RGBDS_LINK_HASHMAP_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define HASH_NB_BITS 32
|
||||
#define HALF_HASH_NB_BITS 16
|
||||
_Static_assert(HALF_HASH_NB_BITS * 2 == HASH_NB_BITS, "");
|
||||
static_assert(HALF_HASH_NB_BITS * 2 == HASH_NB_BITS, "");
|
||||
#define HASHMAP_NB_BUCKETS (1 << HALF_HASH_NB_BITS)
|
||||
|
||||
/* HashMapEntry is internal, please do not attempt to use it */
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
/* Variables related to CLI options */
|
||||
extern bool isDmgMode;
|
||||
extern char const *linkerScriptName;
|
||||
extern char *linkerScriptName;
|
||||
extern char const *mapFileName;
|
||||
extern char const *symFileName;
|
||||
extern char const *overlayFileName;
|
||||
@@ -25,6 +27,7 @@ extern uint8_t padValue;
|
||||
extern bool is32kMode;
|
||||
extern bool beVerbose;
|
||||
extern bool isWRA0Mode;
|
||||
extern bool disablePadding;
|
||||
|
||||
/* Helper macro for printing verbose-mode messages */
|
||||
#define verbosePrint(...) do { \
|
||||
@@ -32,13 +35,17 @@ extern bool isWRA0Mode;
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
void error(char const *fmt, ...);
|
||||
|
||||
noreturn_ void fatal(char const *fmt, ...);
|
||||
|
||||
/**
|
||||
* Opens a file if specified, and aborts on error.
|
||||
* @param fileName The name of the file to open; if NULL, no file will be opened
|
||||
* @param mode The mode to open the file with
|
||||
* @return A pointer to a valid FILE structure, or NULL if fileName was NULL
|
||||
*/
|
||||
FILE * openFile(char const *fileName, char const *mode);
|
||||
FILE *openFile(char const *fileName, char const *mode);
|
||||
|
||||
#define closeFile(file) do { \
|
||||
FILE *tmp = file; \
|
||||
|
||||
@@ -20,13 +20,12 @@
|
||||
struct Assertion {
|
||||
struct Patch patch;
|
||||
// enum AssertionType type; The `patch`'s field is instead re-used
|
||||
struct Section *section;
|
||||
char *message;
|
||||
/*
|
||||
* This would be redundant with `.section->fileSymbols`... but
|
||||
* `section` is sometimes NULL!
|
||||
*/
|
||||
struct Symbol ** fileSymbols;
|
||||
struct Symbol **fileSymbols;
|
||||
|
||||
struct Assertion *next;
|
||||
};
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "linkdefs.h"
|
||||
|
||||
struct Section;
|
||||
|
||||
struct AttachedSymbol {
|
||||
struct Symbol *symbol;
|
||||
struct AttachedSymbol *next;
|
||||
@@ -27,23 +29,29 @@ struct AttachedSymbol {
|
||||
struct Patch {
|
||||
char *fileName;
|
||||
int32_t offset;
|
||||
uint32_t pcSectionID;
|
||||
uint32_t pcOffset;
|
||||
enum PatchType type;
|
||||
int32_t rpnSize;
|
||||
uint8_t *rpnExpression;
|
||||
|
||||
struct Section const *pcSection;
|
||||
};
|
||||
|
||||
struct Section {
|
||||
/* Info contained in the object files */
|
||||
char *name;
|
||||
uint16_t size;
|
||||
uint16_t offset;
|
||||
enum SectionType type;
|
||||
bool isUnion;
|
||||
enum SectionModifier modifier;
|
||||
bool isAddressFixed;
|
||||
uint16_t org;
|
||||
bool isBankFixed;
|
||||
uint32_t bank;
|
||||
bool isAlignFixed;
|
||||
uint16_t alignMask;
|
||||
uint16_t alignOfs;
|
||||
uint8_t *data; /* Array of size `size`*/
|
||||
uint32_t nbPatches;
|
||||
struct Patch *patches;
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define RGBDS_OBJECT_VERSION_STRING "RGB%1hhu"
|
||||
#define RGBDS_OBJECT_VERSION_NUMBER (uint8_t)9
|
||||
#define RGBDS_OBJECT_REV 3
|
||||
#define RGBDS_OBJECT_VERSION_STRING "RGB%1u"
|
||||
#define RGBDS_OBJECT_VERSION_NUMBER 9U
|
||||
#define RGBDS_OBJECT_REV 5U
|
||||
|
||||
enum AssertionType {
|
||||
ASSERT_WARN,
|
||||
@@ -73,6 +73,14 @@ enum SectionType {
|
||||
SECTTYPE_INVALID
|
||||
};
|
||||
|
||||
enum SectionModifier {
|
||||
SECTION_NORMAL,
|
||||
SECTION_UNION,
|
||||
SECTION_FRAGMENT
|
||||
};
|
||||
|
||||
extern char const * const sectionModNames[];
|
||||
|
||||
/**
|
||||
* Tells whether a section has data in its object file definition,
|
||||
* depending on type.
|
||||
|
||||
35
include/platform.h
Normal file
35
include/platform.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 2020 RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* platform-specific hacks */
|
||||
|
||||
#ifndef RGBDS_PLATFORM_H
|
||||
#define RGBDS_PLATFORM_H
|
||||
|
||||
/* MSVC doesn't have strncasecmp, use a suitable replacement */
|
||||
#ifdef _MSC_VER
|
||||
# include <string.h>
|
||||
# define strncasecmp _strnicmp
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
/* MSVC has deprecated strdup in favor of _strdup */
|
||||
#ifdef _MSC_VER
|
||||
# define strdup _strdup
|
||||
#endif
|
||||
|
||||
/* MSVC prefixes the names of S_* macros with underscores,
|
||||
and doesn't define any S_IS* macros. Define them ourselves */
|
||||
#ifdef _MSC_VER
|
||||
# define S_IFMT _S_IFMT
|
||||
# define S_IFDIR _S_IFDIR
|
||||
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
|
||||
#endif /* RGBDS_PLATFORM_H */
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#define PACKAGE_VERSION_MAJOR (0)
|
||||
#define PACKAGE_VERSION_MINOR (4)
|
||||
#define PACKAGE_VERSION_PATCH (0)
|
||||
#define PACKAGE_VERSION_PATCH (1)
|
||||
|
||||
const char *get_package_version_string(void);
|
||||
|
||||
|
||||
100
src/CMakeLists.txt
Normal file
100
src/CMakeLists.txt
Normal file
@@ -0,0 +1,100 @@
|
||||
#
|
||||
# This file is part of RGBDS.
|
||||
#
|
||||
# Copyright (c) 2020 RGBDS contributors.
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
|
||||
set(common_src
|
||||
"extern/err.c"
|
||||
"extern/getopt.c"
|
||||
"version.c"
|
||||
)
|
||||
|
||||
BISON_TARGET(ASMy "asm/asmy.y"
|
||||
"${PROJECT_SOURCE_DIR}/src/asm/asmy.c"
|
||||
DEFINES_FILE "${PROJECT_SOURCE_DIR}/src/asm/asmy.h"
|
||||
)
|
||||
|
||||
# Lexer is not present yet
|
||||
if(False) # FLEX_FOUND
|
||||
FLEX_TARGET(Lexer "asm/lexer.l"
|
||||
"${PROJECT_SOURCE_DIR}/src/asm/lexer.c"
|
||||
)
|
||||
ADD_FLEX_BISON_DEPENDENCY(Lexer ASMy)
|
||||
set(Lexer_SOURCE "${FLEX_Lexer_OUTPUTS}")
|
||||
else()
|
||||
set(Lexer_SOURCE "asm/lexer.c")
|
||||
endif()
|
||||
|
||||
set(rgbasm_src
|
||||
"${BISON_ASMy_OUTPUT_SOURCE}"
|
||||
"${Lexer_SOURCE}"
|
||||
"asm/charmap.c"
|
||||
"asm/fstack.c"
|
||||
"asm/globlex.c"
|
||||
"asm/macro.c"
|
||||
"asm/main.c"
|
||||
"asm/math.c"
|
||||
"asm/output.c"
|
||||
"asm/rpn.c"
|
||||
"asm/section.c"
|
||||
"asm/symbol.c"
|
||||
"asm/util.c"
|
||||
"asm/warning.c"
|
||||
"extern/utf8decoder.c"
|
||||
"hashmap.c"
|
||||
"linkdefs.c"
|
||||
)
|
||||
|
||||
set(rgbfix_src
|
||||
"fix/main.c"
|
||||
)
|
||||
|
||||
set(rgbgfx_src
|
||||
"gfx/gb.c"
|
||||
"gfx/main.c"
|
||||
"gfx/makepng.c"
|
||||
)
|
||||
|
||||
set(rgblink_src
|
||||
"link/assign.c"
|
||||
"link/main.c"
|
||||
"link/object.c"
|
||||
"link/output.c"
|
||||
"link/patch.c"
|
||||
"link/script.c"
|
||||
"link/section.c"
|
||||
"link/symbol.c"
|
||||
"hashmap.c"
|
||||
"linkdefs.c"
|
||||
)
|
||||
|
||||
foreach(PROG "asm" "fix" "gfx" "link")
|
||||
add_executable(rgb${PROG}
|
||||
${rgb${PROG}_src}
|
||||
${common_src}
|
||||
)
|
||||
install(TARGETS rgb${PROG} RUNTIME DESTINATION bin)
|
||||
endforeach()
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 2.8.12)
|
||||
add_definitions(${PNG_DEFINITIONS})
|
||||
include_directories(${PNG_INCLUDE_DIRS})
|
||||
target_link_libraries(rgbgfx ${PNG_LIBRARIES})
|
||||
else()
|
||||
target_compile_definitions(rgbgfx PRIVATE ${PNG_DEFINITIONS})
|
||||
target_include_directories(rgbgfx PRIVATE ${PNG_INCLUDE_DIRS})
|
||||
target_link_libraries(rgbgfx PRIVATE ${PNG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
include(CheckLibraryExists)
|
||||
check_library_exists("m" "sin" "" HAS_LIBM)
|
||||
if(HAS_LIBM)
|
||||
if(CMAKE_VERSION VERSION_LESS 2.8.12)
|
||||
target_link_libraries(rgbasm LINK_PRIVATE "m")
|
||||
else()
|
||||
target_link_libraries(rgbasm PRIVATE "m")
|
||||
endif()
|
||||
endif()
|
||||
@@ -9,12 +9,12 @@
|
||||
%{
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "asm/asm.h"
|
||||
#include "asm/charmap.h"
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "extern/utf8decoder.h"
|
||||
|
||||
#include "linkdefs.h"
|
||||
#include "platform.h" // strncasecmp, strdup
|
||||
|
||||
uint32_t nListCountEmpty;
|
||||
char *tzNewMacro;
|
||||
@@ -43,7 +44,7 @@ size_t symvaluetostring(char *dest, size_t maxLength, char *symName,
|
||||
const char *mode)
|
||||
{
|
||||
size_t length;
|
||||
struct sSymbol *sym = sym_FindSymbol(symName);
|
||||
struct Symbol *sym = sym_FindSymbol(symName);
|
||||
|
||||
if (sym && sym->type == SYM_EQUS) {
|
||||
char const *src = sym_GetStringValue(sym);
|
||||
@@ -79,7 +80,7 @@ size_t symvaluetostring(char *dest, size_t maxLength, char *symName,
|
||||
strncpy(dest, write_ptr, maxLength + 1);
|
||||
} else {
|
||||
fullLength = snprintf(dest, maxLength + 1,
|
||||
mode ? mode : "$%X",
|
||||
mode ? mode : "$%" PRIX32,
|
||||
value);
|
||||
}
|
||||
|
||||
@@ -495,6 +496,7 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len)
|
||||
char tzString[MAXSTRLEN + 1];
|
||||
struct Expression sVal;
|
||||
int32_t nConstValue;
|
||||
enum SectionModifier sectMod;
|
||||
struct SectionSpec sectSpec;
|
||||
struct MacroArgs *macroArg;
|
||||
enum AssertionType assertType;
|
||||
@@ -569,7 +571,7 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len)
|
||||
%token T_POP_IF T_POP_ELIF T_POP_ELSE T_POP_ENDC
|
||||
%token T_POP_EXPORT T_POP_GLOBAL T_POP_XDEF
|
||||
%token T_POP_DB T_POP_DS T_POP_DW T_POP_DL
|
||||
%token T_POP_SECTION
|
||||
%token T_POP_SECTION T_POP_FRAGMENT
|
||||
%token T_POP_RB
|
||||
%token T_POP_RW
|
||||
%token T_POP_RL
|
||||
@@ -599,7 +601,7 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len)
|
||||
%token T_SECT_WRAM0 T_SECT_VRAM T_SECT_ROMX T_SECT_ROM0 T_SECT_HRAM
|
||||
%token T_SECT_WRAMX T_SECT_SRAM T_SECT_OAM
|
||||
|
||||
%type <nConstValue> sectunion
|
||||
%type <sectMod> sectmod
|
||||
%type <macroArg> macroargs
|
||||
|
||||
%token T_Z80_ADC T_Z80_ADD T_Z80_AND
|
||||
@@ -710,8 +712,7 @@ macro : T_ID {
|
||||
yy_set_state(LEX_STATE_MACROARGS);
|
||||
} macroargs {
|
||||
yy_set_state(LEX_STATE_NORMAL);
|
||||
if (!fstk_RunMacro($1, $3))
|
||||
fatalerror("Macro '%s' not defined", $1);
|
||||
fstk_RunMacro($1, $3);
|
||||
}
|
||||
;
|
||||
|
||||
@@ -720,10 +721,10 @@ macroargs : /* empty */ {
|
||||
}
|
||||
| T_STRING {
|
||||
$$ = macro_NewArgs();
|
||||
macro_AppendArg($$, strdup($1));
|
||||
macro_AppendArg(&($$), strdup($1));
|
||||
}
|
||||
| macroargs ',' T_STRING {
|
||||
macro_AppendArg($$, strdup($3));
|
||||
macro_AppendArg(&($$), strdup($3));
|
||||
}
|
||||
;
|
||||
|
||||
@@ -774,6 +775,26 @@ simple_pseudoop : include
|
||||
| popo
|
||||
| pusho
|
||||
| opt
|
||||
| align
|
||||
;
|
||||
|
||||
align : T_OP_ALIGN uconst {
|
||||
if ($2 > 16)
|
||||
yyerror("Alignment must be between 0 and 16, not %u",
|
||||
$2);
|
||||
else
|
||||
sect_AlignPC($2, 0);
|
||||
}
|
||||
| T_OP_ALIGN uconst ',' uconst {
|
||||
if ($2 > 16)
|
||||
yyerror("Alignment must be between 0 and 16, not %u",
|
||||
$2);
|
||||
else if ($4 >= 1 << $2)
|
||||
yyerror("Offset must be between 0 and %u, not %u",
|
||||
(1 << $2) - 1, $4);
|
||||
else
|
||||
sect_AlignPC($2, $4);
|
||||
}
|
||||
;
|
||||
|
||||
opt : T_POP_OPT {
|
||||
@@ -976,7 +997,7 @@ endu : T_POP_ENDU {
|
||||
}
|
||||
;
|
||||
|
||||
ds : T_POP_DS uconst { out_Skip($2); }
|
||||
ds : T_POP_DS uconst { out_Skip($2, true); }
|
||||
| T_POP_DS uconst ',' reloc_8bit {
|
||||
out_RelBytes(&$4, $2);
|
||||
}
|
||||
@@ -1088,10 +1109,10 @@ popc : T_POP_POPC { charmap_Pop(); }
|
||||
printt : T_POP_PRINTT string { printf("%s", $2); }
|
||||
;
|
||||
|
||||
printv : T_POP_PRINTV const { printf("$%X", $2); }
|
||||
printv : T_POP_PRINTV const { printf("$%" PRIX32, $2); }
|
||||
;
|
||||
|
||||
printi : T_POP_PRINTI const { printf("%d", $2); }
|
||||
printi : T_POP_PRINTI const { printf("%" PRId32, $2); }
|
||||
;
|
||||
|
||||
printf : T_POP_PRINTF const { math_Print($2); }
|
||||
@@ -1170,7 +1191,7 @@ constlist_8bit : constlist_8bit_entry
|
||||
;
|
||||
|
||||
constlist_8bit_entry : /* empty */ {
|
||||
out_Skip(1);
|
||||
out_Skip(1, false);
|
||||
nListCountEmpty++;
|
||||
}
|
||||
| reloc_8bit_no_str { out_RelByte(&$1); }
|
||||
@@ -1188,7 +1209,7 @@ constlist_16bit : constlist_16bit_entry
|
||||
;
|
||||
|
||||
constlist_16bit_entry : /* empty */ {
|
||||
out_Skip(2);
|
||||
out_Skip(2, false);
|
||||
nListCountEmpty++;
|
||||
}
|
||||
| reloc_16bit { out_RelWord(&$1); }
|
||||
@@ -1199,7 +1220,7 @@ constlist_32bit : constlist_32bit_entry
|
||||
;
|
||||
|
||||
constlist_32bit_entry : /* empty */ {
|
||||
out_Skip(4);
|
||||
out_Skip(4, false);
|
||||
nListCountEmpty++;
|
||||
}
|
||||
| relocexpr { out_RelLong(&$1); }
|
||||
@@ -1314,7 +1335,7 @@ relocexpr_no_str : scoped_id { rpn_Symbol(&$$, $1); }
|
||||
| T_OP_DEF {
|
||||
oDontExpandStrings = true;
|
||||
} '(' scoped_id ')' {
|
||||
struct sSymbol const *sym = sym_FindSymbol($4);
|
||||
struct Symbol const *sym = sym_FindSymbol($4);
|
||||
|
||||
rpn_Number(&$$, !!sym);
|
||||
|
||||
@@ -1418,13 +1439,15 @@ string : T_STRING {
|
||||
}
|
||||
;
|
||||
|
||||
section : T_POP_SECTION sectunion string ',' sectiontype sectorg sectattrs {
|
||||
section : T_POP_SECTION sectmod string ',' sectiontype sectorg sectattrs {
|
||||
out_NewSection($3, $5, $6, &$7, $2);
|
||||
}
|
||||
;
|
||||
|
||||
sectunion : /* empty */ { $$ = false; }
|
||||
| T_POP_UNION { $$ = true; }
|
||||
sectmod : /* empty */ { $$ = SECTION_NORMAL; }
|
||||
| T_POP_UNION { $$ = SECTION_UNION; }
|
||||
| T_POP_FRAGMENT{ $$ = SECTION_FRAGMENT; }
|
||||
;
|
||||
|
||||
sectiontype : T_SECT_WRAM0 { $$ = SECTTYPE_WRAM0; }
|
||||
| T_SECT_VRAM { $$ = SECTTYPE_VRAM; }
|
||||
@@ -1449,15 +1472,29 @@ sectorg : /* empty */ { $$ = -1; }
|
||||
|
||||
sectattrs : /* empty */ {
|
||||
$$.alignment = 0;
|
||||
$$.alignOfs = 0;
|
||||
$$.bank = -1;
|
||||
}
|
||||
| sectattrs ',' T_OP_ALIGN '[' uconst ']' {
|
||||
if ($5 < 0 || $5 > 16)
|
||||
yyerror("Alignment must be between 0 and 16 bits, not %u",
|
||||
if ($5 > 16)
|
||||
yyerror("Alignment must be between 0 and 16, not %u",
|
||||
$5);
|
||||
else
|
||||
$$.alignment = $5;
|
||||
}
|
||||
| sectattrs ',' T_OP_ALIGN '[' uconst ',' uconst ']' {
|
||||
if ($5 > 16) {
|
||||
yyerror("Alignment must be between 0 and 16, not %u",
|
||||
$5);
|
||||
} else {
|
||||
$$.alignment = $5;
|
||||
if ($7 >= 1 << $$.alignment)
|
||||
yyerror("Alignment offset must not be greater than alignment (%u < %u)",
|
||||
$7, 1 << $$.alignment);
|
||||
else
|
||||
$$.alignOfs = $7;
|
||||
}
|
||||
}
|
||||
| sectattrs ',' T_OP_BANK '[' uconst ']' {
|
||||
/* We cannot check the validity of this now */
|
||||
$$.bank = $5;
|
||||
@@ -1584,7 +1621,7 @@ z80_ei : T_Z80_EI { out_AbsByte(0xFB); }
|
||||
|
||||
z80_halt : T_Z80_HALT {
|
||||
out_AbsByte(0x76);
|
||||
if (CurrentOptions.haltnop)
|
||||
if (haltnop)
|
||||
out_AbsByte(0x00);
|
||||
}
|
||||
;
|
||||
@@ -1684,8 +1721,8 @@ z80_ld_mem : T_Z80_LD op_mem_ind ',' T_MODE_SP {
|
||||
out_RelWord(&$2);
|
||||
}
|
||||
| T_Z80_LD op_mem_ind ',' T_MODE_A {
|
||||
if (CurrentOptions.optimizeloads &&
|
||||
(rpn_isKnown(&$2)) && ($2.nVal >= 0xFF00)) {
|
||||
if (optimizeloads && rpn_isKnown(&$2)
|
||||
&& $2.nVal >= 0xFF00) {
|
||||
out_AbsByte(0xE0);
|
||||
out_AbsByte($2.nVal & 0xFF);
|
||||
rpn_Free(&$2);
|
||||
@@ -1732,8 +1769,8 @@ z80_ld_a : T_Z80_LD reg_r ',' T_MODE_C_IND {
|
||||
}
|
||||
| T_Z80_LD reg_r ',' op_mem_ind {
|
||||
if ($2 == REG_A) {
|
||||
if (CurrentOptions.optimizeloads &&
|
||||
(rpn_isKnown(&$4)) && ($4.nVal >= 0xFF00)) {
|
||||
if (optimizeloads && rpn_isKnown(&$4)
|
||||
&& $4.nVal >= 0xFF00) {
|
||||
out_AbsByte(0xF0);
|
||||
out_AbsByte($4.nVal & 0xFF);
|
||||
rpn_Free(&$4);
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
* FileStack routines
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "asm/fstack.h"
|
||||
#include "asm/lexer.h"
|
||||
@@ -29,12 +29,13 @@
|
||||
|
||||
#include "extern/err.h"
|
||||
|
||||
#include "platform.h" // S_ISDIR (stat macro)
|
||||
#include "types.h"
|
||||
|
||||
static struct sContext *pFileStack;
|
||||
static unsigned int nFileStackDepth;
|
||||
unsigned int nMaxRecursionDepth;
|
||||
static struct sSymbol *pCurrentMacro;
|
||||
static struct Symbol const *pCurrentMacro;
|
||||
static YY_BUFFER_STATE CurrentFlexHandle;
|
||||
static FILE *pCurrentFile;
|
||||
static uint32_t nCurrentStatus;
|
||||
@@ -69,7 +70,7 @@ static void pushcontext(void)
|
||||
struct sContext **ppFileStack;
|
||||
|
||||
if (++nFileStackDepth > nMaxRecursionDepth)
|
||||
fatalerror("Recursion limit (%d) exceeded", nMaxRecursionDepth);
|
||||
fatalerror("Recursion limit (%u) exceeded", nMaxRecursionDepth);
|
||||
|
||||
ppFileStack = &pFileStack;
|
||||
while (*ppFileStack)
|
||||
@@ -271,12 +272,12 @@ void fstk_Dump(void)
|
||||
pLastFile = pFileStack;
|
||||
|
||||
while (pLastFile) {
|
||||
fprintf(stderr, "%s(%d) -> ", pLastFile->tzFileName,
|
||||
fprintf(stderr, "%s(%" PRId32 ") -> ", pLastFile->tzFileName,
|
||||
pLastFile->nLine);
|
||||
pLastFile = pLastFile->pNext;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s(%d)", tzCurrentFileName, nLineNo);
|
||||
fprintf(stderr, "%s(%" PRId32 ")", tzCurrentFileName, nLineNo);
|
||||
}
|
||||
|
||||
void fstk_DumpToStr(char *buf, size_t buflen)
|
||||
@@ -286,7 +287,7 @@ void fstk_DumpToStr(char *buf, size_t buflen)
|
||||
size_t len = buflen;
|
||||
|
||||
while (pLastFile) {
|
||||
retcode = snprintf(&buf[buflen - len], len, "%s(%d) -> ",
|
||||
retcode = snprintf(&buf[buflen - len], len, "%s(%" PRId32 ") -> ",
|
||||
pLastFile->tzFileName, pLastFile->nLine);
|
||||
if (retcode < 0)
|
||||
fatalerror("Failed to dump file stack to string: %s",
|
||||
@@ -298,8 +299,8 @@ void fstk_DumpToStr(char *buf, size_t buflen)
|
||||
pLastFile = pLastFile->pNext;
|
||||
}
|
||||
|
||||
retcode = snprintf(&buf[buflen - len], len, "%s(%d)", tzCurrentFileName,
|
||||
nLineNo);
|
||||
retcode = snprintf(&buf[buflen - len], len, "%s(%" PRId32 ")",
|
||||
tzCurrentFileName, nLineNo);
|
||||
if (retcode < 0)
|
||||
fatalerror("Failed to dump file stack to string: %s",
|
||||
strerror(errno));
|
||||
@@ -434,7 +435,7 @@ void fstk_RunInclude(char *tzFileName)
|
||||
nCurrentStatus = STAT_isInclude;
|
||||
snprintf(tzCurrentFileName, sizeof(tzCurrentFileName), "%s%s",
|
||||
incPathUsed, tzFileName);
|
||||
if (CurrentOptions.verbose)
|
||||
if (verbose)
|
||||
printf("Assembling %s\n", tzCurrentFileName);
|
||||
pCurrentFile = f;
|
||||
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
|
||||
@@ -449,52 +450,38 @@ void fstk_RunInclude(char *tzFileName)
|
||||
/*
|
||||
* Set up a macro for parsing
|
||||
*/
|
||||
bool fstk_RunMacro(char *s, struct MacroArgs *args)
|
||||
void fstk_RunMacro(char *s, struct MacroArgs *args)
|
||||
{
|
||||
struct sSymbol *sym = sym_FindMacro(s);
|
||||
struct Symbol const *sym = sym_FindSymbol(s);
|
||||
int nPrintedChars;
|
||||
|
||||
if (sym == NULL || sym->pMacro == NULL)
|
||||
return false;
|
||||
if (sym == NULL) {
|
||||
yyerror("Macro \"%s\" not defined", s);
|
||||
return;
|
||||
}
|
||||
if (sym->type != SYM_MACRO) {
|
||||
yyerror("\"%s\" is not a macro", s);
|
||||
return;
|
||||
}
|
||||
|
||||
pushcontext();
|
||||
macro_SetUniqueID(nMacroCount++);
|
||||
/* Minus 1 because there is a newline at the beginning of the buffer */
|
||||
nLineNo = sym->nFileLine - 1;
|
||||
nLineNo = sym->fileLine - 1;
|
||||
macro_UseNewArgs(args);
|
||||
nCurrentStatus = STAT_isMacro;
|
||||
nPrintedChars = snprintf(tzCurrentFileName, _MAX_PATH + 1,
|
||||
"%s::%s", sym->tzFileName, s);
|
||||
"%s::%s", sym->fileName, s);
|
||||
if (nPrintedChars > _MAX_PATH) {
|
||||
popcontext();
|
||||
fatalerror("File name + macro name is too large to fit into buffer");
|
||||
}
|
||||
|
||||
pCurrentMacro = sym;
|
||||
CurrentFlexHandle = yy_scan_bytes(pCurrentMacro->pMacro,
|
||||
strlen(pCurrentMacro->pMacro));
|
||||
/* TODO: why is `strlen` being used when there's a macro size field? */
|
||||
CurrentFlexHandle = yy_scan_bytes(pCurrentMacro->macro,
|
||||
strlen(pCurrentMacro->macro));
|
||||
yy_switch_to_buffer(CurrentFlexHandle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a stringequate for parsing
|
||||
*/
|
||||
void fstk_RunString(char *s)
|
||||
{
|
||||
const struct sSymbol *pSym = sym_FindSymbol(s);
|
||||
|
||||
if (pSym != NULL) {
|
||||
pushcontext();
|
||||
nCurrentStatus = STAT_isMacroArg;
|
||||
strcpy(tzCurrentFileName, s);
|
||||
CurrentFlexHandle =
|
||||
yy_scan_bytes(pSym->pMacro, strlen(pSym->pMacro));
|
||||
yy_switch_to_buffer(CurrentFlexHandle);
|
||||
} else {
|
||||
yyerror("No such string symbol '%s'", s);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -544,8 +531,8 @@ void fstk_Init(char *pFileName)
|
||||
} else {
|
||||
pCurrentFile = fopen(pFileName, "rb");
|
||||
if (pCurrentFile == NULL)
|
||||
yyerror("Unable to open file '%s': %s", pFileName,
|
||||
strerror(errno));
|
||||
fatalerror("Unable to open file '%s': %s", pFileName,
|
||||
strerror(errno));
|
||||
}
|
||||
nFileStackDepth = 0;
|
||||
|
||||
|
||||
@@ -277,10 +277,10 @@ uint32_t ParseSymbol(char *src, uint32_t size)
|
||||
|
||||
/* If the symbol is an EQUS, expand it */
|
||||
if (!oDontExpandStrings) {
|
||||
struct sSymbol const *sym = sym_FindSymbol(dest);
|
||||
struct Symbol const *sym = sym_FindSymbol(dest);
|
||||
|
||||
if (sym && sym->type == SYM_EQUS) {
|
||||
char *s;
|
||||
char const *s;
|
||||
|
||||
lex_BeginStringExpansion(dest);
|
||||
|
||||
@@ -442,6 +442,7 @@ const struct sLexInitString lexer_strings[] = {
|
||||
|
||||
{"def", T_OP_DEF},
|
||||
|
||||
{"fragment", T_POP_FRAGMENT},
|
||||
{"bank", T_OP_BANK},
|
||||
{"align", T_OP_ALIGN},
|
||||
|
||||
@@ -654,6 +655,7 @@ void setup_lexer(void)
|
||||
lex_FloatAddFirstRange(id, 'a', 'z');
|
||||
lex_FloatAddFirstRange(id, 'A', 'Z');
|
||||
lex_FloatAddFirstRange(id, '_', '_');
|
||||
lex_FloatAddSecondRange(id, '.', '.');
|
||||
lex_FloatAddSecondRange(id, 'a', 'z');
|
||||
lex_FloatAddSecondRange(id, 'A', 'Z');
|
||||
lex_FloatAddSecondRange(id, '0', '9');
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "asm/asm.h"
|
||||
#include "asm/fstack.h"
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "extern/err.h"
|
||||
|
||||
#include "asmy.h"
|
||||
#include "platform.h" // strncasecmp, strdup
|
||||
|
||||
struct sLexString {
|
||||
char *tzName;
|
||||
@@ -120,7 +121,7 @@ void yyunputstr(const char *s)
|
||||
void lex_BeginStringExpansion(const char *tzName)
|
||||
{
|
||||
if (++nNbStringExpansions > nMaxRecursionDepth)
|
||||
fatalerror("Recursion limit (%d) exceeded", nMaxRecursionDepth);
|
||||
fatalerror("Recursion limit (%u) exceeded", nMaxRecursionDepth);
|
||||
|
||||
struct sStringExpansionPos *pNewStringExpansion =
|
||||
malloc(sizeof(*pNewStringExpansion));
|
||||
@@ -190,7 +191,7 @@ static void yy_buffer_append_newlines(YY_BUFFER_STATE buf, size_t capacity)
|
||||
}
|
||||
}
|
||||
|
||||
YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size)
|
||||
YY_BUFFER_STATE yy_scan_bytes(char const *mem, uint32_t size)
|
||||
{
|
||||
YY_BUFFER_STATE pBuffer = malloc(sizeof(struct yy_buffer_state));
|
||||
|
||||
@@ -254,7 +255,7 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f)
|
||||
else if (capacity == 0)
|
||||
capacity = 1;
|
||||
|
||||
while (!feof(f)) {
|
||||
do {
|
||||
if (buf == NULL || size >= capacity) {
|
||||
if (buf)
|
||||
capacity *= 2;
|
||||
@@ -273,7 +274,7 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f)
|
||||
fatalerror("%s: fread error", __func__);
|
||||
|
||||
size += read_count;
|
||||
}
|
||||
} while (!feof(f));
|
||||
|
||||
pBuffer->pBufferRealStart = buf;
|
||||
pBuffer->pBufferStart = buf + SAFETYMARGIN;
|
||||
@@ -342,6 +343,7 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f)
|
||||
*mem++ = ' ';
|
||||
/* Comments that start with * at the start of a line */
|
||||
} else if ((mem[0] == '\n') && (mem[1] == '*')) {
|
||||
warning(WARNING_OBSOLETE, "'*' is deprecated for comments, please use ';' instead");
|
||||
mem++;
|
||||
while (!((*mem == '\n') || (*mem == '\0')))
|
||||
*mem++ = ' ';
|
||||
@@ -370,7 +372,7 @@ uint32_t lex_FloatAlloc(const struct sLexFloat *token)
|
||||
bool lex_CheckCharacterRange(uint16_t start, uint16_t end)
|
||||
{
|
||||
if (start > end || start < 1 || end > 127) {
|
||||
yyerror("Invalid character range (start: %u, end: %u)",
|
||||
yyerror("Invalid character range (start: %" PRIu16 ", end: %" PRIu16 ")",
|
||||
start, end);
|
||||
return false;
|
||||
}
|
||||
@@ -486,9 +488,9 @@ void lex_AddStrings(const struct sLexInitString *lex)
|
||||
{
|
||||
while (lex->tzName) {
|
||||
struct sLexString **ppHash;
|
||||
uint32_t hash;
|
||||
uint32_t hash = lexcalchash(lex->tzName);
|
||||
|
||||
ppHash = &tLexHash[hash = lexcalchash(lex->tzName)];
|
||||
ppHash = &tLexHash[hash];
|
||||
while (*ppHash)
|
||||
ppHash = &((*ppHash)->pNext);
|
||||
|
||||
@@ -671,7 +673,7 @@ size_t yylex_ReadBracketedSymbol(char *dest, size_t index)
|
||||
* so it's handled differently
|
||||
*/
|
||||
static const char * const formatSpecifiers[] = {
|
||||
"", "%x", "%X", "%d"
|
||||
"", "%" PRIx32, "%" PRIX32, "%" PRId32
|
||||
};
|
||||
/* Prevent reading out of bounds! */
|
||||
const char *designatedMode;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -8,14 +10,25 @@
|
||||
#include "asm/macro.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
/*
|
||||
* Your average macro invocation does not go past the tens, but some go further
|
||||
* This ensures that sane and slightly insane invocations suffer no penalties,
|
||||
* and the rest is insane and thus will assume responsibility.
|
||||
* Additionally, ~300 bytes (on x64) of memory per level of nesting has been
|
||||
* deemed reasonable. (Halve that on x86.)
|
||||
*/
|
||||
#define INITIAL_ARG_SIZE 32
|
||||
struct MacroArgs {
|
||||
char *args[MAXMACROARGS];
|
||||
unsigned int nbArgs;
|
||||
unsigned int shift;
|
||||
unsigned int capacity;
|
||||
char *args[];
|
||||
};
|
||||
|
||||
static struct MacroArgs defaultArgs = { .nbArgs = 0, .shift = 0 };
|
||||
static struct MacroArgs *macroArgs = &defaultArgs;
|
||||
#define SIZEOF_ARGS(nbArgs) (sizeof(struct MacroArgs) + \
|
||||
sizeof(((struct MacroArgs){0}).args[0]) * (nbArgs))
|
||||
|
||||
static struct MacroArgs *macroArgs = NULL;
|
||||
static uint32_t uniqueID = -1;
|
||||
/*
|
||||
* The initialization is somewhat harmful, since it is never used, but it
|
||||
@@ -32,19 +45,34 @@ struct MacroArgs *macro_GetCurrentArgs(void)
|
||||
|
||||
struct MacroArgs *macro_NewArgs(void)
|
||||
{
|
||||
struct MacroArgs *args = malloc(sizeof(*args));
|
||||
struct MacroArgs *args = malloc(SIZEOF_ARGS(INITIAL_ARG_SIZE));
|
||||
|
||||
if (!args)
|
||||
fatalerror("Unable to register macro arguments: %s", strerror(errno));
|
||||
|
||||
args->nbArgs = 0;
|
||||
args->shift = 0;
|
||||
args->capacity = INITIAL_ARG_SIZE;
|
||||
return args;
|
||||
}
|
||||
|
||||
void macro_AppendArg(struct MacroArgs *args, char *s)
|
||||
void macro_AppendArg(struct MacroArgs **argPtr, char *s)
|
||||
{
|
||||
if (args->nbArgs == MAXMACROARGS)
|
||||
#define macArgs (*argPtr)
|
||||
if (macArgs->nbArgs == MAXMACROARGS)
|
||||
yyerror("A maximum of " EXPAND_AND_STR(MAXMACROARGS)
|
||||
" arguments is allowed");
|
||||
args->args[args->nbArgs++] = s;
|
||||
if (macArgs->nbArgs >= macArgs->capacity) {
|
||||
macArgs->capacity *= 2;
|
||||
/* Check that overflow didn't roll us back */
|
||||
if (macArgs->capacity <= macArgs->nbArgs)
|
||||
fatalerror("Failed to add new macro argument: possible capacity overflow");
|
||||
macArgs = realloc(macArgs, SIZEOF_ARGS(macArgs->capacity));
|
||||
if (!macArgs)
|
||||
fatalerror("Error adding new macro argument: %s", strerror(errno));
|
||||
}
|
||||
macArgs->args[macArgs->nbArgs++] = s;
|
||||
#undef macArgs
|
||||
}
|
||||
|
||||
void macro_UseNewArgs(struct MacroArgs *args)
|
||||
@@ -62,7 +90,8 @@ char const *macro_GetArg(uint32_t i)
|
||||
{
|
||||
uint32_t realIndex = i + macroArgs->shift - 1;
|
||||
|
||||
return realIndex >= MAXMACROARGS ? NULL : macroArgs->args[realIndex];
|
||||
return realIndex >= macroArgs->nbArgs ? NULL
|
||||
: macroArgs->args[realIndex];
|
||||
}
|
||||
|
||||
uint32_t macro_GetUniqueID(void)
|
||||
@@ -82,7 +111,7 @@ void macro_SetUniqueID(uint32_t id)
|
||||
uniqueIDPtr = NULL;
|
||||
} else {
|
||||
/* The buffer is guaranteed to be the correct size */
|
||||
sprintf(uniqueIDBuf, "_%u", id);
|
||||
sprintf(uniqueIDBuf, "_%" PRIu32, id);
|
||||
uniqueIDPtr = uniqueIDBuf;
|
||||
}
|
||||
}
|
||||
|
||||
101
src/asm/main.c
101
src/asm/main.c
@@ -63,6 +63,10 @@ char *tzTargetFileName;
|
||||
|
||||
struct sOptions DefaultOptions;
|
||||
struct sOptions CurrentOptions;
|
||||
bool haltnop;
|
||||
bool optimizeloads;
|
||||
bool verbose;
|
||||
bool warnings; /* True to enable warnings, false to disable them. */
|
||||
|
||||
struct sOptionStackEntry {
|
||||
struct sOptions Options;
|
||||
@@ -163,7 +167,7 @@ void opt_Parse(char *s)
|
||||
/* fallthrough */
|
||||
case 'p':
|
||||
if (strlen(&s[1]) <= 2) {
|
||||
int32_t result;
|
||||
int result;
|
||||
unsigned int fillchar;
|
||||
|
||||
result = sscanf(&s[1], "%x", &fillchar);
|
||||
@@ -360,12 +364,12 @@ int main(int argc, char *argv[])
|
||||
DefaultOptions.gbgfx[3] = '3';
|
||||
DefaultOptions.binary[0] = '0';
|
||||
DefaultOptions.binary[1] = '1';
|
||||
DefaultOptions.exportall = false;
|
||||
DefaultOptions.fillchar = 0;
|
||||
DefaultOptions.optimizeloads = true;
|
||||
DefaultOptions.haltnop = true;
|
||||
DefaultOptions.verbose = false;
|
||||
DefaultOptions.warnings = true;
|
||||
optimizeloads = true;
|
||||
haltnop = true;
|
||||
verbose = false;
|
||||
warnings = true;
|
||||
bool exportall = false;
|
||||
|
||||
opt_SetCurrentOptions(&DefaultOptions);
|
||||
|
||||
@@ -386,7 +390,7 @@ int main(int argc, char *argv[])
|
||||
opt_AddDefine(optarg);
|
||||
break;
|
||||
case 'E':
|
||||
newopt.exportall = true;
|
||||
exportall = true;
|
||||
break;
|
||||
case 'g':
|
||||
if (strlen(optarg) == 4) {
|
||||
@@ -399,13 +403,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
newopt.haltnop = false;
|
||||
haltnop = false;
|
||||
break;
|
||||
case 'i':
|
||||
fstk_AddIncludePath(optarg);
|
||||
break;
|
||||
case 'L':
|
||||
newopt.optimizeloads = false;
|
||||
optimizeloads = false;
|
||||
break;
|
||||
case 'M':
|
||||
if (!strcmp("-", optarg))
|
||||
@@ -439,49 +443,54 @@ int main(int argc, char *argv[])
|
||||
printf("rgbasm %s\n", get_package_version_string());
|
||||
exit(0);
|
||||
case 'v':
|
||||
newopt.verbose = true;
|
||||
verbose = true;
|
||||
break;
|
||||
case 'W':
|
||||
processWarningFlag(optarg);
|
||||
break;
|
||||
case 'w':
|
||||
newopt.warnings = false;
|
||||
warnings = false;
|
||||
break;
|
||||
|
||||
/* Long-only options */
|
||||
case 0:
|
||||
if (depType) {
|
||||
switch (depType) {
|
||||
case 'G':
|
||||
oGeneratedMissingIncludes = true;
|
||||
break;
|
||||
case 'P':
|
||||
oGeneratePhonyDeps = true;
|
||||
break;
|
||||
case 'Q':
|
||||
case 'T':
|
||||
if (optind == argc)
|
||||
errx(1, "-M%c takes a target file name argument",
|
||||
depType);
|
||||
ep = optarg;
|
||||
if (depType == 'Q')
|
||||
ep = make_escape(ep);
|
||||
switch (depType) {
|
||||
case 'G':
|
||||
oGeneratedMissingIncludes = true;
|
||||
break;
|
||||
case 'P':
|
||||
oGeneratePhonyDeps = true;
|
||||
break;
|
||||
case 'Q':
|
||||
case 'T':
|
||||
if (optind == argc)
|
||||
errx(1, "-M%c takes a target file name argument",
|
||||
depType);
|
||||
ep = optarg;
|
||||
if (depType == 'Q')
|
||||
ep = make_escape(ep);
|
||||
|
||||
nTargetFileNameLen += strlen(ep) + 1;
|
||||
nTargetFileNameLen += strlen(ep) + 1;
|
||||
if (!tzTargetFileName) {
|
||||
/* On first alloc, make an empty str */
|
||||
tzTargetFileName =
|
||||
malloc(nTargetFileNameLen + 1);
|
||||
*tzTargetFileName = '\0';
|
||||
} else {
|
||||
tzTargetFileName =
|
||||
realloc(tzTargetFileName,
|
||||
nTargetFileNameLen + 1);
|
||||
if (tzTargetFileName == NULL)
|
||||
err(1, "Cannot append new file to target file list");
|
||||
strcat(tzTargetFileName, ep);
|
||||
if (depType == 'Q')
|
||||
free(ep);
|
||||
char *ptr = tzTargetFileName +
|
||||
strlen(tzTargetFileName);
|
||||
*ptr++ = ' ';
|
||||
*ptr = '\0';
|
||||
break;
|
||||
}
|
||||
if (tzTargetFileName == NULL)
|
||||
err(1, "Cannot append new file to target file list");
|
||||
strcat(tzTargetFileName, ep);
|
||||
if (depType == 'Q')
|
||||
free(ep);
|
||||
char *ptr = tzTargetFileName +
|
||||
strlen(tzTargetFileName);
|
||||
*ptr++ = ' ';
|
||||
*ptr = '\0';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -510,7 +519,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
setup_lexer();
|
||||
|
||||
if (CurrentOptions.verbose)
|
||||
if (verbose)
|
||||
printf("Assembling %s\n", tzMainfile);
|
||||
|
||||
if (dependfile) {
|
||||
@@ -528,7 +537,7 @@ int main(int argc, char *argv[])
|
||||
skipElif = true;
|
||||
nUnionDepth = 0;
|
||||
sym_Init();
|
||||
sym_SetExportAll(CurrentOptions.exportall);
|
||||
sym_SetExportAll(exportall);
|
||||
fstk_Init(tzMainfile);
|
||||
opt_ParseDefines();
|
||||
charmap_InitMain();
|
||||
@@ -542,10 +551,11 @@ int main(int argc, char *argv[])
|
||||
fclose(dependfile);
|
||||
|
||||
if (nIFDepth != 0)
|
||||
errx(1, "Unterminated IF construct (%u levels)!", nIFDepth);
|
||||
errx(1, "Unterminated IF construct (%" PRIu32 " levels)!",
|
||||
nIFDepth);
|
||||
|
||||
if (nUnionDepth != 0) {
|
||||
errx(1, "Unterminated UNION construct (%u levels)!",
|
||||
errx(1, "Unterminated UNION construct (%" PRIu32 " levels)!",
|
||||
nUnionDepth);
|
||||
}
|
||||
|
||||
@@ -554,9 +564,10 @@ int main(int argc, char *argv[])
|
||||
nEndClock = clock();
|
||||
timespent = ((double)(nEndClock - nStartClock))
|
||||
/ (double)CLOCKS_PER_SEC;
|
||||
if (CurrentOptions.verbose) {
|
||||
printf("Success! %u lines in %d.%02d seconds ", nTotalLines,
|
||||
(int)timespent, ((int)(timespent * 100.0)) % 100);
|
||||
if (verbose) {
|
||||
printf("Success! %" PRIu32 " lines in %d.%02d seconds ",
|
||||
nTotalLines, (int)timespent,
|
||||
((int)(timespent * 100.0)) % 100);
|
||||
if (timespent < FLT_MIN_EXP)
|
||||
printf("(INFINITY lines/minute)\n");
|
||||
else
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* Fixedpoint math routines
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -37,12 +38,16 @@ void math_DefinePI(void)
|
||||
*/
|
||||
void math_Print(int32_t i)
|
||||
{
|
||||
if (i >= 0)
|
||||
printf("%d.%05d", i >> 16,
|
||||
((int32_t)(fx2double(i) * 100000 + 0.5)) % 100000);
|
||||
else
|
||||
printf("-%d.%05d", (-i) >> 16,
|
||||
((int32_t)(fx2double(-i) * 100000 + 0.5)) % 100000);
|
||||
uint32_t u = i;
|
||||
const char *sign = "";
|
||||
|
||||
if (i < 0) {
|
||||
u = -u;
|
||||
sign = "-";
|
||||
}
|
||||
|
||||
printf("%s%" PRIu32 ".%05" PRIu32, sign, u >> 16,
|
||||
((uint32_t)(fx2double(u) * 100000 + 0.5)) % 100000);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
105
src/asm/output.c
105
src/asm/output.c
@@ -30,10 +30,13 @@
|
||||
#include "extern/err.h"
|
||||
|
||||
#include "linkdefs.h"
|
||||
#include "platform.h" // strdup
|
||||
|
||||
struct Patch {
|
||||
char tzFilename[_MAX_PATH + 1];
|
||||
uint32_t nOffset;
|
||||
struct Section *pcSection;
|
||||
uint32_t pcOffset;
|
||||
uint8_t nType;
|
||||
uint32_t nRPNSize;
|
||||
uint8_t *pRPN;
|
||||
@@ -53,8 +56,8 @@ char *tzObjectname;
|
||||
struct Section *pSectionList, *pCurrentSection;
|
||||
|
||||
/* Linked list of symbols to put in the object file */
|
||||
static struct sSymbol *objectSymbols = NULL;
|
||||
static struct sSymbol **objectSymbolsTail = &objectSymbols;
|
||||
static struct Symbol *objectSymbols = NULL;
|
||||
static struct Symbol **objectSymbolsTail = &objectSymbols;
|
||||
static uint32_t nbSymbols = 0; /* Length of the above list */
|
||||
|
||||
static struct Assertion *assertions = NULL;
|
||||
@@ -79,16 +82,13 @@ static uint32_t countsections(void)
|
||||
/*
|
||||
* Count the number of patches used in this object
|
||||
*/
|
||||
static uint32_t countpatches(struct Section *pSect)
|
||||
static uint32_t countpatches(struct Section const *pSect)
|
||||
{
|
||||
struct Patch *pPatch;
|
||||
uint32_t r = 0;
|
||||
|
||||
pPatch = pSect->pPatches;
|
||||
while (pPatch) {
|
||||
for (struct Patch const *patch = pSect->pPatches; patch != NULL;
|
||||
patch = patch->pNext)
|
||||
r++;
|
||||
pPatch = pPatch->pNext;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -132,9 +132,9 @@ static void fputstring(char const *s, FILE *f)
|
||||
/*
|
||||
* Return a section's ID
|
||||
*/
|
||||
static uint32_t getsectid(struct Section *pSect)
|
||||
static uint32_t getsectid(struct Section const *pSect)
|
||||
{
|
||||
struct Section *sec;
|
||||
struct Section const *sec;
|
||||
uint32_t ID = 0;
|
||||
|
||||
sec = pSectionList;
|
||||
@@ -149,13 +149,20 @@ static uint32_t getsectid(struct Section *pSect)
|
||||
fatalerror("Unknown section '%s'", pSect->pzName);
|
||||
}
|
||||
|
||||
static uint32_t getSectIDIfAny(struct Section const *sect)
|
||||
{
|
||||
return sect ? getsectid(sect) : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a patch to a file
|
||||
*/
|
||||
static void writepatch(struct Patch *pPatch, FILE *f)
|
||||
static void writepatch(struct Patch const *pPatch, FILE *f)
|
||||
{
|
||||
fputstring(pPatch->tzFilename, f);
|
||||
fputlong(pPatch->nOffset, f);
|
||||
fputlong(getSectIDIfAny(pPatch->pcSection), f);
|
||||
fputlong(pPatch->pcOffset, f);
|
||||
fputc(pPatch->nType, f);
|
||||
fputlong(pPatch->nRPNSize, f);
|
||||
fwrite(pPatch->pRPN, 1, pPatch->nRPNSize, f);
|
||||
@@ -164,46 +171,46 @@ static void writepatch(struct Patch *pPatch, FILE *f)
|
||||
/*
|
||||
* Write a section to a file
|
||||
*/
|
||||
static void writesection(struct Section *pSect, FILE *f)
|
||||
static void writesection(struct Section const *pSect, FILE *f)
|
||||
{
|
||||
fputstring(pSect->pzName, f);
|
||||
|
||||
fputlong(pSect->size, f);
|
||||
|
||||
fputc(pSect->nType | pSect->isUnion << 7, f);
|
||||
bool isUnion = pSect->modifier == SECTION_UNION;
|
||||
bool isFragment = pSect->modifier == SECTION_FRAGMENT;
|
||||
|
||||
fputc(pSect->nType | isUnion << 7 | isFragment << 6, f);
|
||||
|
||||
fputlong(pSect->nOrg, f);
|
||||
fputlong(pSect->nBank, f);
|
||||
fputlong(pSect->nAlign, f);
|
||||
fputc(pSect->nAlign, f);
|
||||
fputlong(pSect->alignOfs, f);
|
||||
|
||||
if (sect_HasData(pSect->nType)) {
|
||||
struct Patch *pPatch;
|
||||
|
||||
fwrite(pSect->tData, 1, pSect->size, f);
|
||||
fputlong(countpatches(pSect), f);
|
||||
|
||||
pPatch = pSect->pPatches;
|
||||
while (pPatch) {
|
||||
writepatch(pPatch, f);
|
||||
pPatch = pPatch->pNext;
|
||||
}
|
||||
for (struct Patch const *patch = pSect->pPatches; patch != NULL;
|
||||
patch = patch->pNext)
|
||||
writepatch(patch, f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a symbol to a file
|
||||
*/
|
||||
static void writesymbol(struct sSymbol const *pSym, FILE *f)
|
||||
static void writesymbol(struct Symbol const *sym, FILE *f)
|
||||
{
|
||||
fputstring(pSym->tzName, f);
|
||||
if (!sym_IsDefined(pSym)) {
|
||||
fputstring(sym->name, f);
|
||||
if (!sym_IsDefined(sym)) {
|
||||
fputc(SYMTYPE_IMPORT, f);
|
||||
} else {
|
||||
fputc(pSym->isExported ? SYMTYPE_EXPORT : SYMTYPE_LOCAL, f);
|
||||
fputstring(pSym->tzFileName, f);
|
||||
fputlong(pSym->nFileLine, f);
|
||||
fputlong(pSym->pSection ? getsectid(pSym->pSection) : -1, f);
|
||||
fputlong(pSym->nValue, f);
|
||||
fputc(sym->isExported ? SYMTYPE_EXPORT : SYMTYPE_LOCAL, f);
|
||||
fputstring(sym->fileName, f);
|
||||
fputlong(sym->fileLine, f);
|
||||
fputlong(getSectIDIfAny(sym_GetSection(sym)), f);
|
||||
fputlong(sym->value, f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +218,7 @@ static void writesymbol(struct sSymbol const *pSym, FILE *f)
|
||||
* Returns a symbol's ID within the object file
|
||||
* If the symbol does not have one, one is assigned by registering the symbol
|
||||
*/
|
||||
static uint32_t getSymbolID(struct sSymbol *sym)
|
||||
static uint32_t getSymbolID(struct Symbol *sym)
|
||||
{
|
||||
if (sym->ID == -1) {
|
||||
sym->ID = nbSymbols++;
|
||||
@@ -244,7 +251,7 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
|
||||
{
|
||||
for (unsigned int i = -1; (tzSym[++i] = popbyte()); )
|
||||
;
|
||||
struct sSymbol *sym = sym_FindSymbol(tzSym);
|
||||
struct Symbol *sym = sym_FindSymbol(tzSym);
|
||||
uint32_t value;
|
||||
|
||||
if (sym_IsConstant(sym)) {
|
||||
@@ -264,7 +271,7 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
|
||||
{
|
||||
for (unsigned int i = -1; (tzSym[++i] = popbyte()); )
|
||||
;
|
||||
struct sSymbol *sym = sym_FindSymbol(tzSym);
|
||||
struct Symbol *sym = sym_FindSymbol(tzSym);
|
||||
uint32_t value = getSymbolID(sym);
|
||||
|
||||
writebyte(RPN_BANK_SYM);
|
||||
@@ -300,9 +307,7 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
|
||||
static struct Patch *allocpatch(uint32_t type, struct Expression const *expr,
|
||||
uint32_t ofs)
|
||||
{
|
||||
struct Patch *pPatch;
|
||||
|
||||
pPatch = malloc(sizeof(struct Patch));
|
||||
struct Patch *pPatch = malloc(sizeof(struct Patch));
|
||||
|
||||
if (!pPatch)
|
||||
fatalerror("No memory for patch: %s", strerror(errno));
|
||||
@@ -316,6 +321,8 @@ static struct Patch *allocpatch(uint32_t type, struct Expression const *expr,
|
||||
pPatch->nType = type;
|
||||
fstk_DumpToStr(pPatch->tzFilename, sizeof(pPatch->tzFilename));
|
||||
pPatch->nOffset = ofs;
|
||||
pPatch->pcSection = sect_GetSymbolSection();
|
||||
pPatch->pcOffset = curOffset;
|
||||
|
||||
writerpn(pPatch->pRPN, &pPatch->nRPNSize, expr->tRPN, expr->nRPNLength);
|
||||
assert(pPatch->nRPNSize == expr->nRPNPatchSize);
|
||||
@@ -346,7 +353,6 @@ bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
|
||||
return false;
|
||||
|
||||
assertion->patch = allocpatch(type, expr, ofs);
|
||||
assertion->section = pCurrentSection;
|
||||
assertion->message = strdup(message);
|
||||
if (!assertion->message) {
|
||||
free(assertion);
|
||||
@@ -362,14 +368,13 @@ bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
|
||||
static void writeassert(struct Assertion *assert, FILE *f)
|
||||
{
|
||||
writepatch(assert->patch, f);
|
||||
fputlong(assert->section ? getsectid(assert->section) : -1, f);
|
||||
fputstring(assert->message, f);
|
||||
}
|
||||
|
||||
static void registerExportedSymbol(struct sSymbol *symbol, void *arg)
|
||||
static void registerExportedSymbol(struct Symbol *symbol, void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
if (symbol->isExported && symbol->ID == -1) {
|
||||
if (sym_IsExported(symbol) && symbol->ID == -1) {
|
||||
*objectSymbolsTail = symbol;
|
||||
objectSymbolsTail = &symbol->next;
|
||||
nbSymbols++;
|
||||
@@ -381,11 +386,8 @@ static void registerExportedSymbol(struct sSymbol *symbol, void *arg)
|
||||
*/
|
||||
void out_WriteObject(void)
|
||||
{
|
||||
FILE *f;
|
||||
struct Section *pSect;
|
||||
struct Assertion *assert = assertions;
|
||||
FILE *f = fopen(tzObjectname, "wb");
|
||||
|
||||
f = fopen(tzObjectname, "wb");
|
||||
if (!f)
|
||||
err(1, "Couldn't write file '%s'", tzObjectname);
|
||||
|
||||
@@ -398,21 +400,16 @@ void out_WriteObject(void)
|
||||
fputlong(nbSymbols, f);
|
||||
fputlong(countsections(), f);
|
||||
|
||||
for (struct sSymbol const *sym = objectSymbols; sym; sym = sym->next) {
|
||||
for (struct Symbol const *sym = objectSymbols; sym; sym = sym->next)
|
||||
writesymbol(sym, f);
|
||||
}
|
||||
|
||||
pSect = pSectionList;
|
||||
while (pSect) {
|
||||
writesection(pSect, f);
|
||||
pSect = pSect->pNext;
|
||||
}
|
||||
for (struct Section *sect = pSectionList; sect; sect = sect->pNext)
|
||||
writesection(sect, f);
|
||||
|
||||
fputlong(countasserts(), f);
|
||||
while (assert) {
|
||||
for (struct Assertion *assert = assertions; assert;
|
||||
assert = assert->next)
|
||||
writeassert(assert, f);
|
||||
assert = assert->next;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
@@ -423,6 +420,6 @@ void out_WriteObject(void)
|
||||
void out_SetFileName(char *s)
|
||||
{
|
||||
tzObjectname = s;
|
||||
if (CurrentOptions.verbose)
|
||||
if (verbose)
|
||||
printf("Output filename %s\n", s);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
.Op Fl g Ar chars
|
||||
.Op Fl i Ar path
|
||||
.Op Fl M Ar depend_file
|
||||
.Op Fl MG
|
||||
.Op Fl MP
|
||||
.Op Fl MT Ar target_file
|
||||
.Op Fl MQ Ar target_file
|
||||
.Op Fl o Ar out_file
|
||||
.Op Fl p Ar pad_value
|
||||
.Op Fl r Ar recursion_depth
|
||||
@@ -86,6 +90,41 @@ Print
|
||||
.Xr make 1
|
||||
dependencies to
|
||||
.Ar depend_file .
|
||||
.It Fl MG
|
||||
To be used in conjunction with
|
||||
.Fl M .
|
||||
This makes
|
||||
.Nm
|
||||
assume that missing files are auto-generated: when
|
||||
.Ic INCLUDE
|
||||
or
|
||||
.Ic INCBIN
|
||||
is attempted on a non-existent file, it is added as a dependency, then
|
||||
.Nm
|
||||
exits normally instead of erroring out.
|
||||
This feature is used in automatic updating of makefiles.
|
||||
.It Fl MP
|
||||
When enabled, this causes a phony target to be added for each dependency other than the main file.
|
||||
This prevents
|
||||
.Xr make 1
|
||||
from erroring out when dependency files are deleted.
|
||||
.It Fl MT Ar target_file
|
||||
Add a target to the rules emitted by
|
||||
.Fl M .
|
||||
The exact string provided will be written, including spaces and special characters.
|
||||
.Dl Fl MT fileA Fl MT fileB
|
||||
is equivalent to
|
||||
.Dl Fl MT 'fileA fileB' .
|
||||
If neither this nor
|
||||
.Fl MQ
|
||||
is specified, the output file name is used.
|
||||
.It Fl MQ Ar target_file
|
||||
Same as
|
||||
.Fl MT ,
|
||||
but additionally escapes any special
|
||||
.Xr make 1
|
||||
characters, essentially
|
||||
.Sq $ .
|
||||
.It Fl o Ar out_file , Fl Fl output Ar out_file
|
||||
Write an object file to the given filename.
|
||||
.It Fl p Ar pad_value , Fl Fl pad-value Ar pad_value
|
||||
@@ -180,14 +219,12 @@ This warning is enabled by
|
||||
Warn when a string too long to fit in internal buffers is encountered.
|
||||
This warning is enabled by
|
||||
.Fl Wall .
|
||||
.It Fl Wobsolete
|
||||
.It Fl Wno-obsolete
|
||||
Warn when obsolete constructs such as the
|
||||
.Ic jp [hl]
|
||||
instruction or
|
||||
.Ic HOME
|
||||
section type are encountered.
|
||||
This warning is enabled by
|
||||
.Fl Wextra .
|
||||
.It Fl Wshift
|
||||
Warn when shifting right a negative value.
|
||||
Use a division by 2^N instead.
|
||||
|
||||
@@ -165,7 +165,7 @@ still evaluates both operands of
|
||||
and
|
||||
.Sq || .
|
||||
.Pp
|
||||
! returns 1 if the operand was 0, and 1 otherwise.
|
||||
! returns 1 if the operand was 0, and 0 otherwise.
|
||||
.Ss Fixed‐point Expressions
|
||||
.Pp
|
||||
Fixed-point numbers are basically normal (32-bit) integers, which count 65536th's instead of entire units, offering better precision than integers but limiting the range of values.
|
||||
@@ -367,7 +367,6 @@ This tells the assembler what kind of information follows and, if it is code, wh
|
||||
.Pp
|
||||
.Ar name
|
||||
is a string enclosed in double quotes, and can be a new name or the name of an existing section.
|
||||
All sections assembled at the same time that have the same name are considered to be the same section, and their code is put together in the object file generated by the assembler.
|
||||
If the type doesn't match, an error occurs.
|
||||
All other sections must have a unique name, even in different source files, or the linker will treat it as an error.
|
||||
.Pp
|
||||
@@ -492,13 +491,21 @@ See above for possible values for
|
||||
.Ar bank ,
|
||||
depending on
|
||||
.Ar type .
|
||||
.It Ic ALIGN Ns Bq Ar align
|
||||
.It Ic ALIGN Ns Bq Ar align , offset
|
||||
Place the section at an address whose
|
||||
.Ar align
|
||||
least‐significant bits are zero.
|
||||
least‐significant bits are equal to
|
||||
.Ar offset .
|
||||
(Note that
|
||||
.Ic ALIGN Ns Bq Ar align
|
||||
is a shorthand for
|
||||
.Ic ALIGN Ns Bq Ar align , No 0 ) .
|
||||
This option can be used with
|
||||
.Ar addr ,
|
||||
.Bq Ar addr ,
|
||||
as long as they don't contradict eachother.
|
||||
It's also possible to request alignment in the middle of a section, see
|
||||
.Sx Requesting alignment
|
||||
below.
|
||||
.El
|
||||
.Pp
|
||||
If
|
||||
@@ -520,7 +527,7 @@ Section examples:
|
||||
.Bl -item
|
||||
.It
|
||||
.Bd -literal -offset indent
|
||||
SECTION "CoolStuff",ROMX
|
||||
SECTION "Cool Stuff",ROMX
|
||||
.Ed
|
||||
This switches to the section called
|
||||
.Dq CoolStuff ,
|
||||
@@ -530,17 +537,17 @@ Code and data may follow.
|
||||
.It
|
||||
If it is needed, the the base address of the section can be specified:
|
||||
.Bd -literal -offset indent
|
||||
SECTION "CoolStuff",ROMX[$4567]
|
||||
SECTION "Cool Stuff",ROMX[$4567]
|
||||
.Ed
|
||||
.It
|
||||
An example with a fixed bank:
|
||||
.Bd -literal -offset indent
|
||||
SECTION "CoolStuff",ROMX[$4567],BANK[3]
|
||||
SECTION "Cool Stuff",ROMX[$4567],BANK[3]
|
||||
.Ed
|
||||
.It
|
||||
And if you want to force only the section's bank, and not its position within the bank, that's also possible:
|
||||
.Bd -literal -offset indent
|
||||
SECTION "CoolStuff",ROMX,BANK[7]
|
||||
SECTION "Cool Stuff",ROMX,BANK[7]
|
||||
.Ed
|
||||
.It
|
||||
Alignment examples:
|
||||
@@ -647,7 +654,7 @@ The same unionized section (= having the same name) can be declared several time
|
||||
invocation, and across several invocations.
|
||||
Different declarations are treated and merged identically whether within the same invocation, or different ones.
|
||||
.It
|
||||
A section cannot be declared both as unionized or non-unionized.
|
||||
If one section has been declared as unionized, all sections with the same name must be declared unionized as well.
|
||||
.It
|
||||
All declarations must have the same type.
|
||||
For example, even if
|
||||
@@ -671,6 +678,49 @@ or
|
||||
Different declarations of the same unionized section are not appended, but instead overlaid on top of eachother, just like
|
||||
.Sx Unions .
|
||||
Similarly, the size of an unionized section is the largest of all its declarations.
|
||||
.Ss Section Fragments
|
||||
Section fragments are sections with a small twist: when several of the same name are encountered, they are concatenated instead of producing an error.
|
||||
This works within the same file (paralleling the behavior "plain" sections has in previous versions), but also across object files.
|
||||
However, similarly to
|
||||
.Sx Unionized Sections ,
|
||||
some rules must be followed:
|
||||
.Bl -bullet -offset indent
|
||||
.It
|
||||
If one section has been declared as fragment, all sections with the same name must be declared fragments as well.
|
||||
.It
|
||||
All declarations must have the same type.
|
||||
For example, even if
|
||||
.Xr rgblink 1 Ap s
|
||||
.Fl w
|
||||
flag is used,
|
||||
.Ic WRAM0
|
||||
and
|
||||
.Ic WRAMX
|
||||
types are still considered different.
|
||||
.It
|
||||
Different constraints (alignment, bank, etc.) can be specified for each unionized section declaration, but they must all be compatible.
|
||||
For example, alignment must be compatible with any fixed address, all specified banks must be the same, etc.
|
||||
.It
|
||||
A section fragment may not be unionized; after all, that wouldn't make much sense.
|
||||
.El
|
||||
.Pp
|
||||
When RGBASM merges two fragments, the one encountered later is appended to the one encountered earlier.
|
||||
.Pp
|
||||
When RGBLINK merges two fragments, the one whose file was specified last is appended to the one whose file was specified first.
|
||||
For example, assuming
|
||||
.Ql bar.o ,
|
||||
.Ql baz.o ,
|
||||
and
|
||||
.Ql foo.o
|
||||
all contain a fragment with the same name, the command
|
||||
.Dl rgblink -o rom.gb baz.o foo.o bar.o
|
||||
would produce the fragment from
|
||||
.Ql baz.o
|
||||
first, followed by the one from
|
||||
.Ql foo.o ,
|
||||
and the one from
|
||||
.Ql bar.o
|
||||
last.
|
||||
.Sh SYMBOLS
|
||||
.Pp
|
||||
RGBDS supports several types of symbols:
|
||||
@@ -731,6 +781,8 @@ If the former notation is used, then
|
||||
.Ql scope
|
||||
must be the actual current scope.
|
||||
.Pp
|
||||
Local labels may have whitespace before their declaration as the only exception to the rule.
|
||||
.Pp
|
||||
A label's location (and thus value) is usually not determined until the linking stage, so labels usually cannot be used as constants.
|
||||
However, if the section in which the label is declared has a fixed base address, its value is known at assembly time.
|
||||
.Pp
|
||||
@@ -1460,10 +1512,29 @@ provide the interface to the option stack.
|
||||
will push the current set of options on the option stack.
|
||||
.Ic POPO
|
||||
can then later be used to restore them.
|
||||
Useful if you want to change some options in an include file and you don't want
|
||||
to destroy the options set by the program that included your file.
|
||||
The stack's number of entries is limited only by the amount of memory in your
|
||||
machine.
|
||||
Useful if you want to change some options in an include file and you don't want to destroy the options set by the program that included your file.
|
||||
The stack's number of entries is limited only by the amount of memory in your machine.
|
||||
.Ss Requesting alignment
|
||||
.Pp
|
||||
While
|
||||
.Ic ALIGN
|
||||
as presented in
|
||||
.Sx SECTIONS
|
||||
is often useful as-is, sometimes you instead want a particular piece of data (or code) in the middle of the section to be aligned.
|
||||
This is made easier through the use of mid-section
|
||||
.Ic align Ar align , offset .
|
||||
It will alter the section's attributes to ensure that the location the
|
||||
.Ic align
|
||||
directive is at, has its
|
||||
.Ar align
|
||||
lower bits equal to
|
||||
.Ar offset .
|
||||
.Pp
|
||||
If the constraint cannot be met (for example because the section is fixed at an incompatible address), and error is produced.
|
||||
Note that
|
||||
.Ic align Ar align
|
||||
is a shorthand for
|
||||
.Ic align Ar align , No 0 .
|
||||
.Sh SEE ALSO
|
||||
.Xr rgbasm 1 ,
|
||||
.Xr rgblink 1 ,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -50,8 +51,8 @@ static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
|
||||
* To avoid generating humongous object files, cap the
|
||||
* size of RPN expressions
|
||||
*/
|
||||
fatalerror("RPN expression cannot grow larger than %d bytes",
|
||||
MAXRPNLEN);
|
||||
fatalerror("RPN expression cannot grow larger than %lu bytes",
|
||||
(unsigned long)MAXRPNLEN);
|
||||
else if (expr->nRPNCapacity > MAXRPNLEN / 2)
|
||||
expr->nRPNCapacity = MAXRPNLEN;
|
||||
else
|
||||
@@ -104,9 +105,9 @@ void rpn_Number(struct Expression *expr, uint32_t i)
|
||||
|
||||
void rpn_Symbol(struct Expression *expr, char *tzSym)
|
||||
{
|
||||
struct sSymbol *sym = sym_FindSymbol(tzSym);
|
||||
struct Symbol *sym = sym_FindSymbol(tzSym);
|
||||
|
||||
if (sym == pPCSymbol && !pPCSymbol->pSection) {
|
||||
if (sym_IsPC(sym) && !sect_GetSymbolSection()) {
|
||||
yyerror("PC has no value outside a section");
|
||||
rpn_Number(expr, 0);
|
||||
} else if (!sym || !sym_IsConstant(sym)) {
|
||||
@@ -114,9 +115,9 @@ void rpn_Symbol(struct Expression *expr, char *tzSym)
|
||||
expr->isSymbol = true;
|
||||
|
||||
sym_Ref(tzSym);
|
||||
makeUnknown(expr, strcmp(tzSym, "@")
|
||||
? "'%s' is not constant at assembly time"
|
||||
: "PC is not constant at assembly time",
|
||||
makeUnknown(expr, sym_IsPC(sym)
|
||||
? "PC is not constant at assembly time"
|
||||
: "'%s' is not constant at assembly time",
|
||||
tzSym);
|
||||
expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */
|
||||
|
||||
@@ -126,7 +127,7 @@ void rpn_Symbol(struct Expression *expr, char *tzSym)
|
||||
memcpy(ptr, tzSym, nameLen);
|
||||
|
||||
/* RGBLINK assumes PC is at the byte being computed... */
|
||||
if (sym == pPCSymbol && nPCOffset) {
|
||||
if (sym_IsPC(sym) && nPCOffset) {
|
||||
struct Expression pc = *expr, offset;
|
||||
|
||||
rpn_Number(&offset, nPCOffset);
|
||||
@@ -143,7 +144,10 @@ void rpn_BankSelf(struct Expression *expr)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
|
||||
if (pCurrentSection->nBank == -1) {
|
||||
if (!pCurrentSection) {
|
||||
yyerror("PC has no bank outside a section");
|
||||
expr->nVal = 1;
|
||||
} else if (pCurrentSection->nBank == -1) {
|
||||
makeUnknown(expr, "Current section's bank is not known");
|
||||
expr->nRPNPatchSize++;
|
||||
*reserveSpace(expr, 1) = RPN_BANK_SELF;
|
||||
@@ -154,10 +158,10 @@ void rpn_BankSelf(struct Expression *expr)
|
||||
|
||||
void rpn_BankSymbol(struct Expression *expr, char const *tzSym)
|
||||
{
|
||||
struct sSymbol const *sym = sym_FindSymbol(tzSym);
|
||||
struct Symbol const *sym = sym_FindSymbol(tzSym);
|
||||
|
||||
/* The @ symbol is treated differently. */
|
||||
if (sym == pPCSymbol) {
|
||||
if (sym_IsPC(sym)) {
|
||||
rpn_BankSelf(expr);
|
||||
return;
|
||||
}
|
||||
@@ -167,12 +171,13 @@ void rpn_BankSymbol(struct Expression *expr, char const *tzSym)
|
||||
yyerror("BANK argument must be a label");
|
||||
} else {
|
||||
sym_Ref(tzSym);
|
||||
/* If the symbol didn't exist, `sym_Ref` created it */
|
||||
struct sSymbol *pSymbol = sym_FindSymbol(tzSym);
|
||||
if (!sym)
|
||||
/* If the symbol didn't exist, `sym_Ref` created it */
|
||||
sym = sym_FindSymbol(tzSym);
|
||||
|
||||
if (pSymbol->pSection && pSymbol->pSection->nBank != -1) {
|
||||
if (sym_GetSection(sym) && sym_GetSection(sym)->nBank != -1) {
|
||||
/* Symbol's section is known and bank is fixed */
|
||||
expr->nVal = pSymbol->pSection->nBank;
|
||||
expr->nVal = sym_GetSection(sym)->nBank;
|
||||
} else {
|
||||
makeUnknown(expr, "\"%s\"'s bank is not known", tzSym);
|
||||
expr->nRPNPatchSize += 5; /* opcode + 4-byte sect ID */
|
||||
@@ -218,7 +223,8 @@ void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
||||
/* That range is valid, but only keep the lower byte */
|
||||
expr->nVal &= 0xFF;
|
||||
} else if (expr->nVal < 0 || expr->nVal > 0xFF) {
|
||||
yyerror("Source address $%x not in $FF00 to $FFFF", expr->nVal);
|
||||
yyerror("Source address $%" PRIx32 " not between $FF00 to $FFFF",
|
||||
expr->nVal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +235,8 @@ void rpn_CheckRST(struct Expression *expr, const struct Expression *src)
|
||||
if (rpn_isKnown(expr)) {
|
||||
/* A valid RST address must be masked with 0x38 */
|
||||
if (expr->nVal & ~0x38)
|
||||
yyerror("Invalid address $%x for RST", expr->nVal);
|
||||
yyerror("Invalid address $%" PRIx32 " for RST",
|
||||
expr->nVal);
|
||||
/* The target is in the "0x38" bits, all other bits are set */
|
||||
expr->nVal |= 0xC7;
|
||||
} else {
|
||||
@@ -256,7 +263,7 @@ static int32_t shift(int32_t shiftee, int32_t amount)
|
||||
if (amount >= 0) {
|
||||
// Left shift
|
||||
if (amount >= 32) {
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %d",
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %" PRId32,
|
||||
amount);
|
||||
return 0;
|
||||
|
||||
@@ -272,7 +279,7 @@ static int32_t shift(int32_t shiftee, int32_t amount)
|
||||
// Right shift
|
||||
amount = -amount;
|
||||
if (amount >= 32) {
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %d",
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32,
|
||||
amount);
|
||||
return shiftee < 0 ? -1 : 0;
|
||||
|
||||
@@ -285,12 +292,12 @@ static int32_t shift(int32_t shiftee, int32_t amount)
|
||||
* undefined, so use a left shift manually sign-extended
|
||||
*/
|
||||
return (uint32_t)shiftee >> amount
|
||||
| -((uint32_t)1 << (32 - amount));
|
||||
| -(UINT32_C(1) << (32 - amount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct sSymbol const *symbolOf(struct Expression const *expr)
|
||||
static struct Symbol const *symbolOf(struct Expression const *expr)
|
||||
{
|
||||
if (!rpn_isSymbol(expr))
|
||||
return NULL;
|
||||
@@ -301,14 +308,14 @@ static bool isDiffConstant(struct Expression const *src1,
|
||||
struct Expression const *src2)
|
||||
{
|
||||
/* Check if both expressions only refer to a single symbol */
|
||||
struct sSymbol const *symbol1 = symbolOf(src1);
|
||||
struct sSymbol const *symbol2 = symbolOf(src2);
|
||||
struct Symbol const *symbol1 = symbolOf(src1);
|
||||
struct Symbol const *symbol2 = symbolOf(src2);
|
||||
|
||||
if (!symbol1 || !symbol2
|
||||
|| symbol1->type != SYM_LABEL || symbol2->type != SYM_LABEL)
|
||||
return false;
|
||||
|
||||
return symbol1->pSection == symbol2->pSection;
|
||||
return sym_GetSection(symbol1) == sym_GetSection(symbol2);
|
||||
}
|
||||
|
||||
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
@@ -366,18 +373,18 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
break;
|
||||
case RPN_SHL:
|
||||
if (src2->nVal < 0)
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %d",
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %" PRId32,
|
||||
src2->nVal);
|
||||
|
||||
expr->nVal = shift(src1->nVal, src2->nVal);
|
||||
break;
|
||||
case RPN_SHR:
|
||||
if (src1->nVal < 0)
|
||||
warning(WARNING_SHIFT, "Shifting negative value %d",
|
||||
warning(WARNING_SHIFT, "Shifting negative value %" PRId32,
|
||||
src1->nVal);
|
||||
|
||||
if (src2->nVal < 0)
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %d",
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32,
|
||||
src2->nVal);
|
||||
|
||||
expr->nVal = shift(src1->nVal, -src2->nVal);
|
||||
@@ -417,12 +424,12 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
case RPN_RST:
|
||||
case RPN_CONST:
|
||||
case RPN_SYM:
|
||||
fatalerror("%d is no binary operator", op);
|
||||
fatalerror("%d is not a binary operator", op);
|
||||
}
|
||||
|
||||
} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
|
||||
struct sSymbol const *symbol1 = symbolOf(src1);
|
||||
struct sSymbol const *symbol2 = symbolOf(src2);
|
||||
struct Symbol const *symbol1 = symbolOf(src1);
|
||||
struct Symbol const *symbol2 = symbolOf(src2);
|
||||
|
||||
expr->nVal = sym_GetValue(symbol1) - sym_GetValue(symbol2);
|
||||
expr->isKnown = true;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -12,10 +14,11 @@
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "extern/err.h"
|
||||
#include "platform.h" // strdup
|
||||
|
||||
struct SectionStackEntry {
|
||||
struct Section *pSection;
|
||||
struct sSymbol *pScope; /* Section's symbol scope */
|
||||
struct Symbol *pScope; /* Section's symbol scope */
|
||||
uint32_t offset;
|
||||
struct SectionStackEntry *pNext;
|
||||
};
|
||||
@@ -63,7 +66,7 @@ static void reserveSpace(uint32_t delta_size)
|
||||
* A check at the linking stage is still necessary.
|
||||
*/
|
||||
if (newSize > maxSize)
|
||||
fatalerror("Section '%s' is too big (max size = 0x%X bytes, reached 0x%X).",
|
||||
fatalerror("Section '%s' is too big (max size = 0x%" PRIX32 " bytes, reached 0x%" PRIX32 ").",
|
||||
pCurrentSection->pzName, maxSize, newSize);
|
||||
}
|
||||
|
||||
@@ -85,29 +88,40 @@ struct Section *out_FindSectionByName(const char *pzName)
|
||||
* Find a section by name and type. If it doesn't exist, create it
|
||||
*/
|
||||
static struct Section *getSection(char const *pzName, enum SectionType type,
|
||||
uint32_t org, uint32_t bank,
|
||||
uint32_t alignment, bool isUnion)
|
||||
uint32_t org, struct SectionSpec const *attrs,
|
||||
enum SectionModifier mod)
|
||||
{
|
||||
#define mask(align) ((1 << (align)) - 1)
|
||||
uint32_t bank = attrs->bank;
|
||||
uint8_t alignment = attrs->alignment;
|
||||
uint16_t alignOffset = attrs->alignOfs;
|
||||
|
||||
if (bank != -1) {
|
||||
if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM
|
||||
&& type != SECTTYPE_SRAM && type != SECTTYPE_WRAMX)
|
||||
yyerror("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections");
|
||||
else if (bank < bankranges[type][0]
|
||||
|| bank > bankranges[type][1])
|
||||
yyerror("%s bank value $%x out of range ($%x to $%x)",
|
||||
yyerror("%s bank value $%" PRIx32 " out of range ($%" PRIx32 " to $%" PRIx32 ")",
|
||||
typeNames[type], bank,
|
||||
bankranges[type][0], bankranges[type][1]);
|
||||
}
|
||||
|
||||
if (alignment != 1) {
|
||||
/* It doesn't make sense to have both set */
|
||||
uint32_t mask = alignment - 1;
|
||||
if (alignOffset >= 1 << alignment) {
|
||||
yyerror("Alignment offset must not be greater than alignment (%" PRIu16 " < %u)",
|
||||
alignOffset, 1U << alignment);
|
||||
alignOffset = 0;
|
||||
}
|
||||
|
||||
if (alignment != 0) {
|
||||
/* It doesn't make sense to have both alignment and org set */
|
||||
uint32_t mask = mask(alignment);
|
||||
|
||||
if (org != -1) {
|
||||
if (org & mask)
|
||||
if ((org - alignOffset) & mask)
|
||||
yyerror("Section \"%s\"'s fixed address doesn't match its alignment",
|
||||
pzName);
|
||||
alignment = 1; /* Ignore it if it's satisfied */
|
||||
alignment = 0; /* Ignore it if it's satisfied */
|
||||
} else if (startaddr[type] & mask) {
|
||||
yyerror("Section \"%s\"'s alignment cannot be attained in %s",
|
||||
pzName, typeNames[type]);
|
||||
@@ -116,7 +130,7 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
|
||||
|
||||
if (org != -1) {
|
||||
if (org < startaddr[type] || org > endaddr(type))
|
||||
yyerror("Section \"%s\"'s fixed address %#x is outside of range [%#x; %#x]",
|
||||
yyerror("Section \"%s\"'s fixed address %#" PRIx32 " is outside of range [%#" PRIx16 "; %#" PRIx16 "]",
|
||||
pzName, org, startaddr[type], endaddr(type));
|
||||
}
|
||||
|
||||
@@ -137,48 +151,57 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
|
||||
fail("Section \"%s\" already exists but with type %s",
|
||||
pSect->pzName, typeNames[pSect->nType]);
|
||||
|
||||
if (pSect->modifier != mod)
|
||||
fail("Section \"%s\" already declared as %s section",
|
||||
pSect->pzName, sectionModNames[pSect->modifier]);
|
||||
/*
|
||||
* Normal sections need to have exactly identical constraints;
|
||||
* but unionized sections only need "compatible" constraints,
|
||||
* and they end up with the strictest combination of both
|
||||
*/
|
||||
if (isUnion) {
|
||||
if (!pSect->isUnion)
|
||||
fail("Section \"%s\" already declared as non-union",
|
||||
pSect->pzName);
|
||||
if (mod == SECTION_UNION) {
|
||||
/*
|
||||
* WARNING: see comment abount assumption in
|
||||
* WARNING: see comment about assumption in
|
||||
* `EndLoadSection` if modifying the following check!
|
||||
*/
|
||||
if (sect_HasData(type))
|
||||
fail("Cannot declare ROM sections as UNION");
|
||||
if (org != -1) {
|
||||
/* If neither is fixed, they must be the same */
|
||||
/* If both are fixed, they must be the same */
|
||||
if (pSect->nOrg != -1 && pSect->nOrg != org)
|
||||
fail("Section \"%s\" already declared as fixed at different address $%x",
|
||||
fail("Section \"%s\" already declared as fixed at different address $%" PRIx32,
|
||||
pSect->pzName, pSect->nOrg);
|
||||
else if (pSect->nAlign != 0
|
||||
&& ((pSect->nAlign - 1) & org))
|
||||
fail("Section \"%s\" already declared as aligned to %u bytes",
|
||||
pSect->pzName, pSect->nAlign);
|
||||
&& (mask(pSect->nAlign)
|
||||
& (org - pSect->alignOfs)))
|
||||
fail("Section \"%s\" already declared as aligned to %u bytes (offset %" PRIu16 ")",
|
||||
pSect->pzName, 1U << pSect->nAlign,
|
||||
pSect->alignOfs);
|
||||
else
|
||||
/* Otherwise, just override */
|
||||
pSect->nOrg = org;
|
||||
} else if (alignment != 0) {
|
||||
/* Make sure any fixed address is compatible */
|
||||
if (pSect->nOrg != -1) {
|
||||
uint32_t mask = alignment - 1;
|
||||
|
||||
if (pSect->nOrg & mask)
|
||||
fail("Section \"%s\" already declared as fixed at incompatible address $%x",
|
||||
if ((pSect->nOrg - alignOffset)
|
||||
& mask(alignment))
|
||||
fail("Section \"%s\" already declared as fixed at incompatible address $%" PRIx32,
|
||||
pSect->pzName,
|
||||
pSect->nOrg);
|
||||
/* Check if alignment offsets are compatible */
|
||||
} else if ((alignOffset & mask(pSect->nAlign))
|
||||
!= (pSect->alignOfs
|
||||
& mask(alignment))) {
|
||||
fail("Section \"%s\" already declared with incompatible %" PRIu8 "-byte alignment (offset %" PRIu16 ")",
|
||||
pSect->pzName, pSect->nAlign,
|
||||
pSect->alignOfs);
|
||||
} else if (alignment > pSect->nAlign) {
|
||||
/*
|
||||
* If the section is not fixed,
|
||||
* its alignment is the largest of both
|
||||
*/
|
||||
pSect->nAlign = alignment;
|
||||
pSect->alignOfs = alignOffset;
|
||||
}
|
||||
}
|
||||
/* If the section's bank is unspecified, override it */
|
||||
@@ -186,18 +209,19 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
|
||||
pSect->nBank = bank;
|
||||
/* If both specify a bank, it must be the same one */
|
||||
else if (bank != -1 && pSect->nBank != bank)
|
||||
fail("Section \"%s\" already declared with different bank %u",
|
||||
fail("Section \"%s\" already declared with different bank %" PRIu32,
|
||||
pSect->pzName, pSect->nBank);
|
||||
} else {
|
||||
if (pSect->isUnion)
|
||||
fail("Section \"%s\" already declared as union",
|
||||
pSect->pzName);
|
||||
} else { /* Section fragments are handled identically in RGBASM */
|
||||
/* However, concaternating non-fragments will be made an error */
|
||||
if (pSect->modifier != SECTION_FRAGMENT || mod != SECTION_FRAGMENT)
|
||||
warning(WARNING_OBSOLETE, "Concatenation of non-fragment sections is deprecated");
|
||||
|
||||
if (org != pSect->nOrg) {
|
||||
if (pSect->nOrg == -1)
|
||||
fail("Section \"%s\" already declared as floating",
|
||||
pSect->pzName);
|
||||
else
|
||||
fail("Section \"%s\" already declared as fixed at $%x",
|
||||
fail("Section \"%s\" already declared as fixed at $%" PRIx32,
|
||||
pSect->pzName, pSect->nOrg);
|
||||
}
|
||||
if (bank != pSect->nBank) {
|
||||
@@ -205,7 +229,7 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
|
||||
fail("Section \"%s\" already declared as floating bank",
|
||||
pSect->pzName);
|
||||
else
|
||||
fail("Section \"%s\" already declared as fixed at bank %u",
|
||||
fail("Section \"%s\" already declared as fixed at bank %" PRIu32,
|
||||
pSect->pzName, pSect->nBank);
|
||||
}
|
||||
if (alignment != pSect->nAlign) {
|
||||
@@ -214,7 +238,8 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
|
||||
pSect->pzName);
|
||||
else
|
||||
fail("Section \"%s\" already declared as aligned to %u bytes",
|
||||
pSect->pzName, pSect->nAlign);
|
||||
pSect->pzName,
|
||||
1U << pSect->nAlign);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,11 +259,12 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
|
||||
fatalerror("Not enough memory for sectionname");
|
||||
|
||||
pSect->nType = type;
|
||||
pSect->isUnion = isUnion;
|
||||
pSect->modifier = mod;
|
||||
pSect->size = 0;
|
||||
pSect->nOrg = org;
|
||||
pSect->nBank = bank;
|
||||
pSect->nAlign = alignment;
|
||||
pSect->alignOfs = alignOffset;
|
||||
pSect->pNext = pSectionList;
|
||||
pSect->pPatches = NULL;
|
||||
|
||||
@@ -261,18 +287,17 @@ static struct Section *getSection(char const *pzName, enum SectionType type,
|
||||
pSectionList = pSect;
|
||||
|
||||
return pSect;
|
||||
#undef mask
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the current section
|
||||
*/
|
||||
static void setSection(struct Section *pSect)
|
||||
static void changeSection(void)
|
||||
{
|
||||
if (nUnionDepth > 0)
|
||||
fatalerror("Cannot change the section within a UNION");
|
||||
|
||||
pPCSymbol->pSection = pSect;
|
||||
|
||||
sym_SetCurrentSymbolScope(NULL);
|
||||
}
|
||||
|
||||
@@ -280,16 +305,15 @@ static void setSection(struct Section *pSect)
|
||||
* Set the current section by name and type
|
||||
*/
|
||||
void out_NewSection(char const *pzName, uint32_t type, uint32_t org,
|
||||
struct SectionSpec const *attributes, bool isUnion)
|
||||
struct SectionSpec const *attribs, enum SectionModifier mod)
|
||||
{
|
||||
if (currentLoadSection)
|
||||
fatalerror("Cannot change the section within a `LOAD` block");
|
||||
|
||||
struct Section *pSect = getSection(pzName, type, org, attributes->bank,
|
||||
1 << attributes->alignment, isUnion);
|
||||
struct Section *pSect = getSection(pzName, type, org, attribs, mod);
|
||||
|
||||
setSection(pSect);
|
||||
curOffset = isUnion ? 0 : pSect->size;
|
||||
changeSection();
|
||||
curOffset = mod == SECTION_UNION ? 0 : pSect->size;
|
||||
pCurrentSection = pSect;
|
||||
}
|
||||
|
||||
@@ -297,19 +321,18 @@ void out_NewSection(char const *pzName, uint32_t type, uint32_t org,
|
||||
* Set the current section by name and type
|
||||
*/
|
||||
void out_SetLoadSection(char const *name, uint32_t type, uint32_t org,
|
||||
struct SectionSpec const *attributes)
|
||||
struct SectionSpec const *attribs)
|
||||
{
|
||||
checkcodesection();
|
||||
|
||||
if (currentLoadSection)
|
||||
fatalerror("`LOAD` blocks cannot be nested");
|
||||
|
||||
struct Section *pSect = getSection(name, type, org, attributes->bank,
|
||||
1 << attributes->alignment, false);
|
||||
struct Section *pSect = getSection(name, type, org, attribs, false);
|
||||
|
||||
loadOffset = curOffset;
|
||||
curOffset = 0; /* curOffset -= loadOffset; */
|
||||
setSection(pSect);
|
||||
changeSection();
|
||||
currentLoadSection = pSect;
|
||||
}
|
||||
|
||||
@@ -319,7 +342,7 @@ void out_EndLoadSection(void)
|
||||
yyerror("Found `ENDL` outside of a `LOAD` block");
|
||||
currentLoadSection = NULL;
|
||||
|
||||
setSection(pCurrentSection);
|
||||
changeSection();
|
||||
curOffset += loadOffset;
|
||||
loadOffset = 0;
|
||||
}
|
||||
@@ -334,6 +357,30 @@ uint32_t sect_GetOutputOffset(void)
|
||||
return curOffset + loadOffset;
|
||||
}
|
||||
|
||||
void sect_AlignPC(uint8_t alignment, uint16_t offset)
|
||||
{
|
||||
struct Section *sect = sect_GetSymbolSection();
|
||||
|
||||
if (sect->nOrg != -1) {
|
||||
if ((sym_GetPCValue() - offset) % (1 << alignment))
|
||||
yyerror("Section's fixed address fails required alignment (PC = $%04" PRIx32 ")",
|
||||
sym_GetPCValue());
|
||||
} else if (sect->nAlign != 0) {
|
||||
if ((((sect->alignOfs + curOffset) % (1 << sect->nAlign))
|
||||
- offset) % (1 << alignment)) {
|
||||
yyerror("Section's alignment fails required alignment (offset from section start = $%04" PRIx32 ")",
|
||||
curOffset);
|
||||
} else if (alignment > sect->nAlign) {
|
||||
sect->nAlign = alignment;
|
||||
sect->alignOfs =
|
||||
(offset - curOffset) % (1 << alignment);
|
||||
}
|
||||
} else {
|
||||
sect->nAlign = alignment;
|
||||
sect->alignOfs = offset;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void growSection(uint32_t growth)
|
||||
{
|
||||
curOffset += growth;
|
||||
@@ -392,11 +439,14 @@ void out_AbsByteGroup(uint8_t const *s, int32_t length)
|
||||
/*
|
||||
* Skip this many bytes
|
||||
*/
|
||||
void out_Skip(int32_t skip)
|
||||
void out_Skip(int32_t skip, bool ds)
|
||||
{
|
||||
checksection();
|
||||
reserveSpace(skip);
|
||||
|
||||
if (!ds && sect_HasData(pCurrentSection->nType))
|
||||
warning(WARNING_EMPTY_DATA_DIRECTIVE, "db/dw/dl directive without data in ROM");
|
||||
|
||||
if (!sect_HasData(pCurrentSection->nType)) {
|
||||
growSection(skip);
|
||||
} else if (nUnionDepth > 0) {
|
||||
@@ -509,12 +559,12 @@ void out_PCRelByte(struct Expression *expr)
|
||||
writebyte(0);
|
||||
} else {
|
||||
/* Target is relative to the byte *after* the operand */
|
||||
uint16_t address = sym_GetValue(pPCSymbol) + 1;
|
||||
uint16_t address = sym_GetPCValue() + 1;
|
||||
/* The offset wraps (jump from ROM to HRAM, for loopexample) */
|
||||
int16_t offset = expr->nVal - address;
|
||||
|
||||
if (offset < -128 || offset > 127) {
|
||||
yyerror("jr target out of reach (expected -129 < %d < 128)",
|
||||
yyerror("jr target out of reach (expected -129 < %" PRId16 " < 128)",
|
||||
offset);
|
||||
writebyte(0);
|
||||
} else {
|
||||
@@ -570,12 +620,13 @@ void out_BinaryFile(char const *s)
|
||||
void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
|
||||
{
|
||||
if (start_pos < 0) {
|
||||
yyerror("Start position cannot be negative (%d)", start_pos);
|
||||
yyerror("Start position cannot be negative (%" PRId32 ")",
|
||||
start_pos);
|
||||
start_pos = 0;
|
||||
}
|
||||
|
||||
if (length < 0) {
|
||||
yyerror("Number of bytes to read cannot be negative (%d)",
|
||||
yyerror("Number of bytes to read cannot be negative (%" PRId32 ")",
|
||||
length);
|
||||
length = 0;
|
||||
}
|
||||
@@ -630,7 +681,7 @@ void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
|
||||
yyerror("Error reading INCBIN file '%s': %s", s,
|
||||
strerror(errno));
|
||||
} else {
|
||||
yyerror("Premature end of file (%d bytes left to read)",
|
||||
yyerror("Premature end of file (%" PRId32 " bytes left to read)",
|
||||
todo + 1);
|
||||
}
|
||||
}
|
||||
@@ -654,6 +705,7 @@ void out_PushSection(void)
|
||||
pSect->offset = curOffset;
|
||||
pSect->pNext = pSectionStack;
|
||||
pSectionStack = pSect;
|
||||
/* TODO: maybe set current section to NULL? */
|
||||
}
|
||||
|
||||
void out_PopSection(void)
|
||||
@@ -667,7 +719,7 @@ void out_PopSection(void)
|
||||
struct SectionStackEntry *pSect;
|
||||
|
||||
pSect = pSectionStack;
|
||||
setSection(pSect->pSection);
|
||||
changeSection();
|
||||
pCurrentSection = pSect->pSection;
|
||||
sym_SetCurrentSymbolScope(pSect->pScope);
|
||||
curOffset = pSect->offset;
|
||||
|
||||
509
src/asm/symbol.c
509
src/asm/symbol.c
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -35,112 +36,111 @@
|
||||
|
||||
HashMap symbols;
|
||||
|
||||
static struct sSymbol *pScope; /* Current section symbol scope */
|
||||
struct sSymbol *pPCSymbol;
|
||||
static struct sSymbol *p_NARGSymbol;
|
||||
static struct sSymbol *p__LINE__Symbol;
|
||||
static char SavedTIME[256];
|
||||
static char SavedDATE[256];
|
||||
static char SavedTIMESTAMP_ISO8601_LOCAL[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 struct Symbol *symbolScope; /* Current section symbol scope */
|
||||
static struct Symbol *PCSymbol;
|
||||
static char savedTIME[256];
|
||||
static char savedDATE[256];
|
||||
static char savedTIMESTAMP_ISO8601_LOCAL[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;
|
||||
|
||||
bool sym_IsPC(struct Symbol const *sym)
|
||||
{
|
||||
return sym == PCSymbol;
|
||||
}
|
||||
|
||||
struct ForEachArgs {
|
||||
void (*func)(struct sSymbol *, void *);
|
||||
void (*func)(struct Symbol *symbol, void *arg);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static void forEachWrapper(void *_symbol, void *_argWrapper)
|
||||
{
|
||||
struct ForEachArgs *argWrapper = _argWrapper;
|
||||
struct sSymbol *symbol = _symbol;
|
||||
struct Symbol *symbol = _symbol;
|
||||
|
||||
argWrapper->func(symbol, argWrapper->arg);
|
||||
}
|
||||
|
||||
void sym_ForEach(void (*func)(struct sSymbol *, void *), void *arg)
|
||||
void sym_ForEach(void (*func)(struct Symbol *, void *), void *arg)
|
||||
{
|
||||
struct ForEachArgs argWrapper = { .func = func, .arg = arg };
|
||||
|
||||
hash_ForEach(symbols, forEachWrapper, &argWrapper);
|
||||
}
|
||||
|
||||
static int32_t Callback_NARG(struct sSymbol const *self)
|
||||
static int32_t Callback_NARG(void)
|
||||
{
|
||||
(void)self;
|
||||
return macro_NbArgs();
|
||||
}
|
||||
|
||||
static int32_t Callback__LINE__(struct sSymbol const *self)
|
||||
static int32_t Callback__LINE__(void)
|
||||
{
|
||||
(void)self;
|
||||
return nLineNo;
|
||||
}
|
||||
|
||||
static int32_t CallbackPC(struct sSymbol const *self)
|
||||
static int32_t CallbackPC(void)
|
||||
{
|
||||
return self->pSection ? self->pSection->nOrg + curOffset : 0;
|
||||
struct Section const *section = sect_GetSymbolSection();
|
||||
|
||||
return section ? section->nOrg + curOffset : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the nValue field of a symbol
|
||||
* Get the value field of a symbol
|
||||
*/
|
||||
int32_t sym_GetValue(struct sSymbol const *sym)
|
||||
int32_t sym_GetValue(struct Symbol const *sym)
|
||||
{
|
||||
if (sym->Callback)
|
||||
return sym->Callback(sym);
|
||||
if (sym_IsNumeric(sym) && sym->callback)
|
||||
return sym->callback();
|
||||
|
||||
if (sym->type == SYM_LABEL)
|
||||
return sym->nValue + sym->pSection->nOrg;
|
||||
/* TODO: do not use section's org directly */
|
||||
return sym->value + sym_GetSection(sym)->nOrg;
|
||||
|
||||
return sym->nValue;
|
||||
return sym->value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update a symbol's definition filename and line
|
||||
*/
|
||||
static void updateSymbolFilename(struct sSymbol *nsym)
|
||||
static void updateSymbolFilename(struct Symbol *sym)
|
||||
{
|
||||
if (snprintf(nsym->tzFileName, _MAX_PATH + 1, "%s",
|
||||
tzCurrentFileName) > _MAX_PATH) {
|
||||
if (snprintf(sym->fileName, _MAX_PATH + 1, "%s",
|
||||
tzCurrentFileName) > _MAX_PATH)
|
||||
fatalerror("%s: File name is too long: '%s'", __func__,
|
||||
tzCurrentFileName);
|
||||
}
|
||||
nsym->nFileLine = fstk_GetLine();
|
||||
sym->fileLine = fstk_GetLine();
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new symbol by name
|
||||
*/
|
||||
static struct sSymbol *createsymbol(char const *s)
|
||||
static struct Symbol *createsymbol(char const *s)
|
||||
{
|
||||
struct sSymbol *symbol = malloc(sizeof(*symbol));
|
||||
struct Symbol *symbol = malloc(sizeof(*symbol));
|
||||
|
||||
if (!symbol)
|
||||
fatalerror("Failed to create symbol: %s", strerror(errno));
|
||||
|
||||
if (snprintf(symbol->tzName, MAXSYMLEN + 1, "%s", s) > MAXSYMLEN)
|
||||
if (snprintf(symbol->name, MAXSYMLEN + 1, "%s", s) > MAXSYMLEN)
|
||||
warning(WARNING_LONG_STR, "Symbol name is too long: '%s'", s);
|
||||
|
||||
hash_AddElement(symbols, symbol->tzName, symbol);
|
||||
|
||||
symbol->isExported = false;
|
||||
symbol->isBuiltin = false;
|
||||
symbol->pScope = NULL;
|
||||
symbol->pSection = NULL;
|
||||
symbol->nValue = 0; /* TODO: is this necessary? */
|
||||
symbol->pMacro = NULL;
|
||||
symbol->Callback = NULL;
|
||||
|
||||
symbol->scope = NULL;
|
||||
symbol->section = NULL;
|
||||
updateSymbolFilename(symbol);
|
||||
symbol->ID = -1;
|
||||
symbol->next = NULL;
|
||||
updateSymbolFilename(symbol);
|
||||
|
||||
hash_AddElement(symbols, symbol->name, symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@@ -149,20 +149,20 @@ static struct sSymbol *createsymbol(char const *s)
|
||||
* the name with the parent symbol's name.
|
||||
*/
|
||||
static void fullSymbolName(char *output, size_t outputSize,
|
||||
char const *localName, const struct sSymbol *scope)
|
||||
char const *localName, const struct Symbol *scope)
|
||||
{
|
||||
const struct sSymbol *parent = scope->pScope ? scope->pScope : scope;
|
||||
int n = snprintf(output, outputSize, "%s%s", parent->tzName, localName);
|
||||
const struct Symbol *parent = scope->scope ? scope->scope : scope;
|
||||
int n = snprintf(output, outputSize, "%s%s", parent->name, localName);
|
||||
|
||||
if (n >= (int)outputSize)
|
||||
fatalerror("Symbol name is too long: '%s%s'",
|
||||
parent->tzName, localName);
|
||||
fatalerror("Symbol name is too long: '%s%s'", parent->name,
|
||||
localName);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a symbol by name and scope
|
||||
*/
|
||||
static struct sSymbol *findsymbol(char const *s, struct sSymbol const *scope)
|
||||
static struct Symbol *findsymbol(char const *s, struct Symbol const *scope)
|
||||
{
|
||||
char fullname[MAXSYMLEN + 1];
|
||||
|
||||
@@ -183,19 +183,12 @@ static struct sSymbol *findsymbol(char const *s, struct sSymbol const *scope)
|
||||
/*
|
||||
* Find a symbol by name, with automatically determined scope
|
||||
*/
|
||||
struct sSymbol *sym_FindSymbol(char const *tzName)
|
||||
struct Symbol *sym_FindSymbol(char const *symName)
|
||||
{
|
||||
struct sSymbol *pscope;
|
||||
|
||||
if (*tzName == '.')
|
||||
pscope = pScope;
|
||||
else
|
||||
pscope = NULL;
|
||||
|
||||
return findsymbol(tzName, pscope);
|
||||
return findsymbol(symName, symName[0] == '.' ? symbolScope : NULL);
|
||||
}
|
||||
|
||||
static inline bool isReferenced(struct sSymbol const *sym)
|
||||
static inline bool isReferenced(struct Symbol const *sym)
|
||||
{
|
||||
return sym->ID != -1;
|
||||
}
|
||||
@@ -203,48 +196,54 @@ static inline bool isReferenced(struct sSymbol const *sym)
|
||||
/*
|
||||
* Purge a symbol
|
||||
*/
|
||||
void sym_Purge(char const *tzName)
|
||||
void sym_Purge(char const *symName)
|
||||
{
|
||||
struct sSymbol *scope = tzName[0] == '.' ? pScope : NULL;
|
||||
struct sSymbol *symbol = findsymbol(tzName, scope);
|
||||
struct Symbol *scope = symName[0] == '.' ? symbolScope : NULL;
|
||||
struct Symbol *symbol = findsymbol(symName, scope);
|
||||
|
||||
if (!symbol) {
|
||||
yyerror("'%s' not defined", tzName);
|
||||
yyerror("'%s' not defined", symName);
|
||||
} else if (symbol->isBuiltin) {
|
||||
yyerror("Built-in symbol '%s' cannot be purged", tzName);
|
||||
yyerror("Built-in symbol '%s' cannot be purged", symName);
|
||||
} else if (isReferenced(symbol)) {
|
||||
yyerror("Symbol \"%s\" is referenced and thus cannot be purged",
|
||||
tzName);
|
||||
symName);
|
||||
} else {
|
||||
hash_RemoveElement(symbols, tzName);
|
||||
free(symbol->pMacro);
|
||||
hash_RemoveElement(symbols, symbol->name);
|
||||
if (symbol->type == SYM_MACRO)
|
||||
free(symbol->macro);
|
||||
free(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t sym_GetPCValue(void)
|
||||
{
|
||||
struct Section const *sect = sect_GetSymbolSection();
|
||||
|
||||
if (!sect)
|
||||
yyerror("PC has no value outside a section");
|
||||
else if (sect->nOrg == -1)
|
||||
yyerror("Expected constant PC but section is not fixed");
|
||||
else
|
||||
return CallbackPC();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a constant symbols value
|
||||
*/
|
||||
uint32_t sym_GetConstantValue(char const *s)
|
||||
{
|
||||
struct sSymbol const *psym = sym_FindSymbol(s);
|
||||
struct Symbol const *sym = sym_FindSymbol(s);
|
||||
|
||||
if (psym == pPCSymbol) {
|
||||
if (!pCurrentSection)
|
||||
yyerror("PC has no value outside a section");
|
||||
else if (pCurrentSection->nOrg == -1)
|
||||
yyerror("Expected constant PC but section is not fixed");
|
||||
else
|
||||
return sym_GetValue(psym);
|
||||
|
||||
} else if (psym != NULL) {
|
||||
if (sym_IsConstant(psym))
|
||||
return sym_GetValue(psym);
|
||||
|
||||
yyerror("\"%s\" does not have a constant value", s);
|
||||
} else {
|
||||
if (sym == NULL)
|
||||
yyerror("'%s' not defined", s);
|
||||
}
|
||||
else if (sym == PCSymbol)
|
||||
return sym_GetPCValue();
|
||||
else if (!sym_IsConstant(sym))
|
||||
yyerror("\"%s\" does not have a constant value", s);
|
||||
else
|
||||
return sym_GetValue(sym);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -254,38 +253,26 @@ uint32_t sym_GetConstantValue(char const *s)
|
||||
*/
|
||||
uint32_t sym_GetDefinedValue(char const *s)
|
||||
{
|
||||
struct sSymbol const *psym = sym_FindSymbol(s);
|
||||
struct Symbol const *sym = sym_FindSymbol(s);
|
||||
|
||||
if (psym != NULL) {
|
||||
if (sym_IsDefined(psym)) {
|
||||
if (!sym_IsNumeric(psym))
|
||||
yyerror("'%s' is a macro or string symbol", s);
|
||||
|
||||
return sym_GetValue(psym);
|
||||
}
|
||||
}
|
||||
|
||||
yyerror("'%s' not defined", s);
|
||||
if (sym == NULL || !sym_IsDefined(sym))
|
||||
yyerror("'%s' not defined", s);
|
||||
else if (!sym_IsNumeric(sym))
|
||||
yyerror("'%s' is a macro or string symbol", s);
|
||||
else
|
||||
return sym_GetValue(sym);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sSymbol *sym_GetCurrentSymbolScope(void)
|
||||
struct Symbol *sym_GetCurrentSymbolScope(void)
|
||||
{
|
||||
return pScope;
|
||||
return symbolScope;
|
||||
}
|
||||
|
||||
void sym_SetCurrentSymbolScope(struct sSymbol *pNewScope)
|
||||
void sym_SetCurrentSymbolScope(struct Symbol *newScope)
|
||||
{
|
||||
pScope = pNewScope;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a macro by name
|
||||
*/
|
||||
struct sSymbol *sym_FindMacro(char const *s)
|
||||
{
|
||||
return findsymbol(s, NULL);
|
||||
symbolScope = newScope;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -293,38 +280,31 @@ struct sSymbol *sym_FindMacro(char const *s)
|
||||
* hasn't already been defined or referenced in a context that would
|
||||
* require that it be relocatable
|
||||
*/
|
||||
static struct sSymbol *createNonrelocSymbol(char const *tzSym)
|
||||
static struct Symbol *createNonrelocSymbol(char const *symbolName)
|
||||
{
|
||||
struct sSymbol *nsym = findsymbol(tzSym, NULL);
|
||||
struct Symbol *symbol = findsymbol(symbolName, NULL);
|
||||
|
||||
if (nsym != NULL) {
|
||||
if (sym_IsDefined(nsym)) {
|
||||
yyerror("'%s' already defined at %s(%u)",
|
||||
tzSym, nsym->tzFileName, nsym->nFileLine);
|
||||
} else {
|
||||
yyerror("'%s' referenced as label at %s(%u)",
|
||||
tzSym, nsym->tzFileName, nsym->nFileLine);
|
||||
}
|
||||
} else {
|
||||
nsym = createsymbol(tzSym);
|
||||
}
|
||||
if (!symbol)
|
||||
symbol = createsymbol(symbolName);
|
||||
else if (sym_IsDefined(symbol))
|
||||
yyerror("'%s' already defined at %s(%" PRIu32 ")", symbolName,
|
||||
symbol->fileName, symbol->fileLine);
|
||||
|
||||
return nsym;
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an equated symbol
|
||||
*/
|
||||
struct sSymbol *sym_AddEqu(char const *tzSym, int32_t value)
|
||||
struct Symbol *sym_AddEqu(char const *symName, int32_t value)
|
||||
{
|
||||
struct sSymbol *nsym = createNonrelocSymbol(tzSym);
|
||||
struct Symbol *sym = createNonrelocSymbol(symName);
|
||||
|
||||
nsym->nValue = value;
|
||||
nsym->type = SYM_EQU;
|
||||
nsym->pScope = NULL;
|
||||
updateSymbolFilename(nsym);
|
||||
sym->type = SYM_EQU;
|
||||
sym->callback = NULL;
|
||||
sym->value = value;
|
||||
|
||||
return nsym;
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -339,191 +319,180 @@ struct sSymbol *sym_AddEqu(char const *tzSym, int32_t value)
|
||||
* of the string are enough: sym_AddString("M_PI", "3.1415"). This is the same
|
||||
* as ``` M_PI EQUS "3.1415" ```
|
||||
*/
|
||||
struct sSymbol *sym_AddString(char const *tzSym, char const *tzValue)
|
||||
struct Symbol *sym_AddString(char const *symName, char const *value)
|
||||
{
|
||||
struct sSymbol *nsym = createNonrelocSymbol(tzSym);
|
||||
struct Symbol *sym = createNonrelocSymbol(symName);
|
||||
size_t len = strlen(value);
|
||||
char *string = malloc(len + 1);
|
||||
|
||||
nsym->pMacro = malloc(strlen(tzValue) + 1);
|
||||
|
||||
if (nsym->pMacro != NULL)
|
||||
strcpy(nsym->pMacro, tzValue);
|
||||
else
|
||||
if (string == NULL)
|
||||
fatalerror("No memory for string equate");
|
||||
strcpy(string, value);
|
||||
|
||||
nsym->type = SYM_EQUS;
|
||||
nsym->ulMacroSize = strlen(tzValue);
|
||||
nsym->pScope = NULL;
|
||||
sym->type = SYM_EQUS;
|
||||
/* TODO: use other fields */
|
||||
sym->macroSize = len;
|
||||
sym->macro = string;
|
||||
|
||||
return nsym;
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Alter a SET symbols value
|
||||
*/
|
||||
struct sSymbol *sym_AddSet(char const *tzSym, int32_t value)
|
||||
struct Symbol *sym_AddSet(char const *symName, int32_t value)
|
||||
{
|
||||
struct sSymbol *nsym = findsymbol(tzSym, NULL);
|
||||
struct Symbol *sym = findsymbol(symName, NULL);
|
||||
|
||||
if (nsym != NULL) {
|
||||
if (sym_IsDefined(nsym)) {
|
||||
if (nsym->type == SYM_LABEL)
|
||||
yyerror("'%s' already defined as non-constant at %s(%u)",
|
||||
tzSym,
|
||||
nsym->tzFileName,
|
||||
nsym->nFileLine);
|
||||
else if (nsym->type != SYM_SET)
|
||||
yyerror("'%s' already defined as constant at %s(%u)",
|
||||
tzSym,
|
||||
nsym->tzFileName,
|
||||
nsym->nFileLine);
|
||||
} else if (nsym->type == SYM_REF) {
|
||||
yyerror("'%s' already referenced at %s(%u)",
|
||||
tzSym,
|
||||
nsym->tzFileName,
|
||||
nsym->nFileLine);
|
||||
}
|
||||
} else {
|
||||
nsym = createsymbol(tzSym);
|
||||
}
|
||||
if (sym == NULL)
|
||||
sym = createsymbol(symName);
|
||||
else if (sym_IsDefined(sym) && sym->type != SYM_SET)
|
||||
yyerror("'%s' already defined as %s at %s(%" PRIu32 ")",
|
||||
symName, sym->type == SYM_LABEL ? "label" : "constant",
|
||||
sym->fileName, sym->fileLine);
|
||||
else
|
||||
/* TODO: can the scope be incorrect when talking over refs? */
|
||||
updateSymbolFilename(sym);
|
||||
|
||||
nsym->nValue = value;
|
||||
nsym->type = SYM_SET;
|
||||
nsym->pScope = NULL;
|
||||
updateSymbolFilename(nsym);
|
||||
sym->type = SYM_SET;
|
||||
sym->callback = NULL;
|
||||
sym->value = value;
|
||||
|
||||
return nsym;
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a local (.name) relocatable symbol
|
||||
*/
|
||||
struct sSymbol *sym_AddLocalReloc(char const *tzSym)
|
||||
struct Symbol *sym_AddLocalReloc(char const *symName)
|
||||
{
|
||||
if (pScope) {
|
||||
char fullname[MAXSYMLEN + 1];
|
||||
|
||||
fullSymbolName(fullname, sizeof(fullname), tzSym, pScope);
|
||||
return sym_AddReloc(fullname);
|
||||
} else {
|
||||
yyerror("Local label '%s' in main scope", tzSym);
|
||||
if (!symbolScope) {
|
||||
yyerror("Local label '%s' in main scope", symName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char fullname[MAXSYMLEN + 1];
|
||||
|
||||
fullSymbolName(fullname, sizeof(fullname), symName, symbolScope);
|
||||
return sym_AddReloc(fullname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a relocatable symbol
|
||||
*/
|
||||
struct sSymbol *sym_AddReloc(char const *tzSym)
|
||||
struct Symbol *sym_AddReloc(char const *symName)
|
||||
{
|
||||
struct sSymbol *scope = NULL;
|
||||
struct sSymbol *nsym;
|
||||
char *localPtr = strchr(tzSym, '.');
|
||||
struct Symbol const *scope = NULL;
|
||||
char *localPtr = strchr(symName, '.');
|
||||
|
||||
if (localPtr != NULL) {
|
||||
if (!pScope) {
|
||||
if (!symbolScope) {
|
||||
yyerror("Local label in main scope");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sSymbol *parent = pScope->pScope ?
|
||||
pScope->pScope : pScope;
|
||||
uint32_t parentLen = localPtr - tzSym;
|
||||
scope = symbolScope->scope ? symbolScope->scope : symbolScope;
|
||||
uint32_t parentLen = localPtr - symName;
|
||||
|
||||
if (strchr(localPtr + 1, '.') != NULL)
|
||||
fatalerror("'%s' is a nonsensical reference to a nested local symbol",
|
||||
tzSym);
|
||||
else if (strlen(parent->tzName) != parentLen
|
||||
|| strncmp(tzSym, parent->tzName, parentLen) != 0)
|
||||
symName);
|
||||
else if (strlen(scope->name) != parentLen
|
||||
|| strncmp(symName, scope->name, parentLen) != 0)
|
||||
yyerror("Not currently in the scope of '%.*s'",
|
||||
parentLen, tzSym);
|
||||
|
||||
scope = parent;
|
||||
parentLen, symName);
|
||||
}
|
||||
|
||||
nsym = findsymbol(tzSym, scope);
|
||||
struct Symbol *sym = findsymbol(symName, scope);
|
||||
|
||||
if (!nsym)
|
||||
nsym = createsymbol(tzSym);
|
||||
else if (sym_IsDefined(nsym))
|
||||
yyerror("'%s' already defined in %s(%d)", tzSym,
|
||||
nsym->tzFileName, nsym->nFileLine);
|
||||
if (!sym)
|
||||
sym = createsymbol(symName);
|
||||
else if (sym_IsDefined(sym))
|
||||
yyerror("'%s' already defined in %s(%" PRIu32 ")", symName,
|
||||
sym->fileName, sym->fileLine);
|
||||
/* If the symbol already exists as a ref, just "take over" it */
|
||||
|
||||
nsym->nValue = curOffset;
|
||||
nsym->type = SYM_LABEL;
|
||||
sym->type = SYM_LABEL;
|
||||
sym->callback = NULL;
|
||||
sym->value = curOffset;
|
||||
|
||||
if (exportall)
|
||||
nsym->isExported = true;
|
||||
sym->isExported = true;
|
||||
|
||||
nsym->pScope = scope;
|
||||
nsym->pSection = sect_GetSymbolSection();
|
||||
sym->scope = scope;
|
||||
sym->section = sect_GetSymbolSection();
|
||||
/* Labels need to be assigned a section, except PC */
|
||||
if (!pCurrentSection && strcmp(tzSym, "@"))
|
||||
if (!sym->section && strcmp(symName, "@"))
|
||||
yyerror("Label \"%s\" created outside of a SECTION",
|
||||
tzSym);
|
||||
symName);
|
||||
|
||||
updateSymbolFilename(nsym);
|
||||
updateSymbolFilename(sym);
|
||||
|
||||
pScope = findsymbol(tzSym, scope);
|
||||
return pScope;
|
||||
/* Set the symbol as the new scope */
|
||||
/* TODO: don't do this for local labels */
|
||||
symbolScope = findsymbol(symName, scope);
|
||||
return symbolScope;
|
||||
}
|
||||
|
||||
/*
|
||||
* Export a symbol
|
||||
*/
|
||||
void sym_Export(char const *tzSym)
|
||||
void sym_Export(char const *symName)
|
||||
{
|
||||
struct sSymbol *nsym = sym_FindSymbol(tzSym);
|
||||
struct Symbol *sym = sym_FindSymbol(symName);
|
||||
|
||||
/* If the symbol doesn't exist, create a ref that can be purged */
|
||||
if (!nsym)
|
||||
nsym = sym_Ref(tzSym);
|
||||
nsym->isExported = true;
|
||||
if (!sym)
|
||||
sym = sym_Ref(symName);
|
||||
sym->isExported = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a macro definition
|
||||
*/
|
||||
struct sSymbol *sym_AddMacro(char const *tzSym, int32_t nDefLineNo)
|
||||
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo)
|
||||
{
|
||||
struct sSymbol *nsym = createNonrelocSymbol(tzSym);
|
||||
struct Symbol *sym = createNonrelocSymbol(symName);
|
||||
|
||||
nsym->type = SYM_MACRO;
|
||||
nsym->pScope = NULL;
|
||||
nsym->ulMacroSize = ulNewMacroSize;
|
||||
nsym->pMacro = tzNewMacro;
|
||||
updateSymbolFilename(nsym);
|
||||
sym->type = SYM_MACRO;
|
||||
sym->macroSize = ulNewMacroSize;
|
||||
sym->macro = tzNewMacro;
|
||||
updateSymbolFilename(sym);
|
||||
/*
|
||||
* The symbol is created at the line after the `endm`,
|
||||
* override this with the actual definition line
|
||||
*/
|
||||
nsym->nFileLine = nDefLineNo;
|
||||
sym->fileLine = defLineNo;
|
||||
|
||||
return nsym;
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flag that a symbol is referenced in an RPN expression
|
||||
* and create it if it doesn't exist yet
|
||||
*/
|
||||
struct sSymbol *sym_Ref(char const *tzSym)
|
||||
struct Symbol *sym_Ref(char const *symName)
|
||||
{
|
||||
struct sSymbol *nsym = sym_FindSymbol(tzSym);
|
||||
struct Symbol *nsym = sym_FindSymbol(symName);
|
||||
|
||||
if (nsym == NULL) {
|
||||
char fullname[MAXSYMLEN + 1];
|
||||
struct Symbol const *scope = NULL;
|
||||
|
||||
if (*tzSym == '.') {
|
||||
if (!pScope)
|
||||
if (symName[0] == '.') {
|
||||
if (!symbolScope)
|
||||
fatalerror("Local label reference '%s' in main scope",
|
||||
tzSym);
|
||||
fullSymbolName(fullname, sizeof(fullname), tzSym,
|
||||
pScope);
|
||||
tzSym = fullname;
|
||||
symName);
|
||||
scope = symbolScope->scope ? symbolScope->scope
|
||||
: symbolScope;
|
||||
fullSymbolName(fullname, sizeof(fullname), symName,
|
||||
symbolScope);
|
||||
symName = fullname;
|
||||
}
|
||||
|
||||
nsym = createsymbol(tzSym);
|
||||
nsym = createsymbol(symName);
|
||||
nsym->type = SYM_REF;
|
||||
nsym->scope = scope;
|
||||
}
|
||||
|
||||
return nsym;
|
||||
@@ -553,22 +522,21 @@ static inline char const *removeLeadingZeros(char const *ptr)
|
||||
*/
|
||||
void sym_Init(void)
|
||||
{
|
||||
pPCSymbol = sym_AddReloc("@");
|
||||
pPCSymbol->Callback = CallbackPC;
|
||||
pPCSymbol->isBuiltin = true;
|
||||
p_NARGSymbol = sym_AddEqu("_NARG", 0);
|
||||
p_NARGSymbol->Callback = Callback_NARG;
|
||||
p_NARGSymbol->isBuiltin = true;
|
||||
p__LINE__Symbol = sym_AddEqu("__LINE__", 0);
|
||||
p__LINE__Symbol->Callback = Callback__LINE__;
|
||||
p__LINE__Symbol->isBuiltin = true;
|
||||
struct sSymbol *_RSSymbol = sym_AddSet("_RS", 0);
|
||||
struct Symbol *_NARGSymbol = sym_AddEqu("_NARG", 0);
|
||||
struct Symbol *__LINE__Symbol = sym_AddEqu("__LINE__", 0);
|
||||
|
||||
_RSSymbol->isBuiltin = true;
|
||||
PCSymbol = sym_AddReloc("@"),
|
||||
PCSymbol->isBuiltin = true;
|
||||
PCSymbol->callback = CallbackPC;
|
||||
_NARGSymbol->isBuiltin = true;
|
||||
_NARGSymbol->callback = Callback_NARG;
|
||||
__LINE__Symbol->isBuiltin = true;
|
||||
__LINE__Symbol->callback = Callback__LINE__;
|
||||
sym_AddSet("_RS", 0)->isBuiltin = true;
|
||||
|
||||
sym_AddEqu("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR);
|
||||
sym_AddEqu("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR);
|
||||
sym_AddEqu("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH);
|
||||
sym_AddEqu("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR)->isBuiltin = true;
|
||||
sym_AddEqu("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR)->isBuiltin = true;
|
||||
sym_AddEqu("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH)->isBuiltin = true;
|
||||
|
||||
time_t now = time(NULL);
|
||||
|
||||
@@ -581,43 +549,38 @@ void sym_Init(void)
|
||||
const struct tm *time_utc = gmtime(&now);
|
||||
const struct tm *time_local = localtime(&now);
|
||||
|
||||
strftime(SavedTIME, sizeof(SavedTIME), "\"%H:%M:%S\"",
|
||||
time_local);
|
||||
strftime(SavedDATE, sizeof(SavedDATE), "\"%d %B %Y\"",
|
||||
time_local);
|
||||
strftime(SavedTIMESTAMP_ISO8601_LOCAL,
|
||||
sizeof(SavedTIMESTAMP_ISO8601_LOCAL), "\"%Y-%m-%dT%H-%M-%S%z\"",
|
||||
strftime(savedTIME, sizeof(savedTIME), "\"%H:%M:%S\"", time_local);
|
||||
strftime(savedDATE, sizeof(savedDATE), "\"%d %B %Y\"", time_local);
|
||||
strftime(savedTIMESTAMP_ISO8601_LOCAL,
|
||||
sizeof(savedTIMESTAMP_ISO8601_LOCAL), "\"%Y-%m-%dT%H:%M:%S%z\"",
|
||||
time_local);
|
||||
|
||||
strftime(SavedTIMESTAMP_ISO8601_UTC,
|
||||
sizeof(SavedTIMESTAMP_ISO8601_UTC), "\"%Y-%m-%dT%H-%M-%SZ\"",
|
||||
strftime(savedTIMESTAMP_ISO8601_UTC,
|
||||
sizeof(savedTIMESTAMP_ISO8601_UTC), "\"%Y-%m-%dT%H:%M:%SZ\"",
|
||||
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);
|
||||
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) do { \
|
||||
struct sSymbol *symbol = sym_AddString(name, val); \
|
||||
symbol->isBuiltin = true; \
|
||||
} while (0)
|
||||
addString("__TIME__", SavedTIME);
|
||||
addString("__DATE__", SavedDATE);
|
||||
addString("__ISO_8601_LOCAL__", SavedTIMESTAMP_ISO8601_LOCAL);
|
||||
addString("__ISO_8601_UTC__", SavedTIMESTAMP_ISO8601_UTC);
|
||||
#define addString(name, val) sym_AddString(name, val)->isBuiltin = true
|
||||
addString("__TIME__", savedTIME);
|
||||
addString("__DATE__", savedDATE);
|
||||
addString("__ISO_8601_LOCAL__", savedTIMESTAMP_ISO8601_LOCAL);
|
||||
addString("__ISO_8601_UTC__", savedTIMESTAMP_ISO8601_UTC);
|
||||
/* This cannot start with zeros */
|
||||
addString("__UTC_YEAR__", SavedYEAR);
|
||||
addString("__UTC_MONTH__", removeLeadingZeros(SavedMONTH));
|
||||
addString("__UTC_DAY__", removeLeadingZeros(SavedDAY));
|
||||
addString("__UTC_HOUR__", removeLeadingZeros(SavedHOUR));
|
||||
addString("__UTC_MINUTE__", removeLeadingZeros(SavedMINUTE));
|
||||
addString("__UTC_SECOND__", removeLeadingZeros(SavedSECOND));
|
||||
addString("__UTC_YEAR__", savedYEAR);
|
||||
addString("__UTC_MONTH__", removeLeadingZeros(savedMONTH));
|
||||
addString("__UTC_DAY__", removeLeadingZeros(savedDAY));
|
||||
addString("__UTC_HOUR__", removeLeadingZeros(savedHOUR));
|
||||
addString("__UTC_MINUTE__", removeLeadingZeros(savedMINUTE));
|
||||
addString("__UTC_SECOND__", removeLeadingZeros(savedSECOND));
|
||||
#undef addString
|
||||
|
||||
pScope = NULL;
|
||||
symbolScope = NULL;
|
||||
|
||||
math_DefinePI();
|
||||
}
|
||||
|
||||
@@ -31,10 +31,11 @@ static enum WarningState const defaultWarnings[NB_WARNINGS] = {
|
||||
WARNING_ENABLED, /* Assertions */
|
||||
WARNING_DISABLED, /* Invalid args to builtins */
|
||||
WARNING_DISABLED, /* Division undefined behavior */
|
||||
WARNING_DISABLED, /* `db`, `dw`, or `dl` with no directive in ROM */
|
||||
WARNING_DISABLED, /* Empty entry in `db`, `dw` or `dl` */
|
||||
WARNING_DISABLED, /* Constants too large */
|
||||
WARNING_DISABLED, /* String too long for internal buffers */
|
||||
WARNING_DISABLED, /* Obsolete things */
|
||||
WARNING_ENABLED, /* Obsolete things */
|
||||
WARNING_DISABLED, /* Shifting undefined behavior */
|
||||
WARNING_DISABLED, /* Strange shift amount */
|
||||
WARNING_ENABLED, /* Implicit truncation loses some bits */
|
||||
@@ -48,7 +49,7 @@ static bool warningsAreErrors; /* Set if `-Werror` was specified */
|
||||
static enum WarningState warningState(enum WarningID id)
|
||||
{
|
||||
/* Check if warnings are globally disabled */
|
||||
if (!CurrentOptions.warnings)
|
||||
if (!warnings)
|
||||
return WARNING_DISABLED;
|
||||
|
||||
/* Get the actual state */
|
||||
@@ -68,6 +69,7 @@ static char const *warningFlags[NB_WARNINGS_ALL] = {
|
||||
"assert",
|
||||
"builtin-args",
|
||||
"div",
|
||||
"empty-data-directive",
|
||||
"empty-entry",
|
||||
"large-constant",
|
||||
"long-string",
|
||||
@@ -90,6 +92,7 @@ enum MetaWarningCommand {
|
||||
/* Warnings that probably indicate an error */
|
||||
static uint8_t const _wallCommands[] = {
|
||||
WARNING_BUILTIN_ARG,
|
||||
WARNING_EMPTY_DATA_DIRECTIVE,
|
||||
WARNING_LARGE_CONSTANT,
|
||||
WARNING_LONG_STR,
|
||||
META_WARNING_DONE
|
||||
@@ -98,7 +101,6 @@ static uint8_t const _wallCommands[] = {
|
||||
/* Warnings that are less likely to indicate an error */
|
||||
static uint8_t const _wextraCommands[] = {
|
||||
WARNING_EMPTY_ENTRY,
|
||||
WARNING_OBSOLETE,
|
||||
META_WARNING_DONE
|
||||
};
|
||||
|
||||
@@ -106,6 +108,7 @@ static uint8_t const _wextraCommands[] = {
|
||||
static uint8_t const _weverythingCommands[] = {
|
||||
WARNING_BUILTIN_ARG,
|
||||
WARNING_DIV,
|
||||
WARNING_EMPTY_DATA_DIRECTIVE,
|
||||
WARNING_EMPTY_ENTRY,
|
||||
WARNING_LARGE_CONSTANT,
|
||||
WARNING_LONG_STR,
|
||||
|
||||
138
src/extern/getopt.c
vendored
138
src/extern/getopt.c
vendored
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2005-2019 Rich Felker, et al.
|
||||
* Copyright © 2005-2020 Rich Felker, et al.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@@ -26,40 +26,128 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#ifndef _MSC_VER
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "extern/getopt.h"
|
||||
|
||||
int __optpos, __optreset;
|
||||
#ifdef _MSC_VER
|
||||
char *optarg;
|
||||
int optind=1, opterr=1, optopt;
|
||||
#endif
|
||||
int optreset=0;
|
||||
static int optpos;
|
||||
|
||||
void musl__getopt_msg(const char *a, const char *b, const char *c, size_t l)
|
||||
static void musl_getopt_msg(const char *a, const char *b, const char *c, size_t l)
|
||||
{
|
||||
FILE *f = stderr;
|
||||
(void)(fputs(a, f)>=0
|
||||
&& fwrite(b, strlen(b), 1, f)
|
||||
&& fwrite(c, 1, l, f)==l
|
||||
&& putc('\n', f));
|
||||
|
||||
if (fputs(a, f) >= 0 &&
|
||||
fwrite(b, strlen(b), 1, f) &&
|
||||
fwrite(c, 1, l, f) == l)
|
||||
putc('\n', f);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static int getopt(int argc, char *argv[], const char *optstring)
|
||||
{
|
||||
int i;
|
||||
wchar_t c, d;
|
||||
int k, l;
|
||||
char *optchar;
|
||||
|
||||
if (!optind || optreset) {
|
||||
optreset = 0;
|
||||
optpos = 0;
|
||||
optind = 1;
|
||||
}
|
||||
|
||||
if (optind >= argc || !argv[optind])
|
||||
return -1;
|
||||
|
||||
if (argv[optind][0] != '-') {
|
||||
if (optstring[0] == '-') {
|
||||
optarg = argv[optind++];
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!argv[optind][1])
|
||||
return -1;
|
||||
|
||||
if (argv[optind][1] == '-' && !argv[optind][2])
|
||||
return optind++, -1;
|
||||
|
||||
if (!optpos) optpos++;
|
||||
if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) {
|
||||
k = 1;
|
||||
c = 0xfffd; /* replacement char */
|
||||
}
|
||||
optchar = argv[optind]+optpos;
|
||||
optpos += k;
|
||||
|
||||
if (!argv[optind][optpos]) {
|
||||
optind++;
|
||||
optpos = 0;
|
||||
}
|
||||
|
||||
if (optstring[0] == '-' || optstring[0] == '+')
|
||||
optstring++;
|
||||
|
||||
i = 0;
|
||||
d = 0;
|
||||
do {
|
||||
l = mbtowc(&d, optstring+i, MB_LEN_MAX);
|
||||
if (l>0) i+=l; else i++;
|
||||
} while (l && d != c);
|
||||
|
||||
if (d != c || c == ':') {
|
||||
optopt = c;
|
||||
if (optstring[0] != ':' && opterr)
|
||||
musl_getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
|
||||
return '?';
|
||||
}
|
||||
if (optstring[i] == ':') {
|
||||
optarg = 0;
|
||||
if (optstring[i+1] != ':' || optpos) {
|
||||
optarg = argv[optind++] + optpos;
|
||||
optpos = 0;
|
||||
}
|
||||
if (optind > argc) {
|
||||
optopt = c;
|
||||
if (optstring[0] == ':') return ':';
|
||||
if (opterr) musl_getopt_msg(argv[0],
|
||||
": option requires an argument: ",
|
||||
optchar, k);
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
static void permute(char **argv, int dest, int src)
|
||||
{
|
||||
char **av = (char **)argv;
|
||||
char *tmp = av[src];
|
||||
char *tmp = argv[src];
|
||||
int i;
|
||||
for (i=src; i>dest; i--)
|
||||
av[i] = av[i-1];
|
||||
av[dest] = tmp;
|
||||
argv[i] = argv[i-1];
|
||||
argv[dest] = tmp;
|
||||
}
|
||||
|
||||
static int musl__getopt_long_core(int argc, char **argv, const char *optstring, const struct option *longopts, int *idx, int longonly);
|
||||
static int musl_getopt_long_core(int argc, char **argv, const char *optstring, const struct option *longopts, int *idx, int longonly);
|
||||
|
||||
static int musl__getopt_long(int argc, char **argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
|
||||
static int musl_getopt_long(int argc, char **argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
|
||||
{
|
||||
int ret, skipped, resumed;
|
||||
if (!optind || __optreset) {
|
||||
__optreset = 0;
|
||||
__optpos = 0;
|
||||
if (!optind || optreset) {
|
||||
optreset = 0;
|
||||
optpos = 0;
|
||||
optind = 1;
|
||||
}
|
||||
if (optind >= argc || !argv[optind]) return -1;
|
||||
@@ -73,7 +161,7 @@ static int musl__getopt_long(int argc, char **argv, const char *optstring, const
|
||||
optind = i;
|
||||
}
|
||||
resumed = optind;
|
||||
ret = musl__getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
|
||||
ret = musl_getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
|
||||
if (resumed > skipped) {
|
||||
int i, cnt = optind-resumed;
|
||||
for (i=0; i<cnt; i++)
|
||||
@@ -83,7 +171,7 @@ static int musl__getopt_long(int argc, char **argv, const char *optstring, const
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int musl__getopt_long_core(int argc, char **argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
|
||||
static int musl_getopt_long_core(int argc, char **argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
|
||||
{
|
||||
optarg = 0;
|
||||
if (longopts && argv[optind][0] == '-' &&
|
||||
@@ -91,8 +179,8 @@ static int musl__getopt_long_core(int argc, char **argv, const char *optstring,
|
||||
(argv[optind][1] == '-' && argv[optind][2])))
|
||||
{
|
||||
int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':';
|
||||
int i, cnt, match;
|
||||
char *arg, *opt, *start = argv[optind]+1;
|
||||
int i, cnt, match = 0;
|
||||
char *arg = 0, *opt, *start = argv[optind]+1;
|
||||
for (cnt=i=0; longopts[i].name; i++) {
|
||||
const char *name = longopts[i].name;
|
||||
opt = start;
|
||||
@@ -128,7 +216,7 @@ static int musl__getopt_long_core(int argc, char **argv, const char *optstring,
|
||||
optopt = longopts[i].val;
|
||||
if (colon || !opterr)
|
||||
return '?';
|
||||
musl__getopt_msg(argv[0],
|
||||
musl_getopt_msg(argv[0],
|
||||
": option does not take an argument: ",
|
||||
longopts[i].name,
|
||||
strlen(longopts[i].name));
|
||||
@@ -140,7 +228,7 @@ static int musl__getopt_long_core(int argc, char **argv, const char *optstring,
|
||||
optopt = longopts[i].val;
|
||||
if (colon) return ':';
|
||||
if (!opterr) return '?';
|
||||
musl__getopt_msg(argv[0],
|
||||
musl_getopt_msg(argv[0],
|
||||
": option requires an argument: ",
|
||||
longopts[i].name,
|
||||
strlen(longopts[i].name));
|
||||
@@ -158,7 +246,7 @@ static int musl__getopt_long_core(int argc, char **argv, const char *optstring,
|
||||
if (argv[optind][1] == '-') {
|
||||
optopt = 0;
|
||||
if (!colon && opterr)
|
||||
musl__getopt_msg(argv[0], cnt ?
|
||||
musl_getopt_msg(argv[0], cnt ?
|
||||
": option is ambiguous: " :
|
||||
": unrecognized option: ",
|
||||
argv[optind]+2,
|
||||
@@ -172,5 +260,5 @@ static int musl__getopt_long_core(int argc, char **argv, const char *optstring,
|
||||
|
||||
int musl_getopt_long_only(int argc, char **argv, const char *optstring, const struct option *longopts, int *idx)
|
||||
{
|
||||
return musl__getopt_long(argc, argv, optstring, longopts, idx, 1);
|
||||
return musl_getopt_long(argc, argv, optstring, longopts, idx, 1);
|
||||
}
|
||||
|
||||
@@ -98,9 +98,9 @@ int main(int argc, char *argv[])
|
||||
bool resize = false;
|
||||
bool setversion = false;
|
||||
|
||||
char *title; /* game title in ASCII */
|
||||
char *id; /* game ID in ASCII */
|
||||
char *newlicensee; /* new licensee ID, two ASCII characters */
|
||||
char *title = NULL; /* game title in ASCII */
|
||||
char *id = NULL; /* game ID in ASCII */
|
||||
char *newlicensee = NULL; /* new licensee ID, two ASCII characters */
|
||||
|
||||
int licensee = 0; /* old licensee ID */
|
||||
int cartridge = 0; /* cartridge hardware ID */
|
||||
|
||||
@@ -1142,10 +1142,10 @@ This is roughly equivalent to the following
|
||||
.Em imaginary
|
||||
instructions:
|
||||
.Bd -literal -offset indent
|
||||
ld f, [sp] ; See below for individual flags
|
||||
inc sp
|
||||
ld a, [sp]
|
||||
inc sp
|
||||
ld f, [sp] ; See below for individual flags
|
||||
.Ed
|
||||
.Pp
|
||||
Cycles: 3
|
||||
|
||||
48
src/gfx/gb.c
48
src/gfx/gb.c
@@ -10,7 +10,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gfx/main.h"
|
||||
#include "gfx/gb.h"
|
||||
|
||||
void transpose_tiles(struct GBImage *gb, int width)
|
||||
{
|
||||
@@ -19,6 +19,9 @@ void transpose_tiles(struct GBImage *gb, int width)
|
||||
int newbyte;
|
||||
|
||||
newdata = calloc(gb->size, 1);
|
||||
if (!newdata)
|
||||
err(1, "%s: Failed to allocate memory for new data", __func__);
|
||||
|
||||
for (i = 0; i < gb->size; i++) {
|
||||
newbyte = i / (8 * depth) * width * 8 * depth;
|
||||
newbyte = newbyte % gb->size
|
||||
@@ -62,7 +65,8 @@ void output_file(const struct Options *opts, const struct GBImage *gb)
|
||||
|
||||
f = fopen(opts->outfile, "wb");
|
||||
if (!f)
|
||||
err(1, "Opening output file '%s' failed", opts->outfile);
|
||||
err(1, "%s: Opening output file '%s' failed", __func__,
|
||||
opts->outfile);
|
||||
|
||||
fwrite(gb->data, 1, gb->size - gb->trim * 8 * depth, f);
|
||||
|
||||
@@ -136,6 +140,9 @@ int get_mirrored_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
|
||||
}
|
||||
|
||||
tile_yflip = malloc(tile_size);
|
||||
if (!tile_yflip)
|
||||
err(1, "%s: Failed to allocate memory for Y flip of tile",
|
||||
__func__);
|
||||
yflip(tile, tile_yflip, tile_size);
|
||||
index = get_tile_index(tile_yflip, tiles, num_tiles, tile_size);
|
||||
if (index >= 0) {
|
||||
@@ -145,6 +152,9 @@ int get_mirrored_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
|
||||
}
|
||||
|
||||
tile_xflip = malloc(tile_size);
|
||||
if (!tile_xflip)
|
||||
err(1, "%s: Failed to allocate memory for X flip of tile",
|
||||
__func__);
|
||||
xflip(tile, tile_xflip, tile_size);
|
||||
index = get_tile_index(tile_xflip, tiles, num_tiles, tile_size);
|
||||
if (index >= 0) {
|
||||
@@ -178,7 +188,7 @@ void create_mapfiles(const struct Options *opts, struct GBImage *gb,
|
||||
uint8_t *tile;
|
||||
uint8_t **tiles;
|
||||
|
||||
tile_size = sizeof(uint8_t) * depth * 8;
|
||||
tile_size = sizeof(*tile) * depth * 8;
|
||||
gb_size = gb->size - (gb->trim * tile_size);
|
||||
max_tiles = gb_size / tile_size;
|
||||
|
||||
@@ -186,16 +196,24 @@ void create_mapfiles(const struct Options *opts, struct GBImage *gb,
|
||||
if (gb_size > max_tiles * tile_size)
|
||||
max_tiles++;
|
||||
|
||||
tiles = calloc(max_tiles, sizeof(uint8_t *));
|
||||
tiles = calloc(max_tiles, sizeof(*tiles));
|
||||
if (!tiles)
|
||||
err(1, "%s: Failed to allocate memory for tiles", __func__);
|
||||
num_tiles = 0;
|
||||
|
||||
if (*opts->tilemapfile) {
|
||||
tilemap->data = calloc(max_tiles, sizeof(uint8_t));
|
||||
tilemap->data = calloc(max_tiles, sizeof(*tilemap->data));
|
||||
if (!tilemap->data)
|
||||
err(1, "%s: Failed to allocate memory for tilemap data",
|
||||
__func__);
|
||||
tilemap->size = 0;
|
||||
}
|
||||
|
||||
if (*opts->attrmapfile) {
|
||||
attrmap->data = calloc(max_tiles, sizeof(uint8_t));
|
||||
attrmap->data = calloc(max_tiles, sizeof(*attrmap->data));
|
||||
if (!attrmap->data)
|
||||
err(1, "%s: Failed to allocate memory for attrmap data",
|
||||
__func__);
|
||||
attrmap->size = 0;
|
||||
}
|
||||
|
||||
@@ -203,6 +221,9 @@ void create_mapfiles(const struct Options *opts, struct GBImage *gb,
|
||||
while (gb_i < gb_size) {
|
||||
flags = 0;
|
||||
tile = malloc(tile_size);
|
||||
if (!tile)
|
||||
err(1, "%s: Failed to allocate memory for tile",
|
||||
__func__);
|
||||
for (i = 0; i < tile_size; i++) {
|
||||
tile[i] = gb->data[gb_i];
|
||||
gb_i++;
|
||||
@@ -217,10 +238,13 @@ void create_mapfiles(const struct Options *opts, struct GBImage *gb,
|
||||
index = get_tile_index(tile, tiles, num_tiles,
|
||||
tile_size);
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = num_tiles;
|
||||
tiles[num_tiles] = tile;
|
||||
num_tiles++;
|
||||
} else {
|
||||
free(tile);
|
||||
}
|
||||
} else {
|
||||
index = num_tiles;
|
||||
@@ -240,6 +264,9 @@ void create_mapfiles(const struct Options *opts, struct GBImage *gb,
|
||||
if (opts->unique) {
|
||||
free(gb->data);
|
||||
gb->data = malloc(tile_size * num_tiles);
|
||||
if (!gb->data)
|
||||
err(1, "%s: Failed to allocate memory for tile data",
|
||||
__func__);
|
||||
for (i = 0; i < num_tiles; i++) {
|
||||
tile = tiles[i];
|
||||
for (j = 0; j < tile_size; j++)
|
||||
@@ -261,7 +288,8 @@ void output_tilemap_file(const struct Options *opts,
|
||||
|
||||
f = fopen(opts->tilemapfile, "wb");
|
||||
if (!f)
|
||||
err(1, "Opening tilemap file '%s' failed", opts->tilemapfile);
|
||||
err(1, "%s: Opening tilemap file '%s' failed", __func__,
|
||||
opts->tilemapfile);
|
||||
|
||||
fwrite(tilemap->data, 1, tilemap->size, f);
|
||||
fclose(f);
|
||||
@@ -277,7 +305,8 @@ void output_attrmap_file(const struct Options *opts,
|
||||
|
||||
f = fopen(opts->attrmapfile, "wb");
|
||||
if (!f)
|
||||
err(1, "Opening attrmap file '%s' failed", opts->attrmapfile);
|
||||
err(1, "%s: Opening attrmap file '%s' failed", __func__,
|
||||
opts->attrmapfile);
|
||||
|
||||
fwrite(attrmap->data, 1, attrmap->size, f);
|
||||
fclose(f);
|
||||
@@ -319,7 +348,8 @@ void output_palette_file(const struct Options *opts,
|
||||
|
||||
f = fopen(opts->palfile, "wb");
|
||||
if (!f)
|
||||
err(1, "Opening palette file '%s' failed", opts->palfile);
|
||||
err(1, "%s: Opening palette file '%s' failed", __func__,
|
||||
opts->palfile);
|
||||
|
||||
for (i = 0; i < raw_image->num_colors; i++) {
|
||||
int r = raw_image->palette[i].red;
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "extern/getopt.h"
|
||||
#include "version.h"
|
||||
|
||||
int depth, colors;
|
||||
|
||||
/* Short options */
|
||||
static char const *optstring = "Aa:CDd:Ffhmo:Pp:Tt:uVvx:";
|
||||
|
||||
@@ -208,7 +210,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (opts.trim &&
|
||||
opts.trim > (raw_image->width / 8) * (raw_image->height / 8) - 1) {
|
||||
errx(1, "Trim (%i) for input raw_image file '%s' too large (max: %i)",
|
||||
errx(1, "Trim (%d) for input raw_image file '%s' too large (max: %u)",
|
||||
opts.trim, opts.infile,
|
||||
(raw_image->width / 8) * (raw_image->height / 8) - 1);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gfx/main.h"
|
||||
#include "gfx/makepng.h"
|
||||
|
||||
static void initialize_png(struct PNGImage *img, FILE * f);
|
||||
static struct RawIndexedImage *indexed_png_to_raw(struct PNGImage *img);
|
||||
@@ -38,7 +38,7 @@ struct RawIndexedImage *input_png_file(const struct Options *opts,
|
||||
|
||||
if (img.depth != depth) {
|
||||
if (opts->verbose) {
|
||||
warnx("Image bit depth is not %i (is %i).",
|
||||
warnx("Image bit depth is not %d (is %d).",
|
||||
depth, img.depth);
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,9 @@ void output_png_file(const struct Options *opts,
|
||||
*/
|
||||
if (opts->debug) {
|
||||
outfile = malloc(strlen(opts->infile) + 5);
|
||||
if (!outfile)
|
||||
err(1, "%s: Failed to allocate memory for outfile",
|
||||
__func__);
|
||||
strcpy(outfile, opts->infile);
|
||||
strcat(outfile, ".out");
|
||||
} else {
|
||||
@@ -110,7 +113,10 @@ void output_png_file(const struct Options *opts,
|
||||
8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_palette = malloc(sizeof(png_color *) * raw_image->num_colors);
|
||||
png_palette = malloc(sizeof(*png_palette) * raw_image->num_colors);
|
||||
if (!png_palette)
|
||||
err(1, "%s: Failed to allocate memory for PNG palette",
|
||||
__func__);
|
||||
for (i = 0; i < raw_image->num_colors; i++) {
|
||||
png_palette[i].red = raw_image->palette[i].red;
|
||||
png_palette[i].green = raw_image->palette[i].green;
|
||||
@@ -207,9 +213,16 @@ static struct RawIndexedImage *indexed_png_to_raw(struct PNGImage *img)
|
||||
if (png_get_tRNS(img->png, img->info, &trans_alpha, &num_trans,
|
||||
&trans_color)) {
|
||||
original_palette = palette;
|
||||
palette = malloc(sizeof(png_color) * colors_in_PLTE);
|
||||
palette = malloc(sizeof(*palette) * colors_in_PLTE);
|
||||
if (!palette)
|
||||
err(1, "%s: Failed to allocate memory for palette",
|
||||
__func__);
|
||||
colors_in_new_palette = 0;
|
||||
old_to_new_palette = malloc(sizeof(uint8_t) * colors_in_PLTE);
|
||||
old_to_new_palette = malloc(sizeof(*old_to_new_palette)
|
||||
* colors_in_PLTE);
|
||||
if (!old_to_new_palette)
|
||||
err(1, "%s: Failed to allocate memory for new palette",
|
||||
__func__);
|
||||
|
||||
for (i = 0; i < num_trans; i++) {
|
||||
if (trans_alpha[i] == 0) {
|
||||
@@ -227,8 +240,11 @@ static struct RawIndexedImage *indexed_png_to_raw(struct PNGImage *img)
|
||||
|
||||
if (colors_in_new_palette != colors_in_PLTE) {
|
||||
palette = realloc(palette,
|
||||
sizeof(png_color) *
|
||||
sizeof(*palette) *
|
||||
colors_in_new_palette);
|
||||
if (!palette)
|
||||
err(1, "%s: Failed to allocate memory for palette",
|
||||
__func__);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -247,6 +263,7 @@ static struct RawIndexedImage *indexed_png_to_raw(struct PNGImage *img)
|
||||
}
|
||||
}
|
||||
|
||||
free(palette);
|
||||
free(old_to_new_palette);
|
||||
} else {
|
||||
set_raw_image_palette(raw_image, palette, colors_in_PLTE);
|
||||
@@ -353,7 +370,9 @@ static void rgba_build_palette(struct PNGImage *img,
|
||||
* By filling the palette up with black by default, if the image
|
||||
* doesn't have enough colors, the palette gets padded with black.
|
||||
*/
|
||||
*palette_ptr_ptr = calloc(colors, sizeof(png_color));
|
||||
*palette_ptr_ptr = calloc(colors, sizeof(**palette_ptr_ptr));
|
||||
if (!*palette_ptr_ptr)
|
||||
err(1, "%s: Failed to allocate memory for palette", __func__);
|
||||
palette = *palette_ptr_ptr;
|
||||
*num_colors = 0;
|
||||
|
||||
@@ -421,10 +440,15 @@ static void update_built_palette(png_color *palette,
|
||||
static int fit_grayscale_palette(png_color *palette, int *num_colors)
|
||||
{
|
||||
int interval = 256 / colors;
|
||||
png_color *fitted_palette = malloc(sizeof(png_color) * colors);
|
||||
bool *set_indices = calloc(colors, sizeof(bool));
|
||||
png_color *fitted_palette = malloc(sizeof(*fitted_palette) * colors);
|
||||
bool *set_indices = calloc(colors, sizeof(*set_indices));
|
||||
int i, shade_index;
|
||||
|
||||
if (!fitted_palette)
|
||||
err(1, "%s: Failed to allocate memory for palette", __func__);
|
||||
if (!set_indices)
|
||||
err(1, "%s: Failed to allocate memory for indices", __func__);
|
||||
|
||||
fitted_palette[0].red = 0xFF;
|
||||
fitted_palette[0].green = 0xFF;
|
||||
fitted_palette[0].blue = 0xFF;
|
||||
@@ -481,7 +505,10 @@ static void order_color_palette(png_color *palette, int num_colors)
|
||||
{
|
||||
int i;
|
||||
struct ColorWithLuminance *palette_with_luminance =
|
||||
malloc(sizeof(struct ColorWithLuminance) * num_colors);
|
||||
malloc(sizeof(*palette_with_luminance) * num_colors);
|
||||
|
||||
if (!palette_with_luminance)
|
||||
err(1, "%s: Failed to allocate memory for palette", __func__);
|
||||
|
||||
for (i = 0; i < num_colors; i++) {
|
||||
/*
|
||||
@@ -494,7 +521,7 @@ static void order_color_palette(png_color *palette, int num_colors)
|
||||
722 * palette[i].blue;
|
||||
}
|
||||
qsort(palette_with_luminance, num_colors,
|
||||
sizeof(struct ColorWithLuminance), compare_luminance);
|
||||
sizeof(*palette_with_luminance), compare_luminance);
|
||||
for (i = 0; i < num_colors; i++)
|
||||
palette[i] = palette_with_luminance[i].color;
|
||||
|
||||
@@ -582,9 +609,16 @@ static void read_png(struct PNGImage *img)
|
||||
|
||||
png_read_update_info(img->png, img->info);
|
||||
|
||||
img->data = malloc(sizeof(png_byte *) * img->height);
|
||||
for (y = 0; y < img->height; y++)
|
||||
img->data = malloc(sizeof(*img->data) * img->height);
|
||||
if (!img->data)
|
||||
err(1, "%s: Failed to allocate memory for image data",
|
||||
__func__);
|
||||
for (y = 0; y < img->height; y++) {
|
||||
img->data[y] = malloc(png_get_rowbytes(img->png, img->info));
|
||||
if (!img->data[y])
|
||||
err(1, "%s: Failed to allocate memory for image data",
|
||||
__func__);
|
||||
}
|
||||
|
||||
png_read_image(img->png, img->data);
|
||||
png_read_end(img->png, img->info);
|
||||
@@ -596,17 +630,31 @@ static struct RawIndexedImage *create_raw_image(int width, int height,
|
||||
struct RawIndexedImage *raw_image;
|
||||
int y;
|
||||
|
||||
raw_image = malloc(sizeof(struct RawIndexedImage));
|
||||
raw_image = malloc(sizeof(*raw_image));
|
||||
if (!raw_image)
|
||||
err(1, "%s: Failed to allocate memory for raw image",
|
||||
__func__);
|
||||
|
||||
raw_image->width = width;
|
||||
raw_image->height = height;
|
||||
raw_image->num_colors = num_colors;
|
||||
|
||||
raw_image->palette = malloc(sizeof(struct RGBColor) * num_colors);
|
||||
raw_image->palette = malloc(sizeof(*raw_image->palette) * num_colors);
|
||||
if (!raw_image->palette)
|
||||
err(1, "%s: Failed to allocate memory for raw image palette",
|
||||
__func__);
|
||||
|
||||
raw_image->data = malloc(sizeof(uint8_t *) * height);
|
||||
for (y = 0; y < height; y++)
|
||||
raw_image->data[y] = malloc(sizeof(uint8_t) * width);
|
||||
raw_image->data = malloc(sizeof(*raw_image->data) * height);
|
||||
if (!raw_image->data)
|
||||
err(1, "%s: Failed to allocate memory for raw image data",
|
||||
__func__);
|
||||
for (y = 0; y < height; y++) {
|
||||
raw_image->data[y] = malloc(sizeof(*raw_image->data[y])
|
||||
* width);
|
||||
if (!raw_image->data[y])
|
||||
err(1, "%s: Failed to allocate memory for raw image data",
|
||||
__func__);
|
||||
}
|
||||
|
||||
return raw_image;
|
||||
}
|
||||
@@ -690,7 +738,10 @@ static void set_text(const struct PNGImage *img,
|
||||
png_text *text;
|
||||
char buffer[3];
|
||||
|
||||
text = malloc(sizeof(png_text));
|
||||
text = malloc(sizeof(*text));
|
||||
if (!text)
|
||||
err(1, "%s: Failed to allocate memory for PNG text",
|
||||
__func__);
|
||||
|
||||
if (png_options->horizontal) {
|
||||
text[0].key = "h";
|
||||
|
||||
@@ -78,6 +78,7 @@ bool hash_RemoveElement(HashMap map, char const *key)
|
||||
*ptr = next;
|
||||
return true;
|
||||
}
|
||||
ptr = &(*ptr)->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -51,7 +52,7 @@ static void initFreeSpace(void)
|
||||
memory[type][bank].next =
|
||||
malloc(sizeof(*memory[type][0].next));
|
||||
if (!memory[type][bank].next)
|
||||
err(1, "Failed to init free space for region %d bank %u",
|
||||
err(1, "Failed to init free space for region %d bank %" PRIu32,
|
||||
type, bank);
|
||||
memory[type][bank].next->address = startaddr[type];
|
||||
memory[type][bank].next->size = maxsize[type];
|
||||
@@ -80,15 +81,15 @@ static void processLinkerScript(void)
|
||||
|
||||
/* Check if this doesn't conflict with what the code says */
|
||||
if (section->isBankFixed && placement->bank != section->bank)
|
||||
errx(1, "Linker script contradicts \"%s\"'s bank placement",
|
||||
section->name);
|
||||
error("Linker script contradicts \"%s\"'s bank placement",
|
||||
section->name);
|
||||
if (section->isAddressFixed && placement->org != section->org)
|
||||
errx(1, "Linker script contradicts \"%s\"'s address placement",
|
||||
section->name);
|
||||
error("Linker script contradicts \"%s\"'s address placement",
|
||||
section->name);
|
||||
if (section->isAlignFixed
|
||||
&& (placement->org & section->alignMask) != 0)
|
||||
errx(1, "Linker script contradicts \"%s\"'s alignment",
|
||||
section->name);
|
||||
error("Linker script contradicts \"%s\"'s alignment",
|
||||
section->name);
|
||||
|
||||
section->isAddressFixed = true;
|
||||
section->org = placement->org;
|
||||
@@ -132,7 +133,8 @@ static bool isLocationSuitable(struct Section const *section,
|
||||
if (section->isAddressFixed && section->org != location->address)
|
||||
return false;
|
||||
|
||||
if (section->isAlignFixed && location->address & section->alignMask)
|
||||
if (section->isAlignFixed
|
||||
&& ((location->address - section->alignOfs) & section->alignMask))
|
||||
return false;
|
||||
|
||||
if (location->address < freeSpace->address)
|
||||
@@ -183,8 +185,13 @@ static struct FreeSpace *getPlacement(struct Section const *section,
|
||||
space = NULL;
|
||||
} else if (section->isAlignFixed) {
|
||||
/* Move to next aligned location */
|
||||
/* Move back to alignment boundary */
|
||||
location->address -= section->alignOfs;
|
||||
/* Ensure we're there (e.g. on first check) */
|
||||
location->address &= ~section->alignMask;
|
||||
location->address += section->alignMask + 1;
|
||||
/* Go to next align boundary and add offset */
|
||||
location->address += section->alignMask + 1
|
||||
+ section->alignOfs;
|
||||
} else {
|
||||
/* Any location is fine, so, next free block */
|
||||
space = space->next;
|
||||
@@ -298,19 +305,22 @@ static void placeSection(struct Section *section)
|
||||
|
||||
if (section->isBankFixed && nbbanks(section->type) != 1) {
|
||||
if (section->isAddressFixed)
|
||||
snprintf(where, 64, "at $%02x:%04x",
|
||||
snprintf(where, 64, "at $%02" PRIx32 ":%04" PRIx16,
|
||||
section->bank, section->org);
|
||||
else if (section->isAlignFixed)
|
||||
snprintf(where, 64, "in bank $%02x with align mask %x",
|
||||
section->bank, ~section->alignMask);
|
||||
snprintf(where, 64, "in bank $%02" PRIx32 " with align mask %" PRIx16,
|
||||
section->bank, (uint16_t)~section->alignMask);
|
||||
else
|
||||
snprintf(where, 64, "in bank $%02x", section->bank);
|
||||
snprintf(where, 64, "in bank $%02" PRIx32,
|
||||
section->bank);
|
||||
} else {
|
||||
if (section->isAddressFixed)
|
||||
snprintf(where, 64, "at address $%04x", section->org);
|
||||
snprintf(where, 64, "at address $%04" PRIx16,
|
||||
section->org);
|
||||
else if (section->isAlignFixed)
|
||||
snprintf(where, 64, "with align mask %x",
|
||||
~section->alignMask);
|
||||
snprintf(where, 64, "with align mask %" PRIx16 " and offset %" PRIx16,
|
||||
(uint16_t)~section->alignMask,
|
||||
section->alignOfs);
|
||||
else
|
||||
strcpy(where, "anywhere");
|
||||
}
|
||||
@@ -321,7 +331,7 @@ static void placeSection(struct Section *section)
|
||||
section->name, typeNames[section->type], where);
|
||||
/* If the section just can't fit the bank, report that */
|
||||
else if (section->org + section->size > endaddr(section->type) + 1)
|
||||
errx(1, "Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > $%04x)",
|
||||
errx(1, "Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04" PRIx16 " > $%04" PRIx16 ")",
|
||||
section->name, typeNames[section->type], where,
|
||||
section->org + section->size, endaddr(section->type) + 1);
|
||||
/* Otherwise there is overlap with another section */
|
||||
@@ -412,7 +422,7 @@ void assign_AssignSections(void)
|
||||
/* Overlaying requires only fully-constrained sections */
|
||||
verbosePrint("Assigning other sections...\n");
|
||||
if (overlayFileName)
|
||||
errx(1, "All sections must be fixed when using an overlay file; %lu %sn't",
|
||||
errx(1, "All sections must be fixed when using an overlay file; %" PRIu64 " %sn't",
|
||||
nbSectionsToAssign, nbSectionsToAssign == 1 ? "is" : "are");
|
||||
|
||||
/* Assign all remaining sections by decreasing constraint order */
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "link/object.h"
|
||||
#include "link/symbol.h"
|
||||
@@ -25,7 +26,7 @@
|
||||
#include "version.h"
|
||||
|
||||
bool isDmgMode; /* -d */
|
||||
char const *linkerScriptName; /* -l */
|
||||
char *linkerScriptName; /* -l */
|
||||
char const *mapFileName; /* -m */
|
||||
char const *symFileName; /* -n */
|
||||
char const *overlayFileName; /* -O */
|
||||
@@ -34,6 +35,41 @@ uint8_t padValue; /* -p */
|
||||
bool is32kMode; /* -t */
|
||||
bool beVerbose; /* -v */
|
||||
bool isWRA0Mode; /* -w */
|
||||
bool disablePadding; /* -x */
|
||||
|
||||
static uint32_t nbErrors = 0;
|
||||
|
||||
void error(char const *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "error: ");
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
putc('\n', stderr);
|
||||
|
||||
if (nbErrors != UINT32_MAX)
|
||||
nbErrors++;
|
||||
}
|
||||
|
||||
noreturn_ void fatal(char const *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "fatal: ");
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
putc('\n', stderr);
|
||||
|
||||
if (nbErrors != UINT32_MAX)
|
||||
nbErrors++;
|
||||
|
||||
fprintf(stderr, "Linking aborted after %" PRIu32 " error%s\n", nbErrors,
|
||||
nbErrors != 1 ? "s" : "");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
FILE *openFile(char const *fileName, char const *mode)
|
||||
{
|
||||
@@ -49,7 +85,7 @@ FILE *openFile(char const *fileName, char const *mode)
|
||||
}
|
||||
|
||||
/* Short options */
|
||||
static char const *optstring = "dl:m:n:O:o:p:s:tVvw";
|
||||
static char const *optstring = "dl:m:n:O:o:p:s:tVvwx";
|
||||
|
||||
/*
|
||||
* Equivalent long options
|
||||
@@ -74,6 +110,7 @@ static struct option const longopts[] = {
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "wramx", no_argument, NULL, 'w' },
|
||||
{ "nopad", no_argument, NULL, 'x' },
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
@@ -83,7 +120,7 @@ static struct option const longopts[] = {
|
||||
static void printUsage(void)
|
||||
{
|
||||
fputs(
|
||||
"Usage: rgblink [-dtVvw] [-l script] [-m map_file] [-n sym_file]\n"
|
||||
"Usage: rgblink [-dtVvwx] [-l script] [-m map_file] [-n sym_file]\n"
|
||||
" [-O overlay_file] [-o out_file] [-p pad_value] [-s symbol]\n"
|
||||
" <file> ...\n"
|
||||
"Useful options:\n"
|
||||
@@ -92,6 +129,7 @@ static void printUsage(void)
|
||||
" -n, --sym <path> set the output symbol list file\n"
|
||||
" -o, --output <path> set the output file\n"
|
||||
" -p, --pad <value> set the value to pad between sections with\n"
|
||||
" -x, --nopad disable padding of output binary\n"
|
||||
" -V, --version print RGBLINK version and exits\n"
|
||||
"\n"
|
||||
"For help, use `man rgblink' or go to https://rednex.github.io/rgbds/\n",
|
||||
@@ -138,10 +176,14 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
case 'p':
|
||||
value = strtoul(optarg, &endptr, 0);
|
||||
if (optarg[0] == '\0' || *endptr != '\0')
|
||||
errx(1, "Invalid argument for option 'p'");
|
||||
if (value > 0xFF)
|
||||
errx(1, "Argument for 'p' must be a byte (between 0 and 0xFF)");
|
||||
if (optarg[0] == '\0' || *endptr != '\0') {
|
||||
error("Invalid argument for option 'p'");
|
||||
value = 0xFF;
|
||||
}
|
||||
if (value > 0xFF) {
|
||||
error("Argument for 'p' must be a byte (between 0 and 0xFF)");
|
||||
value = 0xFF;
|
||||
}
|
||||
padValue = value;
|
||||
break;
|
||||
case 's':
|
||||
@@ -161,6 +203,11 @@ int main(int argc, char *argv[])
|
||||
case 'w':
|
||||
isWRA0Mode = true;
|
||||
break;
|
||||
case 'x':
|
||||
disablePadding = true;
|
||||
/* implies tiny mode */
|
||||
is32kMode = true;
|
||||
break;
|
||||
default:
|
||||
printUsage();
|
||||
exit(1);
|
||||
@@ -171,7 +218,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* If no input files were specified, the user must have screwed up */
|
||||
if (curArgIndex == argc) {
|
||||
fputs("FATAL: no input files\n", stderr);
|
||||
fputs("fatal: no input files\n", stderr);
|
||||
printUsage();
|
||||
exit(1);
|
||||
}
|
||||
@@ -198,6 +245,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* and finally output the result. */
|
||||
patch_ApplyPatches();
|
||||
if (nbErrors) {
|
||||
fprintf(stderr, "Linking failed with %" PRIu32 " error%s\n",
|
||||
nbErrors, nbErrors != 1 ? "s" : "");
|
||||
exit(1);
|
||||
}
|
||||
out_WriteFiles();
|
||||
|
||||
/* Do cleanup before quitting, though. */
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "link/assign.h"
|
||||
#include "link/main.h"
|
||||
@@ -207,20 +208,30 @@ static void readSymbol(FILE *file, struct Symbol *symbol, char const *fileName)
|
||||
* @param fileName The filename to report in errors
|
||||
* @param i The number of the patch to report in errors
|
||||
*/
|
||||
static void readPatch(FILE *file, struct Patch *patch,
|
||||
char const *fileName, char const *sectName, uint32_t i)
|
||||
static void readPatch(FILE *file, struct Patch *patch, char const *fileName,
|
||||
char const *sectName, uint32_t i,
|
||||
struct Section *fileSections[])
|
||||
{
|
||||
tryReadstr(patch->fileName, file,
|
||||
"%s: Unable to read \"%s\"'s patch #%u's name: %s",
|
||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s name: %s",
|
||||
fileName, sectName, i);
|
||||
tryReadlong(patch->offset, file,
|
||||
"%s: Unable to read \"%s\"'s patch #%u's offset: %s",
|
||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s offset: %s",
|
||||
fileName, sectName, i);
|
||||
tryReadlong(patch->pcSectionID, file,
|
||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s",
|
||||
fileName, sectName, i);
|
||||
patch->pcSection = patch->pcSectionID == -1
|
||||
? NULL
|
||||
: fileSections[patch->pcSectionID];
|
||||
tryReadlong(patch->pcOffset, file,
|
||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s",
|
||||
fileName, sectName, i);
|
||||
tryGetc(patch->type, file,
|
||||
"%s: Unable to read \"%s\"'s patch #%u's type: %s",
|
||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s type: %s",
|
||||
fileName, sectName, i);
|
||||
tryReadlong(patch->rpnSize, file,
|
||||
"%s: Unable to read \"%s\"'s patch #%u's RPN size: %s",
|
||||
"%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s RPN size: %s",
|
||||
fileName, sectName, i);
|
||||
|
||||
uint8_t *rpnExpression =
|
||||
@@ -229,7 +240,7 @@ static void readPatch(FILE *file, struct Patch *patch,
|
||||
patch->rpnSize, file);
|
||||
|
||||
if (nbElementsRead != patch->rpnSize)
|
||||
errx(1, "%s: Cannot read \"%s\"'s patch #%u's RPN expression: %s",
|
||||
errx(1, "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s RPN expression: %s",
|
||||
fileName, sectName, i,
|
||||
feof(file) ? "Unexpected end of file" : strerror(errno));
|
||||
patch->rpnExpression = rpnExpression;
|
||||
@@ -242,37 +253,54 @@ static void readPatch(FILE *file, struct Patch *patch,
|
||||
* @param fileName The filename to report in errors
|
||||
*/
|
||||
static void readSection(FILE *file, struct Section *section,
|
||||
char const *fileName)
|
||||
char const *fileName, struct Section *fileSections[])
|
||||
{
|
||||
int32_t tmp;
|
||||
uint8_t type;
|
||||
uint8_t byte;
|
||||
|
||||
tryReadstr(section->name, file, "%s: Cannot read section name: %s",
|
||||
fileName);
|
||||
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s' size: %s",
|
||||
fileName, section->name);
|
||||
if (tmp < 0 || tmp > UINT16_MAX)
|
||||
errx(1, "\"%s\"'s section size (%d) is invalid", section->name,
|
||||
tmp);
|
||||
errx(1, "\"%s\"'s section size (%" PRId32 ") is invalid",
|
||||
section->name, tmp);
|
||||
section->size = tmp;
|
||||
tryGetc(type, file, "%s: Cannot read \"%s\"'s type: %s",
|
||||
section->offset = 0;
|
||||
tryGetc(byte, file, "%s: Cannot read \"%s\"'s type: %s",
|
||||
fileName, section->name);
|
||||
section->type = type & 0x7F;
|
||||
section->isUnion = type >> 7;
|
||||
section->type = byte & 0x3F;
|
||||
if (byte >> 7)
|
||||
section->modifier = SECTION_UNION;
|
||||
else if (byte >> 6)
|
||||
section->modifier = SECTION_FRAGMENT;
|
||||
else
|
||||
section->modifier = SECTION_NORMAL;
|
||||
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s org: %s",
|
||||
fileName, section->name);
|
||||
section->isAddressFixed = tmp >= 0;
|
||||
if (tmp > UINT16_MAX)
|
||||
errx(1, "\"%s\"'s org' is too large (%d)", section->name, tmp);
|
||||
if (tmp > UINT16_MAX) {
|
||||
error("\"%s\"'s org is too large (%" PRId32 ")",
|
||||
section->name, tmp);
|
||||
tmp = UINT16_MAX;
|
||||
}
|
||||
section->org = tmp;
|
||||
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s",
|
||||
fileName, section->name);
|
||||
section->isBankFixed = tmp >= 0;
|
||||
section->bank = tmp;
|
||||
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s alignment: %s",
|
||||
tryGetc(byte, file, "%s: Cannot read \"%s\"'s alignment: %s",
|
||||
fileName, section->name);
|
||||
section->isAlignFixed = byte != 0;
|
||||
section->alignMask = (1 << byte) - 1;
|
||||
tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s alignment offset: %s",
|
||||
fileName, section->name);
|
||||
section->isAlignFixed = tmp != 1;
|
||||
section->alignMask = tmp - 1;
|
||||
if (tmp > UINT16_MAX) {
|
||||
error("\"%s\"'s alignment offset is too large (%" PRId32 ")",
|
||||
section->name, tmp);
|
||||
tmp = UINT16_MAX;
|
||||
}
|
||||
section->alignOfs = tmp;
|
||||
|
||||
if (sect_HasData(section->type)) {
|
||||
/* Ensure we never allocate 0 bytes */
|
||||
@@ -302,9 +330,10 @@ static void readSection(FILE *file, struct Section *section,
|
||||
if (!patches)
|
||||
err(1, "%s: Unable to read \"%s\"'s patches", fileName,
|
||||
section->name);
|
||||
for (uint32_t i = 0; i < section->nbPatches; i++)
|
||||
for (uint32_t i = 0; i < section->nbPatches; i++) {
|
||||
readPatch(file, &patches[i], fileName, section->name,
|
||||
i);
|
||||
i, fileSections);
|
||||
}
|
||||
section->patches = patches;
|
||||
}
|
||||
}
|
||||
@@ -345,25 +374,21 @@ static void linkSymToSect(struct Symbol const *symbol, struct Section *section)
|
||||
* @param fileName The filename to report in errors
|
||||
*/
|
||||
static void readAssertion(FILE *file, struct Assertion *assert,
|
||||
char const *fileName, struct Section *fileSections[],
|
||||
uint32_t i)
|
||||
char const *fileName, uint32_t i,
|
||||
struct Section *fileSections[])
|
||||
{
|
||||
char assertName[sizeof("Assertion #" EXPAND_AND_STR(UINT32_MAX))];
|
||||
uint32_t sectionID;
|
||||
|
||||
snprintf(assertName, sizeof(assertName), "Assertion #%u", i);
|
||||
snprintf(assertName, sizeof(assertName), "Assertion #%" PRIu32, i);
|
||||
|
||||
readPatch(file, &assert->patch, fileName, assertName, 0);
|
||||
tryReadlong(sectionID, file, "%s: Cannot read assertion's section ID: %s",
|
||||
fileName);
|
||||
assert->section = sectionID == -1 ? NULL : fileSections[sectionID];
|
||||
readPatch(file, &assert->patch, fileName, assertName, 0, fileSections);
|
||||
tryReadstr(assert->message, file, "%s: Cannot read assertion's message: %s",
|
||||
fileName);
|
||||
}
|
||||
|
||||
static inline struct Section *getMainSection(struct Section *section)
|
||||
{
|
||||
if (section->isUnion)
|
||||
if (section->modifier != SECTION_NORMAL)
|
||||
section = sect_GetSection(section->name);
|
||||
|
||||
return section;
|
||||
@@ -381,18 +406,18 @@ void obj_ReadFile(char const *fileName)
|
||||
err(1, "Could not open file %s", fileName);
|
||||
|
||||
/* Begin by reading the magic bytes and version number */
|
||||
uint8_t versionNumber;
|
||||
unsigned versionNumber;
|
||||
int matchedElems = fscanf(file, RGBDS_OBJECT_VERSION_STRING,
|
||||
&versionNumber);
|
||||
|
||||
if (matchedElems != 1)
|
||||
errx(1, "\"%s\" is not a RGBDS object file", fileName);
|
||||
|
||||
verbosePrint("Reading object file %s, version %hhu\n",
|
||||
verbosePrint("Reading object file %s, version %u\n",
|
||||
fileName, versionNumber);
|
||||
|
||||
if (versionNumber != RGBDS_OBJECT_VERSION_NUMBER)
|
||||
errx(1, "\"%s\" is an incompatible version %hhu object file",
|
||||
errx(1, "\"%s\" is an incompatible version %u object file",
|
||||
fileName, versionNumber);
|
||||
|
||||
uint32_t revNum;
|
||||
@@ -400,7 +425,7 @@ void obj_ReadFile(char const *fileName)
|
||||
tryReadlong(revNum, file, "%s: Cannot read revision number: %s",
|
||||
fileName);
|
||||
if (revNum != RGBDS_OBJECT_REV)
|
||||
errx(1, "%s is a revision 0x%04x object file, only 0x%04x is supported",
|
||||
errx(1, "%s is a revision 0x%04" PRIx32 " object file; only 0x%04x is supported",
|
||||
fileName, revNum, RGBDS_OBJECT_REV);
|
||||
|
||||
uint32_t nbSymbols;
|
||||
@@ -429,11 +454,10 @@ void obj_ReadFile(char const *fileName)
|
||||
symbolList->next = symbolLists;
|
||||
symbolLists = symbolList;
|
||||
|
||||
uint32_t nbSymPerSect[nbSections ? nbSections : 1];
|
||||
uint32_t *nbSymPerSect = calloc(nbSections ? nbSections : 1,
|
||||
sizeof(*nbSymPerSect));
|
||||
|
||||
memset(nbSymPerSect, 0, sizeof(nbSymPerSect));
|
||||
|
||||
verbosePrint("Reading %u symbols...\n", nbSymbols);
|
||||
verbosePrint("Reading %" PRIu32 " symbols...\n", nbSymbols);
|
||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||
/* Read symbol */
|
||||
struct Symbol *symbol = malloc(sizeof(*symbol));
|
||||
@@ -450,33 +474,35 @@ void obj_ReadFile(char const *fileName)
|
||||
}
|
||||
|
||||
/* This file's sections, stored in a table to link symbols to them */
|
||||
struct Section *fileSections[nbSections ? nbSections : 1];
|
||||
struct Section **fileSections = malloc(sizeof(*fileSections)
|
||||
* (nbSections ? nbSections : 1));
|
||||
|
||||
verbosePrint("Reading %u sections...\n", nbSections);
|
||||
verbosePrint("Reading %" PRIu32 " sections...\n", nbSections);
|
||||
for (uint32_t i = 0; i < nbSections; i++) {
|
||||
/* Read section */
|
||||
struct Section *section = malloc(sizeof(*section));
|
||||
|
||||
if (!section)
|
||||
fileSections[i] = malloc(sizeof(*fileSections[i]));
|
||||
if (!fileSections[i])
|
||||
err(1, "%s: Couldn't create new section", fileName);
|
||||
section->nextu = NULL;
|
||||
readSection(file, section, fileName);
|
||||
section->fileSymbols = fileSymbols;
|
||||
|
||||
sect_AddSection(section);
|
||||
fileSections[i] = section;
|
||||
fileSections[i]->nextu = NULL;
|
||||
readSection(file, fileSections[i], fileName, fileSections);
|
||||
fileSections[i]->fileSymbols = fileSymbols;
|
||||
if (nbSymPerSect[i]) {
|
||||
section->symbols = malloc(sizeof(*section->symbols)
|
||||
* nbSymPerSect[i]);
|
||||
if (!section->symbols)
|
||||
fileSections[i]->symbols = malloc(nbSymPerSect[i]
|
||||
* sizeof(*fileSections[i]->symbols));
|
||||
if (!fileSections[i]->symbols)
|
||||
err(1, "%s: Couldn't link to symbols",
|
||||
fileName);
|
||||
} else {
|
||||
section->symbols = NULL;
|
||||
fileSections[i]->symbols = NULL;
|
||||
}
|
||||
section->nbSymbols = 0;
|
||||
fileSections[i]->nbSymbols = 0;
|
||||
|
||||
sect_AddSection(fileSections[i]);
|
||||
}
|
||||
|
||||
free(nbSymPerSect);
|
||||
|
||||
/* Give symbols pointers to their sections */
|
||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||
int32_t sectionID = fileSymbols[i]->sectionID;
|
||||
@@ -484,10 +510,18 @@ void obj_ReadFile(char const *fileName)
|
||||
if (sectionID == -1) {
|
||||
fileSymbols[i]->section = NULL;
|
||||
} else {
|
||||
struct Section *section = fileSections[sectionID];
|
||||
|
||||
/* Give the section a pointer to the symbol as well */
|
||||
linkSymToSect(fileSymbols[i], fileSections[sectionID]);
|
||||
fileSymbols[i]->section =
|
||||
getMainSection(fileSections[sectionID]);
|
||||
linkSymToSect(fileSymbols[i], section);
|
||||
|
||||
if (section->modifier != SECTION_NORMAL) {
|
||||
if (section->modifier == SECTION_FRAGMENT)
|
||||
/* Add the fragment's offset to the symbol's */
|
||||
fileSymbols[i]->offset += section->offset;
|
||||
section = getMainSection(section);
|
||||
}
|
||||
fileSymbols[i]->section = section;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,18 +529,19 @@ void obj_ReadFile(char const *fileName)
|
||||
|
||||
tryReadlong(nbAsserts, file, "%s: Cannot read number of assertions: %s",
|
||||
fileName);
|
||||
verbosePrint("Reading %u assertions...\n", nbAsserts);
|
||||
verbosePrint("Reading %" PRIu32 " assertions...\n", nbAsserts);
|
||||
for (uint32_t i = 0; i < nbAsserts; i++) {
|
||||
struct Assertion *assertion = malloc(sizeof(*assertion));
|
||||
|
||||
if (!assertion)
|
||||
err(1, "%s: Couldn't create new assertion", fileName);
|
||||
readAssertion(file, assertion, fileName, fileSections, i);
|
||||
readAssertion(file, assertion, fileName, i, fileSections);
|
||||
assertion->fileSymbols = fileSymbols;
|
||||
assertion->next = assertions;
|
||||
assertions = assertion;
|
||||
}
|
||||
|
||||
free(fileSections);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "link/output.h"
|
||||
#include "link/main.h"
|
||||
@@ -51,7 +52,7 @@ void out_AddSection(struct Section const *section)
|
||||
uint32_t minNbBanks = targetBank + 1;
|
||||
|
||||
if (minNbBanks > maxNbBanks[section->type])
|
||||
errx(1, "Section \"%s\" has invalid bank range (%u > %u)",
|
||||
errx(1, "Section \"%s\" has an invalid bank range (%" PRIu32 " > %" PRIu32 ")",
|
||||
section->name, section->bank,
|
||||
maxNbBanks[section->type] - 1);
|
||||
|
||||
@@ -87,8 +88,9 @@ void out_AddSection(struct Section const *section)
|
||||
|
||||
struct Section const *out_OverlappingSection(struct Section const *section)
|
||||
{
|
||||
struct SortedSections *banks = sections[section->type].banks;
|
||||
struct SortedSection *ptr =
|
||||
sections[section->type].banks[section->bank].sections;
|
||||
banks[section->bank - bankranges[section->type][0]].sections;
|
||||
|
||||
while (ptr) {
|
||||
if (ptr->section->org < section->org + section->size
|
||||
@@ -175,9 +177,13 @@ static void writeBank(struct SortedSection *bankSections, uint16_t baseOffset,
|
||||
bankSections = bankSections->next;
|
||||
}
|
||||
|
||||
while (offset < size) {
|
||||
putc(overlayFile ? getc(overlayFile) : padValue, outputFile);
|
||||
offset++;
|
||||
if (!disablePadding) {
|
||||
while (offset < size) {
|
||||
putc(overlayFile ? getc(overlayFile)
|
||||
: padValue,
|
||||
outputFile);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +285,7 @@ static void writeSymBank(struct SortedSections const *bankSections)
|
||||
|
||||
minSectList = &zlSectList;
|
||||
}
|
||||
fprintf(symFile, "%02x:%04x %s\n",
|
||||
fprintf(symFile, "%02" PRIx32 ":%04" PRIx16 " %s\n",
|
||||
minSectList->sect->bank, minSectList->addr,
|
||||
minSectList->sym->name);
|
||||
minSectList->i++;
|
||||
@@ -300,7 +306,7 @@ static void writeMapBank(struct SortedSections const *sectList,
|
||||
struct SortedSection const *section = sectList->sections;
|
||||
struct SortedSection const *zeroLenSection = sectList->zeroLenSections;
|
||||
|
||||
fprintf(mapFile, "%s bank #%u:\n", typeNames[type],
|
||||
fprintf(mapFile, "%s bank #%" PRIu32 ":\n", typeNames[type],
|
||||
bank + bankranges[type][0]);
|
||||
|
||||
uint16_t slack = maxsize[type];
|
||||
@@ -312,12 +318,17 @@ static void writeMapBank(struct SortedSections const *sectList,
|
||||
|
||||
slack -= sect->size;
|
||||
|
||||
fprintf(mapFile, " SECTION: $%04x-$%04x ($%04x byte%s) [\"%s\"]\n",
|
||||
sect->org, sect->org + sect->size - 1, sect->size,
|
||||
sect->size == 1 ? "" : "s", sect->name);
|
||||
if (sect->size != 0)
|
||||
fprintf(mapFile, " SECTION: $%04" PRIx16 "-$%04" PRIx16 " ($%04" PRIx16 " byte%s) [\"%s\"]\n",
|
||||
sect->org, sect->org + sect->size - 1,
|
||||
sect->size, sect->size == 1 ? "" : "s",
|
||||
sect->name);
|
||||
else
|
||||
fprintf(mapFile, " SECTION: $%04" PRIx16 " (0 bytes) [\"%s\"]\n",
|
||||
sect->org, sect->name);
|
||||
|
||||
for (size_t i = 0; i < sect->nbSymbols; i++)
|
||||
fprintf(mapFile, " $%04x = %s\n",
|
||||
fprintf(mapFile, " $%04" PRIx32 " = %s\n",
|
||||
sect->symbols[i]->offset + sect->org,
|
||||
sect->symbols[i]->name);
|
||||
|
||||
@@ -327,7 +338,7 @@ static void writeMapBank(struct SortedSections const *sectList,
|
||||
if (slack == maxsize[type])
|
||||
fputs(" EMPTY\n\n", mapFile);
|
||||
else
|
||||
fprintf(mapFile, " SLACK: $%04x byte%s\n\n", slack,
|
||||
fprintf(mapFile, " SLACK: $%04" PRIx16 " byte%s\n\n", slack,
|
||||
slack == 1 ? "" : "s");
|
||||
}
|
||||
|
||||
|
||||
163
src/link/patch.c
163
src/link/patch.c
@@ -6,8 +6,9 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "link/patch.h"
|
||||
@@ -82,10 +83,20 @@ static inline void clearRPNStack(void)
|
||||
static void pushRPN(int32_t value)
|
||||
{
|
||||
if (stack.size >= stack.capacity) {
|
||||
stack.capacity *= 2;
|
||||
static const size_t increase_factor = 2;
|
||||
|
||||
if (stack.capacity > SIZE_MAX / increase_factor)
|
||||
errx(1, "Overflow in RPN stack resize");
|
||||
|
||||
stack.capacity *= increase_factor;
|
||||
stack.buf =
|
||||
realloc(stack.buf, sizeof(*stack.buf) * stack.capacity);
|
||||
if (!stack.buf)
|
||||
/*
|
||||
* Static analysis tools complain that the capacity might become
|
||||
* zero due to overflow, but fail to realize that it's caught by
|
||||
* the overflow check above. Hence the stringent check below.
|
||||
*/
|
||||
if (!stack.buf || !stack.capacity)
|
||||
err(1, "Failed to resize RPN stack");
|
||||
}
|
||||
|
||||
@@ -118,19 +129,13 @@ static uint32_t getRPNByte(uint8_t const **expression, int32_t *size,
|
||||
}
|
||||
|
||||
static struct Symbol const *getSymbol(struct Symbol const * const *symbolList,
|
||||
uint32_t index, char const *fileName)
|
||||
uint32_t index)
|
||||
{
|
||||
struct Symbol const *symbol = symbolList[index];
|
||||
|
||||
/* If the symbol is defined elsewhere... */
|
||||
if (symbol->type == SYMTYPE_IMPORT) {
|
||||
struct Symbol const *symbolDefinition =
|
||||
sym_GetSymbol(symbol->name);
|
||||
if (!symbolDefinition)
|
||||
errx(1, "%s: Unknown symbol \"%s\"", fileName,
|
||||
symbol->name);
|
||||
symbol = symbolDefinition;
|
||||
}
|
||||
if (symbol->type == SYMTYPE_IMPORT)
|
||||
return sym_GetSymbol(symbol->name);
|
||||
|
||||
return symbol;
|
||||
}
|
||||
@@ -142,7 +147,6 @@ static struct Symbol const *getSymbol(struct Symbol const * const *symbolList,
|
||||
* @return The patch's value
|
||||
*/
|
||||
static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
struct Section const *section,
|
||||
struct Symbol const * const *fileSymbols)
|
||||
{
|
||||
/* Small shortcut to avoid a lot of repetition */
|
||||
@@ -182,13 +186,23 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
break;
|
||||
case RPN_DIV:
|
||||
value = popRPN();
|
||||
if (value == 0)
|
||||
errx(1, "%s: Division by 0", patch->fileName);
|
||||
value = popRPN() / value;
|
||||
if (value == 0) {
|
||||
error("%s: Division by 0", patch->fileName);
|
||||
popRPN();
|
||||
value = INT32_MAX;
|
||||
} else {
|
||||
value = popRPN() / value;
|
||||
}
|
||||
break;
|
||||
case RPN_MOD:
|
||||
value = popRPN();
|
||||
value = popRPN() % value;
|
||||
if (value == 0) {
|
||||
error("%s: Modulo by 0", patch->fileName);
|
||||
popRPN();
|
||||
value = 0;
|
||||
} else {
|
||||
value = popRPN() % value;
|
||||
}
|
||||
break;
|
||||
case RPN_UNSUB:
|
||||
value = -popRPN();
|
||||
@@ -256,9 +270,21 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
for (uint8_t shift = 0; shift < 32; shift += 8)
|
||||
value |= getRPNByte(&expression, &size,
|
||||
patch->fileName) << shift;
|
||||
symbol = getSymbol(fileSymbols, value);
|
||||
|
||||
value = getSymbol(fileSymbols, value,
|
||||
patch->fileName)->section->bank;
|
||||
if (!symbol) {
|
||||
error("%s: Requested BANK() of symbol \"%s\", which was not found",
|
||||
patch->fileName,
|
||||
fileSymbols[value]->name);
|
||||
value = 1;
|
||||
} else if (!symbol->section) {
|
||||
error("%s: Requested BANK() of non-label symbol \"%s\"",
|
||||
patch->fileName,
|
||||
fileSymbols[value]->name);
|
||||
value = 1;
|
||||
} else {
|
||||
value = symbol->section->bank;
|
||||
}
|
||||
break;
|
||||
|
||||
case RPN_BANK_SECT:
|
||||
@@ -268,15 +294,22 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
|
||||
sect = sect_GetSection(name);
|
||||
|
||||
if (!sect)
|
||||
errx(1, "%s: Requested BANK() of section \"%s\", which was not found",
|
||||
patch->fileName, name);
|
||||
|
||||
value = sect->bank;
|
||||
if (!sect) {
|
||||
error("%s: Requested BANK() of section \"%s\", which was not found",
|
||||
patch->fileName, name);
|
||||
value = 1;
|
||||
} else {
|
||||
value = sect->bank;
|
||||
}
|
||||
break;
|
||||
|
||||
case RPN_BANK_SELF:
|
||||
value = section->bank;
|
||||
if (!patch->pcSection) {
|
||||
error("%s: PC has no bank outside a section");
|
||||
value = 1;
|
||||
} else {
|
||||
value = patch->pcSection->bank;
|
||||
}
|
||||
break;
|
||||
|
||||
case RPN_HRAM:
|
||||
@@ -284,8 +317,8 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
if (value < 0
|
||||
|| (value > 0xFF && value < 0xFF00)
|
||||
|| value > 0xFFFF)
|
||||
errx(1, "%s: Value %d is not in HRAM range",
|
||||
patch->fileName, value);
|
||||
error("%s: Value %" PRId32 " is not in HRAM range",
|
||||
patch->fileName, value);
|
||||
value &= 0xFF;
|
||||
break;
|
||||
|
||||
@@ -295,8 +328,8 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
* They can be easily checked with a bitmask
|
||||
*/
|
||||
if (value & ~0x38)
|
||||
errx(1, "%s: Value %d is not a RST vector",
|
||||
patch->fileName, value);
|
||||
error("%s: Value %" PRId32 " is not a RST vector",
|
||||
patch->fileName, value);
|
||||
value |= 0xC7;
|
||||
break;
|
||||
|
||||
@@ -313,15 +346,23 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
value |= getRPNByte(&expression, &size,
|
||||
patch->fileName) << shift;
|
||||
|
||||
symbol = getSymbol(fileSymbols, value, patch->fileName);
|
||||
symbol = getSymbol(fileSymbols, value);
|
||||
|
||||
if (!strcmp(symbol->name, "@")) {
|
||||
value = section->org + patch->offset;
|
||||
} else {
|
||||
if (!symbol) {
|
||||
error("%s: Unknown symbol \"%s\"",
|
||||
patch->fileName,
|
||||
fileSymbols[value]->name);
|
||||
} else if (strcmp(symbol->name, "@")) {
|
||||
value = symbol->value;
|
||||
/* Symbols attached to sections have offsets */
|
||||
if (symbol->section)
|
||||
value += symbol->section->org;
|
||||
} else if (!patch->pcSection) {
|
||||
error("%s: PC has no value outside a section",
|
||||
patch->fileName);
|
||||
value = 0;
|
||||
} else {
|
||||
value = patch->pcOffset + patch->pcSection->org;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -330,7 +371,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
}
|
||||
|
||||
if (stack.size > 1)
|
||||
warnx("%s: RPN stack has %lu entries on exit, not 1",
|
||||
error("%s: RPN stack has %zu entries on exit, not 1",
|
||||
patch->fileName, stack.size);
|
||||
|
||||
return popRPN();
|
||||
@@ -343,25 +384,21 @@ void patch_CheckAssertions(struct Assertion *assert)
|
||||
verbosePrint("Checking assertions...");
|
||||
initRPNStack();
|
||||
|
||||
uint8_t failures = 0;
|
||||
|
||||
while (assert) {
|
||||
if (!computeRPNExpr(&assert->patch, assert->section,
|
||||
if (!computeRPNExpr(&assert->patch,
|
||||
(struct Symbol const * const *)
|
||||
assert->fileSymbols)) {
|
||||
assert->fileSymbols)) {
|
||||
switch ((enum AssertionType)assert->patch.type) {
|
||||
case ASSERT_FATAL:
|
||||
errx(1, "%s: %s", assert->patch.fileName,
|
||||
assert->message[0] ? assert->message
|
||||
: "assert failure");
|
||||
fatal("%s: %s", assert->patch.fileName,
|
||||
assert->message[0] ? assert->message
|
||||
: "assert failure");
|
||||
/* Not reached */
|
||||
break; /* Here so checkpatch doesn't complain */
|
||||
case ASSERT_ERROR:
|
||||
fprintf(stderr, "%s: %s\n",
|
||||
assert->patch.fileName,
|
||||
assert->message[0] ? assert->message
|
||||
: "assert failure");
|
||||
failures++;
|
||||
error("%s: %s", assert->patch.fileName,
|
||||
assert->message[0] ? assert->message
|
||||
: "assert failure");
|
||||
break;
|
||||
case ASSERT_WARN:
|
||||
warnx("%s: %s", assert->patch.fileName,
|
||||
@@ -377,9 +414,6 @@ void patch_CheckAssertions(struct Assertion *assert)
|
||||
}
|
||||
|
||||
freeRPNStack();
|
||||
|
||||
if (failures)
|
||||
errx(1, "%u assertions failed!", failures);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,7 +421,7 @@ void patch_CheckAssertions(struct Assertion *assert)
|
||||
* @param section The section to patch
|
||||
* @param arg Ignored callback arg
|
||||
*/
|
||||
static void applyFilePatches(struct Section *section)
|
||||
static void applyFilePatches(struct Section *section, struct Section *dataSection)
|
||||
{
|
||||
if (!sect_HasData(section->type))
|
||||
return;
|
||||
@@ -395,20 +429,22 @@ static void applyFilePatches(struct Section *section)
|
||||
verbosePrint("Patching section \"%s\"...\n", section->name);
|
||||
for (uint32_t patchID = 0; patchID < section->nbPatches; patchID++) {
|
||||
struct Patch *patch = §ion->patches[patchID];
|
||||
int32_t value = computeRPNExpr(patch, section,
|
||||
int32_t value = computeRPNExpr(patch,
|
||||
(struct Symbol const * const *)
|
||||
section->fileSymbols);
|
||||
uint16_t offset = patch->offset + section->offset;
|
||||
|
||||
/* `jr` is quite unlike the others... */
|
||||
if (patch->type == PATCHTYPE_JR) {
|
||||
/* Target is relative to the byte *after* the operand */
|
||||
uint16_t address = section->org + patch->offset + 1;
|
||||
int16_t offset = value - address;
|
||||
uint16_t address = patch->pcSection->org
|
||||
+ patch->pcOffset + 1;
|
||||
int16_t jumpOffset = value - address;
|
||||
|
||||
if (offset < -128 || offset > 127)
|
||||
errx(1, "%s: jr target out of reach (expected -129 < %d < 128)",
|
||||
patch->fileName, offset);
|
||||
section->data[patch->offset] = offset & 0xFF;
|
||||
if (jumpOffset < -128 || jumpOffset > 127)
|
||||
error("%s: jr target out of reach (expected -129 < %" PRId16 " < 128)",
|
||||
patch->fileName, jumpOffset);
|
||||
dataSection->data[offset] = jumpOffset & 0xFF;
|
||||
} else {
|
||||
/* Patch a certain number of bytes */
|
||||
struct {
|
||||
@@ -423,12 +459,12 @@ static void applyFilePatches(struct Section *section)
|
||||
|
||||
if (value < types[patch->type].min
|
||||
|| value > types[patch->type].max)
|
||||
errx(1, "%s: Value %#x%s is not %u-bit",
|
||||
patch->fileName, value,
|
||||
value < 0 ? " (maybe negative?)" : "",
|
||||
types[patch->type].size * 8);
|
||||
error("%s: Value %#" PRIx32 "%s is not %u-bit",
|
||||
patch->fileName, value,
|
||||
value < 0 ? " (maybe negative?)" : "",
|
||||
types[patch->type].size * 8U);
|
||||
for (uint8_t i = 0; i < types[patch->type].size; i++) {
|
||||
section->data[patch->offset + i] = value & 0xFF;
|
||||
dataSection->data[offset + i] = value & 0xFF;
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
@@ -444,9 +480,10 @@ static void applyFilePatches(struct Section *section)
|
||||
static void applyPatches(struct Section *section, void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
struct Section *dataSection = section;
|
||||
|
||||
do {
|
||||
applyFilePatches(section);
|
||||
applyFilePatches(section, dataSection);
|
||||
section = section->nextu;
|
||||
} while (section);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
.Nd Game Boy linker
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl dtVvw
|
||||
.Op Fl dtVvwx
|
||||
.Op Fl l Ar linker_script
|
||||
.Op Fl m Ar map_file
|
||||
.Op Fl n Ar sym_file
|
||||
@@ -63,7 +63,7 @@ The arguments are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl d , Fl Fl dmg
|
||||
Enable DMG mode.
|
||||
Prohibit the use of sections that doesn't exist on a DMG, such as WRAMX and VRAM bank 1.
|
||||
Prohibit the use of sections that doesn't exist on a DMG, such as VRAM bank 1.
|
||||
This option automatically enables
|
||||
.Fl w .
|
||||
.It Fl l Ar linker_script, Fl Fl linkerscript Ar linker_script
|
||||
@@ -94,14 +94,24 @@ This option is ignored.
|
||||
It was supposed to perform smart linking but fell into disrepair, and so has been removed.
|
||||
It will be reimplemented at some point.
|
||||
.It Fl t , Fl Fl tiny
|
||||
Expand the ROM0 section size from 16 KiB to the full 32 KiB assigned to ROM and prohibit the use of ROMX sections.
|
||||
Expand the ROM0 section size from 16 KiB to the full 32 KiB assigned to ROM.
|
||||
ROMX sections that are fixed to a bank other than 1 become errors, other ROMX sections are treated as ROM0.
|
||||
Useful for ROMs that fit in 32 KiB.
|
||||
.It Fl V , Fl Fl version
|
||||
Print the version of the program and exit.
|
||||
.It Fl v , Fl Fl verbose
|
||||
Verbose: enable printing more information to standard error.
|
||||
.It Fl w , Fl Fl wramx
|
||||
Expand the WRAM0 section size from 4 KiB to the full 8 KiB assigned to WRAM and prohibit the use of WRAMX sections.
|
||||
Expand the WRAM0 section size from 4 KiB to the full 8 KiB assigned to WRAM.
|
||||
WRAMX sections that are fixed to a bank other than 1 become errors, other WRAMX sections are treated as WRAM0.
|
||||
.It Fl x , Fl Fl nopad
|
||||
Disables padding the end of the final file.
|
||||
This option automatically enables
|
||||
.Fl t .
|
||||
You can use this when not not making a ROM.
|
||||
When making a ROM, be careful that not using this is not a replacement for
|
||||
.Xr rgbfix 1 Ap s Fl p
|
||||
option!
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
All you need for a basic ROM is an object file, which can be made into a ROM image like so:
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "link/main.h"
|
||||
#include "link/script.h"
|
||||
@@ -19,22 +20,23 @@
|
||||
#include "extern/err.h"
|
||||
|
||||
FILE * linkerScript;
|
||||
char *includeFileName;
|
||||
|
||||
static uint32_t lineNo;
|
||||
|
||||
static struct {
|
||||
FILE *file;
|
||||
uint32_t lineNo;
|
||||
char const *name;
|
||||
char *name;
|
||||
} *fileStack;
|
||||
|
||||
static uint32_t fileStackSize;
|
||||
static uint32_t fileStackIndex;
|
||||
|
||||
static void pushFile(char const *newFileName)
|
||||
static void pushFile(char *newFileName)
|
||||
{
|
||||
if (fileStackIndex == UINT32_MAX)
|
||||
errx(1, "%s(%u): INCLUDE recursion limit reached",
|
||||
errx(1, "%s(%" PRIu32 "): INCLUDE recursion limit reached",
|
||||
linkerScriptName, lineNo);
|
||||
|
||||
if (fileStackIndex == fileStackSize) {
|
||||
@@ -44,7 +46,7 @@ static void pushFile(char const *newFileName)
|
||||
fileStack = realloc(fileStack,
|
||||
sizeof(*fileStack) * fileStackSize);
|
||||
if (!fileStack)
|
||||
err(1, "%s(%u): Internal INCLUDE error",
|
||||
err(1, "%s(%" PRIu32 "): Internal INCLUDE error",
|
||||
linkerScriptName, lineNo);
|
||||
}
|
||||
|
||||
@@ -55,7 +57,7 @@ static void pushFile(char const *newFileName)
|
||||
|
||||
linkerScript = fopen(newFileName, "r");
|
||||
if (!linkerScript)
|
||||
err(1, "%s(%u): Could not open \"%s\"",
|
||||
err(1, "%s(%" PRIu32 "): Could not open \"%s\"",
|
||||
linkerScriptName, lineNo, newFileName);
|
||||
lineNo = 1;
|
||||
linkerScriptName = newFileName;
|
||||
@@ -66,6 +68,8 @@ static bool popFile(void)
|
||||
if (!fileStackIndex)
|
||||
return false;
|
||||
|
||||
free(linkerScriptName);
|
||||
|
||||
fileStackIndex--;
|
||||
linkerScript = fileStack[fileStackIndex].file;
|
||||
lineNo = fileStack[fileStackIndex].lineNo;
|
||||
@@ -174,12 +178,12 @@ static int readChar(FILE *file)
|
||||
int curchar = getc(file);
|
||||
|
||||
if (curchar == EOF && ferror(file))
|
||||
err(1, "%s(%u): Unexpected error in %s", linkerScriptName,
|
||||
lineNo, __func__);
|
||||
err(1, "%s(%" PRIu32 "): Unexpected error in %s",
|
||||
linkerScriptName, lineNo, __func__);
|
||||
return curchar;
|
||||
}
|
||||
|
||||
static struct LinkerScriptToken const *nextToken(void)
|
||||
static struct LinkerScriptToken *nextToken(void)
|
||||
{
|
||||
static struct LinkerScriptToken token;
|
||||
int curchar;
|
||||
@@ -220,7 +224,7 @@ static struct LinkerScriptToken const *nextToken(void)
|
||||
do {
|
||||
curchar = readChar(linkerScript);
|
||||
if (curchar == EOF || isNewline(curchar))
|
||||
errx(1, "%s(%u): Unterminated string",
|
||||
errx(1, "%s(%" PRIu32 "): Unterminated string",
|
||||
linkerScriptName, lineNo);
|
||||
else if (curchar == '"')
|
||||
/* Quotes force a string termination */
|
||||
@@ -299,7 +303,7 @@ static struct LinkerScriptToken const *nextToken(void)
|
||||
if (tryParseNumber(str, &token.attr.number))
|
||||
token.type = TOKEN_NUMBER;
|
||||
else
|
||||
errx(1, "%s(%u): Unknown token \"%s\"",
|
||||
errx(1, "%s(%" PRIu32 "): Unknown token \"%s\"",
|
||||
linkerScriptName, lineNo, str);
|
||||
}
|
||||
|
||||
@@ -327,7 +331,7 @@ static void processCommand(enum LinkerScriptCommand command, uint16_t arg,
|
||||
}
|
||||
|
||||
if (arg < *pc)
|
||||
errx(1, "%s(%u): `%s` cannot be used to go backwards",
|
||||
errx(1, "%s(%" PRIu32 "): `%s` cannot be used to go backwards",
|
||||
linkerScriptName, lineNo, commands[command]);
|
||||
*pc = arg;
|
||||
}
|
||||
@@ -368,7 +372,7 @@ struct SectionPlacement *script_NextSection(void)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
struct LinkerScriptToken const *token = nextToken();
|
||||
struct LinkerScriptToken *token = nextToken();
|
||||
enum LinkerScriptTokenType tokType;
|
||||
union LinkerScriptTokenAttr attr;
|
||||
bool hasArg;
|
||||
@@ -376,11 +380,11 @@ struct SectionPlacement *script_NextSection(void)
|
||||
|
||||
if (type != SECTTYPE_INVALID) {
|
||||
if (curaddr[type][bankID] > endaddr(type) + 1)
|
||||
errx(1, "%s(%u): Sections would extend past the end of %s ($%04hx > $%04hx)",
|
||||
errx(1, "%s(%" PRIu32 "): Sections would extend past the end of %s ($%04" PRIx16 " > $%04" PRIx16 ")",
|
||||
linkerScriptName, lineNo, typeNames[type],
|
||||
curaddr[type][bankID], endaddr(type));
|
||||
if (curaddr[type][bankID] < startaddr[type])
|
||||
errx(1, "%s(%u): PC underflowed ($%04hx < $%04hx)",
|
||||
errx(1, "%s(%" PRIu32 "): PC underflowed ($%04" PRIx16 " < $%04" PRIx16 ")",
|
||||
linkerScriptName, lineNo,
|
||||
curaddr[type][bankID], startaddr[type]);
|
||||
}
|
||||
@@ -401,7 +405,7 @@ struct SectionPlacement *script_NextSection(void)
|
||||
break;
|
||||
|
||||
case TOKEN_NUMBER:
|
||||
errx(1, "%s(%u): stray number \"%u\"",
|
||||
errx(1, "%s(%" PRIu32 "): stray number \"%" PRIu32 "\"",
|
||||
linkerScriptName, lineNo,
|
||||
token->attr.number);
|
||||
|
||||
@@ -414,13 +418,13 @@ struct SectionPlacement *script_NextSection(void)
|
||||
parserState = PARSER_LINEEND;
|
||||
|
||||
if (type == SECTTYPE_INVALID)
|
||||
errx(1, "%s(%u): Didn't specify a location before the section",
|
||||
errx(1, "%s(%" PRIu32 "): Didn't specify a location before the section",
|
||||
linkerScriptName, lineNo);
|
||||
|
||||
section.section =
|
||||
sect_GetSection(token->attr.string);
|
||||
if (!section.section)
|
||||
errx(1, "%s(%u): Unknown section \"%s\"",
|
||||
errx(1, "%s(%" PRIu32 "): Unknown section \"%s\"",
|
||||
linkerScriptName, lineNo,
|
||||
token->attr.string);
|
||||
section.org = curaddr[type][bankID];
|
||||
@@ -449,10 +453,10 @@ struct SectionPlacement *script_NextSection(void)
|
||||
|
||||
if (tokType == TOKEN_COMMAND) {
|
||||
if (type == SECTTYPE_INVALID)
|
||||
errx(1, "%s(%u): Didn't specify a location before the command",
|
||||
errx(1, "%s(%" PRIu32 "): Didn't specify a location before the command",
|
||||
linkerScriptName, lineNo);
|
||||
if (!hasArg)
|
||||
errx(1, "%s(%u): Command specified without an argument",
|
||||
errx(1, "%s(%" PRIu32 "): Command specified without an argument",
|
||||
linkerScriptName, lineNo);
|
||||
|
||||
processCommand(attr.command, arg,
|
||||
@@ -464,16 +468,16 @@ struct SectionPlacement *script_NextSection(void)
|
||||
* specifying the number is optional.
|
||||
*/
|
||||
if (!hasArg && nbbanks(type) != 1)
|
||||
errx(1, "%s(%u): Didn't specify a bank number",
|
||||
errx(1, "%s(%" PRIu32 "): Didn't specify a bank number",
|
||||
linkerScriptName, lineNo);
|
||||
else if (!hasArg)
|
||||
arg = bankranges[type][0];
|
||||
else if (arg < bankranges[type][0])
|
||||
errx(1, "%s(%u): specified bank number is too low (%u < %u)",
|
||||
errx(1, "%s(%" PRIu32 "): specified bank number is too low (%" PRIu32 " < %" PRIu32 ")",
|
||||
linkerScriptName, lineNo,
|
||||
arg, bankranges[type][0]);
|
||||
else if (arg > bankranges[type][1])
|
||||
errx(1, "%s(%u): specified bank number is too high (%u > %u)",
|
||||
errx(1, "%s(%" PRIu32 "): specified bank number is too high (%" PRIu32 " > %" PRIu32 ")",
|
||||
linkerScriptName, lineNo,
|
||||
arg, bankranges[type][1]);
|
||||
bank = arg;
|
||||
@@ -493,11 +497,13 @@ struct SectionPlacement *script_NextSection(void)
|
||||
|
||||
case PARSER_INCLUDE:
|
||||
if (token->type != TOKEN_STRING)
|
||||
errx(1, "%s(%u): Expected a file name after INCLUDE",
|
||||
errx(1, "%s(%" PRIu32 "): Expected a file name after INCLUDE",
|
||||
linkerScriptName, lineNo);
|
||||
|
||||
/* Switch to that file */
|
||||
pushFile(token->attr.string);
|
||||
/* The file stack took ownership of the string */
|
||||
token->attr.string = NULL;
|
||||
|
||||
parserState = PARSER_LINESTART;
|
||||
break;
|
||||
@@ -511,7 +517,7 @@ lineend:
|
||||
return NULL;
|
||||
parserState = PARSER_LINEEND;
|
||||
} else if (token->type != TOKEN_NEWLINE)
|
||||
errx(1, "%s(%u): Unexpected %s at the end of the line",
|
||||
errx(1, "%s(%" PRIu32 "): Unexpected %s at the end of the line",
|
||||
linkerScriptName, lineNo,
|
||||
tokenTypes[token->type]);
|
||||
break;
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "link/main.h"
|
||||
#include "link/section.h"
|
||||
@@ -36,7 +39,7 @@ void sect_ForEach(void (*callback)(struct Section *, void *), void *arg)
|
||||
hash_ForEach(sections, forEach, &callbackArg);
|
||||
}
|
||||
|
||||
static void mergeSections(struct Section *target, struct Section *other)
|
||||
static void mergeSections(struct Section *target, struct Section *other, enum SectionModifier mod)
|
||||
{
|
||||
if (target->type != other->type)
|
||||
errx(1, "Section \"%s\" is defined with conflicting types %s and %s",
|
||||
@@ -45,24 +48,31 @@ static void mergeSections(struct Section *target, struct Section *other)
|
||||
if (other->isAddressFixed) {
|
||||
if (target->isAddressFixed) {
|
||||
if (target->org != other->org)
|
||||
errx(1, "Section \"%s\" is defined with conflicting addresses $%x and $%x",
|
||||
errx(1, "Section \"%s\" is defined with conflicting addresses $%" PRIx16 " and $%" PRIx16,
|
||||
other->name, target->org, other->org);
|
||||
} else if (target->isAlignFixed) {
|
||||
if (other->org & target->alignMask)
|
||||
errx(1, "Section \"%s\" is defined with conflicting %u-byte alignment and address $%x",
|
||||
if ((other->org - target->alignOfs) & target->alignMask)
|
||||
errx(1, "Section \"%s\" is defined with conflicting %" PRIu16 "-byte alignment (offset %" PRIu16 ") and address $%" PRIx16,
|
||||
other->name, target->alignMask + 1,
|
||||
other->org);
|
||||
target->alignOfs, other->org);
|
||||
}
|
||||
target->isAddressFixed = true;
|
||||
target->org = other->org;
|
||||
} else if (other->isAlignFixed) {
|
||||
if (target->isAddressFixed) {
|
||||
if (target->org & other->alignMask)
|
||||
errx(1, "Section \"%s\" is defined with conflicting address $%x and %u-byte alignment",
|
||||
if ((target->org - other->alignOfs) & other->alignMask)
|
||||
errx(1, "Section \"%s\" is defined with conflicting address $%" PRIx16 " and %" PRIu16 "-byte alignment (offset %" PRIu16 ")",
|
||||
other->name, target->org,
|
||||
other->alignMask + 1);
|
||||
other->alignMask + 1, other->alignOfs);
|
||||
} else if (target->isAlignFixed
|
||||
&& (other->alignMask & target->alignOfs)
|
||||
!= (target->alignMask & other->alignOfs)) {
|
||||
errx(1, "Section \"%s\" is defined with conflicting %" PRIu16 "-byte alignment (offset %" PRIu16 ") and %" PRIu16 "-byte alignment (offset %" PRIu16 ")",
|
||||
other->name, target->alignMask + 1,
|
||||
target->alignOfs, other->alignMask + 1,
|
||||
other->alignOfs);
|
||||
} else if (!target->isAlignFixed
|
||||
|| other->alignMask > target->alignMask) {
|
||||
|| (other->alignMask > target->alignMask)) {
|
||||
target->isAlignFixed = true;
|
||||
target->alignMask = other->alignMask;
|
||||
}
|
||||
@@ -73,14 +83,35 @@ static void mergeSections(struct Section *target, struct Section *other)
|
||||
target->isBankFixed = true;
|
||||
target->bank = other->bank;
|
||||
} else if (target->bank != other->bank) {
|
||||
errx(1, "Section \"%s\" is defined with conflicting banks %u and %u",
|
||||
errx(1, "Section \"%s\" is defined with conflicting banks %" PRIu32 " and %" PRIu32,
|
||||
other->name, target->bank, other->bank);
|
||||
}
|
||||
}
|
||||
|
||||
if (other->size > target->size)
|
||||
target->size = other->size;
|
||||
switch (mod) {
|
||||
case SECTION_UNION:
|
||||
if (other->size > target->size)
|
||||
target->size = other->size;
|
||||
break;
|
||||
|
||||
case SECTION_FRAGMENT:
|
||||
target->size += other->size;
|
||||
other->offset = target->size - other->size;
|
||||
if (sect_HasData(target->type)) {
|
||||
/* Ensure we're not allocating 0 bytes */
|
||||
target->data = realloc(target->data,
|
||||
sizeof(*target->data) * target->size + 1);
|
||||
if (!target->data)
|
||||
errx(1, "Failed to concatenate \"%s\"'s fragments", target->name);
|
||||
memcpy(target->data + target->size - other->size, other->data, other->size);
|
||||
}
|
||||
break;
|
||||
|
||||
case SECTION_NORMAL:
|
||||
trap_;
|
||||
}
|
||||
|
||||
other->nextu = target->nextu;
|
||||
target->nextu = other;
|
||||
}
|
||||
|
||||
@@ -90,16 +121,14 @@ void sect_AddSection(struct Section *section)
|
||||
struct Section *other = hash_GetElement(sections, section->name);
|
||||
|
||||
if (other) {
|
||||
if (other->isUnion && section->isUnion) {
|
||||
mergeSections(other, section);
|
||||
} else if (section->isUnion || other->isUnion) {
|
||||
errx(1, "Section \"%s\" defined as both unionized and not",
|
||||
section->name);
|
||||
} else {
|
||||
errx(1, "Section name \"%s\" is already in use",
|
||||
section->name);
|
||||
}
|
||||
} else if (section->isUnion && sect_HasData(section->type)) {
|
||||
if (section->modifier != other->modifier)
|
||||
errx(1, "Section \"%s\" defined as %s and %s", section->name,
|
||||
sectionModNames[section->modifier], sectionModNames[other->modifier]);
|
||||
else if (section->modifier == SECTION_NORMAL)
|
||||
errx(1, "Section name \"%s\" is already in use", section->name);
|
||||
else
|
||||
mergeSections(other, section, section->modifier);
|
||||
} else if (section->modifier == SECTION_UNION && sect_HasData(section->type)) {
|
||||
errx(1, "Section \"%s\" is of type %s, which cannot be unionized",
|
||||
section->name, typeNames[section->type]);
|
||||
} else {
|
||||
@@ -164,7 +193,7 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
/* Too large an alignment may not be satisfiable */
|
||||
if (section->isAlignFixed
|
||||
&& (section->alignMask & startaddr[section->type]))
|
||||
fail("%s: %s sections cannot be aligned to $%x bytes",
|
||||
fail("%s: %s sections cannot be aligned to $%" PRIx16 " bytes",
|
||||
section->name, typeNames[section->type],
|
||||
section->alignMask + 1);
|
||||
|
||||
@@ -174,13 +203,13 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
if (section->isBankFixed && section->bank < minbank
|
||||
&& section->bank > maxbank)
|
||||
fail(minbank == maxbank
|
||||
? "Cannot place section \"%s\" in bank %d, it must be %d"
|
||||
: "Cannot place section \"%s\" in bank %d, it must be between %d and %d",
|
||||
? "Cannot place section \"%s\" in bank %" PRIu32 ", it must be %" PRIu32
|
||||
: "Cannot place section \"%s\" in bank %" PRIu32 ", it must be between %" PRIu32 " and %" PRIu32,
|
||||
section->name, section->bank, minbank, maxbank);
|
||||
|
||||
/* Check if section has a chance to be placed */
|
||||
if (section->size > maxsize[section->type])
|
||||
fail("Section \"%s\" is bigger than the max size for that type: %#x > %#x",
|
||||
fail("Section \"%s\" is bigger than the max size for that type: %#" PRIx16 " > %#" PRIx16,
|
||||
section->name, section->size, maxsize[section->type]);
|
||||
|
||||
/* Translate loose constraints to strong ones when they're equivalent */
|
||||
@@ -211,12 +240,12 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
/* Ensure the target address is valid */
|
||||
if (section->org < startaddr[section->type]
|
||||
|| section->org > endaddr(section->type))
|
||||
fail("Section \"%s\"'s fixed address %#x is outside of range [%#x; %#x]",
|
||||
fail("Section \"%s\"'s fixed address %#" PRIx16 " is outside of range [%#" PRIx16 "; %#" PRIx16 "]",
|
||||
section->name, section->org,
|
||||
startaddr[section->type], endaddr(section->type));
|
||||
|
||||
if (section->org + section->size > endaddr(section->type) + 1)
|
||||
fail("Section \"%s\"'s end address %#x is greater than last address %#x",
|
||||
fail("Section \"%s\"'s end address %#" PRIx16 " is greater than last address %#" PRIx16,
|
||||
section->name, section->org + section->size,
|
||||
endaddr(section->type) + 1);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "link/symbol.h"
|
||||
@@ -40,7 +41,7 @@ void sym_AddSymbol(struct Symbol *symbol)
|
||||
struct Symbol *other = hash_GetElement(symbols, symbol->name);
|
||||
|
||||
if (other)
|
||||
errx(1, "\"%s\" both in %s from %s(%d) and in %s from %s(%d)",
|
||||
errx(1, "\"%s\" both in %s from %s(%" PRId32 ") and in %s from %s(%" PRId32 ")",
|
||||
symbol->name,
|
||||
symbol->objFileName, symbol->fileName, symbol->lineNo,
|
||||
other->objFileName, other->fileName, other->lineNo);
|
||||
|
||||
@@ -44,3 +44,9 @@ char const * const typeNames[] = {
|
||||
[SECTTYPE_OAM] = "OAM",
|
||||
[SECTTYPE_HRAM] = "HRAM"
|
||||
};
|
||||
|
||||
char const * const sectionModNames[] = {
|
||||
[SECTION_NORMAL] = "regular",
|
||||
[SECTION_UNION] = "union",
|
||||
[SECTION_FRAGMENT] = "fragment",
|
||||
};
|
||||
|
||||
31
src/rgbds.5
31
src/rgbds.5
@@ -92,8 +92,10 @@ REPT NumberOfSections
|
||||
; decide (floating bank). This field is only valid for ROMX,
|
||||
; VRAM, WRAMX and SRAM sections.
|
||||
|
||||
LONG Align ; Alignment of this section, expressed as 1 << align. 1 if
|
||||
; not specified.
|
||||
BYTE Align ; Alignment of this section, as N bits. 0 when not specified.
|
||||
|
||||
LONG Ofs ; Offset relative to the alignment specified above.
|
||||
; Must be below 1 << Align.
|
||||
|
||||
IF (Type == ROMX) || (Type == ROM0) ; Sections that can contain data.
|
||||
|
||||
@@ -101,8 +103,6 @@ REPT NumberOfSections
|
||||
|
||||
LONG NumberOfPatches ; Number of patches to apply.
|
||||
|
||||
; These types of sections may have patches
|
||||
|
||||
REPT NumberOfPatches
|
||||
|
||||
STRING SourceFile ; Name of the source file (for printing error
|
||||
@@ -111,6 +111,16 @@ REPT NumberOfSections
|
||||
LONG Offset ; Offset into the section where patch should
|
||||
; be applied (in bytes).
|
||||
|
||||
LONG PCSectionID ; Index within the file of the section in which
|
||||
; PC is located.
|
||||
; This is usually the same section that the
|
||||
; patch should be applied into, except e.g.
|
||||
; with LOAD blocks.
|
||||
|
||||
LONG PCOffset ; PC's offset into the above section.
|
||||
; Used because the section may be floating, so
|
||||
; PC's value is not known to RGBASM.
|
||||
|
||||
BYTE Type ; 0 = BYTE patch.
|
||||
; 1 = little endian WORD patch.
|
||||
; 2 = little endian LONG patch.
|
||||
@@ -137,6 +147,13 @@ REPT NumberOfAssertions
|
||||
|
||||
LONG Offset ; Offset into the section where the assertion is located.
|
||||
|
||||
LONG SectionID ; Index within the file of the section in which PC is
|
||||
; located, or -1 if defined outside a section.
|
||||
|
||||
LONG PCOffset ; PC's offset into the above section.
|
||||
; Used because the section may be floating, so PC's value
|
||||
; is not known to RGBASM.
|
||||
|
||||
BYTE Type ; 0 = Prints the message but allows linking to continue
|
||||
; 1 = Prints the message and evaluates other assertions,
|
||||
; but linking fails afterwards
|
||||
@@ -146,10 +163,6 @@ REPT NumberOfAssertions
|
||||
|
||||
BYTE RPN[RPNSize] ; RPN expression, same as patches. Assert fails if == 0.
|
||||
|
||||
LONG SectionID ; The section number (of this object file) in which this
|
||||
; assert is defined. If it doesn't belong to any specific
|
||||
; section (like a constant), this field has the value -1.
|
||||
|
||||
STRING Message ; A message displayed when the assert fails. If set to
|
||||
; the empty string, a generic message is printed instead.
|
||||
|
||||
@@ -182,7 +195,7 @@ with some bytes being special prefixes for integers and symbols.
|
||||
.It Li $13 Ta Li unary ~
|
||||
.It Li $21 Ta Li && comparison
|
||||
.It Li $22 Ta Li || comparison
|
||||
.It Li $23 Ta Li unary !
|
||||
.It Li $23 Ta Li unary\ !
|
||||
.It Li $30 Ta Li == comparison
|
||||
.It Li $31 Ta Li != comparison
|
||||
.It Li $32 Ta Li > comparison
|
||||
|
||||
22
test/asm/align-pc.asm
Normal file
22
test/asm/align-pc.asm
Normal file
@@ -0,0 +1,22 @@
|
||||
SECTION "fixed org", SRAM[$BEAD]
|
||||
ds 42
|
||||
static_assert @ == $BED7
|
||||
align 5,$17
|
||||
|
||||
|
||||
; Should land at $0001
|
||||
SECTION "align", ROM0,ALIGN[1,1]
|
||||
db 69
|
||||
align 1 ; This wants to go at $0000, $0002, $0004...
|
||||
|
||||
|
||||
; Should land at $0003
|
||||
SECTION "under-aligned", ROM0,ALIGN[1,1]
|
||||
dw $BEEF
|
||||
align 2,1 ; This wants to go at $0001, $0005, $0009...
|
||||
|
||||
|
||||
; Should land at $0005
|
||||
SECTION "forced align", ROM0
|
||||
dw $DEAD
|
||||
align 2,3 ; This wants to go at $0003, $0007, $000B...
|
||||
0
test/asm/align-pc.err
Normal file
0
test/asm/align-pc.err
Normal file
0
test/asm/align-pc.out
Normal file
0
test/asm/align-pc.out
Normal file
0
test/asm/align-pc.out.bin
Normal file
0
test/asm/align-pc.out.bin
Normal file
1
test/asm/assert-nosect-bank.asm
Normal file
1
test/asm/assert-nosect-bank.asm
Normal file
@@ -0,0 +1 @@
|
||||
assert BANK(@) == 1
|
||||
3
test/asm/assert-nosect-bank.err
Normal file
3
test/asm/assert-nosect-bank.err
Normal file
@@ -0,0 +1,3 @@
|
||||
ERROR: assert-nosect-bank.asm(1):
|
||||
PC has no bank outside a section
|
||||
error: Assembly aborted (1 errors)!
|
||||
0
test/asm/assert-nosect-bank.out
Normal file
0
test/asm/assert-nosect-bank.out
Normal file
@@ -1 +1 @@
|
||||
SECTION "sec", ROMX[$/0]
|
||||
SECTION "sec", ROMX[1/0]
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
ERROR: divzero-section-bank.asm(1):
|
||||
Invalid integer constant
|
||||
ERROR: divzero-section-bank.asm(1):
|
||||
Division by zero
|
||||
|
||||
16
test/asm/empty-data-directive.asm
Normal file
16
test/asm/empty-data-directive.asm
Normal file
@@ -0,0 +1,16 @@
|
||||
SECTION "Empty Data Directive in ROM", ROM0
|
||||
ds 1
|
||||
ds 2
|
||||
ds 3
|
||||
ds 4
|
||||
db
|
||||
dw
|
||||
dl
|
||||
SECTION "Empty Data Directive in HRAM", HRAM
|
||||
ds 1
|
||||
ds 2
|
||||
ds 3
|
||||
ds 4
|
||||
db
|
||||
dw
|
||||
dl
|
||||
6
test/asm/empty-data-directive.err
Normal file
6
test/asm/empty-data-directive.err
Normal file
@@ -0,0 +1,6 @@
|
||||
warning: empty-data-directive.asm(6): [-Wempty-data-directive]
|
||||
db/dw/dl directive without data in ROM
|
||||
warning: empty-data-directive.asm(7): [-Wempty-data-directive]
|
||||
db/dw/dl directive without data in ROM
|
||||
warning: empty-data-directive.asm(8): [-Wempty-data-directive]
|
||||
db/dw/dl directive without data in ROM
|
||||
0
test/asm/empty-data-directive.out
Normal file
0
test/asm/empty-data-directive.out
Normal file
8
test/asm/local-purge.asm
Normal file
8
test/asm/local-purge.asm
Normal file
@@ -0,0 +1,8 @@
|
||||
; At some point, the name of the local label was passed *unexpanded* to the
|
||||
; function doing the removal. Ensure that this is fixed.
|
||||
|
||||
SECTION "Test", ROM0[0]
|
||||
Glob:
|
||||
.loc
|
||||
PURGE .loc
|
||||
PRINTT "{.loc}\n" ; This should fail because the label doesn't exist anymore
|
||||
3
test/asm/local-purge.err
Normal file
3
test/asm/local-purge.err
Normal file
@@ -0,0 +1,3 @@
|
||||
ERROR: local-purge.asm(8):
|
||||
'.loc' not defined
|
||||
error: Assembly aborted (1 errors)!
|
||||
1
test/asm/local-purge.out
Normal file
1
test/asm/local-purge.out
Normal file
@@ -0,0 +1 @@
|
||||
$0
|
||||
@@ -1,4 +1,5 @@
|
||||
ERROR: macro-@.asm(1):
|
||||
Label "foo" created outside of a SECTION
|
||||
ERROR: macro-@.asm(1):
|
||||
Macro '@' not defined
|
||||
"@" is not a macro
|
||||
error: Assembly aborted (2 errors)!
|
||||
|
||||
789
test/asm/macro-argument-limit.asm
Normal file
789
test/asm/macro-argument-limit.asm
Normal file
@@ -0,0 +1,789 @@
|
||||
addargs: MACRO
|
||||
sum = 0
|
||||
rept _NARG
|
||||
sum = sum + \1
|
||||
shift
|
||||
endr
|
||||
dw sum & $FFFF
|
||||
dw (sum >> 16) & $FFFF
|
||||
ENDM
|
||||
|
||||
SECTION "test", ROM0[0]
|
||||
addargs 1, 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, 30, \
|
||||
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, \
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, \
|
||||
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, \
|
||||
61, 62, 63, 64, 65, 66, 67, 68, 69, 70, \
|
||||
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, \
|
||||
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, \
|
||||
91, 92, 93, 94, 95, 96, 97, 98, 99, 100, \
|
||||
101, 102, 103, 104, 105, 106, 107, 108, 109, 110, \
|
||||
111, 112, 113, 114, 115, 116, 117, 118, 119, 120, \
|
||||
121, 122, 123, 124, 125, 126, 127, 128, 129, 130, \
|
||||
131, 132, 133, 134, 135, 136, 137, 138, 139, 140, \
|
||||
141, 142, 143, 144, 145, 146, 147, 148, 149, 150, \
|
||||
151, 152, 153, 154, 155, 156, 157, 158, 159, 160, \
|
||||
161, 162, 163, 164, 165, 166, 167, 168, 169, 170, \
|
||||
171, 172, 173, 174, 175, 176, 177, 178, 179, 180, \
|
||||
181, 182, 183, 184, 185, 186, 187, 188, 189, 190, \
|
||||
191, 192, 193, 194, 195, 196, 197, 198, 199, 200, \
|
||||
201, 202, 203, 204, 205, 206, 207, 208, 209, 210, \
|
||||
211, 212, 213, 214, 215, 216, 217, 218, 219, 220, \
|
||||
221, 222, 223, 224, 225, 226, 227, 228, 229, 230, \
|
||||
231, 232, 233, 234, 235, 236, 237, 238, 239, 240, \
|
||||
241, 242, 243, 244, 245, 246, 247, 248, 249, 250, \
|
||||
251, 252, 253, 254, 255, 256, 257, 258, 259, 260, \
|
||||
261, 262, 263, 264, 265, 266, 267, 268, 269, 270, \
|
||||
271, 272, 273, 274, 275, 276, 277, 278, 279, 280, \
|
||||
281, 282, 283, 284, 285, 286, 287, 288, 289, 290, \
|
||||
291, 292, 293, 294, 295, 296, 297, 298, 299, 300, \
|
||||
301, 302, 303, 304, 305, 306, 307, 308, 309, 310, \
|
||||
311, 312, 313, 314, 315, 316, 317, 318, 319, 320, \
|
||||
321, 322, 323, 324, 325, 326, 327, 328, 329, 330, \
|
||||
331, 332, 333, 334, 335, 336, 337, 338, 339, 340, \
|
||||
341, 342, 343, 344, 345, 346, 347, 348, 349, 350, \
|
||||
351, 352, 353, 354, 355, 356, 357, 358, 359, 360, \
|
||||
361, 362, 363, 364, 365, 366, 367, 368, 369, 370, \
|
||||
371, 372, 373, 374, 375, 376, 377, 378, 379, 380, \
|
||||
381, 382, 383, 384, 385, 386, 387, 388, 389, 390, \
|
||||
391, 392, 393, 394, 395, 396, 397, 398, 399, 400, \
|
||||
401, 402, 403, 404, 405, 406, 407, 408, 409, 410, \
|
||||
411, 412, 413, 414, 415, 416, 417, 418, 419, 420, \
|
||||
421, 422, 423, 424, 425, 426, 427, 428, 429, 430, \
|
||||
431, 432, 433, 434, 435, 436, 437, 438, 439, 440, \
|
||||
441, 442, 443, 444, 445, 446, 447, 448, 449, 450, \
|
||||
451, 452, 453, 454, 455, 456, 457, 458, 459, 460, \
|
||||
461, 462, 463, 464, 465, 466, 467, 468, 469, 470, \
|
||||
471, 472, 473, 474, 475, 476, 477, 478, 479, 480, \
|
||||
481, 482, 483, 484, 485, 486, 487, 488, 489, 490, \
|
||||
491, 492, 493, 494, 495, 496, 497, 498, 499, 500, \
|
||||
501, 502, 503, 504, 505, 506, 507, 508, 509, 510, \
|
||||
511, 512, 513, 514, 515, 516, 517, 518, 519, 520, \
|
||||
521, 522, 523, 524, 525, 526, 527, 528, 529, 530, \
|
||||
531, 532, 533, 534, 535, 536, 537, 538, 539, 540, \
|
||||
541, 542, 543, 544, 545, 546, 547, 548, 549, 550, \
|
||||
551, 552, 553, 554, 555, 556, 557, 558, 559, 560, \
|
||||
561, 562, 563, 564, 565, 566, 567, 568, 569, 570, \
|
||||
571, 572, 573, 574, 575, 576, 577, 578, 579, 580, \
|
||||
581, 582, 583, 584, 585, 586, 587, 588, 589, 590, \
|
||||
591, 592, 593, 594, 595, 596, 597, 598, 599, 600, \
|
||||
601, 602, 603, 604, 605, 606, 607, 608, 609, 610, \
|
||||
611, 612, 613, 614, 615, 616, 617, 618, 619, 620, \
|
||||
621, 622, 623, 624, 625, 626, 627, 628, 629, 630, \
|
||||
631, 632, 633, 634, 635, 636, 637, 638, 639, 640, \
|
||||
641, 642, 643, 644, 645, 646, 647, 648, 649, 650, \
|
||||
651, 652, 653, 654, 655, 656, 657, 658, 659, 660, \
|
||||
661, 662, 663, 664, 665, 666, 667, 668, 669, 670, \
|
||||
671, 672, 673, 674, 675, 676, 677, 678, 679, 680, \
|
||||
681, 682, 683, 684, 685, 686, 687, 688, 689, 690, \
|
||||
691, 692, 693, 694, 695, 696, 697, 698, 699, 700, \
|
||||
701, 702, 703, 704, 705, 706, 707, 708, 709, 710, \
|
||||
711, 712, 713, 714, 715, 716, 717, 718, 719, 720, \
|
||||
721, 722, 723, 724, 725, 726, 727, 728, 729, 730, \
|
||||
731, 732, 733, 734, 735, 736, 737, 738, 739, 740, \
|
||||
741, 742, 743, 744, 745, 746, 747, 748, 749, 750, \
|
||||
751, 752, 753, 754, 755, 756, 757, 758, 759, 760, \
|
||||
761, 762, 763, 764, 765, 766, 767, 768, 769, 770, \
|
||||
771, 772, 773, 774, 775, 776, 777, 778, 779, 780, \
|
||||
781, 782, 783, 784, 785, 786, 787, 788, 789, 790, \
|
||||
791, 792, 793, 794, 795, 796, 797, 798, 799, 800, \
|
||||
801, 802, 803, 804, 805, 806, 807, 808, 809, 810, \
|
||||
811, 812, 813, 814, 815, 816, 817, 818, 819, 820, \
|
||||
821, 822, 823, 824, 825, 826, 827, 828, 829, 830, \
|
||||
831, 832, 833, 834, 835, 836, 837, 838, 839, 840, \
|
||||
841, 842, 843, 844, 845, 846, 847, 848, 849, 850, \
|
||||
851, 852, 853, 854, 855, 856, 857, 858, 859, 860, \
|
||||
861, 862, 863, 864, 865, 866, 867, 868, 869, 870, \
|
||||
871, 872, 873, 874, 875, 876, 877, 878, 879, 880, \
|
||||
881, 882, 883, 884, 885, 886, 887, 888, 889, 890, \
|
||||
891, 892, 893, 894, 895, 896, 897, 898, 899, 900, \
|
||||
901, 902, 903, 904, 905, 906, 907, 908, 909, 910, \
|
||||
911, 912, 913, 914, 915, 916, 917, 918, 919, 920, \
|
||||
921, 922, 923, 924, 925, 926, 927, 928, 929, 930, \
|
||||
931, 932, 933, 934, 935, 936, 937, 938, 939, 940, \
|
||||
941, 942, 943, 944, 945, 946, 947, 948, 949, 950, \
|
||||
951, 952, 953, 954, 955, 956, 957, 958, 959, 960, \
|
||||
961, 962, 963, 964, 965, 966, 967, 968, 969, 970, \
|
||||
971, 972, 973, 974, 975, 976, 977, 978, 979, 980, \
|
||||
981, 982, 983, 984, 985, 986, 987, 988, 989, 990, \
|
||||
991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, \
|
||||
1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, \
|
||||
1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, \
|
||||
1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, \
|
||||
1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, \
|
||||
1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, \
|
||||
1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, \
|
||||
1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, \
|
||||
1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, \
|
||||
1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, \
|
||||
1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, \
|
||||
1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, \
|
||||
1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, \
|
||||
1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, \
|
||||
1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, \
|
||||
1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, \
|
||||
1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, \
|
||||
1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, \
|
||||
1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, \
|
||||
1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, \
|
||||
1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, \
|
||||
1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210, \
|
||||
1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, \
|
||||
1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, \
|
||||
1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, \
|
||||
1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, \
|
||||
1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260, \
|
||||
1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, \
|
||||
1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, \
|
||||
1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, \
|
||||
1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300, \
|
||||
1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, \
|
||||
1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, \
|
||||
1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, \
|
||||
1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, \
|
||||
1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, \
|
||||
1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, \
|
||||
1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, \
|
||||
1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, \
|
||||
1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, \
|
||||
1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, \
|
||||
1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, \
|
||||
1411, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1419, 1420, \
|
||||
1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, \
|
||||
1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440, \
|
||||
1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, \
|
||||
1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, \
|
||||
1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, \
|
||||
1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, \
|
||||
1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, \
|
||||
1491, 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, \
|
||||
1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, \
|
||||
1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1520, \
|
||||
1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1529, 1530, \
|
||||
1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, \
|
||||
1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1549, 1550, \
|
||||
1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, \
|
||||
1561, 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569, 1570, \
|
||||
1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, \
|
||||
1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, \
|
||||
1591, 1592, 1593, 1594, 1595, 1596, 1597, 1598, 1599, 1600, \
|
||||
1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, \
|
||||
1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, \
|
||||
1621, 1622, 1623, 1624, 1625, 1626, 1627, 1628, 1629, 1630, \
|
||||
1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, \
|
||||
1641, 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, \
|
||||
1651, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659, 1660, \
|
||||
1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, \
|
||||
1671, 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679, 1680, \
|
||||
1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, 1690, \
|
||||
1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, \
|
||||
1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, \
|
||||
1711, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, 1720, \
|
||||
1721, 1722, 1723, 1724, 1725, 1726, 1727, 1728, 1729, 1730, \
|
||||
1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1739, 1740, \
|
||||
1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, 1750, \
|
||||
1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, \
|
||||
1761, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, 1770, \
|
||||
1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, \
|
||||
1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, \
|
||||
1791, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, \
|
||||
1801, 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1809, 1810, \
|
||||
1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819, 1820, \
|
||||
1821, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, \
|
||||
1831, 1832, 1833, 1834, 1835, 1836, 1837, 1838, 1839, 1840, \
|
||||
1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, 1850, \
|
||||
1851, 1852, 1853, 1854, 1855, 1856, 1857, 1858, 1859, 1860, \
|
||||
1861, 1862, 1863, 1864, 1865, 1866, 1867, 1868, 1869, 1870, \
|
||||
1871, 1872, 1873, 1874, 1875, 1876, 1877, 1878, 1879, 1880, \
|
||||
1881, 1882, 1883, 1884, 1885, 1886, 1887, 1888, 1889, 1890, \
|
||||
1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, 1899, 1900, \
|
||||
1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, \
|
||||
1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, \
|
||||
1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, \
|
||||
1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, \
|
||||
1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, \
|
||||
1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, \
|
||||
1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, \
|
||||
1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, \
|
||||
1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, \
|
||||
1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, \
|
||||
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, \
|
||||
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, \
|
||||
2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, \
|
||||
2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, \
|
||||
2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, \
|
||||
2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, \
|
||||
2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, \
|
||||
2071, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, 2080, \
|
||||
2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2090, \
|
||||
2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, \
|
||||
2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, \
|
||||
2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, \
|
||||
2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, \
|
||||
2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, \
|
||||
2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149, 2150, \
|
||||
2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, \
|
||||
2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, \
|
||||
2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180, \
|
||||
2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, \
|
||||
2191, 2192, 2193, 2194, 2195, 2196, 2197, 2198, 2199, 2200, \
|
||||
2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, \
|
||||
2211, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, \
|
||||
2221, 2222, 2223, 2224, 2225, 2226, 2227, 2228, 2229, 2230, \
|
||||
2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, \
|
||||
2241, 2242, 2243, 2244, 2245, 2246, 2247, 2248, 2249, 2250, \
|
||||
2251, 2252, 2253, 2254, 2255, 2256, 2257, 2258, 2259, 2260, \
|
||||
2261, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2270, \
|
||||
2271, 2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, \
|
||||
2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, 2290, \
|
||||
2291, 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2299, 2300, \
|
||||
2301, 2302, 2303, 2304, 2305, 2306, 2307, 2308, 2309, 2310, \
|
||||
2311, 2312, 2313, 2314, 2315, 2316, 2317, 2318, 2319, 2320, \
|
||||
2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2330, \
|
||||
2331, 2332, 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2340, \
|
||||
2341, 2342, 2343, 2344, 2345, 2346, 2347, 2348, 2349, 2350, \
|
||||
2351, 2352, 2353, 2354, 2355, 2356, 2357, 2358, 2359, 2360, \
|
||||
2361, 2362, 2363, 2364, 2365, 2366, 2367, 2368, 2369, 2370, \
|
||||
2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379, 2380, \
|
||||
2381, 2382, 2383, 2384, 2385, 2386, 2387, 2388, 2389, 2390, \
|
||||
2391, 2392, 2393, 2394, 2395, 2396, 2397, 2398, 2399, 2400, \
|
||||
2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, \
|
||||
2411, 2412, 2413, 2414, 2415, 2416, 2417, 2418, 2419, 2420, \
|
||||
2421, 2422, 2423, 2424, 2425, 2426, 2427, 2428, 2429, 2430, \
|
||||
2431, 2432, 2433, 2434, 2435, 2436, 2437, 2438, 2439, 2440, \
|
||||
2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, 2449, 2450, \
|
||||
2451, 2452, 2453, 2454, 2455, 2456, 2457, 2458, 2459, 2460, \
|
||||
2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 2470, \
|
||||
2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, 2480, \
|
||||
2481, 2482, 2483, 2484, 2485, 2486, 2487, 2488, 2489, 2490, \
|
||||
2491, 2492, 2493, 2494, 2495, 2496, 2497, 2498, 2499, 2500, \
|
||||
2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, \
|
||||
2511, 2512, 2513, 2514, 2515, 2516, 2517, 2518, 2519, 2520, \
|
||||
2521, 2522, 2523, 2524, 2525, 2526, 2527, 2528, 2529, 2530, \
|
||||
2531, 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, \
|
||||
2541, 2542, 2543, 2544, 2545, 2546, 2547, 2548, 2549, 2550, \
|
||||
2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, \
|
||||
2561, 2562, 2563, 2564, 2565, 2566, 2567, 2568, 2569, 2570, \
|
||||
2571, 2572, 2573, 2574, 2575, 2576, 2577, 2578, 2579, 2580, \
|
||||
2581, 2582, 2583, 2584, 2585, 2586, 2587, 2588, 2589, 2590, \
|
||||
2591, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2600, \
|
||||
2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, \
|
||||
2611, 2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, \
|
||||
2621, 2622, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, \
|
||||
2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, \
|
||||
2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2650, \
|
||||
2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, \
|
||||
2661, 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, \
|
||||
2671, 2672, 2673, 2674, 2675, 2676, 2677, 2678, 2679, 2680, \
|
||||
2681, 2682, 2683, 2684, 2685, 2686, 2687, 2688, 2689, 2690, \
|
||||
2691, 2692, 2693, 2694, 2695, 2696, 2697, 2698, 2699, 2700, \
|
||||
2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2710, \
|
||||
2711, 2712, 2713, 2714, 2715, 2716, 2717, 2718, 2719, 2720, \
|
||||
2721, 2722, 2723, 2724, 2725, 2726, 2727, 2728, 2729, 2730, \
|
||||
2731, 2732, 2733, 2734, 2735, 2736, 2737, 2738, 2739, 2740, \
|
||||
2741, 2742, 2743, 2744, 2745, 2746, 2747, 2748, 2749, 2750, \
|
||||
2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2760, \
|
||||
2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, \
|
||||
2771, 2772, 2773, 2774, 2775, 2776, 2777, 2778, 2779, 2780, \
|
||||
2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, \
|
||||
2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2800, \
|
||||
2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, \
|
||||
2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, \
|
||||
2821, 2822, 2823, 2824, 2825, 2826, 2827, 2828, 2829, 2830, \
|
||||
2831, 2832, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, \
|
||||
2841, 2842, 2843, 2844, 2845, 2846, 2847, 2848, 2849, 2850, \
|
||||
2851, 2852, 2853, 2854, 2855, 2856, 2857, 2858, 2859, 2860, \
|
||||
2861, 2862, 2863, 2864, 2865, 2866, 2867, 2868, 2869, 2870, \
|
||||
2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, \
|
||||
2881, 2882, 2883, 2884, 2885, 2886, 2887, 2888, 2889, 2890, \
|
||||
2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, 2899, 2900, \
|
||||
2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909, 2910, \
|
||||
2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, \
|
||||
2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, \
|
||||
2931, 2932, 2933, 2934, 2935, 2936, 2937, 2938, 2939, 2940, \
|
||||
2941, 2942, 2943, 2944, 2945, 2946, 2947, 2948, 2949, 2950, \
|
||||
2951, 2952, 2953, 2954, 2955, 2956, 2957, 2958, 2959, 2960, \
|
||||
2961, 2962, 2963, 2964, 2965, 2966, 2967, 2968, 2969, 2970, \
|
||||
2971, 2972, 2973, 2974, 2975, 2976, 2977, 2978, 2979, 2980, \
|
||||
2981, 2982, 2983, 2984, 2985, 2986, 2987, 2988, 2989, 2990, \
|
||||
2991, 2992, 2993, 2994, 2995, 2996, 2997, 2998, 2999, 3000, \
|
||||
3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, \
|
||||
3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, 3020, \
|
||||
3021, 3022, 3023, 3024, 3025, 3026, 3027, 3028, 3029, 3030, \
|
||||
3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, \
|
||||
3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3050, \
|
||||
3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, \
|
||||
3061, 3062, 3063, 3064, 3065, 3066, 3067, 3068, 3069, 3070, \
|
||||
3071, 3072, 3073, 3074, 3075, 3076, 3077, 3078, 3079, 3080, \
|
||||
3081, 3082, 3083, 3084, 3085, 3086, 3087, 3088, 3089, 3090, \
|
||||
3091, 3092, 3093, 3094, 3095, 3096, 3097, 3098, 3099, 3100, \
|
||||
3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, \
|
||||
3111, 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, \
|
||||
3121, 3122, 3123, 3124, 3125, 3126, 3127, 3128, 3129, 3130, \
|
||||
3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, \
|
||||
3141, 3142, 3143, 3144, 3145, 3146, 3147, 3148, 3149, 3150, \
|
||||
3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, \
|
||||
3161, 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, \
|
||||
3171, 3172, 3173, 3174, 3175, 3176, 3177, 3178, 3179, 3180, \
|
||||
3181, 3182, 3183, 3184, 3185, 3186, 3187, 3188, 3189, 3190, \
|
||||
3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3199, 3200, \
|
||||
3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3210, \
|
||||
3211, 3212, 3213, 3214, 3215, 3216, 3217, 3218, 3219, 3220, \
|
||||
3221, 3222, 3223, 3224, 3225, 3226, 3227, 3228, 3229, 3230, \
|
||||
3231, 3232, 3233, 3234, 3235, 3236, 3237, 3238, 3239, 3240, \
|
||||
3241, 3242, 3243, 3244, 3245, 3246, 3247, 3248, 3249, 3250, \
|
||||
3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3260, \
|
||||
3261, 3262, 3263, 3264, 3265, 3266, 3267, 3268, 3269, 3270, \
|
||||
3271, 3272, 3273, 3274, 3275, 3276, 3277, 3278, 3279, 3280, \
|
||||
3281, 3282, 3283, 3284, 3285, 3286, 3287, 3288, 3289, 3290, \
|
||||
3291, 3292, 3293, 3294, 3295, 3296, 3297, 3298, 3299, 3300, \
|
||||
3301, 3302, 3303, 3304, 3305, 3306, 3307, 3308, 3309, 3310, \
|
||||
3311, 3312, 3313, 3314, 3315, 3316, 3317, 3318, 3319, 3320, \
|
||||
3321, 3322, 3323, 3324, 3325, 3326, 3327, 3328, 3329, 3330, \
|
||||
3331, 3332, 3333, 3334, 3335, 3336, 3337, 3338, 3339, 3340, \
|
||||
3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, 3350, \
|
||||
3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, \
|
||||
3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369, 3370, \
|
||||
3371, 3372, 3373, 3374, 3375, 3376, 3377, 3378, 3379, 3380, \
|
||||
3381, 3382, 3383, 3384, 3385, 3386, 3387, 3388, 3389, 3390, \
|
||||
3391, 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399, 3400, \
|
||||
3401, 3402, 3403, 3404, 3405, 3406, 3407, 3408, 3409, 3410, \
|
||||
3411, 3412, 3413, 3414, 3415, 3416, 3417, 3418, 3419, 3420, \
|
||||
3421, 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429, 3430, \
|
||||
3431, 3432, 3433, 3434, 3435, 3436, 3437, 3438, 3439, 3440, \
|
||||
3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448, 3449, 3450, \
|
||||
3451, 3452, 3453, 3454, 3455, 3456, 3457, 3458, 3459, 3460, \
|
||||
3461, 3462, 3463, 3464, 3465, 3466, 3467, 3468, 3469, 3470, \
|
||||
3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, 3479, 3480, \
|
||||
3481, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3489, 3490, \
|
||||
3491, 3492, 3493, 3494, 3495, 3496, 3497, 3498, 3499, 3500, \
|
||||
3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, \
|
||||
3511, 3512, 3513, 3514, 3515, 3516, 3517, 3518, 3519, 3520, \
|
||||
3521, 3522, 3523, 3524, 3525, 3526, 3527, 3528, 3529, 3530, \
|
||||
3531, 3532, 3533, 3534, 3535, 3536, 3537, 3538, 3539, 3540, \
|
||||
3541, 3542, 3543, 3544, 3545, 3546, 3547, 3548, 3549, 3550, \
|
||||
3551, 3552, 3553, 3554, 3555, 3556, 3557, 3558, 3559, 3560, \
|
||||
3561, 3562, 3563, 3564, 3565, 3566, 3567, 3568, 3569, 3570, \
|
||||
3571, 3572, 3573, 3574, 3575, 3576, 3577, 3578, 3579, 3580, \
|
||||
3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, \
|
||||
3591, 3592, 3593, 3594, 3595, 3596, 3597, 3598, 3599, 3600, \
|
||||
3601, 3602, 3603, 3604, 3605, 3606, 3607, 3608, 3609, 3610, \
|
||||
3611, 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3619, 3620, \
|
||||
3621, 3622, 3623, 3624, 3625, 3626, 3627, 3628, 3629, 3630, \
|
||||
3631, 3632, 3633, 3634, 3635, 3636, 3637, 3638, 3639, 3640, \
|
||||
3641, 3642, 3643, 3644, 3645, 3646, 3647, 3648, 3649, 3650, \
|
||||
3651, 3652, 3653, 3654, 3655, 3656, 3657, 3658, 3659, 3660, \
|
||||
3661, 3662, 3663, 3664, 3665, 3666, 3667, 3668, 3669, 3670, \
|
||||
3671, 3672, 3673, 3674, 3675, 3676, 3677, 3678, 3679, 3680, \
|
||||
3681, 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, 3690, \
|
||||
3691, 3692, 3693, 3694, 3695, 3696, 3697, 3698, 3699, 3700, \
|
||||
3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710, \
|
||||
3711, 3712, 3713, 3714, 3715, 3716, 3717, 3718, 3719, 3720, \
|
||||
3721, 3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729, 3730, \
|
||||
3731, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, \
|
||||
3741, 3742, 3743, 3744, 3745, 3746, 3747, 3748, 3749, 3750, \
|
||||
3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3760, \
|
||||
3761, 3762, 3763, 3764, 3765, 3766, 3767, 3768, 3769, 3770, \
|
||||
3771, 3772, 3773, 3774, 3775, 3776, 3777, 3778, 3779, 3780, \
|
||||
3781, 3782, 3783, 3784, 3785, 3786, 3787, 3788, 3789, 3790, \
|
||||
3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, 3800, \
|
||||
3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, \
|
||||
3811, 3812, 3813, 3814, 3815, 3816, 3817, 3818, 3819, 3820, \
|
||||
3821, 3822, 3823, 3824, 3825, 3826, 3827, 3828, 3829, 3830, \
|
||||
3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, \
|
||||
3841, 3842, 3843, 3844, 3845, 3846, 3847, 3848, 3849, 3850, \
|
||||
3851, 3852, 3853, 3854, 3855, 3856, 3857, 3858, 3859, 3860, \
|
||||
3861, 3862, 3863, 3864, 3865, 3866, 3867, 3868, 3869, 3870, \
|
||||
3871, 3872, 3873, 3874, 3875, 3876, 3877, 3878, 3879, 3880, \
|
||||
3881, 3882, 3883, 3884, 3885, 3886, 3887, 3888, 3889, 3890, \
|
||||
3891, 3892, 3893, 3894, 3895, 3896, 3897, 3898, 3899, 3900, \
|
||||
3901, 3902, 3903, 3904, 3905, 3906, 3907, 3908, 3909, 3910, \
|
||||
3911, 3912, 3913, 3914, 3915, 3916, 3917, 3918, 3919, 3920, \
|
||||
3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, \
|
||||
3931, 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3939, 3940, \
|
||||
3941, 3942, 3943, 3944, 3945, 3946, 3947, 3948, 3949, 3950, \
|
||||
3951, 3952, 3953, 3954, 3955, 3956, 3957, 3958, 3959, 3960, \
|
||||
3961, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, \
|
||||
3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3980, \
|
||||
3981, 3982, 3983, 3984, 3985, 3986, 3987, 3988, 3989, 3990, \
|
||||
3991, 3992, 3993, 3994, 3995, 3996, 3997, 3998, 3999, 4000, \
|
||||
4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, 4010, \
|
||||
4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, \
|
||||
4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, \
|
||||
4031, 4032, 4033, 4034, 4035, 4036, 4037, 4038, 4039, 4040, \
|
||||
4041, 4042, 4043, 4044, 4045, 4046, 4047, 4048, 4049, 4050, \
|
||||
4051, 4052, 4053, 4054, 4055, 4056, 4057, 4058, 4059, 4060, \
|
||||
4061, 4062, 4063, 4064, 4065, 4066, 4067, 4068, 4069, 4070, \
|
||||
4071, 4072, 4073, 4074, 4075, 4076, 4077, 4078, 4079, 4080, \
|
||||
4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, \
|
||||
4091, 4092, 4093, 4094, 4095, 4096, 4097, 4098, 4099, 4100, \
|
||||
4101, 4102, 4103, 4104, 4105, 4106, 4107, 4108, 4109, 4110, \
|
||||
4111, 4112, 4113, 4114, 4115, 4116, 4117, 4118, 4119, 4120, \
|
||||
4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, \
|
||||
4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, \
|
||||
4141, 4142, 4143, 4144, 4145, 4146, 4147, 4148, 4149, 4150, \
|
||||
4151, 4152, 4153, 4154, 4155, 4156, 4157, 4158, 4159, 4160, \
|
||||
4161, 4162, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, \
|
||||
4171, 4172, 4173, 4174, 4175, 4176, 4177, 4178, 4179, 4180, \
|
||||
4181, 4182, 4183, 4184, 4185, 4186, 4187, 4188, 4189, 4190, \
|
||||
4191, 4192, 4193, 4194, 4195, 4196, 4197, 4198, 4199, 4200, \
|
||||
4201, 4202, 4203, 4204, 4205, 4206, 4207, 4208, 4209, 4210, \
|
||||
4211, 4212, 4213, 4214, 4215, 4216, 4217, 4218, 4219, 4220, \
|
||||
4221, 4222, 4223, 4224, 4225, 4226, 4227, 4228, 4229, 4230, \
|
||||
4231, 4232, 4233, 4234, 4235, 4236, 4237, 4238, 4239, 4240, \
|
||||
4241, 4242, 4243, 4244, 4245, 4246, 4247, 4248, 4249, 4250, \
|
||||
4251, 4252, 4253, 4254, 4255, 4256, 4257, 4258, 4259, 4260, \
|
||||
4261, 4262, 4263, 4264, 4265, 4266, 4267, 4268, 4269, 4270, \
|
||||
4271, 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, 4280, \
|
||||
4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, \
|
||||
4291, 4292, 4293, 4294, 4295, 4296, 4297, 4298, 4299, 4300, \
|
||||
4301, 4302, 4303, 4304, 4305, 4306, 4307, 4308, 4309, 4310, \
|
||||
4311, 4312, 4313, 4314, 4315, 4316, 4317, 4318, 4319, 4320, \
|
||||
4321, 4322, 4323, 4324, 4325, 4326, 4327, 4328, 4329, 4330, \
|
||||
4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, 4339, 4340, \
|
||||
4341, 4342, 4343, 4344, 4345, 4346, 4347, 4348, 4349, 4350, \
|
||||
4351, 4352, 4353, 4354, 4355, 4356, 4357, 4358, 4359, 4360, \
|
||||
4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, \
|
||||
4371, 4372, 4373, 4374, 4375, 4376, 4377, 4378, 4379, 4380, \
|
||||
4381, 4382, 4383, 4384, 4385, 4386, 4387, 4388, 4389, 4390, \
|
||||
4391, 4392, 4393, 4394, 4395, 4396, 4397, 4398, 4399, 4400, \
|
||||
4401, 4402, 4403, 4404, 4405, 4406, 4407, 4408, 4409, 4410, \
|
||||
4411, 4412, 4413, 4414, 4415, 4416, 4417, 4418, 4419, 4420, \
|
||||
4421, 4422, 4423, 4424, 4425, 4426, 4427, 4428, 4429, 4430, \
|
||||
4431, 4432, 4433, 4434, 4435, 4436, 4437, 4438, 4439, 4440, \
|
||||
4441, 4442, 4443, 4444, 4445, 4446, 4447, 4448, 4449, 4450, \
|
||||
4451, 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460, \
|
||||
4461, 4462, 4463, 4464, 4465, 4466, 4467, 4468, 4469, 4470, \
|
||||
4471, 4472, 4473, 4474, 4475, 4476, 4477, 4478, 4479, 4480, \
|
||||
4481, 4482, 4483, 4484, 4485, 4486, 4487, 4488, 4489, 4490, \
|
||||
4491, 4492, 4493, 4494, 4495, 4496, 4497, 4498, 4499, 4500, \
|
||||
4501, 4502, 4503, 4504, 4505, 4506, 4507, 4508, 4509, 4510, \
|
||||
4511, 4512, 4513, 4514, 4515, 4516, 4517, 4518, 4519, 4520, \
|
||||
4521, 4522, 4523, 4524, 4525, 4526, 4527, 4528, 4529, 4530, \
|
||||
4531, 4532, 4533, 4534, 4535, 4536, 4537, 4538, 4539, 4540, \
|
||||
4541, 4542, 4543, 4544, 4545, 4546, 4547, 4548, 4549, 4550, \
|
||||
4551, 4552, 4553, 4554, 4555, 4556, 4557, 4558, 4559, 4560, \
|
||||
4561, 4562, 4563, 4564, 4565, 4566, 4567, 4568, 4569, 4570, \
|
||||
4571, 4572, 4573, 4574, 4575, 4576, 4577, 4578, 4579, 4580, \
|
||||
4581, 4582, 4583, 4584, 4585, 4586, 4587, 4588, 4589, 4590, \
|
||||
4591, 4592, 4593, 4594, 4595, 4596, 4597, 4598, 4599, 4600, \
|
||||
4601, 4602, 4603, 4604, 4605, 4606, 4607, 4608, 4609, 4610, \
|
||||
4611, 4612, 4613, 4614, 4615, 4616, 4617, 4618, 4619, 4620, \
|
||||
4621, 4622, 4623, 4624, 4625, 4626, 4627, 4628, 4629, 4630, \
|
||||
4631, 4632, 4633, 4634, 4635, 4636, 4637, 4638, 4639, 4640, \
|
||||
4641, 4642, 4643, 4644, 4645, 4646, 4647, 4648, 4649, 4650, \
|
||||
4651, 4652, 4653, 4654, 4655, 4656, 4657, 4658, 4659, 4660, \
|
||||
4661, 4662, 4663, 4664, 4665, 4666, 4667, 4668, 4669, 4670, \
|
||||
4671, 4672, 4673, 4674, 4675, 4676, 4677, 4678, 4679, 4680, \
|
||||
4681, 4682, 4683, 4684, 4685, 4686, 4687, 4688, 4689, 4690, \
|
||||
4691, 4692, 4693, 4694, 4695, 4696, 4697, 4698, 4699, 4700, \
|
||||
4701, 4702, 4703, 4704, 4705, 4706, 4707, 4708, 4709, 4710, \
|
||||
4711, 4712, 4713, 4714, 4715, 4716, 4717, 4718, 4719, 4720, \
|
||||
4721, 4722, 4723, 4724, 4725, 4726, 4727, 4728, 4729, 4730, \
|
||||
4731, 4732, 4733, 4734, 4735, 4736, 4737, 4738, 4739, 4740, \
|
||||
4741, 4742, 4743, 4744, 4745, 4746, 4747, 4748, 4749, 4750, \
|
||||
4751, 4752, 4753, 4754, 4755, 4756, 4757, 4758, 4759, 4760, \
|
||||
4761, 4762, 4763, 4764, 4765, 4766, 4767, 4768, 4769, 4770, \
|
||||
4771, 4772, 4773, 4774, 4775, 4776, 4777, 4778, 4779, 4780, \
|
||||
4781, 4782, 4783, 4784, 4785, 4786, 4787, 4788, 4789, 4790, \
|
||||
4791, 4792, 4793, 4794, 4795, 4796, 4797, 4798, 4799, 4800, \
|
||||
4801, 4802, 4803, 4804, 4805, 4806, 4807, 4808, 4809, 4810, \
|
||||
4811, 4812, 4813, 4814, 4815, 4816, 4817, 4818, 4819, 4820, \
|
||||
4821, 4822, 4823, 4824, 4825, 4826, 4827, 4828, 4829, 4830, \
|
||||
4831, 4832, 4833, 4834, 4835, 4836, 4837, 4838, 4839, 4840, \
|
||||
4841, 4842, 4843, 4844, 4845, 4846, 4847, 4848, 4849, 4850, \
|
||||
4851, 4852, 4853, 4854, 4855, 4856, 4857, 4858, 4859, 4860, \
|
||||
4861, 4862, 4863, 4864, 4865, 4866, 4867, 4868, 4869, 4870, \
|
||||
4871, 4872, 4873, 4874, 4875, 4876, 4877, 4878, 4879, 4880, \
|
||||
4881, 4882, 4883, 4884, 4885, 4886, 4887, 4888, 4889, 4890, \
|
||||
4891, 4892, 4893, 4894, 4895, 4896, 4897, 4898, 4899, 4900, \
|
||||
4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, 4910, \
|
||||
4911, 4912, 4913, 4914, 4915, 4916, 4917, 4918, 4919, 4920, \
|
||||
4921, 4922, 4923, 4924, 4925, 4926, 4927, 4928, 4929, 4930, \
|
||||
4931, 4932, 4933, 4934, 4935, 4936, 4937, 4938, 4939, 4940, \
|
||||
4941, 4942, 4943, 4944, 4945, 4946, 4947, 4948, 4949, 4950, \
|
||||
4951, 4952, 4953, 4954, 4955, 4956, 4957, 4958, 4959, 4960, \
|
||||
4961, 4962, 4963, 4964, 4965, 4966, 4967, 4968, 4969, 4970, \
|
||||
4971, 4972, 4973, 4974, 4975, 4976, 4977, 4978, 4979, 4980, \
|
||||
4981, 4982, 4983, 4984, 4985, 4986, 4987, 4988, 4989, 4990, \
|
||||
4991, 4992, 4993, 4994, 4995, 4996, 4997, 4998, 4999, 5000, \
|
||||
5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, \
|
||||
5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, \
|
||||
5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, 5030, \
|
||||
5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040, \
|
||||
5041, 5042, 5043, 5044, 5045, 5046, 5047, 5048, 5049, 5050, \
|
||||
5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, 5060, \
|
||||
5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, \
|
||||
5071, 5072, 5073, 5074, 5075, 5076, 5077, 5078, 5079, 5080, \
|
||||
5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, 5089, 5090, \
|
||||
5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, 5100, \
|
||||
5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108, 5109, 5110, \
|
||||
5111, 5112, 5113, 5114, 5115, 5116, 5117, 5118, 5119, 5120, \
|
||||
5121, 5122, 5123, 5124, 5125, 5126, 5127, 5128, 5129, 5130, \
|
||||
5131, 5132, 5133, 5134, 5135, 5136, 5137, 5138, 5139, 5140, \
|
||||
5141, 5142, 5143, 5144, 5145, 5146, 5147, 5148, 5149, 5150, \
|
||||
5151, 5152, 5153, 5154, 5155, 5156, 5157, 5158, 5159, 5160, \
|
||||
5161, 5162, 5163, 5164, 5165, 5166, 5167, 5168, 5169, 5170, \
|
||||
5171, 5172, 5173, 5174, 5175, 5176, 5177, 5178, 5179, 5180, \
|
||||
5181, 5182, 5183, 5184, 5185, 5186, 5187, 5188, 5189, 5190, \
|
||||
5191, 5192, 5193, 5194, 5195, 5196, 5197, 5198, 5199, 5200, \
|
||||
5201, 5202, 5203, 5204, 5205, 5206, 5207, 5208, 5209, 5210, \
|
||||
5211, 5212, 5213, 5214, 5215, 5216, 5217, 5218, 5219, 5220, \
|
||||
5221, 5222, 5223, 5224, 5225, 5226, 5227, 5228, 5229, 5230, \
|
||||
5231, 5232, 5233, 5234, 5235, 5236, 5237, 5238, 5239, 5240, \
|
||||
5241, 5242, 5243, 5244, 5245, 5246, 5247, 5248, 5249, 5250, \
|
||||
5251, 5252, 5253, 5254, 5255, 5256, 5257, 5258, 5259, 5260, \
|
||||
5261, 5262, 5263, 5264, 5265, 5266, 5267, 5268, 5269, 5270, \
|
||||
5271, 5272, 5273, 5274, 5275, 5276, 5277, 5278, 5279, 5280, \
|
||||
5281, 5282, 5283, 5284, 5285, 5286, 5287, 5288, 5289, 5290, \
|
||||
5291, 5292, 5293, 5294, 5295, 5296, 5297, 5298, 5299, 5300, \
|
||||
5301, 5302, 5303, 5304, 5305, 5306, 5307, 5308, 5309, 5310, \
|
||||
5311, 5312, 5313, 5314, 5315, 5316, 5317, 5318, 5319, 5320, \
|
||||
5321, 5322, 5323, 5324, 5325, 5326, 5327, 5328, 5329, 5330, \
|
||||
5331, 5332, 5333, 5334, 5335, 5336, 5337, 5338, 5339, 5340, \
|
||||
5341, 5342, 5343, 5344, 5345, 5346, 5347, 5348, 5349, 5350, \
|
||||
5351, 5352, 5353, 5354, 5355, 5356, 5357, 5358, 5359, 5360, \
|
||||
5361, 5362, 5363, 5364, 5365, 5366, 5367, 5368, 5369, 5370, \
|
||||
5371, 5372, 5373, 5374, 5375, 5376, 5377, 5378, 5379, 5380, \
|
||||
5381, 5382, 5383, 5384, 5385, 5386, 5387, 5388, 5389, 5390, \
|
||||
5391, 5392, 5393, 5394, 5395, 5396, 5397, 5398, 5399, 5400, \
|
||||
5401, 5402, 5403, 5404, 5405, 5406, 5407, 5408, 5409, 5410, \
|
||||
5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, \
|
||||
5421, 5422, 5423, 5424, 5425, 5426, 5427, 5428, 5429, 5430, \
|
||||
5431, 5432, 5433, 5434, 5435, 5436, 5437, 5438, 5439, 5440, \
|
||||
5441, 5442, 5443, 5444, 5445, 5446, 5447, 5448, 5449, 5450, \
|
||||
5451, 5452, 5453, 5454, 5455, 5456, 5457, 5458, 5459, 5460, \
|
||||
5461, 5462, 5463, 5464, 5465, 5466, 5467, 5468, 5469, 5470, \
|
||||
5471, 5472, 5473, 5474, 5475, 5476, 5477, 5478, 5479, 5480, \
|
||||
5481, 5482, 5483, 5484, 5485, 5486, 5487, 5488, 5489, 5490, \
|
||||
5491, 5492, 5493, 5494, 5495, 5496, 5497, 5498, 5499, 5500, \
|
||||
5501, 5502, 5503, 5504, 5505, 5506, 5507, 5508, 5509, 5510, \
|
||||
5511, 5512, 5513, 5514, 5515, 5516, 5517, 5518, 5519, 5520, \
|
||||
5521, 5522, 5523, 5524, 5525, 5526, 5527, 5528, 5529, 5530, \
|
||||
5531, 5532, 5533, 5534, 5535, 5536, 5537, 5538, 5539, 5540, \
|
||||
5541, 5542, 5543, 5544, 5545, 5546, 5547, 5548, 5549, 5550, \
|
||||
5551, 5552, 5553, 5554, 5555, 5556, 5557, 5558, 5559, 5560, \
|
||||
5561, 5562, 5563, 5564, 5565, 5566, 5567, 5568, 5569, 5570, \
|
||||
5571, 5572, 5573, 5574, 5575, 5576, 5577, 5578, 5579, 5580, \
|
||||
5581, 5582, 5583, 5584, 5585, 5586, 5587, 5588, 5589, 5590, \
|
||||
5591, 5592, 5593, 5594, 5595, 5596, 5597, 5598, 5599, 5600, \
|
||||
5601, 5602, 5603, 5604, 5605, 5606, 5607, 5608, 5609, 5610, \
|
||||
5611, 5612, 5613, 5614, 5615, 5616, 5617, 5618, 5619, 5620, \
|
||||
5621, 5622, 5623, 5624, 5625, 5626, 5627, 5628, 5629, 5630, \
|
||||
5631, 5632, 5633, 5634, 5635, 5636, 5637, 5638, 5639, 5640, \
|
||||
5641, 5642, 5643, 5644, 5645, 5646, 5647, 5648, 5649, 5650, \
|
||||
5651, 5652, 5653, 5654, 5655, 5656, 5657, 5658, 5659, 5660, \
|
||||
5661, 5662, 5663, 5664, 5665, 5666, 5667, 5668, 5669, 5670, \
|
||||
5671, 5672, 5673, 5674, 5675, 5676, 5677, 5678, 5679, 5680, \
|
||||
5681, 5682, 5683, 5684, 5685, 5686, 5687, 5688, 5689, 5690, \
|
||||
5691, 5692, 5693, 5694, 5695, 5696, 5697, 5698, 5699, 5700, \
|
||||
5701, 5702, 5703, 5704, 5705, 5706, 5707, 5708, 5709, 5710, \
|
||||
5711, 5712, 5713, 5714, 5715, 5716, 5717, 5718, 5719, 5720, \
|
||||
5721, 5722, 5723, 5724, 5725, 5726, 5727, 5728, 5729, 5730, \
|
||||
5731, 5732, 5733, 5734, 5735, 5736, 5737, 5738, 5739, 5740, \
|
||||
5741, 5742, 5743, 5744, 5745, 5746, 5747, 5748, 5749, 5750, \
|
||||
5751, 5752, 5753, 5754, 5755, 5756, 5757, 5758, 5759, 5760, \
|
||||
5761, 5762, 5763, 5764, 5765, 5766, 5767, 5768, 5769, 5770, \
|
||||
5771, 5772, 5773, 5774, 5775, 5776, 5777, 5778, 5779, 5780, \
|
||||
5781, 5782, 5783, 5784, 5785, 5786, 5787, 5788, 5789, 5790, \
|
||||
5791, 5792, 5793, 5794, 5795, 5796, 5797, 5798, 5799, 5800, \
|
||||
5801, 5802, 5803, 5804, 5805, 5806, 5807, 5808, 5809, 5810, \
|
||||
5811, 5812, 5813, 5814, 5815, 5816, 5817, 5818, 5819, 5820, \
|
||||
5821, 5822, 5823, 5824, 5825, 5826, 5827, 5828, 5829, 5830, \
|
||||
5831, 5832, 5833, 5834, 5835, 5836, 5837, 5838, 5839, 5840, \
|
||||
5841, 5842, 5843, 5844, 5845, 5846, 5847, 5848, 5849, 5850, \
|
||||
5851, 5852, 5853, 5854, 5855, 5856, 5857, 5858, 5859, 5860, \
|
||||
5861, 5862, 5863, 5864, 5865, 5866, 5867, 5868, 5869, 5870, \
|
||||
5871, 5872, 5873, 5874, 5875, 5876, 5877, 5878, 5879, 5880, \
|
||||
5881, 5882, 5883, 5884, 5885, 5886, 5887, 5888, 5889, 5890, \
|
||||
5891, 5892, 5893, 5894, 5895, 5896, 5897, 5898, 5899, 5900, \
|
||||
5901, 5902, 5903, 5904, 5905, 5906, 5907, 5908, 5909, 5910, \
|
||||
5911, 5912, 5913, 5914, 5915, 5916, 5917, 5918, 5919, 5920, \
|
||||
5921, 5922, 5923, 5924, 5925, 5926, 5927, 5928, 5929, 5930, \
|
||||
5931, 5932, 5933, 5934, 5935, 5936, 5937, 5938, 5939, 5940, \
|
||||
5941, 5942, 5943, 5944, 5945, 5946, 5947, 5948, 5949, 5950, \
|
||||
5951, 5952, 5953, 5954, 5955, 5956, 5957, 5958, 5959, 5960, \
|
||||
5961, 5962, 5963, 5964, 5965, 5966, 5967, 5968, 5969, 5970, \
|
||||
5971, 5972, 5973, 5974, 5975, 5976, 5977, 5978, 5979, 5980, \
|
||||
5981, 5982, 5983, 5984, 5985, 5986, 5987, 5988, 5989, 5990, \
|
||||
5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999, 6000, \
|
||||
6001, 6002, 6003, 6004, 6005, 6006, 6007, 6008, 6009, 6010, \
|
||||
6011, 6012, 6013, 6014, 6015, 6016, 6017, 6018, 6019, 6020, \
|
||||
6021, 6022, 6023, 6024, 6025, 6026, 6027, 6028, 6029, 6030, \
|
||||
6031, 6032, 6033, 6034, 6035, 6036, 6037, 6038, 6039, 6040, \
|
||||
6041, 6042, 6043, 6044, 6045, 6046, 6047, 6048, 6049, 6050, \
|
||||
6051, 6052, 6053, 6054, 6055, 6056, 6057, 6058, 6059, 6060, \
|
||||
6061, 6062, 6063, 6064, 6065, 6066, 6067, 6068, 6069, 6070, \
|
||||
6071, 6072, 6073, 6074, 6075, 6076, 6077, 6078, 6079, 6080, \
|
||||
6081, 6082, 6083, 6084, 6085, 6086, 6087, 6088, 6089, 6090, \
|
||||
6091, 6092, 6093, 6094, 6095, 6096, 6097, 6098, 6099, 6100, \
|
||||
6101, 6102, 6103, 6104, 6105, 6106, 6107, 6108, 6109, 6110, \
|
||||
6111, 6112, 6113, 6114, 6115, 6116, 6117, 6118, 6119, 6120, \
|
||||
6121, 6122, 6123, 6124, 6125, 6126, 6127, 6128, 6129, 6130, \
|
||||
6131, 6132, 6133, 6134, 6135, 6136, 6137, 6138, 6139, 6140, \
|
||||
6141, 6142, 6143, 6144, 6145, 6146, 6147, 6148, 6149, 6150, \
|
||||
6151, 6152, 6153, 6154, 6155, 6156, 6157, 6158, 6159, 6160, \
|
||||
6161, 6162, 6163, 6164, 6165, 6166, 6167, 6168, 6169, 6170, \
|
||||
6171, 6172, 6173, 6174, 6175, 6176, 6177, 6178, 6179, 6180, \
|
||||
6181, 6182, 6183, 6184, 6185, 6186, 6187, 6188, 6189, 6190, \
|
||||
6191, 6192, 6193, 6194, 6195, 6196, 6197, 6198, 6199, 6200, \
|
||||
6201, 6202, 6203, 6204, 6205, 6206, 6207, 6208, 6209, 6210, \
|
||||
6211, 6212, 6213, 6214, 6215, 6216, 6217, 6218, 6219, 6220, \
|
||||
6221, 6222, 6223, 6224, 6225, 6226, 6227, 6228, 6229, 6230, \
|
||||
6231, 6232, 6233, 6234, 6235, 6236, 6237, 6238, 6239, 6240, \
|
||||
6241, 6242, 6243, 6244, 6245, 6246, 6247, 6248, 6249, 6250, \
|
||||
6251, 6252, 6253, 6254, 6255, 6256, 6257, 6258, 6259, 6260, \
|
||||
6261, 6262, 6263, 6264, 6265, 6266, 6267, 6268, 6269, 6270, \
|
||||
6271, 6272, 6273, 6274, 6275, 6276, 6277, 6278, 6279, 6280, \
|
||||
6281, 6282, 6283, 6284, 6285, 6286, 6287, 6288, 6289, 6290, \
|
||||
6291, 6292, 6293, 6294, 6295, 6296, 6297, 6298, 6299, 6300, \
|
||||
6301, 6302, 6303, 6304, 6305, 6306, 6307, 6308, 6309, 6310, \
|
||||
6311, 6312, 6313, 6314, 6315, 6316, 6317, 6318, 6319, 6320, \
|
||||
6321, 6322, 6323, 6324, 6325, 6326, 6327, 6328, 6329, 6330, \
|
||||
6331, 6332, 6333, 6334, 6335, 6336, 6337, 6338, 6339, 6340, \
|
||||
6341, 6342, 6343, 6344, 6345, 6346, 6347, 6348, 6349, 6350, \
|
||||
6351, 6352, 6353, 6354, 6355, 6356, 6357, 6358, 6359, 6360, \
|
||||
6361, 6362, 6363, 6364, 6365, 6366, 6367, 6368, 6369, 6370, \
|
||||
6371, 6372, 6373, 6374, 6375, 6376, 6377, 6378, 6379, 6380, \
|
||||
6381, 6382, 6383, 6384, 6385, 6386, 6387, 6388, 6389, 6390, \
|
||||
6391, 6392, 6393, 6394, 6395, 6396, 6397, 6398, 6399, 6400, \
|
||||
6401, 6402, 6403, 6404, 6405, 6406, 6407, 6408, 6409, 6410, \
|
||||
6411, 6412, 6413, 6414, 6415, 6416, 6417, 6418, 6419, 6420, \
|
||||
6421, 6422, 6423, 6424, 6425, 6426, 6427, 6428, 6429, 6430, \
|
||||
6431, 6432, 6433, 6434, 6435, 6436, 6437, 6438, 6439, 6440, \
|
||||
6441, 6442, 6443, 6444, 6445, 6446, 6447, 6448, 6449, 6450, \
|
||||
6451, 6452, 6453, 6454, 6455, 6456, 6457, 6458, 6459, 6460, \
|
||||
6461, 6462, 6463, 6464, 6465, 6466, 6467, 6468, 6469, 6470, \
|
||||
6471, 6472, 6473, 6474, 6475, 6476, 6477, 6478, 6479, 6480, \
|
||||
6481, 6482, 6483, 6484, 6485, 6486, 6487, 6488, 6489, 6490, \
|
||||
6491, 6492, 6493, 6494, 6495, 6496, 6497, 6498, 6499, 6500, \
|
||||
6501, 6502, 6503, 6504, 6505, 6506, 6507, 6508, 6509, 6510, \
|
||||
6511, 6512, 6513, 6514, 6515, 6516, 6517, 6518, 6519, 6520, \
|
||||
6521, 6522, 6523, 6524, 6525, 6526, 6527, 6528, 6529, 6530, \
|
||||
6531, 6532, 6533, 6534, 6535, 6536, 6537, 6538, 6539, 6540, \
|
||||
6541, 6542, 6543, 6544, 6545, 6546, 6547, 6548, 6549, 6550, \
|
||||
6551, 6552, 6553, 6554, 6555, 6556, 6557, 6558, 6559, 6560, \
|
||||
6561, 6562, 6563, 6564, 6565, 6566, 6567, 6568, 6569, 6570, \
|
||||
6571, 6572, 6573, 6574, 6575, 6576, 6577, 6578, 6579, 6580, \
|
||||
6581, 6582, 6583, 6584, 6585, 6586, 6587, 6588, 6589, 6590, \
|
||||
6591, 6592, 6593, 6594, 6595, 6596, 6597, 6598, 6599, 6600, \
|
||||
6601, 6602, 6603, 6604, 6605, 6606, 6607, 6608, 6609, 6610, \
|
||||
6611, 6612, 6613, 6614, 6615, 6616, 6617, 6618, 6619, 6620, \
|
||||
6621, 6622, 6623, 6624, 6625, 6626, 6627, 6628, 6629, 6630, \
|
||||
6631, 6632, 6633, 6634, 6635, 6636, 6637, 6638, 6639, 6640, \
|
||||
6641, 6642, 6643, 6644, 6645, 6646, 6647, 6648, 6649, 6650, \
|
||||
6651, 6652, 6653, 6654, 6655, 6656, 6657, 6658, 6659, 6660, \
|
||||
6661, 6662, 6663, 6664, 6665, 6666, 6667, 6668, 6669, 6670, \
|
||||
6671, 6672, 6673, 6674, 6675, 6676, 6677, 6678, 6679, 6680, \
|
||||
6681, 6682, 6683, 6684, 6685, 6686, 6687, 6688, 6689, 6690, \
|
||||
6691, 6692, 6693, 6694, 6695, 6696, 6697, 6698, 6699, 6700, \
|
||||
6701, 6702, 6703, 6704, 6705, 6706, 6707, 6708, 6709, 6710, \
|
||||
6711, 6712, 6713, 6714, 6715, 6716, 6717, 6718, 6719, 6720, \
|
||||
6721, 6722, 6723, 6724, 6725, 6726, 6727, 6728, 6729, 6730, \
|
||||
6731, 6732, 6733, 6734, 6735, 6736, 6737, 6738, 6739, 6740, \
|
||||
6741, 6742, 6743, 6744, 6745, 6746, 6747, 6748, 6749, 6750, \
|
||||
6751, 6752, 6753, 6754, 6755, 6756, 6757, 6758, 6759, 6760, \
|
||||
6761, 6762, 6763, 6764, 6765, 6766, 6767, 6768, 6769, 6770, \
|
||||
6771, 6772, 6773, 6774, 6775, 6776, 6777, 6778, 6779, 6780, \
|
||||
6781, 6782, 6783, 6784, 6785, 6786, 6787, 6788, 6789, 6790, \
|
||||
6791, 6792, 6793, 6794, 6795, 6796, 6797, 6798, 6799, 6800, \
|
||||
6801, 6802, 6803, 6804, 6805, 6806, 6807, 6808, 6809, 6810, \
|
||||
6811, 6812, 6813, 6814, 6815, 6816, 6817, 6818, 6819, 6820, \
|
||||
6821, 6822, 6823, 6824, 6825, 6826, 6827, 6828, 6829, 6830, \
|
||||
6831, 6832, 6833, 6834, 6835, 6836, 6837, 6838, 6839, 6840, \
|
||||
6841, 6842, 6843, 6844, 6845, 6846, 6847, 6848, 6849, 6850, \
|
||||
6851, 6852, 6853, 6854, 6855, 6856, 6857, 6858, 6859, 6860, \
|
||||
6861, 6862, 6863, 6864, 6865, 6866, 6867, 6868, 6869, 6870, \
|
||||
6871, 6872, 6873, 6874, 6875, 6876, 6877, 6878, 6879, 6880, \
|
||||
6881, 6882, 6883, 6884, 6885, 6886, 6887, 6888, 6889, 6890, \
|
||||
6891, 6892, 6893, 6894, 6895, 6896, 6897, 6898, 6899, 6900, \
|
||||
6901, 6902, 6903, 6904, 6905, 6906, 6907, 6908, 6909, 6910, \
|
||||
6911, 6912, 6913, 6914, 6915, 6916, 6917, 6918, 6919, 6920, \
|
||||
6921, 6922, 6923, 6924, 6925, 6926, 6927, 6928, 6929, 6930, \
|
||||
6931, 6932, 6933, 6934, 6935, 6936, 6937, 6938, 6939, 6940, \
|
||||
6941, 6942, 6943, 6944, 6945, 6946, 6947, 6948, 6949, 6950, \
|
||||
6951, 6952, 6953, 6954, 6955, 6956, 6957, 6958, 6959, 6960, \
|
||||
6961, 6962, 6963, 6964, 6965, 6966, 6967, 6968, 6969, 6970, \
|
||||
6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978, 6979, 6980, \
|
||||
6981, 6982, 6983, 6984, 6985, 6986, 6987, 6988, 6989, 6990, \
|
||||
6991, 6992, 6993, 6994, 6995, 6996, 6997, 6998, 6999, 7000, \
|
||||
7001, 7002, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, \
|
||||
7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, 7020, \
|
||||
7021, 7022, 7023, 7024, 7025, 7026, 7027, 7028, 7029, 7030, \
|
||||
7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038, 7039, 7040, \
|
||||
7041, 7042, 7043, 7044, 7045, 7046, 7047, 7048, 7049, 7050, \
|
||||
7051, 7052, 7053, 7054, 7055, 7056, 7057, 7058, 7059, 7060, \
|
||||
7061, 7062, 7063, 7064, 7065, 7066, 7067, 7068, 7069, 7070, \
|
||||
7071, 7072, 7073, 7074, 7075, 7076, 7077, 7078, 7079, 7080, \
|
||||
7081, 7082, 7083, 7084, 7085, 7086, 7087, 7088, 7089, 7090, \
|
||||
7091, 7092, 7093, 7094, 7095, 7096, 7097, 7098, 7099, 7100, \
|
||||
7101, 7102, 7103, 7104, 7105, 7106, 7107, 7108, 7109, 7110, \
|
||||
7111, 7112, 7113, 7114, 7115, 7116, 7117, 7118, 7119, 7120, \
|
||||
7121, 7122, 7123, 7124, 7125, 7126, 7127, 7128, 7129, 7130, \
|
||||
7131, 7132, 7133, 7134, 7135, 7136, 7137, 7138, 7139, 7140, \
|
||||
7141, 7142, 7143, 7144, 7145, 7146, 7147, 7148, 7149, 7150, \
|
||||
7151, 7152, 7153, 7154, 7155, 7156, 7157, 7158, 7159, 7160, \
|
||||
7161, 7162, 7163, 7164, 7165, 7166, 7167, 7168, 7169, 7170, \
|
||||
7171, 7172, 7173, 7174, 7175, 7176, 7177, 7178, 7179, 7180, \
|
||||
7181, 7182, 7183, 7184, 7185, 7186, 7187, 7188, 7189, 7190, \
|
||||
7191, 7192, 7193, 7194, 7195, 7196, 7197, 7198, 7199, 7200, \
|
||||
7201, 7202, 7203, 7204, 7205, 7206, 7207, 7208, 7209, 7210, \
|
||||
7211, 7212, 7213, 7214, 7215, 7216, 7217, 7218, 7219, 7220, \
|
||||
7221, 7222, 7223, 7224, 7225, 7226, 7227, 7228, 7229, 7230, \
|
||||
7231, 7232, 7233, 7234, 7235, 7236, 7237, 7238, 7239, 7240, \
|
||||
7241, 7242, 7243, 7244, 7245, 7246, 7247, 7248, 7249, 7250, \
|
||||
7251, 7252, 7253, 7254, 7255, 7256, 7257, 7258, 7259, 7260, \
|
||||
7261, 7262, 7263, 7264, 7265, 7266, 7267, 7268, 7269, 7270, \
|
||||
7271, 7272, 7273, 7274, 7275, 7276, 7277, 7278, 7279, 7280, \
|
||||
7281, 7282, 7283, 7284, 7285, 7286, 7287, 7288, 7289, 7290, \
|
||||
7291, 7292, 7293, 7294, 7295, 7296, 7297, 7298, 7299, 7300, \
|
||||
7301, 7302, 7303, 7304, 7305, 7306, 7307, 7308, 7309, 7310, \
|
||||
7311, 7312, 7313, 7314, 7315, 7316, 7317, 7318, 7319, 7320, \
|
||||
7321, 7322, 7323, 7324, 7325, 7326, 7327, 7328, 7329, 7330, \
|
||||
7331, 7332, 7333, 7334, 7335, 7336, 7337, 7338, 7339, 7340, \
|
||||
7341, 7342, 7343, 7344, 7345, 7346, 7347, 7348, 7349, 7350, \
|
||||
7351, 7352, 7353, 7354, 7355, 7356, 7357, 7358, 7359, 7360, \
|
||||
7361, 7362, 7363, 7364, 7365, 7366, 7367, 7368, 7369, 7370, \
|
||||
7371, 7372, 7373, 7374, 7375, 7376, 7377, 7378, 7379, 7380, \
|
||||
7381, 7382, 7383, 7384, 7385, 7386, 7387, 7388, 7389, 7390, \
|
||||
7391, 7392, 7393, 7394, 7395, 7396, 7397, 7398, 7399, 7400, \
|
||||
7401, 7402, 7403, 7404, 7405, 7406, 7407, 7408, 7409, 7410, \
|
||||
7411, 7412, 7413, 7414, 7415, 7416, 7417, 7418, 7419, 7420, \
|
||||
7421, 7422, 7423, 7424, 7425, 7426, 7427, 7428, 7429, 7430, \
|
||||
7431, 7432, 7433, 7434, 7435, 7436, 7437, 7438, 7439, 7440, \
|
||||
7441, 7442, 7443, 7444, 7445, 7446, 7447, 7448, 7449, 7450, \
|
||||
7451, 7452, 7453, 7454, 7455, 7456, 7457, 7458, 7459, 7460, \
|
||||
7461, 7462, 7463, 7464, 7465, 7466, 7467, 7468, 7469, 7470, \
|
||||
7471, 7472, 7473, 7474, 7475, 7476, 7477, 7478, 7479, 7480, \
|
||||
7481, 7482, 7483, 7484, 7485, 7486, 7487, 7488, 7489, 7490, \
|
||||
7491, 7492, 7493, 7494, 7495, 7496, 7497, 7498, 7499, 7500, \
|
||||
7501, 7502, 7503, 7504, 7505, 7506, 7507, 7508, 7509, 7510, \
|
||||
7511, 7512, 7513, 7514, 7515, 7516, 7517, 7518, 7519, 7520, \
|
||||
7521, 7522, 7523, 7524, 7525, 7526, 7527, 7528, 7529, 7530, \
|
||||
7531, 7532, 7533, 7534, 7535, 7536, 7537, 7538, 7539, 7540, \
|
||||
7541, 7542, 7543, 7544, 7545, 7546, 7547, 7548, 7549, 7550, \
|
||||
7551, 7552, 7553, 7554, 7555, 7556, 7557, 7558, 7559, 7560, \
|
||||
7561, 7562, 7563, 7564, 7565, 7566, 7567, 7568, 7569, 7570, \
|
||||
7571, 7572, 7573, 7574, 7575, 7576, 7577, 7578, 7579, 7580, \
|
||||
7581, 7582, 7583, 7584, 7585, 7586, 7587, 7588, 7589, 7590, \
|
||||
7591, 7592, 7593, 7594, 7595, 7596, 7597, 7598, 7599, 7600, \
|
||||
7601, 7602, 7603, 7604, 7605, 7606, 7607, 7608, 7609, 7610, \
|
||||
7611, 7612, 7613, 7614, 7615, 7616, 7617, 7618, 7619, 7620, \
|
||||
7621, 7622, 7623, 7624, 7625, 7626, 7627, 7628, 7629, 7630, \
|
||||
7631, 7632, 7633, 7634, 7635, 7636, 7637, 7638, 7639, 7640, \
|
||||
7641, 7642, 7643, 7644, 7645, 7646, 7647, 7648, 7649, 7650, \
|
||||
7651, 7652, 7653, 7654, 7655, 7656, 7657, 7658, 7659, 7660, \
|
||||
7661, 7662, 7663, 7664, 7665, 7666, 7667, 7668, 7669, 7670, \
|
||||
7671, 7672, 7673, 7674, 7675, 7676, 7677, 7678, 7679, 7680, \
|
||||
7681, 7682, 7683, 7684, 7685, 7686, 7687, 7688, 7689, 7690, \
|
||||
7691, 7692, 7693, 7694, 7695, 7696, 7697, 7698, 7699, 7700, \
|
||||
7701, 7702, 7703, 7704, 7705, 7706, 7707, 7708, 7709, 7710, \
|
||||
7711, 7712, 7713, 7714, 7715, 7716, 7717, 7718, 7719, 7720, \
|
||||
7721, 7722, 7723, 7724, 7725, 7726, 7727, 7728, 7729, 7730, \
|
||||
7731, 7732, 7733, 7734, 7735, 7736, 7737, 7738, 7739, 7740, \
|
||||
7741, 7742, 7743, 7744, 7745, 7746, 7747, 7748, 7749, 7750, \
|
||||
7751, 7752, 7753, 7754, 7755, 7756, 7757, 7758, 7759, 7760, \
|
||||
7761, 7762, 7763, 7764, 7765, 7766, 7767, 7768, 7769, 7770, \
|
||||
7771, 7772, 7773, 7774, 7775, 7776, 7777
|
||||
0
test/asm/macro-argument-limit.err
Normal file
0
test/asm/macro-argument-limit.err
Normal file
0
test/asm/macro-argument-limit.out
Normal file
0
test/asm/macro-argument-limit.out
Normal file
1
test/asm/macro-argument-limit.out.bin
Normal file
1
test/asm/macro-argument-limit.out.bin
Normal file
@@ -0,0 +1 @@
|
||||
<EFBFBD><EFBFBD>
|
||||
@@ -1,5 +1,5 @@
|
||||
ERROR: pc-bank.asm(2):
|
||||
Source address $2a00 not in $FF00 to $FFFF
|
||||
Source address $2a00 not between $FF00 to $FFFF
|
||||
ERROR: pc-bank.asm(11):
|
||||
Expected constant expression: Current section's bank is not known
|
||||
error: Assembly aborted (2 errors)!
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
SECTION "test", ROM0[1]
|
||||
call Target
|
||||
LOAD "new", WRAM0[$C001]
|
||||
PRINTT "PC in ROM: {@}\n"
|
||||
LOAD "new", WRAMX[$D001],BANK[1]
|
||||
PRINTT "PC in WRAM: {@}\n"
|
||||
assert @ == $D001
|
||||
Target: dl DEAD << 16 | BEEF
|
||||
db BANK(@)
|
||||
jr .end
|
||||
.end
|
||||
jr .end
|
||||
ds 2, $2A
|
||||
ENDL
|
||||
After:
|
||||
@@ -10,16 +16,16 @@ After:
|
||||
ld hl, Word
|
||||
dw Byte, Target.end, After
|
||||
|
||||
SECTION "dead", WRAMX[$DEAD]
|
||||
SECTION "dead", WRAMX[$DEAD],BANK[2]
|
||||
DEAD:
|
||||
SECTION "beef", SRAM[$BEEF]
|
||||
BEEF:
|
||||
|
||||
SECTION "ram test", WRAM0 ; Should end up at $C005
|
||||
SECTION "ram test", WRAMX,BANK[1] ; Should end up at $D005
|
||||
Word:
|
||||
dw
|
||||
|
||||
SECTION "small ram test", WRAM0 ; Should end up at $C000
|
||||
SECTION "small ram test", WRAMX,BANK[1] ; Should end up at $D000
|
||||
Byte:
|
||||
db
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
$C001
|
||||
$C005
|
||||
$A
|
||||
PC in ROM: $4
|
||||
PC in WRAM: $D001
|
||||
$D001
|
||||
$D008
|
||||
$F
|
||||
|
||||
Binary file not shown.
4
test/asm/ref-override.asm
Normal file
4
test/asm/ref-override.asm
Normal file
@@ -0,0 +1,4 @@
|
||||
SECTION "Test", ROM0[0]
|
||||
db CONSTANT
|
||||
|
||||
CONSTANT equ 42
|
||||
0
test/asm/ref-override.err
Normal file
0
test/asm/ref-override.err
Normal file
0
test/asm/ref-override.out
Normal file
0
test/asm/ref-override.out
Normal file
1
test/asm/ref-override.out.bin
Normal file
1
test/asm/ref-override.out.bin
Normal file
@@ -0,0 +1 @@
|
||||
*
|
||||
@@ -1,4 +1,4 @@
|
||||
SECTION "sec", ROM0
|
||||
SECTION "sec", ROM0[0]
|
||||
db X
|
||||
|
||||
X = 2
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
ERROR: reference-undefined-sym.asm(4):
|
||||
'X' already referenced at reference-undefined-sym.asm(2)
|
||||
error: Assembly aborted (1 errors)!
|
||||
|
||||
0
test/asm/reference-undefined-sym.out.bin
Normal file
0
test/asm/reference-undefined-sym.out.bin
Normal file
@@ -1,5 +1,7 @@
|
||||
ERROR: section-union.asm(37):
|
||||
Section "test" already declared as union
|
||||
Section "test" already declared as union section
|
||||
warning: section-union.asm(37): [-Wobsolete]
|
||||
Concatenation of non-fragment sections is deprecated
|
||||
ERROR: section-union.asm(37):
|
||||
Section "test" already declared as fixed at $c000
|
||||
ERROR: section-union.asm(37):
|
||||
|
||||
34
test/asm/sym-collision.asm
Normal file
34
test/asm/sym-collision.asm
Normal file
@@ -0,0 +1,34 @@
|
||||
; Hashmap collisions are pretty poorly-tested code path...
|
||||
; At some point, `PURGE` would malfunction with them
|
||||
|
||||
SECTION "Collision course", OAM[$FE00]
|
||||
|
||||
; All the following symbols collide!
|
||||
aqfj: ds 1 ; Give them different addresses
|
||||
cxje: ds 1
|
||||
dgsd: ds 1
|
||||
dork: ds 1
|
||||
lxok: ds 1
|
||||
psgp: ds 1
|
||||
sfly: ds 1
|
||||
syyq: ds 1
|
||||
ussg: ds 1
|
||||
xlmm: ds 1
|
||||
xtzp: ds 1
|
||||
zxfr: ds 1
|
||||
|
||||
; Completely by accident, but cool
|
||||
PURGE dork
|
||||
|
||||
PRINTT "aqfj: {aqfj}\n"
|
||||
PRINTT "cxje: {cxje}\n"
|
||||
PRINTT "dgsd: {dgsd}\n"
|
||||
PRINTT "dork: {dork}\n"
|
||||
PRINTT "lxok: {lxok}\n"
|
||||
PRINTT "psgp: {psgp}\n"
|
||||
PRINTT "sfly: {sfly}\n"
|
||||
PRINTT "syyq: {syyq}\n"
|
||||
PRINTT "ussg: {ussg}\n"
|
||||
PRINTT "xlmm: {xlmm}\n"
|
||||
PRINTT "xtzp: {xtzp}\n"
|
||||
PRINTT "zxfr: {zxfr}\n"
|
||||
3
test/asm/sym-collision.err
Normal file
3
test/asm/sym-collision.err
Normal file
@@ -0,0 +1,3 @@
|
||||
ERROR: sym-collision.asm(26):
|
||||
'dork' not defined
|
||||
error: Assembly aborted (1 errors)!
|
||||
12
test/asm/sym-collision.out
Normal file
12
test/asm/sym-collision.out
Normal file
@@ -0,0 +1,12 @@
|
||||
aqfj: $FE00
|
||||
cxje: $FE01
|
||||
dgsd: $FE02
|
||||
dork: $0
|
||||
lxok: $FE04
|
||||
psgp: $FE05
|
||||
sfly: $FE06
|
||||
syyq: $FE07
|
||||
ussg: $FE08
|
||||
xlmm: $FE09
|
||||
xtzp: $FE0A
|
||||
zxfr: $FE0B
|
||||
@@ -3,5 +3,5 @@ ERROR: symbol-override.asm(6):
|
||||
ERROR: symbol-override.asm(10):
|
||||
'X' already defined as constant at symbol-override.asm(9)
|
||||
ERROR: symbol-override.asm(14):
|
||||
'Y' already defined as non-constant at symbol-override.asm(13)
|
||||
'Y' already defined as label at symbol-override.asm(13)
|
||||
error: Assembly aborted (3 errors)!
|
||||
|
||||
@@ -1 +1 @@
|
||||
RGBDS version 0.4.0
|
||||
RGBDS version 0.4.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
warning: assert.asm(7): Worry about me, but not too much.
|
||||
assert.asm(8): Okay, this is getting serious!
|
||||
error: assert.asm(9): It all ends now.
|
||||
error: assert.asm(8): Okay, this is getting serious!
|
||||
fatal: assert.asm(9): It all ends now.
|
||||
Linking aborted after 2 errors
|
||||
|
||||
2
test/link/bank-const/a.asm
Normal file
2
test/link/bank-const/a.asm
Normal file
@@ -0,0 +1,2 @@
|
||||
CONSTANT equ 0
|
||||
EXPORT CONSTANT
|
||||
2
test/link/bank-const/b.asm
Normal file
2
test/link/bank-const/b.asm
Normal file
@@ -0,0 +1,2 @@
|
||||
SECTION "Test", ROM0[0]
|
||||
db BANK(CONSTANT)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user