mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
1011 lines
19 KiB
C
1011 lines
19 KiB
C
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* INCLUDES
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "asm/asm.h"
|
|
#include "asm/output.h"
|
|
#include "asm/symbol.h"
|
|
#include "asm/mylink.h"
|
|
#include "asm/main.h"
|
|
#include "asm/rpn.h"
|
|
#include "asm/fstack.h"
|
|
|
|
#define SECTIONCHUNK 0x4000
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Internal structures
|
|
*
|
|
*/
|
|
|
|
void out_SetCurrentSection(struct Section *pSect);
|
|
|
|
struct Patch {
|
|
char tzFilename[_MAX_PATH + 1];
|
|
ULONG nLine;
|
|
ULONG nOffset;
|
|
UBYTE nType;
|
|
ULONG nRPNSize;
|
|
UBYTE *pRPN;
|
|
struct Patch *pNext;
|
|
};
|
|
|
|
struct PatchSymbol {
|
|
ULONG ID;
|
|
struct sSymbol *pSymbol;
|
|
struct PatchSymbol *pNext;
|
|
};
|
|
|
|
struct SectionStackEntry {
|
|
struct Section *pSection;
|
|
struct SectionStackEntry *pNext;
|
|
};
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* VARIABLES
|
|
*
|
|
*/
|
|
|
|
struct Section *pSectionList = NULL, *pCurrentSection = NULL;
|
|
struct PatchSymbol *pPatchSymbols = NULL;
|
|
char tzObjectname[_MAX_PATH];
|
|
struct SectionStackEntry *pSectionStack = NULL;
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Section stack routines
|
|
*
|
|
*/
|
|
|
|
void out_PushSection(void)
|
|
{
|
|
struct SectionStackEntry *pSect;
|
|
|
|
if ((pSect =
|
|
(struct SectionStackEntry *)
|
|
malloc(sizeof(struct SectionStackEntry))) != NULL) {
|
|
pSect->pSection = pCurrentSection;
|
|
pSect->pNext = pSectionStack;
|
|
pSectionStack = pSect;
|
|
} else
|
|
fatalerror("No memory for section stack");
|
|
}
|
|
|
|
void out_PopSection(void)
|
|
{
|
|
if (pSectionStack) {
|
|
struct SectionStackEntry *pSect;
|
|
|
|
pSect = pSectionStack;
|
|
out_SetCurrentSection(pSect->pSection);
|
|
pSectionStack = pSect->pNext;
|
|
free(pSect);
|
|
} else
|
|
fatalerror("No entries in the section stack");
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Count the number of symbols used in this object
|
|
*
|
|
*/
|
|
|
|
ULONG countsymbols(void)
|
|
{
|
|
struct PatchSymbol *pSym;
|
|
ULONG count = 0;
|
|
|
|
pSym = pPatchSymbols;
|
|
|
|
while (pSym) {
|
|
count += 1;
|
|
pSym = pSym->pNext;
|
|
}
|
|
|
|
return (count);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Count the number of sections used in this object
|
|
*
|
|
*/
|
|
|
|
ULONG countsections(void)
|
|
{
|
|
struct Section *pSect;
|
|
ULONG count = 0;
|
|
|
|
pSect = pSectionList;
|
|
|
|
while (pSect) {
|
|
count += 1;
|
|
pSect = pSect->pNext;
|
|
}
|
|
|
|
return (count);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Count the number of patches used in this object
|
|
*
|
|
*/
|
|
|
|
ULONG countpatches(struct Section * pSect)
|
|
{
|
|
struct Patch *pPatch;
|
|
ULONG r = 0;
|
|
|
|
pPatch = pSect->pPatches;
|
|
while (pPatch) {
|
|
r += 1;
|
|
pPatch = pPatch->pNext;
|
|
}
|
|
|
|
return (r);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Write a long to a file (little-endian)
|
|
*
|
|
*/
|
|
|
|
void fputlong(ULONG i, FILE * f)
|
|
{
|
|
fputc(i, f);
|
|
fputc(i >> 8, f);
|
|
fputc(i >> 16, f);
|
|
fputc(i >> 24, f);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Write a NULL-terminated string to a file
|
|
*
|
|
*/
|
|
|
|
void fputstring(char *s, FILE * f)
|
|
{
|
|
while (*s)
|
|
fputc(*s++, f);
|
|
fputc(0, f);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Return a sections ID
|
|
*
|
|
*/
|
|
|
|
ULONG getsectid(struct Section *pSect)
|
|
{
|
|
struct Section *sec;
|
|
ULONG ID = 0;
|
|
|
|
sec = pSectionList;
|
|
|
|
while (sec) {
|
|
if (sec == pSect)
|
|
return (ID);
|
|
ID += 1;
|
|
sec = sec->pNext;
|
|
}
|
|
|
|
fatalerror("INTERNAL: Unknown section");
|
|
return ((ULONG) - 1);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Write a patch to a file
|
|
*
|
|
*/
|
|
|
|
void writepatch(struct Patch *pPatch, FILE * f)
|
|
{
|
|
fputstring(pPatch->tzFilename, f);
|
|
fputlong(pPatch->nLine, f);
|
|
fputlong(pPatch->nOffset, f);
|
|
fputc(pPatch->nType, f);
|
|
fputlong(pPatch->nRPNSize, f);
|
|
fwrite(pPatch->pRPN, 1, pPatch->nRPNSize, f);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Write a section to a file
|
|
*
|
|
*/
|
|
|
|
void writesection(struct Section *pSect, FILE * f)
|
|
{
|
|
//printf( "SECTION: %s, ID: %d\n", pSect->pzName, getsectid(pSect) );
|
|
|
|
fputlong(pSect->nPC, f);
|
|
fputc(pSect->nType, f);
|
|
fputlong(pSect->nOrg, f); // RGB1 addition
|
|
|
|
fputlong(pSect->nBank, f); // RGB1 addition
|
|
|
|
if ((pSect->nType == SECT_HOME)
|
|
|| (pSect->nType == SECT_CODE)) {
|
|
struct Patch *pPatch;
|
|
|
|
fwrite(pSect->tData, 1, pSect->nPC, f);
|
|
fputlong(countpatches(pSect), f);
|
|
|
|
pPatch = pSect->pPatches;
|
|
while (pPatch) {
|
|
writepatch(pPatch, f);
|
|
pPatch = pPatch->pNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Write a symbol to a file
|
|
*
|
|
*/
|
|
|
|
void writesymbol(struct sSymbol *pSym, FILE * f)
|
|
{
|
|
char symname[MAXSYMLEN * 2 + 1];
|
|
ULONG type;
|
|
ULONG offset;
|
|
SLONG sectid;
|
|
|
|
if (pSym->nType & SYMF_IMPORT) {
|
|
/* Symbol should be imported */
|
|
strcpy(symname, pSym->tzName);
|
|
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);
|
|
}
|
|
|
|
fputstring(symname, f);
|
|
fputc(type, f);
|
|
|
|
if (type != SYM_IMPORT) {
|
|
fputlong(sectid, f);
|
|
fputlong(offset, f);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Add a symbol to the object
|
|
*
|
|
*/
|
|
|
|
ULONG addsymbol(struct sSymbol *pSym)
|
|
{
|
|
struct PatchSymbol *pPSym, **ppPSym;
|
|
ULONG ID = 0;
|
|
|
|
pPSym = pPatchSymbols;
|
|
ppPSym = &(pPatchSymbols);
|
|
|
|
while (pPSym) {
|
|
if (pSym == pPSym->pSymbol)
|
|
return (pPSym->ID);
|
|
ppPSym = &(pPSym->pNext);
|
|
pPSym = pPSym->pNext;
|
|
ID += 1;
|
|
}
|
|
|
|
if ((*ppPSym = pPSym =
|
|
(struct PatchSymbol *)malloc(sizeof(struct PatchSymbol))) !=
|
|
NULL) {
|
|
pPSym->pNext = NULL;
|
|
pPSym->pSymbol = pSym;
|
|
pPSym->ID = ID;
|
|
return (ID);
|
|
} else
|
|
fatalerror("No memory for patchsymbol");
|
|
|
|
return ((ULONG) - 1);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Add all exported symbols to the object
|
|
*
|
|
*/
|
|
|
|
void addexports(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < HASHSIZE; i += 1) {
|
|
struct sSymbol *pSym;
|
|
|
|
pSym = tHashedSymbols[i];
|
|
while (pSym) {
|
|
if (pSym->nType & SYMF_EXPORT)
|
|
addsymbol(pSym);
|
|
pSym = pSym->pNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Allocate a new patchstructure and link it into the list
|
|
*
|
|
*/
|
|
|
|
struct Patch *allocpatch(void)
|
|
{
|
|
struct Patch *pPatch, **ppPatch;
|
|
|
|
pPatch = pCurrentSection->pPatches;
|
|
ppPatch = &(pCurrentSection->pPatches);
|
|
|
|
while (pPatch) {
|
|
ppPatch = &(pPatch->pNext);
|
|
pPatch = pPatch->pNext;
|
|
}
|
|
|
|
if ((*ppPatch = pPatch =
|
|
(struct Patch *)malloc(sizeof(struct Patch))) != NULL) {
|
|
pPatch->pNext = NULL;
|
|
pPatch->nRPNSize = 0;
|
|
pPatch->pRPN = NULL;
|
|
} else
|
|
fatalerror("No memory for patch");
|
|
|
|
return (pPatch);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Create a new patch (includes the rpn expr)
|
|
*
|
|
*/
|
|
|
|
void createpatch(ULONG type, struct Expression *expr)
|
|
{
|
|
struct Patch *pPatch;
|
|
UWORD rpndata;
|
|
UBYTE rpnexpr[2048];
|
|
char tzSym[512];
|
|
ULONG rpnptr = 0, symptr;
|
|
|
|
pPatch = allocpatch();
|
|
pPatch->nType = type;
|
|
strcpy(pPatch->tzFilename, tzCurrentFileName);
|
|
pPatch->nLine = nLineNo;
|
|
pPatch->nOffset = nPC;
|
|
|
|
while ((rpndata = rpn_PopByte(expr)) != 0xDEAD) {
|
|
switch (rpndata) {
|
|
case RPN_CONST:
|
|
rpnexpr[rpnptr++] = RPN_CONST;
|
|
rpnexpr[rpnptr++] = rpn_PopByte(expr);
|
|
rpnexpr[rpnptr++] = rpn_PopByte(expr);
|
|
rpnexpr[rpnptr++] = rpn_PopByte(expr);
|
|
rpnexpr[rpnptr++] = rpn_PopByte(expr);
|
|
break;
|
|
case RPN_SYM:
|
|
symptr = 0;
|
|
while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0) ;
|
|
if (sym_isConstant(tzSym)) {
|
|
ULONG value;
|
|
|
|
value = sym_GetConstantValue(tzSym);
|
|
rpnexpr[rpnptr++] = RPN_CONST;
|
|
rpnexpr[rpnptr++] = value & 0xFF;
|
|
rpnexpr[rpnptr++] = value >> 8;
|
|
rpnexpr[rpnptr++] = value >> 16;
|
|
rpnexpr[rpnptr++] = value >> 24;
|
|
} else {
|
|
symptr = addsymbol(sym_FindSymbol(tzSym));
|
|
rpnexpr[rpnptr++] = RPN_SYM;
|
|
rpnexpr[rpnptr++] = symptr & 0xFF;
|
|
rpnexpr[rpnptr++] = symptr >> 8;
|
|
rpnexpr[rpnptr++] = symptr >> 16;
|
|
rpnexpr[rpnptr++] = symptr >> 24;
|
|
}
|
|
break;
|
|
case RPN_BANK:
|
|
symptr = 0;
|
|
while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0) ;
|
|
symptr = addsymbol(sym_FindSymbol(tzSym));
|
|
rpnexpr[rpnptr++] = RPN_BANK;
|
|
rpnexpr[rpnptr++] = symptr & 0xFF;
|
|
rpnexpr[rpnptr++] = symptr >> 8;
|
|
rpnexpr[rpnptr++] = symptr >> 16;
|
|
rpnexpr[rpnptr++] = symptr >> 24;
|
|
break;
|
|
default:
|
|
rpnexpr[rpnptr++] = rpndata;
|
|
break;
|
|
}
|
|
}
|
|
if ((pPatch->pRPN = (UBYTE *) malloc(rpnptr)) != NULL) {
|
|
memcpy(pPatch->pRPN, rpnexpr, rpnptr);
|
|
pPatch->nRPNSize = rpnptr;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* A quick check to see if we have an initialized section
|
|
*
|
|
*/
|
|
|
|
void checksection(void)
|
|
{
|
|
if (pCurrentSection)
|
|
return;
|
|
else
|
|
fatalerror("Code generation before SECTION directive");
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* A quick check to see if we have an initialized section that can contain
|
|
* this much initialized data
|
|
*
|
|
*/
|
|
|
|
void checkcodesection(SLONG size)
|
|
{
|
|
checksection();
|
|
if ((pCurrentSection->nType == SECT_HOME
|
|
|| pCurrentSection->nType == SECT_CODE)
|
|
&& (pCurrentSection->nPC + size <= MAXSECTIONSIZE)) {
|
|
if (((pCurrentSection->nPC % SECTIONCHUNK) >
|
|
((pCurrentSection->nPC + size) % SECTIONCHUNK))
|
|
&& (pCurrentSection->nType == SECT_HOME
|
|
|| pCurrentSection->nType == SECT_CODE)) {
|
|
if ((pCurrentSection->tData =
|
|
(UBYTE *) realloc(pCurrentSection->tData,
|
|
((pCurrentSection->nPC +
|
|
size) / SECTIONCHUNK +
|
|
1) * SECTIONCHUNK)) != NULL) {
|
|
return;
|
|
} else
|
|
fatalerror
|
|
("Not enough memory to expand section");
|
|
}
|
|
return;
|
|
} else
|
|
fatalerror
|
|
("Section can't contain initialized data or section limit exceeded");
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Write an objectfile
|
|
*
|
|
*/
|
|
|
|
void out_WriteObject(void)
|
|
{
|
|
FILE *f;
|
|
|
|
addexports();
|
|
|
|
if ((f = fopen(tzObjectname, "wb")) != NULL) {
|
|
struct PatchSymbol *pSym;
|
|
struct Section *pSect;
|
|
|
|
fwrite("RGB2", 1, 4, f);
|
|
fputlong(countsymbols(), f);
|
|
fputlong(countsections(), f);
|
|
|
|
pSym = pPatchSymbols;
|
|
while (pSym) {
|
|
writesymbol(pSym->pSymbol, f);
|
|
pSym = pSym->pNext;
|
|
}
|
|
|
|
pSect = pSectionList;
|
|
while (pSect) {
|
|
writesection(pSect, f);
|
|
pSect = pSect->pNext;
|
|
}
|
|
|
|
fclose(f);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Prepare for pass #2
|
|
*
|
|
*/
|
|
|
|
void out_PrepPass2(void)
|
|
{
|
|
struct Section *pSect;
|
|
|
|
pSect = pSectionList;
|
|
while (pSect) {
|
|
pSect->nPC = 0;
|
|
pSect = pSect->pNext;
|
|
}
|
|
pCurrentSection = NULL;
|
|
pSectionStack = NULL;
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Set the objectfilename
|
|
*
|
|
*/
|
|
|
|
void out_SetFileName(char *s)
|
|
{
|
|
strcpy(tzObjectname, s);
|
|
printf("Output filename %s\n", s);
|
|
pSectionList = NULL;
|
|
pCurrentSection = NULL;
|
|
pPatchSymbols = NULL;
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Find a section by name and type. If it doesn't exist, create it
|
|
*
|
|
*/
|
|
|
|
struct Section *out_FindSection(char *pzName, ULONG secttype, SLONG org,
|
|
SLONG bank)
|
|
{
|
|
struct Section *pSect, **ppSect;
|
|
|
|
ppSect = &pSectionList;
|
|
pSect = pSectionList;
|
|
|
|
while (pSect) {
|
|
if (strcmp(pzName, pSect->pzName) == 0) {
|
|
if (secttype == pSect->nType
|
|
&& ((ULONG) org) == pSect->nOrg
|
|
&& ((ULONG) bank) == pSect->nBank) {
|
|
return (pSect);
|
|
} else
|
|
fatalerror
|
|
("Section already exists but with a different type");
|
|
}
|
|
ppSect = &(pSect->pNext);
|
|
pSect = pSect->pNext;
|
|
}
|
|
|
|
if ((*ppSect =
|
|
(pSect =
|
|
(struct Section *)malloc(sizeof(struct Section)))) != NULL) {
|
|
if ((pSect->pzName =
|
|
(char *)malloc(strlen(pzName) + 1)) != NULL) {
|
|
strcpy(pSect->pzName, pzName);
|
|
pSect->nType = secttype;
|
|
pSect->nPC = 0;
|
|
pSect->nOrg = org;
|
|
pSect->nBank = bank;
|
|
pSect->pNext = NULL;
|
|
pSect->pPatches = NULL;
|
|
pPatchSymbols = NULL;
|
|
|
|
if ((pSect->tData =
|
|
(UBYTE *) malloc(SECTIONCHUNK)) != NULL) {
|
|
return (pSect);
|
|
} else
|
|
fatalerror("Not enough memory for section");
|
|
} else
|
|
fatalerror("Not enough memory for sectionname");
|
|
} else
|
|
fatalerror("Not enough memory for section");
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Set the current section
|
|
*
|
|
*/
|
|
|
|
void out_SetCurrentSection(struct Section *pSect)
|
|
{
|
|
pCurrentSection = pSect;
|
|
nPC = pSect->nPC;
|
|
|
|
pPCSymbol->nValue = nPC;
|
|
pPCSymbol->pSection = pCurrentSection;
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Set the current section by name and type
|
|
*
|
|
*/
|
|
|
|
void out_NewSection(char *pzName, ULONG secttype)
|
|
{
|
|
out_SetCurrentSection(out_FindSection(pzName, secttype, -1, -1));
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Set the current section by name and type
|
|
*
|
|
*/
|
|
|
|
void out_NewAbsSection(char *pzName, ULONG secttype, SLONG org, SLONG bank)
|
|
{
|
|
out_SetCurrentSection(out_FindSection(pzName, secttype, org, bank));
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Output an absolute byte
|
|
*
|
|
*/
|
|
|
|
void out_AbsByte(int b)
|
|
{
|
|
checkcodesection(1);
|
|
b &= 0xFF;
|
|
if (nPass == 2)
|
|
pCurrentSection->tData[nPC] = b;
|
|
|
|
pCurrentSection->nPC += 1;
|
|
nPC += 1;
|
|
pPCSymbol->nValue += 1;
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Skip this many bytes
|
|
*
|
|
*/
|
|
|
|
void out_Skip(int skip)
|
|
{
|
|
checksection();
|
|
if ((CurrentOptions.fillchar == -1)
|
|
|| !((pCurrentSection->nType == SECT_HOME)
|
|
|| (pCurrentSection->nType == SECT_CODE))) {
|
|
pCurrentSection->nPC += skip;
|
|
nPC += skip;
|
|
pPCSymbol->nValue += skip;
|
|
} else {
|
|
checkcodesection(skip);
|
|
while (skip--)
|
|
out_AbsByte(CurrentOptions.fillchar);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Output a NULL terminated string (excluding the NULL-character)
|
|
*
|
|
*/
|
|
|
|
void out_String(char *s)
|
|
{
|
|
checkcodesection(strlen(s));
|
|
while (*s)
|
|
out_AbsByte(*s++);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Output a relocatable byte. Checking will be done to see if it
|
|
* is an absolute value in disguise.
|
|
*
|
|
*/
|
|
|
|
void out_RelByte(struct Expression *expr)
|
|
{
|
|
checkcodesection(1);
|
|
if (rpn_isReloc(expr)) {
|
|
if (nPass == 2) {
|
|
pCurrentSection->tData[nPC] = 0;
|
|
createpatch(PATCH_BYTE, expr);
|
|
}
|
|
pCurrentSection->nPC += 1;
|
|
nPC += 1;
|
|
pPCSymbol->nValue += 1;
|
|
} else
|
|
out_AbsByte(expr->nVal);
|
|
|
|
rpn_Reset(expr);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Output an absolute word
|
|
*
|
|
*/
|
|
|
|
void out_AbsWord(int b)
|
|
{
|
|
checkcodesection(2);
|
|
b &= 0xFFFF;
|
|
if (nPass == 2) {
|
|
if (CurrentOptions.endian == ASM_LITTLE_ENDIAN) {
|
|
pCurrentSection->tData[nPC] = b & 0xFF;
|
|
pCurrentSection->tData[nPC + 1] = b >> 8;
|
|
} else {
|
|
// Assume big endian
|
|
pCurrentSection->tData[nPC] = b >> 8;
|
|
pCurrentSection->tData[nPC + 1] = b & 0xFF;
|
|
}
|
|
}
|
|
pCurrentSection->nPC += 2;
|
|
nPC += 2;
|
|
pPCSymbol->nValue += 2;
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Output a relocatable word. Checking will be done to see if
|
|
* is an absolute value in disguise.
|
|
*
|
|
*/
|
|
|
|
void out_RelWord(struct Expression *expr)
|
|
{
|
|
ULONG b;
|
|
|
|
checkcodesection(2);
|
|
b = expr->nVal & 0xFFFF;
|
|
if (rpn_isReloc(expr)) {
|
|
if (nPass == 2) {
|
|
if (CurrentOptions.endian == ASM_LITTLE_ENDIAN) {
|
|
pCurrentSection->tData[nPC] = b & 0xFF;
|
|
pCurrentSection->tData[nPC + 1] = b >> 8;
|
|
createpatch(PATCH_WORD_L, expr);
|
|
} else {
|
|
// Assume big endian
|
|
pCurrentSection->tData[nPC] = b >> 8;
|
|
pCurrentSection->tData[nPC + 1] = b & 0xFF;
|
|
createpatch(PATCH_WORD_B, expr);
|
|
}
|
|
}
|
|
pCurrentSection->nPC += 2;
|
|
nPC += 2;
|
|
pPCSymbol->nValue += 2;
|
|
} else
|
|
out_AbsWord(expr->nVal);
|
|
rpn_Reset(expr);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Output an absolute longword
|
|
*
|
|
*/
|
|
|
|
void out_AbsLong(SLONG b)
|
|
{
|
|
checkcodesection(sizeof(SLONG));
|
|
if (nPass == 2) {
|
|
if (CurrentOptions.endian == ASM_LITTLE_ENDIAN) {
|
|
pCurrentSection->tData[nPC] = b & 0xFF;
|
|
pCurrentSection->tData[nPC + 1] = b >> 8;
|
|
pCurrentSection->tData[nPC + 2] = b >> 16;
|
|
pCurrentSection->tData[nPC + 3] = b >> 24;
|
|
} else {
|
|
// Assume big endian
|
|
pCurrentSection->tData[nPC] = b >> 24;
|
|
pCurrentSection->tData[nPC + 1] = b >> 16;
|
|
pCurrentSection->tData[nPC + 2] = b >> 8;
|
|
pCurrentSection->tData[nPC + 3] = b & 0xFF;
|
|
}
|
|
}
|
|
pCurrentSection->nPC += 4;
|
|
nPC += 4;
|
|
pPCSymbol->nValue += 4;
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Output a relocatable longword. Checking will be done to see if
|
|
* is an absolute value in disguise.
|
|
*
|
|
*/
|
|
|
|
void out_RelLong(struct Expression *expr)
|
|
{
|
|
SLONG b;
|
|
|
|
checkcodesection(4);
|
|
b = expr->nVal;
|
|
if (rpn_isReloc(expr)) {
|
|
if (nPass == 2) {
|
|
if (CurrentOptions.endian == ASM_LITTLE_ENDIAN) {
|
|
pCurrentSection->tData[nPC] = b & 0xFF;
|
|
pCurrentSection->tData[nPC + 1] = b >> 8;
|
|
pCurrentSection->tData[nPC + 2] = b >> 16;
|
|
pCurrentSection->tData[nPC + 3] = b >> 24;
|
|
createpatch(PATCH_LONG_L, expr);
|
|
} else {
|
|
// Assume big endian
|
|
pCurrentSection->tData[nPC] = b >> 24;
|
|
pCurrentSection->tData[nPC + 1] = b >> 16;
|
|
pCurrentSection->tData[nPC + 2] = b >> 8;
|
|
pCurrentSection->tData[nPC + 3] = b & 0xFF;
|
|
createpatch(PATCH_LONG_B, expr);
|
|
}
|
|
}
|
|
pCurrentSection->nPC += 4;
|
|
nPC += 4;
|
|
pPCSymbol->nValue += 4;
|
|
} else
|
|
out_AbsLong(expr->nVal);
|
|
rpn_Reset(expr);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Output a PC-relative byte
|
|
*
|
|
*/
|
|
|
|
void out_PCRelByte(struct Expression *expr)
|
|
{
|
|
SLONG b = expr->nVal;
|
|
|
|
checkcodesection(1);
|
|
b = (b & 0xFFFF) - (nPC + 1);
|
|
if (nPass == 2 && (b < -128 || b > 127))
|
|
yyerror("PC-relative value must be 8-bit");
|
|
|
|
out_AbsByte(b);
|
|
rpn_Reset(expr);
|
|
}
|
|
|
|
/*
|
|
* RGBAsm - OUTPUT.C - Outputs an objectfile
|
|
*
|
|
* Output a binary file
|
|
*
|
|
*/
|
|
|
|
void out_BinaryFile(char *s)
|
|
{
|
|
FILE *f;
|
|
|
|
fstk_FindFile(s);
|
|
|
|
if ((f = fopen(s, "rb")) != NULL) {
|
|
SLONG fsize;
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
fsize = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
checkcodesection(fsize);
|
|
|
|
if (nPass == 2) {
|
|
SLONG dest = nPC;
|
|
SLONG todo = fsize;
|
|
|
|
while (todo--)
|
|
pCurrentSection->tData[dest++] = fgetc(f);
|
|
}
|
|
|
|
pCurrentSection->nPC += fsize;
|
|
nPC += fsize;
|
|
pPCSymbol->nValue += fsize;
|
|
fclose(f);
|
|
} else
|
|
fatalerror("File not found");
|
|
}
|
|
|
|
void out_BinaryFileSlice(char *s, SLONG start_pos, SLONG length)
|
|
{
|
|
FILE *f;
|
|
|
|
if (start_pos < 0)
|
|
fatalerror("Start position cannot be negative");
|
|
|
|
if (length < 0)
|
|
fatalerror("Number of bytes to read must be greater than zero");
|
|
|
|
fstk_FindFile (s);
|
|
|
|
if( (f=fopen(s,"rb"))!=NULL )
|
|
{
|
|
SLONG fsize;
|
|
|
|
fseek (f, 0, SEEK_END);
|
|
fsize = ftell (f);
|
|
|
|
if (start_pos >= fsize)
|
|
fatalerror("Specified start position is greater than length of file");
|
|
|
|
if( (start_pos + length) > fsize )
|
|
fatalerror("Specified range in INCBIN is out of bounds");
|
|
|
|
fseek (f, start_pos, SEEK_SET);
|
|
|
|
checkcodesection (length);
|
|
|
|
if (nPass == 2)
|
|
{
|
|
SLONG dest = nPC;
|
|
SLONG todo = length;
|
|
|
|
while (todo--)
|
|
pCurrentSection->tData[dest++] = fgetc (f);
|
|
}
|
|
|
|
pCurrentSection->nPC += length;
|
|
nPC += length;
|
|
pPCSymbol->nValue += length;
|
|
|
|
fclose (f);
|
|
}
|
|
else
|
|
fatalerror ("File not found");
|
|
}
|
|
|