Last active
April 2, 2019 19:39
-
-
Save Madsy/80f6410d6200194abb54b51967046c74 to your computer and use it in GitHub Desktop.
SNES 'lorom' toolchain.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
PREFIX=$(HOME)/snes-toolchain | |
#clone binutils development branch | |
git clone git://sourceware.org/git/binutils-gdb.git binutils-gdb | |
cd binutils-gdb | |
# Checkout a *very* old binutils commit from 2005, as gas support for the coff-w65 target was discontinued a long time ago. | |
# This version is the best one I found so far. | |
git checkout 0fdc72dad81fc7f32b898cb408da0300667f728b | |
# Remove gdb directory as gdb does not support the coff-w65 BFD / target. It probably did before | |
# this commit, but become broken somewhere down the line | |
# autoconf will just ignore the missing project directory and not recurse | |
rm -rf ./gdb | |
# --program-prefix added due to bug where host and target are not added as prefix | |
../binutils-gdb/configure --build=x86_64-pc-linux-gnu --host=x86_64-pc-linux-gnu --target=w65-none-system \ | |
--enable-plugins --enable-shared --disable-werror --with-system-zlib --prefix=$(PREFIX) \ | |
--disable-gdb --program-prefix=w65-none-system- | |
#Workaround: Systems nowadays have a too new version of makeinfo to generate the documentation, which breaks the install step | |
#Overriding $(MAKEINFO) to true at least lets us complete the build and install. | |
make -j4 install MAKEINFO=true | |
exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Copyright 2017 Mads Elvheim / 'Madsy' | |
Redistribution and use in source and binary forms, with or without modification, are permitted provided | |
that the following conditions are met: | |
1. Redistributions of source code must retain the above copyright notice, this list of conditions | |
and the following disclaimer. | |
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions | |
and the following disclaimer in the documentation and/or other materials provided with the distribution. | |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
/* | |
============================== SNES 'lorom' linker script for GNU Binutils =========================== | |
General information: | |
====================================================================================================== | |
bank0: (rom address 0x000000, snes address 0x8000) <--- last 64 bytes here contains the SNES header. | |
bank1: (rom address 0x008000, snes address 0x18000) | |
bank2: (rom address 0x010000, snes address 0x28000) | |
bank3: (rom address 0x018000, snes address 0x38000) | |
bank4: (rom address 0x020000, snes address 0x48000) | |
... | |
And so on, you get the drift. | |
The number of mirrored ROM address regions depends on which SNES game's physical pinouts, | |
the ROM size, the cartridge memory controller and whether the cart has SRAM or not. To get the behavior you want | |
when testing in an emulator, it might be good idea to fill the SNES header with data from another | |
'lorom' game to pretend that your ROM image is an existing game the emulator knows about. | |
To fill the SNES header with information, look for the _snesheader label in "init.s". | |
Either hardcode the values, or use an external tool to update the header after the linking step. | |
====================================================================================================== | |
Usage of the linker script: | |
====================================================================================================== | |
The ROM image is split into 32k memory regions in order to correct for the SNES' 'lowrom' memory mapping. | |
The regions are tightly packed in the image, while the SNES only sees the ROM image mapped to the upper | |
32KiB in each of its 65k banks from 0x00 to 0x3F. Access the higher banks to get a continuous region of ROM. | |
The memory region setup lets you put read-only data and code exactly in the bank you want. | |
For example, to put code into bank 0x00, put your code into the .text0 section and data into .rodata0 section. | |
To put code into bank 0x04, put your code and data into the .text4 and .rodata4 sections, and so on. | |
For brevity, only output sections for banks 0x00 to 0x04 is defined, which is usually enough. To add more, | |
simple follow the same pattern. | |
*/ | |
OUTPUT_FORMAT("coff-w65") | |
OUTPUT_ARCH(w65) | |
SEARCH_DIR(.) | |
BANK_SIZE = 32k; | |
SNES_HEADER_SIZE = 64; | |
MEMORY | |
{ | |
wram (rw) : ORIGIN = 0x000000, LENGTH = 8k | |
rom_bank_00 (rx) : ORIGIN = 0x008000, LENGTH = (32k - 64) | |
header_bank (rx) : ORIGIN = 0x00FFC0, LENGTH = 64 | |
rom_bank_01 (rx) : ORIGIN = 0x018000, LENGTH = 32k | |
rom_bank_02 (rx) : ORIGIN = 0x028000, LENGTH = 32k | |
rom_bank_03 (rx) : ORIGIN = 0x038000, LENGTH = 32k /* this is the end of a 1 MBit cart */ | |
rom_bank_04 (rx) : ORIGIN = 0x048000, LENGTH = 32k | |
rom_bank_05 (rx) : ORIGIN = 0x058000, LENGTH = 32k | |
rom_bank_06 (rx) : ORIGIN = 0x068000, LENGTH = 32k | |
rom_bank_07 (rx) : ORIGIN = 0x078000, LENGTH = 32k /* this is the end of a 2 MBit cart */ | |
rom_bank_08 (rx) : ORIGIN = 0x088000, LENGTH = 32k | |
rom_bank_09 (rx) : ORIGIN = 0x098000, LENGTH = 32k | |
rom_bank_0A (rx) : ORIGIN = 0x0A8000, LENGTH = 32k | |
rom_bank_0B (rx) : ORIGIN = 0x0B8000, LENGTH = 32k | |
rom_bank_0C (rx) : ORIGIN = 0x0C8000, LENGTH = 32k | |
rom_bank_0D (rx) : ORIGIN = 0x0D8000, LENGTH = 32k | |
rom_bank_0E (rx) : ORIGIN = 0x0E8000, LENGTH = 32k | |
rom_bank_0F (rx) : ORIGIN = 0x0F8000, LENGTH = 32k /* this is the end of a 4 MBit cart */ | |
rom_bank_10 (rx) : ORIGIN = 0x108000, LENGTH = 32k | |
rom_bank_11 (rx) : ORIGIN = 0x118000, LENGTH = 32k | |
rom_bank_12 (rx) : ORIGIN = 0x128000, LENGTH = 32k | |
rom_bank_13 (rx) : ORIGIN = 0x138000, LENGTH = 32k | |
rom_bank_14 (rx) : ORIGIN = 0x148000, LENGTH = 32k | |
rom_bank_15 (rx) : ORIGIN = 0x158000, LENGTH = 32k | |
rom_bank_16 (rx) : ORIGIN = 0x168000, LENGTH = 32k | |
rom_bank_17 (rx) : ORIGIN = 0x178000, LENGTH = 32k | |
rom_bank_18 (rx) : ORIGIN = 0x188000, LENGTH = 32k | |
rom_bank_19 (rx) : ORIGIN = 0x198000, LENGTH = 32k | |
rom_bank_1A (rx) : ORIGIN = 0x1A8000, LENGTH = 32k | |
rom_bank_1B (rx) : ORIGIN = 0x1B8000, LENGTH = 32k | |
rom_bank_1C (rx) : ORIGIN = 0x1C8000, LENGTH = 32k | |
rom_bank_1D (rx) : ORIGIN = 0x1D8000, LENGTH = 32k | |
rom_bank_1E (rx) : ORIGIN = 0x1E8000, LENGTH = 32k | |
rom_bank_1F (rx) : ORIGIN = 0x1F8000, LENGTH = 32k /* this is the end of a 8 MBit cart */ | |
rom_bank_20 (rx) : ORIGIN = 0x208000, LENGTH = 32k | |
rom_bank_21 (rx) : ORIGIN = 0x218000, LENGTH = 32k | |
rom_bank_22 (rx) : ORIGIN = 0x228000, LENGTH = 32k | |
rom_bank_23 (rx) : ORIGIN = 0x238000, LENGTH = 32k | |
rom_bank_24 (rx) : ORIGIN = 0x248000, LENGTH = 32k | |
rom_bank_25 (rx) : ORIGIN = 0x258000, LENGTH = 32k | |
rom_bank_26 (rx) : ORIGIN = 0x268000, LENGTH = 32k | |
rom_bank_27 (rx) : ORIGIN = 0x278000, LENGTH = 32k | |
rom_bank_28 (rx) : ORIGIN = 0x288000, LENGTH = 32k | |
rom_bank_29 (rx) : ORIGIN = 0x298000, LENGTH = 32k | |
rom_bank_2A (rx) : ORIGIN = 0x2A8000, LENGTH = 32k | |
rom_bank_2B (rx) : ORIGIN = 0x2B8000, LENGTH = 32k | |
rom_bank_2C (rx) : ORIGIN = 0x2C8000, LENGTH = 32k | |
rom_bank_2D (rx) : ORIGIN = 0x2D8000, LENGTH = 32k | |
rom_bank_2E (rx) : ORIGIN = 0x2E8000, LENGTH = 32k | |
rom_bank_2F (rx) : ORIGIN = 0x2F8000, LENGTH = 32k | |
rom_bank_30 (rx) : ORIGIN = 0x308000, LENGTH = 32k | |
rom_bank_31 (rx) : ORIGIN = 0x318000, LENGTH = 32k | |
rom_bank_32 (rx) : ORIGIN = 0x328000, LENGTH = 32k | |
rom_bank_33 (rx) : ORIGIN = 0x338000, LENGTH = 32k | |
rom_bank_34 (rx) : ORIGIN = 0x348000, LENGTH = 32k | |
rom_bank_35 (rx) : ORIGIN = 0x358000, LENGTH = 32k | |
rom_bank_36 (rx) : ORIGIN = 0x368000, LENGTH = 32k | |
rom_bank_37 (rx) : ORIGIN = 0x378000, LENGTH = 32k | |
rom_bank_38 (rx) : ORIGIN = 0x388000, LENGTH = 32k | |
rom_bank_39 (rx) : ORIGIN = 0x398000, LENGTH = 32k | |
rom_bank_3A (rx) : ORIGIN = 0x3A8000, LENGTH = 32k | |
rom_bank_3B (rx) : ORIGIN = 0x3B8000, LENGTH = 32k | |
rom_bank_3C (rx) : ORIGIN = 0x3C8000, LENGTH = 32k | |
rom_bank_3D (rx) : ORIGIN = 0x3D8000, LENGTH = 32k | |
rom_bank_3E (rx) : ORIGIN = 0x3E8000, LENGTH = 32k | |
rom_bank_3F (rx) : ORIGIN = 0x3F8000, LENGTH = 32k /* this is the end of a 16 MBit cart */ | |
} | |
SECTIONS | |
{ | |
.bank0 : | |
{ | |
KEEP(*(.vectors .vectors.*)) | |
*(.text0 .text0.*) | |
*(.rodata0 .rodata0.*) | |
/* BUG WORKAROUND. THE FOLLOWING POSITION JUMP CAN NOT BE A NORMAL ALIGNMENT!! | |
AGAIN, DO NOT USE . = ALIGN(x) here! | |
LD will troll you and put the SNES header 'x' bytes back. This will happen no matter how | |
large you make the header_bank region.*/ | |
. = (32k - 64); | |
} > rom_bank_00 = 0xFF | |
_bank0_end = .; | |
.sheader : AT (_bank0_end) | |
{ | |
*(.snesh) | |
. = ALIGN(32k); | |
} > header_bank | |
_header_bank_end = .; | |
.bank1 : AT (_header_bank_end) | |
{ | |
*(.text1 .text1.*) | |
*(.rodata1 .rodata1.*) | |
. = ALIGN(32k); | |
} > rom_bank_01 | |
_bank1_end = .; | |
.bank2 : AT (_bank1_end) | |
{ | |
*(.text2 .text2.*) | |
*(.rodata2 .rodata2.*) | |
. = ALIGN(32k); | |
} > rom_bank_02 | |
_bank2_end = .; | |
.bank3 : AT (_bank2_end) | |
{ | |
*(.text3 .text3.*) | |
*(.rodata3 .rodata3.*) | |
. = ALIGN(32k); | |
} > rom_bank_03 | |
_bank3_end = .; | |
.bank4 : AT (_bank3_end) | |
{ | |
*(.text4 .text4.*) | |
*(.rodata4 .rodata4.*) | |
. = ALIGN(32k); | |
} > rom_bank_04 | |
_bank4_end = .; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment