mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-23 11:32:07 +00:00
The linker script now allows you to assign a section with the same attributes as in the source. To do this, I've removed a check from AssignSectionAddressAndBankByName that would never be triggered, due to that condition being checked before. Shouldn't this and IsSectionSameTypeBankAndAttrs be condensed into a single function?
238 lines
6.2 KiB
C
238 lines
6.2 KiB
C
/*
|
|
* This file is part of RGBDS.
|
|
*
|
|
* Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "extern/err.h"
|
|
|
|
#include "link/assign.h"
|
|
#include "link/mylink.h"
|
|
|
|
static struct {
|
|
uint32_t address; /* current address to write sections to */
|
|
uint32_t top_address; /* not inclusive */
|
|
enum eSectionType type;
|
|
} bank[BANK_INDEX_MAX];
|
|
|
|
static int32_t current_bank = -1; /* Bank as seen by the bank array */
|
|
static int32_t current_real_bank = -1; /* bank as seen by the GB */
|
|
|
|
/* Current section attributes */
|
|
static int32_t fix_org = -1;
|
|
static int32_t fix_align = 1;
|
|
|
|
void script_InitSections(void)
|
|
{
|
|
int32_t i;
|
|
|
|
for (i = 0; i < BANK_INDEX_MAX; i++) {
|
|
if (BankIndexIsROM0(i)) {
|
|
/* ROM0 bank */
|
|
bank[i].address = 0x0000;
|
|
if (options & OPT_TINY)
|
|
bank[i].top_address = 0x8000;
|
|
else
|
|
bank[i].top_address = 0x4000;
|
|
bank[i].type = SECT_ROM0;
|
|
} else if (BankIndexIsROMX(i)) {
|
|
/* Swappable ROM bank */
|
|
bank[i].address = 0x4000;
|
|
bank[i].top_address = 0x8000;
|
|
bank[i].type = SECT_ROMX;
|
|
} else if (BankIndexIsWRAM0(i)) {
|
|
/* WRAM */
|
|
bank[i].address = 0xC000;
|
|
if (options & OPT_CONTWRAM)
|
|
bank[i].top_address = 0xE000;
|
|
else
|
|
bank[i].top_address = 0xD000;
|
|
bank[i].type = SECT_WRAM0;
|
|
} else if (BankIndexIsSRAM(i)) {
|
|
/* Swappable SRAM bank */
|
|
bank[i].address = 0xA000;
|
|
bank[i].top_address = 0xC000;
|
|
bank[i].type = SECT_SRAM;
|
|
} else if (BankIndexIsWRAMX(i)) {
|
|
/* Swappable WRAM bank */
|
|
bank[i].address = 0xD000;
|
|
bank[i].top_address = 0xE000;
|
|
bank[i].type = SECT_WRAMX;
|
|
} else if (BankIndexIsVRAM(i)) {
|
|
/* Swappable VRAM bank */
|
|
bank[i].address = 0x8000;
|
|
bank[i].type = SECT_VRAM;
|
|
if (options & OPT_DMG_MODE && i != BANK_INDEX_VRAM) {
|
|
/* In DMG the only available bank is bank 0. */
|
|
bank[i].top_address = 0x8000;
|
|
} else {
|
|
bank[i].top_address = 0xA000;
|
|
}
|
|
} else if (BankIndexIsOAM(i)) {
|
|
/* OAM */
|
|
bank[i].address = 0xFE00;
|
|
bank[i].top_address = 0xFEA0;
|
|
bank[i].type = SECT_OAM;
|
|
} else if (BankIndexIsHRAM(i)) {
|
|
/* HRAM */
|
|
bank[i].address = 0xFF80;
|
|
bank[i].top_address = 0xFFFF;
|
|
bank[i].type = SECT_HRAM;
|
|
} else {
|
|
errx(1, "%s: Unknown bank type %d", __func__, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void script_SetCurrentSectionType(const char *type, uint32_t bank_num)
|
|
{
|
|
if (strcmp(type, "ROM0") == 0) {
|
|
if (bank_num != 0)
|
|
errx(1, "Trying to assign a bank number to ROM0.\n");
|
|
current_bank = BANK_INDEX_ROM0;
|
|
current_real_bank = 0;
|
|
return;
|
|
} else if (strcmp(type, "ROMX") == 0) {
|
|
if (bank_num == 0)
|
|
errx(1, "ROMX index can't be 0.\n");
|
|
if (bank_num > BANK_COUNT_ROMX) {
|
|
errx(1, "ROMX index too big (%d > %d).\n", bank_num,
|
|
BANK_COUNT_ROMX);
|
|
}
|
|
current_bank = BANK_INDEX_ROMX + bank_num - 1;
|
|
current_real_bank = bank_num;
|
|
return;
|
|
} else if (strcmp(type, "VRAM") == 0) {
|
|
if (bank_num >= BANK_COUNT_VRAM) {
|
|
errx(1, "VRAM index too big (%d >= %d).\n", bank_num,
|
|
BANK_COUNT_VRAM);
|
|
}
|
|
current_bank = BANK_INDEX_VRAM + bank_num;
|
|
current_real_bank = bank_num;
|
|
return;
|
|
} else if (strcmp(type, "WRAM0") == 0) {
|
|
if (bank_num != 0)
|
|
errx(1, "Trying to assign a bank number to WRAM0.\n");
|
|
|
|
current_bank = BANK_INDEX_WRAM0;
|
|
current_real_bank = 0;
|
|
return;
|
|
} else if (strcmp(type, "WRAMX") == 0) {
|
|
if (bank_num == 0)
|
|
errx(1, "WRAMX index can't be 0.\n");
|
|
if (bank_num > BANK_COUNT_WRAMX) {
|
|
errx(1, "WRAMX index too big (%d > %d).\n", bank_num,
|
|
BANK_COUNT_WRAMX);
|
|
}
|
|
current_bank = BANK_INDEX_WRAMX + bank_num - 1;
|
|
current_real_bank = bank_num;
|
|
return;
|
|
} else if (strcmp(type, "SRAM") == 0) {
|
|
if (bank_num >= BANK_COUNT_SRAM) {
|
|
errx(1, "SRAM index too big (%d >= %d).\n", bank_num,
|
|
BANK_COUNT_SRAM);
|
|
}
|
|
current_bank = BANK_INDEX_SRAM + bank_num;
|
|
current_real_bank = bank_num;
|
|
return;
|
|
} else if (strcmp(type, "OAM") == 0) {
|
|
if (bank_num != 0) {
|
|
errx(1, "%s: Trying to assign a bank number to OAM.\n",
|
|
__func__);
|
|
}
|
|
current_bank = BANK_INDEX_OAM;
|
|
current_real_bank = 0;
|
|
return;
|
|
} else if (strcmp(type, "HRAM") == 0) {
|
|
if (bank_num != 0) {
|
|
errx(1, "%s: Trying to assign a bank number to HRAM.\n",
|
|
__func__);
|
|
}
|
|
current_bank = BANK_INDEX_HRAM;
|
|
current_real_bank = 0;
|
|
return;
|
|
}
|
|
|
|
errx(1, "%s: Unknown section type \"%s\".\n", __func__, type);
|
|
}
|
|
|
|
void script_SetAddress(uint32_t addr)
|
|
{
|
|
if (current_bank == -1)
|
|
errx(1, "Trying to set an address without assigned bank\n");
|
|
|
|
/* Make sure that we don't go back. */
|
|
if (bank[current_bank].address > addr) {
|
|
errx(1, "Trying to go to a previous address (0x%04X to 0x%04X)\n",
|
|
bank[current_bank].address, addr);
|
|
}
|
|
|
|
bank[current_bank].address = addr;
|
|
|
|
/* Make sure we don't overflow */
|
|
if (bank[current_bank].address >= bank[current_bank].top_address) {
|
|
errx(1, "Bank overflowed (0x%04X >= 0x%04X)\n",
|
|
bank[current_bank].address,
|
|
bank[current_bank].top_address);
|
|
}
|
|
|
|
fix_org = addr;
|
|
}
|
|
|
|
void script_SetAlignment(uint32_t alignment)
|
|
{
|
|
if (current_bank == -1)
|
|
errx(1, "Trying to set an alignment without assigned bank\n");
|
|
|
|
if (alignment > 15)
|
|
errx(1, "Trying to set an alignment too big: %d\n", alignment);
|
|
|
|
uint32_t size = 1 << alignment;
|
|
uint32_t mask = size - 1;
|
|
|
|
if (bank[current_bank].address & mask) {
|
|
bank[current_bank].address &= ~mask;
|
|
bank[current_bank].address += size;
|
|
}
|
|
|
|
/* Make sure we don't overflow */
|
|
if (bank[current_bank].address >= bank[current_bank].top_address) {
|
|
errx(1, "Bank overflowed (0x%04X >= 0x%04X)\n",
|
|
bank[current_bank].address,
|
|
bank[current_bank].top_address);
|
|
}
|
|
|
|
fix_align = size;
|
|
}
|
|
|
|
void script_OutputSection(const char *section_name)
|
|
{
|
|
if (current_bank == -1) {
|
|
errx(1, "Trying to place section \"%s\" without assigned bank\n",
|
|
section_name);
|
|
}
|
|
|
|
if (!IsSectionSameTypeBankAndAttrs(section_name,
|
|
bank[current_bank].type,
|
|
current_real_bank,
|
|
fix_org,
|
|
fix_align)) {
|
|
errx(1, "Different attributes for \"%s\" in source and linkerscript\n",
|
|
section_name);
|
|
}
|
|
|
|
/* Move section to its place. */
|
|
bank[current_bank].address +=
|
|
AssignSectionAddressAndBankByName(section_name,
|
|
bank[current_bank].address,
|
|
current_real_bank);
|
|
|
|
fix_org = -1;
|
|
fix_align = 1;
|
|
}
|