mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Implement linkerscript parser
Signed-off-by: AntonioND <antonio_nd@outlook.com>
This commit is contained in:
6
LICENSE
6
LICENSE
@@ -11,7 +11,7 @@ released under the following license:
|
|||||||
This program is free software. It comes without any warranty, to
|
This program is free software. It comes without any warranty, to
|
||||||
the extent permitted by applicable law. You can redistribute it
|
the extent permitted by applicable law. You can redistribute it
|
||||||
and/or modify it under the terms of the DO WHATEVER PUBLIC LICENSE
|
and/or modify it under the terms of the DO WHATEVER PUBLIC LICENSE
|
||||||
|
|
||||||
Software originally created by Justin Lloyd @ http://otakunozoku.com/
|
Software originally created by Justin Lloyd @ http://otakunozoku.com/
|
||||||
|
|
||||||
|
|
||||||
@@ -20,6 +20,10 @@ 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.
|
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
|
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
|
released under the MIT license. The remainder of charmap.c was written by
|
||||||
stag019, and is released under the ISC license.
|
stag019, and is released under the ISC license.
|
||||||
|
|||||||
19
Makefile
19
Makefile
@@ -4,6 +4,12 @@ PNGFLAGS != ${PKG_CONFIG} --cflags libpng
|
|||||||
REALCFLAGS = ${CFLAGS} ${WARNFLAGS} ${PNGFLAGS} -Iinclude -g \
|
REALCFLAGS = ${CFLAGS} ${WARNFLAGS} ${PNGFLAGS} -Iinclude -g \
|
||||||
-std=c99 -D_POSIX_C_SOURCE=200809L
|
-std=c99 -D_POSIX_C_SOURCE=200809L
|
||||||
|
|
||||||
|
LFLAGS := --nounistd
|
||||||
|
|
||||||
|
YACC := yacc
|
||||||
|
FLEX := flex
|
||||||
|
RM := rm -rf
|
||||||
|
|
||||||
# User-defined variables
|
# User-defined variables
|
||||||
PREFIX = /usr/local
|
PREFIX = /usr/local
|
||||||
BINPREFIX = ${PREFIX}/bin
|
BINPREFIX = ${PREFIX}/bin
|
||||||
@@ -32,12 +38,15 @@ rgbasm_obj = \
|
|||||||
|
|
||||||
rgblink_obj = \
|
rgblink_obj = \
|
||||||
src/link/assign.o \
|
src/link/assign.o \
|
||||||
|
src/link/lexer.o \
|
||||||
src/link/library.o \
|
src/link/library.o \
|
||||||
src/link/main.o \
|
src/link/main.o \
|
||||||
src/link/mapfile.o \
|
src/link/mapfile.o \
|
||||||
src/link/object.o \
|
src/link/object.o \
|
||||||
src/link/output.o \
|
src/link/output.o \
|
||||||
src/link/patch.o \
|
src/link/patch.o \
|
||||||
|
src/link/parser.o \
|
||||||
|
src/link/script.o \
|
||||||
src/link/symbol.o \
|
src/link/symbol.o \
|
||||||
src/extern/err.o
|
src/extern/err.o
|
||||||
|
|
||||||
@@ -60,6 +69,7 @@ clean:
|
|||||||
$Qrm -rf rgbfix rgbfix.exe ${rgbfix_obj} rgbfix.html
|
$Qrm -rf rgbfix rgbfix.exe ${rgbfix_obj} rgbfix.html
|
||||||
$Qrm -rf rgbgfx rgbgfx.exe ${rgbgfx_obj} rgbgfx.html
|
$Qrm -rf rgbgfx rgbgfx.exe ${rgbgfx_obj} rgbgfx.html
|
||||||
$Qrm -rf src/asm/asmy.c src/asm/asmy.h
|
$Qrm -rf src/asm/asmy.c src/asm/asmy.h
|
||||||
|
$Qrm -rf src/link/lexer.c src/link/parser.c src/link/parser.h
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
$Qmkdir -p ${BINPREFIX}
|
$Qmkdir -p ${BINPREFIX}
|
||||||
@@ -89,12 +99,21 @@ rgbgfx: ${rgbgfx_obj}
|
|||||||
.y.c:
|
.y.c:
|
||||||
$Q${YACC} -d ${YFLAGS} -o $@ $<
|
$Q${YACC} -d ${YFLAGS} -o $@ $<
|
||||||
|
|
||||||
|
.l.o:
|
||||||
|
$Q${RM} $*.c
|
||||||
|
$Q${FLEX} ${LFLAGS} -o $*.c $<
|
||||||
|
$Q${CC} ${REALCFLAGS} -c -o $@ $*.c
|
||||||
|
$Q${RM} $*.c
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
$Q${CC} ${REALCFLAGS} -c -o $@ $<
|
$Q${CC} ${REALCFLAGS} -c -o $@ $<
|
||||||
|
|
||||||
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
|
||||||
src/asm/asmy.h: src/asm/asmy.c
|
src/asm/asmy.h: src/asm/asmy.c
|
||||||
|
|
||||||
|
src/link/lexer.o : src/link/parser.h
|
||||||
|
src/link/parser.h : src/link/parser.c
|
||||||
|
|
||||||
# Below is a target for the project maintainer to easily create win32 exes.
|
# Below is a target for the project maintainer to easily create win32 exes.
|
||||||
# This is not for Windows users!
|
# This is not for Windows users!
|
||||||
# If you're building on Windows with Cygwin or Mingw, just follow the Unix
|
# If you're building on Windows with Cygwin or Mingw, just follow the Unix
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef RGBDS_LINK_ASSIGN_H
|
#ifndef RGBDS_LINK_ASSIGN_H
|
||||||
#define RGBDS_LINK_ASSIGN_H
|
#define RGBDS_LINK_ASSIGN_H
|
||||||
|
|
||||||
|
#include "mylink.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
enum eBankCount {
|
enum eBankCount {
|
||||||
@@ -34,4 +35,10 @@ extern void CreateSymbolTable(void);
|
|||||||
extern SLONG MaxBankUsed;
|
extern SLONG MaxBankUsed;
|
||||||
extern SLONG MaxAvail[MAXBANKS];
|
extern SLONG MaxAvail[MAXBANKS];
|
||||||
|
|
||||||
|
int
|
||||||
|
IsSectionSameTypeBankAndFloating(const char *name, enum eSectionType type, int bank);
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
AssignSectionAddressByName(const char *name, unsigned int address);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
29
include/link/script.h
Normal file
29
include/link/script.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Antonio Nino Diaz <antonio_nd@outlook.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGBDS_LINK_SCRIPT_H
|
||||||
|
#define RGBDS_LINK_SCRIPT_H
|
||||||
|
|
||||||
|
void script_Parse(const char *path);
|
||||||
|
|
||||||
|
void script_InitSections(void);
|
||||||
|
void script_SetCurrentSectionType(const char *type, unsigned int bank);
|
||||||
|
void script_SetAddress(unsigned int addr);
|
||||||
|
void script_SetAlignment(unsigned int alignment);
|
||||||
|
void script_OutputSection(const char *section_name);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
2
src/link/.gitignore
vendored
Normal file
2
src/link/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
parser.c
|
||||||
|
parser.h
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "extern/err.h"
|
#include "extern/err.h"
|
||||||
#include "link/mylink.h"
|
#include "link/mylink.h"
|
||||||
@@ -214,6 +215,54 @@ FindLargestSection(enum eSectionType type, bool bankFixed)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IsSectionSameTypeBankAndFloating(const char *name, enum eSectionType type, int bank)
|
||||||
|
{
|
||||||
|
struct sSection *pSection;
|
||||||
|
|
||||||
|
pSection = pSections;
|
||||||
|
while (pSection) {
|
||||||
|
if (pSection->oAssigned == 0) {
|
||||||
|
if (strcmp(pSection->pzName, name) == 0) {
|
||||||
|
/* Section must be floating in source */
|
||||||
|
if (pSection->nOrg != -1 || pSection->nAlign != 1)
|
||||||
|
return 0;
|
||||||
|
/* It must have the same type in source and linkerscript */
|
||||||
|
if (pSection->Type != type)
|
||||||
|
return 0;
|
||||||
|
/* Bank number must be unassigned in source or equal */
|
||||||
|
if (pSection->nBank != -1 && pSection->nBank != bank)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pSection = pSection->pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
errx(1, "Section \"%s\" not found (or already used).\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
AssignSectionAddressByName(const char *name, unsigned int address)
|
||||||
|
{
|
||||||
|
struct sSection *pSection;
|
||||||
|
|
||||||
|
pSection = pSections;
|
||||||
|
while (pSection) {
|
||||||
|
if (pSection->oAssigned == 0) {
|
||||||
|
if (strcmp(pSection->pzName, name) == 0) {
|
||||||
|
if (pSection->nOrg != -1 || pSection->nAlign != 1)
|
||||||
|
errx(1, "Section \"%s\" from linkerscript isn't floating.\n", name);
|
||||||
|
pSection->nOrg = address;
|
||||||
|
pSection->nAlign = -1;
|
||||||
|
return pSection->nByteSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pSection = pSection->pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
errx(1, "Section \"%s\" not found (or already used).\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
VerifyAndSetBank(struct sSection *pSection)
|
VerifyAndSetBank(struct sSection *pSection)
|
||||||
|
|||||||
75
src/link/lexer.l
Normal file
75
src/link/lexer.l
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
%option noinput
|
||||||
|
%option nounput
|
||||||
|
%option noyywrap
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "extern/err.h"
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
\"([^\\\"]|\\.)*\" {
|
||||||
|
if (strlen(yytext) > sizeof(yylval.s) - 1)
|
||||||
|
errx(1, "String is too long: \"%s\"\n.", yytext);
|
||||||
|
if (strlen(yytext) < 3) /* 2 quotes + 1 character */
|
||||||
|
errx(1, "String \"%s\" is invalid\n.", yytext);
|
||||||
|
|
||||||
|
yytext++; /* ignore first quote */
|
||||||
|
strcpy(yylval.s, yytext);
|
||||||
|
yylval.s[strlen(yylval.s)-1] = '\0'; /* remove end quote */
|
||||||
|
|
||||||
|
return STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
\$[a-fA-F0-9]+ {
|
||||||
|
yytext++; /* Skip prefix */
|
||||||
|
yylval.i = strtol(yytext, NULL, 16);
|
||||||
|
return INTEGER;
|
||||||
|
}
|
||||||
|
[0-9]+ {
|
||||||
|
yylval.i = strtol(yytext, NULL, 10);
|
||||||
|
return INTEGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
(?i:ROM0) { strcpy(yylval.s, "ROM0"); return SECTION_NONBANKED; }
|
||||||
|
(?i:ROMX) { strcpy(yylval.s, "ROMX"); return SECTION_BANKED; }
|
||||||
|
(?i:VRAM) { strcpy(yylval.s, "VRAM"); return SECTION_BANKED; }
|
||||||
|
(?i:WRAM0) { strcpy(yylval.s, "WRAM0"); return SECTION_NONBANKED; }
|
||||||
|
(?i:WRAMX) { strcpy(yylval.s, "WRAMX"); return SECTION_BANKED; }
|
||||||
|
(?i:SRAM) { strcpy(yylval.s, "SRAM"); return SECTION_BANKED; }
|
||||||
|
(?i:OAM) { strcpy(yylval.s, "OAM"); return SECTION_NONBANKED; }
|
||||||
|
(?i:HRAM) { strcpy(yylval.s, "HRAM"); return SECTION_NONBANKED; }
|
||||||
|
|
||||||
|
(?i:ALIGN) { return COMMAND_ALIGN; }
|
||||||
|
(?i:ORG) { return COMMAND_ORG; }
|
||||||
|
|
||||||
|
"\n" { return NEWLINE; }
|
||||||
|
|
||||||
|
;.* { /* Ignore comments. A dot doesn't match newline. */ }
|
||||||
|
|
||||||
|
[[:space:]] { /* Ignore whitespace. */ }
|
||||||
|
|
||||||
|
. { errx(1, "Invalid character [%s]\n.", yytext); }
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
123
src/link/parser.y
Normal file
123
src/link/parser.y
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* 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 "extern/err.h"
|
||||||
|
#include "link/script.h"
|
||||||
|
|
||||||
|
int yylex();
|
||||||
|
void yyerror(char *);
|
||||||
|
|
||||||
|
static int nline = 1;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%union { int i; char s[512]; }
|
||||||
|
|
||||||
|
%token<i> INTEGER
|
||||||
|
%token<s> STRING
|
||||||
|
|
||||||
|
%token<s> SECTION_NONBANKED
|
||||||
|
%token<s> SECTION_BANKED
|
||||||
|
|
||||||
|
%token COMMAND_ALIGN
|
||||||
|
%token COMMAND_ORG
|
||||||
|
|
||||||
|
%token NEWLINE
|
||||||
|
|
||||||
|
%start lines
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
lines:
|
||||||
|
/* empty */
|
||||||
|
| lines line NEWLINE
|
||||||
|
;
|
||||||
|
|
||||||
|
line:
|
||||||
|
/* empty */ { nline++; }
|
||||||
|
| statement { nline++; }
|
||||||
|
;
|
||||||
|
|
||||||
|
statement:
|
||||||
|
/* Statements to set the current section */
|
||||||
|
SECTION_NONBANKED {
|
||||||
|
script_SetCurrentSectionType($1, 0);
|
||||||
|
}
|
||||||
|
| SECTION_NONBANKED INTEGER {
|
||||||
|
errx(1, "%d:Trying to assign a bank to a non-banked section.\n", nline);
|
||||||
|
}
|
||||||
|
|
||||||
|
| SECTION_BANKED {
|
||||||
|
errx(1, "%d:Banked section without assigned bank.\n", nline);
|
||||||
|
}
|
||||||
|
| SECTION_BANKED INTEGER {
|
||||||
|
script_SetCurrentSectionType($1, $2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Commands to adjust the address inside the current section */
|
||||||
|
| COMMAND_ALIGN INTEGER {
|
||||||
|
script_SetAlignment($2);
|
||||||
|
}
|
||||||
|
| COMMAND_ALIGN {
|
||||||
|
errx(1, "%d:ALIGN keyword needs an argument.\n", nline);
|
||||||
|
}
|
||||||
|
| COMMAND_ORG INTEGER {
|
||||||
|
script_SetAddress($2);
|
||||||
|
}
|
||||||
|
| COMMAND_ORG {
|
||||||
|
errx(1, "%d:ORG keyword needs an argument.\n", nline);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section name */
|
||||||
|
| STRING {
|
||||||
|
script_OutputSection($1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End */
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
extern int yylex();
|
||||||
|
extern int yyparse();
|
||||||
|
|
||||||
|
extern FILE *yyin;
|
||||||
|
|
||||||
|
void yyerror(char *s)
|
||||||
|
{
|
||||||
|
errx(1, "%d:Linkerscript parse error: \"%s\"\n", nline, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void script_Parse(const char *path)
|
||||||
|
{
|
||||||
|
script_InitSections();
|
||||||
|
|
||||||
|
FILE *f = fopen(path, "r");
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
errx(1, "Error opening file! \"%s\"\n", path);
|
||||||
|
|
||||||
|
yyin = f;
|
||||||
|
|
||||||
|
do {
|
||||||
|
yyparse();
|
||||||
|
} while (!feof(yyin));
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
218
src/link/script.c
Normal file
218
src/link/script.c
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* 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 <string.h>
|
||||||
|
#include "extern/err.h"
|
||||||
|
#include "link/assign.h"
|
||||||
|
#include "link/mylink.h"
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
unsigned int address; /* current address to write sections to */
|
||||||
|
unsigned int top_address; /* not inclusive */
|
||||||
|
enum eSectionType type;
|
||||||
|
} bank[MAXBANKS];
|
||||||
|
|
||||||
|
static int current_bank = -1; /* Bank as seen by the bank array */
|
||||||
|
static int current_real_bank = -1; /* bank as seen by the GB */
|
||||||
|
|
||||||
|
void script_InitSections(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < MAXBANKS; i++) {
|
||||||
|
if (i == BANK_ROM0) {
|
||||||
|
/* ROM0 bank */
|
||||||
|
bank[i].address = 0x0000;
|
||||||
|
if (options & OPT_SMALL) {
|
||||||
|
bank[i].top_address = 0x8000;
|
||||||
|
} else {
|
||||||
|
bank[i].top_address = 0x4000;
|
||||||
|
}
|
||||||
|
bank[i].type = SECT_ROM0;
|
||||||
|
} else if (i >= BANK_ROMX && i < BANK_ROMX + BANK_COUNT_ROMX) {
|
||||||
|
/* Swappable ROM bank */
|
||||||
|
bank[i].address = 0x4000;
|
||||||
|
/*
|
||||||
|
* Now, this shouldn't really be necessary... but for
|
||||||
|
* good measure we'll do it anyway.
|
||||||
|
*/
|
||||||
|
if (options & OPT_SMALL) {
|
||||||
|
bank[i].top_address = 0x4000;
|
||||||
|
} else {
|
||||||
|
bank[i].top_address = 0x8000;
|
||||||
|
}
|
||||||
|
bank[i].type = SECT_ROMX;
|
||||||
|
} else if (i == BANK_WRAM0) {
|
||||||
|
/* WRAM */
|
||||||
|
bank[i].address = 0xC000;
|
||||||
|
if (options & OPT_CONTWRAM) {
|
||||||
|
bank[i].top_address = 0xE000;
|
||||||
|
} else {
|
||||||
|
bank[i].top_address = 0xD000;
|
||||||
|
}
|
||||||
|
bank[i].type = SECT_WRAM0;
|
||||||
|
} else if (i >= BANK_SRAM && i < BANK_SRAM + BANK_COUNT_SRAM) {
|
||||||
|
/* Swappable SRAM bank */
|
||||||
|
bank[i].address = 0xA000;
|
||||||
|
bank[i].top_address = 0xC000;
|
||||||
|
bank[i].type = SECT_SRAM;
|
||||||
|
} else if (i >= BANK_WRAMX && i < BANK_WRAMX + BANK_COUNT_WRAMX) {
|
||||||
|
/* Swappable WRAM bank */
|
||||||
|
bank[i].address = 0xD000;
|
||||||
|
bank[i].top_address = 0xE000;
|
||||||
|
bank[i].type = SECT_WRAMX;
|
||||||
|
} else if (i >= BANK_VRAM && i < BANK_VRAM + BANK_COUNT_VRAM) {
|
||||||
|
/* Swappable VRAM bank */
|
||||||
|
bank[i].address = 0x8000;
|
||||||
|
bank[i].top_address = 0xA000;
|
||||||
|
bank[i].type = SECT_VRAM;
|
||||||
|
} else if (i == BANK_OAM) {
|
||||||
|
/* OAM */
|
||||||
|
bank[i].address = 0xFE00;
|
||||||
|
bank[i].top_address = 0xFEA0;
|
||||||
|
bank[i].type = SECT_OAM;
|
||||||
|
} else if (i == BANK_HRAM) {
|
||||||
|
/* HRAM */
|
||||||
|
bank[i].address = 0xFF80;
|
||||||
|
bank[i].top_address = 0xFFFF;
|
||||||
|
bank[i].type = SECT_HRAM;
|
||||||
|
} else {
|
||||||
|
errx(1, "(INTERNAL) Unknown bank type!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void script_SetCurrentSectionType(const char *type, unsigned int bank)
|
||||||
|
{
|
||||||
|
if (strcmp(type, "ROM0") == 0) {
|
||||||
|
if (bank != 0)
|
||||||
|
errx(1, "(Internal) Trying to assign a bank number to ROM0.\n");
|
||||||
|
current_bank = BANK_ROM0;
|
||||||
|
current_real_bank = 0;
|
||||||
|
return;
|
||||||
|
} else if (strcmp(type, "ROMX") == 0) {
|
||||||
|
if (bank == 0)
|
||||||
|
errx(1, "ROMX index can't be 0.\n");
|
||||||
|
if (bank > BANK_COUNT_ROMX)
|
||||||
|
errx(1, "ROMX index too big (%d > %d).\n", bank, BANK_COUNT_ROMX);
|
||||||
|
current_bank = BANK_ROMX + bank - 1;
|
||||||
|
current_real_bank = bank;
|
||||||
|
return;
|
||||||
|
} else if (strcmp(type, "VRAM") == 0) {
|
||||||
|
if (bank >= BANK_COUNT_VRAM)
|
||||||
|
errx(1, "VRAM index too big (%d >= %d).\n", bank, BANK_COUNT_VRAM);
|
||||||
|
current_bank = BANK_VRAM + bank;
|
||||||
|
current_real_bank = bank;
|
||||||
|
return;
|
||||||
|
} else if (strcmp(type, "WRAM0") == 0) {
|
||||||
|
if (bank != 0)
|
||||||
|
errx(1, "(Internal) Trying to assign a bank number to WRAM0.\n");
|
||||||
|
current_bank = BANK_WRAM0;
|
||||||
|
current_real_bank = 0;
|
||||||
|
return;
|
||||||
|
} else if (strcmp(type, "WRAMX") == 0) {
|
||||||
|
if (bank == 0)
|
||||||
|
errx(1, "WRAMX index can't be 0.\n");
|
||||||
|
if (bank > BANK_COUNT_WRAMX)
|
||||||
|
errx(1, "WRAMX index too big (%d > %d).\n", bank, BANK_COUNT_WRAMX);
|
||||||
|
current_bank = BANK_WRAMX + bank - 1;
|
||||||
|
current_real_bank = bank - 1;
|
||||||
|
return;
|
||||||
|
} else if (strcmp(type, "SRAM") == 0) {
|
||||||
|
if (bank >= BANK_COUNT_SRAM)
|
||||||
|
errx(1, "SRAM index too big (%d >= %d).\n", bank, BANK_COUNT_SRAM);
|
||||||
|
current_bank = BANK_SRAM + bank;
|
||||||
|
current_real_bank = bank;
|
||||||
|
return;
|
||||||
|
} else if (strcmp(type, "OAM") == 0) {
|
||||||
|
if (bank != 0)
|
||||||
|
errx(1, "(Internal) Trying to assign a bank number to OAM.\n");
|
||||||
|
current_bank = BANK_OAM;
|
||||||
|
current_real_bank = 0;
|
||||||
|
return;
|
||||||
|
} else if (strcmp(type, "HRAM") == 0) {
|
||||||
|
if (bank != 0)
|
||||||
|
errx(1, "(Internal) Trying to assign a bank number to HRAM.\n");
|
||||||
|
current_bank = BANK_HRAM;
|
||||||
|
current_real_bank = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
errx(1, "(Internal) Unknown section type \"%s\".\n", type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void script_SetAddress(unsigned int addr)
|
||||||
|
{
|
||||||
|
if (current_bank == -1) {
|
||||||
|
errx(1, "Trying to set an address without assigned bank\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure that we don't go back. */
|
||||||
|
if (bank[current_bank].address > addr) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Make sure we don't overflow */
|
||||||
|
if (bank[current_bank].address >= bank[current_bank].top_address) {
|
||||||
|
errx(1, "Bank overflowed (0x%04X >= 0x%04X)\n",
|
||||||
|
bank[current_bank].address, bank[current_bank].top_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void script_SetAlignment(unsigned int alignment)
|
||||||
|
{
|
||||||
|
if (current_bank == -1) {
|
||||||
|
errx(1, "Trying to set an alignment without assigned bank\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alignment > 15) {
|
||||||
|
errx(1, "Trying to set an alignment too big: %d\n", alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int size = 1 << alignment;
|
||||||
|
unsigned int mask = size - 1;
|
||||||
|
|
||||||
|
if (bank[current_bank].address & mask) {
|
||||||
|
bank[current_bank].address &= ~mask;
|
||||||
|
bank[current_bank].address += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we don't overflow */
|
||||||
|
if (bank[current_bank].address >= bank[current_bank].top_address) {
|
||||||
|
errx(1, "Bank overflowed (0x%04X >= 0x%04X)\n",
|
||||||
|
bank[current_bank].address, bank[current_bank].top_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void script_OutputSection(const char *section_name)
|
||||||
|
{
|
||||||
|
if (current_bank == -1) {
|
||||||
|
errx(1, "Trying to place section \"%s\" without assigned bank\n", section_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsSectionSameTypeBankAndFloating(section_name, bank[current_bank].type,
|
||||||
|
current_real_bank)) {
|
||||||
|
errx(1, "Different attributes for \"%s\" in source and linkerscript\n",
|
||||||
|
section_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move section to its place. */
|
||||||
|
bank[current_bank].address +=
|
||||||
|
AssignSectionAddressByName(section_name, bank[current_bank].address);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user