Punkline
Dr. Frankenstack
- Joined
- May 15, 2015
- Messages
- 423
RT Stack Snacks is a module for MCM that enables a unique method of allocating globally accessible variables using a series of files kept in the MCM directory. These allocations may be thought of as static, but do not take up space in the DOL or in the dynamic memory heap -- and are initially zeroed out. They may be used to house data variables as needed for large code projects in a way that makes them very easy to define and use from multiple Melee codes.
Clone or Download the latest version here - https://github.com/Punkline/MCM-RTStackSnacks.git
When installed, the code uses
To install, copy everything in the ‘MCM’ folder to your MCM root directory. Then, move the text file to your Mods Library folder.
To load the module for use in other codes, use the line:
---
How to configure:
You may modify the contents of RTStackSnacks.s or the files contained in the “.RTStackSnacks” subdirectory. The comments briefly explain how to use the module, and what it is comprised of:
“Snack” allocations are made by generating a runtime stack frame before the Melee scene loop begins. This is done exactly once at the beginning of the game, which makes this frame permanent, and effectively static; with allocations starting at address 804eebb0 (using a negative offset). If the frame is made too large, it may impose unintended limits on the runtime stack's capacity that may cause problems. If you keep your allocations snack-sized however, then tens of thousands of bytes can be afforded without issue.
(These allocations will survive purges of the dynamic memory heap, as though they were static.)
In addition to the snacks made out of the bogus stackframe, a centralized container for static data in the DOL is also made available as a separate customizable table -- for convenience. Data can be defined in here at assembly time, so it is useful for making default values that can be copied to the snack variables when a default is required, or at the start of the game.
Both tables are accessible from pointers stored in rtoc offsets -0x2014 and -0x2018 through the use of mytoc block 335.
These have been given special macros called
Any code may reach these snack variables or predefined data tables by using a shared set of symbols that are loaded by the module. This means that a code that is written to use these variables does not need to reference specific numerical offsets to reach the allocation it wants from the table -- only a unique keyword. Because of this, the order of installation does not matter, and if they have a specific name, then offsets for a specific code can be stacked into the allocation table at any position.
In short, this means that codes made this way can be ported between different configurations of the module, and easily combined for large code projects.
Additional GAS modules may be bundled with this module to create symbols and macros that every code using it will have access to. Some default modules are bundled to create core features.
Finally, an injection event is created inside of the initialization injection code that is put into the beginning of the game, just after snacks have been allocated. Developers may attach code to this for the sake of initializing variables or launching other initialization processes. This literally inserts the instructions into the injection code container rather than make a call to a function, so calls to any initialization functions must be made with
The bare version of this code should be compatible with the Gecko Code Table generation feature in MCM, and can even facilitate defining static branch-in lists for supporting specially written custom functions that can be called (by keyword name) using just 4 instructions by any gecko code included in an installation with this module. UnclePunch
---
A special core module has been included to enable the ‘enum’ macro -- which can be used to enumerate named offset values meant to be used from a common base address. The macro counts the total bytes enumerated, and the code uses it to calculate a total for the new stack frame size used to support snack allocations.
To create new snack variables, use the ‘enum’ macro to define new offset names in the following section:
These snack variable allocations can be accessed at any time using a pointer stored in -0x2018(rtoc), or by loading the static address
For example:
To create data that the module puts in the DOL to boot up with, you can edit the ‘Predef’ section:
This data can be accessed at any time using a pointer stored in -0x2014(rtoc). Alternatively, you may just use the
If you want to make enumerations for the offsets of some of these predefined data values, you may use the following section to declare additional symbol or macro objects:
It’s important to separate this section from the ‘Predef’ data section because it is invoked each time the module is loaded -- while the data is only emitted once via macro call.
If you want to inject extra code into the game-start event, you can do so by adding instructions or calls to functions in this section:
For each of these sections, you may instead use the mentioned file to append the contents instead of directly editing the module file. These are kept in the subdirectory included with the module, called ".RTStackSnacks". If you modify these txt files, you can create configurations that may be plugged into a project.
For example, you can place ‘enum’ calls in the file “.RTStackSnacks\Snacks.txt” to isolate a configuration of variables to a separate file.
You may further explode this abstraction by using
Clone or Download the latest version here - https://github.com/Punkline/MCM-RTStackSnacks.git
When installed, the code uses
.include
to tap into a highly customizable file called RTStackSnacks.s. Additional modules and the contents of the 4 “.RTStackSnacks\*.txt” files may be bundled for certain project configurations. You may configure RTStackSnacks.s to create variables by following the comments, or see below for more details.To install, copy everything in the ‘MCM’ folder to your MCM root directory. Then, move the text file to your Mods Library folder.
To load the module for use in other codes, use the line:
.include "RTStackSnacks.s"
---
How to configure:
You may modify the contents of RTStackSnacks.s or the files contained in the “.RTStackSnacks” subdirectory. The comments briefly explain how to use the module, and what it is comprised of:
Rich (BB code):
# --- RTStackSnacks.s - v0.1
# .include this module in your code to enable snacks.
# use the line: .include "RTStackSnacks.s"
# --- to find the snacks - use one of these methods:
# getsnacks rSnacks # get variable allocations
# getsnacks.predef rPredef # get predefined data table
# - or:
# lwz rSnacks, -0x2018(rtoc)
# lwz rPredef, -0x2014(rtoc)
# --- to get a snack - use a snack allocation symbol:
# lwz rSnack, xMySnack(rSnacks)
# - or:
# addi rSnack, rSnacks, xMySnack
# - these symbols are generated below, in Snack Allocations
# - they may also be generated in .RTStackSnacks\Snacks.txt
# 'Snacks' are variable allocations.
# Snack data is effectively static, but initially blank.
# - snacks take up no space in the static DOL file
# - snacks take up no space in the dynamic memory heap
# - snacks are not volatile, and persist between scenes
# - snacks all derive from base address 804eebb0 - size
# - you may access this from a pointer in -0x2018(rtoc)
# - shortcut macro: getsnacks rSnacks
# 'Predef' data is just regular static data.
# - Predef data takes up space in the DOL
# - Predef data can be used to define default values
# - Predef data is static, but loc isn't known by assembler
# - you may access this from a pointer in -0x2014(rtoc)
# - shortcut macro: getsnacks.predef rPredef
# 'Setup symbols' can be used to initialize GAS objects
# - all codes that .include this file will inherit these
# - symbols for Predef structures may be added here
# - utility macros may also be added here
# 'Setup instructions' can be used to initialize Snacks
# - setup instructions are executed at start of the game
# - they may be used to initialize snack variables
# - Predef may be used to copy defaults if needed
“Snack” allocations are made by generating a runtime stack frame before the Melee scene loop begins. This is done exactly once at the beginning of the game, which makes this frame permanent, and effectively static; with allocations starting at address 804eebb0 (using a negative offset). If the frame is made too large, it may impose unintended limits on the runtime stack's capacity that may cause problems. If you keep your allocations snack-sized however, then tens of thousands of bytes can be afforded without issue.
(These allocations will survive purges of the dynamic memory heap, as though they were static.)
In addition to the snacks made out of the bogus stackframe, a centralized container for static data in the DOL is also made available as a separate customizable table -- for convenience. Data can be defined in here at assembly time, so it is useful for making default values that can be copied to the snack variables when a default is required, or at the start of the game.
Both tables are accessible from pointers stored in rtoc offsets -0x2014 and -0x2018 through the use of mytoc block 335.
These have been given special macros called
getsnacks
and getsnacks.predef
-- which may be used like so to retrieve data:Any code may reach these snack variables or predefined data tables by using a shared set of symbols that are loaded by the module. This means that a code that is written to use these variables does not need to reference specific numerical offsets to reach the allocation it wants from the table -- only a unique keyword. Because of this, the order of installation does not matter, and if they have a specific name, then offsets for a specific code can be stacked into the allocation table at any position.
In short, this means that codes made this way can be ported between different configurations of the module, and easily combined for large code projects.
Additional GAS modules may be bundled with this module to create symbols and macros that every code using it will have access to. Some default modules are bundled to create core features.
Finally, an injection event is created inside of the initialization injection code that is put into the beginning of the game, just after snacks have been allocated. Developers may attach code to this for the sake of initializing variables or launching other initialization processes. This literally inserts the instructions into the injection code container rather than make a call to a function, so calls to any initialization functions must be made with
bl
or blrl
instructions.The bare version of this code should be compatible with the Gecko Code Table generation feature in MCM, and can even facilitate defining static branch-in lists for supporting specially written custom functions that can be called (by keyword name) using just 4 instructions by any gecko code included in an installation with this module. UnclePunch
---
A special core module has been included to enable the ‘enum’ macro -- which can be used to enumerate named offset values meant to be used from a common base address. The macro counts the total bytes enumerated, and the code uses it to calculate a total for the new stack frame size used to support snack allocations.
To create new snack variables, use the ‘enum’ macro to define new offset names in the following section:
Rich (BB code):
# --- Example Snack Allocations:
# You may use 'enum' to list exact offset names
# enum [base], [size], [name1, name2, ...]
enum 0, 4, example.xMyVar, example.xMySecond, example.xMyThird
# You may use a blank [base] value to continue enumeration with another group of names
enum , 4, example.namespace.xMyVar
# You may use 'enumf' to format names with a common prefix
# enumf [base], [size], [prefix], [suffix], [name1, name2, ...]
enumf, 4, example.namespace.,, xMySecond, xMyThird, xMyFourth
# You may use (expressions) in parentheses to change [size] inline with the arguments
enumf, 4, example.,, xMySingle, (8),xMyDouble, (2),xMyHWord, (1),xByteA, xByteB, (4),xMyWord
# You may use the property 'enum' to reference the current [base] memory
example.size = enum - example.xMyVar
# - the last enum value is used to calculate total size in a way similar to this
# - the enum value must therfore remain intact while building the snacks allocation table
# - you may store the value of enum in another variable identifier temporarily, if needed
# --- Create Snack Allocations here: - start at base of 0
# - names must be unique, so using a parent namespace is recommended
enum 0, 4,
# --- end of Snack Allocations
.include ".RTStackSnacks\\Snacks.txt"
# -- (you may also include additional offsets in this file)
RTStackSnacks.xSnackRack = enum
RTStackSnacks.bogusframesize = (enum + RTStackSnacks.SnackRack.size + 0x80)
# - this helps define the stack frame size using any enumerations that were defined
These snack variable allocations can be accessed at any time using a pointer stored in -0x2018(rtoc), or by loading the static address
(0x804eebb0 - (RTStackSnacks.bogusframesize - 0x80))
. Alternatively, you may just use the getsnacks
macro to assign the base address to a register of your choice.For example:
Rich (BB code):
<example.MyVar.interface>
# - standalone function may be called in MCM by any code
.include "RTStackSnacks.s" # load module
enum r3, 1, rWrite, rRead, rSnacks # name registers
getSnacks rSnacks # load base address
lwz rRead, example.xMyVar(rSnacks)
stw rWrite, example.xMySecond(rSnacks)
blr # returns: r4=MyVar; r5=base of snacks table
To create data that the module puts in the DOL to boot up with, you can edit the ‘Predef’ section:
Rich (BB code):
.macro RTStackSnacks.PredefDataEmitter
# This container is for real data, not symbols
# You may access it from the getsnacks.predef macro
# - these definitions will take up space in the DOL
## # Examples:
## .long 0, 1, 2, 3
## .asciz "Hello World"
## mflr r0
# --- Initialize Predef Data here:
# --- end of Predef Data
.include ".RTStackSnacks\\PredefData.txt"
# -- (you may also include data in this file)
# -- (you may use the .incbin directive to include binary files)
.endm
This data can be accessed at any time using a pointer stored in -0x2014(rtoc). Alternatively, you may just use the
getsnacks.predef
macro to assign the base address to a register of your choice.If you want to make enumerations for the offsets of some of these predefined data values, you may use the following section to declare additional symbol or macro objects:
Rich (BB code):
# --- Bundled Modules:
.include "enum.s" # - enables useful enumeration macros and register/cr symbols
.include "blaba.s" # - enables bla and ba instructions as long-form blrl and bctr branches
# --- Setup Symbols and Macros here:
# - non-snack symbols or macros can be defined here for every code that uses the this module
# --- end of Setup Symbols and Macros
.include ".RTStackSnacks\\SetupSymbols.txt"
# -- (you may also include stuff in this file)
It’s important to separate this section from the ‘Predef’ data section because it is invoked each time the module is loaded -- while the data is only emitted once via macro call.
If you want to inject extra code into the game-start event, you can do so by adding instructions or calls to functions in this section:
Rich (BB code):
.macro RTStackSnacks.SetupInstructions
# This last container is for any instructions you want
# to include at the very beginning of the game.
# They will be executed before Melee is fully initialized.
# --- Extra Setup Instructions go here:
# --- end of Setup Instructions
.include ".RTStackSnacks\\SetupInstructions.txt"
# -- (you may also include stuff in this file)
.endm
For each of these sections, you may instead use the mentioned file to append the contents instead of directly editing the module file. These are kept in the subdirectory included with the module, called ".RTStackSnacks". If you modify these txt files, you can create configurations that may be plugged into a project.
For example, you can place ‘enum’ calls in the file “.RTStackSnacks\Snacks.txt” to isolate a configuration of variables to a separate file.
You may further explode this abstraction by using
.include
directives in these file to reference multiple other files; making a collection of variable groups.
Last edited: