In order to use the linker file properly, it helps to have a few
well-understood concepts in mind. From these, many different interesting
structures can be built. (It's like getting to know a few pieces in the Lincoln
Logs toy set and then being able to design and build many different interesting
buildings.) After reading this page, I'd recommend returning to the example
source code page to take a closer look at the linker file provided there.
There are only three central ideas. So here they are (note
that when I write 'Mb' I mean 'megabyte, and not megabit'):
ROM Files to Patch -- RMI and RMO
Directives
|
The RMI directive specifies your source
ROM filename. That filename must already exist in the file
system. This is tested. |
|
|
The RMO directive specifies your
destination (resulting) ROM filename. This filename does not
have to already exist in the file system. |
|
|
If you don't specify either of these,
then ASMPATCH doesn't do any patching and the behavior defaults
back to the original Merlin32 assembler/linker behaviors. |
|
|
If you provide both directives, then
the RMI directive's filename is first copied to the RMO
directive's filename, before patching takes place. If there was
already an existing ROM directive filename, that filename is
over-ridden (destroyed) prior to copying. |
|
|
If you provide only the RMI directive's
filename, then that file is used directly and patched in-place.
No copy is made. (Best used only when you really are certain and
confident about using this behavior.) |
|
|
If you provide only the RMO directive's
filename, then that file is created (if needed) and then patched
in-place. |
|
|
Regardless of the above rules and
behaviors, the ROM file being patched will be pre-extended (if
necessary) to
the size indicated by the MAP directives, discussed in the next
section below. It will not be shortened, though. So you can
patch larger binary files without losing the 'excess' tail end
of the binary file. I'm not sure if that has any value, but
that's the way it works. |
|
|
|
ROM File Layout -- MAP Directive
|
A ROM file is a binary file. As a rule,
binary files aren't human-readable. But there are rules about
correctly reading one and rules about creating a new one or
modifying an existing one. ASMPATCH
needs to know these rules. |
|
|
The disk image of a ROM may be a
simple, linear copy of the internal ROM. But the CPU system
addresses may be redirected or altered by intervening hardware
(present within the game system itself or present within the
cartridge.) So there needs to be a way of documenting the
address mapping between the game system's CPU addresses and the
file addresses of the ROM's disk image. |
|
|
For example, the so-called ExHiROM
arrangement on the SNES maps the first 4Mb of the ROM's disk
image
to the uppermost 4Mb 'quadrant,' quadrant 3, of the 24-bit
(16Mb) address space of the SNES's CPU, the 65C816. And it maps
the second 4Mb of the ROM's disk image to each of the remaining
quadrants; 0, 1, and 2. That would seem to top out at 8Mb. But
it's also possible for such a ROM to be much larger -- easily
128Mb -- if there is also some additional remapping hardware on
the cartridge itself. (There is no theoretical limit, only
realistic ones.) This additional hardware may, under
software control, remap any selected portions of the internal
ROM into any selected portion of the SNES address space as seen
by the 65C816. To compound things, the so-called LoROM
arrangement on the SNES eliminates the A15 address line (deletes
it, so to speak) so that the remaining A23 to A16 address lines
now appear as A22 to A15 at the cartridge slot. (It's not
important for mapping purposes, but the SNES also can disable
the cartridge entirely for some address ranges.) |
|
|
The MAP directive(s) in the linker file
is used to associate linear file addresses of the ROM's disk
image with any such
reasonable CPU address mapping by hardware. The first MAP directive
documents the first section (of any arbitrary size) of the disk
image, providing the range of CPU addresses that apply
to that section. The second MAP directive documents the next
section (again, of any arbitrary size that may be the same or
different than the first.) The third MAP directive documents the
third. And so on. You can use as many of these named MAP
sections as are necessary to completely document the ROM image.
No limit here. This means you can readily prepare a ROM image
that is 128Mb, or more. (At least one MAP directive is required,
for ROM patching to occur.) The size of the resulting ROM file
will be equal to the sum of the MAP sections added together. |
|
|
You can use the exact same, or
overlapping too, CPU addresses for both earlier and
later MAP sections. You could have 100 different MAP sections
mapped to the exact same range of CPU addresses, in
fact. It just doesn't matter. So in cases where different parts
of the ROM are mapped into the same CPU address range,
but at different times during execution, there is no difficulty
whatsoever in documenting that fact with the MAP directives. |
|
|
Once documented, you may also now
direct any of your assembly patch segments to any of the above,
named
map sections. |
|
|
|
Patch Segments -- SEG, ROM, ORG, BSZ, and
ASM Directives
|
A patch segment is any named collection
of one or more assembly source code files that are to be
assembled together and directed as a group towards a specific
ROM section. There is no specific requirement that you divide up
your source code into multiple files. That's your choice based
upon your own sense of what works for you in writing your source
code. |
|
|
The only issue to consider here
is, whether it is one assembly source code file or ten such
files, that all of the addresses implied by your source code
must target a single part of the ROM, indicated by the named MAP
section, and the resulting linked CPU addresses associated with
the patch will be interpreted in that specific ROM addressing
layout context. |
|
|
If you want to target a different MAP
section, then you must set up another patch segment in the
linker file. Each patch segment is indicated by a leading SEG
directive, which names a new patch segment. Patch segment names
need to be unique. So duplicate segment names aren't allowed.
(As a nod towards the original Merlin32 implementation, a DSK
directive doubles as a SEG directive. You can use either SEG or
DSK to achieve the same results here.) |
|
|
Following the SEG directive, it's
appropriate to include a ROM directive. The ROM directive names
a ROM section provided in a MAP directive in the linker file.
This is how a patch segment is directed to a specific ROM
section in the disk/file image that will be generated/patched.
Only one ROM directive is required as it's not possible to
direct a patch segment to more than one ROM section. |
|
|
In addition, a patch segment includes
an ORG directive. This provides the first allowable address for
the patch segment. It also provides the initial starting address
assumption for code and data found in the first listed assembly
file (given by ASM directives mentioned shortly), if that
assembly file doesn't already use an ORG inside of it to start
the addressing there. (Some assembly source code files may start
with REL to indicate "relocatable" and in this case the ORG in
the linker file will determine the beginning addresses while
assembling that source code.) Only one ORG directive is
required, as well, because there is only one starting addres for
the patch segment and only one restriction allowed, as well. If
code or data attempts to reach addresses earlier than this
specified ORG address, a warning or error message will be
produced and the associated code and data that lays earlier than
this address will not be used to patch the ROM. |
|
|
A patch segment may optionally include
a BSZ directive. This specifies the size of the patch segment
and, in conjunction with the required ORG directive, determines
the last allowable address for the patch. If it is not
specified, then there is no 'last address' limitation and the
patch may be of any size. If provided and if code or data
attempts to reach addresses later than this specified ORG+BSZ
end address, a warning or error message will be produced and the
associated code and data that lays after this address will not
be used to patch the ROM. |
|
|
Finally, a patch segment needs at least
one ASM directive. These directives name the source code files
that will be applied as part of the patch segment. They will be
assembled and linked together. If the source code doesn't use
ORG to skip around from one address to another, and instead uses
REL to indicated 'relocatable' source, then the second source
code file referred to by the second ASM directive will be
automatically appended to the first, extending the total size of
the patch segment. And the third will be appended to the second.
And so on. However, there is no requirement here and therefore
no limitation on your source code. The second named assembly
source code file may also change the addressing to a
non-contiguous location using the ORG. This simply overrides the
default arrangement, but causes no problems at all. It's up to
you how to apply things in your design approach. |
|
|
To start a new patch segment, allowing
you to select a different ROM section and a different set of
assembly files and a different set of addressing restrictions,
just specify the next SEG directive. The above mentioned process
just starts all over again, then. There are no limits to how
many different patch segments you want to use. Note that
different patch segments may use the exact same ORG address.
None of that matters here. You can specify directing this new
patch to the same ROM section or to a different ROM section,
also. Again, there is no restriction here. How you organize your
patches is entirely your own business. Use it as you please. |
|
|
That's really all there is to it. So there are three basic parts to a linker
file. One part specifies the ROM files to be modified/patched. One part
specifies the layout of the resulting patched ROM file. And the third part,
which may included more than one segment description, provides the details
needed to properly assemble a patch segment and to apply it to the ROM file.
Although any given linker file may seem "complicated," and a design may require
some "complexity," they really only have those three basic ideas to know about.
You can build very complex schemes from them. But there are still only three
basic ideas there.
Last updated 5/17/2016, 16:00 UT. You may contact me at jonk at infinitefactors dot org.