Freespace
Freespace is a concept that comes into play when extending an existing ROM. To insert new code or data into a ROM, the ROM must contain enough continuous unused space for everything to fit into. Space like that is referred to as freespace. Many tools attempt to find freespace in a ROM by looking for continuous blocks of a certain value (most commonly $00
). This method on its own isn't reliable as freespace finders could erroneously detect binary data or code with a certain pattern as freespace. For this reason, the RATS format was invented to protect data inserted into a ROM (see SMW Wiki for details on the RATS format). When placing RATS tags at the beginning of occupied memory blocks inside a ROM, freespace finders can search for them to know which parts of the ROM not to overwrite. Asar supports a number of commands for working with freespace directly, including freespace finders with automatic RATS tag generation.
freespace
/ freecode
/ freedata
/ segment
freespace {ram/noram}[,norats][,align][,cleaned][,static][,bankcross][,bank={num}][,start={num}][,pin={label}]
freecode [options...]
freedata [options...]
segment [ram/noram][,align][,bankcross][,bank={num}][,start={num}][,pin={label}]
The freespace command makes Asar search the output ROM for a freespace area large enough to contain the following section of code/data. If such an area is found, the pc is placed at its beginning and a RATS tag automatically written. If no such area is found, an error is thrown. The parameters control what kind of freespace to look for.
The freecode
command is an alias of freespace ram
, whereas freedata
is an alias of freespace noram
. The segment
command is an alias for freespace norats
. (Additionally, with segment
specifying ram
or noram
is optional and defaults to noram
.)
Parameter | Details |
---|---|
ram | The freespace finder searches for an area where RAM mirrors are available (banks $10 to $3F). Recommended when inserting code. |
noram | The freespace finder searches for an area where RAM mirrors aren't available (banks $40 to $6F and $F0 to $FF). If no such area is found, it searches in the remaining banks ($10 to $3F). Recommended when inserting data. |
norats | Do not write a RATS tag. This is mostly useful for homebrews, or other setups where the ROM is rebuilt from scratch. Using this option makes the ram /noram options optional, defaulting to noram . It also cannot be used with cleaned or static , which are specfic to the RATS system. |
align | The freespace finder searches for an area at the beginning of a bank. |
cleaned | Suppresses the warning about freespace leaking. Useful when Asar's leak detection misbehaves on an autoclean with a complicated math statement or similar. |
static | Prevents the freespace area from moving once assigned. This also prevents it from growing (an error is thrown if the area would need to grow). Useful in situations where data needs to remain in a certain location (for example: when another tool or another patch needs to access it). |
bank= | Only search for freespace in the given bank. Mostly useful when using norats . |
start= | Search for freespace starting at the specified position in ROM. Useful for hacking non-SMW games, where the original ROM might be bigger or smaller. Note that technically, this limits the freespace finder to positions that are after the location of start in the ROM file: For example, when using $C00000 as the start position in hirom , the entire ROM will be searched, since $C00000 is at the start of the ROM file. |
pin= | Pin this freespace to another one, forcing them to be placed in the same bank. |
bankcross | Allow this freespace to cross bank borders. You must also use check bankcross off inside the freespace to allow the data inside it to cross borders. Note that all of the concerns regarding check bankcross off also apply here. |
Every boolean option also has a negative version prefixed with no
that allows disabling it to restore the default behavior. (In the case of norats
, using rats
will restore the default behavior.)
One thing to note about freespaces is that if Asar places two freespace areas within the same bank, it will use 24-bit addressing in cases where they reference each other, despite 16-bit addressing being possible in theory. This can be worked around by only using a single freespace area instead. It's not recommended to explicitly use 16-bit addressing in these cases as the two freespace areas are not guaranteed to always end up in the same bank for all users.
; Let's assume this to be some location in the ROM originally containing
;lda #$10
;sta $1F
org $01A56B
autoclean jsl MyNewCode
freecode
MyNewCode:
; Do something here
; ...
.Return:
; We overwrote some code from the original ROM with our org, so we have to restore it here
lda #$10
sta $1F
rtl
freespacebyte
freespacebyte {value}
This command sets the byte which Asar considers to be free space. This value will be used for searching for freespace, as padding when resizing the ROM, or when cleaning up old freespaces.
freespace_settings
freespace_settings {options...}
This command allows giving default values for the freespace
/freecode
/... commands. The syntax is the same as the freespace
command. Asar will act like any options provided here are prepended to all freespace
/etc commands.
freespace_settings start=$088000
freecode static ; this will act like `freespace start=$088000,ram,static`
; (the `ram` comes from using freecode instead of freespace:
; note how it's added after the default settings.)
autoclean
autoclean jml/jsl/lda/cmp/.../dl {label}
autoclean {snes_address}
The autoclean command makes it possible for Asar to automatically clean up and reuse all of the freespace allocated by a patch when applying that patch again. The purpose of this is to prevent freespace leaks. Normally, applying a patch including a freespace (or similar) command to the same ROM multiple times would allocate a new freespace area each time. Since Asar automatically protects allocated freespace via RATS tags, all freespace areas previously allocated by the same patch would leak and become unusable, making the output ROM run out of freespace eventually. The autoclean command can prevent this by freeing up freespace areas previously allocated by the patch before allocating new ones. How it accomplishes this depends on how it is used:
- When used with an assembly instruction (most commonly
jml
orjsl
):
Thelabel
parameter must be a label pointing to inside a freespace area. The instruction can be any instruction that supports long (24-bit) addressing. When the patch is applied and the autoclean is encountered, Asar checks whether the output ROM contains the same instruction at the current pc. If it does, and the instruction points into a freespace area with a valid RATS tag, the RATS tag is removed along with its contents. - When used with a
dl
:
Thelabel
parameter must be a label pointing to inside a freespace area. When the patch is applied and the autoclean is encountered, Asar checks whether the output ROM contains an address pointing to the expanded area of the ROM (banks $10+) at the current pc. If it does, Asar checks whether that address points to an area protected by a RATS tag (including the RATS tag itself). If it does, Asar cleans up that area and removes the RATS tag. - When used with just an address:
Thesnes_address
parameter must be any label, number literal or math statement evaluating to an SNES address pointing to inside a freespace area. When the patch is applied and the autoclean is encountered, Asar checks whether that address points to the expanded area of the ROM (banks $10+). If it does, Asar checks whether it points to an area protected by a RATS tag (including the RATS tag itself). If it does, Asar cleans up that area and removes the RATS tag.
When using autoclean with an instruction or dl, Asar will also assemble the respective line of code at the current pc. For simplicity, you can treat the autoclean command like a modifier in those cases. A few more things to note when using the autoclean command:
- The autoclean command itself may not be used inside a freespace area. To automatically clean up freespace that is only referenced within another freespace area, you can use the
prot
command. - It is safe to have multiple autoclean commands pointing to the same freespace area.
- You can not use autoclean with a label pointing to the very end of a freespace area.
; Let's assume this to be some location in the ROM containing a function pointer table or similar
org $00A5F2
autoclean dl MyNewFunction1
autoclean dl MyNewFunction2
freecode
MyNewFunction1:
; ...
rtl
MyNewFunction2:
; ...
rtl
prot
prot {label}[,label...]
The prot command makes it possible for Asar to automatically clean up a freespace area that is only referenced within another freespace area and thus can't be cleaned via an autoclean directly. It must be used at the beginning of a freespace area (right after the freespace command), where the label
parameter must be a label pointing to inside a freespace area (you can pass up to 85 labels separated by commas to a single prot). When a freespace area containing a prot is cleaned by an autoclean, all freespace areas referenced by the prot are also cleaned up.
org $0194BC
autoclean jsl MyNewFunction
freecode
prot SomeLargeData
MyNewFunction:
ldx.b #0
.Loop:
{
lda SomeLargeData,x
cmp #$FF
beq .Return
; ...
inx
bra .Loop
}
.Return:
rtl
freedata
SomeLargeData:
db $00,$01,$02,$03
; ...
db $FF