shithub: rgbds

ref: ab47428c0e3e9fc68621a20f42bb6e7372fa3358
dir: /src/link/assign.c/

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

#include "link/mylink.h"
#include "link/main.h"
#include "link/symbol.h"
#include "link/assign.h"

struct sFreeArea {
	SLONG nOrg;
	SLONG nSize;
	struct sFreeArea *pPrev, *pNext;
};

struct sFreeArea *BankFree[MAXBANKS];
SLONG MaxAvail[MAXBANKS];
SLONG MaxBankUsed;
SLONG MaxVBankUsed;

#define DOMAXBANK(x)	{if( (x)>MaxBankUsed ) MaxBankUsed=(x);}
#define DOMAXVBANK(x)	{if( (x)>MaxVBankUsed ) MaxVBankUsed=(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 {
						fprintf(stderr,
						    "Out of memory!\n");
						exit(1);
					}
				}
			}
		}
		ppArea = &(pArea->pNext);
		pArea = *ppArea;
	}

	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_AllocAbsCODEAnyBank(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)
{
	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_AllocVRAMAnyBank(SLONG size)
{
	SLONG i, org;

	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_AllocCODEAnyBank(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 *
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 *
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
AssignVRAMSections(void)
{
	struct sSection *pSection;

	while ((pSection = FindLargestVRAM())) {
		SLONG org;

		if ((org = area_AllocVRAMAnyBank(pSection->nByteSize)) != -1) {
			pSection->nOrg = org & 0xFFFF;
			pSection->nBank = org >> 16;
			pSection->oAssigned = 1;
			DOMAXVBANK(pSection->nBank);
		} else {
			fprintf(stderr,
			    "Unable to place VRAM section anywhere\n");
			exit(1);
		}
	}
}

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 {
			fprintf(stderr,
			    "Unable to place CODE section anywhere\n");
			exit(1);
		}
	}
}

void 
AssignSections(void)
{
	SLONG i;
	struct sSection *pSection;

	MaxBankUsed = 0;

	/*
	 * Initialize the memory areas
	 *
	 */

	for (i = 0; i < MAXBANKS; i += 1) {
		BankFree[i] = malloc(sizeof *BankFree[i]);

		if (!BankFree[i]) {
			fprintf(stderr, "Out of memory!\n");
			exit(1);
		}

		if (i == 0) {
			/* 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) {
			/* Swappable ROM bank */
			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) {
			/* WRAM */
			BankFree[i]->nOrg = 0xC000;
			BankFree[i]->nSize = 0x2000;
			MaxAvail[i] = 0x2000;
		} else if (i == BANK_VRAM || i == BANK_VRAM + 1) {
			/* 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;
		}
		BankFree[i]->pPrev = NULL;
		BankFree[i]->pNext = NULL;
	}

	/*
	 * 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) {
					fprintf(stderr,
					    "Unable to load fixed BSS section "
					    "at $%lX\n", pSection->nOrg);
					exit(1);
				}
				pSection->oAssigned = 1;
				pSection->nBank = BANK_BSS;
				break;
			case SECT_HRAM:
				if (area_AllocAbs
				    (&BankFree[BANK_HRAM], pSection->nOrg,
					pSection->nByteSize) != pSection->nOrg) {
					fprintf(stderr, "Unable to load fixed "
					    "HRAM section at $%lX\n",
					    pSection->nOrg);
					exit(1);
				}
				pSection->oAssigned = 1;
				pSection->nBank = BANK_HRAM;
				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) {
								fprintf(stderr,
"Unable to load fixed VRAM section at $%lX in bank $%02lX\n", pSection->nOrg, pSection->nBank - BANK_VRAM);
								exit(1);
							}
							DOMAXVBANK(pSection->
							    nBank);
							pSection->oAssigned = 1;
						} else {
							fprintf(stderr,
"Unable to load fixed VRAM section at $%lX in bank $%02lX\n", pSection->nOrg, pSection->nBank - BANK_VRAM);
							exit(1);
						}
					}
				}
				break;
			case SECT_HOME:
				if (area_AllocAbs
				    (&BankFree[BANK_HOME], pSection->nOrg,
					pSection->nByteSize) != pSection->nOrg) {
					fprintf(stderr, "Unable to load fixed "
					    "HOME section at $%lX\n",
					    pSection->nOrg);
					exit(1);
				}
				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 <= 511) {
							if (area_AllocAbs
							    (&BankFree
								[pSection->nBank],
								pSection->nOrg,
								pSection->
								nByteSize) !=
							    pSection->nOrg) {
								fprintf(stderr, "Unable to load fixed CODE/DATA section at $%lX in bank $%02lX\n", pSection->nOrg, pSection->nBank);
								exit(1);
							}
							DOMAXBANK(pSection->
							    nBank);
							pSection->oAssigned = 1;
						} else {
							fprintf(stderr, "Unable to load fixed CODE/DATA section at $%lX in bank $%02lX\n", pSection->nOrg, pSection->nBank);
							exit(1);
						}
					}

				}
				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 <= 511) {
				if ((pSection->nOrg =
					area_Alloc(&BankFree[pSection->nBank],
					    pSection->nByteSize)) == -1) {
					fprintf(stderr, "Unable to load fixed CODE/DATA section into bank $%02lX\n", pSection->nBank);
					exit(1);
				}
				pSection->oAssigned = 1;
				DOMAXBANK(pSection->nBank);
			} else {
				fprintf(stderr, "Unable to load fixed CODE/DATA section into bank $%02lX\n", pSection->nBank);
				exit(1);
			}
		} 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) {
					fprintf(stderr, "Unable to load fixed VRAM section into bank $%02lX\n", pSection->nBank - BANK_VRAM);
					exit(1);
				}
				pSection->oAssigned = 1;
				DOMAXBANK(pSection->nBank);
			} else {
				fprintf(stderr, "Unable to load fixed VRAM section into bank $%02lX\n", pSection->nBank - BANK_VRAM);
				exit(1);
			}
		}
		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) {
				fprintf(stderr, "Unable to load fixed CODE/DATA section at $%lX into any bank\n", pSection->nOrg);
				exit(1);
			}
			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) {
				fprintf(stderr, "Unable to load fixed VRAM section at $%lX into any bank\n", pSection->nOrg);
				exit(1);
			}
			pSection->oAssigned = 1;
			DOMAXVBANK(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) {
					fprintf(stderr, "BSS section too large\n");
					exit(1);
				}
				pSection->nBank = BANK_BSS;
				pSection->oAssigned = 1;
				break;
			case SECT_HRAM:
				if ((pSection->nOrg =
					area_Alloc(&BankFree[BANK_HRAM],
					    pSection->nByteSize)) == -1) {
					fprintf(stderr, "HRAM section too large\n");
					exit(1);
				}
				pSection->nBank = BANK_HRAM;
				pSection->oAssigned = 1;
				break;
			case SECT_VRAM:
				break;
			case SECT_HOME:
				if ((pSection->nOrg =
					area_Alloc(&BankFree[BANK_HOME],
					    pSection->nByteSize)) == -1) {
					fprintf(stderr, "HOME section too large\n");
					exit(1);
				}
				pSection->nBank = BANK_HOME;
				pSection->oAssigned = 1;
				break;
			case SECT_CODE:
				break;
			default:
				fprintf(stderr, "(INTERNAL) Unknown section type!\n");
				exit(1);
				break;
			}
		}
		pSection = pSection->pNext;
	}

	AssignCodeSections();
	AssignVRAMSections();
}

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;
	}
}