Compare commits

...

26 Commits

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

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

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

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

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

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

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

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

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

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

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

Add missing EQUs to list of keywords in documentation.

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

Manpages and help command line output updated.

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

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

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

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

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

View File

@@ -15,8 +15,15 @@ PNGCFLAGS := `${PKG_CONFIG} --static --cflags libpng`
PNGLDFLAGS := `${PKG_CONFIG} --static --libs-only-L libpng`
PNGLDLIBS := `${PKG_CONFIG} --static --libs-only-l libpng`
VERSION_STRING := `git describe --tags --dirty --always 2>/dev/null`
WARNFLAGS := -Wall -Werror
CFLAGS := ${WARNFLAGS} -g -std=c99 -D_POSIX_C_SOURCE=200809L -Iinclude
# Overridable CFLAGS
CFLAGS := -g
# Non-overridable CFLAGS
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=c99 -D_POSIX_C_SOURCE=200809L \
-Iinclude -DBUILD_VERSION_STRING=\"${VERSION_STRING}\"
YFLAGS :=
LFLAGS := --nounistd
@@ -44,7 +51,9 @@ rgbasm_obj := \
src/extern/err.o \
src/extern/reallocarray.o \
src/extern/strlcpy.o \
src/extern/strlcat.o
src/extern/strlcat.o \
src/extern/version.o
src/asm/asmy.h: src/asm/asmy.c
src/asm/locallex.o src/asm/globlex.o src/asm/lexer.o: src/asm/asmy.h
@@ -61,32 +70,35 @@ rgblink_obj := \
src/link/parser.o \
src/link/script.o \
src/link/symbol.o \
src/extern/err.o
src/extern/err.o \
src/extern/version.o
src/link/parser.h: src/link/parser.c
src/link/lexer.o: src/link/parser.h
rgbfix_obj := \
src/fix/main.o \
src/extern/err.o
src/extern/err.o \
src/extern/version.o
rgbgfx_obj := \
src/gfx/gb.o \
src/gfx/main.o \
src/gfx/makepng.o \
src/extern/err.o
src/extern/err.o \
src/extern/version.o
rgbasm: ${rgbasm_obj}
$Q${CC} ${CFLAGS} -o $@ ${rgbasm_obj} -lm
$Q${CC} ${REALCFLAGS} -o $@ ${rgbasm_obj} -lm
rgblink: ${rgblink_obj}
$Q${CC} ${CFLAGS} -o $@ ${rgblink_obj}
$Q${CC} ${REALCFLAGS} -o $@ ${rgblink_obj}
rgbfix: ${rgbfix_obj}
$Q${CC} ${CFLAGS} -o $@ ${rgbfix_obj}
$Q${CC} ${REALCFLAGS} -o $@ ${rgbfix_obj}
rgbgfx: ${rgbgfx_obj}
$Q${CC} ${CFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${PNGLDLIBS}
$Q${CC} ${REALCFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${PNGLDLIBS}
# Rules to process files
@@ -96,11 +108,11 @@ rgbgfx: ${rgbgfx_obj}
.l.o:
$Q${RM} $*.c
$Q${LEX} ${LFLAGS} -o $*.c $<
$Q${CC} ${CFLAGS} -c -o $@ $*.c
$Q${CC} ${REALCFLAGS} -c -o $@ $*.c
$Q${RM} $*.c
.c.o:
$Q${CC} ${CFLAGS} ${PNGCFLAGS} -c -o $@ $<
$Q${CC} ${REALCFLAGS} ${PNGCFLAGS} -c -o $@ $<
# Target used to remove all files generated by other Makefile targets.

View File

@@ -18,18 +18,23 @@
#include "asm/localasm.h"
#define MAXUNIONS 128
#define MAXMACROARGS 256
#define MAXINCPATHS 128
extern SLONG nLineNo;
extern ULONG nTotalLines;
extern ULONG nPC;
extern ULONG nPass;
extern ULONG nIFDepth;
extern bool skipElif;
extern ULONG nUnionDepth;
extern ULONG unionStart[MAXUNIONS];
extern ULONG unionSize[MAXUNIONS];
extern char tzCurrentFileName[_MAX_PATH + 1];
extern struct Section *pCurrentSection;
extern struct sSymbol *tHashedSymbols[HASHSIZE];
extern struct sSymbol *pPCSymbol;
extern bool oDontExpandStrings;
#define MAXMACROARGS 256
#define MAXINCPATHS 128
#endif /* // ASM_H */

View File

@@ -41,6 +41,8 @@ extern void fstk_RunRept(ULONG count);
FILE *
fstk_FindFile(char *);
int fstk_GetLine(void);
extern int yywrap(void);
#endif

View File

@@ -15,7 +15,9 @@ struct sSymbol {
struct Section *pSection;
ULONG ulMacroSize;
char *pMacro;
SLONG(*Callback) (struct sSymbol *);
SLONG(*Callback) (struct sSymbol *);
char tzFileName[_MAX_PATH + 1]; /* File where the symbol was defined. */
ULONG nFileLine; /* Line where the symbol was defined. */
};
#define SYMF_RELOC 0x001 /* symbol will be reloc'ed during
* linking, it's absolute value is

6
include/common.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef RGBDS_COMMON_H
#define RGBDS_COMMON_H
#define RGBDS_OBJECT_VERSION_STRING "RGB5"
#endif /* RGBDS_COMMON_H */

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

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

@@ -89,6 +89,9 @@ struct sSymbol {
SLONG nSectionID; /* internal to object.c */
struct sSection *pSection;
SLONG nOffset;
char *pzObjFileName; /* Object file where the symbol is located. */
char *pzFileName; /* Source file where the symbol was defined. */
ULONG nFileLine; /* Line where the symbol was defined. */
};
enum ePatchType {

View File

@@ -4,7 +4,8 @@
#include "types.h"
void sym_Init(void);
void sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank);
void sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank,
char *tzObjFileName, char *tzFileName, ULONG nFileLine);
SLONG sym_GetValue(char *tzName);
SLONG sym_GetBank(char *tzName);

View File

@@ -23,7 +23,7 @@ ULONG ulNewMacroSize;
void
bankrangecheck(char *name, ULONG secttype, SLONG org, SLONG bank)
{
SLONG minbank, maxbank;
SLONG minbank = 0, maxbank = 0;
char *stype = NULL;
switch (secttype) {
case SECT_ROMX:
@@ -289,70 +289,75 @@ void copymacro( void )
yyskipbytes( ulNewMacroSize+4 );
}
ULONG isIf( char *s )
ULONG isIf(char *s)
{
return( (strncasecmp(s,"If",2)==0) && isWhiteSpace(*(s-1)) && isWhiteSpace(s[2]) );
return((strncasecmp(s,"If",2) == 0) && isWhiteSpace(s[-1]) && isWhiteSpace(s[2]));
}
ULONG isElse( char *s )
ULONG isElif(char *s)
{
return( (strncasecmp(s,"Else",4)==0) && isWhiteSpace(*(s-1)) && isWhiteSpace(s[4]) );
return((strncasecmp(s,"Elif",4) == 0) && isWhiteSpace(s[-1]) && isWhiteSpace(s[4]));
}
ULONG isEndc( char *s )
ULONG isElse(char *s)
{
return( (strncasecmp(s,"Endc",4)==0) && isWhiteSpace(*(s-1)) && isWhiteSpace(s[4]) );
return((strncasecmp(s,"Else",4) == 0) && isWhiteSpace(s[-1]) && isWhiteSpace(s[4]));
}
void if_skip_to_else( void )
ULONG isEndc(char *s)
{
SLONG level=1, len, instring=0;
char *src=pCurrentBuffer->pBuffer;
return((strncasecmp(s,"Endc",4) == 0) && isWhiteSpace(s[-1]) && isWhiteSpace(s[4]));
}
while( *src && level )
{
if( *src=='\n' )
nLineNo+=1;
void if_skip_to_else()
{
SLONG level = 1;
bool inString = false;
char *src=pCurrentBuffer->pBuffer;
if( instring==0 )
{
if( isIf(src) )
{
level+=1;
src+=2;
}
else if( level==1 && isElse(src) )
{
level-=1;
src+=4;
}
else if( isEndc(src) )
{
level-=1;
if( level!=0 )
src+=4;
}
else
{
if( *src=='\"' )
instring=1;
src+=1;
}
while (*src && level) {
if (*src == '\n') {
nLineNo++;
}
else
{
if( *src=='\\' )
{
src+=2;
if (!inString) {
if (isIf(src)) {
level++;
src += 2;
} else if (level == 1 && isElif(src)) {
level--;
skipElif = false;
} else if (level == 1 && isElse(src)) {
level--;
src += 4;
} else if (isEndc(src)) {
level--;
if (level != 0) {
src += 4;
}
} else {
if (*src=='\"') {
inString = true;
}
src++;
}
else if( *src=='\"' )
{
src+=1;
instring=0;
}
else
{
src+=1;
} else {
switch (*src) {
case '\\':
src += 2;
break;
case '\"':
src++;
inString = false;
default:
src++;
break;
}
}
}
@@ -361,57 +366,56 @@ void if_skip_to_else( void )
fatalerror("Unterminated IF construct");
}
len=src-pCurrentBuffer->pBuffer;
SLONG len = src - pCurrentBuffer->pBuffer;
yyskipbytes( len );
yyunput( '\n' );
nLineNo-=1;
yyskipbytes(len);
yyunput('\n');
nLineNo--;
}
void if_skip_to_endc( void )
void if_skip_to_endc()
{
SLONG level=1, len, instring=0;
char *src=pCurrentBuffer->pBuffer;
SLONG level = 1;
bool inString = false;
char *src=pCurrentBuffer->pBuffer;
while( *src && level )
{
if( *src=='\n' )
nLineNo+=1;
while (*src && level) {
if (*src == '\n') {
nLineNo++;
}
if( instring==0 )
{
if( isIf(src) )
{
level+=1;
src+=2;
}
else if( isEndc(src) )
{
level-=1;
if( level!=0 )
src+=4;
}
else
{
if( *src=='\"' )
instring=1;
src+=1;
if (!inString) {
if (isIf(src)) {
level++;
src += 2;
} else if (isEndc(src)) {
level--;
if (level != 0) {
src += 4;
}
} else {
if (*src=='\"') {
inString = true;
}
src++;
}
}
else
{
if( *src=='\\' )
{
src+=2;
}
else if( *src=='\"' )
{
src+=1;
instring=0;
}
else
{
src+=1;
else {
switch (*src) {
case '\\':
src += 2;
break;
case '\"':
src++;
inString = false;
break;
default:
src++;
break;
}
}
}
@@ -420,11 +424,39 @@ void if_skip_to_endc( void )
fatalerror("Unterminated IF construct");
}
len=src-pCurrentBuffer->pBuffer;
SLONG len = src - pCurrentBuffer->pBuffer;
yyskipbytes( len );
yyunput( '\n' );
nLineNo-=1;
yyskipbytes(len);
yyunput('\n');
nLineNo--;
}
void startUnion() {
if (!pCurrentSection) {
fatalerror("UNIONs must be inside a SECTION");
}
ULONG unionIndex = nUnionDepth;
nUnionDepth++;
if (nUnionDepth > MAXUNIONS) {
fatalerror("Too many nested UNIONs");
}
unionStart[unionIndex] = nPC;
unionSize[unionIndex] = 0;
}
void updateUnion() {
ULONG unionIndex = nUnionDepth - 1;
ULONG size = nPC - unionStart[unionIndex];
if (size > unionSize[unionIndex]) {
unionSize[unionIndex] = size;
}
nPC = unionStart[unionIndex];
pCurrentSection->nPC = unionStart[unionIndex];
pPCSymbol->nValue = unionStart[unionIndex];
}
%}
@@ -492,7 +524,7 @@ void if_skip_to_endc( void )
%token <tzSym> T_POP_SET
%token <tzSym> T_POP_EQUS
%token T_POP_INCLUDE T_POP_PRINTF T_POP_PRINTT T_POP_PRINTV T_POP_IF T_POP_ELSE T_POP_ENDC
%token T_POP_INCLUDE T_POP_PRINTF T_POP_PRINTT T_POP_PRINTV T_POP_IF T_POP_ELIF T_POP_ELSE T_POP_ENDC
%token T_POP_IMPORT T_POP_EXPORT T_POP_GLOBAL
%token T_POP_DB T_POP_DS T_POP_DW T_POP_DL
%token T_POP_SECTION
@@ -502,6 +534,7 @@ void if_skip_to_endc( void )
%token T_POP_MACRO
%token T_POP_ENDM
%token T_POP_RSRESET T_POP_RSSET
%token T_POP_UNION T_POP_NEXTU T_POP_ENDU
%token T_POP_INCBIN T_POP_REPT
%token T_POP_CHARMAP
%token T_POP_SHIFT
@@ -627,6 +660,7 @@ simple_pseudoop : include
| printt
| printv
| if
| elif
| else
| endc
| import
@@ -639,6 +673,9 @@ simple_pseudoop : include
| section
| rsreset
| rsset
| union
| nextu
| endu
| incbin
| charmap
| rept
@@ -740,6 +777,31 @@ rb : T_LABEL T_POP_RB uconst
}
;
union : T_POP_UNION {
startUnion();
};
nextu : T_POP_NEXTU {
if (nUnionDepth <= 0) {
fatalerror("Found NEXTU outside of a UNION construct");
}
updateUnion();
};
endu : T_POP_ENDU {
if (nUnionDepth <= 0) {
fatalerror("Found ENDU outside of a UNION construct");
}
updateUnion();
nUnionDepth--;
nPC = unionStart[nUnionDepth] + unionSize[nUnionDepth];
pCurrentSection->nPC = nPC;
pPCSymbol->nValue = nPC;
};
ds : T_POP_DS uconst
{ out_Skip( $2 ); }
;
@@ -867,26 +929,47 @@ printf : T_POP_PRINTF const
}
;
if : T_POP_IF const
{
nIFDepth+=1;
if( !$2 )
{
if_skip_to_else(); /* will continue parsing just after ELSE or just at ENDC keyword */
if : T_POP_IF const {
nIFDepth++;
if (!$2) {
if_skip_to_else(); // Continue parsing after ELSE, or at ELIF or ENDC keyword
}
}
};
else : T_POP_ELSE
{
if_skip_to_endc(); /* will continue parsing just at ENDC keyword */
}
;
elif : T_POP_ELIF const {
if (nIFDepth <= 0) {
fatalerror("Found ELIF outside an IF construct");
}
endc : T_POP_ENDC
{
nIFDepth-=1;
}
;
if (skipElif) {
// This is for when ELIF is reached at the end of an IF or ELIF block for which the condition was true.
if_skip_to_endc(); // Continue parsing at ENDC keyword
} else {
// This is for when ELIF is skipped to because the condition of the previous IF or ELIF block was false.
skipElif = true;
if (!$2) {
if_skip_to_else(); // Continue parsing after ELSE, or at ELIF or ENDC keyword
}
}
};
else : T_POP_ELSE {
if (nIFDepth <= 0) {
fatalerror("Found ELSE outside an IF construct");
}
if_skip_to_endc(); // Continue parsing at ENDC keyword
};
endc : T_POP_ENDC {
if (nIFDepth <= 0) {
fatalerror("Found ENDC outside an IF construct");
}
nIFDepth--;
};
const_3bit : const
{

View File

@@ -42,8 +42,8 @@ extern FILE *dependfile;
/*
* defines for nCurrentStatus
*/
#define STAT_isInclude 0
#define STAT_isMacro 1
#define STAT_isInclude 0 /* 'Normal' state as well */
#define STAT_isMacro 1
#define STAT_isMacroArg 2
#define STAT_isREPTBlock 3
@@ -151,6 +151,37 @@ popcontext(void)
return (1);
}
int
fstk_GetLine(void)
{
struct sContext *pLastFile, **ppLastFile;
switch (nCurrentStatus) {
case STAT_isInclude:
/* This is the normal mode, also used when including a file. */
return nLineNo;
case STAT_isMacro:
break; /* Peek top file of the stack */
case STAT_isMacroArg:
return nLineNo; /* ??? */
case STAT_isREPTBlock:
break; /* Peek top file of the stack */
}
if ((pLastFile = pFileStack) != NULL) {
ppLastFile = &pFileStack;
while (pLastFile->pNext) {
ppLastFile = &(pLastFile->pNext);
pLastFile = *ppLastFile;
}
return pLastFile->nLine;
}
/* This is only reached if the lexer is in REPT or MACRO mode but there
* are no saved contexts with the origin of said REPT or MACRO. */
fatalerror("fstk_GetLine: Internal error.");
}
int
yywrap(void)
{

View File

@@ -329,7 +329,12 @@ struct sLexInitString staticstrings[] = {
{"if", T_POP_IF},
{"else", T_POP_ELSE},
{"elif", T_POP_ELIF},
{"endc", T_POP_ENDC},
{"union", T_POP_UNION},
{"nextu", T_POP_NEXTU},
{"endu", T_POP_ENDU},
{"wram0", T_SECT_WRAM0},
{"vram", T_SECT_VRAM},

View File

@@ -12,6 +12,7 @@
#include "asm/main.h"
#include "extern/err.h"
#include "extern/reallocarray.h"
#include "extern/version.h"
int yyparse(void);
void setuplex(void);
@@ -22,7 +23,9 @@ char **cldefines;
clock_t nStartClock, nEndClock;
SLONG nLineNo;
ULONG nTotalLines, nPass, nPC, nIFDepth, nErrors;
ULONG nTotalLines, nPass, nPC, nIFDepth, nUnionDepth, nErrors;
bool skipElif;
ULONG unionStart[128], unionSize[128];
extern int yydebug;
@@ -276,7 +279,7 @@ static void
usage(void)
{
printf(
"Usage: rgbasm [-hvE] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
"Usage: rgbasm [-EhVvw] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
" [-M dependfile] [-o outfile] [-p pad_value] file.asm\n");
exit(1);
}
@@ -322,7 +325,7 @@ main(int argc, char *argv[])
newopt = CurrentOptions;
while ((ch = getopt(argc, argv, "b:D:g:hi:M:o:p:vEw")) != -1) {
while ((ch = getopt(argc, argv, "b:D:g:hi:M:o:p:EVvw")) != -1) {
switch (ch) {
case 'b':
if (strlen(optarg) == 2) {
@@ -336,6 +339,9 @@ main(int argc, char *argv[])
case 'D':
opt_AddDefine(optarg);
break;
case 'E':
newopt.exportall = true;
break;
case 'g':
if (strlen(optarg) == 4) {
newopt.gbgfx[0] = optarg[1];
@@ -371,17 +377,18 @@ main(int argc, char *argv[])
"between 0 and 0xFF");
}
break;
case 'V':
printf("rgbasm %s\n", get_package_version_string());
exit(0);
case 'v':
newopt.verbose = true;
break;
case 'E':
newopt.exportall = true;
break;
case 'w':
newopt.warnings = false;
break;
default:
usage();
/* NOTREACHED */
}
}
argc -= optind;
@@ -414,6 +421,8 @@ main(int argc, char *argv[])
nLineNo = 1;
nTotalLines = 0;
nIFDepth = 0;
skipElif = true;
nUnionDepth = 0;
nPC = 0;
nPass = 1;
nErrors = 0;
@@ -436,10 +445,16 @@ main(int argc, char *argv[])
if (nIFDepth != 0) {
errx(1, "Unterminated IF construct (%ld levels)!", nIFDepth);
}
if (nUnionDepth != 0) {
errx(1, "Unterminated UNION construct (%ld levels)!", nUnionDepth);
}
nTotalLines = 0;
nLineNo = 1;
nIFDepth = 0;
skipElif = true;
nUnionDepth = 0;
nPC = 0;
nPass = 2;
nErrors = 0;

View File

@@ -15,6 +15,7 @@
#include "asm/main.h"
#include "asm/rpn.h"
#include "asm/fstack.h"
#include "common.h"
#include "extern/err.h"
void out_SetCurrentSection(struct Section * pSect);
@@ -282,6 +283,9 @@ writesymbol(struct sSymbol * pSym, FILE * f)
fputc(type, f);
if (type != SYM_IMPORT) {
fputstring(pSym->tzFileName, f);
fputlong(pSym->nFileLine, f);
fputlong(sectid, f);
fputlong(offset, f);
}
@@ -460,6 +464,8 @@ checkcodesection(void)
pCurrentSection->nType != SECT_ROMX) {
fatalerror("Section '%s' cannot contain code or data (not ROM0 or ROMX)",
pCurrentSection->pzName);
} else if (nUnionDepth > 0) {
fatalerror("UNIONs cannot contain code or data");
}
}
@@ -499,7 +505,9 @@ out_WriteObject(void)
struct PatchSymbol *pSym;
struct Section *pSect;
fwrite("RGB4", 1, 4, f);
fwrite(RGBDS_OBJECT_VERSION_STRING, 1,
strlen(RGBDS_OBJECT_VERSION_STRING), f);
fputlong(countsymbols(), f);
fputlong(countsections(), f);
@@ -613,6 +621,10 @@ out_FindSection(char *pzName, ULONG secttype, SLONG org, SLONG bank, SLONG align
void
out_SetCurrentSection(struct Section * pSect)
{
if (nUnionDepth > 0) {
fatalerror("Cannot change the section within a UNION");
}
pCurrentSection = pSect;
nPC = pSect->nPC;
@@ -651,12 +663,11 @@ out_NewAlignedSection(char *pzName, ULONG secttype, SLONG alignment, SLONG bank)
}
/*
* Output an absolute byte
* Output an absolute byte (bypassing ROM/union checks)
*/
void
out_AbsByte(int b)
out_AbsByteBypassCheck(int b)
{
checkcodesection();
checksectionoverflow(1);
b &= 0xFF;
if (nPass == 2)
@@ -667,6 +678,16 @@ out_AbsByte(int b)
pPCSymbol->nValue += 1;
}
/*
* Output an absolute byte
*/
void
out_AbsByte(int b)
{
checkcodesection();
out_AbsByteBypassCheck(b);
}
void
out_AbsByteGroup(char *s, int length)
{
@@ -689,6 +710,9 @@ out_Skip(int skip)
pCurrentSection->nPC += skip;
nPC += skip;
pPCSymbol->nValue += skip;
} else if (nUnionDepth > 0) {
while (skip--)
out_AbsByteBypassCheck(CurrentOptions.fillchar);
} else {
checkcodesection();
while (skip--)

View File

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

View File

@@ -12,7 +12,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd April 17, 2017
.Dd July 22, 2017
.Dt RGBASM 5
.Os RGBDS Manual
.Sh NAME
@@ -275,7 +275,7 @@ Alternatively you can use = as a synonym for SET.
.Pp
.Dl COUNT = 2
.Pp
.It Sy RSSET , RERESET , RB , RW
.It Sy RSSET , RSRESET , RB , RW
.Pp
The RS group of commands is a handy way of defining structures:
.Pp
@@ -549,6 +549,9 @@ The following symbols are defined by the assembler:
.It Ic EQU Ta Ic __UTC_HOUR__ Ta Ta Current hour, 0-23
.It Ic EQU Ta Ic __UTC_MINUTE__ Ta Ta Current minute, 0-59
.It Ic EQU Ta Ic __UTC_SECOND__ Ta Ta Current second, 0-59
.It Ic EQU Ta Ic __RGBDS_MAJOR__ Ta Ta Major version number of RGBDS.
.It Ic EQU Ta Ic __RGBDS_MINOR__ Ta Ta Minor version number of RGBDS.
.It Ic EQU Ta Ic __RGBDS_PATCH__ Ta Ta Patch version number of RGBDS.
.El
.Pp
.Sh DEFINING DATA
@@ -612,6 +615,41 @@ You can also include only part of a file with
The example below includes 256 bytes from data.bin starting from byte 78.
.Pp
.Dl INCBIN \[dq]data.bin\[dq],78,256
.Ss Unions
Unions allow multiple memory allocations to share the same space in memory,
like unions in C.
This allows you to easily reuse memory for different purposes, depending on
the game's state.
.Pp
You create unions using the
.Ic UNION ,
.Ic NEXTU
and
.Ic ENDU
keywords.
.Ic NEXTU
lets you create a new block of allocations, and you may use it as many times
within a union as necessary.
.Pp
.Bd -literal -offset indent
UNION
Name: ds 8
Nickname: ds 8
NEXTU
Health: dw
Something: ds 3
Lives: db
NEXTU
Temporary: ds 19
ENDU
.Ed
.Pp
This union will use up 19 bytes, as this is the size of the largest block
(the last one, containing 'Temporary').
Of course, as 'Name', 'Health', and 'Temporary' all point to the same memory
locations, writes to any one of these will affect values read from the others.
.Pp
Unions may be used in any section, but code and data may not be included.
.Sh THE MACRO LANGUAGE
.Pp
.Ss Printing things during assembly
@@ -704,27 +742,48 @@ calls infinitely (or until you run out of memory, whichever comes first).
.Dl INCLUDE \[dq]irq.inc\[dq]
.Pp
.Ss Conditional assembling
The three commands
The four commands
.Ic IF ,
.Ic ELSE
.Ic ELIF ,
.Ic ELSE ,
and
.Ic ENDC
are used to conditionally assemble parts of your file.
This is a powerful feature commonly used in macros.
.Pp
.Bd -literal -offset indent
IF 2+2==4
PRINTT \[dq]2+2==4\[rs]n\[dq]
IF NUM < 0
PRINTT \[dq]NUM < 0\[rs]n\[dq]
ELIF NUM == 0
PRINTT \[dq]NUM == 0\[rs]n\[dq]
ELSE
PRINTT \[dq]2+2!=4\[rs]n\[dq]
PRINTT \[dq]NUM > 0\[rs]n\[dq]
ENDC
.Ed
.Pp
The
.Ic ELIF
and
.Ic ELSE
block is optional.
.Ic IF No / Ic ELSE No / Ic ENDC
blocks are optional.
.Ic IF No / Ic ELIF No / Ic ELSE No / Ic ENDC
blocks can be nested.
.Pp
Note that if an
.Ic ELSE
block is found before an
.Ic ELIF
block, the
.Ic ELIF
block will be ignored.
All
.Ic ELIF
blocks must go before the
.Ic ELSE
block.
Also, if there is more than one
.Ic ELSE
block, all of them but the first one are ignored.
.Ss Integer and Boolean expressions
An expression can be composed of many things.
Expressions are always evaluated using signed 32-bit math.
@@ -956,6 +1015,15 @@ machine.
.It Sx __ISO_8601_UTC__
.It Sx __LINE__
.It Sx __TIME__
.It Sx __RGBDS_MAJOR__
.It Sx __RGBDS_MINOR__
.It Sx __RGBDS_PATCH__
.It Sx __UTC_YEAR__
.It Sx __UTC_MONTH__
.It Sx __UTC_DAY__
.It Sx __UTC_HOUR__
.It Sx __UTC_MINUTE__
.It Sx __UTC_SECOND__
.It Sx _NARG
.It Sx _PI
.It Sx _RS
@@ -970,6 +1038,7 @@ machine.
.It Sx DIV
.It Sx DS
.It Sx DW
.It Sx ELIF
.It Sx ELSE
.It Sx ENDC
.It Sx ENDM

View File

@@ -8,11 +8,13 @@
#include <time.h>
#include "asm/asm.h"
#include "asm/fstack.h"
#include "asm/symbol.h"
#include "asm/main.h"
#include "asm/mymath.h"
#include "asm/output.h"
#include "extern/err.h"
#include "extern/version.h"
struct sSymbol *tHashedSymbols[HASHSIZE];
struct sSymbol *pScope = NULL;
@@ -108,6 +110,8 @@ createsymbol(char *s)
(*ppsym)->pMacro = NULL;
(*ppsym)->pSection = NULL;
(*ppsym)->Callback = NULL;
strcpy((*ppsym)->tzFileName, tzCurrentFileName);
(*ppsym)->nFileLine = fstk_GetLine();
return (*ppsym);
} else {
fatalerror("No memory for symbol");
@@ -517,7 +521,8 @@ sym_AddEqu(char *tzSym, SLONG value)
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
yyerror("'%s' already defined in %s(%d)",
tzSym, nsym->tzFileName, nsym->nFileLine);
}
} else
nsym = createsymbol(tzSym);
@@ -549,7 +554,8 @@ sym_AddString(char *tzSym, char *tzValue)
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
yyerror("'%s' already defined in %s(%d)",
tzSym, nsym->tzFileName, nsym->nFileLine);
}
} else
nsym = createsymbol(tzSym);
@@ -652,7 +658,8 @@ sym_AddReloc(char *tzSym)
if ((nsym = findsymbol(tzSym, scope)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
yyerror("'%s' already defined in %s(%d)",
tzSym, nsym->tzFileName, nsym->nFileLine);
}
} else
nsym = createsymbol(tzSym);
@@ -781,7 +788,8 @@ sym_AddMacro(char *tzSym)
if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
yyerror("'%s' already defined in %s(%d)",
tzSym, nsym->tzFileName, nsym->nFileLine);
}
} else
nsym = createsymbol(tzSym);
@@ -848,6 +856,9 @@ sym_PrepPass2(void)
sym_AddString("__UTC_HOUR__", SavedHOUR);
sym_AddString("__UTC_MINUTE__", SavedMINUTE);
sym_AddString("__UTC_SECOND__", SavedSECOND);
sym_AddEqu("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR);
sym_AddEqu("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR);
sym_AddEqu("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH);
sym_AddSet("_RS", 0);
sym_AddEqu("_NARG", 0);

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

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

View File

@@ -22,12 +22,13 @@
#include <unistd.h>
#include "extern/err.h"
#include "extern/version.h"
static void
usage(void)
{
printf(
"usage: rgbfix [-Ccjsv] [-i game_id] [-k licensee_str] [-l licensee_id]\n"
"usage: rgbfix [-CcjsVv] [-i game_id] [-k licensee_str] [-l licensee_id]\n"
" [-m mbc_type] [-n rom_version] [-p pad_value] [-r ram_size]\n"
" [-t title_str] file\n");
exit(1);
@@ -63,13 +64,13 @@ main(int argc, char *argv[])
char *id; /* game ID in ASCII */
char *newlicensee; /* new licensee ID, two ASCII characters */
int licensee; /* old licensee ID */
int cartridge; /* cartridge hardware ID */
int ramsize; /* RAM size ID */
int version; /* mask ROM version number */
int padvalue; /* to pad the rom with if it changes size */
int licensee = 0; /* old licensee ID */
int cartridge = 0; /* cartridge hardware ID */
int ramsize = 0; /* RAM size ID */
int version = 0; /* mask ROM version number */
int padvalue = 0; /* to pad the rom with if it changes size */
while ((ch = getopt(argc, argv, "Cci:jk:l:m:n:p:sr:t:v")) != -1) {
while ((ch = getopt(argc, argv, "Cci:jk:l:m:n:p:sr:t:Vv")) != -1) {
switch (ch) {
case 'C':
coloronly = true;
@@ -177,6 +178,9 @@ main(int argc, char *argv[])
title = optarg;
break;
case 'V':
printf("rgbfix %s\n", get_package_version_string());
exit(0);
case 'v':
validate = true;
break;

View File

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

View File

@@ -14,17 +14,19 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern/version.h"
#include "gfx/main.h"
static void
usage(void)
{
printf(
"usage: rgbgfx [-DFfhPTuv] [-d #] [-o outfile] [-p palfile] [-t mapfile]\n"
"[-x #] infile\n");
"usage: rgbgfx [-DFfhPTuVv] [-d #] [-o outfile] [-p palfile] [-t mapfile]\n"
" [-x #] infile\n");
exit(1);
}
@@ -49,27 +51,30 @@ main(int argc, char *argv[])
depth = 2;
while((ch = getopt(argc, argv, "DvFfd:hx:Tt:uPp:o:")) != -1) {
while((ch = getopt(argc, argv, "Dd:Ffho:Tt:uPp:Vvx:")) != -1) {
switch(ch) {
case 'D':
opts.debug = true;
break;
case 'v':
opts.verbose = true;
case 'd':
depth = strtoul(optarg, NULL, 0);
break;
case 'F':
opts.hardfix = true;
case 'f':
opts.fix = true;
break;
case 'd':
depth = strtoul(optarg, NULL, 0);
break;
case 'h':
opts.horizontal = true;
break;
case 'x':
opts.trim = strtoul(optarg, NULL, 0);
case 'o':
opts.outfile = optarg;
break;
case 'P':
opts.palout = true;
break;
case 'p':
opts.palfile = optarg;
break;
case 'T':
opts.mapout = true;
@@ -80,17 +85,18 @@ main(int argc, char *argv[])
case 'u':
opts.unique = true;
break;
case 'P':
opts.palout = true;
case 'V':
printf("rgbgfx %s\n", get_package_version_string());
exit(0);
case 'v':
opts.verbose = true;
break;
case 'p':
opts.palfile = optarg;
break;
case 'o':
opts.outfile = optarg;
case 'x':
opts.trim = strtoul(optarg, NULL, 0);
break;
default:
usage();
/* NOTREACHED */
}
}
argc -= optind;

View File

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

View File

@@ -336,7 +336,7 @@ AssignFloatingBankSections(enum eSectionType type)
if ((org = area_AllocAnyBank(pSection->nByteSize, pSection->nAlign, type)) != -1) {
if (options & OPT_OVERLAY) {
errx(1, "All sections must be fixed when using overlay");
errx(1, "All sections must be fixed when using an overlay file.");
}
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
@@ -512,7 +512,7 @@ AssignSections(void)
if (pSection->oAssigned == 0
&& pSection->nOrg != -1 && pSection->nBank == -1) {
if (options & OPT_OVERLAY) {
errx(1, "All sections must be fixed when using overlay");
errx(1, "All sections must be fixed when using an overlay file.");
}
switch (pSection->Type) {
case SECT_ROMX:
@@ -566,16 +566,21 @@ CreateSymbolTable(void)
((pSect->tSymbols[i]->pSection == pSect) ||
(pSect->tSymbols[i]->pSection == NULL))) {
if (pSect->tSymbols[i]->pSection == NULL)
sym_CreateSymbol(pSect->tSymbols[i]->
pzName,
pSect->tSymbols[i]->
nOffset, -1);
sym_CreateSymbol(
pSect->tSymbols[i]->pzName,
pSect->tSymbols[i]->nOffset,
-1,
pSect->tSymbols[i]->pzObjFileName,
pSect->tSymbols[i]->pzFileName,
pSect->tSymbols[i]->nFileLine);
else
sym_CreateSymbol(pSect->tSymbols[i]->
pzName,
pSect->nOrg +
pSect->tSymbols[i]->
nOffset, pSect->nBank);
sym_CreateSymbol(
pSect->tSymbols[i]->pzName,
pSect->nOrg + pSect->tSymbols[i]->nOffset,
pSect->nBank,
pSect->tSymbols[i]->pzObjFileName,
pSect->tSymbols[i]->pzFileName,
pSect->tSymbols[i]->nFileLine);
}
}
pSect = pSect->pNext;

View File

@@ -4,6 +4,7 @@
#include <unistd.h>
#include "extern/err.h"
#include "extern/version.h"
#include "link/object.h"
#include "link/output.h"
#include "link/assign.h"
@@ -33,7 +34,7 @@ static void
usage(void)
{
printf(
"usage: rgblink [-twd] [-l linkerscript] [-m mapfile] [-n symfile] [-O overlay]\n"
"usage: rgblink [-dtVw] [-l linkerscript] [-m mapfile] [-n symfile] [-O overlay]\n"
" [-o outfile] [-p pad_value] [-s symbol] file [...]\n");
exit(1);
}
@@ -52,7 +53,7 @@ main(int argc, char *argv[])
if (argc == 1)
usage();
while ((ch = getopt(argc, argv, "l:m:n:o:O:p:s:twd")) != -1) {
while ((ch = getopt(argc, argv, "dl:m:n:O:o:p:s:tVw")) != -1) {
switch (ch) {
case 'l':
SetLinkerscriptName(optarg);
@@ -76,8 +77,7 @@ main(int argc, char *argv[])
errx(1, "Invalid argument for option 'p'");
}
if (fillchar < 0 || fillchar > 0xFF) {
fprintf(stderr, "Argument for option 'p' must be between 0 and 0xFF");
exit(1);
errx(1, "Argument for option 'p' must be between 0 and 0xFF");
}
break;
case 's':
@@ -98,7 +98,7 @@ main(int argc, char *argv[])
* This option implies OPT_CONTWRAM.
*/
options |= OPT_DMG_MODE;
/* fallthrough */
/* FALLTHROUGH */
case 'w':
/* Set to set WRAM as a single continuous block as on
* DMG. All WRAM sections must be WRAM0 as bankable WRAM
@@ -106,6 +106,9 @@ main(int argc, char *argv[])
* will raise an error. */
options |= OPT_CONTWRAM;
break;
case 'V':
printf("rgblink %s\n", get_package_version_string());
exit(0);
default:
usage();
/* NOTREACHED */

View File

@@ -3,11 +3,13 @@
*
*/
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "extern/err.h"
#include "link/assign.h"
#include "link/mylink.h"
@@ -116,7 +118,7 @@ AllocSection(void)
*/
struct sSymbol *
obj_ReadSymbol(FILE * f)
obj_ReadSymbol(FILE * f, char *tzObjectfile)
{
struct sSymbol *pSym;
@@ -126,7 +128,14 @@ obj_ReadSymbol(FILE * f)
}
readasciiz(&pSym->pzName, f);
if ((pSym->Type = (enum eSymbolType) fgetc(f)) != SYM_IMPORT) {
pSym->Type = (enum eSymbolType)fgetc(f);
pSym->pzObjFileName = tzObjectfile;
if (pSym->Type != SYM_IMPORT) {
readasciiz(&pSym->pzFileName, f);
pSym->nFileLine = readlong(f);
pSym->nSectionID = readlong(f);
pSym->nOffset = readlong(f);
}
@@ -219,8 +228,11 @@ obj_ReadRGBSection(FILE * f)
SLONG nNumberOfPatches;
struct sPatch **ppPatch, *pPatch;
fread(pSection->pData, sizeof(UBYTE),
pSection->nByteSize, f);
if (fread(pSection->pData, sizeof(UBYTE),
pSection->nByteSize, f) != pSection->nByteSize) {
err(1, "Read error.");
}
nNumberOfPatches = readlong(f);
ppPatch = &pSection->pPatches;
@@ -245,8 +257,10 @@ obj_ReadRGBSection(FILE * f)
err(1, NULL);
}
fread(pPatch->pRPN, sizeof(UBYTE),
pPatch->nRPNSize, f);
if (fread(pPatch->pRPN, sizeof(UBYTE),
pPatch->nRPNSize, f) != pPatch->nRPNSize) {
errx(1, "Read error.");
}
} else
pPatch->pRPN = NULL;
@@ -263,7 +277,7 @@ obj_ReadRGBSection(FILE * f)
}
void
obj_ReadRGB(FILE * pObjfile)
obj_ReadRGB(FILE * pObjfile, char *tzObjectfile)
{
struct sSection *pFirstSection;
SLONG nNumberOfSymbols, nNumberOfSections, i;
@@ -280,7 +294,7 @@ obj_ReadRGB(FILE * pObjfile)
}
for (i = 0; i < nNumberOfSymbols; i += 1)
tSymbols[i] = obj_ReadSymbol(pObjfile);
tSymbols[i] = obj_ReadSymbol(pObjfile, tzObjectfile);
} else
tSymbols = (struct sSymbol **) & dummymem;
@@ -325,21 +339,24 @@ obj_ReadRGB(FILE * pObjfile)
void
obj_ReadOpenFile(FILE * pObjfile, char *tzObjectfile)
{
char tzHeader[8];
char tzHeader[strlen(RGBDS_OBJECT_VERSION_STRING) + 1];
fread(tzHeader, sizeof(char), 4, pObjfile);
tzHeader[4] = 0;
if (strncmp(tzHeader, "RGB", 3) == 0) {
switch (tzHeader[3]) {
case '3':
case '4': // V4 supports OAM sections, but is otherwise identical
obj_ReadRGB(pObjfile);
break;
default:
errx(1, "'%s' uses an unsupported object file version (%s). Please reassemble it.", tzObjectfile, tzHeader);
}
if (fread(tzHeader, sizeof(char), strlen(RGBDS_OBJECT_VERSION_STRING),
pObjfile) != strlen(RGBDS_OBJECT_VERSION_STRING)) {
errx(1, "%s: Read error.", tzObjectfile);
}
tzHeader[strlen(RGBDS_OBJECT_VERSION_STRING)] = 0;
if (strncmp(tzHeader, RGBDS_OBJECT_VERSION_STRING,
strlen(RGBDS_OBJECT_VERSION_STRING)) == 0) {
obj_ReadRGB(pObjfile, tzObjectfile);
} else {
errx(1, "'%s' is not a valid object", tzObjectfile);
for (int i = 0; i < strlen(RGBDS_OBJECT_VERSION_STRING); i++)
if (!isprint(tzHeader[i]))
tzHeader[i] = '?';
errx(1, "%s: Invalid file or object file version [%s]",
tzObjectfile, tzHeader);
}
}

View File

@@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include "extern/err.h"
#include "link/mylink.h"
#include "link/mapfile.h"
#include "link/main.h"
@@ -24,7 +25,10 @@ writehome(FILE * f, FILE * f_overlay)
if (f_overlay != NULL) {
fseek(f_overlay, 0L, SEEK_SET);
fread(mem, 1, MaxAvail[BANK_ROM0], f_overlay);
if (fread(mem, 1, MaxAvail[BANK_ROM0], f_overlay) !=
MaxAvail[BANK_ROM0]) {
warnx("Failed to read data from overlay file.");
}
} else {
memset(mem, fillchar, MaxAvail[BANK_ROM0]);
}
@@ -58,7 +62,10 @@ writebank(FILE * f, FILE * f_overlay, SLONG bank)
if (f_overlay != NULL && bank <= MaxOverlayBank) {
fseek(f_overlay, bank*0x4000, SEEK_SET);
fread(mem, 1, MaxAvail[bank], f_overlay);
if (fread(mem, 1, MaxAvail[bank], f_overlay) !=
MaxAvail[bank]) {
warnx("Failed to read data from overlay file.");
}
} else {
memset(mem, fillchar, MaxAvail[bank]);
}
@@ -104,18 +111,15 @@ Output(void)
if (tzOverlayname) {
f_overlay = fopen(tzOverlayname, "rb");
if (!f_overlay) {
fprintf(stderr, "Failed to open overlay file %s\n", tzOverlayname);
exit(1);
errx(1, "Failed to open overlay file %s\n", tzOverlayname);
}
fseek(f_overlay, 0, SEEK_END);
if (ftell(f_overlay) % 0x4000 != 0) {
fprintf(stderr, "Overlay file must be aligned to 0x4000 bytes\n");
exit(1);
errx(1, "Overlay file must be aligned to 0x4000 bytes.");
}
MaxOverlayBank = (ftell(f_overlay) / 0x4000) - 1;
if (MaxOverlayBank < 1) {
fprintf(stderr, "Overlay file be at least 0x8000 bytes\n");
exit(1);
errx(1, "Overlay file must be at least 0x8000 bytes.");
}
if (MaxOverlayBank > MaxBankUsed) {
MaxBankUsed = MaxOverlayBank;

View File

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

View File

@@ -12,8 +12,10 @@
struct ISymbol {
char *pzName;
SLONG nValue;
SLONG nBank;
//-1 = const
SLONG nBank; /* -1 = constant */
char tzObjFileName[_MAX_PATH + 1]; /* Object file where the symbol was defined. */
char tzFileName[_MAX_PATH + 1]; /* Source file where the symbol was defined. */
ULONG nFileLine; /* Line where the symbol was defined. */
struct ISymbol *pNext;
};
@@ -76,7 +78,8 @@ sym_GetBank(char *tzName)
}
void
sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank)
sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank, char *tzObjFileName,
char *tzFileName, ULONG nFileLine)
{
if (strcmp(tzName, "@") == 0)
return;
@@ -92,7 +95,10 @@ sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank)
if (nBank == -1)
return;
errx(1, "Symbol '%s' defined more than once", tzName);
errx(1, "'%s' in both %s : %s(%d) and %s : %s(%d)",
tzName, tzObjFileName, tzFileName, nFileLine,
(*ppSym)->tzObjFileName,
(*ppSym)->tzFileName, (*ppSym)->nFileLine);
}
}
@@ -102,6 +108,11 @@ sym_CreateSymbol(char *tzName, SLONG nValue, SLONG nBank)
(*ppSym)->nValue = nValue;
(*ppSym)->nBank = nBank;
(*ppSym)->pNext = NULL;
strncpy((*ppSym)->tzObjFileName, tzObjFileName,
sizeof((*ppSym)->tzObjFileName));
strncpy((*ppSym)->tzFileName, tzFileName,
sizeof((*ppSym)->tzFileName));
(*ppSym)->nFileLine = nFileLine;
}
}
}

View File

@@ -12,7 +12,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd April 17, 2017
.Dd July 22, 2017
.Dt RGBDS 5
.Os RGBDS Manual
.Sh NAME
@@ -42,7 +42,7 @@ is a 0terminated string of
.Bd -literal
; Header
BYTE ID[4] ; "RGB4"
BYTE ID[4] ; "RGB5"
LONG NumberOfSymbols ; The number of symbols used in this file
LONG NumberOfSections ; The number of sections used in this file
@@ -59,6 +59,10 @@ REPT NumberOfSymbols ; Number of symbols defined in this object file.
IF Type != 1 ; If symbol is defined in this object file.
STRING FileName ; File where the symbol is defined.
LONG LineNum ; Line number in the file where the symbol is defined.
LONG SectionID ; The section number (of this object file) in which
; this symbol is defined.

View File

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

View File

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

View File

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

View File

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