Merge github.com:rednex/rgbds into overlay

This commit is contained in:
Sanqui
2017-02-28 18:58:58 +01:00
67 changed files with 1488 additions and 2792 deletions

View File

@@ -24,7 +24,7 @@ void
bankrangecheck(char *name, ULONG secttype, SLONG org, SLONG bank)
{
SLONG minbank, maxbank;
char *stype;
char *stype = NULL;
switch (secttype) {
case SECT_ROMX:
stype = "ROMX";
@@ -51,7 +51,7 @@ bankrangecheck(char *name, ULONG secttype, SLONG org, SLONG bank)
"ROMX, WRAMX, SRAM, or VRAM sections");
}
if (bank < minbank || bank > maxbank) {
if (stype && (bank < minbank || bank > maxbank)) {
yyerror("%s bank value $%x out of range ($%x to $%x)",
stype, bank, minbank, maxbank);
}
@@ -142,8 +142,9 @@ void copyrept( void )
{
SLONG level=1, len, instring=0;
char *src=pCurrentBuffer->pBuffer;
char *bufferEnd = pCurrentBuffer->pBufferStart + pCurrentBuffer->nBufferSize;
while( *src && level )
while( src < bufferEnd && level )
{
if( instring==0 )
{
@@ -182,6 +183,10 @@ void copyrept( void )
}
}
if (level != 0) {
fatalerror("Unterminated REPT block");
}
len=src-pCurrentBuffer->pBuffer-4;
src=pCurrentBuffer->pBuffer;
@@ -217,8 +222,9 @@ void copymacro( void )
{
SLONG level=1, len, instring=0;
char *src=pCurrentBuffer->pBuffer;
char *bufferEnd = pCurrentBuffer->pBufferStart + pCurrentBuffer->nBufferSize;
while( *src && level )
while( src < bufferEnd && level )
{
if( instring==0 )
{
@@ -257,6 +263,10 @@ void copymacro( void )
}
}
if (level != 0) {
fatalerror("Unterminated MACRO definition");
}
len=src-pCurrentBuffer->pBuffer-4;
src=pCurrentBuffer->pBuffer;
@@ -348,6 +358,10 @@ void if_skip_to_else( void )
}
}
if (level != 0) {
fatalerror("Unterminated IF construct");
}
len=src-pCurrentBuffer->pBuffer;
yyskipbytes( len );
@@ -403,6 +417,10 @@ void if_skip_to_endc( void )
}
}
if (level != 0) {
fatalerror("Unterminated IF construct");
}
len=src-pCurrentBuffer->pBuffer;
yyskipbytes( len );
@@ -1079,9 +1097,9 @@ string : T_STRING
| T_OP_STRCAT '(' string ',' string ')'
{ strcpy($$,$3); strcat($$,$5); }
| T_OP_STRUPR '(' string ')'
{ strcpy($$,$3); strupr($$); }
{ strcpy($$,$3); upperstring($$); }
| T_OP_STRLWR '(' string ')'
{ strcpy($$,$3); strlwr($$); }
{ strcpy($$,$3); lowerstring($$); }
;
section:
T_POP_SECTION string ',' sectiontype
@@ -1263,12 +1281,16 @@ z80_ldi : T_Z80_LDI T_MODE_HL_IND comma T_MODE_A
{ out_AbsByte(0x02|(2<<4)); }
| T_Z80_LDI T_MODE_A comma T_MODE_HL
{ out_AbsByte(0x0A|(2<<4)); }
| T_Z80_LDI T_MODE_A comma T_MODE_HL_IND
{ out_AbsByte(0x0A|(2<<4)); }
;
z80_ldd : T_Z80_LDD T_MODE_HL_IND comma T_MODE_A
{ out_AbsByte(0x02|(3<<4)); }
| T_Z80_LDD T_MODE_A comma T_MODE_HL
{ out_AbsByte(0x0A|(3<<4)); }
| T_Z80_LDD T_MODE_A comma T_MODE_HL_IND
{ out_AbsByte(0x0A|(3<<4)); }
;
z80_ldio : T_Z80_LDIO T_MODE_A comma op_mem_ind

View File

@@ -1,3 +1,57 @@
/*
* UTF-8 decoder copyright © 20082009 Björn Höhrmann <bjoern@hoehrmann.de>
* http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
*
* 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.
*/
#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>
*
@@ -28,122 +82,94 @@ struct Charmap globalCharmap = {0};
extern struct Section *pCurrentSection;
int
readUTF8Char(char *destination, char *source)
readUTF8Char(char *dest, char *src)
{
int size;
UBYTE first;
first = source[0];
uint32_t state;
uint32_t codep;
int i;
if(first >= 0xFC)
{
size = 6;
for (i = 0, state = 0;; i++) {
if (decode(&state, &codep, (uint8_t)src[i]) == 1) {
fatalerror("invalid UTF-8 character");
}
dest[i] = src[i];
i++;
if (state == 0) {
dest[i] = '\0';
return i;
}
dest[i] = src[i];
}
else if(first >= 0xF8)
{
size = 5;
}
else if(first >= 0xF0)
{
size = 4;
}
else if(first >= 0xE0)
{
size = 3;
}
else if(first >= 0xC0)
{
size = 2;
}
else if(first != '\0')
{
size = 1;
}
else
{
size = 0;
}
strncpy(destination, source, size);
destination[size] = 0;
return size;
}
int
charmap_Add(char *input, UBYTE output)
{
int i, input_length;
char temp1i[CHARMAPLENGTH + 1], temp2i[CHARMAPLENGTH + 1], temp1o = 0, temp2o = 0;
char temp1i[CHARMAPLENGTH + 1], temp2i[CHARMAPLENGTH + 1], temp1o = 0,
temp2o = 0;
struct Charmap *charmap;
if(pCurrentSection)
{
if(pCurrentSection -> charmap)
{
charmap = pCurrentSection -> charmap;
}
else
{
if((charmap = (struct Charmap *) calloc(1, sizeof(struct Charmap))) == NULL)
{
if (pCurrentSection) {
if (pCurrentSection->charmap) {
charmap = pCurrentSection->charmap;
} else {
if ((charmap = calloc(1, sizeof(struct Charmap))) ==
NULL) {
fatalerror("Not enough memory for charmap");
}
pCurrentSection -> charmap = charmap;
pCurrentSection->charmap = charmap;
}
}
else
{
} else {
charmap = &globalCharmap;
}
if(nPass == 2)
{
return charmap -> count;
if (nPass == 2) {
return charmap->count;
}
if(charmap -> count > MAXCHARMAPS || strlen(input) > CHARMAPLENGTH)
{
if (charmap->count > MAXCHARMAPS || strlen(input) > CHARMAPLENGTH) {
return -1;
}
input_length = strlen(input);
if(input_length > 1)
{
if (input_length > 1) {
i = 0;
while(i < charmap -> count + 1)
{
if(input_length > strlen(charmap -> input[i]))
{
memcpy(temp1i, charmap -> input[i], CHARMAPLENGTH + 1);
memcpy(charmap -> input[i], input, input_length);
temp1o = charmap -> output[i];
charmap -> output[i] = output;
while (i < charmap->count + 1) {
if (input_length > strlen(charmap->input[i])) {
memcpy(temp1i, charmap->input[i],
CHARMAPLENGTH + 1);
memcpy(charmap->input[i], input, input_length);
temp1o = charmap->output[i];
charmap->output[i] = output;
i++;
break;
}
i++;
}
while(i < charmap -> count + 1)
{
memcpy(temp2i, charmap -> input[i], CHARMAPLENGTH + 1);
memcpy(charmap -> input[i], temp1i, CHARMAPLENGTH + 1);
while (i < charmap->count + 1) {
memcpy(temp2i, charmap->input[i], CHARMAPLENGTH + 1);
memcpy(charmap->input[i], temp1i, CHARMAPLENGTH + 1);
memcpy(temp1i, temp2i, CHARMAPLENGTH + 1);
temp2o = charmap -> output[i];
charmap -> output[i] = temp1o;
temp2o = charmap->output[i];
charmap->output[i] = temp1o;
temp1o = temp2o;
i++;
}
memcpy(charmap -> input[charmap -> count + 1], temp1i, CHARMAPLENGTH + 1);
charmap -> output[charmap -> count + 1] = temp1o;
memcpy(charmap->input[charmap->count + 1], temp1i,
CHARMAPLENGTH + 1);
charmap->output[charmap->count + 1] = temp1o;
} else {
memcpy(charmap->input[charmap->count], input, input_length);
charmap->output[charmap->count] = output;
}
else
{
memcpy(charmap -> input[charmap -> count], input, input_length);
charmap -> output[charmap -> count] = output;
}
return ++charmap -> count;
return ++charmap->count;
}
int
int
charmap_Convert(char **input)
{
struct Charmap *charmap;
@@ -152,47 +178,35 @@ charmap_Convert(char **input)
char *buffer;
int i, j, length;
if(pCurrentSection && pCurrentSection -> charmap)
{
charmap = pCurrentSection -> charmap;
}
else
{
if (pCurrentSection && pCurrentSection->charmap) {
charmap = pCurrentSection->charmap;
} else {
charmap = &globalCharmap;
}
if((buffer = (char *) malloc(strlen(*input))) == NULL)
{
if ((buffer = malloc(strlen(*input))) == NULL) {
fatalerror("Not enough memory for buffer");
}
length = 0;
while(**input)
{
while (**input) {
j = 0;
for(i = 0; i < charmap -> count; i++)
{
j = strlen(charmap -> input[i]);
if(memcmp(*input, charmap -> input[i], j) == 0)
{
outchar[0] = charmap -> output[i];
for (i = 0; i < charmap->count; i++) {
j = strlen(charmap->input[i]);
if (memcmp(*input, charmap->input[i], j) == 0) {
outchar[0] = charmap->output[i];
outchar[1] = 0;
break;
}
j = 0;
}
if(!j)
{
if (!j) {
j = readUTF8Char(outchar, *input);
}
if(!outchar[0])
{
if (!outchar[0]) {
buffer[length++] = 0;
}
else
{
for(i = 0; outchar[i]; i++)
{
} else {
for (i = 0; outchar[i]; i++) {
buffer[length++] = outchar[i];
}
}
@@ -201,4 +215,3 @@ charmap_Convert(char **input)
*input = buffer;
return length;
}

View File

@@ -179,7 +179,15 @@ fstk_Dump(void)
void
fstk_AddIncludePath(char *s)
{
strcpy(IncludePaths[NextIncPath++], s);
if (NextIncPath == MAXINCPATHS) {
fatalerror("Too many include directories passed from command line");
return;
}
if (strlcpy(IncludePaths[NextIncPath++], s, _MAX_PATH) >= _MAX_PATH) {
fatalerror("Include path too long '%s'",s);
return;
}
}
FILE *

View File

@@ -97,7 +97,7 @@ ascii2bin(char *s)
while (*s != '\0') {
c = convertfunc(*s++);
result = result * 2 + ((c & 1) << 8) + ((c & 2) >> 1);
result = result * 2 + ((c & 2) << 7) + (c & 1);
}
} else {
while (*s != '\0')

View File

@@ -39,9 +39,8 @@ ULONG tFloatingChars[256];
ULONG nFloating;
enum eLexerState lexerstate = LEX_STATE_NORMAL;
#ifdef __GNUC__
void
strupr(char *s)
upperstring(char *s)
{
while (*s) {
*s = toupper(*s);
@@ -50,14 +49,14 @@ strupr(char *s)
}
void
strlwr(char *s)
lowerstring(char *s)
{
while (*s) {
*s = tolower(*s);
s += 1;
}
}
#endif
void
yyskipbytes(ULONG count)
{
@@ -352,7 +351,7 @@ lex_AddStrings(struct sLexInitString * lex)
(*ppHash)->nToken = lex->nToken;
(*ppHash)->pNext = NULL;
strupr((*ppHash)->tzName);
upperstring((*ppHash)->tzName);
if ((*ppHash)->nNameLength > nLexMaxLength)
nLexMaxLength = (*ppHash)->nNameLength;

View File

@@ -257,7 +257,7 @@ static void
usage(void)
{
printf(
"Usage: rgbasm [-hv] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
"Usage: rgbasm [-hvE] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
" [-o outfile] [-p pad_value] file.asm\n");
exit(1);
}
@@ -296,12 +296,13 @@ main(int argc, char *argv[])
DefaultOptions.fillchar = 0;
DefaultOptions.verbose = false;
DefaultOptions.haltnop = true;
DefaultOptions.exportall = false;
opt_SetCurrentOptions(&DefaultOptions);
newopt = CurrentOptions;
while ((ch = getopt(argc, argv, "b:D:g:hi:o:p:v")) != -1) {
while ((ch = getopt(argc, argv, "b:D:g:hi:o:p:vE")) != -1) {
switch (ch) {
case 'b':
if (strlen(optarg) == 2) {
@@ -348,6 +349,9 @@ main(int argc, char *argv[])
case 'v':
newopt.verbose = true;
break;
case 'E':
newopt.exportall = true;
break;
default:
usage();
}
@@ -379,6 +383,7 @@ main(int argc, char *argv[])
nPass = 1;
nErrors = 0;
sym_PrepPass1();
sym_SetExportAll(CurrentOptions.exportall);
fstk_Init(tzMainfile);
opt_ParseDefines();

View File

@@ -243,25 +243,27 @@ writesymbol(struct sSymbol * pSym, FILE * f)
offset = 0;
sectid = -1;
type = SYM_IMPORT;
} else if (pSym->nType & SYMF_EXPORT) {
/* Symbol should be exported */
strcpy(symname, pSym->tzName);
type = SYM_EXPORT;
offset = pSym->nValue;
if (pSym->nType & SYMF_CONST)
sectid = -1;
else
sectid = getsectid(pSym->pSection);
} else {
/* Symbol is local to this file */
if (pSym->nType & SYMF_LOCAL) {
strcpy(symname, pSym->pScope->tzName);
strcat(symname, pSym->tzName);
} else
strcpy(symname, pSym->tzName);
type = SYM_LOCAL;
offset = pSym->nValue;
sectid = getsectid(pSym->pSection);
if (pSym->nType & SYMF_EXPORT) {
/* Symbol should be exported */
type = SYM_EXPORT;
offset = pSym->nValue;
if (pSym->nType & SYMF_CONST)
sectid = -1;
else
sectid = getsectid(pSym->pSection);
} else {
/* Symbol is local to this file */
type = SYM_LOCAL;
offset = pSym->nValue;
sectid = getsectid(pSym->pSection);
}
}
fputstring(symname, f);
@@ -282,6 +284,7 @@ addsymbol(struct sSymbol * pSym)
struct PatchSymbol *pPSym, **ppPSym;
static ULONG nextID = 0;
ULONG hash;
hash = calchash(pSym->tzName);
ppPSym = &(tHashedPatchSymbols[hash]);

View File

@@ -6,7 +6,7 @@
.Nd Game Boy assembler
.Sh SYNOPSIS
.Nm rgbasm
.Op Fl hv
.Op Fl Ehv
.Op Fl b Ar chars
.Op Fl D Ar name Ns Op = Ns Ar value
.Op Fl g Ar chars
@@ -29,6 +29,8 @@ Add string symbol to the compiled source code. This is equivalent to
.Cm EQUS
.Qq Ar "value"
in code. If a value is not specified, a value of 1 is given.
.It Fl E
Export all labels, including unreferenced and local labels.
.It Fl g Ar chars
Change the four characters used for binary constants.
The defaults are 0123.
@@ -67,6 +69,8 @@ and
.Xr rgbfix 1 ,
.Xr rgblink 1 ,
.Xr rgbds 7
.Pp
.Lk https://rednex.github.io/rgbds/asm.htm rgbasm assembly commands
.Sh HISTORY
.Nm
was originally written by Carsten S\(/orensen as part of the ASMotor package,

View File

@@ -114,14 +114,11 @@ void
rpn_Bank(struct Expression * expr, char *tzSym)
{
if (!sym_isConstant(tzSym)) {
struct sSymbol *psym;
rpn_Reset(expr);
psym = sym_FindSymbol(tzSym);
if (nPass == 2 && psym == NULL) {
yyerror("'%s' not defined", tzSym);
}
/* Check that the symbol exists by evaluating and discarding the value. */
sym_GetValue(tzSym);
expr->isReloc = 1;
pushbyte(expr, RPN_BANK);
while (*tzSym)
@@ -316,6 +313,9 @@ rpn_DIV(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
{
joinexpr();
if (src2->nVal == 0) {
fatalerror("division by zero");
}
expr->nVal = (expr->nVal / src2->nVal);
pushbyte(expr, RPN_DIV);
}
@@ -325,6 +325,9 @@ rpn_MOD(struct Expression * expr, struct Expression * src1,
struct Expression * src2)
{
joinexpr();
if (src2->nVal == 0) {
fatalerror("division by zero");
}
expr->nVal = (expr->nVal % src2->nVal);
pushbyte(expr, RPN_MOD);
}

View File

@@ -21,6 +21,7 @@ char *currentmacroargs[MAXMACROARGS + 1];
char *newmacroargs[MAXMACROARGS + 1];
char SavedTIME[256];
char SavedDATE[256];
bool exportall;
SLONG
Callback_NARG(struct sSymbol * sym)
@@ -575,6 +576,9 @@ sym_AddLocalReloc(char *tzSym)
nsym->nValue = nPC;
nsym->nType |=
SYMF_RELOC | SYMF_LOCAL | SYMF_DEFINED;
if (exportall) {
nsym->nType |= SYMF_EXPORT;
}
nsym->pScope = pScope;
nsym->pSection = pCurrentSection;
}
@@ -604,6 +608,9 @@ sym_AddReloc(char *tzSym)
if (nsym) {
nsym->nValue = nPC;
nsym->nType |= SYMF_RELOC | SYMF_DEFINED;
if (exportall) {
nsym->nType |= SYMF_EXPORT;
}
nsym->pScope = NULL;
nsym->pSection = pCurrentSection;
}
@@ -709,6 +716,13 @@ sym_AddMacro(char *tzSym)
}
}
/*
* Set whether to export all relocable symbols by default
*/
void sym_SetExportAll(BBOOL set) {
exportall = set;
}
/*
* Prepare for pass #1
*/

203
src/gfx/gb.c Normal file
View File

@@ -0,0 +1,203 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include "gfx/main.h"
void
transpose_tiles(struct GBImage *gb, int width)
{
uint8_t *newdata;
int i;
int newbyte;
newdata = calloc(gb->size, 1);
for (i = 0; i < gb->size; i++) {
newbyte = i / (8 * depth) * width * 8 * depth;
newbyte = newbyte % gb->size + 8 * depth * (newbyte / gb->size) + i % (8 * depth);
newdata[newbyte] = gb->data[i];
}
free(gb->data);
gb->data = newdata;
}
void
png_to_gb(struct PNGImage png, struct GBImage *gb)
{
int x, y, byte;
png_byte index;
for (y = 0; y < png.height; y++) {
for (x = 0; x < png.width; x++) {
index = png.data[y][x];
index &= (1 << depth) - 1;
if (!gb->horizontal) {
byte = y * depth + x / 8 * png.height / 8 * 8 * depth;
} else {
byte = y * depth + x / 8 * png.height / 8 * 8 * depth;
}
gb->data[byte] |= (index & 1) << (7 - x % 8);
if (depth == 2) {
gb->data[byte + 1] |= (index >> 1) << (7 - x % 8);
}
}
}
if (!gb->horizontal) {
transpose_tiles(gb, png.width / 8);
}
}
void
output_file(struct Options opts, struct GBImage gb)
{
FILE *f;
f = fopen(opts.outfile, "wb");
if (!f) {
err(1, "Opening output file '%s' failed", opts.outfile);
}
fwrite(gb.data, 1, gb.size - gb.trim * 8 * depth, f);
fclose(f);
}
int
get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles, int tile_size)
{
int i, j;
for (i = 0; i < num_tiles; i++) {
for (j = 0; j < tile_size; j++) {
if (tile[j] != tiles[i][j]) {
break;
}
}
if (j >= tile_size) {
return i;
}
}
return -1;
}
void
create_tilemap(struct Options opts, struct GBImage *gb, struct Tilemap *tilemap)
{
int i, j;
int gb_i;
int tile_size;
int max_tiles;
int num_tiles;
int index;
int gb_size;
uint8_t *tile;
uint8_t **tiles;
tile_size = sizeof(uint8_t) * depth * 8;
gb_size = gb->size - (gb->trim * tile_size);
max_tiles = gb_size / tile_size;
tiles = malloc(sizeof(uint8_t*) * max_tiles);
num_tiles = 0;
tilemap->data = malloc(sizeof(uint8_t) * max_tiles);
tilemap->size = 0;
gb_i = 0;
while (gb_i < gb_size) {
tile = malloc(tile_size);
for (i = 0; i < tile_size; i++) {
tile[i] = gb->data[gb_i];
gb_i++;
}
if (opts.unique) {
index = get_tile_index(tile, tiles, num_tiles, tile_size);
if (index < 0) {
index = num_tiles;
tiles[num_tiles] = tile;
num_tiles++;
}
} else {
index = num_tiles;
tiles[num_tiles] = tile;
num_tiles++;
}
tilemap->data[tilemap->size] = index;
tilemap->size++;
}
if (opts.unique) {
free(gb->data);
gb->data = malloc(tile_size * num_tiles);
for (i = 0; i < num_tiles; i++) {
tile = tiles[i];
for (j = 0; j < tile_size; j++) {
gb->data[i * tile_size + j] = tile[j];
}
}
gb->size = i * tile_size;
}
for (i = 0; i < num_tiles; i++) {
free(tiles[i]);
}
free(tiles);
}
void
output_tilemap_file(struct Options opts, struct Tilemap tilemap)
{
FILE *f;
f = fopen(opts.mapfile, "wb");
if (!f) {
err(1, "Opening tilemap file '%s' failed", opts.mapfile);
}
fwrite(tilemap.data, 1, tilemap.size, f);
fclose(f);
if (opts.mapout) {
free(opts.mapfile);
}
}
void
output_palette_file(struct Options opts, struct PNGImage png)
{
FILE *f;
int i, colors, color;
png_color *palette;
if (png_get_PLTE(png.png, png.info, &palette, &colors)) {
f = fopen(opts.palfile, "wb");
if (!f) {
err(1, "Opening palette file '%s' failed", opts.palfile);
}
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) {
free(opts.palfile);
}
}

255
src/gfx/main.c Normal file
View File

@@ -0,0 +1,255 @@
/*
* 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 <getopt.h>
#include <stdlib.h>
#include <string.h>
#include "gfx/main.h"
char *progname;
static void
usage(void)
{
printf(
"usage: rgbgfx [-DFfhPTuv] [-d #] [-o outfile] [-p palfile] [-t mapfile]\n"
"[-x #] infile\n");
exit(1);
}
int
main(int argc, char *argv[])
{
int ch, size;
struct Options opts = {0};
struct PNGImage png = {0};
struct GBImage gb = {0};
struct Tilemap tilemap = {0};
char *ext;
const char *errmsg = "Warning: The PNG's %s setting is not the same as the setting defined on the command line.";
progname = argv[0];
if (argc == 1) {
usage();
}
opts.mapfile = "";
opts.palfile = "";
opts.outfile = "";
depth = 2;
while((ch = getopt(argc, argv, "DvFfd:hx:Tt:uPp:o:")) != -1) {
switch(ch) {
case 'D':
opts.debug = true;
break;
case 'v':
opts.verbose = true;
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);
break;
case 'T':
opts.mapout = true;
break;
case 't':
opts.mapfile = optarg;
break;
case 'u':
opts.unique = true;
break;
case 'P':
opts.palout = true;
break;
case 'p':
opts.palfile = optarg;
break;
case 'o':
opts.outfile = optarg;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc == 0) {
usage();
}
opts.infile = argv[argc - 1];
if (depth != 1 && depth != 2) {
errx(1, "Depth option must be either 1 or 2.");
}
colors = 1 << depth;
input_png_file(opts, &png);
png.mapfile = "";
png.palfile = "";
get_text(&png);
if (png.horizontal != opts.horizontal) {
if (opts.verbose) {
warnx(errmsg, "horizontal");
}
if (opts.hardfix) {
png.horizontal = opts.horizontal;
}
}
if (png.horizontal) {
opts.horizontal = png.horizontal;
}
if (png.trim != opts.trim) {
if (opts.verbose) {
warnx(errmsg, "trim");
}
if (opts.hardfix) {
png.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 (opts.verbose) {
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.verbose) {
warnx(errmsg, "tilemap file");
}
if (opts.hardfix) {
png.mapout = opts.mapout;
}
}
if (png.mapout) {
opts.mapout = png.mapout;
}
if (strcmp(png.palfile, opts.palfile) != 0) {
if (opts.verbose) {
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 ((ext = strrchr(opts.infile, '.')) != NULL) {
size = ext - opts.infile + 9;
opts.mapfile = malloc(size);
strncpy(opts.mapfile, opts.infile, size);
*strrchr(opts.mapfile, '.') = '\0';
strcat(opts.mapfile, ".tilemap");
} else {
opts.mapfile = malloc(strlen(opts.infile) + 9);
strcpy(opts.mapfile, opts.infile);
strcat(opts.mapfile, ".tilemap");
}
}
if (!*opts.palfile && opts.palout) {
if ((ext = strrchr(opts.infile, '.')) != NULL) {
size = ext - opts.infile + 5;
opts.palfile = malloc(size);
strncpy(opts.palfile, opts.infile, size);
*strrchr(opts.palfile, '.') = '\0';
strcat(opts.palfile, ".pal");
} else {
opts.palfile = malloc(strlen(opts.infile) + 5);
strcpy(opts.palfile, opts.infile);
strcat(opts.palfile, ".pal");
}
}
gb.size = png.width * png.height * depth / 8;
gb.data = calloc(gb.size, 1);
gb.trim = opts.trim;
gb.horizontal = opts.horizontal;
if (*opts.outfile || *opts.mapfile) {
png_to_gb(png, &gb);
create_tilemap(opts, &gb, &tilemap);
}
if (*opts.outfile) {
output_file(opts, gb);
}
if (*opts.mapfile) {
output_tilemap_file(opts, tilemap);
}
if (*opts.palfile) {
output_palette_file(opts, png);
}
if (opts.fix || opts.debug) {
set_text(&png);
output_png_file(opts, &png);
}
free_png_data(&png);
free(gb.data);
return 0;
}

339
src/gfx/makepng.c Normal file
View File

@@ -0,0 +1,339 @@
/*
* 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 <string.h>
#include "gfx/main.h"
void
input_png_file(struct Options opts, struct PNGImage *img)
{
FILE *f;
int i, y, num_trans;
bool has_palette = false;
png_byte *trans_alpha;
png_color_16 *trans_values;
bool *full_alpha;
png_color *palette;
f = fopen(opts.infile, "rb");
if (!f) {
err(1, "Opening input png file '%s' failed", opts.infile);
}
img->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!img->png) {
errx(1, "Creating png structure failed");
}
img->info = png_create_info_struct(img->png);
if (!img->info) {
errx(1, "Creating png info structure failed");
}
/* Better error handling here? */
if (setjmp(png_jmpbuf(img->png))) {
exit(1);
}
png_init_io(img->png, f);
png_read_info(img->png, img->info);
img->width = png_get_image_width(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->type = png_get_color_type(img->png, img->info);
if (img->type & PNG_COLOR_MASK_ALPHA) {
png_set_strip_alpha(img->png);
}
if (img->depth != depth) {
if (opts.verbose) {
warnx("Image bit depth is not %i (is %i).", depth,
img->depth);
}
}
if (img->type == PNG_COLOR_TYPE_GRAY) {
if (img->depth < 8) {
png_set_expand_gray_1_2_4_to_8(img->png);
}
png_set_gray_to_rgb(img->png);
} else {
if (img->depth < 8) {
png_set_expand_gray_1_2_4_to_8(img->png);
}
has_palette = png_get_PLTE(img->png, img->info, &palette,
&colors);
}
if (png_get_tRNS(img->png, img->info, &trans_alpha, &num_trans,
&trans_values)) {
if (img->type == PNG_COLOR_TYPE_PALETTE) {
full_alpha = malloc(sizeof(bool) * num_trans);
for (i = 0; i < num_trans; i++) {
if (trans_alpha[i] > 0) {
full_alpha[i] = false;
} else {
full_alpha[i] = true;
}
}
for (i = 0; i < num_trans; i++) {
if (full_alpha[i]) {
palette[i].red = 0xFF;
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 (has_palette) {
/* Make sure palette only has the amount of colors you want. */
} else {
/*
* Eventually when this copies colors from the image itself,
* make sure order is lightest to darkest.
*/
palette = malloc(sizeof(png_color) * colors);
if (strcmp(opts.infile, "rgb.png") == 0) {
palette[0].red = 0xFF;
palette[0].green = 0xEF;
palette[0].blue = 0xFF;
palette[1].red = 0xF7;
palette[1].green = 0xF7;
palette[1].blue = 0x8C;
palette[2].red = 0x94;
palette[2].green = 0x94;
palette[2].blue = 0xC6;
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;
}
}
/*
* 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) {
png_set_PLTE(img->png, img->info, palette, colors);
free(palette);
}
/*
* If other useless chunks exist (sRGB, bKGD, pHYs, gAMA, cHRM, iCCP,
* etc.) offer to remove?
*/
png_read_update_info(img->png, img->info);
img->data = malloc(sizeof(png_byte *) * img->height);
for (y = 0; y < img->height; y++) {
img->data[y] = malloc(png_get_rowbytes(img->png, img->info));
}
png_read_image(img->png, img->data);
png_read_end(img->png, img->info);
fclose(f);
}
void
get_text(struct PNGImage *png)
{
png_text *text;
int i, numtxts, numremoved;
png_get_text(png->png, png->info, &text, &numtxts);
for (i = 0; i < numtxts; i++) {
if (strcmp(text[i].key, "h") == 0 && !*text[i].text) {
png->horizontal = true;
png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
} else if (strcmp(text[i].key, "x") == 0) {
png->trim = strtoul(text[i].text, NULL, 0);
png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
} else if (strcmp(text[i].key, "t") == 0) {
png->mapfile = text[i].text;
png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
} else if (strcmp(text[i].key, "T") == 0 && !*text[i].text) {
png->mapout = true;
png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
} else if (strcmp(text[i].key, "p") == 0) {
png->palfile = text[i].text;
png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
} else if (strcmp(text[i].key, "P") == 0 && !*text[i].text) {
png->palout = true;
png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
}
}
/* TODO: Remove this and simply change the warning function not to warn instead. */
for (i = 0, numremoved = 0; i < numtxts; i++) {
if (text[i].key == NULL) {
numremoved++;
}
text[i].key = text[i + numremoved].key;
text[i].text = text[i + numremoved].text;
text[i].compression = text[i + numremoved].compression;
}
png_set_text(png->png, png->info, text, numtxts - numremoved);
}
void
set_text(struct PNGImage *png)
{
png_text *text;
char buffer[3];
text = malloc(sizeof(png_text));
if (png->horizontal) {
text[0].key = "h";
text[0].text = "";
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1);
}
if (png->trim) {
text[0].key = "x";
snprintf(buffer, 3, "%d", png->trim);
text[0].text = buffer;
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1);
}
if (*png->mapfile) {
text[0].key = "t";
text[0].text = "";
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1);
}
if (png->mapout) {
text[0].key = "T";
text[0].text = "";
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1);
}
if (*png->palfile) {
text[0].key = "p";
text[0].text = "";
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1);
}
if (png->palout) {
text[0].key = "P";
text[0].text = "";
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
png_set_text(png->png, png->info, text, 1);
}
free(text);
}
void
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;
for (y = 0; y < png->height; y++) {
free(png->data[y]);
}
free(png->data);
}

90
src/gfx/rgbgfx.1 Normal file
View File

@@ -0,0 +1,90 @@
.Dd $Mdocdate$
.Dt RGBGFX 1
.Os RGBDS Manual
.Sh NAME
.Nm rgbgfx
.Nd Game Boy graphics converter
.Sh SYNOPSIS
.Nm rgbgfx
.Op Fl DfFhPTv
.Op Fl o Ar outfile
.Op Fl d Ar depth
.Op Fl p Ar palfile
.Op Fl t Ar mapfile
.Op Fl x Ar tiles
.Ar file
.Sh DESCRIPTION
The
.Nm
program converts PNG images into the Nintendo Game Boy's planar tile format.
The arguments are as follows:
.Bl -tag -width Ds
.It Fl D
Debug features are enabled.
.It Fl f
Fix the input PNG file to be a correctly indexed image.
.It Fl F
Same as
.Fl f ,
but additionally, the input PNG file is fixed to have its parameters match the
command line's parameters.
.It Fl d Ar depth
The bitdepth of the output image (either 1 or 2).
By default, the bitdepth is 2 (two bits per pixel).
.It Fl h
Lay out tiles horizontally rather than vertically.
.It Fl o Ar outfile
The name of the output file.
.It Fl p Ar palfile
Raw bytes (8 bytes for two bits per pixel, 4 bytes for one bit per pixel)
containing the RGB15 values in the little-endian byte order and then ordered
from lightest to darkest.
.It Fl P
Same as
.Fl p ,
but the pallete file output name is made by taking the input filename,
removing the file extension, and appending
.Pa .pal .
.It Fl t Ar mapfile
If any tiles are the same, don't place the repeat tiles in the output file, and
make a tilemap file.
.It Fl T
Same as
.Fl t ,
but the tilemap file output name is made by taking the input filename,
removing the file extension, and appending
.Pa .tilemap .
.It Fl u
Truncate repeated tiles. Useful with tilemaps.
.It Fl v
Verbose.
Print errors when the command line parameters and the parameters in
the PNG file don't match.
.It Fl x Ar tiles
Trim the end of the output file by this many tiles.
.El
.Sh EXAMPLES
The following will take a PNG file with a bitdepth of 1, 2, or 8, and output
planar 2bpp data:
.Pp
.D1 $ rgbgfx -o out.2bpp in.png
.Pp
The following creates a planar 2bpp file with only unique tiles, and its tilemap
.Pa out.tilemap :
.Pp
.D1 $ rgbgfx -T -u -o out.2bpp in.png
.Pp
The following will do nothing:
.Pp
.D1 $ rgbgfx in.png
.Sh SEE ALSO
.Xr rgbds 7 ,
.Xr rgbasm 1 ,
.Xr rgblink 1 ,
.Xr rgbfix 1 ,
.Xr gbz80 7
.Sh HISTORY
.Nm
was created by
.An stag019
to be included in RGBDS.

View File

@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "extern/err.h"
#include "link/mylink.h"
@@ -13,6 +14,14 @@ struct sFreeArea {
struct sFreeArea *pPrev, *pNext;
};
struct sSectionAttributes {
const char *name;
SLONG bank;
SLONG offset; // bank + offset = bank originally stored in a section struct
SLONG minBank;
SLONG bankCount;
};
struct sFreeArea *BankFree[MAXBANKS];
SLONG MaxAvail[MAXBANKS];
SLONG MaxBankUsed;
@@ -20,11 +29,37 @@ SLONG MaxWBankUsed;
SLONG MaxSBankUsed;
SLONG MaxVBankUsed;
#define DOMAXBANK(x) {if( (x)>MaxBankUsed ) MaxBankUsed=(x);}
const enum eSectionType SECT_MIN = SECT_WRAM0;
const enum eSectionType SECT_MAX = SECT_SRAM;
const struct sSectionAttributes SECT_ATTRIBUTES[] = {
{"WRAM0", BANK_WRAM0, 0, 0, BANK_COUNT_WRAM0},
{"VRAM", BANK_VRAM, 0, 0, BANK_COUNT_VRAM},
{"ROMX", BANK_ROMX, -1, 1, BANK_COUNT_ROMX},
{"ROM0", BANK_ROM0, 0, 0, BANK_COUNT_ROM0},
{"HRAM", BANK_HRAM, 0, 0, BANK_COUNT_HRAM},
{"WRAMX", BANK_WRAMX, 0, 0, BANK_COUNT_WRAMX},
{"SRAM", BANK_SRAM, 0, 0, BANK_COUNT_SRAM}
};
#define DOMAXBANK(x, y) {switch (x) { \
case SECT_ROMX: DOMAXRBANK(y); break; \
case SECT_WRAMX: DOMAXWBANK(y); break; \
case SECT_SRAM: DOMAXSBANK(y); break; \
case SECT_VRAM: DOMAXVBANK(y); break; \
default: errx(1, "DOMAXBANK used with invalid parameters"); 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) {
errx(1, "(INTERNAL) Invalid section type found.");
}
}
SLONG
area_Avail(SLONG bank)
{
@@ -42,7 +77,7 @@ area_Avail(SLONG bank)
return (r);
}
SLONG
SLONG
area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
{
struct sFreeArea *pArea;
@@ -54,12 +89,12 @@ area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
if (org == pArea->nOrg) {
pArea->nOrg += size;
pArea->nSize -= size;
return (org);
return 0;
} else {
if ((org + size - 1) ==
(pArea->nOrg + pArea->nSize - 1)) {
pArea->nSize -= size;
return (org);
return 0;
} else {
struct sFreeArea *pNewArea;
@@ -75,7 +110,7 @@ area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
pNewArea->nSize -=
size + pArea->nSize;
return (org);
return 0;
} else {
err(1, NULL);
}
@@ -86,62 +121,26 @@ area_AllocAbs(struct sFreeArea ** ppArea, SLONG org, SLONG size)
pArea = *ppArea;
}
return (-1);
return -1;
}
SLONG
area_AllocAbsSRAMAnyBank(SLONG org, SLONG size)
area_AllocAbsAnyBank(SLONG org, SLONG size, enum eSectionType type)
{
int i;
for (i = 0; i < 4; ++i) {
if (area_AllocAbs(&BankFree[BANK_SRAM + i], org, size) == org) {
return BANK_SRAM + i;
ensureSectionTypeIsValid(type);
SLONG startBank = SECT_ATTRIBUTES[type].bank;
SLONG bankCount = SECT_ATTRIBUTES[type].bankCount;
for (int i = 0; i < bankCount; i++) {
if (area_AllocAbs(&BankFree[startBank + i], org, size) != -1) {
return startBank + i;
}
}
return -1;
}
SLONG
area_AllocAbsWRAMAnyBank(SLONG org, SLONG size)
{
SLONG i;
for (i = 1; i <= 7; i += 1) {
if (area_AllocAbs(&BankFree[BANK_WRAMX + i - 1], org, size) == org) {
return BANK_WRAMX + i - 1;
}
}
return -1;
}
SLONG
area_AllocAbsVRAMAnyBank(SLONG org, SLONG size)
{
if (area_AllocAbs(&BankFree[BANK_VRAM], org, size) == org) {
return BANK_VRAM;
}
if (area_AllocAbs(&BankFree[BANK_VRAM + 1], org, size) == org) {
return BANK_VRAM + 1;
}
return -1;
}
SLONG
area_AllocAbsROMXAnyBank(SLONG org, SLONG size)
{
SLONG i;
for (i = 1; i <= 511; i += 1) {
if (area_AllocAbs(&BankFree[i], org, size) == org)
return (i);
}
return (-1);
}
SLONG
area_Alloc(struct sFreeArea ** ppArea, SLONG size)
{
@@ -166,67 +165,31 @@ area_Alloc(struct sFreeArea ** ppArea, SLONG size)
}
SLONG
area_AllocVRAMAnyBank(SLONG size)
{
SLONG i, org;
area_AllocAnyBank(SLONG size, enum eSectionType type) {
ensureSectionTypeIsValid(type);
for (i = BANK_VRAM; i <= BANK_VRAM + 1; i += 1) {
if ((org = area_Alloc(&BankFree[i], size)) != -1)
return ((i << 16) | org);
}
return (-1);
}
SLONG
area_AllocSRAMAnyBank(SLONG size)
{
SLONG i, org;
for (i = 0; i < 4; ++i) {
if ((org = area_Alloc(&BankFree[BANK_SRAM + i], size)) != -1) {
return (i << 16) | org;
SLONG startBank = SECT_ATTRIBUTES[type].bank;
SLONG bankCount = SECT_ATTRIBUTES[type].bankCount;
for (int i = 0; i < bankCount; i++) {
SLONG org = area_Alloc(&BankFree[startBank + i], size);
if (org != -1) {
return ((startBank + i) << 16) | org;
}
}
return -1;
}
SLONG
area_AllocWRAMAnyBank(SLONG size)
{
SLONG i, org;
for (i = 1; i <= 7; i += 1) {
if ((org = area_Alloc(&BankFree[BANK_WRAMX + i - 1], size)) != -1) {
return (i << 16) | org;
}
}
return -1;
}
SLONG
area_AllocROMXAnyBank(SLONG size)
{
SLONG i, org;
for (i = 1; i <= 511; i += 1) {
if ((org = area_Alloc(&BankFree[i], size)) != -1)
return ((i << 16) | org);
}
return (-1);
}
struct sSection *
FindLargestWRAM(void)
FindLargestSection(enum eSectionType type)
{
struct sSection *pSection, *r = NULL;
SLONG nLargest = 0;
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0 && pSection->Type == SECT_WRAMX) {
if (pSection->oAssigned == 0 && pSection->Type == type) {
if (pSection->nByteSize > nLargest) {
nLargest = pSection->nByteSize;
r = pSection;
@@ -237,142 +200,44 @@ FindLargestWRAM(void)
return r;
}
struct sSection *
FindLargestVRAM(void)
{
struct sSection *pSection, *r = NULL;
SLONG nLargest = 0;
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0 && pSection->Type == SECT_VRAM) {
if (pSection->nByteSize > nLargest) {
nLargest = pSection->nByteSize;
r = pSection;
}
}
pSection = pSection->pNext;
}
return r;
}
struct sSection *
FindLargestSRAM(void)
{
struct sSection *pSection, *r = NULL;
SLONG nLargest = 0;
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0 && pSection->Type == SECT_SRAM) {
if (pSection->nByteSize > nLargest) {
nLargest = pSection->nByteSize;
r = pSection;
}
}
pSection = pSection->pNext;
}
return r;
}
struct sSection *
FindLargestCode(void)
{
struct sSection *pSection, *r = NULL;
SLONG nLargest = 0;
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0 && pSection->Type == SECT_ROMX) {
if (pSection->nByteSize > nLargest) {
nLargest = pSection->nByteSize;
r = pSection;
}
}
pSection = pSection->pNext;
}
return (r);
}
void
AssignVRAMSections(void)
AssignBankedSections(enum eSectionType type)
{
ensureSectionTypeIsValid(type);
struct sSection *pSection;
while ((pSection = FindLargestVRAM())) {
while ((pSection = FindLargestSection(type))) {
SLONG org;
if ((org = area_AllocVRAMAnyBank(pSection->nByteSize)) != -1) {
if ((org = area_AllocAnyBank(pSection->nByteSize, type)) != -1) {
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->oAssigned = 1;
DOMAXVBANK(pSection->nBank);
DOMAXBANK(pSection->Type, pSection->nBank);
} else {
errx(1, "Unable to place VRAM section anywhere");
errx(1, "Unable to place %s section anywhere",
SECT_ATTRIBUTES[type].name);
}
}
}
bool
VerifyAndSetBank(struct sSection *pSection)
{
ensureSectionTypeIsValid(pSection->Type);
if (pSection->nBank >= SECT_ATTRIBUTES[pSection->Type].minBank
&& pSection->nBank < SECT_ATTRIBUTES[pSection->Type].minBank + SECT_ATTRIBUTES[pSection->Type].bankCount) {
pSection->nBank += SECT_ATTRIBUTES[pSection->Type].bank + SECT_ATTRIBUTES[pSection->Type].offset;
return true;
} else {
return false;
}
}
void
AssignSRAMSections(void)
{
struct sSection *pSection;
while ((pSection = FindLargestSRAM())) {
SLONG org;
if ((org = area_AllocSRAMAnyBank(pSection->nByteSize)) != -1) {
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->nBank += BANK_SRAM;
pSection->oAssigned = 1;
DOMAXSBANK(pSection->nBank);
} else {
errx(1, "Unable to place SRAM section anywhere");
}
}
}
void
AssignWRAMSections(void)
{
struct sSection *pSection;
while ((pSection = FindLargestWRAM())) {
SLONG org;
if ((org = area_AllocWRAMAnyBank(pSection->nByteSize)) != -1) {
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->nBank += BANK_WRAMX - 1;
pSection->oAssigned = 1;
DOMAXWBANK(pSection->nBank);
} else {
errx(1, "Unable to place WRAMX section anywhere");
}
}
}
void
AssignCodeSections(void)
{
struct sSection *pSection;
while ((pSection = FindLargestCode())) {
SLONG org;
if ((org = area_AllocROMXAnyBank(pSection->nByteSize)) != -1) {
pSection->nOrg = org & 0xFFFF;
pSection->nBank = org >> 16;
pSection->oAssigned = 1;
DOMAXBANK(pSection->nBank);
} else {
errx(1, "Unable to place ROMX section anywhere");
}
}
}
void
AssignSections(void)
{
SLONG i;
@@ -392,17 +257,15 @@ AssignSections(void)
err(1, NULL);
}
if (i == 0) {
if (i == BANK_ROM0) {
/* ROM0 bank */
BankFree[i]->nOrg = 0x0000;
if (options & OPT_SMALL) {
BankFree[i]->nSize = 0x8000;
MaxAvail[i] = 0x8000;
} else {
BankFree[i]->nSize = 0x4000;
MaxAvail[i] = 0x4000;
}
} else if (i >= 1 && i <= 511) {
} else if (i >= BANK_ROMX && i < BANK_ROMX + BANK_COUNT_ROMX) {
/* Swappable ROM bank */
BankFree[i]->nOrg = 0x4000;
/*
@@ -411,37 +274,34 @@ AssignSections(void)
*/
if (options & OPT_SMALL) {
BankFree[i]->nSize = 0;
MaxAvail[i] = 0;
} else {
BankFree[i]->nSize = 0x4000;
MaxAvail[i] = 0x4000;
}
} else if (i == BANK_WRAM0) {
/* WRAM */
BankFree[i]->nOrg = 0xC000;
BankFree[i]->nSize = 0x1000;
MaxAvail[i] = 0x1000;
} else if (i >= BANK_SRAM && i <= BANK_SRAM + 3) {
} else if (i >= BANK_SRAM && i < BANK_SRAM + BANK_COUNT_SRAM) {
/* Swappable SRAM bank */
BankFree[i]->nOrg = 0xA000;
BankFree[i]->nSize = 0x2000;
MaxAvail[i] = 0x2000;
} else if (i >= BANK_WRAMX && i <= BANK_WRAMX + 6) {
} else if (i >= BANK_WRAMX && i < BANK_WRAMX + BANK_COUNT_WRAMX) {
/* Swappable WRAM bank */
BankFree[i]->nOrg = 0xD000;
BankFree[i]->nSize = 0x1000;
MaxAvail[i] = 0x1000;
} else if (i == BANK_VRAM || i == BANK_VRAM + 1) {
} else if (i >= BANK_VRAM && i < BANK_VRAM + BANK_COUNT_VRAM) {
/* Swappable VRAM bank */
BankFree[i]->nOrg = 0x8000;
BankFree[i]->nSize = 0x2000;
MaxAvail[i] = 0x2000;
} else if (i == BANK_HRAM) {
/* HRAM */
BankFree[i]->nOrg = 0xFF80;
BankFree[i]->nSize = 0x007F;
MaxAvail[i] = 0x007F;
} else {
errx(1, "(INTERNAL) Unknown bank type!");
}
MaxAvail[i] = BankFree[i]->nSize;
BankFree[i]->pPrev = NULL;
BankFree[i]->pNext = NULL;
}
@@ -460,241 +320,31 @@ AssignSections(void)
switch (pSection->Type) {
case SECT_WRAM0:
if (area_AllocAbs
(&BankFree[BANK_WRAM0], pSection->nOrg,
pSection->nByteSize) != pSection->nOrg) {
errx(1,
"Unable to load fixed WRAM0 "
"section at $%lX", pSection->nOrg);
}
pSection->oAssigned = 1;
pSection->nBank = BANK_WRAM0;
break;
case SECT_HRAM:
if (area_AllocAbs
(&BankFree[BANK_HRAM], pSection->nOrg,
pSection->nByteSize) != pSection->nOrg) {
errx(1, "Unable to load fixed HRAM "
"section at $%lX", pSection->nOrg);
}
pSection->oAssigned = 1;
pSection->nBank = BANK_HRAM;
break;
case SECT_SRAM:
if (pSection->nBank == -1) {
/*
* User doesn't care which bank.
* Therefore he must here be specifying
* position within the bank.
* Defer until later.
*/
;
} else {
/*
* User specified which bank to use.
* Does he also care about position
* within the bank?
*/
if (pSection->nOrg == -1) {
/*
* Nope, any position will do
* Again, we'll do that later
*
*/
;
} else {
/*
* Bank and position within the
* bank are hardcoded.
*/
if (pSection->nBank >= 0
&& pSection->nBank <= 3) {
pSection->nBank +=
BANK_SRAM;
if (area_AllocAbs
(&BankFree
[pSection->nBank],
pSection->nOrg,
pSection->nByteSize)
!= pSection->nOrg) {
errx(1,
"Unable to load fixed SRAM section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
DOMAXVBANK(pSection->
nBank);
pSection->oAssigned = 1;
} else {
errx(1,
"Unable to load fixed SRAM section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
}
}
break;
case SECT_WRAMX:
if (pSection->nBank == -1) {
/*
* User doesn't care which bank.
* Therefore he must here be specifying
* position within the bank.
* Defer until later.
*/
;
} else {
/*
* User specified which bank to use.
* Does he also care about position
* within the bank?
*/
if (pSection->nOrg == -1) {
/*
* Nope, any position will do
* Again, we'll do that later
*
*/
;
} else {
/*
* Bank and position within the
* bank are hardcoded.
*/
if (pSection->nBank >= 0
&& pSection->nBank <= 6) {
pSection->nBank +=
BANK_WRAMX;
if (area_AllocAbs
(&BankFree
[pSection->nBank],
pSection->nOrg,
pSection->nByteSize)
!= pSection->nOrg) {
errx(1,
"Unable to load fixed WRAMX section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
DOMAXWBANK(pSection->
nBank);
pSection->oAssigned = 1;
} else {
errx(1,
"Unable to load fixed WRAMX section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
}
}
break;
case SECT_VRAM:
if (pSection->nBank == -1) {
/*
* User doesn't care which bank.
* Therefore he must here be specifying
* position within the bank.
* Defer until later.
*/
;
} else {
/*
* User specified which bank to use.
* Does he also care about position
* within the bank?
*/
if (pSection->nOrg == -1) {
/*
* Nope, any position will do
* Again, we'll do that later
*
*/
;
} else {
/*
* Bank and position within the
* bank are hardcoded.
*/
if (pSection->nBank >= 0
&& pSection->nBank <= 1) {
pSection->nBank +=
BANK_VRAM;
if (area_AllocAbs
(&BankFree
[pSection->nBank],
pSection->nOrg,
pSection->nByteSize)
!= pSection->nOrg) {
errx(1,
"Unable to load fixed VRAM section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
DOMAXVBANK(pSection->
nBank);
pSection->oAssigned = 1;
} else {
errx(1,
"Unable to load fixed VRAM section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
}
}
break;
case SECT_ROM0:
if (area_AllocAbs
(&BankFree[BANK_ROM0], pSection->nOrg,
pSection->nByteSize) != pSection->nOrg) {
errx(1, "Unable to load fixed ROM0 "
"section at $%lX", pSection->nOrg);
pSection->nBank = SECT_ATTRIBUTES[pSection->Type].bank;
if (area_AllocAbs(&BankFree[pSection->nBank], pSection->nOrg,
pSection->nByteSize) == -1) {
errx(1, "Unable to load fixed %s section at $%lX",
SECT_ATTRIBUTES[pSection->Type].name,
pSection->nOrg);
}
pSection->oAssigned = 1;
pSection->nBank = BANK_ROM0;
break;
case SECT_SRAM:
case SECT_WRAMX:
case SECT_VRAM:
case SECT_ROMX:
if (pSection->nBank == -1) {
/*
* User doesn't care which bank, so he must want to
* decide which position within that bank.
* We'll do that at a later stage when the really
* hardcoded things are allocated
*
*/
} else {
/*
* User wants to decide which bank we use
* Does he care about the position as well?
*
*/
if (pSection->nOrg == -1) {
/*
* Nope, any position will do
* Again, we'll do that later
*
*/
if (pSection->nBank != -1 && pSection->nOrg != -1) {
if (VerifyAndSetBank(pSection) &&
area_AllocAbs(&BankFree[pSection->nBank], pSection->nOrg, pSection->nByteSize) != -1) {
DOMAXBANK(pSection->Type, pSection->nBank);
pSection->oAssigned = 1;
} else {
/*
* How hardcore can you possibly get? Why does
* he even USE this package? Yeah let's just
* direct address everything, shall we?
* Oh well, the customer is always right
*
*/
if (pSection->nBank >= 1
&& pSection->nBank <= 511) {
if (area_AllocAbs
(&BankFree
[pSection->nBank],
pSection->nOrg,
pSection->
nByteSize) !=
pSection->nOrg) {
errx(1,
"Unable to load fixed ROMX section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
DOMAXBANK(pSection->
nBank);
pSection->oAssigned = 1;
} else {
errx(1,
"Unable to load fixed ROMX section at $%lX in bank $%02lX", pSection->nOrg, pSection->nBank);
}
errx(1,
"Unable to load fixed %s section at $%lX in bank $%02lX", SECT_ATTRIBUTES[pSection->Type].name, pSection->nOrg, pSection->nBank);
}
}
break;
}
@@ -710,74 +360,30 @@ AssignSections(void)
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0
&& pSection->Type == SECT_ROMX
&& pSection->nOrg == -1 && pSection->nBank != -1) {
/* User wants to have a say... and he's pissed */
if (options & OPT_OVERLAY) {
errx(1, "All ROM sections must be fixed when using overlay");
&& pSection->nOrg == -1 && pSection->nBank != -1) {
if (pSection->Type == SECT_ROMX && options & OPT_OVERLAY) {
errx(1, "All ROMX sections must be fixed when using overlay");
}
if (pSection->nBank >= 1 && pSection->nBank <= 511) {
if ((pSection->nOrg =
area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize)) == -1) {
errx(1,
"Unable to load fixed ROMX section into bank $%02lX", pSection->nBank);
switch (pSection->Type) {
case SECT_ROMX:
case SECT_SRAM:
case SECT_VRAM:
case SECT_WRAMX:
if (VerifyAndSetBank(pSection) &&
(pSection->nOrg = area_Alloc(&BankFree[pSection->nBank], pSection->nByteSize)) != -1) {
pSection->oAssigned = 1;
DOMAXBANK(pSection->Type, pSection->nBank);
} else {
errx(1, "Unable to load fixed %s section into bank $%02lX",
SECT_ATTRIBUTES[pSection->Type].name, pSection->nBank);
}
pSection->oAssigned = 1;
DOMAXBANK(pSection->nBank);
} else {
errx(1, "Unable to load fixed ROMX section into bank $%02lX", pSection->nBank);
}
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_SRAM
&& pSection->nOrg == -1 && pSection->nBank != -1) {
pSection->nBank += BANK_SRAM;
/* User wants to have a say... and he's pissed */
if (pSection->nBank >= BANK_SRAM && pSection->nBank <= BANK_SRAM + 3) {
if ((pSection->nOrg =
area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize)) == -1) {
errx(1, "Unable to load fixed SRAM section into bank $%02lX", pSection->nBank);
}
pSection->oAssigned = 1;
DOMAXSBANK(pSection->nBank);
} else {
errx(1, "Unable to load fixed VRAM section into bank $%02lX", pSection->nBank);
}
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_VRAM
&& pSection->nOrg == -1 && pSection->nBank != -1) {
pSection->nBank += BANK_VRAM;
/* User wants to have a say... and he's pissed */
if (pSection->nBank >= BANK_VRAM && pSection->nBank <= BANK_VRAM + 1) {
if ((pSection->nOrg =
area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize)) == -1) {
errx(1, "Unable to load fixed VRAM section into bank $%02lX", pSection->nBank);
}
pSection->oAssigned = 1;
DOMAXVBANK(pSection->nBank);
} else {
errx(1, "Unable to load fixed VRAM section into bank $%02lX", pSection->nBank);
}
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_WRAMX
&& pSection->nOrg == -1 && pSection->nBank != -1) {
pSection->nBank += BANK_WRAMX;
/* User wants to have a say... and he's pissed */
if (pSection->nBank >= BANK_WRAMX && pSection->nBank <= BANK_WRAMX + 6) {
if ((pSection->nOrg =
area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize)) == -1) {
errx(1, "Unable to load fixed WRAMX section into bank $%02lX", pSection->nBank - BANK_WRAMX);
}
pSection->oAssigned = 1;
DOMAXWBANK(pSection->nBank);
} else {
errx(1, "Unable to load fixed WRAMX section into bank $%02lX", pSection->nBank - BANK_WRAMX);
break;
default: // Handle other sections later
break;
}
}
pSection = pSection->pNext;
}
@@ -789,61 +395,30 @@ AssignSections(void)
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0
&& pSection->Type == SECT_ROMX
&& pSection->nOrg != -1 && pSection->nBank == -1) {
/* User wants to have a say... and he's back with a
* vengeance */
if (options & OPT_OVERLAY) {
errx(1, "All ROM sections must be fixed when using overlay");
&& pSection->nOrg != -1 && pSection->nBank == -1) {
if (pSection->Type == SECT_ROMX && options & OPT_OVERLAY) {
errx(1, "All ROMX sections must be fixed when using overlay");
}
if ((pSection->nBank =
area_AllocAbsROMXAnyBank(pSection->nOrg,
pSection->nByteSize)) ==
-1) {
errx(1, "Unable to load fixed ROMX section at $%lX into any bank", pSection->nOrg);
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 load fixed %s section at $%lX into any bank",
SECT_ATTRIBUTES[pSection->Type].name, pSection->nOrg);
}
pSection->oAssigned = 1;
DOMAXBANK(pSection->Type, pSection->nBank);
break;
default: // Handle other sections later
break;
}
pSection->oAssigned = 1;
DOMAXBANK(pSection->nBank);
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_VRAM
&& pSection->nOrg != -1 && pSection->nBank == -1) {
/* User wants to have a say... and he's back with a
* vengeance */
if ((pSection->nBank =
area_AllocAbsVRAMAnyBank(pSection->nOrg,
pSection->nByteSize)) ==
-1) {
errx(1, "Unable to load fixed VRAM section at $%lX into any bank", pSection->nOrg);
}
pSection->oAssigned = 1;
DOMAXVBANK(pSection->nBank);
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_SRAM
&& pSection->nOrg != -1 && pSection->nBank == -1) {
/* User wants to have a say... and he's back with a
* vengeance */
if ((pSection->nBank =
area_AllocAbsSRAMAnyBank(pSection->nOrg,
pSection->nByteSize)) ==
-1) {
errx(1, "Unable to load fixed SRAM section at $%lX into any bank", pSection->nOrg);
}
pSection->oAssigned = 1;
DOMAXSBANK(pSection->nBank);
} else if (pSection->oAssigned == 0
&& pSection->Type == SECT_WRAMX
&& pSection->nOrg != -1 && pSection->nBank == -1) {
/* User wants to have a say... and he's back with a
* vengeance */
if ((pSection->nBank =
area_AllocAbsWRAMAnyBank(pSection->nOrg,
pSection->nByteSize)) ==
-1) {
errx(1, "Unable to load fixed WRAMX section at $%lX into any bank", pSection->nOrg);
}
pSection->oAssigned = 1;
DOMAXWBANK(pSection->nBank);
}
pSection = pSection->pNext;
}
@@ -856,48 +431,28 @@ AssignSections(void)
pSection = pSections;
while (pSection) {
if (pSection->oAssigned == 0) {
if (pSection->Type == SECT_ROMX && options & OPT_OVERLAY) {
errx(1, "All ROMX sections must be fixed when using overlay");
}
switch (pSection->Type) {
case SECT_WRAM0:
if ((pSection->nOrg =
area_Alloc(&BankFree[BANK_WRAM0],
pSection->nByteSize)) == -1) {
errx(1, "WRAM0 section too large");
}
pSection->nBank = BANK_WRAM0;
pSection->oAssigned = 1;
break;
case SECT_HRAM:
if ((pSection->nOrg =
area_Alloc(&BankFree[BANK_HRAM],
pSection->nByteSize)) == -1) {
errx(1, "HRAM section too large");
}
pSection->nBank = BANK_HRAM;
pSection->oAssigned = 1;
break;
case SECT_SRAM:
break;
case SECT_VRAM:
break;
case SECT_WRAMX:
break;
case SECT_ROM0:
if (options & OPT_OVERLAY) {
errx(1, "All ROM sections must be fixed when using overlay");
}
pSection->nBank = SECT_ATTRIBUTES[pSection->Type].bank;
if ((pSection->nOrg =
area_Alloc(&BankFree[BANK_ROM0],
area_Alloc(&BankFree[pSection->nBank],
pSection->nByteSize)) == -1) {
errx(1, "ROM0 section too large");
errx(1, "%s section too large", SECT_ATTRIBUTES[pSection->Type].name);
}
pSection->nBank = BANK_ROM0;
pSection->oAssigned = 1;
break;
case SECT_SRAM:
case SECT_VRAM:
case SECT_WRAMX:
case SECT_ROMX:
if (options & OPT_OVERLAY) {
errx(1, "All ROM sections must be fixed when using overlay");
}
break;
default:
errx(1, "(INTERNAL) Unknown section type!");
break;
@@ -906,10 +461,10 @@ AssignSections(void)
pSection = pSection->pNext;
}
AssignCodeSections();
AssignVRAMSections();
AssignWRAMSections();
AssignSRAMSections();
AssignBankedSections(SECT_ROMX);
AssignBankedSections(SECT_VRAM);
AssignBankedSections(SECT_WRAMX);
AssignBankedSections(SECT_SRAM);
}
void

View File

@@ -68,6 +68,7 @@ getsymbank(SLONG symid)
errx(1, "*INTERNAL* UNKNOWN SYMBOL TYPE");
}
if (nBank == BANK_WRAM0) return 0;
if (nBank >= BANK_WRAMX && nBank <= (BANK_WRAMX+6))
return nBank - BANK_WRAMX + 1;
if (nBank >= BANK_VRAM && nBank <= (BANK_VRAM+1))