Compare commits

...

83 Commits

Author SHA1 Message Date
Antonio Niño Díaz
ea4276c7ac Increase version number to 0.3.6
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-03-20 20:11:38 +00:00
Antonio Niño Díaz
7bce97f817 Fix crash in rgbgfx with height not multiple of 8
Images are allowed to have any arbitrary height if the width is 8. If
the height is not a multiple of 8, the number of tiles calculated won't
be an exact number and it will be rounded down. This patch increases the
number of tiles allocated in this case to prevent rgbgfx from accessing
memory that hasn't been allocated.

The buffers are now initialized to 0 with calloc instead of being
created with malloc.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-03-19 21:47:19 +00:00
Antonio Niño Díaz
483a63156b Document character maps
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-03-15 21:04:43 +00:00
Anthony J. Bentley
5a4bbe4985 Add a new flag, -f, which allows independently fixing or trashing checksums. 2018-03-10 21:48:23 -07:00
Antonio Niño Díaz
f86dbafad0 Fix format in manpage
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-03-07 18:23:44 +00:00
Antonio Niño Díaz
8744d360a3 Fix format of manpage
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-27 19:42:29 +00:00
Antonio Niño Díaz
b6bd57a764 Merge pull request #237 from continue-lines
Allow to continue lines

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-26 21:55:19 +00:00
Antonio Niño Díaz
f2b55527d5 Update html manpages
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-26 21:49:19 +00:00
Antonio Niño Díaz
84a6899c6c Document line continuation syntax
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-26 21:48:28 +00:00
Antonio Niño Díaz
8cffe22295 Fix style of code sections in manpages
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-26 21:48:26 +00:00
Antonio Niño Díaz
0c85240b97 Allow line continuations in list of macro args
For example:

    PrintMacro : MACRO
        PRINTT \1
    ENDM

        PrintMacro STRCAT(\"Hello\"\,  \
                          \" world\\n\")

It is possible to have spaces after the '\' and before the newline
character. This is needed because Windows line endings "\r\n" are
converted to " \n" before the lexer has a chance to handle them.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-26 21:47:52 +00:00
Antonio Niño Díaz
58ab88da82 Allow to scape " in lists of macro args
For example:

    PrintMacro : MACRO
        PRINTT \1
    ENDM

        PrintMacro STRCAT(\"Hello\"\,  \" world\\n\")

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-26 21:47:52 +00:00
Antonio Niño Díaz
3e219dee36 Allow to continuate lines except inside macros
Lines can be continuated after a newline character ('\n'):

    DB 1, 2, 3, 4 \
       5, 6, 7, 8

This doesn't work for now in lists of arguments of macros.

It is possible to have spaces after the '\' and before the newline
character. This is needed because Windows line endings "\r\n" are
converted to " \n" before the lexer has a chance to handle them.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-26 21:47:52 +00:00
Antonio Niño Díaz
6ad5bd2325 Add flag to rgbasm to disable LD->LDH optimization
rgbasm tries to optimize any loads from/to $FF00-$FFFF and generate
LDH 2-byte opcodes instead of regular LD 3-byte opcodes. This is a bit
inconsistent as it only works for constant values. If a load is trying
to access a label in a HRAM floating section, or a section found in a
different object file, this optimization doesn't work.

This means that a simple refactor or code could allow rgbasm to perform
the optimzation or prevent it from doing so. For certain projects, like
disassemblies, this is a problem.

This patch adds flag -L to rgbasm to disable the optimization, and
doesn't change the behaviour of any other existing code.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-26 21:44:00 +00:00
Antonio Niño Díaz
2a97535e75 Add safeguards against string overflows
Use snprintf instead of other unsafe functions. That way it is possible
to limit the size of the buffer and to ensure that it never overflows.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-25 22:58:29 +00:00
Antonio Niño Díaz
0e0e12a769 Add CSS file for the html documentation
It has been obtained from here:

http://mdocml.bsd.lv/cgi-bin/cvsweb/mandoc.css

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-24 16:40:55 +00:00
Antonio Niño Díaz
3bebedf1f8 Handle newlines and comments correctly
Newlines have to be handled before comments or comments won't be able to
handle line endings that don't include at least one LF character.

Also, document an obscure comment syntax: Anything that follows a '*'
placed at the start of a line is also a comment until the end of the
line.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-23 19:24:18 +00:00
Antonio Niño Díaz
2ed937db2c Allow JR between sections
Previously, JR was only allowed if the destination label was in the same
section as the JR. This patch removes this restriction. The check to see
if the relative value overflows is now done when linking the ROM.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-23 19:21:44 +00:00
Antonio Niño Díaz
d243bd04ef Introduce command PRINTI to print integers
PRINTV prints integers in hexadecimal, PRINTI prints them in signed
decimal. For example:

    PRINTT "Error at line "
    PRINTI __LINE__
    PRINTT "\n"

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-23 19:20:52 +00:00
Antonio Niño Díaz
3623638be7 Fix HIGH() and LOW() for constants
HIGH() and LOW() only worked with labels and register pairs.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-22 21:23:25 +00:00
Antonio Niño Díaz
8ea3669a64 Merge pull request #235 from obskyr/rgbgfx-color
Add color support to rgbgfx (again)!

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-20 19:56:39 +00:00
obskyr
8fe5293077 Allow superfluous height for 1-tile-wide images
Currently used here and there for small, icon-like tiles, it seems.

Signed-off-by: obskyr <powpowd@gmail.com>
2018-02-20 10:06:33 +01:00
obskyr
825fa915ee Fix rgbgfx's code style
Signed-off-by: obskyr <powpowd@gmail.com>
2018-02-20 10:06:00 +01:00
obskyr
885e8ea24a Add to contributor list
Signed-off-by: obskyr <powpowd@gmail.com>
2018-02-20 09:35:07 +01:00
obskyr
898f75ce57 Clarify and update rgbgfx documentation
Signed-off-by: obskyr <powpowd@gmail.com>
2018-02-20 09:35:00 +01:00
obskyr
b8af100c63 Handle grayscale images as expected
Signed-off-by: obskyr <powpowd@gmail.com>
2018-02-20 09:34:48 +01:00
obskyr
3075945367 Add color and transparency support to rgbgfx
In addition, fix various bugs.
Among them are minor memory issues and edge cases with certain inputs.

Signed-off-by: obskyr <powpowd@gmail.com>
2018-02-20 09:33:53 +01:00
Antonio Niño Díaz
d602ebfde5 Fix typo in rgblink manpage
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-02-18 19:57:02 +00:00
Antonio Niño Díaz
305512a2b7 Increase version number to 0.3.5
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-28 13:08:00 +00:00
Antonio Niño Díaz
a6b244b12e Move version files out of extern folder
The folder extern is reserved for external contributions, not common
files.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-28 13:07:21 +00:00
Antonio Niño Díaz
ceabbeaa2f Fix linkerscript man page
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-27 17:25:21 +00:00
Antonio Niño Díaz
3995852cc5 Fix nit in rgbasm.5 man page
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-27 15:19:18 +00:00
Antonio Niño Díaz
9793bcba6f Fix local execution of run-tests.sh script
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-27 15:04:17 +00:00
Antonio Niño Díaz
0727eb4374 Add test to verify hex codes of all instructions
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-27 14:38:52 +00:00
Antonio Niño Díaz
f8f67fcbce Add external projects to Travis CI jobs
Small tests like the ones included in this repository are good to test
individual features, but it is also a good idea to test some real
projects.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-27 11:14:10 +00:00
Anthony J. Bentley
abeca2d305 Prefer snprintf to strncpy when outputting C strings
strncpy is designed to output to fixed‐width buffers, not C strings
(hence its weird null termination behavior). In this case it happens to
work correctly due to the length check but, for style reasons, I would
rather use snprintf. Especially in this case, where it shortens the
code a bit.
2018-01-27 01:22:58 +00:00
Antonio Niño Díaz
a7dc86001c Add note about the MIT License in CONTRIBUTING.rst
Also, LICENSE.rst doesn't have any special formatting now, so it has
been renamed to LICENSE.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-27 00:47:06 +00:00
Antonio Niño Díaz
c071586ae5 Remove dependency of reallocarray()
By removing this dependency, all of the code of this repository is
licensed under the MIT license.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-27 00:30:13 +00:00
Antonio Niño Díaz
c6187be210 Remove dependency of strlcpy()
There was only one place where `strlcpy` was still used.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-27 00:02:44 +00:00
Antonio Niño Díaz
f9f3bb7761 Remove dependency of strlcat()
There was only one place where `strlcat` was used, and `snprintf`
actually does a better job at what the code was trying to achieve.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-27 00:02:26 +00:00
Antonio Niño Díaz
1a5c423984 Relicense codebase under MIT license
With permission from the main authors [1], most of the code has been
relicensed under the MIT license.

SPDX license identifiers are used so that the license headers in source
code files aren't too large.

Add CONTRIBUTORS.rst file.

[1] https://github.com/rednex/rgbds/issues/128

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-26 22:59:02 +00:00
Antonio Niño Díaz
b382dffdec Split src/asm/charmap.c into two files
This way it is easier to identify the license of the code.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-26 22:55:13 +00:00
Antonio Niño Díaz
33e9eb098c Exclude html files from checkpatch
Also, fix 2 nits in the codebase.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-26 18:57:25 +00:00
Antonio Niño Díaz
e77ebfe38a Disable OSX builds in Travis CI
Travis seems to be having some problems with OSX builds, so it's better
to disable them temporarily.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-25 22:23:43 +00:00
Antonio Niño Díaz
698ed9d5fc Don't clean html files with make clean
Added a new target to remove html files: `cleanwwwman`.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-25 22:12:31 +00:00
Antonio Niño Díaz
b07a8501d6 Fix linkerscript linking errors
The problems were introduced by the following commits:

- 959bfe2a9d

- 975200834e

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-25 22:07:16 +00:00
Antonio Niño Díaz
f779e724e2 Fix typo in manpage
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-24 20:29:27 +00:00
Antonio Niño Díaz
494b98e46a Fix html doc file name
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-24 20:29:09 +00:00
Antonio Niño Díaz
d1ff057889 Make clean target of Makefile clean html files
The html files generated with `make wwwman` weren't cleaned correctly
with `clean`.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-23 22:54:37 +00:00
Antonio Niño Díaz
292302c6d1 Move documentation to this repository
Modified Makefile wwwman target to output files inside docs/.

Modified .gitignore to allow *.html files.

Update README.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2018-01-23 21:28:10 +00:00
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
104 changed files with 12003 additions and 5588 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

2
.gitignore vendored
View File

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

View File

@@ -2,15 +2,13 @@ language: c
sudo: required sudo: required
install: install:
- ./.travis-deps.sh - ./.travis-deps.sh
- make
- sudo make install
os: os:
- linux - linux
- osx
compiler: compiler:
- clang - clang
- gcc - gcc
script: script:
- make - cd test
- sudo make install - ./run-tests.sh
after_success:
- pushd test/asm/ && ./test.sh && popd
- pushd test/link/ && ./test.sh && popd

93
CONTRIBUTING.rst Normal file
View File

@@ -0,0 +1,93 @@
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.
Note that you must contribute all your changes under the MIT License. If you are
just modifying a file, you don't need to do anything (maybe update the copyright
years). If you are adding new files, you need to use the correct header with the
copyright and the reference to the MIT License.
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.

41
CONTRIBUTORS.rst Normal file
View File

@@ -0,0 +1,41 @@
Contributors to RGBDS
=====================
Original author
---------------
- Carsten Elton Sørensen <csoren@gmail.com>
Main contributors
-----------------
- Justin Lloyd <jlloyd@imf.la>
- Vegard Nossum <vegard.nossum@gmail.com>
- Anthony J. Bentley <anthony@anjbe.name>
- stag019 <stag019@gmail.com>
- Antonio Niño Díaz <antonio_nd@outlook.com>
Other contributors
------------------
- Ben10do
- Björn Höhrmann <bjoern@hoehrmann.de>
- Christophe Staïesse <chastai@skynet.be>
- The Musl C library <http://www.musl-libc.org>
- obskyr <powpowd@gmail.com>
- The OpenBSD Project <http://www.openbsd.org>
- Sanqui <gsanky@gmail.com>
- YamaArashi <shadow962@live.com>
- yenatch <yenatch@gmail.com>

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License
Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

View File

@@ -1,74 +0,0 @@
# Original code
Copyright (C) 1997 Carsten Sorensen <surfsmurf@matilde.demon.co.uk>
The ASMotor package (xAsm, xLink, RGBFix, examples and documentation) is
freeware and distributed as is. The author retains his copyright and right to
modify the specifications and operation of the software without notice.
In other words this means I encourage you to...
- use it for whatever purpose even professional work without me charging you a
penny
- copy it to another person (wholly or in part, though I'm sure he'd appreciate
the whole package) in whatever form you find suitable
- mass-distribute the ASMotor package if it is complete (xAsm, xLink, RGBFix and
documentation).
- contact me if you have any problems
This also means you can't...
- blame me for loss of profit, data, sleep, food or other nasty things through
the use or distribution of ASMotor. If you choose to use ASMotor you do so at
your own risk.
- expect me to be able to help you should you have a problem related or not to
ASMotor.
# 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
0. You can do whatever you want to with the work.
1. You cannot stop anybody from doing whatever they want to with the work.
2. You cannot revoke anybody elses DO WHATEVER PUBLIC LICENSE in the work.
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the DO WHATEVER PUBLIC LICENSE
Software originally created by Justin Lloyd @ http://otakunozoku.com/
```
# rgbds-linux
Copyright (C) 2009 Vegard Nossum <vegard.nossum@gmail.com>
# 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.
rgbgfx was written by stag019, and is released under the ISC license.
Some files of rgblink were written by Antonio Niño Díaz, and they are relased
under the ISC license. The affected files have the appropriate license in the
header of the file.
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/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.

View File

@@ -1,3 +1,11 @@
#
# This file is part of RGBDS.
#
# Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
#
# SPDX-License-Identifier: MIT
#
# User-defined variables # User-defined variables
Q := @ Q := @
@@ -7,6 +15,7 @@ mandir := ${PREFIX}/man
STRIP := -s STRIP := -s
BINMODE := 555 BINMODE := 555
MANMODE := 444 MANMODE := 444
CHECKPATCH := ../linux/scripts/checkpatch.pl
# Other variables # Other variables
@@ -47,13 +56,9 @@ rgbasm_obj := \
src/asm/output.o \ src/asm/output.o \
src/asm/rpn.o \ src/asm/rpn.o \
src/asm/symbol.o \ src/asm/symbol.o \
src/asm/locallex.o \
src/extern/err.o \ src/extern/err.o \
src/extern/reallocarray.o \ src/extern/utf8decoder.o \
src/extern/strlcpy.o \ src/version.o
src/extern/strlcat.o \
src/extern/version.o
src/asm/asmy.h: src/asm/asmy.c src/asm/asmy.h: src/asm/asmy.c
src/asm/locallex.o src/asm/globlex.o src/asm/lexer.o: src/asm/asmy.h src/asm/locallex.o src/asm/globlex.o src/asm/lexer.o: src/asm/asmy.h
@@ -71,7 +76,7 @@ rgblink_obj := \
src/link/script.o \ src/link/script.o \
src/link/symbol.o \ src/link/symbol.o \
src/extern/err.o \ src/extern/err.o \
src/extern/version.o src/version.o
src/link/parser.h: src/link/parser.c src/link/parser.h: src/link/parser.c
src/link/lexer.o: src/link/parser.h src/link/lexer.o: src/link/parser.h
@@ -79,14 +84,14 @@ src/link/lexer.o: src/link/parser.h
rgbfix_obj := \ rgbfix_obj := \
src/fix/main.o \ src/fix/main.o \
src/extern/err.o \ src/extern/err.o \
src/extern/version.o src/version.o
rgbgfx_obj := \ rgbgfx_obj := \
src/gfx/gb.o \ src/gfx/gb.o \
src/gfx/main.o \ src/gfx/main.o \
src/gfx/makepng.o \ src/gfx/makepng.o \
src/extern/err.o \ src/extern/err.o \
src/extern/version.o src/version.o
rgbasm: ${rgbasm_obj} rgbasm: ${rgbasm_obj}
$Q${CC} ${REALCFLAGS} -o $@ ${rgbasm_obj} -lm $Q${CC} ${REALCFLAGS} -o $@ ${rgbasm_obj} -lm
@@ -114,17 +119,26 @@ rgbgfx: ${rgbgfx_obj}
.c.o: .c.o:
$Q${CC} ${REALCFLAGS} ${PNGCFLAGS} -c -o $@ $< $Q${CC} ${REALCFLAGS} ${PNGCFLAGS} -c -o $@ $<
# Target used to remove all files generated by other Makefile targets. # Target used to remove all files generated by other Makefile targets, except
# for the html documentation.
clean: clean:
$Q${RM} rgbds.7.html gbz80.7.html rgbds.5.html $Q${RM} rgbasm rgbasm.exe ${rgbasm_obj}
$Q${RM} rgbasm rgbasm.exe ${rgbasm_obj} rgbasm.1.html rgbasm.5.html $Q${RM} rgblink rgblink.exe ${rgblink_obj}
$Q${RM} rgblink rgblink.exe ${rgblink_obj} rgblink.1.html rgblink.5.html $Q${RM} rgbfix rgbfix.exe ${rgbfix_obj}
$Q${RM} rgbfix rgbfix.exe ${rgbfix_obj} rgbfix.1.html $Q${RM} rgbgfx rgbgfx.exe ${rgbgfx_obj}
$Q${RM} rgbgfx rgbgfx.exe ${rgbgfx_obj} rgbgfx.1.html
$Q${RM} src/asm/asmy.c src/asm/asmy.h $Q${RM} src/asm/asmy.c src/asm/asmy.h
$Q${RM} src/link/lexer.c src/link/parser.c src/link/parser.h $Q${RM} src/link/lexer.c src/link/parser.c src/link/parser.h
# Target used to remove all html files generated by the wwwman target
cleanwwwman:
$Q${RM} docs/rgbds.7.html docs/gbz80.7.html docs/rgbds.5.html
$Q${RM} docs/rgbasm.1.html docs/rgbasm.5.html
$Q${RM} docs/rgblink.1.html docs/rgblink.5.html
$Q${RM} docs/rgbfix.1.html
$Q${RM} docs/rgbgfx.1.html
# Target used to install the binaries and man pages. # Target used to install the binaries and man pages.
install: all install: all
@@ -144,21 +158,40 @@ install: all
$Qinstall -m ${MANMODE} src/link/rgblink.5 ${DESTDIR}${mandir}/man5/rgblink.5 $Qinstall -m ${MANMODE} src/link/rgblink.5 ${DESTDIR}${mandir}/man5/rgblink.5
$Qinstall -m ${MANMODE} src/gfx/rgbgfx.1 ${DESTDIR}${mandir}/man1/rgbgfx.1 $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' | grep -v '\.html'`; 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. # Target for the project maintainer to easily create web manuals.
# It relies on mandoc: http://mdocml.bsd.lv # It relies on mandoc: http://mdocml.bsd.lv
MANDOC := -Thtml -Ios=General -Oman=%N.%S.html -Ostyle=manual.css MANDOC := -Thtml -Ios=General -Oman=%N.%S.html -Ostyle=mandoc.css
wwwman: wwwman:
$Qmandoc ${MANDOC} src/rgbds.7 > rgbds.7.html $Qmandoc ${MANDOC} src/rgbds.7 > docs/rgbds.7.html
$Qmandoc ${MANDOC} src/gbz80.7 > gbz80.7.html $Qmandoc ${MANDOC} src/gbz80.7 > docs/gbz80.7.html
$Qmandoc ${MANDOC} src/rgbds.5 > rgbds.5.html $Qmandoc ${MANDOC} src/rgbds.5 > docs/rgbds.5.html
$Qmandoc ${MANDOC} src/asm/rgbasm.1 > rgbasm.1.html $Qmandoc ${MANDOC} src/asm/rgbasm.1 > docs/rgbasm.1.html
$Qmandoc ${MANDOC} src/asm/rgbasm.5 > rgbasm.5.html $Qmandoc ${MANDOC} src/asm/rgbasm.5 > docs/rgbasm.5.html
$Qmandoc ${MANDOC} src/fix/rgbfix.1 > rgbfix.1.html $Qmandoc ${MANDOC} src/fix/rgbfix.1 > docs/rgbfix.1.html
$Qmandoc ${MANDOC} src/link/rgblink.1 > rgblink.1.html $Qmandoc ${MANDOC} src/link/rgblink.1 > docs/rgblink.1.html
$Qmandoc ${MANDOC} src/link/rgblink.5 > rgblink.5.html $Qmandoc ${MANDOC} src/link/rgblink.5 > docs/rgblink.5.html
$Qmandoc ${MANDOC} src/gfx/rgbgfx.1 > rgbgfx.1.html $Qmandoc ${MANDOC} src/gfx/rgbgfx.1 > docs/rgbgfx.1.html
# Targets for the project maintainer to easily create Windows exes. # Targets for the project maintainer to easily create Windows exes.
# This is not for Windows users! # This is not for Windows users!

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.

174
README.rst Normal file
View File

@@ -0,0 +1,174 @@
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>`__.
The documentation of this toolchain can be viewed online
`here <https://rednex.github.io/rgbds/>`__, 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.
- 2018, codebase relicensed under the MIT license.

1701
docs/gbz80.7.html Normal file

File diff suppressed because it is too large Load Diff

36
docs/index.html Normal file
View File

@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>General Information</title>
<link rel="stylesheet" type="text/css" href="mandoc.css">
</head>
<body>
<h1>RGBDS — Rednex Game Boy Development System</h1>
<h2>Table of Contents</h2>
<ol>
<li>General information
<ul>
<li><a href="rgbds.7.html">RGBDS general information</a></li>
<li><a href="rgbds.5.html">RGBDS object file format</a></li>
</ul>
<li>Language description
<ul>
<li><a href="rgbasm.5.html">RGBASM language description</a></li>
<li><a href="rgblink.5.html">RGBLINK linkerscript language description</a></li>
<li><a href="gbz80.7.html">GBZ80 CPU instruction set description</a></li>
</ul>
<li>Command line usage
<ul>
<li><a href="rgbasm.1.html">RGBASM command-line usage</a></li>
<li><a href="rgblink.1.html">RGBLINK command-line usage</a></li>
<li><a href="rgbfix.1.html">RGBFIX command-line usage</a></li>
<li><a href="rgbgfx.1.html">RGBGFX command-line usage</a></li>
</ul>
</ol>
<h2 id="GitHub Repository">GitHub Repository:</h2>
<ul>
<li><a href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a></li>
</ul>
</body>

203
docs/mandoc.css Executable file
View File

@@ -0,0 +1,203 @@
/* $Id: mandoc.css,v 1.22 2017/07/16 18:45:00 schwarze Exp $ */
/*
* Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
*/
/* Global defaults. */
html { max-width: 100ex; }
body { font-family: Helvetica,Arial,sans-serif; }
table { margin-top: 0em;
margin-bottom: 0em; }
td { vertical-align: top; }
ul, ol, dl { margin-top: 0em;
margin-bottom: 0em; }
li, dt { margin-top: 1em; }
a.selflink { border-bottom: thin dotted;
color: inherit;
font: inherit;
text-decoration: inherit; }
* { clear: both }
/* Search form and search results. */
fieldset { border: thin solid silver;
border-radius: 1em;
text-align: center; }
input[name=expr] {
width: 25%; }
table.results { margin-top: 1em;
margin-left: 2em;
font-size: smaller; }
/* Header and footer lines. */
table.head { width: 100%;
border-bottom: 1px dotted #808080;
margin-bottom: 1em;
font-size: smaller; }
td.head-vol { text-align: center; }
td.head-rtitle {
text-align: right; }
span.Nd { }
table.foot { width: 100%;
border-top: 1px dotted #808080;
margin-top: 1em;
font-size: smaller; }
td.foot-os { text-align: right; }
/* Sections and paragraphs. */
div.manual-text {
margin-left: 5ex; }
h1.Sh { margin-top: 2ex;
margin-bottom: 1ex;
margin-left: -4ex;
font-size: 110%; }
h2.Ss { margin-top: 2ex;
margin-bottom: 1ex;
margin-left: -2ex;
font-size: 105%; }
div.Pp { margin: 1ex 0ex; }
a.Sx { }
a.Xr { }
/* Displays and lists. */
div.Bd { }
div.D1 { margin-left: 5ex; }
ul.Bl-bullet { list-style-type: disc;
padding-left: 1em; }
li.It-bullet { }
ul.Bl-dash { list-style-type: none;
padding-left: 0em; }
li.It-dash:before {
content: "\2014 "; }
ul.Bl-item { list-style-type: none;
padding-left: 0em; }
li.It-item { }
ul.Bl-compact > li {
margin-top: 0ex; }
ol.Bl-enum { padding-left: 2em; }
li.It-enum { }
ol.Bl-compact > li {
margin-top: 0ex; }
dl.Bl-diag { }
dt.It-diag { }
dd.It-diag { margin-left: 0ex; }
b.It-diag { font-style: normal; }
dl.Bl-hang { }
dt.It-hang { }
dd.It-hang { margin-left: 10.2ex; }
dl.Bl-inset { }
dt.It-inset { }
dd.It-inset { margin-left: 0ex; }
dl.Bl-ohang { }
dt.It-ohang { }
dd.It-ohang { margin-left: 0ex; }
dl.Bl-tag { margin-left: 10.2ex; }
dt.It-tag { float: left;
margin-top: 0ex;
margin-left: -10.2ex;
padding-right: 2ex;
vertical-align: top; }
dd.It-tag { clear: right;
width: 100%;
margin-top: 0ex;
margin-left: 0ex;
vertical-align: top;
overflow: auto; }
dl.Bl-compact > dt {
margin-top: 0ex; }
table.Bl-column { }
tr.It-column { }
td.It-column { margin-top: 1em; }
table.Bl-compact > tbody > tr > td {
margin-top: 0ex; }
cite.Rs { font-style: normal;
font-weight: normal; }
span.RsA { }
i.RsB { font-weight: normal; }
span.RsC { }
span.RsD { }
i.RsI { font-weight: normal; }
i.RsJ { font-weight: normal; }
span.RsN { }
span.RsO { }
span.RsP { }
span.RsQ { }
span.RsR { }
span.RsT { text-decoration: underline; }
a.RsU { }
span.RsV { }
span.eqn { }
table.tbl { }
/* Semantic markup for command line utilities. */
table.Nm { }
b.Nm { font-style: normal; }
b.Fl { font-style: normal; }
b.Cm { font-style: normal; }
var.Ar { font-style: italic;
font-weight: normal; }
span.Op { }
b.Ic { font-style: normal; }
code.Ev { font-style: normal;
font-weight: normal;
font-family: monospace; }
i.Pa { font-weight: normal; }
/* Semantic markup for function libraries. */
span.Lb { }
b.In { font-style: normal; }
a.In { }
b.Fd { font-style: normal; }
var.Ft { font-style: italic;
font-weight: normal; }
b.Fn { font-style: normal; }
var.Fa { font-style: italic;
font-weight: normal; }
var.Vt { font-style: italic;
font-weight: normal; }
var.Va { font-style: italic;
font-weight: normal; }
code.Dv { font-style: normal;
font-weight: normal;
font-family: monospace; }
code.Er { font-style: normal;
font-weight: normal;
font-family: monospace; }
/* Various semantic markup. */
span.An { }
a.Lk { }
a.Mt { }
b.Cd { font-style: normal; }
i.Ad { font-weight: normal; }
b.Ms { font-style: normal; }
span.St { }
a.Ux { }
/* Physical markup. */
.No { font-style: normal;
font-weight: normal; }
.Em { font-style: italic;
font-weight: normal; }
.Sy { font-style: normal;
font-weight: bold; }
.Li { font-style: normal;
font-weight: normal;
font-family: monospace; }

157
docs/rgbasm.1.html Normal file
View File

@@ -0,0 +1,157 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
table.head, table.foot { width: 100%; }
td.head-rtitle, td.foot-os { text-align: right; }
td.head-vol { text-align: center; }
div.Pp { margin: 1ex 0ex; }
</style>
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
<title>RGBASM(1)</title>
</head>
<body>
<table class="head">
<tr>
<td class="head-ltitle">RGBASM(1)</td>
<td class="head-vol">General Commands Manual</td>
<td class="head-rtitle">RGBASM(1)</td>
</tr>
</table>
<div class="manual-text">
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
<b class="Nm" title="Nm">rgbasm</b> &#x2014; <span class="Nd" title="Nd">Game
Boy assembler</span>
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
<table class="Nm">
<tr>
<td><b class="Nm" title="Nm">rgbasm</b></td>
<td>[<span class="Op"><b class="Fl" title="Fl">-EhLVvw</b></span>]
[<span class="Op"><b class="Fl" title="Fl">-b</b>
<var class="Ar" title="Ar">chars</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-D</b>
<var class="Ar" title="Ar">name</var>[<span class="Op">=<var class="Ar" title="Ar">value</var></span>]</span>]
[<span class="Op"><b class="Fl" title="Fl">-g</b>
<var class="Ar" title="Ar">chars</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-i</b>
<var class="Ar" title="Ar">path</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-M</b>
<var class="Ar" title="Ar">dependfile</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-o</b>
<var class="Ar" title="Ar">outfile</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-p</b>
<var class="Ar" title="Ar">pad_value</var></span>]
<var class="Ar" title="Ar">file</var></td>
</tr>
</table>
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
The <b class="Nm" title="Nm">rgbasm</b> program creates an object file from an
assembly source file. Its arguments are as follows:
<dl class="Bl-tag">
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#b"><b class="Fl" title="Fl" id="b">-b</b></a>
<var class="Ar" title="Ar">chars</var></dt>
<dd class="It-tag">Change the two characters used for binary constants. The
defaults are 01.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#D"><b class="Fl" title="Fl" id="D">-D</b></a>
<var class="Ar" title="Ar">name</var>[<span class="Op">=<var class="Ar" title="Ar">value</var></span>]</dt>
<dd class="It-tag">Add string symbol to the compiled source code. This is
equivalent to <var class="Ar" title="Ar">name</var>
<b class="Cm" title="Cm">EQUS</b>
&#x201C;<var class="Ar" title="Ar">value</var>&#x201D; in code. If a value
is not specified, a value of 1 is given.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#E"><b class="Fl" title="Fl" id="E">-E</b></a></dt>
<dd class="It-tag">Export all labels, including unreferenced and local
labels.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#g"><b class="Fl" title="Fl" id="g">-g</b></a>
<var class="Ar" title="Ar">chars</var></dt>
<dd class="It-tag">Change the four characters used for binary constants. The
defaults are 0123.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#h"><b class="Fl" title="Fl" id="h">-h</b></a></dt>
<dd class="It-tag">By default, <b class="Nm" title="Nm">rgbasm</b> inserts a
&#x2018;nop&#x2019; instruction immediately after any &#x2018;halt&#x2019;
instruction. The <b class="Fl" title="Fl">-h</b> option disables this
behavior.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#i"><b class="Fl" title="Fl" id="i">-i</b></a>
<var class="Ar" title="Ar">path</var></dt>
<dd class="It-tag">Add an include path.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#L"><b class="Fl" title="Fl" id="L">-L</b></a></dt>
<dd class="It-tag">Disable the optimization that turns loads of the form
<b class="Sy" title="Sy">LD [$FF00+n8],A</b> into the opcode
<b class="Sy" title="Sy">LDH [$FF00+n8],A</b> in order to have full
control of the result in the final ROM.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#M"><b class="Fl" title="Fl" id="M">-M</b></a>
<var class="Ar" title="Ar">dependfile</var></dt>
<dd class="It-tag">Print <a class="Xr" title="Xr">make(1)</a> dependencies to
<var class="Ar" title="Ar">dependfile</var>.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#o"><b class="Fl" title="Fl" id="o">-o</b></a>
<var class="Ar" title="Ar">outfile</var></dt>
<dd class="It-tag">Write an object file to the given filename.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
<var class="Ar" title="Ar">pad_value</var></dt>
<dd class="It-tag">When padding an image, pad with this value. The default is
0x00.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
<dd class="It-tag">Print the version of the program and exit.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#v"><b class="Fl" title="Fl" id="v">-v</b></a></dt>
<dd class="It-tag">Be verbose.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#w"><b class="Fl" title="Fl" id="w">-w</b></a></dt>
<dd class="It-tag">Disable warning output.</dd>
</dl>
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
Assembling a basic source file is simple:
<div class="Pp"></div>
<div class="Bd" style="margin-left: 5.00ex;">
<pre class="Li">
$ rgbasm -o bar.o foo.asm
</pre>
</div>
<div class="Pp"></div>
The resulting object file is not yet a usable ROM image &#x2014; it must first
be run through <a class="Xr" title="Xr">rgblink(1)</a> and
<a class="Xr" title="Xr">rgbfix(1)</a>.
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
ALSO</a></h1>
<a class="Xr" title="Xr">rgbasm(5)</a>, <a class="Xr" title="Xr">rgbfix(1)</a>,
<a class="Xr" title="Xr">rgblink(1)</a>,
<a class="Xr" title="Xr">rgbds(5)</a>, <a class="Xr" title="Xr">rgbds(7)</a>,
<a class="Xr" title="Xr">gbz80(7)</a>
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
<b class="Nm" title="Nm">rgbasm</b> was originally written by Carsten
S&#x00F8;rensen as part of the ASMotor package, and was later packaged in
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
<table class="foot">
<tr>
<td class="foot-date">February 24, 2018</td>
<td class="foot-os">RGBDS Manual</td>
</tr>
</table>
</body>
</html>

1599
docs/rgbasm.5.html Normal file

File diff suppressed because it is too large Load Diff

307
docs/rgbds.5.html Normal file
View File

@@ -0,0 +1,307 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
table.head, table.foot { width: 100%; }
td.head-rtitle, td.foot-os { text-align: right; }
td.head-vol { text-align: center; }
div.Pp { margin: 1ex 0ex; }
</style>
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
<title>RGBDS(5)</title>
</head>
<body>
<table class="head">
<tr>
<td class="head-ltitle">RGBDS(5)</td>
<td class="head-vol">File Formats Manual</td>
<td class="head-rtitle">RGBDS(5)</td>
</tr>
</table>
<div class="manual-text">
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
<b class="Nm" title="Nm">rgbds</b> &#x2014; <span class="Nd" title="Nd">object
file format documentation</span>
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
This is the description of the object files used by
<a class="Xr" title="Xr">rgbasm(1)</a> and
<a class="Xr" title="Xr">rgblink(1)</a>. Please, note that the specifications
may change. This toolchain is in development and new features may require
adding more information to the current format, or modifying some fields, which
would break compatibility with older versions.
<h1 class="Sh" title="Sh" id="FILE_STRUCTURE"><a class="selflink" href="#FILE_STRUCTURE">FILE
STRUCTURE</a></h1>
The following types are used:
<div class="Pp"></div>
<var class="Ar" title="Ar">LONG</var> is a 32&#x2010;bit integer stored in
little&#x2010;endian format (Intel). <var class="Ar" title="Ar">BYTE</var> is
an 8&#x2010;bit integer. <var class="Ar" title="Ar">STRING</var> is a
0&#x2010;terminated string of <var class="Ar" title="Ar">BYTE</var>.
<div class="Pp"></div>
<div class="Bd" style="margin-left: 0.00ex;">
<pre class="Li">
; Header
BYTE ID[4] ; &quot;RGB6&quot;
LONG NumberOfSymbols ; The number of symbols used in this file
LONG NumberOfSections ; The number of sections used in this file
; Symbols
REPT NumberOfSymbols ; Number of symbols defined in this object file.
STRING Name ; The name of this symbol. Local symbols are stored
; as &quot;Scope.Symbol&quot;.
BYTE Type ; 0 = LOCAL symbol only used in this file.
; 1 = IMPORT this symbol from elsewhere (unused).
; 2 = EXPORT this symbol to other objects.
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.
LONG Value ; The symbols value. It's the offset into that
; symbol's section.
ENDC
ENDR
; Sections
REPT NumberOfSections
STRING Name ; Name of the section
LONG Size ; Size in bytes of this section
BYTE Type ; 0 = WRAM0
; 1 = VRAM
; 2 = ROMX
; 3 = ROM0
; 4 = HRAM
; 5 = WRAMX
; 6 = SRAM
; 7 = OAM
LONG Org ; Address to fix this section at. -1 if the linker should
; decide (floating address).
LONG Bank ; Bank to load this section into. -1 if the linker should
; decide (floating bank). This field is only valid for ROMX,
; VRAM, WRAMX and SRAM sections.
LONG Align ; Alignment of this section (expressed as number of low bits
; to leave as 0). -1 if not defined.
IF (Type == ROMX) || (Type == ROM0) ; Sections that can contain data.
BYTE Data[Size] ; Raw data of the section.
LONG NumberOfPatches ; Number of patches to apply.
; These types of sections may have patches
REPT NumberOfPatches
STRING SourceFile ; Name of the source file (for printing error
; messages).
LONG Line ; The line of the source file.
LONG Offset ; Offset into the section where patch should
; be applied (in bytes).
BYTE Type ; 0 = BYTE patch.
; 1 = little endian WORD patch.
; 2 = little endian LONG patch.
; 3 = JR offset value BYTE patch.
LONG RPNSize ; Size of the buffer with the RPN.
; expression.
BYTE RPN[RPNSize] ; RPN expression. Definition below.
ENDR
ENDC
ENDR
</pre>
</div>
<h2 class="Ss" title="Ss" id="RPN_DATA"><a class="selflink" href="#RPN_DATA">RPN
DATA</a></h2>
Expressions in the object file are stored as RPN. This is an expression of the
form &#x201C;2 5 +&#x201D;. This will first push the value &#x201C;2&#x201D;
to the stack. Then &#x201C;5&#x201D;. The &#x201C;+&#x201D; operator pops two
arguments from the stack, adds them, and then pushes the result on the stack,
effectively replacing the two top arguments with their sum. In the RGB format,
RPN expressions are stored as BYTEs with some bytes being special prefixes for
integers and symbols.
<table class="Bl-column" style="margin-left: 6.00ex;">
<colgroup>
<col style="width: 15.00ex;"/>
<col style="min-width: 10.00ex;"/>
</colgroup>
<tr class="It-column">
<td class="It-column"><b class="Sy" title="Sy">Value</b></td>
<td class="It-column"><b class="Sy" title="Sy">Meaning</b></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$00"><code class="Li" id="$00">$00</code></a></td>
<td class="It-column"><a class="selflink" href="#+_operator"><code class="Li" id="+_operator">+
operator</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$01"><code class="Li" id="$01">$01</code></a></td>
<td class="It-column"><a class="selflink" href="#-_operator"><code class="Li" id="-_operator">-
operator</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$02"><code class="Li" id="$02">$02</code></a></td>
<td class="It-column"><a class="selflink" href="#*_operator"><code class="Li" id="*_operator">*
operator</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$03"><code class="Li" id="$03">$03</code></a></td>
<td class="It-column"><a class="selflink" href="#/_operator"><code class="Li" id="/_operator">/
operator</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$04"><code class="Li" id="$04">$04</code></a></td>
<td class="It-column"><a class="selflink" href="#%_operator"><code class="Li" id="%_operator">%
operator</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$05"><code class="Li" id="$05">$05</code></a></td>
<td class="It-column"><a class="selflink" href="#unary_-"><code class="Li" id="unary_-">unary
-</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$10"><code class="Li" id="$10">$10</code></a></td>
<td class="It-column">|
<a class="selflink" href="#operator"><code class="Li" id="operator">operator</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$11"><code class="Li" id="$11">$11</code></a></td>
<td class="It-column"><a class="selflink" href="#&amp;_operator"><code class="Li" id="&amp;_operator">&amp;
operator</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$12"><code class="Li" id="$12">$12</code></a></td>
<td class="It-column"><a class="selflink" href="#^_operator"><code class="Li" id="^_operator">^
operator</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$13"><code class="Li" id="$13">$13</code></a></td>
<td class="It-column"><a class="selflink" href="#unary_~"><code class="Li" id="unary_~">unary
~</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$21"><code class="Li" id="$21">$21</code></a></td>
<td class="It-column"><a class="selflink" href="#&amp;&amp;_comparison"><code class="Li" id="&amp;&amp;_comparison">&amp;&amp;
comparison</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$22"><code class="Li" id="$22">$22</code></a></td>
<td class="It-column"><a class="selflink" href="#||_comparison"><code class="Li" id="||_comparison">||
comparison</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$23"><code class="Li" id="$23">$23</code></a></td>
<td class="It-column"><a class="selflink" href="#unary"><code class="Li" id="unary">unary</code></a>!</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$30"><code class="Li" id="$30">$30</code></a></td>
<td class="It-column"><a class="selflink" href="#==_comparison"><code class="Li" id="==_comparison">==
comparison</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$31"><code class="Li" id="$31">$31</code></a></td>
<td class="It-column"><a class="selflink" href="#!=_comparison"><code class="Li" id="!=_comparison">!=
comparison</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$32"><code class="Li" id="$32">$32</code></a></td>
<td class="It-column"><a class="selflink" href="#&gt;_comparison"><code class="Li" id="&gt;_comparison">&gt;
comparison</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$33"><code class="Li" id="$33">$33</code></a></td>
<td class="It-column"><a class="selflink" href="#&lt;_comparison"><code class="Li" id="&lt;_comparison">&lt;
comparison</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$34"><code class="Li" id="$34">$34</code></a></td>
<td class="It-column"><a class="selflink" href="#&gt;=_comparison"><code class="Li" id="&gt;=_comparison">&gt;=
comparison</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$35"><code class="Li" id="$35">$35</code></a></td>
<td class="It-column"><a class="selflink" href="#&lt;=_comparison"><code class="Li" id="&lt;=_comparison">&lt;=
comparison</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$40"><code class="Li" id="$40">$40</code></a></td>
<td class="It-column"><a class="selflink" href="#&lt;&lt;_comparison"><code class="Li" id="&lt;&lt;_comparison">&lt;&lt;
comparison</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$41"><code class="Li" id="$41">$41</code></a></td>
<td class="It-column"><a class="selflink" href="#&gt;&gt;_comparison"><code class="Li" id="&gt;&gt;_comparison">&gt;&gt;
comparison</code></a></td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$50"><code class="Li" id="$50">$50</code></a></td>
<td class="It-column"><a class="selflink" href="#BANK(symbol),"><code class="Li" id="BANK(symbol),">BANK(symbol),</code></a>
a <var class="Ar" title="Ar">LONG</var> Symbol ID follows.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$51"><code class="Li" id="$51">$51</code></a></td>
<td class="It-column"><a class="selflink" href="#BANK(section_name),"><code class="Li" id="BANK(section_name),">BANK(section_name),</code></a>
a null-terminated string follows.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$52"><code class="Li" id="$52">$52</code></a></td>
<td class="It-column"><a class="selflink" href="#Current_BANK()"><code class="Li" id="Current_BANK()">Current
BANK()</code></a>.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$60"><code class="Li" id="$60">$60</code></a></td>
<td class="It-column"><a class="selflink" href="#HRAMCheck."><code class="Li" id="HRAMCheck.">HRAMCheck.</code></a>
Check if the value is in HRAM, AND it with 0xFF.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$80"><code class="Li" id="$80">$80</code></a></td>
<td class="It-column"><var class="Ar" title="Ar">LONG</var> integer
follows.</td>
</tr>
<tr class="It-column">
<td class="It-column"><a class="selflink" href="#$81"><code class="Li" id="$81">$81</code></a></td>
<td class="It-column"><var class="Ar" title="Ar">LONG</var> Symbol ID
follows.</td>
</tr>
</table>
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
ALSO</a></h1>
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(1)</a>,
<a class="Xr" title="Xr">rgbds(7)</a>, <a class="Xr" title="Xr">gbz80(7)</a>
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
<b class="Nm" title="Nm">rgbds</b> was originally written by Carsten
S&#x00F8;rensen as part of the ASMotor package, and was later packaged in
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
<table class="foot">
<tr>
<td class="foot-date">January 26, 2018</td>
<td class="foot-os">RGBDS Manual</td>
</tr>
</table>
</body>
</html>

71
docs/rgbds.7.html Normal file
View File

@@ -0,0 +1,71 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
table.head, table.foot { width: 100%; }
td.head-rtitle, td.foot-os { text-align: right; }
td.head-vol { text-align: center; }
div.Pp { margin: 1ex 0ex; }
</style>
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
<title>RGBDS(7)</title>
</head>
<body>
<table class="head">
<tr>
<td class="head-ltitle">RGBDS(7)</td>
<td class="head-vol">Miscellaneous Information Manual</td>
<td class="head-rtitle">RGBDS(7)</td>
</tr>
</table>
<div class="manual-text">
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
<b class="Nm" title="Nm">rgbds</b> &#x2014; <span class="Nd" title="Nd">Rednex
Game Boy Development System</span>
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
To get a working ROM image from a single assembly source file:
<div class="Pp"></div>
<div class="Bd" style="margin-left: 5.00ex;">
<pre class="Li">
$ rgbasm -o bar.o foo.asm
$ rgblink -o baz.gb bar.o
$ rgbfix -v -p 0 baz.gb
</pre>
</div>
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
ALSO</a></h1>
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgbfix(1)</a>,
<a class="Xr" title="Xr">rgblink(1)</a>,
<a class="Xr" title="Xr">rgbds(5)</a>, <a class="Xr" title="Xr">gbz80(7)</a>
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
<dl class="Bl-ohang">
<dt class="It-ohang"></dt>
<dd class="It-ohang">1997, Carsten S&#x00F8;rensen (AKA SurfSmurf) writes
ASMotor as a general-purpose assembler/linker system for DOS/Win32.</dd>
<dt class="It-ohang"></dt>
<dd class="It-ohang">1999, Justin Lloyd (AKA Otaku no Zoku) adapts ASMotor to
read and produce GBZ80 assembly/machine code, and releases this version as
RGBDS.</dd>
<dt class="It-ohang"></dt>
<dd class="It-ohang">2009, Vegard Nossum adapts the code to be more UNIX-like
and releases this version as rgbds-linux on GitHub.</dd>
<dt class="It-ohang"></dt>
<dd class="It-ohang">2010, Anthony J. Bentley forks that repository. The fork
becomes the reference implementation of rgbds.</dd>
<dt class="It-ohang"></dt>
<dd class="It-ohang">2017, Bentley's repository is moved to a neutral name. It
is now maintained by a number of contributors at
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</dd>
<dt class="It-ohang"></dt>
<dd class="It-ohang">2018, codebase relicensed under the MIT license.</dd>
</dl>
</div>
<table class="foot">
<tr>
<td class="foot-date">March 7, 2018</td>
<td class="foot-os">RGBDS Manual</td>
</tr>
</table>
</body>
</html>

213
docs/rgbfix.1.html Normal file
View File

@@ -0,0 +1,213 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
table.head, table.foot { width: 100%; }
td.head-rtitle, td.foot-os { text-align: right; }
td.head-vol { text-align: center; }
div.Pp { margin: 1ex 0ex; }
</style>
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
<title>RGBFIX(1)</title>
</head>
<body>
<table class="head">
<tr>
<td class="head-ltitle">RGBFIX(1)</td>
<td class="head-vol">General Commands Manual</td>
<td class="head-rtitle">RGBFIX(1)</td>
</tr>
</table>
<div class="manual-text">
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
<b class="Nm" title="Nm">rgbfix</b> &#x2014; <span class="Nd" title="Nd">Game
Boy checksum fixer</span>
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
<table class="Nm">
<tr>
<td><b class="Nm" title="Nm">rgbfix</b></td>
<td>[<span class="Op"><b class="Fl" title="Fl">-CcjsVv</b></span>]
[<span class="Op"><b class="Fl" title="Fl">-f</b>
<var class="Ar" title="Ar">fix_spec</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-i</b>
<var class="Ar" title="Ar">game_id</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-k</b>
<var class="Ar" title="Ar">licensee_str</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-l</b>
<var class="Ar" title="Ar">licensee_id</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-m</b>
<var class="Ar" title="Ar">mbc_type</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-n</b>
<var class="Ar" title="Ar">rom_version</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-p</b>
<var class="Ar" title="Ar">pad_value</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-r</b>
<var class="Ar" title="Ar">ram_size</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-t</b>
<var class="Ar" title="Ar">title_str</var></span>]
<var class="Ar" title="Ar">file</var></td>
</tr>
</table>
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
The <b class="Nm" title="Nm">rgbfix</b> program changes headers of Game Boy ROM
images. It also performs other filetype operations, such as truncation. The
arguments are as follows:
<dl class="Bl-tag">
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#C"><b class="Fl" title="Fl" id="C">-C</b></a></dt>
<dd class="It-tag">Set the Game Boy Color&#x2013;only flag:
<i class="Ad">0x143</i> = 0xC0. If both this and the
<b class="Fl" title="Fl">-c</b> flag are set, this takes precedence.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#c"><b class="Fl" title="Fl" id="c">-c</b></a></dt>
<dd class="It-tag">Set the Game Boy Color&#x2013;compatible flag:
<i class="Ad">0x143</i> = 0x80. If both this and the
<b class="Fl" title="Fl">-C</b> flag are set,
<b class="Fl" title="Fl">-C</b> takes precedence.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#f"><b class="Fl" title="Fl" id="f">-f</b></a>
<var class="Ar" title="Ar">fix_spec</var></dt>
<dd class="It-tag">Fix certain header values that the Game Boy checks for
correctness. Alternatively, intentionally trash these values by writing
their binary inverse instead. <var class="Ar" title="Ar">fix_spec</var> is
a string containing any combination of the following characters:
<div class="Pp"></div>
<dl class="Bl-tag Bl-compact" style="margin-left: 5.40ex;">
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#l"><b class="Cm" title="Cm" id="l">l</b></a></dt>
<dd class="It-tag">Fix the Nintendo logo
(<i class="Ad">0x104</i>&#x2013;<i class="Ad">0x133</i>).</dd>
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#L"><b class="Cm" title="Cm" id="L">L</b></a></dt>
<dd class="It-tag">Trash the Nintendo logo.</dd>
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#h"><b class="Cm" title="Cm" id="h">h</b></a></dt>
<dd class="It-tag">Fix the header checksum (<i class="Ad">0x14D</i>).</dd>
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#H"><b class="Cm" title="Cm" id="H">H</b></a></dt>
<dd class="It-tag">Trash the header checksum.</dd>
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#g"><b class="Cm" title="Cm" id="g">g</b></a></dt>
<dd class="It-tag">Fix the global checksum
(<i class="Ad">0x14E</i>&#x2013;<i class="Ad">0x14F</i>).</dd>
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#G"><b class="Cm" title="Cm" id="G">G</b></a></dt>
<dd class="It-tag">Trash the global checksum.</dd>
</dl>
</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#i"><b class="Fl" title="Fl" id="i">-i</b></a>
<var class="Ar" title="Ar">game_id</var></dt>
<dd class="It-tag">Set the game ID string
(<i class="Ad">0x13F</i>&#x2013;<i class="Ad">0x142</i>) to a given string
of exactly 4 characters. If both this and the title are set, the game ID
will overwrite the overlapping portion of the title.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#j"><b class="Fl" title="Fl" id="j">-j</b></a></dt>
<dd class="It-tag">Set the non-Japanese region flag: <i class="Ad">0x14A</i> =
1.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#k"><b class="Fl" title="Fl" id="k">-k</b></a>
<var class="Ar" title="Ar">licensee_str</var></dt>
<dd class="It-tag">Set the new licensee string
(<i class="Ad">0x144</i>&#x2013;<i class="Ad">0x145</i>) to a given
string, truncated to at most two characters.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#l"><b class="Fl" title="Fl" id="l">-l</b></a>
<var class="Ar" title="Ar">licensee_id</var></dt>
<dd class="It-tag">Set the old licensee code, <i class="Ad">0x14B</i>, to a
given value from 0 to 0xFF. This value is deprecated and should be set to
0x33 in all new software.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#m"><b class="Fl" title="Fl" id="m">-m</b></a>
<var class="Ar" title="Ar">mbc_type</var></dt>
<dd class="It-tag">Set the MBC type, <i class="Ad">0x147</i>, to a given value
from 0 to 0xFF.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#n"><b class="Fl" title="Fl" id="n">-n</b></a>
<var class="Ar" title="Ar">rom_version</var></dt>
<dd class="It-tag">Set the ROM version, <i class="Ad">0x14C</i>, to a given
value from 0 to 0xFF.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
<var class="Ar" title="Ar">pad_value</var></dt>
<dd class="It-tag">Pad the image to a valid size with a given pad value from 0
to 0xFF. <b class="Nm" title="Nm">rgbfix</b> will automatically pick a
size from 32KiB, 64KiB, 128KiB, ..., 8192KiB and give a warning
thereafter. The cartridge size byte (<i class="Ad">0x148</i>) will be
changed to reflect this new size.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#r"><b class="Fl" title="Fl" id="r">-r</b></a>
<var class="Ar" title="Ar">ram_size</var></dt>
<dd class="It-tag">Set the RAM size, <i class="Ad">0x149</i>, to a given value
from 0 to 0xFF.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#s"><b class="Fl" title="Fl" id="s">-s</b></a></dt>
<dd class="It-tag">Set the SGB flag: <i class="Ad">0x146</i> = 3.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#t"><b class="Fl" title="Fl" id="t">-t</b></a>
<var class="Ar" title="Ar">title</var></dt>
<dd class="It-tag">Set the title string
(<i class="Ad">0x134</i>&#x2013;<i class="Ad">0x143</i>) to a given
string, truncated to at most 16 characters. It is recommended to use 15
characters instead, to avoid clashing with the CGB flag
(<b class="Fl" title="Fl">-c</b> or <b class="Fl" title="Fl">-C</b>). If
both this and the game ID are set, the game ID will overwrite the
overlapping portion of the title.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
<dd class="It-tag">Print the version of the program and exit.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#v"><b class="Fl" title="Fl" id="v">-v</b></a></dt>
<dd class="It-tag">Equivalent to <b class="Fl" title="Fl">-f</b>
<b class="Cm" title="Cm">lhg</b>.</dd>
</dl>
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
Most values in the ROM header are only cosmetic. The bare minimum requirements
for a workable image are checksums, the Nintendo logo, and (if needed) the
CGB/SGB flags. It is a good idea to pad the image to a valid size as well
(&#x201C;valid&#x201D; meaning a multiple of 32KiB).
<div class="Pp"></div>
The following will make a plain, no-color Game Boy game without checking for a
valid size:
<div class="Pp"></div>
<div class="D1">$ rgbfix -v foo.gb</div>
<div class="Pp"></div>
The following will make a SGB-enabled, color-enabled game with a title of
&#x201C;foobar&#x201D;, and pad it to a multiple of 32KiB. (The Game Boy
itself does not use the title, but some emulators or ROM managers might.)
<div class="Pp"></div>
<div class="D1">$ rgbfix -vcs -l 0x33 -p 0 -t foobar baz.gb</div>
<div class="Pp"></div>
The following will duplicate the header (sans global checksum) of the game
&#x201C;Survival Kids&#x201D;:
<div class="Pp"></div>
<div class="D1">$ rgbfix -cjsv -k A4 -l 0x33 -m 0x1B -p 0xFF -r 3 -t
SURVIVALKIDAVKE SurvivalKids.gbc</div>
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
ALSO</a></h1>
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(1)</a>,
<a class="Xr" title="Xr">rgbds(7)</a>
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
<b class="Nm" title="Nm">rgbfix</b> was originally released by Carsten
S&#x00F8;rensen as a standalone program called gbfix, and was later packaged
in RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
<table class="foot">
<tr>
<td class="foot-date">March 11, 2018</td>
<td class="foot-os">RGBDS Manual</td>
</tr>
</table>
</body>
</html>

175
docs/rgbgfx.1.html Normal file
View File

@@ -0,0 +1,175 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
table.head, table.foot { width: 100%; }
td.head-rtitle, td.foot-os { text-align: right; }
td.head-vol { text-align: center; }
div.Pp { margin: 1ex 0ex; }
</style>
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
<title>RGBGFX(1)</title>
</head>
<body>
<table class="head">
<tr>
<td class="head-ltitle">RGBGFX(1)</td>
<td class="head-vol">General Commands Manual</td>
<td class="head-rtitle">RGBGFX(1)</td>
</tr>
</table>
<div class="manual-text">
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
<b class="Nm" title="Nm">rgbgfx</b> &#x2014; <span class="Nd" title="Nd">Game
Boy graphics converter</span>
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
<table class="Nm">
<tr>
<td><b class="Nm" title="Nm">rgbgfx</b></td>
<td>[<span class="Op"><b class="Fl" title="Fl">-DfFhPTVv</b></span>]
[<span class="Op"><b class="Fl" title="Fl">-o</b>
<var class="Ar" title="Ar">outfile</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-d</b>
<var class="Ar" title="Ar">depth</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-p</b>
<var class="Ar" title="Ar">palfile</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-t</b>
<var class="Ar" title="Ar">mapfile</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-x</b>
<var class="Ar" title="Ar">tiles</var></span>]
<var class="Ar" title="Ar">file</var></td>
</tr>
</table>
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
The <b class="Nm" title="Nm">rgbgfx</b> program converts PNG images into the
Nintendo Game Boy's planar tile format.
<div style="height: 1.00em;">&#x00A0;</div>
The resulting colors and their palette indices are determined differently
depending on the input PNG file:
<ul class="Bl-dash">
<li class="It-dash">If the file has an embedded palette, that palette's color
and order are used.</li>
<li class="It-dash">If not, and the image only contains shades of gray, rgbgfx
maps them to the indices appropriate for each shade. Any undetermined
indices are set to respective default shades of gray. For example: if the
bit depth is 2 and the image contains light gray and black, they become
the second and fourth colors - and the first and third colors get set to
default white and dark gray. If the image has multiple shades that map to
the same index, the palette is instead determined as if the image had
color.</li>
<li class="It-dash">If the image has color (or the grayscale method failed),
the colors are sorted from lightest to darkest.</li>
</ul>
<div style="height: 1.00em;">&#x00A0;</div>
The input image may not contain more colors than the selected bit depth allows.
Transparent pixels are set to palette index 0.
<h1 class="Sh" title="Sh" id="ARGUMENTS"><a class="selflink" href="#ARGUMENTS">ARGUMENTS</a></h1>
<dl class="Bl-tag">
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#D"><b class="Fl" title="Fl" id="D">-D</b></a></dt>
<dd class="It-tag">Debug features are enabled.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#f"><b class="Fl" title="Fl" id="f">-f</b></a></dt>
<dd class="It-tag">Fix the input PNG file to be a correctly indexed
image.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#F"><b class="Fl" title="Fl" id="F">-F</b></a></dt>
<dd class="It-tag">Same as <b class="Fl" title="Fl">-f</b>, but additionally,
the supplied command line parameters are saved within the PNG and will be
loaded and automatically used next time.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#d"><b class="Fl" title="Fl" id="d">-d</b></a>
<var class="Ar" title="Ar">depth</var></dt>
<dd class="It-tag">The bit depth of the output image (either 1 or 2). By
default, the bit depth is 2 (two bits per pixel).</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#h"><b class="Fl" title="Fl" id="h">-h</b></a></dt>
<dd class="It-tag">Lay out tiles horizontally rather than vertically.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#o"><b class="Fl" title="Fl" id="o">-o</b></a>
<var class="Ar" title="Ar">outfile</var></dt>
<dd class="It-tag">The name of the output file.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
<var class="Ar" title="Ar">palfile</var></dt>
<dd class="It-tag">Output the image's palette in standard GBC palette format -
bytes (8 bytes for two bits per pixel, 4 bytes for one bit per pixel)
containing the RGB15 values in little-endian byte order. If the palette
contains too few colors, the remaining entries are set to black.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#P"><b class="Fl" title="Fl" id="P">-P</b></a></dt>
<dd class="It-tag">Same as <b class="Fl" title="Fl">-p</b>, but the palette
file output name is made by taking the input PNG file's filename, removing
the file extension, and appending <i class="Pa" title="Pa">.pal</i>.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#t"><b class="Fl" title="Fl" id="t">-t</b></a>
<var class="Ar" title="Ar">mapfile</var></dt>
<dd class="It-tag">If any tiles are the same, don't place the repeat tiles in
the output file, and make a tilemap file.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#T"><b class="Fl" title="Fl" id="T">-T</b></a></dt>
<dd class="It-tag">Same as <b class="Fl" title="Fl">-t</b>, but the tilemap
file output name is made by taking the input filename, removing the file
extension, and appending <i class="Pa" title="Pa">.tilemap</i>.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#u"><b class="Fl" title="Fl" id="u">-u</b></a></dt>
<dd class="It-tag">Truncate repeated tiles. Useful with tilemaps.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
<dd class="It-tag">Print the version of the program and exit.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#v"><b class="Fl" title="Fl" id="v">-v</b></a></dt>
<dd class="It-tag">Verbose. Print errors when the command line parameters and
the parameters in the PNG file don't match.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#x"><b class="Fl" title="Fl" id="x">-x</b></a>
<var class="Ar" title="Ar">tiles</var></dt>
<dd class="It-tag">Trim the end of the output file by this many tiles.</dd>
</dl>
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
The following will take a PNG file with a bit depth of 1, 2, or 8, and output
planar 2bpp data:
<div class="Pp"></div>
<div class="D1">$ rgbgfx -o out.2bpp in.png</div>
<div class="Pp"></div>
The following creates a planar 2bpp file with only unique tiles, and its tilemap
<i class="Pa" title="Pa">out.tilemap</i>:
<div class="Pp"></div>
<div class="D1">$ rgbgfx -T -u -o out.2bpp in.png</div>
<div class="Pp"></div>
The following will do nothing:
<div class="Pp"></div>
<div class="D1">$ rgbgfx in.png</div>
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
ALSO</a></h1>
<a class="Xr" title="Xr">rgbds(7)</a>, <a class="Xr" title="Xr">rgbasm(1)</a>,
<a class="Xr" title="Xr">rgblink(1)</a>,
<a class="Xr" title="Xr">rgbfix(1)</a>, <a class="Xr" title="Xr">gbz80(7)</a>
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
<b class="Nm" title="Nm">rgbgfx</b> was created by
<span class="An" title="An">stag019</span> to be included in RGBDS. It is now
maintained by a number of contributors at
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
<table class="foot">
<tr>
<td class="foot-date">January 26, 2018</td>
<td class="foot-os">RGBDS Manual</td>
</tr>
</table>
</body>
</html>

161
docs/rgblink.1.html Normal file
View File

@@ -0,0 +1,161 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
table.head, table.foot { width: 100%; }
td.head-rtitle, td.foot-os { text-align: right; }
td.head-vol { text-align: center; }
div.Pp { margin: 1ex 0ex; }
</style>
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
<title>RGBLINK(1)</title>
</head>
<body>
<table class="head">
<tr>
<td class="head-ltitle">RGBLINK(1)</td>
<td class="head-vol">General Commands Manual</td>
<td class="head-rtitle">RGBLINK(1)</td>
</tr>
</table>
<div class="manual-text">
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
<b class="Nm" title="Nm">rgblink</b> &#x2014; <span class="Nd" title="Nd">Game
Boy linker</span>
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
<table class="Nm">
<tr>
<td><b class="Nm" title="Nm">rgblink</b></td>
<td>[<span class="Op"><b class="Fl" title="Fl">-dtVw</b></span>]
[<span class="Op"><b class="Fl" title="Fl">-m</b>
<var class="Ar" title="Ar">mapfile</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-n</b>
<var class="Ar" title="Ar">symfile</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-O</b>
<var class="Ar" title="Ar">overlayfile</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-o</b>
<var class="Ar" title="Ar">outfile</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-p</b>
<var class="Ar" title="Ar">pad_value</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-s</b>
<var class="Ar" title="Ar">symbol</var></span>]
[<span class="Op"><b class="Fl" title="Fl">-l</b>
<var class="Ar" title="Ar">linkerscript</var></span>]
<var class="Ar" title="Ar">file ...</var></td>
</tr>
</table>
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
The <b class="Nm" title="Nm">rgblink</b> program links objects created by
<a class="Xr" title="Xr">rgbasm(1)</a> into a single Game Boy ROM file.
<div class="Pp"></div>
By default, ROM0 sections created by the assembler are placed in the 16KiB bank
0, and ROMX sections are placed in any bank except bank 0. If your ROM will
only be 32KiB, you can use the <b class="Fl" title="Fl">-t</b> option to
override this.
<div class="Pp"></div>
Similarly, WRAM0 sections are placed in the first 4KiB of WRAM bank 0 and WRAMX
sections are placed in any bank except bank 0. If your ROM doesn't use banked
WRAM you can use option <b class="Fl" title="Fl">-w</b> option to override
this.
<div class="Pp"></div>
Also, if your ROM is designed for DMG, you can make sure that you don't use any
prohibited section by using the option <b class="Fl" title="Fl">-d</b>, which
implies <b class="Fl" title="Fl">-w</b> but also prohibits the use of VRAM
bank 1.
<div class="Pp"></div>
The arguments are as follows:
<dl class="Bl-tag">
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#m"><b class="Fl" title="Fl" id="m">-m</b></a>
<var class="Ar" title="Ar">mapfile</var></dt>
<dd class="It-tag">Write a mapfile to the given filename.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#n"><b class="Fl" title="Fl" id="n">-n</b></a>
<var class="Ar" title="Ar">symfile</var></dt>
<dd class="It-tag">Write a symbol file to the given filename.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#O"><b class="Fl" title="Fl" id="O">-O</b></a>
<var class="Ar" title="Ar">overlayfile</var></dt>
<dd class="It-tag">The ROM image to overlay sections over. When an overlay ROM
is provided, all sections must be fixed. This may be used to patch an
existing binary.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#o"><b class="Fl" title="Fl" id="o">-o</b></a>
<var class="Ar" title="Ar">outfile</var></dt>
<dd class="It-tag">Write ROM image to the given filename.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
<var class="Ar" title="Ar">pad_value</var></dt>
<dd class="It-tag">When padding an image, pad with this value. The default is
0x00.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#s"><b class="Fl" title="Fl" id="s">-s</b></a>
<var class="Ar" title="Ar">symbol</var></dt>
<dd class="It-tag">???</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#w"><b class="Fl" title="Fl" id="w">-w</b></a></dt>
<dd class="It-tag">Expand the WRAM0 section size from 4KiB to the full 8KiB
assigned to WRAM and prohibit the use of WRAMX sections.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#d"><b class="Fl" title="Fl" id="d">-d</b></a></dt>
<dd class="It-tag">Enable DMG mode. Prohibit the use of sections that doesn't
exist on a DMG, such as WRAMX and VRAM bank 1. This option automatically
enables <b class="Fl" title="Fl">-w</b>.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#t"><b class="Fl" title="Fl" id="t">-t</b></a></dt>
<dd class="It-tag">Expand the ROM0 section size from 16KiB to the full 32KiB
assigned to ROM and prohibit the use of ROMX sections. Useful for ROMs
that fit in 32 KiB.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#l"><b class="Fl" title="Fl" id="l">-l</b></a>
<var class="Ar" title="Ar">linkerscript</var></dt>
<dd class="It-tag">Specify a linkerscript file that tells the linker how
sections must be placed in the ROM. This file has priority over the
attributes assigned in the source code, but they have to be consistent.
See <a class="Xr" title="Xr">rgblink(5)</a> for more information about its
format.</dd>
<dt class="It-tag">&#x00A0;</dt>
<dd class="It-tag">&#x00A0;</dd>
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
<dd class="It-tag">Print the version of the program and exit.</dd>
</dl>
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
All you need for a basic ROM is an object file, which can be made into a ROM
image like so:
<div class="Pp"></div>
<div class="D1">$ rgblink -o bar.gb foo.o</div>
<div class="Pp"></div>
The resulting bar.gb will not have correct checksums (unless you put them in the
assembly source). You should use <a class="Xr" title="Xr">rgbfix(1)</a> to fix
these so that the program will actually run in a Game Boy:
<div class="Pp"></div>
<div class="D1">$ rgbfix -v bar.gb</div>
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
ALSO</a></h1>
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(5)</a>,
<a class="Xr" title="Xr">rgbfix(1)</a>, <a class="Xr" title="Xr">rgbds(5)</a>,
<a class="Xr" title="Xr">rgbds(7)</a>
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
<b class="Nm" title="Nm">rgblink</b> was originally written by Carsten
S&#x00F8;rensen as part of the ASMotor package, and was later packaged in
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
<table class="foot">
<tr>
<td class="foot-date">January 26, 2018</td>
<td class="foot-os">RGBDS Manual</td>
</tr>
</table>
</body>
</html>

105
docs/rgblink.5.html Normal file
View File

@@ -0,0 +1,105 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
table.head, table.foot { width: 100%; }
td.head-rtitle, td.foot-os { text-align: right; }
td.head-vol { text-align: center; }
div.Pp { margin: 1ex 0ex; }
</style>
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
<title>RGBLINK(5)</title>
</head>
<body>
<table class="head">
<tr>
<td class="head-ltitle">RGBLINK(5)</td>
<td class="head-vol">File Formats Manual</td>
<td class="head-rtitle">RGBLINK(5)</td>
</tr>
</table>
<div class="manual-text">
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
<b class="Nm" title="Nm">rgblink</b> &#x2014;
<span class="Nd" title="Nd">linkerscript file format</span>
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
The linkerscript is an external file that allows the user to specify the order
of sections without the need for doing so before assembling each object file.
<div class="Pp"></div>
The placement of sections specified in the linkerscript is done before the
sections whose placement is defined in the source code.
<div class="Pp"></div>
A linkerscript consists on a series of banks followed by a list of sections and,
optionally, commands. They can be lowercase or uppercase, it is ignored. Any
line can contain a comment starting with
&#x2018;<code class="Li">;</code>&#x2019; that ends at the end of the line:
<div class="Pp"></div>
<div class="Bd" style="margin-left: 5.00ex;">
<pre class="Li">
ROMX $F ; This is a comment
&quot;Functions to read array&quot;
ALIGN 8
&quot;Array aligned to 256 bytes&quot;
WRAMX 2
&quot;Some variables&quot;
</pre>
</div>
<div class="Pp"></div>
Numbers can be in decimal or hexadecimal format (the prefix is
&#x2018;<code class="Li">$</code>&#x2019;). It is an error if any section name
or command are found before setting a bank.
<div class="Pp"></div>
Files can be included by using the <var class="Ar" title="Ar">INCLUDE</var>
keyword followed by a string with the path of the file that has to be
included.
<div class="Pp"></div>
The possible bank types are: <b class="Sy" title="Sy">ROM0</b>,
<b class="Sy" title="Sy">ROMX</b>, <b class="Sy" title="Sy">VRAM</b>,
<b class="Sy" title="Sy">WRAM0</b>, <b class="Sy" title="Sy">WRAMX</b>,
<b class="Sy" title="Sy">OAM</b> and <b class="Sy" title="Sy">HRAM</b>. Types
<b class="Sy" title="Sy">ROMX</b>, <b class="Sy" title="Sy">VRAM</b>,
<b class="Sy" title="Sy">WRAMX</b> and <b class="Sy" title="Sy">SRAM</b> are
banked, which means that it is needed to specify a bank after the type.
<div class="Pp"></div>
When a new bank statement is found, sections found after it will be placed right
from the beginning of that bank. If the linkerscript switches to a different
bank and then it comes back to the previous one it will continue from the last
address that was used.
<div class="Pp"></div>
The only two commands are <var class="Ar" title="Ar">ORG</var> and
<var class="Ar" title="Ar">ALIGN</var>:
<ul class="Bl-bullet">
<li class="It-bullet"><var class="Ar" title="Ar">ORG</var> sets the address in
which new sections will be placed. It can not be lower than the current
address.</li>
<li class="It-bullet"><var class="Ar" title="Ar">ALIGN</var> will increase the
address until it is aligned to the specified boundary (it tries to set to
0 the number of bits specified after the command:
<b class="Sy" title="Sy">ALIGN 8</b> will align to $100).</li>
</ul>
<div class="Pp"></div>
Note: The bank, alignment, address and type of sections can be specified both in
the source code and in the linkerscript. For a section to be able to be placed
with the linkerscript the bank must be left unassigned in the source code or
be the same as the one specified in the linkerscript. The address and
alignment musn't be set.
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
ALSO</a></h1>
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(1)</a>,
<a class="Xr" title="Xr">rgbfix(1)</a>, <a class="Xr" title="Xr">rgbds(5)</a>,
<a class="Xr" title="Xr">rgbds(7)</a>
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
<b class="Nm" title="Nm">rgblink</b> was originally written by Carsten
S&#x00F8;rensen as part of the ASMotor package, and was later packaged in
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
<table class="foot">
<tr>
<td class="foot-date">January 27, 2018</td>
<td class="foot-os">RGBDS Manual</td>
</tr>
</table>
</body>
</html>

View File

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

View File

@@ -1,18 +1,27 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_CHARMAP_H #ifndef RGBDS_ASM_CHARMAP_H
#define RGBDS_ASM_CHARMAP_H #define RGBDS_ASM_CHARMAP_H
#include <stdint.h>
#define MAXCHARMAPS 512 #define MAXCHARMAPS 512
#define CHARMAPLENGTH 16 #define CHARMAPLENGTH 16
struct Charmap { struct Charmap {
int count; int32_t count;
char input[MAXCHARMAPS][CHARMAPLENGTH + 1]; char input[MAXCHARMAPS][CHARMAPLENGTH + 1];
char output[MAXCHARMAPS]; char output[MAXCHARMAPS];
}; };
int readUTF8Char(char *destination, char *source); int32_t readUTF8Char(char *destination, char *source);
void charmap_Sort(); int32_t charmap_Add(char *input, uint8_t output);
int charmap_Add(char *input, UBYTE output); int32_t charmap_Convert(char **input);
int charmap_Convert(char **input);
#endif #endif /* RGBDS_ASM_CHARMAP_H */

View File

@@ -1,48 +1,48 @@
/* fstack.h /*
* This file is part of RGBDS.
* *
* Contains some assembler-wide defines and externs * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* Copyright 1997 Carsten Sorensen
* *
* SPDX-License-Identifier: MIT
*/
/*
* Contains some assembler-wide defines and externs
*/ */
#ifndef RGBDS_ASM_FSTACK_H #ifndef RGBDS_ASM_FSTACK_H
#define RGBDS_ASM_FSTACK_H #define RGBDS_ASM_FSTACK_H
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include "asm/asm.h" #include "asm/asm.h"
#include "types.h"
#include "asm/lexer.h" #include "asm/lexer.h"
#include "types.h"
struct sContext { struct sContext {
YY_BUFFER_STATE FlexHandle; YY_BUFFER_STATE FlexHandle;
struct sSymbol *pMacro; struct sSymbol *pMacro;
struct sContext *pNext; struct sContext *pNext;
char tzFileName[_MAX_PATH + 1]; char tzFileName[_MAX_PATH + 1];
char *tzMacroArgs[MAXMACROARGS + 1]; char *tzMacroArgs[MAXMACROARGS + 1];
SLONG nLine; int32_t nLine;
ULONG nStatus; uint32_t nStatus;
FILE *pFile; FILE *pFile;
char *pREPTBlock; char *pREPTBlock;
ULONG nREPTBlockCount; uint32_t nREPTBlockCount;
ULONG nREPTBlockSize; uint32_t nREPTBlockSize;
}; };
void void fstk_RunInclude(char *tzFileName);
fstk_RunInclude(char *); void fstk_RunMacroArg(int32_t s);
extern void fstk_RunMacroArg(SLONG s); void fstk_Init(char *s);
void void fstk_Dump(void);
fstk_Init(char *); void fstk_AddIncludePath(char *s);
extern void fstk_Dump(void); uint32_t fstk_RunMacro(char *s);
extern void fstk_AddIncludePath(char *s); void fstk_RunRept(uint32_t count);
extern ULONG fstk_RunMacro(char *s); FILE *fstk_FindFile(char *fname);
extern void fstk_RunRept(ULONG count); int32_t fstk_GetLine(void);
FILE *
fstk_FindFile(char *);
int fstk_GetLine(void); #endif /* RGBDS_ASM_FSTACK_H */
extern int yywrap(void);
#endif

View File

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

View File

@@ -1,92 +1,97 @@
/* GB Z80 instruction groups /*
* This file is part of RGBDS.
n3 = 3-bit *
n = 8-bit * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
nn = 16-bit *
* SPDX-License-Identifier: MIT
* ADC A,n : 0xCE
* ADC A,r : 0x88|r
* ADD A,n : 0xC6
* ADD A,r : 0x80|r
* ADD HL,ss : 0x09|(ss<<4)
* ADD SP,n : 0xE8
* AND A,n : 0xE6
* AND A,r : 0xA0|r
* BIT n3,r : 0xCB 0x40|(n3<<3)|r
* CALL cc,nn : 0xC4|(cc<<3)
* CALL nn : 0xCD
* CCF : 0x3F
* CP A,n : 0xFE
* CP A,r : 0xB8|r
* CPL : 0x2F
* DAA : 0x27
* DEC r : 0x05|(r<<3)
* DEC ss : 0x0B|(ss<<4)
* DI : 0xF3
* EI : 0xFB
* HALT : 0x76
* INC r : 0x04|(r<<3)
* INC ss : 0x03|(ss<<4)
* JP HL : 0xE9
* JP cc,nn : 0xC2|(cc<<3)
* JP nn : 0xC3|(cc<<3)
* JR n : 0x18
* JR cc,n : 0x20|(cc<<3)
* LD (nn),SP : 0x08
* LD ($FF00+C),A : 0xE2
* LD ($FF00+n),A : 0xE0
* LD (nn),A : 0xEA
* LD (rr),A : 0x02|(rr<<4) // HL+ and HL- included
* LD A,($FF00+C) : 0xF2
* LD A,($FF00+n) : 0xF0
* LD A,(nn) : 0xFA
* LD A,(rr) : 0x0A|(rr<<4) // HL+ and HL- included
* LD HL,SP+n : 0xF8
* LD SP,HL : 0xF9
* LD r,n : 0x06|(r<<3)
* LD r,r' : 0x40|(r<<3)|r' // NOTE: LD (HL),(HL) not allowed
* LD ss,nn : 0x01|(ss<<4)
* NOP : 0x00
* OR A,n : 0xF6
* OR A,r : 0xB0|r
* POP tt : 0xC1|(tt<<4)
* PUSH tt : 0xC5|(tt<<4)
* RES n3,r : 0xCB 0x80|(n3<<3)|r
* RET : 0xC9
* RET cc : 0xC0|(cc<<3)
* RETI : 0xD9
* RL r : 0xCB 0x10|r
* RLA : 0x17
* RLC r : 0xCB 0x00|r
* RLCA : 0x07
* RR r : 0xCB 0x18|r
* RRA : 0x1F
* RRC r : 0xCB 0x08|r
* RRCA : 0x0F
* RST n : 0xC7|n
* SBC A,n : 0xDE
* SBC A,r : 0x98|r
* SCF : 0x37
* SET n3,r : 0xCB 0xC0|(n8<<3)|r
* SLA r : 0xCB 0x20|r
* SRA r : 0xCB 0x28|r
* SRL r : 0xCB 0x38|r
* STOP : 0x10 0x00
* SUB A,n : 0xD6
* SUB A,r : 0x90|r
* SWAP r : 0xCB 0x30|r
* XOR A,n : 0xEE
* XOR A,r : 0xA8|r
*/ */
#define NAME_DB "db" #ifndef RGBDS_ASM_LOCALASM_H
#define NAME_DW "dw" #define RGBDS_ASM_LOCALASM_H
#define NAME_RB "rb"
#define NAME_RW "rw" /*
* 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
* ADD A,r : 0x80|r
* ADD HL,ss : 0x09|(ss<<4)
* ADD SP,n : 0xE8
* AND A,n : 0xE6
* AND A,r : 0xA0|r
* BIT n3,r : 0xCB 0x40|(n3<<3)|r
* CALL cc,nn : 0xC4|(cc<<3)
* CALL nn : 0xCD
* CCF : 0x3F
* CP A,n : 0xFE
* CP A,r : 0xB8|r
* CPL : 0x2F
* DAA : 0x27
* DEC r : 0x05|(r<<3)
* DEC ss : 0x0B|(ss<<4)
* DI : 0xF3
* EI : 0xFB
* HALT : 0x76
* INC r : 0x04|(r<<3)
* INC ss : 0x03|(ss<<4)
* JP HL : 0xE9
* JP cc,nn : 0xC2|(cc<<3)
* JP nn : 0xC3|(cc<<3)
* JR n : 0x18
* JR cc,n : 0x20|(cc<<3)
* LD (nn),SP : 0x08
* LD ($FF00+C),A : 0xE2
* LD ($FF00+n),A : 0xE0
* LD (nn),A : 0xEA
* LD (rr),A : 0x02|(rr<<4) // HL+ and HL- included
* LD A,($FF00+C) : 0xF2
* LD A,($FF00+n) : 0xF0
* LD A,(nn) : 0xFA
* LD A,(rr) : 0x0A|(rr<<4) // HL+ and HL- included
* LD HL,SP+n : 0xF8
* LD SP,HL : 0xF9
* LD r,n : 0x06|(r<<3)
* LD r,r' : 0x40|(r<<3)|r' // NOTE: LD (HL),(HL) not allowed
* LD ss,nn : 0x01|(ss<<4)
* NOP : 0x00
* OR A,n : 0xF6
* OR A,r : 0xB0|r
* POP tt : 0xC1|(tt<<4)
* PUSH tt : 0xC5|(tt<<4)
* RES n3,r : 0xCB 0x80|(n3<<3)|r
* RET : 0xC9
* RET cc : 0xC0|(cc<<3)
* RETI : 0xD9
* RL r : 0xCB 0x10|r
* RLA : 0x17
* RLC r : 0xCB 0x00|r
* RLCA : 0x07
* RR r : 0xCB 0x18|r
* RRA : 0x1F
* RRC r : 0xCB 0x08|r
* RRCA : 0x0F
* RST n : 0xC7|n
* SBC A,n : 0xDE
* SBC A,r : 0x98|r
* SCF : 0x37
* SET n3,r : 0xCB 0xC0|(n8<<3)|r
* SLA r : 0xCB 0x20|r
* SRA r : 0xCB 0x28|r
* SRL r : 0xCB 0x38|r
* STOP : 0x10 0x00
* SUB A,n : 0xD6
* SUB A,r : 0x90|r
* SWAP r : 0xCB 0x30|r
* XOR A,n : 0xEE
* XOR A,r : 0xA8|r
*/
/* "r" defs */ /* "r" defs */
enum { enum {
REG_B = 0, REG_B = 0,
REG_C, REG_C,
@@ -97,36 +102,30 @@ enum {
REG_HL_IND, REG_HL_IND,
REG_A REG_A
}; };
/* "rr" defs */
/* "rr" defs */
enum { enum {
REG_BC_IND = 0, REG_BC_IND = 0,
REG_DE_IND, REG_DE_IND,
REG_HL_INDINC, REG_HL_INDINC,
REG_HL_INDDEC, REG_HL_INDDEC,
}; };
/* "ss" defs */
/* "ss" defs (SP) and "tt" defs (AF) */
enum { enum {
REG_BC = 0, REG_BC = 0,
REG_DE, REG_DE = 1,
REG_HL, REG_HL = 2,
REG_SP 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 */ /* "cc" defs */
enum { enum {
CC_NZ = 0, CC_NZ = 0,
CC_Z, CC_Z,
CC_NC, CC_NC,
CC_C CC_C
}; };
#endif /* RGBDS_ASM_LOCALASM_H */

View File

@@ -1,30 +1,43 @@
#ifndef RGBDS_MAIN_H /*
#define RGBDS_MAIN_H * This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_MAIN_H
#define RGBDS_MAIN_H
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "extern/stdnoreturn.h" #include "extern/stdnoreturn.h"
struct sOptions { struct sOptions {
char gbgfx[4];
char binary[2]; char binary[2];
SLONG fillchar; char gbgfx[4];
bool verbose;
bool haltnop;
bool exportall; bool exportall;
bool warnings; /* true to enable warnings, false to disable them. */ int32_t fillchar;
//-1 == random bool haltnop;
bool optimizeloads;
bool verbose;
bool warnings; /* True to enable warnings, false to disable them. */
}; };
extern char *tzNewMacro; extern char *tzNewMacro;
extern ULONG ulNewMacroSize; extern uint32_t ulNewMacroSize;
extern SLONG nGBGfxID; extern int32_t nGBGfxID;
extern SLONG nBinaryID; extern int32_t nBinaryID;
extern struct sOptions DefaultOptions; extern struct sOptions DefaultOptions;
extern struct sOptions CurrentOptions; extern struct sOptions CurrentOptions;
extern void opt_Push(void);
extern void opt_Pop(void); extern FILE *dependfile;
extern void opt_Parse(char *s);
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 * Used for errors that compromise the whole assembly process by affecting the
@@ -34,6 +47,7 @@ extern void opt_Parse(char *s);
* when it fails to allocate memory). * when it fails to allocate memory).
*/ */
noreturn void fatalerror(const char *fmt, ...); noreturn void fatalerror(const char *fmt, ...);
/* /*
* Used for errors that make it impossible to assemble correctly, but don't * 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 * affect the following code. The code will fail to assemble but the user will
@@ -41,17 +55,18 @@ noreturn void fatalerror(const char *fmt, ...);
* once. * once.
*/ */
void yyerror(const char *fmt, ...); void yyerror(const char *fmt, ...);
/* /*
* Used to warn the user about problems that don't prevent the generation of * Used to warn the user about problems that don't prevent the generation of
* valid code. * valid code.
*/ */
void warning(const char *fmt, ...); void warning(const char *fmt, ...);
#define YY_FATAL_ERROR fatalerror #define YY_FATAL_ERROR fatalerror
#ifdef YYLMAX #ifdef YYLMAX
#undef YYLMAX #undef YYLMAX
#endif #endif
#define YYLMAX 65536 #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,29 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_MATH_H #ifndef RGBDS_ASM_MATH_H
#define RGBDS_ASM_MATH_H #define RGBDS_ASM_MATH_H
#include "types.h" #include <stdint.h>
void math_DefinePI(void); void math_DefinePI(void);
void math_Print(SLONG i); void math_Print(int32_t i);
SLONG math_Sin(SLONG i); int32_t math_Sin(int32_t i);
SLONG math_Cos(SLONG i); int32_t math_Cos(int32_t i);
SLONG math_Tan(SLONG i); int32_t math_Tan(int32_t i);
SLONG math_ASin(SLONG i); int32_t math_ASin(int32_t i);
SLONG math_ACos(SLONG i); int32_t math_ACos(int32_t i);
SLONG math_ATan(SLONG i); int32_t math_ATan(int32_t i);
SLONG math_ATan2(SLONG i, SLONG j); int32_t math_ATan2(int32_t i, int32_t j);
SLONG math_Mul(SLONG i, SLONG j); int32_t math_Mul(int32_t i, int32_t j);
SLONG math_Div(SLONG i, SLONG j); int32_t math_Div(int32_t i, int32_t j);
SLONG math_Round(SLONG i); int32_t math_Round(int32_t i);
SLONG math_Ceil(SLONG i); int32_t math_Ceil(int32_t i);
SLONG math_Floor(SLONG i); int32_t math_Floor(int32_t i);
#endif #endif /* RGBDS_ASM_MATH_H */

View File

@@ -1,40 +1,53 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_OUTPUT_H #ifndef RGBDS_ASM_OUTPUT_H
#define RGBDS_ASM_OUTPUT_H #define RGBDS_ASM_OUTPUT_H
#include <stdint.h>
#include "asm/rpn.h" #include "asm/rpn.h"
#include "types.h"
struct Section { struct Section {
char *pzName; char *pzName;
UBYTE nType; uint8_t nType;
ULONG nPC; uint32_t nPC;
ULONG nOrg; uint32_t nOrg;
ULONG nBank; uint32_t nBank;
ULONG nAlign; uint32_t nAlign;
struct Section *pNext; struct Section *pNext;
struct Patch *pPatches; struct Patch *pPatches;
struct Charmap *charmap; struct Charmap *charmap;
UBYTE *tData; uint8_t *tData;
}; };
extern char *tzObjectname;
void out_PrepPass2(void); void out_PrepPass2(void);
void out_SetFileName(char *s); void out_SetFileName(char *s);
void out_NewSection(char *pzName, ULONG secttype); void out_NewSection(char *pzName, uint32_t secttype);
void out_NewAbsSection(char *pzName, ULONG secttype, SLONG org, SLONG bank); void out_NewAbsSection(char *pzName, uint32_t secttype, int32_t org,
void out_NewAlignedSection(char *pzName, ULONG secttype, SLONG alignment, SLONG bank); int32_t bank);
void out_AbsByte(int b); void out_NewAlignedSection(char *pzName, uint32_t secttype, int32_t alignment,
void out_AbsByteGroup(char *s, int length); int32_t bank);
void out_RelByte(struct Expression * expr); void out_AbsByte(int32_t b);
void out_RelWord(struct Expression * expr); void out_AbsByteGroup(char *s, int32_t length);
void out_PCRelByte(struct Expression * expr); void out_RelByte(struct Expression *expr);
void out_RelWord(struct Expression *expr);
void out_PCRelByte(struct Expression *expr);
void out_WriteObject(void); void out_WriteObject(void);
void out_Skip(int skip); void out_Skip(int32_t skip);
void out_BinaryFile(char *s); 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_String(char *s);
void out_AbsLong(SLONG b); void out_AbsLong(int32_t b);
void out_RelLong(struct Expression * expr); void out_RelLong(struct Expression *expr);
void out_PushSection(void); void out_PushSection(void);
void out_PopSection(void); void out_PopSection(void);
#endif #endif /* RGBDS_ASM_OUTPUT_H */

View File

@@ -1,81 +1,75 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_RPN_H #ifndef RGBDS_ASM_RPN_H
#define RGBDS_ASM_RPN_H #define RGBDS_ASM_RPN_H
#include <stdint.h>
struct Expression { struct Expression {
SLONG nVal; int32_t nVal;
UBYTE tRPN[256]; uint8_t tRPN[256];
ULONG nRPNLength; uint32_t nRPNLength;
ULONG nRPNOut; uint32_t nRPNOut;
ULONG isReloc; uint32_t isReloc;
ULONG isPCRel; uint32_t isPCRel;
}; };
ULONG rpn_isReloc(struct Expression * expr); uint32_t rpn_isReloc(const struct Expression *expr);
ULONG rpn_isPCRelative(struct Expression * expr); uint32_t rpn_isPCRelative(const struct Expression *expr);
void rpn_Symbol(struct Expression * expr, char *tzSym); void rpn_Symbol(struct Expression *expr, char *tzSym);
void rpn_Number(struct Expression * expr, ULONG i); void rpn_Number(struct Expression *expr, uint32_t i);
void rpn_LOGNOT(struct Expression * expr, struct Expression * src1); void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
void void rpn_LOGOR(struct Expression *expr, const struct Expression *src1,
rpn_LOGOR(struct Expression * expr, struct Expression * src1, const struct Expression *src2);
struct Expression * src2); void rpn_LOGAND(struct Expression *expr, const struct Expression *src1,
void const struct Expression *src2);
rpn_LOGAND(struct Expression * expr, struct Expression * src1, void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1,
struct Expression * src2); const struct Expression *src2);
void void rpn_LOGGT(struct Expression *expr, const struct Expression *src1,
rpn_LOGEQU(struct Expression * expr, struct Expression * src1, const struct Expression *src2);
struct Expression * src2); void rpn_LOGLT(struct Expression *expr, const struct Expression *src1,
void const struct Expression *src2);
rpn_LOGGT(struct Expression * expr, struct Expression * src1, void rpn_LOGGE(struct Expression *expr, const struct Expression *src1,
struct Expression * src2); const struct Expression *src2);
void void rpn_LOGLE(struct Expression *expr, const struct Expression *src1,
rpn_LOGLT(struct Expression * expr, struct Expression * src1, const struct Expression *src2);
struct Expression * src2); void rpn_LOGNE(struct Expression *expr, const struct Expression *src1,
void const struct Expression *src2);
rpn_LOGGE(struct Expression * expr, struct Expression * src1, void rpn_ADD(struct Expression *expr, const struct Expression *src1,
struct Expression * src2); const struct Expression *src2);
void void rpn_SUB(struct Expression *expr, const struct Expression *src1,
rpn_LOGLE(struct Expression * expr, struct Expression * src1, const struct Expression *src2);
struct Expression * src2); void rpn_XOR(struct Expression *expr, const struct Expression *src1,
void const struct Expression *src2);
rpn_LOGNE(struct Expression * expr, struct Expression * src1, void rpn_OR(struct Expression *expr, const struct Expression *src1,
struct Expression * src2); const struct Expression *src2);
void void rpn_AND(struct Expression *expr, const struct Expression *src1,
rpn_ADD(struct Expression * expr, struct Expression * src1, const struct Expression *src2);
struct Expression * src2); void rpn_SHL(struct Expression *expr, const struct Expression *src1,
void const struct Expression *src2);
rpn_SUB(struct Expression * expr, struct Expression * src1, void rpn_SHR(struct Expression *expr, const struct Expression *src1,
struct Expression * src2); const struct Expression *src2);
void void rpn_MUL(struct Expression *expr, const struct Expression *src1,
rpn_XOR(struct Expression * expr, struct Expression * src1, const struct Expression *src2);
struct Expression * src2); void rpn_DIV(struct Expression *expr, const struct Expression *src1,
void const struct Expression *src2);
rpn_OR(struct Expression * expr, struct Expression * src1, void rpn_MOD(struct Expression *expr, const struct Expression *src1,
struct Expression * src2); const struct Expression *src2);
void void rpn_HIGH(struct Expression *expr, const struct Expression *src);
rpn_AND(struct Expression * expr, struct Expression * src1, void rpn_LOW(struct Expression *expr, const struct Expression *src);
struct Expression * src2); void rpn_UNNEG(struct Expression *expr, const struct Expression *src);
void void rpn_UNNOT(struct Expression *expr, const struct Expression *src);
rpn_SHL(struct Expression * expr, struct Expression * src1, uint16_t rpn_PopByte(struct Expression *expr);
struct Expression * src2); void rpn_BankSymbol(struct Expression *expr, char *tzSym);
void void rpn_BankSection(struct Expression *expr, char *tzSectionName);
rpn_SHR(struct Expression * expr, struct Expression * src1, void rpn_BankSelf(struct Expression *expr);
struct Expression * src2); void rpn_Reset(struct Expression *expr);
void void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
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_Reset(struct Expression * expr);
void rpn_CheckHRAM(struct Expression * expr, struct Expression * src1);
#endif #endif /* RGBDS_ASM_RPN_H */

View File

@@ -1,44 +1,58 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_SYMBOL_H #ifndef RGBDS_SYMBOL_H
#define RGBDS_SYMBOL_H #define RGBDS_SYMBOL_H
#include <stdint.h>
#include "types.h" #include "types.h"
#define HASHSIZE (1 << 16) #define HASHSIZE (1 << 16)
#define MAXSYMLEN 256 #define MAXSYMLEN 256
struct sSymbol { struct sSymbol {
char tzName[MAXSYMLEN + 1]; char tzName[MAXSYMLEN + 1];
SLONG nValue; int32_t nValue;
ULONG nType; uint32_t nType;
struct sSymbol *pScope; struct sSymbol *pScope;
struct sSymbol *pNext; struct sSymbol *pNext;
struct Section *pSection; struct Section *pSection;
ULONG ulMacroSize; uint32_t ulMacroSize;
char *pMacro; char *pMacro;
SLONG(*Callback) (struct sSymbol *); int32_t (*Callback)(struct sSymbol *);
char tzFileName[_MAX_PATH + 1]; /* File where the symbol was defined. */ char tzFileName[_MAX_PATH + 1]; /* File where the symbol was defined. */
ULONG nFileLine; /* Line 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); /* Symbol will be relocated during linking, it's absolute value is unknown */
void sym_SetExportAll(BBOOL set); #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_PrepPass1(void);
void sym_PrepPass2(void); void sym_PrepPass2(void);
void sym_AddLocalReloc(char *tzSym); void sym_AddLocalReloc(char *tzSym);
@@ -52,26 +66,30 @@ void sym_SaveCurrentMacroArgs(char *save[]);
void sym_RestoreCurrentMacroArgs(char *save[]); void sym_RestoreCurrentMacroArgs(char *save[]);
void sym_UseNewMacroArgs(void); void sym_UseNewMacroArgs(void);
void sym_FreeCurrentMacroArgs(void); void sym_FreeCurrentMacroArgs(void);
void sym_AddEqu(char *tzSym, SLONG value); void sym_AddEqu(char *tzSym, int32_t value);
void sym_AddSet(char *tzSym, SLONG value); void sym_AddSet(char *tzSym, int32_t value);
void sym_Init(void); void sym_Init(void);
ULONG sym_GetConstantValue(char *s); uint32_t sym_GetConstantValue(char *s);
ULONG sym_isConstant(char *s); uint32_t sym_isConstant(char *s);
struct sSymbol *sym_FindSymbol(char *tzName); struct sSymbol *sym_FindSymbol(char *tzName);
void sym_Global(char *tzSym); void sym_Global(char *tzSym);
char *sym_FindMacroArg(SLONG i); char *sym_FindMacroArg(int32_t i);
char *sym_GetStringValue(char *tzSym); char *sym_GetStringValue(char *tzSym);
void sym_UseCurrentMacroArgs(void); void sym_UseCurrentMacroArgs(void);
void sym_SetMacroArgID(ULONG nMacroCount); void sym_SetMacroArgID(uint32_t nMacroCount);
ULONG sym_isString(char *tzSym); uint32_t sym_isString(char *tzSym);
void sym_AddMacro(char *tzSym); void sym_AddMacro(char *tzSym);
void sym_ShiftCurrentMacroArgs(void); void sym_ShiftCurrentMacroArgs(void);
void sym_AddString(char *tzSym, char *tzValue); void sym_AddString(char *tzSym, char *tzValue);
ULONG sym_GetValue(char *s); uint32_t sym_GetValue(char *s);
ULONG sym_GetDefinedValue(char *s); uint32_t sym_GetDefinedValue(char *s);
ULONG sym_isDefined(char *tzName); uint32_t sym_isDefined(char *tzName);
void sym_Purge(char *tzName); void sym_Purge(char *tzName);
ULONG sym_isConstDefined(char *tzName); uint32_t sym_isConstDefined(char *tzName);
int sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2); 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 */

View File

@@ -1,6 +1,44 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_COMMON_H #ifndef RGBDS_COMMON_H
#define RGBDS_COMMON_H #define RGBDS_COMMON_H
#define RGBDS_OBJECT_VERSION_STRING "RGB5" #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 */ #endif /* RGBDS_COMMON_H */

33
include/extern/err.h vendored
View File

@@ -1,11 +1,22 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef EXTERN_ERR_H #ifndef EXTERN_ERR_H
#define EXTERN_ERR_H #define EXTERN_ERR_H
#ifdef ERR_IN_LIBC #ifdef ERR_IN_LIBC
#include <err.h> #include <err.h>
#else
#else /* ERR_IN_LIBC */
#include <stdarg.h> #include <stdarg.h>
#include "extern/stdnoreturn.h" #include "extern/stdnoreturn.h"
#define warn rgbds_warn #define warn rgbds_warn
@@ -18,16 +29,16 @@
#define errx rgbds_errx #define errx rgbds_errx
#define verrx rgbds_verrx #define verrx rgbds_verrx
void warn(const char *, ...); void warn(const char *fmt, ...);
void vwarn(const char *, va_list); void vwarn(const char *fmt, va_list ap);
void warnx(const char *, ...); void warnx(const char *fmt, ...);
void vwarnx(const char *, va_list); void vwarnx(const char *fmt, va_list ap);
noreturn void err(int, const char *, ...); noreturn void err(int status, const char *fmt, ...);
noreturn void verr(int, const char *, va_list); noreturn void verr(int status, const char *fmt, va_list ap);
noreturn void errx(int, const char *, ...); noreturn void errx(int status, const char *fmt, ...);
noreturn void verrx(int, const char *, va_list); noreturn void verrx(int status, const char *fmt, va_list ap);
#endif #endif /* ERR_IN_LIBC */
#endif #endif /* EXTERN_ERR_H */

View File

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

View File

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

13
include/extern/strl.h vendored
View File

@@ -1,13 +0,0 @@
#ifndef STRL_H
#define STRL_H
#ifdef STRL_IN_LIBC
#include <string.h>
#else
#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
#endif

14
include/extern/utf8decoder.h vendored Normal file
View File

@@ -0,0 +1,14 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2018, Antonio Nino Diaz and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef EXTERN_UTF8DECODER_H
#define EXTERN_UTF8DECODER_H
uint32_t decode(uint32_t *state, uint32_t *codep, uint32_t byte);
#endif /* EXTERN_UTF8DECODER_H */

View File

@@ -1,21 +0,0 @@
/*
* 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.
*/
#define PACKAGE_VERSION_MAJOR (0)
#define PACKAGE_VERSION_MINOR (3)
#define PACKAGE_VERSION_PATCH (2)
const char * get_package_version_string(void);

View File

@@ -1,17 +1,9 @@
/* /*
* Copyright © 2013 stag019 <stag019@gmail.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2013-2018, stag019 and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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 RGBDS_GFX_GB_H #ifndef RGBDS_GFX_GB_H
@@ -20,11 +12,15 @@
#include <stdint.h> #include <stdint.h>
#include "gfx/main.h" #include "gfx/main.h"
void png_to_gb(struct PNGImage png, struct GBImage *gb); void raw_to_gb(const struct RawIndexedImage *raw_image, struct GBImage *gb);
void output_file(struct Options opts, 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); int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
void create_tilemap(struct Options opts, struct GBImage *gb, struct Tilemap *tilemap); int tile_size);
void output_tilemap_file(struct Options opts, struct Tilemap tilemap); void create_tilemap(const struct Options *opts, struct GBImage *gb,
void output_palette_file(struct Options opts, struct PNGImage png); 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 RawIndexedImage *raw_image);
#endif #endif

View File

@@ -1,17 +1,9 @@
/* /*
* Copyright © 2013 stag019 <stag019@gmail.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2013-2018, stag019 and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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 RGBDS_GFX_MAIN_H #ifndef RGBDS_GFX_MAIN_H
@@ -39,6 +31,21 @@ struct Options {
char *infile; char *infile;
}; };
struct RGBColor {
uint8_t red;
uint8_t green;
uint8_t blue;
};
struct ImageOptions {
bool horizontal;
int trim;
char *mapfile;
bool mapout;
char *palfile;
bool palout;
};
struct PNGImage { struct PNGImage {
png_struct *png; png_struct *png;
png_info *info; png_info *info;
@@ -47,12 +54,14 @@ struct PNGImage {
int height; int height;
png_byte depth; png_byte depth;
png_byte type; png_byte type;
bool horizontal; };
int trim;
char *mapfile; struct RawIndexedImage {
bool mapout; uint8_t **data;
char *palfile; struct RGBColor *palette;
bool palout; int num_colors;
int width;
int height;
}; };
struct GBImage { struct GBImage {
@@ -72,4 +81,4 @@ int depth, colors;
#include "gfx/makepng.h" #include "gfx/makepng.h"
#include "gfx/gb.h" #include "gfx/gb.h"
#endif #endif /* RGBDS_GFX_MAIN_H */

View File

@@ -1,17 +1,9 @@
/* /*
* Copyright © 2013 stag019 <stag019@gmail.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2013-2018, stag019 and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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 RGBDS_GFX_PNG_H #ifndef RGBDS_GFX_PNG_H
@@ -19,10 +11,11 @@
#include "gfx/main.h" #include "gfx/main.h"
void input_png_file(struct Options opts, struct PNGImage *img); struct RawIndexedImage *input_png_file(const struct Options *opts,
void get_text(struct PNGImage *png); struct ImageOptions *png_options);
void set_text(struct PNGImage *png); void output_png_file(const struct Options *opts,
void output_png_file(struct Options opts, struct PNGImage *png); const struct ImageOptions *png_options,
void free_png_data(struct PNGImage *png); const struct RawIndexedImage *raw_image);
void destroy_raw_image(struct RawIndexedImage **raw_image_ptr_ptr);
#endif #endif /* RGBDS_GFX_PNG_H */

View File

@@ -1,50 +1,53 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_LINK_ASSIGN_H #ifndef RGBDS_LINK_ASSIGN_H
#define RGBDS_LINK_ASSIGN_H #define RGBDS_LINK_ASSIGN_H
#include <stdint.h>
#include "common.h"
#include "mylink.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 { enum eBankDefine {
BANK_ROM0 = 0, BANK_INDEX_ROM0 = 0,
BANK_ROMX = BANK_ROM0 + BANK_COUNT_ROM0, BANK_INDEX_ROMX = BANK_INDEX_ROM0 + BANK_COUNT_ROM0,
BANK_WRAM0 = BANK_ROMX + BANK_COUNT_ROMX, BANK_INDEX_WRAM0 = BANK_INDEX_ROMX + BANK_COUNT_ROMX,
BANK_WRAMX = BANK_WRAM0 + BANK_COUNT_WRAM0, BANK_INDEX_WRAMX = BANK_INDEX_WRAM0 + BANK_COUNT_WRAM0,
BANK_VRAM = BANK_WRAMX + BANK_COUNT_WRAMX, BANK_INDEX_VRAM = BANK_INDEX_WRAMX + BANK_COUNT_WRAMX,
BANK_OAM = BANK_VRAM + BANK_COUNT_VRAM, BANK_INDEX_OAM = BANK_INDEX_VRAM + BANK_COUNT_VRAM,
BANK_HRAM = BANK_OAM + BANK_COUNT_OAM, BANK_INDEX_HRAM = BANK_INDEX_OAM + BANK_COUNT_OAM,
BANK_SRAM = BANK_HRAM + BANK_COUNT_HRAM 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 \ extern int32_t MaxBankUsed;
+ BANK_COUNT_VRAM + BANK_COUNT_OAM + BANK_COUNT_HRAM + BANK_COUNT_SRAM) extern int32_t MaxAvail[BANK_INDEX_MAX];
extern SLONG area_Avail(SLONG bank); int32_t area_Avail(int32_t bank);
extern void AssignSections(void); void AssignSections(void);
extern void CreateSymbolTable(void); void CreateSymbolTable(void);
extern SLONG MaxBankUsed; struct sSection *GetSectionByName(const char *name);
extern SLONG MaxAvail[MAXBANKS]; 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 int BankIndexIsROM0(int32_t bank);
IsSectionNameInUse(const char *name); 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 #endif /* RGBDS_LINK_ASSIGN_H */
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

View File

@@ -1,6 +1,14 @@
#ifndef RGBDS_LINK_LIBRARY_H /*
#define RGBDS_LINK_LIBRARY_H * This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
extern void AddNeededModules(void); #ifndef RGBDS_LINK_LIBRARY_H
#define RGBDS_LINK_LIBRARY_H
#endif void AddNeededModules(void);
#endif /* RGBDS_LINK_LIBRARY_H */

View File

@@ -1,9 +1,17 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_LINK_MAIN_H #ifndef RGBDS_LINK_MAIN_H
#define 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; extern char *smartlinkstartsymbol;
#endif #endif /* RGBDS_LINK_MAIN_H */

View File

@@ -1,11 +1,21 @@
#ifndef RGBDS_LINK_MAPFILE_H /*
#define RGBDS_LINK_MAPFILE_H * This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
extern void SetMapfileName(char *name); #ifndef RGBDS_LINK_MAPFILE_H
extern void SetSymfileName(char *name); #define RGBDS_LINK_MAPFILE_H
extern void CloseMapfile(void);
extern void MapfileWriteSection(struct sSection * pSect);
extern void MapfileInitBank(SLONG bank);
extern void MapfileCloseBank(SLONG slack);
#endif #include <stdint.h>
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,117 +1,68 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_LINK_LINK_H #ifndef RGBDS_LINK_LINK_H
#define RGBDS_LINK_LINK_H #define RGBDS_LINK_LINK_H
#ifndef _MAX_PATH #include <stdint.h>
#define _MAX_PATH 512
#endif
#include "types.h" #include "linkdefs.h"
extern int32_t options;
extern SLONG options;
#define OPT_TINY 0x01 #define OPT_TINY 0x01
#define OPT_SMART_C_LINK 0x02 #define OPT_SMART_C_LINK 0x02
#define OPT_OVERLAY 0x04 #define OPT_OVERLAY 0x04
#define OPT_CONTWRAM 0x08 #define OPT_CONTWRAM 0x08
#define OPT_DMG_MODE 0x10 #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 { struct sSection {
SLONG nBank; int32_t nBank;
SLONG nOrg; int32_t nOrg;
SLONG nAlign; int32_t nAlign;
BBOOL oAssigned; uint8_t oAssigned;
char *pzName; char *pzName;
SLONG nByteSize; int32_t nByteSize;
enum eSectionType Type; enum eSectionType Type;
UBYTE *pData; uint8_t *pData;
SLONG nNumberOfSymbols; int32_t nNumberOfSymbols;
struct sSymbol **tSymbols; struct sSymbol **tSymbols;
struct sPatch *pPatches; struct sPatch *pPatches;
struct sSection *pNext; struct sSection *pNext;
}; };
enum eSymbolType {
SYM_LOCAL,
SYM_IMPORT,
SYM_EXPORT
};
struct sSymbol { struct sSymbol {
char *pzName; char *pzName;
enum eSymbolType Type; enum eSymbolType Type;
/* the following 3 items only valid when Type!=SYM_IMPORT */
SLONG nSectionID; /* internal to object.c */ /* The following 3 items only valid when Type!=SYM_IMPORT */
int32_t nSectionID; /* Internal to object.c */
struct sSection *pSection; struct sSection *pSection;
SLONG nOffset; int32_t nOffset;
char *pzObjFileName; /* Object file where the symbol is located. */ char *pzObjFileName; /* Object file where the symbol is located. */
char *pzFileName; /* Source file where the symbol was defined. */ char *pzFileName; /* Source file where the symbol was defined. */
ULONG nFileLine; /* Line where the symbol was defined. */ uint32_t nFileLine; /* Line where the symbol was defined. */
};
enum ePatchType {
PATCH_BYTE = 0,
PATCH_WORD_L,
PATCH_LONG_L
}; };
struct sPatch { struct sPatch {
char *pzFilename; char *pzFilename;
SLONG nLineNo; int32_t nLineNo;
SLONG nOffset; int32_t nOffset;
enum ePatchType Type; enum ePatchType Type;
SLONG nRPNSize; int32_t nRPNSize;
UBYTE *pRPN; uint8_t *pRPN;
struct sPatch *pNext; struct sPatch *pNext;
BBOOL oRelocPatch; uint8_t oRelocPatch;
}; };
extern struct sSection *pSections; extern struct sSection *pSections;
extern struct sSection *pLibSections; extern struct sSection *pLibSections;
#endif #endif /* RGBDS_LINK_LINK_H */

View File

@@ -1,6 +1,14 @@
#ifndef RGBDS_LINK_OBJECT_H /*
#define RGBDS_LINK_OBJECT_H * This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
extern void obj_Readfile(char *tzObjectfile); #ifndef RGBDS_LINK_OBJECT_H
#define RGBDS_LINK_OBJECT_H
#endif void obj_Readfile(char *tzObjectfile);
#endif /* RGBDS_LINK_OBJECT_H */

View File

@@ -1,8 +1,16 @@
#ifndef RGBDS_LINK_OUTPUT_H /*
#define RGBDS_LINK_OUTPUT_H * This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_LINK_OUTPUT_H
#define RGBDS_LINK_OUTPUT_H
void out_Setname(char *tzOutputfile); void out_Setname(char *tzOutputfile);
void out_SetOverlayname(char *tzOverlayfile); void out_SetOverlayname(char *tzOverlayfile);
void Output(void); void Output(void);
#endif #endif /* RGBDS_LINK_OUTPUT_H */

View File

@@ -1,9 +1,17 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_LINK_PATCH_H #ifndef RGBDS_LINK_PATCH_H
#define RGBDS_LINK_PATCH_H #define RGBDS_LINK_PATCH_H
#include "types.h" #include <stdint.h>
void Patch(void); void Patch(void);
extern SLONG nPC; extern int32_t nPC;
#endif #endif /* RGBDS_LINK_PATCH_H */

View File

@@ -1,22 +1,16 @@
/* /*
* Copyright (C) 2017 Antonio Nino Diaz <antonio_nd@outlook.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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 RGBDS_LINK_SCRIPT_H #ifndef RGBDS_LINK_SCRIPT_H
#define RGBDS_LINK_SCRIPT_H #define RGBDS_LINK_SCRIPT_H
#include <stdint.h>
#include "extern/stdnoreturn.h" #include "extern/stdnoreturn.h"
noreturn void script_fatalerror(const char *fmt, ...); noreturn void script_fatalerror(const char *fmt, ...);
@@ -24,14 +18,13 @@ noreturn void script_fatalerror(const char *fmt, ...);
void script_Parse(const char *path); void script_Parse(const char *path);
void script_IncludeFile(const char *path); void script_IncludeFile(const char *path);
int script_IncludeDepthGet(void); int32_t script_IncludeDepthGet(void);
void script_IncludePop(void); void script_IncludePop(void);
void script_InitSections(void); void script_InitSections(void);
void script_SetCurrentSectionType(const char *type, unsigned int bank); void script_SetCurrentSectionType(const char *type, uint32_t bank);
void script_SetAddress(unsigned int addr); void script_SetAddress(uint32_t addr);
void script_SetAlignment(unsigned int alignment); void script_SetAlignment(uint32_t alignment);
void script_OutputSection(const char *section_name); void script_OutputSection(const char *section_name);
#endif #endif /* RGBDS_LINK_SCRIPT_H */

View File

@@ -1,12 +1,21 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_LINK_SYMBOL_H #ifndef RGBDS_LINK_SYMBOL_H
#define RGBDS_LINK_SYMBOL_H #define RGBDS_LINK_SYMBOL_H
#include "types.h" #include <stdint.h>
void sym_Init(void); void sym_Init(void);
void sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank, void sym_CreateSymbol(char *tzName, int32_t nValue, int32_t nBank,
char *tzObjFileName, char *tzFileName, ULONG nFileLine); char *tzObjFileName, char *tzFileName,
SLONG sym_GetValue(char *tzName); uint32_t nFileLine);
SLONG sym_GetBank(char *tzName); int32_t sym_GetValue(char *tzName);
int32_t sym_GetBank(char *tzName);
#endif #endif /* RGBDS_LINK_SYMBOL_H */

73
include/linkdefs.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#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,
PATCH_BYTE_JR = 0x03
};
#endif /* RGBDS_LINKDEFS_H */

View File

@@ -1,16 +1,16 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_TYPES_H #ifndef RGBDS_TYPES_H
#define RGBDS_TYPES_H #define RGBDS_TYPES_H
#ifndef _MAX_PATH #ifndef _MAX_PATH
#define _MAX_PATH 512 #define _MAX_PATH 512
#endif #endif
typedef unsigned char UBYTE; #endif /* RGBDS_TYPES_H */
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

18
include/version.h Normal file
View File

@@ -0,0 +1,18 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef EXTERN_VERSION_H
#define EXTERN_VERSION_H
#define PACKAGE_VERSION_MAJOR (0)
#define PACKAGE_VERSION_MINOR (3)
#define PACKAGE_VERSION_PATCH (6)
const char *get_package_version_string(void);
#endif /* EXTERN_VERSION_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,73 +1,12 @@
/* /*
* UTF-8 decoder copyright © 20082009 Björn Höhrmann <bjoern@hoehrmann.de> * This file is part of RGBDS.
* http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Copyright (c) 2013-2018, stag019 and RGBDS contributors.
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * SPDX-License-Identifier: MIT
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/ */
#include <stdint.h> #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
};
uint32_t
decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
uint32_t type = utf8d[byte];
*codep = (*state != 0) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*state = utf8d[256 + *state*16 + type];
return *state;
}
/*
* Copyright © 2013 stag019 <stag019@gmail.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 <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -77,21 +16,19 @@ decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
#include "asm/main.h" #include "asm/main.h"
#include "asm/output.h" #include "asm/output.h"
#include "extern/utf8decoder.h"
struct Charmap globalCharmap = {0}; struct Charmap globalCharmap = {0};
extern struct Section *pCurrentSection; int32_t readUTF8Char(char *dest, char *src)
int
readUTF8Char(char *dest, char *src)
{ {
uint32_t state; uint32_t state;
uint32_t codep; uint32_t codep;
int i; int32_t i;
for (i = 0, state = 0;; 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"); fatalerror("invalid UTF-8 character");
}
dest[i] = src[i]; dest[i] = src[i];
@@ -104,13 +41,12 @@ readUTF8Char(char *dest, char *src)
} }
} }
int int32_t charmap_Add(char *input, uint8_t output)
charmap_Add(char *input, UBYTE output)
{ {
int i; int32_t i;
size_t input_length; size_t input_length;
char temp1i[CHARMAPLENGTH + 1], temp2i[CHARMAPLENGTH + 1], temp1o = 0, char temp1i[CHARMAPLENGTH + 1], temp2i[CHARMAPLENGTH + 1];
temp2o = 0; char temp1o = 0, temp2o = 0;
struct Charmap *charmap; struct Charmap *charmap;
@@ -118,23 +54,21 @@ charmap_Add(char *input, UBYTE output)
if (pCurrentSection->charmap) { if (pCurrentSection->charmap) {
charmap = pCurrentSection->charmap; charmap = pCurrentSection->charmap;
} else { } else {
if ((charmap = calloc(1, sizeof(struct Charmap))) == charmap = calloc(1, sizeof(struct Charmap));
NULL) { if (charmap == NULL)
fatalerror("Not enough memory for charmap"); fatalerror("Not enough memory for charmap");
}
pCurrentSection->charmap = charmap; pCurrentSection->charmap = charmap;
} }
} else { } else {
charmap = &globalCharmap; charmap = &globalCharmap;
} }
if (nPass == 2) { if (nPass == 2)
return charmap->count; return charmap->count;
}
if (charmap->count > MAXCHARMAPS || strlen(input) > CHARMAPLENGTH) { if (charmap->count > MAXCHARMAPS || strlen(input) > CHARMAPLENGTH)
return -1; return -1;
}
input_length = strlen(input); input_length = strlen(input);
if (input_length > 1) { if (input_length > 1) {
@@ -142,7 +76,7 @@ charmap_Add(char *input, UBYTE output)
while (i < charmap->count + 1) { while (i < charmap->count + 1) {
if (input_length > strlen(charmap->input[i])) { if (input_length > strlen(charmap->input[i])) {
memcpy(temp1i, charmap->input[i], memcpy(temp1i, charmap->input[i],
CHARMAPLENGTH + 1); CHARMAPLENGTH + 1);
memcpy(charmap->input[i], input, input_length); memcpy(charmap->input[i], input, input_length);
temp1o = charmap->output[i]; temp1o = charmap->output[i];
charmap->output[i] = output; charmap->output[i] = output;
@@ -161,7 +95,7 @@ charmap_Add(char *input, UBYTE output)
i++; i++;
} }
memcpy(charmap->input[charmap->count + 1], temp1i, memcpy(charmap->input[charmap->count + 1], temp1i,
CHARMAPLENGTH + 1); CHARMAPLENGTH + 1);
charmap->output[charmap->count + 1] = temp1o; charmap->output[charmap->count + 1] = temp1o;
} else { } else {
memcpy(charmap->input[charmap->count], input, input_length); memcpy(charmap->input[charmap->count], input, input_length);
@@ -170,24 +104,22 @@ charmap_Add(char *input, UBYTE output)
return ++charmap->count; return ++charmap->count;
} }
int int32_t charmap_Convert(char **input)
charmap_Convert(char **input)
{ {
struct Charmap *charmap; struct Charmap *charmap;
char outchar[CHARMAPLENGTH + 1]; char outchar[CHARMAPLENGTH + 1];
char *buffer; char *buffer;
int i, j, length; int32_t i, j, length;
if (pCurrentSection && pCurrentSection->charmap) { if (pCurrentSection && pCurrentSection->charmap)
charmap = pCurrentSection->charmap; charmap = pCurrentSection->charmap;
} else { else
charmap = &globalCharmap; charmap = &globalCharmap;
}
if ((buffer = malloc(strlen(*input))) == NULL) { buffer = malloc(strlen(*input));
if (buffer == NULL)
fatalerror("Not enough memory for buffer"); fatalerror("Not enough memory for buffer");
}
length = 0; length = 0;
while (**input) { while (**input) {
@@ -201,15 +133,15 @@ charmap_Convert(char **input)
} }
j = 0; j = 0;
} }
if (!j) {
if (!j)
j = readUTF8Char(outchar, *input); j = readUTF8Char(outchar, *input);
}
if (!outchar[0]) { if (!outchar[0]) {
buffer[length++] = 0; buffer[length++] = 0;
} else { } else {
for (i = 0; outchar[i]; i++) { for (i = 0; outchar[i]; i++)
buffer[length++] = outchar[i]; buffer[length++] = outchar[i];
}
} }
*input += j; *input += j;
} }

View File

@@ -1,43 +1,47 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
/* /*
* FileStack routines * FileStack routines
*/ */
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "asm/symbol.h"
#include "asm/fstack.h" #include "asm/fstack.h"
#include "types.h"
#include "asm/main.h"
#include "asm/lexer.h" #include "asm/lexer.h"
#include "asm/main.h"
#include "asm/output.h"
#include "asm/symbol.h"
#include "extern/err.h" #include "extern/err.h"
#include "extern/strl.h"
#ifndef PATH_MAX #include "types.h"
#define PATH_MAX 256
#endif
struct sContext *pFileStack; static struct sContext *pFileStack;
struct sSymbol *pCurrentMacro; static struct sSymbol *pCurrentMacro;
YY_BUFFER_STATE CurrentFlexHandle; static YY_BUFFER_STATE CurrentFlexHandle;
FILE *pCurrentFile; static FILE *pCurrentFile;
ULONG nCurrentStatus; static uint32_t nCurrentStatus;
char tzCurrentFileName[_MAX_PATH + 1]; char tzCurrentFileName[_MAX_PATH + 1];
char IncludePaths[MAXINCPATHS][_MAX_PATH + 1]; static char IncludePaths[MAXINCPATHS][_MAX_PATH + 1];
SLONG NextIncPath = 0; static int32_t NextIncPath;
ULONG nMacroCount; static uint32_t nMacroCount;
char *pCurrentREPTBlock; static char *pCurrentREPTBlock;
ULONG nCurrentREPTBlockSize; static uint32_t nCurrentREPTBlockSize;
ULONG nCurrentREPTBlockCount; static uint32_t nCurrentREPTBlockCount;
ULONG ulMacroReturnValue; uint32_t ulMacroReturnValue;
extern char *tzObjectname;
extern FILE *dependfile;
/* /*
* defines for nCurrentStatus * defines for nCurrentStatus
@@ -50,8 +54,7 @@ extern FILE *dependfile;
/* /*
* Context push and pop * Context push and pop
*/ */
void static void pushcontext(void)
pushcontext(void)
{ {
struct sContext **ppFileStack; struct sContext **ppFileStack;
@@ -59,36 +62,37 @@ pushcontext(void)
while (*ppFileStack) while (*ppFileStack)
ppFileStack = &((*ppFileStack)->pNext); ppFileStack = &((*ppFileStack)->pNext);
if ((*ppFileStack = malloc(sizeof(struct sContext))) != NULL) { *ppFileStack = malloc(sizeof(struct sContext));
(*ppFileStack)->FlexHandle = CurrentFlexHandle;
(*ppFileStack)->pNext = NULL; if (*ppFileStack == NULL)
strcpy((char *) (*ppFileStack)->tzFileName,
(char *) tzCurrentFileName);
(*ppFileStack)->nLine = nLineNo;
switch ((*ppFileStack)->nStatus = nCurrentStatus) {
case STAT_isMacroArg:
case STAT_isMacro:
sym_SaveCurrentMacroArgs((*ppFileStack)->tzMacroArgs);
(*ppFileStack)->pMacro = pCurrentMacro;
break;
case STAT_isInclude:
(*ppFileStack)->pFile = pCurrentFile;
break;
case STAT_isREPTBlock:
sym_SaveCurrentMacroArgs((*ppFileStack)->tzMacroArgs);
(*ppFileStack)->pREPTBlock = pCurrentREPTBlock;
(*ppFileStack)->nREPTBlockSize = nCurrentREPTBlockSize;
(*ppFileStack)->nREPTBlockCount =
nCurrentREPTBlockCount;
break;
}
nLineNo = 0;
} else
fatalerror("No memory for context"); fatalerror("No memory for context");
(*ppFileStack)->FlexHandle = CurrentFlexHandle;
(*ppFileStack)->pNext = NULL;
strcpy((char *)(*ppFileStack)->tzFileName, (char *)tzCurrentFileName);
(*ppFileStack)->nLine = nLineNo;
switch ((*ppFileStack)->nStatus = nCurrentStatus) {
case STAT_isMacroArg:
case STAT_isMacro:
sym_SaveCurrentMacroArgs((*ppFileStack)->tzMacroArgs);
(*ppFileStack)->pMacro = pCurrentMacro;
break;
case STAT_isInclude:
(*ppFileStack)->pFile = pCurrentFile;
break;
case STAT_isREPTBlock:
sym_SaveCurrentMacroArgs((*ppFileStack)->tzMacroArgs);
(*ppFileStack)->pREPTBlock = pCurrentREPTBlock;
(*ppFileStack)->nREPTBlockSize = nCurrentREPTBlockSize;
(*ppFileStack)->nREPTBlockCount = nCurrentREPTBlockCount;
break;
}
nLineNo = 0;
} }
int static int32_t popcontext(void)
popcontext(void)
{ {
struct sContext *pLastFile, **ppLastFile; struct sContext *pLastFile, **ppLastFile;
@@ -96,63 +100,67 @@ popcontext(void)
if (--nCurrentREPTBlockCount) { if (--nCurrentREPTBlockCount) {
yy_delete_buffer(CurrentFlexHandle); yy_delete_buffer(CurrentFlexHandle);
CurrentFlexHandle = CurrentFlexHandle =
yy_scan_bytes(pCurrentREPTBlock, yy_scan_bytes(pCurrentREPTBlock,
nCurrentREPTBlockSize); nCurrentREPTBlockSize);
yy_switch_to_buffer(CurrentFlexHandle); yy_switch_to_buffer(CurrentFlexHandle);
sym_UseCurrentMacroArgs(); sym_UseCurrentMacroArgs();
sym_SetMacroArgID(nMacroCount++); sym_SetMacroArgID(nMacroCount++);
sym_UseNewMacroArgs(); sym_UseNewMacroArgs();
return (0); return 0;
} }
} }
if ((pLastFile = pFileStack) != NULL) {
ppLastFile = &pFileStack;
while (pLastFile->pNext) {
ppLastFile = &(pLastFile->pNext);
pLastFile = *ppLastFile;
}
yy_delete_buffer(CurrentFlexHandle); pLastFile = pFileStack;
nLineNo = pLastFile->nLine; if (pLastFile == NULL)
if (nCurrentStatus == STAT_isInclude) return 1;
fclose(pCurrentFile);
if (nCurrentStatus == STAT_isMacro) {
sym_FreeCurrentMacroArgs();
nLineNo += 1;
}
if (nCurrentStatus == STAT_isREPTBlock)
nLineNo += 1;
CurrentFlexHandle = pLastFile->FlexHandle; ppLastFile = &pFileStack;
strcpy((char *) tzCurrentFileName, while (pLastFile->pNext) {
(char *) pLastFile->tzFileName); ppLastFile = &(pLastFile->pNext);
switch (nCurrentStatus = pLastFile->nStatus) { pLastFile = *ppLastFile;
case STAT_isMacroArg: }
case STAT_isMacro:
sym_RestoreCurrentMacroArgs(pLastFile->tzMacroArgs);
pCurrentMacro = pLastFile->pMacro;
break;
case STAT_isInclude:
pCurrentFile = pLastFile->pFile;
break;
case STAT_isREPTBlock:
sym_RestoreCurrentMacroArgs(pLastFile->tzMacroArgs);
pCurrentREPTBlock = pLastFile->pREPTBlock;
nCurrentREPTBlockSize = pLastFile->nREPTBlockSize;
nCurrentREPTBlockCount = pLastFile->nREPTBlockCount;
break;
}
free(*ppLastFile); yy_delete_buffer(CurrentFlexHandle);
*ppLastFile = NULL; nLineNo = pLastFile->nLine;
yy_switch_to_buffer(CurrentFlexHandle);
return (0); if (nCurrentStatus == STAT_isInclude)
} else fclose(pCurrentFile);
return (1);
if (nCurrentStatus == STAT_isMacro) {
sym_FreeCurrentMacroArgs();
nLineNo += 1;
}
if (nCurrentStatus == STAT_isREPTBlock)
nLineNo += 1;
CurrentFlexHandle = pLastFile->FlexHandle;
strcpy((char *)tzCurrentFileName, (char *)pLastFile->tzFileName);
switch (nCurrentStatus = pLastFile->nStatus) {
case STAT_isMacroArg:
case STAT_isMacro:
sym_RestoreCurrentMacroArgs(pLastFile->tzMacroArgs);
pCurrentMacro = pLastFile->pMacro;
break;
case STAT_isInclude:
pCurrentFile = pLastFile->pFile;
break;
case STAT_isREPTBlock:
sym_RestoreCurrentMacroArgs(pLastFile->tzMacroArgs);
pCurrentREPTBlock = pLastFile->pREPTBlock;
nCurrentREPTBlockSize = pLastFile->nREPTBlockSize;
nCurrentREPTBlockCount = pLastFile->nREPTBlockCount;
break;
}
free(*ppLastFile);
*ppLastFile = NULL;
yy_switch_to_buffer(CurrentFlexHandle);
return 0;
} }
int int32_t fstk_GetLine(void)
fstk_GetLine(void)
{ {
struct sContext *pLastFile, **ppLastFile; struct sContext *pLastFile, **ppLastFile;
@@ -168,7 +176,9 @@ fstk_GetLine(void)
break; /* Peek top file of the stack */ break; /* Peek top file of the stack */
} }
if ((pLastFile = pFileStack) != NULL) { pLastFile = pFileStack;
if (pLastFile != NULL) {
ppLastFile = &pFileStack; ppLastFile = &pFileStack;
while (pLastFile->pNext) { while (pLastFile->pNext) {
ppLastFile = &(pLastFile->pNext); ppLastFile = &(pLastFile->pNext);
@@ -177,79 +187,86 @@ fstk_GetLine(void)
return pLastFile->nLine; 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. */ * This is only reached if the lexer is in REPT or MACRO mode but there
fatalerror("fstk_GetLine: Internal error."); * are no saved contexts with the origin of said REPT or MACRO.
*/
fatalerror("%s: Internal error.", __func__);
} }
int int yywrap(void)
yywrap(void)
{ {
return (popcontext()); return popcontext();
} }
/* /*
* Dump the context stack to stderr * Dump the context stack to stderr
*/ */
void void fstk_Dump(void)
fstk_Dump(void)
{ {
struct sContext *pLastFile; const struct sContext *pLastFile;
pLastFile = pFileStack; pLastFile = pFileStack;
while (pLastFile) { while (pLastFile) {
fprintf(stderr, "%s(%ld) -> ", pLastFile->tzFileName, fprintf(stderr, "%s(%d) -> ", pLastFile->tzFileName,
pLastFile->nLine); pLastFile->nLine);
pLastFile = pLastFile->pNext; pLastFile = pLastFile->pNext;
} }
fprintf(stderr, "%s(%ld)", tzCurrentFileName, nLineNo); fprintf(stderr, "%s(%d)", tzCurrentFileName, nLineNo);
} }
/* /*
* Extra includepath stuff * Extra includepath stuff
*/ */
void void fstk_AddIncludePath(char *s)
fstk_AddIncludePath(char *s)
{ {
if (NextIncPath == MAXINCPATHS) { if (NextIncPath == MAXINCPATHS)
fatalerror("Too many include directories passed from command line"); fatalerror("Too many include directories passed from command line");
return;
}
if (strlcpy(IncludePaths[NextIncPath++], s, _MAX_PATH) >= _MAX_PATH) { if (snprintf(IncludePaths[NextIncPath++], _MAX_PATH, "%s", s) >= _MAX_PATH)
fatalerror("Include path too long '%s'",s); fatalerror("Include path too long '%s'", s);
return;
}
} }
FILE * FILE *fstk_FindFile(char *fname)
fstk_FindFile(char *fname)
{ {
char path[PATH_MAX]; char path[_MAX_PATH];
int i; int32_t i;
FILE *f; FILE *f;
if ((f = fopen(fname, "rb")) != NULL || errno != ENOENT) { if (fname == NULL)
if (dependfile) { return NULL;
f = fopen(fname, "rb");
if (f != NULL || errno != ENOENT) {
if (dependfile)
fprintf(dependfile, "%s: %s\n", tzObjectname, fname); fprintf(dependfile, "%s: %s\n", tzObjectname, fname);
}
return f; return f;
} }
for (i = 0; i < NextIncPath; ++i) { for (i = 0; i < NextIncPath; ++i) {
if (strlcpy(path, IncludePaths[i], sizeof path) >= /*
sizeof path) { * The function snprintf() does not write more than `size` bytes
* (including the terminating null byte ('\0')). If the output
* was truncated due to this limit, the return value is the
* number of characters (excluding the terminating null byte)
* which would have been written to the final string if enough
* space had been available. Thus, a return value of `size` or
* more means that the output was truncated.
*/
if (snprintf(path, sizeof(path), "%s%s", IncludePaths[i], fname)
>= sizeof(path))
continue; continue;
}
if (strlcat(path, fname, sizeof path) >= sizeof path) {
continue;
}
if ((f = fopen(path, "rb")) != NULL || errno != ENOENT) { f = fopen(path, "rb");
if (f != NULL || errno != ENOENT) {
if (dependfile) { if (dependfile) {
fprintf(dependfile, "%s: %s\n", tzObjectname, path); fprintf(dependfile, "%s: %s\n", tzObjectname,
path);
} }
return f; return f;
} }
@@ -262,17 +279,12 @@ fstk_FindFile(char *fname)
/* /*
* Set up an include file for parsing * Set up an include file for parsing
*/ */
void void fstk_RunInclude(char *tzFileName)
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(); pushcontext();
nLineNo = 1; nLineNo = 1;
@@ -282,7 +294,7 @@ fstk_RunInclude(char *tzFileName)
CurrentFlexHandle = yy_create_buffer(pCurrentFile); CurrentFlexHandle = yy_create_buffer(pCurrentFile);
yy_switch_to_buffer(CurrentFlexHandle); 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'); yyunput('\n');
nLineNo -= 1; nLineNo -= 1;
@@ -291,35 +303,35 @@ fstk_RunInclude(char *tzFileName)
/* /*
* Set up a macro for parsing * Set up a macro for parsing
*/ */
ULONG uint32_t fstk_RunMacro(char *s)
fstk_RunMacro(char *s)
{ {
struct sSymbol *sym; struct sSymbol *sym = sym_FindMacro(s);
if ((sym = sym_FindMacro(s)) != NULL) { if (sym == NULL)
pushcontext(); return 0;
sym_SetMacroArgID(nMacroCount++);
nLineNo = -1; pushcontext();
sym_UseNewMacroArgs(); sym_SetMacroArgID(nMacroCount++);
nCurrentStatus = STAT_isMacro; nLineNo = -1;
strcpy(tzCurrentFileName, s); sym_UseNewMacroArgs();
if (sym->pMacro == NULL) nCurrentStatus = STAT_isMacro;
return 0; strcpy(tzCurrentFileName, s);
pCurrentMacro = sym;
CurrentFlexHandle = if (sym->pMacro == NULL)
yy_scan_bytes(pCurrentMacro->pMacro, return 0;
strlen(pCurrentMacro->pMacro));
yy_switch_to_buffer(CurrentFlexHandle); pCurrentMacro = sym;
return (1); CurrentFlexHandle = yy_scan_bytes(pCurrentMacro->pMacro,
} else strlen(pCurrentMacro->pMacro));
return (0); yy_switch_to_buffer(CurrentFlexHandle);
return 1;
} }
/* /*
* Set up a macroargument for parsing * Set up a macroargument for parsing
*/ */
void void fstk_RunMacroArg(int32_t s)
fstk_RunMacroArg(SLONG s)
{ {
char *sym; char *sym;
@@ -328,40 +340,41 @@ fstk_RunMacroArg(SLONG s)
else else
s -= '0'; s -= '0';
if ((sym = sym_FindMacroArg(s)) != NULL) { sym = sym_FindMacroArg(s);
pushcontext();
nCurrentStatus = STAT_isMacroArg; if (sym == NULL)
sprintf(tzCurrentFileName, "%c", (UBYTE) s);
CurrentFlexHandle = yy_scan_bytes(sym, strlen(sym));
yy_switch_to_buffer(CurrentFlexHandle);
} else
fatalerror("No such macroargument"); fatalerror("No such macroargument");
pushcontext();
nCurrentStatus = STAT_isMacroArg;
snprintf(tzCurrentFileName, _MAX_PATH + 1, "%c", (uint8_t)s);
CurrentFlexHandle = yy_scan_bytes(sym, strlen(sym));
yy_switch_to_buffer(CurrentFlexHandle);
} }
/* /*
* Set up a stringequate for parsing * Set up a stringequate for parsing
*/ */
void void fstk_RunString(char *s)
fstk_RunString(char *s)
{ {
struct sSymbol *pSym; const struct sSymbol *pSym = sym_FindSymbol(s);
if ((pSym = sym_FindSymbol(s)) != NULL) { if (pSym != NULL) {
pushcontext(); pushcontext();
nCurrentStatus = STAT_isMacroArg; nCurrentStatus = STAT_isMacroArg;
strcpy(tzCurrentFileName, s); strcpy(tzCurrentFileName, s);
CurrentFlexHandle = CurrentFlexHandle =
yy_scan_bytes(pSym->pMacro, strlen(pSym->pMacro)); yy_scan_bytes(pSym->pMacro, strlen(pSym->pMacro));
yy_switch_to_buffer(CurrentFlexHandle); yy_switch_to_buffer(CurrentFlexHandle);
} else } else {
yyerror("No such string symbol '%s'", s); yyerror("No such string symbol '%s'", s);
}
} }
/* /*
* Set up a repeat block for parsing * Set up a repeat block for parsing
*/ */
void void fstk_RunRept(uint32_t count)
fstk_RunRept(ULONG count)
{ {
if (count) { if (count) {
pushcontext(); pushcontext();
@@ -373,7 +386,7 @@ fstk_RunRept(ULONG count)
nCurrentREPTBlockSize = ulNewMacroSize; nCurrentREPTBlockSize = ulNewMacroSize;
pCurrentREPTBlock = tzNewMacro; pCurrentREPTBlock = tzNewMacro;
CurrentFlexHandle = CurrentFlexHandle =
yy_scan_bytes(pCurrentREPTBlock, nCurrentREPTBlockSize); yy_scan_bytes(pCurrentREPTBlock, nCurrentREPTBlockSize);
yy_switch_to_buffer(CurrentFlexHandle); yy_switch_to_buffer(CurrentFlexHandle);
} }
} }
@@ -381,25 +394,23 @@ fstk_RunRept(ULONG count)
/* /*
* Initialize the filestack routines * Initialize the filestack routines
*/ */
void void fstk_Init(char *s)
fstk_Init(char *s)
{ {
char tzFileName[_MAX_PATH + 1]; char tzFileName[_MAX_PATH + 1];
char tzSymFileName[_MAX_PATH + 1 + 2]; char tzSymFileName[_MAX_PATH + 1 + 2];
snprintf(tzSymFileName, sizeof(tzSymFileName), "\"%s\"", s); snprintf(tzSymFileName, sizeof(tzSymFileName), "\"%s\"", s);
sym_AddString("__FILE__", tzSymFileName); sym_AddString("__FILE__", tzSymFileName);
strcpy(tzFileName, s); strcpy(tzFileName, s);
pFileStack = NULL; pFileStack = NULL;
pCurrentFile = fopen(tzFileName, "rb"); pCurrentFile = fopen(tzFileName, "rb");
if (pCurrentFile == NULL) { if (pCurrentFile == NULL)
err(1, "Unable to open file '%s'", tzFileName); err(1, "Unable to open file '%s'", tzFileName);
}
nMacroCount = 0; nMacroCount = 0;
nCurrentStatus = STAT_isInclude; nCurrentStatus = STAT_isInclude;
strcpy(tzCurrentFileName, tzFileName); snprintf(tzCurrentFileName, _MAX_PATH + 1, "%s", tzFileName);
CurrentFlexHandle = yy_create_buffer(pCurrentFile); CurrentFlexHandle = yy_create_buffer(pCurrentFile);
yy_switch_to_buffer(CurrentFlexHandle); yy_switch_to_buffer(CurrentFlexHandle);
nLineNo = 1; nLineNo = 1;

View File

@@ -1,52 +1,56 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "asm/asm.h" #include "asm/asm.h"
#include "asm/symbol.h" #include "asm/lexer.h"
#include "asm/main.h"
#include "asm/rpn.h" #include "asm/rpn.h"
#include "asm/symbol.h" #include "asm/symbol.h"
#include "asm/main.h" #include "asm/symbol.h"
#include "asm/lexer.h"
#include "asmy.h" #include "asmy.h"
#include <stdbool.h> bool oDontExpandStrings;
#include <stdio.h> int32_t nGBGfxID = -1;
#include <stdlib.h> int32_t nBinaryID = -1;
#include <math.h>
#include <string.h>
bool oDontExpandStrings = false; static int32_t gbgfx2bin(char ch)
SLONG nGBGfxID = -1;
SLONG nBinaryID = -1;
SLONG
gbgfx2bin(char ch)
{ {
SLONG i; int32_t i;
for (i = 0; i <= 3; i += 1) { for (i = 0; i <= 3; i += 1) {
if (CurrentOptions.gbgfx[i] == ch) { if (CurrentOptions.gbgfx[i] == ch)
return (i); return i;
}
} }
return (0); return 0;
} }
SLONG static int32_t binary2bin(char ch)
binary2bin(char ch)
{ {
SLONG i; int32_t i;
for (i = 0; i <= 1; i += 1) { for (i = 0; i <= 1; i += 1) {
if (CurrentOptions.binary[i] == ch) { if (CurrentOptions.binary[i] == ch)
return (i); return i;
}
} }
return (0); return 0;
} }
SLONG static int32_t char2bin(char ch)
char2bin(char ch)
{ {
if (ch >= 'a' && ch <= 'f') if (ch >= 'a' && ch <= 'f')
return (ch - 'a' + 10); return (ch - 'a' + 10);
@@ -57,16 +61,15 @@ char2bin(char ch)
if (ch >= '0' && ch <= '9') if (ch >= '0' && ch <= '9')
return (ch - '0'); return (ch - '0');
return (0); return 0;
} }
typedef SLONG(*x2bin) (char ch); typedef int32_t(*x2bin) (char ch);
SLONG static int32_t ascii2bin(char *s)
ascii2bin(char *s)
{ {
SLONG radix = 10; int32_t radix = 10;
SLONG result = 0; int32_t result = 0;
x2bin convertfunc = char2bin; x2bin convertfunc = char2bin;
switch (*s) { switch (*s) {
@@ -93,7 +96,7 @@ ascii2bin(char *s)
} }
if (radix == 4) { if (radix == 4) {
SLONG c; int32_t c;
while (*s != '\0') { while (*s != '\0') {
c = convertfunc(*s++); c = convertfunc(*s++);
@@ -104,37 +107,31 @@ ascii2bin(char *s)
result = result * radix + convertfunc(*s++); result = result * radix + convertfunc(*s++);
} }
return (result); return result;
} }
ULONG uint32_t ParseFixedPoint(char *s, uint32_t size)
ParseFixedPoint(char *s, ULONG size)
{ {
//char dest[256]; uint32_t i = 0, dot = 0;
ULONG i = 0, dot = 0;
while (size && dot != 2) { while (size && dot != 2) {
if (s[i] == '.') if (s[i] == '.')
dot += 1; dot += 1;
if (dot < 2) { if (dot < 2) {
//dest[i] = s[i];
size -= 1; size -= 1;
i += 1; i += 1;
} }
} }
//dest[i] = 0;
yyunputbytes(size); yyunputbytes(size);
yylval.nConstValue = (SLONG) (atof(s) * 65536); yylval.nConstValue = (int32_t)(atof(s) * 65536);
return (1); return 1;
} }
ULONG uint32_t ParseNumber(char *s, uint32_t size)
ParseNumber(char *s, ULONG size)
{ {
char dest[256]; char dest[256];
@@ -142,14 +139,13 @@ ParseNumber(char *s, ULONG size)
dest[size] = 0; dest[size] = 0;
yylval.nConstValue = ascii2bin(dest); yylval.nConstValue = ascii2bin(dest);
return (1); return 1;
} }
ULONG uint32_t ParseSymbol(char *src, uint32_t size)
ParseSymbol(char *src, ULONG size)
{ {
char dest[MAXSYMLEN + 1]; char dest[MAXSYMLEN + 1];
int copied = 0, size_backup = size; int32_t copied = 0, size_backup = size;
while (size && copied < MAXSYMLEN) { while (size && copied < MAXSYMLEN) {
if (*src == '\\') { if (*src == '\\') {
@@ -158,13 +154,13 @@ ParseSymbol(char *src, ULONG size)
src += 1; src += 1;
size -= 1; size -= 1;
if (*src == '@') if (*src == '@') {
marg = sym_FindMacroArg(-1); marg = sym_FindMacroArg(-1);
else if (*src >= '0' && *src <= '9') } else if (*src >= '0' && *src <= '9') {
marg = sym_FindMacroArg(*src - '0'); marg = sym_FindMacroArg(*src - '0');
else { } else {
fatalerror("Malformed ID"); fatalerror("Malformed ID");
return (0); return 0;
} }
src += 1; src += 1;
@@ -192,47 +188,48 @@ ParseSymbol(char *src, ULONG size)
yyunputstr(s = sym_GetStringValue(dest)); yyunputstr(s = sym_GetStringValue(dest));
while (*s) { while (*s) {
if (*s++ == '\n') { if (*s++ == '\n')
nLineNo -= 1; nLineNo -= 1;
}
} }
return (0); return 0;
} else {
strcpy(yylval.tzString, dest);
return (1);
} }
strcpy(yylval.tzString, dest);
return 1;
} }
ULONG uint32_t PutMacroArg(char *src, uint32_t size)
PutMacroArg(char *src, ULONG size)
{ {
char *s; char *s;
yyskipbytes(size); yyskipbytes(size);
if ((size == 2 && src[1] >= '1' && src[1] <= '9')) { 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); yyunputstr(s);
} else { else
yyerror("Macro argument not defined"); yyerror("Macro argument not defined");
}
} else { } else {
yyerror("Invalid macro argument"); yyerror("Invalid macro argument");
} }
return (0); return 0;
} }
ULONG uint32_t PutUniqueArg(char *src, uint32_t size)
PutUniqueArg(char *src, ULONG size)
{ {
char *s; char *s;
yyskipbytes(size); yyskipbytes(size);
if ((s = sym_FindMacroArg(-1)) != NULL) {
s = sym_FindMacroArg(-1);
if (s != NULL)
yyunputstr(s); yyunputstr(s);
} else { else
yyerror("Macro unique label string not defined"); yyerror("Macro unique label string not defined");
}
return (0); return 0;
} }
enum { enum {
@@ -240,9 +237,85 @@ enum {
T_LEX_MACROUNIQUE 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_LOGICOR},
{"&&", T_OP_LOGICAND}, {"&&", T_OP_LOGICAND},
{"==", T_OP_LOGICEQU}, {"==", T_OP_LOGICEQU},
@@ -295,6 +368,7 @@ struct sLexInitString staticstrings[] = {
{"include", T_POP_INCLUDE}, {"include", T_POP_INCLUDE},
{"printt", T_POP_PRINTT}, {"printt", T_POP_PRINTT},
{"printi", T_POP_PRINTI},
{"printv", T_POP_PRINTV}, {"printv", T_POP_PRINTV},
{"printf", T_POP_PRINTF}, {"printf", T_POP_PRINTF},
{"export", T_POP_EXPORT}, {"export", T_POP_EXPORT},
@@ -303,8 +377,9 @@ struct sLexInitString staticstrings[] = {
{"xref", T_POP_IMPORT}, {"xref", T_POP_IMPORT},
{"global", T_POP_GLOBAL}, {"global", T_POP_GLOBAL},
{"ds", T_POP_DS}, {"ds", T_POP_DS},
{NAME_DB, T_POP_DB}, {"db", T_POP_DB},
{NAME_DW, T_POP_DW}, {"dw", T_POP_DW},
{"dl", T_POP_DL},
{"section", T_POP_SECTION}, {"section", T_POP_SECTION},
{"purge", T_POP_PURGE}, {"purge", T_POP_PURGE},
@@ -318,7 +393,6 @@ struct sLexInitString staticstrings[] = {
{"warn", T_POP_WARN}, {"warn", T_POP_WARN},
{"macro", T_POP_MACRO}, {"macro", T_POP_MACRO},
/* Not needed but we have it here just to protect the name */ /* Not needed but we have it here just to protect the name */
{"endm", T_POP_ENDM}, {"endm", T_POP_ENDM},
{"shift", T_POP_SHIFT}, {"shift", T_POP_SHIFT},
@@ -351,12 +425,13 @@ struct sLexInitString staticstrings[] = {
{"data", T_SECT_DATA}, {"data", T_SECT_DATA},
{"bss", T_SECT_BSS}, {"bss", T_SECT_BSS},
{NAME_RB, T_POP_RB}, {"rb", T_POP_RB},
{NAME_RW, T_POP_RW}, {"rw", T_POP_RW},
{"equ", T_POP_EQU}, {"equ", T_POP_EQU},
{"equs", T_POP_EQUS}, {"equs", T_POP_EQUS},
{"set", T_POP_SET}, /* Handled before in list of CPU instructions */
/* {"set", T_POP_SET}, */
{"=", T_POP_SET}, {"=", T_POP_SET},
{"pushs", T_POP_PUSHS}, {"pushs", T_POP_PUSHS},
@@ -369,43 +444,41 @@ struct sLexInitString staticstrings[] = {
{NULL, 0} {NULL, 0}
}; };
struct sLexFloat tNumberToken = { const struct sLexFloat tNumberToken = {
ParseNumber, ParseNumber,
T_NUMBER T_NUMBER
}; };
struct sLexFloat tFixedPointToken = { const struct sLexFloat tFixedPointToken = {
ParseFixedPoint, ParseFixedPoint,
T_NUMBER T_NUMBER
}; };
struct sLexFloat tIDToken = { const struct sLexFloat tIDToken = {
ParseSymbol, ParseSymbol,
T_ID T_ID
}; };
struct sLexFloat tMacroArgToken = { const struct sLexFloat tMacroArgToken = {
PutMacroArg, PutMacroArg,
T_LEX_MACROARG T_LEX_MACROARG
}; };
struct sLexFloat tMacroUniqueToken = { const struct sLexFloat tMacroUniqueToken = {
PutUniqueArg, PutUniqueArg,
T_LEX_MACROUNIQUE T_LEX_MACROUNIQUE
}; };
void void setup_lexer(void)
setuplex(void)
{ {
ULONG id; uint32_t id;
lex_Init(); lex_Init();
lex_AddStrings(staticstrings); lex_AddStrings(lexer_strings);
lex_AddStrings(localstrings);
//Macro arguments //Macro arguments
id = lex_FloatAlloc(&tMacroArgToken); id = lex_FloatAlloc(&tMacroArgToken);
lex_FloatAddFirstRange(id, '\\', '\\'); lex_FloatAddFirstRange(id, '\\', '\\');
lex_FloatAddSecondRange(id, '1', '9'); lex_FloatAddSecondRange(id, '1', '9');
id = lex_FloatAlloc(&tMacroUniqueToken); id = lex_FloatAlloc(&tMacroUniqueToken);
@@ -414,43 +487,45 @@ setuplex(void)
//Decimal constants //Decimal constants
id = lex_FloatAlloc(&tNumberToken); id = lex_FloatAlloc(&tNumberToken);
lex_FloatAddFirstRange(id, '0', '9'); lex_FloatAddFirstRange(id, '0', '9');
lex_FloatAddSecondRange(id, '0', '9'); lex_FloatAddSecondRange(id, '0', '9');
lex_FloatAddRange(id, '0', '9'); lex_FloatAddRange(id, '0', '9');
//Binary constants //Binary constants
nBinaryID = id = lex_FloatAlloc(&tNumberToken); id = lex_FloatAlloc(&tNumberToken);
nBinaryID = id;
lex_FloatAddFirstRange(id, '%', '%'); lex_FloatAddFirstRange(id, '%', '%');
lex_FloatAddSecondRange(id, CurrentOptions.binary[0], lex_FloatAddSecondRange(id, CurrentOptions.binary[0],
CurrentOptions.binary[0]); CurrentOptions.binary[0]);
lex_FloatAddSecondRange(id, CurrentOptions.binary[1], lex_FloatAddSecondRange(id, CurrentOptions.binary[1],
CurrentOptions.binary[1]); CurrentOptions.binary[1]);
lex_FloatAddRange(id, CurrentOptions.binary[0], lex_FloatAddRange(id, CurrentOptions.binary[0],
CurrentOptions.binary[0]); CurrentOptions.binary[0]);
lex_FloatAddRange(id, CurrentOptions.binary[1], lex_FloatAddRange(id, CurrentOptions.binary[1],
CurrentOptions.binary[1]); CurrentOptions.binary[1]);
//Octal constants //Octal constants
id = lex_FloatAlloc(&tNumberToken); id = lex_FloatAlloc(&tNumberToken);
lex_FloatAddFirstRange(id, '&', '&'); lex_FloatAddFirstRange(id, '&', '&');
lex_FloatAddSecondRange(id, '0', '7'); lex_FloatAddSecondRange(id, '0', '7');
lex_FloatAddRange(id, '0', '7'); lex_FloatAddRange(id, '0', '7');
//Gameboy gfx constants //Gameboy gfx constants
nGBGfxID = id = lex_FloatAlloc(&tNumberToken); id = lex_FloatAlloc(&tNumberToken);
nGBGfxID = id;
lex_FloatAddFirstRange(id, '`', '`'); lex_FloatAddFirstRange(id, '`', '`');
lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[0], lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[0],
CurrentOptions.gbgfx[0]); CurrentOptions.gbgfx[0]);
lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[1], lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[1],
CurrentOptions.gbgfx[1]); CurrentOptions.gbgfx[1]);
lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[2], lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[2],
CurrentOptions.gbgfx[2]); CurrentOptions.gbgfx[2]);
lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[3], lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[3],
CurrentOptions.gbgfx[3]); CurrentOptions.gbgfx[3]);
lex_FloatAddRange(id, CurrentOptions.gbgfx[0], CurrentOptions.gbgfx[0]); lex_FloatAddRange(id, CurrentOptions.gbgfx[0], CurrentOptions.gbgfx[0]);
lex_FloatAddRange(id, CurrentOptions.gbgfx[1], CurrentOptions.gbgfx[1]); lex_FloatAddRange(id, CurrentOptions.gbgfx[1], CurrentOptions.gbgfx[1]);
lex_FloatAddRange(id, CurrentOptions.gbgfx[2], CurrentOptions.gbgfx[2]); lex_FloatAddRange(id, CurrentOptions.gbgfx[2], CurrentOptions.gbgfx[2]);
@@ -458,7 +533,7 @@ setuplex(void)
//Hex constants //Hex constants
id = lex_FloatAlloc(&tNumberToken); id = lex_FloatAlloc(&tNumberToken);
lex_FloatAddFirstRange(id, '$', '$'); lex_FloatAddFirstRange(id, '$', '$');
lex_FloatAddSecondRange(id, '0', '9'); lex_FloatAddSecondRange(id, '0', '9');
lex_FloatAddSecondRange(id, 'A', 'F'); lex_FloatAddSecondRange(id, 'A', 'F');
@@ -469,7 +544,7 @@ setuplex(void)
//ID 's //ID 's
id = lex_FloatAlloc(&tIDToken); id = lex_FloatAlloc(&tIDToken);
lex_FloatAddFirstRange(id, 'a', 'z'); lex_FloatAddFirstRange(id, 'a', 'z');
lex_FloatAddFirstRange(id, 'A', 'Z'); lex_FloatAddFirstRange(id, 'A', 'Z');
lex_FloatAddFirstRange(id, '_', '_'); lex_FloatAddFirstRange(id, '_', '_');
@@ -491,7 +566,7 @@ setuplex(void)
//Local ID //Local ID
id = lex_FloatAlloc(&tIDToken); id = lex_FloatAlloc(&tIDToken);
lex_FloatAddFirstRange(id, '.', '.'); lex_FloatAddFirstRange(id, '.', '.');
lex_FloatAddSecondRange(id, 'a', 'z'); lex_FloatAddSecondRange(id, 'a', 'z');
lex_FloatAddSecondRange(id, 'A', 'Z'); lex_FloatAddSecondRange(id, 'A', 'Z');
@@ -506,17 +581,16 @@ setuplex(void)
//@ID //@ID
id = lex_FloatAlloc(&tIDToken); id = lex_FloatAlloc(&tIDToken);
lex_FloatAddFirstRange(id, '@', '@'); lex_FloatAddFirstRange(id, '@', '@');
//Fixed point constants //Fixed point constants
id = lex_FloatAlloc(&tFixedPointToken); id = lex_FloatAlloc(&tFixedPointToken);
lex_FloatAddFirstRange(id, '.', '.'); lex_FloatAddFirstRange(id, '.', '.');
lex_FloatAddFirstRange(id, '0', '9'); lex_FloatAddFirstRange(id, '0', '9');
lex_FloatAddSecondRange(id, '.', '.'); lex_FloatAddSecondRange(id, '.', '.');
lex_FloatAddSecondRange(id, '0', '9'); lex_FloatAddSecondRange(id, '0', '9');
lex_FloatAddRange(id, '.', '.'); lex_FloatAddRange(id, '.', '.');
lex_FloatAddRange(id, '0', '9'); lex_FloatAddRange(id, '0', '9');
} }

View File

@@ -1,46 +1,53 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <ctype.h> #include <ctype.h>
#include "asm/asm.h" #include "asm/asm.h"
#include "asm/fstack.h"
#include "asm/lexer.h" #include "asm/lexer.h"
#include "types.h"
#include "asm/main.h" #include "asm/main.h"
#include "asm/rpn.h" #include "asm/rpn.h"
#include "asm/fstack.h"
#include "extern/err.h" #include "extern/err.h"
#include "asmy.h" #include "asmy.h"
struct sLexString { struct sLexString {
char *tzName; char *tzName;
ULONG nToken; uint32_t nToken;
ULONG nNameLength; uint32_t nNameLength;
struct sLexString *pNext; struct sLexString *pNext;
}; };
#define pLexBufferRealStart (pCurrentBuffer->pBufferRealStart)
#define pLexBuffer (pCurrentBuffer->pBuffer)
#define AtLineStart (pCurrentBuffer->oAtLineStart)
#define SAFETYMARGIN 1024 #define pLexBufferRealStart (pCurrentBuffer->pBufferRealStart)
#define pLexBuffer (pCurrentBuffer->pBuffer)
#define AtLineStart (pCurrentBuffer->oAtLineStart)
extern size_t symvaluetostring(char *dest, size_t maxLength, char *sym); #define SAFETYMARGIN 1024
struct sLexFloat tLexFloat[32]; struct sLexFloat tLexFloat[32];
struct sLexString *tLexHash[LEXHASHSIZE]; struct sLexString *tLexHash[LEXHASHSIZE];
YY_BUFFER_STATE pCurrentBuffer; 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]; uint32_t tFloatingSecondChar[256];
ULONG tFloatingFirstChar[256]; uint32_t tFloatingFirstChar[256];
ULONG tFloatingChars[256]; uint32_t tFloatingChars[256];
ULONG nFloating; uint32_t nFloating;
enum eLexerState lexerstate = LEX_STATE_NORMAL; enum eLexerState lexerstate = LEX_STATE_NORMAL;
void void upperstring(char *s)
upperstring(char *s)
{ {
while (*s) { while (*s) {
*s = toupper(*s); *s = toupper(*s);
@@ -48,8 +55,7 @@ upperstring(char *s)
} }
} }
void void lowerstring(char *s)
lowerstring(char *s)
{ {
while (*s) { while (*s) {
*s = tolower(*s); *s = tolower(*s);
@@ -57,20 +63,17 @@ lowerstring(char *s)
} }
} }
void void yyskipbytes(uint32_t count)
yyskipbytes(ULONG count)
{ {
pLexBuffer += count; pLexBuffer += count;
} }
void void yyunputbytes(uint32_t count)
yyunputbytes(ULONG count)
{ {
pLexBuffer -= count; pLexBuffer -= count;
} }
void void yyunput(char c)
yyunput(char c)
{ {
if (pLexBuffer <= pLexBufferRealStart) if (pLexBuffer <= pLexBufferRealStart)
fatalerror("Buffer safety margin exceeded"); fatalerror("Buffer safety margin exceeded");
@@ -78,10 +81,9 @@ yyunput(char c)
*(--pLexBuffer) = c; *(--pLexBuffer) = c;
} }
void void yyunputstr(char *s)
yyunputstr(char *s)
{ {
int i, len; int32_t i, len;
len = strlen(s); len = strlen(s);
@@ -92,114 +94,135 @@ yyunputstr(char *s)
*(--pLexBuffer) = s[i]; *(--pLexBuffer) = s[i];
} }
void void yy_switch_to_buffer(YY_BUFFER_STATE buf)
yy_switch_to_buffer(YY_BUFFER_STATE buf)
{ {
pCurrentBuffer = buf; pCurrentBuffer = buf;
} }
void void yy_set_state(enum eLexerState i)
yy_set_state(enum eLexerState i)
{ {
lexerstate = i; lexerstate = i;
} }
void void yy_delete_buffer(YY_BUFFER_STATE buf)
yy_delete_buffer(YY_BUFFER_STATE buf)
{ {
free(buf->pBufferStart - SAFETYMARGIN); free(buf->pBufferStart - SAFETYMARGIN);
free(buf); free(buf);
} }
YY_BUFFER_STATE YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size)
yy_scan_bytes(char *mem, ULONG size)
{ {
YY_BUFFER_STATE pBuffer; YY_BUFFER_STATE pBuffer = malloc(sizeof(struct yy_buffer_state));
if ((pBuffer = malloc(sizeof(struct yy_buffer_state))) != NULL) { if (pBuffer == NULL)
if ((pBuffer->pBufferRealStart = fatalerror("%s: Out of memory!", __func__);
malloc(size + 1 + SAFETYMARGIN)) != NULL) {
pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN; pBuffer->pBufferRealStart = malloc(size + 1 + SAFETYMARGIN);
pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN;
memcpy(pBuffer->pBuffer, mem, size); if (pBuffer->pBufferRealStart == NULL)
pBuffer->nBufferSize = size; fatalerror("%s: Out of memory for buffer!", __func__);
pBuffer->oAtLineStart = 1;
pBuffer->pBuffer[size] = 0; pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN;
return (pBuffer); pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN;
} memcpy(pBuffer->pBuffer, mem, size);
} pBuffer->nBufferSize = size;
fatalerror("Out of memory!"); pBuffer->oAtLineStart = 1;
return (NULL); pBuffer->pBuffer[size] = 0;
return pBuffer;
} }
YY_BUFFER_STATE YY_BUFFER_STATE yy_create_buffer(FILE *f)
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) { if (pBuffer == NULL)
ULONG size; fatalerror("%s: Out of memory!", __func__);
fseek(f, 0, SEEK_END); uint32_t size;
size = ftell(f);
fseek(f, 0, SEEK_SET);
if ((pBuffer->pBufferRealStart = fseek(f, 0, SEEK_END);
malloc(size + 2 + SAFETYMARGIN)) != NULL) { size = ftell(f);
char *mem; fseek(f, 0, SEEK_SET);
ULONG instring = 0;
pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN; pBuffer->pBufferRealStart = malloc(size + 2 + SAFETYMARGIN);
pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN;
size = fread(pBuffer->pBuffer, sizeof(UBYTE), size, f); if (pBuffer->pBufferRealStart == NULL)
fatalerror("%s: Out of memory for buffer!", __func__);
pBuffer->pBuffer[size] = '\n'; pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN;
pBuffer->pBuffer[size + 1] = 0; pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN;
pBuffer->nBufferSize = size + 1;
mem = pBuffer->pBuffer; size = fread(pBuffer->pBuffer, sizeof(uint8_t), size, f);
while (*mem) { pBuffer->pBuffer[size] = '\n';
if (*mem == '\"') pBuffer->pBuffer[size + 1] = 0;
instring = 1 - instring; pBuffer->nBufferSize = size + 1;
if (mem[0] == '\\' && /* Convert all line endings to LF and spaces */
(mem[1] == '\"' || mem[1] == '\\')) {
mem += 2; char *mem = pBuffer->pBuffer;
} else if (instring) { uint32_t instring = 0;
mem += 1;
} else { while (*mem) {
if ((mem[0] == 10 && mem[1] == 13) if (*mem == '\"')
|| (mem[0] == 13 && mem[1] == 10)) { instring = 1 - instring;
mem[0] = ' ';
mem[1] = '\n'; if ((mem[0] == '\\') && (mem[1] == '\"' || mem[1] == '\\')) {
mem += 2; mem += 2;
} else if (mem[0] == 10 || mem[0] == 13) { } else if (instring) {
mem[0] = '\n'; mem += 1;
mem += 1; } else {
} else if (mem[0] == '\n' && mem[1] == '*') { /* LF CR and CR LF */
mem += 1; if (((mem[0] == 10) && (mem[1] == 13))
while (!(*mem == '\n' || *mem == '\0')) || ((mem[0] == 13) && (mem[1] == 10))) {
*mem++ = ' '; mem[0] = ' ';
} else if (*mem == ';') { mem[1] = '\n';
while (!(*mem == '\n' || *mem == '\0')) mem += 2;
*mem++ = ' '; /* LF and CR */
} else } else if ((mem[0] == 10) || (mem[0] == 13)) {
mem += 1; mem[0] = '\n';
} mem += 1;
} else {
mem += 1;
} }
pBuffer->oAtLineStart = 1;
return (pBuffer);
} }
} }
fatalerror("Out of memory!");
return (NULL); /* Remove comments */
mem = pBuffer->pBuffer;
instring = 0;
while (*mem) {
if (*mem == '\"')
instring = 1 - instring;
if ((mem[0] == '\\') && (mem[1] == '\"' || mem[1] == '\\')) {
mem += 2;
} else if (instring) {
mem += 1;
} else {
/* Comments that start with ; anywhere in a line */
if (*mem == ';') {
while (!((*mem == '\n') || (*mem == '\0')))
*mem++ = ' ';
/* Comments that start with * at the start of a line */
} else if ((mem[0] == '\n') && (mem[1] == '*')) {
mem += 1;
while (!((*mem == '\n') || (*mem == '\0')))
*mem++ = ' ';
} else {
mem += 1;
}
}
}
pBuffer->oAtLineStart = 1;
return pBuffer;
} }
ULONG uint32_t lex_FloatAlloc(const struct sLexFloat *token)
lex_FloatAlloc(struct sLexFloat *token)
{ {
tLexFloat[nFloating] = *token; tLexFloat[nFloating] = *token;
@@ -210,17 +233,15 @@ lex_FloatAlloc(struct sLexFloat *token)
* Make sure that only non-zero ASCII characters are used. Also, check if the * Make sure that only non-zero ASCII characters are used. Also, check if the
* start is greater than the end of the range. * start is greater than the end of the range.
*/ */
void void lex_CheckCharacterRange(uint16_t start, uint16_t end)
lex_CheckCharacterRange(UWORD start, UWORD end)
{ {
if (start > end || start < 1 || end > 127) { if (start > end || start < 1 || end > 127) {
errx(1, "Invalid character range (start: %u, end: %u)", errx(1, "Invalid character range (start: %u, end: %u)",
start, end); start, end);
} }
} }
void void lex_FloatDeleteRange(uint32_t id, uint16_t start, uint16_t end)
lex_FloatDeleteRange(ULONG id, UWORD start, UWORD end)
{ {
lex_CheckCharacterRange(start, end); lex_CheckCharacterRange(start, end);
@@ -230,8 +251,7 @@ lex_FloatDeleteRange(ULONG id, UWORD start, UWORD end)
} }
} }
void void lex_FloatAddRange(uint32_t id, uint16_t start, uint16_t end)
lex_FloatAddRange(ULONG id, UWORD start, UWORD end)
{ {
lex_CheckCharacterRange(start, end); lex_CheckCharacterRange(start, end);
@@ -241,8 +261,7 @@ lex_FloatAddRange(ULONG id, UWORD start, UWORD end)
} }
} }
void void lex_FloatDeleteFirstRange(uint32_t id, uint16_t start, uint16_t end)
lex_FloatDeleteFirstRange(ULONG id, UWORD start, UWORD end)
{ {
lex_CheckCharacterRange(start, end); lex_CheckCharacterRange(start, end);
@@ -252,8 +271,7 @@ lex_FloatDeleteFirstRange(ULONG id, UWORD start, UWORD end)
} }
} }
void void lex_FloatAddFirstRange(uint32_t id, uint16_t start, uint16_t end)
lex_FloatAddFirstRange(ULONG id, UWORD start, UWORD end)
{ {
lex_CheckCharacterRange(start, end); lex_CheckCharacterRange(start, end);
@@ -263,8 +281,7 @@ lex_FloatAddFirstRange(ULONG id, UWORD start, UWORD end)
} }
} }
void void lex_FloatDeleteSecondRange(uint32_t id, uint16_t start, uint16_t end)
lex_FloatDeleteSecondRange(ULONG id, UWORD start, UWORD end)
{ {
lex_CheckCharacterRange(start, end); lex_CheckCharacterRange(start, end);
@@ -274,8 +291,7 @@ lex_FloatDeleteSecondRange(ULONG id, UWORD start, UWORD end)
} }
} }
void void lex_FloatAddSecondRange(uint32_t id, uint16_t start, uint16_t end)
lex_FloatAddSecondRange(ULONG id, UWORD start, UWORD end)
{ {
lex_CheckCharacterRange(start, end); lex_CheckCharacterRange(start, end);
@@ -285,43 +301,37 @@ lex_FloatAddSecondRange(ULONG id, UWORD start, UWORD end)
} }
} }
struct sLexFloat * static struct sLexFloat *lexgetfloat(uint32_t nFloatMask)
lexgetfloat(ULONG nFloatMask)
{ {
if (nFloatMask == 0) { if (nFloatMask == 0)
fatalerror("Internal error in lexgetfloat"); fatalerror("Internal error in %s", __func__);
}
int i = 0; int32_t i = 0;
while ((nFloatMask & 1) == 0) { while ((nFloatMask & 1) == 0) {
nFloatMask >>= 1; nFloatMask >>= 1;
i++; i++;
} }
return (&tLexFloat[i]); return &tLexFloat[i];
} }
ULONG static uint32_t lexcalchash(char *s)
lexcalchash(char *s)
{ {
ULONG hash = 0; uint32_t hash = 0;
while (*s) { while (*s)
hash = (hash * 283) ^ toupper(*s++); hash = (hash * 283) ^ toupper(*s++);
}
return (hash % LEXHASHSIZE); return hash % LEXHASHSIZE;
} }
void void lex_Init(void)
lex_Init(void)
{ {
ULONG i; uint32_t i;
for (i = 0; i < LEXHASHSIZE; i++) { for (i = 0; i < LEXHASHSIZE; i++)
tLexHash[i] = NULL; tLexHash[i] = NULL;
}
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
tFloatingFirstChar[i] = 0; tFloatingFirstChar[i] = 0;
@@ -333,34 +343,33 @@ lex_Init(void)
nFloating = 0; nFloating = 0;
} }
void void lex_AddStrings(const struct sLexInitString *lex)
lex_AddStrings(struct sLexInitString * lex)
{ {
while (lex->tzName) { while (lex->tzName) {
struct sLexString **ppHash; struct sLexString **ppHash;
ULONG hash; uint32_t hash;
ppHash = &tLexHash[hash = lexcalchash(lex->tzName)]; ppHash = &tLexHash[hash = lexcalchash(lex->tzName)];
while (*ppHash) while (*ppHash)
ppHash = &((*ppHash)->pNext); ppHash = &((*ppHash)->pNext);
if (((*ppHash) = malloc(sizeof(struct sLexString))) != NULL) { *ppHash = malloc(sizeof(struct sLexString));
if (((*ppHash)->tzName = if (*ppHash == NULL)
(char *) strdup(lex->tzName)) != NULL) {
(*ppHash)->nNameLength = strlen(lex->tzName);
(*ppHash)->nToken = lex->nToken;
(*ppHash)->pNext = NULL;
upperstring((*ppHash)->tzName);
if ((*ppHash)->nNameLength > nLexMaxLength)
nLexMaxLength = (*ppHash)->nNameLength;
} else
fatalerror("Out of memory!");
} else
fatalerror("Out of memory!"); 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;
upperstring((*ppHash)->tzName);
if ((*ppHash)->nNameLength > nLexMaxLength)
nLexMaxLength = (*ppHash)->nNameLength;
lex += 1; lex += 1;
} }
} }
@@ -375,42 +384,42 @@ lex_AddStrings(struct sLexInitString * lex)
* The token types with the longest match from the current position in the * The token types with the longest match from the current position in the
* buffer will have their bits set in the float mask. * buffer will have their bits set in the float mask.
*/ */
void void yylex_GetFloatMaskAndFloatLen(uint32_t *pnFloatMask, uint32_t *pnFloatLen)
yylex_GetFloatMaskAndFloatLen(ULONG *pnFloatMask, ULONG *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; char *s = pLexBuffer;
ULONG nOldFloatMask = 0; uint32_t nOldFloatMask = 0;
ULONG nFloatMask = tFloatingFirstChar[(int)*s]; uint32_t nFloatMask = tFloatingFirstChar[(int32_t)*s];
if (nFloatMask != 0) { if (nFloatMask != 0) {
s++; s++;
nOldFloatMask = nFloatMask; nOldFloatMask = nFloatMask;
nFloatMask &= tFloatingSecondChar[(int)*s]; nFloatMask &= tFloatingSecondChar[(int32_t)*s];
while (nFloatMask != 0) { while (nFloatMask != 0) {
s++; s++;
nOldFloatMask = nFloatMask; nOldFloatMask = nFloatMask;
nFloatMask &= tFloatingChars[(int)*s]; nFloatMask &= tFloatingChars[(int32_t)*s];
} }
} }
*pnFloatMask = nOldFloatMask; *pnFloatMask = nOldFloatMask;
*pnFloatLen = (ULONG)(s - pLexBuffer); *pnFloatLen = (uint32_t)(s - pLexBuffer);
} }
/* /*
* Gets the longest keyword/operator from the current position in the buffer. * Gets the longest keyword/operator from the current position in the buffer.
*/ */
struct sLexString * struct sLexString *yylex_GetLongestFixed()
yylex_GetLongestFixed()
{ {
struct sLexString *pLongestFixed = NULL; struct sLexString *pLongestFixed = NULL;
char *s = pLexBuffer; char *s = pLexBuffer;
ULONG hash = 0; uint32_t hash = 0;
ULONG length = 0; uint32_t length = 0;
while (length < nLexMaxLength && *s) { while (length < nLexMaxLength && *s) {
hash = (hash * 283) ^ toupper(*s); hash = (hash * 283) ^ toupper(*s);
@@ -432,12 +441,11 @@ yylex_GetLongestFixed()
return pLongestFixed; return pLongestFixed;
} }
size_t size_t CopyMacroArg(char *dest, size_t maxLength, char c)
CopyMacroArg(char *dest, size_t maxLength, char c)
{ {
size_t i; size_t i;
char *s; char *s;
int argNum; int32_t argNum;
switch (c) { switch (c) {
case '1': case '1':
@@ -458,35 +466,33 @@ CopyMacroArg(char *dest, size_t maxLength, char c)
return 0; return 0;
} }
if ((s = sym_FindMacroArg(argNum)) == NULL) s = sym_FindMacroArg(argNum);
if (s == NULL)
fatalerror("Macro argument not defined"); fatalerror("Macro argument not defined");
for (i = 0; s[i] != 0; i++) { for (i = 0; s[i] != 0; i++) {
if (i >= maxLength) { if (i >= maxLength)
fatalerror("Macro argument too long to fit buffer"); fatalerror("Macro argument too long to fit buffer");
}
dest[i] = s[i]; dest[i] = s[i];
} }
return i; return i;
} }
static inline void static inline void yylex_StringWriteChar(char *s, size_t index, char c)
yylex_StringWriteChar(char *s, size_t index, char c)
{ {
if (index >= MAXSTRLEN) { if (index >= MAXSTRLEN)
fatalerror("String too long"); fatalerror("String too long");
}
s[index] = c; s[index] = c;
} }
static inline void static inline void yylex_SymbolWriteChar(char *s, size_t index, char c)
yylex_SymbolWriteChar(char *s, size_t index, char c)
{ {
if (index >= MAXSYMLEN) { if (index >= MAXSYMLEN)
fatalerror("Symbol too long"); fatalerror("Symbol too long");
}
s[index] = c; s[index] = c;
} }
@@ -497,14 +503,15 @@ yylex_SymbolWriteChar(char *s, size_t index, char c)
*/ */
void yylex_TrimEnd(char *s, size_t index) 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; s[i] = 0;
i--;
}
} }
size_t size_t yylex_ReadBracketedSymbol(char *dest, size_t index)
yylex_ReadBracketedSymbol(char *dest, size_t index)
{ {
char sym[MAXSYMLEN + 1]; char sym[MAXSYMLEN + 1];
char ch; char ch;
@@ -523,13 +530,15 @@ yylex_ReadBracketedSymbol(char *dest, size_t index)
i += length; i += length;
else else
fatalerror("Illegal character escape '%c'", ch); fatalerror("Illegal character escape '%c'", ch);
} else } else {
yylex_SymbolWriteChar(sym, i++, ch); yylex_SymbolWriteChar(sym, i++, ch);
}
} }
yylex_SymbolWriteChar(sym, i, 0); 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); length = symvaluetostring(&dest[index], maxLength, sym);
if (*pLexBuffer == '}') if (*pLexBuffer == '}')
@@ -540,8 +549,7 @@ yylex_ReadBracketedSymbol(char *dest, size_t index)
return length; return length;
} }
void static void yylex_ReadQuotedString(void)
yylex_ReadQuotedString()
{ {
size_t index = 0; size_t index = 0;
size_t length, maxLength; size_t length, maxLength;
@@ -576,19 +584,22 @@ yylex_ReadQuotedString()
break; break;
default: default:
maxLength = MAXSTRLEN - index; maxLength = MAXSTRLEN - index;
length = CopyMacroArg(&yylval.tzString[index], maxLength, ch); length = CopyMacroArg(&yylval.tzString[index],
maxLength, ch);
if (length != 0) if (length != 0)
index += length; index += length;
else else
fatalerror("Illegal character escape '%c'", ch); fatalerror("Illegal character escape '%c'",
ch);
ch = 0; ch = 0;
break; break;
} }
} else if (ch == '{') { } else if (ch == '{') {
// Get bracketed symbol within string. // Get bracketed symbol within string.
index += yylex_ReadBracketedSymbol(yylval.tzString, index); index += yylex_ReadBracketedSymbol(yylval.tzString,
index);
ch = 0; ch = 0;
} }
@@ -604,12 +615,11 @@ yylex_ReadQuotedString()
fatalerror("Unterminated string"); fatalerror("Unterminated string");
} }
ULONG static uint32_t yylex_NORMAL(void)
yylex_NORMAL()
{ {
struct sLexString *pLongestFixed = NULL; struct sLexString *pLongestFixed = NULL;
ULONG nFloatMask, nFloatLen; uint32_t nFloatMask, nFloatLen;
ULONG linestart = AtLineStart; uint32_t linestart = AtLineStart;
AtLineStart = 0; AtLineStart = 0;
@@ -628,15 +638,58 @@ scanagain:
} }
} }
// Try to match an identifier, macro argument (e.g. \1), /* Check for line continuation character */
// or numeric literal. if (*pLexBuffer == '\\') {
/*
* Look for line continuation character after a series of
* spaces. This is also useful for files that use Windows line
* endings: "\r\n" is replaced by " \n" before the lexer has the
* opportunity to see it.
*/
if (pLexBuffer[1] == ' ') {
pLexBuffer += 2;
while (1) {
if (*pLexBuffer == ' ') {
pLexBuffer++;
} else if (*pLexBuffer == '\n') {
pLexBuffer++;
nLineNo += 1;
goto scanagain;
} else {
errx(1, "Expected a new line after the continuation character.");
}
}
}
/* Line continuation character */
if (pLexBuffer[1] == '\n') {
pLexBuffer += 2;
nLineNo += 1;
goto scanagain;
}
/*
* If there isn't a newline character or a space, ignore the
* character '\'. It will eventually be handled by other
* functions like PutMacroArg().
*/
}
/*
* Try to match an identifier, macro argument (e.g. \1),
* or numeric literal.
*/
yylex_GetFloatMaskAndFloatLen(&nFloatMask, &nFloatLen); yylex_GetFloatMaskAndFloatLen(&nFloatMask, &nFloatLen);
// Try to match a keyword or operator. /* Try to match a keyword or operator. */
pLongestFixed = yylex_GetLongestFixed(); pLongestFixed = yylex_GetLongestFixed();
if (nFloatLen == 0 && pLongestFixed == NULL) { if (nFloatLen == 0 && pLongestFixed == NULL) {
// No keyword, identifier, operator, or numerical literal matches. /*
* No keyword, identifier, operator, or numerical literal
* matches.
*/
if (*pLexBuffer == '"') { if (*pLexBuffer == '"') {
pLexBuffer++; pLexBuffer++;
@@ -646,52 +699,55 @@ scanagain:
pLexBuffer++; pLexBuffer++;
yylex_ReadBracketedSymbol(yylval.tzString, 0); yylex_ReadBracketedSymbol(yylval.tzString, 0);
return T_STRING; 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.
if (*pLexBuffer == '\n')
AtLineStart = 1;
return *pLexBuffer++;
} }
/*
* 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) { 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); struct sLexFloat *token = lexgetfloat(nFloatMask);
if (token->Callback) { if (token->Callback) {
int done = token->Callback(pLexBuffer, nFloatLen); int32_t done = token->Callback(pLexBuffer, nFloatLen);
if (!done) if (!done)
goto scanagain; goto scanagain;
} }
pLexBuffer += nFloatLen; pLexBuffer += nFloatLen;
if (token->nToken == T_ID && linestart) { if (token->nToken == T_ID && linestart)
return T_LABEL; return T_LABEL;
} else { else
return token->nToken; return token->nToken;
}
} }
// Longest match was a keyword or operator. /* Longest match was a keyword or operator. */
pLexBuffer += pLongestFixed->nNameLength; pLexBuffer += pLongestFixed->nNameLength;
return pLongestFixed->nToken; return pLongestFixed->nToken;
} }
ULONG static uint32_t yylex_MACROARGS(void)
yylex_MACROARGS()
{ {
size_t index = 0; size_t index = 0;
size_t length, maxLength; size_t length, maxLength;
while (*pLexBuffer == ' ' || *pLexBuffer == '\t') { while ((*pLexBuffer == ' ') || (*pLexBuffer == '\t'))
pLexBuffer++; pLexBuffer++;
}
while (*pLexBuffer != ',' && (*pLexBuffer != '\n')) { while ((*pLexBuffer != ',') && (*pLexBuffer != '\n')) {
char ch = *pLexBuffer++; char ch = *pLexBuffer++;
if (ch == '\\') { if (ch == '\\') {
@@ -707,6 +763,9 @@ yylex_MACROARGS()
case '\\': case '\\':
ch = '\\'; ch = '\\';
break; break;
case '"':
ch = '\"';
break;
case ',': case ',':
ch = ','; ch = ',';
break; break;
@@ -716,20 +775,49 @@ yylex_MACROARGS()
case '}': case '}':
ch = '}'; ch = '}';
break; break;
case ' ':
/*
* Look for line continuation character after a
* series of spaces. This is also useful for
* files that use Windows line endings: "\r\n"
* is replaced by " \n" before the lexer has the
* opportunity to see it.
*/
while (1) {
if (*pLexBuffer == ' ') {
pLexBuffer++;
} else if (*pLexBuffer == '\n') {
pLexBuffer++;
nLineNo += 1;
ch = 0;
break;
} else {
errx(1, "Expected a new line after the continuation character.");
}
}
break;
case '\n':
/* Line continuation character */
nLineNo += 1;
ch = 0;
break;
default: default:
maxLength = MAXSTRLEN - index; maxLength = MAXSTRLEN - index;
length = CopyMacroArg(&yylval.tzString[index], maxLength, ch); length = CopyMacroArg(&yylval.tzString[index],
maxLength, ch);
if (length != 0) if (length != 0)
index += length; index += length;
else else
fatalerror("Illegal character escape '%c'", ch); fatalerror("Illegal character escape '%c'",
ch);
ch = 0; ch = 0;
break; break;
} }
} else if (ch == '{') { } else if (ch == '{') {
index += yylex_ReadBracketedSymbol(yylval.tzString, index); index += yylex_ReadBracketedSymbol(yylval.tzString,
index);
ch = 0; ch = 0;
} }
if (ch) if (ch)
@@ -739,7 +827,7 @@ yylex_MACROARGS()
if (index) { if (index) {
yylex_StringWriteChar(yylval.tzString, index, 0); 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') if (*pLexBuffer == '\n')
yylex_TrimEnd(yylval.tzString, index); yylex_TrimEnd(yylval.tzString, index);
@@ -753,12 +841,10 @@ yylex_MACROARGS()
return ','; return ',';
} }
fatalerror("Internal error in yylex_MACROARGS"); fatalerror("Internal error in %s", __func__);
return 0;
} }
ULONG uint32_t yylex(void)
yylex(void)
{ {
switch (lexerstate) { switch (lexerstate) {
case LEX_STATE_NORMAL: case LEX_STATE_NORMAL:
@@ -767,6 +853,5 @@ yylex(void)
return yylex_MACROARGS(); return yylex_MACROARGS();
} }
fatalerror("Internal error in yylex"); fatalerror("Internal error in %s", __func__);
return 0;
} }

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,15 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <math.h> #include <math.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@@ -8,29 +17,31 @@
#include "asm/symbol.h" #include "asm/symbol.h"
#include "asm/fstack.h" #include "asm/fstack.h"
#include "asm/lexer.h"
#include "asm/output.h" #include "asm/output.h"
#include "asm/main.h" #include "asm/main.h"
#include "extern/err.h" #include "extern/err.h"
#include "extern/reallocarray.h"
#include "extern/version.h"
int yyparse(void); #include "version.h"
void setuplex(void);
int cldefines_index; extern int yyparse(void);
int cldefines_size;
size_t cldefines_index;
size_t cldefines_numindices;
size_t cldefines_bufsize;
const size_t cldefine_entrysize = 2 * sizeof(void *);
char **cldefines; char **cldefines;
clock_t nStartClock, nEndClock; clock_t nStartClock, nEndClock;
SLONG nLineNo; int32_t nLineNo;
ULONG nTotalLines, nPass, nPC, nIFDepth, nUnionDepth, nErrors; uint32_t nTotalLines, nPass, nPC, nIFDepth, nUnionDepth, nErrors;
bool skipElif; bool skipElif;
ULONG unionStart[128], unionSize[128]; uint32_t unionStart[128], unionSize[128];
extern int yydebug; /* extern int yydebug; */
FILE *dependfile; FILE *dependfile;
extern char *tzObjectname;
/* /*
* Option stack * Option stack
@@ -44,73 +55,71 @@ struct sOptionStackEntry {
struct sOptionStackEntry *pNext; struct sOptionStackEntry *pNext;
}; };
struct sOptionStackEntry *pOptionStack = NULL; struct sOptionStackEntry *pOptionStack;
void void opt_SetCurrentOptions(struct sOptions *pOpt)
opt_SetCurrentOptions(struct sOptions * pOpt)
{ {
if (nGBGfxID != -1) { if (nGBGfxID != -1) {
lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[0], lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[0],
CurrentOptions.gbgfx[0]); CurrentOptions.gbgfx[0]);
lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[1], lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[1],
CurrentOptions.gbgfx[1]); CurrentOptions.gbgfx[1]);
lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[2], lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[2],
CurrentOptions.gbgfx[2]); CurrentOptions.gbgfx[2]);
lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[3], lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[3],
CurrentOptions.gbgfx[3]); CurrentOptions.gbgfx[3]);
lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[0], lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[0],
CurrentOptions.gbgfx[0]); CurrentOptions.gbgfx[0]);
lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[1], lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[1],
CurrentOptions.gbgfx[1]); CurrentOptions.gbgfx[1]);
lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[2], lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[2],
CurrentOptions.gbgfx[2]); CurrentOptions.gbgfx[2]);
lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[3], lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[3],
CurrentOptions.gbgfx[3]); CurrentOptions.gbgfx[3]);
} }
if (nBinaryID != -1) { if (nBinaryID != -1) {
lex_FloatDeleteRange(nBinaryID, CurrentOptions.binary[0], lex_FloatDeleteRange(nBinaryID, CurrentOptions.binary[0],
CurrentOptions.binary[0]); CurrentOptions.binary[0]);
lex_FloatDeleteRange(nBinaryID, CurrentOptions.binary[1], lex_FloatDeleteRange(nBinaryID, CurrentOptions.binary[1],
CurrentOptions.binary[1]); CurrentOptions.binary[1]);
lex_FloatDeleteSecondRange(nBinaryID, CurrentOptions.binary[0], lex_FloatDeleteSecondRange(nBinaryID, CurrentOptions.binary[0],
CurrentOptions.binary[0]); CurrentOptions.binary[0]);
lex_FloatDeleteSecondRange(nBinaryID, CurrentOptions.binary[1], lex_FloatDeleteSecondRange(nBinaryID, CurrentOptions.binary[1],
CurrentOptions.binary[1]); CurrentOptions.binary[1]);
} }
CurrentOptions = *pOpt; CurrentOptions = *pOpt;
if (nGBGfxID != -1) { if (nGBGfxID != -1) {
lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[0], lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[0],
CurrentOptions.gbgfx[0]); CurrentOptions.gbgfx[0]);
lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[1], lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[1],
CurrentOptions.gbgfx[1]); CurrentOptions.gbgfx[1]);
lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[2], lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[2],
CurrentOptions.gbgfx[2]); CurrentOptions.gbgfx[2]);
lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[3], lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[3],
CurrentOptions.gbgfx[3]); CurrentOptions.gbgfx[3]);
lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[0], lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[0],
CurrentOptions.gbgfx[0]); CurrentOptions.gbgfx[0]);
lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[1], lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[1],
CurrentOptions.gbgfx[1]); CurrentOptions.gbgfx[1]);
lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[2], lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[2],
CurrentOptions.gbgfx[2]); CurrentOptions.gbgfx[2]);
lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[3], lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[3],
CurrentOptions.gbgfx[3]); CurrentOptions.gbgfx[3]);
} }
if (nBinaryID != -1) { if (nBinaryID != -1) {
lex_FloatAddRange(nBinaryID, CurrentOptions.binary[0], lex_FloatAddRange(nBinaryID, CurrentOptions.binary[0],
CurrentOptions.binary[0]); CurrentOptions.binary[0]);
lex_FloatAddRange(nBinaryID, CurrentOptions.binary[1], lex_FloatAddRange(nBinaryID, CurrentOptions.binary[1],
CurrentOptions.binary[1]); CurrentOptions.binary[1]);
lex_FloatAddSecondRange(nBinaryID, CurrentOptions.binary[0], lex_FloatAddSecondRange(nBinaryID, CurrentOptions.binary[0],
CurrentOptions.binary[0]); CurrentOptions.binary[0]);
lex_FloatAddSecondRange(nBinaryID, CurrentOptions.binary[1], lex_FloatAddSecondRange(nBinaryID, CurrentOptions.binary[1],
CurrentOptions.binary[1]); CurrentOptions.binary[1]);
} }
} }
void void opt_Parse(char *s)
opt_Parse(char *s)
{ {
struct sOptions newopt; struct sOptions newopt;
@@ -124,8 +133,7 @@ opt_Parse(char *s)
newopt.gbgfx[2] = s[3]; newopt.gbgfx[2] = s[3];
newopt.gbgfx[3] = s[4]; newopt.gbgfx[3] = s[4];
} else { } else {
errx(1, "Must specify exactly 4 characters for " errx(1, "Must specify exactly 4 characters for option 'g'");
"option 'g'");
} }
break; break;
case 'b': case 'b':
@@ -133,21 +141,18 @@ opt_Parse(char *s)
newopt.binary[0] = s[1]; newopt.binary[0] = s[1];
newopt.binary[1] = s[2]; newopt.binary[1] = s[2];
} else { } else {
errx(1, "Must specify exactly 2 characters for option " errx(1, "Must specify exactly 2 characters for option 'b'");
"'b'");
} }
break; break;
case 'z': case 'z':
if (strlen(&s[1]) <= 2) { if (strlen(&s[1]) <= 2) {
int result; int32_t result;
result = sscanf(&s[1], "%lx", &newopt.fillchar); result = sscanf(&s[1], "%x", &newopt.fillchar);
if (!((result == EOF) || (result == 1))) { if (!((result == EOF) || (result == 1)))
errx(1, "Invalid argument for option 'z'"); errx(1, "Invalid argument for option 'z'");
}
} else { } else {
errx(1, "Invalid argument for option 'z'"); errx(1, "Invalid argument for option 'z'");
exit(1);
} }
break; break;
default: default:
@@ -158,77 +163,75 @@ opt_Parse(char *s)
opt_SetCurrentOptions(&newopt); opt_SetCurrentOptions(&newopt);
} }
void void opt_Push(void)
opt_Push(void)
{ {
struct sOptionStackEntry *pOpt; struct sOptionStackEntry *pOpt;
if ((pOpt = malloc(sizeof(struct sOptionStackEntry))) != NULL) { pOpt = malloc(sizeof(struct sOptionStackEntry));
pOpt->Options = CurrentOptions;
pOpt->pNext = pOptionStack; if (pOpt == NULL)
pOptionStack = pOpt;
} else
fatalerror("No memory for option stack"); fatalerror("No memory for option stack");
pOpt->Options = CurrentOptions;
pOpt->pNext = pOptionStack;
pOptionStack = pOpt;
} }
void void opt_Pop(void)
opt_Pop(void)
{ {
if (pOptionStack) { if (pOptionStack == NULL)
struct sOptionStackEntry *pOpt;
pOpt = pOptionStack;
opt_SetCurrentOptions(&(pOpt->Options));
pOptionStack = pOpt->pNext;
free(pOpt);
} else
fatalerror("No entries in the option stack"); fatalerror("No entries in the option stack");
struct sOptionStackEntry *pOpt;
pOpt = pOptionStack;
opt_SetCurrentOptions(&(pOpt->Options));
pOptionStack = pOpt->pNext;
free(pOpt);
} }
void void opt_AddDefine(char *s)
opt_AddDefine(char *s)
{ {
char *value, *equals; char *value, *equals;
if(cldefines_index >= cldefines_size)
{ if (cldefines_index >= cldefines_numindices) {
cldefines_size *= 2; /* Check for overflows */
cldefines = reallocarray(cldefines, cldefines_size, if ((cldefines_numindices * 2) < cldefines_numindices)
2 * sizeof(void *)); fatalerror("No memory for command line defines");
if(!cldefines)
{ if ((cldefines_bufsize * 2) < cldefines_bufsize)
fatalerror("No memory for command line defines");
cldefines_numindices *= 2;
cldefines_bufsize *= 2;
cldefines = realloc(cldefines, cldefines_bufsize);
if (!cldefines)
fatalerror("No memory for command line defines"); fatalerror("No memory for command line defines");
}
} }
equals = strchr(s, '='); equals = strchr(s, '=');
if(equals) if (equals) {
{
*equals = '\0'; *equals = '\0';
value = equals + 1; value = equals + 1;
} } else {
else
{
value = "1"; value = "1";
} }
cldefines[cldefines_index++] = s; cldefines[cldefines_index++] = s;
cldefines[cldefines_index++] = value; cldefines[cldefines_index++] = value;
} }
void static void opt_ParseDefines(void)
opt_ParseDefines()
{ {
int i; int32_t i;
for(i = 0; i < cldefines_index; i += 2) for (i = 0; i < cldefines_index; i += 2)
{
sym_AddString(cldefines[i], cldefines[i + 1]); sym_AddString(cldefines[i], cldefines[i + 1]);
}
} }
/* /*
* Error handling * Error handling
*/ */
void void verror(const char *fmt, va_list args)
verror(const char *fmt, va_list args)
{ {
fprintf(stderr, "ERROR: "); fprintf(stderr, "ERROR: ");
fstk_Dump(); fstk_Dump();
@@ -238,32 +241,33 @@ verror(const char *fmt, va_list args)
nErrors += 1; nErrors += 1;
} }
void void yyerror(const char *fmt, ...)
yyerror(const char *fmt, ...)
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
verror(fmt, args); verror(fmt, args);
va_end(args); va_end(args);
} }
void void fatalerror(const char *fmt, ...)
fatalerror(const char *fmt, ...)
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
verror(fmt, args); verror(fmt, args);
va_end(args); va_end(args);
exit(5); exit(5);
} }
void void warning(const char *fmt, ...)
warning(const char *fmt, ...)
{ {
if (!CurrentOptions.warnings) if (!CurrentOptions.warnings)
return; return;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
fprintf(stderr, "warning: "); fprintf(stderr, "warning: ");
@@ -275,17 +279,15 @@ warning(const char *fmt, ...)
va_end(args); va_end(args);
} }
static void static void print_usage(void)
usage(void)
{ {
printf( printf(
"Usage: rgbasm [-EhVvw] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n" "usage: rgbasm [-EhLVvw] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
" [-M dependfile] [-o outfile] [-p pad_value] file.asm\n"); " [-M dependfile] [-o outfile] [-p pad_value] file.asm\n");
exit(1); exit(1);
} }
int int main(int argc, char *argv[])
main(int argc, char *argv[])
{ {
int ch; int ch;
char *ep; char *ep;
@@ -296,16 +298,15 @@ main(int argc, char *argv[])
dependfile = NULL; dependfile = NULL;
cldefines_size = 32; /* Initial number of allocated elements in array */
cldefines = reallocarray(cldefines, cldefines_size, cldefines_numindices = 32;
2 * sizeof(void *)); cldefines_bufsize = cldefines_numindices * cldefine_entrysize;
if(!cldefines) cldefines = malloc(cldefines_bufsize);
{ if (!cldefines)
fatalerror("No memory for command line defines"); fatalerror("No memory for command line defines");
}
if (argc == 1) if (argc == 1)
usage(); print_usage();
/* yydebug=1; */ /* yydebug=1; */
@@ -315,25 +316,25 @@ main(int argc, char *argv[])
DefaultOptions.gbgfx[3] = '3'; DefaultOptions.gbgfx[3] = '3';
DefaultOptions.binary[0] = '0'; DefaultOptions.binary[0] = '0';
DefaultOptions.binary[1] = '1'; DefaultOptions.binary[1] = '1';
DefaultOptions.fillchar = 0;
DefaultOptions.verbose = false;
DefaultOptions.haltnop = true;
DefaultOptions.exportall = false; DefaultOptions.exportall = false;
DefaultOptions.fillchar = 0;
DefaultOptions.optimizeloads = true;
DefaultOptions.haltnop = true;
DefaultOptions.verbose = false;
DefaultOptions.warnings = true; DefaultOptions.warnings = true;
opt_SetCurrentOptions(&DefaultOptions); opt_SetCurrentOptions(&DefaultOptions);
newopt = CurrentOptions; newopt = CurrentOptions;
while ((ch = getopt(argc, argv, "b:D:g:hi:M:o:p:EVvw")) != -1) { while ((ch = getopt(argc, argv, "b:D:Eg:hi:LM:o:p:Vvw")) != -1) {
switch (ch) { switch (ch) {
case 'b': case 'b':
if (strlen(optarg) == 2) { if (strlen(optarg) == 2) {
newopt.binary[0] = optarg[1]; newopt.binary[0] = optarg[1];
newopt.binary[1] = optarg[2]; newopt.binary[1] = optarg[2];
} else { } else {
errx(1, "Must specify exactly 2 characters for " errx(1, "Must specify exactly 2 characters for option 'b'");
"option 'b'");
} }
break; break;
case 'D': case 'D':
@@ -349,8 +350,7 @@ main(int argc, char *argv[])
newopt.gbgfx[2] = optarg[3]; newopt.gbgfx[2] = optarg[3];
newopt.gbgfx[3] = optarg[4]; newopt.gbgfx[3] = optarg[4];
} else { } else {
errx(1, "Must specify exactly 4 characters for " errx(1, "Must specify exactly 4 characters for option 'g'");
"option 'g'");
} }
break; break;
case 'h': case 'h':
@@ -359,23 +359,27 @@ main(int argc, char *argv[])
case 'i': case 'i':
fstk_AddIncludePath(optarg); fstk_AddIncludePath(optarg);
break; break;
case 'L':
newopt.optimizeloads = false;
break;
case 'M': case 'M':
if ((dependfile = fopen(optarg, "w")) == NULL) { dependfile = fopen(optarg, "w");
if (dependfile == NULL)
err(1, "Could not open dependfile %s", optarg); err(1, "Could not open dependfile %s", optarg);
}
break; break;
case 'o': case 'o':
out_SetFileName(optarg); out_SetFileName(optarg);
break; break;
case 'p': case 'p':
newopt.fillchar = strtoul(optarg, &ep, 0); 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'"); errx(1, "Invalid argument for option 'p'");
}
if (newopt.fillchar < 0 || newopt.fillchar > 0xFF) { if (newopt.fillchar < 0 || newopt.fillchar > 0xFF)
errx(1, "Argument for option 'p' must be " errx(1, "Argument for option 'p' must be between 0 and 0xFF");
"between 0 and 0xFF");
}
break; break;
case 'V': case 'V':
printf("rgbasm %s\n", get_package_version_string()); printf("rgbasm %s\n", get_package_version_string());
@@ -387,7 +391,7 @@ main(int argc, char *argv[])
newopt.warnings = false; newopt.warnings = false;
break; break;
default: default:
usage(); print_usage();
/* NOTREACHED */ /* NOTREACHED */
} }
} }
@@ -399,15 +403,14 @@ main(int argc, char *argv[])
DefaultOptions = CurrentOptions; DefaultOptions = CurrentOptions;
if (argc == 0) if (argc == 0)
usage(); print_usage();
tzMainfile = argv[argc - 1]; tzMainfile = argv[argc - 1];
setuplex(); setup_lexer();
if (CurrentOptions.verbose) { if (CurrentOptions.verbose)
printf("Assembling %s\n", tzMainfile); printf("Assembling %s\n", tzMainfile);
}
if (dependfile) { if (dependfile) {
if (!tzObjectname) if (!tzObjectname)
@@ -431,23 +434,21 @@ main(int argc, char *argv[])
fstk_Init(tzMainfile); fstk_Init(tzMainfile);
opt_ParseDefines(); opt_ParseDefines();
if (CurrentOptions.verbose) { if (CurrentOptions.verbose)
printf("Pass 1...\n"); printf("Pass 1...\n");
}
yy_set_state(LEX_STATE_NORMAL); yy_set_state(LEX_STATE_NORMAL);
opt_SetCurrentOptions(&DefaultOptions); opt_SetCurrentOptions(&DefaultOptions);
if (yyparse() != 0 || nErrors != 0) { if (yyparse() != 0 || nErrors != 0)
errx(1, "Assembly aborted in pass 1 (%ld errors)!", nErrors); errx(1, "Assembly aborted in pass 1 (%ld errors)!", nErrors);
}
if (nIFDepth != 0) { if (nIFDepth != 0)
errx(1, "Unterminated IF construct (%ld levels)!", nIFDepth); errx(1, "Unterminated IF construct (%ld levels)!", nIFDepth);
}
if (nUnionDepth != 0) { if (nUnionDepth != 0) {
errx(1, "Unterminated UNION construct (%ld levels)!", nUnionDepth); errx(1, "Unterminated UNION construct (%ld levels)!",
nUnionDepth);
} }
nTotalLines = 0; nTotalLines = 0;
@@ -465,27 +466,25 @@ main(int argc, char *argv[])
opt_SetCurrentOptions(&DefaultOptions); opt_SetCurrentOptions(&DefaultOptions);
opt_ParseDefines(); opt_ParseDefines();
if (CurrentOptions.verbose) { if (CurrentOptions.verbose)
printf("Pass 2...\n"); printf("Pass 2...\n");
}
if (yyparse() != 0 || nErrors != 0) { if (yyparse() != 0 || nErrors != 0)
errx(1, "Assembly aborted in pass 2 (%ld errors)!", nErrors); errx(1, "Assembly aborted in pass 2 (%ld errors)!", nErrors);
}
double timespent; double timespent;
nEndClock = clock(); nEndClock = clock();
timespent = ((double)(nEndClock - nStartClock)) timespent = ((double)(nEndClock - nStartClock))
/ (double)CLOCKS_PER_SEC; / (double)CLOCKS_PER_SEC;
if (CurrentOptions.verbose) { 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); (int)timespent, ((int)(timespent * 100.0)) % 100);
if (timespent == 0) if (timespent == 0)
printf("(INFINITY lines/minute)\n"); printf("(INFINITY lines/minute)\n");
else else
printf("(%d lines/minute)\n", printf("(%d lines/minute)\n",
(int) (60 / timespent * nTotalLines)); (int)(60 / timespent * nTotalLines));
} }
out_WriteObject(); out_WriteObject();
return 0; return 0;

View File

@@ -1,148 +1,142 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
/* /*
* Fixedpoint math routines * Fixedpoint math routines
*/ */
#include <math.h> #include <math.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include "types.h"
#include "asm/mymath.h" #include "asm/mymath.h"
#include "asm/symbol.h" #include "asm/symbol.h"
#define fix2double(i) ((double)(i/65536.0)) #define fx2double(i) ((double)((i) / 65536.0))
#define double2fix(d) ((SLONG)(d*65536.0)) #define double2fx(d) ((int32_t)((d) * 65536.0))
#ifndef PI
#define PI (acos(-1)) #ifndef M_PI
#define M_PI 3.14159265358979323846
#endif #endif
/* /*
* Define the _PI symbol * Define the _PI symbol
*/ */
void void math_DefinePI(void)
math_DefinePI(void)
{ {
sym_AddEqu("_PI", double2fix(PI)); sym_AddEqu("_PI", double2fx(M_PI));
} }
/* /*
* Print a fixed point value * Print a fixed point value
*/ */
void void math_Print(int32_t i)
math_Print(SLONG i)
{ {
if (i >= 0) if (i >= 0)
printf("%ld.%05ld", i >> 16, printf("%d.%05d", i >> 16,
((SLONG) (fix2double(i) * 100000 + 0.5)) % 100000); ((int32_t)(fx2double(i) * 100000 + 0.5)) % 100000);
else else
printf("-%ld.%05ld", (-i) >> 16, printf("-%d.%05d", (-i) >> 16,
((SLONG) (fix2double(-i) * 100000 + 0.5)) % 100000); ((int32_t)(fx2double(-i) * 100000 + 0.5)) % 100000);
} }
/* /*
* Calculate sine * Calculate sine
*/ */
SLONG int32_t math_Sin(int32_t i)
math_Sin(SLONG i)
{ {
return (double2fix(sin(fix2double(i) * 2 * PI / 65536))); return double2fx(sin(fx2double(i) * 2 * M_PI / 65536));
} }
/* /*
* Calculate cosine * Calculate cosine
*/ */
SLONG int32_t math_Cos(int32_t i)
math_Cos(SLONG i)
{ {
return (double2fix(cos(fix2double(i) * 2 * PI / 65536))); return double2fx(cos(fx2double(i) * 2 * M_PI / 65536));
} }
/* /*
* Calculate tangent * Calculate tangent
*/ */
SLONG int32_t math_Tan(int32_t i)
math_Tan(SLONG i)
{ {
return (double2fix(tan(fix2double(i) * 2 * PI / 65536))); return double2fx(tan(fx2double(i) * 2 * M_PI / 65536));
} }
/* /*
* Calculate arcsine * Calculate arcsine
*/ */
SLONG int32_t math_ASin(int32_t i)
math_ASin(SLONG i)
{ {
return (double2fix(asin(fix2double(i)) / 2 / PI * 65536)); return double2fx(asin(fx2double(i)) / 2 / M_PI * 65536);
} }
/* /*
* Calculate arccosine * Calculate arccosine
*/ */
SLONG int32_t math_ACos(int32_t i)
math_ACos(SLONG i)
{ {
return (double2fix(acos(fix2double(i)) / 2 / PI * 65536)); return double2fx(acos(fx2double(i)) / 2 / M_PI * 65536);
} }
/* /*
* Calculate arctangent * Calculate arctangent
*/ */
SLONG int32_t math_ATan(int32_t i)
math_ATan(SLONG i)
{ {
return (double2fix(atan(fix2double(i)) / 2 / PI * 65536)); return double2fx(atan(fx2double(i)) / 2 / M_PI * 65536);
} }
/* /*
* Calculate atan2 * Calculate atan2
*/ */
SLONG int32_t math_ATan2(int32_t i, int32_t j)
math_ATan2(SLONG i, SLONG j)
{ {
return (double2fix return double2fx(atan2(fx2double(i), fx2double(j)) / 2 / M_PI * 65536);
(atan2(fix2double(i), fix2double(j)) / 2 / PI * 65536));
} }
/* /*
* Multiplication * Multiplication
*/ */
SLONG int32_t math_Mul(int32_t i, int32_t j)
math_Mul(SLONG i, SLONG j)
{ {
return (double2fix(fix2double(i) * fix2double(j))); return double2fx(fx2double(i) * fx2double(j));
} }
/* /*
* Division * Division
*/ */
SLONG int32_t math_Div(int32_t i, int32_t j)
math_Div(SLONG i, SLONG j)
{ {
return (double2fix(fix2double(i) / fix2double(j))); return double2fx(fx2double(i) / fx2double(j));
} }
/* /*
* Round * Round
*/ */
SLONG int32_t math_Round(int32_t i)
math_Round(SLONG i)
{ {
return double2fix(round(fix2double(i))); return double2fx(round(fx2double(i)));
} }
/* /*
* Ceil * Ceil
*/ */
SLONG int32_t math_Ceil(int32_t i)
math_Ceil(SLONG i)
{ {
return double2fix(ceil(fix2double(i))); return double2fx(ceil(fx2double(i)));
} }
/* /*
* Floor * Floor
*/ */
SLONG int32_t math_Floor(int32_t i)
math_Floor(SLONG i)
{ {
return double2fix(floor(fix2double(i))); return double2fx(floor(fx2double(i)));
} }

View File

@@ -1,98 +1,118 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
/* /*
* Outputs an objectfile * Outputs an objectfile
*/ */
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "asm/asm.h" #include "asm/asm.h"
#include "asm/charmap.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/fstack.h"
#include "common.h" #include "asm/main.h"
#include "asm/output.h"
#include "asm/rpn.h"
#include "asm/symbol.h"
#include "extern/err.h" #include "extern/err.h"
void out_SetCurrentSection(struct Section * pSect); #include "common.h"
#include "linkdefs.h"
void out_SetCurrentSection(struct Section *pSect);
struct Patch { struct Patch {
char tzFilename[_MAX_PATH + 1]; char tzFilename[_MAX_PATH + 1];
ULONG nLine; uint32_t nLine;
ULONG nOffset; uint32_t nOffset;
UBYTE nType; uint8_t nType;
ULONG nRPNSize; uint32_t nRPNSize;
UBYTE *pRPN; uint8_t *pRPN;
struct Patch *pNext; struct Patch *pNext;
}; };
struct PatchSymbol { struct PatchSymbol {
ULONG ID; uint32_t ID;
struct sSymbol *pSymbol; struct sSymbol *pSymbol;
struct PatchSymbol *pNext; struct PatchSymbol *pNext;
struct PatchSymbol *pBucketNext; // next symbol in hash table bucket struct PatchSymbol *pBucketNext; /* next symbol in hash table bucket */
}; };
struct SectionStackEntry { struct SectionStackEntry {
struct Section *pSection; struct Section *pSection;
struct sSymbol *pScope; /* Section's symbol scope */
struct SectionStackEntry *pNext; struct SectionStackEntry *pNext;
}; };
struct PatchSymbol *tHashedPatchSymbols[HASHSIZE]; struct PatchSymbol *tHashedPatchSymbols[HASHSIZE];
struct Section *pSectionList = NULL, *pCurrentSection = NULL; struct Section *pSectionList, *pCurrentSection;
struct PatchSymbol *pPatchSymbols = NULL; struct PatchSymbol *pPatchSymbols;
struct PatchSymbol **ppPatchSymbolsTail = &pPatchSymbols; struct PatchSymbol **ppPatchSymbolsTail = &pPatchSymbols;
char *tzObjectname; char *tzObjectname;
struct SectionStackEntry *pSectionStack = NULL; struct SectionStackEntry *pSectionStack;
/* /*
* Section stack routines * Section stack routines
*/ */
void void out_PushSection(void)
out_PushSection(void)
{ {
struct SectionStackEntry *pSect; struct SectionStackEntry *pSect;
if ((pSect = malloc(sizeof(struct SectionStackEntry))) != NULL) { pSect = malloc(sizeof(struct SectionStackEntry));
pSect->pSection = pCurrentSection; if (pSect == NULL)
pSect->pNext = pSectionStack;
pSectionStack = pSect;
} else
fatalerror("No memory for section stack"); fatalerror("No memory for section stack");
pSect->pSection = pCurrentSection;
pSect->pScope = sym_GetCurrentSymbolScope();
pSect->pNext = pSectionStack;
pSectionStack = pSect;
} }
void void out_PopSection(void)
out_PopSection(void)
{ {
if (pSectionStack) { if (pSectionStack == NULL)
struct SectionStackEntry *pSect;
pSect = pSectionStack;
out_SetCurrentSection(pSect->pSection);
pSectionStack = pSect->pNext;
free(pSect);
} else
fatalerror("No entries in the section stack"); 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);
} }
ULONG static uint32_t getmaxsectionsize(uint32_t secttype, char *sectname)
getmaxsectionsize(ULONG secttype, char * sectname)
{ {
switch (secttype) switch (secttype) {
{ case SECT_ROM0:
case SECT_ROM0: return 0x8000; /* If ROMX sections not used. */ return 0x8000; /* If ROMX sections not used */
case SECT_ROMX: return 0x4000; case SECT_ROMX:
case SECT_VRAM: return 0x2000; return 0x4000;
case SECT_SRAM: return 0x2000; case SECT_VRAM:
case SECT_WRAM0: return 0x2000; /* If WRAMX sections not used. */ return 0x2000;
case SECT_WRAMX: return 0x1000; case SECT_SRAM:
case SECT_OAM: return 0xA0; return 0x2000;
case SECT_HRAM: return 0x7F; case SECT_WRAM0:
default: break; 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); errx(1, "Section \"%s\" has an invalid section type.", sectname);
} }
@@ -100,11 +120,10 @@ getmaxsectionsize(ULONG secttype, char * sectname)
/* /*
* Count the number of symbols used in this object * Count the number of symbols used in this object
*/ */
ULONG static uint32_t countsymbols(void)
countsymbols(void)
{ {
struct PatchSymbol *pSym; struct PatchSymbol *pSym;
ULONG count = 0; uint32_t count = 0;
pSym = pPatchSymbols; pSym = pPatchSymbols;
@@ -119,11 +138,10 @@ countsymbols(void)
/* /*
* Count the number of sections used in this object * Count the number of sections used in this object
*/ */
ULONG static uint32_t countsections(void)
countsections(void)
{ {
struct Section *pSect; struct Section *pSect;
ULONG count = 0; uint32_t count = 0;
pSect = pSectionList; pSect = pSectionList;
@@ -138,11 +156,10 @@ countsections(void)
/* /*
* Count the number of patches used in this object * Count the number of patches used in this object
*/ */
ULONG static uint32_t countpatches(struct Section *pSect)
countpatches(struct Section * pSect)
{ {
struct Patch *pPatch; struct Patch *pPatch;
ULONG r = 0; uint32_t r = 0;
pPatch = pSect->pPatches; pPatch = pSect->pPatches;
while (pPatch) { while (pPatch) {
@@ -156,8 +173,7 @@ countpatches(struct Section * pSect)
/* /*
* Write a long to a file (little-endian) * Write a long to a file (little-endian)
*/ */
void static void fputlong(uint32_t i, FILE *f)
fputlong(ULONG i, FILE * f)
{ {
fputc(i, f); fputc(i, f);
fputc(i >> 8, f); fputc(i >> 8, f);
@@ -168,8 +184,7 @@ fputlong(ULONG i, FILE * f)
/* /*
* Write a NULL-terminated string to a file * Write a NULL-terminated string to a file
*/ */
void static void fputstring(char *s, FILE *f)
fputstring(char *s, FILE * f)
{ {
while (*s) while (*s)
fputc(*s++, f); fputc(*s++, f);
@@ -179,30 +194,28 @@ fputstring(char *s, FILE * f)
/* /*
* Return a section's ID * Return a section's ID
*/ */
ULONG static uint32_t getsectid(struct Section *pSect)
getsectid(struct Section * pSect)
{ {
struct Section *sec; struct Section *sec;
ULONG ID = 0; uint32_t ID = 0;
sec = pSectionList; sec = pSectionList;
while (sec) { while (sec) {
if (sec == pSect) if (sec == pSect)
return (ID); return ID;
ID += 1; ID += 1;
sec = sec->pNext; sec = sec->pNext;
} }
fatalerror("INTERNAL: Unknown section"); fatalerror("%s: Unknown section", __func__);
return ((ULONG) - 1); return (uint32_t)(-1);
} }
/* /*
* Write a patch to a file * Write a patch to a file
*/ */
void static void writepatch(struct Patch *pPatch, FILE *f)
writepatch(struct Patch * pPatch, FILE * f)
{ {
fputstring(pPatch->tzFilename, f); fputstring(pPatch->tzFilename, f);
fputlong(pPatch->nLine, f); fputlong(pPatch->nLine, f);
@@ -215,8 +228,7 @@ writepatch(struct Patch * pPatch, FILE * f)
/* /*
* Write a section to a file * Write a section to a file
*/ */
void static void writesection(struct Section *pSect, FILE *f)
writesection(struct Section * pSect, FILE * f)
{ {
fputstring(pSect->pzName, f); fputstring(pSect->pzName, f);
@@ -228,8 +240,7 @@ writesection(struct Section * pSect, FILE * f)
fputlong(pSect->nBank, f); fputlong(pSect->nBank, f);
fputlong(pSect->nAlign, f); fputlong(pSect->nAlign, f);
if ((pSect->nType == SECT_ROM0) if ((pSect->nType == SECT_ROM0) || (pSect->nType == SECT_ROMX)) {
|| (pSect->nType == SECT_ROMX)) {
struct Patch *pPatch; struct Patch *pPatch;
fwrite(pSect->tData, 1, pSect->nPC, f); fwrite(pSect->tData, 1, pSect->nPC, f);
@@ -246,13 +257,12 @@ writesection(struct Section * pSect, FILE * f)
/* /*
* Write a symbol to a file * Write a symbol to a file
*/ */
void static void writesymbol(struct sSymbol *pSym, FILE *f)
writesymbol(struct sSymbol * pSym, FILE * f)
{ {
char symname[MAXSYMLEN * 2 + 1]; char symname[MAXSYMLEN * 2 + 1];
ULONG type; uint32_t type;
ULONG offset; uint32_t offset;
SLONG sectid; int32_t sectid;
if (pSym->nType & SYMF_IMPORT) { if (pSym->nType & SYMF_IMPORT) {
/* Symbol should be imported */ /* Symbol should be imported */
@@ -294,12 +304,12 @@ writesymbol(struct sSymbol * pSym, FILE * f)
/* /*
* Add a symbol to the object * Add a symbol to the object
*/ */
ULONG static uint32_t nextID;
addsymbol(struct sSymbol * pSym)
static uint32_t addsymbol(struct sSymbol *pSym)
{ {
struct PatchSymbol *pPSym, **ppPSym; struct PatchSymbol *pPSym, **ppPSym;
static ULONG nextID = 0; uint32_t hash;
ULONG hash;
hash = calchash(pSym->tzName); hash = calchash(pSym->tzName);
ppPSym = &(tHashedPatchSymbols[hash]); ppPSym = &(tHashedPatchSymbols[hash]);
@@ -310,14 +320,17 @@ addsymbol(struct sSymbol * pSym)
ppPSym = &((*ppPSym)->pBucketNext); ppPSym = &((*ppPSym)->pBucketNext);
} }
if ((*ppPSym = pPSym = malloc(sizeof(struct PatchSymbol))) != NULL) { pPSym = malloc(sizeof(struct PatchSymbol));
pPSym->pNext = NULL; *ppPSym = pPSym;
pPSym->pBucketNext = NULL;
pPSym->pSymbol = pSym; if (pPSym == NULL)
pPSym->ID = nextID++;
} else
fatalerror("No memory for patchsymbol"); fatalerror("No memory for patchsymbol");
pPSym->pNext = NULL;
pPSym->pBucketNext = NULL;
pPSym->pSymbol = pSym;
pPSym->ID = nextID++;
*ppPatchSymbolsTail = pPSym; *ppPatchSymbolsTail = pPSym;
ppPatchSymbolsTail = &(pPSym->pNext); ppPatchSymbolsTail = &(pPSym->pNext);
@@ -327,10 +340,9 @@ addsymbol(struct sSymbol * pSym)
/* /*
* Add all exported symbols to the object * Add all exported symbols to the object
*/ */
void static void addexports(void)
addexports(void)
{ {
int i; int32_t i;
for (i = 0; i < HASHSIZE; i += 1) { for (i = 0; i < HASHSIZE; i += 1) {
struct sSymbol *pSym; struct sSymbol *pSym;
@@ -347,34 +359,33 @@ addexports(void)
/* /*
* Allocate a new patchstructure and link it into the list * Allocate a new patchstructure and link it into the list
*/ */
struct Patch * struct Patch *allocpatch(void)
allocpatch(void)
{ {
struct Patch *pPatch; struct Patch *pPatch;
if ((pPatch = malloc(sizeof(struct Patch))) != NULL) { pPatch = malloc(sizeof(struct Patch));
pPatch->pNext = pCurrentSection->pPatches;
pPatch->nRPNSize = 0; if (pPatch == NULL)
pPatch->pRPN = NULL;
} else
fatalerror("No memory for patch"); fatalerror("No memory for patch");
pPatch->pNext = pCurrentSection->pPatches;
pPatch->nRPNSize = 0;
pPatch->pRPN = NULL;
pCurrentSection->pPatches = pPatch; pCurrentSection->pPatches = pPatch;
return (pPatch); return pPatch;
} }
/* /*
* Create a new patch (includes the rpn expr) * Create a new patch (includes the rpn expr)
*/ */
void void createpatch(uint32_t type, struct Expression *expr)
createpatch(ULONG type, struct Expression * expr)
{ {
struct Patch *pPatch; struct Patch *pPatch;
UWORD rpndata; uint16_t rpndata;
UBYTE rpnexpr[2048]; uint8_t rpnexpr[2048];
char tzSym[512]; char tzSym[512];
ULONG rpnptr = 0, symptr; uint32_t rpnptr = 0, symptr;
pPatch = allocpatch(); pPatch = allocpatch();
pPatch->nType = type; pPatch->nType = type;
@@ -393,9 +404,11 @@ createpatch(ULONG type, struct Expression * expr)
break; break;
case RPN_SYM: case RPN_SYM:
symptr = 0; symptr = 0;
while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0); while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0)
;
if (sym_isConstant(tzSym)) { if (sym_isConstant(tzSym)) {
ULONG value; uint32_t value;
value = sym_GetConstantValue(tzSym); value = sym_GetConstantValue(tzSym);
rpnexpr[rpnptr++] = RPN_CONST; rpnexpr[rpnptr++] = RPN_CONST;
@@ -404,9 +417,11 @@ createpatch(ULONG type, struct Expression * expr)
rpnexpr[rpnptr++] = value >> 16; rpnexpr[rpnptr++] = value >> 16;
rpnexpr[rpnptr++] = value >> 24; rpnexpr[rpnptr++] = value >> 24;
} else { } else {
struct sSymbol *sym; struct sSymbol *sym = sym_FindSymbol(tzSym);
if ((sym = sym_FindSymbol(tzSym)) == NULL)
if (sym == NULL)
break; break;
symptr = addsymbol(sym); symptr = addsymbol(sym);
rpnexpr[rpnptr++] = RPN_SYM; rpnexpr[rpnptr++] = RPN_SYM;
rpnexpr[rpnptr++] = symptr & 0xFF; rpnexpr[rpnptr++] = symptr & 0xFF;
@@ -415,26 +430,46 @@ createpatch(ULONG type, struct Expression * expr)
rpnexpr[rpnptr++] = symptr >> 24; rpnexpr[rpnptr++] = symptr >> 24;
} }
break; break;
case RPN_BANK: { case RPN_BANK_SYM:
{
struct sSymbol *sym; struct sSymbol *sym;
symptr = 0; symptr = 0;
while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0); while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0)
if ((sym = sym_FindSymbol(tzSym)) == NULL) ;
sym = sym_FindSymbol(tzSym);
if (sym == NULL)
break; break;
symptr = addsymbol(sym); symptr = addsymbol(sym);
rpnexpr[rpnptr++] = RPN_BANK; rpnexpr[rpnptr++] = RPN_BANK_SYM;
rpnexpr[rpnptr++] = symptr & 0xFF; rpnexpr[rpnptr++] = symptr & 0xFF;
rpnexpr[rpnptr++] = symptr >> 8; rpnexpr[rpnptr++] = symptr >> 8;
rpnexpr[rpnptr++] = symptr >> 16; rpnexpr[rpnptr++] = symptr >> 16;
rpnexpr[rpnptr++] = symptr >> 24; rpnexpr[rpnptr++] = symptr >> 24;
}
break; 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: default:
rpnexpr[rpnptr++] = rpndata; rpnexpr[rpnptr++] = rpndata;
break; break;
} }
} }
if ((pPatch->pRPN = malloc(rpnptr)) != NULL) {
pPatch->pRPN = malloc(rpnptr);
if (pPatch->pRPN != NULL) {
memcpy(pPatch->pRPN, rpnexpr, rpnptr); memcpy(pPatch->pRPN, rpnexpr, rpnptr);
pPatch->nRPNSize = rpnptr; pPatch->nRPNSize = rpnptr;
} }
@@ -443,12 +478,9 @@ createpatch(ULONG type, struct Expression * expr)
/* /*
* A quick check to see if we have an initialized section * A quick check to see if we have an initialized section
*/ */
void static void checksection(void)
checksection(void)
{ {
if (pCurrentSection) if (pCurrentSection == NULL)
return;
else
fatalerror("Code generation before SECTION directive"); fatalerror("Code generation before SECTION directive");
} }
@@ -456,14 +488,13 @@ checksection(void)
* A quick check to see if we have an initialized section that can contain * A quick check to see if we have an initialized section that can contain
* this much initialized data * this much initialized data
*/ */
void static void checkcodesection(void)
checkcodesection(void)
{ {
checksection(); checksection();
if (pCurrentSection->nType != SECT_ROM0 && if (pCurrentSection->nType != SECT_ROM0 &&
pCurrentSection->nType != SECT_ROMX) { pCurrentSection->nType != SECT_ROMX) {
fatalerror("Section '%s' cannot contain code or data (not ROM0 or ROMX)", fatalerror("Section '%s' cannot contain code or data (not ROM0 or ROMX)",
pCurrentSection->pzName); pCurrentSection->pzName);
} else if (nUnionDepth > 0) { } else if (nUnionDepth > 0) {
fatalerror("UNIONs cannot contain code or data"); fatalerror("UNIONs cannot contain code or data");
} }
@@ -472,10 +503,9 @@ checkcodesection(void)
/* /*
* Check if the section has grown too much. * Check if the section has grown too much.
*/ */
void static void checksectionoverflow(uint32_t delta_size)
checksectionoverflow(ULONG delta_size)
{ {
ULONG maxsize = getmaxsectionsize(pCurrentSection->nType, uint32_t maxsize = getmaxsectionsize(pCurrentSection->nType,
pCurrentSection->pzName); pCurrentSection->pzName);
if (pCurrentSection->nPC + delta_size > maxsize) { if (pCurrentSection->nPC + delta_size > maxsize) {
@@ -487,51 +517,55 @@ checksectionoverflow(ULONG delta_size)
* The real check must be done at the linking stage. * The real check must be done at the linking stage.
*/ */
fatalerror("Section '%s' is too big (max size = 0x%X bytes).", fatalerror("Section '%s' is too big (max size = 0x%X bytes).",
pCurrentSection->pzName, maxsize); pCurrentSection->pzName, maxsize);
} }
} }
/* /*
* Write an objectfile * Write an objectfile
*/ */
void void out_WriteObject(void)
out_WriteObject(void)
{ {
FILE *f; FILE *f;
addexports(); addexports();
if ((f = fopen(tzObjectname, "wb")) != NULL) { /* If no path specified, don't write file */
struct PatchSymbol *pSym; if (tzObjectname == NULL)
struct Section *pSect; return;
fwrite(RGBDS_OBJECT_VERSION_STRING, 1, f = fopen(tzObjectname, "wb");
strlen(RGBDS_OBJECT_VERSION_STRING), f); if (f == NULL)
fatalerror("Couldn't write file '%s'\n", tzObjectname);
fputlong(countsymbols(), f); struct PatchSymbol *pSym;
fputlong(countsections(), f); struct Section *pSect;
pSym = pPatchSymbols; fwrite(RGBDS_OBJECT_VERSION_STRING, 1,
while (pSym) { strlen(RGBDS_OBJECT_VERSION_STRING), f);
writesymbol(pSym->pSymbol, f);
pSym = pSym->pNext;
}
pSect = pSectionList; fputlong(countsymbols(), f);
while (pSect) { fputlong(countsections(), f);
writesection(pSect, f);
pSect = pSect->pNext;
}
fclose(f); pSym = pPatchSymbols;
while (pSym) {
writesymbol(pSym->pSymbol, f);
pSym = pSym->pNext;
} }
pSect = pSectionList;
while (pSect) {
writesection(pSect, f);
pSect = pSect->pNext;
}
fclose(f);
} }
/* /*
* Prepare for pass #2 * Prepare for pass #2
*/ */
void void out_PrepPass2(void)
out_PrepPass2(void)
{ {
struct Section *pSect; struct Section *pSect;
@@ -547,23 +581,22 @@ out_PrepPass2(void)
/* /*
* Set the objectfilename * Set the objectfilename
*/ */
void void out_SetFileName(char *s)
out_SetFileName(char *s)
{ {
tzObjectname = s; tzObjectname = s;
if (CurrentOptions.verbose) { if (CurrentOptions.verbose)
printf("Output filename %s\n", s); printf("Output filename %s\n", s);
}
pSectionList = NULL; pSectionList = NULL;
pCurrentSection = NULL; pCurrentSection = NULL;
pPatchSymbols = NULL; pPatchSymbols = NULL;
} }
/* /*
* Find a section by name and type. If it doesn't exist, create it * Find a section by name and type. If it doesn't exist, create it
*/ */
struct Section * struct Section *out_FindSection(char *pzName, uint32_t secttype, int32_t org,
out_FindSection(char *pzName, ULONG secttype, SLONG org, SLONG bank, SLONG alignment) int32_t bank, int32_t alignment)
{ {
struct Section *pSect, **ppSect; struct Section *pSect, **ppSect;
@@ -573,57 +606,60 @@ out_FindSection(char *pzName, ULONG secttype, SLONG org, SLONG bank, SLONG align
while (pSect) { while (pSect) {
if (strcmp(pzName, pSect->pzName) == 0) { if (strcmp(pzName, pSect->pzName) == 0) {
if (secttype == pSect->nType if (secttype == pSect->nType
&& ((ULONG) org) == pSect->nOrg && ((uint32_t)org) == pSect->nOrg
&& ((ULONG) bank) == pSect->nBank && ((uint32_t)bank) == pSect->nBank
&& ((ULONG) alignment == pSect->nAlign)) { && ((uint32_t)alignment == pSect->nAlign)) {
return (pSect); return pSect;
} else }
fatalerror
("Section already exists but with a different type"); fatalerror("Section already exists but with a different type");
} }
ppSect = &(pSect->pNext); ppSect = &(pSect->pNext);
pSect = pSect->pNext; pSect = pSect->pNext;
} }
if ((*ppSect = (pSect = malloc(sizeof(struct Section)))) != NULL) { pSect = malloc(sizeof(struct Section));
if ((pSect->pzName = malloc(strlen(pzName) + 1)) != NULL) { *ppSect = pSect;
strcpy(pSect->pzName, pzName); if (pSect == NULL)
pSect->nType = secttype;
pSect->nPC = 0;
pSect->nOrg = org;
pSect->nBank = bank;
pSect->nAlign = alignment;
pSect->pNext = NULL;
pSect->pPatches = NULL;
pSect->charmap = NULL;
pPatchSymbols = NULL;
pSect->tData = NULL;
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"); fatalerror("Not enough memory for section");
return (NULL); 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;
pSect->nOrg = org;
pSect->nBank = bank;
pSect->nAlign = alignment;
pSect->pNext = NULL;
pSect->pPatches = NULL;
pSect->charmap = NULL;
pPatchSymbols = NULL;
/* It is only needed to allocate memory for ROM sections. */
if (secttype == SECT_ROM0 || secttype == SECT_ROMX) {
uint32_t sectsize;
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 * Set the current section
*/ */
void void out_SetCurrentSection(struct Section *pSect)
out_SetCurrentSection(struct Section * pSect)
{ {
if (nUnionDepth > 0) { if (nUnionDepth > 0)
fatalerror("Cannot change the section within a UNION"); fatalerror("Cannot change the section within a UNION");
}
pCurrentSection = pSect; pCurrentSection = pSect;
nPC = pSect->nPC; nPC = pSect->nPC;
@@ -635,8 +671,7 @@ out_SetCurrentSection(struct Section * pSect)
/* /*
* Set the current section by name and type * Set the current section by name and type
*/ */
void void out_NewSection(char *pzName, uint32_t secttype)
out_NewSection(char *pzName, ULONG secttype)
{ {
out_SetCurrentSection(out_FindSection(pzName, secttype, -1, -1, 1)); out_SetCurrentSection(out_FindSection(pzName, secttype, -1, -1, 1));
} }
@@ -644,8 +679,8 @@ out_NewSection(char *pzName, ULONG secttype)
/* /*
* Set the current section by name and type * Set the current section by name and type
*/ */
void void out_NewAbsSection(char *pzName, uint32_t secttype, int32_t org,
out_NewAbsSection(char *pzName, ULONG secttype, SLONG org, SLONG bank) int32_t bank)
{ {
out_SetCurrentSection(out_FindSection(pzName, secttype, org, bank, 1)); out_SetCurrentSection(out_FindSection(pzName, secttype, org, bank, 1));
} }
@@ -653,20 +688,20 @@ out_NewAbsSection(char *pzName, ULONG secttype, SLONG org, SLONG bank)
/* /*
* Set the current section by name and type, using a given byte alignment * Set the current section by name and type, using a given byte alignment
*/ */
void void out_NewAlignedSection(char *pzName, uint32_t secttype, int32_t alignment,
out_NewAlignedSection(char *pzName, ULONG secttype, SLONG alignment, SLONG bank) int32_t bank)
{ {
if (alignment < 0 || alignment > 16) { if (alignment < 0 || alignment > 16)
yyerror("Alignment must be between 0-16 bits."); 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 (bypassing ROM/union checks) * Output an absolute byte (bypassing ROM/union checks)
*/ */
void void out_AbsByteBypassCheck(int32_t b)
out_AbsByteBypassCheck(int b)
{ {
checksectionoverflow(1); checksectionoverflow(1);
b &= 0xFF; b &= 0xFF;
@@ -681,15 +716,13 @@ out_AbsByteBypassCheck(int b)
/* /*
* Output an absolute byte * Output an absolute byte
*/ */
void void out_AbsByte(int32_t b)
out_AbsByte(int b)
{ {
checkcodesection(); checkcodesection();
out_AbsByteBypassCheck(b); out_AbsByteBypassCheck(b);
} }
void void out_AbsByteGroup(char *s, int32_t length)
out_AbsByteGroup(char *s, int length)
{ {
checkcodesection(); checkcodesection();
checksectionoverflow(length); checksectionoverflow(length);
@@ -700,8 +733,7 @@ out_AbsByteGroup(char *s, int length)
/* /*
* Skip this many bytes * Skip this many bytes
*/ */
void void out_Skip(int32_t skip)
out_Skip(int skip)
{ {
checksection(); checksection();
checksectionoverflow(skip); checksectionoverflow(skip);
@@ -723,8 +755,7 @@ out_Skip(int skip)
/* /*
* Output a NULL terminated string (excluding the NULL-character) * Output a NULL terminated string (excluding the NULL-character)
*/ */
void void out_String(char *s)
out_String(char *s)
{ {
checkcodesection(); checkcodesection();
checksectionoverflow(strlen(s)); checksectionoverflow(strlen(s));
@@ -733,12 +764,10 @@ out_String(char *s)
} }
/* /*
* Output a relocatable byte. Checking will be done to see if it * Output a relocatable byte. Checking will be done to see if it
* is an absolute value in disguise. * is an absolute value in disguise.
*/ */
void out_RelByte(struct Expression *expr)
void
out_RelByte(struct Expression * expr)
{ {
checkcodesection(); checkcodesection();
checksectionoverflow(1); checksectionoverflow(1);
@@ -750,17 +779,16 @@ out_RelByte(struct Expression * expr)
pCurrentSection->nPC += 1; pCurrentSection->nPC += 1;
nPC += 1; nPC += 1;
pPCSymbol->nValue += 1; pPCSymbol->nValue += 1;
} else } else {
out_AbsByte(expr->nVal); out_AbsByte(expr->nVal);
}
rpn_Reset(expr); rpn_Reset(expr);
} }
/* /*
* Output an absolute word * Output an absolute word
*/ */
void void out_AbsWord(int32_t b)
out_AbsWord(int b)
{ {
checkcodesection(); checkcodesection();
checksectionoverflow(2); checksectionoverflow(2);
@@ -775,13 +803,12 @@ out_AbsWord(int b)
} }
/* /*
* Output a relocatable word. Checking will be done to see if * Output a relocatable word. Checking will be done to see if
* it's an absolute value in disguise. * it's an absolute value in disguise.
*/ */
void void out_RelWord(struct Expression *expr)
out_RelWord(struct Expression * expr)
{ {
ULONG b; uint32_t b;
checkcodesection(); checkcodesection();
checksectionoverflow(2); checksectionoverflow(2);
@@ -795,19 +822,19 @@ out_RelWord(struct Expression * expr)
pCurrentSection->nPC += 2; pCurrentSection->nPC += 2;
nPC += 2; nPC += 2;
pPCSymbol->nValue += 2; pPCSymbol->nValue += 2;
} else } else {
out_AbsWord(expr->nVal); out_AbsWord(expr->nVal);
}
rpn_Reset(expr); rpn_Reset(expr);
} }
/* /*
* Output an absolute longword * Output an absolute longword
*/ */
void void out_AbsLong(int32_t b)
out_AbsLong(SLONG b)
{ {
checkcodesection(); checkcodesection();
checksectionoverflow(sizeof(SLONG)); checksectionoverflow(sizeof(int32_t));
if (nPass == 2) { if (nPass == 2) {
pCurrentSection->tData[nPC] = b & 0xFF; pCurrentSection->tData[nPC] = b & 0xFF;
pCurrentSection->tData[nPC + 1] = b >> 8; pCurrentSection->tData[nPC + 1] = b >> 8;
@@ -820,13 +847,12 @@ out_AbsLong(SLONG b)
} }
/* /*
* Output a relocatable longword. Checking will be done to see if * Output a relocatable longword. Checking will be done to see if
* is an absolute value in disguise. * is an absolute value in disguise.
*/ */
void void out_RelLong(struct Expression *expr)
out_RelLong(struct Expression * expr)
{ {
SLONG b; int32_t b;
checkcodesection(); checkcodesection();
checksectionoverflow(4); checksectionoverflow(4);
@@ -842,43 +868,53 @@ out_RelLong(struct Expression * expr)
pCurrentSection->nPC += 4; pCurrentSection->nPC += 4;
nPC += 4; nPC += 4;
pPCSymbol->nValue += 4; pPCSymbol->nValue += 4;
} else } else {
out_AbsLong(expr->nVal); out_AbsLong(expr->nVal);
}
rpn_Reset(expr); rpn_Reset(expr);
} }
/* /*
* Output a PC-relative byte * Output a PC-relative relocatable byte. Checking will be done to see if it
* is an absolute value in disguise.
*/ */
void void out_PCRelByte(struct Expression *expr)
out_PCRelByte(struct Expression * expr)
{ {
SLONG b = expr->nVal;
checkcodesection(); checkcodesection();
checksectionoverflow(1); checksectionoverflow(1);
b = (b & 0xFFFF) - (nPC + 1); if (rpn_isReloc(expr)) {
if (nPass == 2 && (b < -128 || b > 127)) if (nPass == 2) {
yyerror("PC-relative value must be 8-bit"); pCurrentSection->tData[nPC] = 0;
createpatch(PATCH_BYTE_JR, expr);
}
pCurrentSection->nPC += 1;
nPC += 1;
pPCSymbol->nValue += 1;
} else {
int32_t b = expr->nVal;
out_AbsByte(b); b = (int16_t)((b & 0xFFFF) - (nPC + 1));
if (nPass == 2 && ((b < -128) || (b > 127)))
yyerror("PC-relative value must be 8-bit");
out_AbsByte(b & 0xFF);
}
rpn_Reset(expr); rpn_Reset(expr);
} }
/* /*
* Output a binary file * Output a binary file
*/ */
void void out_BinaryFile(char *s)
out_BinaryFile(char *s)
{ {
FILE *f; FILE *f;
f = fstk_FindFile(s); f = fstk_FindFile(s);
if (f == NULL) { if (f == NULL)
err(1, "Unable to open incbin file '%s'", s); err(1, "Unable to open incbin file '%s'", s);
}
SLONG fsize; int32_t fsize;
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
fsize = ftell(f); fsize = ftell(f);
@@ -888,8 +924,8 @@ out_BinaryFile(char *s)
checksectionoverflow(fsize); checksectionoverflow(fsize);
if (nPass == 2) { if (nPass == 2) {
SLONG dest = nPC; int32_t dest = nPC;
SLONG todo = fsize; int32_t todo = fsize;
while (todo--) while (todo--)
pCurrentSection->tData[dest++] = fgetc(f); pCurrentSection->tData[dest++] = fgetc(f);
@@ -900,8 +936,7 @@ out_BinaryFile(char *s)
fclose(f); fclose(f);
} }
void void out_BinaryFileSlice(char *s, int32_t start_pos, int32_t length)
out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length)
{ {
FILE *f; FILE *f;
@@ -912,11 +947,10 @@ out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length)
fatalerror("Number of bytes to read must be greater than zero"); fatalerror("Number of bytes to read must be greater than zero");
f = fstk_FindFile(s); f = fstk_FindFile(s);
if (f == NULL) { if (f == NULL)
err(1, "Unable to open included file '%s'", s); err(1, "Unable to open included file '%s'", s);
}
SLONG fsize; int32_t fsize;
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
fsize = ftell(f); fsize = ftell(f);
@@ -933,8 +967,8 @@ out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length)
checksectionoverflow(length); checksectionoverflow(length);
if (nPass == 2) { if (nPass == 2) {
SLONG dest = nPC; int32_t dest = nPC;
SLONG todo = length; int32_t todo = length;
while (todo--) while (todo--)
pCurrentSection->tData[dest++] = fgetc(f); pCurrentSection->tData[dest++] = fgetc(f);

View File

@@ -1,18 +1,11 @@
.\" Copyright © 2010 Anthony J. Bentley <anthony@anjbe.name>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" This file is part of RGBDS.
.\" 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 .\" Copyright (c) 2010-2018, Anthony J. Bentley and RGBDS contributors.
.\" 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.
.\" .\"
.Dd April 17, 2017 .\" SPDX-License-Identifier: MIT
.\"
.Dd February 24, 2018
.Dt RGBASM 1 .Dt RGBASM 1
.Os RGBDS Manual .Os RGBDS Manual
.Sh NAME .Sh NAME
@@ -20,7 +13,7 @@
.Nd Game Boy assembler .Nd Game Boy assembler
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm rgbasm .Nm rgbasm
.Op Fl EhVvw .Op Fl EhLVvw
.Op Fl b Ar chars .Op Fl b Ar chars
.Op Fl D Ar name Ns Op = Ns Ar value .Op Fl D Ar name Ns Op = Ns Ar value
.Op Fl g Ar chars .Op Fl g Ar chars
@@ -62,6 +55,12 @@ The
option disables this behavior. option disables this behavior.
.It Fl i Ar path .It Fl i Ar path
Add an include path. Add an include path.
.It Fl L
Disable the optimization that turns loads of the form
.Sy LD [$FF00+n8],A
into the opcode
.Sy LDH [$FF00+n8],A
in order to have full control of the result in the final ROM.
.It Fl M Ar dependfile .It Fl M Ar dependfile
Print Print
.Xr make 1 .Xr make 1
@@ -82,7 +81,9 @@ Disable warning output.
.Sh EXAMPLES .Sh EXAMPLES
Assembling a basic source file is simple: Assembling a basic source file is simple:
.Pp .Pp
.D1 $ rgbasm -o bar.o foo.asm .Bd -literal -offset indent
$ rgbasm -o bar.o foo.asm
.Ed
.Pp .Pp
The resulting object file is not yet a usable ROM image \(em it must first be The resulting object file is not yet a usable ROM image \(em it must first be
run through run through

View File

@@ -1,18 +1,11 @@
.\" Copyright (c) 2017 Antonio Nino Diaz <antonio_nd@outlook.com>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" This file is part of RGBDS.
.\" 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 .\" Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
.\" 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.
.\" .\"
.Dd July 22, 2017 .\" SPDX-License-Identifier: MIT
.\"
.Dd March 13, 2018
.Dt RGBASM 5 .Dt RGBASM 5
.Os RGBDS Manual .Os RGBDS Manual
.Sh NAME .Sh NAME
@@ -33,16 +26,46 @@ one instruction or pseudoop per line:
.Pp .Pp
Example: Example:
.Pp .Pp
.Dl John: ld a,87 ;Weee .Bd -literal -offset indent
John: ld a,87 ;Weee
.Ed
.Pp .Pp
All pseudoops, mnemonics and registers (reserved keywords) are caseinsensitive All pseudoops, mnemonics and registers (reserved keywords) are caseinsensitive
and all labels are casesensitive. and all labels are casesensitive.
.Pp
There are two syntaxes for comments. In both cases, a comment ends at the end of
the line. The most common one is: anything that follows a semicolon
\[dq]\&;\[dq] (that isn't inside a string) is a comment. There is another
format: anything that follows a \[dq]*\[dq] that is placed right at the start of
a line is a comment. The assembler removes all comments from the code before
doing anything else.
.Pp
Sometimes lines can be too long and it may be necessary to split them. The
syntax to do so is the following one:
.Pp
.Bd -literal -offset indent
DB 1, 2, 3, 4 \[rs]
5, 6, 7, 8
.Ed
.Pp
This works anywhere in the code except inside of strings. To split strings it is
needed to use
.Sy STRCAT
like this:
.Pp
.Bd -literal -offset indent
DB STRCAT("Hello ", \[rs]
"world!")
.Ed
.Pp
.Ss Sections .Ss Sections
Before you can start writing code, you must define a section. Before you can start writing code, you must define a section.
This tells the assembler what kind of information follows and, if it is code, This tells the assembler what kind of information follows and, if it is code,
where to put it. where to put it.
.Pp .Pp
.Dl SECTION \[dq]CoolStuff\[dq],ROMX .Bd -literal -offset indent
SECTION \[dq]CoolStuff\[dq],ROMX
.Ed
.Pp .Pp
This switches to the section called "CoolStuff" (or creates it if it doesn't This switches to the section called "CoolStuff" (or creates it if it doesn't
already exist) and it defines it as a code section. already exist) and it defines it as a code section.
@@ -111,7 +134,13 @@ and
.Sy LDH A,[$FF00+n8] .Sy LDH A,[$FF00+n8]
syntax instead. syntax instead.
This forces the assembler to emit the correct instruction and the linker to This forces the assembler to emit the correct instruction and the linker to
check if the value is in the correct range. check if the value is in the correct range. This optimization can be disabled
by passing the
.Fl L
flag to
.Sy rgbasm
as explained in
.Xr rgbasm 1 .
.El .El
.Pp .Pp
A section is usually defined as a floating one, but the code can restrict where A section is usually defined as a floating one, but the code can restrict where
@@ -123,22 +152,30 @@ obligation to follow any specific rules.
The following example defines a section that can be placed anywhere in any ROMX The following example defines a section that can be placed anywhere in any ROMX
bank: bank:
.Pp .Pp
.Dl SECTION \[dq]CoolStuff\[dq],ROMX .Bd -literal -offset indent
SECTION \[dq]CoolStuff\[dq],ROMX
.Ed
.Pp .Pp
If it is needed, the following syntax can be used to fix the base address of the If it is needed, the following syntax can be used to fix the base address of the
section: section:
.Pp .Pp
.Dl SECTION \[dq]CoolStuff\[dq],ROMX[$4567] .Bd -literal -offset indent
SECTION \[dq]CoolStuff\[dq],ROMX[$4567]
.Ed
.Pp .Pp
It won't, however, fix the bank number, which is left to the linker. It won't, however, fix the bank number, which is left to the linker.
If you also want to specify the bank you can do: If you also want to specify the bank you can do:
.Pp .Pp
.Dl SECTION \[dq]CoolStuff\[dq],ROMX[$4567],BANK[3] .Bd -literal -offset indent
SECTION \[dq]CoolStuff\[dq],ROMX[$4567],BANK[3]
.Ed
.Pp .Pp
And if you only want to force the section into a certain bank, and not it's And if you only want to force the section into a certain bank, and not it's
position within the bank, that's also possible: position within the bank, that's also possible:
.Pp .Pp
.Dl SECTION \[dq]CoolStuff\[dq],ROMX,BANK[7] .Bd -literal -offset indent
SECTION \[dq]CoolStuff\[dq],ROMX,BANK[7]
.Ed
.Pp .Pp
In addition, you can specify byte alignment for a section. In addition, you can specify byte alignment for a section.
This ensures that the section starts at a memory address where the given number This ensures that the section starts at a memory address where the given number
@@ -150,9 +187,11 @@ However, if an alignment is specified, the base address must be left unassigned.
This can be useful when using DMA to copy data or when it is needed to align the This can be useful when using DMA to copy data or when it is needed to align the
start of an array to 256 bytes to optimize the code that accesses it. start of an array to 256 bytes to optimize the code that accesses it.
.Pp .Pp
.Dl SECTION \[dq]OAM Data\[dq],WRAM0,ALIGN[8] ; align to 256 bytes .Bd -literal -offset indent
.Pp SECTION \[dq]OAM Data\[dq],WRAM0,ALIGN[8] ; align to 256 bytes
.Dl SECTION \[dq]VRAM Data\[dq],ROMX,BANK[2],ALIGN[4] ; align to 16 bytes
SECTION \[dq]VRAM Data\[dq],ROMX,BANK[2],ALIGN[4] ; align to 16 bytes
.Ed
.Pp .Pp
HINT: If you think this is a lot of typing for doing a simple HINT: If you think this is a lot of typing for doing a simple
.Ic ORG .Ic ORG
@@ -250,8 +289,10 @@ EQUates are constant symbols.
They can, for example, be used for things such as bit-definitions of hardware They can, for example, be used for things such as bit-definitions of hardware
registers. registers.
.Pp .Pp
.Dl EXIT_OK EQU $00 .Bd -literal -offset indent
.Dl EXIT_FAILURE EQU $01 EXIT_OK EQU $00
EXIT_FAILURE EQU $01
.Ed
.Pp .Pp
Note that a colon (:) following the label-name is not allowed. Note that a colon (:) following the label-name is not allowed.
EQUates cannot be exported and imported. EQUates cannot be exported and imported.
@@ -273,7 +314,9 @@ Note that a colon (:) following the label-name is not allowed.
SETs cannot be exported and imported. SETs cannot be exported and imported.
Alternatively you can use = as a synonym for SET. Alternatively you can use = as a synonym for SET.
.Pp .Pp
.Dl COUNT = 2 .Bd -literal -offset indent
COUNT = 2
.Ed
.Pp .Pp
.It Sy RSSET , RSRESET , RB , RW .It Sy RSSET , RSRESET , RB , RW
.Pp .Pp
@@ -300,7 +343,7 @@ There are four commands in the RS group of commands:
.Pp .Pp
.Bl -column ".Sy String" ".Sy String" .Bl -column ".Sy String" ".Sy String"
.It Sy Command Ta Ta Ta Sy Meaning .It Sy Command Ta Ta Ta Sy Meaning
.It Ic RSRESET No Ta Ta Resets the _RS counter to zero. .It Ic RSRESET Ta Ta Resets the _RS counter to zero.
.It Ic RSSET Ar constexpr Ta Sets the .It Ic RSSET Ar constexpr Ta Sets the
.Ic _RS No counter to Ar constexpr . .Ic _RS No counter to Ar constexpr .
.It Ic RB Ar constexpr Ta Sets the preceding symbol to .It Ic RB Ar constexpr Ta Sets the preceding symbol to
@@ -325,10 +368,10 @@ If you are familiar with C you can think of it as the same as #define.
.Pp .Pp
.Bd -literal -offset indent .Bd -literal -offset indent
COUNTREG EQUS "[hl+]" COUNTREG EQUS "[hl+]"
ld a,COUNTREG ld a,COUNTREG
PLAYER_NAME EQUS \[dq]\[rs]\[dq]John\[rs]\[dq]\[dq] PLAYER_NAME EQUS \[dq]\[rs]\[dq]John\[rs]\[dq]\[dq]
db PLAYER_NAME db PLAYER_NAME
.Ed .Ed
.Pp .Pp
Note that : following the label-name is not allowed, and that strings must be Note that : following the label-name is not allowed, and that strings must be
@@ -336,12 +379,16 @@ quoted to be useful.
.Pp .Pp
This will be interpreted as: This will be interpreted as:
.Pp .Pp
.Dl ld a,[hl+] .Bd -literal -offset indent
.Dl db \[dq]John\[dq] ld a,[hl+]
db \[dq]John\[dq]
.Ed
.Pp .Pp
String-symbols can also be used to define small one-line macros: String-symbols can also be used to define small one-line macros:
.Pp .Pp
.Dl PUSHA EQUS \[dq]push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n\[dq] .Bd -literal -offset indent
PUSHA EQUS \[dq]push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n\[dq]
.Ed
.Pp .Pp
Note that a colon (:) following the label-name is not allowed. Note that a colon (:) following the label-name is not allowed.
String equates can't be exported or imported. String equates can't be exported or imported.
@@ -454,7 +501,9 @@ Now I can call the macro specifying two arguments.
The first being the address and the second being a bytecount. The first being the address and the second being a bytecount.
The macro will then reset all bytes in this range. The macro will then reset all bytes in this range.
.Pp .Pp
.Dl LoopyMacro MyVars,54 .Bd -literal -offset indent
LoopyMacro MyVars,54
.Ed
.Pp .Pp
Arguments are passed as string equates. Arguments are passed as string equates.
There's no need to enclose them in quotes. There's no need to enclose them in quotes.
@@ -474,6 +523,19 @@ In reality, up to 256 arguments can be passed to a macro, but you can only use
the first 9 like this. If you want to use the rest, you need to use the keyword the first 9 like this. If you want to use the rest, you need to use the keyword
.Ic SHIFT . .Ic SHIFT .
.Pp .Pp
Line continuations work as usual inside macros or lists of arguments of macros.
Strings, however, are a bit trickier. The following example shows how to use
strings as arguments for a macro:
.Pp
.Bd -literal -offset indent
PrintMacro : MACRO
PRINTT \[rs]1
ENDM
PrintMacro STRCAT(\[rs]\[dq]Hello\[rs]\[dq]\[rs], \[rs]
\[rs]\[dq] world\[rs]\[rs]n\[rs]\[dq])
.Ed
.Pp
.Ic SHIFT .Ic SHIFT
is a special command only available in macros. is a special command only available in macros.
Very useful in REPT-blocks. Very useful in REPT-blocks.
@@ -558,30 +620,39 @@ The following symbols are defined by the assembler:
.Ss Defining constant data .Ss Defining constant data
.Ic DB .Ic DB
defines a list of bytes that will be stored in the final image. defines a list of bytes that will be stored in the final image.
Ideal for tables and text. Ideal for tables and text (which is not zero-terminated).
.Pp .Pp
.Dl DB 1,2,3,4,\[dq]This is a string\[dq] .Bd -literal -offset indent
DB 1,2,3,4,\[dq]This is a string\[dq]
.Ed
.Pp .Pp
Alternatively, you can use Alternatively, you can use
.Ic DW .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 Strings are not allowed as arguments to
.Ic DW . .Ic DW
and
.Ic DL .
.Pp .Pp
You can also use You can also use
.Ic DB .Ic DB ,
and
.Ic DW .Ic DW
without arguments.
This works exactly like
.Sy DS 1
and 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 .Sy DS 2
and
.Sy DS 4
respectively. respectively.
Consequently, Consequently,
.Ic DB .Ic DB ,
and
.Ic DW .Ic DW
and
.Ic DL
can be used in a can be used in a
.Sy WRAM0 No / Sy WRAMX No / Sy HRAM No / Sy VRAM No / Sy SRAM .Sy WRAM0 No / Sy WRAMX No / Sy HRAM No / Sy VRAM No / Sy SRAM
section. section.
@@ -591,12 +662,15 @@ allocates a number of bytes.
The content is undefined. The content is undefined.
This is the preferred method of allocationg space in a RAM section. This is the preferred method of allocationg space in a RAM section.
You can, however, use You can, however, use
.Ic DB .Ic DB ,
and
.Ic DW .Ic DW
and
.Ic DL
without any arguments instead. without any arguments instead.
.Pp .Pp
.Dl DS str_SIZEOF ;allocate str_SIZEOF bytes .Bd -literal -offset indent
DS str_SIZEOF ;allocate str_SIZEOF bytes
.Ed
.Pp .Pp
.Ss Including binary files .Ss Including binary files
You probably have some graphics you'd like to include. You probably have some graphics you'd like to include.
@@ -606,15 +680,19 @@ to include a raw binary file as it is.
If the file isn't found in the current directory, the include-path list passed If the file isn't found in the current directory, the include-path list passed
to the linker on the command line will be searched. to the linker on the command line will be searched.
.Pp .Pp
.Dl INCBIN \[dq]titlepic.bin\[dq] .Bd -literal -offset indent
.Dl INCBIN \[dq]sprites/hero.bin\[dq]\ ; UNIX INCBIN \[dq]titlepic.bin\[dq]
.Dl INCBIN \[dq]sprites\[rs]\[rs]hero.bin\[dq]\ ; Windows INCBIN \[dq]sprites/hero.bin\[dq]\ ; UNIX
INCBIN \[dq]sprites\[rs]\[rs]hero.bin\[dq]\ ; Windows
.Ed
.Pp .Pp
You can also include only part of a file with You can also include only part of a file with
.Ic INCBIN . .Ic INCBIN .
The example below includes 256 bytes from data.bin starting from byte 78. The example below includes 256 bytes from data.bin starting from byte 78.
.Pp .Pp
.Dl INCBIN \[dq]data.bin\[dq],78,256 .Bd -literal -offset indent
INCBIN \[dq]data.bin\[dq],78,256
.Ed
.Ss Unions .Ss Unions
Unions allow multiple memory allocations to share the same space in memory, Unions allow multiple memory allocations to share the same space in memory,
like unions in C. like unions in C.
@@ -659,16 +737,19 @@ some important information.
.Pp .Pp
.Bd -literal -offset indent .Bd -literal -offset indent
PRINTT \[dq]I'm the greatest programmer in the whole wide world\[rs]n\[dq] PRINTT \[dq]I'm the greatest programmer in the whole wide world\[rs]n\[dq]
PRINTV (2+3)/5 PRINTI (2 + 3) / 5
PRINTF MUL(3.14,3987.0) PRINTV $FF00 + $F0
PRINTF MUL(3.14, 3987.0)
.Ed .Ed
.Pp .Pp
.Bl -inset .Bl -inset
.It Ic PRINTT .It Ic PRINTT
prints out a string. prints out a string.
.It Ic PRINTV .It Ic PRINTV
prints out an integer value or, as in the example, the result of a calculation. prints out an integer value in hexadecimal or, as in the example, the result of
Unsurprisingly, you can also print out a constant symbols value. a calculation. Unsurprisingly, you can also print out a constant symbols value.
.It Ic PRINTI
prints out a signed integer value.
.It Ic PRINTF .It Ic PRINTF
prints out a fixed point value. prints out a fixed point value.
.El .El
@@ -739,7 +820,9 @@ You may nest
.Ic INCLUDE .Ic INCLUDE
calls infinitely (or until you run out of memory, whichever comes first). calls infinitely (or until you run out of memory, whichever comes first).
.Pp .Pp
.Dl INCLUDE \[dq]irq.inc\[dq] .Bd -literal -offset indent
INCLUDE \[dq]irq.inc\[dq]
.Ed
.Pp .Pp
.Ss Conditional assembling .Ss Conditional assembling
The four commands The four commands
@@ -815,7 +898,9 @@ The last one, Gameboy graphics, is quite interesting and useful.
The values are actually pixel values and it converts the The values are actually pixel values and it converts the
.Do chunky Dc data to Do planar Dc data as used in the Gameboy. .Do chunky Dc data to Do planar Dc data as used in the Gameboy.
.Pp .Pp
.Dl DW \`01012323 .Bd -literal -offset indent
DW \`01012323
.Ed
.Pp .Pp
Admittedly, an expression with just a single number is quite boring. Admittedly, an expression with just a single number is quite boring.
To spice things up a bit there are a few operators you can use to perform To spice things up a bit there are a few operators you can use to perform
@@ -956,14 +1041,48 @@ new string.
the new string. the new string.
.El .El
.Pp .Pp
.Ss Character maps
.Pp
When writing text that is meant to be displayed in the Game Boy, the ASCII
characters used in the source code may not be the same ones used in the tileset
used in the ROM.
For example, the tiles used for uppercase letters may be placed starting at tile
index 128, which makes it difficult to add text strings to the ROM.
.Pp
Character maps allow the code to map strings up to 16 characters long to an
abitrary 8-bit value:
.Pp
.Bd -literal -offset indent
CHARMAP "<LF>", 10
CHARMAP "&iacute", 20
CHARMAP "A", 128
.Ed
.Pp
.Sy Note:
Character maps affect all strings in the file from the point in which they are
defined.
This means that any string that the code may want to print as debug information
will also be affected by it.
.Pp
.Sy Note:
The output value of a mapping can be 0.
If this happens, the assembler will treat this as the end of the string and the
rest of it will be trimmed.
.Pp
.Ss Other functions .Ss Other functions
There are a few other functions that do various useful things: There are a few other functions that do various useful things:
.Pp .Pp
.Bl -column ".Sy String" ".Sy String" .Bl -column ".Sy String" ".Sy String"
.It Sy Name Ta Ta Ta Sy Operation .It Sy Name Ta Ta Ta Sy Operation
.It Li BANK(label) Ta Returns the bank number label is in. .It Li BANK(\@/str/lbl) Ta Returns a bank number.
The linker will have to resolve this so it can't be used when the expression has If the argument is the symbol
to be constant. .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 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 .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. label or constant, or the top 8-bit register if it is a 16-bit register.
@@ -1032,10 +1151,12 @@ machine.
.It Sx ATAN .It Sx ATAN
.It Sx ATAN2 .It Sx ATAN2
.It Sx BANK .It Sx BANK
.It Sx CHARMAP
.It Sx COS .It Sx COS
.It Sx DB .It Sx DB
.It Sx DEF .It Sx DEF
.It Sx DIV .It Sx DIV
.It Sx DL
.It Sx DS .It Sx DS
.It Sx DW .It Sx DW
.It Sx ELIF .It Sx ELIF
@@ -1060,6 +1181,7 @@ machine.
.It Sx POPO .It Sx POPO
.It Sx POPS .It Sx POPS
.It Sx PRINTF .It Sx PRINTF
.It Sx PRINTI
.It Sx PRINTT .It Sx PRINTT
.It Sx PRINTV .It Sx PRINTV
.It Sx PURGE .It Sx PURGE

View File

@@ -1,20 +1,28 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
/* /*
* Controls RPN expressions for objectfiles * Controls RPN expressions for objectfiles
*/ */
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "asm/mylink.h"
#include "types.h"
#include "asm/symbol.h"
#include "asm/asm.h" #include "asm/asm.h"
#include "asm/main.h" #include "asm/main.h"
#include "asm/rpn.h" #include "asm/rpn.h"
#include "asm/symbol.h"
void #include "linkdefs.h"
mergetwoexpressions(struct Expression * expr, struct Expression * src1,
struct Expression * src2) void mergetwoexpressions(struct Expression *expr, const struct Expression *src1,
const struct Expression *src2)
{ {
*expr = *src1; *expr = *src1;
memcpy(&(expr->tRPN[expr->nRPNLength]), src2->tRPN, src2->nRPNLength); memcpy(&(expr->tRPN[expr->nRPNLength]), src2->tRPN, src2->nRPNLength);
@@ -23,13 +31,13 @@ mergetwoexpressions(struct Expression * expr, struct Expression * src1,
expr->isReloc |= src2->isReloc; expr->isReloc |= src2->isReloc;
expr->isPCRel |= src2->isPCRel; expr->isPCRel |= src2->isPCRel;
} }
#define joinexpr() mergetwoexpressions(expr,src1,src2)
#define joinexpr() mergetwoexpressions(expr, src1, src2)
/* /*
* Add a byte to the RPN expression * Add a byte to the RPN expression
*/ */
void void pushbyte(struct Expression *expr, int b)
pushbyte(struct Expression * expr, int b)
{ {
expr->tRPN[expr->nRPNLength++] = b & 0xFF; expr->tRPN[expr->nRPNLength++] = b & 0xFF;
} }
@@ -37,47 +45,45 @@ pushbyte(struct Expression * expr, int b)
/* /*
* Reset the RPN module * Reset the RPN module
*/ */
void void rpn_Reset(struct Expression *expr)
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 * Returns the next rpn byte in expression
*/ */
UWORD uint16_t rpn_PopByte(struct Expression *expr)
rpn_PopByte(struct Expression * expr)
{ {
if (expr->nRPNOut == expr->nRPNLength) { if (expr->nRPNOut == expr->nRPNLength)
return (0xDEAD); return 0xDEAD;
} else
return (expr->tRPN[expr->nRPNOut++]); return expr->tRPN[expr->nRPNOut++];
} }
/* /*
* Determine if the current expression is relocatable * Determine if the current expression is relocatable
*/ */
ULONG uint32_t rpn_isReloc(const struct Expression *expr)
rpn_isReloc(struct Expression * expr)
{ {
return (expr->isReloc); return expr->isReloc;
} }
/* /*
* Determine if the current expression can be pc-relative * Determine if the current expression can be pc-relative
*/ */
ULONG uint32_t rpn_isPCRelative(const struct Expression *expr)
rpn_isPCRelative(struct Expression * expr)
{ {
return (expr->isPCRel); return expr->isPCRel;
} }
/* /*
* Add symbols, constants and operators to expression * Add symbols, constants and operators to expression
*/ */
void void rpn_Number(struct Expression *expr, uint32_t i)
rpn_Number(struct Expression * expr, ULONG i)
{ {
rpn_Reset(expr); rpn_Reset(expr);
pushbyte(expr, RPN_CONST); pushbyte(expr, RPN_CONST);
@@ -88,11 +94,10 @@ rpn_Number(struct Expression * expr, ULONG i)
expr->nVal = i; expr->nVal = i;
} }
void void rpn_Symbol(struct Expression *expr, char *tzSym)
rpn_Symbol(struct Expression * expr, char *tzSym)
{ {
if (!sym_isConstant(tzSym)) { if (!sym_isConstant(tzSym)) {
struct sSymbol *psym; const struct sSymbol *psym;
rpn_Reset(expr); rpn_Reset(expr);
@@ -106,62 +111,96 @@ rpn_Symbol(struct Expression * expr, char *tzSym)
while (*tzSym) while (*tzSym)
pushbyte(expr, *tzSym++); pushbyte(expr, *tzSym++);
pushbyte(expr, 0); pushbyte(expr, 0);
} else } else {
rpn_Number(expr, sym_GetConstantValue(tzSym)); rpn_Number(expr, sym_GetConstantValue(tzSym));
}
} }
void void rpn_BankSelf(struct Expression *expr)
rpn_Bank(struct Expression * expr, char *tzSym)
{ {
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)) { if (!sym_isConstant(tzSym)) {
rpn_Reset(expr); 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); sym_GetValue(tzSym);
expr->isReloc = 1; expr->isReloc = 1;
pushbyte(expr, RPN_BANK); pushbyte(expr, RPN_BANK_SYM);
while (*tzSym) while (*tzSym)
pushbyte(expr, *tzSym++); pushbyte(expr, *tzSym++);
pushbyte(expr, 0); pushbyte(expr, 0);
} else } else {
yyerror("BANK argument must be a relocatable identifier"); yyerror("BANK argument must be a relocatable identifier");
}
} }
void void rpn_BankSection(struct Expression *expr, char *tzSectionName)
rpn_CheckHRAM(struct Expression * expr, struct Expression * src) {
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; *expr = *src;
pushbyte(expr, RPN_HRAM); pushbyte(expr, RPN_HRAM);
} }
void void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
rpn_LOGNOT(struct Expression * expr, struct Expression * src)
{ {
*expr = *src; *expr = *src;
pushbyte(expr, RPN_LOGUNNOT); pushbyte(expr, RPN_LOGUNNOT);
} }
void void rpn_LOGOR(struct Expression *expr, const struct Expression *src1,
rpn_LOGOR(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal || src2->nVal); expr->nVal = (expr->nVal || src2->nVal);
pushbyte(expr, RPN_LOGOR); pushbyte(expr, RPN_LOGOR);
} }
void void rpn_LOGAND(struct Expression *expr, const struct Expression *src1,
rpn_LOGAND(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal && src2->nVal); expr->nVal = (expr->nVal && src2->nVal);
pushbyte(expr, RPN_LOGAND); pushbyte(expr, RPN_LOGAND);
} }
void void rpn_HIGH(struct Expression *expr, const struct Expression *src)
rpn_HIGH(struct Expression * expr, struct Expression * src)
{ {
*expr = *src; *expr = *src;
@@ -184,8 +223,7 @@ rpn_HIGH(struct Expression * expr, struct Expression * src)
pushbyte(expr, RPN_AND); pushbyte(expr, RPN_AND);
} }
void void rpn_LOW(struct Expression *expr, const struct Expression *src)
rpn_LOW(struct Expression * expr, struct Expression * src)
{ {
*expr = *src; *expr = *src;
@@ -200,168 +238,150 @@ rpn_LOW(struct Expression * expr, struct Expression * src)
pushbyte(expr, RPN_AND); pushbyte(expr, RPN_AND);
} }
void void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1,
rpn_LOGEQU(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal == src2->nVal); expr->nVal = (expr->nVal == src2->nVal);
pushbyte(expr, RPN_LOGEQ); pushbyte(expr, RPN_LOGEQ);
} }
void void rpn_LOGGT(struct Expression *expr, const struct Expression *src1,
rpn_LOGGT(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal > src2->nVal); expr->nVal = (expr->nVal > src2->nVal);
pushbyte(expr, RPN_LOGGT); pushbyte(expr, RPN_LOGGT);
} }
void void rpn_LOGLT(struct Expression *expr, const struct Expression *src1,
rpn_LOGLT(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal < src2->nVal); expr->nVal = (expr->nVal < src2->nVal);
pushbyte(expr, RPN_LOGLT); pushbyte(expr, RPN_LOGLT);
} }
void void rpn_LOGGE(struct Expression *expr, const struct Expression *src1,
rpn_LOGGE(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal >= src2->nVal); expr->nVal = (expr->nVal >= src2->nVal);
pushbyte(expr, RPN_LOGGE); pushbyte(expr, RPN_LOGGE);
} }
void void rpn_LOGLE(struct Expression *expr, const struct Expression *src1,
rpn_LOGLE(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal <= src2->nVal); expr->nVal = (expr->nVal <= src2->nVal);
pushbyte(expr, RPN_LOGLE); pushbyte(expr, RPN_LOGLE);
} }
void void rpn_LOGNE(struct Expression *expr, const struct Expression *src1,
rpn_LOGNE(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal != src2->nVal); expr->nVal = (expr->nVal != src2->nVal);
pushbyte(expr, RPN_LOGNE); pushbyte(expr, RPN_LOGNE);
} }
void void rpn_ADD(struct Expression *expr, const struct Expression *src1,
rpn_ADD(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal + src2->nVal); expr->nVal = (expr->nVal + src2->nVal);
pushbyte(expr, RPN_ADD); pushbyte(expr, RPN_ADD);
} }
void void rpn_SUB(struct Expression *expr, const struct Expression *src1,
rpn_SUB(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal - src2->nVal); expr->nVal = (expr->nVal - src2->nVal);
pushbyte(expr, RPN_SUB); pushbyte(expr, RPN_SUB);
} }
void void rpn_XOR(struct Expression *expr, const struct Expression *src1,
rpn_XOR(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal ^ src2->nVal); expr->nVal = (expr->nVal ^ src2->nVal);
pushbyte(expr, RPN_XOR); pushbyte(expr, RPN_XOR);
} }
void void rpn_OR(struct Expression *expr, const struct Expression *src1,
rpn_OR(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal | src2->nVal); expr->nVal = (expr->nVal | src2->nVal);
pushbyte(expr, RPN_OR); pushbyte(expr, RPN_OR);
} }
void void rpn_AND(struct Expression *expr, const struct Expression *src1,
rpn_AND(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal & src2->nVal); expr->nVal = (expr->nVal & src2->nVal);
pushbyte(expr, RPN_AND); pushbyte(expr, RPN_AND);
} }
void void rpn_SHL(struct Expression *expr, const struct Expression *src1,
rpn_SHL(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal << src2->nVal); expr->nVal = (expr->nVal << src2->nVal);
pushbyte(expr, RPN_SHL); pushbyte(expr, RPN_SHL);
} }
void void rpn_SHR(struct Expression *expr, const struct Expression *src1,
rpn_SHR(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal >> src2->nVal); expr->nVal = (expr->nVal >> src2->nVal);
pushbyte(expr, RPN_SHR); pushbyte(expr, RPN_SHR);
} }
void void rpn_MUL(struct Expression *expr, const struct Expression *src1,
rpn_MUL(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
expr->nVal = (expr->nVal * src2->nVal); expr->nVal = (expr->nVal * src2->nVal);
pushbyte(expr, RPN_MUL); pushbyte(expr, RPN_MUL);
} }
void void rpn_DIV(struct Expression *expr, const struct Expression *src1,
rpn_DIV(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
if (src2->nVal == 0) { if (src2->nVal == 0)
fatalerror("division by zero"); fatalerror("division by zero");
}
expr->nVal = (expr->nVal / src2->nVal); expr->nVal = (expr->nVal / src2->nVal);
pushbyte(expr, RPN_DIV); pushbyte(expr, RPN_DIV);
} }
void void rpn_MOD(struct Expression *expr, const struct Expression *src1,
rpn_MOD(struct Expression * expr, struct Expression * src1, const struct Expression *src2)
struct Expression * src2)
{ {
joinexpr(); joinexpr();
if (src2->nVal == 0) { if (src2->nVal == 0)
fatalerror("division by zero"); fatalerror("division by zero");
}
expr->nVal = (expr->nVal % src2->nVal); expr->nVal = (expr->nVal % src2->nVal);
pushbyte(expr, RPN_MOD); pushbyte(expr, RPN_MOD);
} }
void void rpn_UNNEG(struct Expression *expr, const struct Expression *src)
rpn_UNNEG(struct Expression * expr, struct Expression * src)
{ {
*expr = *src; *expr = *src;
expr->nVal = -expr->nVal; expr->nVal = -expr->nVal;
pushbyte(expr, RPN_UNSUB); pushbyte(expr, RPN_UNSUB);
} }
void void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
rpn_UNNOT(struct Expression * expr, struct Expression * src)
{ {
*expr = *src; *expr = *src;
expr->nVal = expr->nVal ^ 0xFFFFFFFF; expr->nVal = ~expr->nVal;
pushbyte(expr, RPN_UNNOT); pushbyte(expr, RPN_UNNOT);
} }

File diff suppressed because it is too large Load Diff

50
src/extern/err.c vendored
View File

@@ -1,36 +1,22 @@
/* /*
* Copyright © 2005-2013 Rich Felker, et al. * This file is part of RGBDS.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Copyright (c) 2005-2018, Rich Felker and RGBDS contributors.
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
* *
* The above copyright notice and this permission notice shall be * SPDX-License-Identifier: MIT
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "extern/err.h" #include "extern/err.h"
void rgbds_vwarn(const char *fmt, va_list ap) void rgbds_vwarn(const char *fmt, va_list ap)
{ {
fprintf (stderr, "warning"); fprintf(stderr, "warning");
if (fmt) { if (fmt) {
fputs (": ", stderr); fputs(": ", stderr);
vfprintf(stderr, fmt, ap); vfprintf(stderr, fmt, ap);
} }
putc('\n', stderr); putc('\n', stderr);
@@ -39,9 +25,9 @@ void rgbds_vwarn(const char *fmt, va_list ap)
void rgbds_vwarnx(const char *fmt, va_list ap) void rgbds_vwarnx(const char *fmt, va_list ap)
{ {
fprintf (stderr, "warning"); fprintf(stderr, "warning");
if (fmt) { if (fmt) {
fputs (": ", stderr); fputs(": ", stderr);
vfprintf(stderr, fmt, ap); vfprintf(stderr, fmt, ap);
} }
putc('\n', stderr); putc('\n', stderr);
@@ -49,9 +35,9 @@ void rgbds_vwarnx(const char *fmt, va_list ap)
noreturn void rgbds_verr(int status, const char *fmt, va_list ap) noreturn void rgbds_verr(int status, const char *fmt, va_list ap)
{ {
fprintf (stderr, "error"); fprintf(stderr, "error");
if (fmt) { if (fmt) {
fputs (": ", stderr); fputs(": ", stderr);
vfprintf(stderr, fmt, ap); vfprintf(stderr, fmt, ap);
} }
putc('\n', stderr); putc('\n', stderr);
@@ -60,11 +46,11 @@ noreturn void rgbds_verr(int status, const char *fmt, va_list ap)
noreturn void rgbds_verrx(int status, const char *fmt, va_list ap) noreturn void rgbds_verrx(int status, const char *fmt, va_list ap)
{ {
fprintf (stderr, "error"); fprintf(stderr, "error");
if (fmt) { if (fmt) {
fputs (": ", stderr); fputs(": ", stderr);
vfprintf(stderr, fmt, ap); vfprintf(stderr, fmt, ap);
} }
putc('\n', stderr); putc('\n', stderr);
exit(status); exit(status);
} }
@@ -72,6 +58,7 @@ noreturn void rgbds_verrx(int status, const char *fmt, va_list ap)
void rgbds_warn(const char *fmt, ...) void rgbds_warn(const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
vwarn(fmt, ap); vwarn(fmt, ap);
va_end(ap); va_end(ap);
@@ -80,6 +67,7 @@ void rgbds_warn(const char *fmt, ...)
void rgbds_warnx(const char *fmt, ...) void rgbds_warnx(const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
vwarnx(fmt, ap); vwarnx(fmt, ap);
va_end(ap); va_end(ap);
@@ -88,6 +76,7 @@ void rgbds_warnx(const char *fmt, ...)
noreturn void rgbds_err(int status, const char *fmt, ...) noreturn void rgbds_err(int status, const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
verr(status, fmt, ap); verr(status, fmt, ap);
va_end(ap); va_end(ap);
@@ -96,6 +85,7 @@ noreturn void rgbds_err(int status, const char *fmt, ...)
noreturn void rgbds_errx(int status, const char *fmt, ...) noreturn void rgbds_errx(int status, const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
verrx(status, fmt, ap); verrx(status, fmt, ap);
va_end(ap); va_end(ap);

View File

@@ -1,38 +0,0 @@
/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
/*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
*
* 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 <sys/types.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
*/
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
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) {
errno = ENOMEM;
return NULL;
}
return realloc(optr, size * nmemb);
}

55
src/extern/strlcat.c vendored
View File

@@ -1,55 +0,0 @@
/* $OpenBSD: strlcat.c,v 1.14 2015/01/15 03:54:12 millert Exp $ */
/*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.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 <sys/types.h>
#include <string.h>
/*
* Appends src to string dst of size dsize (unlike strncat, dsize is the
* full size of dst, not space left). At most dsize-1 characters
* will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
* 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)
{
const char *odst = dst;
const char *osrc = src;
size_t n = dsize;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end. */
while (n-- != 0 && *dst != '\0')
dst++;
dlen = dst - odst;
n = dsize - dlen;
if (n-- == 0)
return(dlen + strlen(src));
while (*src != '\0') {
if (n != 0) {
*dst++ = *src;
n--;
}
src++;
}
*dst = '\0';
return(dlen + (src - osrc)); /* count does not include NUL */
}

50
src/extern/strlcpy.c vendored
View File

@@ -1,50 +0,0 @@
/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */
/*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.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 <sys/types.h>
#include <string.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)
{
const char *osrc = src;
size_t nleft = dsize;
/* Copy as many bytes as will fit. */
if (nleft != 0) {
while (--nleft != 0) {
if ((*dst++ = *src++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src. */
if (nleft == 0) {
if (dsize != 0)
*dst = '\0'; /* NUL-terminate dst */
while (*src++)
;
}
return(src - osrc - 1); /* count does not include NUL */
}

54
src/extern/utf8decoder.c vendored Normal file
View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2008-2009, Björn Höhrmann <bjoern@hoehrmann.de>
*
* SPDX-License-Identifier: MIT
*/
/*
* UTF-8 decoder: http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
*/
#include <stdint.h>
static const uint8_t utf8d[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00..0f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10..1f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20..2f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30..3f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40..4f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50..5f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60..6f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70..7f */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80..8f */
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, /* 90..9f */
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* a0..af */
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* b0..bf */
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* c0..cf */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* d0..df */
0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, /* e0..e7 */
0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, /* e8..ef */
0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, /* f0..f7 */
0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, /* f8..ff */
0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, /* s0.. */
0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, /* ..s0 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s1 */
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, /* s1 */
1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, /* s3 */
1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, /* s4 */
1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, /* s5 */
1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s6 */
1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s7 */
1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s8 */
};
uint32_t decode(uint32_t *state, uint32_t *codep, uint32_t byte)
{
uint32_t type = utf8d[byte];
*codep = (*state != 0) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*state = utf8d[256 + *state * 16 + type];
return *state;
}

34
src/extern/version.c vendored
View File

@@ -1,34 +0,0 @@
/*
* 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

@@ -1,17 +1,9 @@
/* /*
* Copyright © 2010 Anthony J. Bentley <anthonyjbentley@gmail.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2010-2018, Anthony J. Bentley and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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 <stdbool.h> #include <stdbool.h>
@@ -22,20 +14,19 @@
#include <unistd.h> #include <unistd.h>
#include "extern/err.h" #include "extern/err.h"
#include "extern/version.h"
static void #include "version.h"
usage(void)
static void print_usage(void)
{ {
printf( printf(
"usage: rgbfix [-CcjsVv] [-i game_id] [-k licensee_str] [-l licensee_id]\n" "usage: rgbfix [-CcjsVv] [-f fix_spec] [-i game_id] [-k licensee_str]\n"
" [-m mbc_type] [-n rom_version] [-p pad_value] [-r ram_size]\n" " [-l licensee_id] [-m mbc_type] [-n rom_version] [-p pad_value]\n"
" [-t title_str] file\n"); " [-r ram_size] [-t title_str] file\n");
exit(1); exit(1);
} }
int int main(int argc, char *argv[])
main(int argc, char *argv[])
{ {
FILE *rom; FILE *rom;
int ch; int ch;
@@ -46,7 +37,12 @@ main(int argc, char *argv[])
*/ */
/* all flags default to false unless options specify otherwise */ /* all flags default to false unless options specify otherwise */
bool validate = false; bool fixlogo = false;
bool fixheadsum = false;
bool fixglobalsum = false;
bool trashlogo = false;
bool trashheadsum = false;
bool trashglobalsum = false;
bool settitle = false; bool settitle = false;
bool setid = false; bool setid = false;
bool colorcompatible = false; bool colorcompatible = false;
@@ -70,7 +66,7 @@ main(int argc, char *argv[])
int version = 0; /* mask ROM version number */ int version = 0; /* mask ROM version number */
int padvalue = 0; /* to pad the rom with if it changes size */ 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:Vv")) != -1) { while ((ch = getopt(argc, argv, "Ccf:i:jk:l:m:n:p:sr:t:Vv")) != -1) {
switch (ch) { switch (ch) {
case 'C': case 'C':
coloronly = true; coloronly = true;
@@ -78,13 +74,20 @@ main(int argc, char *argv[])
case 'c': case 'c':
colorcompatible = true; colorcompatible = true;
break; break;
case 'f':
fixlogo = strchr(optarg, 'l');
fixheadsum = strchr(optarg, 'h');
fixglobalsum = strchr(optarg, 'g');
trashlogo = strchr(optarg, 'L');
trashheadsum = strchr(optarg, 'H');
trashglobalsum = strchr(optarg, 'G');
break;
case 'i': case 'i':
setid = true; setid = true;
if (strlen(optarg) != 4) { if (strlen(optarg) != 4)
errx(1, "Game ID %s must be exactly 4 " errx(1, "Game ID %s must be exactly 4 characters",
"characters", optarg); optarg);
}
id = optarg; id = optarg;
break; break;
@@ -94,10 +97,9 @@ main(int argc, char *argv[])
case 'k': case 'k':
setnewlicensee = true; setnewlicensee = true;
if (strlen(optarg) != 2) { if (strlen(optarg) != 2)
errx(1, "New licensee code %s is not the " errx(1, "New licensee code %s is not the correct length of 2 characters",
"correct length of 2 characters", optarg); optarg);
}
newlicensee = optarg; newlicensee = optarg;
break; break;
@@ -105,61 +107,59 @@ main(int argc, char *argv[])
setlicensee = true; setlicensee = true;
licensee = strtoul(optarg, &ep, 0); licensee = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') { if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'l'"); errx(1, "Invalid argument for option 'l'");
}
if (licensee < 0 || licensee > 0xFF) { if (licensee < 0 || licensee > 0xFF)
errx(1, "Argument for option 'l' must be " errx(1, "Argument for option 'l' must be between 0 and 255");
"between 0 and 255");
}
break; break;
case 'm': case 'm':
setcartridge = true; setcartridge = true;
cartridge = strtoul(optarg, &ep, 0); cartridge = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') { if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'm'"); errx(1, "Invalid argument for option 'm'");
}
if (cartridge < 0 || cartridge > 0xFF) { if (cartridge < 0 || cartridge > 0xFF)
errx(1, "Argument for option 'm' must be " errx(1, "Argument for option 'm' must be between 0 and 255");
"between 0 and 255");
}
break; break;
case 'n': case 'n':
setversion = true; setversion = true;
version = strtoul(optarg, &ep, 0); version = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'n'"); errx(1, "Invalid argument for option 'n'");
}
if (version < 0 || version > 0xFF) { if (version < 0 || version > 0xFF)
errx(1, "Argument for option 'n' must be " errx(1, "Argument for option 'n' must be between 0 and 255");
"between 0 and 255");
}
break; break;
case 'p': case 'p':
resize = true; resize = true;
padvalue = strtoul(optarg, &ep, 0); padvalue = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'p'"); errx(1, "Invalid argument for option 'p'");
}
if (padvalue < 0 || padvalue > 0xFF) { if (padvalue < 0 || padvalue > 0xFF)
errx(1, "Argument for option 'p' must be " errx(1, "Argument for option 'p' must be between 0 and 255");
"between 0 and 255");
}
break; break;
case 'r': case 'r':
setramsize = true; setramsize = true;
ramsize = strtoul(optarg, &ep, 0); ramsize = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') {
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'r'"); errx(1, "Invalid argument for option 'r'");
}
if (ramsize < 0 || ramsize > 0xFF) { if (ramsize < 0 || ramsize > 0xFF)
errx(1, "Argument for option 'r' must be " errx(1, "Argument for option 'r' must be between 0 and 255");
"between 0 and 255");
}
break; break;
case 's': case 's':
super = true; super = true;
@@ -167,14 +167,13 @@ main(int argc, char *argv[])
case 't': case 't':
settitle = true; settitle = true;
if (strlen(optarg) > 16) { if (strlen(optarg) > 16)
errx(1, "Title %s is greater than the " errx(1, "Title \"%s\" is greater than the maximum of 16 characters",
"maximum of 16 characters", optarg); optarg);
}
if (strlen(optarg) == 16) if (strlen(optarg) == 16)
warnx("Title %s is 16 chars, it is best to " warnx("Title \"%s\" is 16 chars, it is best to keep it to 15 or fewer",
"keep it to 15 or fewer", optarg); optarg);
title = optarg; title = optarg;
break; break;
@@ -182,10 +181,12 @@ main(int argc, char *argv[])
printf("rgbfix %s\n", get_package_version_string()); printf("rgbfix %s\n", get_package_version_string());
exit(0); exit(0);
case 'v': case 'v':
validate = true; fixlogo = true;
fixheadsum = true;
fixglobalsum = true;
break; break;
default: default:
usage(); print_usage();
/* NOTREACHED */ /* NOTREACHED */
} }
} }
@@ -194,21 +195,22 @@ main(int argc, char *argv[])
argv += optind; argv += optind;
if (argc == 0) if (argc == 0)
usage(); print_usage();
/* /*
* Open the ROM file * 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]); err(1, "Error opening file %s", argv[argc - 1]);
}
/* /*
* Write changes to ROM * Write changes to ROM
*/ */
if (validate) { if (fixlogo || trashlogo) {
/* /*
* Offset 0x1040x133: Nintendo Logo * Offset 0x1040x133: Nintendo Logo
* This is a bitmap image that displays when the Game Boy is * This is a bitmap image that displays when the Game Boy is
@@ -218,7 +220,7 @@ main(int argc, char *argv[])
/* /*
* See also: global checksums at 0x14D0x14F, They must * See also: global checksums at 0x14D0x14F, They must
* also be correct for the game to boot, so we fix them * also be correct for the game to boot, so we fix them
* as well when the -v flag is set. * as well when requested with the -f flag.
*/ */
uint8_t ninlogo[48] = { uint8_t ninlogo[48] = {
@@ -230,6 +232,10 @@ main(int argc, char *argv[])
0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E
}; };
if (trashlogo)
for (int i = 0; i < sizeof(ninlogo); i++)
ninlogo[i] = ~ninlogo[i];
fseek(rom, 0x104, SEEK_SET); fseek(rom, 0x104, SEEK_SET);
fwrite(ninlogo, 1, 48, rom); fwrite(ninlogo, 1, 48, rom);
} }
@@ -266,7 +272,7 @@ main(int argc, char *argv[])
* characters). * characters).
*/ */
fseek(rom,0x13F,SEEK_SET); fseek(rom, 0x13F, SEEK_SET);
fwrite(id, 1, 4, rom); fwrite(id, 1, 4, rom);
} }
@@ -332,8 +338,7 @@ main(int argc, char *argv[])
*/ */
if (!setlicensee) if (!setlicensee)
warnx("You should probably set both '-s' and " warnx("You should probably set both '-s' and '-l 0x33'");
"'-l 0x33'");
fseek(rom, 0x146, SEEK_SET); fseek(rom, 0x146, SEEK_SET);
fputc(3, rom); fputc(3, rom);
@@ -360,6 +365,7 @@ main(int argc, char *argv[])
long romsize, newsize; long romsize, newsize;
int headbyte; int headbyte;
uint8_t *buf; uint8_t *buf;
fseek(rom, 0, SEEK_END); fseek(rom, 0, SEEK_END);
romsize = ftell(rom); romsize = ftell(rom);
newsize = 0x8000; newsize = 0x8000;
@@ -428,38 +434,44 @@ main(int argc, char *argv[])
fputc(version, rom); fputc(version, rom);
} }
if (validate) { if (fixheadsum || trashheadsum) {
/* /*
* Offset 0x14D: Header Checksum * Offset 0x14D: Header Checksum
*/ */
uint8_t headcksum; uint8_t headcksum = 0;
headcksum = 0;
fseek(rom, 0x134, SEEK_SET); fseek(rom, 0x134, SEEK_SET);
for (int i = 0; i < (0x14D - 0x134); ++i) for (int i = 0; i < (0x14D - 0x134); ++i)
headcksum = headcksum - fgetc(rom) - 1; headcksum = headcksum - fgetc(rom) - 1;
if (trashheadsum)
headcksum = ~headcksum;
fseek(rom, 0x14D, SEEK_SET); fseek(rom, 0x14D, SEEK_SET);
fputc(headcksum, rom); fputc(headcksum, rom);
}
if (fixglobalsum || trashglobalsum) {
/* /*
* Offset 0x14E0x14F: Global Checksum * Offset 0x14E0x14F: Global Checksum
*/ */
uint16_t globalcksum; uint16_t globalcksum = 0;
globalcksum = 0;
rewind(rom); rewind(rom);
for (int i = 0; i < 0x14E; ++i) for (int i = 0; i < 0x14E; ++i)
globalcksum += fgetc(rom); globalcksum += fgetc(rom);
int byte; int byte;
fseek(rom, 0x150, SEEK_SET); fseek(rom, 0x150, SEEK_SET);
while ((byte = fgetc(rom)) != EOF) while ((byte = fgetc(rom)) != EOF)
globalcksum += byte; globalcksum += byte;
if (trashglobalsum)
globalcksum = ~globalcksum;
fseek(rom, 0x14E, SEEK_SET); fseek(rom, 0x14E, SEEK_SET);
fputc(globalcksum >> 8, rom); fputc(globalcksum >> 8, rom);
fputc(globalcksum & 0xFF, rom); fputc(globalcksum & 0xFF, rom);

View File

@@ -1,18 +1,11 @@
.\" Copyright © 2010 Anthony J. Bentley <anthony@anjbe.name>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" This file is part of RGBDS.
.\" 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 .\" Copyright (c) 2010-2017, Anthony J. Bentley and RGBDS contributors.
.\" 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.
.\" .\"
.Dd April 17, 2017 .\" SPDX-License-Identifier: MIT
.\"
.Dd March 11, 2018
.Dt RGBFIX 1 .Dt RGBFIX 1
.Os RGBDS Manual .Os RGBDS Manual
.Sh NAME .Sh NAME
@@ -21,6 +14,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm rgbfix .Nm rgbfix
.Op Fl CcjsVv .Op Fl CcjsVv
.Op Fl f Ar fix_spec
.Op Fl i Ar game_id .Op Fl i Ar game_id
.Op Fl k Ar licensee_str .Op Fl k Ar licensee_str
.Op Fl l Ar licensee_id .Op Fl l Ar licensee_id
@@ -53,6 +47,30 @@ If both this and the
flag are set, flag are set,
.Fl C .Fl C
takes precedence. takes precedence.
.It Fl f Ar fix_spec
Fix certain header values that the Game Boy checks for correctness.
Alternatively, intentionally trash these values by writing their binary inverse
instead.
.Ar fix_spec
is a string containing any combination of the following characters:
.Pp
.Bl -tag -compact -width xx
.It Cm l
Fix the Nintendo logo
.Pq Ad 0x104 Ns \(en Ns Ad 0x133 .
.It Cm L
Trash the Nintendo logo.
.It Cm h
Fix the header checksum
.Pq Ad 0x14D .
.It Cm H
Trash the header checksum.
.It Cm g
Fix the global checksum
.Pq Ad 0x14E Ns \(en Ns Ad 0x14F .
.It Cm G
Trash the global checksum.
.El
.It Fl i Ar game_id .It Fl i Ar game_id
Set the game ID string Set the game ID string
.Pq Ad 0x13F Ns \(en Ns Ad 0x142 .Pq Ad 0x13F Ns \(en Ns Ad 0x142
@@ -111,12 +129,8 @@ overlapping portion of the title.
.It Fl V .It Fl V
Print the version of the program and exit. Print the version of the program and exit.
.It Fl v .It Fl v
Validate the header and fix checksums: the Nintendo character area Equivalent to
.Pq Ad 0x104 Ns \(en Ns Ad 0x133 , .Fl f Cm lhg .
the header checksum
.Pq Ad 0x14D ,
and the global checksum
.Pq Ad 0x14E Ns \(en Ns Ad 0x14F .
.El .El
.Sh EXAMPLES .Sh EXAMPLES
Most values in the ROM header are only cosmetic. Most values in the ROM header are only cosmetic.

View File

@@ -1,18 +1,11 @@
.\" Copyright (c) 2017 Antonio Nino Diaz <antonio_nd@outlook.com>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" This file is part of RGBDS.
.\" 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 .\" Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
.\" 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.
.\" .\"
.Dd April 17, 2017 .\" SPDX-License-Identifier: MIT
.\"
.Dd February 23, 2018
.Dt GBZ80 7 .Dt GBZ80 7
.Os RGBDS Manual .Os RGBDS Manual
.Sh NAME .Sh NAME
@@ -31,8 +24,10 @@ as destination can omit the destination as it is assumed it's register
.Sy A . .Sy A .
The following two lines have the same effect: The following two lines have the same effect:
.Pp .Pp
.Dl OR A,B .Bd -literal -offset indent
.Dl OR B OR A,B
OR B
.Ed
.Pp .Pp
.Sh LEGEND .Sh LEGEND
List of abbreviations used in this document. List of abbreviations used in this document.
@@ -201,7 +196,7 @@ and
.It Sx PUSH AF .It Sx PUSH AF
.It Sx PUSH r16 .It Sx PUSH r16
.El .El
.Ss Miscelaneous Instructions .Ss Miscellaneous Instructions
.Bl -inset -compact .Bl -inset -compact
.It Sx CCF .It Sx CCF
.It Sx CPL .It Sx CPL
@@ -1669,7 +1664,7 @@ Flags: See
.Sx SRA r8 .Sx SRA r8
.Ss STOP .Ss STOP
Enter CPU very low power mode. Enter CPU very low power mode.
Also used to switch between doube speed and normal CPU modes in GBC. Also used to switch between double and normal speed CPU modes in GBC.
.Pp .Pp
Cycles: - Cycles: -
.Pp .Pp

View File

@@ -1,26 +1,18 @@
/* /*
* Copyright © 2013 stag019 <stag019@gmail.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2013-2018, stag019 and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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 <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "gfx/main.h" #include "gfx/main.h"
void void transpose_tiles(struct GBImage *gb, int width)
transpose_tiles(struct GBImage *gb, int width)
{ {
uint8_t *newdata; uint8_t *newdata;
int i; int i;
@@ -29,7 +21,9 @@ transpose_tiles(struct GBImage *gb, int width)
newdata = calloc(gb->size, 1); newdata = calloc(gb->size, 1);
for (i = 0; i < gb->size; i++) { for (i = 0; i < gb->size; i++) {
newbyte = i / (8 * depth) * width * 8 * depth; 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]; newdata[newbyte] = gb->data[i];
} }
@@ -38,67 +32,61 @@ transpose_tiles(struct GBImage *gb, int width)
gb->data = newdata; gb->data = newdata;
} }
void void raw_to_gb(const struct RawIndexedImage *raw_image, struct GBImage *gb)
png_to_gb(struct PNGImage png, struct GBImage *gb)
{ {
int x, y, byte; int x, y, byte;
png_byte index; uint8_t index;
for (y = 0; y < png.height; y++) { for (y = 0; y < raw_image->height; y++) {
for (x = 0; x < png.width; x++) { for (x = 0; x < raw_image->width; x++) {
index = png.data[y][x]; index = raw_image->data[y][x];
index &= (1 << depth) - 1; index &= (1 << depth) - 1;
if (!gb->horizontal) { byte = y * depth
byte = y * depth + x / 8 * png.height / 8 * 8 * depth; + x / 8 * raw_image->height / 8 * 8 * depth;
} else {
byte = y * depth + x / 8 * png.height / 8 * 8 * depth;
}
gb->data[byte] |= (index & 1) << (7 - x % 8); gb->data[byte] |= (index & 1) << (7 - x % 8);
if (depth == 2) { 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); transpose_tiles(gb, raw_image->width / 8);
}
} }
void void output_file(const struct Options *opts, const struct GBImage *gb)
output_file(struct Options opts, struct GBImage gb)
{ {
FILE *f; FILE *f;
f = fopen(opts.outfile, "wb"); f = fopen(opts->outfile, "wb");
if (!f) { if (!f)
err(1, "Opening output file '%s' failed", opts.outfile); err(1, "Opening output file '%s' failed", opts->outfile);
}
fwrite(gb.data, 1, gb.size - gb.trim * 8 * depth, f); fwrite(gb->data, 1, gb->size - gb->trim * 8 * depth, f);
fclose(f); fclose(f);
} }
int int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles, int tile_size)
get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles, int tile_size)
{ {
int i, j; int i, j;
for (i = 0; i < num_tiles; i++) { for (i = 0; i < num_tiles; i++) {
for (j = 0; j < tile_size; j++) { for (j = 0; j < tile_size; j++) {
if (tile[j] != tiles[i][j]) { if (tile[j] != tiles[i][j])
break; break;
}
} }
if (j >= tile_size) {
if (j >= tile_size)
return i; return i;
}
} }
return -1; return -1;
} }
void void create_tilemap(const struct Options *opts, struct GBImage *gb,
create_tilemap(struct Options opts, struct GBImage *gb, struct Tilemap *tilemap) struct Tilemap *tilemap)
{ {
int i, j; int i, j;
int gb_i; int gb_i;
@@ -113,10 +101,15 @@ create_tilemap(struct Options opts, struct GBImage *gb, struct Tilemap *tilemap)
tile_size = sizeof(uint8_t) * depth * 8; tile_size = sizeof(uint8_t) * depth * 8;
gb_size = gb->size - (gb->trim * tile_size); gb_size = gb->size - (gb->trim * tile_size);
max_tiles = gb_size / tile_size; max_tiles = gb_size / tile_size;
tiles = malloc(sizeof(uint8_t*) * max_tiles);
/* If the input image doesn't fill the last tile, increase the count. */
if (gb_size > max_tiles * tile_size)
max_tiles++;
tiles = calloc(max_tiles, sizeof(uint8_t *));
num_tiles = 0; num_tiles = 0;
tilemap->data = malloc(sizeof(uint8_t) * max_tiles); tilemap->data = calloc(max_tiles, sizeof(uint8_t));
tilemap->size = 0; tilemap->size = 0;
gb_i = 0; gb_i = 0;
@@ -126,8 +119,9 @@ create_tilemap(struct Options opts, struct GBImage *gb, struct Tilemap *tilemap)
tile[i] = gb->data[gb_i]; tile[i] = gb->data[gb_i];
gb_i++; gb_i++;
} }
if (opts.unique) { 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) { if (index < 0) {
index = num_tiles; index = num_tiles;
tiles[num_tiles] = tile; tiles[num_tiles] = tile;
@@ -142,62 +136,61 @@ create_tilemap(struct Options opts, struct GBImage *gb, struct Tilemap *tilemap)
tilemap->size++; tilemap->size++;
} }
if (opts.unique) { if (opts->unique) {
free(gb->data); free(gb->data);
gb->data = malloc(tile_size * num_tiles); gb->data = malloc(tile_size * num_tiles);
for (i = 0; i < num_tiles; i++) { for (i = 0; i < num_tiles; i++) {
tile = 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->data[i * tile_size + j] = tile[j];
}
} }
gb->size = i * tile_size; gb->size = i * tile_size;
} }
for (i = 0; i < num_tiles; i++) { for (i = 0; i < num_tiles; i++)
free(tiles[i]); free(tiles[i]);
}
free(tiles); free(tiles);
} }
void void output_tilemap_file(const struct Options *opts,
output_tilemap_file(struct Options opts, struct Tilemap tilemap) const struct Tilemap *tilemap)
{ {
FILE *f; FILE *f;
f = fopen(opts.mapfile, "wb"); f = fopen(opts->mapfile, "wb");
if (!f) { if (!f)
err(1, "Opening tilemap file '%s' failed", opts.mapfile); err(1, "Opening tilemap file '%s' failed", opts->mapfile);
}
fwrite(tilemap.data, 1, tilemap.size, f); fwrite(tilemap->data, 1, tilemap->size, f);
fclose(f); fclose(f);
if (opts.mapout) { if (opts->mapout)
free(opts.mapfile); free(opts->mapfile);
}
} }
void void output_palette_file(const struct Options *opts,
output_palette_file(struct Options opts, struct PNGImage png) const struct RawIndexedImage *raw_image)
{ {
FILE *f; FILE *f;
int i, colors, color; int i, color;
png_color *palette; uint8_t cur_bytes[2];
if (png_get_PLTE(png.png, png.info, &palette, &colors)) { f = fopen(opts->palfile, "wb");
f = fopen(opts.palfile, "wb"); if (!f)
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;
fwrite(&color, 2, 1, f);
}
fclose(f);
}
if (opts.palout) { for (i = 0; i < raw_image->num_colors; i++) {
free(opts.palfile); color =
raw_image->palette[i].blue >> 3 << 10 |
raw_image->palette[i].green >> 3 << 5 |
raw_image->palette[i].red >> 3;
cur_bytes[0] = color & 0xFF;
cur_bytes[1] = color >> 8;
fwrite(cur_bytes, 2, 1, f);
} }
fclose(f);
if (opts->palout)
free(opts->palfile);
} }

View File

@@ -1,28 +1,21 @@
/* /*
* Copyright © 2013 stag019 <stag019@gmail.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2013-2018, stag019 and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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 <png.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "extern/version.h"
#include "gfx/main.h" #include "gfx/main.h"
static void #include "version.h"
usage(void)
static void print_usage(void)
{ {
printf( printf(
"usage: rgbgfx [-DFfhPTuVv] [-d #] [-o outfile] [-p palfile] [-t mapfile]\n" "usage: rgbgfx [-DFfhPTuVv] [-d #] [-o outfile] [-p palfile] [-t mapfile]\n"
@@ -30,20 +23,19 @@ usage(void)
exit(1); exit(1);
} }
int int main(int argc, char *argv[])
main(int argc, char *argv[])
{ {
int ch, size; int ch, size;
struct Options opts = {0}; struct Options opts = {0};
struct PNGImage png = {0}; struct ImageOptions png_options = {0};
struct RawIndexedImage *raw_image;
struct GBImage gb = {0}; struct GBImage gb = {0};
struct Tilemap tilemap = {0}; struct Tilemap tilemap = {0};
char *ext; char *ext;
const char *errmsg = "Warning: The PNG's %s setting is not the same as the setting defined on the command line."; const char *errmsg = "Warning: The PNG's %s setting is not the same as the setting defined on the command line.";
if (argc == 1) { if (argc == 1)
usage(); print_usage();
}
opts.mapfile = ""; opts.mapfile = "";
opts.palfile = ""; opts.palfile = "";
@@ -51,8 +43,8 @@ main(int argc, char *argv[])
depth = 2; depth = 2;
while((ch = getopt(argc, argv, "Dd:Ffho:Tt:uPp:Vvx:")) != -1) { while ((ch = getopt(argc, argv, "Dd:Ffho:Tt:uPp:Vvx:")) != -1) {
switch(ch) { switch (ch) {
case 'D': case 'D':
opts.debug = true; opts.debug = true;
break; break;
@@ -95,108 +87,111 @@ main(int argc, char *argv[])
opts.trim = strtoul(optarg, NULL, 0); opts.trim = strtoul(optarg, NULL, 0);
break; break;
default: default:
usage(); print_usage();
/* NOTREACHED */ /* NOTREACHED */
} }
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (argc == 0) { if (argc == 0)
usage(); print_usage();
}
opts.infile = argv[argc - 1]; 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."); errx(1, "Depth option must be either 1 or 2.");
}
colors = 1 << depth; colors = 1 << depth;
input_png_file(opts, &png); raw_image = input_png_file(&opts, &png_options);
png.mapfile = ""; png_options.mapfile = "";
png.palfile = ""; png_options.palfile = "";
get_text(&png); if (png_options.horizontal != opts.horizontal) {
if (opts.verbose)
if (png.horizontal != opts.horizontal) {
if (opts.verbose) {
warnx(errmsg, "horizontal"); warnx(errmsg, "horizontal");
}
if (opts.hardfix) { if (opts.hardfix)
png.horizontal = opts.horizontal; png_options.horizontal = opts.horizontal;
}
}
if (png.horizontal) {
opts.horizontal = png.horizontal;
} }
if (png.trim != opts.trim) { if (png_options.horizontal)
if (opts.verbose) { opts.horizontal = png_options.horizontal;
if (png_options.trim != opts.trim) {
if (opts.verbose)
warnx(errmsg, "trim"); warnx(errmsg, "trim");
}
if (opts.hardfix) { if (opts.hardfix)
png.trim = opts.trim; png_options.trim = opts.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);
} }
if (strcmp(png.mapfile, opts.mapfile) != 0) { if (png_options.trim)
if (opts.verbose) { opts.trim = png_options.trim;
if (raw_image->width % 8) {
errx(1, "Input PNG file %s not sized correctly. The image's width must be a multiple of 8.",
opts.infile);
}
if (raw_image->width / 8 > 1 && raw_image->height % 8) {
errx(1, "Input PNG file %s not sized correctly. If the image is more than 1 tile wide, its height must be a multiple of 8.",
opts.infile);
}
if (opts.trim &&
opts.trim > (raw_image->width / 8) * (raw_image->height / 8) - 1) {
errx(1, "Trim (%i) for input raw_image file '%s' too large (max: %i)",
opts.trim, opts.infile,
(raw_image->width / 8) * (raw_image->height / 8) - 1);
}
if (strcmp(png_options.mapfile, opts.mapfile) != 0) {
if (opts.verbose)
warnx(errmsg, "tilemap file"); warnx(errmsg, "tilemap file");
}
if (opts.hardfix) {
png.mapfile = opts.mapfile;
}
}
if (!*opts.mapfile) {
opts.mapfile = png.mapfile;
}
if (png.mapout != opts.mapout) { if (opts.hardfix)
if (opts.verbose) { png_options.mapfile = opts.mapfile;
}
if (!*opts.mapfile)
opts.mapfile = png_options.mapfile;
if (png_options.mapout != opts.mapout) {
if (opts.verbose)
warnx(errmsg, "tilemap file"); warnx(errmsg, "tilemap file");
}
if (opts.hardfix) { if (opts.hardfix)
png.mapout = opts.mapout; png_options.mapout = opts.mapout;
}
} }
if (png.mapout) { if (png_options.mapout)
opts.mapout = png.mapout; opts.mapout = png_options.mapout;
if (strcmp(png_options.palfile, opts.palfile) != 0) {
if (opts.verbose)
warnx(errmsg, "palette file");
if (opts.hardfix)
png_options.palfile = opts.palfile;
}
if (!*opts.palfile)
opts.palfile = png_options.palfile;
if (png_options.palout != opts.palout) {
if (opts.verbose)
warnx(errmsg, "palette file");
if (opts.hardfix)
png_options.palout = opts.palout;
} }
if (strcmp(png.palfile, opts.palfile) != 0) { if (png_options.palout)
if (opts.verbose) { opts.palout = png_options.palout;
warnx(errmsg, "palette file");
}
if (opts.hardfix) {
png.palfile = opts.palfile;
}
}
if (!*opts.palfile) {
opts.palfile = png.palfile;
}
if (png.palout != opts.palout) {
if (opts.verbose) {
warnx(errmsg, "palette file");
}
if (opts.hardfix) {
png.palout = opts.palout;
}
}
if (png.palout) {
opts.palout = png.palout;
}
if (!*opts.mapfile && opts.mapout) { if (!*opts.mapfile && opts.mapout) {
if ((ext = strrchr(opts.infile, '.')) != NULL) { ext = strrchr(opts.infile, '.');
if (ext != NULL) {
size = ext - opts.infile + 9; size = ext - opts.infile + 9;
opts.mapfile = malloc(size); opts.mapfile = malloc(size);
strncpy(opts.mapfile, opts.infile, size); strncpy(opts.mapfile, opts.infile, size);
@@ -210,7 +205,9 @@ main(int argc, char *argv[])
} }
if (!*opts.palfile && opts.palout) { if (!*opts.palfile && opts.palout) {
if ((ext = strrchr(opts.infile, '.')) != NULL) { ext = strrchr(opts.infile, '.');
if (ext != NULL) {
size = ext - opts.infile + 5; size = ext - opts.infile + 5;
opts.palfile = malloc(size); opts.palfile = malloc(size);
strncpy(opts.palfile, opts.infile, size); strncpy(opts.palfile, opts.infile, size);
@@ -223,34 +220,29 @@ main(int argc, char *argv[])
} }
} }
gb.size = png.width * png.height * depth / 8; gb.size = raw_image->width * raw_image->height * depth / 8;
gb.data = calloc(gb.size, 1); gb.data = calloc(gb.size, 1);
gb.trim = opts.trim; gb.trim = opts.trim;
gb.horizontal = opts.horizontal; gb.horizontal = opts.horizontal;
if (*opts.outfile || *opts.mapfile) { if (*opts.outfile || *opts.mapfile) {
png_to_gb(png, &gb); raw_to_gb(raw_image, &gb);
create_tilemap(opts, &gb, &tilemap); create_tilemap(&opts, &gb, &tilemap);
} }
if (*opts.outfile) { if (*opts.outfile)
output_file(opts, gb); output_file(&opts, &gb);
}
if (*opts.mapfile) { if (*opts.mapfile)
output_tilemap_file(opts, tilemap); output_tilemap_file(&opts, &tilemap);
}
if (*opts.palfile) { if (*opts.palfile)
output_palette_file(opts, png); output_palette_file(&opts, raw_image);
}
if (opts.fix || opts.debug) { if (opts.fix || opts.debug)
set_text(&png); output_png_file(&opts, &png_options, raw_image);
output_png_file(opts, &png);
}
free_png_data(&png); destroy_raw_image(&raw_image);
free(gb.data); free(gb.data);
return 0; return 0;

View File

@@ -1,53 +1,166 @@
/* /*
* Copyright © 2013 stag019 <stag019@gmail.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2013-2018, stag019 and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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 <png.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "gfx/main.h" #include "gfx/main.h"
void static void initialize_png(struct PNGImage *img, FILE *f);
input_png_file(struct Options opts, struct PNGImage *img) static struct RawIndexedImage *indexed_png_to_raw(struct PNGImage *img);
static struct RawIndexedImage *grayscale_png_to_raw(struct PNGImage *img);
static struct RawIndexedImage *truecolor_png_to_raw(struct PNGImage *img);
static void get_text(const struct PNGImage *img,
struct ImageOptions *png_options);
static void set_text(const struct PNGImage *img,
const struct ImageOptions *png_options);
static void free_png_data(const struct PNGImage *png);
struct RawIndexedImage *input_png_file(const struct Options *opts,
struct ImageOptions *png_options)
{
struct PNGImage img;
struct RawIndexedImage *raw_image;
FILE *f;
f = fopen(opts->infile, "rb");
if (!f)
err(1, "Opening input png file '%s' failed", opts->infile);
initialize_png(&img, f);
if (img.depth != depth) {
if (opts->verbose) {
warnx("Image bit depth is not %i (is %i).",
depth, img.depth);
}
}
switch (img.type) {
case PNG_COLOR_TYPE_PALETTE:
raw_image = indexed_png_to_raw(&img); break;
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_GRAY_ALPHA:
raw_image = grayscale_png_to_raw(&img); break;
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
raw_image = truecolor_png_to_raw(&img); break;
default:
/* Shouldn't happen, but might as well handle just in case. */
errx(1, "Input PNG file is of invalid color type.");
}
get_text(&img, png_options);
png_destroy_read_struct(&img.png, &img.info, NULL);
fclose(f);
free_png_data(&img);
return raw_image;
}
void output_png_file(const struct Options *opts,
const struct ImageOptions *png_options,
const struct RawIndexedImage *raw_image)
{ {
FILE *f; FILE *f;
int i, y, num_trans; char *outfile;
bool has_palette = false; struct PNGImage img;
png_byte *trans_alpha; png_color *png_palette;
png_color_16 *trans_values; int i;
bool *full_alpha;
png_color *palette;
f = fopen(opts.infile, "rb"); /*
if (!f) { * TODO: Variable outfile is for debugging purposes. Eventually,
err(1, "Opening input png file '%s' failed", opts.infile); * opts.infile will be used directly.
*/
if (opts->debug) {
outfile = malloc(strlen(opts->infile) + 5);
strcpy(outfile, opts->infile);
strcat(outfile, ".out");
} else {
outfile = opts->infile;
} }
img->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); f = fopen(outfile, "wb");
if (!img->png) { if (!f)
err(1, "Opening output png file '%s' failed", outfile);
img.png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if (!img.png)
errx(1, "Creating png structure failed"); errx(1, "Creating png structure failed");
img.info = png_create_info_struct(img.png);
if (!img.info)
errx(1, "Creating png info structure failed");
if (setjmp(png_jmpbuf(img.png)))
exit(1);
png_init_io(img.png, f);
png_set_IHDR(img.png, img.info, raw_image->width, raw_image->height,
8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_palette = malloc(sizeof(png_color *) * raw_image->num_colors);
for (i = 0; i < raw_image->num_colors; i++) {
png_palette[i].red = raw_image->palette[i].red;
png_palette[i].green = raw_image->palette[i].green;
png_palette[i].blue = raw_image->palette[i].blue;
} }
png_set_PLTE(img.png, img.info, png_palette, raw_image->num_colors);
free(png_palette);
if (opts->fix)
set_text(&img, png_options);
png_write_info(img.png, img.info);
png_write_image(img.png, (png_byte **) raw_image->data);
png_write_end(img.png, NULL);
png_destroy_write_struct(&img.png, &img.info);
fclose(f);
if (opts->debug)
free(outfile);
}
void destroy_raw_image(struct RawIndexedImage **raw_image_ptr_ptr)
{
int y;
struct RawIndexedImage *raw_image = *raw_image_ptr_ptr;
for (y = 0; y < raw_image->height; y++)
free(raw_image->data[y]);
free(raw_image->data);
free(raw_image->palette);
free(raw_image);
*raw_image_ptr_ptr = NULL;
}
static void initialize_png(struct PNGImage *img, FILE *f)
{
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); img->info = png_create_info_struct(img->png);
if (!img->info) { if (!img->info)
errx(1, "Creating png info structure failed"); errx(1, "Creating png info structure failed");
}
/* Better error handling here? */ if (setjmp(png_jmpbuf(img->png)))
if (setjmp(png_jmpbuf(img->png))) {
exit(1); exit(1);
}
png_init_io(img->png, f); png_init_io(img->png, f);
@@ -57,283 +170,567 @@ input_png_file(struct Options opts, struct PNGImage *img)
img->height = png_get_image_height(img->png, img->info); img->height = png_get_image_height(img->png, img->info);
img->depth = png_get_bit_depth(img->png, img->info); img->depth = png_get_bit_depth(img->png, img->info);
img->type = png_get_color_type(img->png, img->info); img->type = png_get_color_type(img->png, img->info);
}
if (img->type & PNG_COLOR_MASK_ALPHA) { static void read_png(struct PNGImage *img);
png_set_strip_alpha(img->png); static struct RawIndexedImage *create_raw_image(int width, int height,
} int num_colors);
static void set_raw_image_palette(struct RawIndexedImage *raw_image,
const png_color *palette, int num_colors);
if (img->depth != depth) { static struct RawIndexedImage *indexed_png_to_raw(struct PNGImage *img)
if (opts.verbose) { {
warnx("Image bit depth is not %i (is %i).", depth, struct RawIndexedImage *raw_image;
img->depth); png_color *palette;
} int colors_in_PLTE;
} int colors_in_new_palette;
png_byte *trans_alpha;
int num_trans;
png_color_16 *trans_color;
png_color *original_palette;
uint8_t *old_to_new_palette;
int i, x, y;
if (img->type == PNG_COLOR_TYPE_GRAY) { if (img->depth < 8)
if (img->depth < 8) { png_set_packing(img->png);
png_set_expand_gray_1_2_4_to_8(img->png);
}
png_set_gray_to_rgb(img->png);
} else {
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);
}
png_get_PLTE(img->png, img->info, &palette, &colors_in_PLTE);
raw_image = create_raw_image(img->width, img->height, colors);
/*
* Transparent palette entries are removed, and the palette is collapsed.
* Transparent pixels are then replaced with palette index 0.
* This way, an indexed PNG can contain transparent pixels in *addition*
* to 4 normal colors.
*/
if (png_get_tRNS(img->png, img->info, &trans_alpha, &num_trans, if (png_get_tRNS(img->png, img->info, &trans_alpha, &num_trans,
&trans_values)) { &trans_color)) {
if (img->type == PNG_COLOR_TYPE_PALETTE) { original_palette = palette;
full_alpha = malloc(sizeof(bool) * num_trans); palette = malloc(sizeof(png_color) * colors_in_PLTE);
colors_in_new_palette = 0;
old_to_new_palette = malloc(sizeof(uint8_t) * colors_in_PLTE);
for (i = 0; i < num_trans; i++) { for (i = 0; i < num_trans; i++) {
if (trans_alpha[i] > 0) { if (trans_alpha[i] == 0) {
full_alpha[i] = false; old_to_new_palette[i] = 0;
} else { } else {
full_alpha[i] = true; old_to_new_palette[i] = colors_in_new_palette;
} palette[colors_in_new_palette++] =
original_palette[i];
} }
}
for (i = 0; i < num_trans; i++) { for (i = num_trans; i < colors_in_PLTE; i++) {
if (full_alpha[i]) { old_to_new_palette[i] = colors_in_new_palette;
palette[i].red = 0xFF; palette[colors_in_new_palette++] = original_palette[i];
palette[i].green = 0x00;
palette[i].blue = 0xFF;
/*
* Set to the lightest color in the
* palette.
*/
}
}
free(full_alpha);
} else {
/* Set to the lightest color in the image. */
} }
png_free_data(img->png, img->info, PNG_FREE_TRNS, -1); if (colors_in_new_palette != colors_in_PLTE) {
} palette = realloc(palette,
sizeof(png_color) *
colors_in_new_palette);
}
if (has_palette) {
/* Make sure palette only has the amount of colors you want. */
} else {
/* /*
* Eventually when this copies colors from the image itself, * Setting and validating palette before reading
* make sure order is lightest to darkest. * allows us to error out *before* doing the data
* transformation if the palette is too long.
*/ */
palette = malloc(sizeof(png_color) * colors); set_raw_image_palette(raw_image, palette,
colors_in_new_palette);
read_png(img);
if (strcmp(opts.infile, "rgb.png") == 0) { for (y = 0; y < img->height; y++) {
palette[0].red = 0xFF; for (x = 0; x < img->width; x++) {
palette[0].green = 0xEF; raw_image->data[y][x] =
palette[0].blue = 0xFF; old_to_new_palette[img->data[y][x]];
}
}
palette[1].red = 0xF7; free(old_to_new_palette);
palette[1].green = 0xF7; } else {
palette[1].blue = 0x8C; set_raw_image_palette(raw_image, palette, colors_in_PLTE);
read_png(img);
palette[2].red = 0x94; for (y = 0; y < img->height; y++) {
palette[2].green = 0x94; for (x = 0; x < img->width; x++)
palette[2].blue = 0xC6; raw_image->data[y][x] = img->data[y][x];
palette[3].red = 0x39;
palette[3].green = 0x39;
palette[3].blue = 0x84;
} else {
palette[0].red = 0xFF;
palette[0].green = 0xFF;
palette[0].blue = 0xFF;
palette[1].red = 0xA9;
palette[1].green = 0xA9;
palette[1].blue = 0xA9;
palette[2].red = 0x55;
palette[2].green = 0x55;
palette[2].blue = 0x55;
palette[3].red = 0x00;
palette[3].green = 0x00;
palette[3].blue = 0x00;
} }
} }
/* return raw_image;
* Also unfortunately, this sets it at 8 bit, and I can't find any }
* option to reduce to 2 or 1 bit.
*/
#if PNG_LIBPNG_VER < 10402
png_set_dither(img->png, palette, colors, colors, NULL, 1);
#else
png_set_quantize(img->png, palette, colors, colors, NULL, 1);
#endif
if (!has_palette) { static struct RawIndexedImage *grayscale_png_to_raw(struct PNGImage *img)
png_set_PLTE(img->png, img->info, palette, colors); {
free(palette); if (img->depth < 8)
png_set_expand_gray_1_2_4_to_8(img->png);
png_set_gray_to_rgb(img->png);
return truecolor_png_to_raw(img);
}
static void rgba_png_palette(struct PNGImage *img,
png_color **palette_ptr_ptr, int *num_colors);
static struct RawIndexedImage
*processed_rgba_png_to_raw(const struct PNGImage *img,
const png_color *palette,
int colors_in_palette);
static struct RawIndexedImage *truecolor_png_to_raw(struct PNGImage *img)
{
struct RawIndexedImage *raw_image;
png_color *palette;
int colors_in_palette;
if (img->depth == 16) {
#if PNG_LIBPNG_VER >= 10504
png_set_scale_16(img->png);
#else
png_set_strip_16(img->png);
#endif
} }
if (!(img->type & PNG_COLOR_MASK_ALPHA)) {
if (png_get_valid(img->png, img->info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(img->png);
else
png_set_add_alpha(img->png, 0xFF, PNG_FILLER_AFTER);
}
read_png(img);
rgba_png_palette(img, &palette, &colors_in_palette);
raw_image = processed_rgba_png_to_raw(img, palette, colors_in_palette);
free(palette);
return raw_image;
}
static void rgba_PLTE_palette(struct PNGImage *img,
png_color **palette_ptr_ptr, int *num_colors);
static void rgba_build_palette(struct PNGImage *img,
png_color **palette_ptr_ptr, int *num_colors);
static void rgba_png_palette(struct PNGImage *img,
png_color **palette_ptr_ptr, int *num_colors)
{
if (png_get_valid(img->png, img->info, PNG_INFO_PLTE))
return rgba_PLTE_palette(img, palette_ptr_ptr, num_colors);
else
return rgba_build_palette(img, palette_ptr_ptr, num_colors);
}
static void rgba_PLTE_palette(struct PNGImage *img,
png_color **palette_ptr_ptr, int *num_colors)
{
png_get_PLTE(img->png, img->info, palette_ptr_ptr, num_colors);
/* /*
* If other useless chunks exist (sRGB, bKGD, pHYs, gAMA, cHRM, iCCP, * Lets us free the palette manually instead of leaving it to libpng,
* etc.) offer to remove? * which lets us handle a PLTE and a built palette the same way.
*/ */
png_data_freer(img->png, img->info,
PNG_USER_WILL_FREE_DATA, PNG_FREE_PLTE);
}
static void update_built_palette(png_color *palette,
const png_color *pixel_color, png_byte alpha,
int *num_colors, bool *only_grayscale);
static int fit_grayscale_palette(png_color *palette, int *num_colors);
static void order_color_palette(png_color *palette, int num_colors);
static void rgba_build_palette(struct PNGImage *img,
png_color **palette_ptr_ptr, int *num_colors)
{
png_color *palette;
int y, value_index;
png_color cur_pixel_color;
png_byte cur_alpha;
bool only_grayscale = true;
/*
* By filling the palette up with black by default, if the image
* doesn't have enough colors, the palette gets padded with black.
*/
*palette_ptr_ptr = calloc(colors, sizeof(png_color));
palette = *palette_ptr_ptr;
*num_colors = 0;
for (y = 0; y < img->height; y++) {
value_index = 0;
while (value_index < img->width * 4) {
cur_pixel_color.red = img->data[y][value_index++];
cur_pixel_color.green = img->data[y][value_index++];
cur_pixel_color.blue = img->data[y][value_index++];
cur_alpha = img->data[y][value_index++];
update_built_palette(palette, &cur_pixel_color,
cur_alpha,
num_colors, &only_grayscale);
}
}
/* In order not to count 100% transparent images as grayscale. */
only_grayscale = *num_colors ? only_grayscale : false;
if (!only_grayscale || !fit_grayscale_palette(palette, num_colors))
order_color_palette(palette, *num_colors);
}
static void update_built_palette(png_color *palette,
const png_color *pixel_color, png_byte alpha,
int *num_colors, bool *only_grayscale)
{
bool color_exists;
png_color cur_palette_color;
int i;
/*
* Transparent pixels don't count toward the palette,
* as they'll be replaced with color #0 later.
*/
if (alpha == 0)
return;
if (*only_grayscale && !(pixel_color->red == pixel_color->green &&
pixel_color->red == pixel_color->blue)) {
*only_grayscale = false;
}
color_exists = false;
for (i = 0; i < *num_colors; i++) {
cur_palette_color = palette[i];
if (pixel_color->red == cur_palette_color.red &&
pixel_color->green == cur_palette_color.green &&
pixel_color->blue == cur_palette_color.blue) {
color_exists = true;
break;
}
}
if (!color_exists) {
if (*num_colors == colors) {
err(1, "Too many colors in input PNG file to fit into a %d-bit palette (max %d).",
depth, colors);
}
palette[*num_colors] = *pixel_color;
(*num_colors)++;
}
}
static int fit_grayscale_palette(png_color *palette, int *num_colors)
{
int interval = 256 / colors;
png_color *fitted_palette = malloc(sizeof(png_color) * colors);
bool *set_indices = calloc(colors, sizeof(bool));
int i, shade_index;
fitted_palette[0].red = 0xFF;
fitted_palette[0].green = 0xFF;
fitted_palette[0].blue = 0xFF;
fitted_palette[colors - 1].red = 0;
fitted_palette[colors - 1].green = 0;
fitted_palette[colors - 1].blue = 0;
if (colors == 4) {
fitted_palette[1].red = 0xA9;
fitted_palette[1].green = 0xA9;
fitted_palette[1].blue = 0xA9;
fitted_palette[2].red = 0x55;
fitted_palette[2].green = 0x55;
fitted_palette[2].blue = 0x55;
}
for (i = 0; i < *num_colors; i++) {
shade_index = colors - 1 - palette[i].red / interval;
if (set_indices[shade_index]) {
free(fitted_palette);
free(set_indices);
return false;
}
fitted_palette[shade_index] = palette[i];
set_indices[shade_index] = true;
}
for (i = 0; i < colors; i++)
palette[i] = fitted_palette[i];
*num_colors = colors;
free(fitted_palette);
free(set_indices);
return true;
}
/* A combined struct is needed to sort csolors in order of luminance. */
struct ColorWithLuminance {
png_color color;
int luminance;
};
static int compare_luminance(const void *a, const void *b)
{
struct ColorWithLuminance *x = (struct ColorWithLuminance *)a;
struct ColorWithLuminance *y = (struct ColorWithLuminance *)b;
return y->luminance - x->luminance;
}
static void order_color_palette(png_color *palette, int num_colors)
{
int i;
struct ColorWithLuminance *palette_with_luminance =
malloc(sizeof(struct ColorWithLuminance) * num_colors);
for (i = 0; i < num_colors; i++) {
/*
* Normally this would be done with floats, but since it's only
* used for comparison, we might as well use integer math.
*/
palette_with_luminance[i].color = palette[i];
palette_with_luminance[i].luminance = 2126 * palette[i].red +
7152 * palette[i].green +
722 * palette[i].blue;
}
qsort(palette_with_luminance, num_colors,
sizeof(struct ColorWithLuminance), compare_luminance);
for (i = 0; i < num_colors; i++)
palette[i] = palette_with_luminance[i].color;
free(palette_with_luminance);
}
static void put_raw_image_pixel(struct RawIndexedImage *raw_image,
const struct PNGImage *img,
int *value_index, int x, int y,
const png_color *palette,
int colors_in_palette);
static struct RawIndexedImage
*processed_rgba_png_to_raw(const struct PNGImage *img,
const png_color *palette,
int colors_in_palette)
{
struct RawIndexedImage *raw_image;
int x, y, value_index;
raw_image = create_raw_image(img->width, img->height, colors);
set_raw_image_palette(raw_image, palette, colors_in_palette);
for (y = 0; y < img->height; y++) {
x = raw_image->width - 1;
value_index = img->width * 4 - 1;
while (x >= 0) {
put_raw_image_pixel(raw_image, img,
&value_index, x, y,
palette, colors_in_palette);
x--;
}
}
return raw_image;
}
static uint8_t palette_index_of(const png_color *palette,
int num_colors, const png_color *color);
static void put_raw_image_pixel(struct RawIndexedImage *raw_image,
const struct PNGImage *img,
int *value_index, int x, int y,
const png_color *palette,
int colors_in_palette)
{
png_color pixel_color;
png_byte alpha;
alpha = img->data[y][*value_index];
if (alpha == 0) {
raw_image->data[y][x] = 0;
*value_index -= 4;
} else {
(*value_index)--;
pixel_color.blue = img->data[y][(*value_index)--];
pixel_color.green = img->data[y][(*value_index)--];
pixel_color.red = img->data[y][(*value_index)--];
raw_image->data[y][x] = palette_index_of(palette,
colors_in_palette,
&pixel_color);
}
}
static uint8_t palette_index_of(const png_color *palette,
int num_colors, const png_color *color)
{
uint8_t i;
for (i = 0; i < num_colors; i++) {
if (palette[i].red == color->red &&
palette[i].green == color->green &&
palette[i].blue == color->blue) {
return i;
}
}
errx(1, "The input PNG file contains colors that don't appear in its embedded palette.");
}
static void read_png(struct PNGImage *img)
{
int y;
png_read_update_info(img->png, img->info); png_read_update_info(img->png, img->info);
img->data = malloc(sizeof(png_byte *) * img->height); 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)); img->data[y] = malloc(png_get_rowbytes(img->png, img->info));
}
png_read_image(img->png, img->data); png_read_image(img->png, img->data);
png_read_end(img->png, img->info); png_read_end(img->png, img->info);
fclose(f);
} }
void static struct RawIndexedImage *create_raw_image(int width, int height,
get_text(struct PNGImage *png) int num_colors)
{
struct RawIndexedImage *raw_image;
int y;
raw_image = malloc(sizeof(struct RawIndexedImage));
raw_image->width = width;
raw_image->height = height;
raw_image->num_colors = num_colors;
raw_image->palette = malloc(sizeof(struct RGBColor) * num_colors);
raw_image->data = malloc(sizeof(uint8_t *) * height);
for (y = 0; y < height; y++)
raw_image->data[y] = malloc(sizeof(uint8_t) * width);
return raw_image;
}
static void set_raw_image_palette(struct RawIndexedImage *raw_image,
const png_color *palette, int num_colors)
{
int i;
if (num_colors > raw_image->num_colors) {
errx(1, "Too many colors in input PNG file's palette to fit into a %d-bit palette (%d in input palette, max %d).",
raw_image->num_colors >> 1,
num_colors, raw_image->num_colors);
}
for (i = 0; i < num_colors; i++) {
raw_image->palette[i].red = palette[i].red;
raw_image->palette[i].green = palette[i].green;
raw_image->palette[i].blue = palette[i].blue;
}
for (i = num_colors; i < raw_image->num_colors; i++) {
raw_image->palette[i].red = 0;
raw_image->palette[i].green = 0;
raw_image->palette[i].blue = 0;
}
}
static void get_text(const struct PNGImage *img,
struct ImageOptions *png_options)
{ {
png_text *text; png_text *text;
int i, numtxts, numremoved; int i, numtxts, numremoved;
png_get_text(png->png, png->info, &text, &numtxts); png_get_text(img->png, img->info, &text, &numtxts);
for (i = 0; i < numtxts; i++) { for (i = 0; i < numtxts; i++) {
if (strcmp(text[i].key, "h") == 0 && !*text[i].text) { if (strcmp(text[i].key, "h") == 0 && !*text[i].text) {
png->horizontal = true; png_options->horizontal = true;
png_free_data(png->png, png->info, PNG_FREE_TEXT, i); png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
} else if (strcmp(text[i].key, "x") == 0) { } else if (strcmp(text[i].key, "x") == 0) {
png->trim = strtoul(text[i].text, NULL, 0); png_options->trim = strtoul(text[i].text, NULL, 0);
png_free_data(png->png, png->info, PNG_FREE_TEXT, i); png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
} else if (strcmp(text[i].key, "t") == 0) { } else if (strcmp(text[i].key, "t") == 0) {
png->mapfile = text[i].text; png_options->mapfile = text[i].text;
png_free_data(png->png, png->info, PNG_FREE_TEXT, i); png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
} else if (strcmp(text[i].key, "T") == 0 && !*text[i].text) { } else if (strcmp(text[i].key, "T") == 0 && !*text[i].text) {
png->mapout = true; png_options->mapout = true;
png_free_data(png->png, png->info, PNG_FREE_TEXT, i); png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
} else if (strcmp(text[i].key, "p") == 0) { } else if (strcmp(text[i].key, "p") == 0) {
png->palfile = text[i].text; png_options->palfile = text[i].text;
png_free_data(png->png, png->info, PNG_FREE_TEXT, i); png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
} else if (strcmp(text[i].key, "P") == 0 && !*text[i].text) { } else if (strcmp(text[i].key, "P") == 0 && !*text[i].text) {
png->palout = true; png_options->palout = true;
png_free_data(png->png, png->info, PNG_FREE_TEXT, i); png_free_data(img->png, img->info, PNG_FREE_TEXT, i);
} }
} }
/* 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++) { for (i = 0, numremoved = 0; i < numtxts; i++) {
if (text[i].key == NULL) { if (text[i].key == NULL)
numremoved++; numremoved++;
}
text[i].key = text[i + numremoved].key; text[i].key = text[i + numremoved].key;
text[i].text = text[i + numremoved].text; text[i].text = text[i + numremoved].text;
text[i].compression = text[i + numremoved].compression; text[i].compression = text[i + numremoved].compression;
} }
png_set_text(png->png, png->info, text, numtxts - numremoved); png_set_text(img->png, img->info, text, numtxts - numremoved);
} }
void static void set_text(const struct PNGImage *img,
set_text(struct PNGImage *png) const struct ImageOptions *png_options)
{ {
png_text *text; png_text *text;
char buffer[3]; char buffer[3];
text = malloc(sizeof(png_text)); text = malloc(sizeof(png_text));
if (png->horizontal) { if (png_options->horizontal) {
text[0].key = "h"; text[0].key = "h";
text[0].text = ""; text[0].text = "";
text[0].compression = PNG_TEXT_COMPRESSION_NONE; text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1); png_set_text(img->png, img->info, text, 1);
} }
if (png->trim) { if (png_options->trim) {
text[0].key = "x"; text[0].key = "x";
snprintf(buffer, 3, "%d", png->trim); snprintf(buffer, 3, "%d", png_options->trim);
text[0].text = buffer; text[0].text = buffer;
text[0].compression = PNG_TEXT_COMPRESSION_NONE; text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1); png_set_text(img->png, img->info, text, 1);
} }
if (*png->mapfile) { if (*png_options->mapfile) {
text[0].key = "t"; text[0].key = "t";
text[0].text = ""; text[0].text = "";
text[0].compression = PNG_TEXT_COMPRESSION_NONE; text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1); png_set_text(img->png, img->info, text, 1);
} }
if (png->mapout) { if (png_options->mapout) {
text[0].key = "T"; text[0].key = "T";
text[0].text = ""; text[0].text = "";
text[0].compression = PNG_TEXT_COMPRESSION_NONE; text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1); png_set_text(img->png, img->info, text, 1);
} }
if (*png->palfile) { if (*png_options->palfile) {
text[0].key = "p"; text[0].key = "p";
text[0].text = ""; text[0].text = "";
text[0].compression = PNG_TEXT_COMPRESSION_NONE; text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1); png_set_text(img->png, img->info, text, 1);
} }
if (png->palout) { if (png_options->palout) {
text[0].key = "P"; text[0].key = "P";
text[0].text = ""; text[0].text = "";
text[0].compression = PNG_TEXT_COMPRESSION_NONE; text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1); png_set_text(img->png, img->info, text, 1);
} }
free(text); free(text);
} }
void static void free_png_data(const struct PNGImage *img)
output_png_file(struct Options opts, struct PNGImage *png)
{
FILE *f;
char *outfile;
png_struct *img;
/* 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);
strcat(outfile, ".out");
} else {
outfile = opts.infile;
}
f = fopen(outfile, "wb");
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) {
errx(1, "Creating png structure failed");
}
/* Better error handling here? */
if (setjmp(png_jmpbuf(img))) {
exit(1);
}
png_init_io(img, f);
png_write_info(img, png->info);
png_write_image(img, png->data);
png_write_end(img, NULL);
fclose(f);
if (opts.debug) {
free(outfile);
}
}
void
free_png_data(struct PNGImage *png)
{ {
int y; int y;
for (y = 0; y < png->height; y++) { for (y = 0; y < img->height; y++)
free(png->data[y]); free(img->data[y]);
}
free(png->data); free(img->data);
} }

View File

@@ -1,18 +1,11 @@
.\" Copyright © 2013 stag019 <stag019@gmail.com>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" This file is part of RGBDS.
.\" 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 .\" Copyright (c) 2013-2018, stag019 and RGBDS contributors.
.\" 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.
.\" .\"
.Dd April 17, 2017 .\" SPDX-License-Identifier: MIT
.\"
.Dd January 26, 2018
.Dt RGBGFX 1 .Dt RGBGFX 1
.Os RGBDS Manual .Os RGBDS Manual
.Sh NAME .Sh NAME
@@ -31,7 +24,28 @@
The The
.Nm .Nm
program converts PNG images into the Nintendo Game Boy's planar tile format. program converts PNG images into the Nintendo Game Boy's planar tile format.
The arguments are as follows:
The resulting colors and their palette indices are determined differently
depending on the input PNG file:
.Bl -dash -width Ds
.It
If the file has an embedded palette, that palette's color and order are used.
.It
If not, and the image only contains shades of gray, rgbgfx maps them to the
indices appropriate for each shade. Any undetermined indices are set to
respective default shades of gray. For example: if the bit depth is 2 and the
image contains light gray and black, they become the second and fourth colors -
and the first and third colors get set to default white and dark gray. If the
image has multiple shades that map to the same index, the palette is instead
determined as if the image had color.
.It
If the image has color (or the grayscale method failed), the colors are sorted
from lightest to darkest.
.El
The input image may not contain more colors than the selected bit depth
allows. Transparent pixels are set to palette index 0.
.Sh ARGUMENTS
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl D .It Fl D
Debug features are enabled. Debug features are enabled.
@@ -40,24 +54,25 @@ Fix the input PNG file to be a correctly indexed image.
.It Fl F .It Fl F
Same as Same as
.Fl f , .Fl f ,
but additionally, the input PNG file is fixed to have its parameters match the but additionally, the supplied command line parameters are saved within the PNG
command line's parameters. and will be loaded and automatically used next time.
.It Fl d Ar depth .It Fl d Ar depth
The bitdepth of the output image (either 1 or 2). The bit depth of the output image (either 1 or 2).
By default, the bitdepth is 2 (two bits per pixel). By default, the bit depth is 2 (two bits per pixel).
.It Fl h .It Fl h
Lay out tiles horizontally rather than vertically. Lay out tiles horizontally rather than vertically.
.It Fl o Ar outfile .It Fl o Ar outfile
The name of the output file. The name of the output file.
.It Fl p Ar palfile .It Fl p Ar palfile
Raw bytes (8 bytes for two bits per pixel, 4 bytes for one bit per pixel) Output the image's palette in standard GBC palette format - bytes (8 bytes for
containing the RGB15 values in the little-endian byte order and then ordered two bits per pixel, 4 bytes for one bit per pixel) containing the RGB15 values
from lightest to darkest. in little-endian byte order. If the palette contains too few colors, the
remaining entries are set to black.
.It Fl P .It Fl P
Same as Same as
.Fl p , .Fl p ,
but the pallete file output name is made by taking the input filename, but the palette file output name is made by taking the input PNG file's
removing the file extension, and appending filename, removing the file extension, and appending
.Pa .pal . .Pa .pal .
.It Fl t Ar mapfile .It Fl t Ar mapfile
If any tiles are the same, don't place the repeat tiles in the output file, and If any tiles are the same, don't place the repeat tiles in the output file, and
@@ -80,7 +95,7 @@ the PNG file don't match.
Trim the end of the output file by this many tiles. Trim the end of the output file by this many tiles.
.El .El
.Sh EXAMPLES .Sh EXAMPLES
The following will take a PNG file with a bitdepth of 1, 2, or 8, and output The following will take a PNG file with a bit depth of 1, 2, or 8, and output
planar 2bpp data: planar 2bpp data:
.Pp .Pp
.D1 $ rgbgfx -o out.2bpp in.png .D1 $ rgbgfx -o out.2bpp in.png

View File

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

View File

@@ -1,17 +1,9 @@
/* /*
* Copyright (C) 2017 Antonio Nino Diaz <antonio_nd@outlook.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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.
*/ */
%option noinput %option noinput
@@ -19,25 +11,29 @@
%{ %{
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include "extern/err.h" #include "extern/err.h"
#include "link/mylink.h" #include "link/mylink.h"
#include "link/script.h" #include "link/script.h"
#include "parser.h" #include "parser.h"
#include "types.h"
extern int yyparse(); extern int yyparse();
/* File include stack. */ /* File include stack. */
#define MAX_INCLUDE_DEPTH 8 #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 YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
static char include_path[MAX_INCLUDE_DEPTH][_MAX_PATH + 1]; 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 */ static char linkerscript_path[_MAX_PATH + 1]; /* Base file */
%} %}
@@ -45,14 +41,21 @@ static char linkerscript_path[_MAX_PATH + 1]; /* Base file */
%% %%
\"([^\\\"]|\\.)*\" { \"([^\\\"]|\\.)*\" {
if (strlen(yytext) > sizeof(yylval.s) - 1) if (strlen(yytext) > sizeof(yylval.s) - 1) {
script_fatalerror("String is too long: %s\n.", yytext); script_fatalerror("String is too long: %s\n.",
if (strlen(yytext) < 3) /* 2 quotes + 1 character */ yytext);
script_fatalerror("String %s is invalid\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); 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; return STRING;
} }
@@ -108,12 +111,11 @@ void script_Parse(const char * path)
} while (!feof(yyin)); } while (!feof(yyin));
fclose(yyin); fclose(yyin);
} }
void script_IncludeFile(const char * path) void script_IncludeFile(const char * path)
{ {
if (include_stack_ptr == (MAX_INCLUDE_DEPTH-1)) if (include_stack_ptr == (MAX_INCLUDE_DEPTH - 1))
script_fatalerror("Includes nested too deeply."); script_fatalerror("Includes nested too deeply.");
include_line[include_stack_ptr] = yylineno; include_line[include_stack_ptr] = yylineno;
@@ -121,13 +123,13 @@ void script_IncludeFile(const char * path)
include_stack_ptr++; include_stack_ptr++;
yyin = fopen(path, "r" ); yyin = fopen(path, "r");
if (!yyin) if (!yyin)
script_fatalerror("Couldn't open file \"%s\"", path); script_fatalerror("Couldn't open file \"%s\"", path);
strncpy(include_path[include_stack_ptr], path, sizeof(include_path[0])); strncpy(include_path[include_stack_ptr], path, sizeof(include_path[0]));
include_path[include_stack_ptr][sizeof(include_path[0])-1] = '\0'; include_path[include_stack_ptr][sizeof(include_path[0]) - 1] = '\0';
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
yylineno = 1; yylineno = 1;
@@ -148,7 +150,7 @@ void script_IncludeFile(const char * path)
unput('\n'); unput('\n');
} }
int script_IncludeDepthGet(void) int32_t script_IncludeDepthGet(void)
{ {
return include_stack_ptr; return include_stack_ptr;
} }
@@ -166,7 +168,7 @@ void script_IncludePop(void)
void script_PrintFileStack(void) void script_PrintFileStack(void)
{ {
int i = include_stack_ptr; int32_t i = include_stack_ptr;
include_line[i] = yylineno; include_line[i] = yylineno;

View File

@@ -1,73 +1,79 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "extern/err.h" #include "extern/err.h"
#include "types.h"
#include "link/mylink.h" #include "link/mylink.h"
#include "link/main.h" #include "link/main.h"
static BBOOL static uint8_t symboldefined(char *name)
symboldefined(char *name)
{ {
struct sSection *pSect; const struct sSection *pSect;
pSect = pSections; pSect = pSections;
while (pSect) { while (pSect) {
int i; int32_t i;
for (i = 0; i < pSect->nNumberOfSymbols; i += 1) { for (i = 0; i < pSect->nNumberOfSymbols; i += 1) {
if ((pSect->tSymbols[i]->Type == SYM_EXPORT) const struct sSymbol *tSymbol = pSect->tSymbols[i];
|| ((pSect->tSymbols[i]->Type == SYM_LOCAL)
&& (pSect == pSect->tSymbols[i]->pSection))) { if ((tSymbol->Type == SYM_EXPORT)
if (strcmp(pSect->tSymbols[i]->pzName, name) == || ((tSymbol->Type == SYM_LOCAL)
0) && (pSect == tSymbol->pSection))) {
return (1);
if (strcmp(tSymbol->pzName, name) == 0)
return 1;
} }
} }
pSect = pSect->pNext; pSect = pSect->pNext;
} }
return (0); return 0;
} }
static BBOOL static uint8_t addmodulecontaining(char *name)
addmodulecontaining(char *name)
{ {
struct sSection **ppLSect; struct sSection **ppLSect = &pLibSections;
ppLSect = &pLibSections;
while (*ppLSect) { while (*ppLSect) {
int i; int32_t i;
for (i = 0; i < (*ppLSect)->nNumberOfSymbols; i += 1) { for (i = 0; i < (*ppLSect)->nNumberOfSymbols; i += 1) {
if (((*ppLSect)->tSymbols[i]->Type == SYM_EXPORT) const struct sSymbol *tSymbol = (*ppLSect)->tSymbols[i];
|| (((*ppLSect)->tSymbols[i]->Type == SYM_LOCAL)
&& ((*ppLSect) == if ((tSymbol->Type == SYM_EXPORT)
(*ppLSect)->tSymbols[i]->pSection))) { || ((tSymbol->Type == SYM_LOCAL)
if (strcmp && ((*ppLSect) == tSymbol->pSection))) {
((*ppLSect)->tSymbols[i]->pzName,
name) == 0) { if (strcmp(tSymbol->pzName, name) == 0) {
struct sSection **ppSect; struct sSection **ppSect = &pSections;
ppSect = &pSections;
while (*ppSect) while (*ppSect)
ppSect = &((*ppSect)->pNext); ppSect = &((*ppSect)->pNext);
*ppSect = *ppLSect; *ppSect = *ppLSect;
*ppLSect = (*ppLSect)->pNext; *ppLSect = (*ppLSect)->pNext;
(*ppSect)->pNext = NULL; (*ppSect)->pNext = NULL;
return (1); return 1;
} }
} }
} }
ppLSect = &((*ppLSect)->pNext); ppLSect = &((*ppLSect)->pNext);
} }
return (0); return 0;
} }
void void AddNeededModules(void)
AddNeededModules(void)
{ {
struct sSection *pSect; struct sSection *pSect;
@@ -77,8 +83,8 @@ AddNeededModules(void)
ppLSect = &pLibSections; ppLSect = &pLibSections;
while (*ppLSect) { while (*ppLSect) {
struct sSection **ppSect; struct sSection **ppSect = &pSections;
ppSect = &pSections;
while (*ppSect) while (*ppSect)
ppSect = &((*ppSect)->pNext); ppSect = &((*ppSect)->pNext);
@@ -93,23 +99,22 @@ AddNeededModules(void)
if (options & OPT_SMART_C_LINK) { if (options & OPT_SMART_C_LINK) {
if (!addmodulecontaining(smartlinkstartsymbol)) { if (!addmodulecontaining(smartlinkstartsymbol)) {
errx(1, "Can't find start symbol '%s'", errx(1, "Can't find start symbol '%s'",
smartlinkstartsymbol); smartlinkstartsymbol);
} else } else {
printf("Smart linking with symbol '%s'\n", printf("Smart linking with symbol '%s'\n",
smartlinkstartsymbol); smartlinkstartsymbol);
}
} }
pSect = pSections; pSect = pSections;
while (pSect) { while (pSect) {
int i; int32_t i;
for (i = 0; i < pSect->nNumberOfSymbols; i += 1) { for (i = 0; i < pSect->nNumberOfSymbols; i += 1) {
if ((pSect->tSymbols[i]->Type == SYM_IMPORT) if ((pSect->tSymbols[i]->Type == SYM_IMPORT)
|| (pSect->tSymbols[i]->Type == SYM_LOCAL)) { || (pSect->tSymbols[i]->Type == SYM_LOCAL)) {
if (!symboldefined(pSect->tSymbols[i]->pzName)) { if (!symboldefined(pSect->tSymbols[i]->pzName))
addmodulecontaining(pSect->tSymbols[i]-> addmodulecontaining(pSect->tSymbols[i]->pzName);
pzName);
}
} }
} }
pSect = pSect->pNext; pSect = pSect->pNext;

View File

@@ -1,10 +1,19 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "extern/err.h" #include "extern/err.h"
#include "extern/version.h"
#include "link/object.h" #include "link/object.h"
#include "link/output.h" #include "link/output.h"
#include "link/assign.h" #include "link/assign.h"
@@ -14,6 +23,8 @@
#include "link/main.h" #include "link/main.h"
#include "link/library.h" #include "link/library.h"
#include "version.h"
enum eBlockType { enum eBlockType {
BLOCK_COMMENT, BLOCK_COMMENT,
BLOCK_OBJECTS, BLOCK_OBJECTS,
@@ -21,17 +32,15 @@ enum eBlockType {
BLOCK_OUTPUT BLOCK_OUTPUT
}; };
SLONG options = 0; int32_t options;
SLONG fillchar = 0; int32_t fillchar;
char *smartlinkstartsymbol; char *smartlinkstartsymbol;
/* /*
* Print the usagescreen * Print the usagescreen
*
*/ */
static void static void print_usage(void)
usage(void)
{ {
printf( printf(
"usage: rgblink [-dtVw] [-l linkerscript] [-m mapfile] [-n symfile] [-O overlay]\n" "usage: rgblink [-dtVw] [-l linkerscript] [-m mapfile] [-n symfile] [-O overlay]\n"
@@ -41,17 +50,15 @@ usage(void)
/* /*
* The main routine * The main routine
*
*/ */
int int main(int argc, char *argv[])
main(int argc, char *argv[])
{ {
int ch; int ch;
char *ep; char *ep;
if (argc == 1) if (argc == 1)
usage(); print_usage();
while ((ch = getopt(argc, argv, "dl:m:n:O:o:p:s:tVw")) != -1) { while ((ch = getopt(argc, argv, "dl:m:n:O:o:p:s:tVw")) != -1) {
switch (ch) { switch (ch) {
@@ -73,12 +80,10 @@ main(int argc, char *argv[])
break; break;
case 'p': case 'p':
fillchar = strtoul(optarg, &ep, 0); fillchar = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0') { if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'p'"); errx(1, "Invalid argument for option 'p'");
} if (fillchar < 0 || fillchar > 0xFF)
if (fillchar < 0 || fillchar > 0xFF) {
errx(1, "Argument for option 'p' must be between 0 and 0xFF"); errx(1, "Argument for option 'p' must be between 0 and 0xFF");
}
break; break;
case 's': case 's':
options |= OPT_SMART_C_LINK; options |= OPT_SMART_C_LINK;
@@ -100,17 +105,19 @@ main(int argc, char *argv[])
options |= OPT_DMG_MODE; options |= OPT_DMG_MODE;
/* FALLTHROUGH */ /* FALLTHROUGH */
case 'w': 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 * DMG. All WRAM sections must be WRAM0 as bankable WRAM
* sections do not exist in this mode. A WRAMX section * sections do not exist in this mode. A WRAMX section
* will raise an error. */ * will raise an error.
*/
options |= OPT_CONTWRAM; options |= OPT_CONTWRAM;
break; break;
case 'V': case 'V':
printf("rgblink %s\n", get_package_version_string()); printf("rgblink %s\n", get_package_version_string());
exit(0); exit(0);
default: default:
usage(); print_usage();
/* NOTREACHED */ /* NOTREACHED */
} }
} }
@@ -118,9 +125,9 @@ main(int argc, char *argv[])
argv += optind; argv += optind;
if (argc == 0) 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]); obj_Readfile(argv[i]);
AddNeededModules(); AddNeededModules();
@@ -130,5 +137,5 @@ main(int argc, char *argv[])
Output(); Output();
CloseMapfile(); CloseMapfile();
return (0); return 0;
} }

View File

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

View File

@@ -1,61 +1,55 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
/* /*
* Here we have the routines that read an objectfile * Here we have the routines that read an objectfile
*
*/ */
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "common.h" #include "common.h"
#include "extern/err.h" #include "extern/err.h"
#include "link/assign.h" #include "link/assign.h"
#include "link/mylink.h" #include "link/mylink.h"
#include "link/main.h" #include "link/main.h"
struct sSymbol **tSymbols; struct sSymbol **tSymbols;
struct sSection *pSections = NULL; struct sSection *pSections;
struct sSection *pLibSections = NULL; struct sSection *pLibSections;
UBYTE dummymem; uint8_t dummymem;
BBOOL oReadLib = 0; uint8_t oReadLib;
/* /*
* The usual byte order stuff * Read 32-bit values with the correct endianness
*
*/ */
static int32_t readlong(FILE *f)
SLONG
readlong(FILE * f)
{ {
SLONG r; int32_t r;
r = fgetc(f); r = fgetc(f);
r |= fgetc(f) << 8; r |= fgetc(f) << 8;
r |= fgetc(f) << 16; r |= fgetc(f) << 16;
r |= fgetc(f) << 24; r |= fgetc(f) << 24;
return (r); return r;
}
UWORD
readword(FILE * f)
{
UWORD r;
r = fgetc(f);
r |= fgetc(f) << 8;
return (r);
} }
/* /*
* Read a NULL terminated string from a file * Read a NULL terminated string from a file
*
*/ */
SLONG int32_t readasciiz(char **dest, FILE *f)
readasciiz(char **dest, FILE *f)
{ {
size_t r = 0; size_t r = 0;
@@ -63,9 +57,8 @@ readasciiz(char **dest, FILE *f)
char *start = malloc(bufferLength); char *start = malloc(bufferLength);
char *s = start; char *s = start;
if (!s) { if (!s)
err(1, NULL); err(1, "%s: Couldn't allocate memory", __func__);
}
while (((*s++) = fgetc(f)) != 0) { while (((*s++) = fgetc(f)) != 0) {
r += 1; r += 1;
@@ -74,7 +67,8 @@ readasciiz(char **dest, FILE *f)
bufferLength *= 2; bufferLength *= 2;
start = realloc(start, bufferLength); start = realloc(start, bufferLength);
if (!start) { if (!start) {
err(1, NULL); err(1, "%s: Couldn't allocate memory",
__func__);
} }
s = start + r; s = start + r;
} }
@@ -86,11 +80,8 @@ readasciiz(char **dest, FILE *f)
/* /*
* Allocate a new section and link it into the list * Allocate a new section and link it into the list
*
*/ */
struct sSection *AllocSection(void)
struct sSection *
AllocSection(void)
{ {
struct sSection **ppSections; struct sSection **ppSections;
@@ -103,29 +94,26 @@ AllocSection(void)
ppSections = &((*ppSections)->pNext); ppSections = &((*ppSections)->pNext);
*ppSections = malloc(sizeof **ppSections); *ppSections = malloc(sizeof **ppSections);
if (!*ppSections) { if (!*ppSections)
err(1, NULL); err(1, "%s: Couldn't allocate memory", __func__);
}
(*ppSections)->tSymbols = tSymbols; (*ppSections)->tSymbols = tSymbols;
(*ppSections)->pNext = NULL; (*ppSections)->pNext = NULL;
(*ppSections)->pPatches = NULL; (*ppSections)->pPatches = NULL;
(*ppSections)->oAssigned = 0; (*ppSections)->oAssigned = 0;
return *ppSections; return *ppSections;
} }
/* /*
* Read a symbol from a file * Read a symbol from a file
*
*/ */
struct sSymbol *obj_ReadSymbol(FILE *f, char *tzObjectfile)
struct sSymbol *
obj_ReadSymbol(FILE * f, char *tzObjectfile)
{ {
struct sSymbol *pSym; struct sSymbol *pSym;
pSym = malloc(sizeof *pSym); pSym = malloc(sizeof(*pSym));
if (!pSym) { if (!pSym)
err(1, NULL); err(1, "%s: Couldn't allocate memory", __func__);
}
readasciiz(&pSym->pzName, f); readasciiz(&pSym->pzName, f);
pSym->Type = (enum eSymbolType)fgetc(f); pSym->Type = (enum eSymbolType)fgetc(f);
@@ -139,19 +127,18 @@ obj_ReadSymbol(FILE * f, char *tzObjectfile)
pSym->nSectionID = readlong(f); pSym->nSectionID = readlong(f);
pSym->nOffset = readlong(f); pSym->nOffset = readlong(f);
} }
return pSym; return pSym;
} }
/* /*
* RGB object reader routines * RGB object reader routines
*
*/ */
struct sSection * struct sSection *obj_ReadRGBSection(FILE *f)
obj_ReadRGBSection(FILE * f)
{ {
struct sSection *pSection; struct sSection *pSection;
char *pzName; char *pzName;
readasciiz(&pzName, f); readasciiz(&pzName, f);
if (IsSectionNameInUse(pzName)) if (IsSectionNameInUse(pzName))
errx(1, "Section name \"%s\" is already in use.", pzName); errx(1, "Section name \"%s\" is already in use.", pzName);
@@ -160,127 +147,128 @@ obj_ReadRGBSection(FILE * f)
pSection->pzName = pzName; pSection->pzName = pzName;
pSection->nByteSize = readlong(f); pSection->nByteSize = readlong(f);
pSection->Type = (enum eSectionType) fgetc(f); pSection->Type = (enum eSectionType)fgetc(f);
pSection->nOrg = readlong(f); pSection->nOrg = readlong(f);
pSection->nBank = readlong(f); pSection->nBank = readlong(f);
pSection->nAlign = 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."); 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."); errx(1, "WRAMX sections can't be used with options -w or -d.");
}
if (options & OPT_DMG_MODE) { if (options & OPT_DMG_MODE) {
/* WRAMX sections are checked for OPT_CONTWRAM */ /* 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."); 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 */ /* Verify that the section isn't too big */
switch (pSection->Type) switch (pSection->Type) {
{ case SECT_ROM0:
case SECT_ROM0: maxsize = (options & OPT_TINY) ? 0x8000 : 0x4000;
maxsize = (options & OPT_TINY) ? 0x8000 : 0x4000; break;
break; case SECT_ROMX:
case SECT_ROMX: maxsize = 0x4000;
maxsize = 0x4000; break;
break; case SECT_VRAM:
case SECT_VRAM: case SECT_SRAM:
case SECT_SRAM: maxsize = 0x2000;
maxsize = 0x2000; break;
break; case SECT_WRAM0:
case SECT_WRAM0: maxsize = (options & OPT_CONTWRAM) ? 0x2000 : 0x1000;
maxsize = (options & OPT_CONTWRAM) ? 0x2000 : 0x1000; break;
break; case SECT_WRAMX:
case SECT_WRAMX: maxsize = 0x1000;
maxsize = 0x1000; break;
break; case SECT_OAM:
case SECT_OAM: maxsize = 0xA0;
maxsize = 0xA0; break;
break; case SECT_HRAM:
case SECT_HRAM: maxsize = 0x7F;
maxsize = 0x7F; break;
break; default:
default: errx(1, "Section \"%s\" has an invalid section type.", pzName);
errx(1, "Section \"%s\" has an invalid section type.", pzName); break;
break;
} }
if (pSection->nByteSize > maxsize) { if (pSection->nByteSize > maxsize) {
errx(1, "Section \"%s\" is bigger than the max size for that type: 0x%X > 0x%X", errx(1, "Section \"%s\" is bigger than the max size for that type: 0x%X > 0x%X",
pzName, pSection->nByteSize, maxsize); pzName, pSection->nByteSize, maxsize);
} }
if ((pSection->Type == SECT_ROMX) || (pSection->Type == SECT_ROM0)) { /*
/* * If the section doesn't contain data, it is ready
* These sectiontypes contain data... */
* if ((pSection->Type != SECT_ROMX) && (pSection->Type != SECT_ROM0))
*/ return pSection;
if (pSection->nByteSize) {
pSection->pData = malloc(pSection->nByteSize); /* If there is no data to read, exit */
if (!pSection->pData) { if (pSection->nByteSize == 0) {
err(1, NULL); /* Skip number of patches */
readlong(f);
pSection->pData = &dummymem;
return pSection;
}
pSection->pData = malloc(pSection->nByteSize);
if (!pSection->pData)
err(1, "%s: Couldn't allocate memory", __func__);
int32_t nNumberOfPatches;
struct sPatch **ppPatch, *pPatch;
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, "%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);
pPatch->nRPNSize = readlong(f);
if (pPatch->nRPNSize > 0) {
pPatch->pRPN = malloc(pPatch->nRPNSize);
if (!pPatch->pRPN) {
err(1, "%s: Couldn't allocate memory",
__func__);
} }
SLONG nNumberOfPatches; if (fread(pPatch->pRPN, sizeof(uint8_t),
struct sPatch **ppPatch, *pPatch; pPatch->nRPNSize, f) != pPatch->nRPNSize) {
errx(1, "%s: Read error", __func__);
if (fread(pSection->pData, sizeof(UBYTE),
pSection->nByteSize, f) != pSection->nByteSize) {
err(1, "Read error.");
}
nNumberOfPatches = readlong(f);
ppPatch = &pSection->pPatches;
/*
* And patches...
*
*/
while (nNumberOfPatches--) {
pPatch = malloc(sizeof *pPatch);
if (!pPatch) {
err(1, NULL);
}
*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->pRPN = malloc(pPatch->nRPNSize);
if (!pPatch->pRPN) {
err(1, NULL);
}
if (fread(pPatch->pRPN, sizeof(UBYTE),
pPatch->nRPNSize, f) != pPatch->nRPNSize) {
errx(1, "Read error.");
}
} else
pPatch->pRPN = NULL;
pPatch->pNext = NULL;
ppPatch = &(pPatch->pNext);
} }
} else { } else {
/* Skip number of patches */ pPatch->pRPN = NULL;
readlong(f);
pSection->pData = &dummymem;
} }
pPatch->pNext = NULL;
ppPatch = &(pPatch->pNext);
} }
return pSection; return pSection;
} }
void void obj_ReadRGB(FILE *pObjfile, char *tzObjectfile)
obj_ReadRGB(FILE * pObjfile, char *tzObjectfile)
{ {
struct sSection *pFirstSection; struct sSection *pFirstSection;
SLONG nNumberOfSymbols, nNumberOfSections, i; int32_t nNumberOfSymbols, nNumberOfSections, i;
nNumberOfSymbols = readlong(pObjfile); nNumberOfSymbols = readlong(pObjfile);
nNumberOfSections = readlong(pObjfile); nNumberOfSections = readlong(pObjfile);
@@ -288,15 +276,15 @@ obj_ReadRGB(FILE * pObjfile, char *tzObjectfile)
/* First comes the symbols */ /* First comes the symbols */
if (nNumberOfSymbols) { if (nNumberOfSymbols) {
tSymbols = malloc(nNumberOfSymbols * sizeof *tSymbols); tSymbols = malloc(nNumberOfSymbols * sizeof(*tSymbols));
if (!tSymbols) { if (!tSymbols)
err(1, NULL); err(1, "%s: Couldn't allocate memory", __func__);
}
for (i = 0; i < nNumberOfSymbols; i += 1) for (i = 0; i < nNumberOfSymbols; i += 1)
tSymbols[i] = obj_ReadSymbol(pObjfile, tzObjectfile); tSymbols[i] = obj_ReadSymbol(pObjfile, tzObjectfile);
} else } else {
tSymbols = (struct sSymbol **) & dummymem; tSymbols = (struct sSymbol **)&dummymem;
}
/* Next we have the sections */ /* Next we have the sections */
@@ -313,55 +301,56 @@ obj_ReadRGB(FILE * pObjfile, char *tzObjectfile)
/* /*
* Fill in the pSection entry in the symbolstructure. * Fill in the pSection entry in the symbolstructure.
* This REALLY needs some cleaning up... but, hey, it works * This REALLY needs some cleaning up... but, hey, it works
*
*/ */
for (i = 0; i < nNumberOfSymbols; i += 1) { for (i = 0; i < nNumberOfSymbols; i += 1) {
struct sSection *pConvSect = pFirstSection; struct sSection *pConvSect = pFirstSection;
if (tSymbols[i]->Type != SYM_IMPORT if ((tSymbols[i]->Type != SYM_IMPORT) &&
&& tSymbols[i]->nSectionID != -1) { (tSymbols[i]->nSectionID != -1)) {
SLONG j = 0; int32_t j = 0;
while (j != tSymbols[i]->nSectionID) { while (j != tSymbols[i]->nSectionID) {
j += 1; j += 1;
pConvSect = pConvSect->pNext; pConvSect = pConvSect->pNext;
} }
tSymbols[i]->pSection = pConvSect; tSymbols[i]->pSection = pConvSect;
} else } else {
tSymbols[i]->pSection = NULL; tSymbols[i]->pSection = NULL;
}
} }
} }
/* /*
* The main objectfileloadroutine (phew) * The main objectfileloadroutine (phew)
*
*/ */
void obj_ReadOpenFile(FILE *pObjfile, char *tzObjectfile)
void
obj_ReadOpenFile(FILE * pObjfile, char *tzObjectfile)
{ {
char tzHeader[strlen(RGBDS_OBJECT_VERSION_STRING) + 1]; char tzHeader[strlen(RGBDS_OBJECT_VERSION_STRING) + 1];
if (fread(tzHeader, sizeof(char), strlen(RGBDS_OBJECT_VERSION_STRING), if (fread(tzHeader, sizeof(char), strlen(RGBDS_OBJECT_VERSION_STRING),
pObjfile) != strlen(RGBDS_OBJECT_VERSION_STRING)) { pObjfile) != strlen(RGBDS_OBJECT_VERSION_STRING)) {
errx(1, "%s: Read error.", tzObjectfile); errx(1, "%s: Read error", tzObjectfile);
} }
tzHeader[strlen(RGBDS_OBJECT_VERSION_STRING)] = 0; tzHeader[strlen(RGBDS_OBJECT_VERSION_STRING)] = 0;
if (strncmp(tzHeader, RGBDS_OBJECT_VERSION_STRING, if (strncmp(tzHeader, RGBDS_OBJECT_VERSION_STRING,
strlen(RGBDS_OBJECT_VERSION_STRING)) == 0) { strlen(RGBDS_OBJECT_VERSION_STRING)) == 0) {
obj_ReadRGB(pObjfile, tzObjectfile); obj_ReadRGB(pObjfile, tzObjectfile);
} else { } else {
for (int i = 0; i < strlen(RGBDS_OBJECT_VERSION_STRING); i++) int32_t i;
for (i = 0; i < strlen(RGBDS_OBJECT_VERSION_STRING); i++)
if (!isprint(tzHeader[i])) if (!isprint(tzHeader[i]))
tzHeader[i] = '?'; tzHeader[i] = '?';
errx(1, "%s: Invalid file or object file version [%s]", errx(1, "%s: Invalid file or object file version [%s]",
tzObjectfile, tzHeader); tzObjectfile, tzHeader);
} }
} }
void void obj_Readfile(char *tzObjectfile)
obj_Readfile(char *tzObjectfile)
{ {
FILE *pObjfile; FILE *pObjfile;
@@ -371,24 +360,23 @@ obj_Readfile(char *tzObjectfile)
oReadLib = 0; oReadLib = 0;
pObjfile = fopen(tzObjectfile, "rb"); pObjfile = fopen(tzObjectfile, "rb");
if (pObjfile == NULL) { if (pObjfile == NULL)
err(1, "Unable to open object '%s'", tzObjectfile); err(1, "Unable to open object '%s'", tzObjectfile);
}
obj_ReadOpenFile(pObjfile, tzObjectfile); obj_ReadOpenFile(pObjfile, tzObjectfile);
fclose(pObjfile); fclose(pObjfile);
oReadLib = 0; oReadLib = 0;
} }
SLONG int32_t file_Length(FILE *f)
file_Length(FILE * f)
{ {
ULONG r, p; uint32_t r, p;
p = ftell(f); p = ftell(f);
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
r = ftell(f); r = ftell(f);
fseek(f, p, SEEK_SET); fseek(f, p, SEEK_SET);
return (r); return r;
} }

View File

@@ -1,36 +1,45 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "extern/err.h" #include "extern/err.h"
#include "link/mylink.h" #include "link/mylink.h"
#include "link/mapfile.h" #include "link/mapfile.h"
#include "link/main.h" #include "link/main.h"
#include "link/assign.h" #include "link/assign.h"
char *tzOutname; char *tzOutname;
char *tzOverlayname = NULL; char *tzOverlayname;
SLONG MaxOverlayBank; int32_t MaxOverlayBank;
void void writehome(FILE *f, FILE *f_overlay)
writehome(FILE * f, FILE * f_overlay)
{ {
struct sSection *pSect; const struct sSection *pSect;
UBYTE *mem; uint8_t *mem;
mem = malloc(MaxAvail[BANK_ROM0]); mem = malloc(MaxAvail[BANK_INDEX_ROM0]);
if (!mem) if (!mem)
return; return;
if (f_overlay != NULL) { if (f_overlay != NULL) {
fseek(f_overlay, 0L, SEEK_SET); fseek(f_overlay, 0L, SEEK_SET);
if (fread(mem, 1, MaxAvail[BANK_ROM0], f_overlay) != if (fread(mem, 1, MaxAvail[BANK_INDEX_ROM0], f_overlay) !=
MaxAvail[BANK_ROM0]) { MaxAvail[BANK_INDEX_ROM0]) {
warnx("Failed to read data from overlay file."); warnx("Failed to read data from overlay file.");
} }
} else { } else {
memset(mem, fillchar, MaxAvail[BANK_ROM0]); memset(mem, fillchar, MaxAvail[BANK_INDEX_ROM0]);
} }
MapfileInitBank(0); MapfileInitBank(0);
@@ -38,7 +47,7 @@ writehome(FILE * f, FILE * f_overlay)
while (pSect) { while (pSect) {
if (pSect->Type == SECT_ROM0) { if (pSect->Type == SECT_ROM0) {
memcpy(mem + pSect->nOrg, pSect->pData, memcpy(mem + pSect->nOrg, pSect->pData,
pSect->nByteSize); pSect->nByteSize);
MapfileWriteSection(pSect); MapfileWriteSection(pSect);
} }
pSect = pSect->pNext; pSect = pSect->pNext;
@@ -46,26 +55,23 @@ writehome(FILE * f, FILE * f_overlay)
MapfileCloseBank(area_Avail(0)); MapfileCloseBank(area_Avail(0));
fwrite(mem, 1, MaxAvail[BANK_ROM0], f); fwrite(mem, 1, MaxAvail[BANK_INDEX_ROM0], f);
free(mem); free(mem);
} }
void void writebank(FILE *f, FILE *f_overlay, int32_t bank)
writebank(FILE * f, FILE * f_overlay, SLONG bank)
{ {
struct sSection *pSect; const struct sSection *pSect;
UBYTE *mem; uint8_t *mem;
mem = malloc(MaxAvail[bank]); mem = malloc(MaxAvail[bank]);
if (!mem) if (!mem)
return; return;
if (f_overlay != NULL && bank <= MaxOverlayBank) { if (f_overlay != NULL && bank <= MaxOverlayBank) {
fseek(f_overlay, bank*0x4000, SEEK_SET); fseek(f_overlay, bank * 0x4000, SEEK_SET);
if (fread(mem, 1, MaxAvail[bank], f_overlay) != if (fread(mem, 1, MaxAvail[bank], f_overlay) != MaxAvail[bank])
MaxAvail[bank]) {
warnx("Failed to read data from overlay file."); warnx("Failed to read data from overlay file.");
}
} else { } else {
memset(mem, fillchar, MaxAvail[bank]); memset(mem, fillchar, MaxAvail[bank]);
} }
@@ -75,7 +81,7 @@ writebank(FILE * f, FILE * f_overlay, SLONG bank)
while (pSect) { while (pSect) {
if (pSect->Type == SECT_ROMX && pSect->nBank == bank) { if (pSect->Type == SECT_ROMX && pSect->nBank == bank) {
memcpy(mem + pSect->nOrg - 0x4000, pSect->pData, memcpy(mem + pSect->nOrg - 0x4000, pSect->pData,
pSect->nByteSize); pSect->nByteSize);
MapfileWriteSection(pSect); MapfileWriteSection(pSect);
} }
pSect = pSect->pNext; pSect = pSect->pNext;
@@ -87,43 +93,49 @@ writebank(FILE * f, FILE * f_overlay, SLONG bank)
free(mem); free(mem);
} }
void void out_Setname(char *tzOutputfile)
out_Setname(char *tzOutputfile)
{ {
tzOutname = tzOutputfile; tzOutname = tzOutputfile;
} }
void void out_SetOverlayname(char *tzOverlayfile)
out_SetOverlayname(char *tzOverlayfile)
{ {
tzOverlayname = tzOverlayfile; tzOverlayname = tzOverlayfile;
} }
void Output(void)
void
Output(void)
{ {
SLONG i; int32_t i;
FILE *f; FILE *f;
FILE *f_overlay = NULL; FILE *f_overlay = NULL;
if ((f = fopen(tzOutname, "wb"))) { /*
* Apply overlay
*/
f = fopen(tzOutname, "wb");
if (f != NULL) {
if (tzOverlayname) { if (tzOverlayname) {
f_overlay = fopen(tzOverlayname, "rb"); f_overlay = fopen(tzOverlayname, "rb");
if (!f_overlay) { if (!f_overlay) {
errx(1, "Failed to open overlay file %s\n", tzOverlayname); errx(1, "Failed to open overlay file %s\n",
tzOverlayname);
} }
fseek(f_overlay, 0, SEEK_END); fseek(f_overlay, 0, SEEK_END);
if (ftell(f_overlay) % 0x4000 != 0) {
if (ftell(f_overlay) % 0x4000 != 0)
errx(1, "Overlay file must be aligned to 0x4000 bytes."); errx(1, "Overlay file must be aligned to 0x4000 bytes.");
}
MaxOverlayBank = (ftell(f_overlay) / 0x4000) - 1; MaxOverlayBank = (ftell(f_overlay) / 0x4000) - 1;
if (MaxOverlayBank < 1) {
if (MaxOverlayBank < 1)
errx(1, "Overlay file must be at least 0x8000 bytes."); errx(1, "Overlay file must be at least 0x8000 bytes.");
}
if (MaxOverlayBank > MaxBankUsed) { if (MaxOverlayBank > MaxBankUsed)
MaxBankUsed = MaxOverlayBank; MaxBankUsed = MaxOverlayBank;
}
} }
writehome(f, f_overlay); writehome(f, f_overlay);
@@ -132,18 +144,22 @@ Output(void)
fclose(f); fclose(f);
if (tzOverlayname) { if (tzOverlayname)
fclose(f_overlay); 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); MapfileInitBank(i);
pSect = pSections; pSect = pSections;
while (pSect) { while (pSect) {
if (pSect->nBank == i) { if (pSect->nBank == i)
MapfileWriteSection(pSect); MapfileWriteSection(pSect);
}
pSect = pSect->pNext; pSect = pSect->pNext;
} }
MapfileCloseBank(area_Avail(i)); MapfileCloseBank(area_Avail(i));

View File

@@ -1,23 +1,17 @@
/* /*
* Copyright (C) 2017 Antonio Nino Diaz <antonio_nd@outlook.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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 <stdint.h>
#include <stdio.h> #include <stdio.h>
#include "extern/err.h" #include "extern/err.h"
#include "link/script.h" #include "link/script.h"
int yylex(); int yylex();
@@ -26,7 +20,10 @@ void yyerror(char *);
extern int yylineno; extern int yylineno;
%} %}
%union { int i; char s[512]; } %union {
int32_t i;
char s[512];
}
%token<i> INTEGER %token<i> INTEGER
%token<s> STRING %token<s> STRING
@@ -48,55 +45,65 @@ extern int yylineno;
lines: lines:
/* empty */ /* empty */
| lines line NEWLINE | lines line NEWLINE
; ;
line: line:
/* empty */ /* empty */
| statement | statement
; ;
statement: statement:
/* Statements to set the current section */ /* Statements to set the current section */
SECTION_NONBANKED { SECTION_NONBANKED
{
script_SetCurrentSectionType($1, 0); script_SetCurrentSectionType($1, 0);
} }
| SECTION_NONBANKED INTEGER { | SECTION_NONBANKED INTEGER
{
script_fatalerror("Trying to assign a bank to a non-banked section.\n"); 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"); script_fatalerror("Banked section without assigned bank.\n");
} }
| SECTION_BANKED INTEGER { | SECTION_BANKED INTEGER
{
script_SetCurrentSectionType($1, $2); script_SetCurrentSectionType($1, $2);
} }
/* Commands to adjust the address inside the current section */ /* Commands to adjust the address inside the current section */
| COMMAND_ALIGN INTEGER { | COMMAND_ALIGN INTEGER
{
script_SetAlignment($2); script_SetAlignment($2);
} }
| COMMAND_ALIGN { | COMMAND_ALIGN
{
script_fatalerror("ALIGN keyword needs an argument.\n"); script_fatalerror("ALIGN keyword needs an argument.\n");
} }
| COMMAND_ORG INTEGER { | COMMAND_ORG INTEGER
{
script_SetAddress($2); script_SetAddress($2);
} }
| COMMAND_ORG { | COMMAND_ORG
{
script_fatalerror("ORG keyword needs an argument.\n"); script_fatalerror("ORG keyword needs an argument.\n");
} }
/* Section name */ /* Section name */
| STRING { | STRING
{
script_OutputSection($1); script_OutputSection($1);
} }
/* Include file */ /* Include file */
| COMMAND_INCLUDE STRING { | COMMAND_INCLUDE STRING
{
script_IncludeFile($2); script_IncludeFile($2);
} }
/* End */ /* End */
; ;
%% %%

View File

@@ -1,92 +1,106 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "extern/err.h" #include "extern/err.h"
#include "link/assign.h" #include "link/assign.h"
#include "link/main.h"
#include "link/mylink.h" #include "link/mylink.h"
#include "link/symbol.h" #include "link/symbol.h"
#include "link/main.h"
struct sSection *pCurrentSection; static struct sSection *pCurrentSection;
SLONG rpnstack[256]; static int32_t rpnstack[256];
SLONG rpnp; static int32_t rpnp;
SLONG nPC; int32_t nPC;
void static void rpnpush(int32_t i)
rpnpush(SLONG i)
{ {
rpnstack[rpnp++] = i; rpnstack[rpnp] = i;
rpnp++;
} }
SLONG static int32_t rpnpop(void)
rpnpop(void)
{ {
return (rpnstack[--rpnp]); rpnp--;
return rpnstack[rpnp];
} }
SLONG static int32_t getsymvalue(int32_t symid)
getsymvalue(SLONG symid)
{ {
switch (pCurrentSection->tSymbols[symid]->Type) { const struct sSymbol *tSymbol = pCurrentSection->tSymbols[symid];
case SYM_IMPORT:
return (sym_GetValue(pCurrentSection->tSymbols[symid]->pzName));
break;
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);
}
default:
break;
}
errx(1, "*INTERNAL* UNKNOWN SYMBOL TYPE");
}
SLONG switch (tSymbol->Type) {
getsymbank(SLONG symid)
{
SLONG nBank;
switch (pCurrentSection->tSymbols[symid]->Type) {
case SYM_IMPORT: case SYM_IMPORT:
nBank = sym_GetBank(pCurrentSection->tSymbols[symid]->pzName); return sym_GetValue(tSymbol->pzName);
case SYM_EXPORT:
case SYM_LOCAL:
if (strcmp(tSymbol->pzName, "@") == 0)
return nPC;
return tSymbol->nOffset + tSymbol->pSection->nOrg;
default:
break;
}
errx(1, "%s: Unknown symbol type", __func__);
}
static int32_t getrealbankfrominternalbank(int32_t n)
{
if (BankIndexIsWRAM0(n) || BankIndexIsROM0(n) ||
BankIndexIsOAM(n) || BankIndexIsHRAM(n)) {
return 0;
} 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 n;
}
static int32_t getsymbank(int32_t symid)
{
int32_t nBank;
const struct sSymbol *tSymbol = pCurrentSection->tSymbols[symid];
switch (tSymbol->Type) {
case SYM_IMPORT:
nBank = sym_GetBank(tSymbol->pzName);
break; break;
case SYM_EXPORT: case SYM_EXPORT:
case SYM_LOCAL: case SYM_LOCAL:
nBank = pCurrentSection->tSymbols[symid]->pSection->nBank; nBank = tSymbol->pSection->nBank;
break; break;
default: default:
errx(1, "*INTERNAL* UNKNOWN SYMBOL TYPE"); errx(1, "%s: Unknown symbol type", __func__);
} }
if (nBank == BANK_WRAM0 || nBank == BANK_ROM0 || nBank == BANK_OAM || return getrealbankfrominternalbank(nBank);
nBank == BANK_HRAM) {
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;
}
return nBank;
} }
SLONG int32_t calcrpn(struct sPatch *pPatch)
calcrpn(struct sPatch * pPatch)
{ {
SLONG t, size; int32_t t, size;
UBYTE *rpn; uint8_t *rpn;
uint8_t rpn_cmd;
int32_t nBank;
rpnp = 0; rpnp = 0;
@@ -96,7 +110,9 @@ calcrpn(struct sPatch * pPatch)
while (size > 0) { while (size > 0) {
size -= 1; size -= 1;
switch (*rpn++) { rpn_cmd = *rpn++;
switch (rpn_cmd) {
case RPN_ADD: case RPN_ADD:
rpnpush(rpnpop() + rpnpop()); rpnpush(rpnpop() + rpnpop());
break; break;
@@ -128,7 +144,7 @@ calcrpn(struct sPatch * pPatch)
rpnpush(rpnpop() ^ rpnpop()); rpnpush(rpnpop() ^ rpnpop());
break; break;
case RPN_UNNOT: case RPN_UNNOT:
rpnpush(rpnpop() ^ 0xFFFFFFFF); rpnpush(~rpnpop());
break; break;
case RPN_LOGAND: case RPN_LOGAND:
rpnpush(rpnpop() && rpnpop()); rpnpush(rpnpop() && rpnpop());
@@ -174,8 +190,8 @@ calcrpn(struct sPatch * pPatch)
rpnpush(t & 0xFF); rpnpush(t & 0xFF);
if (t < 0 || (t > 0xFF && t < 0xFF00) || t > 0xFFFF) { if (t < 0 || (t > 0xFF && t < 0xFF00) || t > 0xFFFF) {
errx(1, errx(1,
"%s(%ld) : Value must be in the HRAM area", "%s(%ld) : Value must be in the HRAM area",
pPatch->pzFilename, pPatch->nLineNo); pPatch->pzFilename, pPatch->nLineNo);
} }
break; break;
case RPN_CONST: case RPN_CONST:
@@ -197,7 +213,7 @@ calcrpn(struct sPatch * pPatch)
pPatch->oRelocPatch |= (getsymbank(t) != -1); pPatch->oRelocPatch |= (getsymbank(t) != -1);
size -= 4; size -= 4;
break; break;
case RPN_BANK: case RPN_BANK_SYM:
/* symbol */ /* symbol */
t = (*rpn++); t = (*rpn++);
t |= (*rpn++) << 8; t |= (*rpn++) << 8;
@@ -206,13 +222,40 @@ calcrpn(struct sPatch * pPatch)
rpnpush(getsymbank(t)); rpnpush(getsymbank(t));
size -= 4; size -= 4;
break; break;
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);
}
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()); return rpnpop();
} }
void void Patch(void)
Patch(void)
{ {
struct sSection *pSect; struct sSection *pSect;
@@ -223,7 +266,8 @@ Patch(void)
pCurrentSection = pSect; pCurrentSection = pSect;
pPatch = pSect->pPatches; pPatch = pSect->pPatches;
while (pPatch) { while (pPatch) {
SLONG t; int32_t t;
int32_t nPatchOrg;
nPC = pSect->nOrg + pPatch->nOffset; nPC = pSect->nOrg + pPatch->nOffset;
t = calcrpn(pPatch); t = calcrpn(pPatch);
@@ -232,12 +276,12 @@ Patch(void)
if (t >= -128 && t <= 255) { if (t >= -128 && t <= 255) {
t &= 0xFF; t &= 0xFF;
pSect->pData[pPatch->nOffset] = pSect->pData[pPatch->nOffset] =
(UBYTE) t; (uint8_t)t;
} else { } else {
errx(1, errx(1,
"%s(%ld) : Value must be 8-bit", "%s(%ld) : Value must be 8-bit",
pPatch->pzFilename, pPatch->pzFilename,
pPatch->nLineNo); pPatch->nLineNo);
} }
break; break;
case PATCH_WORD_L: case PATCH_WORD_L:
@@ -249,19 +293,37 @@ Patch(void)
(t >> 8) & 0xFF; (t >> 8) & 0xFF;
} else { } else {
errx(1, errx(1,
"%s(%ld) : Value must be 16-bit", "%s(%ld) : Value must be 16-bit",
pPatch->pzFilename, pPatch->pzFilename,
pPatch->nLineNo); pPatch->nLineNo);
} }
break; break;
case PATCH_LONG_L: case PATCH_LONG_L:
pSect->pData[pPatch->nOffset + 0] = t & 0xFF; pSect->pData[pPatch->nOffset + 0] = t & 0xFF;
pSect->pData[pPatch->nOffset + 1] = pSect->pData[pPatch->nOffset + 1] =
(t >> 8) & 0xFF; (t >> 8) & 0xFF;
pSect->pData[pPatch->nOffset + 2] = pSect->pData[pPatch->nOffset + 2] =
(t >> 16) & 0xFF; (t >> 16) & 0xFF;
pSect->pData[pPatch->nOffset + 3] = pSect->pData[pPatch->nOffset + 3] =
(t >> 24) & 0xFF; (t >> 24) & 0xFF;
break;
case PATCH_BYTE_JR:
/* Calculate absolute address of the patch */
nPatchOrg = pSect->nOrg + pPatch->nOffset;
/* t contains the destination of the jump */
t = (int16_t)((t & 0xFFFF) - (nPatchOrg + 1));
if (t >= -128 && t <= 255) {
t &= 0xFF;
pSect->pData[pPatch->nOffset] =
(uint8_t)t;
} else {
errx(1,
"%s(%ld) : Value must be 8-bit",
pPatch->pzFilename,
pPatch->nLineNo);
}
break; break;
} }

View File

@@ -1,18 +1,11 @@
.\" Copyright © 2010 Anthony J. Bentley <anthony@anjbe.name>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" This file is part of RGBDS.
.\" 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 .\" Copyright (c) 2010-2018, Anthony J. Bentley and RGBDS contributors.
.\" 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.
.\" .\"
.Dd April 17, 2017 .\" SPDX-License-Identifier: MIT
.\"
.Dd January 26, 2018
.Dt RGBLINK 1 .Dt RGBLINK 1
.Os RGBDS Manual .Os RGBDS Manual
.Sh NAME .Sh NAME
@@ -64,7 +57,7 @@ Write a symbol file to the given filename.
.It Fl O Ar overlayfile .It Fl O Ar overlayfile
The ROM image to overlay sections over. The ROM image to overlay sections over.
When an overlay ROM is provided, all sections must be fixed. When an overlay ROM is provided, all sections must be fixed.
This may be used to patch an existing binray. This may be used to patch an existing binary.
.It Fl o Ar outfile .It Fl o Ar outfile
Write ROM image to the given filename. Write ROM image to the given filename.
.It Fl p Ar pad_value .It Fl p Ar pad_value

View File

@@ -1,18 +1,11 @@
.\" Copyright (C) 2017 Antonio Nino Diaz <antonio_nd@outlook.com>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" This file is part of RGBDS.
.\" 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 .\" Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
.\" 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.
.\" .\"
.Dd April 17, 2017 .\" SPDX-License-Identifier: MIT
.\"
.Dd January 27, 2018
.Dt RGBLINK 5 .Dt RGBLINK 5
.Os RGBDS Manual .Os RGBDS Manual
.Sh NAME .Sh NAME
@@ -45,7 +38,7 @@ WRAMX 2
.Pp .Pp
Numbers can be in decimal or hexadecimal format (the prefix is Numbers can be in decimal or hexadecimal format (the prefix is
.Ql $ ) . .Ql $ ) .
It is an error if any bank or command is found before setting a bank. It is an error if any section name or command are found before setting a bank.
.Pp .Pp
Files can be included by using the Files can be included by using the
.Ar INCLUDE .Ar INCLUDE

View File

@@ -1,165 +1,171 @@
/* /*
* Copyright (C) 2017 Antonio Nino Diaz <antonio_nd@outlook.com> * This file is part of RGBDS.
* *
* Permission to use, copy, modify, and distribute this software for any * Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
* 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 * SPDX-License-Identifier: MIT
* 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 <stdint.h>
#include <string.h> #include <string.h>
#include "extern/err.h" #include "extern/err.h"
#include "link/assign.h" #include "link/assign.h"
#include "link/mylink.h" #include "link/mylink.h"
static struct { static struct {
unsigned int address; /* current address to write sections to */ uint32_t address; /* current address to write sections to */
unsigned int top_address; /* not inclusive */ uint32_t top_address; /* not inclusive */
enum eSectionType type; enum eSectionType type;
} bank[MAXBANKS]; } bank[BANK_INDEX_MAX];
static int current_bank = -1; /* Bank as seen by the bank array */ static int32_t 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_real_bank = -1; /* bank as seen by the GB */
void script_InitSections(void) void script_InitSections(void)
{ {
int i; int32_t i;
for (i = 0; i < MAXBANKS; i++) {
if (i == BANK_ROM0) { for (i = 0; i < BANK_INDEX_MAX; i++) {
if (BankIndexIsROM0(i)) {
/* ROM0 bank */ /* ROM0 bank */
bank[i].address = 0x0000; bank[i].address = 0x0000;
if (options & OPT_TINY) { if (options & OPT_TINY)
bank[i].top_address = 0x8000; bank[i].top_address = 0x8000;
} else { else
bank[i].top_address = 0x4000; bank[i].top_address = 0x4000;
}
bank[i].type = SECT_ROM0; bank[i].type = SECT_ROM0;
} else if (i >= BANK_ROMX && i < BANK_ROMX + BANK_COUNT_ROMX) { } else if (BankIndexIsROMX(i)) {
/* Swappable ROM bank */ /* Swappable ROM bank */
bank[i].address = 0x4000; bank[i].address = 0x4000;
bank[i].top_address = 0x8000; bank[i].top_address = 0x8000;
bank[i].type = SECT_ROMX; bank[i].type = SECT_ROMX;
} else if (i == BANK_WRAM0) { } else if (BankIndexIsWRAM0(i)) {
/* WRAM */ /* WRAM */
bank[i].address = 0xC000; bank[i].address = 0xC000;
if (options & OPT_CONTWRAM) { if (options & OPT_CONTWRAM)
bank[i].top_address = 0xE000; bank[i].top_address = 0xE000;
} else { else
bank[i].top_address = 0xD000; bank[i].top_address = 0xD000;
}
bank[i].type = SECT_WRAM0; bank[i].type = SECT_WRAM0;
} else if (i >= BANK_SRAM && i < BANK_SRAM + BANK_COUNT_SRAM) { } else if (BankIndexIsSRAM(i)) {
/* Swappable SRAM bank */ /* Swappable SRAM bank */
bank[i].address = 0xA000; bank[i].address = 0xA000;
bank[i].top_address = 0xC000; bank[i].top_address = 0xC000;
bank[i].type = SECT_SRAM; bank[i].type = SECT_SRAM;
} else if (i >= BANK_WRAMX && i < BANK_WRAMX + BANK_COUNT_WRAMX) { } else if (BankIndexIsWRAMX(i)) {
/* Swappable WRAM bank */ /* Swappable WRAM bank */
bank[i].address = 0xD000; bank[i].address = 0xD000;
bank[i].top_address = 0xE000; bank[i].top_address = 0xE000;
bank[i].type = SECT_WRAMX; bank[i].type = SECT_WRAMX;
} else if (i >= BANK_VRAM && i < BANK_VRAM + BANK_COUNT_VRAM) { } else if (BankIndexIsVRAM(i)) {
/* Swappable VRAM bank */ /* Swappable VRAM bank */
bank[i].address = 0x8000; bank[i].address = 0x8000;
bank[i].type = SECT_VRAM; 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. */ /* In DMG the only available bank is bank 0. */
bank[i].top_address = 0x8000; bank[i].top_address = 0x8000;
} else { } else {
bank[i].top_address = 0xA000; bank[i].top_address = 0xA000;
} }
} else if (i == BANK_OAM) { } else if (BankIndexIsOAM(i)) {
/* OAM */ /* OAM */
bank[i].address = 0xFE00; bank[i].address = 0xFE00;
bank[i].top_address = 0xFEA0; bank[i].top_address = 0xFEA0;
bank[i].type = SECT_OAM; bank[i].type = SECT_OAM;
} else if (i == BANK_HRAM) { } else if (BankIndexIsHRAM(i)) {
/* HRAM */ /* HRAM */
bank[i].address = 0xFF80; bank[i].address = 0xFF80;
bank[i].top_address = 0xFFFF; bank[i].top_address = 0xFFFF;
bank[i].type = SECT_HRAM; bank[i].type = SECT_HRAM;
} else { } 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 (strcmp(type, "ROM0") == 0) {
if (bank != 0) if (bank != 0)
errx(1, "(Internal) Trying to assign a bank number to ROM0.\n"); errx(1, "Trying to assign a bank number to ROM0.\n");
current_bank = BANK_ROM0; current_bank = BANK_INDEX_ROM0;
current_real_bank = 0; current_real_bank = 0;
return; return;
} else if (strcmp(type, "ROMX") == 0) { } else if (strcmp(type, "ROMX") == 0) {
if (bank == 0) if (bank == 0)
errx(1, "ROMX index can't be 0.\n"); errx(1, "ROMX index can't be 0.\n");
if (bank > BANK_COUNT_ROMX) if (bank > BANK_COUNT_ROMX) {
errx(1, "ROMX index too big (%d > %d).\n", bank, BANK_COUNT_ROMX); errx(1, "ROMX index too big (%d > %d).\n", bank,
current_bank = BANK_ROMX + bank - 1; BANK_COUNT_ROMX);
}
current_bank = BANK_INDEX_ROMX + bank - 1;
current_real_bank = bank; current_real_bank = bank;
return; return;
} else if (strcmp(type, "VRAM") == 0) { } else if (strcmp(type, "VRAM") == 0) {
if (bank >= BANK_COUNT_VRAM) if (bank >= BANK_COUNT_VRAM) {
errx(1, "VRAM index too big (%d >= %d).\n", bank, BANK_COUNT_VRAM); errx(1, "VRAM index too big (%d >= %d).\n", bank,
current_bank = BANK_VRAM + bank; BANK_COUNT_VRAM);
}
current_bank = BANK_INDEX_VRAM + bank;
current_real_bank = bank; current_real_bank = bank;
return; return;
} else if (strcmp(type, "WRAM0") == 0) { } else if (strcmp(type, "WRAM0") == 0) {
if (bank != 0) if (bank != 0)
errx(1, "(Internal) Trying to assign a bank number to WRAM0.\n"); errx(1, "Trying to assign a bank number to WRAM0.\n");
current_bank = BANK_WRAM0;
current_bank = BANK_INDEX_WRAM0;
current_real_bank = 0; current_real_bank = 0;
return; return;
} else if (strcmp(type, "WRAMX") == 0) { } else if (strcmp(type, "WRAMX") == 0) {
if (bank == 0) if (bank == 0)
errx(1, "WRAMX index can't be 0.\n"); errx(1, "WRAMX index can't be 0.\n");
if (bank > BANK_COUNT_WRAMX) if (bank > BANK_COUNT_WRAMX) {
errx(1, "WRAMX index too big (%d > %d).\n", bank, BANK_COUNT_WRAMX); errx(1, "WRAMX index too big (%d > %d).\n", bank,
current_bank = BANK_WRAMX + bank - 1; BANK_COUNT_WRAMX);
current_real_bank = bank - 1; }
current_bank = BANK_INDEX_WRAMX + bank - 1;
current_real_bank = bank;
return; return;
} else if (strcmp(type, "SRAM") == 0) { } else if (strcmp(type, "SRAM") == 0) {
if (bank >= BANK_COUNT_SRAM) if (bank >= BANK_COUNT_SRAM) {
errx(1, "SRAM index too big (%d >= %d).\n", bank, BANK_COUNT_SRAM); errx(1, "SRAM index too big (%d >= %d).\n", bank,
current_bank = BANK_SRAM + bank; BANK_COUNT_SRAM);
}
current_bank = BANK_INDEX_SRAM + bank;
current_real_bank = bank; current_real_bank = bank;
return; return;
} else if (strcmp(type, "OAM") == 0) { } else if (strcmp(type, "OAM") == 0) {
if (bank != 0) if (bank != 0) {
errx(1, "(Internal) Trying to assign a bank number to OAM.\n"); errx(1, "%s: Trying to assign a bank number to OAM.\n",
current_bank = BANK_OAM; __func__);
}
current_bank = BANK_INDEX_OAM;
current_real_bank = 0; current_real_bank = 0;
return; return;
} else if (strcmp(type, "HRAM") == 0) { } else if (strcmp(type, "HRAM") == 0) {
if (bank != 0) if (bank != 0) {
errx(1, "(Internal) Trying to assign a bank number to HRAM.\n"); errx(1, "%s: Trying to assign a bank number to HRAM.\n",
current_bank = BANK_HRAM; __func__);
}
current_bank = BANK_INDEX_HRAM;
current_real_bank = 0; current_real_bank = 0;
return; 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"); errx(1, "Trying to set an address without assigned bank\n");
}
/* Make sure that we don't go back. */ /* Make sure that we don't go back. */
if (bank[current_bank].address > addr) { if (bank[current_bank].address > addr) {
errx(1, "Trying to go to a previous address (0x%04X to 0x%04X)\n", errx(1, "Trying to go to a previous address (0x%04X to 0x%04X)\n",
bank[current_bank].address, addr); bank[current_bank].address, addr);
} }
bank[current_bank].address = addr; bank[current_bank].address = addr;
@@ -167,22 +173,21 @@ void script_SetAddress(unsigned int addr)
/* Make sure we don't overflow */ /* Make sure we don't overflow */
if (bank[current_bank].address >= bank[current_bank].top_address) { if (bank[current_bank].address >= bank[current_bank].top_address) {
errx(1, "Bank overflowed (0x%04X >= 0x%04X)\n", 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"); 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); errx(1, "Trying to set an alignment too big: %d\n", alignment);
}
unsigned int size = 1 << alignment; uint32_t size = 1 << alignment;
unsigned int mask = size - 1; uint32_t mask = size - 1;
if (bank[current_bank].address & mask) { if (bank[current_bank].address & mask) {
bank[current_bank].address &= ~mask; bank[current_bank].address &= ~mask;
@@ -192,25 +197,29 @@ void script_SetAlignment(unsigned int alignment)
/* Make sure we don't overflow */ /* Make sure we don't overflow */
if (bank[current_bank].address >= bank[current_bank].top_address) { if (bank[current_bank].address >= bank[current_bank].top_address) {
errx(1, "Bank overflowed (0x%04X >= 0x%04X)\n", 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) void script_OutputSection(const char *section_name)
{ {
if (current_bank == -1) { 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,
current_real_bank)) { bank[current_bank].type,
current_real_bank)) {
errx(1, "Different attributes for \"%s\" in source and linkerscript\n", errx(1, "Different attributes for \"%s\" in source and linkerscript\n",
section_name); section_name);
} }
/* Move section to its place. */ /* Move section to its place. */
bank[current_bank].address += bank[current_bank].address +=
AssignSectionAddressAndBankByName(section_name, AssignSectionAddressAndBankByName(section_name,
bank[current_bank].address, current_real_bank); bank[current_bank].address,
current_real_bank);
} }

View File

@@ -1,85 +1,93 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "extern/err.h" #include "extern/err.h"
#include "link/main.h" #include "link/main.h"
#include "link/patch.h" #include "link/patch.h"
#include "types.h" #include "types.h"
#define HASHSIZE 73 #define HASHSIZE 73
struct ISymbol { struct ISymbol {
char *pzName; char *pzName;
SLONG nValue; int32_t nValue;
SLONG nBank; /* -1 = constant */ int32_t nBank; /* -1 = constant */
char tzObjFileName[_MAX_PATH + 1]; /* Object file where the symbol was defined. */ /* Object file where the symbol was defined. */
char tzFileName[_MAX_PATH + 1]; /* Source file where the symbol was defined. */ char tzObjFileName[_MAX_PATH + 1];
ULONG nFileLine; /* Line where the symbol was defined. */ /* 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 *pNext;
}; };
struct ISymbol *tHash[HASHSIZE]; struct ISymbol *tHash[HASHSIZE];
SLONG int32_t calchash(char *s)
calchash(char *s)
{ {
SLONG r = 0; int32_t r = 0;
while (*s) while (*s)
r += *s++; r += *s++;
return (r % HASHSIZE); return r % HASHSIZE;
} }
void void sym_Init(void)
sym_Init(void)
{ {
SLONG i; int32_t i;
for (i = 0; i < HASHSIZE; i += 1) for (i = 0; i < HASHSIZE; i += 1)
tHash[i] = NULL; tHash[i] = NULL;
} }
SLONG int32_t sym_GetValue(char *tzName)
sym_GetValue(char *tzName)
{ {
if (strcmp(tzName, "@") == 0) { if (strcmp(tzName, "@") == 0)
return (nPC); return nPC;
} else {
struct ISymbol **ppSym;
ppSym = &(tHash[calchash(tzName)]);
while (*ppSym) {
if (strcmp(tzName, (*ppSym)->pzName)) {
ppSym = &((*ppSym)->pNext);
} else {
return ((*ppSym)->nValue);
}
}
errx(1, "Unknown symbol '%s'", tzName);
}
}
SLONG
sym_GetBank(char *tzName)
{
struct ISymbol **ppSym; struct ISymbol **ppSym;
ppSym = &(tHash[calchash(tzName)]); ppSym = &(tHash[calchash(tzName)]);
while (*ppSym) { while (*ppSym) {
if (strcmp(tzName, (*ppSym)->pzName)) { if (strcmp(tzName, (*ppSym)->pzName))
ppSym = &((*ppSym)->pNext); ppSym = &((*ppSym)->pNext);
} else { else
return ((*ppSym)->nBank); return ((*ppSym)->nValue);
}
} }
errx(1, "Unknown symbol '%s'", tzName); errx(1, "Unknown symbol '%s'", tzName);
} }
void int32_t sym_GetBank(char *tzName)
sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank, char *tzObjFileName, {
char *tzFileName, ULONG nFileLine) struct ISymbol **ppSym;
ppSym = &(tHash[calchash(tzName)]);
while (*ppSym) {
if (strcmp(tzName, (*ppSym)->pzName))
ppSym = &((*ppSym)->pNext);
else
return ((*ppSym)->nBank);
}
errx(1, "Unknown symbol '%s'", tzName);
}
void sym_CreateSymbol(char *tzName, int32_t nValue, int32_t nBank,
char *tzObjFileName, char *tzFileName, uint32_t nFileLine)
{ {
if (strcmp(tzName, "@") == 0) if (strcmp(tzName, "@") == 0)
return; return;
@@ -96,14 +104,18 @@ sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank, char *tzObjFileName,
return; return;
errx(1, "'%s' in both %s : %s(%d) and %s : %s(%d)", errx(1, "'%s' in both %s : %s(%d) and %s : %s(%d)",
tzName, tzObjFileName, tzFileName, nFileLine, tzName, tzObjFileName, tzFileName, nFileLine,
(*ppSym)->tzObjFileName, (*ppSym)->tzObjFileName,
(*ppSym)->tzFileName, (*ppSym)->nFileLine); (*ppSym)->tzFileName, (*ppSym)->nFileLine);
} }
} }
if ((*ppSym = malloc(sizeof **ppSym))) { *ppSym = malloc(sizeof **ppSym);
if (((*ppSym)->pzName = malloc(strlen(tzName) + 1))) {
if (*ppSym != NULL) {
(*ppSym)->pzName = malloc(strlen(tzName) + 1);
if ((*ppSym)->pzName != NULL) {
strcpy((*ppSym)->pzName, tzName); strcpy((*ppSym)->pzName, tzName);
(*ppSym)->nValue = nValue; (*ppSym)->nValue = nValue;
(*ppSym)->nBank = nBank; (*ppSym)->nBank = nBank;

View File

@@ -1,18 +1,11 @@
.\" Copyright (c) 2017 Antonio Nino Diaz <antonio_nd@outlook.com>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" This file is part of RGBDS.
.\" 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 .\" Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
.\" 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.
.\" .\"
.Dd July 22, 2017 .\" SPDX-License-Identifier: MIT
.\"
.Dd January 26, 2018
.Dt RGBDS 5 .Dt RGBDS 5
.Os RGBDS Manual .Os RGBDS Manual
.Sh NAME .Sh NAME
@@ -42,7 +35,7 @@ is a 0terminated string of
.Bd -literal .Bd -literal
; Header ; Header
BYTE ID[4] ; "RGB5" BYTE ID[4] ; "RGB6"
LONG NumberOfSymbols ; The number of symbols used in this file LONG NumberOfSymbols ; The number of symbols used in this file
LONG NumberOfSections ; The number of sections used in this file LONG NumberOfSections ; The number of sections used in this file
@@ -120,6 +113,7 @@ REPT NumberOfSections
BYTE Type ; 0 = BYTE patch. BYTE Type ; 0 = BYTE patch.
; 1 = little endian WORD patch. ; 1 = little endian WORD patch.
; 2 = little endian LONG patch. ; 2 = little endian LONG patch.
; 3 = JR offset value BYTE patch.
LONG RPNSize ; Size of the buffer with the RPN. LONG RPNSize ; Size of the buffer with the RPN.
; expression. ; expression.
@@ -155,25 +149,29 @@ special prefixes for integers and symbols.
.It Li $03 Ta Li / operator .It Li $03 Ta Li / operator
.It Li $04 Ta Li % operator .It Li $04 Ta Li % operator
.It Li $05 Ta Li unary - .It Li $05 Ta Li unary -
.It Li $06 Ta Li | operator .It Li $10 Ta Li | operator
.It Li $07 Ta Li & operator .It Li $11 Ta Li & operator
.It Li $08 Ta Li ^ operator .It Li $12 Ta Li ^ operator
.It Li $09 Ta Li unary ~ .It Li $13 Ta Li unary ~
.It Li $0A Ta Li && comparison .It Li $21 Ta Li && comparison
.It Li $0B Ta Li || comparison .It Li $22 Ta Li || comparison
.It Li $0C Ta Li unary ! .It Li $23 Ta Li unary !
.It Li $0D Ta Li == comparison .It Li $30 Ta Li == comparison
.It Li $0E Ta Li != comparison .It Li $31 Ta Li != comparison
.It Li $0F Ta Li > comparison .It Li $32 Ta Li > comparison
.It Li $10 Ta Li < comparison .It Li $33 Ta Li < comparison
.It Li $11 Ta Li >= comparison .It Li $34 Ta Li >= comparison
.It Li $12 Ta Li <= comparison .It Li $35 Ta Li <= comparison
.It Li $13 Ta Li << comparison .It Li $40 Ta Li << comparison
.It Li $14 Ta Li >> comparison .It Li $41 Ta Li >> comparison
.It Li $15 Ta Li BANK() .It Li $50 Ta Li BANK(symbol),
function. a
A symbol ID follows. .Ar LONG
.It Li $16 Ta Li HRAMCheck. 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. Check if the value is in HRAM, AND it with 0xFF.
.It Li $80 Ta Ar LONG .It Li $80 Ta Ar LONG
integer follows. integer follows.

View File

@@ -1,18 +1,11 @@
.\" Copyright © 2010 Anthony J. Bentley <anthony@anjbe.name>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" This file is part of RGBDS.
.\" 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 .\" Copyright (c) 2010-2018, Anthony J. Bentley and RGBDS contributors.
.\" 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.
.\" .\"
.Dd April 17, 2017 .\" SPDX-License-Identifier: MIT
.\"
.Dd March 7, 2018
.Dt RGBDS 7 .Dt RGBDS 7
.Os RGBDS Manual .Os RGBDS Manual
.Sh NAME .Sh NAME
@@ -21,9 +14,11 @@
.Sh EXAMPLES .Sh EXAMPLES
To get a working ROM image from a single assembly source file: To get a working ROM image from a single assembly source file:
.Pp .Pp
.D1 $ rgbasm \-o bar.o foo.asm .Bd -literal -offset indent
.D1 $ rgblink \-o baz.gb bar.o $ rgbasm \-o bar.o foo.asm
.D1 $ rgbfix \-v \-p 0 baz.gb $ rgblink \-o baz.gb bar.o
$ rgbfix \-v \-p 0 baz.gb
.Ed
.Sh SEE ALSO .Sh SEE ALSO
.Xr rgbasm 1 , .Xr rgbasm 1 ,
.Xr rgbfix 1 , .Xr rgbfix 1 ,
@@ -48,4 +43,6 @@ implementation of rgbds.
2017, Bentley's repository is moved to a neutral name. 2017, Bentley's repository is moved to a neutral name.
It is now maintained by a number of contributors at It is now maintained by a number of contributors at
.Lk https://github.com/rednex/rgbds . .Lk https://github.com/rednex/rgbds .
.It
2018, codebase relicensed under the MIT license.
.El .El

26
src/version.c Normal file
View File

@@ -0,0 +1,26 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include <string.h>
#include "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

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

View File

@@ -0,0 +1,237 @@
SECTION "All instructions", ROM0
; 8-bit Arithmetic and Logic Instructions
alu_instruction_list : MACRO
\1 a,a
\1 a,b
\1 a,c
\1 a,d
\1 a,$DB
\1 a,e
\1 a,h
\1 a,[hl]
\1 a,l
ENDM
alu_instruction_list adc
alu_instruction_list add
alu_instruction_list and
alu_instruction_list cp
alu_instruction_list or
alu_instruction_list sbc
alu_instruction_list sub
alu_instruction_list xor
incdec_8bit_instruction_list : MACRO
\1 a
\1 b
\1 c
\1 d
\1 e
\1 h
\1 [hl]
\1 l
ENDM
incdec_8bit_instruction_list inc
incdec_8bit_instruction_list dec
; 16-bit Arithmetic Instructions
add hl,bc
add hl,de
add hl,hl
add hl,sp
inc bc
inc de
inc hl
inc sp
dec bc
dec de
dec hl
dec sp
; Bit Operations Instructions
bitop_u3_instruction_list : MACRO
NBIT SET 0
REPT 8
\1 NBIT,a
\1 NBIT,b
\1 NBIT,c
\1 NBIT,d
\1 NBIT,e
\1 NBIT,h
\1 NBIT,[hl]
\1 NBIT,l
NBIT SET NBIT + 1
ENDR
ENDM
bitop_u3_instruction_list bit
bitop_u3_instruction_list res
bitop_u3_instruction_list set
bitop_noarg_instruction_list : MACRO
\1 a
\1 b
\1 c
\1 d
\1 e
\1 h
\1 [hl]
\1 l
ENDM
bitop_noarg_instruction_list swap
; Bit Shift Instructions
rla
rlca
rra
rrca
bitop_noarg_instruction_list rl
bitop_noarg_instruction_list rlc
bitop_noarg_instruction_list rr
bitop_noarg_instruction_list rrc
bitop_noarg_instruction_list sla
bitop_noarg_instruction_list sra
bitop_noarg_instruction_list srl
; Load Instructions
ld_r8_x_instruction_list : MACRO
ld \1,a
ld \1,b
ld \1,c
ld \1,d
ld \1,$DB
ld \1,e
ld \1,h
ld \1,l
ENDM
ld_r8_x_instruction_list a
ld_r8_x_instruction_list b
ld_r8_x_instruction_list c
ld_r8_x_instruction_list d
ld_r8_x_instruction_list e
ld_r8_x_instruction_list h
ld_r8_x_instruction_list [hl]
ld_r8_x_instruction_list l
ld_x_r8_instruction_list : MACRO
ld a,\1
ld b,\1
ld c,\1
ld d,\1
ld e,\1
ld h,\1
ld l,\1
ENDM
ld_x_r8_instruction_list a
ld_x_r8_instruction_list b
ld_x_r8_instruction_list c
ld_x_r8_instruction_list d
ld_x_r8_instruction_list e
ld_x_r8_instruction_list h
ld_x_r8_instruction_list [hl]
ld_x_r8_instruction_list l
ld bc,$ABCD
ld de,$ABCD
ld hl,$ABCD
ld sp,$ABCD
ld [bc],a
ld [de],a
ld [hl],a
ld [$ABCD],a
ldh [$ff00+$DB],a
ld [$ff00+c],a
ld a,[bc]
ld a,[de]
ld a,[hl]
ld a,[$ABCD]
ldh a,[$ff00+$DB]
ld a,[$ff00+c]
ld [hl+],a
ld [hl-],a
ld a,[hl+]
ld a,[hl-]
; Jumps and Subroutines
call $ABCD
call z,$ABCD
call nz,$ABCD
call c,$ABCD
call nc,$ABCD
jp hl
jp $ABCD
jp z,$ABCD
jp nz,$ABCD
jp c,$ABCD
jp nc,$ABCD
jrlabel:
jr jrlabel
jr z,jrlabel
jr nz,jrlabel
jr c,jrlabel
jr nc,jrlabel
ret
ret z
ret nz
ret c
ret nc
reti
rst $00
rst $08
rst $10
rst $18
rst $20
rst $28
rst $30
rst $38
; Stack Operations Instructions
add sp,$DB
ld [$ABCD],sp
ld hl,sp+$DB
ld sp,hl
pop af
pop bc
pop de
pop hl
push af
push bc
push de
push hl
; Miscellaneous Instructions
ccf
cpl
daa
di
ei
halt
nop
scf
stop

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More