ASMPATCH ROM Patch Concepts

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.

     Related Pages

  Discussion and example source code using ASMPATCH ASMPATCH: Patching SNES ROMs from Assembly  
  Modifications used to create the ASMPATCH tool from Merlin32 source code ASMPATCH: Modifications to Merlin32  

 

Concepts for ROM Patching Used in the Linker File by ASMPATCH

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.