Dynamic Xtreme ASM API
| English | Português | Español | 日本語 |
This article explains how to use Dynamic Xtreme's routines and macros from ASM code. Each entry explains the call's purpose, inputs, and results, with an example.
To learn how to organize a complete sprite, see the sprite creation guide.
Features required to use the API
Available routines, macros, and variables depend on the features selected when installing Dynamic Xtreme. This table shows what to enable for each system:
| Feature | Available routines and macros | Dependencies and details |
|---|---|---|
GraphicsChange
|
VRAM transfers: TransferToVRAM and its FromAddr, Resource, WithLenght, and Forced variants.
|
Provides graphics loading. Also required by DynamicPoses and PlayerFeatures.
|
DynamicPoses
|
DefineDynamicSpaceConfig, DynamicPoseSpaceConfig, TakeDynamicRequest, DynamicRoutine, SetPropertyAndOffset, !Upload, !UploadWithoutPoseOffset, and the general macros GeneralUpload, Upload, and StandardSpriteUpload.
|
Requires GraphicsChange. Drawing the obtained poses also requires DrawingSystem.
|
DrawingSystem
|
!DXDraw, !DXDrawWithOffset, and general macros Draw, StandardSpriteDraw, and DrawStatic. Includes the system's drawing and tile validation routines.
|
Dynamic pose drawing also requires DynamicPoses. DrawStatic can draw static poses without the dynamic pose system.
|
PalettesChange
|
AssignPalette, !PaletteAssignment, !PaletteAssignmentNoUpload, !ReplacePalette, and their general macros; LoadPaletteIDAndAddress; TransferPalette macros and CGRAM transfers.
|
Provides palette assignment and loading. Effects additionally require PalettesEffects.
|
PalettesEffects
|
SetRGBBase, SetHSLBase, Mix, MixAndMerge, PaletteTransition, DoEffect, and RGB/HSL conversions, including their variants. Also enables ConcatenateRGBPaletteEffectToGlobal and ConcatenateHSLPaletteEffectToGlobal, as sprite aliases or general macros.
|
Requires PalettesChange. Allows global effects through palette assignment or TransferPalette.
|
PlayerFeatures
|
Customizes player graphics and palettes through the player variables. Does not add a separate family of calls to the categories above. | Requires GraphicsChange and PalettesChange.
|
YoshiFeatures
|
Customizes Yoshi's graphics through the Yoshi variables. | Requires PlayerFeatures and its dependencies.
|
Free7E2000
|
Adds no calls to this API. | Frees and reorganizes the corresponding RAM area. Not an additional requirement for loading or drawing macros. Disabled on SA-1. |
ControllerOptimization, FixedColorOptimization, KevinLMVRAMOptimization, and StatusBarOptimization
|
Add no call families to this API. | Change how their respective systems work internally. These are not required for pose, drawing, palette, or math macros. |
| No additional feature | Mul, Div, and their W and After... variants. | Math macros are included from DXDefines.asm independently of the options above.
|
PPU macros are included when GraphicsChange or PalettesChange is enabled, but use VRAM transfers with GraphicsChange and CGRAM transfers with PalettesChange. Asar recognizing a macro's name does not mean its required lists and variables are enabled.
To load and draw dynamic poses, enable GraphicsChange, DynamicPoses, and DrawingSystem. Add PalettesChange if the sprite loads palettes and PalettesEffects if it uses effects.
Tool integration
| Context | Files and calls |
|---|---|
| PIXI | Installation copies general defines to asm/ExtraDefines and shared routines to routines. For sprite aliases, include NormalSpriteDefines.asm, ClusterSpriteDefines.asm, or ExtendedSpriteDefines.asm as appropriate. Each entry explains type-specific differences.
|
| UberASMTool | Installation links ExtraDefines/DXDefines.asm from other/macro_library.asm. Use general macros and patch routines with their parameters; aliases such as !Upload belong to PIXI sprite defines files.
|
| GPS | Installation links ExtraDefines/DXDefines.asm from defines.asm. Use general macros and patch routines, preparing their inputs from the block's code.
|
These integrations are prepared for tools configured during installation. If Asar cannot find a name, check the required feature, included files, and, for generated defines, the exact spelling in DXDefines.asm. After changing features or resources, reinstall Dynamic Xtreme and rerun tools using its defines, as explained in the Quick Start guide.
Variables and defines
DXDefines.asm gathers the names Dynamic Xtreme uses for its variables, configurations, resources, and routines. Some represent runtime data; others are constants or generated during resource installation.
General variable names start with DX_ and have no ! prefix, for example DX_Timer. Defines such as !DynamicPoseIDMySprite000 do include !. Keep each name's exact spelling.
Available variables depend on installed features. You do not need to memorize them all: find the category for the system you are using.
General variables
In these tables, size is the number of bytes occupied by one value. Tables also list their entry count. Dynamic Xtreme maintains variables marked internal; normally use API routines to work with them.
Counters and data per frame
| Variable | Size | Purpose |
|---|---|---|
DX_Timer |
2 bytes | Counts frames in which Dynamic Xtreme runs. Continues during pause and frozen action. Used to track each pose's last use. |
DX_SyncTimer |
2 bytes | Counts frames but stops during pause or frozen action. Useful for animations that should stop with the game. |
DX_Dynamic_CurrentDataSend |
2 bytes | Bytes already scheduled for transfer in the current frame. Updated by loading routines. |
DX_Dynamic_MaxDataPerFrame |
2 bytes | Maximum bytes normal uploads can schedule per frame. Forced variants can exceed it.
|
Poses loaded in VRAM
These internal cache tables track which poses are loaded, where they are, and which remain in use. Request poses with !Upload or !TakeDynamicRequest.
| Variable | Size | Purpose |
|---|---|---|
DX_Dynamic_Pose_Length |
1 byte | Number of poses currently registered in the cache. |
DX_Dynamic_Pose_HashSize |
128 one-byte values | Helps find poses by ID. |
DX_Dynamic_Pose_ID |
128 two-byte values | ID of each registered pose. |
DX_Dynamic_Pose_Offset |
128 one-byte values | Location of each pose's graphics in dynamic VRAM space, measured in 16×16 blocks. |
DX_Dynamic_Pose_TimeLastUse |
128 two-byte values | DX_Timer at each pose's last use. Prevents replacement of graphics still being displayed.
|
DX_Dynamic_Tile_Size / DX_Dynamic_Tile_Pose |
128 shared bytes | Describe free and occupied VRAM regions. Two names for the same memory. |
DX_Dynamic_Tile_Offset |
128 one-byte values | Helps traverse free and occupied VRAM regions. |
Palettes and the global effect
The 16-palette tables use palette order 0–F. In two-byte tables, palette 1 starts at +2, palette 2 at +4, and so on.
| Variable | Size | Purpose |
|---|---|---|
DX_Dynamic_Palettes_GlobalBGEnable |
1 byte | Each bit determines whether one of palettes 0–7 receives the global effect. |
DX_Dynamic_Palettes_GlobalSPEnable |
1 byte | Each bit determines whether one of sprite palettes 8–F receives the global effect. |
DX_Dynamic_Palettes_GlobalEffectID |
2 bytes | Desired global effect ID. Zero means no global effect. |
DX_Dynamic_Palettes_LastGlobalEffectID |
2 bytes | Last global effect examined by the system, used to detect changes. |
DX_Dynamic_Palettes_LastGlobalEffectIDPerPal |
16 two-byte values | Last global effect calculated per palette. $FFFF: no result yet; $FFFE: update pending, previous result retained.
|
DX_Dynamic_Palettes_ID |
16 two-byte values | ID associated with each palette. $FFFF means free; $FFFE excludes it from automatic selection.
|
DX_Dynamic_Palettes_Updated |
16 one-byte values | Palettes already updated this frame. Internal. |
DX_Dynamic_Palettes_DisableTimer |
16 one-byte values | A nonzero timer protects a palette from replacement by another automatic assignment. Calls using it reset it to 2. |
DX_Dynamic_Palettes_EffectEnabled |
1 byte | Tracks sprite palettes using effects. Internal palette management state. |
To reserve a sprite palette against automatic selection, set its DX_Dynamic_Palettes_ID entry to $FFFE before sprites request palettes.
Color copies and effect results
| Variable | Size | Purpose |
|---|---|---|
DX_PPU_CGRAM_PaletteCopy |
512 bytes | Working copy of 256 colors at 2 bytes each. Source for SetRGBBaseDefault and SetHSLBaseDefault.
|
DX_PPU_CGRAM_BaseRGBPalette |
768 bytes | Original colors split into red, green, and blue: 3 bytes per color. |
DX_PPU_CGRAM_BaseHSLPalette |
768 bytes | Original colors split into hue, saturation, and lightness: 3 bytes per color. |
DX_PPU_CGRAM_LocalEffectBuffer |
768 bytes | Working space for a local effect result before combining it with the global effect. |
DX_PPU_CGRAM_LocalEffectID |
16 two-byte values | Local effect ID applied to each palette. |
DX_PPU_CGRAM_PaletteWriteMirror |
512 bytes | Resulting colors in SNES format, 2 bytes each. AndMergeDefault variants write here.
|
DX_PPU_CGRAM_BGBaseRGBPaletteLoaded / DX_PPU_CGRAM_SPBaseRGBPaletteLoaded |
1 byte each | Each bit indicates a background or sprite palette's RGB base is prepared. |
DX_PPU_CGRAM_BGBaseHSLPaletteLoaded / DX_PPU_CGRAM_SPBaseHSLPaletteLoaded |
1 byte each | Same for HSL bases. |
DX_PPU_CGRAM_BGEffectLoaded / DX_PPU_CGRAM_SPEffectLoaded |
1 byte each | Each bit indicates an available effect result for that palette. |
DX_PPU_CGRAM_LastPlayerPal |
2 bytes | Last processed player palette address, compared to detect changes. |
Writing colors to a RAM copy does not immediately send them to CGRAM. Use palette routines or a transfer to update the display. The system manages prepared-base and effect flags; they do not need clearing before each call.
Fixed color and the first palette color
The SNES fixed color can be used for color addition and subtraction effects. Color 0,0 is CGRAM's first entry. Dynamic Xtreme can apply the global effect to either independently.
| Variable | Size | Purpose |
|---|---|---|
DX_PPU_ColorEffect_Enable |
1 byte | Enables the global effect: bit $01 for fixed color and $02 for color 0,0. $03 enables both.
|
DX_PPU_ColorEffect_BaseLoaded |
1 byte | Tracks saved original colors, one bit per target: $01 and $02.
|
DX_PPU_ColorEffect_RGBBaseLoaded / DX_PPU_ColorEffect_HSLBaseLoaded |
1 byte each | Tracks prepared RGB/HSL colors, using the same bits. |
DX_PPU_FixedColor_Mirror |
2 bytes | Fixed color copy used by the game's normal update. |
DX_PPU_FixedColor_Base |
2 bytes | Original fixed color before effects. |
DX_PPU_FixedColor_RGBBase / DX_PPU_FixedColor_HSLBase |
3 bytes each | Original fixed color split into RGB or HSL. |
DX_PPU_FixedColor_Result |
2 bytes | Fixed color calculated after the effect. |
DX_PPU_FixedColor_LastGlobalEffectID |
2 bytes | Last global effect calculated for fixed color. |
DX_PPU_PaletteColor00_Base |
2 bytes | Original color 0,0. |
DX_PPU_PaletteColor00_RGBBase / DX_PPU_PaletteColor00_HSLBase |
3 bytes each | Original color 0,0 split into RGB or HSL. |
DX_PPU_PaletteColor00_Result |
2 bytes | Desired color 0,0. |
DX_PPU_PaletteColor00_LastGlobalEffectID |
2 bytes | Last global effect calculated for color 0,0. |
DX_PPU_PaletteColor00_Update |
1 byte | Nonzero requests copying Result to color 0,0 during NMI. Reset to 0 afterward.
|
Pending transfers
These variables store copies to perform during NMI. PPU macros populate them for you. Each copy needs a source, destination, and byte count.
| Variable | Contents |
|---|---|
DX_PPU_VRAM_Transfer_Length |
Pending graphics copy count, 1 byte. |
DX_PPU_VRAM_Transfer_SourceLength |
Bytes per copy, two-byte values. |
DX_PPU_VRAM_Transfer_Offset |
Each copy's VRAM destination, two-byte values. |
DX_PPU_VRAM_Transfer_Source |
Each copy's source address, two-byte values. |
DX_PPU_VRAM_Transfer_SourceBNK |
Each copy's source bank. The table reserves 2 bytes per entry. |
DX_PPU_CGRAM_Transfer_Length |
Pending color copy count, 1 byte. |
DX_PPU_CGRAM_Transfer_SourceLength |
Bytes per copy, two-byte values. |
DX_PPU_CGRAM_Transfer_Offset |
Each copy's first destination color, one-byte values. |
DX_PPU_CGRAM_Transfer_Source |
Each copy's source address, two-byte values. |
DX_PPU_CGRAM_Transfer_SourceBNK |
Each copy's source bank. |
Player and Yoshi
These variables change the sources of player graphics and colors and Yoshi graphics. Graphics files must retain the layout expected by the game routines.
| Variable | Size | Purpose |
|---|---|---|
DX_Dynamic_Player_GFX_Enable |
1 byte | Zero disables player graphics loading through this system; nonzero enables it. |
DX_Dynamic_Player_GFX_Addr |
2 bytes | Player graphics start address within the specified bank. |
DX_Dynamic_Player_GFX_BNK |
2 bytes reserved | Player graphics source bank, specified in the low byte. |
DX_Dynamic_Player_Palette_Enable |
1 byte | Zero disables player palette management through this system; nonzero enables it. |
DX_Dynamic_Player_Palette_Addr |
2 bytes | Player palette source address. |
DX_Dynamic_Player_Palette_BNK |
1 byte | Palette bank. When zero, the routine uses the game's player palette address. |
DX_Dynamic_Player_CustomPlayer / DX_Dynamic_Player_LastCustomPlayer |
1 byte each | Reserved to identify current and previous custom players. Initialized to 0 and $FF; currently do not select character graphics by themselves.
|
DX_Dynamic_Yoshi_VRAMEnable |
1 byte | Zero disables Yoshi graphics loading through this system; nonzero enables it. |
DX_Dynamic_Yoshi_Addr |
2 bytes | Yoshi graphics start address within the bank. |
DX_Dynamic_Yoshi_BNK |
1 byte | Yoshi graphics source bank. |
Drawing and sprite variables
DX_Drawing_InitialIndexHighPriority and DX_Drawing_InitialIndexLowPriority each occupy 1 byte and track available drawing positions for high- and low-priority sprites. DX_Drawing_OAMMap occupies 128 bytes and helps organize drawn tiles. These variables are used on LoROM; SA-1 uses its corresponding drawing management.
Individual sprite variables are defined in DynamicXSpritesTables.asm. NormalSpriteDefines.asm, ClusterSpriteDefines.asm, and ExtendedSpriteDefines.asm let all three types use the same names:
| Sprite name | Contents |
|---|---|
!PoseIndex,x |
Desired pose. |
!LastPoseIndex,x |
Last obtained pose available for drawing. Initialize to $FF.
|
!LastPoseHashIndex,x |
Cache entry tracking the graphics' location. Initialize to $FF.
|
!GlobalFlip,x / !LocalFlip,x / !LastFlip,x |
Overall flip, additional pose flip, and effective drawing flip. |
!Palette,x |
Assigned palette: $00 for 8, $02 for 9, through $0E for F. Initialize to $FF for dynamic assignment.
|
!PaletteOption,x |
EPPP---- options: global effect and palette or palette-group selection.
|
!PaletteAssignmentOption,x |
Assignment mode: automatic, manual, or manual without uploading colors. |
!Version,x / !LastVersion,x |
Sprite variant and last variant processed for its palette. Initialize !LastVersion to $FF.
|
!RenderXDistanceOutOfScreen,x / !RenderYDistanceOutOfScreen,x |
Distances that allow drawing when the sprite's position is offscreen but some of its pose may remain visible. |
!SafeFrameLowByte,x / !SafeFrameHighByte,x |
Last frame a pose request was attempted, preventing repeated work in the same frame. |
!AnimationIndex,x / !AnimationPoseIndex,x / !AnimationTimer,x |
Available variables for the animation, current step, and timer. The resource's code decides how to use them. |
!State,x |
Resource state or behavior variable. |
Each variable occupies 1 byte per sprite. Normal sprites have !MaxSprites entries, cluster sprites 20, and extended sprites 10. Do not use !MaxSprites as the cluster or extended entry count.
DX_FreeRams and DX_FreeRams2 mark the start of these table areas. They are not free memory for storing your own data over sprite variables.
Fixed defines
These names represent known configurations and addresses, not variables that change during gameplay.
LoROM and SA-1 compatibility
DXDefines.asm detects the ROM type and selects the corresponding values. Use these names to support both types.
| Define | LoROM | SA-1 | Use |
|---|---|---|---|
!sa1 |
0 | 1 | Select different code by ROM type. |
!dp |
$0000 |
$3000 |
Direct-page address adjustment. |
!addr |
$0000 |
$6000 |
!addr. |
!rom |
$800000 |
$000000 |
Adjustment for original game code addresses. |
!MaxSprites |
$0C (12) |
$16 (22) |
Normal sprite slot count. |
!MultiplicationResult |
$4216 |
$2306 |
Multiplication result address. |
!DivisionResult |
$4214 |
$2306 |
Division quotient address. |
!RemainderResult |
$4216 |
$2308 |
Division remainder address. |
Other variable-placement defines are !normalBnk, !PalCopyBNK, !Variables, and !Variables2. Normally, use each DX_... variable's name rather than calculate its address from these values.
Graphics addresses in VRAM
These defines specify transfer destinations without numeric addresses. Each family has lines 0 through 7; replace N with the line number.
| Family | Line 0 | Increment per line | Example |
|---|---|---|---|
!FG1LineN |
$0000 |
$0100 |
!FG1Line1 = $0100
|
!FG2LineN |
$0800 |
$0100 |
!FG2Line1 = $0900
|
!BG1LineN |
$1000 |
$0100 |
!BG1Line1 = $1100
|
!FG3LineN |
$1800 |
$0100 |
!FG3Line1 = $1900
|
!BG2LineN |
$2000 |
$0100 |
!BG2Line1 = $2100
|
!BG3LineN |
$2800 |
$0100 |
!BG3Line1 = $2900
|
!LG1LineN through !LG4LineN |
$4000, $4400, $4800, $4C00 |
$0080 |
!LG1Line1 = $4080
|
!SP1LineN through !SP4LineN |
$6000, $6800, $7000, $7800 |
$0100 |
!SP4Line1 = $7900
|
!Layer1Tilemap = $3000 and !Layer2Tilemap = $3800 are the usual Layer 1 and Layer 2 tilemap addresses. VRAM addresses here use 2-byte words, as do the transfer macros.
Space configurations for dynamic poses
Pass !DynamicSpaceConfig... defines to !DynamicPoseSpaceConfig. Each name identifies the allowed graphics areas. FirstHalf and SecondHalf identify half-areas. Names containing WithPlayer or WithDSX are intended for those configurations.
| Value | Define |
|---|---|
$00 |
!DynamicSpaceConfigSecondHalfSSP4
|
$01 |
!DynamicSpaceConfigSP4
|
$02 |
!DynamicSpaceConfigSecondHalfSP3
|
$03 |
!DynamicSpaceConfigFirstHalfSP3
|
$04 |
!DynamicSpaceConfigSP3
|
$05 |
!DynamicSpaceConfigSecondHalfSP2
|
$06 |
!DynamicSpaceConfigFirstHalfSP2
|
$07 |
!DynamicSpaceConfigSP2
|
$08 |
!DynamicSpaceConfigSecondHalfSP1
|
$09 |
!DynamicSpaceConfigFirstHalfSP1
|
$0A |
!DynamicSpaceConfigSP1
|
$0B |
!DynamicSpaceConfigFirstHalfSP1WithPlayer
|
$0C |
!DynamicSpaceConfigSP11WithPlayer
|
$0D |
!DynamicSpaceConfigSecondHalfSP3ndSP4
|
$0E |
!DynamicSpaceConfigSP34
|
$0F |
!DynamicSpaceConfigSecondHalfSP2andSP34
|
$10 |
!DynamicSpaceConfigSP234
|
$11 |
!DynamicSpaceConfigSecondHalfSP1andSP234
|
$12 |
!DynamicSpaceConfigSP1234
|
$13 |
!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayer
|
$14 |
!DynamicSpaceConfigSP1234WithPlayer
|
$15 |
!DynamicSpaceConfigSecondHalfSP3ndSP4WithDSX
|
$16 |
!DynamicSpaceConfigSP34WithDSX
|
$17 |
!DynamicSpaceConfigSecondHalfSP2andSP34WithDSX
|
$18 |
!DynamicSpaceConfigSP234WithDSX
|
$19 |
!DynamicSpaceConfigSecondHalfSP1andSP234WithDSX
|
$1A |
!DynamicSpaceConfigSP1234WithDSX
|
$1B |
!DynamicSpaceConfigSecondHalfSP1andSP234WithPlayerAndDSX
|
$1C |
!DynamicSpaceConfigSP1234WithPlayerAndDSX
|
Spell these names exactly as published in DXDefines.asm, including names such as SecondHalfSSP4 and SP11WithPlayer.
Other constants
| Define | Value or use |
|---|---|
!AN2Buffer1 / !AN2Buffer2 |
Animation data addresses $7EC100 and $7EAD00.
|
!GFX32Buffer |
$7E2000, the usual GFX32 buffer address.
|
!PlayerPaletteColor2To5 |
$00B280, player palette colors 2–5.
|
!PlayerBasePalette |
$00B2C8, player base palette data.
|
!VRAMTransferSize / !CGRAMTransferSize |
Both are 64 in the current template. Reserve transfer tables; they are not the per-frame byte limit. |
Installation options such as !DynamicPoses, !DrawingSystem, !GraphicsChange, !PalettesChange, !PalettesEffects, !PlayerFeatures, and !YoshiFeatures come from Options.asm. They identify installed features and are not changed at runtime.
Generated defines
Dynamic Xtreme creates these defines during resource installation and adds them to DXDefines.asm. Use their names rather than copied numeric values, because IDs, addresses, and sizes may change when resources are added or modified.
Names use PascalCase normalization: remove spaces, underscores, hyphens, and other separators and capitalize each word's first letter. For example, my_sprite, my-sprite, and my sprite become MySprite. Other existing capitalization is preserved. When unsure, copy the exact name from DXDefines.asm.
Dynamic poses and drawing poses
| Family or example | Meaning |
|---|---|
!DynamicPoseIDMySprite000 |
ID of pose graphics declared in DynamicInfo. Used to request loading with !Upload.
|
!DynamicPoseMySprite000 |
ROM address of those graphics. |
!DynamicPoseMySprite000Size |
Graphics data size in bytes. |
!PoseIDMySprite_Frame0 |
DrawInfo pose ID. Used for drawing with !DXDraw or DrawStatic.
|
!RenderBoxXDistanceOutOfScreenMySprite |
Horizontal distance calculated from DrawInfo to determine when the sprite is no longer visible. |
!RenderBoxYDistanceOutOfScreenMySprite |
Vertical distance for the same check. |
Dynamic IDs choose which graphics to load; drawing IDs choose how tiles form the pose. These are different values. Do not substitute a !DynamicPoseID... for a !PoseID....
Palettes and effects
| Family or example | Meaning |
|---|---|
!PaletteIDMyPalette |
ID of a palette declared in DynamicInfo. |
!PaletteMyPalette |
ROM address of its colors. |
!PaletteMyPaletteSize |
Palette size in bytes. |
!MySpritePaletteTableOffset |
Start of that DynamicInfo's palette list. Passed to !PaletteAssignment and its variants.
|
!PaletteEffectIDMyEffect0 |
Effect ID from my_effect.paleffect. The suffix is the effect's index within the file; global IDs start at 1.
|
!PaletteMyTargetRGB / !PaletteMyTargetHSL |
ROM address of a target palette converted for an RGB/HSL transition. Generated when an effect needs that palette. |
!PaletteMyTargetRGBSize / !PaletteMyTargetHSLSize |
Converted palette sizes in bytes. |
Example names follow the same normalization: my_palette becomes MyPalette and my_effect becomes MyEffect. Defines are generated during installation and stored in DXDefines.asm.
General resources and buffers
| Family or example | Meaning |
|---|---|
!ResourceIDMyResource |
General resource ID from DynamicInfo. |
!ResourceMyResource |
Resource ROM address. |
!ResourceMyResourceSize |
Resource size in bytes. |
!BufferIDMyBuffer |
ID of a tool-inserted buffer. |
!BufferMyBuffer |
ROM address of the inserted buffer, not temporary RAM. |
!BufferMyBufferSize |
Buffer size in bytes. |
Names depend on installed resources and use the same normalization: my_resource becomes MyResource. Check DXDefines.asm for your installation's names and values.
Generated counts and tables
These defines expose counts and tables generated during installation. Normal sprites usually need only the individual IDs in the tables above.
| Define | Meaning |
|---|---|
!NumberOfDynamicPoses / !NumberOfPoses |
Installed dynamic pose count and drawing pose count, respectively. |
!NumberOfPalettes / !NumberOfResources / !NumberOfBuffers |
Inserted normal palette, general resource, and buffer counts. |
!NumberOfPaletteEffects |
Value used to size effect tables. Generation includes space for ID 0; do not interpret this as a single *.paleffect file's effect count.
|
!PaletteTableSize |
Total entries in DynamicInfo palette lists. |
!PaletteIDTables |
Address of those lists' ID table. |
!PaletteAddrTables |
Address of the table containing their color ROM addresses. |
!PaletteEffectsTypes |
Table of installed effect types. |
!PaletteEffectsChannels1, !PaletteEffectsChannels2, !PaletteEffectsChannels3 |
Tables of each effect's color values. |
!PaletteEffectsRatios1, !PaletteEffectsRatios2, !PaletteEffectsRatios3 |
Ratio tables controlling each change's strength. |
!BufferTable, !PaletteTables, !PaletteEffectsTable |
Table addresses published by the patch. |
Routine defines
These defines represent system calls, not data variables. This table helps locate them; their use is explained in the routine and macro sections.
| Define or family | Use |
|---|---|
!AllowedGameMode |
Checks whether the current game mode permits the corresponding operations. |
!DynamicPoseSpaceConfig |
Selects VRAM regions available for dynamic poses. |
!TakeDynamicRequest |
Requests a pose by ID. |
!DynamicRoutine |
Prepares pose graphics transfers to VRAM. |
!SetPropertyAndOffset |
Gets a dynamic pose's graphics location and properties for drawing. |
!Draw / !Draw_Return |
Drawing routine entry and return point. |
!RemapOamTile |
Adjusts tile numbers for the actual dynamic graphics location. |
!IsValid, !XIsValid, !YIsValid |
Drawing checks to determine tile visibility. |
!AssignPalette |
Selects a palette destination according to assignment mode. |
!LoadPaletteOnBuffer |
Loads palette data into a working buffer. |
!SetRGBBase / !SetHSLBase |
Prepares colors for RGB/HSL effects. |
!RGBToHSL / !HSLToRGB |
Converts between color spaces. |
!RGBMerge |
Converts separate RGB colors to SNES palette format. |
!Mix... / !MixAndMerge... |
Changes one or more color components. |
!PalTransitionRGB / !PalTransitionHSL |
Calculates a palette transition. |
!PalTransitionAndMergeRGB / !PalTransitionAndMergeHSL |
Calculates a transition and produces SNES-format colors. |
!DoEffect / !DoEffectAndMerge |
Applies an effect by ID. |
!PalFunctionRGB, !PalFunctionHSL, and AndMerge variants |
Reserved names for color functions not implemented yet. |
!Routines is the table address used to obtain these calls. You do not need to calculate offsets to use published defines.
CPU state and temporary memory
Each call requires the register widths specified in its inputs. A register can return in 8-bit mode while losing its previous value: width and contents are different things.
Unless an entry states otherwise, these rules apply throughout this article:
- Run in native mode with decimal mode disabled. The system's arithmetic uses binary numbers.
- Direct page D:
$0000on LoROM and$3000in the usual SA-1 Pack context. Short addresses such as$00are relative to that base. Calls do not prepare or change D for you. - Data bank DBR: must allow access to the RAM mirrors and hardware registers used by the call. The usual context uses banks with these mirrors, such as
$00-$3For$80-$BF. If an operand reads a table through a 16-bit address, DBR must also allow access to that table. A 24-bit pointer carries its own bank.DynamicRoutinehas a specific DBR requirement explained in its entry. - Calls preserve DBR and D. Some change DBR temporarily and restore it before returning. This does not make every input bank valid.
- Flags: only use explicitly documented output flags. Do not assume N, Z, V, or carry retain their old values. A and X/Y width changes are specified per call.
- Temporary memory: listed scratch may be overwritten on success or failure. Save values needed afterward elsewhere. Outputs are valid only under the stated conditions.
- Stack: calls remove their own temporary stack data. Match your own pushes and pulls at the same register width and respect the routine or macro's return type.
To preserve a register, save it before the call and restore it afterward at the same width. Check returned carry before another operation changes it; restoring P with PLP also replaces that carry.
Sprite routines
These routines check whether a sprite should be drawn, load its graphics, and manage its palettes. Include the appropriate defines file first: NormalSpriteDefines.asm, ClusterSpriteDefines.asm, or ExtendedSpriteDefines.asm. Its path is relative to the sprite ASM.
DBR, D, flag, and stack requirements are explained in CPU state and temporary memory. The table below distinguishes register widths from preserved values.
Write calls such as !RenderBox or !Upload directly, as in the examples. Do not prefix them with JSR or JSL. Unless stated otherwise, X must contain the sprite slot index.
Sprite call registers and scratch
Enter with 8-bit X and Y. A's width depends on the call:
| Call | A on entry | Registers on return | Scratch potentially overwritten |
|---|---|---|---|
!RenderBox
|
8 bits. | A changes and returns in 8-bit mode. X and Y retain their values and widths. | No scratch; modifies the Dynamic Xtreme tables described in its entry. |
!PaletteAssignment and !PaletteAssignmentNoUpload
|
16 bits with PalettesChange enabled; 8 bits when disabled, without using the table offset.
|
A and Y may change. X is reloaded from !SpriteIndex when used internally. The no-upload variant returns information in Y. All three return in 8-bit mode.
|
$00-$0F, $65-$67, and $D5, depending on the path. With effects, may also use the effect temporaries listed below.
|
!Upload and !UploadWithoutPoseOffset
|
16 bits. | A and Y may change. X is restored from !SpriteIndex. All three return in 8-bit mode.
|
$00-$0F and $47-$51 when preparing a new load.
|
!DXDraw and !DXDrawWithOffset
|
16 bits. | A and Y may change. When drawing, X is restored from !SpriteIndex; if no valid pose exists, input X is retained. All three return in 8-bit mode.
|
$00-$0F, $45-$4F, and $8A. Additional offsets also use $8B-$8C.
|
!ReplacePalette
|
8 bits. | A and Y may change. X is restored from !SpriteIndex. All three return in 8-bit mode.
|
$00-$01 and temporaries used for color loading; effect temporaries when applicable.
|
!ConcatenateRGBPaletteEffectToGlobal and its HSL variant
|
16 bits. | A and Y may change. X takes a palette on entry but contains !SpriteIndex on return. All three return in 8-bit mode.
|
Effect temporaries, $05-$06, and $F0-$F3.
|
PIXI maintains !SpriteIndex as the current sprite index. If you temporarily change X, calls restoring that index do not necessarily preserve the X value you supplied. After effect concatenation, X identifies the sprite again, not its palette. PIXI aliases call their shared routines and continue at the next instruction; the examples' RTS belongs to the sprite's own routine.
RenderBox
!RenderBox checks whether the sprite is on screen or close enough to its edges to keep drawing. Use it at the start of the main routine to choose between core logic only (short routine) or graphics loading, palette management, and drawing as well (long routine).
Routine used by sprite type
- Normal sprite:
%DXNormalRenderBox(). - Cluster sprite:
%DXClusterRenderBox(). - Extended sprite:
%DXExtendedRenderBox().
Inputs
- X: sprite index.
!RenderXDistanceOutOfScreen,xand!RenderYDistanceOutOfScreen,x: allowed horizontal and vertical distances outside the screen.
Result
- Carry set: the sprite is on screen or within the allowed offscreen distance; run the long routine.
- Carry clear: the sprite is too far offscreen to draw; run the short routine.
When too far offscreen, sets !Palette, !LastVersion, !LastPoseIndex, and !LastPoseHashIndex to $FF, indicating that palette and pose must be obtained again when it returns. Also combines !GlobalFlip and !LocalFlip into !LastFlip. For normal sprites, updates horizontal and vertical offscreen flags as well.
Example
print "INIT ",pc
LDA.b #!RenderBoxXDistanceOutOfScreenMySprite
STA !RenderXDistanceOutOfScreen,x
LDA.b #!RenderBoxYDistanceOutOfScreenMySprite
STA !RenderYDistanceOutOfScreen,x
; Put the rest of the sprite initialization here
RTL
SpriteCode:
!RenderBox
BCS .LongRoutine
.ShortRoutine
LDA #$00
%SubOffScreen()
; Put your sprite's logic here
RTS
.LongRoutine
; Put palette management, pose loading, drawing,
; and your sprite's logic here
RTS
The example's %SubOffScreen() is for normal sprites and takes A from 0 to 7 to select offscreen removal settings. It uses the usual value, 0. Calling it in the short routine is recommended; it is redundant in the long routine.
!RenderBoxXDistanceOutOfScreenMySprite and !RenderBoxYDistanceOutOfScreenMySprite are generated from DrawInfo and stored in DXDefines.asm. Resource names use PascalCase: remove spaces, underscores, and hyphens and capitalize each word's first letter. For example, my_sprite becomes MySprite. With multiple DrawInfo files, use the largest horizontal and vertical distances among them.
PaletteAssignment
!PaletteAssignment selects a DynamicInfo palette using !Version,x, assigns it to one of sprite palettes 8–F, and loads its colors when needed. If already assigned, resets its protection timer to 2 so another resource cannot replace it. Call every long-routine frame; this does not mean colors are uploaded every time.
If bit E of !PaletteOption,x is set ($80), it also processes the corresponding global palette effects. Otherwise the palette is excluded from the global effect.
How the palette is selected
!Version,x selects an entry from DynamicInfo's palette list: 0 for the first, 1 for the second, and so on. For a list containing red and blue palettes, versions 0 and 1 select those colors. Sprite behavior may also depend on this variable; palette management only uses it to select colors.
!PaletteOption,x determines which sprite palette may be used and whether it receives the global effect. Format: EPPP----:
E: 0 excludes the palette from the global effect; 1 allows it.PPP: in manual mode, selects palette 8–F.000selects 8,001selects 9, through111for F.- In automatic mode,
PPP = 000allows all eight palettes. Nonzero0XXlimits the search to 8–B;1XXlimits it to C–F. - The low four bits are unused by these options.
!PaletteAssignmentOption,x determines who chooses the destination and whether colors are uploaded. Format: --AA----:
AA = 00($00): automatic. Dynamic Xtreme chooses an allowed palette and loads DynamicInfo's colors.AA = 01($10): manual. Uses the palette specified byPPPand loads DynamicInfo's colors.AA = 10($20): manual without upload. Uses the specified palette with the level's existing colors.
For normal sprites, !PaletteOption,x is !ExtraByte1,x and !PaletteAssignmentOption,x is !ExtraProp2,x. Commonly use EPPPVVVV in Extra Byte 1 and copy its low four bits to !Version,x in INIT, selecting the version through Lunar Magic. For cluster and extended sprites, the spawning code must set these variables.
For example, manual !PaletteOption,x = $A0 uses palette A and allows the global effect. With !Version,x = 1, it loads the second palette from DynamicInfo.
Routine used by sprite type
- Normal sprite:
%DXNormalPaletteAssignment(). - Cluster sprite:
%DXClusterPaletteAssignment(). - Extended sprite:
%DXExtendedPaletteAssignment().
Inputs
- 16-bit A:
!MySpritePaletteTableOffsetfor the DynamicInfo containing the palettes. - X: sprite index.
!Version,x: palette index in the table.!LastVersion,x: last processed version, compared with!Version,xto detect changes. Initialize to$FF.!PaletteOption,x: palette selection and participation in the global effect.!PaletteAssignmentOption,x: automatic, manual, or manual-without-upload assignment.
Result
- Carry set: the sprite can be drawn with the assigned palette.
- Carry clear: the sprite has no palette ready for drawing yet.
!Palette,x: assigned palette, increasing by two from$00to$0Efor palettes 8–F.!LastVersion,x: updated to!Version,xwhen the new assignment is processed.- A, X, and Y return in 8-bit mode.
Example
PaletteManagement:
REP #$20
LDA #!MySpritePaletteTableOffset
!PaletteAssignment
RTS
!MySpritePaletteTableOffset is generated from DynamicInfo and stored in DXDefines.asm. The resource name uses PascalCase normalization: remove separators and capitalize each word's first letter, so my_sprite becomes MySprite.
PaletteAssignmentNoUpload
!PaletteAssignmentNoUpload selects a palette like !PaletteAssignment but leaves the color upload pending. Use it to modify the palette first, for example by applying a local effect combined with the global effect. If already assigned, resets its protection timer to 2 against replacement.
Bit E of !PaletteOption,x ($80) also controls global effects. This variant prepares assignment and the base palette; a subsequent routine such as !ConcatenateRGBPaletteEffectToGlobal or !ConcatenateHSLPaletteEffectToGlobal completes the effects and upload.
!Version,x selects the DynamicInfo palette: 0 for the first, 1 for the second. !PaletteOption,x uses EPPP----: E enables the global effect, and PPP selects palette 8–F manually or a search group automatically. In automatic mode, 000 allows all, nonzero 0XX allows 8–B, and 1XX allows C–F.
!PaletteAssignmentOption,x uses --AA----: $00 selects the destination automatically, $10 uses PPP, and $20 uses existing level colors. To prepare a palette for a later local effect, use a mode that reads DynamicInfo colors: automatic or manual with upload.
Routine used by sprite type
- Normal sprite:
%DXNormalPaletteAssignmentNoUpload(). - Cluster sprite:
%DXClusterPaletteAssignmentNoUpload(). - Extended sprite:
%DXExtendedPaletteAssignmentNoUpload().
Inputs
- 16-bit A:
!MySpritePaletteTableOffsetfor the DynamicInfo containing the palettes. - X: sprite index.
!Version,x,!PaletteOption,x, and!PaletteAssignmentOption,x: same options as!PaletteAssignment.!LastVersion,x: last processed version, compared with!Version,xto detect changes. Initialize to$FF.
Result
- Carry set: a palette is assigned; clear if one could not be obtained.
!Palette,x: assigned palette.!LastVersion,x: updated to!Version,xwhen the new assignment is processed.$00-$01: ID of the selected DynamicInfo palette when using a mode that loads its colors.$02-$04: base palette ROM address.- Y = 1: palette newly assigned and effect must be calculated; Y = 0: no recalculation needed due to a new assignment. Pass this value to the concatenation routine.
- A, X, and Y return in 8-bit mode.
Example
REP #$20
LDA #!MySpritePaletteTableOffset
!PaletteAssignmentNoUpload
BCC .Return
; Prepare and concatenate the effect here.
; Preserve Y and the $02-$04 address for that call.
.Return
RTS
$00-$01 identifies the chosen DynamicInfo palette; !Palette,x identifies the sprite palette 8–F used for drawing. $00-$04 is prepared only when the routine reads DynamicInfo. Do not treat it as output in manual-without-upload mode, with palette changes disabled, or when the current game mode does not process the call.
!MySpritePaletteTableOffset is generated from DynamicInfo and stored in DXDefines.asm. PascalCase normalization removes separators: my_sprite becomes MySprite.
Upload
!Upload makes the graphics for the sprite's current pose available for drawing. It selects the pose by adding !PoseIndex,x to the dynamic pose ID in A. If the graphics are already in VRAM, it updates their last-use record to protect them from replacement. Otherwise, it requests an upload. Call it every frame in the long routine.
Routine used by sprite type
- Normal sprite:
%DXNormalUpload(). - Cluster sprite:
%DXClusterUpload(). - Extended sprite:
%DXExtendedUpload().
Inputs
- 16-bit A: base dynamic pose ID.
- X: sprite index.
!PoseIndex,x: index added to the base ID.!GlobalFlip,xand!LocalFlip,x: flip settings combined when drawing the pose.
Result
- Carry set: the sprite has a pose it can draw. This may be the requested pose or the previous one if the new pose could not be uploaded yet.
- Carry clear: the sprite does not have a pose it can draw yet.
!LastPoseIndex,x,!LastPoseHashIndex,x, and!LastFlip,x: state of the pose available for drawing.- A, X, and Y return in 8-bit mode.
Example
PoseManagement:
REP #$20
LDA #!DynamicPoseIDMySprite000
!Upload
RTS
!DynamicPoseIDMySprite000 is generated from the DynamicInfo and written to DXDefines.asm. Names are normalized to PascalCase: separators are removed and each word starts with a capital letter, as in my_sprite → MySprite.
UploadWithoutPoseOffset
!UploadWithoutPoseOffset requests the exact dynamic pose ID in A, without adding !PoseIndex. Like !Upload, it reuses graphics already in VRAM and can keep the previous pose available until the new one can be uploaded.
Routine used by sprite type
- Normal sprite:
%DXNormalUploadWithoutPoseOffset(). - Cluster sprite:
%DXClusterUploadWithoutPoseOffset(). - Extended sprite:
%DXExtendedUploadWithoutPoseOffset()exists, butExtendedSpriteDefines.asmcurrently does not provide the!UploadWithoutPoseOffsetalias.
Inputs
- 16-bit A: exact dynamic pose ID.
- X: sprite index.
!GlobalFlip,xand!LocalFlip,x: sprite flip settings.
Result
- Carry set: the sprite has a pose it can draw. Carry clear: no pose is available yet.
- Stores the pose available for drawing in
!LastPoseIndex,xand its graphics location in!LastPoseHashIndex,x, just like!Upload. - A, X, and Y return in 8-bit mode.
Example
PoseManagement:
REP #$20
LDA #!DynamicPoseIDMySprite003
!UploadWithoutPoseOffset
RTS
!DynamicPoseIDMySprite003 is generated from the DynamicInfo and written to DXDefines.asm. Names use PascalCase, with separators removed: my_sprite becomes MySprite.
DXDraw
!DXDraw draws a pose using the dynamic graphics available to the sprite.
Routine used by sprite type
- Normal sprite:
%DXNormalDraw(). - Cluster sprite:
%DXClusterDraw(). - Extended sprite:
%DXExtendedDraw().
Inputs
- 16-bit A: drawing pose ID.
- X: sprite index.
!PropParam($52): additional properties inYXCC----format.!MaxTilePriorityParam($0A): maximum tile priority;$00highest,$01high,$02the sprite type's own priority, and$03lowest.!Palette,x,!LastFlip,x, and!LastPoseHashIndex,x: palette, flip settings, and location of the available graphics.
Result
Draws the pose on screen. If !LastPoseHashIndex,x is $FF, nothing is drawn. A, X, and Y return in 8-bit mode.
Example
Draw:
LDA #$20
STA !PropParam
LDA #$02
STA !MaxTilePriorityParam
LDA !LastPoseIndex,x
REP #$21
AND #$00FF
ADC #!PoseIDMySprite_Frame0
!DXDraw
RTS
In this example, the poses must appear in the same order in the DrawInfo and DynamicInfo. !LastPoseIndex identifies the pose that can actually be drawn: if the new pose could not be uploaded yet, the previous one is drawn instead.
!PoseIDMySprite_Frame0 is generated from the DrawInfo and written to DXDefines.asm. Resource and pose names are normalized to PascalCase by removing separators, as in my_sprite → MySprite. This drawing ID is separate from the DynamicInfo's !DynamicPoseID... IDs.
DXDrawWithOffset
!DXDrawWithOffset draws the pose a few pixels to the right, left, above, or below the sprite's position. This only changes where the pose is drawn; movement and collision still use the sprite's original position.
Routine used by sprite type
- Normal sprite:
%DXNormalDrawWithOffset(). - Cluster sprite:
%DXClusterDrawWithOffset(). - Extended sprite:
%DXExtendedDrawWithOffset().
Inputs
- The same inputs as
!DXDraw. !XOffsetParam($8A): signed 8-bit horizontal offset.!YOffsetParam($8B): signed 8-bit vertical offset.
Result
Draws the pose like !DXDraw, with the specified offsets added. A positive !XOffsetParam moves the drawing to the right, and a positive !YOffsetParam moves it down. Negative values move it left or up.
Example
Draw:
LDA #$08
STA !XOffsetParam
LDA #$F8
STA !YOffsetParam
LDA #$20
STA !PropParam
LDA #$02
STA !MaxTilePriorityParam
LDA !LastPoseIndex,x
REP #$21
AND #$00FF
ADC #!PoseIDMySprite_Frame0
!DXDrawWithOffset
RTS
The example draws the pose 8 pixels to the right and 8 pixels up. !PoseIDMySprite_Frame0 is generated from the DrawInfo and written to DXDefines.asm; names are normalized to PascalCase by removing separators, as in my_sprite → MySprite.
ReplacePalette
!ReplacePalette changes the colors of the sprite's assigned palette without changing its assignment ID. For example, it can replace the normal palette during a special state. If other sprites share that palette, their colors change too. Call it when the colors need to change; calling it every frame makes the system prepare the palette and its effects again each time.
It is commonly used after !PaletteAssignmentNoUpload: assign the palette without uploading its colors, then replace them with the colors you want. Before calling !ReplacePalette, put the address of the new colors in $02-$04.
Routine used by sprite type
- Normal sprite:
%DXNormalReplacePalette(). - Cluster sprite:
%DXClusterReplacePalette(). - Extended sprite:
%DXExtendedReplacePalette().
Inputs
- X: sprite index.
- A in 8-bit mode.
$02-$04: ROM address of the new palette in BGR555 format.!Palette,x: the assigned palette.!PaletteOption,x: whether the palette is affected by the global effect.
Result
- Carry set: the palette is ready for drawing. If the new colors are not ready yet, the previous colors remain available.
- Carry clear: the palette has no colors ready for drawing yet.
Keeps the same palette ID and requests a change to its colors. When marking the effect for recalculation, it uses $FFFF if no colors have ever been ready for drawing, or $FFFE if the previous colors can still be used while the new ones are prepared.
Example
ReplaceSpritePalette:
; Run when an assigned palette needs new colors.
LDA.b #!PaletteMyAlternatePalette
STA $02
LDA.b #!PaletteMyAlternatePalette>>8
STA $03
LDA.b #!PaletteMyAlternatePalette>>16
STA $04
!ReplacePalette
RTS
!PaletteMyAlternatePalette is the address of a palette inserted from the resources declared in a DynamicInfo. It is written to DXDefines.asm. Its name is normalized to PascalCase: my_alternate_palette becomes MyAlternatePalette.
ConcatenateRGBPaletteEffectToGlobal
!ConcatenateRGBPaletteEffectToGlobal lets the sprite's palette use its own RGB effect while still being affected by the global effect. It applies the local effect, such as PaletteTransitionRGB, first, then applies the global effect to that result. Call it after !PaletteAssignmentNoUpload, which prepares the original palette.
The usual sequence is to assign the palette with !PaletteAssignmentNoUpload, check that carry is set, then call this routine to apply the effects and finish uploading the colors.
Routine used by sprite type
- Normal sprite:
%DXNormalConcatenateRGBPaletteEffectToGlobal(). - Cluster sprite:
%DXClusterConcatenateRGBPaletteEffectToGlobal(). - Extended sprite:
%DXExtendedConcatenateRGBPaletteEffectToGlobal().
Inputs
- 16-bit A: local RGB effect ID.
- 8-bit X: copy the value of
!Palette,xhere usingLDA !Palette,xfollowed byTAX, as shown in the example. - 8-bit Y: keep the value returned by
!PaletteAssignmentNoUpload. A value of 1 forces the effect to be recalculated; 0 allows the previous result to be reused if nothing has changed. $02-$04: BGR555 base palette address prepared by palette assignment.!PaletteOption: theEbit must be set to combine the local effect with the global effect.
Result
- Carry set: the palette can be used for drawing. If the new effect is not ready yet, the previous result remains in use.
- Carry clear: the palette has no colors ready for drawing yet.
- A, X, and Y return in 8-bit mode.
Example
PaletteManagement:
REP #$20
LDA #!MySpritePaletteTableOffset
!PaletteAssignmentNoUpload
BCC .Return
LDA !Palette,x
TAX
REP #$20
LDA #!PaletteEffectIDMyRGBEffect0
!ConcatenateRGBPaletteEffectToGlobal
.Return
RTS
!MySpritePaletteTableOffset is generated from the DynamicInfo, and !PaletteEffectIDMyRGBEffect0 from a *.paleffect file. Both are written to DXDefines.asm. Names are normalized to PascalCase by removing separators, as in my_sprite → MySprite. If you use Y to select an effect from a table, save it with PHY and restore it with PLY before calling the concatenation routine.
ConcatenateHSLPaletteEffectToGlobal
!ConcatenateHSLPaletteEffectToGlobal lets the sprite's palette use its own HSL effect, such as MixH, while still being affected by the global effect. It applies the local effect first, followed by the global effect. Call it after !PaletteAssignmentNoUpload, which prepares the original palette.
The usual sequence is to assign the palette with !PaletteAssignmentNoUpload, check that carry is set, then call this routine to apply the effects and finish uploading the colors.
Routine used by sprite type
- Normal sprite:
%DXNormalConcatenateHSLPaletteEffectToGlobal(). - Cluster sprite:
%DXClusterConcatenateHSLPaletteEffectToGlobal(). - Extended sprite:
%DXExtendedConcatenateHSLPaletteEffectToGlobal().
Inputs
- 16-bit A: local HSL effect ID.
- 8-bit X: copy the value of
!Palette,xhere usingLDA !Palette,xfollowed byTAX, as shown in the example. - 8-bit Y: keep the value returned by
!PaletteAssignmentNoUpload. A value of 1 forces the effect to be recalculated; 0 allows the previous result to be reused if nothing has changed. $02-$04: BGR555 base palette address prepared by palette assignment.!PaletteOption: theEbit must be set to combine the local effect with the global effect.
Result
- Carry set: the palette can be used for drawing. If the new effect is not ready yet, the previous result remains in use.
- Carry clear: the palette has no colors ready for drawing yet.
- A, X, and Y return in 8-bit mode.
Example
PaletteManagement:
REP #$20
LDA #!MySpritePaletteTableOffset
!PaletteAssignmentNoUpload
BCC .Return
LDA !Palette,x
TAX
REP #$20
LDA #!PaletteEffectIDMyHSLEffect0
!ConcatenateHSLPaletteEffectToGlobal
.Return
RTS
!MySpritePaletteTableOffset is generated from the DynamicInfo, and !PaletteEffectIDMyHSLEffect0 from a *.paleffect file. Both are written to DXDefines.asm. Names are normalized to PascalCase: separators are removed and each word starts with a capital letter. Save and restore Y with PHY/PLY if you temporarily use it to select an effect.
Both concatenation variants handle the required conversions when the local and global effects use different color spaces. See Effect types to find out which effects use RGB or HSL.
General Routines and Macros
These routines and macros let sprites, UberASM, and other code use Dynamic Xtreme's systems. Macro arguments specify the variables and values to use. If an argument contains a comma, such as !NormalPoseIndex,x, put it in quotation marks so Asar reads it as a single argument. Use # for immediate values, such as #$04.
The rules for DBR, direct page, flags, and the stack also apply here. Each family's calling requirements explain which registers and temporary memory you must save if you need to preserve them.
Calls and returns at a glance
Some macros include the return instruction that ends the routine containing them. In those cases, code written after the macro does not run as a continuation of that routine.
| Call or family | Included return | Usage |
|---|---|---|
Sprite aliases: !RenderBox, !Upload, !DXDraw, !PaletteAssignment, and the other aliases in this category.
|
The call returns and execution continues after the alias. | Write the alias directly, without JSR or JSL. Your routine still needs its own return instruction.
|
| GeneralUpload, Upload (general macro), and StandardSpriteUpload. | RTS.
|
Place the macro at the end of a routine called with JSR.
|
| Draw, StandardSpriteDraw, and DrawStatic. | RTS.
|
Place the macro at the end of a routine called with JSR.
|
| PaletteAssignment, PaletteAssignmentNoUpload, StandardSpritePaletteAssignment, and StandardSpritePaletteAssignmentNoUpload. | RTL.
|
Place the macro at the end of a routine called with JSL.
|
| The general macro versions of ReplacePalette and ConcatenateRGBPaletteEffectToGlobal and ConcatenateHSLPaletteEffectToGlobal. | RTL.
|
Place the macro at the end of a routine called with JSL.
|
| LoadPaletteIDAndAddress and DefineDynamicSpaceConfig. | None: execution continues after the macro. | You can write more code after the macro. Your routine needs its own return instruction. |
| TransferPaletteFromAddress, FromPointer, FromTable, Resource, and ResourceWithLength. | None: execution continues after the macro. | Check carry after the macro, then continue or return according to the result. |
Base preparation, mixing, transition, DoEffect, and conversion macros, including their Default variants.
|
None: execution continues after the macro. | You can chain more operations after the macro. The two concatenation macros are the exceptions listed above. |
VRAM and CGRAM transfer macros, including Forced variants, and math macros.
|
None: execution continues after the macro. | Your routine needs its own return instruction. |
| Patch routines DynamicPoseSpaceConfig, TakeDynamicRequest, and DynamicRoutine. | The called routine returns with RTL.
|
Use JSL !NombreDeLaRutina. On return, execution resumes at the instruction after JSL; your routine still needs its own return instruction.
|
For example, a routine containing %Upload(...) is called with JSR PoseManagement and ends with the macro's own RTS. A routine containing %PaletteAssignment(...) is called with JSL PaletteManagement and ends with its RTL. The !Upload alias works differently: it calls a shared PIXI routine and allows execution to continue afterward, rather than expanding %Upload(...) directly.
Dynamic poses
DynamicPoseSpaceConfig
Registers and temporary memory: enter with A, X, and Y in 8-bit mode. Modifies A and X; preserves Y and register sizes. Uses no scratch memory. Saves and restores DBR around configuration selection. Does not return a result in carry. Called with JSL; returns with RTL.
JSL !DynamicPoseSpaceConfig selects the parts of graphics memory (VRAM) that Dynamic Xtreme can use for dynamic poses. It is normally called from UberASM's init when entering a level.
The available configurations are defined in DXDefines.asm under names beginning with !DynamicSpaceConfig....
Input
- 8-bit A: one of the
!DynamicSpaceConfig...configurations inDXDefines.asm. Values range from$00to$1C.
Result
After this call, Dynamic Xtreme can only place new poses in the selected regions. Changing the configuration does not remove poses already in VRAM. It is normally set when entering the level, before sprites request their graphics.
Example
init:
LDA #!DynamicSpaceConfigSP4
JSL !DynamicPoseSpaceConfig
RTL
!DynamicSpaceConfigSP4 is a constant in DXDefines.asm that enables SP4. Other options include !DynamicSpaceConfigSP3, !DynamicSpaceConfigSP34, and !DynamicSpaceConfigSP234. Choose a region that does not overlap the level's static graphics.
DefineDynamicSpaceConfig
%DefineDynamicSpaceConfig() specifies which VRAM regions can hold dynamic poses and which are restricted. Use it to create your own configuration instead of selecting a preset with !DynamicPoseSpaceConfig.
Parameters
%DefineDynamicSpaceConfig(init, end, restricted)
init: ID of the region's first 16×16 block.end: ID of the region's last 16×16 block. Both endpoints are included.restricted:$00allows dynamic poses in this region;$80restricts it, preventing the system from placing poses there.
All three parameters are assembly-time constants and are written without #. The first block must be less than or equal to the last, and both must be between $00 and $7F. For example, $60 through $7F covers 32 blocks.
Block numbering
For this configuration, sprite graphics memory is treated as a 128×256-pixel grid. The upper 128×128 half corresponds to SP1 and SP2; the lower 128×128 half corresponds to SP3 and SP4.
The grid is divided into 16×16 blocks: 8 blocks per row and 16 rows, for a total of 128 blocks. IDs run from left to right, continuing on the next row from top to bottom:
| Row of 16×16 tiles | Col. 0 | Col. 1 | Col. 2 | Col. 3 | Col. 4 | Col. 5 | Col. 6 | Col. 7 |
|---|---|---|---|---|---|---|---|---|
| 0 | $00 |
$01 |
$02 |
$03 |
$04 |
$05 |
$06 |
$07
|
| 1 | $08 |
$09 |
$0A |
$0B |
$0C |
$0D |
$0E |
$0F
|
| 2 | $10 |
$11 |
$12 |
$13 |
$14 |
$15 |
$16 |
$17
|
| 3 | $18 |
$19 |
$1A |
$1B |
$1C |
$1D |
$1E |
$1F
|
| 4 | $20 |
$21 |
$22 |
$23 |
$24 |
$25 |
$26 |
$27
|
| 5 | $28 |
$29 |
$2A |
$2B |
$2C |
$2D |
$2E |
$2F
|
| 6 | $30 |
$31 |
$32 |
$33 |
$34 |
$35 |
$36 |
$37
|
| 7 | $38 |
$39 |
$3A |
$3B |
$3C |
$3D |
$3E |
$3F
|
| 8 | $40 |
$41 |
$42 |
$43 |
$44 |
$45 |
$46 |
$47
|
| 9 | $48 |
$49 |
$4A |
$4B |
$4C |
$4D |
$4E |
$4F
|
| 10 | $50 |
$51 |
$52 |
$53 |
$54 |
$55 |
$56 |
$57
|
| 11 | $58 |
$59 |
$5A |
$5B |
$5C |
$5D |
$5E |
$5F
|
| 12 | $60 |
$61 |
$62 |
$63 |
$64 |
$65 |
$66 |
$67
|
| 13 | $68 |
$69 |
$6A |
$6B |
$6C |
$6D |
$6E |
$6F
|
| 14 | $70 |
$71 |
$72 |
$73 |
$74 |
$75 |
$76 |
$77
|
| 15 | $78 |
$79 |
$7A |
$7B |
$7C |
$7D |
$7E |
$7F
|
Each cell represents a 16×16 tile and contains its block ID. Rows are numbered 0–15 and columns 0–7. These IDs are separate from the 8×8 TileCodes used in DrawInfo.
| Section | Blocks | Position in the grid |
|---|---|---|
| SP1 | $00–$1F |
First four rows. |
| SP2 | $20–$3F |
Next four rows. |
| SP3 | $40–$5F |
Next four rows. |
| SP4 | $60–$7F |
Last four rows. |
Examples from the patch
These configurations use the same ranges as the patch's presets. Place them in UberASM's init, before sprites request their poses.
Use SP4 only:
init:
; Restrict SP1, SP2, and SP3.
%DefineDynamicSpaceConfig($00, $5F, $80)
; Make SP4 available for dynamic poses.
%DefineDynamicSpaceConfig($60, $7F, $00)
RTL
Use SP3 only:
init:
; Restrict SP1 and SP2.
%DefineDynamicSpaceConfig($00, $3F, $80)
; Make SP3 available for dynamic poses.
%DefineDynamicSpaceConfig($40, $5F, $00)
; Restrict SP4.
%DefineDynamicSpaceConfig($60, $7F, $80)
RTL
Use SP3 and SP4:
init:
; Restrict SP1 and SP2.
%DefineDynamicSpaceConfig($00, $3F, $80)
; Make SP3 and SP4 available as a single region.
%DefineDynamicSpaceConfig($40, $7F, $00)
RTL
Each example is an alternative configuration. Use one complete configuration covering blocks $00–$7F with consecutive, non-overlapping regions. Restrict any blocks used by the player, static sprites, or other resources whose graphics must stay in place. The macro does not detect those uses for you.
Registers and result
- A must be in 8-bit mode. The macro modifies A and the N/Z flags; it preserves X, Y, carry, DBR, and D, and does not change register sizes.
- Writes the configuration to
DX_Dynamic_Tile_SizeandDX_Dynamic_Tile_Offsetat both ends of the specified region. Uses no scratch memory. - Does not upload graphics or move poses already in VRAM. Use it to configure the available space when entering the level.
- Does not report success or failure in carry, and includes neither
RTSnorRTL: execution continues after each call. TheRTLin the examples ends UberASM'sinit.
TakeDynamicRequest
Registers and temporary memory: enter with 8-bit A and 16-bit X/Y. A, X, and Y return in 8-bit mode; their values may change. X is a valid cache entry index only when carry is set; it does not preserve the sprite index. May overwrite $00-$0F and $47-$51 when preparing a new upload. Preserves DBR and D on both success and failure. Called with JSL; returns with RTL.
JSL !TakeDynamicRequest takes a pose ID and looks for its graphics in VRAM. If they are already loaded, it marks them as in use to protect them from replacement. Otherwise, it finds space and schedules an upload for the next NMI, when the game updates graphics between frames.
Input
- 16-bit Y: exact dynamic pose ID.
Result
- Carry set: the graphics are already in VRAM or their upload has been scheduled for the next NMI. X contains the cache entry index that records their location.
- Carry clear: there is not enough VRAM space, or uploading the pose would exceed the frame's transfer limit.
- A, X, and Y return in 8-bit mode.
Example
RequestPose:
REP #$10
LDY #!DynamicPoseIDMySprite000
JSL !TakeDynamicRequest
BCC .Unavailable
; X contains the requested pose's hash table index.
; Your code can save this index to draw the pose.
RTS
.Unavailable
; Handle unavailable resources here.
RTS
!DynamicPoseIDMySprite000 is generated from the DynamicInfo and written to DXDefines.asm. Names are normalized to PascalCase by removing separators and capitalizing each word: my_sprite becomes MySprite.
This call returns the cache entry that records the graphics location, but does not store it in the sprite's variables or fall back to the previous pose if the request fails. Use !Upload for that complete behavior.
DynamicRoutine
Registers and temporary memory: sets A, X, and Y to 16-bit mode for its calculations and leaves them in 8-bit mode on return. All three values may change. May overwrite $00-$0B and $47-$51; PoseIDBackup occupies $02-$03 in direct page. Preserves D and does not change DBR: set the tables' data bank before calling it. Called with JSL; returns with RTL.
JSL !DynamicRoutine queues an upload of a pose's graphics to a specific VRAM location. The transfer takes place during NMI.
The routine needs to know which pose to copy and where to place it. It receives the destination in A, but reads the pose ID from an internal variable called PoseIDBackup. !TakeDynamicRequest prepares these values before calling it.
Required inputs
- Low 8 bits of A: starting block in the dynamic system's VRAM map. The routine converts this value into a VRAM address.
PoseIDBackup: internal 16-bit variable containing the ID of the pose to copy.- DBR (Data Bank Register): must select the bank containing the pose address and size tables.
Before calling this routine, your code must have allocated enough VRAM space and checked that the upload fits within the frame's byte limit. !TakeDynamicRequest handles both tasks.
Result
Reads the address and amount of graphics data for the pose, calculates how to place it at the destination, and adds the required transfers to the VRAM queue. A, X, and Y return in 8-bit mode. Carry does not report success or failure.
How it works
When a sprite requests a pose that is not yet in VRAM, !TakeDynamicRequest finds a place for it. It then stores the ID in PoseIDBackup and calls !DynamicRoutine with the selected position in A. !DynamicRoutine prepares the graphics transfer; NMI performs it.
Use !Upload to load a pose from sprite code. Use !TakeDynamicRequest to request one directly by ID. Calling !DynamicRoutine also requires you to prepare the internal pose ID, data bank, and destination space described above.
GeneralUpload
Registers and temporary memory: enter with 16-bit A and 8-bit X/Y. A, X, and Y return in 8-bit mode. A and Y may change; with sprite = 1 or 2, X is restored from !SpriteIndex; with sprite = 0, X is not preserved. May overwrite $00-$0F and $47-$51, including temporary values used for a new request. Preserves DBR and D. Includes RTS: use JSR to call the routine containing the macro.
%GeneralUpload() handles pose uploads like the sprite routines, but lets you choose the variables used to store the pose index, flip settings, and graphics location. This is useful for an entity with several independent poses, or for code that uses its own tables.
Parameters
%GeneralUpload(Pose16, checkLast, sprite, flip, safeCheck, withoutOffset,
safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,
globalFlip, localFlip, lastFlip)
The signature above shows the parameter order; write the actual call on one line.
Pose16: 0 uses 8-bit pose indices; 1 uses 16-bit indices.checkLast: 1 keeps the previous pose available if the new one cannot be obtained; 0 disables this fallback.sprite: 0 uses your own variables without restoring the sprite index; 1 uses sprite tables and restores X from!SpriteIndex; 2 works like 1, but requests the pose without comparing or updatinglastPoseIndex.flip: 1 combinesglobalFlipandlocalFlipintolastFlip; 0 skips this update.safeCheck: 1 usessafeLowandsafeHighto prevent duplicate requests in the same frame; 0 skips this check.withoutOffset: 0 addsposeIndexto the base ID; 1 uses the supplied ID directly.safeLowandsafeHigh: variables holding the low and high bytes of the request's frame number. They are written even whensafeCheckis 0.poseIndex: variable holding the desired pose index.lastPoseIndex: variable holding the last available pose index.lastPoseHashIndex: variable identifying the entry where Dynamic Xtreme records the graphics location in VRAM.$FFmeans no graphics are available yet.globalFlip,localFlip, andlastFlip: global, local, and combined flip variables.
Additional input
- 16-bit A: base or exact dynamic pose ID, depending on
withoutOffset. - With
sprite = 1orsprite = 2,!SpriteIndexmust contain the sprite index.
With sprite = 2, the macro requests the pose even when poseIndex equals lastPoseIndex, and leaves lastPoseIndex unchanged. If it obtains the graphics, it stores their location in lastPoseHashIndex. If the request fails and checkLast is 1, the previous graphics can still be used. safeCheck still controls whether another request is allowed in the same frame.
The value 2 does not change the index size. Select Pose16 = 1 to use 16-bit index variables. The dynamic pose ID supplied in A is always 16-bit.
sprite = 2 is commonly used for dynamic sprites with several parts, such as a head and body whose graphics must change together. By leaving lastPoseIndex unchanged, it lets the sprite code coordinate all parts before updating the pose index. The macro does not synchronize the parts itself; the calling code handles that.
Result
Returns carry set when a pose is available for drawing: either the requested pose or the previous one if checkLast allows it. Returns carry clear if neither is available. Stores the pose's state in the supplied variables and marks its graphics as in use to protect them from replacement. The macro ends with RTS; place it at the end of a routine called with JSR.
Example
PoseManagement:
REP #$20
LDA #!DynamicPoseIDMySprite000
%GeneralUpload(0, 1, 1, 1, 1, 0, "!NormalSafeFrameLowByte,x", "!NormalSafeFrameHighByte,x", "!NormalPoseIndex,x", "!NormalLastPoseIndex,x", "!NormalLastPoseHashIndex,x", "!NormalGlobalFlip,x", "!NormalLocalFlip,x", "!NormalLastFlip,x")
The example uses normal sprite tables and an 8-bit pose index. !DynamicPoseIDMySprite000 is generated from the DynamicInfo and written to DXDefines.asm; names are normalized to PascalCase by removing separators, as in my_sprite → MySprite.
Upload (general macro)
Registers and temporary memory: follows the same requirements as GeneralUpload, with Pose16 = 0. Enter with 16-bit A and 8-bit X/Y; all three return in 8-bit mode. The sprite parameter determines whether X is reloaded from !SpriteIndex. The macro includes RTS.
%Upload() is the 8-bit pose index variant of %GeneralUpload(). It is separate from the sprite alias !Upload.
Parameters
%Upload(sprite, checkLast, flip, safeCheck, withoutOffset,
safeLow, safeHigh, poseIndex, lastPoseIndex, lastPoseHashIndex,
globalFlip, localFlip, lastFlip)
Takes the same inputs as %GeneralUpload(), but indices stored in variables are always 8-bit. The macro includes the RTS that ends the routine.
The sprite parameter also accepts 2: this skips the comparison with lastPoseIndex and leaves that variable unchanged, but still updates lastPoseHashIndex when the pose is obtained. It does not enable 16-bit indices; use %GeneralUpload() with Pose16 = 1 for those.
This mode is commonly used to make several parts of a dynamic sprite change their graphics together. For example, your code can handle head and body uploads separately, then update the pose index when both parts should change. Leaving lastPoseIndex unchanged lets the sprite code control that change.
Example
PoseManagement:
REP #$20
LDA #!DynamicPoseIDMySprite000
%Upload(1, 1, 1, 1, 0, "!NormalSafeFrameLowByte,x", "!NormalSafeFrameHighByte,x", "!NormalPoseIndex,x", "!NormalLastPoseIndex,x", "!NormalLastPoseHashIndex,x", "!NormalGlobalFlip,x", "!NormalLocalFlip,x", "!NormalLastFlip,x")
!DynamicPoseIDMySprite000 is generated from the DynamicInfo and written to DXDefines.asm. Names use PascalCase, with separators removed: my_sprite becomes MySprite.
StandardSpriteUpload
Registers and temporary memory: follows GeneralUpload with sprite = 1. Enter with 16-bit A and 8-bit X/Y. On return, X contains !SpriteIndex; A and Y may change, and all three are in 8-bit mode. Uses the same scratch memory and ends with RTS.
%StandardSpriteUpload(withoutOffset, type) automatically selects the Dynamic Xtreme tables for a normal, cluster, or extended sprite. PIXI's upload routines use this macro.
Parameters and inputs
withoutOffset: 0 adds!PoseIndexto the base ID; 1 uses the exact ID.type:"Normal","Cluster", or"Extended".- 16-bit A: dynamic pose ID.
!SpriteIndex: sprite index.- Dynamic Xtreme pose and flip tables for the selected sprite type, initialized as described for
!Upload.
Result
Selects the variables for the specified sprite type. Keeps the previous pose available if the new one is not ready, updates flip settings, and prevents duplicate requests in the same frame. Carry works as it does for !Upload. The macro includes the RTS that ends the routine.
Example
PoseManagement:
REP #$20
LDA #!DynamicPoseIDMySprite000
%StandardSpriteUpload(0, "Normal")
!DynamicPoseIDMySprite000 is generated from the DynamicInfo and written to DXDefines.asm. Names are normalized to PascalCase: my_sprite becomes MySprite, with separators removed.
Pose drawing
Macros in this category end the routine containing them with RTS. Call the example routines with JSR. A must hold the 16-bit drawing pose ID; prepare !PropParam ($52) and !MaxTilePriorityParam ($0A) as described for !DXDraw.
Draw
Registers and temporary memory: enter with 16-bit A and 8-bit X/Y. A and Y may change. With sprite = 1, X is restored from !SpriteIndex when preparing a valid pose; with sprite = 0, the original X is not preserved. If no valid pose is available, X is unchanged. All three return in 8-bit mode. May overwrite $00-$0F, $45-$4F, and $8A; with offset = 1, also $8B-$8C. Preserves DBR and D. Includes RTS.
%Draw() draws a dynamic pose. Its arguments specify the graphics, palette, flip settings, and position to use.
Parameters
%Draw(offset, sprite, lastPoseHashIndex, lastFlip, palette, xl, xh, yl, yh)
offset: 0 uses the supplied coordinates; 1 adds the signed 8-bit offsets!XOffsetParam($8A) and!YOffsetParam($8B).sprite: 1 restores the sprite index in X from!SpriteIndexbefore reading its palette and position; 0 skips this step.lastPoseHashIndex: variable identifying the entry where Dynamic Xtreme records the pose's graphics. If it contains$FF, nothing is drawn.lastFlip: variable or value specifying the flip settings for drawing.palette: palette variable or value;$00selects palette 8,$02selects 9, and so on up to$0Efor F.xlandxh: variables or values for the low and high bytes of the X position.ylandyh: variables or values for the low and high bytes of the Y position.
Result
Draws the pose using the graphics identified by lastPoseHashIndex at the supplied X and Y position. You can pass a sprite's position variables or specify another position to draw from UberASM or other code.
Example
DrawPose:
LDA #$20
STA !PropParam
LDA #$02
STA !MaxTilePriorityParam
REP #$20
LDA #!PoseIDMySprite_Frame0
%Draw(0, 1, "!NormalLastPoseHashIndex,x", "!NormalLastFlip,x", "!NormalPalette,x", "!SpriteXLow,x", "!SpriteXHigh,x", "!SpriteYLow,x", "!SpriteYHigh,x")
!PoseIDMySprite_Frame0 is generated from the DrawInfo and written to DXDefines.asm. Names are normalized to PascalCase by removing separators, as in my_sprite → MySprite. The ID must match the available dynamic graphics.
StandardSpriteDraw
Registers and temporary memory: follows Draw and uses the same scratch memory, with sprite = 1. Enter with 16-bit A and 8-bit X/Y. Set X to the sprite index before calling it, because it reads the hash index before restoring !SpriteIndex. All three return in 8-bit mode. Includes RTS.
%StandardSpriteDraw(offset, type) draws a dynamic pose using the Dynamic Xtreme tables for the selected sprite type.
Parameters and inputs
offset: 0 adds no offset; 1 uses the offsets in$8Aand$8B.type:"Normal","Cluster", or"Extended".- 16-bit A: drawing pose ID.
!SpriteIndex: sprite index.!PropParamand!MaxTilePriorityParam: properties and priority.- Dynamic Xtreme palette, last flip, and hash index tables for the selected sprite type.
Result
The same result as %Draw(), using the standard tables. PIXI's !DXDraw and !DXDrawWithOffset routines use this macro.
For normal sprites, the PIXI routines prepare the coordinate aliases !NormalXLow, !NormalXHigh, !NormalYLow, and !NormalYHigh. If you expand the macro directly, these must also be defined, as in this example.
Example
!NormalXLow = !SpriteXLow
!NormalXHigh = !SpriteXHigh
!NormalYLow = !SpriteYLow
!NormalYHigh = !SpriteYHigh
DrawPose:
LDA #$20
STA !PropParam
LDA #$02
STA !MaxTilePriorityParam
REP #$20
LDA #!PoseIDMySprite_Frame0
%StandardSpriteDraw(0, "Normal")
!PoseIDMySprite_Frame0 is generated from the DrawInfo and written to DXDefines.asm. Its name uses PascalCase, with separators removed: my_sprite becomes MySprite.
DrawStatic
Registers and temporary memory: enter with 16-bit A and 8-bit X/Y. A and Y may change; X is preserved, but all three return in 8-bit mode. May overwrite $00-$0F, $45-$4F, and $8A; with offset = 1, also $8B-$8C. In this macro, sprite does not restore X from !SpriteIndex. Preserves DBR and D. Includes RTS.
%DrawStatic() draws a static pose declared with .IsStatic in the DrawInfo. Its graphics must already be loaded at the VRAM locations specified by its tiles.
Parameters
%DrawStatic(offset, sprite, lastFlip, palette, xl, xh, yl, yh)
offset: 0 adds no offset; 1 uses the signed offsets!XOffsetParam($8A) and!YOffsetParam($8B).sprite: retained in the signature, but unused by the current implementation.lastFlip: flip variable or value;#$00draws without flipping.palette: palette variable or value;#$00selects palette 8,#$02selects 9, and so on up to#$0Efor F.xlandxh: variables or values for the low and high bytes of the X position.ylandyh: variables or values for the low and high bytes of the Y position.
Additional inputs
- 16-bit A: static drawing pose ID.
!PropParam($52) and!MaxTilePriorityParam($0A): properties and priority.!Tile($05): tile number, when all tiles in the pose use the default value of 0. If the DrawInfo specifies other values, those tile numbers are used directly.
Result
Draws the pose without looking up the dynamic graphics cache. Requires neither !LastPoseHashIndex nor a prior call to !Upload.
Example
DrawPose:
LDA #$80
STA !Tile
LDA #$20
STA !PropParam
LDA #$02
STA !MaxTilePriorityParam
REP #$20
LDA #!PoseIDMyStaticSprite_Frame0
%DrawStatic(0, 1, #$00, #$04, "!SpriteXLow,x", "!SpriteXHigh,x", "!SpriteYLow,x", "!SpriteYHigh,x")
The example uses tile $80 if the pose is configured to read it from !Tile, with no flipping and palette A. !PoseIDMyStaticSprite_Frame0 is generated from the DrawInfo and written to DXDefines.asm. Its name uses PascalCase: separators are removed and each word starts with a capital letter, so my_static_sprite becomes MyStaticSprite.
Paletas
These macros let you choose a sprite's palette, upload its colors, and change them during gameplay.
LoadPaletteIDAndAddress
Registers and temporary memory: enter with 8-bit A; the macro sets the register sizes it needs to calculate addresses. Modifies A and X. Y is not used, but switches to 8-bit mode and loses its high byte if it was previously 16-bit. All three return in 8-bit mode. Writes $00-$04 and reads $0E-$0F. Preserves DBR and D; carry does not report success. Execution continues after the macro.
%LoadPaletteIDAndAddress() retrieves a palette's ID and the ROM address of its colors. It selects a palette from the DynamicInfo: 0 for the first, 1 for the second, and so on. It does not upload colors; it provides these values for later use.
Inputs
- 8-bit A: palette index within the DynamicInfo.
$0E-$0F: store your DynamicInfo's 16-bit!MySpritePaletteTableOffsetdefine here, as shown in the example.
Result
$00-$01: palette ID.$02-$04: ROM address of its colors in BGR555 format.- A, X, and Y return in 8-bit mode.
Example
REP #$20
LDA #!MySpritePaletteTableOffset
STA $0E
SEP #$20
LDA #$01 ; Second palette in the DynamicInfo
%LoadPaletteIDAndAddress()
; $00-$01 holds its ID; $02-$04 holds its ROM address.
In PIXI, you can also use %DXLoadPaletteIDAndAddress(), with the same inputs and results. This variant calls a shared routine, then continues with the next instruction.
!MySpritePaletteTableOffset is generated from the DynamicInfo and written to DXDefines.asm. Names are normalized by removing spaces, underscores, and hyphens, then capitalizing the first letter of each word: my_sprite becomes MySprite.
PaletteAssignment (general macro)
Registers and temporary memory: enter with 8-bit X/Y and, when PalettesChange is enabled, 16-bit A. When it is disabled, enter with 8-bit A; the table offset is not used. A and Y may change; with sprite = 1, X is restored from !SpriteIndex when needed internally; with sprite = 0, X is not preserved. All three return in 8-bit mode. May overwrite $00-$0F, $D5, and effect temporary memory when applicable. Preserves DBR and D. Ends with RTL.
%PaletteAssignment() assigns and uploads a palette like !PaletteAssignment, but lets you specify the variables holding its options and state. Use it for an additional sprite palette or for code with its own variables.
If the palette is already assigned, it keeps its use timer at 2 to protect it from replacement while in use. If option bit $80 is set, it also applies the appropriate global effect.
Parameters
%PaletteAssignment(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)
sprite: 1 uses!SpriteIndexto access sprite tables; 0 lets you use variables independent of the sprite index.palette: variable receiving the assigned palette. Initialize it to$FF. Values$00,$02, ...,$0Ecorrespond to palettes 8–F.paletteAssignment: variable or value in--AA----format.$00lets Dynamic Xtreme choose the destination and upload the colors;$10uploads the colors to your chosen destination;$20uses that destination with the colors already loaded in the level.paletteOption: variable or value inEPPP----format. E = 1 enables the global effect; E = 0 excludes this palette from it. In manual mode, PPP selects palette 8 (000) through F (111). In automatic mode,000allows all palettes, nonzero0XXallows 8–B, and1XXallows C–F. These options do not use the low four bits.paletteVersion: variable or value selecting a palette from the DynamicInfo list: 0 for the first, 1 for the second, and so on. Sprite routines use!Version,xfor this.paletteLastVersion: variable holding the last processed version. Initialize it to$FF.manualIDGroupandmanualID: together, these identify the palette in manual modes. The first selects the group:#$FEfor normal,#$FCfor cluster, and#$FDfor extended sprites. The second identifies the sprite type; normal sprites use!CustomSpriteNumber,x, as shown in the example.
You can also define your own groups: for example, manualIDGroup = #$FB for the player and #$FA for another type of entity. These are examples, not predefined Dynamic Xtreme values. Choose values not already used by another group, and use manualID to distinguish resources within each group. Groups $FE, $FD, and $FC are already used by the normal, extended, and cluster sprite routines, respectively.
Additional input
- 16-bit A:
!MySpritePaletteTableOffsetfor the DynamicInfo containing the palettes. - With
sprite = 1,!SpriteIndexmust contain the sprite index.
Result
- Carry set: a palette is available for drawing. Carry clear: none is available yet.
- Stores the palette number in
paletteand updatespaletteLastVersionwhen processing the version. - A, X, and Y return in 8-bit mode.
Example
PaletteManagement:
REP #$20
LDA #!MySpritePaletteTableOffset
%PaletteAssignment(1, "!NormalPalette,x", "!NormalPaletteAssignment,x", "!NormalPaletteOption,x", "!NormalVersion,x", "!NormalLastVersion,x", #$FE, "!CustomSpriteNumber,x")
The example uses normal sprite variables. !MySpritePaletteTableOffset is generated from the DynamicInfo and written to DXDefines.asm. Names are normalized to PascalCase by removing separators: my_sprite becomes MySprite.
Call the example routine with JSL PaletteManagement. The macro includes the RTL that ends the routine, so do not place more code after it.
PaletteAssignmentNoUpload (general macro)
Registers and temporary memory: follows PaletteAssignment (general macro). In addition to carry, returns Y as described below; do not keep another value in Y if you need it afterward. Outputs in $00-$04 are valid only when a palette was read from the DynamicInfo. Ends with RTL.
%PaletteAssignmentNoUpload() selects a palette like %PaletteAssignment(), but leaves the color upload pending. This lets you apply a local effect and combine it with the global effect afterward.
Parameters and inputs
%PaletteAssignmentNoUpload(sprite, palette, paletteAssignment, paletteOption, paletteVersion, paletteLastVersion, manualIDGroup, manualID)
Takes the same parameters as %PaletteAssignment(). A receives the 16-bit table offset. Initialize palette and paletteLastVersion to $FF.
paletteVersion selects colors from the DynamicInfo list: 0 for the first palette, 1 for the second, and so on. paletteAssignment selects the mode: $00 automatic, $10 manual, and $20 manual without uploading colors. paletteOption uses EPPP----: E enables the global effect, and PPP selects palette 8–F in manual mode. In automatic mode, 000 allows all palettes, nonzero 0XX allows 8–B, and 1XX allows C–F. To apply a local effect to the DynamicInfo colors afterward, use automatic assignment or manual assignment with upload.
Result
- Carry set: a palette is assigned. Carry clear: assignment failed.
palette: assigned palette number, in steps of two from$00to$0E.paletteLastVersion: last processed version.$00-$01: ID of the palette selected from the DynamicInfo.$02-$04: ROM address of its colors.- Y = 1 means the palette was just assigned and its effect must be calculated. Y = 0 means a new assignment does not require recalculation.
- A, X, and Y return in 8-bit mode.
Use the values in $00-$04 only when the call read a palette from the DynamicInfo. If you use an existing level palette without uploading it, disable palette changes, or call from a game mode where processing is skipped, these addresses may contain values left by other code.
Example
AssignPaletteForEffect:
REP #$20
LDA #!MySpritePaletteTableOffset
%PaletteAssignmentNoUpload(1, "!NormalPalette,x", "!NormalPaletteAssignment,x", "!NormalPaletteOption,x", "!NormalVersion,x", "!NormalLastVersion,x", #$FE, "!CustomSpriteNumber,x")
After calling AssignPaletteForEffect with JSL, check carry and apply the effect using the returned values. Keep Y and $02-$04 intact for the concatenation call.
The macro ends its routine with RTL. Put the effect code after the JSL AssignPaletteForEffect call, not after the macro inside that routine.
!MySpritePaletteTableOffset is generated from the DynamicInfo and written to DXDefines.asm. Its name uses PascalCase, with separators removed: my_sprite becomes MySprite.
StandardSpritePaletteAssignment
Registers and temporary memory: follows PaletteAssignment (general macro), with sprite = 1. Enter with X set to read the sprite's tables and !SpriteIndex identifying the same sprite. Restores X from that index when needed internally; A and Y may change. Includes RTL.
%StandardSpritePaletteAssignment() uses the palette variables for the specified sprite type. PIXI's palette assignment routines use this macro.
Parameters and inputs
%StandardSpritePaletteAssignment(type, manualIDGroup, manualID)
type:"Normal","Cluster", or"Extended".manualIDGroup:#$FEfor normal,#$FCfor cluster, or#$FDfor extended sprites.- You can also choose your own group, such as
#$FBfor the player or#$FAfor another type of entity, provided no other group in your project uses those values. manualID: variable or value identifying the sprite type in manual modes.- 16-bit A:
!MySpritePaletteTableOffsetfor the DynamicInfo containing the palettes. !SpriteIndex: sprite index.- Dynamic Xtreme palette, option, version, and last-version variables for the selected type, prepared as described for
!PaletteAssignment.
Result
The same result as !PaletteAssignment: stores the assigned palette in the sprite table and returns carry set when it can be used for drawing.
The macro includes RTL. Call the example routine with JSL PaletteManagement and do not place more code after the macro.
Example
PaletteManagement:
REP #$20
LDA #!MySpritePaletteTableOffset
%StandardSpritePaletteAssignment("Normal", #$FE, "!CustomSpriteNumber,x")
!MySpritePaletteTableOffset is generated from the DynamicInfo and written to DXDefines.asm. Names are normalized to PascalCase: my_sprite becomes MySprite when separators are removed.
StandardSpritePaletteAssignmentNoUpload
Registers and temporary memory: follows PaletteAssignmentNoUpload (general macro), with sprite = 1. X and !SpriteIndex must identify the same sprite on entry. Keep the returned Y and $02-$04 intact if you will concatenate an effect. Includes RTL.
%StandardSpritePaletteAssignmentNoUpload() uses the selected sprite type's variables to assign a palette, leaving the color upload pending.
Parameters and inputs
%StandardSpritePaletteAssignmentNoUpload(type, manualIDGroup, manualID)
Takes the same parameters and inputs as %StandardSpritePaletteAssignment(). A must hold the 16-bit palette table offset.
Result
The same result as !PaletteAssignmentNoUpload: stores the assigned palette and returns carry, Y, the ID in $00-$01, and the address in $02-$04, under the conditions described in that entry.
The macro includes RTL. Call the example routine with JSL AssignPaletteForEffect. Put the effect code after that call.
Example
AssignPaletteForEffect:
REP #$20
LDA #!MySpritePaletteTableOffset
%StandardSpritePaletteAssignmentNoUpload("Normal", #$FE, "!CustomSpriteNumber,x")
!MySpritePaletteTableOffset is generated from the DynamicInfo and written to DXDefines.asm. Its name is normalized to PascalCase by removing separators: my_sprite becomes MySprite.
ReplacePalette (general macro)
Registers and temporary memory: enter with 8-bit A, X, and Y, and the source pointer in $02-$04. A and Y may change; with sprite = 1, X is restored from !SpriteIndex; with sprite = 0, X is not preserved. All three return in 8-bit mode. May overwrite $00-$01 and effect temporary memory when applicable. Preserves DBR and D. Ends with RTL.
%ReplacePalette() replaces the colors of a palette already in use. It works like !ReplacePalette, but lets you choose which variables to read. Other sprites or code sharing that palette will also use the new colors.
It is commonly used after assignment without upload, such as %PaletteAssignmentNoUpload(). First obtain the assigned palette, then put the address of the replacement colors in $02-$04.
Parameters and inputs
%ReplacePalette(sprite, paletteOption, palette)
sprite: 1 retrieves the sprite index from!SpriteIndex; 0 uses variables independent of that index.paletteOption: palette option variable or value. Bit$80controls whether the global effect is applied.palette: destination palette variable or value, in steps of two from$00to$0E.$02-$04: ROM address of the new BGR555 colors.- A in 8-bit mode.
Result
Changes the colors without changing the assignment ID. Returns carry set when colors are available for drawing, including the previous colors if the change could not be completed yet. Returns carry clear if no result is available.
Call it when the colors need to change. Calling it every frame makes the system prepare the palette and its effects again each time.
Call the example routine with JSL ReplaceSpritePalette. The macro includes the RTL that ends the routine.
Example
ReplaceSpritePalette:
LDA.b #!PaletteMyAlternatePalette
STA $02
LDA.b #!PaletteMyAlternatePalette>>8
STA $03
LDA.b #!PaletteMyAlternatePalette>>16
STA $04
%ReplacePalette(1, "!NormalPaletteOption,x", "!NormalPalette,x")
!PaletteMyAlternatePalette is the address of a palette inserted from the DynamicInfo's resources and written to DXDefines.asm. Its name is normalized by removing separators and capitalizing each word: my_alternate_palette becomes MyAlternatePalette.
Uploading colors with TransferPalette
These macros upload colors to a palette you choose, without automatic assignment. Use them to change a background palette, a palette set aside for a sprite, or colors prepared in RAM.
They also update the game's palette copies and prepare the effect state, unlike the PPU transfer macros. You do not need to copy the buffers or invalidate their effect flags manually.
Common parameters
CGRAMOffset: first color to change, from$00to$FF. This is an 8-bit operand:#$91starts at color 1 of palette 9;$00uses the number stored in that scratch byte.Length: number of bytes to copy. This is an assembly-time value, without#:$001Ecopies 15 colors. It must be positive and even, and the upload must not extend beyond the last CGRAM color.GlobalEffect: use0to upload without the global effect, or1to apply the global effect. This is a fixed option in the call, not a RAM variable.
What GlobalEffect does
| Value | Behavior |
|---|---|
0 |
Schedules a transfer of the colors without an effect and updates the SMW and Dynamic Xtreme buffers. If effects are enabled, excludes the modified palettes from the global effect. |
1 |
Stores the original colors so the system can apply the global effect before uploading them. Marks the modified palettes to receive the effect and clears their previous effect flags. |
With GlobalEffect = 1, no unaffected version is uploaded first: the upload waits for the effect result. This also prepares a palette for global effects when the current global effect ID is still 0. If palette effects are disabled in the installation, the call uses a direct upload.
These options affect every 16-color palette touched by the upload, not just the copied colors. When uploading with the global effect enabled, supply all visible colors of each affected palette: for example, the 15 colors of a sprite palette, starting at color 1. Do not rely on a partial upload to preserve original colors you have not prepared yet.
Common inputs and results
- Enter with 8-bit A, X, and Y. D must be
$0000in LoROM or$3000in the usual SA-1 Pack context. DBR must allow access to SMW's palette buffer:$0703in LoROM or its$6703mirror in SA-1. The usual banks with RAM mirrors, such as$00-$3Fand$80-$BF, allow these accesses. If you pass tables using 16-bit addresses, DBR must also allow access to them. - Carry set: the direct transfer was accepted, or the original colors were prepared for the global effect. In the latter case, this does not mean the result has already been uploaded to CGRAM.
- Carry clear: the direct transfer was rejected because of the frame's data limit. You can retry later; the buffers and effect flags for this upload remain unchanged.
- A and X may change on both success and failure. Y may change when colors are copied; do not use it to preserve another value across calls. All three return in 8-bit mode in either case. DBR and D are preserved.
- Calls may modify
$68-$6Dwhen effects are enabled. TheFromAddress,FromTable, andResourcevariants, includingResourceWithLength, also use$65-$67. Do not store the source pointer or destination color in scratch memory that the call overwrites before it finishes using those values. - Includes neither
RTSnorRTL: execution continues after the macro.
If the source is in RAM, you must keep its contents unchanged until the scheduled transfer takes place. The source data must not cross a bank boundary. For CGRAMOffset, use an immediate value or a variable that remains valid after the macro changes X and Y; avoid operands indexed by those registers.
Call these macros when the colors need to change, rather than every frame while the palette stays the same. If you use a sprite palette at a fixed destination, restrict it so automatic assignment does not use it.
TransferPaletteFromAddress
%TransferPaletteFromAddress() uploads colors from an address known at assembly time. This can be a label in your code or a define containing the resource's full address.
Parameters
%TransferPaletteFromAddress(Address, CGRAMOffset, Length, GlobalEffect)
Address: full source address, without#.- Other parameters and carry work as described in Uploading colors with TransferPalette.
Example
; Palette 9, colors 1-F, with the global effect.
%TransferPaletteFromAddress(!PaletteMyPalette, #$91, $001E, 1)
!PaletteMyPalette is generated when installing a palette declared in a DynamicInfo's Palettes section and written to DXDefines.asm. Names use PascalCase: spaces, underscores, and hyphens are removed, and each word starts with a capital letter. For example, my_palette becomes MyPalette.
TransferPaletteFromPointer
%TransferPaletteFromPointer() uses a source address already stored in three consecutive scratch bytes. This is useful when your code selects a palette during gameplay.
Parameters
%TransferPaletteFromPointer(Pointer, CGRAMOffset, Length, GlobalEffect)
Pointer: address of the first scratch byte, without#. The three bytes must hold the source address in low-byte, high-byte, bank order. For example,$02uses$02-$04.- Other parameters and carry work as described in Uploading colors with TransferPalette.
Example
; Put the palette address in $02-$04.
REP #$20
LDA.w #!PaletteMyPalette
STA $02
SEP #$20
LDA.b #!PaletteMyPalette>>16
STA $04
; Palette 9, colors 1-F, without the global effect.
%TransferPaletteFromPointer($02, #$91, $001E, 0)
!PaletteMyPalette is generated from a DynamicInfo palette and written to DXDefines.asm. Its name is normalized to PascalCase by removing separators: my_palette becomes MyPalette.
TransferPaletteFromTable
%TransferPaletteFromTable() accepts the source's two address bytes and bank byte separately. These can come from tables, variables, or immediate values. The macro combines them in $65-$67.
Parameters
%TransferPaletteFromTable(TableAddr, TableBNK, CGRAMOffset, Length, GlobalEffect)
TableAddr: operand read with 16-bit A to obtain the two address bytes.TableBNK: operand read with 8-bit A to obtain the bank.- Other parameters and carry work as described in Uploading colors with TransferPalette.
Example
; $02-$03 holds the address; $04 holds the bank.
%TransferPaletteFromTable("$02", "$04", #$91, $001E, 1)
Unlike FromPointer, the address and bank operands do not need to occupy consecutive bytes. If you read them from tables in your code, the data bank must allow access to those tables.
TransferPaletteResource
%TransferPaletteResource() uploads an entire palette registered in the DynamicInfo. You do not need to specify its address or byte count.
Parameters
%TransferPaletteResource(Name, CGRAMOffset, GlobalEffect)
Name: normalized palette name, without the!Paletteprefix or file extension. The macro uses!Palette<Name>and!Palette<Name>Size.- Other parameters and carry work as described in Uploading colors with TransferPalette.
Example
; MyPalette contains 15 colors.
%TransferPaletteResource(MyPalette, #$91, 1)
BCS .Accepted
; Direct upload rejected: retry later.
RTL
.Accepted
; Continue with the rest of the code.
The example continues at .Accepted if the direct upload was accepted or the colors were prepared for the global effect. The RTL belongs to the example, not the macro.
MyPalette corresponds to !PaletteMyPalette and !PaletteMyPaletteSize, generated in DXDefines.asm from the DynamicInfo's Palettes section. Names use PascalCase, with spaces, underscores, and hyphens removed: my_palette becomes MyPalette. This call does not use !Resource... defines from the Resources section or converted RGB/HSL palettes from a *.paleffect file.
TransferPaletteResourceWithLength
%TransferPaletteResourceWithLength() uses a registered palette's address, but copies only the number of bytes you specify.
Parameters
%TransferPaletteResourceWithLength(Name, CGRAMOffset, Length, GlobalEffect)
Name: normalized palette name, as in%TransferPaletteResource().Length: number of bytes to copy, without#. Must not exceed the resource size.- Other parameters and carry work as described in Uploading colors with TransferPalette.
Example
; Copy 4 colors to the start of palette 9, without the global effect.
%TransferPaletteResourceWithLength(MyPalette, #$90, $0008, 0)
MyPalette uses !PaletteMyPalette, generated from a DynamicInfo palette and written to DXDefines.asm. Its name is normalized to PascalCase by removing separators: my_palette becomes MyPalette.
TransferPaletteCommon and TransferPaletteData are internal components shared by these calls. To upload palettes from your code, use the variants above, which also prepare the effect state.
Palette effects
These macros change a palette's colors: tint it, adjust its brightness, transition between palettes, or apply an effect saved in a *.paleffect file.
For complete examples, see Applying a global palette effect in the UberASM guide, which covers a fixed effect, a cycle, and a transition. Changing palettes during gameplay shows how to upload colors with TransferPalette and check whether the call was accepted.
RGB works with red, green, and blue. HSL works with hue, saturation, and lightness. Choose RGB or HSL macros according to the change you want. See Effect types for the available effects.
Which call do you need?
| To… | Use… |
|---|---|
| Tint a palette or change its hue, saturation, or lightness. | Mix / MixAndMerge.
|
| Transition from one palette to another. | PaletteTransition.
|
Apply an effect already defined in a *.paleffect file. |
DoEffect / DoEffectAndMerge.
|
| Give a sprite its own effect while keeping the global effect. | ConcatenateRGBPaletteEffectToGlobal or its HSL variant, after assigning the palette without upload.
|
To calculate an effect directly, first prepare the original colors with SetRGBBase or SetHSLBase, then apply the change. The examples use Default variants, which work with Dynamic Xtreme's palette copies so you do not need to specify memory addresses.
The AndMerge variants produce colors in the format the SNES needs to display them. Calculating them does not upload them automatically: palette handling or a CGRAM transfer completes the upload. When used after PaletteAssignmentNoUpload, the concatenation routines handle both color preparation and the upload.
Set A to 8-bit mode before calling the macros in these examples.
Effect registers and temporary memory
- Base preparation, mixing, transition, conversion, and
DoEffectmacros take 8-bit A, X, and Y. TheirDefaultvariants follow the same requirements. Concatenation macros take different inputs, described in their section. - These macros prepare their arguments and call the patch routine internally. Execution then continues at the next instruction; they do not include a return that ends your routine.
- Treat A, X, and Y as temporary; they return in 8-bit mode. Carry does not report success or failure: the result is the colors written to the destination buffer. DBR and D are preserved under the CPU state rules.
- Depending on the operation, they may overwrite
$00-$0F,$45-$54,$6A,$8A-$8F, and$D5-$D7. These locations hold pointers, lengths, channels, and ratios; do not store values there that must survive the call. - Source and destination banks are read with 8-bit A; addresses, offsets, and color counts are read with 16-bit A during preparation. Channels and ratios are read with 8-bit A. The
DoEffectID is read with 16-bit A. Prepare memory operands at the corresponding size. - If your operands are indexed, X and Y must identify their data on entry. Their values may change during the call. In the full variants, arguments must also avoid overlapping temporary values prepared before those arguments are read.
Preparing colors: SetRGBBase and SetHSLBase
Before changing colors, you need a working copy for the effect calculations. %SetRGBBase() prepares it for RGB effects; %SetHSLBase() prepares it for HSL. If the original colors have not changed, you can reuse this copy in later frames.
The Default variants only require the first color and the number of colors to prepare:
%SetRGBBaseDefault(offset, length) %SetHSLBaseDefault(offset, length)
offset is the first color number, and length is the color count. For example, #$0081 and #$000F select palette 8's 15 visible colors.
Use the full versions if you need to choose the addresses to read from and write to:
%SetRGBBase(src, srcbnk, dst, dstbnk, offset, length) %SetHSLBase(src, srcbnk, dst, dstbnk, offset, length)
%SetRGBBaseDefault(offset, length) and %SetHSLBaseDefault(offset, length) read from DX_PPU_CGRAM_PaletteCopy and write the result to DX_PPU_CGRAM_BaseRGBPalette or DX_PPU_CGRAM_BaseHSLPalette.
Example: preparing a sprite palette
; Palette 8, excluding its first, transparent color.
%SetRGBBaseDefault(#$0081, #$000F)
; Use this variant instead to work in HSL:
; %SetHSLBaseDefault(#$0081, #$000F)
$81 is palette 8's second color: the palette starts at color $80, and the next 15 colors are processed.
Mixing colors: Mix and MixAndMerge
These macros move the original colors toward values you specify. For example, move red toward 31 and green and blue toward 0 to tint a palette red. Changing the ratios gradually makes the effect fade in.
The v parameters specify the target color values, from 0 to 31. The r parameters control how far to move toward them: 0 keeps the original, 127 applies the full change, and 64 applies roughly half. The examples write these as #$00, #$7F, and #$40.
For RGB, components 1, 2, and 3 are red, green, and blue. For HSL, they are hue, saturation, and lightness.
The end of the name identifies the components to change:
| RGB | HSL | Components changed |
|---|---|---|
R, G, B |
H, S, L |
One. |
RG, RB, GB |
HS, HL, SL |
Two. |
RGB |
HSL |
All three. |
Each combination is available as Mix..., MixAndMerge..., and MixAndMerge...Default. For example: %MixR(), %MixAndMergeR(), and %MixAndMergeRDefault().
Supply the selected components' ratios first, then their target values, in the order given by the name. Source and destination addresses, first color, and color count follow. Default variants omit the addresses.
%MixRGB(r1, r2, r3, v1, v2, v3, src, srcbnk, dst, dstbnk, offset, length) %MixAndMergeRG(r1, r2, v1, v2, src, srcbnk, dst, dstbnk, offset, length) %MixAndMergeLDefault(r3, v3, offset, length)
RGB example: tinting a palette red
; Prepare palette 8's original colors.
%SetRGBBaseDefault(#$0081, #$000F)
; Move all three components roughly halfway toward pure red.
%MixAndMergeRGBDefault(#$40, #$40, #$40, #$1F, #$00, #$00, #$0081, #$000F)
The first three #$40 values set the strength of the change for red, green, and blue. The next three, #$1F, #$00, #$00, specify pure red as the target. The last two select palette 8's 15 colors.
HSL example: lightening a palette
%SetHSLBaseDefault(#$0081, #$000F)
%MixAndMergeLDefault(#$40, #$1F, #$0081, #$000F)
Only lightness changes here: #$40 applies roughly half the change, and #$1F is maximum lightness. This example is independent of the previous one.
Transitioning between palettes: PaletteTransition
These macros move each original color toward the corresponding color in another palette. Unlike Mix, each color has its own target. For example, they can transition a sprite from its normal colors to a damage palette.
The variants are PaletteTransitionRGB, PaletteTransitionHSL, PaletteTransitionRGBAndMerge, and PaletteTransitionHSLAndMerge. Both AndMerge variants also have a Default version.
%PaletteTransitionRGB(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length) %PaletteTransitionHSLAndMerge(r1, r2, r3, src, srcbnk, targetpal, targetpalbnk, dst, dstbnk, offset, length) %PaletteTransitionRGBAndMergeDefault(r1, r2, r3, targetpal, targetpalbnk, offset, length)
targetpal and targetpalbnk specify the target palette's address and bank. Prepare it with 3 bytes per color, in RGB or HSL according to the macro. The ratios control how far each component moves toward its target.
Example: calculating an intermediate transition step
; This example uses the palette copy's first 15 colors.
%SetRGBBaseDefault(#$0000, #$000F)
%PaletteTransitionRGBAndMergeDefault(#$40, #$40, #$40, #!PaletteMyTargetRGB, #!PaletteMyTargetRGB>>16, #$0000, #$000F)
The example assumes !PaletteMyTargetRGB is an RGB target palette generated when installing a transition *.paleffect. Its address is written to DXDefines.asm. Names are normalized by removing spaces, hyphens, and underscores and capitalizing each word: my_target becomes MyTarget. For HSL, use the HSL-converted palette and the corresponding macro.
Applying an effect from a file: DoEffect
%DoEffect() applies an effect from a *.paleffect file by ID. The file already defines the effect type, color values, and ratios, so you do not need to supply them individually.
%DoEffect(effect, src, srcbnk, dst, dstbnk, offset, length) %DoEffectAndMerge(effect, src, srcbnk, dst, dstbnk, offset, length) %DoEffectAndMergeDefaultRGB(effect, offset, length) %DoEffectAndMergeDefaultHSL(effect, offset, length)
effect: effect ID, such as#!PaletteEffectIDMyEffect0.- The source must contain separate RGB or HSL components, depending on the selected effect.
DoEffectwrites 3 bytes per color so you can apply further changes.DoEffectAndMergewrites colors in SNES format. TheDefaultRGBandDefaultHSLvariants select the corresponding base and write toDX_PPU_CGRAM_PaletteWriteMirror.
Example: applying an RGB effect to palette 8
%SetRGBBaseDefault(#$0081, #$000F)
%DoEffectAndMergeDefaultRGB(#!PaletteEffectIDMyEffect0, #$81, #$000F)
!PaletteEffectIDMyEffect0 is generated from a *.paleffect file and written to DXDefines.asm. Its name is normalized to PascalCase by removing separators: my_effect becomes MyEffect. The final number identifies the effect within the file. For an HSL effect, prepare the HSL base and use %DoEffectAndMergeDefaultHSL().
Converting between RGB and HSL
%RGBToHSL() converts RGB colors to HSL; %HSLToRGB() converts them back. Both read and write 3 bytes per color. Use them when you want to continue modifying a palette with an effect that uses the other color space.
%RGBToHSL(src, srcbnk, dst, dstbnk, offset, length) %HSLToRGB(src, srcbnk, dst, dstbnk, offset, length)
Example: converting the RGB base to HSL
%RGBToHSL(#DX_PPU_CGRAM_BaseRGBPalette, #DX_PPU_CGRAM_BaseRGBPalette>>16, #DX_PPU_CGRAM_BaseHSLPalette, #DX_PPU_CGRAM_BaseHSLPalette>>16, #$0081, #$000F)
The example reads palette 8's 15 colors from the RGB base and writes their equivalents to the HSL base. Prepare the RGB base before calling the conversion.
Combining a local effect with the global effect
Registers and temporary memory: these two macros take 16-bit A, 8-bit X holding the palette value, and 8-bit Y holding the result of assignment without upload. All three return in 8-bit mode. With sprite = 1, X is restored from !SpriteIndex; with sprite = 0, X is not preserved. A and Y may change. Uses effect temporary memory and $F0-$F3. Preserves DBR and D. Unlike the other effect macros, these include RTL and report availability through carry, including when reusing a previous result.
%ConcatenateRGBPaletteEffectToGlobal() and %ConcatenateHSLPaletteEffectToGlobal() apply a local effect to a palette that must also receive the global effect. The sprite calls of the same name use these macros, but the macros let you choose your palette variables.
They are commonly used after %PaletteAssignmentNoUpload() or its sprite variant: assign the palette without uploading colors, then apply the effects. Keep the assignment's returned values intact for this second call.
%ConcatenateRGBPaletteEffectToGlobal(sprite, paletteOption, palette) %ConcatenateHSLPaletteEffectToGlobal(sprite, paletteOption, palette)
sprite: 1 restores the sprite index from!SpriteIndex; 0 lets you use your own variables.paletteOption: palette option variable or value; set bit$80to include the global effect.palette: variable holding the assigned palette, in steps of two from$00to$0E.- 16-bit A: local RGB or HSL effect ID, according to the macro.
- 8-bit X: copy of the assigned palette value.
- 8-bit Y: keep the value returned by assignment without upload.
$02-$04: original color address prepared by that assignment.
Returns carry set if drawing can use the requested effect, or the previous effect while the new one is being prepared. Returns carry clear if no result is available yet. Both macros end the routine with RTL.
Example: completing assignment without upload
; Call this routine with JSL after assigning the palette without upload.
; Keep Y and $02-$04 from that call intact.
ApplyLocalEffect:
LDA !NormalPalette,x
TAX
REP #$20
LDA #!PaletteEffectIDMyEffect0
%ConcatenateRGBPaletteEffectToGlobal(1, "!NormalPaletteOption,x", "!NormalPalette,x")
!PaletteEffectIDMyEffect0 is generated from a *.paleffect file and written to DXDefines.asm. Its name is normalized to PascalCase by removing separators: my_effect becomes MyEffect. Use the HSL macro for an HSL effect. If you use Y to read an effect table, save it with PHY and restore it with PLY before concatenating.
Choosing addresses and combining several effects
The examples' Default variants choose the addresses for you. Use the full versions to store results elsewhere or apply several effects in sequence. Their address parameters are:
src: where to read the original colors;srcbnk: their bank.dst: where to write the result;dstbnk: its bank. The destination must be RAM available to your code.offset: first color to process, counting from 0.length: number of colors to process.
For a fixed address, use #Nombre for the address and #Nombre>>16 for its bank, as in the RGB-to-HSL example. You can also pass variables containing these values.
The required space depends on the operation:
| Operation | Reads | Writes |
|---|---|---|
SetRGBBase / SetHSLBase |
Standard palette: 2 bytes per color. | Separate components: 3 bytes per color. |
Mix, PaletteTransition, DoEffect without AndMerge |
Separate components: 3 bytes per color. | Separate components: 3 bytes per color. |
AndMerge variants |
Separate components: 3 bytes per color. | Standard palette: 2 bytes per color. |
RGBToHSL / HSLToRGB |
Separate components: 3 bytes per color. | Separate components: 3 bytes per color. |
For example, to apply two effects in sequence, the first must write separate components, without AndMerge. The second reads that result and uses AndMerge to prepare the palette for upload. If one effect uses RGB and the other HSL, convert the colors between steps.
Depending on the operation, the macros use temporary memory including $45-$50, $51-$53, $6A, $8A, $8C, $8E, $0E-$0F, and $D5-$D7. Do not store values there that you need to keep after the call.
PPU
These macros upload graphics to VRAM and colors to CGRAM. The SNES stores graphics in VRAM and their palettes in CGRAM.
A call schedules a transfer for the next NMI, when the game can update those memories. It does not copy the data immediately. The source data must remain available until the transfer takes place.
Which call to use
| To… | VRAM | CGRAM |
|---|---|---|
| Supply the source address and bank separately. | TransferToVRAM |
TransferToCGRAM
|
| Supply a full address and let the macro extract the bank. | TransferToVRAMFromAddr |
TransferToCGRAMFromAddr
|
| Upload an entire resource registered in Dynamic Xtreme. | TransferResourceToVRAM |
TransferResourceToCGRAM
|
| Upload a specified number of bytes from a resource. | TransferResourceToVRAMWithLenght |
TransferResourceToCGRAMWithLenght
|
The normal versions check whether the transfer fits within the frame's byte limit:
- Carry set: the transfer was scheduled.
- Carry clear: the transfer was not scheduled because it would exceed the limit. Your code can retry in another frame.
This limit is shared by all Dynamic Xtreme uploads. Several transfers in one frame use the same allowance. These macros modify A and X. If accepted, the transfer leaves A, X, and Y in 8-bit mode; if rejected, A returns in 8-bit mode, but X and Y do not necessarily change size.
Transfer limits and requirements
Keep these limits in mind before preparing the inputs:
Byte budget and transfer list capacity
| Limit | What it controls | Default |
|---|---|---|
DX_Dynamic_MaxDataPerFrame
|
Total number of bytes that may be requested in one frame. Compared against DX_Dynamic_CurrentDataSend, which counts the bytes requested by all resources.
|
$0800 bytes, shared by Dynamic Xtreme uploads.
|
| VRAM list | Number of requests its tables can hold. Each entry uses two bytes per table; !VRAMTransferSize allocates the byte count for each table.
|
!VRAMTransferSize = 64: room for 32 requests.
|
| CGRAM list | Number of requests its tables can hold. !CGRAMTransferSize sets the number of available entries.
|
!CGRAMTransferSize = 64: room for 64 requests.
|
These are separate limits. For example, 32 VRAM transfers of 2 bytes request only 64 bytes, but fill all 32 entries in the default list. You cannot add another request just because some byte budget remains.
Normal macros check the byte budget, but do not check for a free list entry. If the list is full, your code must postpone the request. Adding it anyway can write beyond the tables and corrupt other variables; there is no separate failure result for a full list. Include requests from other systems in your count: a dynamic pose may require several transfers.
Forced variants skip the byte budget check and add the requested amount to DX_Dynamic_CurrentDataSend. They do not increase list capacity or the time available for transfers. List counters are 8-bit and the byte counter is 16-bit: do not let them overflow.
Transfer requirements
| Value | Your code's responsibility |
|---|---|
| Length | Use a positive, even byte count. In DMA, $0000 means 65536 bytes, not an empty transfer. PPU macros do not check these conditions.
|
| Source | The resource or buffer must contain the requested number of bytes, without crossing a bank boundary. DMA does not continue automatically into the next bank. Split the upload if needed. |
| RAM source | You must keep the buffer unchanged until NMI performs the transfer. The list stores its address, not a copy of its data. In SA-1, use memory that the S-CPU can also read, since it performs the transfer. |
| VRAM destination | The address is measured in 2-byte words. Both the start and end must be within $0000–$7FFF and within the graphics space available to your resource. For example, $0200 bytes starting at $6000 occupy words $6000–$60FF.
|
| CGRAM destination | The destination specifies the first color. Each color occupies 2 bytes; the upload must not extend beyond color $FF. For example, 15 colors fit from $F1 onward, or $001E bytes.
|
Carry set from a normal macro means the request was accepted within the byte budget. It does not confirm that the source, destination, length, or list capacity was validated. These requirements also apply to Forced variants.
Use TransferPalette to change colors while updating SMW's palette copies and the effect state. PPU transfers to CGRAM only schedule the copy.
Register state
- Enter with 8-bit A, X, and Y. Normal versions set A to 16-bit mode internally to check the budget, but this entry state also supports
Forcedvariants, especially CGRAM transfers. - On acceptance, A and X change and all three registers return in 8-bit mode. Y is not used as a working register, but loses its high byte if you entered with 16-bit indices. On rejection, A changes and returns in 8-bit mode; X and Y retain their original values and sizes.
- Uses no scratch memory to prepare the request. Writes to the transfer lists and frame byte counter. Preserves DBR and D. DBR must allow access to the counter; some variants may also need that bank to read your memory operands.
- Source addresses and lengths are read with 16-bit A. The VRAM destination and bank argument are read with 16-bit A; supply the bank as a 16-bit value with a zero high byte. For CGRAM, the source bank and destination color are read with 8-bit A.
- X changes before several arguments are read. Do not pass X-indexed addresses assuming X will still hold the sprite index. Prefer immediate values or variables independent of X for transfer arguments.
- Includes neither
RTSnorRTL. Execution continues after expansion. Check carry from normal variants before another operation changes it.Forcedvariants do not return a success flag in carry.
These rules also apply to FromAddr, Resource, and WithLenght variants: they prepare the arguments and expand the same transfer macro.
TransferToVRAM
%TransferToVRAM() schedules a graphics transfer from ROM or RAM to VRAM.
%TransferToVRAM(VRAMOffset, ResourceAddr, ResourceBNK, Lenght)
VRAMOffset: VRAM destination address, measured in 2-byte words. For example, copying$0200bytes starting at$6000occupies words$6000-$60FF.ResourceAddr: source address within its bank.ResourceBNK: source bank.Lenght: number of bytes to copy. This spelling is retained because it is the parameter's actual name.
Example: scheduling a graphics upload
%TransferToVRAM(#$6000, #!ResourceMyGraphics, #!ResourceMyGraphics>>16, #$0200)
BCC .NotLoaded
; The transfer will take place during the next NMI.
.NotLoaded
!ResourceMyGraphics is the address of a resource registered through a DynamicInfo and written to DXDefines.asm. Its name is normalized by removing spaces, hyphens, and underscores and capitalizing each word: my_graphics becomes MyGraphics. The resource must contain the requested number of bytes.
TransferToVRAMFromAddr
Performs the same transfer, but takes the full source address. The macro separates the address and bank for you.
%TransferToVRAMFromAddr(VRAMOffset, addr, Lenght)
Write addr without #; supply the other parameters as in TransferToVRAM.
Example
%TransferToVRAMFromAddr(#$6000, !ResourceMyGraphics, #$0200)
BCC .NotLoaded
.NotLoaded
!ResourceMyGraphics is generated from a DynamicInfo resource and written to DXDefines.asm. Its name is normalized to PascalCase: my_graphics becomes MyGraphics.
TransferResourceToVRAM and TransferResourceToVRAMWithLenght
These variants take the name of a Dynamic Xtreme resource. The first copies the entire resource; the second copies the number of bytes you specify.
%TransferResourceToVRAM(VRAMOffset, ResourceName) %TransferResourceToVRAMWithLenght(VRAMOffset, ResourceName, Lenght)
For a resource with defines !ResourceMyGraphics and !ResourceMyGraphicsSize, use "MyGraphics" as ResourceName.
Example: uploading the entire resource
%TransferResourceToVRAM(#$6000, "MyGraphics")
BCC .NotLoaded
.NotLoaded
Example: uploading only its first $0200 bytes
%TransferResourceToVRAMWithLenght(#$6000, "MyGraphics", #$0200)
BCC .NotLoaded
.NotLoaded
The name and size come from the defines generated in DXDefines.asm when installing DynamicInfo resources. Use the normalized name: my_graphics becomes MyGraphics, with separators removed and each word capitalized.
TransferToCGRAM
%TransferToCGRAM() schedules a color transfer from ROM or RAM to a SNES palette.
%TransferToCGRAM(CGRAMOffset, TableAddr, TableBNK, Lenght)
CGRAMOffset: first destination color number, from$00to$FF. For example, palette 8 starts at color$80.TableAddrandTableBNK: address and bank of the colors to copy.Lenght: byte count. Each color occupies 2 bytes; 15 colors occupy$001Ebytes.
Source colors must use the standard SNES BGR555 format. If you calculated an effect, use its final 2-byte-per-color result, such as the output of an AndMerge variant.
Example: copying palette 8's 15 visible colors
%TransferToCGRAM(#$81, #DX_PPU_CGRAM_PaletteWriteMirror+$0102, #DX_PPU_CGRAM_PaletteWriteMirror>>16, #$001E)
BCC .NotLoaded
.NotLoaded
This example uses an effect result stored in DX_PPU_CGRAM_PaletteWriteMirror. Offset $0102 corresponds to color $81, since each color occupies 2 bytes. It skips the palette's first color, which is transparent for sprites.
TransferToCGRAMFromAddr
Performs the same color transfer, but takes the full source address. Write addr without #.
%TransferToCGRAMFromAddr(CGRAMOffset, addr, Lenght)
Example
%TransferToCGRAMFromAddr(#$81, DX_PPU_CGRAM_PaletteWriteMirror+$0102, #$001E)
BCC .NotLoaded
.NotLoaded
The result is the same as in the previous example: schedules an upload of 15 colors starting at palette 8's second color.
TransferResourceToCGRAM and TransferResourceToCGRAMWithLenght
These variants copy colors from a resource registered in Dynamic Xtreme. The first uses the full resource size; the second uses the byte count you specify.
%TransferResourceToCGRAM(CGRAMOffset, ResourceName) %TransferResourceToCGRAMWithLenght(CGRAMOffset, ResourceName, Lenght)
Example: copying an entire color resource
%TransferResourceToCGRAM(#$80, "MyColors")
BCC .NotLoaded
.NotLoaded
Example: copying only 15 colors
%TransferResourceToCGRAMWithLenght(#$81, "MyColors", #$001E)
BCC .NotLoaded
.NotLoaded
These examples assume a general color resource with defines !ResourceMyColors and !ResourceMyColorsSize, generated in DXDefines.asm from a DynamicInfo. Use the normalized name: my_colors becomes MyColors. In the second example, the resource must begin with the 15 colors to copy, without a transparent color before them.
Forced variants
All transfers above have a variant whose name begins with Forced. These schedule the transfer even if it exceeds the frame's byte limit. The byte count is still added to the frame's total.
| VRAM | CGRAM |
|---|---|
ForcedTransferToVRAM |
ForcedTransferToCGRAM
|
ForcedTransferToVRAMFromAddr |
ForcedTransferToCGRAMFromAddr
|
ForcedTransferResourceToVRAM |
ForcedTransferResourceToCGRAM
|
ForcedTransferResourceToVRAMWithLenght |
ForcedTransferResourceToCGRAMWithLenght
|
They take the same parameters as the versions without Forced. Carry does not report whether the transfer was accepted. Set A to 8-bit mode before using them; A, X, and Y return in 8-bit mode.
Example
%ForcedTransferResourceToVRAM(#$6000, "MyGraphics") ; Do not check carry for this variant.
MyGraphics corresponds to the DynamicInfo resource !ResourceMyGraphics in DXDefines.asm. Use the normalized name, as in my_graphics → MyGraphics.
Use Forced for uploads that need priority and whose data size you already control. Forcing too much data can exceed the time available for graphics updates. For other uploads, use the normal variants and check carry.
Math
These macros multiply and divide using SNES or SA-1 hardware, depending on the ROM. They use unsigned numbers: values represent positive quantities or zero.
Set A to 8-bit mode before calling them. The macros do not change the size of A, X, or Y for you.
Registers and temporary memory: all macros in this category, including W and After... variants, modify A and N/Z, preserve X, Y, carry, DBR, and D, and use no scratch memory. They retain their entry register sizes; A must be 8-bit for correct hardware writes. DBR must allow access to the SNES or SA-1 arithmetic registers as appropriate. Includes neither RTS nor RTL; execution continues after the macro. Results are in the hardware registers listed below, not in A. Carry does not report success or arithmetic overflow.
Writing the arguments
Mul, Div, MulAfterMul, and DivAfterDiv append the argument directly to LDA. Put the argument in quotation marks with a leading space: " #$05" produces LDA #$05.
You can also start the argument with .b, .w, or .l to select the memory access encoding. For example, if $02 holds the number to multiply:
%Mul(".b $02", " #$07")
This generates LDA.b $02 to read the first number and LDA #$07 for the second. These suffixes control address encoding; they do not change A's size. The multiplication still uses 8-bit numbers.
Variants with W, along with MulAfterDiv and DivAfterMul, already add a space before their arguments. Write their values normally, as in %MulW(#$05, #$07). The current implementation does not accept .b, .w, or .l suffixes in the same way for these variants, because the inserted space would separate LDA from the suffix.
What does W mean?
The hardware needs a short time to finish the calculation. Macros with W include that wait, so you can read the result immediately afterward. Versions without W let you run other code while the hardware calculates, but you must allow enough time before reading the result. Use a W variant if you need the result in the next instruction.
Read results through these defines:
!MultiplicationResult: 16-bit multiplication result.!DivisionResult: 16-bit division quotient.!RemainderResult: 16-bit division remainder.
These defines select the correct SNES or SA-1 address. The next calculation may overwrite previous results; save them if you need them later.
Mul and MulW
Multiply two 8-bit values to produce a 16-bit result.
%Mul(a, b) %MulW(a, b)
a and b can be immediate values, such as #$06, or 8-bit variables.
Example: 6 × 7 = 42
%MulW(#$06, #$07)
REP #$20
LDA !MultiplicationResult ; A = $002A, or 42
SEP #$20
The call without a wait is %Mul(" #$06", " #$07"). Do not read its result immediately: first run other code that does not use the multiplication or division hardware.
Div and DivW
Divide a 16-bit number by an 8-bit number. Supply the 16-bit number as two bytes: high byte first, then low byte.
%Div(ah, al, b) %DivW(ah, al, b)
ah: high byte of the number to divide.al: low byte of the same number.b: divisor, from 1 to 255.
Example: 300 ÷ 7 = 42, remainder 6
; 300 = $012C: high byte $01, low byte $2C.
%DivW(#$01, #$2C, #$07)
REP #$20
LDA !DivisionResult ; A = $002A, or 42
LDA !RemainderResult ; A = $0006
SEP #$20
You can also pass a 16-bit variable as two arguments: %DivW(MiNumero+1, MiNumero, #$07). Here, MiNumero represents a variable defined by your code.
Continuing from the previous result
AfterMul and AfterDiv variants use the previous calculation's result as the first number. You only need to supply the second number.
| Macro | Calculation |
|---|---|
MulAfterMul(b) / MulWAfterMul(b) |
Multiplies the low 8 bits of the previous multiplication result by b. |
MulAfterDiv(b) / MulWAfterDiv(b) |
Multiplies the low 8 bits of the previous quotient by b. |
DivAfterMul(b) / DivWAfterMul(b) |
Divides the full previous multiplication result by b. |
DivAfterDiv(b) / DivWAfterDiv(b) |
Divides the full previous quotient by b. |
W still means the new result can be read immediately afterward. After... variants already include the wait needed to read the previous calculation's result.
Example: two multiplications, (6 × 7) × 2 = 84
%Mul(" #$06", " #$07")
%MulWAfterMul(#$02)
REP #$20
LDA !MultiplicationResult ; A = $0054, or 84
SEP #$20
Example: division followed by multiplication, (100 ÷ 4) × 3 = 75
%Div(" #$00", " #$64", " #$04")
%MulWAfterDiv(#$03)
REP #$20
LDA !MultiplicationResult ; A = $004B, or 75
SEP #$20
Example: multiplication followed by division, (20 × 15) ÷ 4 = 75
%Mul(" #$14", " #$0F")
%DivWAfterMul(#$04)
REP #$20
LDA !DivisionResult ; A = $004B, or 75
SEP #$20
Example: two divisions, (300 ÷ 3) ÷ 4 = 25
%Div(" #$01", " #$2C", " #$03")
%DivWAfterDiv(#$04)
REP #$20
LDA !DivisionResult ; A = $0019, or 25
SEP #$20
In multiplication, the first number is always limited to 8 bits. If the previous result exceeds 255, MulAfterMul or MulAfterDiv uses only its low byte. The division macros in this table use the full 16-bit previous result.