shithub: rgbds

ref: e7a8bb1140a6949b2dce92e613a54e7a40ebf8c8
dir: /src/link/patch.c/

View raw version
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "extern/err.h"
#include "link/assign.h"
#include "link/mylink.h"
#include "link/symbol.h"
#include "link/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;
	}
	errx(1, "*INTERNAL* UNKNOWN SYMBOL TYPE");
}

SLONG
getsymbank(SLONG symid)
{
	SLONG nBank;

	switch (pCurrentSection->tSymbols[symid]->Type) {
	case SYM_IMPORT:
		nBank = sym_GetBank(pCurrentSection->tSymbols[symid]->pzName);
		break;
	case SYM_EXPORT:
	case SYM_LOCAL:
		nBank = pCurrentSection->tSymbols[symid]->pSection->nBank;
		break;
	default:
		errx(1, "*INTERNAL* UNKNOWN SYMBOL TYPE");
	}

	if (nBank == BANK_WRAM0 || nBank == BANK_ROM0 || nBank == BANK_OAM ||
			nBank == BANK_HRAM) {
		return 0;
	} else if (nBank >= BANK_WRAMX && nBank < (BANK_WRAMX + BANK_COUNT_WRAMX)) {
		return nBank - BANK_WRAMX + 1;
	} else if (nBank >= BANK_VRAM && nBank < (BANK_VRAM + BANK_COUNT_VRAM)) {
		return nBank - BANK_VRAM;
	} else if (nBank >= BANK_SRAM && nBank < (BANK_SRAM + BANK_COUNT_SRAM)) {
		return nBank - BANK_SRAM;
	}

	return nBank;
}

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) {
				errx(1,
				    "%s(%ld) : Value must be in the HRAM area",
				    pPatch->pzFilename, pPatch->nLineNo);
			}
			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;
		}
	}
	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 {
					errx(1,
					    "%s(%ld) : Value must be 8-bit",
					    pPatch->pzFilename,
					    pPatch->nLineNo);
				}
				break;
			case PATCH_WORD_L:
				if (t >= -32768 && t <= 65535) {
					t &= 0xFFFF;
					pSect->pData[pPatch->nOffset] =
						t & 0xFF;
					pSect->pData[pPatch->nOffset + 1] =
						(t >> 8) & 0xFF;
				} else {
					errx(1,
					    "%s(%ld) : Value must be 16-bit",
					    pPatch->pzFilename,
					    pPatch->nLineNo);
				}
				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;
			}

			pPatch = pPatch->pNext;
		}

		pSect = pSect->pNext;
	}
}