Compare commits

..

59 Commits

Author SHA1 Message Date
Antonio Niño Díaz
b55fead749 Fix typo in documentation
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-23 20:37:00 +00:00
Antonio Niño Díaz
844e027a18 Increase version number to 0.3.4
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-23 20:30:47 +00:00
Antonio Niño Díaz
0fb80cd7a9 Fix indentation in asmy.y
Remove extra spaces.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-21 22:51:42 +00:00
Antonio Niño Díaz
311b412f5d Improve error messages
NULL error messages have been given a description.

Messages that weren't descriptive enough now also print the name of the
function that has failed.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-16 22:39:44 +00:00
Antonio Niño Díaz
975200834e Fix WRAMX BANK offset in the right place
ROMX and WRAMX bank numers are stored in an object file as their number
minus one. This means that this offset has to be applied somewhere.

The old code applied the fix for ROMX and WRAMX in two different places.
It looks like the patch that added support for WRAMX didn't set the
offset correctly in 'src/link/assign.c'. When this was fixed, it was
done in the wrong place, in 'src/asm/asm.y'. This patch moves the fix to
'src/link/assign.c'.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-16 22:39:44 +00:00
Antonio Niño Díaz
c8fa799883 Output error msg when object file can't be opened
In rgbasm, output a fatal error if the destination object file can't be
opened.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-16 22:39:44 +00:00
Antonio Niño Díaz
7f37eef218 Cleanup BANK related definitions
Simplify comparisons and remove magic numbers.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-16 00:46:29 +00:00
Antonio Niño Díaz
8521e45edc Reduce SRAM bank number to 16 in rgbasm
The limit was already 16 banks in the linker, which made the previous
limit of 511 useless.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-14 16:12:29 +00:00
Antonio Niño Díaz
7bd082563d Add CONTRIBUTING.rst file
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-14 14:07:22 +00:00
Antonio Niño Díaz
de32e245c9 PUSHS and POPS also affect the symbol scope
Now, when POPS is executed, it restores the symbol scope of the
corresponding PUSHS. That way, the local symbols previously available
can be used again after the POPS.

This is useful in cases like this one:

```
    SECTION "Section 1", ROMX

BigFunction:

    ...

.loop:

    ...

    PUSHS

    SECTION "Section 2", ROMX

DataForBigFunction:
    DB 1, 2, 3, 4, 5

    POPS

    ld  a,BANK(DataForBigFunction)
    ld  hl,DataForBigFunction

    ...

    jr  .loop
```

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-07 23:05:04 +00:00
Antonio Niño Díaz
f5164325d2 Convert Markdown files to reStructuredText
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-07 19:22:38 +00:00
Antonio Niño Díaz
959bfe2a9d Allow to request BANK() of sections and PC
The bank of a section can be requested with `BANK("Section Name")`, and
the bank of the current section with `BANK(@)`. In both cases, the bank
number is resolved by the linker.

New commands have been added to the list of RPN commands of object
files, and the rest has been moved so that new additions don't force a
new change in the number of the enumerations.

Increase object file version, as it is now incompatible with the old
format.

Update manpages to reflect the new ways of using `BANK()` and the new
format of the object files.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-07 02:05:05 +00:00
Antonio Niño Díaz
d24cf11ad4 Make list of linker symbols common
That way the definitions of the assembler and the linker are always the
same.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-05 00:32:50 +00:00
Antonio Niño Díaz
8d89ba39d4 Decouple commands in checkpatch Makefile target
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-04 21:54:10 +00:00
Antonio Niño Díaz
b04596a32b Move externs to header files
Follow Linux kernel coding style.

Remove exception from checkpatch.pl configuration file.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-04 01:28:23 +00:00
Antonio Niño Díaz
8e8865940a Join list of keywords of locallex.c and globlex.c
It made sense to have them in different files when the toolchain
targeted systems other than the GB. Now, there are no generic and
system-specific keywords because there is only one supported system.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-04 01:28:23 +00:00
Antonio Niño Díaz
3c14f9760f Fix echo command in checkpatch target in Makefile
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-03 19:46:48 +01:00
Antonio Niño Díaz
3c15b141e0 Add checkpatch.pl config file and Makefile targets
This is used to verify the coding style of patches.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-02 17:09:36 +01:00
Antonio Niño Díaz
72f801283d Cleanup code of rgbasm
Follow Linux kernel coding style.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-02 17:09:36 +01:00
Antonio Niño Díaz
2ffaf72e39 Cleanup code of rgbfix, rgbgfx and external libs
Follow Linux kernel coding style.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-02 13:16:53 +01:00
Antonio Niño Díaz
f41c532400 Cleanup code of rbglink
Follow Linux kernel coding style.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-02 13:16:53 +01:00
Antonio Niño Díaz
ec76431c51 Replace C types by stdint.h types
Not all occurrences have been replaced, in some cases they have been
left as they were before (like in rgbgfx and when they are in the
interface of a C standard library function).

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-12-31 15:46:22 +01:00
Antonio Niño Díaz
71961a88a0 Use M_PI instead of PI
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-12-31 15:16:08 +01:00
Antonio Niño Díaz
ba944527ec Replace ULONG by uint32_t
All affected `printf` have been fixed.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-12-31 15:16:08 +01:00
Antonio Niño Díaz
87c9d819a1 Replace SLONG by int32_t
All affected `printf` have been fixed.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-12-31 15:16:08 +01:00
Antonio Niño Díaz
13c0684497 Replace 8 and 16 bit custom types by stdint.h types
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-12-31 15:16:08 +01:00
Antonio Niño Díaz
c24cab6d1d Use NOT operator to complement bits instead of XOR
The previous way of doing it relied on the variable being 32-bit wide.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-12-31 15:16:08 +01:00
Antonio Niño Díaz
0cbe6abbd5 Increase package version number to 0.3.3
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-12-31 15:16:08 +01:00
Antonio Niño Díaz
fe6e5e445b Remove warning on DB/DW/DL emtpy lists
This warning was added in 781c90b940 as a
way of catching the following cases, which are most likely programmer
mistakes:

    DB 1,, 2
    DB 1, 2,

However, the warning was also triggered in the following case:

    DB

It can be used as a replacement of:

    DS 1

In this case, it shouldn't output a warning.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-12-29 12:05:57 +01:00
Antonio Niño Díaz
781c90b940 Add warnings for empty elements in lists of consts
Even though this behaviour is documented (empty elements are treated as
0), it can be misleading. By having a warning, compatibility is
maintained and potential problems in the code can be detected.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-12-07 22:37:43 +00:00
Antonio Niño Díaz
e7a8bb1140 Fix and document DL keyword
This keyword acts like DB or DW but for 32-bit values.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-12-07 22:36:50 +00:00
Antonio Niño Díaz
f1c13af703 Fix warning about unused variable
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-10-27 20:21:03 +01:00
Antonio Niño Díaz
90bc8d9110 Reintroduce EQU __LINE__
It was removed in commit 6198cc185c, but
the documentation wasn't updated back then.

It makes more sense to reintroduce it now than to remove it from the
docs.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-10-26 23:23:22 +01:00
Antonio Niño Díaz
193cc06561 Improve error messages
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-08-21 23:48:24 +01:00
Antonio Niño Díaz
f3b475453f Replace fprintf by errx for consistency
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-08-21 23:35:56 +01:00
Antonio Niño Díaz
0c71f5a4e9 Check return values of fread in rgblink
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-08-21 23:35:52 +01:00
Antonio Niño Díaz
4b0dfd4f4a Initialize variables in rgbfix
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-08-21 23:35:45 +01:00
Antonio Niño Díaz
2d117f68c9 Fix compiler warnings about unused return values
In some implementations of libc the function fread has the attribute
`warn_unused_result`, that is treated as an error by the compiler as
specified in the flags passed to it.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-08-17 23:03:42 +01:00
Antonio Niño Díaz
8954858bf7 Fix warning about using uninitialized variable
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-08-06 22:20:39 +01:00
Antonio Niño Díaz
4877e6dbba Merge pull request #196 from error-msgs
Print more useful error messages when redefining symbols

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-08-01 19:46:58 +01:00
Antonio Niño Díaz
ec171c5f00 Make object file magic string a common define
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-29 13:11:26 +01:00
Antonio Niño Díaz
840ddcecd2 Update dates in manpages
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 15:34:24 +01:00
Antonio Niño Díaz
c00f7409ee Improve linker symbol redefinition error messages
Now, the object file in which each definition is (as well as the source
file and line) are printed with the error message.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 15:27:30 +01:00
Antonio Niño Díaz
92449a4fe4 Save object file name of each symbol in linker
This is useful to generate error messages when there is a symbol that
appears in more than one object file.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 15:27:25 +01:00
Antonio Niño Díaz
4e2a035838 Print location of definition of redefined symbols
When trying to define a symbol with a name that is used by another one,
print the location of the first definition in the error message.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 15:27:22 +01:00
Antonio Niño Díaz
df25fa73af Update documentation of object files
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 15:27:17 +01:00
Antonio Niño Díaz
03bb2d04c3 Increment version number of object files
The previous change has broken compatibility of object files, so it is
needed to increment the version number to make the linker reject files
generated with the old code.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 15:27:14 +01:00
Antonio Niño Díaz
4dc376b0ee Save location information of symbol definitions
Now, object files save the file name and line number where each global
symbol is defined.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 15:27:06 +01:00
Antonio Niño Díaz
3dec5698db Merge pull request #188 from version-string
Add command to print version string

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 14:10:10 +01:00
Ben10do
f8bbe9be48 Add support for unions
Unions allow multiple memory allocations (using ds, etc.) to share the
same space in memory.

This allows games to use the same memory for different purposes,
depending on their state.

This also adds documentation on how to use the new UNION, NEXTU, and
ENDU keywords.
2017-07-22 14:03:17 +01:00
Antonio Niño Díaz
4d01b2d5ac Document ELIF
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 10:45:17 +01:00
Antonio Niño Díaz
086f02c1d9 Add EQUs with the version numbers of RGBDS
Document new EQUs.

Add missing EQUs to list of keywords in documentation.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 10:27:49 +01:00
Antonio Niño Díaz
8ed6c32ae7 Reorder getopt switch options alphabetically
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 10:14:02 +01:00
Antonio Niño Díaz
d0e0525302 Add -V to all programs to show the version
This option has been added to all programs of the toolchain, and it
prints the version string of the toolchain.

Manpages and help command line output updated.

Add missing 'w' flag to the command line output of rgbasm. It was
correctly documented in the manpages.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 10:14:02 +01:00
Antonio Niño Díaz
318c981c00 Add code to determine a version string
If the folder where the code is compiled is a valid git repository, the
version string is generated with `git describe`. If it isn't a valid
repository, a string included in the source code is used instead. This
one must be updated regularly as the toolchain is developed.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-22 10:14:02 +01:00
YamaArashi
5c7db42fc4 Added ELIF
In addition, make some formatting changes, and add some extra error handling (for when ELIF, ELSE, or ENDC are encountered without a corresponding IF).
2017-07-21 22:32:15 +01:00
Ben10do
4be92e14e6 Add shebang to test shell scripts
This ensures that the test scripts are correctly run with the Bourne shell, regardless of the (potentially more exotic) shell that is used to invoke the script.
2017-07-20 19:21:06 +01:00
Antonio Niño Díaz
1b155d9d4c Fix typo in documentation of RSRESET
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-18 21:48:19 +01:00
Antonio Niño Díaz
f9a1aba0d8 Allow CFLAGS to be modified from make command line
Previously, if the user wanted to modify CFLAGS, it was necessary to add
the options used in the Makefile as well, which doesn't make sense.

This patch splits CFLAGS into CFLAGS and the previously removed
REALCFLAGS so that the user can modify the arguments passed to the
compiler without having to worry about things like passing the list of
include directories.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-15 20:10:28 +01:00
82 changed files with 5769 additions and 4750 deletions

60
.checkpatch.conf Normal file
View File

@@ -0,0 +1,60 @@
# Configuration for checkpatch.pl
# ===============================
# Enable more tests
--strict
# Quiet
--quiet
# No per-file summary
--no-summary
# Don't expect the Linux kernel tree
--no-tree
# Show file line, not input line
--showfile
# List of ignored rules
# ---------------------
# There's no BIT macro
--ignore BIT_MACRO
# Allow CamelCase
--ignore CAMELCASE
# Comparing to NULL explicitly isn't a bad thing
--ignore COMPARISON_TO_NULL
# Causes false positives
--ignore COMPLEX_MACRO
# Don't complain about structs not being const
--ignore CONST_STRUCT
# Do not check the format of commit messages
--ignore GIT_COMMIT_ID
# We don't have a MAINTAINERS file, don't complain about it.
--ignore FILE_PATH_CHANGES
# Writing the continuation on the start of the line can make it clearer
--ignore LOGICAL_CONTINUATIONS
# Don't complain if a line that contains a string is too long. It's better to
# have a really long line that can be found with grep.
--ignore LONG_LINE_STRING
# Allow new typedefs
--ignore NEW_TYPEDEFS
# Prefer stdint.h types over kernel types
--ignore PREFER_KERNEL_TYPES
# Parentheses can make the code clearer
--ignore UNNECESSARY_PARENTHESES
# Don't complain when files are modified in 'include/asm'
--ignore MODIFIED_INCLUDE_ASM

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ rgbgfx
*.o
*.exe
*.html
.checkpatch-camelcase.*

88
CONTRIBUTING.rst Normal file
View File

@@ -0,0 +1,88 @@
Contributing
============
RGBDS was created in the late 90's and has received contributions from several
developers since then. It wouldn't have been possible to get to this point
without their work and, for that reason, it is always open to the contributions
of other people.
Reporting Bugs
--------------
Bug reports are essential to improve RGBDS and they are always welcome. If you
want to report a bug:
1. Make sure that there isn't a similar issue already reported
`here <https://github.com/rednex/rgbds/issues>`__.
2. Figure out a way of reproducing it reliably.
3. If there is a piece of code that triggers the bug, try to reduce it to the
smallest file you can.
4. Create a new `issue <https://github.com/rednex/rgbds/issues>`__.
Of course, it may not always be possible to give an accurate bug report, but it
always helps to fix it.
Requesting new features
-----------------------
If you come up with a good idea that could be implemented, you can propose it to
be done.
1. Create a new `issue <https://github.com/rednex/rgbds/issues>`__.
2. Try to be as accurate as possible. Describe what you need and why you need
it, maybe with examples.
Please understand that the contributors are doing it in their free time, so
simple requests are more likely to catch the interest of a contributor than
complicated ones. If you really need something to be done, and you think you can
implement it yourself, you can always contribute to RGBDS with your own code.
Contributing code
-----------------
If you want to contribute with your own code, whether it is to fix a current
issue or to add something that nobody had requested, you should first consider
if your change is going to be small (and likely to be accepted as-is) or big
(and will have to go through some rework).
Big changes will most likely require some discussion, so open an
`issue <https://github.com/rednex/rgbds/issues>`__ and explain what you want to
do and how you intend to do it. If you already have a prototype, it's always a
good idea to show it. Tests help, too.
If you are going to work on a specific issue that involves a lot of work, it is
always a good idea to leave a message, just in case someone else is interested
but doesn't know that there's someone working on it.
1. Fork this repository.
2. Checkout the ``develop`` branch.
3. Create a new branch to work on. You could still work on ``develop``, but it's
easier that way.
4. Sign off your commits: ``git commit -s``
5. Follow the Linux kernel coding style, which can be found in the file
``Documentation/process/coding-style.rst`` in the Linux kernel repository.
Note that the coding style isn't writen on stone, if there is a good reason
to deviate from it, it should be fine.
6. Download the files ``checkpatch.pl``, ``const_structs.checkpatch`` and
``spelling.txt`` from the folder ``scripts`` in the Linux kernel repository.
7. To use ``checkpatch.pl`` you can use ``make checkpatch``, which will check
the coding style of all patches between the current one and the upstream
code. By default, the Makefile expects the script (and associate files) to be
located in ``../linux/scripts/``, but you can place them anywhere you like as
long as you specify it when executing the command:
``CHECKPATCH=../path/to/folder make checkpatch``.
8. Create a pull request against the branch ``develop``.
9. Be prepared to get some comments about your code and to modify it. Tip: Use
``git rebase -i origin/develop`` to modify chains of commits.

View File

@@ -1,4 +1,8 @@
# Original code
LICENSE
=======
Original code
-------------
Copyright (C) 1997 Carsten Sorensen <surfsmurf@matilde.demon.co.uk>
@@ -24,11 +28,13 @@ This also means you can't...
- expect me to be able to help you should you have a problem related or not to
ASMotor.
# Otaku no Zoku's modifications
Otaku no Zoku's modifications
-----------------------------
Copyright (C) 1999 Justin Lloyd <jlloyd@imf.la> (?)
```
::
DO WHATEVER PUBLIC LICENSE*
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@@ -41,18 +47,19 @@ Copyright (C) 1999 Justin Lloyd <jlloyd@imf.la> (?)
and/or modify it under the terms of the DO WHATEVER PUBLIC LICENSE
Software originally created by Justin Lloyd @ http://otakunozoku.com/
```
# rgbds-linux
rgbds-linux
-----------
Copyright (C) 2009 Vegard Nossum <vegard.nossum@gmail.com>
# Current
Current
-------
rgbasm and rgblink are derived from Justin Lloyd's RGBDS.
rgbfix was rewritten from scratch by Anthony J. Bentley, and is released
under the ISC license; see the source file for the text of the license.
rgbfix was rewritten from scratch by Anthony J. Bentley, and is released under
the ISC license; see the source file for the text of the license.
rgbgfx was written by stag019, and is released under the ISC license.
@@ -64,11 +71,11 @@ The UTF-8 decoder in src/asm/charmap.c was written by Björn Höhrmann and is
released under the MIT license. The remainder of charmap.c was written by
stag019, and is released under the ISC license.
extern/err.c is derived from the Musl C library, http://www.musl-libc.org,
and is released under the MIT license.
extern/err.c is derived from the Musl C library, http://www.musl-libc.org, and
is released under the MIT license.
extern/reallocarray.c is derived from the OpenBSD Project,
http://www.openbsd.org, and is released under the ISC license.
extern/strl.c is derived from the OpenBSD Project, http://www.openbsd.org,
and is released under the BSD license.
extern/strl.c is derived from the OpenBSD Project, http://www.openbsd.org, and
is released under the BSD license.

View File

@@ -7,6 +7,7 @@ mandir := ${PREFIX}/man
STRIP := -s
BINMODE := 555
MANMODE := 444
CHECKPATCH := ../linux/scripts/checkpatch.pl
# Other variables
@@ -15,8 +16,15 @@ PNGCFLAGS := `${PKG_CONFIG} --static --cflags libpng`
PNGLDFLAGS := `${PKG_CONFIG} --static --libs-only-L libpng`
PNGLDLIBS := `${PKG_CONFIG} --static --libs-only-l libpng`
VERSION_STRING := `git describe --tags --dirty --always 2>/dev/null`
WARNFLAGS := -Wall -Werror
CFLAGS := ${WARNFLAGS} -g -std=c99 -D_POSIX_C_SOURCE=200809L -Iinclude
# Overridable CFLAGS
CFLAGS := -g
# Non-overridable CFLAGS
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=c99 -D_POSIX_C_SOURCE=200809L \
-Iinclude -DBUILD_VERSION_STRING=\"${VERSION_STRING}\"
YFLAGS :=
LFLAGS := --nounistd
@@ -40,11 +48,12 @@ rgbasm_obj := \
src/asm/output.o \
src/asm/rpn.o \
src/asm/symbol.o \
src/asm/locallex.o \
src/extern/err.o \
src/extern/reallocarray.o \
src/extern/strlcpy.o \
src/extern/strlcat.o
src/extern/strlcat.o \
src/extern/version.o
src/asm/asmy.h: src/asm/asmy.c
src/asm/locallex.o src/asm/globlex.o src/asm/lexer.o: src/asm/asmy.h
@@ -61,32 +70,35 @@ rgblink_obj := \
src/link/parser.o \
src/link/script.o \
src/link/symbol.o \
src/extern/err.o
src/extern/err.o \
src/extern/version.o
src/link/parser.h: src/link/parser.c
src/link/lexer.o: src/link/parser.h
rgbfix_obj := \
src/fix/main.o \
src/extern/err.o
src/extern/err.o \
src/extern/version.o
rgbgfx_obj := \
src/gfx/gb.o \
src/gfx/main.o \
src/gfx/makepng.o \
src/extern/err.o
src/extern/err.o \
src/extern/version.o
rgbasm: ${rgbasm_obj}
$Q${CC} ${CFLAGS} -o $@ ${rgbasm_obj} -lm
$Q${CC} ${REALCFLAGS} -o $@ ${rgbasm_obj} -lm
rgblink: ${rgblink_obj}
$Q${CC} ${CFLAGS} -o $@ ${rgblink_obj}
$Q${CC} ${REALCFLAGS} -o $@ ${rgblink_obj}
rgbfix: ${rgbfix_obj}
$Q${CC} ${CFLAGS} -o $@ ${rgbfix_obj}
$Q${CC} ${REALCFLAGS} -o $@ ${rgbfix_obj}
rgbgfx: ${rgbgfx_obj}
$Q${CC} ${CFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${PNGLDLIBS}
$Q${CC} ${REALCFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${PNGLDLIBS}
# Rules to process files
@@ -96,11 +108,11 @@ rgbgfx: ${rgbgfx_obj}
.l.o:
$Q${RM} $*.c
$Q${LEX} ${LFLAGS} -o $*.c $<
$Q${CC} ${CFLAGS} -c -o $@ $*.c
$Q${CC} ${REALCFLAGS} -c -o $@ $*.c
$Q${RM} $*.c
.c.o:
$Q${CC} ${CFLAGS} ${PNGCFLAGS} -c -o $@ $<
$Q${CC} ${REALCFLAGS} ${PNGCFLAGS} -c -o $@ $<
# Target used to remove all files generated by other Makefile targets.
@@ -132,6 +144,25 @@ install: all
$Qinstall -m ${MANMODE} src/link/rgblink.5 ${DESTDIR}${mandir}/man5/rgblink.5
$Qinstall -m ${MANMODE} src/gfx/rgbgfx.1 ${DESTDIR}${mandir}/man1/rgbgfx.1
# Target used to check the coding style of the whole codebase. '.y' and '.l'
# files aren't checked, unfortunately...
checkcodebase:
$Qfor file in `git ls-files | grep -E '\.c|\.h'`; do \
${CHECKPATCH} -f "$$file"; \
done
# Target used to check the coding style of the patches from the upstream branch
# to the HEAD. Runs checkpatch once for each commit between the current HEAD and
# the first common commit between the HEAD and origin/develop. '.y' and '.l'
# files aren't checked, unfortunately...
checkpatch:
$Qeval COMMON_COMMIT=$$(git merge-base HEAD origin/develop); \
for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do \
echo "[*] Analyzing commit '$$commit'"; \
git format-patch --stdout "$$commit~..$$commit" \
| ${CHECKPATCH} - || true; \
done
# Target for the project maintainer to easily create web manuals.
# It relies on mandoc: http://mdocml.bsd.lv

157
README.md
View File

@@ -1,157 +0,0 @@
# RGBDS
RGBDS (Rednex Game Boy Development System) is a free assembler/linker package
for the Game Boy and Game Boy Color. It consists of:
- rgbasm (assembler)
- rgblink (linker)
- rgbfix (checksum/header fixer)
- rgbgfx (PNGtoGame Boy graphics converter)
This is a fork of the original RGBDS which aims to make the programs more like
other UNIX tools.
This toolchain is maintained on [GitHub](https://github.com/rednex/rgbds), as
well as its [documentation](https://github.com/rednex/rednex.github.io).
The documentation of this toolchain can be viewed online
[here](https://rednex.github.io/), it is generated from the man pages found in
this repository.
## 1. Installing RGBDS
### 1.1 Windows
Windows builds are available in the releases page on GitHub:
https://github.com/rednex/rgbds/releases
Copy the `.exe` files to `C:\Windows\` or similar.
If you require the latest version in development, it should be possible to
compile RGBDS with MinGW or Cygwin by following the instructions to build it
on UNIX systems.
### 1.2 macOS
You can build RGBDS by following the instructions below. However, if you would
prefer not to build RGBDS yourself, you may also install it using
[Homebrew](http://brew.sh/).
To install the latest release, use:
```sh
brew install rgbds
```
To install RGBDS with all of the current changes in development (as seen on the
`master` branch on GitHub), use:
```sh
brew install rgbds --HEAD
```
### 1.3 Other UNIX-like systems
No official binaries of RGBDS are distributed for these systems, you must follow
the simple instructions below to compile and install it.
## 2. Building RGBDS from source
RGBDS can be built in UNIX-like systems by following the instructions below.
### 2.1 Dependencies
RGBDS requires yacc, flex, libpng and pkg-config to be installed.
On macOS, install the latter two with [Homebrew](http://brew.sh/):
```sh
brew install libpng pkg-config
```
On other Unixes, use the built-in package manager. For example, on Debian or
Ubuntu:
```sh
sudo apt-get install byacc flex pkg-config libpng-dev
```
You can test if libpng and pkg-config are installed by running
`pkg-config --cflags libpng`: if the output is a path, then you're good, and if
it outputs an error then you need to install them via a package manager.
### 2.2 Build process
To build the programs, run in your terminal:
```sh
make
```
Then, to install the compiled programs and manual pages, run (with appropriate
privileges, e.g, with `sudo`):
```sh
make install
```
After installation, you can read the manuals with the `man` command. E.g.,
```sh
man 7 rgbds
```
There are some variables in the Makefile that can be redefined by the user. The
variables described below can affect installation behavior when given on the
make command line. For example, to install RGBDS in your home directory instead
of systemwide, run the following:
```sh
make install PREFIX=$HOME
```
To do a verbose build, run:
```sh
make Q=
```
This is the complete list of user-defined variables:
- `PREFIX`: Location where RGBDS will be installed. Defaults to `/usr/local`.
- `bindir`: Location where the binaries will be installed. Defaults to `${PREFIX}/bin`.
- `mandir`: Location where the manpages will be installed. Defaults to `${PREFIX}/man`.
- `DESTDIR`: This is prepended to all paths during the installation. It is
mainly used for packaging.
- `Q`: Whether to quiet the build or not. To make the build more verbose, clear
this variable. Defaults to `@`.
- `STRIP`: Whether to strip the installed binaries of debug symbols or not.
Defaults to `-s`.
- `BINMODE`: Permissions of the installed binaries. Defaults to `555`.
- `MANMODE`: Permissions of the installed manpages. Defaults to `444`.
## 3 History
- Around 1997, Carsten Sorensen (AKA SurfSmurf) writes ASMotor as a
general-purpose assembler/linker system for DOS/Win32
- Around 1999, Justin Lloyd (AKA Otaku no Zoku) adapts ASMotor to read and
produce GBZ80 assembly/machine code, and releases this version as RGBDS.
- 2009, Vegard Nossum adapts the code to be more UNIX-like and releases this
version as rgbds-linux on [GitHub](https://github.com/vegard/rgbds-linux).
- 2010, Anthony J. Bentley forks that repository. The fork becomes the reference
implementation of rgbds.
- 2017, Bentley's repository is moved to a neutral name.

173
README.rst Normal file
View File

@@ -0,0 +1,173 @@
RGBDS
=====
RGBDS (Rednex Game Boy Development System) is a free assembler/linker package
for the Game Boy and Game Boy Color. It consists of:
- rgbasm (assembler)
- rgblink (linker)
- rgbfix (checksum/header fixer)
- rgbgfx (PNGtoGame Boy graphics converter)
This is a fork of the original RGBDS which aims to make the programs more like
other UNIX tools.
This toolchain is maintained on `GitHub <https://github.com/rednex/rgbds>`__, as
well as its `documentation <https://github.com/rednex/rednex.github.io>`__.
The documentation of this toolchain can be viewed online
`here <https://rednex.github.io/>`__, it is generated from the man pages found
in this repository.
1. Installing RGBDS
-------------------
1.1 Windows
~~~~~~~~~~~
Windows builds are available in the releases page on GitHub:
::
https://github.com/rednex/rgbds/releases
Copy the ``.exe`` files to ``C:\Windows\`` or similar.
If you require the latest version in development, it should be possible to
compile RGBDS with MinGW or Cygwin by following the instructions to build it on
UNIX systems.
1.2 macOS
~~~~~~~~~
You can build RGBDS by following the instructions below. However, if you would
prefer not to build RGBDS yourself, you may also install it using
`Homebrew <http://brew.sh/>`__.
To install the latest release, use:
.. code:: sh
brew install rgbds
To install RGBDS with all of the current changes in development (as seen on the
``master`` branch on GitHub), use:
.. code:: sh
brew install rgbds --HEAD
1.3 Other UNIX-like systems
~~~~~~~~~~~~~~~~~~~~~~~~~~~
No official binaries of RGBDS are distributed for these systems, you must follow
the simple instructions below to compile and install it.
2. Building RGBDS from source
-----------------------------
RGBDS can be built in UNIX-like systems by following the instructions below.
2.1 Dependencies
~~~~~~~~~~~~~~~~
RGBDS requires yacc, flex, libpng and pkg-config to be installed.
On macOS, install the latter two with `Homebrew <http://brew.sh/>`__:
.. code:: sh
brew install libpng pkg-config
On other Unixes, use the built-in package manager. For example, on Debian or
Ubuntu:
.. code:: sh
sudo apt-get install byacc flex pkg-config libpng-dev
You can test if libpng and pkg-config are installed by running ``pkg-config
--cflags libpng``: if the output is a path, then you're good, and if it outputs
an error then you need to install them via a package manager.
2.2 Build process
~~~~~~~~~~~~~~~~~
To build the programs, run in your terminal:
.. code:: sh
make
Then, to install the compiled programs and manual pages, run (with appropriate
privileges, e.g, with ``sudo``):
.. code:: sh
make install
After installation, you can read the manuals with the ``man`` command. E.g.,
.. code:: sh
man 7 rgbds
There are some variables in the Makefile that can be redefined by the user. The
variables described below can affect installation behavior when given on the
make command line. For example, to install RGBDS in your home directory instead
of systemwide, run the following:
.. code:: sh
make install PREFIX=$HOME
To do a verbose build, run:
.. code:: sh
make Q=
This is the complete list of user-defined variables:
- ``PREFIX``: Location where RGBDS will be installed. Defaults to
``/usr/local``.
- ``bindir``: Location where the binaries will be installed. Defaults to
``${PREFIX}/bin``.
- ``mandir``: Location where the manpages will be installed. Defaults to
``${PREFIX}/man``.
- ``DESTDIR``: This is prepended to all paths during the installation. It is
mainly used for packaging.
- ``Q``: Whether to quiet the build or not. To make the build more verbose,
clear this variable. Defaults to ``@``.
- ``STRIP``: Whether to strip the installed binaries of debug symbols or not.
Defaults to ``-s``.
- ``BINMODE``: Permissions of the installed binaries. Defaults to ``555``.
- ``MANMODE``: Permissions of the installed manpages. Defaults to ``444``.
- ``CHECKPATCH``: Path of the script ``checkpatch.pl`` of the Linux kernel.
Defaults to ``../linux/scripts/checkpatch.pl``.
3 History
---------
- Around 1997, Carsten Sorensen (AKA SurfSmurf) writes ASMotor as a
general-purpose assembler/linker system for DOS/Win32
- Around 1999, Justin Lloyd (AKA Otaku no Zoku) adapts ASMotor to read and
produce GBZ80 assembly/machine code, and releases this version as RGBDS.
- 2009, Vegard Nossum adapts the code to be more UNIX-like and releases
this version as rgbds-linux on
`GitHub <https://github.com/vegard/rgbds-linux>`__.
- 2010, Anthony J. Bentley forks that repository. The fork becomes the reference
implementation of rgbds.
- 2017, Bentley's repository is moved to a neutral name.

View File

@@ -1,35 +1,41 @@
/* asm.h
/*
* asm.h
*
* Contains some assembler-wide defines and externs
*
* Copyright 1997 Carsten Sorensen
*
*/
#ifndef RGBDS_ASM_ASM_H
#define RGBDS_ASM_ASM_H
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "types.h"
#include "asm/localasm.h"
#include "asm/symbol.h"
#include "asm/localasm.h"
#define MAXUNIONS 128
#define MAXMACROARGS 256
#define MAXINCPATHS 128
extern SLONG nLineNo;
extern ULONG nTotalLines;
extern ULONG nPC;
extern ULONG nPass;
extern ULONG nIFDepth;
extern int32_t nLineNo;
extern uint32_t nTotalLines;
extern uint32_t nPC;
extern uint32_t nPass;
extern uint32_t nIFDepth;
extern bool skipElif;
extern uint32_t nUnionDepth;
extern uint32_t unionStart[MAXUNIONS];
extern uint32_t unionSize[MAXUNIONS];
extern char tzCurrentFileName[_MAX_PATH + 1];
extern struct Section *pCurrentSection;
extern struct sSymbol *tHashedSymbols[HASHSIZE];
extern struct sSymbol *pPCSymbol;
extern bool oDontExpandStrings;
#define MAXMACROARGS 256
#define MAXINCPATHS 128
size_t symvaluetostring(char *dest, size_t maxLength, char *sym);
#endif /* // ASM_H */
#endif /* RGBDS_ASM_ASM_H */

View File

@@ -1,18 +1,19 @@
#ifndef RGBDS_ASM_CHARMAP_H
#define RGBDS_ASM_CHARMAP_H
#include <stdint.h>
#define MAXCHARMAPS 512
#define CHARMAPLENGTH 16
struct Charmap {
int count;
int32_t count;
char input[MAXCHARMAPS][CHARMAPLENGTH + 1];
char output[MAXCHARMAPS];
};
int readUTF8Char(char *destination, char *source);
void charmap_Sort();
int charmap_Add(char *input, UBYTE output);
int charmap_Convert(char **input);
int32_t readUTF8Char(char *destination, char *source);
int32_t charmap_Add(char *input, uint8_t output);
int32_t charmap_Convert(char **input);
#endif
#endif /* RGBDS_ASM_CHARMAP_H */

View File

@@ -9,38 +9,36 @@
#ifndef RGBDS_ASM_FSTACK_H
#define RGBDS_ASM_FSTACK_H
#include <stdint.h>
#include <stdio.h>
#include "asm/asm.h"
#include "types.h"
#include "asm/lexer.h"
#include "types.h"
struct sContext {
YY_BUFFER_STATE FlexHandle;
struct sSymbol *pMacro;
struct sContext *pNext;
char tzFileName[_MAX_PATH + 1];
char *tzMacroArgs[MAXMACROARGS + 1];
SLONG nLine;
ULONG nStatus;
int32_t nLine;
uint32_t nStatus;
FILE *pFile;
char *pREPTBlock;
ULONG nREPTBlockCount;
ULONG nREPTBlockSize;
uint32_t nREPTBlockCount;
uint32_t nREPTBlockSize;
};
void
fstk_RunInclude(char *);
extern void fstk_RunMacroArg(SLONG s);
void
fstk_Init(char *);
extern void fstk_Dump(void);
extern void fstk_AddIncludePath(char *s);
extern ULONG fstk_RunMacro(char *s);
extern void fstk_RunRept(ULONG count);
FILE *
fstk_FindFile(char *);
void fstk_RunInclude(char *tzFileName);
void fstk_RunMacroArg(int32_t s);
void fstk_Init(char *s);
void fstk_Dump(void);
void fstk_AddIncludePath(char *s);
uint32_t fstk_RunMacro(char *s);
void fstk_RunRept(uint32_t count);
FILE *fstk_FindFile(char *fname);
int32_t fstk_GetLine(void);
extern int yywrap(void);
#endif
#endif /* RGBDS_ASM_FSTACK_H */

View File

@@ -1,65 +1,69 @@
#ifndef RGBDS_ASM_LEXER_H
#define RGBDS_ASM_LEXER_H
#include <stdint.h>
#include <stdio.h>
#include "types.h"
#define LEXHASHSIZE (1 << 11)
#define MAXSTRLEN 255
struct sLexInitString {
char *tzName;
ULONG nToken;
uint32_t nToken;
};
struct sLexFloat {
ULONG(*Callback) (char *s, ULONG size);
ULONG nToken;
uint32_t (*Callback)(char *s, uint32_t size);
uint32_t nToken;
};
struct yy_buffer_state {
char *pBufferRealStart; // actual starting address
char *pBufferStart; // address where the data is initially written
// after the "safety margin"
/* Actual starting address */
char *pBufferRealStart;
/* Address where the data is initially written after a safety margin */
char *pBufferStart;
char *pBuffer;
ULONG nBufferSize;
ULONG oAtLineStart;
uint32_t nBufferSize;
uint32_t oAtLineStart;
};
enum eLexerState {
LEX_STATE_NORMAL,
LEX_STATE_MACROARGS
};
#define INITIAL 0
#define macroarg 3
typedef struct yy_buffer_state *YY_BUFFER_STATE;
extern void yy_set_state(enum eLexerState i);
extern YY_BUFFER_STATE yy_create_buffer(FILE * f);
extern YY_BUFFER_STATE yy_scan_bytes(char *mem, ULONG size);
extern void yy_delete_buffer(YY_BUFFER_STATE);
extern void yy_switch_to_buffer(YY_BUFFER_STATE);
extern ULONG lex_FloatAlloc(struct sLexFloat * tok);
extern void lex_FloatAddRange(ULONG id, UWORD start, UWORD end);
extern void lex_FloatDeleteRange(ULONG id, UWORD start, UWORD end);
extern void lex_FloatAddFirstRange(ULONG id, UWORD start, UWORD end);
extern void lex_FloatDeleteFirstRange(ULONG id, UWORD start, UWORD end);
extern void lex_FloatAddSecondRange(ULONG id, UWORD start, UWORD end);
extern void lex_FloatDeleteSecondRange(ULONG id, UWORD start, UWORD end);
extern void lex_Init(void);
extern void lex_AddStrings(struct sLexInitString * lex);
extern void lex_SetBuffer(char *buffer, ULONG len);
extern ULONG yylex(void);
extern void yyunput(char c);
extern void yyunputstr(char *s);
extern void yyskipbytes(ULONG count);
extern void yyunputbytes(ULONG count);
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);
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);
void lex_FloatAddRange(uint32_t id, uint16_t start, uint16_t end);
void lex_FloatDeleteRange(uint32_t id, uint16_t start, uint16_t end);
void lex_FloatAddFirstRange(uint32_t id, uint16_t start, uint16_t end);
void lex_FloatDeleteFirstRange(uint32_t id, uint16_t start, uint16_t end);
void lex_FloatAddSecondRange(uint32_t id, uint16_t start, uint16_t end);
void lex_FloatDeleteSecondRange(uint32_t id, uint16_t start, uint16_t end);
void lex_Init(void);
void lex_AddStrings(const struct sLexInitString *lex);
void lex_SetBuffer(char *buffer, uint32_t len);
int yywrap(void);
uint32_t yylex(void);
void yyunput(char c);
void yyunputstr(char *s);
void yyskipbytes(uint32_t count);
void yyunputbytes(uint32_t count);
extern YY_BUFFER_STATE pCurrentBuffer;
extern void upperstring(char *s);
extern void lowerstring(char *s);
void upperstring(char *s);
void lowerstring(char *s);
#endif
#endif /* RGBDS_ASM_LEXER_H */

View File

@@ -1,9 +1,13 @@
/* GB Z80 instruction groups
n3 = 3-bit
n = 8-bit
nn = 16-bit
#ifndef RGBDS_ASM_LOCALASM_H
#define RGBDS_ASM_LOCALASM_H
/*
* GB Z80 instruction groups
*
* n3 = 3-bit
* n = 8-bit
* nn = 16-bit
*
* ADC A,n : 0xCE
* ADC A,r : 0x88|r
* ADD A,n : 0xC6
@@ -77,16 +81,9 @@
* SWAP r : 0xCB 0x30|r
* XOR A,n : 0xEE
* XOR A,r : 0xA8|r
*/
#define NAME_DB "db"
#define NAME_DW "dw"
#define NAME_RB "rb"
#define NAME_RW "rw"
/* "r" defs */
enum {
REG_B = 0,
REG_C,
@@ -97,36 +94,30 @@ enum {
REG_HL_IND,
REG_A
};
/* "rr" defs */
/* "rr" defs */
enum {
REG_BC_IND = 0,
REG_DE_IND,
REG_HL_INDINC,
REG_HL_INDDEC,
};
/* "ss" defs */
/* "ss" defs (SP) and "tt" defs (AF) */
enum {
REG_BC = 0,
REG_DE,
REG_HL,
REG_SP
REG_DE = 1,
REG_HL = 2,
REG_SP = 3,
REG_AF = 3
};
/* "tt" defs */
/*
#define REG_BC 0
#define REG_DE 1
#define REG_HL 2
*/
#define REG_AF 3
/* "cc" defs */
enum {
CC_NZ = 0,
CC_Z,
CC_NC,
CC_C
};
#endif /* RGBDS_ASM_LOCALASM_H */

View File

@@ -2,29 +2,33 @@
#define RGBDS_MAIN_H
#include <stdbool.h>
#include <stdint.h>
#include "extern/stdnoreturn.h"
struct sOptions {
char gbgfx[4];
char binary[2];
SLONG fillchar;
int32_t fillchar;
bool verbose;
bool haltnop;
bool exportall;
bool warnings; /* true to enable warnings, false to disable them. */
//-1 == random
bool warnings; /* True to enable warnings, false to disable them. */
};
extern char *tzNewMacro;
extern ULONG ulNewMacroSize;
extern SLONG nGBGfxID;
extern SLONG nBinaryID;
extern uint32_t ulNewMacroSize;
extern int32_t nGBGfxID;
extern int32_t nBinaryID;
extern struct sOptions DefaultOptions;
extern struct sOptions CurrentOptions;
extern void opt_Push(void);
extern void opt_Pop(void);
extern void opt_Parse(char *s);
extern FILE *dependfile;
void opt_Push(void);
void opt_Pop(void);
void opt_Parse(char *s);
/*
* Used for errors that compromise the whole assembly process by affecting the
@@ -34,6 +38,7 @@ extern void opt_Parse(char *s);
* when it fails to allocate memory).
*/
noreturn void fatalerror(const char *fmt, ...);
/*
* Used for errors that make it impossible to assemble correctly, but don't
* affect the following code. The code will fail to assemble but the user will
@@ -41,6 +46,7 @@ noreturn void fatalerror(const char *fmt, ...);
* once.
*/
void yyerror(const char *fmt, ...);
/*
* Used to warn the user about problems that don't prevent the generation of
* valid code.
@@ -54,4 +60,4 @@ void warning(const char *fmt, ...);
#endif
#define YYLMAX 65536
#endif
#endif /* RGBDS_MAIN_H */

View File

@@ -1,61 +0,0 @@
#ifndef RGBDS_ASM_LINK_H
#define RGBDS_ASM_LINK_H
enum {
RPN_ADD = 0,
RPN_SUB,
RPN_MUL,
RPN_DIV,
RPN_MOD,
RPN_UNSUB,
RPN_OR,
RPN_AND,
RPN_XOR,
RPN_UNNOT,
RPN_LOGAND,
RPN_LOGOR,
RPN_LOGUNNOT,
RPN_LOGEQ,
RPN_LOGNE,
RPN_LOGGT,
RPN_LOGLT,
RPN_LOGGE,
RPN_LOGLE,
RPN_SHL,
RPN_SHR,
RPN_BANK,
RPN_HRAM,
RPN_CONST = 0x80,
RPN_SYM = 0x81
};
enum {
SECT_WRAM0 = 0,
SECT_VRAM,
SECT_ROMX,
SECT_ROM0,
SECT_HRAM,
SECT_WRAMX,
SECT_SRAM,
SECT_OAM
};
enum {
SYM_LOCAL = 0,
SYM_IMPORT,
SYM_EXPORT
};
enum {
PATCH_BYTE = 0,
PATCH_WORD_L,
PATCH_LONG_L
};
#endif

View File

@@ -1,21 +1,21 @@
#ifndef RGBDS_ASM_MATH_H
#define RGBDS_ASM_MATH_H
#include "types.h"
#include <stdint.h>
void math_DefinePI(void);
void math_Print(SLONG i);
SLONG math_Sin(SLONG i);
SLONG math_Cos(SLONG i);
SLONG math_Tan(SLONG i);
SLONG math_ASin(SLONG i);
SLONG math_ACos(SLONG i);
SLONG math_ATan(SLONG i);
SLONG math_ATan2(SLONG i, SLONG j);
SLONG math_Mul(SLONG i, SLONG j);
SLONG math_Div(SLONG i, SLONG j);
SLONG math_Round(SLONG i);
SLONG math_Ceil(SLONG i);
SLONG math_Floor(SLONG i);
void math_Print(int32_t i);
int32_t math_Sin(int32_t i);
int32_t math_Cos(int32_t i);
int32_t math_Tan(int32_t i);
int32_t math_ASin(int32_t i);
int32_t math_ACos(int32_t i);
int32_t math_ATan(int32_t i);
int32_t math_ATan2(int32_t i, int32_t j);
int32_t math_Mul(int32_t i, int32_t j);
int32_t math_Div(int32_t i, int32_t j);
int32_t math_Round(int32_t i);
int32_t math_Ceil(int32_t i);
int32_t math_Floor(int32_t i);
#endif
#endif /* RGBDS_ASM_MATH_H */

View File

@@ -1,40 +1,45 @@
#ifndef RGBDS_ASM_OUTPUT_H
#define RGBDS_ASM_OUTPUT_H
#include <stdint.h>
#include "asm/rpn.h"
#include "types.h"
struct Section {
char *pzName;
UBYTE nType;
ULONG nPC;
ULONG nOrg;
ULONG nBank;
ULONG nAlign;
uint8_t nType;
uint32_t nPC;
uint32_t nOrg;
uint32_t nBank;
uint32_t nAlign;
struct Section *pNext;
struct Patch *pPatches;
struct Charmap *charmap;
UBYTE *tData;
uint8_t *tData;
};
extern char *tzObjectname;
void out_PrepPass2(void);
void out_SetFileName(char *s);
void out_NewSection(char *pzName, ULONG secttype);
void out_NewAbsSection(char *pzName, ULONG secttype, SLONG org, SLONG bank);
void out_NewAlignedSection(char *pzName, ULONG secttype, SLONG alignment, SLONG bank);
void out_AbsByte(int b);
void out_AbsByteGroup(char *s, int length);
void out_NewSection(char *pzName, uint32_t secttype);
void out_NewAbsSection(char *pzName, uint32_t secttype, int32_t org,
int32_t bank);
void out_NewAlignedSection(char *pzName, uint32_t secttype, int32_t alignment,
int32_t bank);
void out_AbsByte(int32_t b);
void out_AbsByteGroup(char *s, int32_t length);
void out_RelByte(struct Expression *expr);
void out_RelWord(struct Expression *expr);
void out_PCRelByte(struct Expression *expr);
void out_WriteObject(void);
void out_Skip(int skip);
void out_Skip(int32_t skip);
void out_BinaryFile(char *s);
void out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length);
void out_BinaryFileSlice(char *s, int32_t start_pos, int32_t length);
void out_String(char *s);
void out_AbsLong(SLONG b);
void out_AbsLong(int32_t b);
void out_RelLong(struct Expression *expr);
void out_PushSection(void);
void out_PopSection(void);
#endif
#endif /* RGBDS_ASM_OUTPUT_H */

View File

@@ -1,81 +1,67 @@
#ifndef RGBDS_ASM_RPN_H
#define RGBDS_ASM_RPN_H
#include <stdint.h>
struct Expression {
SLONG nVal;
UBYTE tRPN[256];
ULONG nRPNLength;
ULONG nRPNOut;
ULONG isReloc;
ULONG isPCRel;
int32_t nVal;
uint8_t tRPN[256];
uint32_t nRPNLength;
uint32_t nRPNOut;
uint32_t isReloc;
uint32_t isPCRel;
};
ULONG rpn_isReloc(struct Expression * expr);
ULONG rpn_isPCRelative(struct Expression * expr);
uint32_t rpn_isReloc(const struct Expression *expr);
uint32_t rpn_isPCRelative(const struct Expression *expr);
void rpn_Symbol(struct Expression *expr, char *tzSym);
void rpn_Number(struct Expression * expr, ULONG i);
void rpn_LOGNOT(struct Expression * expr, struct Expression * src1);
void
rpn_LOGOR(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_LOGAND(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_LOGEQU(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_LOGGT(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_LOGLT(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_LOGGE(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_LOGLE(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_LOGNE(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_ADD(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_SUB(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_XOR(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_OR(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_AND(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_SHL(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_SHR(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_MUL(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_DIV(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void
rpn_MOD(struct Expression * expr, struct Expression * src1,
struct Expression * src2);
void rpn_HIGH(struct Expression * expr, struct Expression * src);
void rpn_LOW(struct Expression * expr, struct Expression * src);
void rpn_UNNEG(struct Expression * expr, struct Expression * src);
void rpn_UNNOT(struct Expression * expr, struct Expression * src);
UWORD rpn_PopByte(struct Expression * expr);
void rpn_Bank(struct Expression * expr, char *tzSym);
void rpn_Number(struct Expression *expr, uint32_t i);
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
void rpn_LOGOR(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_LOGAND(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_LOGGT(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_LOGLT(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_LOGGE(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_LOGLE(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_LOGNE(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_ADD(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_SUB(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_XOR(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_OR(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_AND(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_SHL(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_SHR(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_MUL(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_DIV(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_MOD(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2);
void rpn_HIGH(struct Expression *expr, const struct Expression *src);
void rpn_LOW(struct Expression *expr, const struct Expression *src);
void rpn_UNNEG(struct Expression *expr, const struct Expression *src);
void rpn_UNNOT(struct Expression *expr, const struct Expression *src);
uint16_t rpn_PopByte(struct Expression *expr);
void rpn_BankSymbol(struct Expression *expr, char *tzSym);
void rpn_BankSection(struct Expression *expr, char *tzSectionName);
void rpn_BankSelf(struct Expression *expr);
void rpn_Reset(struct Expression *expr);
void rpn_CheckHRAM(struct Expression * expr, struct Expression * src1);
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
#endif
#endif /* RGBDS_ASM_RPN_H */

View File

@@ -1,6 +1,8 @@
#ifndef RGBDS_SYMBOL_H
#define RGBDS_SYMBOL_H
#include <stdint.h>
#include "types.h"
#define HASHSIZE (1 << 16)
@@ -8,35 +10,41 @@
struct sSymbol {
char tzName[MAXSYMLEN + 1];
SLONG nValue;
ULONG nType;
int32_t nValue;
uint32_t nType;
struct sSymbol *pScope;
struct sSymbol *pNext;
struct Section *pSection;
ULONG ulMacroSize;
uint32_t ulMacroSize;
char *pMacro;
SLONG(*Callback) (struct sSymbol *);
int32_t (*Callback)(struct sSymbol *);
char tzFileName[_MAX_PATH + 1]; /* File where the symbol was defined. */
uint32_t nFileLine; /* Line where the symbol was defined. */
};
#define SYMF_RELOC 0x001 /* symbol will be reloc'ed during
* linking, it's absolute value is
* unknown */
#define SYMF_EQU 0x002 /* symbol is defined using EQU, will
* not be changed during linking */
#define SYMF_SET 0x004 /* symbol is (re)defined using SET,
* will not be changed during linking */
#define SYMF_EXPORT 0x008 /* symbol should be exported */
#define SYMF_IMPORT 0x010 /* symbol is imported, it's value is
* unknown */
#define SYMF_LOCAL 0x020 /* symbol is a local symbol */
#define SYMF_DEFINED 0x040 /* symbol has been defined, not only
* referenced */
#define SYMF_MACRO 0x080 /* symbol is a macro */
#define SYMF_STRING 0x100 /* symbol is a stringsymbol */
#define SYMF_CONST 0x200 /* symbol has a constant value, will
* not be changed during linking */
ULONG calchash(char *s);
void sym_SetExportAll(BBOOL set);
/* Symbol will be relocated during linking, it's absolute value is unknown */
#define SYMF_RELOC 0x001
/* Symbol is defined using EQU, will not be changed during linking */
#define SYMF_EQU 0x002
/* Symbol is (re)defined using SET, will not be changed during linking */
#define SYMF_SET 0x004
/* Symbol should be exported */
#define SYMF_EXPORT 0x008
/* Symbol is imported, it's value is unknown */
#define SYMF_IMPORT 0x010
/* Symbol is a local symbol */
#define SYMF_LOCAL 0x020
/* Symbol has been defined, not only referenced */
#define SYMF_DEFINED 0x040
/* Symbol is a macro */
#define SYMF_MACRO 0x080
/* Symbol is a stringsymbol */
#define SYMF_STRING 0x100
/* Symbol has a constant value, will not be changed during linking */
#define SYMF_CONST 0x200
uint32_t calchash(char *s);
void sym_SetExportAll(uint8_t set);
void sym_PrepPass1(void);
void sym_PrepPass2(void);
void sym_AddLocalReloc(char *tzSym);
@@ -50,26 +58,30 @@ void sym_SaveCurrentMacroArgs(char *save[]);
void sym_RestoreCurrentMacroArgs(char *save[]);
void sym_UseNewMacroArgs(void);
void sym_FreeCurrentMacroArgs(void);
void sym_AddEqu(char *tzSym, SLONG value);
void sym_AddSet(char *tzSym, SLONG value);
void sym_AddEqu(char *tzSym, int32_t value);
void sym_AddSet(char *tzSym, int32_t value);
void sym_Init(void);
ULONG sym_GetConstantValue(char *s);
ULONG sym_isConstant(char *s);
uint32_t sym_GetConstantValue(char *s);
uint32_t sym_isConstant(char *s);
struct sSymbol *sym_FindSymbol(char *tzName);
void sym_Global(char *tzSym);
char *sym_FindMacroArg(SLONG i);
char *sym_FindMacroArg(int32_t i);
char *sym_GetStringValue(char *tzSym);
void sym_UseCurrentMacroArgs(void);
void sym_SetMacroArgID(ULONG nMacroCount);
ULONG sym_isString(char *tzSym);
void sym_SetMacroArgID(uint32_t nMacroCount);
uint32_t sym_isString(char *tzSym);
void sym_AddMacro(char *tzSym);
void sym_ShiftCurrentMacroArgs(void);
void sym_AddString(char *tzSym, char *tzValue);
ULONG sym_GetValue(char *s);
ULONG sym_GetDefinedValue(char *s);
ULONG sym_isDefined(char *tzName);
uint32_t sym_GetValue(char *s);
uint32_t sym_GetDefinedValue(char *s);
uint32_t sym_isDefined(char *tzName);
void sym_Purge(char *tzName);
ULONG sym_isConstDefined(char *tzName);
int sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2);
uint32_t sym_isConstDefined(char *tzName);
int32_t sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2);
#endif
/* Functions to save and restore the current symbol scope. */
struct sSymbol *sym_GetCurrentSymbolScope(void);
void sym_SetCurrentSymbolScope(struct sSymbol *pNewScope);
#endif /* RGBDS_SYMBOL_H */

36
include/common.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef RGBDS_COMMON_H
#define RGBDS_COMMON_H
#define RGBDS_OBJECT_VERSION_STRING "RGB6"
enum eBankCount {
BANK_COUNT_ROM0 = 1,
BANK_COUNT_ROMX = 511,
BANK_COUNT_WRAM0 = 1,
BANK_COUNT_WRAMX = 7,
BANK_COUNT_VRAM = 2,
BANK_COUNT_OAM = 1,
BANK_COUNT_HRAM = 1,
BANK_COUNT_SRAM = 16
};
enum eBankGBCount {
BANK_MIN_ROM0 = 0,
BANK_MAX_ROM0 = BANK_COUNT_ROM0 + BANK_MIN_ROM0 - 1,
BANK_MIN_ROMX = 1,
BANK_MAX_ROMX = BANK_COUNT_ROMX + BANK_MIN_ROMX - 1,
BANK_MIN_WRAM0 = 0,
BANK_MAX_WRAM0 = BANK_COUNT_WRAM0 + BANK_MIN_WRAM0 - 1,
BANK_MIN_WRAMX = 1,
BANK_MAX_WRAMX = BANK_COUNT_WRAMX + BANK_MIN_WRAMX - 1,
BANK_MIN_VRAM = 0,
BANK_MAX_VRAM = BANK_COUNT_VRAM + BANK_MIN_VRAM - 1,
BANK_MIN_OAM = 0,
BANK_MAX_OAM = BANK_COUNT_OAM + BANK_MIN_OAM - 1,
BANK_MIN_HRAM = 0,
BANK_MAX_HRAM = BANK_COUNT_HRAM + BANK_MIN_HRAM - 1,
BANK_MIN_SRAM = 0,
BANK_MAX_SRAM = BANK_COUNT_SRAM + BANK_MIN_SRAM - 1
};
#endif /* RGBDS_COMMON_H */

25
include/extern/err.h vendored
View File

@@ -2,10 +2,13 @@
#define EXTERN_ERR_H
#ifdef ERR_IN_LIBC
#include <err.h>
#else
#else /* ERR_IN_LIBC */
#include <stdarg.h>
#include "extern/stdnoreturn.h"
#define warn rgbds_warn
@@ -18,16 +21,16 @@
#define errx rgbds_errx
#define verrx rgbds_verrx
void warn(const char *, ...);
void vwarn(const char *, va_list);
void warnx(const char *, ...);
void vwarnx(const char *, va_list);
void warn(const char *fmt, ...);
void vwarn(const char *fmt, va_list ap);
void warnx(const char *fmt, ...);
void vwarnx(const char *fmt, va_list ap);
noreturn void err(int, const char *, ...);
noreturn void verr(int, const char *, va_list);
noreturn void errx(int, const char *, ...);
noreturn void verrx(int, const char *, va_list);
noreturn void err(int status, const char *fmt, ...);
noreturn void verr(int status, const char *fmt, va_list ap);
noreturn void errx(int status, const char *fmt, ...);
noreturn void verrx(int status, const char *fmt, va_list ap);
#endif
#endif /* ERR_IN_LIBC */
#endif
#endif /* EXTERN_ERR_H */

View File

@@ -2,13 +2,14 @@
#define EXTERN_REALLOCARRAY_H
#ifdef REALLOCARRAY_IN_LIBC
#include <stdlib.h>
#else
#else /* REALLOCARRAY_IN_LIBC */
#define reallocarray rgbds_reallocarray
void *reallocarray(void *, size_t, size_t);
#endif
#endif /* REALLOCARRAY_IN_LIBC */
#endif
#endif /* EXTERN_REALLOCARRAY_H */

View File

@@ -1,3 +1,6 @@
#ifndef EXTERN_STDNORETURN_H
#define EXTERN_STDNORETURN_H
#if __STDC_VERSION__ >= 201112L
/* C11 or newer */
#define noreturn _Noreturn
@@ -11,6 +14,8 @@
/* MS Visual Studio 2003/.NET Framework 1.1 or newer */
#define noreturn _declspec(noreturn)
#else
/* unsupported, but no need to throw a fit */
/* Unsupported, but no need to throw a fit */
#define noreturn
#endif
#endif /* EXTERN_STDNORETURN_H */

18
include/extern/strl.h vendored
View File

@@ -1,13 +1,17 @@
#ifndef STRL_H
#define STRL_H
#ifndef EXTERN_STRL_H
#define EXTERN_STRL_H
#ifdef STRL_IN_LIBC
#include <string.h>
#else
#else /* STRL_IN_LIBC */
#define strlcpy rgbds_strlcpy
#define strlcat rgbds_strlcat
size_t strlcpy(char *, const char *, size_t);
size_t strlcat(char *, const char *, size_t);
#endif
size_t strlcpy(char *dst, const char *src, size_t dsize);
size_t strlcat(char *dst, const char *src, size_t dsize);
#endif
#endif /* STRL_IN_LIBC */
#endif /* EXTERN_STRL_H */

26
include/extern/version.h vendored Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2017 Antonio Nino Diaz <antonio_nd@outlook.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef EXTERN_VERSION_H
#define EXTERN_VERSION_H
#define PACKAGE_VERSION_MAJOR (0)
#define PACKAGE_VERSION_MINOR (3)
#define PACKAGE_VERSION_PATCH (4)
const char *get_package_version_string(void);
#endif /* EXTERN_VERSION_H */

View File

@@ -20,11 +20,14 @@
#include <stdint.h>
#include "gfx/main.h"
void png_to_gb(struct PNGImage png, struct GBImage *gb);
void output_file(struct Options opts, struct GBImage gb);
int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles, int tile_size);
void create_tilemap(struct Options opts, struct GBImage *gb, struct Tilemap *tilemap);
void output_tilemap_file(struct Options opts, struct Tilemap tilemap);
void output_palette_file(struct Options opts, struct PNGImage png);
void png_to_gb(const struct PNGImage png, struct GBImage *gb);
void output_file(const struct Options opts, const struct GBImage gb);
int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
int tile_size);
void create_tilemap(const struct Options opts, struct GBImage *gb,
struct Tilemap *tilemap);
void output_tilemap_file(const struct Options opts,
const struct Tilemap tilemap);
void output_palette_file(const struct Options opts, const struct PNGImage png);
#endif

View File

@@ -72,4 +72,4 @@ int depth, colors;
#include "gfx/makepng.h"
#include "gfx/gb.h"
#endif
#endif /* RGBDS_GFX_MAIN_H */

View File

@@ -19,10 +19,10 @@
#include "gfx/main.h"
void input_png_file(struct Options opts, struct PNGImage *img);
void input_png_file(const struct Options opts, struct PNGImage *img);
void get_text(struct PNGImage *png);
void set_text(struct PNGImage *png);
void output_png_file(struct Options opts, struct PNGImage *png);
void free_png_data(struct PNGImage *png);
void set_text(const struct PNGImage *png);
void output_png_file(const struct Options opts, const struct PNGImage *png);
void free_png_data(const struct PNGImage *png);
#endif
#endif /* RGBDS_GFX_PNG_H */

View File

@@ -1,50 +1,45 @@
#ifndef RGBDS_LINK_ASSIGN_H
#define RGBDS_LINK_ASSIGN_H
#include <stdint.h>
#include "common.h"
#include "mylink.h"
#include "types.h"
enum eBankCount {
BANK_COUNT_ROM0 = 1,
BANK_COUNT_ROMX = 511,
BANK_COUNT_WRAM0 = 1,
BANK_COUNT_WRAMX = 7,
BANK_COUNT_VRAM = 2,
BANK_COUNT_OAM = 1,
BANK_COUNT_HRAM = 1,
BANK_COUNT_SRAM = 16
};
/* Bank numbers as seen by the linker */
enum eBankDefine {
BANK_ROM0 = 0,
BANK_ROMX = BANK_ROM0 + BANK_COUNT_ROM0,
BANK_WRAM0 = BANK_ROMX + BANK_COUNT_ROMX,
BANK_WRAMX = BANK_WRAM0 + BANK_COUNT_WRAM0,
BANK_VRAM = BANK_WRAMX + BANK_COUNT_WRAMX,
BANK_OAM = BANK_VRAM + BANK_COUNT_VRAM,
BANK_HRAM = BANK_OAM + BANK_COUNT_OAM,
BANK_SRAM = BANK_HRAM + BANK_COUNT_HRAM
BANK_INDEX_ROM0 = 0,
BANK_INDEX_ROMX = BANK_INDEX_ROM0 + BANK_COUNT_ROM0,
BANK_INDEX_WRAM0 = BANK_INDEX_ROMX + BANK_COUNT_ROMX,
BANK_INDEX_WRAMX = BANK_INDEX_WRAM0 + BANK_COUNT_WRAM0,
BANK_INDEX_VRAM = BANK_INDEX_WRAMX + BANK_COUNT_WRAMX,
BANK_INDEX_OAM = BANK_INDEX_VRAM + BANK_COUNT_VRAM,
BANK_INDEX_HRAM = BANK_INDEX_OAM + BANK_COUNT_OAM,
BANK_INDEX_SRAM = BANK_INDEX_HRAM + BANK_COUNT_HRAM,
BANK_INDEX_MAX = BANK_INDEX_SRAM + BANK_COUNT_SRAM
};
#define MAXBANKS (BANK_COUNT_ROM0 + BANK_COUNT_ROMX + BANK_COUNT_WRAM0 + BANK_COUNT_WRAMX \
+ BANK_COUNT_VRAM + BANK_COUNT_OAM + BANK_COUNT_HRAM + BANK_COUNT_SRAM)
extern int32_t MaxBankUsed;
extern int32_t MaxAvail[BANK_INDEX_MAX];
extern SLONG area_Avail(SLONG bank);
extern void AssignSections(void);
extern void CreateSymbolTable(void);
extern SLONG MaxBankUsed;
extern SLONG MaxAvail[MAXBANKS];
int32_t area_Avail(int32_t bank);
void AssignSections(void);
void CreateSymbolTable(void);
struct sSection *GetSectionByName(const char *name);
int32_t IsSectionNameInUse(const char *name);
void SetLinkerscriptName(char *tzLinkerscriptFile);
int32_t IsSectionSameTypeBankAndFloating(const char *name,
enum eSectionType type, int32_t bank);
uint32_t AssignSectionAddressAndBankByName(const char *name, uint32_t address,
int32_t bank);
int
IsSectionNameInUse(const char *name);
int BankIndexIsROM0(int32_t bank);
int BankIndexIsROMX(int32_t bank);
int BankIndexIsWRAM0(int32_t bank);
int BankIndexIsWRAMX(int32_t bank);
int BankIndexIsVRAM(int32_t bank);
int BankIndexIsOAM(int32_t bank);
int BankIndexIsHRAM(int32_t bank);
int BankIndexIsSRAM(int32_t bank);
void
SetLinkerscriptName(char *tzLinkerscriptFile);
int
IsSectionSameTypeBankAndFloating(const char *name, enum eSectionType type, int bank);
unsigned int
AssignSectionAddressAndBankByName(const char *name, unsigned int address, int bank);
#endif
#endif /* RGBDS_LINK_ASSIGN_H */

View File

@@ -1,6 +1,6 @@
#ifndef RGBDS_LINK_LIBRARY_H
#define RGBDS_LINK_LIBRARY_H
extern void AddNeededModules(void);
void AddNeededModules(void);
#endif
#endif /* RGBDS_LINK_LIBRARY_H */

View File

@@ -1,9 +1,9 @@
#ifndef RGBDS_LINK_MAIN_H
#define RGBDS_LINK_MAIN_H
#include "types.h"
#include <stdint.h>
extern SLONG fillchar;
extern int32_t fillchar;
extern char *smartlinkstartsymbol;
#endif
#endif /* RGBDS_LINK_MAIN_H */

View File

@@ -1,11 +1,13 @@
#ifndef RGBDS_LINK_MAPFILE_H
#define RGBDS_LINK_MAPFILE_H
extern void SetMapfileName(char *name);
extern void SetSymfileName(char *name);
extern void CloseMapfile(void);
extern void MapfileWriteSection(struct sSection * pSect);
extern void MapfileInitBank(SLONG bank);
extern void MapfileCloseBank(SLONG slack);
#include <stdint.h>
#endif
void SetMapfileName(char *name);
void SetSymfileName(char *name);
void CloseMapfile(void);
void MapfileWriteSection(const struct sSection *pSect);
void MapfileInitBank(int32_t bank);
void MapfileCloseBank(int32_t slack);
#endif /* RGBDS_LINK_MAPFILE_H */

View File

@@ -1,114 +1,60 @@
#ifndef RGBDS_LINK_LINK_H
#define RGBDS_LINK_LINK_H
#ifndef _MAX_PATH
#define _MAX_PATH 512
#endif
#include <stdint.h>
#include "types.h"
#include "linkdefs.h"
extern int32_t options;
extern SLONG options;
#define OPT_TINY 0x01
#define OPT_SMART_C_LINK 0x02
#define OPT_OVERLAY 0x04
#define OPT_CONTWRAM 0x08
#define OPT_DMG_MODE 0x10
enum eRpnData {
RPN_ADD = 0,
RPN_SUB,
RPN_MUL,
RPN_DIV,
RPN_MOD,
RPN_UNSUB,
RPN_OR,
RPN_AND,
RPN_XOR,
RPN_UNNOT,
RPN_LOGAND,
RPN_LOGOR,
RPN_LOGUNNOT,
RPN_LOGEQ,
RPN_LOGNE,
RPN_LOGGT,
RPN_LOGLT,
RPN_LOGGE,
RPN_LOGLE,
RPN_SHL,
RPN_SHR,
RPN_BANK,
RPN_HRAM,
RPN_CONST = 0x80,
RPN_SYM = 0x81
};
enum eSectionType {
SECT_WRAM0,
SECT_VRAM,
SECT_ROMX,
SECT_ROM0,
SECT_HRAM,
SECT_WRAMX,
SECT_SRAM,
SECT_OAM
};
struct sSection {
SLONG nBank;
SLONG nOrg;
SLONG nAlign;
BBOOL oAssigned;
int32_t nBank;
int32_t nOrg;
int32_t nAlign;
uint8_t oAssigned;
char *pzName;
SLONG nByteSize;
int32_t nByteSize;
enum eSectionType Type;
UBYTE *pData;
SLONG nNumberOfSymbols;
uint8_t *pData;
int32_t nNumberOfSymbols;
struct sSymbol **tSymbols;
struct sPatch *pPatches;
struct sSection *pNext;
};
enum eSymbolType {
SYM_LOCAL,
SYM_IMPORT,
SYM_EXPORT
};
struct sSymbol {
char *pzName;
enum eSymbolType Type;
/* the following 3 items only valid when Type!=SYM_IMPORT */
SLONG nSectionID; /* internal to object.c */
struct sSection *pSection;
SLONG nOffset;
};
enum ePatchType {
PATCH_BYTE = 0,
PATCH_WORD_L,
PATCH_LONG_L
/* The following 3 items only valid when Type!=SYM_IMPORT */
int32_t nSectionID; /* Internal to object.c */
struct sSection *pSection;
int32_t nOffset;
char *pzObjFileName; /* Object file where the symbol is located. */
char *pzFileName; /* Source file where the symbol was defined. */
uint32_t nFileLine; /* Line where the symbol was defined. */
};
struct sPatch {
char *pzFilename;
SLONG nLineNo;
SLONG nOffset;
int32_t nLineNo;
int32_t nOffset;
enum ePatchType Type;
SLONG nRPNSize;
UBYTE *pRPN;
int32_t nRPNSize;
uint8_t *pRPN;
struct sPatch *pNext;
BBOOL oRelocPatch;
uint8_t oRelocPatch;
};
extern struct sSection *pSections;
extern struct sSection *pLibSections;
#endif
#endif /* RGBDS_LINK_LINK_H */

View File

@@ -1,6 +1,6 @@
#ifndef RGBDS_LINK_OBJECT_H
#define RGBDS_LINK_OBJECT_H
extern void obj_Readfile(char *tzObjectfile);
void obj_Readfile(char *tzObjectfile);
#endif
#endif /* RGBDS_LINK_OBJECT_H */

View File

@@ -5,4 +5,4 @@ void out_Setname(char *tzOutputfile);
void out_SetOverlayname(char *tzOverlayfile);
void Output(void);
#endif
#endif /* RGBDS_LINK_OUTPUT_H */

View File

@@ -1,9 +1,9 @@
#ifndef RGBDS_LINK_PATCH_H
#define RGBDS_LINK_PATCH_H
#include "types.h"
#include <stdint.h>
void Patch(void);
extern SLONG nPC;
extern int32_t nPC;
#endif
#endif /* RGBDS_LINK_PATCH_H */

View File

@@ -17,6 +17,8 @@
#ifndef RGBDS_LINK_SCRIPT_H
#define RGBDS_LINK_SCRIPT_H
#include <stdint.h>
#include "extern/stdnoreturn.h"
noreturn void script_fatalerror(const char *fmt, ...);
@@ -24,14 +26,13 @@ noreturn void script_fatalerror(const char *fmt, ...);
void script_Parse(const char *path);
void script_IncludeFile(const char *path);
int script_IncludeDepthGet(void);
int32_t script_IncludeDepthGet(void);
void script_IncludePop(void);
void script_InitSections(void);
void script_SetCurrentSectionType(const char *type, unsigned int bank);
void script_SetAddress(unsigned int addr);
void script_SetAlignment(unsigned int alignment);
void script_SetCurrentSectionType(const char *type, uint32_t bank);
void script_SetAddress(uint32_t addr);
void script_SetAlignment(uint32_t alignment);
void script_OutputSection(const char *section_name);
#endif
#endif /* RGBDS_LINK_SCRIPT_H */

View File

@@ -1,11 +1,13 @@
#ifndef RGBDS_LINK_SYMBOL_H
#define RGBDS_LINK_SYMBOL_H
#include "types.h"
#include <stdint.h>
void sym_Init(void);
void sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank);
SLONG sym_GetValue(char *tzName);
SLONG sym_GetBank(char *tzName);
void sym_CreateSymbol(char *tzName, int32_t nValue, int32_t nBank,
char *tzObjFileName, char *tzFileName,
uint32_t nFileLine);
int32_t sym_GetValue(char *tzName);
int32_t sym_GetBank(char *tzName);
#endif
#endif /* RGBDS_LINK_SYMBOL_H */

64
include/linkdefs.h Normal file
View File

@@ -0,0 +1,64 @@
#ifndef RGBDS_LINKDEFS_H
#define RGBDS_LINKDEFS_H
enum eRpnData {
RPN_ADD = 0x00,
RPN_SUB = 0x01,
RPN_MUL = 0x02,
RPN_DIV = 0x03,
RPN_MOD = 0x04,
RPN_UNSUB = 0x05,
RPN_OR = 0x10,
RPN_AND = 0x11,
RPN_XOR = 0x12,
RPN_UNNOT = 0x13,
RPN_LOGAND = 0x21,
RPN_LOGOR = 0x22,
RPN_LOGUNNOT = 0x23,
RPN_LOGEQ = 0x30,
RPN_LOGNE = 0x31,
RPN_LOGGT = 0x32,
RPN_LOGLT = 0x33,
RPN_LOGGE = 0x34,
RPN_LOGLE = 0x35,
RPN_SHL = 0x40,
RPN_SHR = 0x41,
RPN_BANK_SYM = 0x50,
RPN_BANK_SECT = 0x51,
RPN_BANK_SELF = 0x52,
RPN_HRAM = 0x60,
RPN_CONST = 0x80,
RPN_SYM = 0x81
};
enum eSectionType {
SECT_WRAM0 = 0x00,
SECT_VRAM = 0x01,
SECT_ROMX = 0x02,
SECT_ROM0 = 0x03,
SECT_HRAM = 0x04,
SECT_WRAMX = 0x05,
SECT_SRAM = 0x06,
SECT_OAM = 0x07
};
enum eSymbolType {
SYM_LOCAL = 0x00,
SYM_IMPORT = 0x01,
SYM_EXPORT = 0x02
};
enum ePatchType {
PATCH_BYTE = 0x00,
PATCH_WORD_L = 0x01,
PATCH_LONG_L = 0x02
};
#endif /* RGBDS_LINKDEFS_H */

View File

@@ -5,12 +5,4 @@
#define _MAX_PATH 512
#endif
typedef unsigned char UBYTE;
typedef signed char SBYTE;
typedef unsigned short UWORD;
typedef signed short SWORD;
typedef unsigned long ULONG;
typedef signed long SLONG;
typedef signed char BBOOL;
#endif
#endif /* RGBDS_TYPES_H */

File diff suppressed because it is too large Load Diff

View File

@@ -24,24 +24,38 @@
#include <stdint.h>
static const uint8_t utf8d[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00..0f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10..1f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20..2f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30..3f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40..4f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50..5f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60..6f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70..7f */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80..8f */
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, /* 90..9f */
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* a0..af */
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* b0..bf */
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* c0..cf */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* d0..df */
0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, /* e0..e7 */
0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, /* e8..ef */
0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, /* f0..f7 */
0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, /* f8..ff */
0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, /* s0.. */
0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, /* ..s0 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s1 */
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, /* s1 */
1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, /* s3 */
1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, /* s4 */
1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, /* s5 */
1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s6 */
1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s7 */
1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s8 */
};
uint32_t
decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
uint32_t decode(uint32_t *state, uint32_t *codep, uint32_t byte)
{
uint32_t type = utf8d[byte];
*codep = (*state != 0) ?
@@ -79,19 +93,15 @@ decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
struct Charmap globalCharmap = {0};
extern struct Section *pCurrentSection;
int
readUTF8Char(char *dest, char *src)
int32_t readUTF8Char(char *dest, char *src)
{
uint32_t state;
uint32_t codep;
int i;
int32_t i;
for (i = 0, state = 0;; i++) {
if (decode(&state, &codep, (uint8_t)src[i]) == 1) {
if (decode(&state, &codep, (uint8_t)src[i]) == 1)
fatalerror("invalid UTF-8 character");
}
dest[i] = src[i];
@@ -104,13 +114,12 @@ readUTF8Char(char *dest, char *src)
}
}
int
charmap_Add(char *input, UBYTE output)
int32_t charmap_Add(char *input, uint8_t output)
{
int i;
int32_t i;
size_t input_length;
char temp1i[CHARMAPLENGTH + 1], temp2i[CHARMAPLENGTH + 1], temp1o = 0,
temp2o = 0;
char temp1i[CHARMAPLENGTH + 1], temp2i[CHARMAPLENGTH + 1];
char temp1o = 0, temp2o = 0;
struct Charmap *charmap;
@@ -118,23 +127,21 @@ charmap_Add(char *input, UBYTE output)
if (pCurrentSection->charmap) {
charmap = pCurrentSection->charmap;
} else {
if ((charmap = calloc(1, sizeof(struct Charmap))) ==
NULL) {
charmap = calloc(1, sizeof(struct Charmap));
if (charmap == NULL)
fatalerror("Not enough memory for charmap");
}
pCurrentSection->charmap = charmap;
}
} else {
charmap = &globalCharmap;
}
if (nPass == 2) {
if (nPass == 2)
return charmap->count;
}
if (charmap->count > MAXCHARMAPS || strlen(input) > CHARMAPLENGTH) {
if (charmap->count > MAXCHARMAPS || strlen(input) > CHARMAPLENGTH)
return -1;
}
input_length = strlen(input);
if (input_length > 1) {
@@ -170,24 +177,22 @@ charmap_Add(char *input, UBYTE output)
return ++charmap->count;
}
int
charmap_Convert(char **input)
int32_t charmap_Convert(char **input)
{
struct Charmap *charmap;
char outchar[CHARMAPLENGTH + 1];
char *buffer;
int i, j, length;
int32_t i, j, length;
if (pCurrentSection && pCurrentSection->charmap) {
if (pCurrentSection && pCurrentSection->charmap)
charmap = pCurrentSection->charmap;
} else {
else
charmap = &globalCharmap;
}
if ((buffer = malloc(strlen(*input))) == NULL) {
buffer = malloc(strlen(*input));
if (buffer == NULL)
fatalerror("Not enough memory for buffer");
}
length = 0;
while (**input) {
@@ -201,16 +206,16 @@ charmap_Convert(char **input)
}
j = 0;
}
if (!j) {
if (!j)
j = readUTF8Char(outchar, *input);
}
if (!outchar[0]) {
buffer[length++] = 0;
} else {
for (i = 0; outchar[i]; i++) {
for (i = 0; outchar[i]; i++)
buffer[length++] = outchar[i];
}
}
*input += j;
}
*input = buffer;

View File

@@ -4,45 +4,42 @@
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "asm/symbol.h"
#include "asm/fstack.h"
#include "types.h"
#include "asm/main.h"
#include "asm/lexer.h"
#include "asm/main.h"
#include "asm/output.h"
#include "asm/symbol.h"
#include "extern/err.h"
#include "extern/strl.h"
#ifndef PATH_MAX
#define PATH_MAX 256
#endif
#include "types.h"
struct sContext *pFileStack;
struct sSymbol *pCurrentMacro;
YY_BUFFER_STATE CurrentFlexHandle;
FILE *pCurrentFile;
ULONG nCurrentStatus;
static struct sContext *pFileStack;
static struct sSymbol *pCurrentMacro;
static YY_BUFFER_STATE CurrentFlexHandle;
static FILE *pCurrentFile;
static uint32_t nCurrentStatus;
char tzCurrentFileName[_MAX_PATH + 1];
char IncludePaths[MAXINCPATHS][_MAX_PATH + 1];
SLONG NextIncPath = 0;
ULONG nMacroCount;
static char IncludePaths[MAXINCPATHS][_MAX_PATH + 1];
static int32_t NextIncPath;
static uint32_t nMacroCount;
char *pCurrentREPTBlock;
ULONG nCurrentREPTBlockSize;
ULONG nCurrentREPTBlockCount;
static char *pCurrentREPTBlock;
static uint32_t nCurrentREPTBlockSize;
static uint32_t nCurrentREPTBlockCount;
ULONG ulMacroReturnValue;
extern char *tzObjectname;
extern FILE *dependfile;
uint32_t ulMacroReturnValue;
/*
* defines for nCurrentStatus
*/
#define STAT_isInclude 0
#define STAT_isInclude 0 /* 'Normal' state as well */
#define STAT_isMacro 1
#define STAT_isMacroArg 2
#define STAT_isREPTBlock 3
@@ -50,8 +47,7 @@ extern FILE *dependfile;
/*
* Context push and pop
*/
void
pushcontext(void)
static void pushcontext(void)
{
struct sContext **ppFileStack;
@@ -59,12 +55,16 @@ pushcontext(void)
while (*ppFileStack)
ppFileStack = &((*ppFileStack)->pNext);
if ((*ppFileStack = malloc(sizeof(struct sContext))) != NULL) {
*ppFileStack = malloc(sizeof(struct sContext));
if (*ppFileStack == NULL)
fatalerror("No memory for context");
(*ppFileStack)->FlexHandle = CurrentFlexHandle;
(*ppFileStack)->pNext = NULL;
strcpy((char *) (*ppFileStack)->tzFileName,
(char *) tzCurrentFileName);
strcpy((char *)(*ppFileStack)->tzFileName, (char *)tzCurrentFileName);
(*ppFileStack)->nLine = nLineNo;
switch ((*ppFileStack)->nStatus = nCurrentStatus) {
case STAT_isMacroArg:
case STAT_isMacro:
@@ -78,17 +78,14 @@ pushcontext(void)
sym_SaveCurrentMacroArgs((*ppFileStack)->tzMacroArgs);
(*ppFileStack)->pREPTBlock = pCurrentREPTBlock;
(*ppFileStack)->nREPTBlockSize = nCurrentREPTBlockSize;
(*ppFileStack)->nREPTBlockCount =
nCurrentREPTBlockCount;
(*ppFileStack)->nREPTBlockCount = nCurrentREPTBlockCount;
break;
}
nLineNo = 0;
} else
fatalerror("No memory for context");
}
int
popcontext(void)
static int32_t popcontext(void)
{
struct sContext *pLastFile, **ppLastFile;
@@ -102,10 +99,14 @@ popcontext(void)
sym_UseCurrentMacroArgs();
sym_SetMacroArgID(nMacroCount++);
sym_UseNewMacroArgs();
return (0);
return 0;
}
}
if ((pLastFile = pFileStack) != NULL) {
pLastFile = pFileStack;
if (pLastFile == NULL)
return 1;
ppLastFile = &pFileStack;
while (pLastFile->pNext) {
ppLastFile = &(pLastFile->pNext);
@@ -114,18 +115,21 @@ popcontext(void)
yy_delete_buffer(CurrentFlexHandle);
nLineNo = pLastFile->nLine;
if (nCurrentStatus == STAT_isInclude)
fclose(pCurrentFile);
if (nCurrentStatus == STAT_isMacro) {
sym_FreeCurrentMacroArgs();
nLineNo += 1;
}
if (nCurrentStatus == STAT_isREPTBlock)
nLineNo += 1;
CurrentFlexHandle = pLastFile->FlexHandle;
strcpy((char *) tzCurrentFileName,
(char *) pLastFile->tzFileName);
strcpy((char *)tzCurrentFileName, (char *)pLastFile->tzFileName);
switch (nCurrentStatus = pLastFile->nStatus) {
case STAT_isMacroArg:
case STAT_isMacro:
@@ -146,79 +150,107 @@ popcontext(void)
free(*ppLastFile);
*ppLastFile = NULL;
yy_switch_to_buffer(CurrentFlexHandle);
return (0);
} else
return (1);
return 0;
}
int
yywrap(void)
int32_t fstk_GetLine(void)
{
return (popcontext());
struct sContext *pLastFile, **ppLastFile;
switch (nCurrentStatus) {
case STAT_isInclude:
/* This is the normal mode, also used when including a file. */
return nLineNo;
case STAT_isMacro:
break; /* Peek top file of the stack */
case STAT_isMacroArg:
return nLineNo; /* ??? */
case STAT_isREPTBlock:
break; /* Peek top file of the stack */
}
pLastFile = pFileStack;
if (pLastFile != NULL) {
ppLastFile = &pFileStack;
while (pLastFile->pNext) {
ppLastFile = &(pLastFile->pNext);
pLastFile = *ppLastFile;
}
return pLastFile->nLine;
}
/*
* This is only reached if the lexer is in REPT or MACRO mode but there
* are no saved contexts with the origin of said REPT or MACRO.
*/
fatalerror("%s: Internal error.", __func__);
}
int yywrap(void)
{
return popcontext();
}
/*
* Dump the context stack to stderr
*/
void
fstk_Dump(void)
void fstk_Dump(void)
{
struct sContext *pLastFile;
const struct sContext *pLastFile;
pLastFile = pFileStack;
while (pLastFile) {
fprintf(stderr, "%s(%ld) -> ", pLastFile->tzFileName,
fprintf(stderr, "%s(%d) -> ", pLastFile->tzFileName,
pLastFile->nLine);
pLastFile = pLastFile->pNext;
}
fprintf(stderr, "%s(%ld)", tzCurrentFileName, nLineNo);
fprintf(stderr, "%s(%d)", tzCurrentFileName, nLineNo);
}
/*
* Extra includepath stuff
*/
void
fstk_AddIncludePath(char *s)
void fstk_AddIncludePath(char *s)
{
if (NextIncPath == MAXINCPATHS) {
if (NextIncPath == MAXINCPATHS)
fatalerror("Too many include directories passed from command line");
return;
}
if (strlcpy(IncludePaths[NextIncPath++], s, _MAX_PATH) >= _MAX_PATH) {
if (strlcpy(IncludePaths[NextIncPath++], s, _MAX_PATH) >= _MAX_PATH)
fatalerror("Include path too long '%s'", s);
return;
}
}
FILE *
fstk_FindFile(char *fname)
FILE *fstk_FindFile(char *fname)
{
char path[PATH_MAX];
int i;
char path[_MAX_PATH];
int32_t i;
FILE *f;
if ((f = fopen(fname, "rb")) != NULL || errno != ENOENT) {
if (dependfile) {
f = fopen(fname, "rb");
if (f != NULL || errno != ENOENT) {
if (dependfile)
fprintf(dependfile, "%s: %s\n", tzObjectname, fname);
}
return f;
}
for (i = 0; i < NextIncPath; ++i) {
if (strlcpy(path, IncludePaths[i], sizeof path) >=
sizeof path) {
if (strlcpy(path, IncludePaths[i], sizeof(path))
>= sizeof(path))
continue;
}
if (strlcat(path, fname, sizeof path) >= sizeof path) {
continue;
}
if ((f = fopen(path, "rb")) != NULL || errno != ENOENT) {
if (strlcat(path, fname, sizeof(path)) >= sizeof(path))
continue;
f = fopen(path, "rb");
if (f != NULL || errno != ENOENT) {
if (dependfile) {
fprintf(dependfile, "%s: %s\n", tzObjectname, path);
fprintf(dependfile, "%s: %s\n", tzObjectname,
path);
}
return f;
}
@@ -231,17 +263,12 @@ fstk_FindFile(char *fname)
/*
* Set up an include file for parsing
*/
void
fstk_RunInclude(char *tzFileName)
void fstk_RunInclude(char *tzFileName)
{
FILE *f;
FILE *f = fstk_FindFile(tzFileName);
f = fstk_FindFile(tzFileName);
if (f == NULL) {
err(1, "Unable to open included file '%s'",
tzFileName);
}
if (f == NULL)
err(1, "Unable to open included file '%s'", tzFileName);
pushcontext();
nLineNo = 1;
@@ -251,7 +278,7 @@ fstk_RunInclude(char *tzFileName)
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
yy_switch_to_buffer(CurrentFlexHandle);
//Dirty hack to give the INCLUDE directive a linefeed
/* Dirty hack to give the INCLUDE directive a linefeed */
yyunput('\n');
nLineNo -= 1;
@@ -260,35 +287,35 @@ fstk_RunInclude(char *tzFileName)
/*
* Set up a macro for parsing
*/
ULONG
fstk_RunMacro(char *s)
uint32_t fstk_RunMacro(char *s)
{
struct sSymbol *sym;
struct sSymbol *sym = sym_FindMacro(s);
if (sym == NULL)
return 0;
if ((sym = sym_FindMacro(s)) != NULL) {
pushcontext();
sym_SetMacroArgID(nMacroCount++);
nLineNo = -1;
sym_UseNewMacroArgs();
nCurrentStatus = STAT_isMacro;
strcpy(tzCurrentFileName, s);
if (sym->pMacro == NULL)
return 0;
pCurrentMacro = sym;
CurrentFlexHandle =
yy_scan_bytes(pCurrentMacro->pMacro,
CurrentFlexHandle = yy_scan_bytes(pCurrentMacro->pMacro,
strlen(pCurrentMacro->pMacro));
yy_switch_to_buffer(CurrentFlexHandle);
return (1);
} else
return (0);
return 1;
}
/*
* Set up a macroargument for parsing
*/
void
fstk_RunMacroArg(SLONG s)
void fstk_RunMacroArg(int32_t s)
{
char *sym;
@@ -297,40 +324,41 @@ fstk_RunMacroArg(SLONG s)
else
s -= '0';
if ((sym = sym_FindMacroArg(s)) != NULL) {
sym = sym_FindMacroArg(s);
if (sym == NULL)
fatalerror("No such macroargument");
pushcontext();
nCurrentStatus = STAT_isMacroArg;
sprintf(tzCurrentFileName, "%c", (UBYTE) s);
sprintf(tzCurrentFileName, "%c", (uint8_t)s);
CurrentFlexHandle = yy_scan_bytes(sym, strlen(sym));
yy_switch_to_buffer(CurrentFlexHandle);
} else
fatalerror("No such macroargument");
}
/*
* Set up a stringequate for parsing
*/
void
fstk_RunString(char *s)
void fstk_RunString(char *s)
{
struct sSymbol *pSym;
const struct sSymbol *pSym = sym_FindSymbol(s);
if ((pSym = sym_FindSymbol(s)) != NULL) {
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
} else {
yyerror("No such string symbol '%s'", s);
}
}
/*
* Set up a repeat block for parsing
*/
void
fstk_RunRept(ULONG count)
void fstk_RunRept(uint32_t count)
{
if (count) {
pushcontext();
@@ -350,21 +378,19 @@ fstk_RunRept(ULONG count)
/*
* Initialize the filestack routines
*/
void
fstk_Init(char *s)
void fstk_Init(char *s)
{
char tzFileName[_MAX_PATH + 1];
char tzSymFileName[_MAX_PATH + 1 + 2];
snprintf(tzSymFileName, sizeof(tzSymFileName), "\"%s\"", s);
sym_AddString("__FILE__", tzSymFileName);
strcpy(tzFileName, s);
pFileStack = NULL;
pCurrentFile = fopen(tzFileName, "rb");
if (pCurrentFile == NULL) {
if (pCurrentFile == NULL)
err(1, "Unable to open file '%s'", tzFileName);
}
nMacroCount = 0;
nCurrentStatus = STAT_isInclude;

View File

@@ -1,52 +1,48 @@
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "asm/asm.h"
#include "asm/symbol.h"
#include "asm/lexer.h"
#include "asm/main.h"
#include "asm/rpn.h"
#include "asm/symbol.h"
#include "asm/main.h"
#include "asm/lexer.h"
#include "asm/symbol.h"
#include "asmy.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
bool oDontExpandStrings;
int32_t nGBGfxID = -1;
int32_t nBinaryID = -1;
bool oDontExpandStrings = false;
SLONG nGBGfxID = -1;
SLONG nBinaryID = -1;
SLONG
gbgfx2bin(char ch)
static int32_t gbgfx2bin(char ch)
{
SLONG i;
int32_t i;
for (i = 0; i <= 3; i += 1) {
if (CurrentOptions.gbgfx[i] == ch) {
return (i);
}
if (CurrentOptions.gbgfx[i] == ch)
return i;
}
return (0);
return 0;
}
SLONG
binary2bin(char ch)
static int32_t binary2bin(char ch)
{
SLONG i;
int32_t i;
for (i = 0; i <= 1; i += 1) {
if (CurrentOptions.binary[i] == ch) {
return (i);
}
if (CurrentOptions.binary[i] == ch)
return i;
}
return (0);
return 0;
}
SLONG
char2bin(char ch)
static int32_t char2bin(char ch)
{
if (ch >= 'a' && ch <= 'f')
return (ch - 'a' + 10);
@@ -57,16 +53,15 @@ char2bin(char ch)
if (ch >= '0' && ch <= '9')
return (ch - '0');
return (0);
return 0;
}
typedef SLONG(*x2bin) (char ch);
typedef int32_t(*x2bin) (char ch);
SLONG
ascii2bin(char *s)
static int32_t ascii2bin(char *s)
{
SLONG radix = 10;
SLONG result = 0;
int32_t radix = 10;
int32_t result = 0;
x2bin convertfunc = char2bin;
switch (*s) {
@@ -93,7 +88,7 @@ ascii2bin(char *s)
}
if (radix == 4) {
SLONG c;
int32_t c;
while (*s != '\0') {
c = convertfunc(*s++);
@@ -104,37 +99,31 @@ ascii2bin(char *s)
result = result * radix + convertfunc(*s++);
}
return (result);
return result;
}
ULONG
ParseFixedPoint(char *s, ULONG size)
uint32_t ParseFixedPoint(char *s, uint32_t size)
{
//char dest[256];
ULONG i = 0, dot = 0;
uint32_t i = 0, dot = 0;
while (size && dot != 2) {
if (s[i] == '.')
dot += 1;
if (dot < 2) {
//dest[i] = s[i];
size -= 1;
i += 1;
}
}
//dest[i] = 0;
yyunputbytes(size);
yylval.nConstValue = (SLONG) (atof(s) * 65536);
yylval.nConstValue = (int32_t)(atof(s) * 65536);
return (1);
return 1;
}
ULONG
ParseNumber(char *s, ULONG size)
uint32_t ParseNumber(char *s, uint32_t size)
{
char dest[256];
@@ -142,14 +131,13 @@ ParseNumber(char *s, ULONG size)
dest[size] = 0;
yylval.nConstValue = ascii2bin(dest);
return (1);
return 1;
}
ULONG
ParseSymbol(char *src, ULONG size)
uint32_t ParseSymbol(char *src, uint32_t size)
{
char dest[MAXSYMLEN + 1];
int copied = 0, size_backup = size;
int32_t copied = 0, size_backup = size;
while (size && copied < MAXSYMLEN) {
if (*src == '\\') {
@@ -158,13 +146,13 @@ ParseSymbol(char *src, ULONG size)
src += 1;
size -= 1;
if (*src == '@')
if (*src == '@') {
marg = sym_FindMacroArg(-1);
else if (*src >= '0' && *src <= '9')
} else if (*src >= '0' && *src <= '9') {
marg = sym_FindMacroArg(*src - '0');
else {
} else {
fatalerror("Malformed ID");
return (0);
return 0;
}
src += 1;
@@ -192,47 +180,48 @@ ParseSymbol(char *src, ULONG size)
yyunputstr(s = sym_GetStringValue(dest));
while (*s) {
if (*s++ == '\n') {
if (*s++ == '\n')
nLineNo -= 1;
}
}
return (0);
} else {
strcpy(yylval.tzString, dest);
return (1);
}
return 0;
}
ULONG
PutMacroArg(char *src, ULONG size)
strcpy(yylval.tzString, dest);
return 1;
}
uint32_t PutMacroArg(char *src, uint32_t size)
{
char *s;
yyskipbytes(size);
if ((size == 2 && src[1] >= '1' && src[1] <= '9')) {
if ((s = sym_FindMacroArg(src[1] - '0')) != NULL) {
s = sym_FindMacroArg(src[1] - '0');
if (s != NULL)
yyunputstr(s);
} else {
else
yyerror("Macro argument not defined");
}
} else {
yyerror("Invalid macro argument");
}
return (0);
return 0;
}
ULONG
PutUniqueArg(char *src, ULONG size)
uint32_t PutUniqueArg(char *src, uint32_t size)
{
char *s;
yyskipbytes(size);
if ((s = sym_FindMacroArg(-1)) != NULL) {
s = sym_FindMacroArg(-1);
if (s != NULL)
yyunputstr(s);
} else {
else
yyerror("Macro unique label string not defined");
}
return (0);
return 0;
}
enum {
@@ -240,9 +229,85 @@ enum {
T_LEX_MACROUNIQUE
};
extern struct sLexInitString localstrings[];
const struct sLexInitString lexer_strings[] = {
{"adc", T_Z80_ADC},
{"add", T_Z80_ADD},
{"and", T_Z80_AND},
{"bit", T_Z80_BIT},
{"call", T_Z80_CALL},
{"ccf", T_Z80_CCF},
{"cpl", T_Z80_CPL},
{"cp", T_Z80_CP},
{"daa", T_Z80_DAA},
{"dec", T_Z80_DEC},
{"di", T_Z80_DI},
{"ei", T_Z80_EI},
{"halt", T_Z80_HALT},
{"inc", T_Z80_INC},
{"jp", T_Z80_JP},
{"jr", T_Z80_JR},
{"ld", T_Z80_LD},
{"ldi", T_Z80_LDI},
{"ldd", T_Z80_LDD},
{"ldio", T_Z80_LDIO},
{"ldh", T_Z80_LDIO},
{"nop", T_Z80_NOP},
{"or", T_Z80_OR},
{"pop", T_Z80_POP},
{"push", T_Z80_PUSH},
{"res", T_Z80_RES},
{"reti", T_Z80_RETI},
{"ret", T_Z80_RET},
{"rlca", T_Z80_RLCA},
{"rlc", T_Z80_RLC},
{"rla", T_Z80_RLA},
{"rl", T_Z80_RL},
{"rrc", T_Z80_RRC},
{"rrca", T_Z80_RRCA},
{"rra", T_Z80_RRA},
{"rr", T_Z80_RR},
{"rst", T_Z80_RST},
{"sbc", T_Z80_SBC},
{"scf", T_Z80_SCF},
{"set", T_POP_SET},
{"sla", T_Z80_SLA},
{"sra", T_Z80_SRA},
{"srl", T_Z80_SRL},
{"stop", T_Z80_STOP},
{"sub", T_Z80_SUB},
{"swap", T_Z80_SWAP},
{"xor", T_Z80_XOR},
{"nz", T_CC_NZ},
{"z", T_CC_Z},
{"nc", T_CC_NC},
/* Handled in list of registers */
/* { "c", T_TOKEN_C }, */
{"[bc]", T_MODE_BC_IND},
{"[de]", T_MODE_DE_IND},
{"[hl]", T_MODE_HL_IND},
{"[hl+]", T_MODE_HL_INDINC},
{"[hl-]", T_MODE_HL_INDDEC},
{"[hli]", T_MODE_HL_INDINC},
{"[hld]", T_MODE_HL_INDDEC},
{"[sp]", T_MODE_SP_IND},
{"af", T_MODE_AF},
{"bc", T_MODE_BC},
{"de", T_MODE_DE},
{"hl", T_MODE_HL},
{"sp", T_MODE_SP},
{"[c]", T_MODE_C_IND},
{"[$ff00+c]", T_MODE_C_IND},
{"a", T_TOKEN_A},
{"b", T_TOKEN_B},
{"c", T_TOKEN_C},
{"d", T_TOKEN_D},
{"e", T_TOKEN_E},
{"h", T_TOKEN_H},
{"l", T_TOKEN_L},
struct sLexInitString staticstrings[] = {
{"||", T_OP_LOGICOR},
{"&&", T_OP_LOGICAND},
{"==", T_OP_LOGICEQU},
@@ -303,8 +368,9 @@ struct sLexInitString staticstrings[] = {
{"xref", T_POP_IMPORT},
{"global", T_POP_GLOBAL},
{"ds", T_POP_DS},
{NAME_DB, T_POP_DB},
{NAME_DW, T_POP_DW},
{"db", T_POP_DB},
{"dw", T_POP_DW},
{"dl", T_POP_DL},
{"section", T_POP_SECTION},
{"purge", T_POP_PURGE},
@@ -318,7 +384,6 @@ struct sLexInitString staticstrings[] = {
{"warn", T_POP_WARN},
{"macro", T_POP_MACRO},
/* Not needed but we have it here just to protect the name */
{"endm", T_POP_ENDM},
{"shift", T_POP_SHIFT},
@@ -329,8 +394,13 @@ struct sLexInitString staticstrings[] = {
{"if", T_POP_IF},
{"else", T_POP_ELSE},
{"elif", T_POP_ELIF},
{"endc", T_POP_ENDC},
{"union", T_POP_UNION},
{"nextu", T_POP_NEXTU},
{"endu", T_POP_ENDU},
{"wram0", T_SECT_WRAM0},
{"vram", T_SECT_VRAM},
{"romx", T_SECT_ROMX},
@@ -346,12 +416,13 @@ struct sLexInitString staticstrings[] = {
{"data", T_SECT_DATA},
{"bss", T_SECT_BSS},
{NAME_RB, T_POP_RB},
{NAME_RW, T_POP_RW},
{"rb", T_POP_RB},
{"rw", T_POP_RW},
{"equ", T_POP_EQU},
{"equs", T_POP_EQUS},
{"set", T_POP_SET},
/* Handled before in list of CPU instructions */
/* {"set", T_POP_SET}, */
{"=", T_POP_SET},
{"pushs", T_POP_PUSHS},
@@ -364,39 +435,37 @@ struct sLexInitString staticstrings[] = {
{NULL, 0}
};
struct sLexFloat tNumberToken = {
const struct sLexFloat tNumberToken = {
ParseNumber,
T_NUMBER
};
struct sLexFloat tFixedPointToken = {
const struct sLexFloat tFixedPointToken = {
ParseFixedPoint,
T_NUMBER
};
struct sLexFloat tIDToken = {
const struct sLexFloat tIDToken = {
ParseSymbol,
T_ID
};
struct sLexFloat tMacroArgToken = {
const struct sLexFloat tMacroArgToken = {
PutMacroArg,
T_LEX_MACROARG
};
struct sLexFloat tMacroUniqueToken = {
const struct sLexFloat tMacroUniqueToken = {
PutUniqueArg,
T_LEX_MACROUNIQUE
};
void
setuplex(void)
void setup_lexer(void)
{
ULONG id;
uint32_t id;
lex_Init();
lex_AddStrings(staticstrings);
lex_AddStrings(localstrings);
lex_AddStrings(lexer_strings);
//Macro arguments
@@ -416,7 +485,8 @@ setuplex(void)
//Binary constants
nBinaryID = id = lex_FloatAlloc(&tNumberToken);
id = lex_FloatAlloc(&tNumberToken);
nBinaryID = id;
lex_FloatAddFirstRange(id, '%', '%');
lex_FloatAddSecondRange(id, CurrentOptions.binary[0],
CurrentOptions.binary[0]);
@@ -436,7 +506,8 @@ setuplex(void)
//Gameboy gfx constants
nGBGfxID = id = lex_FloatAlloc(&tNumberToken);
id = lex_FloatAlloc(&tNumberToken);
nGBGfxID = id;
lex_FloatAddFirstRange(id, '`', '`');
lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[0],
CurrentOptions.gbgfx[0]);
@@ -513,5 +584,4 @@ setuplex(void)
lex_FloatAddSecondRange(id, '0', '9');
lex_FloatAddRange(id, '.', '.');
lex_FloatAddRange(id, '0', '9');
}

View File

@@ -1,46 +1,45 @@
#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"
#include "asm/lexer.h"
#include "types.h"
#include "asm/main.h"
#include "asm/rpn.h"
#include "asm/fstack.h"
#include "extern/err.h"
#include "asmy.h"
struct sLexString {
char *tzName;
ULONG nToken;
ULONG nNameLength;
uint32_t nToken;
uint32_t nNameLength;
struct sLexString *pNext;
};
#define pLexBufferRealStart (pCurrentBuffer->pBufferRealStart)
#define pLexBuffer (pCurrentBuffer->pBuffer)
#define AtLineStart (pCurrentBuffer->oAtLineStart)
#define SAFETYMARGIN 1024
extern size_t symvaluetostring(char *dest, size_t maxLength, char *sym);
struct sLexFloat tLexFloat[32];
struct sLexString *tLexHash[LEXHASHSIZE];
YY_BUFFER_STATE pCurrentBuffer;
ULONG nLexMaxLength; // max length of all keywords and operators
uint32_t nLexMaxLength; // max length of all keywords and operators
ULONG tFloatingSecondChar[256];
ULONG tFloatingFirstChar[256];
ULONG tFloatingChars[256];
ULONG nFloating;
uint32_t tFloatingSecondChar[256];
uint32_t tFloatingFirstChar[256];
uint32_t tFloatingChars[256];
uint32_t nFloating;
enum eLexerState lexerstate = LEX_STATE_NORMAL;
void
upperstring(char *s)
void upperstring(char *s)
{
while (*s) {
*s = toupper(*s);
@@ -48,8 +47,7 @@ upperstring(char *s)
}
}
void
lowerstring(char *s)
void lowerstring(char *s)
{
while (*s) {
*s = tolower(*s);
@@ -57,20 +55,17 @@ lowerstring(char *s)
}
}
void
yyskipbytes(ULONG count)
void yyskipbytes(uint32_t count)
{
pLexBuffer += count;
}
void
yyunputbytes(ULONG count)
void yyunputbytes(uint32_t count)
{
pLexBuffer -= count;
}
void
yyunput(char c)
void yyunput(char c)
{
if (pLexBuffer <= pLexBufferRealStart)
fatalerror("Buffer safety margin exceeded");
@@ -78,10 +73,9 @@ yyunput(char c)
*(--pLexBuffer) = c;
}
void
yyunputstr(char *s)
void yyunputstr(char *s)
{
int i, len;
int32_t i, len;
len = strlen(s);
@@ -92,80 +86,79 @@ yyunputstr(char *s)
*(--pLexBuffer) = s[i];
}
void
yy_switch_to_buffer(YY_BUFFER_STATE buf)
void yy_switch_to_buffer(YY_BUFFER_STATE buf)
{
pCurrentBuffer = buf;
}
void
yy_set_state(enum eLexerState i)
void yy_set_state(enum eLexerState i)
{
lexerstate = i;
}
void
yy_delete_buffer(YY_BUFFER_STATE buf)
void yy_delete_buffer(YY_BUFFER_STATE buf)
{
free(buf->pBufferStart - SAFETYMARGIN);
free(buf);
}
YY_BUFFER_STATE
yy_scan_bytes(char *mem, ULONG size)
YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size)
{
YY_BUFFER_STATE pBuffer;
YY_BUFFER_STATE pBuffer = malloc(sizeof(struct yy_buffer_state));
if (pBuffer == NULL)
fatalerror("%s: Out of memory!", __func__);
pBuffer->pBufferRealStart = malloc(size + 1 + SAFETYMARGIN);
if (pBuffer->pBufferRealStart == NULL)
fatalerror("%s: Out of memory for buffer!", __func__);
if ((pBuffer = malloc(sizeof(struct yy_buffer_state))) != NULL) {
if ((pBuffer->pBufferRealStart =
malloc(size + 1 + SAFETYMARGIN)) != NULL) {
pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN;
pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN;
memcpy(pBuffer->pBuffer, mem, size);
pBuffer->nBufferSize = size;
pBuffer->oAtLineStart = 1;
pBuffer->pBuffer[size] = 0;
return (pBuffer);
}
}
fatalerror("Out of memory!");
return (NULL);
return pBuffer;
}
YY_BUFFER_STATE
yy_create_buffer(FILE * f)
YY_BUFFER_STATE yy_create_buffer(FILE *f)
{
YY_BUFFER_STATE pBuffer;
YY_BUFFER_STATE pBuffer = malloc(sizeof(struct yy_buffer_state));
if ((pBuffer = malloc(sizeof(struct yy_buffer_state))) != NULL) {
ULONG size;
if (pBuffer == NULL)
fatalerror("%s: Out of memory!", __func__);
uint32_t size;
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
if ((pBuffer->pBufferRealStart =
malloc(size + 2 + SAFETYMARGIN)) != NULL) {
char *mem;
ULONG instring = 0;
pBuffer->pBufferRealStart = malloc(size + 2 + SAFETYMARGIN);
if (pBuffer->pBufferRealStart == NULL)
fatalerror("%s: Out of memory for buffer!", __func__);
pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN;
pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN;
size = fread(pBuffer->pBuffer, sizeof(UBYTE), size, f);
size = fread(pBuffer->pBuffer, sizeof(uint8_t), size, f);
pBuffer->pBuffer[size] = '\n';
pBuffer->pBuffer[size + 1] = 0;
pBuffer->nBufferSize = size + 1;
mem = pBuffer->pBuffer;
char *mem = pBuffer->pBuffer;
uint32_t instring = 0;
while (*mem) {
if (*mem == '\"')
instring = 1 - instring;
if (mem[0] == '\\' &&
(mem[1] == '\"' || mem[1] == '\\')) {
if ((mem[0] == '\\') && (mem[1] == '\"' || mem[1] == '\\')) {
mem += 2;
} else if (instring) {
mem += 1;
@@ -185,21 +178,17 @@ yy_create_buffer(FILE * f)
} else if (*mem == ';') {
while (!(*mem == '\n' || *mem == '\0'))
*mem++ = ' ';
} else
} else {
mem += 1;
}
}
}
pBuffer->oAtLineStart = 1;
return (pBuffer);
}
}
fatalerror("Out of memory!");
return (NULL);
return pBuffer;
}
ULONG
lex_FloatAlloc(struct sLexFloat *token)
uint32_t lex_FloatAlloc(const struct sLexFloat *token)
{
tLexFloat[nFloating] = *token;
@@ -210,8 +199,7 @@ lex_FloatAlloc(struct sLexFloat *token)
* Make sure that only non-zero ASCII characters are used. Also, check if the
* start is greater than the end of the range.
*/
void
lex_CheckCharacterRange(UWORD start, UWORD end)
void lex_CheckCharacterRange(uint16_t start, uint16_t end)
{
if (start > end || start < 1 || end > 127) {
errx(1, "Invalid character range (start: %u, end: %u)",
@@ -219,8 +207,7 @@ lex_CheckCharacterRange(UWORD start, UWORD end)
}
}
void
lex_FloatDeleteRange(ULONG id, UWORD start, UWORD end)
void lex_FloatDeleteRange(uint32_t id, uint16_t start, uint16_t end)
{
lex_CheckCharacterRange(start, end);
@@ -230,8 +217,7 @@ lex_FloatDeleteRange(ULONG id, UWORD start, UWORD end)
}
}
void
lex_FloatAddRange(ULONG id, UWORD start, UWORD end)
void lex_FloatAddRange(uint32_t id, uint16_t start, uint16_t end)
{
lex_CheckCharacterRange(start, end);
@@ -241,8 +227,7 @@ lex_FloatAddRange(ULONG id, UWORD start, UWORD end)
}
}
void
lex_FloatDeleteFirstRange(ULONG id, UWORD start, UWORD end)
void lex_FloatDeleteFirstRange(uint32_t id, uint16_t start, uint16_t end)
{
lex_CheckCharacterRange(start, end);
@@ -252,8 +237,7 @@ lex_FloatDeleteFirstRange(ULONG id, UWORD start, UWORD end)
}
}
void
lex_FloatAddFirstRange(ULONG id, UWORD start, UWORD end)
void lex_FloatAddFirstRange(uint32_t id, uint16_t start, uint16_t end)
{
lex_CheckCharacterRange(start, end);
@@ -263,8 +247,7 @@ lex_FloatAddFirstRange(ULONG id, UWORD start, UWORD end)
}
}
void
lex_FloatDeleteSecondRange(ULONG id, UWORD start, UWORD end)
void lex_FloatDeleteSecondRange(uint32_t id, uint16_t start, uint16_t end)
{
lex_CheckCharacterRange(start, end);
@@ -274,8 +257,7 @@ lex_FloatDeleteSecondRange(ULONG id, UWORD start, UWORD end)
}
}
void
lex_FloatAddSecondRange(ULONG id, UWORD start, UWORD end)
void lex_FloatAddSecondRange(uint32_t id, uint16_t start, uint16_t end)
{
lex_CheckCharacterRange(start, end);
@@ -285,43 +267,37 @@ lex_FloatAddSecondRange(ULONG id, UWORD start, UWORD end)
}
}
struct sLexFloat *
lexgetfloat(ULONG nFloatMask)
static struct sLexFloat *lexgetfloat(uint32_t nFloatMask)
{
if (nFloatMask == 0) {
fatalerror("Internal error in lexgetfloat");
}
if (nFloatMask == 0)
fatalerror("Internal error in %s", __func__);
int i = 0;
int32_t i = 0;
while ((nFloatMask & 1) == 0) {
nFloatMask >>= 1;
i++;
}
return (&tLexFloat[i]);
return &tLexFloat[i];
}
ULONG
lexcalchash(char *s)
static uint32_t lexcalchash(char *s)
{
ULONG hash = 0;
uint32_t hash = 0;
while (*s) {
while (*s)
hash = (hash * 283) ^ toupper(*s++);
return hash % LEXHASHSIZE;
}
return (hash % LEXHASHSIZE);
}
void
lex_Init(void)
void lex_Init(void)
{
ULONG i;
uint32_t i;
for (i = 0; i < LEXHASHSIZE; i++) {
for (i = 0; i < LEXHASHSIZE; i++)
tLexHash[i] = NULL;
}
for (i = 0; i < 256; i++) {
tFloatingFirstChar[i] = 0;
@@ -333,20 +309,24 @@ lex_Init(void)
nFloating = 0;
}
void
lex_AddStrings(struct sLexInitString * lex)
void lex_AddStrings(const struct sLexInitString *lex)
{
while (lex->tzName) {
struct sLexString **ppHash;
ULONG hash;
uint32_t hash;
ppHash = &tLexHash[hash = lexcalchash(lex->tzName)];
while (*ppHash)
ppHash = &((*ppHash)->pNext);
if (((*ppHash) = malloc(sizeof(struct sLexString))) != NULL) {
if (((*ppHash)->tzName =
(char *) strdup(lex->tzName)) != NULL) {
*ppHash = malloc(sizeof(struct sLexString));
if (*ppHash == NULL)
fatalerror("Out of memory!");
(*ppHash)->tzName = (char *)strdup(lex->tzName);
if ((*ppHash)->tzName == NULL)
fatalerror("Out of memory!");
(*ppHash)->nNameLength = strlen(lex->tzName);
(*ppHash)->nToken = lex->nToken;
(*ppHash)->pNext = NULL;
@@ -356,11 +336,6 @@ lex_AddStrings(struct sLexInitString * lex)
if ((*ppHash)->nNameLength > nLexMaxLength)
nLexMaxLength = (*ppHash)->nNameLength;
} else
fatalerror("Out of memory!");
} else
fatalerror("Out of memory!");
lex += 1;
}
}
@@ -375,42 +350,42 @@ lex_AddStrings(struct sLexInitString * lex)
* The token types with the longest match from the current position in the
* buffer will have their bits set in the float mask.
*/
void
yylex_GetFloatMaskAndFloatLen(ULONG *pnFloatMask, ULONG *pnFloatLen)
void yylex_GetFloatMaskAndFloatLen(uint32_t *pnFloatMask, uint32_t *pnFloatLen)
{
// Note that '\0' should always have a bit mask of 0 in the "floating"
// tables, so it doesn't need to be checked for separately.
/*
* Note that '\0' should always have a bit mask of 0 in the "floating"
* tables, so it doesn't need to be checked for separately.
*/
char *s = pLexBuffer;
ULONG nOldFloatMask = 0;
ULONG nFloatMask = tFloatingFirstChar[(int)*s];
uint32_t nOldFloatMask = 0;
uint32_t nFloatMask = tFloatingFirstChar[(int32_t)*s];
if (nFloatMask != 0) {
s++;
nOldFloatMask = nFloatMask;
nFloatMask &= tFloatingSecondChar[(int)*s];
nFloatMask &= tFloatingSecondChar[(int32_t)*s];
while (nFloatMask != 0) {
s++;
nOldFloatMask = nFloatMask;
nFloatMask &= tFloatingChars[(int)*s];
nFloatMask &= tFloatingChars[(int32_t)*s];
}
}
*pnFloatMask = nOldFloatMask;
*pnFloatLen = (ULONG)(s - pLexBuffer);
*pnFloatLen = (uint32_t)(s - pLexBuffer);
}
/*
* Gets the longest keyword/operator from the current position in the buffer.
*/
struct sLexString *
yylex_GetLongestFixed()
struct sLexString *yylex_GetLongestFixed()
{
struct sLexString *pLongestFixed = NULL;
char *s = pLexBuffer;
ULONG hash = 0;
ULONG length = 0;
uint32_t hash = 0;
uint32_t length = 0;
while (length < nLexMaxLength && *s) {
hash = (hash * 283) ^ toupper(*s);
@@ -432,12 +407,11 @@ yylex_GetLongestFixed()
return pLongestFixed;
}
size_t
CopyMacroArg(char *dest, size_t maxLength, char c)
size_t CopyMacroArg(char *dest, size_t maxLength, char c)
{
size_t i;
char *s;
int argNum;
int32_t argNum;
switch (c) {
case '1':
@@ -458,35 +432,33 @@ CopyMacroArg(char *dest, size_t maxLength, char c)
return 0;
}
if ((s = sym_FindMacroArg(argNum)) == NULL)
s = sym_FindMacroArg(argNum);
if (s == NULL)
fatalerror("Macro argument not defined");
for (i = 0; s[i] != 0; i++) {
if (i >= maxLength) {
if (i >= maxLength)
fatalerror("Macro argument too long to fit buffer");
}
dest[i] = s[i];
}
return i;
}
static inline void
yylex_StringWriteChar(char *s, size_t index, char c)
static inline void yylex_StringWriteChar(char *s, size_t index, char c)
{
if (index >= MAXSTRLEN) {
if (index >= MAXSTRLEN)
fatalerror("String too long");
}
s[index] = c;
}
static inline void
yylex_SymbolWriteChar(char *s, size_t index, char c)
static inline void yylex_SymbolWriteChar(char *s, size_t index, char c)
{
if (index >= MAXSYMLEN) {
if (index >= MAXSYMLEN)
fatalerror("Symbol too long");
}
s[index] = c;
}
@@ -497,14 +469,15 @@ yylex_SymbolWriteChar(char *s, size_t index, char c)
*/
void yylex_TrimEnd(char *s, size_t index)
{
int i;
int32_t i = (int32_t)index - 1;
for (i = (int)index - 1; i >= 0 && (s[i] == ' ' || s[i] == '\t'); i--)
while ((i >= 0) && (s[i] == ' ' || s[i] == '\t')) {
s[i] = 0;
i--;
}
}
size_t
yylex_ReadBracketedSymbol(char *dest, size_t index)
size_t yylex_ReadBracketedSymbol(char *dest, size_t index)
{
char sym[MAXSYMLEN + 1];
char ch;
@@ -523,13 +496,15 @@ yylex_ReadBracketedSymbol(char *dest, size_t index)
i += length;
else
fatalerror("Illegal character escape '%c'", ch);
} else
} else {
yylex_SymbolWriteChar(sym, i++, ch);
}
}
yylex_SymbolWriteChar(sym, i, 0);
maxLength = MAXSTRLEN - index; // it's assumed we're writing to a T_STRING
/* It's assumed we're writing to a T_STRING */
maxLength = MAXSTRLEN - index;
length = symvaluetostring(&dest[index], maxLength, sym);
if (*pLexBuffer == '}')
@@ -540,8 +515,7 @@ yylex_ReadBracketedSymbol(char *dest, size_t index)
return length;
}
void
yylex_ReadQuotedString()
static void yylex_ReadQuotedString(void)
{
size_t index = 0;
size_t length, maxLength;
@@ -576,19 +550,22 @@ yylex_ReadQuotedString()
break;
default:
maxLength = MAXSTRLEN - index;
length = CopyMacroArg(&yylval.tzString[index], maxLength, ch);
length = CopyMacroArg(&yylval.tzString[index],
maxLength, ch);
if (length != 0)
index += length;
else
fatalerror("Illegal character escape '%c'", ch);
fatalerror("Illegal character escape '%c'",
ch);
ch = 0;
break;
}
} else if (ch == '{') {
// Get bracketed symbol within string.
index += yylex_ReadBracketedSymbol(yylval.tzString, index);
index += yylex_ReadBracketedSymbol(yylval.tzString,
index);
ch = 0;
}
@@ -604,12 +581,11 @@ yylex_ReadQuotedString()
fatalerror("Unterminated string");
}
ULONG
yylex_NORMAL()
static uint32_t yylex_NORMAL(void)
{
struct sLexString *pLongestFixed = NULL;
ULONG nFloatMask, nFloatLen;
ULONG linestart = AtLineStart;
uint32_t nFloatMask, nFloatLen;
uint32_t linestart = AtLineStart;
AtLineStart = 0;
@@ -628,15 +604,20 @@ scanagain:
}
}
// Try to match an identifier, macro argument (e.g. \1),
// or numeric literal.
/*
* Try to match an identifier, macro argument (e.g. \1),
* or numeric literal.
*/
yylex_GetFloatMaskAndFloatLen(&nFloatMask, &nFloatLen);
// Try to match a keyword or operator.
/* Try to match a keyword or operator. */
pLongestFixed = yylex_GetLongestFixed();
if (nFloatLen == 0 && pLongestFixed == NULL) {
// No keyword, identifier, operator, or numerical literal matches.
/*
* No keyword, identifier, operator, or numerical literal
* matches.
*/
if (*pLexBuffer == '"') {
pLexBuffer++;
@@ -646,52 +627,55 @@ scanagain:
pLexBuffer++;
yylex_ReadBracketedSymbol(yylval.tzString, 0);
return T_STRING;
} else {
// It's not a keyword, operator, identifier, macro argument,
// numeric literal, string, or bracketed symbol, so just return
// the ASCII character.
}
/*
* It's not a keyword, operator, identifier, macro argument,
* numeric literal, string, or bracketed symbol, so just return
* the ASCII character.
*/
if (*pLexBuffer == '\n')
AtLineStart = 1;
return *pLexBuffer++;
}
}
if (pLongestFixed == NULL || nFloatLen > pLongestFixed->nNameLength) {
// Longest match was an identifier, macro argument, or numeric literal.
/*
* Longest match was an identifier, macro argument, or numeric
* literal.
*/
struct sLexFloat *token = lexgetfloat(nFloatMask);
if (token->Callback) {
int done = token->Callback(pLexBuffer, nFloatLen);
int32_t done = token->Callback(pLexBuffer, nFloatLen);
if (!done)
goto scanagain;
}
pLexBuffer += nFloatLen;
if (token->nToken == T_ID && linestart) {
if (token->nToken == T_ID && linestart)
return T_LABEL;
} else {
else
return token->nToken;
}
}
// Longest match was a keyword or operator.
/* Longest match was a keyword or operator. */
pLexBuffer += pLongestFixed->nNameLength;
return pLongestFixed->nToken;
}
ULONG
yylex_MACROARGS()
static uint32_t yylex_MACROARGS(void)
{
size_t index = 0;
size_t length, maxLength;
while (*pLexBuffer == ' ' || *pLexBuffer == '\t') {
while ((*pLexBuffer == ' ') || (*pLexBuffer == '\t'))
pLexBuffer++;
}
while (*pLexBuffer != ',' && (*pLexBuffer != '\n')) {
while ((*pLexBuffer != ',') && (*pLexBuffer != '\n')) {
char ch = *pLexBuffer++;
if (ch == '\\') {
@@ -718,18 +702,21 @@ yylex_MACROARGS()
break;
default:
maxLength = MAXSTRLEN - index;
length = CopyMacroArg(&yylval.tzString[index], maxLength, ch);
length = CopyMacroArg(&yylval.tzString[index],
maxLength, ch);
if (length != 0)
index += length;
else
fatalerror("Illegal character escape '%c'", ch);
fatalerror("Illegal character escape '%c'",
ch);
ch = 0;
break;
}
} else if (ch == '{') {
index += yylex_ReadBracketedSymbol(yylval.tzString, index);
index += yylex_ReadBracketedSymbol(yylval.tzString,
index);
ch = 0;
}
if (ch)
@@ -739,7 +726,7 @@ yylex_MACROARGS()
if (index) {
yylex_StringWriteChar(yylval.tzString, index, 0);
// trim trailing white space at the end of the line
/* trim trailing white space at the end of the line */
if (*pLexBuffer == '\n')
yylex_TrimEnd(yylval.tzString, index);
@@ -753,12 +740,10 @@ yylex_MACROARGS()
return ',';
}
fatalerror("Internal error in yylex_MACROARGS");
return 0;
fatalerror("Internal error in %s", __func__);
}
ULONG
yylex(void)
uint32_t yylex(void)
{
switch (lexerstate) {
case LEX_STATE_NORMAL:
@@ -767,6 +752,5 @@ yylex(void)
return yylex_MACROARGS();
}
fatalerror("Internal error in yylex");
return 0;
fatalerror("Internal error in %s", __func__);
}

View File

@@ -1,89 +0,0 @@
#include "asm/symbol.h"
#include "asm/lexer.h"
#include "asm/rpn.h"
#include "asmy.h"
struct sLexInitString localstrings[] = {
{"adc", T_Z80_ADC},
{"add", T_Z80_ADD},
{"and", T_Z80_AND},
{"bit", T_Z80_BIT},
{"call", T_Z80_CALL},
{"ccf", T_Z80_CCF},
{"cpl", T_Z80_CPL},
{"cp", T_Z80_CP},
{"daa", T_Z80_DAA},
{"dec", T_Z80_DEC},
{"di", T_Z80_DI},
{"ei", T_Z80_EI},
{"halt", T_Z80_HALT},
{"inc", T_Z80_INC},
{"jp", T_Z80_JP},
{"jr", T_Z80_JR},
{"ld", T_Z80_LD},
{"ldi", T_Z80_LDI},
{"ldd", T_Z80_LDD},
{"ldio", T_Z80_LDIO},
{"ldh", T_Z80_LDIO},
{"nop", T_Z80_NOP},
{"or", T_Z80_OR},
{"pop", T_Z80_POP},
{"push", T_Z80_PUSH},
{"res", T_Z80_RES},
{"reti", T_Z80_RETI},
{"ret", T_Z80_RET},
{"rlca", T_Z80_RLCA},
{"rlc", T_Z80_RLC},
{"rla", T_Z80_RLA},
{"rl", T_Z80_RL},
{"rrc", T_Z80_RRC},
{"rrca", T_Z80_RRCA},
{"rra", T_Z80_RRA},
{"rr", T_Z80_RR},
{"rst", T_Z80_RST},
{"sbc", T_Z80_SBC},
{"scf", T_Z80_SCF},
/* Handled by globallex.c */
/* { "set", T_POP_SET }, */
{"sla", T_Z80_SLA},
{"sra", T_Z80_SRA},
{"srl", T_Z80_SRL},
{"stop", T_Z80_STOP},
{"sub", T_Z80_SUB},
{"swap", T_Z80_SWAP},
{"xor", T_Z80_XOR},
{"nz", T_CC_NZ},
{"z", T_CC_Z},
{"nc", T_CC_NC},
/* { "c", T_TOKEN_C }, */
{"[bc]", T_MODE_BC_IND},
{"[de]", T_MODE_DE_IND},
{"[hl]", T_MODE_HL_IND},
{"[hl+]", T_MODE_HL_INDINC},
{"[hl-]", T_MODE_HL_INDDEC},
{"[hli]", T_MODE_HL_INDINC},
{"[hld]", T_MODE_HL_INDDEC},
{"[sp]", T_MODE_SP_IND},
{"af", T_MODE_AF},
{"bc", T_MODE_BC},
{"de", T_MODE_DE},
{"hl", T_MODE_HL},
{"sp", T_MODE_SP},
{"[c]", T_MODE_C_IND},
{"[$ff00+c]", T_MODE_C_IND},
{"a", T_TOKEN_A},
{"b", T_TOKEN_B},
{"c", T_TOKEN_C},
{"d", T_TOKEN_D},
{"e", T_TOKEN_E},
{"h", T_TOKEN_H},
{"l", T_TOKEN_L},
{NULL, 0}
};

View File

@@ -1,6 +1,7 @@
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -8,26 +9,29 @@
#include "asm/symbol.h"
#include "asm/fstack.h"
#include "asm/lexer.h"
#include "asm/output.h"
#include "asm/main.h"
#include "extern/err.h"
#include "extern/reallocarray.h"
#include "extern/version.h"
int yyparse(void);
void setuplex(void);
extern int yyparse(void);
int cldefines_index;
int cldefines_size;
int32_t cldefines_index;
int32_t cldefines_size;
char **cldefines;
clock_t nStartClock, nEndClock;
SLONG nLineNo;
ULONG nTotalLines, nPass, nPC, nIFDepth, nErrors;
int32_t nLineNo;
uint32_t nTotalLines, nPass, nPC, nIFDepth, nUnionDepth, nErrors;
bool skipElif;
uint32_t unionStart[128], unionSize[128];
extern int yydebug;
/* extern int yydebug; */
FILE *dependfile;
extern char *tzObjectname;
/*
* Option stack
@@ -41,10 +45,9 @@ struct sOptionStackEntry {
struct sOptionStackEntry *pNext;
};
struct sOptionStackEntry *pOptionStack = NULL;
struct sOptionStackEntry *pOptionStack;
void
opt_SetCurrentOptions(struct sOptions * pOpt)
void opt_SetCurrentOptions(struct sOptions *pOpt)
{
if (nGBGfxID != -1) {
lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[0],
@@ -106,8 +109,7 @@ opt_SetCurrentOptions(struct sOptions * pOpt)
}
}
void
opt_Parse(char *s)
void opt_Parse(char *s)
{
struct sOptions newopt;
@@ -121,8 +123,7 @@ opt_Parse(char *s)
newopt.gbgfx[2] = s[3];
newopt.gbgfx[3] = s[4];
} else {
errx(1, "Must specify exactly 4 characters for "
"option 'g'");
errx(1, "Must specify exactly 4 characters for option 'g'");
}
break;
case 'b':
@@ -130,21 +131,18 @@ opt_Parse(char *s)
newopt.binary[0] = s[1];
newopt.binary[1] = s[2];
} else {
errx(1, "Must specify exactly 2 characters for option "
"'b'");
errx(1, "Must specify exactly 2 characters for option 'b'");
}
break;
case 'z':
if (strlen(&s[1]) <= 2) {
int result;
int32_t result;
result = sscanf(&s[1], "%lx", &newopt.fillchar);
if (!((result == EOF) || (result == 1))) {
result = sscanf(&s[1], "%x", &newopt.fillchar);
if (!((result == EOF) || (result == 1)))
errx(1, "Invalid argument for option 'z'");
}
} else {
errx(1, "Invalid argument for option 'z'");
exit(1);
}
break;
default:
@@ -155,77 +153,67 @@ opt_Parse(char *s)
opt_SetCurrentOptions(&newopt);
}
void
opt_Push(void)
void opt_Push(void)
{
struct sOptionStackEntry *pOpt;
if ((pOpt = malloc(sizeof(struct sOptionStackEntry))) != NULL) {
pOpt = malloc(sizeof(struct sOptionStackEntry));
if (pOpt == NULL)
fatalerror("No memory for option stack");
pOpt->Options = CurrentOptions;
pOpt->pNext = pOptionStack;
pOptionStack = pOpt;
} else
fatalerror("No memory for option stack");
}
void
opt_Pop(void)
void opt_Pop(void)
{
if (pOptionStack) {
if (pOptionStack == NULL)
fatalerror("No entries in the option stack");
struct sOptionStackEntry *pOpt;
pOpt = pOptionStack;
opt_SetCurrentOptions(&(pOpt->Options));
pOptionStack = pOpt->pNext;
free(pOpt);
} else
fatalerror("No entries in the option stack");
}
void
opt_AddDefine(char *s)
void opt_AddDefine(char *s)
{
char *value, *equals;
if(cldefines_index >= cldefines_size)
{
if (cldefines_index >= cldefines_size) {
cldefines_size *= 2;
cldefines = reallocarray(cldefines, cldefines_size,
2 * sizeof(void *));
if (!cldefines)
{
fatalerror("No memory for command line defines");
}
}
equals = strchr(s, '=');
if(equals)
{
if (equals) {
*equals = '\0';
value = equals + 1;
}
else
{
} else {
value = "1";
}
cldefines[cldefines_index++] = s;
cldefines[cldefines_index++] = value;
}
void
opt_ParseDefines()
static void opt_ParseDefines(void)
{
int i;
int32_t i;
for (i = 0; i < cldefines_index; i += 2)
{
sym_AddString(cldefines[i], cldefines[i + 1]);
}
}
/*
* Error handling
*/
void
verror(const char *fmt, va_list args)
void verror(const char *fmt, va_list args)
{
fprintf(stderr, "ERROR: ");
fstk_Dump();
@@ -235,32 +223,33 @@ verror(const char *fmt, va_list args)
nErrors += 1;
}
void
yyerror(const char *fmt, ...)
void yyerror(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
verror(fmt, args);
va_end(args);
}
void
fatalerror(const char *fmt, ...)
void fatalerror(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
verror(fmt, args);
va_end(args);
exit(5);
}
void
warning(const char *fmt, ...)
void warning(const char *fmt, ...)
{
if (!CurrentOptions.warnings)
return;
va_list args;
va_start(args, fmt);
fprintf(stderr, "warning: ");
@@ -272,17 +261,15 @@ warning(const char *fmt, ...)
va_end(args);
}
static void
usage(void)
static void print_usage(void)
{
printf(
"Usage: rgbasm [-hvE] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
"usage: rgbasm [-EhVvw] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
" [-M dependfile] [-o outfile] [-p pad_value] file.asm\n");
exit(1);
}
int
main(int argc, char *argv[])
int main(int argc, char *argv[])
{
int ch;
char *ep;
@@ -294,15 +281,12 @@ main(int argc, char *argv[])
dependfile = NULL;
cldefines_size = 32;
cldefines = reallocarray(cldefines, cldefines_size,
2 * sizeof(void *));
cldefines = reallocarray(cldefines, cldefines_size, 2 * sizeof(void *));
if (!cldefines)
{
fatalerror("No memory for command line defines");
}
if (argc == 1)
usage();
print_usage();
/* yydebug=1; */
@@ -322,20 +306,22 @@ main(int argc, char *argv[])
newopt = CurrentOptions;
while ((ch = getopt(argc, argv, "b:D:g:hi:M:o:p:vEw")) != -1) {
while ((ch = getopt(argc, argv, "b:D:g:hi:M:o:p:EVvw")) != -1) {
switch (ch) {
case 'b':
if (strlen(optarg) == 2) {
newopt.binary[0] = optarg[1];
newopt.binary[1] = optarg[2];
} else {
errx(1, "Must specify exactly 2 characters for "
"option 'b'");
errx(1, "Must specify exactly 2 characters for option 'b'");
}
break;
case 'D':
opt_AddDefine(optarg);
break;
case 'E':
newopt.exportall = true;
break;
case 'g':
if (strlen(optarg) == 4) {
newopt.gbgfx[0] = optarg[1];
@@ -343,8 +329,7 @@ main(int argc, char *argv[])
newopt.gbgfx[2] = optarg[3];
newopt.gbgfx[3] = optarg[4];
} else {
errx(1, "Must specify exactly 4 characters for "
"option 'g'");
errx(1, "Must specify exactly 4 characters for option 'g'");
}
break;
case 'h':
@@ -354,34 +339,36 @@ main(int argc, char *argv[])
fstk_AddIncludePath(optarg);
break;
case 'M':
if ((dependfile = fopen(optarg, "w")) == NULL) {
dependfile = fopen(optarg, "w");
if (dependfile == NULL)
err(1, "Could not open dependfile %s", optarg);
}
break;
case 'o':
out_SetFileName(optarg);
break;
case 'p':
newopt.fillchar = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'p'");
}
if (newopt.fillchar < 0 || newopt.fillchar > 0xFF) {
errx(1, "Argument for option 'p' must be "
"between 0 and 0xFF");
}
if (newopt.fillchar < 0 || newopt.fillchar > 0xFF)
errx(1, "Argument for option 'p' must be between 0 and 0xFF");
break;
case 'V':
printf("rgbasm %s\n", get_package_version_string());
exit(0);
case 'v':
newopt.verbose = true;
break;
case 'E':
newopt.exportall = true;
break;
case 'w':
newopt.warnings = false;
break;
default:
usage();
print_usage();
/* NOTREACHED */
}
}
argc -= optind;
@@ -392,15 +379,14 @@ main(int argc, char *argv[])
DefaultOptions = CurrentOptions;
if (argc == 0)
usage();
print_usage();
tzMainfile = argv[argc - 1];
setuplex();
setup_lexer();
if (CurrentOptions.verbose) {
if (CurrentOptions.verbose)
printf("Assembling %s\n", tzMainfile);
}
if (dependfile) {
if (!tzObjectname)
@@ -414,6 +400,8 @@ main(int argc, char *argv[])
nLineNo = 1;
nTotalLines = 0;
nIFDepth = 0;
skipElif = true;
nUnionDepth = 0;
nPC = 0;
nPass = 1;
nErrors = 0;
@@ -422,24 +410,28 @@ main(int argc, char *argv[])
fstk_Init(tzMainfile);
opt_ParseDefines();
if (CurrentOptions.verbose) {
if (CurrentOptions.verbose)
printf("Pass 1...\n");
}
yy_set_state(LEX_STATE_NORMAL);
opt_SetCurrentOptions(&DefaultOptions);
if (yyparse() != 0 || nErrors != 0) {
if (yyparse() != 0 || nErrors != 0)
errx(1, "Assembly aborted in pass 1 (%ld errors)!", nErrors);
}
if (nIFDepth != 0) {
if (nIFDepth != 0)
errx(1, "Unterminated IF construct (%ld levels)!", nIFDepth);
if (nUnionDepth != 0) {
errx(1, "Unterminated UNION construct (%ld levels)!",
nUnionDepth);
}
nTotalLines = 0;
nLineNo = 1;
nIFDepth = 0;
skipElif = true;
nUnionDepth = 0;
nPC = 0;
nPass = 2;
nErrors = 0;
@@ -450,13 +442,11 @@ main(int argc, char *argv[])
opt_SetCurrentOptions(&DefaultOptions);
opt_ParseDefines();
if (CurrentOptions.verbose) {
if (CurrentOptions.verbose)
printf("Pass 2...\n");
}
if (yyparse() != 0 || nErrors != 0) {
if (yyparse() != 0 || nErrors != 0)
errx(1, "Assembly aborted in pass 2 (%ld errors)!", nErrors);
}
double timespent;
@@ -464,7 +454,7 @@ main(int argc, char *argv[])
timespent = ((double)(nEndClock - nStartClock))
/ (double)CLOCKS_PER_SEC;
if (CurrentOptions.verbose) {
printf("Success! %ld lines in %d.%02d seconds ", nTotalLines,
printf("Success! %u lines in %d.%02d seconds ", nTotalLines,
(int)timespent, ((int)(timespent * 100.0)) % 100);
if (timespent == 0)
printf("(INFINITY lines/minute)\n");

View File

@@ -3,146 +3,132 @@
*/
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include "types.h"
#include "asm/mymath.h"
#include "asm/symbol.h"
#define fix2double(i) ((double)(i/65536.0))
#define double2fix(d) ((SLONG)(d*65536.0))
#ifndef PI
#define PI (acos(-1))
#define fx2double(i) ((double)((i) / 65536.0))
#define double2fx(d) ((int32_t)((d) * 65536.0))
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/*
* Define the _PI symbol
*/
void
math_DefinePI(void)
void math_DefinePI(void)
{
sym_AddEqu("_PI", double2fix(PI));
sym_AddEqu("_PI", double2fx(M_PI));
}
/*
* Print a fixed point value
*/
void
math_Print(SLONG i)
void math_Print(int32_t i)
{
if (i >= 0)
printf("%ld.%05ld", i >> 16,
((SLONG) (fix2double(i) * 100000 + 0.5)) % 100000);
printf("%d.%05d", i >> 16,
((int32_t)(fx2double(i) * 100000 + 0.5)) % 100000);
else
printf("-%ld.%05ld", (-i) >> 16,
((SLONG) (fix2double(-i) * 100000 + 0.5)) % 100000);
printf("-%d.%05d", (-i) >> 16,
((int32_t)(fx2double(-i) * 100000 + 0.5)) % 100000);
}
/*
* Calculate sine
*/
SLONG
math_Sin(SLONG i)
int32_t math_Sin(int32_t i)
{
return (double2fix(sin(fix2double(i) * 2 * PI / 65536)));
return double2fx(sin(fx2double(i) * 2 * M_PI / 65536));
}
/*
* Calculate cosine
*/
SLONG
math_Cos(SLONG i)
int32_t math_Cos(int32_t i)
{
return (double2fix(cos(fix2double(i) * 2 * PI / 65536)));
return double2fx(cos(fx2double(i) * 2 * M_PI / 65536));
}
/*
* Calculate tangent
*/
SLONG
math_Tan(SLONG i)
int32_t math_Tan(int32_t i)
{
return (double2fix(tan(fix2double(i) * 2 * PI / 65536)));
return double2fx(tan(fx2double(i) * 2 * M_PI / 65536));
}
/*
* Calculate arcsine
*/
SLONG
math_ASin(SLONG i)
int32_t math_ASin(int32_t i)
{
return (double2fix(asin(fix2double(i)) / 2 / PI * 65536));
return double2fx(asin(fx2double(i)) / 2 / M_PI * 65536);
}
/*
* Calculate arccosine
*/
SLONG
math_ACos(SLONG i)
int32_t math_ACos(int32_t i)
{
return (double2fix(acos(fix2double(i)) / 2 / PI * 65536));
return double2fx(acos(fx2double(i)) / 2 / M_PI * 65536);
}
/*
* Calculate arctangent
*/
SLONG
math_ATan(SLONG i)
int32_t math_ATan(int32_t i)
{
return (double2fix(atan(fix2double(i)) / 2 / PI * 65536));
return double2fx(atan(fx2double(i)) / 2 / M_PI * 65536);
}
/*
* Calculate atan2
*/
SLONG
math_ATan2(SLONG i, SLONG j)
int32_t math_ATan2(int32_t i, int32_t j)
{
return (double2fix
(atan2(fix2double(i), fix2double(j)) / 2 / PI * 65536));
return double2fx(atan2(fx2double(i), fx2double(j)) / 2 / M_PI * 65536);
}
/*
* Multiplication
*/
SLONG
math_Mul(SLONG i, SLONG j)
int32_t math_Mul(int32_t i, int32_t j)
{
return (double2fix(fix2double(i) * fix2double(j)));
return double2fx(fx2double(i) * fx2double(j));
}
/*
* Division
*/
SLONG
math_Div(SLONG i, SLONG j)
int32_t math_Div(int32_t i, int32_t j)
{
return (double2fix(fix2double(i) / fix2double(j)));
return double2fx(fx2double(i) / fx2double(j));
}
/*
* Round
*/
SLONG
math_Round(SLONG i)
int32_t math_Round(int32_t i)
{
return double2fix(round(fix2double(i)));
return double2fx(round(fx2double(i)));
}
/*
* Ceil
*/
SLONG
math_Ceil(SLONG i)
int32_t math_Ceil(int32_t i)
{
return double2fix(ceil(fix2double(i)));
return double2fx(ceil(fx2double(i)));
}
/*
* Floor
*/
SLONG
math_Floor(SLONG i)
int32_t math_Floor(int32_t i)
{
return double2fix(floor(fix2double(i)));
return double2fx(floor(fx2double(i)));
}

View File

@@ -4,94 +4,107 @@
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "asm/asm.h"
#include "asm/charmap.h"
#include "asm/output.h"
#include "asm/symbol.h"
#include "asm/mylink.h"
#include "asm/main.h"
#include "asm/rpn.h"
#include "asm/fstack.h"
#include "asm/main.h"
#include "asm/output.h"
#include "asm/rpn.h"
#include "asm/symbol.h"
#include "extern/err.h"
#include "common.h"
#include "linkdefs.h"
void out_SetCurrentSection(struct Section *pSect);
struct Patch {
char tzFilename[_MAX_PATH + 1];
ULONG nLine;
ULONG nOffset;
UBYTE nType;
ULONG nRPNSize;
UBYTE *pRPN;
uint32_t nLine;
uint32_t nOffset;
uint8_t nType;
uint32_t nRPNSize;
uint8_t *pRPN;
struct Patch *pNext;
};
struct PatchSymbol {
ULONG ID;
uint32_t ID;
struct sSymbol *pSymbol;
struct PatchSymbol *pNext;
struct PatchSymbol *pBucketNext; // next symbol in hash table bucket
struct PatchSymbol *pBucketNext; /* next symbol in hash table bucket */
};
struct SectionStackEntry {
struct Section *pSection;
struct sSymbol *pScope; /* Section's symbol scope */
struct SectionStackEntry *pNext;
};
struct PatchSymbol *tHashedPatchSymbols[HASHSIZE];
struct Section *pSectionList = NULL, *pCurrentSection = NULL;
struct PatchSymbol *pPatchSymbols = NULL;
struct Section *pSectionList, *pCurrentSection;
struct PatchSymbol *pPatchSymbols;
struct PatchSymbol **ppPatchSymbolsTail = &pPatchSymbols;
char *tzObjectname;
struct SectionStackEntry *pSectionStack = NULL;
struct SectionStackEntry *pSectionStack;
/*
* Section stack routines
*/
void
out_PushSection(void)
void out_PushSection(void)
{
struct SectionStackEntry *pSect;
if ((pSect = malloc(sizeof(struct SectionStackEntry))) != NULL) {
pSect = malloc(sizeof(struct SectionStackEntry));
if (pSect == NULL)
fatalerror("No memory for section stack");
pSect->pSection = pCurrentSection;
pSect->pScope = sym_GetCurrentSymbolScope();
pSect->pNext = pSectionStack;
pSectionStack = pSect;
} else
fatalerror("No memory for section stack");
}
void
out_PopSection(void)
void out_PopSection(void)
{
if (pSectionStack) {
if (pSectionStack == NULL)
fatalerror("No entries in the section stack");
struct SectionStackEntry *pSect;
pSect = pSectionStack;
out_SetCurrentSection(pSect->pSection);
sym_SetCurrentSymbolScope(pSect->pScope);
pSectionStack = pSect->pNext;
free(pSect);
} else
fatalerror("No entries in the section stack");
}
ULONG
getmaxsectionsize(ULONG secttype, char * sectname)
static uint32_t getmaxsectionsize(uint32_t secttype, char *sectname)
{
switch (secttype)
{
case SECT_ROM0: return 0x8000; /* If ROMX sections not used. */
case SECT_ROMX: return 0x4000;
case SECT_VRAM: return 0x2000;
case SECT_SRAM: return 0x2000;
case SECT_WRAM0: return 0x2000; /* If WRAMX sections not used. */
case SECT_WRAMX: return 0x1000;
case SECT_OAM: return 0xA0;
case SECT_HRAM: return 0x7F;
default: break;
switch (secttype) {
case SECT_ROM0:
return 0x8000; /* If ROMX sections not used */
case SECT_ROMX:
return 0x4000;
case SECT_VRAM:
return 0x2000;
case SECT_SRAM:
return 0x2000;
case SECT_WRAM0:
return 0x2000; /* If WRAMX sections not used */
case SECT_WRAMX:
return 0x1000;
case SECT_OAM:
return 0xA0;
case SECT_HRAM:
return 0x7F;
default:
break;
}
errx(1, "Section \"%s\" has an invalid section type.", sectname);
}
@@ -99,11 +112,10 @@ getmaxsectionsize(ULONG secttype, char * sectname)
/*
* Count the number of symbols used in this object
*/
ULONG
countsymbols(void)
static uint32_t countsymbols(void)
{
struct PatchSymbol *pSym;
ULONG count = 0;
uint32_t count = 0;
pSym = pPatchSymbols;
@@ -118,11 +130,10 @@ countsymbols(void)
/*
* Count the number of sections used in this object
*/
ULONG
countsections(void)
static uint32_t countsections(void)
{
struct Section *pSect;
ULONG count = 0;
uint32_t count = 0;
pSect = pSectionList;
@@ -137,11 +148,10 @@ countsections(void)
/*
* Count the number of patches used in this object
*/
ULONG
countpatches(struct Section * pSect)
static uint32_t countpatches(struct Section *pSect)
{
struct Patch *pPatch;
ULONG r = 0;
uint32_t r = 0;
pPatch = pSect->pPatches;
while (pPatch) {
@@ -155,8 +165,7 @@ countpatches(struct Section * pSect)
/*
* Write a long to a file (little-endian)
*/
void
fputlong(ULONG i, FILE * f)
static void fputlong(uint32_t i, FILE *f)
{
fputc(i, f);
fputc(i >> 8, f);
@@ -167,8 +176,7 @@ fputlong(ULONG i, FILE * f)
/*
* Write a NULL-terminated string to a file
*/
void
fputstring(char *s, FILE * f)
static void fputstring(char *s, FILE *f)
{
while (*s)
fputc(*s++, f);
@@ -178,30 +186,28 @@ fputstring(char *s, FILE * f)
/*
* Return a section's ID
*/
ULONG
getsectid(struct Section * pSect)
static uint32_t getsectid(struct Section *pSect)
{
struct Section *sec;
ULONG ID = 0;
uint32_t ID = 0;
sec = pSectionList;
while (sec) {
if (sec == pSect)
return (ID);
return ID;
ID += 1;
sec = sec->pNext;
}
fatalerror("INTERNAL: Unknown section");
return ((ULONG) - 1);
fatalerror("%s: Unknown section", __func__);
return (uint32_t)(-1);
}
/*
* Write a patch to a file
*/
void
writepatch(struct Patch * pPatch, FILE * f)
static void writepatch(struct Patch *pPatch, FILE *f)
{
fputstring(pPatch->tzFilename, f);
fputlong(pPatch->nLine, f);
@@ -214,8 +220,7 @@ writepatch(struct Patch * pPatch, FILE * f)
/*
* Write a section to a file
*/
void
writesection(struct Section * pSect, FILE * f)
static void writesection(struct Section *pSect, FILE *f)
{
fputstring(pSect->pzName, f);
@@ -227,8 +232,7 @@ writesection(struct Section * pSect, FILE * f)
fputlong(pSect->nBank, f);
fputlong(pSect->nAlign, f);
if ((pSect->nType == SECT_ROM0)
|| (pSect->nType == SECT_ROMX)) {
if ((pSect->nType == SECT_ROM0) || (pSect->nType == SECT_ROMX)) {
struct Patch *pPatch;
fwrite(pSect->tData, 1, pSect->nPC, f);
@@ -245,13 +249,12 @@ writesection(struct Section * pSect, FILE * f)
/*
* Write a symbol to a file
*/
void
writesymbol(struct sSymbol * pSym, FILE * f)
static void writesymbol(struct sSymbol *pSym, FILE *f)
{
char symname[MAXSYMLEN * 2 + 1];
ULONG type;
ULONG offset;
SLONG sectid;
uint32_t type;
uint32_t offset;
int32_t sectid;
if (pSym->nType & SYMF_IMPORT) {
/* Symbol should be imported */
@@ -282,6 +285,9 @@ writesymbol(struct sSymbol * pSym, FILE * f)
fputc(type, f);
if (type != SYM_IMPORT) {
fputstring(pSym->tzFileName, f);
fputlong(pSym->nFileLine, f);
fputlong(sectid, f);
fputlong(offset, f);
}
@@ -290,12 +296,12 @@ writesymbol(struct sSymbol * pSym, FILE * f)
/*
* Add a symbol to the object
*/
ULONG
addsymbol(struct sSymbol * pSym)
static uint32_t nextID;
static uint32_t addsymbol(struct sSymbol *pSym)
{
struct PatchSymbol *pPSym, **ppPSym;
static ULONG nextID = 0;
ULONG hash;
uint32_t hash;
hash = calchash(pSym->tzName);
ppPSym = &(tHashedPatchSymbols[hash]);
@@ -306,13 +312,16 @@ addsymbol(struct sSymbol * pSym)
ppPSym = &((*ppPSym)->pBucketNext);
}
if ((*ppPSym = pPSym = malloc(sizeof(struct PatchSymbol))) != NULL) {
pPSym = malloc(sizeof(struct PatchSymbol));
*ppPSym = pPSym;
if (pPSym == NULL)
fatalerror("No memory for patchsymbol");
pPSym->pNext = NULL;
pPSym->pBucketNext = NULL;
pPSym->pSymbol = pSym;
pPSym->ID = nextID++;
} else
fatalerror("No memory for patchsymbol");
*ppPatchSymbolsTail = pPSym;
ppPatchSymbolsTail = &(pPSym->pNext);
@@ -323,10 +332,9 @@ addsymbol(struct sSymbol * pSym)
/*
* Add all exported symbols to the object
*/
void
addexports(void)
static void addexports(void)
{
int i;
int32_t i;
for (i = 0; i < HASHSIZE; i += 1) {
struct sSymbol *pSym;
@@ -343,34 +351,33 @@ addexports(void)
/*
* Allocate a new patchstructure and link it into the list
*/
struct Patch *
allocpatch(void)
struct Patch *allocpatch(void)
{
struct Patch *pPatch;
if ((pPatch = malloc(sizeof(struct Patch))) != NULL) {
pPatch = malloc(sizeof(struct Patch));
if (pPatch == NULL)
fatalerror("No memory for patch");
pPatch->pNext = pCurrentSection->pPatches;
pPatch->nRPNSize = 0;
pPatch->pRPN = NULL;
} else
fatalerror("No memory for patch");
pCurrentSection->pPatches = pPatch;
return (pPatch);
return pPatch;
}
/*
* Create a new patch (includes the rpn expr)
*/
void
createpatch(ULONG type, struct Expression * expr)
void createpatch(uint32_t type, struct Expression *expr)
{
struct Patch *pPatch;
UWORD rpndata;
UBYTE rpnexpr[2048];
uint16_t rpndata;
uint8_t rpnexpr[2048];
char tzSym[512];
ULONG rpnptr = 0, symptr;
uint32_t rpnptr = 0, symptr;
pPatch = allocpatch();
pPatch->nType = type;
@@ -389,9 +396,11 @@ createpatch(ULONG type, struct Expression * expr)
break;
case RPN_SYM:
symptr = 0;
while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0);
while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0)
;
if (sym_isConstant(tzSym)) {
ULONG value;
uint32_t value;
value = sym_GetConstantValue(tzSym);
rpnexpr[rpnptr++] = RPN_CONST;
@@ -400,9 +409,11 @@ createpatch(ULONG type, struct Expression * expr)
rpnexpr[rpnptr++] = value >> 16;
rpnexpr[rpnptr++] = value >> 24;
} else {
struct sSymbol *sym;
if ((sym = sym_FindSymbol(tzSym)) == NULL)
struct sSymbol *sym = sym_FindSymbol(tzSym);
if (sym == NULL)
break;
symptr = addsymbol(sym);
rpnexpr[rpnptr++] = RPN_SYM;
rpnexpr[rpnptr++] = symptr & 0xFF;
@@ -411,26 +422,46 @@ createpatch(ULONG type, struct Expression * expr)
rpnexpr[rpnptr++] = symptr >> 24;
}
break;
case RPN_BANK: {
case RPN_BANK_SYM:
{
struct sSymbol *sym;
symptr = 0;
while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0);
if ((sym = sym_FindSymbol(tzSym)) == NULL)
while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0)
;
sym = sym_FindSymbol(tzSym);
if (sym == NULL)
break;
symptr = addsymbol(sym);
rpnexpr[rpnptr++] = RPN_BANK;
rpnexpr[rpnptr++] = RPN_BANK_SYM;
rpnexpr[rpnptr++] = symptr & 0xFF;
rpnexpr[rpnptr++] = symptr >> 8;
rpnexpr[rpnptr++] = symptr >> 16;
rpnexpr[rpnptr++] = symptr >> 24;
}
break;
}
case RPN_BANK_SECT:
{
uint16_t b;
rpnexpr[rpnptr++] = RPN_BANK_SECT;
do {
b = rpn_PopByte(expr);
rpnexpr[rpnptr++] = b & 0xFF;
} while (b != 0);
break;
}
default:
rpnexpr[rpnptr++] = rpndata;
break;
}
}
if ((pPatch->pRPN = malloc(rpnptr)) != NULL) {
pPatch->pRPN = malloc(rpnptr);
if (pPatch->pRPN != NULL) {
memcpy(pPatch->pRPN, rpnexpr, rpnptr);
pPatch->nRPNSize = rpnptr;
}
@@ -439,12 +470,9 @@ createpatch(ULONG type, struct Expression * expr)
/*
* A quick check to see if we have an initialized section
*/
void
checksection(void)
static void checksection(void)
{
if (pCurrentSection)
return;
else
if (pCurrentSection == NULL)
fatalerror("Code generation before SECTION directive");
}
@@ -452,24 +480,24 @@ checksection(void)
* A quick check to see if we have an initialized section that can contain
* this much initialized data
*/
void
checkcodesection(void)
static void checkcodesection(void)
{
checksection();
if (pCurrentSection->nType != SECT_ROM0 &&
pCurrentSection->nType != SECT_ROMX) {
fatalerror("Section '%s' cannot contain code or data (not ROM0 or ROMX)",
pCurrentSection->pzName);
} else if (nUnionDepth > 0) {
fatalerror("UNIONs cannot contain code or data");
}
}
/*
* Check if the section has grown too much.
*/
void
checksectionoverflow(ULONG delta_size)
static void checksectionoverflow(uint32_t delta_size)
{
ULONG maxsize = getmaxsectionsize(pCurrentSection->nType,
uint32_t maxsize = getmaxsectionsize(pCurrentSection->nType,
pCurrentSection->pzName);
if (pCurrentSection->nPC + delta_size > maxsize) {
@@ -488,18 +516,26 @@ checksectionoverflow(ULONG delta_size)
/*
* Write an objectfile
*/
void
out_WriteObject(void)
void out_WriteObject(void)
{
FILE *f;
addexports();
if ((f = fopen(tzObjectname, "wb")) != NULL) {
/* If no path specified, don't write file */
if (tzObjectname == NULL)
return;
f = fopen(tzObjectname, "wb");
if (f == NULL)
fatalerror("Couldn't write file '%s'\n", tzObjectname);
struct PatchSymbol *pSym;
struct Section *pSect;
fwrite("RGB4", 1, 4, f);
fwrite(RGBDS_OBJECT_VERSION_STRING, 1,
strlen(RGBDS_OBJECT_VERSION_STRING), f);
fputlong(countsymbols(), f);
fputlong(countsections(), f);
@@ -517,13 +553,11 @@ out_WriteObject(void)
fclose(f);
}
}
/*
* Prepare for pass #2
*/
void
out_PrepPass2(void)
void out_PrepPass2(void)
{
struct Section *pSect;
@@ -539,13 +573,12 @@ out_PrepPass2(void)
/*
* Set the objectfilename
*/
void
out_SetFileName(char *s)
void out_SetFileName(char *s)
{
tzObjectname = s;
if (CurrentOptions.verbose) {
if (CurrentOptions.verbose)
printf("Output filename %s\n", s);
}
pSectionList = NULL;
pCurrentSection = NULL;
pPatchSymbols = NULL;
@@ -554,8 +587,8 @@ out_SetFileName(char *s)
/*
* Find a section by name and type. If it doesn't exist, create it
*/
struct Section *
out_FindSection(char *pzName, ULONG secttype, SLONG org, SLONG bank, SLONG alignment)
struct Section *out_FindSection(char *pzName, uint32_t secttype, int32_t org,
int32_t bank, int32_t alignment)
{
struct Section *pSect, **ppSect;
@@ -565,20 +598,27 @@ out_FindSection(char *pzName, ULONG secttype, SLONG org, SLONG bank, SLONG align
while (pSect) {
if (strcmp(pzName, pSect->pzName) == 0) {
if (secttype == pSect->nType
&& ((ULONG) org) == pSect->nOrg
&& ((ULONG) bank) == pSect->nBank
&& ((ULONG) alignment == pSect->nAlign)) {
return (pSect);
} else
fatalerror
("Section already exists but with a different type");
&& ((uint32_t)org) == pSect->nOrg
&& ((uint32_t)bank) == pSect->nBank
&& ((uint32_t)alignment == pSect->nAlign)) {
return pSect;
}
fatalerror("Section already exists but with a different type");
}
ppSect = &(pSect->pNext);
pSect = pSect->pNext;
}
if ((*ppSect = (pSect = malloc(sizeof(struct Section)))) != NULL) {
if ((pSect->pzName = malloc(strlen(pzName) + 1)) != NULL) {
pSect = malloc(sizeof(struct Section));
*ppSect = pSect;
if (pSect == NULL)
fatalerror("Not enough memory for section");
pSect->pzName = malloc(strlen(pzName) + 1);
if (pSect->pzName == NULL)
fatalerror("Not enough memory for sectionname");
strcpy(pSect->pzName, pzName);
pSect->nType = secttype;
pSect->nPC = 0;
@@ -590,29 +630,29 @@ out_FindSection(char *pzName, ULONG secttype, SLONG org, SLONG bank, SLONG align
pSect->charmap = NULL;
pPatchSymbols = NULL;
pSect->tData = NULL;
/* It is only needed to allocate memory for ROM sections. */
if (secttype == SECT_ROM0 || secttype == SECT_ROMX) {
/* It is only needed to allocate memory for ROM
* sections. */
ULONG sectsize = getmaxsectionsize(secttype, pzName);
if ((pSect->tData = malloc(sectsize)) == NULL)
fatalerror("Not enough memory for section");
}
return (pSect);
} else
fatalerror("Not enough memory for sectionname");
} else
fatalerror("Not enough memory for section");
uint32_t sectsize;
return (NULL);
sectsize = getmaxsectionsize(secttype, pzName);
pSect->tData = malloc(sectsize);
if (pSect->tData == NULL)
fatalerror("Not enough memory for section");
} else {
pSect->tData = NULL;
}
return (pSect);
}
/*
* Set the current section
*/
void
out_SetCurrentSection(struct Section * pSect)
void out_SetCurrentSection(struct Section *pSect)
{
if (nUnionDepth > 0)
fatalerror("Cannot change the section within a UNION");
pCurrentSection = pSect;
nPC = pSect->nPC;
@@ -623,8 +663,7 @@ out_SetCurrentSection(struct Section * pSect)
/*
* Set the current section by name and type
*/
void
out_NewSection(char *pzName, ULONG secttype)
void out_NewSection(char *pzName, uint32_t secttype)
{
out_SetCurrentSection(out_FindSection(pzName, secttype, -1, -1, 1));
}
@@ -632,8 +671,8 @@ out_NewSection(char *pzName, ULONG secttype)
/*
* Set the current section by name and type
*/
void
out_NewAbsSection(char *pzName, ULONG secttype, SLONG org, SLONG bank)
void out_NewAbsSection(char *pzName, uint32_t secttype, int32_t org,
int32_t bank)
{
out_SetCurrentSection(out_FindSection(pzName, secttype, org, bank, 1));
}
@@ -641,22 +680,21 @@ out_NewAbsSection(char *pzName, ULONG secttype, SLONG org, SLONG bank)
/*
* Set the current section by name and type, using a given byte alignment
*/
void
out_NewAlignedSection(char *pzName, ULONG secttype, SLONG alignment, SLONG bank)
void out_NewAlignedSection(char *pzName, uint32_t secttype, int32_t alignment,
int32_t bank)
{
if (alignment < 0 || alignment > 16) {
if (alignment < 0 || alignment > 16)
yyerror("Alignment must be between 0-16 bits.");
}
out_SetCurrentSection(out_FindSection(pzName, secttype, -1, bank, 1 << alignment));
out_SetCurrentSection(out_FindSection(pzName, secttype, -1, bank,
1 << alignment));
}
/*
* Output an absolute byte
* Output an absolute byte (bypassing ROM/union checks)
*/
void
out_AbsByte(int b)
void out_AbsByteBypassCheck(int32_t b)
{
checkcodesection();
checksectionoverflow(1);
b &= 0xFF;
if (nPass == 2)
@@ -667,8 +705,16 @@ out_AbsByte(int b)
pPCSymbol->nValue += 1;
}
void
out_AbsByteGroup(char *s, int length)
/*
* Output an absolute byte
*/
void out_AbsByte(int32_t b)
{
checkcodesection();
out_AbsByteBypassCheck(b);
}
void out_AbsByteGroup(char *s, int32_t length)
{
checkcodesection();
checksectionoverflow(length);
@@ -679,8 +725,7 @@ out_AbsByteGroup(char *s, int length)
/*
* Skip this many bytes
*/
void
out_Skip(int skip)
void out_Skip(int32_t skip)
{
checksection();
checksectionoverflow(skip);
@@ -689,6 +734,9 @@ out_Skip(int skip)
pCurrentSection->nPC += skip;
nPC += skip;
pPCSymbol->nValue += skip;
} else if (nUnionDepth > 0) {
while (skip--)
out_AbsByteBypassCheck(CurrentOptions.fillchar);
} else {
checkcodesection();
while (skip--)
@@ -699,8 +747,7 @@ out_Skip(int skip)
/*
* Output a NULL terminated string (excluding the NULL-character)
*/
void
out_String(char *s)
void out_String(char *s)
{
checkcodesection();
checksectionoverflow(strlen(s));
@@ -712,9 +759,7 @@ out_String(char *s)
* Output a relocatable byte. Checking will be done to see if it
* is an absolute value in disguise.
*/
void
out_RelByte(struct Expression * expr)
void out_RelByte(struct Expression *expr)
{
checkcodesection();
checksectionoverflow(1);
@@ -726,17 +771,16 @@ out_RelByte(struct Expression * expr)
pCurrentSection->nPC += 1;
nPC += 1;
pPCSymbol->nValue += 1;
} else
} else {
out_AbsByte(expr->nVal);
}
rpn_Reset(expr);
}
/*
* Output an absolute word
*/
void
out_AbsWord(int b)
void out_AbsWord(int32_t b)
{
checkcodesection();
checksectionoverflow(2);
@@ -754,10 +798,9 @@ out_AbsWord(int b)
* Output a relocatable word. Checking will be done to see if
* it's an absolute value in disguise.
*/
void
out_RelWord(struct Expression * expr)
void out_RelWord(struct Expression *expr)
{
ULONG b;
uint32_t b;
checkcodesection();
checksectionoverflow(2);
@@ -771,19 +814,19 @@ out_RelWord(struct Expression * expr)
pCurrentSection->nPC += 2;
nPC += 2;
pPCSymbol->nValue += 2;
} else
} else {
out_AbsWord(expr->nVal);
}
rpn_Reset(expr);
}
/*
* Output an absolute longword
*/
void
out_AbsLong(SLONG b)
void out_AbsLong(int32_t b)
{
checkcodesection();
checksectionoverflow(sizeof(SLONG));
checksectionoverflow(sizeof(int32_t));
if (nPass == 2) {
pCurrentSection->tData[nPC] = b & 0xFF;
pCurrentSection->tData[nPC + 1] = b >> 8;
@@ -799,10 +842,9 @@ out_AbsLong(SLONG b)
* Output a relocatable longword. Checking will be done to see if
* is an absolute value in disguise.
*/
void
out_RelLong(struct Expression * expr)
void out_RelLong(struct Expression *expr)
{
SLONG b;
int32_t b;
checkcodesection();
checksectionoverflow(4);
@@ -818,18 +860,18 @@ out_RelLong(struct Expression * expr)
pCurrentSection->nPC += 4;
nPC += 4;
pPCSymbol->nValue += 4;
} else
} else {
out_AbsLong(expr->nVal);
}
rpn_Reset(expr);
}
/*
* Output a PC-relative byte
*/
void
out_PCRelByte(struct Expression * expr)
void out_PCRelByte(struct Expression *expr)
{
SLONG b = expr->nVal;
int32_t b = expr->nVal;
checkcodesection();
checksectionoverflow(1);
@@ -844,17 +886,15 @@ out_PCRelByte(struct Expression * expr)
/*
* Output a binary file
*/
void
out_BinaryFile(char *s)
void out_BinaryFile(char *s)
{
FILE *f;
f = fstk_FindFile(s);
if (f == NULL) {
if (f == NULL)
err(1, "Unable to open incbin file '%s'", s);
}
SLONG fsize;
int32_t fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
@@ -864,8 +904,8 @@ out_BinaryFile(char *s)
checksectionoverflow(fsize);
if (nPass == 2) {
SLONG dest = nPC;
SLONG todo = fsize;
int32_t dest = nPC;
int32_t todo = fsize;
while (todo--)
pCurrentSection->tData[dest++] = fgetc(f);
@@ -876,8 +916,7 @@ out_BinaryFile(char *s)
fclose(f);
}
void
out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length)
void out_BinaryFileSlice(char *s, int32_t start_pos, int32_t length)
{
FILE *f;
@@ -888,11 +927,10 @@ out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length)
fatalerror("Number of bytes to read must be greater than zero");
f = fstk_FindFile(s);
if (f == NULL) {
if (f == NULL)
err(1, "Unable to open included file '%s'", s);
}
SLONG fsize;
int32_t fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
@@ -909,8 +947,8 @@ out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length)
checksectionoverflow(length);
if (nPass == 2) {
SLONG dest = nPC;
SLONG todo = length;
int32_t dest = nPC;
int32_t todo = length;
while (todo--)
pCurrentSection->tData[dest++] = fgetc(f);

View File

@@ -20,7 +20,7 @@
.Nd Game Boy assembler
.Sh SYNOPSIS
.Nm rgbasm
.Op Fl Ehvw
.Op Fl EhVvw
.Op Fl b Ar chars
.Op Fl D Ar name Ns Op = Ns Ar value
.Op Fl g Ar chars
@@ -72,6 +72,8 @@ Write an object file to the given filename.
.It Fl p Ar pad_value
When padding an image, pad with this value.
The default is 0x00.
.It Fl V
Print the version of the program and exit.
.It Fl v
Be verbose.
.It Fl w

View File

@@ -1,4 +1,4 @@
.\" Copyright (c) 2017 Antonio Nino Diaz <antonio_nd@outlook.com>
.\" Copyright (c) 2017-2018 Antonio Nino Diaz <antonio_nd@outlook.com>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -12,7 +12,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd April 17, 2017
.Dd January 7, 2018
.Dt RGBASM 5
.Os RGBDS Manual
.Sh NAME
@@ -275,7 +275,7 @@ Alternatively you can use = as a synonym for SET.
.Pp
.Dl COUNT = 2
.Pp
.It Sy RSSET , RERESET , RB , RW
.It Sy RSSET , RSRESET , RB , RW
.Pp
The RS group of commands is a handy way of defining structures:
.Pp
@@ -549,36 +549,46 @@ The following symbols are defined by the assembler:
.It Ic EQU Ta Ic __UTC_HOUR__ Ta Ta Current hour, 0-23
.It Ic EQU Ta Ic __UTC_MINUTE__ Ta Ta Current minute, 0-59
.It Ic EQU Ta Ic __UTC_SECOND__ Ta Ta Current second, 0-59
.It Ic EQU Ta Ic __RGBDS_MAJOR__ Ta Ta Major version number of RGBDS.
.It Ic EQU Ta Ic __RGBDS_MINOR__ Ta Ta Minor version number of RGBDS.
.It Ic EQU Ta Ic __RGBDS_PATCH__ Ta Ta Patch version number of RGBDS.
.El
.Pp
.Sh DEFINING DATA
.Ss Defining constant data
.Ic DB
defines a list of bytes that will be stored in the final image.
Ideal for tables and text.
Ideal for tables and text (which is not zero-terminated).
.Pp
.Dl DB 1,2,3,4,\[dq]This is a string\[dq]
.Pp
Alternatively, you can use
.Ic DW
to store a list of words.
to store a list of words (16-bits) or
.Ic DL
to store a list of doublewords/longs (32-bits).
Strings are not allowed as arguments to
.Ic DW .
.Ic DW
and
.Ic DL .
.Pp
You can also use
.Ic DB
and
.Ic DB ,
.Ic DW
without arguments.
This works exactly like
.Sy DS 1
and
.Ic DL
without arguments, or leaving empty elements at any point in the list.
This works exactly like
.Sy DS 1 ,
.Sy DS 2
and
.Sy DS 4
respectively.
Consequently,
.Ic DB
and
.Ic DB ,
.Ic DW
and
.Ic DL
can be used in a
.Sy WRAM0 No / Sy WRAMX No / Sy HRAM No / Sy VRAM No / Sy SRAM
section.
@@ -588,9 +598,10 @@ allocates a number of bytes.
The content is undefined.
This is the preferred method of allocationg space in a RAM section.
You can, however, use
.Ic DB
and
.Ic DB ,
.Ic DW
and
.Ic DL
without any arguments instead.
.Pp
.Dl DS str_SIZEOF ;allocate str_SIZEOF bytes
@@ -612,6 +623,41 @@ You can also include only part of a file with
The example below includes 256 bytes from data.bin starting from byte 78.
.Pp
.Dl INCBIN \[dq]data.bin\[dq],78,256
.Ss Unions
Unions allow multiple memory allocations to share the same space in memory,
like unions in C.
This allows you to easily reuse memory for different purposes, depending on
the game's state.
.Pp
You create unions using the
.Ic UNION ,
.Ic NEXTU
and
.Ic ENDU
keywords.
.Ic NEXTU
lets you create a new block of allocations, and you may use it as many times
within a union as necessary.
.Pp
.Bd -literal -offset indent
UNION
Name: ds 8
Nickname: ds 8
NEXTU
Health: dw
Something: ds 3
Lives: db
NEXTU
Temporary: ds 19
ENDU
.Ed
.Pp
This union will use up 19 bytes, as this is the size of the largest block
(the last one, containing 'Temporary').
Of course, as 'Name', 'Health', and 'Temporary' all point to the same memory
locations, writes to any one of these will affect values read from the others.
.Pp
Unions may be used in any section, but code and data may not be included.
.Sh THE MACRO LANGUAGE
.Pp
.Ss Printing things during assembly
@@ -704,27 +750,48 @@ calls infinitely (or until you run out of memory, whichever comes first).
.Dl INCLUDE \[dq]irq.inc\[dq]
.Pp
.Ss Conditional assembling
The three commands
The four commands
.Ic IF ,
.Ic ELSE
.Ic ELIF ,
.Ic ELSE ,
and
.Ic ENDC
are used to conditionally assemble parts of your file.
This is a powerful feature commonly used in macros.
.Pp
.Bd -literal -offset indent
IF 2+2==4
PRINTT \[dq]2+2==4\[rs]n\[dq]
IF NUM < 0
PRINTT \[dq]NUM < 0\[rs]n\[dq]
ELIF NUM == 0
PRINTT \[dq]NUM == 0\[rs]n\[dq]
ELSE
PRINTT \[dq]2+2!=4\[rs]n\[dq]
PRINTT \[dq]NUM > 0\[rs]n\[dq]
ENDC
.Ed
.Pp
The
.Ic ELIF
and
.Ic ELSE
block is optional.
.Ic IF No / Ic ELSE No / Ic ENDC
blocks are optional.
.Ic IF No / Ic ELIF No / Ic ELSE No / Ic ENDC
blocks can be nested.
.Pp
Note that if an
.Ic ELSE
block is found before an
.Ic ELIF
block, the
.Ic ELIF
block will be ignored.
All
.Ic ELIF
blocks must go before the
.Ic ELSE
block.
Also, if there is more than one
.Ic ELSE
block, all of them but the first one are ignored.
.Ss Integer and Boolean expressions
An expression can be composed of many things.
Expressions are always evaluated using signed 32-bit math.
@@ -902,9 +969,15 @@ There are a few other functions that do various useful things:
.Pp
.Bl -column ".Sy String" ".Sy String"
.It Sy Name Ta Ta Ta Sy Operation
.It Li BANK(label) Ta Returns the bank number label is in.
The linker will have to resolve this so it can't be used when the expression has
to be constant.
.It Li BANK(\@/str/lbl) Ta Returns a bank number.
If the argument is the symbol
.Ic \@,
this function returns the bank of the current section.
If the argument is a string, it returns the bank of the section that has that
name.
If the argument is a label, it returns the bank number the label is in.
For labels, as the linker has to resolve this, it can't be used when the
expression has to be constant.
.It Li DEF(label) Ta Returns TRUE if label has been defined.
.It Li HIGH(r16/cnst/lbl) Ta Returns the top 8 bits of the operand if it is a
label or constant, or the top 8-bit register if it is a 16-bit register.
@@ -956,6 +1029,15 @@ machine.
.It Sx __ISO_8601_UTC__
.It Sx __LINE__
.It Sx __TIME__
.It Sx __RGBDS_MAJOR__
.It Sx __RGBDS_MINOR__
.It Sx __RGBDS_PATCH__
.It Sx __UTC_YEAR__
.It Sx __UTC_MONTH__
.It Sx __UTC_DAY__
.It Sx __UTC_HOUR__
.It Sx __UTC_MINUTE__
.It Sx __UTC_SECOND__
.It Sx _NARG
.It Sx _PI
.It Sx _RS
@@ -968,8 +1050,10 @@ machine.
.It Sx DB
.It Sx DEF
.It Sx DIV
.It Sx DL
.It Sx DS
.It Sx DW
.It Sx ELIF
.It Sx ELSE
.It Sx ENDC
.It Sx ENDM

View File

@@ -2,19 +2,19 @@
* Controls RPN expressions for objectfiles
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "asm/mylink.h"
#include "types.h"
#include "asm/symbol.h"
#include "asm/asm.h"
#include "asm/main.h"
#include "asm/rpn.h"
#include "asm/symbol.h"
void
mergetwoexpressions(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
#include "linkdefs.h"
void mergetwoexpressions(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
*expr = *src1;
memcpy(&(expr->tRPN[expr->nRPNLength]), src2->tRPN, src2->nRPNLength);
@@ -23,13 +23,13 @@ mergetwoexpressions(struct Expression * expr, struct Expression * src1,
expr->isReloc |= src2->isReloc;
expr->isPCRel |= src2->isPCRel;
}
#define joinexpr() mergetwoexpressions(expr, src1, src2)
/*
* Add a byte to the RPN expression
*/
void
pushbyte(struct Expression * expr, int b)
void pushbyte(struct Expression *expr, int b)
{
expr->tRPN[expr->nRPNLength++] = b & 0xFF;
}
@@ -37,47 +37,45 @@ pushbyte(struct Expression * expr, int b)
/*
* Reset the RPN module
*/
void
rpn_Reset(struct Expression * expr)
void rpn_Reset(struct Expression *expr)
{
expr->nRPNLength = expr->nRPNOut = expr->isReloc = expr->isPCRel = 0;
expr->nRPNLength = 0;
expr->nRPNOut = 0;
expr->isReloc = 0;
expr->isPCRel = 0;
}
/*
* Returns the next rpn byte in expression
*/
UWORD
rpn_PopByte(struct Expression * expr)
uint16_t rpn_PopByte(struct Expression *expr)
{
if (expr->nRPNOut == expr->nRPNLength) {
return (0xDEAD);
} else
return (expr->tRPN[expr->nRPNOut++]);
if (expr->nRPNOut == expr->nRPNLength)
return 0xDEAD;
return expr->tRPN[expr->nRPNOut++];
}
/*
* Determine if the current expression is relocatable
*/
ULONG
rpn_isReloc(struct Expression * expr)
uint32_t rpn_isReloc(const struct Expression *expr)
{
return (expr->isReloc);
return expr->isReloc;
}
/*
* Determine if the current expression can be pc-relative
*/
ULONG
rpn_isPCRelative(struct Expression * expr)
uint32_t rpn_isPCRelative(const struct Expression *expr)
{
return (expr->isPCRel);
return expr->isPCRel;
}
/*
* Add symbols, constants and operators to expression
*/
void
rpn_Number(struct Expression * expr, ULONG i)
void rpn_Number(struct Expression *expr, uint32_t i)
{
rpn_Reset(expr);
pushbyte(expr, RPN_CONST);
@@ -88,11 +86,10 @@ rpn_Number(struct Expression * expr, ULONG i)
expr->nVal = i;
}
void
rpn_Symbol(struct Expression * expr, char *tzSym)
void rpn_Symbol(struct Expression *expr, char *tzSym)
{
if (!sym_isConstant(tzSym)) {
struct sSymbol *psym;
const struct sSymbol *psym;
rpn_Reset(expr);
@@ -106,62 +103,96 @@ rpn_Symbol(struct Expression * expr, char *tzSym)
while (*tzSym)
pushbyte(expr, *tzSym++);
pushbyte(expr, 0);
} else
} else {
rpn_Number(expr, sym_GetConstantValue(tzSym));
}
}
void
rpn_Bank(struct Expression * expr, char *tzSym)
void rpn_BankSelf(struct Expression *expr)
{
rpn_Reset(expr);
/*
* This symbol is not really relocatable, but this makes the assembler
* write this expression as a RPN patch to the object file.
*/
expr->isReloc = 1;
pushbyte(expr, RPN_BANK_SELF);
}
void rpn_BankSymbol(struct Expression *expr, char *tzSym)
{
/* The @ symbol is treated differently. */
if (sym_FindSymbol(tzSym) == pPCSymbol) {
rpn_BankSelf(expr);
return;
}
if (!sym_isConstant(tzSym)) {
rpn_Reset(expr);
/* Check that the symbol exists by evaluating and discarding the value. */
/*
* Check that the symbol exists by evaluating and discarding the
* value.
*/
sym_GetValue(tzSym);
expr->isReloc = 1;
pushbyte(expr, RPN_BANK);
pushbyte(expr, RPN_BANK_SYM);
while (*tzSym)
pushbyte(expr, *tzSym++);
pushbyte(expr, 0);
} else
} else {
yyerror("BANK argument must be a relocatable identifier");
}
}
void
rpn_CheckHRAM(struct Expression * expr, struct Expression * src)
void rpn_BankSection(struct Expression *expr, char *tzSectionName)
{
rpn_Reset(expr);
/*
* This symbol is not really relocatable, but this makes the assembler
* write this expression as a RPN patch to the object file.
*/
expr->isReloc = 1;
pushbyte(expr, RPN_BANK_SECT);
while (*tzSectionName)
pushbyte(expr, *tzSectionName++);
pushbyte(expr, 0);
}
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
{
*expr = *src;
pushbyte(expr, RPN_HRAM);
}
void
rpn_LOGNOT(struct Expression * expr, struct Expression * src)
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
{
*expr = *src;
pushbyte(expr, RPN_LOGUNNOT);
}
void
rpn_LOGOR(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_LOGOR(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal || src2->nVal);
pushbyte(expr, RPN_LOGOR);
}
void
rpn_LOGAND(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_LOGAND(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal && src2->nVal);
pushbyte(expr, RPN_LOGAND);
}
void
rpn_HIGH(struct Expression * expr, struct Expression * src)
void rpn_HIGH(struct Expression *expr, const struct Expression *src)
{
*expr = *src;
@@ -184,8 +215,7 @@ rpn_HIGH(struct Expression * expr, struct Expression * src)
pushbyte(expr, RPN_AND);
}
void
rpn_LOW(struct Expression * expr, struct Expression * src)
void rpn_LOW(struct Expression *expr, const struct Expression *src)
{
*expr = *src;
@@ -200,168 +230,150 @@ rpn_LOW(struct Expression * expr, struct Expression * src)
pushbyte(expr, RPN_AND);
}
void
rpn_LOGEQU(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal == src2->nVal);
pushbyte(expr, RPN_LOGEQ);
}
void
rpn_LOGGT(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_LOGGT(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal > src2->nVal);
pushbyte(expr, RPN_LOGGT);
}
void
rpn_LOGLT(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_LOGLT(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal < src2->nVal);
pushbyte(expr, RPN_LOGLT);
}
void
rpn_LOGGE(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_LOGGE(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal >= src2->nVal);
pushbyte(expr, RPN_LOGGE);
}
void
rpn_LOGLE(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_LOGLE(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal <= src2->nVal);
pushbyte(expr, RPN_LOGLE);
}
void
rpn_LOGNE(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_LOGNE(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal != src2->nVal);
pushbyte(expr, RPN_LOGNE);
}
void
rpn_ADD(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_ADD(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal + src2->nVal);
pushbyte(expr, RPN_ADD);
}
void
rpn_SUB(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_SUB(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal - src2->nVal);
pushbyte(expr, RPN_SUB);
}
void
rpn_XOR(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_XOR(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal ^ src2->nVal);
pushbyte(expr, RPN_XOR);
}
void
rpn_OR(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_OR(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal | src2->nVal);
pushbyte(expr, RPN_OR);
}
void
rpn_AND(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_AND(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal & src2->nVal);
pushbyte(expr, RPN_AND);
}
void
rpn_SHL(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_SHL(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal << src2->nVal);
pushbyte(expr, RPN_SHL);
}
void
rpn_SHR(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_SHR(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal >> src2->nVal);
pushbyte(expr, RPN_SHR);
}
void
rpn_MUL(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_MUL(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
expr->nVal = (expr->nVal * src2->nVal);
pushbyte(expr, RPN_MUL);
}
void
rpn_DIV(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_DIV(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
if (src2->nVal == 0) {
if (src2->nVal == 0)
fatalerror("division by zero");
}
expr->nVal = (expr->nVal / src2->nVal);
pushbyte(expr, RPN_DIV);
}
void
rpn_MOD(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
void rpn_MOD(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{
joinexpr();
if (src2->nVal == 0) {
if (src2->nVal == 0)
fatalerror("division by zero");
}
expr->nVal = (expr->nVal % src2->nVal);
pushbyte(expr, RPN_MOD);
}
void
rpn_UNNEG(struct Expression * expr, struct Expression * src)
void rpn_UNNEG(struct Expression *expr, const struct Expression *src)
{
*expr = *src;
expr->nVal = -expr->nVal;
pushbyte(expr, RPN_UNSUB);
}
void
rpn_UNNOT(struct Expression * expr, struct Expression * src)
void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
{
*expr = *src;
expr->nVal = expr->nVal ^ 0xFFFFFFFF;
expr->nVal = ~expr->nVal;
pushbyte(expr, RPN_UNNOT);
}

File diff suppressed because it is too large Load Diff

7
src/extern/err.c vendored
View File

@@ -21,9 +21,10 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "extern/err.h"
void rgbds_vwarn(const char *fmt, va_list ap)
@@ -72,6 +73,7 @@ noreturn void rgbds_verrx(int status, const char *fmt, va_list ap)
void rgbds_warn(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarn(fmt, ap);
va_end(ap);
@@ -80,6 +82,7 @@ void rgbds_warn(const char *fmt, ...)
void rgbds_warnx(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarnx(fmt, ap);
va_end(ap);
@@ -88,6 +91,7 @@ void rgbds_warnx(const char *fmt, ...)
noreturn void rgbds_err(int status, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
verr(status, fmt, ap);
va_end(ap);
@@ -96,6 +100,7 @@ noreturn void rgbds_err(int status, const char *fmt, ...)
noreturn void rgbds_errx(int status, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
verrx(status, fmt, ap);
va_end(ap);

View File

@@ -15,10 +15,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
@@ -26,11 +26,10 @@
*/
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
void *
rgbds_reallocarray(void *optr, size_t nmemb, size_t size)
void *rgbds_reallocarray(void *optr, size_t nmemb, size_t size)
{
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size) {
if (((nmemb >= MUL_NO_OVERFLOW) || (size >= MUL_NO_OVERFLOW)) &&
(nmemb > 0) && (SIZE_MAX / nmemb < size)) {
errno = ENOMEM;
return NULL;
}

View File

@@ -16,8 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#include <sys/types.h>
/*
* Appends src to string dst of size dsize (unlike strncat, dsize is the
@@ -26,8 +26,7 @@
* Returns strlen(src) + MIN(dsize, strlen(initial dst)).
* If retval >= dsize, truncation occurred.
*/
size_t
rgbds_strlcat(char *dst, const char *src, size_t dsize)
size_t rgbds_strlcat(char *dst, const char *src, size_t dsize)
{
const char *odst = dst;
const char *osrc = src;
@@ -51,5 +50,5 @@ rgbds_strlcat(char *dst, const char *src, size_t dsize)
}
*dst = '\0';
return(dlen + (src - osrc)); /* count does not include NUL */
return dlen + (src - osrc); /* count does not include NUL */
}

10
src/extern/strlcpy.c vendored
View File

@@ -16,16 +16,15 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#include <sys/types.h>
/*
* Copy string src to buffer dst of size dsize. At most dsize-1
* chars will be copied. Always NUL terminates (unless dsize == 0).
* Returns strlen(src); if retval >= dsize, truncation occurred.
*/
size_t
rgbds_strlcpy(char *dst, const char *src, size_t dsize)
size_t rgbds_strlcpy(char *dst, const char *src, size_t dsize)
{
const char *osrc = src;
size_t nleft = dsize;
@@ -33,7 +32,10 @@ rgbds_strlcpy(char *dst, const char *src, size_t dsize)
/* Copy as many bytes as will fit. */
if (nleft != 0) {
while (--nleft != 0) {
if ((*dst++ = *src++) == '\0')
char n = *src++;
*dst++ = n;
if (n == '\0')
break;
}
}

34
src/extern/version.c vendored Normal file
View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2017 Antonio Nino Diaz <antonio_nd@outlook.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include "extern/version.h"
const char *get_package_version_string(void)
{
static char s[50];
/* The following conditional should be simplified by the compiler. */
if (strlen(BUILD_VERSION_STRING) == 0) {
snprintf(s, sizeof(s), "v%d.%d.%d", PACKAGE_VERSION_MAJOR,
PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCH);
return s;
} else {
return BUILD_VERSION_STRING;
}
}

View File

@@ -22,19 +22,18 @@
#include <unistd.h>
#include "extern/err.h"
#include "extern/version.h"
static void
usage(void)
static void print_usage(void)
{
printf(
"usage: rgbfix [-Ccjsv] [-i game_id] [-k licensee_str] [-l licensee_id]\n"
"usage: rgbfix [-CcjsVv] [-i game_id] [-k licensee_str] [-l licensee_id]\n"
" [-m mbc_type] [-n rom_version] [-p pad_value] [-r ram_size]\n"
" [-t title_str] file\n");
exit(1);
}
int
main(int argc, char *argv[])
int main(int argc, char *argv[])
{
FILE *rom;
int ch;
@@ -63,13 +62,13 @@ main(int argc, char *argv[])
char *id; /* game ID in ASCII */
char *newlicensee; /* new licensee ID, two ASCII characters */
int licensee; /* old licensee ID */
int cartridge; /* cartridge hardware ID */
int ramsize; /* RAM size ID */
int version; /* mask ROM version number */
int padvalue; /* to pad the rom with if it changes size */
int licensee = 0; /* old licensee ID */
int cartridge = 0; /* cartridge hardware ID */
int ramsize = 0; /* RAM size ID */
int version = 0; /* mask ROM version number */
int padvalue = 0; /* to pad the rom with if it changes size */
while ((ch = getopt(argc, argv, "Cci:jk:l:m:n:p:sr:t:v")) != -1) {
while ((ch = getopt(argc, argv, "Cci:jk:l:m:n:p:sr:t:Vv")) != -1) {
switch (ch) {
case 'C':
coloronly = true;
@@ -80,10 +79,9 @@ main(int argc, char *argv[])
case 'i':
setid = true;
if (strlen(optarg) != 4) {
errx(1, "Game ID %s must be exactly 4 "
"characters", optarg);
}
if (strlen(optarg) != 4)
errx(1, "Game ID %s must be exactly 4 characters",
optarg);
id = optarg;
break;
@@ -93,10 +91,9 @@ main(int argc, char *argv[])
case 'k':
setnewlicensee = true;
if (strlen(optarg) != 2) {
errx(1, "New licensee code %s is not the "
"correct length of 2 characters", optarg);
}
if (strlen(optarg) != 2)
errx(1, "New licensee code %s is not the correct length of 2 characters",
optarg);
newlicensee = optarg;
break;
@@ -104,61 +101,59 @@ main(int argc, char *argv[])
setlicensee = true;
licensee = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'l'");
}
if (licensee < 0 || licensee > 0xFF) {
errx(1, "Argument for option 'l' must be "
"between 0 and 255");
}
if (licensee < 0 || licensee > 0xFF)
errx(1, "Argument for option 'l' must be between 0 and 255");
break;
case 'm':
setcartridge = true;
cartridge = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'm'");
}
if (cartridge < 0 || cartridge > 0xFF) {
errx(1, "Argument for option 'm' must be "
"between 0 and 255");
}
if (cartridge < 0 || cartridge > 0xFF)
errx(1, "Argument for option 'm' must be between 0 and 255");
break;
case 'n':
setversion = true;
version = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'n'");
}
if (version < 0 || version > 0xFF) {
errx(1, "Argument for option 'n' must be "
"between 0 and 255");
}
if (version < 0 || version > 0xFF)
errx(1, "Argument for option 'n' must be between 0 and 255");
break;
case 'p':
resize = true;
padvalue = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'p'");
}
if (padvalue < 0 || padvalue > 0xFF) {
errx(1, "Argument for option 'p' must be "
"between 0 and 255");
}
if (padvalue < 0 || padvalue > 0xFF)
errx(1, "Argument for option 'p' must be between 0 and 255");
break;
case 'r':
setramsize = true;
ramsize = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'r'");
}
if (ramsize < 0 || ramsize > 0xFF) {
errx(1, "Argument for option 'r' must be "
"between 0 and 255");
}
if (ramsize < 0 || ramsize > 0xFF)
errx(1, "Argument for option 'r' must be between 0 and 255");
break;
case 's':
super = true;
@@ -166,22 +161,24 @@ main(int argc, char *argv[])
case 't':
settitle = true;
if (strlen(optarg) > 16) {
errx(1, "Title %s is greater than the "
"maximum of 16 characters", optarg);
}
if (strlen(optarg) > 16)
errx(1, "Title \"%s\" is greater than the maximum of 16 characters",
optarg);
if (strlen(optarg) == 16)
warnx("Title %s is 16 chars, it is best to "
"keep it to 15 or fewer", optarg);
warnx("Title \"%s\" is 16 chars, it is best to keep it to 15 or fewer",
optarg);
title = optarg;
break;
case 'V':
printf("rgbfix %s\n", get_package_version_string());
exit(0);
case 'v':
validate = true;
break;
default:
usage();
print_usage();
/* NOTREACHED */
}
}
@@ -190,15 +187,16 @@ main(int argc, char *argv[])
argv += optind;
if (argc == 0)
usage();
print_usage();
/*
* Open the ROM file
*/
if ((rom = fopen(argv[argc - 1], "rb+")) == NULL) {
rom = fopen(argv[argc - 1], "rb+");
if (rom == NULL)
err(1, "Error opening file %s", argv[argc - 1]);
}
/*
* Write changes to ROM
@@ -328,8 +326,7 @@ main(int argc, char *argv[])
*/
if (!setlicensee)
warnx("You should probably set both '-s' and "
"'-l 0x33'");
warnx("You should probably set both '-s' and '-l 0x33'");
fseek(rom, 0x146, SEEK_SET);
fputc(3, rom);
@@ -356,6 +353,7 @@ main(int argc, char *argv[])
long romsize, newsize;
int headbyte;
uint8_t *buf;
fseek(rom, 0, SEEK_END);
romsize = ftell(rom);
newsize = 0x8000;
@@ -429,9 +427,8 @@ main(int argc, char *argv[])
* Offset 0x14D: Header Checksum
*/
uint8_t headcksum;
uint8_t headcksum = 0;
headcksum = 0;
fseek(rom, 0x134, SEEK_SET);
for (int i = 0; i < (0x14D - 0x134); ++i)
headcksum = headcksum - fgetc(rom) - 1;
@@ -443,15 +440,14 @@ main(int argc, char *argv[])
* Offset 0x14E0x14F: Global Checksum
*/
uint16_t globalcksum;
globalcksum = 0;
uint16_t globalcksum = 0;
rewind(rom);
for (int i = 0; i < 0x14E; ++i)
globalcksum += fgetc(rom);
int byte;
fseek(rom, 0x150, SEEK_SET);
while ((byte = fgetc(rom)) != EOF)
globalcksum += byte;

View File

@@ -20,7 +20,7 @@
.Nd Game Boy checksum fixer
.Sh SYNOPSIS
.Nm rgbfix
.Op Fl Ccjsv
.Op Fl CcjsVv
.Op Fl i Ar game_id
.Op Fl k Ar licensee_str
.Op Fl l Ar licensee_id
@@ -108,6 +108,8 @@ or
.Pc .
If both this and the game ID are set, the game ID will overwrite the
overlapping portion of the title.
.It Fl V
Print the version of the program and exit.
.It Fl v
Validate the header and fix checksums: the Nintendo character area
.Pq Ad 0x104 Ns \(en Ns Ad 0x133 ,

View File

@@ -201,7 +201,7 @@ and
.It Sx PUSH AF
.It Sx PUSH r16
.El
.Ss Miscelaneous Instructions
.Ss Miscellaneous Instructions
.Bl -inset -compact
.It Sx CCF
.It Sx CPL

View File

@@ -19,8 +19,7 @@
#include "gfx/main.h"
void
transpose_tiles(struct GBImage *gb, int width)
void transpose_tiles(struct GBImage *gb, int width)
{
uint8_t *newdata;
int i;
@@ -29,7 +28,9 @@ transpose_tiles(struct GBImage *gb, int width)
newdata = calloc(gb->size, 1);
for (i = 0; i < gb->size; i++) {
newbyte = i / (8 * depth) * width * 8 * depth;
newbyte = newbyte % gb->size + 8 * depth * (newbyte / gb->size) + i % (8 * depth);
newbyte = newbyte % gb->size
+ 8 * depth * (newbyte / gb->size)
+ i % (8 * depth);
newdata[newbyte] = gb->data[i];
}
@@ -38,8 +39,7 @@ transpose_tiles(struct GBImage *gb, int width)
gb->data = newdata;
}
void
png_to_gb(struct PNGImage png, struct GBImage *gb)
void png_to_gb(const struct PNGImage png, struct GBImage *gb)
{
int x, y, byte;
png_byte index;
@@ -50,55 +50,55 @@ png_to_gb(struct PNGImage png, struct GBImage *gb)
index &= (1 << depth) - 1;
if (!gb->horizontal) {
byte = y * depth + x / 8 * png.height / 8 * 8 * depth;
byte = y * depth
+ x / 8 * png.height / 8 * 8 * depth;
} else {
byte = y * depth + x / 8 * png.height / 8 * 8 * depth;
byte = y * depth
+ x / 8 * png.height / 8 * 8 * depth;
}
gb->data[byte] |= (index & 1) << (7 - x % 8);
if (depth == 2) {
gb->data[byte + 1] |= (index >> 1) << (7 - x % 8);
gb->data[byte + 1] |=
(index >> 1) << (7 - x % 8);
}
}
}
if (!gb->horizontal) {
if (!gb->horizontal)
transpose_tiles(gb, png.width / 8);
}
}
void
output_file(struct Options opts, struct GBImage gb)
void output_file(const struct Options opts, const struct GBImage gb)
{
FILE *f;
f = fopen(opts.outfile, "wb");
if (!f) {
if (!f)
err(1, "Opening output file '%s' failed", opts.outfile);
}
fwrite(gb.data, 1, gb.size - gb.trim * 8 * depth, f);
fclose(f);
}
int
get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles, int tile_size)
int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles, int tile_size)
{
int i, j;
for (i = 0; i < num_tiles; i++) {
for (j = 0; j < tile_size; j++) {
if (tile[j] != tiles[i][j]) {
if (tile[j] != tiles[i][j])
break;
}
}
if (j >= tile_size) {
if (j >= tile_size)
return i;
}
}
return -1;
}
void
create_tilemap(struct Options opts, struct GBImage *gb, struct Tilemap *tilemap)
void create_tilemap(const struct Options opts, struct GBImage *gb,
struct Tilemap *tilemap)
{
int i, j;
int gb_i;
@@ -127,7 +127,8 @@ create_tilemap(struct Options opts, struct GBImage *gb, struct Tilemap *tilemap)
gb_i++;
}
if (opts.unique) {
index = get_tile_index(tile, tiles, num_tiles, tile_size);
index = get_tile_index(tile, tiles, num_tiles,
tile_size);
if (index < 0) {
index = num_tiles;
tiles[num_tiles] = tile;
@@ -147,39 +148,35 @@ create_tilemap(struct Options opts, struct GBImage *gb, struct Tilemap *tilemap)
gb->data = malloc(tile_size * num_tiles);
for (i = 0; i < num_tiles; i++) {
tile = tiles[i];
for (j = 0; j < tile_size; j++) {
for (j = 0; j < tile_size; j++)
gb->data[i * tile_size + j] = tile[j];
}
}
gb->size = i * tile_size;
}
for (i = 0; i < num_tiles; i++) {
for (i = 0; i < num_tiles; i++)
free(tiles[i]);
}
free(tiles);
}
void
output_tilemap_file(struct Options opts, struct Tilemap tilemap)
void output_tilemap_file(const struct Options opts,
const struct Tilemap tilemap)
{
FILE *f;
f = fopen(opts.mapfile, "wb");
if (!f) {
if (!f)
err(1, "Opening tilemap file '%s' failed", opts.mapfile);
}
fwrite(tilemap.data, 1, tilemap.size, f);
fclose(f);
if (opts.mapout) {
if (opts.mapout)
free(opts.mapfile);
}
}
void
output_palette_file(struct Options opts, struct PNGImage png)
void output_palette_file(const struct Options opts, const struct PNGImage png)
{
FILE *f;
int i, colors, color;
@@ -188,16 +185,18 @@ output_palette_file(struct Options opts, struct PNGImage png)
if (png_get_PLTE(png.png, png.info, &palette, &colors)) {
f = fopen(opts.palfile, "wb");
if (!f) {
err(1, "Opening palette file '%s' failed", opts.palfile);
err(1, "Opening palette file '%s' failed",
opts.palfile);
}
for (i = 0; i < colors; i++) {
color = palette[i].blue >> 3 << 10 | palette[i].green >> 3 << 5 | palette[i].red >> 3;
color = palette[i].blue >> 3 << 10
| palette[i].green >> 3 << 5
| palette[i].red >> 3;
fwrite(&color, 2, 1, f);
}
fclose(f);
}
if (opts.palout) {
if (opts.palout)
free(opts.palfile);
}
}

View File

@@ -14,22 +14,23 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern/version.h"
#include "gfx/main.h"
static void
usage(void)
static void print_usage(void)
{
printf(
"usage: rgbgfx [-DFfhPTuv] [-d #] [-o outfile] [-p palfile] [-t mapfile]\n"
"usage: rgbgfx [-DFfhPTuVv] [-d #] [-o outfile] [-p palfile] [-t mapfile]\n"
" [-x #] infile\n");
exit(1);
}
int
main(int argc, char *argv[])
int main(int argc, char *argv[])
{
int ch, size;
struct Options opts = {0};
@@ -39,9 +40,8 @@ main(int argc, char *argv[])
char *ext;
const char *errmsg = "Warning: The PNG's %s setting is not the same as the setting defined on the command line.";
if (argc == 1) {
usage();
}
if (argc == 1)
print_usage();
opts.mapfile = "";
opts.palfile = "";
@@ -49,27 +49,30 @@ main(int argc, char *argv[])
depth = 2;
while((ch = getopt(argc, argv, "DvFfd:hx:Tt:uPp:o:")) != -1) {
while ((ch = getopt(argc, argv, "Dd:Ffho:Tt:uPp:Vvx:")) != -1) {
switch (ch) {
case 'D':
opts.debug = true;
break;
case 'v':
opts.verbose = true;
case 'd':
depth = strtoul(optarg, NULL, 0);
break;
case 'F':
opts.hardfix = true;
case 'f':
opts.fix = true;
break;
case 'd':
depth = strtoul(optarg, NULL, 0);
break;
case 'h':
opts.horizontal = true;
break;
case 'x':
opts.trim = strtoul(optarg, NULL, 0);
case 'o':
opts.outfile = optarg;
break;
case 'P':
opts.palout = true;
break;
case 'p':
opts.palfile = optarg;
break;
case 'T':
opts.mapout = true;
@@ -80,31 +83,31 @@ main(int argc, char *argv[])
case 'u':
opts.unique = true;
break;
case 'P':
opts.palout = true;
case 'V':
printf("rgbgfx %s\n", get_package_version_string());
exit(0);
case 'v':
opts.verbose = true;
break;
case 'p':
opts.palfile = optarg;
break;
case 'o':
opts.outfile = optarg;
case 'x':
opts.trim = strtoul(optarg, NULL, 0);
break;
default:
usage();
print_usage();
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
if (argc == 0) {
usage();
}
if (argc == 0)
print_usage();
opts.infile = argv[argc - 1];
if (depth != 1 && depth != 2) {
if (depth != 1 && depth != 2)
errx(1, "Depth option must be either 1 or 2.");
}
colors = 1 << depth;
input_png_file(opts, &png);
@@ -115,82 +118,77 @@ main(int argc, char *argv[])
get_text(&png);
if (png.horizontal != opts.horizontal) {
if (opts.verbose) {
if (opts.verbose)
warnx(errmsg, "horizontal");
}
if (opts.hardfix) {
if (opts.hardfix)
png.horizontal = opts.horizontal;
}
}
if (png.horizontal) {
if (png.horizontal)
opts.horizontal = png.horizontal;
}
if (png.trim != opts.trim) {
if (opts.verbose) {
if (opts.verbose)
warnx(errmsg, "trim");
}
if (opts.hardfix) {
if (opts.hardfix)
png.trim = opts.trim;
}
}
if (png.trim) {
if (png.trim)
opts.trim = png.trim;
}
if (opts.trim > png.width / 8 - 1) {
errx(1, "Trim (%i) for input png file '%s' too large (max: %i)", opts.trim, opts.infile, png.width / 8 - 1);
errx(1, "Trim (%i) for input png file '%s' too large (max: %i)",
opts.trim, opts.infile, png.width / 8 - 1);
}
if (strcmp(png.mapfile, opts.mapfile) != 0) {
if (opts.verbose) {
if (opts.verbose)
warnx(errmsg, "tilemap file");
}
if (opts.hardfix) {
if (opts.hardfix)
png.mapfile = opts.mapfile;
}
}
if (!*opts.mapfile) {
if (!*opts.mapfile)
opts.mapfile = png.mapfile;
}
if (png.mapout != opts.mapout) {
if (opts.verbose) {
if (opts.verbose)
warnx(errmsg, "tilemap file");
}
if (opts.hardfix) {
if (opts.hardfix)
png.mapout = opts.mapout;
}
}
if (png.mapout) {
if (png.mapout)
opts.mapout = png.mapout;
}
if (strcmp(png.palfile, opts.palfile) != 0) {
if (opts.verbose) {
if (opts.verbose)
warnx(errmsg, "palette file");
}
if (opts.hardfix) {
if (opts.hardfix)
png.palfile = opts.palfile;
}
}
if (!*opts.palfile) {
if (!*opts.palfile)
opts.palfile = png.palfile;
}
if (png.palout != opts.palout) {
if (opts.verbose) {
if (opts.verbose)
warnx(errmsg, "palette file");
}
if (opts.hardfix) {
if (opts.hardfix)
png.palout = opts.palout;
}
}
if (png.palout) {
if (png.palout)
opts.palout = png.palout;
}
if (!*opts.mapfile && opts.mapout) {
if ((ext = strrchr(opts.infile, '.')) != NULL) {
ext = strrchr(opts.infile, '.');
if (ext != NULL) {
size = ext - opts.infile + 9;
opts.mapfile = malloc(size);
strncpy(opts.mapfile, opts.infile, size);
@@ -204,7 +202,9 @@ main(int argc, char *argv[])
}
if (!*opts.palfile && opts.palout) {
if ((ext = strrchr(opts.infile, '.')) != NULL) {
ext = strrchr(opts.infile, '.');
if (ext != NULL) {
size = ext - opts.infile + 5;
opts.palfile = malloc(size);
strncpy(opts.palfile, opts.infile, size);
@@ -227,17 +227,14 @@ main(int argc, char *argv[])
create_tilemap(opts, &gb, &tilemap);
}
if (*opts.outfile) {
if (*opts.outfile)
output_file(opts, gb);
}
if (*opts.mapfile) {
if (*opts.mapfile)
output_tilemap_file(opts, tilemap);
}
if (*opts.palfile) {
if (*opts.palfile)
output_palette_file(opts, png);
}
if (opts.fix || opts.debug) {
set_text(&png);

View File

@@ -16,10 +16,10 @@
#include <stdlib.h>
#include <string.h>
#include "gfx/main.h"
void
input_png_file(struct Options opts, struct PNGImage *img)
void input_png_file(const struct Options opts, struct PNGImage *img)
{
FILE *f;
int i, y, num_trans;
@@ -30,24 +30,21 @@ input_png_file(struct Options opts, struct PNGImage *img)
png_color *palette;
f = fopen(opts.infile, "rb");
if (!f) {
if (!f)
err(1, "Opening input png file '%s' failed", opts.infile);
}
img->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!img->png) {
img->png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if (!img->png)
errx(1, "Creating png structure failed");
}
img->info = png_create_info_struct(img->png);
if (!img->info) {
if (!img->info)
errx(1, "Creating png info structure failed");
}
/* Better error handling here? */
if (setjmp(png_jmpbuf(img->png))) {
/* TODO: Better error handling here? */
if (setjmp(png_jmpbuf(img->png)))
exit(1);
}
png_init_io(img->png, f);
@@ -58,9 +55,8 @@ input_png_file(struct Options opts, struct PNGImage *img)
img->depth = png_get_bit_depth(img->png, img->info);
img->type = png_get_color_type(img->png, img->info);
if (img->type & PNG_COLOR_MASK_ALPHA) {
if (img->type & PNG_COLOR_MASK_ALPHA)
png_set_strip_alpha(img->png);
}
if (img->depth != depth) {
if (opts.verbose) {
@@ -70,14 +66,14 @@ input_png_file(struct Options opts, struct PNGImage *img)
}
if (img->type == PNG_COLOR_TYPE_GRAY) {
if (img->depth < 8) {
if (img->depth < 8)
png_set_expand_gray_1_2_4_to_8(img->png);
}
png_set_gray_to_rgb(img->png);
} else {
if (img->depth < 8) {
if (img->depth < 8)
png_set_expand_gray_1_2_4_to_8(img->png);
}
has_palette = png_get_PLTE(img->png, img->info, &palette,
&colors);
}
@@ -88,12 +84,11 @@ input_png_file(struct Options opts, struct PNGImage *img)
full_alpha = malloc(sizeof(bool) * num_trans);
for (i = 0; i < num_trans; i++) {
if (trans_alpha[i] > 0) {
if (trans_alpha[i] > 0)
full_alpha[i] = false;
} else {
else
full_alpha[i] = true;
}
}
for (i = 0; i < num_trans; i++) {
if (full_alpha[i]) {
@@ -182,9 +177,8 @@ input_png_file(struct Options opts, 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++) {
for (y = 0; y < img->height; y++)
img->data[y] = malloc(png_get_rowbytes(img->png, img->info));
}
png_read_image(img->png, img->data);
png_read_end(img->png, img->info);
@@ -192,8 +186,7 @@ input_png_file(struct Options opts, struct PNGImage *img)
fclose(f);
}
void
get_text(struct PNGImage *png)
void get_text(struct PNGImage *png)
{
png_text *text;
int i, numtxts, numremoved;
@@ -221,11 +214,14 @@ get_text(struct PNGImage *png)
}
}
/* TODO: Remove this and simply change the warning function not to warn instead. */
/*
* TODO: Remove this and simply change the warning function not to warn
* instead.
*/
for (i = 0, numremoved = 0; i < numtxts; i++) {
if (text[i].key == NULL) {
if (text[i].key == NULL)
numremoved++;
}
text[i].key = text[i + numremoved].key;
text[i].text = text[i + numremoved].text;
text[i].compression = text[i + numremoved].compression;
@@ -233,8 +229,7 @@ get_text(struct PNGImage *png)
png_set_text(png->png, png->info, text, numtxts - numremoved);
}
void
set_text(struct PNGImage *png)
void set_text(const struct PNGImage *png)
{
png_text *text;
char buffer[3];
@@ -282,14 +277,16 @@ set_text(struct PNGImage *png)
free(text);
}
void
output_png_file(struct Options opts, struct PNGImage *png)
void output_png_file(const struct Options opts, const struct PNGImage *png)
{
FILE *f;
char *outfile;
png_struct *img;
/* Variable outfile is for debugging purposes. Eventually, opts.infile will be used directly. */
/*
* TODO: Variable outfile is for debugging purposes. Eventually,
* opts.infile will be used directly.
*/
if (opts.debug) {
outfile = malloc(strlen(opts.infile) + 5);
strcpy(outfile, opts.infile);
@@ -299,19 +296,16 @@ output_png_file(struct Options opts, struct PNGImage *png)
}
f = fopen(outfile, "wb");
if (!f) {
if (!f)
err(1, "Opening output png file '%s' failed", outfile);
}
img = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!img) {
if (!img)
errx(1, "Creating png structure failed");
}
/* Better error handling here? */
if (setjmp(png_jmpbuf(img))) {
/* TODO: Better error handling here? */
if (setjmp(png_jmpbuf(img)))
exit(1);
}
png_init_io(img, f);
@@ -322,18 +316,16 @@ output_png_file(struct Options opts, struct PNGImage *png)
fclose(f);
if (opts.debug) {
if (opts.debug)
free(outfile);
}
}
void
free_png_data(struct PNGImage *png)
void free_png_data(const struct PNGImage *png)
{
int y;
for (y = 0; y < png->height; y++) {
for (y = 0; y < png->height; y++)
free(png->data[y]);
}
free(png->data);
}

View File

@@ -20,7 +20,7 @@
.Nd Game Boy graphics converter
.Sh SYNOPSIS
.Nm rgbgfx
.Op Fl DfFhPTv
.Op Fl DfFhPTVv
.Op Fl o Ar outfile
.Op Fl d Ar depth
.Op Fl p Ar palfile
@@ -70,6 +70,8 @@ removing the file extension, and appending
.Pa .tilemap .
.It Fl u
Truncate repeated tiles. Useful with tilemaps.
.It Fl V
Print the version of the program and exit.
.It Fl v
Verbose.
Print errors when the command line parameters and the parameters in

View File

@@ -1,9 +1,11 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "extern/err.h"
#include "link/assign.h"
#include "link/mylink.h"
#include "link/main.h"
@@ -11,62 +13,121 @@
#include "link/symbol.h"
struct sFreeArea {
SLONG nOrg;
SLONG nSize;
int32_t nOrg;
int32_t nSize;
struct sFreeArea *pPrev, *pNext;
};
struct sSectionAttributes {
const char *name;
SLONG bank;
SLONG offset; // bank + offset = bank originally stored in a section struct
SLONG minBank;
SLONG bankCount;
/* bank + offset = bank originally stored in a section struct */
int32_t bank;
int32_t offset;
int32_t minBank;
int32_t bankCount;
};
struct sFreeArea *BankFree[MAXBANKS];
SLONG MaxAvail[MAXBANKS];
SLONG MaxBankUsed;
SLONG MaxWBankUsed;
SLONG MaxSBankUsed;
SLONG MaxVBankUsed;
struct sFreeArea *BankFree[BANK_INDEX_MAX];
int32_t MaxAvail[BANK_INDEX_MAX];
int32_t MaxBankUsed;
int32_t MaxWBankUsed;
int32_t MaxSBankUsed;
int32_t MaxVBankUsed;
const enum eSectionType SECT_MIN = SECT_WRAM0;
const enum eSectionType SECT_MAX = SECT_OAM;
const struct sSectionAttributes SECT_ATTRIBUTES[] = {
{"WRAM0", BANK_WRAM0, 0, 0, BANK_COUNT_WRAM0},
{"VRAM", BANK_VRAM, 0, 0, BANK_COUNT_VRAM},
{"ROMX", BANK_ROMX, -1, 1, BANK_COUNT_ROMX},
{"ROM0", BANK_ROM0, 0, 0, BANK_COUNT_ROM0},
{"HRAM", BANK_HRAM, 0, 0, BANK_COUNT_HRAM},
{"WRAMX", BANK_WRAMX, 0, 0, BANK_COUNT_WRAMX},
{"SRAM", BANK_SRAM, 0, 0, BANK_COUNT_SRAM},
{"OAM", BANK_OAM, 0, 0, BANK_COUNT_OAM}
{"WRAM0", BANK_INDEX_WRAM0, 0, 0, BANK_COUNT_WRAM0},
{"VRAM", BANK_INDEX_VRAM, 0, 0, BANK_COUNT_VRAM},
{"ROMX", BANK_INDEX_ROMX, -BANK_MIN_ROMX, BANK_MIN_ROMX, BANK_COUNT_ROMX},
{"ROM0", BANK_INDEX_ROM0, 0, 0, BANK_COUNT_ROM0},
{"HRAM", BANK_INDEX_HRAM, 0, 0, BANK_COUNT_HRAM},
{"WRAMX", BANK_INDEX_WRAMX, -BANK_MIN_WRAMX, BANK_MIN_WRAMX, BANK_COUNT_WRAMX},
{"SRAM", BANK_INDEX_SRAM, 0, 0, BANK_COUNT_SRAM},
{"OAM", BANK_INDEX_OAM, 0, 0, BANK_COUNT_OAM}
};
#define DOMAXBANK(x, y) {switch (x) { \
case SECT_ROMX: DOMAXRBANK(y); break; \
case SECT_WRAMX: DOMAXWBANK(y); break; \
case SECT_SRAM: DOMAXSBANK(y); break; \
case SECT_VRAM: DOMAXVBANK(y); break; \
default: break; }}
#define DOMAXRBANK(x) {if( (x)>MaxBankUsed ) MaxBankUsed=(x);}
#define DOMAXWBANK(x) {if( (x)>MaxWBankUsed ) MaxWBankUsed=(x);}
#define DOMAXSBANK(x) {if( (x)>MaxSBankUsed ) MaxSBankUsed=(x);}
#define DOMAXVBANK(x) {if( (x)>MaxVBankUsed ) MaxVBankUsed=(x);}
void
ensureSectionTypeIsValid(enum eSectionType type)
static void do_max_bank(enum eSectionType Type, int32_t nBank)
{
if (type < SECT_MIN || type > SECT_MAX) {
errx(1, "(INTERNAL) Invalid section type found.");
switch (Type) {
case SECT_ROMX:
if (nBank > MaxBankUsed)
MaxBankUsed = nBank;
break;
case SECT_WRAMX:
if (nBank > MaxWBankUsed)
MaxWBankUsed = nBank;
break;
case SECT_SRAM:
if (nBank > MaxSBankUsed)
MaxSBankUsed = nBank;
break;
case SECT_VRAM:
if (nBank > MaxVBankUsed)
MaxVBankUsed = nBank;
break;
default:
break;
}
}
SLONG
area_Avail(SLONG bank)
void ensureSectionTypeIsValid(enum eSectionType type)
{
SLONG r;
if (type < SECT_MIN || type > SECT_MAX)
errx(1, "%s: Invalid section type found: %d", __func__, type);
}
int BankIndexIsROM0(int32_t bank)
{
return (bank >= BANK_INDEX_ROM0) &&
(bank < (BANK_INDEX_ROM0 + BANK_COUNT_ROM0));
}
int BankIndexIsROMX(int32_t bank)
{
return (bank >= BANK_INDEX_ROMX) &&
(bank < (BANK_INDEX_ROMX + BANK_COUNT_ROMX));
}
int BankIndexIsWRAM0(int32_t bank)
{
return (bank >= BANK_INDEX_WRAM0) &&
(bank < (BANK_INDEX_WRAM0 + BANK_COUNT_WRAM0));
}
int BankIndexIsWRAMX(int32_t bank)
{
return (bank >= BANK_INDEX_WRAMX) &&
(bank < (BANK_INDEX_WRAMX + BANK_COUNT_WRAMX));
}
int BankIndexIsVRAM(int32_t bank)
{
return (bank >= BANK_INDEX_VRAM) &&
(bank < (BANK_INDEX_VRAM + BANK_COUNT_VRAM));
}
int BankIndexIsOAM(int32_t bank)
{
return (bank >= BANK_INDEX_OAM) &&
(bank < (BANK_INDEX_OAM + BANK_COUNT_OAM));
}
int BankIndexIsHRAM(int32_t bank)
{
return (bank >= BANK_INDEX_HRAM) &&
(bank < (BANK_INDEX_HRAM + BANK_COUNT_HRAM));
}
int BankIndexIsSRAM(int32_t bank)
{
return (bank >= BANK_INDEX_SRAM) &&
(bank < (BANK_INDEX_SRAM + BANK_COUNT_SRAM));
}
int32_t area_Avail(int32_t bank)
{
int32_t r;
struct sFreeArea *pArea;
r = 0;
@@ -77,54 +138,55 @@ area_Avail(SLONG bank)
pArea = pArea->pNext;
}
return (r);
return r;
}
SLONG
area_doAlloc(struct sFreeArea *pArea, SLONG org, SLONG size)
int32_t area_doAlloc(struct sFreeArea *pArea, int32_t org, int32_t size)
{
if (org >= pArea->nOrg && (org + size) <= (pArea->nOrg + pArea->nSize)) {
if ((org >= pArea->nOrg)
&& ((org + size) <= (pArea->nOrg + pArea->nSize))) {
if (org == pArea->nOrg) {
pArea->nOrg += size;
pArea->nSize -= size;
return org;
} else {
}
if ((org + size) == (pArea->nOrg + pArea->nSize)) {
pArea->nSize -= size;
return org;
} else {
}
struct sFreeArea *pNewArea;
if ((pNewArea = malloc(sizeof(struct sFreeArea))) != NULL) {
pNewArea = malloc(sizeof(struct sFreeArea));
if (pNewArea == NULL)
err(1, "%s: Failed to allocate memory", __func__);
*pNewArea = *pArea;
pNewArea->pPrev = pArea;
pArea->pNext = pNewArea;
pArea->nSize = org - pArea->nOrg;
pNewArea->nOrg = org + size;
pNewArea->nSize -= size + pArea->nSize;
return org;
} else {
err(1, NULL);
}
}
}
return org;
}
return -1;
}
SLONG
area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
int32_t area_AllocAbs(struct sFreeArea **ppArea, int32_t org, int32_t size)
{
struct sFreeArea *pArea;
pArea = *ppArea;
while (pArea) {
SLONG result = area_doAlloc(pArea, org, size);
if (result != -1) {
int32_t result = area_doAlloc(pArea, org, size);
if (result != -1)
return result;
}
ppArea = &(pArea->pNext);
pArea = *ppArea;
@@ -133,42 +195,41 @@ area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
return -1;
}
SLONG
area_AllocAbsAnyBank(SLONG org, SLONG size, enum eSectionType type)
int32_t area_AllocAbsAnyBank(int32_t org, int32_t size, enum eSectionType type)
{
ensureSectionTypeIsValid(type);
SLONG startBank = SECT_ATTRIBUTES[type].bank;
SLONG bankCount = SECT_ATTRIBUTES[type].bankCount;
int32_t startBank = SECT_ATTRIBUTES[type].bank;
int32_t bankCount = SECT_ATTRIBUTES[type].bankCount;
for (int i = 0; i < bankCount; i++) {
if (area_AllocAbs(&BankFree[startBank + i], org, size) != -1) {
for (int32_t i = 0; i < bankCount; i++) {
if (area_AllocAbs(&BankFree[startBank + i], org, size) != -1)
return startBank + i;
}
}
return -1;
}
SLONG
area_Alloc(struct sFreeArea ** ppArea, SLONG size, SLONG alignment) {
int32_t area_Alloc(struct sFreeArea **ppArea, int32_t size, int32_t alignment)
{
struct sFreeArea *pArea;
if (alignment < 1) {
if (alignment < 1)
alignment = 1;
}
pArea = *ppArea;
while (pArea) {
SLONG org = pArea->nOrg;
if (org % alignment) {
int32_t org = pArea->nOrg;
if (org % alignment)
org += alignment;
}
org -= org % alignment;
SLONG result = area_doAlloc(pArea, org, size);
if (result != -1) {
int32_t result = area_doAlloc(pArea, org, size);
if (result != -1)
return result;
}
ppArea = &(pArea->pNext);
pArea = *ppArea;
@@ -177,34 +238,38 @@ area_Alloc(struct sFreeArea ** ppArea, SLONG size, SLONG alignment) {
return -1;
}
SLONG
area_AllocAnyBank(SLONG size, SLONG alignment, enum eSectionType type) {
int32_t area_AllocAnyBank(int32_t size, int32_t alignment,
enum eSectionType type)
{
ensureSectionTypeIsValid(type);
SLONG startBank = SECT_ATTRIBUTES[type].bank;
SLONG bankCount = SECT_ATTRIBUTES[type].bankCount;
int32_t i, org;
int32_t startBank = SECT_ATTRIBUTES[type].bank;
int32_t bankCount = SECT_ATTRIBUTES[type].bankCount;
for (int i = 0; i < bankCount; i++) {
SLONG org = area_Alloc(&BankFree[startBank + i], size, alignment);
if (org != -1) {
for (i = 0; i < bankCount; i++) {
org = area_Alloc(&BankFree[startBank + i], size, alignment);
if (org != -1)
return ((startBank + i) << 16) | org;
}
}
return -1;
}
struct sSection *
FindLargestSection(enum eSectionType type, bool bankFixed)
struct sSection *FindLargestSection(enum eSectionType type, bool bankFixed)
{
struct sSection *pSection, *r = NULL;
SLONG nLargest = 0;
SLONG nLargestAlignment = 0;
int32_t nLargest = 0;
int32_t nLargestAlignment = 0;
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0 && pSection->Type == type && (bankFixed ^ (pSection->nBank == -1))) {
if (pSection->nAlign > nLargestAlignment || (pSection->nAlign == nLargestAlignment && pSection->nByteSize > nLargest)) {
if (pSection->oAssigned == 0 && pSection->Type == type
&& (bankFixed ^ (pSection->nBank == -1))) {
if (pSection->nAlign > nLargestAlignment
|| (pSection->nAlign == nLargestAlignment
&& pSection->nByteSize > nLargest)) {
nLargest = pSection->nByteSize;
nLargestAlignment = pSection->nAlign;
r = pSection;
@@ -216,12 +281,10 @@ FindLargestSection(enum eSectionType type, bool bankFixed)
return r;
}
int
IsSectionNameInUse(const char *name)
int32_t IsSectionNameInUse(const char *name)
{
struct sSection *pSection;
const struct sSection *pSection = pSections;
pSection = pSections;
while (pSection) {
if (strcmp(pSection->pzName, name) == 0)
return 1;
@@ -232,206 +295,256 @@ IsSectionNameInUse(const char *name)
return 0;
}
int
IsSectionSameTypeBankAndFloating(const char *name, enum eSectionType type, int bank)
struct sSection *GetSectionByName(const char *name)
{
struct sSection *pSection;
struct sSection *pSection = pSections;
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0) {
if (strcmp(pSection->pzName, name) == 0) {
if (strcmp(pSection->pzName, name) == 0)
return pSection;
pSection = pSection->pNext;
}
return NULL;
}
int32_t IsSectionSameTypeBankAndFloating(const char *name,
enum eSectionType type, int32_t bank)
{
const struct sSection *pSection;
for (pSection = pSections; pSection; pSection = pSection->pNext) {
/* Skip if it has already been assigned */
if (pSection->oAssigned == 1)
continue;
/* Check if it has the same name */
if (strcmp(pSection->pzName, name) != 0)
continue;
/*
* The section has the same name, now check if there is a
* mismatch or not.
*/
/* Section must be floating in source */
if (pSection->nOrg != -1 || pSection->nAlign != 1)
return 0;
/* It must have the same type in source and linkerscript */
if (pSection->Type != type)
return 0;
/* Bank number must be unassigned in source or equal */
if (pSection->nBank != -1 && pSection->nBank != bank)
return 0;
return 1;
}
}
pSection = pSection->pNext;
}
errx(1, "Section \"%s\" not found (or already used).\n", name);
}
unsigned int
AssignSectionAddressAndBankByName(const char *name, unsigned int address, int bank)
uint32_t AssignSectionAddressAndBankByName(const char *name, uint32_t address,
int32_t bank)
{
struct sSection *pSection;
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0) {
if (strcmp(pSection->pzName, name) == 0) {
if (pSection->nOrg != -1 || pSection->nAlign != 1)
errx(1, "Section \"%s\" from linkerscript isn't floating.\n", name);
if (pSection->nBank != -1 && pSection->nBank != bank)
errx(1, "Section \"%s\" from linkerscript has different bank number than in the source.\n", name);
for (pSection = pSections; pSection; pSection = pSection->pNext) {
/* Skip if it has already been assigned */
if (pSection->oAssigned == 1)
continue;
/* Check if it has the same name */
if (strcmp(pSection->pzName, name) != 0)
continue;
/* Section has been found. */
/*
* A section can be left as floating in the code if the location
* is assigned in the linkerscript.
*/
if (pSection->nOrg != -1 || pSection->nAlign != 1) {
errx(1, "Section \"%s\" from linkerscript isn't floating.\n",
name);
}
/* The bank can be left as unassigned or be the same */
if (pSection->nBank != -1 && pSection->nBank != bank) {
errx(1, "Section \"%s\" from linkerscript has different bank number than in the source.\n",
name);
}
pSection->nOrg = address;
pSection->nBank = bank;
pSection->nAlign = -1;
return pSection->nByteSize;
}
}
pSection = pSection->pNext;
}
errx(1, "Section \"%s\" not found (or already used).\n", name);
}
bool
VerifyAndSetBank(struct sSection *pSection)
bool VerifyAndSetBank(struct sSection *pSection)
{
ensureSectionTypeIsValid(pSection->Type);
enum eSectionType Type = pSection->Type;
if (pSection->nBank >= SECT_ATTRIBUTES[pSection->Type].minBank
&& pSection->nBank < SECT_ATTRIBUTES[pSection->Type].minBank + SECT_ATTRIBUTES[pSection->Type].bankCount) {
pSection->nBank += SECT_ATTRIBUTES[pSection->Type].bank + SECT_ATTRIBUTES[pSection->Type].offset;
ensureSectionTypeIsValid(Type);
if (pSection->nBank >= SECT_ATTRIBUTES[Type].minBank) {
if (pSection->nBank < SECT_ATTRIBUTES[Type].minBank
+ SECT_ATTRIBUTES[Type].bankCount) {
pSection->nBank += SECT_ATTRIBUTES[Type].bank
+ SECT_ATTRIBUTES[Type].offset;
return true;
}
}
} else {
return false;
}
}
void
AssignFixedBankSections(enum eSectionType type)
void AssignFixedBankSections(enum eSectionType type)
{
ensureSectionTypeIsValid(type);
struct sSection *pSection;
while ((pSection = FindLargestSection(type, true))) {
if (VerifyAndSetBank(pSection) &&
(pSection->nOrg = area_Alloc(&BankFree[pSection->nBank], pSection->nByteSize, pSection->nAlign)) != -1) {
if (VerifyAndSetBank(pSection)) {
pSection->nOrg = area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize,
pSection->nAlign);
if (pSection->nOrg != -1) {
pSection->oAssigned = 1;
DOMAXBANK(pSection->Type, pSection->nBank);
} else {
do_max_bank(pSection->Type, pSection->nBank);
continue;
}
}
if (pSection->nAlign <= 1) {
errx(1, "Unable to place '%s' (%s section) in bank $%02lX",
pSection->pzName, SECT_ATTRIBUTES[pSection->Type].name, pSection->nBank);
pSection->pzName,
SECT_ATTRIBUTES[pSection->Type].name,
pSection->nBank);
} else {
errx(1, "Unable to place '%s' (%s section) in bank $%02lX (with $%lX-byte alignment)",
pSection->pzName, SECT_ATTRIBUTES[pSection->Type].name, pSection->nBank, pSection->nAlign);
}
pSection->pzName,
SECT_ATTRIBUTES[pSection->Type].name,
pSection->nBank, pSection->nAlign);
}
}
}
void
AssignFloatingBankSections(enum eSectionType type)
void AssignFloatingBankSections(enum eSectionType type)
{
ensureSectionTypeIsValid(type);
struct sSection *pSection;
while ((pSection = FindLargestSection(type, false))) {
SLONG org;
int32_t org;
org = area_AllocAnyBank(pSection->nByteSize, pSection->nAlign,
type);
if (org != -1) {
if (options & OPT_OVERLAY)
errx(1, "All sections must be fixed when using an overlay file.");
if ((org = area_AllocAnyBank(pSection->nByteSize, pSection->nAlign, type)) != -1) {
if (options & OPT_OVERLAY) {
errx(1, "All sections must be fixed when using overlay");
}
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->oAssigned = 1;
DOMAXBANK(pSection->Type, pSection->nBank);
do_max_bank(pSection->Type, pSection->nBank);
} else {
const char *locality = "anywhere";
if (SECT_ATTRIBUTES[pSection->Type].bankCount > 1) {
if (SECT_ATTRIBUTES[pSection->Type].bankCount > 1)
locality = "in any bank";
}
if (pSection->nAlign <= 1) {
errx(1, "Unable to place '%s' (%s section) %s",
pSection->pzName, SECT_ATTRIBUTES[type].name, locality);
pSection->pzName,
SECT_ATTRIBUTES[type].name, locality);
} else {
errx(1, "Unable to place '%s' (%s section) %s (with $%lX-byte alignment)",
pSection->pzName, SECT_ATTRIBUTES[type].name, locality, pSection->nAlign);
pSection->pzName,
SECT_ATTRIBUTES[type].name, locality,
pSection->nAlign);
}
}
}
}
char *tzLinkerscriptName = NULL;
char *tzLinkerscriptName;
void
SetLinkerscriptName(char *tzLinkerscriptFile)
void SetLinkerscriptName(char *tzLinkerscriptFile)
{
tzLinkerscriptName = tzLinkerscriptFile;
}
void
AssignSections(void)
void AssignSections(void)
{
SLONG i;
int32_t i;
struct sSection *pSection;
MaxBankUsed = 0;
/*
* Initialize the memory areas
*
*/
for (i = 0; i < MAXBANKS; i += 1) {
BankFree[i] = malloc(sizeof *BankFree[i]);
for (i = 0; i < BANK_INDEX_MAX; i += 1) {
BankFree[i] = malloc(sizeof(*BankFree[i]));
if (!BankFree[i]) {
err(1, NULL);
errx(1, "%s: Couldn't allocate mem for bank %d",
__func__, i);
}
if (i == BANK_ROM0) {
if (BankIndexIsROM0(i)) {
/* ROM0 bank */
BankFree[i]->nOrg = 0x0000;
if (options & OPT_TINY) {
if (options & OPT_TINY)
BankFree[i]->nSize = 0x8000;
} else {
else
BankFree[i]->nSize = 0x4000;
}
} else if (i >= BANK_ROMX && i < BANK_ROMX + BANK_COUNT_ROMX) {
} else if (BankIndexIsROMX(i)) {
/* Swappable ROM bank */
BankFree[i]->nOrg = 0x4000;
BankFree[i]->nSize = 0x4000;
} else if (i == BANK_WRAM0) {
} else if (BankIndexIsWRAM0(i)) {
/* WRAM */
BankFree[i]->nOrg = 0xC000;
if (options & OPT_CONTWRAM) {
if (options & OPT_CONTWRAM)
BankFree[i]->nSize = 0x2000;
} else {
else
BankFree[i]->nSize = 0x1000;
}
} else if (i >= BANK_SRAM && i < BANK_SRAM + BANK_COUNT_SRAM) {
} else if (BankIndexIsSRAM(i)) {
/* Swappable SRAM bank */
BankFree[i]->nOrg = 0xA000;
BankFree[i]->nSize = 0x2000;
} else if (i >= BANK_WRAMX && i < BANK_WRAMX + BANK_COUNT_WRAMX) {
} else if (BankIndexIsWRAMX(i)) {
/* Swappable WRAM bank */
BankFree[i]->nOrg = 0xD000;
BankFree[i]->nSize = 0x1000;
} else if (i >= BANK_VRAM && i < BANK_VRAM + BANK_COUNT_VRAM) {
} else if (BankIndexIsVRAM(i)) {
/* Swappable VRAM bank */
BankFree[i]->nOrg = 0x8000;
if (options & OPT_DMG_MODE && i != BANK_VRAM) {
if (options & OPT_DMG_MODE && i != BANK_INDEX_VRAM)
BankFree[i]->nSize = 0;
} else {
else
BankFree[i]->nSize = 0x2000;
}
} else if (i == BANK_OAM) {
} else if (BankIndexIsOAM(i)) {
BankFree[i]->nOrg = 0xFE00;
BankFree[i]->nSize = 0x00A0;
} else if (i == BANK_HRAM) {
} else if (BankIndexIsHRAM(i)) {
/* HRAM */
BankFree[i]->nOrg = 0xFF80;
BankFree[i]->nSize = 0x007F;
} else {
errx(1, "(INTERNAL) Unknown bank type!");
errx(1, "%s: Unknown bank type %d", __func__, i);
}
MaxAvail[i] = BankFree[i]->nSize;
@@ -441,7 +554,6 @@ AssignSections(void)
/*
* First, let's parse the linkerscript.
*
*/
if (tzLinkerscriptName) {
@@ -451,13 +563,13 @@ AssignSections(void)
/*
* Second, let's assign all the fixed sections...
*
*/
pSection = pSections;
while (pSection) {
if ((pSection->nOrg != -1 || pSection->nBank != -1)
&& pSection->oAssigned == 0) {
for (pSection = pSections ; pSection; pSection = pSection->pNext) {
if (!((pSection->nOrg != -1 || pSection->nBank != -1)
&& pSection->oAssigned == 0))
continue;
/* User wants to have a say... */
switch (pSection->Type) {
@@ -466,10 +578,13 @@ AssignSections(void)
case SECT_ROM0:
case SECT_OAM:
pSection->nBank = SECT_ATTRIBUTES[pSection->Type].bank;
if (area_AllocAbs(&BankFree[pSection->nBank], pSection->nOrg,
if (area_AllocAbs(&BankFree[pSection->nBank],
pSection->nOrg,
pSection->nByteSize) == -1) {
errx(1, "Unable to place '%s' (%s section) at $%lX",
pSection->pzName, SECT_ATTRIBUTES[pSection->Type].name, pSection->nOrg);
errx(1, "Unable to place '%s' (%s section) at $%X",
pSection->pzName,
SECT_ATTRIBUTES[pSection->Type].name,
pSection->nOrg);
}
pSection->oAssigned = 1;
break;
@@ -478,104 +593,113 @@ AssignSections(void)
case SECT_WRAMX:
case SECT_VRAM:
case SECT_ROMX:
if (pSection->nBank != -1 && pSection->nOrg != -1) {
if (!(pSection->nBank != -1 && pSection->nOrg != -1))
break;
if (VerifyAndSetBank(pSection) &&
area_AllocAbs(&BankFree[pSection->nBank], pSection->nOrg, pSection->nByteSize) != -1) {
DOMAXBANK(pSection->Type, pSection->nBank);
area_AllocAbs(&BankFree[pSection->nBank],
pSection->nOrg,
pSection->nByteSize) != -1) {
do_max_bank(pSection->Type, pSection->nBank);
pSection->oAssigned = 1;
} else {
errx(1, "Unable to place '%s' (%s section) at $%lX in bank $%02lX",
pSection->pzName, SECT_ATTRIBUTES[pSection->Type].name, pSection->nOrg, pSection->nBank);
}
errx(1, "Unable to place '%s' (%s section) at $%X in bank $%02X",
pSection->pzName,
SECT_ATTRIBUTES[pSection->Type].name,
pSection->nOrg, pSection->nBank);
}
break;
}
}
pSection = pSection->pNext;
}
/*
* Next, let's assign all the bankfixed ONLY sections...
*
*/
for (enum eSectionType i = SECT_MIN; i <= SECT_MAX; i++) {
for (enum eSectionType i = SECT_MIN; i <= SECT_MAX; i++)
AssignFixedBankSections(i);
}
/*
* Now, let's assign all the floating bank but fixed ROMX sections...
*
*/
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0
&& pSection->nOrg != -1 && pSection->nBank == -1) {
for (pSection = pSections ; pSection; pSection = pSection->pNext) {
if (!(pSection->oAssigned == 0
&& pSection->nOrg != -1 && pSection->nBank == -1))
continue;
if (options & OPT_OVERLAY) {
errx(1, "All sections must be fixed when using overlay");
errx(1, "All sections must be fixed when using an overlay file: '%s'",
pSection->pzName);
}
switch (pSection->Type) {
case SECT_ROMX:
case SECT_VRAM:
case SECT_SRAM:
case SECT_WRAMX:
if ((pSection->nBank =
area_AllocAbsAnyBank(pSection->nOrg, pSection->nByteSize,
pSection->Type)) == -1) {
errx(1, "Unable to place '%s' (%s section) at $%lX in any bank",
pSection->pzName, SECT_ATTRIBUTES[pSection->Type].name, pSection->nOrg);
pSection->nBank =
area_AllocAbsAnyBank(pSection->nOrg,
pSection->nByteSize,
pSection->Type);
if (pSection->nBank == -1) {
errx(1, "Unable to place '%s' (%s section) at $%X in any bank",
pSection->pzName,
SECT_ATTRIBUTES[pSection->Type].name,
pSection->nOrg);
}
pSection->oAssigned = 1;
DOMAXBANK(pSection->Type, pSection->nBank);
do_max_bank(pSection->Type, pSection->nBank);
break;
default: // Handle other sections later
default: /* Handle other sections later */
break;
}
}
pSection = pSection->pNext;
}
/*
* OK, all that nasty stuff is done so let's assign all the other
* sections
*
*/
for (enum eSectionType i = SECT_MIN; i <= SECT_MAX; i++) {
for (enum eSectionType i = SECT_MIN; i <= SECT_MAX; i++)
AssignFloatingBankSections(i);
}
}
void
CreateSymbolTable(void)
void CreateSymbolTable(void)
{
struct sSection *pSect;
const struct sSection *pSect;
sym_Init();
pSect = pSections;
while (pSect) {
SLONG i;
int32_t i;
i = pSect->nNumberOfSymbols;
while (i--) {
if ((pSect->tSymbols[i]->Type == SYM_EXPORT) &&
((pSect->tSymbols[i]->pSection == pSect) ||
(pSect->tSymbols[i]->pSection == NULL))) {
if (pSect->tSymbols[i]->pSection == NULL)
sym_CreateSymbol(pSect->tSymbols[i]->
pzName,
pSect->tSymbols[i]->
nOffset, -1);
const struct sSymbol *tSymbol = pSect->tSymbols[i];
if ((tSymbol->Type == SYM_EXPORT) &&
((tSymbol->pSection == pSect) ||
(tSymbol->pSection == NULL))) {
if (tSymbol->pSection == NULL)
sym_CreateSymbol(
tSymbol->pzName,
tSymbol->nOffset,
-1,
tSymbol->pzObjFileName,
tSymbol->pzFileName,
tSymbol->nFileLine);
else
sym_CreateSymbol(pSect->tSymbols[i]->
pzName,
pSect->nOrg +
pSect->tSymbols[i]->
nOffset, pSect->nBank);
sym_CreateSymbol(
tSymbol->pzName,
pSect->nOrg + tSymbol->nOffset,
pSect->nBank,
tSymbol->pzObjFileName,
tSymbol->pzFileName,
tSymbol->nFileLine);
}
}
pSect = pSect->pNext;

View File

@@ -19,25 +19,29 @@
%{
#include <stdarg.h>
#include <stdint.h>
#include <unistd.h>
#include "extern/err.h"
#include "link/mylink.h"
#include "link/script.h"
#include "parser.h"
#include "types.h"
extern int yyparse();
/* File include stack. */
#define MAX_INCLUDE_DEPTH 8
static int include_stack_ptr = 0;
static int32_t include_stack_ptr;
static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
static char include_path[MAX_INCLUDE_DEPTH][_MAX_PATH + 1];
static int include_line[MAX_INCLUDE_DEPTH];
static int32_t include_line[MAX_INCLUDE_DEPTH];
static char linkerscript_path[_MAX_PATH + 1]; /* Base file */
%}
@@ -45,14 +49,21 @@ static char linkerscript_path[_MAX_PATH + 1]; /* Base file */
%%
\"([^\\\"]|\\.)*\" {
if (strlen(yytext) > sizeof(yylval.s) - 1)
script_fatalerror("String is too long: %s\n.", yytext);
if (strlen(yytext) < 3) /* 2 quotes + 1 character */
script_fatalerror("String %s is invalid\n.", yytext);
if (strlen(yytext) > sizeof(yylval.s) - 1) {
script_fatalerror("String is too long: %s\n.",
yytext);
}
yytext++; /* ignore first quote */
if (strlen(yytext) < 3) { /* 2 quotes + 1 character */
script_fatalerror("String %s is invalid\n.",
yytext);
}
/* Ignore first quote */
yytext++;
strcpy(yylval.s, yytext);
yylval.s[strlen(yylval.s)-1] = '\0'; /* remove end quote */
/* Remove end quote */
yylval.s[strlen(yylval.s)-1] = '\0';
return STRING;
}
@@ -108,7 +119,6 @@ void script_Parse(const char * path)
} while (!feof(yyin));
fclose(yyin);
}
void script_IncludeFile(const char * path)
@@ -148,7 +158,7 @@ void script_IncludeFile(const char * path)
unput('\n');
}
int script_IncludeDepthGet(void)
int32_t script_IncludeDepthGet(void)
{
return include_stack_ptr;
}
@@ -166,7 +176,7 @@ void script_IncludePop(void)
void script_PrintFileStack(void)
{
int i = include_stack_ptr;
int32_t i = include_stack_ptr;
include_line[i] = yylineno;

View File

@@ -1,73 +1,71 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "extern/err.h"
#include "types.h"
#include "link/mylink.h"
#include "link/main.h"
static BBOOL
symboldefined(char *name)
static uint8_t symboldefined(char *name)
{
struct sSection *pSect;
const struct sSection *pSect;
pSect = pSections;
while (pSect) {
int i;
int32_t i;
for (i = 0; i < pSect->nNumberOfSymbols; i += 1) {
if ((pSect->tSymbols[i]->Type == SYM_EXPORT)
|| ((pSect->tSymbols[i]->Type == SYM_LOCAL)
&& (pSect == pSect->tSymbols[i]->pSection))) {
if (strcmp(pSect->tSymbols[i]->pzName, name) ==
0)
return (1);
const struct sSymbol *tSymbol = pSect->tSymbols[i];
if ((tSymbol->Type == SYM_EXPORT)
|| ((tSymbol->Type == SYM_LOCAL)
&& (pSect == tSymbol->pSection))) {
if (strcmp(tSymbol->pzName, name) == 0)
return 1;
}
}
pSect = pSect->pNext;
}
return (0);
return 0;
}
static BBOOL
addmodulecontaining(char *name)
static uint8_t addmodulecontaining(char *name)
{
struct sSection **ppLSect;
ppLSect = &pLibSections;
struct sSection **ppLSect = &pLibSections;
while (*ppLSect) {
int i;
int32_t i;
for (i = 0; i < (*ppLSect)->nNumberOfSymbols; i += 1) {
if (((*ppLSect)->tSymbols[i]->Type == SYM_EXPORT)
|| (((*ppLSect)->tSymbols[i]->Type == SYM_LOCAL)
&& ((*ppLSect) ==
(*ppLSect)->tSymbols[i]->pSection))) {
if (strcmp
((*ppLSect)->tSymbols[i]->pzName,
name) == 0) {
struct sSection **ppSect;
ppSect = &pSections;
const struct sSymbol *tSymbol = (*ppLSect)->tSymbols[i];
if ((tSymbol->Type == SYM_EXPORT)
|| ((tSymbol->Type == SYM_LOCAL)
&& ((*ppLSect) == tSymbol->pSection))) {
if (strcmp(tSymbol->pzName, name) == 0) {
struct sSection **ppSect = &pSections;
while (*ppSect)
ppSect = &((*ppSect)->pNext);
*ppSect = *ppLSect;
*ppLSect = (*ppLSect)->pNext;
(*ppSect)->pNext = NULL;
return (1);
return 1;
}
}
}
ppLSect = &((*ppLSect)->pNext);
}
return (0);
return 0;
}
void
AddNeededModules(void)
void AddNeededModules(void)
{
struct sSection *pSect;
@@ -77,8 +75,8 @@ AddNeededModules(void)
ppLSect = &pLibSections;
while (*ppLSect) {
struct sSection **ppSect;
ppSect = &pSections;
struct sSection **ppSect = &pSections;
while (*ppSect)
ppSect = &((*ppSect)->pNext);
@@ -94,22 +92,21 @@ AddNeededModules(void)
if (!addmodulecontaining(smartlinkstartsymbol)) {
errx(1, "Can't find start symbol '%s'",
smartlinkstartsymbol);
} else
} else {
printf("Smart linking with symbol '%s'\n",
smartlinkstartsymbol);
}
}
pSect = pSections;
while (pSect) {
int i;
int32_t i;
for (i = 0; i < pSect->nNumberOfSymbols; i += 1) {
if ((pSect->tSymbols[i]->Type == SYM_IMPORT)
|| (pSect->tSymbols[i]->Type == SYM_LOCAL)) {
if (!symboldefined(pSect->tSymbols[i]->pzName)) {
addmodulecontaining(pSect->tSymbols[i]->
pzName);
}
if (!symboldefined(pSect->tSymbols[i]->pzName))
addmodulecontaining(pSect->tSymbols[i]->pzName);
}
}
pSect = pSect->pNext;

View File

@@ -1,9 +1,12 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern/err.h"
#include "extern/version.h"
#include "link/object.h"
#include "link/output.h"
#include "link/assign.h"
@@ -20,39 +23,35 @@ enum eBlockType {
BLOCK_OUTPUT
};
SLONG options = 0;
SLONG fillchar = 0;
int32_t options;
int32_t fillchar;
char *smartlinkstartsymbol;
/*
* Print the usagescreen
*
*/
static void
usage(void)
static void print_usage(void)
{
printf(
"usage: rgblink [-twd] [-l linkerscript] [-m mapfile] [-n symfile] [-O overlay]\n"
"usage: rgblink [-dtVw] [-l linkerscript] [-m mapfile] [-n symfile] [-O overlay]\n"
" [-o outfile] [-p pad_value] [-s symbol] file [...]\n");
exit(1);
}
/*
* The main routine
*
*/
int
main(int argc, char *argv[])
int main(int argc, char *argv[])
{
int ch;
char *ep;
if (argc == 1)
usage();
print_usage();
while ((ch = getopt(argc, argv, "l:m:n:o:O:p:s:twd")) != -1) {
while ((ch = getopt(argc, argv, "dl:m:n:O:o:p:s:tVw")) != -1) {
switch (ch) {
case 'l':
SetLinkerscriptName(optarg);
@@ -72,13 +71,10 @@ main(int argc, char *argv[])
break;
case 'p':
fillchar = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'p'");
}
if (fillchar < 0 || fillchar > 0xFF) {
fprintf(stderr, "Argument for option 'p' must be between 0 and 0xFF");
exit(1);
}
if (fillchar < 0 || fillchar > 0xFF)
errx(1, "Argument for option 'p' must be between 0 and 0xFF");
break;
case 's':
options |= OPT_SMART_C_LINK;
@@ -98,16 +94,21 @@ main(int argc, char *argv[])
* This option implies OPT_CONTWRAM.
*/
options |= OPT_DMG_MODE;
/* fallthrough */
/* FALLTHROUGH */
case 'w':
/* Set to set WRAM as a single continuous block as on
/*
* Set to set WRAM as a single continuous block as on
* DMG. All WRAM sections must be WRAM0 as bankable WRAM
* sections do not exist in this mode. A WRAMX section
* will raise an error. */
* will raise an error.
*/
options |= OPT_CONTWRAM;
break;
case 'V':
printf("rgblink %s\n", get_package_version_string());
exit(0);
default:
usage();
print_usage();
/* NOTREACHED */
}
}
@@ -115,9 +116,9 @@ main(int argc, char *argv[])
argv += optind;
if (argc == 0)
usage();
print_usage();
for (int i = 0; i < argc; ++i)
for (int32_t i = 0; i < argc; ++i)
obj_Readfile(argv[i]);
AddNeededModules();
@@ -127,5 +128,5 @@ main(int argc, char *argv[])
Output();
CloseMapfile();
return (0);
return 0;
}

View File

@@ -1,42 +1,39 @@
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "extern/err.h"
#include "link/assign.h"
#include "link/main.h"
#include "link/mylink.h"
#include "link/assign.h"
FILE *mf = NULL;
FILE *sf = NULL;
SLONG currentbank = 0;
SLONG sfbank;
static int32_t currentbank;
static int32_t sfbank;
static FILE *mf;
static FILE *sf;
void
SetMapfileName(char *name)
void SetMapfileName(char *name)
{
mf = fopen(name, "w");
if (mf == NULL) {
if (mf == NULL)
err(1, "Cannot open mapfile '%s'", name);
}
}
void
SetSymfileName(char *name)
void SetSymfileName(char *name)
{
sf = fopen(name, "w");
if (sf == NULL) {
if (sf == NULL)
err(1, "Cannot open symfile '%s'", name);
}
fprintf(sf, "; File generated by rgblink\n\n");
}
void
CloseMapfile(void)
void CloseMapfile(void)
{
if (mf) {
fclose(mf);
@@ -48,76 +45,81 @@ CloseMapfile(void)
}
}
void
MapfileInitBank(SLONG bank)
void MapfileInitBank(int32_t bank)
{
if ((bank < 0) || (bank >= BANK_INDEX_MAX))
errx(1, "%s: Unknown bank %d\n", __func__, bank);
if (mf) {
currentbank = bank;
if (bank == BANK_ROM0)
if (BankIndexIsROM0(bank)) {
fprintf(mf, "ROM Bank #0 (HOME):\n");
else if (bank < BANK_WRAM0)
fprintf(mf, "ROM Bank #%ld:\n", bank);
else if (bank == BANK_WRAM0)
} else if (BankIndexIsROMX(bank)) {
fprintf(mf, "ROM Bank #%d:\n",
bank - BANK_INDEX_ROMX + 1);
} else if (BankIndexIsWRAM0(bank)) {
fprintf(mf, "WRAM Bank #0:\n");
else if (bank < BANK_VRAM)
fprintf(mf, "WRAM Bank #%ld:\n", bank - BANK_WRAMX + 1);
else if (bank == BANK_HRAM)
fprintf(mf, "HRAM:\n");
else if (bank == BANK_VRAM || bank == BANK_VRAM + 1)
fprintf(mf, "VRAM Bank #%ld:\n", bank - BANK_VRAM);
else if (bank == BANK_OAM)
} else if (BankIndexIsWRAMX(bank)) {
fprintf(mf, "WRAM Bank #%d:\n",
bank - BANK_INDEX_WRAMX + 1);
} else if (BankIndexIsVRAM(bank)) {
fprintf(mf, "VRAM Bank #%d:\n", bank - BANK_INDEX_VRAM);
} else if (BankIndexIsOAM(bank)) {
fprintf(mf, "OAM:\n");
else if (bank < MAXBANKS)
fprintf(mf, "SRAM Bank #%ld:\n", bank - BANK_SRAM);
} else if (BankIndexIsHRAM(bank)) {
fprintf(mf, "HRAM:\n");
} else if (BankIndexIsSRAM(bank)) {
fprintf(mf, "SRAM Bank #%d:\n", bank - BANK_INDEX_SRAM);
}
}
if (sf) {
if (bank < BANK_WRAM0)
sfbank = bank;
else if (bank == BANK_WRAM0)
if (BankIndexIsROM0(bank))
sfbank = 0;
else if (bank < BANK_VRAM)
sfbank = bank - BANK_WRAMX + 1;
else if (bank == BANK_HRAM)
else if (BankIndexIsROMX(bank))
sfbank = bank - BANK_INDEX_ROMX + 1;
else if (BankIndexIsWRAM0(bank))
sfbank = 0;
else if (bank == BANK_VRAM || bank == BANK_VRAM + 1)
sfbank = bank - BANK_VRAM;
else if (bank == BANK_OAM)
else if (BankIndexIsWRAMX(bank))
sfbank = bank - BANK_INDEX_WRAMX + 1;
else if (BankIndexIsVRAM(bank))
sfbank = bank - BANK_INDEX_VRAM;
else if (BankIndexIsOAM(bank))
sfbank = 0;
else if (bank < MAXBANKS)
sfbank = bank - BANK_SRAM;
else if (BankIndexIsHRAM(bank))
sfbank = 0;
else if (BankIndexIsSRAM(bank))
sfbank = bank - BANK_INDEX_SRAM;
else
sfbank = 0;
}
}
void
MapfileWriteSection(struct sSection * pSect)
void MapfileWriteSection(const struct sSection *pSect)
{
SLONG i;
int32_t i;
if (mf) {
if (pSect->nByteSize > 0) {
fprintf(mf, " SECTION: $%04lX-$%04lX ($%04lX bytes) [\"%s\"]\n",
fprintf(mf, " SECTION: $%04X-$%04X ($%04X bytes) [\"%s\"]\n",
pSect->nOrg, pSect->nOrg + pSect->nByteSize - 1,
pSect->nByteSize, pSect->pzName);
} else {
fprintf(mf, " SECTION: $%04lX ($0 bytes) [\"%s\"]\n",
fprintf(mf, " SECTION: $%04X ($0 bytes) [\"%s\"]\n",
pSect->nOrg, pSect->pzName);
}
}
for (i = 0; i < pSect->nNumberOfSymbols; i += 1) {
struct sSymbol *pSym;
pSym = pSect->tSymbols[i];
if ((pSym->pSection == pSect)
&& (pSym->Type != SYM_IMPORT)) {
const struct sSymbol *pSym = pSect->tSymbols[i];
if ((pSym->pSection == pSect) && (pSym->Type != SYM_IMPORT)) {
if (mf) {
fprintf(mf, " $%04lX = %s\n",
fprintf(mf, " $%04X = %s\n",
pSym->nOffset + pSect->nOrg,
pSym->pzName);
}
if (sf) {
fprintf(sf, "%02lX:%04lX %s\n", sfbank,
fprintf(sf, "%02X:%04X %s\n", sfbank,
pSym->nOffset + pSect->nOrg,
pSym->pzName);
}
@@ -125,8 +127,7 @@ MapfileWriteSection(struct sSection * pSect)
}
}
void
MapfileCloseBank(SLONG slack)
void MapfileCloseBank(int32_t slack)
{
if (!mf)
return;
@@ -134,5 +135,5 @@ MapfileCloseBank(SLONG slack)
if (slack == MaxAvail[currentbank])
fprintf(mf, " EMPTY\n\n");
else
fprintf(mf, " SLACK: $%04lX bytes\n\n", slack);
fprintf(mf, " SLACK: $%04X bytes\n\n", slack);
}

View File

@@ -1,59 +1,47 @@
/*
* Here we have the routines that read an objectfile
*
*/
#include <ctype.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "extern/err.h"
#include "link/assign.h"
#include "link/mylink.h"
#include "link/main.h"
struct sSymbol **tSymbols;
struct sSection *pSections = NULL;
struct sSection *pLibSections = NULL;
UBYTE dummymem;
BBOOL oReadLib = 0;
struct sSection *pSections;
struct sSection *pLibSections;
uint8_t dummymem;
uint8_t oReadLib;
/*
* The usual byte order stuff
*
* Read 32-bit values with the correct endianness
*/
SLONG
readlong(FILE * f)
static int32_t readlong(FILE *f)
{
SLONG r;
int32_t r;
r = fgetc(f);
r |= fgetc(f) << 8;
r |= fgetc(f) << 16;
r |= fgetc(f) << 24;
return (r);
}
UWORD
readword(FILE * f)
{
UWORD r;
r = fgetc(f);
r |= fgetc(f) << 8;
return (r);
return r;
}
/*
* Read a NULL terminated string from a file
*
*/
SLONG
readasciiz(char **dest, FILE *f)
int32_t readasciiz(char **dest, FILE *f)
{
size_t r = 0;
@@ -61,9 +49,8 @@ readasciiz(char **dest, FILE *f)
char *start = malloc(bufferLength);
char *s = start;
if (!s) {
err(1, NULL);
}
if (!s)
err(1, "%s: Couldn't allocate memory", __func__);
while (((*s++) = fgetc(f)) != 0) {
r += 1;
@@ -72,7 +59,8 @@ readasciiz(char **dest, FILE *f)
bufferLength *= 2;
start = realloc(start, bufferLength);
if (!start) {
err(1, NULL);
err(1, "%s: Couldn't allocate memory",
__func__);
}
s = start + r;
}
@@ -84,11 +72,8 @@ readasciiz(char **dest, FILE *f)
/*
* Allocate a new section and link it into the list
*
*/
struct sSection *
AllocSection(void)
struct sSection *AllocSection(void)
{
struct sSection **ppSections;
@@ -101,48 +86,51 @@ AllocSection(void)
ppSections = &((*ppSections)->pNext);
*ppSections = malloc(sizeof **ppSections);
if (!*ppSections) {
err(1, NULL);
}
if (!*ppSections)
err(1, "%s: Couldn't allocate memory", __func__);
(*ppSections)->tSymbols = tSymbols;
(*ppSections)->pNext = NULL;
(*ppSections)->pPatches = NULL;
(*ppSections)->oAssigned = 0;
return *ppSections;
}
/*
* Read a symbol from a file
*
*/
struct sSymbol *
obj_ReadSymbol(FILE * f)
struct sSymbol *obj_ReadSymbol(FILE *f, char *tzObjectfile)
{
struct sSymbol *pSym;
pSym = malloc(sizeof *pSym);
if (!pSym) {
err(1, NULL);
}
pSym = malloc(sizeof(*pSym));
if (!pSym)
err(1, "%s: Couldn't allocate memory", __func__);
readasciiz(&pSym->pzName, f);
if ((pSym->Type = (enum eSymbolType) fgetc(f)) != SYM_IMPORT) {
pSym->Type = (enum eSymbolType)fgetc(f);
pSym->pzObjFileName = tzObjectfile;
if (pSym->Type != SYM_IMPORT) {
readasciiz(&pSym->pzFileName, f);
pSym->nFileLine = readlong(f);
pSym->nSectionID = readlong(f);
pSym->nOffset = readlong(f);
}
return pSym;
}
/*
* RGB object reader routines
*
*/
struct sSection *
obj_ReadRGBSection(FILE * f)
struct sSection *obj_ReadRGBSection(FILE *f)
{
struct sSection *pSection;
char *pzName;
readasciiz(&pzName, f);
if (IsSectionNameInUse(pzName))
errx(1, "Section name \"%s\" is already in use.", pzName);
@@ -156,24 +144,22 @@ obj_ReadRGBSection(FILE * f)
pSection->nBank = readlong(f);
pSection->nAlign = readlong(f);
if ((options & OPT_TINY) && (pSection->Type == SECT_ROMX)) {
if ((options & OPT_TINY) && (pSection->Type == SECT_ROMX))
errx(1, "ROMX sections can't be used with option -t.");
}
if ((options & OPT_CONTWRAM) && (pSection->Type == SECT_WRAMX)) {
if ((options & OPT_CONTWRAM) && (pSection->Type == SECT_WRAMX))
errx(1, "WRAMX sections can't be used with options -w or -d.");
}
if (options & OPT_DMG_MODE) {
/* WRAMX sections are checked for OPT_CONTWRAM */
if (pSection->Type == SECT_VRAM && pSection->nBank == 1) {
if (pSection->Type == SECT_VRAM && pSection->nBank == 1)
errx(1, "VRAM bank 1 can't be used with option -d.");
}
}
unsigned int maxsize = 0;
uint32_t maxsize = 0;
/* Verify that the section isn't too big */
switch (pSection->Type)
{
switch (pSection->Type) {
case SECT_ROM0:
maxsize = (options & OPT_TINY) ? 0x8000 : 0x4000;
break;
@@ -205,68 +191,76 @@ obj_ReadRGBSection(FILE * f)
pzName, pSection->nByteSize, maxsize);
}
if ((pSection->Type == SECT_ROMX) || (pSection->Type == SECT_ROM0)) {
/*
* These sectiontypes contain data...
*
* If the section doesn't contain data, it is ready
*/
if (pSection->nByteSize) {
pSection->pData = malloc(pSection->nByteSize);
if (!pSection->pData) {
err(1, NULL);
if ((pSection->Type != SECT_ROMX) && (pSection->Type != SECT_ROM0))
return pSection;
/* If there is no data to read, exit */
if (pSection->nByteSize == 0) {
/* Skip number of patches */
readlong(f);
pSection->pData = &dummymem;
return pSection;
}
SLONG nNumberOfPatches;
pSection->pData = malloc(pSection->nByteSize);
if (!pSection->pData)
err(1, "%s: Couldn't allocate memory", __func__);
int32_t nNumberOfPatches;
struct sPatch **ppPatch, *pPatch;
fread(pSection->pData, sizeof(UBYTE),
pSection->nByteSize, f);
if (fread(pSection->pData, sizeof(uint8_t), pSection->nByteSize, f)
!= pSection->nByteSize) {
err(1, "%s: Read error", __func__);
}
nNumberOfPatches = readlong(f);
ppPatch = &pSection->pPatches;
/*
* And patches...
*
*/
while (nNumberOfPatches--) {
pPatch = malloc(sizeof *pPatch);
if (!pPatch) {
err(1, NULL);
}
pPatch = malloc(sizeof(*pPatch));
if (!pPatch)
err(1, "%s: Couldn't allocate memory", __func__);
*ppPatch = pPatch;
readasciiz(&pPatch->pzFilename, f);
pPatch->nLineNo = readlong(f);
pPatch->nOffset = readlong(f);
pPatch->Type = (enum ePatchType)fgetc(f);
if ((pPatch->nRPNSize = readlong(f)) > 0) {
pPatch->nRPNSize = readlong(f);
if (pPatch->nRPNSize > 0) {
pPatch->pRPN = malloc(pPatch->nRPNSize);
if (!pPatch->pRPN) {
err(1, NULL);
err(1, "%s: Couldn't allocate memory",
__func__);
}
fread(pPatch->pRPN, sizeof(UBYTE),
pPatch->nRPNSize, f);
} else
if (fread(pPatch->pRPN, sizeof(uint8_t),
pPatch->nRPNSize, f) != pPatch->nRPNSize) {
errx(1, "%s: Read error", __func__);
}
} else {
pPatch->pRPN = NULL;
}
pPatch->pNext = NULL;
ppPatch = &(pPatch->pNext);
}
} else {
/* Skip number of patches */
readlong(f);
pSection->pData = &dummymem;
}
}
return pSection;
}
void
obj_ReadRGB(FILE * pObjfile)
void obj_ReadRGB(FILE *pObjfile, char *tzObjectfile)
{
struct sSection *pFirstSection;
SLONG nNumberOfSymbols, nNumberOfSections, i;
int32_t nNumberOfSymbols, nNumberOfSections, i;
nNumberOfSymbols = readlong(pObjfile);
nNumberOfSections = readlong(pObjfile);
@@ -274,15 +268,15 @@ obj_ReadRGB(FILE * pObjfile)
/* First comes the symbols */
if (nNumberOfSymbols) {
tSymbols = malloc(nNumberOfSymbols * sizeof *tSymbols);
if (!tSymbols) {
err(1, NULL);
}
tSymbols = malloc(nNumberOfSymbols * sizeof(*tSymbols));
if (!tSymbols)
err(1, "%s: Couldn't allocate memory", __func__);
for (i = 0; i < nNumberOfSymbols; i += 1)
tSymbols[i] = obj_ReadSymbol(pObjfile);
} else
tSymbols[i] = obj_ReadSymbol(pObjfile, tzObjectfile);
} else {
tSymbols = (struct sSymbol **)&dummymem;
}
/* Next we have the sections */
@@ -299,52 +293,56 @@ obj_ReadRGB(FILE * pObjfile)
/*
* Fill in the pSection entry in the symbolstructure.
* This REALLY needs some cleaning up... but, hey, it works
*
*/
for (i = 0; i < nNumberOfSymbols; i += 1) {
struct sSection *pConvSect = pFirstSection;
if (tSymbols[i]->Type != SYM_IMPORT
&& tSymbols[i]->nSectionID != -1) {
SLONG j = 0;
if ((tSymbols[i]->Type != SYM_IMPORT) &&
(tSymbols[i]->nSectionID != -1)) {
int32_t j = 0;
while (j != tSymbols[i]->nSectionID) {
j += 1;
pConvSect = pConvSect->pNext;
}
tSymbols[i]->pSection = pConvSect;
} else
} else {
tSymbols[i]->pSection = NULL;
}
}
}
/*
* The main objectfileloadroutine (phew)
*
*/
void
obj_ReadOpenFile(FILE * pObjfile, char *tzObjectfile)
void obj_ReadOpenFile(FILE *pObjfile, char *tzObjectfile)
{
char tzHeader[8];
char tzHeader[strlen(RGBDS_OBJECT_VERSION_STRING) + 1];
fread(tzHeader, sizeof(char), 4, pObjfile);
tzHeader[4] = 0;
if (strncmp(tzHeader, "RGB", 3) == 0) {
switch (tzHeader[3]) {
case '3':
case '4': // V4 supports OAM sections, but is otherwise identical
obj_ReadRGB(pObjfile);
break;
default:
errx(1, "'%s' uses an unsupported object file version (%s). Please reassemble it.", tzObjectfile, tzHeader);
if (fread(tzHeader, sizeof(char), strlen(RGBDS_OBJECT_VERSION_STRING),
pObjfile) != strlen(RGBDS_OBJECT_VERSION_STRING)) {
errx(1, "%s: Read error", tzObjectfile);
}
tzHeader[strlen(RGBDS_OBJECT_VERSION_STRING)] = 0;
if (strncmp(tzHeader, RGBDS_OBJECT_VERSION_STRING,
strlen(RGBDS_OBJECT_VERSION_STRING)) == 0) {
obj_ReadRGB(pObjfile, tzObjectfile);
} else {
errx(1, "'%s' is not a valid object", tzObjectfile);
int32_t i;
for (i = 0; i < strlen(RGBDS_OBJECT_VERSION_STRING); i++)
if (!isprint(tzHeader[i]))
tzHeader[i] = '?';
errx(1, "%s: Invalid file or object file version [%s]",
tzObjectfile, tzHeader);
}
}
void
obj_Readfile(char *tzObjectfile)
void obj_Readfile(char *tzObjectfile)
{
FILE *pObjfile;
@@ -354,24 +352,23 @@ obj_Readfile(char *tzObjectfile)
oReadLib = 0;
pObjfile = fopen(tzObjectfile, "rb");
if (pObjfile == NULL) {
if (pObjfile == NULL)
err(1, "Unable to open object '%s'", tzObjectfile);
}
obj_ReadOpenFile(pObjfile, tzObjectfile);
fclose(pObjfile);
oReadLib = 0;
}
SLONG
file_Length(FILE * f)
int32_t file_Length(FILE *f)
{
ULONG r, p;
uint32_t r, p;
p = ftell(f);
fseek(f, 0, SEEK_END);
r = ftell(f);
fseek(f, p, SEEK_SET);
return (r);
return r;
}

View File

@@ -1,32 +1,37 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "extern/err.h"
#include "link/mylink.h"
#include "link/mapfile.h"
#include "link/main.h"
#include "link/assign.h"
char *tzOutname;
char *tzOverlayname = NULL;
char *tzOverlayname;
SLONG MaxOverlayBank;
int32_t MaxOverlayBank;
void
writehome(FILE * f, FILE * f_overlay)
void writehome(FILE *f, FILE *f_overlay)
{
struct sSection *pSect;
UBYTE *mem;
const struct sSection *pSect;
uint8_t *mem;
mem = malloc(MaxAvail[BANK_ROM0]);
mem = malloc(MaxAvail[BANK_INDEX_ROM0]);
if (!mem)
return;
if (f_overlay != NULL) {
fseek(f_overlay, 0L, SEEK_SET);
fread(mem, 1, MaxAvail[BANK_ROM0], f_overlay);
if (fread(mem, 1, MaxAvail[BANK_INDEX_ROM0], f_overlay) !=
MaxAvail[BANK_INDEX_ROM0]) {
warnx("Failed to read data from overlay file.");
}
} else {
memset(mem, fillchar, MaxAvail[BANK_ROM0]);
memset(mem, fillchar, MaxAvail[BANK_INDEX_ROM0]);
}
MapfileInitBank(0);
@@ -42,15 +47,14 @@ writehome(FILE * f, FILE * f_overlay)
MapfileCloseBank(area_Avail(0));
fwrite(mem, 1, MaxAvail[BANK_ROM0], f);
fwrite(mem, 1, MaxAvail[BANK_INDEX_ROM0], f);
free(mem);
}
void
writebank(FILE * f, FILE * f_overlay, SLONG bank)
void writebank(FILE *f, FILE *f_overlay, int32_t bank)
{
struct sSection *pSect;
UBYTE *mem;
const struct sSection *pSect;
uint8_t *mem;
mem = malloc(MaxAvail[bank]);
if (!mem)
@@ -58,7 +62,8 @@ writebank(FILE * f, FILE * f_overlay, SLONG bank)
if (f_overlay != NULL && bank <= MaxOverlayBank) {
fseek(f_overlay, bank * 0x4000, SEEK_SET);
fread(mem, 1, MaxAvail[bank], f_overlay);
if (fread(mem, 1, MaxAvail[bank], f_overlay) != MaxAvail[bank])
warnx("Failed to read data from overlay file.");
} else {
memset(mem, fillchar, MaxAvail[bank]);
}
@@ -80,47 +85,50 @@ writebank(FILE * f, FILE * f_overlay, SLONG bank)
free(mem);
}
void
out_Setname(char *tzOutputfile)
void out_Setname(char *tzOutputfile)
{
tzOutname = tzOutputfile;
}
void
out_SetOverlayname(char *tzOverlayfile)
void out_SetOverlayname(char *tzOverlayfile)
{
tzOverlayname = tzOverlayfile;
}
void
Output(void)
void Output(void)
{
SLONG i;
int32_t i;
FILE *f;
FILE *f_overlay = NULL;
if ((f = fopen(tzOutname, "wb"))) {
/*
* Apply overlay
*/
f = fopen(tzOutname, "wb");
if (f != NULL) {
if (tzOverlayname) {
f_overlay = fopen(tzOverlayname, "rb");
if (!f_overlay) {
fprintf(stderr, "Failed to open overlay file %s\n", tzOverlayname);
exit(1);
errx(1, "Failed to open overlay file %s\n",
tzOverlayname);
}
fseek(f_overlay, 0, SEEK_END);
if (ftell(f_overlay) % 0x4000 != 0) {
fprintf(stderr, "Overlay file must be aligned to 0x4000 bytes\n");
exit(1);
}
if (ftell(f_overlay) % 0x4000 != 0)
errx(1, "Overlay file must be aligned to 0x4000 bytes.");
MaxOverlayBank = (ftell(f_overlay) / 0x4000) - 1;
if (MaxOverlayBank < 1) {
fprintf(stderr, "Overlay file be at least 0x8000 bytes\n");
exit(1);
}
if (MaxOverlayBank > MaxBankUsed) {
if (MaxOverlayBank < 1)
errx(1, "Overlay file must be at least 0x8000 bytes.");
if (MaxOverlayBank > MaxBankUsed)
MaxBankUsed = MaxOverlayBank;
}
}
writehome(f, f_overlay);
for (i = 1; i <= MaxBankUsed; i += 1)
@@ -128,18 +136,22 @@ Output(void)
fclose(f);
if (tzOverlayname) {
if (tzOverlayname)
fclose(f_overlay);
}
}
for (i = BANK_WRAM0; i < MAXBANKS; i++) {
struct sSection *pSect;
/*
* Add regular sections
*/
for (i = BANK_INDEX_WRAM0; i < BANK_INDEX_MAX; i++) {
const struct sSection *pSect;
MapfileInitBank(i);
pSect = pSections;
while (pSect) {
if (pSect->nBank == i) {
if (pSect->nBank == i)
MapfileWriteSection(pSect);
}
pSect = pSect->pNext;
}
MapfileCloseBank(area_Avail(i));

View File

@@ -15,9 +15,11 @@
*/
%{
#include <stdint.h>
#include <stdio.h>
#include "extern/err.h"
#include "link/script.h"
int yylex();
@@ -26,7 +28,10 @@ void yyerror(char *);
extern int yylineno;
%}
%union { int i; char s[512]; }
%union {
int32_t i;
char s[512];
}
%token<i> INTEGER
%token<s> STRING
@@ -57,41 +62,51 @@ line:
statement:
/* Statements to set the current section */
SECTION_NONBANKED {
SECTION_NONBANKED
{
script_SetCurrentSectionType($1, 0);
}
| SECTION_NONBANKED INTEGER {
| SECTION_NONBANKED INTEGER
{
script_fatalerror("Trying to assign a bank to a non-banked section.\n");
}
| SECTION_BANKED {
| SECTION_BANKED
{
script_fatalerror("Banked section without assigned bank.\n");
}
| SECTION_BANKED INTEGER {
| SECTION_BANKED INTEGER
{
script_SetCurrentSectionType($1, $2);
}
/* Commands to adjust the address inside the current section */
| COMMAND_ALIGN INTEGER {
| COMMAND_ALIGN INTEGER
{
script_SetAlignment($2);
}
| COMMAND_ALIGN {
| COMMAND_ALIGN
{
script_fatalerror("ALIGN keyword needs an argument.\n");
}
| COMMAND_ORG INTEGER {
| COMMAND_ORG INTEGER
{
script_SetAddress($2);
}
| COMMAND_ORG {
| COMMAND_ORG
{
script_fatalerror("ORG keyword needs an argument.\n");
}
/* Section name */
| STRING {
| STRING
{
script_OutputSection($1);
}
/* Include file */
| COMMAND_INCLUDE STRING {
| COMMAND_INCLUDE STRING
{
script_IncludeFile($2);
}

View File

@@ -1,92 +1,101 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "extern/err.h"
#include "link/assign.h"
#include "link/main.h"
#include "link/mylink.h"
#include "link/symbol.h"
#include "link/main.h"
struct sSection *pCurrentSection;
SLONG rpnstack[256];
SLONG rpnp;
SLONG nPC;
static struct sSection *pCurrentSection;
static int32_t rpnstack[256];
static int32_t rpnp;
int32_t nPC;
void
rpnpush(SLONG i)
static void rpnpush(int32_t i)
{
rpnstack[rpnp++] = i;
rpnstack[rpnp] = i;
rpnp++;
}
SLONG
rpnpop(void)
static int32_t rpnpop(void)
{
return (rpnstack[--rpnp]);
rpnp--;
return rpnstack[rpnp];
}
SLONG
getsymvalue(SLONG symid)
static int32_t getsymvalue(int32_t symid)
{
switch (pCurrentSection->tSymbols[symid]->Type) {
const struct sSymbol *tSymbol = pCurrentSection->tSymbols[symid];
switch (tSymbol->Type) {
case SYM_IMPORT:
return (sym_GetValue(pCurrentSection->tSymbols[symid]->pzName));
break;
return sym_GetValue(tSymbol->pzName);
case SYM_EXPORT:
case SYM_LOCAL:
{
if (strcmp
(pCurrentSection->tSymbols[symid]->pzName,
"@") == 0) {
return (nPC);
} else
return (pCurrentSection->tSymbols[symid]->
nOffset +
pCurrentSection->tSymbols[symid]->
pSection->nOrg);
}
if (strcmp(tSymbol->pzName, "@") == 0)
return nPC;
return tSymbol->nOffset + tSymbol->pSection->nOrg;
default:
break;
}
errx(1, "*INTERNAL* UNKNOWN SYMBOL TYPE");
errx(1, "%s: Unknown symbol type", __func__);
}
SLONG
getsymbank(SLONG symid)
static int32_t getrealbankfrominternalbank(int32_t n)
{
SLONG nBank;
switch (pCurrentSection->tSymbols[symid]->Type) {
case SYM_IMPORT:
nBank = sym_GetBank(pCurrentSection->tSymbols[symid]->pzName);
break;
case SYM_EXPORT:
case SYM_LOCAL:
nBank = pCurrentSection->tSymbols[symid]->pSection->nBank;
break;
default:
errx(1, "*INTERNAL* UNKNOWN SYMBOL TYPE");
}
if (nBank == BANK_WRAM0 || nBank == BANK_ROM0 || nBank == BANK_OAM ||
nBank == BANK_HRAM) {
if (BankIndexIsWRAM0(n) || BankIndexIsROM0(n) ||
BankIndexIsOAM(n) || BankIndexIsHRAM(n)) {
return 0;
} else if (nBank >= BANK_WRAMX && nBank < (BANK_WRAMX + BANK_COUNT_WRAMX)) {
return nBank - BANK_WRAMX + 1;
} else if (nBank >= BANK_VRAM && nBank < (BANK_VRAM + BANK_COUNT_VRAM)) {
return nBank - BANK_VRAM;
} else if (nBank >= BANK_SRAM && nBank < (BANK_SRAM + BANK_COUNT_SRAM)) {
return nBank - BANK_SRAM;
} else if (BankIndexIsROMX(n)) {
return n - BANK_INDEX_ROMX + 1;
} else if (BankIndexIsWRAMX(n)) {
return n - BANK_INDEX_WRAMX + 1;
} else if (BankIndexIsVRAM(n)) {
return n - BANK_INDEX_VRAM;
} else if (BankIndexIsSRAM(n)) {
return n - BANK_INDEX_SRAM;
}
return nBank;
errx(1, "%s: Unknown bank %d", __func__, n);
return n;
}
SLONG
calcrpn(struct sPatch * pPatch)
static int32_t getsymbank(int32_t symid)
{
SLONG t, size;
UBYTE *rpn;
int32_t nBank;
const struct sSymbol *tSymbol = pCurrentSection->tSymbols[symid];
switch (tSymbol->Type) {
case SYM_IMPORT:
nBank = sym_GetBank(tSymbol->pzName);
break;
case SYM_EXPORT:
case SYM_LOCAL:
nBank = tSymbol->pSection->nBank;
break;
default:
errx(1, "%s: Unknown symbol type", __func__);
}
return getrealbankfrominternalbank(nBank);
}
int32_t calcrpn(struct sPatch *pPatch)
{
int32_t t, size;
uint8_t *rpn;
uint8_t rpn_cmd;
int32_t nBank;
rpnp = 0;
@@ -96,7 +105,9 @@ calcrpn(struct sPatch * pPatch)
while (size > 0) {
size -= 1;
switch (*rpn++) {
rpn_cmd = *rpn++;
switch (rpn_cmd) {
case RPN_ADD:
rpnpush(rpnpop() + rpnpop());
break;
@@ -128,7 +139,7 @@ calcrpn(struct sPatch * pPatch)
rpnpush(rpnpop() ^ rpnpop());
break;
case RPN_UNNOT:
rpnpush(rpnpop() ^ 0xFFFFFFFF);
rpnpush(~rpnpop());
break;
case RPN_LOGAND:
rpnpush(rpnpop() && rpnpop());
@@ -197,7 +208,7 @@ calcrpn(struct sPatch * pPatch)
pPatch->oRelocPatch |= (getsymbank(t) != -1);
size -= 4;
break;
case RPN_BANK:
case RPN_BANK_SYM:
/* symbol */
t = (*rpn++);
t |= (*rpn++) << 8;
@@ -206,13 +217,40 @@ calcrpn(struct sPatch * pPatch)
rpnpush(getsymbank(t));
size -= 4;
break;
}
}
return (rpnpop());
case RPN_BANK_SECT:
{
char *name = (char *)rpn;
struct sSection *pSection = GetSectionByName(name);
if (pSection == NULL) {
errx(1, "Requested BANK() of section \"%s\", which was not found.\n",
name);
}
void
Patch(void)
nBank = pSection->nBank;
rpnpush(getrealbankfrominternalbank(nBank));
int len = strlen(name);
size -= len + 1;
rpn += len + 1;
break;
}
case RPN_BANK_SELF:
nBank = pCurrentSection->nBank;
rpnpush(getrealbankfrominternalbank(nBank));
break;
default:
errx(1, "%s: Invalid command %d\n", __func__,
rpn_cmd);
break;
}
}
return rpnpop();
}
void Patch(void)
{
struct sSection *pSect;
@@ -223,7 +261,7 @@ Patch(void)
pCurrentSection = pSect;
pPatch = pSect->pPatches;
while (pPatch) {
SLONG t;
int32_t t;
nPC = pSect->nOrg + pPatch->nOffset;
t = calcrpn(pPatch);
@@ -232,7 +270,7 @@ Patch(void)
if (t >= -128 && t <= 255) {
t &= 0xFF;
pSect->pData[pPatch->nOffset] =
(UBYTE) t;
(uint8_t)t;
} else {
errx(1,
"%s(%ld) : Value must be 8-bit",

View File

@@ -20,9 +20,7 @@
.Nd Game Boy linker
.Sh SYNOPSIS
.Nm rgblink
.Op Fl t
.Op Fl w
.Op Fl d
.Op Fl dtVw
.Op Fl m Ar mapfile
.Op Fl n Ar symfile
.Op Fl O Ar overlayfile
@@ -95,6 +93,8 @@ have to be consistent.
See
.Xr rgblink 5
for more information about its format.
.It Fl V
Print the version of the program and exit.
.El
.Sh EXAMPLES
All you need for a basic ROM is an object file, which can be made into a ROM

View File

@@ -14,147 +14,161 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdint.h>
#include <string.h>
#include "extern/err.h"
#include "link/assign.h"
#include "link/mylink.h"
static struct {
unsigned int address; /* current address to write sections to */
unsigned int top_address; /* not inclusive */
uint32_t address; /* current address to write sections to */
uint32_t top_address; /* not inclusive */
enum eSectionType type;
} bank[MAXBANKS];
} bank[BANK_INDEX_MAX];
static int current_bank = -1; /* Bank as seen by the bank array */
static int current_real_bank = -1; /* bank as seen by the GB */
static int32_t current_bank = -1; /* Bank as seen by the bank array */
static int32_t current_real_bank = -1; /* bank as seen by the GB */
void script_InitSections(void)
{
int i;
for (i = 0; i < MAXBANKS; i++) {
if (i == BANK_ROM0) {
int32_t i;
for (i = 0; i < BANK_INDEX_MAX; i++) {
if (BankIndexIsROM0(i)) {
/* ROM0 bank */
bank[i].address = 0x0000;
if (options & OPT_TINY) {
if (options & OPT_TINY)
bank[i].top_address = 0x8000;
} else {
else
bank[i].top_address = 0x4000;
}
bank[i].type = SECT_ROM0;
} else if (i >= BANK_ROMX && i < BANK_ROMX + BANK_COUNT_ROMX) {
} else if (BankIndexIsROMX(i)) {
/* Swappable ROM bank */
bank[i].address = 0x4000;
bank[i].top_address = 0x8000;
bank[i].type = SECT_ROMX;
} else if (i == BANK_WRAM0) {
} else if (BankIndexIsWRAM0(i)) {
/* WRAM */
bank[i].address = 0xC000;
if (options & OPT_CONTWRAM) {
if (options & OPT_CONTWRAM)
bank[i].top_address = 0xE000;
} else {
else
bank[i].top_address = 0xD000;
}
bank[i].type = SECT_WRAM0;
} else if (i >= BANK_SRAM && i < BANK_SRAM + BANK_COUNT_SRAM) {
} else if (BankIndexIsSRAM(i)) {
/* Swappable SRAM bank */
bank[i].address = 0xA000;
bank[i].top_address = 0xC000;
bank[i].type = SECT_SRAM;
} else if (i >= BANK_WRAMX && i < BANK_WRAMX + BANK_COUNT_WRAMX) {
} else if (BankIndexIsWRAMX(i)) {
/* Swappable WRAM bank */
bank[i].address = 0xD000;
bank[i].top_address = 0xE000;
bank[i].type = SECT_WRAMX;
} else if (i >= BANK_VRAM && i < BANK_VRAM + BANK_COUNT_VRAM) {
} else if (BankIndexIsVRAM(i)) {
/* Swappable VRAM bank */
bank[i].address = 0x8000;
bank[i].type = SECT_VRAM;
if (options & OPT_DMG_MODE && i != BANK_VRAM) {
if (options & OPT_DMG_MODE && i != BANK_INDEX_VRAM) {
/* In DMG the only available bank is bank 0. */
bank[i].top_address = 0x8000;
} else {
bank[i].top_address = 0xA000;
}
} else if (i == BANK_OAM) {
} else if (BankIndexIsOAM(i)) {
/* OAM */
bank[i].address = 0xFE00;
bank[i].top_address = 0xFEA0;
bank[i].type = SECT_OAM;
} else if (i == BANK_HRAM) {
} else if (BankIndexIsHRAM(i)) {
/* HRAM */
bank[i].address = 0xFF80;
bank[i].top_address = 0xFFFF;
bank[i].type = SECT_HRAM;
} else {
errx(1, "(INTERNAL) Unknown bank type!");
errx(1, "%s: Unknown bank type %d", __func__, i);
}
}
}
void script_SetCurrentSectionType(const char *type, unsigned int bank)
void script_SetCurrentSectionType(const char *type, uint32_t bank)
{
if (strcmp(type, "ROM0") == 0) {
if (bank != 0)
errx(1, "(Internal) Trying to assign a bank number to ROM0.\n");
current_bank = BANK_ROM0;
errx(1, "Trying to assign a bank number to ROM0.\n");
current_bank = BANK_INDEX_ROM0;
current_real_bank = 0;
return;
} else if (strcmp(type, "ROMX") == 0) {
if (bank == 0)
errx(1, "ROMX index can't be 0.\n");
if (bank > BANK_COUNT_ROMX)
errx(1, "ROMX index too big (%d > %d).\n", bank, BANK_COUNT_ROMX);
current_bank = BANK_ROMX + bank - 1;
if (bank > BANK_COUNT_ROMX) {
errx(1, "ROMX index too big (%d > %d).\n", bank,
BANK_COUNT_ROMX);
}
current_bank = BANK_INDEX_ROMX + bank - 1;
current_real_bank = bank;
return;
} else if (strcmp(type, "VRAM") == 0) {
if (bank >= BANK_COUNT_VRAM)
errx(1, "VRAM index too big (%d >= %d).\n", bank, BANK_COUNT_VRAM);
current_bank = BANK_VRAM + bank;
if (bank >= BANK_COUNT_VRAM) {
errx(1, "VRAM index too big (%d >= %d).\n", bank,
BANK_COUNT_VRAM);
}
current_bank = BANK_INDEX_VRAM + bank;
current_real_bank = bank;
return;
} else if (strcmp(type, "WRAM0") == 0) {
if (bank != 0)
errx(1, "(Internal) Trying to assign a bank number to WRAM0.\n");
current_bank = BANK_WRAM0;
if (bank != 0) {
errx(1, "Trying to assign a bank number to WRAM0.\n");
}
current_bank = BANK_INDEX_WRAM0;
current_real_bank = 0;
return;
} else if (strcmp(type, "WRAMX") == 0) {
if (bank == 0)
errx(1, "WRAMX index can't be 0.\n");
if (bank > BANK_COUNT_WRAMX)
errx(1, "WRAMX index too big (%d > %d).\n", bank, BANK_COUNT_WRAMX);
current_bank = BANK_WRAMX + bank - 1;
if (bank > BANK_COUNT_WRAMX) {
errx(1, "WRAMX index too big (%d > %d).\n", bank,
BANK_COUNT_WRAMX);
}
current_bank = BANK_INDEX_WRAMX + bank - 1;
current_real_bank = bank - 1;
return;
} else if (strcmp(type, "SRAM") == 0) {
if (bank >= BANK_COUNT_SRAM)
errx(1, "SRAM index too big (%d >= %d).\n", bank, BANK_COUNT_SRAM);
current_bank = BANK_SRAM + bank;
if (bank >= BANK_COUNT_SRAM) {
errx(1, "SRAM index too big (%d >= %d).\n", bank,
BANK_COUNT_SRAM);
}
current_bank = BANK_INDEX_SRAM + bank;
current_real_bank = bank;
return;
} else if (strcmp(type, "OAM") == 0) {
if (bank != 0)
errx(1, "(Internal) Trying to assign a bank number to OAM.\n");
current_bank = BANK_OAM;
if (bank != 0) {
errx(1, "%s: Trying to assign a bank number to OAM.\n",
__func__);
}
current_bank = BANK_INDEX_OAM;
current_real_bank = 0;
return;
} else if (strcmp(type, "HRAM") == 0) {
if (bank != 0)
errx(1, "(Internal) Trying to assign a bank number to HRAM.\n");
current_bank = BANK_HRAM;
if (bank != 0) {
errx(1, "%s: Trying to assign a bank number to HRAM.\n",
__func__);
}
current_bank = BANK_INDEX_HRAM;
current_real_bank = 0;
return;
}
errx(1, "(Internal) Unknown section type \"%s\".\n", type);
errx(1, "%s: Unknown section type \"%s\".\n", __func__, type);
}
void script_SetAddress(unsigned int addr)
void script_SetAddress(uint32_t addr)
{
if (current_bank == -1) {
if (current_bank == -1)
errx(1, "Trying to set an address without assigned bank\n");
}
/* Make sure that we don't go back. */
if (bank[current_bank].address > addr) {
@@ -167,22 +181,21 @@ void script_SetAddress(unsigned int addr)
/* Make sure we don't overflow */
if (bank[current_bank].address >= bank[current_bank].top_address) {
errx(1, "Bank overflowed (0x%04X >= 0x%04X)\n",
bank[current_bank].address, bank[current_bank].top_address);
bank[current_bank].address,
bank[current_bank].top_address);
}
}
void script_SetAlignment(unsigned int alignment)
void script_SetAlignment(uint32_t alignment)
{
if (current_bank == -1) {
if (current_bank == -1)
errx(1, "Trying to set an alignment without assigned bank\n");
}
if (alignment > 15) {
if (alignment > 15)
errx(1, "Trying to set an alignment too big: %d\n", alignment);
}
unsigned int size = 1 << alignment;
unsigned int mask = size - 1;
uint32_t size = 1 << alignment;
uint32_t mask = size - 1;
if (bank[current_bank].address & mask) {
bank[current_bank].address &= ~mask;
@@ -192,17 +205,20 @@ void script_SetAlignment(unsigned int alignment)
/* Make sure we don't overflow */
if (bank[current_bank].address >= bank[current_bank].top_address) {
errx(1, "Bank overflowed (0x%04X >= 0x%04X)\n",
bank[current_bank].address, bank[current_bank].top_address);
bank[current_bank].address,
bank[current_bank].top_address);
}
}
void script_OutputSection(const char *section_name)
{
if (current_bank == -1) {
errx(1, "Trying to place section \"%s\" without assigned bank\n", section_name);
errx(1, "Trying to place section \"%s\" without assigned bank\n",
section_name);
}
if (!IsSectionSameTypeBankAndFloating(section_name, bank[current_bank].type,
if (!IsSectionSameTypeBankAndFloating(section_name,
bank[current_bank].type,
current_real_bank)) {
errx(1, "Different attributes for \"%s\" in source and linkerscript\n",
section_name);
@@ -211,6 +227,7 @@ void script_OutputSection(const char *section_name)
/* Move section to its place. */
bank[current_bank].address +=
AssignSectionAddressAndBankByName(section_name,
bank[current_bank].address, current_real_bank);
bank[current_bank].address,
current_real_bank);
}

View File

@@ -1,82 +1,85 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "extern/err.h"
#include "link/main.h"
#include "link/patch.h"
#include "types.h"
#define HASHSIZE 73
struct ISymbol {
char *pzName;
SLONG nValue;
SLONG nBank;
//-1 = const
int32_t nValue;
int32_t nBank; /* -1 = constant */
/* Object file where the symbol was defined. */
char tzObjFileName[_MAX_PATH + 1];
/* Source file where the symbol was defined. */
char tzFileName[_MAX_PATH + 1];
/* Line where the symbol was defined. */
uint32_t nFileLine;
struct ISymbol *pNext;
};
struct ISymbol *tHash[HASHSIZE];
SLONG
calchash(char *s)
int32_t calchash(char *s)
{
SLONG r = 0;
int32_t r = 0;
while (*s)
r += *s++;
return (r % HASHSIZE);
return r % HASHSIZE;
}
void
sym_Init(void)
void sym_Init(void)
{
SLONG i;
int32_t i;
for (i = 0; i < HASHSIZE; i += 1)
tHash[i] = NULL;
}
SLONG
sym_GetValue(char *tzName)
int32_t sym_GetValue(char *tzName)
{
if (strcmp(tzName, "@") == 0) {
return (nPC);
} else {
if (strcmp(tzName, "@") == 0)
return nPC;
struct ISymbol **ppSym;
ppSym = &(tHash[calchash(tzName)]);
while (*ppSym) {
if (strcmp(tzName, (*ppSym)->pzName)) {
if (strcmp(tzName, (*ppSym)->pzName))
ppSym = &((*ppSym)->pNext);
} else {
else
return ((*ppSym)->nValue);
}
}
errx(1, "Unknown symbol '%s'", tzName);
}
}
SLONG
sym_GetBank(char *tzName)
int32_t sym_GetBank(char *tzName)
{
struct ISymbol **ppSym;
ppSym = &(tHash[calchash(tzName)]);
while (*ppSym) {
if (strcmp(tzName, (*ppSym)->pzName)) {
if (strcmp(tzName, (*ppSym)->pzName))
ppSym = &((*ppSym)->pNext);
} else {
else
return ((*ppSym)->nBank);
}
}
errx(1, "Unknown symbol '%s'", tzName);
}
void
sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank)
void sym_CreateSymbol(char *tzName, int32_t nValue, int32_t nBank,
char *tzObjFileName, char *tzFileName, uint32_t nFileLine)
{
if (strcmp(tzName, "@") == 0)
return;
@@ -92,16 +95,28 @@ sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank)
if (nBank == -1)
return;
errx(1, "Symbol '%s' defined more than once", tzName);
errx(1, "'%s' in both %s : %s(%d) and %s : %s(%d)",
tzName, tzObjFileName, tzFileName, nFileLine,
(*ppSym)->tzObjFileName,
(*ppSym)->tzFileName, (*ppSym)->nFileLine);
}
}
if ((*ppSym = malloc(sizeof **ppSym))) {
if (((*ppSym)->pzName = malloc(strlen(tzName) + 1))) {
*ppSym = malloc(sizeof **ppSym);
if (*ppSym != NULL) {
(*ppSym)->pzName = malloc(strlen(tzName) + 1);
if ((*ppSym)->pzName != NULL) {
strcpy((*ppSym)->pzName, tzName);
(*ppSym)->nValue = nValue;
(*ppSym)->nBank = nBank;
(*ppSym)->pNext = NULL;
strncpy((*ppSym)->tzObjFileName, tzObjFileName,
sizeof((*ppSym)->tzObjFileName));
strncpy((*ppSym)->tzFileName, tzFileName,
sizeof((*ppSym)->tzFileName));
(*ppSym)->nFileLine = nFileLine;
}
}
}

View File

@@ -1,4 +1,4 @@
.\" Copyright (c) 2017 Antonio Nino Diaz <antonio_nd@outlook.com>
.\" Copyright (c) 2017-2018 Antonio Nino Diaz <antonio_nd@outlook.com>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -12,7 +12,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd April 17, 2017
.Dd January 7, 2018
.Dt RGBDS 5
.Os RGBDS Manual
.Sh NAME
@@ -42,7 +42,7 @@ is a 0terminated string of
.Bd -literal
; Header
BYTE ID[4] ; "RGB4"
BYTE ID[4] ; "RGB6"
LONG NumberOfSymbols ; The number of symbols used in this file
LONG NumberOfSections ; The number of sections used in this file
@@ -59,6 +59,10 @@ REPT NumberOfSymbols ; Number of symbols defined in this object file.
IF Type != 1 ; If symbol is defined in this object file.
STRING FileName ; File where the symbol is defined.
LONG LineNum ; Line number in the file where the symbol is defined.
LONG SectionID ; The section number (of this object file) in which
; this symbol is defined.
@@ -151,25 +155,29 @@ special prefixes for integers and symbols.
.It Li $03 Ta Li / operator
.It Li $04 Ta Li % operator
.It Li $05 Ta Li unary -
.It Li $06 Ta Li | operator
.It Li $07 Ta Li & operator
.It Li $08 Ta Li ^ operator
.It Li $09 Ta Li unary ~
.It Li $0A Ta Li && comparison
.It Li $0B Ta Li || comparison
.It Li $0C Ta Li unary !
.It Li $0D Ta Li == comparison
.It Li $0E Ta Li != comparison
.It Li $0F Ta Li > comparison
.It Li $10 Ta Li < comparison
.It Li $11 Ta Li >= comparison
.It Li $12 Ta Li <= comparison
.It Li $13 Ta Li << comparison
.It Li $14 Ta Li >> comparison
.It Li $15 Ta Li BANK()
function.
A symbol ID follows.
.It Li $16 Ta Li HRAMCheck.
.It Li $10 Ta Li | operator
.It Li $11 Ta Li & operator
.It Li $12 Ta Li ^ operator
.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 $30 Ta Li == comparison
.It Li $31 Ta Li != comparison
.It Li $32 Ta Li > comparison
.It Li $33 Ta Li < comparison
.It Li $34 Ta Li >= comparison
.It Li $35 Ta Li <= comparison
.It Li $40 Ta Li << comparison
.It Li $41 Ta Li >> comparison
.It Li $50 Ta Li BANK(symbol),
a
.Ar LONG
Symbol ID follows.
.It Li $51 Ta Li BANK(section_name),
a null-terminated string follows.
.It Li $52 Ta Li Current BANK() .
.It Li $60 Ta Li HRAMCheck.
Check if the value is in HRAM, AND it with 0xFF.
.It Li $80 Ta Ar LONG
integer follows.

View File

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

View File

@@ -1,3 +1,4 @@
#!/bin/sh
fname=$(mktemp)
rc=0

View File

@@ -1,3 +1,4 @@
#!/bin/sh
fname=$(mktemp)
for i in *.asm; do

View File

@@ -1,3 +1,4 @@
#!/bin/sh
otemp=$(mktemp)
gbtemp=$(mktemp)
gbtemp2=$(mktemp)

View File

@@ -1,3 +1,4 @@
#!/bin/sh
otemp=$(mktemp)
gbtemp=$(mktemp)