Initial revision: imported RGBDS source code

The code comes from the RGBDS source and documentation zip files found
on this website:

http://www.otakunozoku.com/1999/08/01/rednex-gameboy-development-system/

The same website reports:

	"Best of all, it’s free! That’s right! Free! The executables
	are free to use, either for personal hobby use, or full blown
	commercial productions — I know of at least a dozen commercial
	games you can purchase that are written with RGBDS — and the
	source code is free to modify.

	"The only thing I ask is that you do not charge for either
	distributing the executables or source code, and any derivative
	works you give credit to the original authors of the tools.
	That means you have to say “Thanks” to the original authors
	SurfSmurf and Otaku."

Signed-off-by: Vegard Nossum <vegard.nossum@gmail.com>
This commit is contained in:
Carsten Sorensen
2009-06-11 06:00:24 +02:00
committed by Vegard Nossum
commit e895832b2b
103 changed files with 13891 additions and 0 deletions

570
src/LINK/ASSIGN.C Normal file
View File

@@ -0,0 +1,570 @@
#include <stdio.h>
#include <stdlib.h>
#include "mylink.h"
#include "main.h"
#include "symbol.h"
#include "assign.h"
struct sFreeArea
{
SLONG nOrg;
SLONG nSize;
struct sFreeArea *pPrev, *pNext;
};
struct sFreeArea *BankFree[MAXBANKS];
SLONG MaxAvail[MAXBANKS];
SLONG MaxBankUsed;
#define DOMAXBANK(x) {if( (x)>MaxBankUsed ) MaxBankUsed=(x);}
SLONG area_Avail( SLONG bank )
{
SLONG r;
struct sFreeArea *pArea;
r=0;
pArea=BankFree[bank];
while( pArea )
{
r+=pArea->nSize;
pArea=pArea->pNext;
}
return( r );
}
SLONG area_AllocAbs( struct sFreeArea **ppArea, SLONG org, SLONG size )
{
struct sFreeArea *pArea;
pArea=*ppArea;
while( pArea )
{
if( org>=pArea->nOrg && (org+size-1)<=(pArea->nOrg+pArea->nSize-1) )
{
if( org==pArea->nOrg )
{
pArea->nOrg+=size;
pArea->nSize-=size;
return( org );
}
else
{
if( (org+size-1)==(pArea->nOrg+pArea->nSize-1) )
{
pArea->nSize-=size;
return( org );
}
else
{
struct sFreeArea *pNewArea;
if( (pNewArea=(struct sFreeArea *)malloc(sizeof(struct sFreeArea)))!=NULL )
{
*pNewArea=*pArea;
pNewArea->pPrev=pArea;
pArea->pNext=pNewArea;
pArea->nSize=org-pArea->nOrg;
pNewArea->nOrg=org+size;
pNewArea->nSize-=size+pArea->nSize;
return( org );
}
else
fatalerror( "Out of memory!" );
}
}
}
ppArea=&(pArea->pNext);
pArea=*ppArea;
}
return( -1 );
}
SLONG area_AllocAbsCODEAnyBank( SLONG org, SLONG size )
{
SLONG i;
for( i=1; i<=255; i+=1 )
{
if( area_AllocAbs( &BankFree[i], org, size )==org )
return( i );
}
return( -1 );
}
SLONG area_Alloc( struct sFreeArea **ppArea, SLONG size )
{
struct sFreeArea *pArea;
pArea=*ppArea;
while( pArea )
{
if( size<=pArea->nSize )
{
SLONG r;
r=pArea->nOrg;
pArea->nOrg+=size;
pArea->nSize-=size;
return( r );
}
ppArea=&(pArea->pNext);
pArea=*ppArea;
}
return( -1 );
}
SLONG area_AllocCODEAnyBank( SLONG size )
{
SLONG i, org;
for( i=1; i<=255; i+=1 )
{
if( (org=area_Alloc(&BankFree[i],size))!=-1 )
return( (i<<16)|org );
}
return( -1 );
}
struct sSection *FindLargestCode( void )
{
struct sSection *pSection, *r=NULL;
SLONG nLargest=0;
pSection=pSections;
while( pSection )
{
if( pSection->oAssigned==0 && pSection->Type==SECT_CODE )
{
if( pSection->nByteSize > nLargest )
{
nLargest=pSection->nByteSize;
r=pSection;
}
}
pSection=pSection->pNext;
}
return( r );
}
void AssignCodeSections( void )
{
struct sSection *pSection;
while( pSection=FindLargestCode() )
{
SLONG org;
if( (org=area_AllocCODEAnyBank( pSection->nByteSize ))!=-1 )
{
pSection->nOrg=org&0xFFFF;
pSection->nBank=org>>16;
pSection->oAssigned=1;
DOMAXBANK(pSection->nBank);
}
else
fatalerror( "Unable to place CODE section anywhere" );
}
}
void GBROM_AssignSections( void )
{
SLONG i;
struct sSection *pSection;
MaxBankUsed=0;
/*
* Initialize the memory areas
*
*/
for( i=0; i<MAXBANKS; i+=1 )
{
if( BankFree[i]=(struct sFreeArea *)malloc(sizeof(struct sFreeArea)) )
{
if( i==0 )
{
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<=255 )
{
BankFree[i]->nOrg=0x4000;
/*
* Now, this shouldn't really be necessary... but for good
* measure we'll do it anyway
*
*/
if( options&OPT_SMALL )
{
BankFree[i]->nSize=0;
MaxAvail[i]=0;
}
else
{
BankFree[i]->nSize=0x4000;
MaxAvail[i]=0x4000;
}
}
else if( i==BANK_BSS )
{
BankFree[i]->nOrg =0xC000;
BankFree[i]->nSize=0x2000;
MaxAvail[i]=0x2000;
}
else if( i==BANK_VRAM )
{
BankFree[i]->nOrg =0x8000;
BankFree[i]->nSize=0x2000;
MaxAvail[i]=0x2000;
}
else if( i==BANK_HRAM )
{
BankFree[i]->nOrg =0xFF80;
BankFree[i]->nSize=0x007F;
MaxAvail[i]=0x007F;
}
BankFree[i]->pPrev=NULL;
BankFree[i]->pNext=NULL;
}
else
fatalerror( "Out of memory!" );
}
/*
* First, let's assign all the fixed sections...
* And all because of that Jens Restemeier character ;)
*
*/
pSection=pSections;
while( pSection )
{
if( (pSection->nOrg!=-1 || pSection->nBank!=-1) && pSection->oAssigned==0 )
{
/* User wants to have a say... */
switch( pSection->Type )
{
case SECT_BSS:
if( area_AllocAbs(&BankFree[BANK_BSS],pSection->nOrg,pSection->nByteSize)!=pSection->nOrg )
{
sprintf( temptext, "Unable to load fixed BSS section at $%X", pSection->nOrg );
fatalerror( temptext );
}
pSection->oAssigned=1;
pSection->nBank=BANK_BSS;
break;
case SECT_HRAM:
if( area_AllocAbs(&BankFree[BANK_HRAM],pSection->nOrg,pSection->nByteSize)!=pSection->nOrg )
{
sprintf( temptext, "Unable to load fixed HRAM section at $%X", pSection->nOrg );
fatalerror( temptext );
}
pSection->oAssigned=1;
pSection->nBank=BANK_HRAM;
break;
case SECT_VRAM:
if( area_AllocAbs(&BankFree[BANK_VRAM],pSection->nOrg,pSection->nByteSize)!=pSection->nOrg )
{
sprintf( temptext, "Unable to load fixed VRAM section at $%X", pSection->nOrg );
fatalerror( temptext );
}
pSection->oAssigned=1;
pSection->nBank=BANK_VRAM;
break;
case SECT_HOME:
if( area_AllocAbs(&BankFree[BANK_HOME],pSection->nOrg,pSection->nByteSize)!=pSection->nOrg )
{
sprintf( temptext, "Unable to load fixed HOME section at $%X", pSection->nOrg );
fatalerror( temptext );
}
pSection->oAssigned=1;
pSection->nBank=BANK_HOME;
break;
case SECT_CODE:
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
*
*/
}
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<=255 )
{
if( area_AllocAbs(&BankFree[pSection->nBank],pSection->nOrg,pSection->nByteSize)!=pSection->nOrg )
{
sprintf( temptext, "Unable to load fixed CODE/DATA section at $%X in bank $%02X", pSection->nOrg, pSection->nBank );
fatalerror( temptext );
}
DOMAXBANK(pSection->nBank);
pSection->oAssigned=1;
}
else
{
sprintf( temptext, "Unable to load fixed CODE/DATA section at $%X in bank $%02X", pSection->nOrg, pSection->nBank );
fatalerror( temptext );
}
}
}
break;
}
}
pSection=pSection->pNext;
}
/*
* Next, let's assign all the bankfixed ONLY CODE sections...
*
*/
pSection=pSections;
while( pSection )
{
if( pSection->oAssigned==0
&& pSection->Type==SECT_CODE
&& pSection->nOrg==-1
&& pSection->nBank!=-1 )
{
/* User wants to have a say... and he's pissed */
if( pSection->nBank>=1 && pSection->nBank<=255 )
{
if( (pSection->nOrg=area_Alloc(&BankFree[pSection->nBank],pSection->nByteSize))==-1 )
{
sprintf( temptext, "Unable to load fixed CODE/DATA section into bank $%02X", pSection->nBank );
fatalerror( temptext );
}
pSection->oAssigned=1;
DOMAXBANK(pSection->nBank);
}
else
{
sprintf( temptext, "Unable to load fixed CODE/DATA section into bank $%02X", pSection->nBank );
fatalerror( temptext );
}
}
pSection=pSection->pNext;
}
/*
* Now, let's assign all the floating bank but fixed CODE sections...
*
*/
pSection=pSections;
while( pSection )
{
if( pSection->oAssigned==0
&& pSection->Type==SECT_CODE
&& pSection->nOrg!=-1
&& pSection->nBank==-1 )
{
/* User wants to have a say... and he's back with a vengeance */
if( (pSection->nBank=area_AllocAbsCODEAnyBank(pSection->nOrg,pSection->nByteSize))==-1 )
{
sprintf( temptext, "Unable to load fixed CODE/DATA section at $%X into any bank", pSection->nOrg );
fatalerror( temptext );
}
pSection->oAssigned=1;
DOMAXBANK(pSection->nBank);
}
pSection=pSection->pNext;
}
/*
* OK, all that nasty stuff is done so let's assign all the other
* sections
*
*/
pSection=pSections;
while( pSection )
{
if( pSection->oAssigned==0 )
{
switch( pSection->Type )
{
case SECT_BSS:
if( (pSection->nOrg=area_Alloc(&BankFree[BANK_BSS],pSection->nByteSize))==-1 )
{
fatalerror( "BSS section too large\n" );
}
pSection->nBank=BANK_BSS;
pSection->oAssigned=1;
break;
case SECT_HRAM:
if( (pSection->nOrg=area_Alloc(&BankFree[BANK_HRAM],pSection->nByteSize))==-1 )
{
fatalerror( "HRAM section too large" );
}
pSection->nBank=BANK_HRAM;
pSection->oAssigned=1;
break;
case SECT_VRAM:
if( (pSection->nOrg=area_Alloc(&BankFree[BANK_VRAM],pSection->nByteSize))==-1 )
{
fatalerror( "VRAM section too large" );
}
pSection->nBank=BANK_VRAM;
pSection->oAssigned=1;
break;
case SECT_HOME:
if( (pSection->nOrg=area_Alloc(&BankFree[BANK_HOME],pSection->nByteSize))==-1 )
{
fatalerror( "HOME section too large" );
}
pSection->nBank=BANK_HOME;
pSection->oAssigned=1;
break;
case SECT_CODE:
break;
default:
fatalerror( "(INTERNAL) Unknown section type!" );
break;
}
}
pSection=pSection->pNext;
}
AssignCodeSections();
}
void PSION2_AssignSections( void )
{
struct sSection *pSection;
if( BankFree[0]=(struct sFreeArea *)malloc(sizeof(struct sFreeArea)) )
{
BankFree[0]->nOrg=0x0000;
BankFree[0]->nSize=0x10000;
MaxAvail[0]=0x10000;
BankFree[0]->pPrev=NULL;
BankFree[0]->pNext=NULL;
pSection=pSections;
while( pSection )
{
if( pSection->oAssigned==0 && pSection->Type==SECT_CODE )
{
pSection->oAssigned=1;
pSection->nBank=0;
pSection->nOrg=BankFree[0]->nOrg;
BankFree[0]->nOrg+=pSection->nByteSize;
BankFree[0]->nSize-=pSection->nByteSize;
}
pSection=pSection->pNext;
}
pSection=pSections;
while( pSection )
{
if( pSection->oAssigned==0 && pSection->Type==SECT_BSS )
{
pSection->oAssigned=1;
pSection->nBank=0;
pSection->nOrg=BankFree[0]->nOrg;
BankFree[0]->nOrg+=pSection->nByteSize;
BankFree[0]->nSize-=pSection->nByteSize;
}
pSection=pSection->pNext;
}
}
else
fatalerror( "Out of memory!" );
}
void AssignSections( void )
{
switch( outputtype )
{
case OUTPUT_GBROM:
GBROM_AssignSections();
break;
case OUTPUT_PSION2:
PSION2_AssignSections();
break;
}
}
void CreateSymbolTable( void )
{
struct sSection *pSect;
sym_Init();
pSect=pSections;
while( pSect )
{
SLONG i;
i=pSect->nNumberOfSymbols;
while( i-- )
{
if( (pSect->tSymbols[i]->Type==SYM_EXPORT) &&
( (pSect->tSymbols[i]->pSection==pSect) ||
(pSect->tSymbols[i]->pSection==NULL)) )
{
if( pSect->tSymbols[i]->pSection==NULL )
sym_CreateSymbol( pSect->tSymbols[i]->pzName,
pSect->tSymbols[i]->nOffset,
-1 );
else
sym_CreateSymbol( pSect->tSymbols[i]->pzName,
pSect->nOrg+pSect->tSymbols[i]->nOffset,
pSect->nBank );
}
}
pSect=pSect->pNext;
}
}

22
src/LINK/INCLUDE/ASSIGN.H Normal file
View File

@@ -0,0 +1,22 @@
#ifndef ASSIGN_H
#define ASSIGN_H
#include "types.h"
enum eBankDefine
{
BANK_HOME=0,
BANK_BSS=256,
BANK_VRAM,
BANK_HRAM
};
#define MAXBANKS 259
extern SLONG area_Avail( SLONG bank );
extern void AssignSections( void );
extern void CreateSymbolTable( void );
extern SLONG MaxBankUsed;
extern SLONG MaxAvail[MAXBANKS];
#endif

View File

@@ -0,0 +1,6 @@
#ifndef LIBRARY_H
#define LIBRARY_H
extern void AddNeededModules( void );
#endif

21
src/LINK/INCLUDE/MAIN.H Normal file
View File

@@ -0,0 +1,21 @@
#ifndef MAIN_H
#define MAIN_H
#include "types.h"
extern void PrintUsage( void );
extern void fatalerror( char *s );
extern char temptext[1024];
extern SLONG fillchar;
extern char smartlinkstartsymbol[256];
enum eOutputType
{
OUTPUT_GBROM,
OUTPUT_PSION2
};
extern enum eOutputType outputtype;
#endif

View File

@@ -0,0 +1,11 @@
#ifndef MAPFILE_H
#define MAPFILE_H
extern void SetMapfileName( char *name );
extern void SetSymfileName( char *name );
extern void CloseMapfile( void );
extern void MapfileWriteSection( struct sSection *pSect );
extern void MapfileInitBank( SLONG bank );
extern void MapfileCloseBank( SLONG slack );
#endif

119
src/LINK/INCLUDE/MYLINK.H Normal file
View File

@@ -0,0 +1,119 @@
#ifndef LINK_H
#define LINK_H 1
#if defined(AMIGA) || defined(__GNUC__)
#define _MAX_PATH 512
#endif
#include "types.h"
extern SLONG options;
#define OPT_SMALL 0x01
#define OPT_SMART_C_LINK 0x02
enum eRpnData
{
RPN_ADD=0,
RPN_SUB,
RPN_MUL,
RPN_DIV,
RPN_MOD,
RPN_UNSUB,
RPN_OR,
RPN_AND,
RPN_XOR,
RPN_UNNOT,
RPN_LOGAND,
RPN_LOGOR,
RPN_LOGUNNOT,
RPN_LOGEQ,
RPN_LOGNE,
RPN_LOGGT,
RPN_LOGLT,
RPN_LOGGE,
RPN_LOGLE,
RPN_SHL,
RPN_SHR,
RPN_BANK,
RPN_HRAM,
RPN_PCEZP,
RPN_RANGECHECK,
RPN_CONST=0x80,
RPN_SYM=0x81
};
enum eSectionType
{
SECT_BSS,
SECT_VRAM,
SECT_CODE,
SECT_HOME,
SECT_HRAM
};
struct sSection
{
SLONG nBank;
SLONG nOrg;
BBOOL oAssigned;
SLONG nByteSize;
enum eSectionType Type;
UBYTE *pData;
SLONG nNumberOfSymbols;
struct sSymbol **tSymbols;
struct sPatch *pPatches;
struct sSection *pNext;
};
enum eSymbolType
{
SYM_LOCAL,
SYM_IMPORT,
SYM_EXPORT
};
struct sSymbol
{
char *pzName;
enum eSymbolType Type;
/* the following 3 items only valid when Type!=SYM_IMPORT */
SLONG nSectionID; /* internal to object.c */
struct sSection *pSection;
SLONG nOffset;
};
enum ePatchType
{
PATCH_BYTE=0,
PATCH_WORD_L,
PATCH_LONG_L,
PATCH_WORD_B,
PATCH_LONG_B
};
struct sPatch
{
char *pzFilename;
SLONG nLineNo;
SLONG nOffset;
enum ePatchType Type;
SLONG nRPNSize;
UBYTE *pRPN;
struct sPatch *pNext;
BBOOL oRelocPatch;
};
extern struct sSection *pSections;
extern struct sSection *pLibSections;
#endif

View File

@@ -0,0 +1,7 @@
#ifndef OBJECT_H
#define OBJECT_H
extern void obj_Readfile( char *tzObjectfile );
extern void lib_Readfile( char *tzLibfile );
#endif

View File

@@ -0,0 +1,7 @@
#ifndef OUTPUT_H
#define OUTPUT_H
void out_Setname( char *tzOutputfile );
void Output( void );
#endif

9
src/LINK/INCLUDE/PATCH.H Normal file
View File

@@ -0,0 +1,9 @@
#ifndef PATCH_H
#define PATCH_H
#include "types.h"
void Patch( void );
extern SLONG nPC;
#endif

11
src/LINK/INCLUDE/SYMBOL.H Normal file
View File

@@ -0,0 +1,11 @@
#ifndef SYMBOL_H
#define SYMBOL_H
#include "types.h"
void sym_Init( void );
void sym_CreateSymbol( char *tzName, SLONG nValue, SBYTE nBank );
SLONG sym_GetValue( char *tzName );
SLONG sym_GetBank( char *tzName );
#endif

16
src/LINK/INCLUDE/TYPES.H Normal file
View File

@@ -0,0 +1,16 @@
#ifndef TYPES_H
#define TYPES_H 1
#if defined(AMIGA) || defined(__GNUC__)
#define _MAX_PATH 512
#endif
typedef unsigned char UBYTE;
typedef signed char SBYTE;
typedef unsigned short UWORD;
typedef signed short SWORD;
typedef unsigned long ULONG;
typedef signed long SLONG;
typedef signed char BBOOL;
#endif

127
src/LINK/LIBRARY.C Normal file
View File

@@ -0,0 +1,127 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "mylink.h"
#include "main.h"
static BBOOL symboldefined( char *name )
{
struct sSection *pSect;
pSect=pSections;
while( pSect )
{
ULONG i;
for( i=0; i<pSect->nNumberOfSymbols; i+=1 )
{
if( (pSect->tSymbols[i]->Type==SYM_EXPORT)
|| ( (pSect->tSymbols[i]->Type==SYM_LOCAL)
&& (pSect==pSect->tSymbols[i]->pSection) ) )
{
if( strcmp(pSect->tSymbols[i]->pzName,name)==0 )
return( 1 );
}
}
pSect=pSect->pNext;
}
return( 0 );
}
static BBOOL addmodulecontaining( char *name )
{
struct sSection **ppLSect;
ppLSect=&pLibSections;
while( *ppLSect )
{
ULONG i;
for( i=0; i<(*ppLSect)->nNumberOfSymbols; i+=1 )
{
if( ((*ppLSect)->tSymbols[i]->Type==SYM_EXPORT)
|| ( ((*ppLSect)->tSymbols[i]->Type==SYM_LOCAL)
&& ((*ppLSect)==(*ppLSect)->tSymbols[i]->pSection) ) )
{
if( strcmp((*ppLSect)->tSymbols[i]->pzName,name)==0 )
{
struct sSection **ppSect;
ppSect=&pSections;
while( *ppSect )
ppSect=&((*ppSect)->pNext);
*ppSect = *ppLSect;
*ppLSect = (*ppLSect)->pNext;
(*ppSect)->pNext = NULL;
return( 1 );
}
}
}
ppLSect=&((*ppLSect)->pNext);
}
return( 0 );
}
void AddNeededModules( void )
{
struct sSection *pSect;
if( (options&OPT_SMART_C_LINK)==0 )
{
struct sSection **ppLSect;
ppLSect=&pLibSections;
while( *ppLSect )
{
struct sSection **ppSect;
ppSect=&pSections;
while( *ppSect )
ppSect=&((*ppSect)->pNext);
*ppSect = *ppLSect;
*ppLSect = (*ppLSect)->pNext;
(*ppSect)->pNext = NULL;
/*ppLSect=&((*ppLSect)->pNext);*/
}
return;
}
if( options&OPT_SMART_C_LINK )
{
if( !addmodulecontaining( smartlinkstartsymbol ) )
{
sprintf( temptext, "Can't find start symbol '%s'", smartlinkstartsymbol );
fatalerror( temptext );
}
else
printf( "Smart linking with symbol '%s'\n", smartlinkstartsymbol );
}
pSect=pSections;
while( pSect )
{
ULONG i;
for( i=0; i<pSect->nNumberOfSymbols; i+=1 )
{
if( (pSect->tSymbols[i]->Type==SYM_IMPORT)
|| (pSect->tSymbols[i]->Type==SYM_LOCAL) )
{
if( !symboldefined(pSect->tSymbols[i]->pzName) )
{
addmodulecontaining( pSect->tSymbols[i]->pzName );
}
}
}
pSect=pSect->pNext;
}
}

230
src/LINK/MAIN.C Normal file
View File

@@ -0,0 +1,230 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "object.h"
#include "output.h"
#include "assign.h"
#include "patch.h"
#include "asmotor.h"
#include "mylink.h"
#include "mapfile.h"
#include "main.h"
#include "library.h"
// Quick and dirty...but it works
#ifdef __GNUC__
#define strcmpi strcasecmp
#endif
enum eBlockType
{
BLOCK_COMMENT,
BLOCK_OBJECTS,
BLOCK_LIBRARIES,
BLOCK_OUTPUT
};
SLONG options=0;
SLONG fillchar=-1;
enum eOutputType outputtype=OUTPUT_GBROM;
char temptext[1024];
char smartlinkstartsymbol[256];
/*
* Print out an errormessage
*
*/
void fatalerror( char *s )
{
printf( "*ERROR* : %s\n", s );
exit( 5 );
}
/*
* Print the usagescreen
*
*/
void PrintUsage( void )
{
printf( "xLink v" LINK_VERSION " (part of ASMotor " ASMOTOR_VERSION ")\n\n"
"Usage: xlink [options] linkfile\n"
"Options:\n\t-h\t\tThis text\n"
"\t-m<mapfile>\tWrite a mapfile\n"
"\t-n<symfile>\tWrite a NO$GMB compatible symfile\n"
"\t-z<hx>\t\tSet the byte value (hex format) used for uninitialised\n"
"\t\t\tdata (default is ? for random)\n"
"\t-s<symbol>\tPerform smart linking starting with <symbol>\n"
"\t-t\t\tOutput target\n"
"\t\t-tg\tGameboy ROM image(default)\n"
"\t\t-ts\tGameboy small mode (32kB)\n"
"\t\t-tp\tPsion2 reloc module\n" );
exit( 0 );
}
/*
* Parse the linkfile and load all the objectfiles
*
*/
void ProcessLinkfile( char *tzLinkfile )
{
FILE *pLinkfile;
enum eBlockType CurrentBlock=BLOCK_COMMENT;
if( pLinkfile=fopen(tzLinkfile,"rt") )
{
while( !feof(pLinkfile) )
{
char tzLine[256];
fscanf( pLinkfile, "%s\n", tzLine );
if( tzLine[0]!='#' )
{
if( tzLine[0]=='[' && tzLine[strlen(tzLine)-1]==']' )
{
if( strcmpi("[objects]",tzLine)==0 )
CurrentBlock=BLOCK_OBJECTS;
else if( strcmpi("[output]",tzLine)==0 )
CurrentBlock=BLOCK_OUTPUT;
else if( strcmpi("[libraries]",tzLine)==0 )
CurrentBlock=BLOCK_LIBRARIES;
else if( strcmpi("[comment]",tzLine)==0 )
CurrentBlock=BLOCK_COMMENT;
else
{
fclose( pLinkfile );
sprintf( temptext, "Unknown block '%s'\n", tzLine );
fatalerror( temptext );
}
}
else
{
switch( CurrentBlock )
{
case BLOCK_COMMENT:
break;
case BLOCK_OBJECTS:
obj_Readfile( tzLine );
break;
case BLOCK_LIBRARIES:
lib_Readfile( tzLine );
break;
case BLOCK_OUTPUT:
out_Setname( tzLine );
break;
}
}
}
}
fclose( pLinkfile );
}
else
{
sprintf( temptext, "Unable to find linkfile '%s'\n", tzLinkfile );
fatalerror( temptext );
}
}
/*
* The main routine
*
*/
int main( int argc, char *argv[] )
{
SLONG argn=0;
argc-=1;
argn+=1;
if( argc==0 )
PrintUsage();
while( *argv[argn]=='-' )
{
char opt;
argc-=1;
switch( opt=argv[argn++][1] )
{
case '?':
case 'h':
PrintUsage();
break;
case 'm':
SetMapfileName( argv[argn-1]+2 );
break;
case 'n':
SetSymfileName( argv[argn-1]+2 );
break;
case 't':
switch( opt=argv[argn-1][2] )
{
case 'g':
outputtype=OUTPUT_GBROM;
break;
case 's':
outputtype=OUTPUT_GBROM;
options|=OPT_SMALL;
break;
case 'p':
outputtype=OUTPUT_PSION2;
break;
default:
sprintf( temptext, "Unknown option 't%c'\n", opt );
fatalerror( temptext );
break;
}
break;
case 'z':
if( strlen(argv[argn-1]+2)<=2 )
{
if( strcmp(argv[argn-1]+2,"?")==0 )
{
fillchar=-1;
}
else
{
int result;
result=sscanf( argv[argn-1]+2, "%x", &fillchar );
if( !((result==EOF) || (result==1)) )
{
fatalerror("Invalid argument for option 'z'\n" );
}
}
}
else
{
fatalerror("Invalid argument for option 'z'\n" );
}
break;
case 's':
options|=OPT_SMART_C_LINK;
strcpy( smartlinkstartsymbol, argv[argn-1]+2 );
break;
default:
sprintf( temptext, "Unknown option '%c'\n", opt );
fatalerror( temptext );
break;
}
}
if( argc==1 )
{
ProcessLinkfile( argv[argn++] );
AddNeededModules();
AssignSections();
CreateSymbolTable();
Patch();
Output();
CloseMapfile();
}
else
PrintUsage();
return( 0 );
}

63
src/LINK/MAKEFILE Normal file
View File

@@ -0,0 +1,63 @@
.ERASE
.EXTENSIONS:
.EXTENSIONS: .obj .c .h
!ifndef TARGET
TARGET = DOS
!endif
!ifeq TARGET DOS
!else
!ifeq TARGET WIN95
!else
!error Invalid TARGET (must be DOS or WIN95)
!endif
!endif
!ifeq TARGET DOS
COPT = /zp4 /5s /fp3 /d2 /oneatx /i=include /i=.. /wx /bt=dos
OBJDIR = OBJS\
EXE = xlink.exe
!endif
!ifeq TARGET WIN95
COPT = /zp4 /5s /fp3 /d3 /oneatx /i=include /i=.. /d2 /wx /bt=nt
OBJDIR = OBJS95\
EXE = xlink95.exe
!endif
C = wcc386 $(COPT)
.c: .
.h: include
.obj: $(OBJDIR)
OBJS = main.obj object.obj assign.obj symbol.obj &
patch.obj output.obj mapfile.obj library.obj
$(EXE) : $(OBJS)
%create link.lnk
!ifeq TARGET DOS
%append link.lnk system pmodew
!endif
!ifeq TARGET WIN95
%append link.lnk system nt
!endif
%append link.lnk option map
%append link.lnk option stack=64k
%append link.lnk debug watcom all
%append link.lnk name $(EXE)
for %i in ($(OBJS)) do %append link.lnk file $(OBJDIR)\%i
wlink @link.lnk
!ifeq TARGET DOS
d:\code\pmodew\pmwsetup /B0 $(EXE)
!endif
.c.obj : .AUTODEPEND
$(C) -fo=$(OBJDIR)$^. $[.
clean: .SYMBOLIC
del $(OBJDIR)*.obj
del *.err
del $(EXE)
del *.map
del link.lnk

108
src/LINK/MAPFILE.C Normal file
View File

@@ -0,0 +1,108 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "asmotor.h"
#include "main.h"
#include "mylink.h"
#include "assign.h"
FILE *mf=NULL;
FILE *sf=NULL;
SLONG currentbank=0;
SLONG sfbank;
void SetMapfileName( char *name )
{
if( mf=fopen(name,"wt") )
return;
else
fatalerror( "Unable to open mapfile for writing" );
}
void SetSymfileName( char *name )
{
if( sf=fopen(name,"wt") )
{
fprintf( sf, ";File generated by xLink v" LINK_VERSION "\n\n" );
return;
}
else
fatalerror( "Unable to open symfile for writing" );
}
void CloseMapfile( void )
{
if( mf )
{
fclose( mf );
mf=NULL;
}
if( sf )
{
fclose( sf );
sf=NULL;
}
}
void MapfileInitBank( SLONG bank )
{
if( mf )
{
currentbank=bank;
if( bank==0 )
fprintf( mf, "Bank #0 (HOME):\n" );
else if( bank<=255 )
fprintf( mf, "Bank #%d:\n", bank );
else if( bank==BANK_BSS )
fprintf( mf, "BSS:\n" );
else if( bank==BANK_HRAM )
fprintf( mf, "HRAM:\n" );
else if( bank==BANK_VRAM )
fprintf( mf, "VRAM:\n" );
}
if( sf )
{
sfbank=(bank>=1&&bank<=255)?bank:0;
}
}
void MapfileWriteSection( struct sSection *pSect )
{
if( mf || sf )
{
SLONG i;
fprintf( mf, " SECTION: $%04X-$%04X ($%04X bytes)\n", pSect->nOrg, pSect->nOrg+pSect->nByteSize-1, pSect->nByteSize );
for( i=0; i<pSect->nNumberOfSymbols; i+=1 )
{
struct sSymbol *pSym;
pSym=pSect->tSymbols[i];
if( (pSym->pSection==pSect) && (pSym->Type!=SYM_IMPORT) )
{
if( mf )
{
fprintf( mf, " $%04X = %s\n", pSym->nOffset+pSect->nOrg, pSym->pzName );
}
if( sf )
{
fprintf( sf, "%02X:%04X %s\n", sfbank, pSym->nOffset+pSect->nOrg, pSym->pzName );
}
}
}
}
}
void MapfileCloseBank( SLONG slack )
{
if( mf )
{
if( slack==MaxAvail[currentbank] )
fprintf( mf, " EMPTY\n\n" );
else
fprintf( mf, " SLACK: $%04X bytes\n\n", slack );
}
}

546
src/LINK/OBJECT.C Normal file
View File

@@ -0,0 +1,546 @@
/*
* Here we have the routines that read an objectfile
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mylink.h"
#include "main.h"
struct sSymbol **tSymbols;
struct sSection *pSections=NULL;
struct sSection *pLibSections=NULL;
UBYTE dummymem;
BBOOL oReadLib=0;
/*
* The usual byte order stuff
*
*/
SLONG readlong( FILE *f )
{
SLONG r;
r =fgetc(f);
r|=fgetc(f)<<8;
r|=fgetc(f)<<16;
r|=fgetc(f)<<24;
return( r );
}
UWORD readword( FILE *f )
{
UWORD r;
r =fgetc(f);
r|=fgetc(f)<<8;
return( r );
}
/*
* Read a NULL terminated string from a file
*
*/
SLONG readasciiz( char *s, FILE *f )
{
SLONG r=0;
while( ((*s++)=fgetc(f))!=0 )
r+=1;
return( r+1 );
}
/*
* Allocate a new section and link it into the list
*
*/
struct sSection *AllocSection( void )
{
struct sSection **ppSections;
if( oReadLib==1 )
ppSections=&pLibSections;
else
ppSections=&pSections;
while( *ppSections )
ppSections=&((*ppSections)->pNext);
if( (*ppSections)=(struct sSection *)malloc(sizeof(struct sSection)) )
{
(*ppSections)->tSymbols=tSymbols;
(*ppSections)->pNext=NULL;
(*ppSections)->pPatches=NULL;
(*ppSections)->oAssigned=0;
return( *ppSections );
}
else
{
fatalerror( "Out of memory!" );
return( NULL );
}
}
/*
* Read a symbol from a file
*
*/
struct sSymbol *obj_ReadSymbol( FILE *f )
{
char s[256];
struct sSymbol *pSym;
if( pSym=(struct sSymbol *)malloc(sizeof(struct sSymbol)) )
{
readasciiz( s, f );
if( pSym->pzName=(char *)malloc(strlen(s)+1) )
{
strcpy( pSym->pzName, s );
if( (pSym->Type=(enum eSymbolType)fgetc(f))!=SYM_IMPORT )
{
pSym->nSectionID=readlong(f);
pSym->nOffset=readlong(f);
}
return( pSym );
}
else
fatalerror( "Out of memory!" );
}
else
fatalerror( "Out of memory!" );
return( NULL );
}
/*
* RGB0 object reader routines
*
*/
struct sSection *obj_ReadRGB0Section( FILE *f )
{
struct sSection *pSection;
pSection=AllocSection();
pSection->nByteSize=readlong( f );
pSection->Type=(enum eSectionType)fgetc( f );
pSection->nOrg=-1;
pSection->nBank=-1;
/* does the user want the -s mode? */
if( (options&OPT_SMALL) && (pSection->Type==SECT_CODE) )
{
pSection->Type=SECT_HOME;
}
if( (pSection->Type==SECT_CODE) || (pSection->Type==SECT_HOME) )
{
/*
* These sectiontypes contain data...
*
*/
if( pSection->nByteSize )
{
if( pSection->pData=(UBYTE *)malloc(pSection->nByteSize) )
{
SLONG nNumberOfPatches;
struct sPatch **ppPatch, *pPatch;
char s[256];
fread( pSection->pData, sizeof(UBYTE), pSection->nByteSize, f );
nNumberOfPatches=readlong(f);
ppPatch=&pSection->pPatches;
/*
* And patches...
*
*/
while( nNumberOfPatches-- )
{
if( pPatch=(struct sPatch *)malloc(sizeof(struct sPatch)) )
{
*ppPatch=pPatch;
readasciiz( s, f );
if( pPatch->pzFilename=(char *)malloc(strlen(s)+1) )
{
strcpy( pPatch->pzFilename, s );
pPatch->nLineNo=readlong( f );
pPatch->nOffset=readlong( f );
pPatch->Type=(enum ePatchType)fgetc( f );
if( (pPatch->nRPNSize=readlong(f))>0 )
{
if( pPatch->pRPN=(UBYTE *)malloc(pPatch->nRPNSize) )
fread( pPatch->pRPN, sizeof(UBYTE), pPatch->nRPNSize, f );
else
fatalerror( "Out of memory!" );
}
else
pPatch->pRPN=NULL;
pPatch->pNext=NULL;
ppPatch=&(pPatch->pNext);
}
else
fatalerror( "Out of memory!" );
}
else
fatalerror( "Out of memory!" );
}
}
else
fatalerror( "Out of memory!" );
}
else
{
readlong(f); // Skip number of patches
pSection->pData=&dummymem;
}
}
return( pSection );
}
void obj_ReadRGB0( FILE *pObjfile )
{
struct sSection *pFirstSection;
SLONG nNumberOfSymbols, nNumberOfSections, i;
nNumberOfSymbols=readlong( pObjfile );
nNumberOfSections=readlong( pObjfile );
/* First comes the symbols */
if( nNumberOfSymbols )
{
if( tSymbols=(struct sSymbol **)malloc(nNumberOfSymbols*sizeof(struct sSymbol *)) )
{
for( i=0; i<nNumberOfSymbols; i+=1 )
tSymbols[i]=obj_ReadSymbol( pObjfile );
}
else
fatalerror( "Out of memory!" );
}
else
tSymbols=(struct sSymbol **)&dummymem;
/* Next we have the sections */
pFirstSection=NULL;
while( nNumberOfSections-- )
{
struct sSection *pNewSection;
pNewSection=obj_ReadRGB0Section( pObjfile );
pNewSection->nNumberOfSymbols=nNumberOfSymbols;
if( pFirstSection==NULL )
pFirstSection=pNewSection;
}
/*
* Fill in the pSection entry in the symbolstructure.
* This REALLY needs some cleaning up... but, hey, it works
*
*/
for( i=0; i<nNumberOfSymbols; i+=1 )
{
struct sSection *pConvSect=pFirstSection;
if( tSymbols[i]->Type!=SYM_IMPORT && tSymbols[i]->nSectionID!=-1 )
{
SLONG j=0;
while( j != tSymbols[i]->nSectionID )
{
j+=1;
pConvSect=pConvSect->pNext;
}
tSymbols[i]->pSection=pConvSect;
}
else
tSymbols[i]->pSection=NULL;
}
}
/*
* RGB1 object reader routines
*
*/
struct sSection *obj_ReadRGB1Section( FILE *f )
{
struct sSection *pSection;
pSection=AllocSection();
pSection->nByteSize=readlong( f );
pSection->Type=(enum eSectionType)fgetc( f );
/*
* And because of THIS new feature I'll have to rewrite loads and
* loads of stuff... oh well it needed to be done anyway
*
*/
pSection->nOrg=readlong( f );
pSection->nBank=readlong( f );
/* does the user want the -s mode? */
if( (options&OPT_SMALL) && (pSection->Type==SECT_CODE) )
{
pSection->Type=SECT_HOME;
}
if( (pSection->Type==SECT_CODE) || (pSection->Type==SECT_HOME) )
{
/*
* These sectiontypes contain data...
*
*/
if( pSection->nByteSize )
{
if( pSection->pData=(UBYTE *)malloc(pSection->nByteSize) )
{
SLONG nNumberOfPatches;
struct sPatch **ppPatch, *pPatch;
char s[256];
fread( pSection->pData, sizeof(UBYTE), pSection->nByteSize, f );
nNumberOfPatches=readlong(f);
ppPatch=&pSection->pPatches;
/*
* And patches...
*
*/
while( nNumberOfPatches-- )
{
if( pPatch=(struct sPatch *)malloc(sizeof(struct sPatch)) )
{
*ppPatch=pPatch;
readasciiz( s, f );
if( pPatch->pzFilename=(char *)malloc(strlen(s)+1) )
{
strcpy( pPatch->pzFilename, s );
pPatch->nLineNo=readlong( f );
pPatch->nOffset=readlong( f );
pPatch->Type=(enum ePatchType)fgetc( f );
if( (pPatch->nRPNSize=readlong(f))>0 )
{
if( pPatch->pRPN=(UBYTE *)malloc(pPatch->nRPNSize) )
fread( pPatch->pRPN, sizeof(UBYTE), pPatch->nRPNSize, f );
else
fatalerror( "Out of memory!" );
}
else
pPatch->pRPN=NULL;
pPatch->pNext=NULL;
ppPatch=&(pPatch->pNext);
}
else
fatalerror( "Out of memory!" );
}
else
fatalerror( "Out of memory!" );
}
}
else
fatalerror( "Out of memory!" );
}
else
{
readlong(f); // Skip number of patches
pSection->pData=&dummymem;
}
}
return( pSection );
}
void obj_ReadRGB1( FILE *pObjfile )
{
struct sSection *pFirstSection;
SLONG nNumberOfSymbols, nNumberOfSections, i;
nNumberOfSymbols=readlong( pObjfile );
nNumberOfSections=readlong( pObjfile );
/* First comes the symbols */
if( nNumberOfSymbols )
{
if( tSymbols=(struct sSymbol **)malloc(nNumberOfSymbols*sizeof(struct sSymbol *)) )
{
for( i=0; i<nNumberOfSymbols; i+=1 )
tSymbols[i]=obj_ReadSymbol( pObjfile );
}
else
fatalerror( "Out of memory!" );
}
else
tSymbols=(struct sSymbol **)&dummymem;
/* Next we have the sections */
pFirstSection=NULL;
while( nNumberOfSections-- )
{
struct sSection *pNewSection;
pNewSection=obj_ReadRGB1Section( pObjfile );
pNewSection->nNumberOfSymbols=nNumberOfSymbols;
if( pFirstSection==NULL )
pFirstSection=pNewSection;
}
/*
* Fill in the pSection entry in the symbolstructure.
* This REALLY needs some cleaning up... but, hey, it works
*
*/
for( i=0; i<nNumberOfSymbols; i+=1 )
{
struct sSection *pConvSect=pFirstSection;
if( tSymbols[i]->Type!=SYM_IMPORT && tSymbols[i]->nSectionID!=-1 )
{
SLONG j=0;
while( j != tSymbols[i]->nSectionID )
{
j+=1;
pConvSect=pConvSect->pNext;
}
tSymbols[i]->pSection=pConvSect;
}
else
tSymbols[i]->pSection=NULL;
}
}
/*
* The main objectfileloadroutine (phew)
*
*/
void obj_ReadOpenFile( FILE *pObjfile, char *tzObjectfile )
{
char tzHeader[8];
fread( tzHeader, sizeof(char), 4, pObjfile );
tzHeader[4]=0;
if( strncmp(tzHeader,"RGB", 3)==0 )
{
switch( tzHeader[3] )
{
case '0':
obj_ReadRGB0( pObjfile );
break;
case '1':
case '2': // V2 is really the same but the are new patch types
obj_ReadRGB1( pObjfile );
break;
default:
sprintf( temptext, "'%s' is an unsupported version\n", tzObjectfile );
fatalerror( temptext );
break;
}
}
else
{
sprintf( temptext, "'%s' is not a valid object\n", tzObjectfile );
fatalerror( temptext );
}
}
void obj_Readfile( char *tzObjectfile )
{
FILE *pObjfile;
if( options&OPT_SMART_C_LINK )
oReadLib=1;
else
oReadLib=0;
if( pObjfile=fopen(tzObjectfile,"rb") )
{
obj_ReadOpenFile( pObjfile, tzObjectfile );
fclose( pObjfile );
}
else
{
sprintf( temptext, "Unable to open '%s'\n", tzObjectfile );
fatalerror( temptext );
}
oReadLib=0;
}
SLONG file_Length( FILE *f )
{
ULONG r,
p;
p=ftell( f );
fseek( f, 0, SEEK_END );
r=ftell( f );
fseek( f, p, SEEK_SET );
return( r );
}
void lib_ReadXLB0( FILE *f )
{
SLONG size;
size=file_Length( f )-4;
while( size )
{
char name[256];
size-=readasciiz( name, f );
readword( f ); size-=2;
readword( f ); size-=2;
size-=readlong( f ); size-=4;
obj_ReadOpenFile( f, name );
}
}
void lib_Readfile( char *tzLibfile )
{
FILE *pObjfile;
oReadLib=1;
if( pObjfile=fopen(tzLibfile,"rb") )
{
char tzHeader[5];
fread( tzHeader, sizeof(char), 4, pObjfile );
tzHeader[4]=0;
if( strcmp(tzHeader,"XLB0")==0 )
lib_ReadXLB0( pObjfile );
else
{
sprintf( temptext, "'%s' is an invalid library\n", tzLibfile );
fatalerror( temptext );
}
fclose( pObjfile );
}
else
{
sprintf( temptext, "Unable to open '%s'\n", tzLibfile );
fatalerror( temptext );
}
}

2
src/LINK/OBJS/DELETE.ME Normal file
View File

@@ -0,0 +1,2 @@
You can safely delete me.
I'm just a dummy so pkzip will store this directory.

View File

@@ -0,0 +1,2 @@
You can safely delete me.
I'm just a dummy so pkzip will store this directory.

222
src/LINK/OUTPUT.C Normal file
View File

@@ -0,0 +1,222 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mylink.h"
#include "mapfile.h"
#include "main.h"
#include "assign.h"
char tzOutname[_MAX_PATH];
BBOOL oOutput=0;
void writehome( FILE *f )
{
struct sSection *pSect;
UBYTE *mem;
if( mem=(UBYTE *)malloc(MaxAvail[BANK_HOME]) )
{
if( fillchar!=-1 )
{
memset( mem, fillchar, MaxAvail[BANK_HOME] );
}
MapfileInitBank( 0 );
pSect=pSections;
while( pSect )
{
if( pSect->Type==SECT_HOME )
{
memcpy( mem+pSect->nOrg, pSect->pData, pSect->nByteSize );
MapfileWriteSection( pSect );
}
pSect=pSect->pNext;
}
MapfileCloseBank( area_Avail(0) );
fwrite( mem, 1, MaxAvail[BANK_HOME], f );
free( mem );
}
}
void writebank( FILE *f, SLONG bank )
{
struct sSection *pSect;
UBYTE *mem;
if( mem=(UBYTE *)malloc(MaxAvail[bank]) )
{
if( fillchar!=-1 )
{
memset( mem, fillchar, MaxAvail[bank] );
}
MapfileInitBank( bank );
pSect=pSections;
while( pSect )
{
if( pSect->Type==SECT_CODE && pSect->nBank==bank )
{
memcpy( mem+pSect->nOrg-0x4000, pSect->pData, pSect->nByteSize );
MapfileWriteSection( pSect );
}
pSect=pSect->pNext;
}
MapfileCloseBank( area_Avail(bank) );
fwrite( mem, 1, MaxAvail[bank], f );
free( mem );
}
}
void out_Setname( char *tzOutputfile )
{
strcpy( tzOutname, tzOutputfile );
oOutput=1;
}
void GBROM_Output( void )
{
SLONG i;
FILE *f;
if( f=fopen(tzOutname,"wb") )
{
writehome( f );
for( i=1; i<=MaxBankUsed; i+=1 )
writebank( f, i );
fclose( f );
}
for( i=256; i<MAXBANKS; i+=1 )
{
struct sSection *pSect;
MapfileInitBank( i );
pSect=pSections;
while( pSect )
{
if( pSect->nBank==i )
{
MapfileWriteSection( pSect );
}
pSect=pSect->pNext;
}
MapfileCloseBank( area_Avail(i) );
}
}
void PSION2_Output( void )
{
FILE *f;
if( f=fopen(tzOutname,"wb") )
{
struct sSection *pSect;
UBYTE *mem;
ULONG size=MaxAvail[0]-area_Avail(0);
ULONG relocpatches;
fputc( size>>24, f );
fputc( size>>16, f );
fputc( size>>8, f );
fputc( size, f );
if( mem=(UBYTE *)malloc(MaxAvail[0]-area_Avail(0)) )
{
MapfileInitBank( 0 );
pSect=pSections;
while( pSect )
{
if( pSect->Type==SECT_CODE )
{
memcpy( mem+pSect->nOrg, pSect->pData, pSect->nByteSize );
MapfileWriteSection( pSect );
}
else
{
memset( mem+pSect->nOrg, 0, pSect->nByteSize );
}
pSect=pSect->pNext;
}
MapfileCloseBank( area_Avail(0) );
fwrite( mem, 1, MaxAvail[0]-area_Avail(0), f );
free( mem );
}
relocpatches=0;
pSect=pSections;
while( pSect )
{
struct sPatch *pPatch;
pPatch=pSect->pPatches;
while( pPatch )
{
if( pPatch->oRelocPatch )
{
relocpatches+=1;
}
pPatch=pPatch->pNext;
}
pSect=pSect->pNext;
}
fputc( relocpatches>>24, f );
fputc( relocpatches>>16, f );
fputc( relocpatches>>8, f );
fputc( relocpatches, f );
pSect=pSections;
while( pSect )
{
struct sPatch *pPatch;
pPatch=pSect->pPatches;
while( pPatch )
{
if( pPatch->oRelocPatch )
{
ULONG address;
address=pPatch->nOffset+pSect->nOrg;
fputc( address>>24, f );
fputc( address>>16, f );
fputc( address>>8, f );
fputc( address, f );
}
pPatch=pPatch->pNext;
}
pSect=pSect->pNext;
}
fclose( f );
}
}
void Output( void )
{
if( oOutput )
{
switch( outputtype )
{
case OUTPUT_GBROM:
GBROM_Output();
break;
case OUTPUT_PSION2:
PSION2_Output();
break;
}
}
}

300
src/LINK/PATCH.C Normal file
View File

@@ -0,0 +1,300 @@
#include <stdio.h>
#include <string.h>
#include "mylink.h"
#include "symbol.h"
#include "main.h"
struct sSection *pCurrentSection;
SLONG rpnstack[256];
SLONG rpnp;
SLONG nPC;
void rpnpush( SLONG i )
{
rpnstack[rpnp++]=i;
}
SLONG rpnpop( void )
{
return( rpnstack[--rpnp] );
}
SLONG getsymvalue( SLONG symid )
{
switch( pCurrentSection->tSymbols[symid]->Type )
{
case SYM_IMPORT:
return( sym_GetValue(pCurrentSection->tSymbols[symid]->pzName) );
break;
case SYM_EXPORT:
case SYM_LOCAL:
{
if( strcmp(pCurrentSection->tSymbols[symid]->pzName,"@")==0 )
{
return( nPC );
}
else
return( pCurrentSection->tSymbols[symid]->nOffset+pCurrentSection->tSymbols[symid]->pSection->nOrg );
}
default:
break;
}
fatalerror( "*INTERNAL* UNKNOWN SYMBOL TYPE" );
return( 0 );
}
SLONG getsymbank( SLONG symid )
{
switch( pCurrentSection->tSymbols[symid]->Type )
{
case SYM_IMPORT:
return( sym_GetBank(pCurrentSection->tSymbols[symid]->pzName) );
break;
case SYM_EXPORT:
case SYM_LOCAL:
return( pCurrentSection->tSymbols[symid]->pSection->nBank );
//return( pCurrentSection->nBank );
default:
break;
}
fatalerror( "*INTERNAL* UNKNOWN SYMBOL TYPE" );
return( 0 );
}
SLONG calcrpn( struct sPatch *pPatch )
{
SLONG t, size;
UBYTE *rpn;
rpnp=0;
size=pPatch->nRPNSize;
rpn=pPatch->pRPN;
pPatch->oRelocPatch=0;
while( size>0 )
{
size-=1;
switch( *rpn++ )
{
case RPN_ADD:
rpnpush( rpnpop()+rpnpop() );
break;
case RPN_SUB:
t=rpnpop();
rpnpush( rpnpop()-t );
break;
case RPN_MUL:
rpnpush( rpnpop()*rpnpop() );
break;
case RPN_DIV:
t=rpnpop();
rpnpush( rpnpop()/t );
break;
case RPN_MOD:
t=rpnpop();
rpnpush( rpnpop()%t );
break;
case RPN_UNSUB:
rpnpush( -rpnpop() );
break;
case RPN_OR:
rpnpush( rpnpop()|rpnpop() );
break;
case RPN_AND:
rpnpush( rpnpop()&rpnpop() );
break;
case RPN_XOR:
rpnpush( rpnpop()^rpnpop() );
break;
case RPN_UNNOT:
rpnpush( rpnpop()^0xFFFFFFFF );
break;
case RPN_LOGAND:
rpnpush( rpnpop()&&rpnpop() );
break;
case RPN_LOGOR:
rpnpush( rpnpop()||rpnpop() );
break;
case RPN_LOGUNNOT:
rpnpush( !rpnpop() );
break;
case RPN_LOGEQ:
rpnpush( rpnpop()==rpnpop() );
break;
case RPN_LOGNE:
rpnpush( rpnpop()!=rpnpop() );
break;
case RPN_LOGGT:
t=rpnpop();
rpnpush( rpnpop()>t );
break;
case RPN_LOGLT:
t=rpnpop();
rpnpush( rpnpop()<t );
break;
case RPN_LOGGE:
t=rpnpop();
rpnpush( rpnpop()>=t );
break;
case RPN_LOGLE:
t=rpnpop();
rpnpush( rpnpop()<=t );
break;
case RPN_SHL:
t=rpnpop();
rpnpush( rpnpop()<<t );
break;
case RPN_SHR:
t=rpnpop();
rpnpush( rpnpop()>>t );
break;
case RPN_HRAM:
t=rpnpop();
rpnpush(t&0xFF);
if( t<0 || (t>0xFF && t<0xFF00) || t>0xFFFF )
{
sprintf( temptext, "%s(%d) : Value must be in the HRAM area", pPatch->pzFilename, pPatch->nLineNo );
fatalerror( temptext );
}
break;
case RPN_PCEZP:
t=rpnpop();
rpnpush(t&0xFF);
if( t<0x2000 || t>0x20FF )
{
sprintf( temptext, "%s(%d) : Value must be in the ZP area", pPatch->pzFilename, pPatch->nLineNo );
fatalerror( temptext );
}
break;
case RPN_CONST:
/* constant */
t=(*rpn++);
t|=(*rpn++)<<8;
t|=(*rpn++)<<16;
t|=(*rpn++)<<24;
rpnpush( t );
size-=4;
break;
case RPN_SYM:
/* symbol */
t=(*rpn++);
t|=(*rpn++)<<8;
t|=(*rpn++)<<16;
t|=(*rpn++)<<24;
rpnpush( getsymvalue(t) );
pPatch->oRelocPatch|=(getsymbank(t)!=-1);
size-=4;
break;
case RPN_BANK:
/* symbol */
t=(*rpn++);
t|=(*rpn++)<<8;
t|=(*rpn++)<<16;
t|=(*rpn++)<<24;
rpnpush( getsymbank(t) );
size-=4;
break;
case RPN_RANGECHECK:
{
SLONG low,
high;
low =(*rpn++);
low|=(*rpn++)<<8;
low|=(*rpn++)<<16;
low|=(*rpn++)<<24;
high =(*rpn++);
high|=(*rpn++)<<8;
high|=(*rpn++)<<16;
high|=(*rpn++)<<24;
t=rpnpop();
if( t<low || t>high )
{
sprintf( temptext, "%s(%d) : Value must be in the range [%d;%d]", pPatch->pzFilename, pPatch->nLineNo, low, high );
fatalerror( temptext );
}
rpnpush(t);
size-=8;
break;
}
}
}
return( rpnpop() );
}
void Patch( void )
{
struct sSection *pSect;
pSect=pSections;
while( pSect )
{
struct sPatch *pPatch;
pCurrentSection=pSect;
pPatch=pSect->pPatches;
while( pPatch )
{
SLONG t;
nPC=pSect->nOrg+pPatch->nOffset;
t=calcrpn( pPatch );
switch( pPatch->Type )
{
case PATCH_BYTE:
if( t>=-128 && t<=255 )
{
t&=0xFF;
pSect->pData[pPatch->nOffset]=(UBYTE)t;
}
else
{
sprintf( temptext, "%s(%d) : Value must be 8-bit\n", pPatch->pzFilename, pPatch->nLineNo );
fatalerror( temptext );
}
break;
case PATCH_WORD_L:
case PATCH_WORD_B:
if( t>=-32768 && t<=65535 )
{
t&=0xFFFF;
if( pPatch->Type==PATCH_WORD_L )
{
pSect->pData[pPatch->nOffset]=t&0xFF;
pSect->pData[pPatch->nOffset+1]=(t>>8)&0xFF;
}
else
{
// Assume big endian
pSect->pData[pPatch->nOffset]=(t>>8)&0xFF;
pSect->pData[pPatch->nOffset+1]=t&0xFF;
}
}
else
{
sprintf( temptext, "%s(%d) : Value must be 16-bit\n", pPatch->pzFilename, pPatch->nLineNo );
fatalerror( temptext );
}
break;
case PATCH_LONG_L:
pSect->pData[pPatch->nOffset+0]=t&0xFF;
pSect->pData[pPatch->nOffset+1]=(t>>8)&0xFF;
pSect->pData[pPatch->nOffset+2]=(t>>16)&0xFF;
pSect->pData[pPatch->nOffset+3]=(t>>24)&0xFF;
break;
case PATCH_LONG_B:
pSect->pData[pPatch->nOffset+0]=(t>>24)&0xFF;
pSect->pData[pPatch->nOffset+1]=(t>>16)&0xFF;
pSect->pData[pPatch->nOffset+2]=(t>>8)&0xFF;
pSect->pData[pPatch->nOffset+3]=t&0xFF;
break;
}
pPatch=pPatch->pNext;
}
pSect=pSect->pNext;
}
}

125
src/LINK/SYMBOL.C Normal file
View File

@@ -0,0 +1,125 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "main.h"
#include "patch.h"
#include "types.h"
#define HASHSIZE 73
struct ISymbol
{
char *pzName;
SLONG nValue;
SLONG nBank; // -1=const
struct ISymbol *pNext;
};
struct ISymbol *tHash[HASHSIZE];
SLONG calchash( char *s )
{
SLONG r=0;
while( *s )
r+=*s++;
return( r%HASHSIZE );
}
void sym_Init( void )
{
SLONG i;
for( i=0; i<HASHSIZE; i+=1 )
tHash[i]=NULL;
}
SLONG sym_GetValue( char *tzName )
{
if( strcmp(tzName,"@")==0 )
{
return( nPC );
}
else
{
struct ISymbol **ppSym;
ppSym=&(tHash[calchash(tzName)]);
while( *ppSym )
{
if( strcmp(tzName,(*ppSym)->pzName) )
{
ppSym=&((*ppSym)->pNext);
}
else
{
return( (*ppSym)->nValue );
}
}
sprintf( temptext, "Unknown symbol '%s'", tzName );
fatalerror( temptext );
return( 0 );
}
}
SLONG sym_GetBank( char *tzName )
{
struct ISymbol **ppSym;
ppSym=&(tHash[calchash(tzName)]);
while( *ppSym )
{
if( strcmp(tzName,(*ppSym)->pzName) )
{
ppSym=&((*ppSym)->pNext);
}
else
{
return( (*ppSym)->nBank );
}
}
sprintf( temptext, "Unknown symbol '%s'" );
fatalerror( temptext );
return( 0 );
}
void sym_CreateSymbol( char *tzName, SLONG nValue, SBYTE nBank )
{
if( strcmp(tzName,"@")==0 )
{
}
else
{
struct ISymbol **ppSym;
ppSym=&(tHash[calchash(tzName)]);
while( *ppSym )
{
if( strcmp(tzName,(*ppSym)->pzName) )
{
ppSym=&((*ppSym)->pNext);
}
else
{
if( nBank==-1 )
return;
sprintf( temptext, "Symbol '%s' defined more than once\n", tzName );
fatalerror( temptext );
}
}
if( *ppSym=(struct ISymbol *)malloc(sizeof(struct ISymbol)) )
{
if( (*ppSym)->pzName=(char *)malloc(strlen(tzName)+1) )
{
strcpy( (*ppSym)->pzName, tzName );
(*ppSym)->nValue=nValue;
(*ppSym)->nBank=nBank;
(*ppSym)->pNext=NULL;
}
}
}
}