code:
	.macro voice_directsound base_midi_key:req, pan:req, sample_data_pointer:req, attack:req, decay:req, sustain:req, release:req
	.byte 0
	_voice_directsound \base_midi_key, \pan, \sample_data_pointer, \attack, \decay, \sustain, \release
	.endm

	.macro voice_directsound_no_resample base_midi_key:req, pan:req, sample_data_pointer:req, attack:req, decay:req, sustain:req, release:req
	.byte 8
	_voice_directsound \base_midi_key, \pan, \sample_data_pointer, \attack, \decay, \sustain, \release
	.endm

	.macro voice_directsound_alt base_midi_key:req, pan:req, sample_data_pointer:req, attack:req, decay:req, sustain:req, release:req
	.byte 16
	_voice_directsound \base_midi_key, \pan, \sample_data_pointer, \attack, \decay, \sustain, \release
	.endm

	.macro _voice_directsound base_midi_key:req, pan:req, sample_data_pointer:req, attack:req, decay:req, sustain:req, release:req
	.byte \base_midi_key
	.byte 0
	.if \pan != 0
	.byte (0x80 | \pan)
	.else
	.byte 0
	.endif
	.4byte \sample_data_pointer
	.byte \attack
	.byte \decay
	.byte \sustain
	.byte \release
	.endm

	.macro voice_square_1 base_midi_key:req, pan:req, sweep:req, duty_cycle:req, attack:req, decay:req, sustain:req, release:req
	_voice_square_1 1, \base_midi_key, \pan, \sweep, \duty_cycle, \attack, \decay, \sustain, \release
	.endm

	.macro voice_square_1_alt base_midi_key:req, pan:req, sweep:req, duty_cycle:req, attack:req, decay:req, sustain:req, release:req
	_voice_square_1 9, \base_midi_key, \pan, \sweep, \duty_cycle, \attack, \decay, \sustain, \release
	.endm

	.macro _voice_square_1 type:req, base_midi_key:req, pan:req, sweep:req, duty_cycle:req, attack:req, decay:req, sustain:req, release:req
	.byte \type
	.byte \base_midi_key
	.if \pan != 0
	.byte (0x80 | \pan)
	.else
	.byte 0
	.endif
	.byte \sweep
	.byte (\duty_cycle & 0x3)
	.byte 0, 0, 0
	.byte (\attack  & 0x7)
	.byte (\decay   & 0x7)
	.byte (\sustain & 0xF)
	.byte (\release & 0x7)
	.endm

	.macro voice_square_2 base_midi_key:req, pan:req, duty_cycle:req, attack:req, decay:req, sustain:req, release:req
	_voice_square_2 2, \base_midi_key, \pan, \duty_cycle, \attack, \decay, \sustain, \release
	.endm

	.macro voice_square_2_alt base_midi_key:req, pan:req, duty_cycle:req, attack:req, decay:req, sustain:req, release:req
	_voice_square_2 10, \base_midi_key, \pan, \duty_cycle, \attack, \decay, \sustain, \release
	.endm

	.macro _voice_square_2 type:req, base_midi_key:req, pan:req, duty_cycle:req, attack:req, decay:req, sustain:req, release:req
	.byte \type
	.byte \base_midi_key
	.if \pan != 0
	.byte (0x80 | \pan)
	.else
	.byte 0
	.endif
	.byte 0
	.byte (\duty_cycle & 0x3)
	.byte 0, 0, 0
	.byte (\attack  & 0x7)
	.byte (\decay   & 0x7)
	.byte (\sustain & 0xF)
	.byte (\release & 0x7)
	.endm

	.macro voice_programmable_wave base_midi_key:req, pan:req, wave_samples_pointer:req, attack:req, decay:req, sustain:req, release:req
	_voice_programmable_wave 3, \base_midi_key, \pan, \wave_samples_pointer, \attack, \decay, \sustain, \release
	.endm

	.macro voice_programmable_wave_alt base_midi_key:req, pan:req, wave_samples_pointer:req, attack:req, decay:req, sustain:req, release:req
	_voice_programmable_wave 11, \base_midi_key, \pan, \wave_samples_pointer, \attack, \decay, \sustain, \release
	.endm

	.macro _voice_programmable_wave type:req, base_midi_key:req, pan:req, wave_samples_pointer:req, attack:req, decay:req, sustain:req, release:req
	.byte \type
	.byte \base_midi_key
	.if \pan != 0
	.byte (0x80 | \pan)
	.else
	.byte 0
	.endif
	.byte 0
	.4byte \wave_samples_pointer
	.byte (\attack  & 0x7)
	.byte (\decay   & 0x7)
	.byte (\sustain & 0xF)
	.byte (\release & 0x7)
	.endm

	.macro voice_noise base_midi_key:req, pan:req, period:req, attack:req, decay:req, sustain:req, release:req
	_voice_noise 4, \base_midi_key, \pan, \period, \attack, \decay, \sustain, \release
	.endm

	.macro voice_noise_alt base_midi_key:req, pan:req, period:req, attack:req, decay:req, sustain:req, release:req
	_voice_noise 12, \base_midi_key, \pan, \period, \attack, \decay, \sustain, \release
	.endm

	.macro _voice_noise type:req, base_midi_key:req, pan:req, period:req, attack:req, decay:req, sustain:req, release:req
	.byte \type
	.byte \base_midi_key
	.if \pan != 0
	.byte (0x80 | \pan)
	.else
	.byte 0
	.endif
	.byte 0
	.byte (\period & 0x1)
	.byte 0, 0, 0
	.byte (\attack  & 0x7)
	.byte (\decay   & 0x7)
	.byte (\sustain & 0xF)
	.byte (\release & 0x7)
	.endm

	.macro voice_keysplit voice_group_pointer:req, keysplit_table_pointer:req
	.byte 0x40, 0, 0, 0
	.4byte \voice_group_pointer
	.4byte \keysplit_table_pointer
	.endm

	.macro voice_keysplit_all voice_group_pointer:req
	.byte 0x80, 0, 0, 0
	.4byte \voice_group_pointer
	.4byte 0
	.endm

	.macro cry sample:req
	.byte 0x20, 60, 0, 0
	.4byte \sample
	.byte 0xff, 0, 0xff, 0
	.endm

	.macro cry2 sample:req
	.byte 0x30, 60, 0, 0
	.4byte \sample
	.byte 0xff, 0, 0xff, 0
	.endm


code:
	.macro pokedex_entry height, width, text_pointer, pokemon_scale, pokemon_offset, trainer_scale, trainer_offset
	.2byte \height @ in decimeters
	.2byte \width @ in hectograms
	.4byte \text_pointer
	.2byte 0 @ unused
	.2byte \pokemon_scale
	.2byte \pokemon_offset
	.2byte \trainer_scale
	.2byte \trainer_offset
	.2byte 0 @ padding
	.endm

	.macro base_stats hp, attack, defense, speed, sp_attack, sp_defense
	.byte \hp
	.byte \attack
	.byte \defense
	.byte \speed
	.byte \sp_attack
	.byte \sp_defense
	.endm

	.macro ev_yield hp, attack, defense, speed, sp_attack, sp_defense
	.2byte (\sp_defense << 10) | (\sp_attack << 8) | (\speed << 6) | (\defense << 4) | (\attack << 2) | \hp
	.endm

	.macro level_up_move level, move
	.2byte (\level << 9) | \move
	.endm

	.macro evo_entry method, parameter, target_species
	.2byte \method
	.2byte \parameter
	.2byte \target_species
	.2byte 0 @ padding
	.endm

	.macro empty_evo_entries count
	.fill 8 * \count, 1, 0
	.endm

	.macro egg_moves_begin species
	.2byte 20000 + \species
	.endm

@ If the min level equals the max level, only one level argument is needed.
	.macro wild_mon species, min_level, max_level
	.byte \min_level

	.ifb \max_level
	.byte \min_level
	.else
	.byte \max_level
	.endif

	.2byte \species
	.endm

repo_name: Lunos/pokeemerald

license: mit


code:
	@ Initialize the Trainer Hill challenge and start the timer
	.macro trainerhill_start
	setvar VAR_0x8004, TRAINER_HILL_FUNC_START
	special CallTrainerHillFunction
	.endm

	@ 0 if not spoken to yet, 1 if spoken to but not received prize, 2 if received prize
	.macro trainerhill_getownerstate
	setvar VAR_0x8004, TRAINER_HILL_FUNC_GET_OWNER_STATE
	special CallTrainerHillFunction
	.endm

	@ Try to give prize. 0 if given successfully, 1 if no room for prize, 2 if giving prize should be skipped
	.macro trainerhill_giveprize
	setvar VAR_0x8004, TRAINER_HILL_FUNC_GIVE_PRIZE
	special CallTrainerHillFunction
	.endm

	@ Check the final challenge time. 0 if new record, 1 if not, 2 if time has already been checked
	.macro trainerhill_finaltime
	setvar VAR_0x8004, TRAINER_HILL_FUNC_CHECK_FINAL_TIME
	special CallTrainerHillFunction
	.endm

	@ Resume the timer. Wont resume if owner has been spoken to or max time has been reached
	.macro trainerhill_resumetimer
	setvar VAR_0x8004, TRAINER_HILL_FUNC_RESUME_TIMER
	special CallTrainerHillFunction
	.endm

	@ Set player lost the challenge (trainerHill.hasLost) to TRUE
	.macro trainerhill_lost
	setvar VAR_0x8004, TRAINER_HILL_FUNC_SET_LOST
	special CallTrainerHillFunction
	.endm

	@ Get the current challenge status (TRAINER_HILL_PLAYER_STATUS_*)
	.macro trainerhill_getstatus
	setvar VAR_0x8004, TRAINER_HILL_FUNC_GET_CHALLENGE_STATUS
	special CallTrainerHillFunction
	.endm

	@ Buffer the current timer to string vars (mins to STR_VAR_1, secs to STR_VAR_2, fraction of sec to STR_VAR_3)
	.macro trainerhill_gettime
	setvar VAR_0x8004, TRAINER_HILL_FUNC_GET_CHALLENGE_TIME
	special CallTrainerHillFunction
	.endm

	@ FALSE if fewer than all 4 floors used, TRUE otherwise. Only FALSE in JP-exclusive modes
	.macro trainerhill_allfloorsused
	setvar VAR_0x8004, TRAINER_HILL_FUNC_GET_ALL_FLOORS_USED
	special CallTrainerHillFunction
	.endm

	@ Unknown, dummied. E-Reader association is assumed. Only side effect is setting VAR_RESULT to 0.
	.macro trainerhill_getusingereader
	setvar VAR_0x8004, TRAINER_HILL_FUNC_GET_IN_EREADER_MODE
	special CallTrainerHillFunction
	.endm

	@ TRUE if currently in a Trainer Hill challenge
	.macro trainerhill_inchallenge
	setvar VAR_0x8004, TRAINER_HILL_FUNC_IN_CHALLENGE
	special CallTrainerHillFunction
	.endm

	@ Show the post battle text for the spoken to Trainer Hill trainer
	.macro trainerhill_postbattletext
	setvar VAR_0x8004, TRAINER_HILL_FUNC_POST_BATTLE_TEXT
	special CallTrainerHillFunction
	.endm

	@ Set all Trainer Hill trainers defeated
	.macro trainerhill_settrainerflags
	setvar VAR_0x8004, TRAINER_HILL_FUNC_SET_ALL_TRAINER_FLAGS
	special CallTrainerHillFunction
	.endm

	@ TRUE if the game has been saved for the challenge, FALSE otherwise
	.macro trainerhill_getsaved
	setvar VAR_0x8004, TRAINER_HILL_FUNC_GET_GAME_SAVED
	special CallTrainerHillFunction
	.endm

	@ Set that the game has been saved for the challenge
	.macro trainerhill_setsaved
	setvar VAR_0x8004, TRAINER_HILL_FUNC_SET_GAME_SAVED
	special CallTrainerHillFunction
	.endm

	@ Clear that the game has been saved for the challenge
	.macro trainerhill_clearsaved
	setvar VAR_0x8004, TRAINER_HILL_FUNC_CLEAR_GAME_SAVED
	special CallTrainerHillFunction
	.endm

	@ FALSE if the Trainer Hill challenge was lost, TRUE otherwise
	.macro trainerhill_getwon
	setvar VAR_0x8004, TRAINER_HILL_FUNC_GET_WON
	special CallTrainerHillFunction
	.endm

	@ Set the challenge mode to HILL_TAG_* (Normal, Variety, Unique, or Expert)
	.macro trainerhill_settag tag:req
	setvar VAR_0x8004, TRAINER_HILL_FUNC_SET_TAG
	copyvar VAR_0x8005, \tag
	special CallTrainerHillFunction
	.endm


code:
	.macro window_template bg_id, x, y, width, height, palette, vram_tile_offset
	.byte \bg_id
	.byte \x
	.byte \y
	.byte \width
	.byte \height
	.byte \palette
	.2byte \vram_tile_offset
	.endm

	.macro null_window_template
	window_template 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000
	.endm

	.macro glyph_width_func font_id, func
	.4byte \font_id
	.4byte \func
	.endm

	.macro keypad_icon tile_offset, width, height
	.2byte \tile_offset
	.byte \width
	.byte \height
	.endm

	.macro font_info func, max_glyph_width, glyph_height, glyph_spacing, line_spacing, text_color, shadow_color, bg_color
	.4byte \func
	.byte \max_glyph_width
	.byte \glyph_height
	.byte \glyph_spacing
	.byte \line_spacing
	.byte \text_color << 4 @ low nybble seems unused
	.byte (\shadow_color << 4) | \bg_color
	.2byte 0 @ padding
	.endm


code:
	.global RomHeaderNintendoLogo
RomHeaderNintendoLogo:
	.space 156

RomHeaderGameTitle:
	.space 12

	.global RomHeaderGameCode
RomHeaderGameCode:
	.space 4

RomHeaderMakerCode:
	.space 2

RomHeaderMagic:
	.byte 0

RomHeaderMainUnitCode:
	.byte 0

RomHeaderDeviceType:
	.byte 0

RomHeaderReserved1:
	.space 7

	.global RomHeaderSoftwareVersion
RomHeaderSoftwareVersion:
	.byte 0

RomHeaderChecksum:
	.byte 0

RomHeaderReserved2:
	.space 2


code:
Param
(
    [Parameter(Position = 0)]
    [string]$Start,

    [Parameter(Position = 1)]
    [string]$Offset,

    [Parameter()]
    [string[]]$DiffTool
)

$ErrorActionPreference = "Stop"

$offset_default_value = "0x100"
$diff_tool_default_value = "diff"

$help = "
$($args[0]) [OPTIONS] Start [Offset]

Performs a diff on the assembly of a function in a rom. 'Start' is the start
location of the function, and 'Offset' is the number of bytes to disassemble.
The assembly is saved to *.dump files.

'Offset' is optional, and defaults to $offset_default_value. If this value is
very large (0x10000+), objdump may hang / freeze.

Requirements:
    - A clean copy of the rom named 'baserom.gba'.
    - $$ENV:DEVKITARM to point to the installation of devkitpro. By default, it is
      installed to 'C:\devkitpro\devkitARM'.

Options:
    -DiffTool <tool>   The tool to use for diffing. Defaults to '$diff_tool_default_value'. For VSCode,
                       you can use -DiffTool 'code --diff'. (Quotes are necessary around 'code --diff')
"

if ((-not (Test-Path variable:Start)) -or [string]::IsNullOrWhiteSpace($Start))
{
    Write-Host $help
    exit
}

if (-not (Test-Path variable:DiffTool) -or [string]::IsNullOrWhiteSpace($DiffTool))
{
    $DiffTool = $diff_tool_default_value
}

if (-not (Test-Path variable:Offset) -or [string]::IsNullOrWhiteSpace($Offset))
{
    $Offset = $offset_default_value
}

if (-Not (Test-Path env:DEVKITARM))
{
    Write-Host "ENV:DEVKITARM variable not set."
    Write-Host $help
    exit
}

if (-Not (Test-Path $env:DEVKITARM))
{
    Write-Host "DEVKITARM path '$env:DEVKITARM' does not exist."
    Write-Host $help
    exit
}

if (-Not (Test-Path ".\pokeemerald.gba"))
{
    Write-Host "File 'pokeemerald.gba' not found."
    Write-Host $help
    exit
}

if (-Not (Test-Path ".\baserom.gba"))
{
    Write-Host "File 'baserom.gba' not found."
}

try
{
    $start_num = [System.Convert]::ToUInt64($Start, 16)
}
catch
{
    Write-Host "Error parsing '$start_num' as a hex number."
    Write-Host $help
    exit
}

try
{
    $offset_num = [System.Convert]::ToUInt64($Offset, 16)
}
catch
{
    Write-Host "Error parsing '$offset_num' as a hex number."
    Write-Host $help
    exit
}

if ($start_num -gt 0x1000000)
{
    Write-Host "Warning: Start address is larger than the ROM file. Hint: ignore the leading number in the address."
}

$end_str = [System.Convert]::ToString($start_num + $offset_num, 16)
$end_str = "0x$end_str"

$start_str = "0x$Start"

Write-Host "$start_str - $end_str"
$objdump = Join-Path -Path $env:DEVKITARM -ChildPath "arm-none-eabi\bin\objdump.exe"
&$objdump -D -bbinary -marmv4t -Mforce-thumb --start-address="$start_str" --stop-address="$end_str" .\baserom.gba > .\baserom.dump
&$objdump -D -bbinary -marmv4t -Mforce-thumb --start-address="$start_str" --stop-address="$end_str" .\pokeemerald.gba > .\pokeemerald.dump
Invoke-Expression "$DiffTool .\baserom.dump .\pokeemerald.dump"


code:
#!/bin/bash

OBJDUMP="$DEVKITARM/bin/arm-none-eabi-objdump -D -bbinary -marmv4t -Mforce-thumb"
if [ $(($1)) -ge $((0x8000000)) ]; then
    OPTIONS="--adjust-vma=0x8000000 --start-address=$(($1)) --stop-address=$(($1 + $2))"
else
    OPTIONS="--start-address=$(($1)) --stop-address=$(($1 + $2))"
fi
$OBJDUMP $OPTIONS baserom.gba > baserom.dump
$OBJDUMP $OPTIONS pokeemerald.gba > pokeemerald.dump
diff -u baserom.dump pokeemerald.dump


code:
#!/bin/sh

echo "This script is deprecated. Next time, run \"make tools\" instead."
for dname in tools/*; do
  if [ -f ${dname}/Makefile ]; then
    make -C ${dname} CXX=${1:-g++} --no-print-directory
  fi
done


code:
gFlashTimeoutFlag
PollFlashStatus
WaitForFlashWrite
ProgramFlashSector
gFlash
ProgramFlashByte
gFlashNumRemainingBytes
EraseFlashChip
EraseFlashSector
gFlashMaxTime


code:
gPreBattleCallback1
gBattleMainFunc
gBattleResults
gLeveledUpInBattle
gBattlerControllerFuncs
gHealthboxSpriteIds
gMultiUsePlayerCursor
gNumberOfMovesToChoose
gUnknown_03005D7C


code: gUnneededFireRedVariable


code:
gContestMonPixels
gImageProcessingContext
gContestPaintingWinner
gContestPaintingMonPalette


code: gSelectedObjectEvent


code:
gCanvasColumnStart
gCanvasPixels
gCanvasRowEnd
gCanvasHeight
gCanvasColumnEnd
gCanvasRowStart
gCanvasMonPersonality
gCanvasWidth
gCanvasPalette
gCanvasPaletteStart


code:
gRfuSlotStatusUNI
gRfuSlotStatusNI
gRfuLinkStatus
gRfuStatic
gRfuFixed


code:
gLinkPartnersHeldKeys
gLinkDebugSeed
gLocalLinkPlayerBlock
gLinkErrorOccurred
gLinkDebugFlags
gLinkFiller1
gRemoteLinkPlayersNotReceived
gBlockReceivedStatus
gLinkFiller2
gLinkHeldKeys
gRecvCmds
gLinkStatus
gLinkDummy1
gLinkDummy2
gReadyToExitStandby
gReadyToCloseLink
gReadyCloseLinkType
gSuppressLinkErrorMessage
gWirelessCommType
gSavedLinkPlayerCount
gSendCmd
gSavedMultiplayerId
gReceivedRemoteLinkPlayers
gLinkTestBGInfo
gLinkCallback
gShouldAdvanceLinkState
gLinkTestBlockChecksums
gBlockRequestType
gLinkFiller3
gLinkFiller4
gLinkFiller5
gLastSendQueueCount
gLink
gLastRecvQueueCount
gLinkSavedIme


code:
gFlashMemoryPresent
gSaveBlock1Ptr
gSaveBlock2Ptr
gPokemonStoragePtr


code:
gSoundInfo
gPokemonCrySongs
gPokemonCryMusicPlayers
gMPlayInfo_BGM
gMPlayJumpTable
gCgbChans
gMPlayInfo_SE1
gMPlayInfo_SE2
gPokemonCryTracks
gPokemonCrySong
gMPlayMemAccArea
gMPlayInfo_SE3


code:
gKeyRepeatStartDelay
gLinkTransferringData
gMain
gKeyRepeatContinueDelay
gSoftResetDisabled
gIntrTable
gLinkVSyncDisabled
IntrMain_Buffer
gPcmDmaCounter


code:
gBGTilemapBuffers1
gBGTilemapBuffers2
gBGTilemapBuffers3
gHeldKeyCodeToSend
gFieldCallback
gFieldCallback2
gLocalLinkPlayerId
gFieldLinkPlayerCount


code:
gUnusedPokedexU8
gPokedexVBlankCB


code:
gRngValue
gRng2Value


code:
gLastWrittenSector
gLastSaveCounter
gLastKnownGoodSector
gDamagedSaveSectors
gSaveCounter
gFastSaveSection
gUnknown_03006208
gSaveUnusedVar
gSaveFileStatus
gGameContinueCallback
gRamSaveSectionLocations
gSaveUnusedVar2
gSaveAttemptStatus


code:
gFonts
gUnknown_03002F84
gUnknown_03002F90
gTextFlags


code:
gWhichTrainerToFaceAfterBattle
gPostBattleMovementScript
gApproachingTrainers
gNoOfApproachingTrainers
gTrainerApproachedPlayer


code:
sCurTVShowSlot
sTV_SecretBaseVisitMovesTemp
sTV_DecorationsBuffer
sTV_SecretBaseVisitMonsTemp


code:
filler_03002F58
filler_03002F5C
gTransparentTileNumber
filler_03002F64
gUnknown_03002F70


code:
	.include "constants/gba_constants.inc"
	.include "constants/global.inc"


code:
	.set PSR_USR_MODE,  0x00000010
	.set PSR_FIQ_MODE,  0x00000011
	.set PSR_IRQ_MODE,  0x00000012
	.set PSR_SVC_MODE,  0x00000013
	.set PSR_ABT_MODE,  0x00000017
	.set PSR_UND_MODE,  0x0000001b
	.set PSR_SYS_MODE,  0x0000001f
	.set PSR_MODE_MASK, 0x0000001f
	.set PSR_T_BIT,     0x00000020
	.set PSR_F_BIT,     0x00000040
	.set PSR_I_BIT,     0x00000080

	.set EWRAM_START, 0x02000000
	.set EWRAM_END,   EWRAM_START + 0x40000
	.set IWRAM_START, 0x03000000
	.set IWRAM_END,   IWRAM_START + 0x8000

	.set PLTT,     0x5000000
	.set BG_PLTT,  PLTT
	.set OBJ_PLTT, PLTT + 0x200

	.set VRAM,      0x6000000
	.set BG_VRAM,   VRAM
	.set OBJ_VRAM0, VRAM + 0x10000 @ text-mode BG
	.set OBJ_VRAM1, VRAM + 0x14000 @ bitmap-mode BG

	.set OAM, 0x7000000

	.set SOUND_INFO_PTR, 0x3007FF0
	.set INTR_CHECK,     0x3007FF8
	.set INTR_VECTOR,    0x3007FFC

	.set INTR_FLAG_VBLANK,  1 << 0
	.set INTR_FLAG_HBLANK,  1 << 1
	.set INTR_FLAG_VCOUNT,  1 << 2
	.set INTR_FLAG_TIMER0,  1 << 3
	.set INTR_FLAG_TIMER1,  1 << 4
	.set INTR_FLAG_TIMER2,  1 << 5
	.set INTR_FLAG_TIMER3,  1 << 6
	.set INTR_FLAG_SERIAL,  1 << 7
	.set INTR_FLAG_DMA0,    1 << 8
	.set INTR_FLAG_DMA1,    1 << 9
	.set INTR_FLAG_DMA2,    1 << 10
	.set INTR_FLAG_DMA3,    1 << 11
	.set INTR_FLAG_KEYPAD,  1 << 12
	.set INTR_FLAG_GAMEPAK, 1 << 13

	.set VCOUNT_VBLANK, 160
	.set TOTAL_SCANLINES, 228

	.set REG_BASE, 0x4000000 @ I/O register base address

@ I/O register offsets
	.set OFFSET_REG_DISPCNT,     0x0
	.set OFFSET_REG_DISPSTAT,    0x4
	.set OFFSET_REG_VCOUNT,      0x6
	.set OFFSET_REG_BG0CNT,      0x8
	.set OFFSET_REG_BG1CNT,      0xa
	.set OFFSET_REG_BG2CNT,      0xc
	.set OFFSET_REG_BG3CNT,      0xe
	.set OFFSET_REG_BG0HOFS,     0x10
	.set OFFSET_REG_BG0VOFS,     0x12
	.set OFFSET_REG_BG1HOFS,     0x14
	.set OFFSET_REG_BG1VOFS,     0x16
	.set OFFSET_REG_BG2HOFS,     0x18
	.set OFFSET_REG_BG2VOFS,     0x1a
	.set OFFSET_REG_BG3HOFS,     0x1c
	.set OFFSET_REG_BG3VOFS,     0x1e
	.set OFFSET_REG_BG2PA,       0x20
	.set OFFSET_REG_BG2PB,       0x22
	.set OFFSET_REG_BG2PC,       0x24
	.set OFFSET_REG_BG2PD,       0x26
	.set OFFSET_REG_BG2X_L,      0x28
	.set OFFSET_REG_BG2X_H,      0x2a
	.set OFFSET_REG_BG2Y_L,      0x2c
	.set OFFSET_REG_BG2Y_H,      0x2e
	.set OFFSET_REG_BG3PA,       0x30
	.set OFFSET_REG_BG3PB,       0x32
	.set OFFSET_REG_BG3PC,       0x34
	.set OFFSET_REG_BG3PD,       0x36
	.set OFFSET_REG_BG3X_L,      0x38
	.set OFFSET_REG_BG3X_H,      0x3a
	.set OFFSET_REG_BG3Y_L,      0x3c
	.set OFFSET_REG_BG3Y_H,      0x3e
	.set OFFSET_REG_WIN0H,       0x40
	.set OFFSET_REG_WIN1H,       0x42
	.set OFFSET_REG_WIN0V,       0x44
	.set OFFSET_REG_WIN1V,       0x46
	.set OFFSET_REG_WININ,       0x48
	.set OFFSET_REG_WINOUT,      0x4a
	.set OFFSET_REG_MOSAIC,      0x4c
	.set OFFSET_REG_BLDCNT,      0x50
	.set OFFSET_REG_BLDALPHA,    0x52
	.set OFFSET_REG_BLDY,        0x54

	.set OFFSET_REG_SOUND1CNT,   0x60
	.set OFFSET_REG_SOUND1CNT_L, 0x60
	.set OFFSET_REG_NR10,        0x60
	.set OFFSET_REG_SOUND1CNT_H, 0x62
	.set OFFSET_REG_NR11,        0x62
	.set OFFSET_REG_NR12,        0x63
	.set OFFSET_REG_SOUND1CNT_X, 0x64
	.set OFFSET_REG_NR13,        0x64
	.set OFFSET_REG_NR14,        0x65
	.set OFFSET_REG_SOUND2CNT,   0x68
	.set OFFSET_REG_SOUND2CNT_L, 0x68
	.set OFFSET_REG_NR21,        0x68
	.set OFFSET_REG_NR22,        0x69
	.set OFFSET_REG_SOUND2CNT_H, 0x6c
	.set OFFSET_REG_NR23,        0x6c
	.set OFFSET_REG_NR24,        0x6d
	.set OFFSET_REG_SOUND3CNT,   0x70
	.set OFFSET_REG_SOUND3CNT_L, 0x70
	.set OFFSET_REG_NR30,        0x70
	.set OFFSET_REG_SOUND3CNT_H, 0x72
	.set OFFSET_REG_NR31,        0x72
	.set OFFSET_REG_NR32,        0x73
	.set OFFSET_REG_SOUND3CNT_X, 0x74
	.set OFFSET_REG_NR33,        0x74
	.set OFFSET_REG_NR34,        0x75
	.set OFFSET_REG_SOUND4CNT,   0x78
	.set OFFSET_REG_SOUND4CNT_L, 0x78
	.set OFFSET_REG_NR41,        0x78
	.set OFFSET_REG_NR42,        0x79
	.set OFFSET_REG_SOUND4CNT_H, 0x7c
	.set OFFSET_REG_NR43,        0x7c
	.set OFFSET_REG_NR44,        0x7d
	.set OFFSET_REG_SOUNDCNT,    0x80
	.set OFFSET_REG_SOUNDCNT_L,  0x80
	.set OFFSET_REG_NR50,        0x80
	.set OFFSET_REG_NR51,        0x81
	.set OFFSET_REG_SOUNDCNT_H,  0x82
	.set OFFSET_REG_SOUNDCNT_X,  0x84
	.set OFFSET_REG_NR52,        0x84
	.set OFFSET_REG_SOUNDBIAS,   0x88
	.set OFFSET_REG_WAVE_RAM,    0x90
	.set OFFSET_REG_WAVE_RAM0,   0x90
	.set OFFSET_REG_WAVE_RAM0_L, 0x90
	.set OFFSET_REG_WAVE_RAM0_H, 0x92
	.set OFFSET_REG_WAVE_RAM1,   0x94
	.set OFFSET_REG_WAVE_RAM1_L, 0x94
	.set OFFSET_REG_WAVE_RAM1_H, 0x96
	.set OFFSET_REG_WAVE_RAM2,   0x98
	.set OFFSET_REG_WAVE_RAM2_L, 0x98
	.set OFFSET_REG_WAVE_RAM2_H, 0x9a
	.set OFFSET_REG_WAVE_RAM3,   0x9c
	.set OFFSET_REG_WAVE_RAM3_L, 0x9c
	.set OFFSET_REG_WAVE_RAM3_H, 0x9e
	.set OFFSET_REG_FIFO,        0xa0
	.set OFFSET_REG_FIFO_A,      0xa0
	.set OFFSET_REG_FIFO_A_L,    0xa0
	.set OFFSET_REG_FIFO_A_H,    0xa2
	.set OFFSET_REG_FIFO_B,      0xa4
	.set OFFSET_REG_FIFO_B_L,    0xa4
	.set OFFSET_REG_FIFO_B_H,    0xa6

	.set OFFSET_REG_DMA0,        0xb0
	.set OFFSET_REG_DMA0SAD,     0xb0
	.set OFFSET_REG_DMA0SAD_L,   0xb0
	.set OFFSET_REG_DMA0SAD_H,   0xb2
	.set OFFSET_REG_DMA0DAD,     0xb4
	.set OFFSET_REG_DMA0DAD_L,   0xb4
	.set OFFSET_REG_DMA0DAD_H,   0xb6
	.set OFFSET_REG_DMA0CNT,     0xb8
	.set OFFSET_REG_DMA0CNT_L,   0xb8
	.set OFFSET_REG_DMA0CNT_H,   0xba
	.set OFFSET_REG_DMA1,        0xbc
	.set OFFSET_REG_DMA1SAD,     0xbc
	.set OFFSET_REG_DMA1SAD_L,   0xbc
	.set OFFSET_REG_DMA1SAD_H,   0xbe
	.set OFFSET_REG_DMA1DAD,     0xc0
	.set OFFSET_REG_DMA1DAD_L,   0xc0
	.set OFFSET_REG_DMA1DAD_H,   0xc2
	.set OFFSET_REG_DMA1CNT,     0xc4
	.set OFFSET_REG_DMA1CNT_L,   0xc4
	.set OFFSET_REG_DMA1CNT_H,   0xc6
	.set OFFSET_REG_DMA2,        0xc8
	.set OFFSET_REG_DMA2SAD,     0xc8
	.set OFFSET_REG_DMA2SAD_L,   0xc8
	.set OFFSET_REG_DMA2SAD_H,   0xca
	.set OFFSET_REG_DMA2DAD,     0xcc
	.set OFFSET_REG_DMA2DAD_L,   0xcc
	.set OFFSET_REG_DMA2DAD_H,   0xce
	.set OFFSET_REG_DMA2CNT,     0xd0
	.set OFFSET_REG_DMA2CNT_L,   0xd0
	.set OFFSET_REG_DMA2CNT_H,   0xd2
	.set OFFSET_REG_DMA3,        0xd4
	.set OFFSET_REG_DMA3SAD,     0xd4
	.set OFFSET_REG_DMA3SAD_L,   0xd4
	.set OFFSET_REG_DMA3SAD_H,   0xd6
	.set OFFSET_REG_DMA3DAD,     0xd8
	.set OFFSET_REG_DMA3DAD_L,   0xd8
	.set OFFSET_REG_DMA3DAD_H,   0xda
	.set OFFSET_REG_DMA3CNT,     0xdc
	.set OFFSET_REG_DMA3CNT_L,   0xdc
	.set OFFSET_REG_DMA3CNT_H,   0xde

	.set OFFSET_REG_TM0CNT,      0x100
	.set OFFSET_REG_TM0CNT_L,    0x100
	.set OFFSET_REG_TM0CNT_H,    0x102
	.set OFFSET_REG_TM1CNT,      0x104
	.set OFFSET_REG_TM1CNT_L,    0x104
	.set OFFSET_REG_TM1CNT_H,    0x106
	.set OFFSET_REG_TM2CNT,      0x108
	.set OFFSET_REG_TM2CNT_L,    0x108
	.set OFFSET_REG_TM2CNT_H,    0x10a
	.set OFFSET_REG_TM3CNT,      0x10c
	.set OFFSET_REG_TM3CNT_L,    0x10c
	.set OFFSET_REG_TM3CNT_H,    0x10e

	.set OFFSET_REG_SIOCNT,      0x128
	.set OFFSET_REG_SIODATA8,    0x12a
	.set OFFSET_REG_SIODATA32,   0x120
	.set OFFSET_REG_SIOMLT_SEND, 0x12a
	.set OFFSET_REG_SIOMLT_RECV, 0x120
	.set OFFSET_REG_SIOMULTI0,   0x120
	.set OFFSET_REG_SIOMULTI1,   0x122
	.set OFFSET_REG_SIOMULTI2,   0x124
	.set OFFSET_REG_SIOMULTI3,   0x126

	.set OFFSET_REG_KEYINPUT,    0x130
	.set OFFSET_REG_KEYCNT,      0x132

	.set OFFSET_REG_RCNT,        0x134

	.set OFFSET_REG_JOYCNT,      0x140
	.set OFFSET_REG_JOYSTAT,     0x158
	.set OFFSET_REG_JOY_RECV,    0x150
	.set OFFSET_REG_JOY_RECV_L,  0x150
	.set OFFSET_REG_JOY_RECV_H,  0x152
	.set OFFSET_REG_JOY_TRANS,   0x154
	.set OFFSET_REG_JOY_TRANS_L, 0x154
	.set OFFSET_REG_JOY_TRANS_H, 0x156

	.set OFFSET_REG_IME,         0x208
	.set OFFSET_REG_IE,          0x200
	.set OFFSET_REG_IF,          0x202

	.set OFFSET_REG_WAITCNT,     0x204

@ I/O register addresses
	.set REG_DISPCNT,     REG_BASE + OFFSET_REG_DISPCNT
	.set REG_DISPSTAT,    REG_BASE + OFFSET_REG_DISPSTAT
	.set REG_VCOUNT,      REG_BASE + OFFSET_REG_VCOUNT
	.set REG_BG0CNT,      REG_BASE + OFFSET_REG_BG0CNT
	.set REG_BG1CNT,      REG_BASE + OFFSET_REG_BG1CNT
	.set REG_BG2CNT,      REG_BASE + OFFSET_REG_BG2CNT
	.set REG_BG3CNT,      REG_BASE + OFFSET_REG_BG3CNT
	.set REG_BG0HOFS,     REG_BASE + OFFSET_REG_BG0HOFS
	.set REG_BG0VOFS,     REG_BASE + OFFSET_REG_BG0VOFS
	.set REG_BG1HOFS,     REG_BASE + OFFSET_REG_BG1HOFS
	.set REG_BG1VOFS,     REG_BASE + OFFSET_REG_BG1VOFS
	.set REG_BG2HOFS,     REG_BASE + OFFSET_REG_BG2HOFS
	.set REG_BG2VOFS,     REG_BASE + OFFSET_REG_BG2VOFS
	.set REG_BG3HOFS,     REG_BASE + OFFSET_REG_BG3HOFS
	.set REG_BG3VOFS,     REG_BASE + OFFSET_REG_BG3VOFS
	.set REG_BG2PA,       REG_BASE + OFFSET_REG_BG2PA
	.set REG_BG2PB,       REG_BASE + OFFSET_REG_BG2PB
	.set REG_BG2PC,       REG_BASE + OFFSET_REG_BG2PC
	.set REG_BG2PD,       REG_BASE + OFFSET_REG_BG2PD
	.set REG_BG2X_L,      REG_BASE + OFFSET_REG_BG2X_L
	.set REG_BG2X_H,      REG_BASE + OFFSET_REG_BG2X_H
	.set REG_BG2Y_L,      REG_BASE + OFFSET_REG_BG2Y_L
	.set REG_BG2Y_H,      REG_BASE + OFFSET_REG_BG2Y_H
	.set REG_BG3PA,       REG_BASE + OFFSET_REG_BG3PA
	.set REG_BG3PB,       REG_BASE + OFFSET_REG_BG3PB
	.set REG_BG3PC,       REG_BASE + OFFSET_REG_BG3PC
	.set REG_BG3PD,       REG_BASE + OFFSET_REG_BG3PD
	.set REG_BG3X_L,      REG_BASE + OFFSET_REG_BG3X_L
	.set REG_BG3X_H,      REG_BASE + OFFSET_REG_BG3X_H
	.set REG_BG3Y_L,      REG_BASE + OFFSET_REG_BG3Y_L
	.set REG_BG3Y_H,      REG_BASE + OFFSET_REG_BG3Y_H
	.set REG_WIN0H,       REG_BASE + OFFSET_REG_WIN0H
	.set REG_WIN1H,       REG_BASE + OFFSET_REG_WIN1H
	.set REG_WIN0V,       REG_BASE + OFFSET_REG_WIN0V
	.set REG_WIN1V,       REG_BASE + OFFSET_REG_WIN1V
	.set REG_WININ,       REG_BASE + OFFSET_REG_WININ
	.set REG_WINOUT,      REG_BASE + OFFSET_REG_WINOUT
	.set REG_MOSAIC,      REG_BASE + OFFSET_REG_MOSAIC
	.set REG_BLDCNT,      REG_BASE + OFFSET_REG_BLDCNT
	.set REG_BLDALPHA,    REG_BASE + OFFSET_REG_BLDALPHA
	.set REG_BLDY,        REG_BASE + OFFSET_REG_BLDY

	.set REG_SOUND1CNT,   REG_BASE + OFFSET_REG_SOUND1CNT
	.set REG_SOUND1CNT_L, REG_BASE + OFFSET_REG_SOUND1CNT_L
	.set REG_NR10,        REG_BASE + OFFSET_REG_NR10
	.set REG_SOUND1CNT_H, REG_BASE + OFFSET_REG_SOUND1CNT_H
	.set REG_NR11,        REG_BASE + OFFSET_REG_NR11
	.set REG_NR12,        REG_BASE + OFFSET_REG_NR12
	.set REG_SOUND1CNT_X, REG_BASE + OFFSET_REG_SOUND1CNT_X
	.set REG_NR13,        REG_BASE + OFFSET_REG_NR13
	.set REG_NR14,        REG_BASE + OFFSET_REG_NR14
	.set REG_SOUND2CNT,   REG_BASE + OFFSET_REG_SOUND2CNT
	.set REG_SOUND2CNT_L, REG_BASE + OFFSET_REG_SOUND2CNT_L
	.set REG_NR21,        REG_BASE + OFFSET_REG_NR21
	.set REG_NR22,        REG_BASE + OFFSET_REG_NR22
	.set REG_SOUND2CNT_H, REG_BASE + OFFSET_REG_SOUND2CNT_H
	.set REG_NR23,        REG_BASE + OFFSET_REG_NR23
	.set REG_NR24,        REG_BASE + OFFSET_REG_NR24
	.set REG_SOUND3CNT,   REG_BASE + OFFSET_REG_SOUND3CNT
	.set REG_SOUND3CNT_L, REG_BASE + OFFSET_REG_SOUND3CNT_L
	.set REG_NR30,        REG_BASE + OFFSET_REG_NR30
	.set REG_SOUND3CNT_H, REG_BASE + OFFSET_REG_SOUND3CNT_H
	.set REG_NR31,        REG_BASE + OFFSET_REG_NR31
	.set REG_NR32,        REG_BASE + OFFSET_REG_NR32
	.set REG_SOUND3CNT_X, REG_BASE + OFFSET_REG_SOUND3CNT_X
	.set REG_NR33,        REG_BASE + OFFSET_REG_NR33
	.set REG_NR34,        REG_BASE + OFFSET_REG_NR34
	.set REG_SOUND4CNT,   REG_BASE + OFFSET_REG_SOUND4CNT
	.set REG_SOUND4CNT_L, REG_BASE + OFFSET_REG_SOUND4CNT_L
	.set REG_NR41,        REG_BASE + OFFSET_REG_NR41
	.set REG_NR42,        REG_BASE + OFFSET_REG_NR42
	.set REG_SOUND4CNT_H, REG_BASE + OFFSET_REG_SOUND4CNT_H
	.set REG_NR43,        REG_BASE + OFFSET_REG_NR43
	.set REG_NR44,        REG_BASE + OFFSET_REG_NR44
	.set REG_SOUNDCNT,    REG_BASE + OFFSET_REG_SOUNDCNT
	.set REG_SOUNDCNT_L,  REG_BASE + OFFSET_REG_SOUNDCNT_L
	.set REG_NR50,        REG_BASE + OFFSET_REG_NR50
	.set REG_NR51,        REG_BASE + OFFSET_REG_NR51
	.set REG_SOUNDCNT_H,  REG_BASE + OFFSET_REG_SOUNDCNT_H
	.set REG_SOUNDCNT_X,  REG_BASE + OFFSET_REG_SOUNDCNT_X
	.set REG_NR52,        REG_BASE + OFFSET_REG_NR52
	.set REG_SOUNDBIAS,   REG_BASE + OFFSET_REG_SOUNDBIAS
	.set REG_WAVE_RAM,    REG_BASE + OFFSET_REG_WAVE_RAM
	.set REG_WAVE_RAM0,   REG_BASE + OFFSET_REG_WAVE_RAM0
	.set REG_WAVE_RAM0_L, REG_BASE + OFFSET_REG_WAVE_RAM0_L
	.set REG_WAVE_RAM0_H, REG_BASE + OFFSET_REG_WAVE_RAM0_H
	.set REG_WAVE_RAM1,   REG_BASE + OFFSET_REG_WAVE_RAM1
	.set REG_WAVE_RAM1_L, REG_BASE + OFFSET_REG_WAVE_RAM1_L
	.set REG_WAVE_RAM1_H, REG_BASE + OFFSET_REG_WAVE_RAM1_H
	.set REG_WAVE_RAM2,   REG_BASE + OFFSET_REG_WAVE_RAM2
	.set REG_WAVE_RAM2_L, REG_BASE + OFFSET_REG_WAVE_RAM2_L
	.set REG_WAVE_RAM2_H, REG_BASE + OFFSET_REG_WAVE_RAM2_H
	.set REG_WAVE_RAM3,   REG_BASE + OFFSET_REG_WAVE_RAM3
	.set REG_WAVE_RAM3_L, REG_BASE + OFFSET_REG_WAVE_RAM3_L
	.set REG_WAVE_RAM3_H, REG_BASE + OFFSET_REG_WAVE_RAM3_H
	.set REG_FIFO,        REG_BASE + OFFSET_REG_FIFO
	.set REG_FIFO_A,      REG_BASE + OFFSET_REG_FIFO_A
	.set REG_FIFO_A_L,    REG_BASE + OFFSET_REG_FIFO_A_L
	.set REG_FIFO_A_H,    REG_BASE + OFFSET_REG_FIFO_A_H
	.set REG_FIFO_B,      REG_BASE + OFFSET_REG_FIFO_B
	.set REG_FIFO_B_L,    REG_BASE + OFFSET_REG_FIFO_B_L
	.set REG_FIFO_B_H,    REG_BASE + OFFSET_REG_FIFO_B_H

	.set REG_DMA0,        REG_BASE + OFFSET_REG_DMA0
	.set REG_DMA0SAD,     REG_BASE + OFFSET_REG_DMA0SAD
	.set REG_DMA0SAD_L,   REG_BASE + OFFSET_REG_DMA0SAD_L
	.set REG_DMA0SAD_H,   REG_BASE + OFFSET_REG_DMA0SAD_H
	.set REG_DMA0DAD,     REG_BASE + OFFSET_REG_DMA0DAD
	.set REG_DMA0DAD_L,   REG_BASE + OFFSET_REG_DMA0DAD_L
	.set REG_DMA0DAD_H,   REG_BASE + OFFSET_REG_DMA0DAD_H
	.set REG_DMA0CNT,     REG_BASE + OFFSET_REG_DMA0CNT
	.set REG_DMA0CNT_L,   REG_BASE + OFFSET_REG_DMA0CNT_L
	.set REG_DMA0CNT_H,   REG_BASE + OFFSET_REG_DMA0CNT_H
	.set REG_DMA1,        REG_BASE + OFFSET_REG_DMA1
	.set REG_DMA1SAD,     REG_BASE + OFFSET_REG_DMA1SAD
	.set REG_DMA1SAD_L,   REG_BASE + OFFSET_REG_DMA1SAD_L
	.set REG_DMA1SAD_H,   REG_BASE + OFFSET_REG_DMA1SAD_H
	.set REG_DMA1DAD,     REG_BASE + OFFSET_REG_DMA1DAD
	.set REG_DMA1DAD_L,   REG_BASE + OFFSET_REG_DMA1DAD_L
	.set REG_DMA1DAD_H,   REG_BASE + OFFSET_REG_DMA1DAD_H
	.set REG_DMA1CNT,     REG_BASE + OFFSET_REG_DMA1CNT
	.set REG_DMA1CNT_L,   REG_BASE + OFFSET_REG_DMA1CNT_L
	.set REG_DMA1CNT_H,   REG_BASE + OFFSET_REG_DMA1CNT_H
	.set REG_DMA2,        REG_BASE + OFFSET_REG_DMA2
	.set REG_DMA2SAD,     REG_BASE + OFFSET_REG_DMA2SAD
	.set REG_DMA2SAD_L,   REG_BASE + OFFSET_REG_DMA2SAD_L
	.set REG_DMA2SAD_H,   REG_BASE + OFFSET_REG_DMA2SAD_H
	.set REG_DMA2DAD,     REG_BASE + OFFSET_REG_DMA2DAD
	.set REG_DMA2DAD_L,   REG_BASE + OFFSET_REG_DMA2DAD_L
	.set REG_DMA2DAD_H,   REG_BASE + OFFSET_REG_DMA2DAD_H
	.set REG_DMA2CNT,     REG_BASE + OFFSET_REG_DMA2CNT
	.set REG_DMA2CNT_L,   REG_BASE + OFFSET_REG_DMA2CNT_L
	.set REG_DMA2CNT_H,   REG_BASE + OFFSET_REG_DMA2CNT_H
	.set REG_DMA3,        REG_BASE + OFFSET_REG_DMA3
	.set REG_DMA3SAD,     REG_BASE + OFFSET_REG_DMA3SAD
	.set REG_DMA3SAD_L,   REG_BASE + OFFSET_REG_DMA3SAD_L
	.set REG_DMA3SAD_H,   REG_BASE + OFFSET_REG_DMA3SAD_H
	.set REG_DMA3DAD,     REG_BASE + OFFSET_REG_DMA3DAD
	.set REG_DMA3DAD_L,   REG_BASE + OFFSET_REG_DMA3DAD_L
	.set REG_DMA3DAD_H,   REG_BASE + OFFSET_REG_DMA3DAD_H
	.set REG_DMA3CNT,     REG_BASE + OFFSET_REG_DMA3CNT
	.set REG_DMA3CNT_L,   REG_BASE + OFFSET_REG_DMA3CNT_L
	.set REG_DMA3CNT_H,   REG_BASE + OFFSET_REG_DMA3CNT_H

	.set REG_TM0CNT,      REG_BASE + OFFSET_REG_TM0CNT
	.set REG_TM0CNT_L,    REG_BASE + OFFSET_REG_TM0CNT_L
	.set REG_TM0CNT_H,    REG_BASE + OFFSET_REG_TM0CNT_H
	.set REG_TM1CNT,      REG_BASE + OFFSET_REG_TM1CNT
	.set REG_TM1CNT_L,    REG_BASE + OFFSET_REG_TM1CNT_L
	.set REG_TM1CNT_H,    REG_BASE + OFFSET_REG_TM1CNT_H
	.set REG_TM2CNT,      REG_BASE + OFFSET_REG_TM2CNT
	.set REG_TM2CNT_L,    REG_BASE + OFFSET_REG_TM2CNT_L
	.set REG_TM2CNT_H,    REG_BASE + OFFSET_REG_TM2CNT_H
	.set REG_TM3CNT,      REG_BASE + OFFSET_REG_TM3CNT
	.set REG_TM3CNT_L,    REG_BASE + OFFSET_REG_TM3CNT_L
	.set REG_TM3CNT_H,    REG_BASE + OFFSET_REG_TM3CNT_H

	.set REG_SIOCNT,      REG_BASE + OFFSET_REG_SIOCNT
	.set REG_SIODATA8,    REG_BASE + OFFSET_REG_SIODATA8
	.set REG_SIODATA32,   REG_BASE + OFFSET_REG_SIODATA32
	.set REG_SIOMLT_SEND, REG_BASE + OFFSET_REG_SIOMLT_SEND
	.set REG_SIOMLT_RECV, REG_BASE + OFFSET_REG_SIOMLT_RECV
	.set REG_SIOMULTI0,   REG_BASE + OFFSET_REG_SIOMULTI0
	.set REG_SIOMULTI1,   REG_BASE + OFFSET_REG_SIOMULTI1
	.set REG_SIOMULTI2,   REG_BASE + OFFSET_REG_SIOMULTI2
	.set REG_SIOMULTI3,   REG_BASE + OFFSET_REG_SIOMULTI3

	.set REG_KEYINPUT,    REG_BASE + OFFSET_REG_KEYINPUT
	.set REG_KEYCNT,      REG_BASE + OFFSET_REG_KEYCNT

	.set REG_RCNT,        REG_BASE + OFFSET_REG_RCNT

	.set REG_JOYCNT,      REG_BASE + OFFSET_REG_JOYCNT
	.set REG_JOYSTAT,     REG_BASE + OFFSET_REG_JOYSTAT
	.set REG_JOY_RECV,    REG_BASE + OFFSET_REG_JOY_RECV
	.set REG_JOY_RECV_L,  REG_BASE + OFFSET_REG_JOY_RECV_L
	.set REG_JOY_RECV_H,  REG_BASE + OFFSET_REG_JOY_RECV_H
	.set REG_JOY_TRANS,   REG_BASE + OFFSET_REG_JOY_TRANS
	.set REG_JOY_TRANS_L, REG_BASE + OFFSET_REG_JOY_TRANS_L
	.set REG_JOY_TRANS_H, REG_BASE + OFFSET_REG_JOY_TRANS_H

	.set REG_IME,         REG_BASE + OFFSET_REG_IME
	.set REG_IE,          REG_BASE + OFFSET_REG_IE
	.set REG_IF,          REG_BASE + OFFSET_REG_IF

	.set REG_WAITCNT,     REG_BASE + OFFSET_REG_WAITCNT

@ DMA register constants

	.set DMA_DEST_INC,      0x0000
	.set DMA_DEST_DEC,      0x0020
	.set DMA_DEST_FIXED,    0x0040
	.set DMA_DEST_RELOAD,   0x0060
	.set DMA_SRC_INC,       0x0000
	.set DMA_SRC_DEC,       0x0080
	.set DMA_SRC_FIXED,     0x0100
	.set DMA_REPEAT,        0x0200
	.set DMA_16BIT,         0x0000
	.set DMA_32BIT,         0x0400
	.set DMA_DREQ_ON,       0x0800
	.set DMA_START_NOW,     0x0000
	.set DMA_START_VBLANK,  0x1000
	.set DMA_START_HBLANK,  0x2000
	.set DMA_START_SPECIAL, 0x3000
	.set DMA_INTR_ENABLE,   0x4000
	.set DMA_ENABLE,        0x8000

@ OAM attribute constants

	.set OAM_OBJ_NORMAL,         0x00000000
	.set OAM_OBJ_BLEND,          0x00000400
	.set OAM_OBJ_WINDOW,         0x00000800

	.set OAM_AFFINE_NONE,        0x00000000
	.set OAM_AFFINE_NORMAL_SIZE, 0x00000100
	.set OAM_OBJ_DISABLED,       0x00000200
	.set OAM_AFFINE_DOUBLE_SIZE, 0x00000300

	.set OAM_MOSAIC_OFF,         0x00000000
	.set OAM_MOSAIC_ON,          0x00001000

	.set OAM_4BPP,               0x00000000
	.set OAM_8BPP,               0x00002000

	.set OAM_H_FLIP,             0x10000000
	.set OAM_V_FLIP,             0x20000000

	.set OAM_SQUARE,             0x00000000
	.set OAM_H_RECTANGLE,        0x00004000
	.set OAM_V_RECTANGLE,        0x00008000
	.set OAM_SIZE_0,             0x00000000
	.set OAM_SIZE_1,             0x40000000
	.set OAM_SIZE_2,             0x80000000
	.set OAM_SIZE_3,             0xc0000000

	.set OAM_SIZE_8x8,           OAM_SIZE_0 | OAM_SQUARE
	.set OAM_SIZE_16x16,         OAM_SIZE_1 | OAM_SQUARE
	.set OAM_SIZE_32x32,         OAM_SIZE_2 | OAM_SQUARE
	.set OAM_SIZE_64x64,         OAM_SIZE_3 | OAM_SQUARE

	.set OAM_SIZE_16x8,          OAM_SIZE_0 | OAM_H_RECTANGLE
	.set OAM_SIZE_32x8,          OAM_SIZE_1 | OAM_H_RECTANGLE
	.set OAM_SIZE_32x16,         OAM_SIZE_2 | OAM_H_RECTANGLE
	.set OAM_SIZE_64x32,         OAM_SIZE_3 | OAM_H_RECTANGLE

	.set OAM_SIZE_8x16,          OAM_SIZE_0 | OAM_V_RECTANGLE
	.set OAM_SIZE_8x32,          OAM_SIZE_1 | OAM_V_RECTANGLE
	.set OAM_SIZE_16x32,         OAM_SIZE_2 | OAM_V_RECTANGLE
	.set OAM_SIZE_32x64,         OAM_SIZE_3 | OAM_V_RECTANGLE

@ BLDCNT

	.set BLDCNT_TGT1_BG0,       1 << 0
	.set BLDCNT_TGT1_BG1,       1 << 1
	.set BLDCNT_TGT1_BG2,       1 << 2
	.set BLDCNT_TGT1_BG3,       1 << 3
	.set BLDCNT_TGT1_OBJ,       1 << 4
	.set BLDCNT_TGT1_BD,        1 << 5
	.set BLDCNT_TGT1_ALL,       BLDCNT_TGT1_BG0 | BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_TGT1_OBJ | BLDCNT_TGT1_BD

	.set BLDCNT_EFFECT_NONE,    0 << 6
	.set BLDCNT_EFFECT_BLEND,   1 << 6
	.set BLDCNT_EFFECT_LIGHTEN, 2 << 6
	.set BLDCNT_EFFECT_DARKEN,  3 << 6

	.set BLDCNT_TGT2_BG0,       1 << 8
	.set BLDCNT_TGT2_BG1,       1 << 9
	.set BLDCNT_TGT2_BG2,       1 << 10
	.set BLDCNT_TGT2_BG3,       1 << 11
	.set BLDCNT_TGT2_OBJ,       1 << 12
	.set BLDCNT_TGT2_BD,        1 << 13
	.set BLDCNT_TGT2_ALL,       BLDCNT_TGT2_BG0 | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_BG2 | BLDCNT_TGT2_BG3 | BLDCNT_TGT2_OBJ | BLDCNT_TGT2_BD


code:
	.set TRUE, 1
	.set FALSE, 0

	.set NULL, 0

	.set SPRITE_SIZE_8x8,   (OAM_SIZE_0 >> 28) | (OAM_SQUARE >> 14)
	.set SPRITE_SIZE_16x16, (OAM_SIZE_1 >> 28) | (OAM_SQUARE >> 14)
	.set SPRITE_SIZE_32x32, (OAM_SIZE_2 >> 28) | (OAM_SQUARE >> 14)
	.set SPRITE_SIZE_64x64, (OAM_SIZE_3 >> 28) | (OAM_SQUARE >> 14)

	.set SPRITE_SIZE_16x8,  (OAM_SIZE_0 >> 28) | (OAM_H_RECTANGLE >> 14)
	.set SPRITE_SIZE_32x8,  (OAM_SIZE_1 >> 28) | (OAM_H_RECTANGLE >> 14)
	.set SPRITE_SIZE_32x16, (OAM_SIZE_2 >> 28) | (OAM_H_RECTANGLE >> 14)
	.set SPRITE_SIZE_64x32, (OAM_SIZE_3 >> 28) | (OAM_H_RECTANGLE >> 14)

	.set SPRITE_SIZE_8x16,  (OAM_SIZE_0 >> 28) | (OAM_V_RECTANGLE >> 14)
	.set SPRITE_SIZE_8x32,  (OAM_SIZE_1 >> 28) | (OAM_V_RECTANGLE >> 14)
	.set SPRITE_SIZE_16x32, (OAM_SIZE_2 >> 28) | (OAM_V_RECTANGLE >> 14)
	.set SPRITE_SIZE_32x64, (OAM_SIZE_3 >> 28) | (OAM_V_RECTANGLE >> 14)

	.set OBJ_IMAGE_ANIM_H_FLIP, 1 << 6
	.set OBJ_IMAGE_ANIM_V_FLIP, 1 << 7


code:
	.equiv ID_NUMBER, 0x68736d53

	.equiv PCM_DMA_BUF_SIZE, 1584

	.equiv C_V, 0x40

	.equiv TONEDATA_TYPE_CGB, 0x07
	.equiv TONEDATA_TYPE_FIX, 0x08
	.equiv TONEDATA_TYPE_REV, 0x10
	.equiv TONEDATA_TYPE_CMP, 0x20
	.equiv TONEDATA_TYPE_SPL, 0x40 @ key split
	.equiv TONEDATA_TYPE_RHY, 0x80 @ rhythm

	.equiv TONEDATA_P_S_PAN,  0xc0

	.equiv SOUND_CHANNEL_SF_START,       0x80
	.equiv SOUND_CHANNEL_SF_STOP,        0x40
	.equiv SOUND_CHANNEL_SF_SPECIAL,     0x20
	.equiv SOUND_CHANNEL_SF_LOOP,        0x10
	.equiv SOUND_CHANNEL_SF_IEC,         0x04
	.equiv SOUND_CHANNEL_SF_ENV,         0x03
	.equiv SOUND_CHANNEL_SF_ENV_ATTACK,  0x03
	.equiv SOUND_CHANNEL_SF_ENV_DECAY,   0x02
	.equiv SOUND_CHANNEL_SF_ENV_SUSTAIN, 0x01
	.equiv SOUND_CHANNEL_SF_ENV_RELEASE, 0x00
	.equiv SOUND_CHANNEL_SF_ON, (SOUND_CHANNEL_SF_START | SOUND_CHANNEL_SF_STOP | SOUND_CHANNEL_SF_IEC | SOUND_CHANNEL_SF_ENV)

	.equiv CGB_CHANNEL_MO_PIT, 0x02
	.equiv CGB_CHANNEL_MO_VOL, 0x01

	.equiv WAVE_DATA_FLAG_LOOP, 0xC0

	.equiv MPT_FLG_VOLSET, 0x01
	.equiv MPT_FLG_VOLCHG, 0x03
	.equiv MPT_FLG_PITSET, 0x04
	.equiv MPT_FLG_PITCHG, 0x0C
	.equiv MPT_FLG_START,  0x40
	.equiv MPT_FLG_EXIST,  0x80

	.macro struct_begin
	.struct 0
	.endm

	.macro struct_field name, size
\name:
	.struct \name + \size
	.endm

	struct_begin
	struct_field o_WaveData_type, 2
	struct_field o_WaveData_d1, 1
	struct_field o_WaveData_flags, 1
	struct_field o_WaveData_freq, 4
	struct_field o_WaveData_loopStart, 4
	struct_field o_WaveData_size, 4
	struct_field o_WaveData_data, 0
	struct_field WaveData_size, 0

	struct_begin
	struct_field o_ToneData_type, 1
	struct_field o_ToneData_key, 1
	struct_field o_ToneData_length, 1
	struct_field o_ToneData_pan_sweep, 1
	struct_field o_ToneData_wav, 4
	struct_field o_ToneData_attack, 1
	struct_field o_ToneData_decay, 1
	struct_field o_ToneData_sustain, 1
	struct_field o_ToneData_release, 1
	struct_field ToneData_size, 0

	struct_begin
	struct_field o_SoundInfo_ident, 4
	struct_field o_SoundInfo_pcmDmaCounter, 1
	struct_field o_SoundInfo_reverb, 1
	struct_field o_SoundInfo_maxChans, 1
	struct_field o_SoundInfo_masterVolume, 1
	struct_field o_SoundInfo_freq, 1
	struct_field o_SoundInfo_mode, 1
	struct_field o_SoundInfo_c15, 1
	struct_field o_SoundInfo_pcmDmaPeriod, 1
	struct_field o_SoundInfo_maxLines, 1
	struct_field o_SoundInfo_gap, 3
	struct_field o_SoundInfo_pcmSamplesPerVBlank, 4
	struct_field o_SoundInfo_pcmFreq, 4
	struct_field o_SoundInfo_divFreq, 4
	struct_field o_SoundInfo_cgbChans, 4
	struct_field o_SoundInfo_MPlayMainHead, 4
	struct_field o_SoundInfo_musicPlayerHead, 4
	struct_field o_SoundInfo_CgbSound, 4
	struct_field o_SoundInfo_CgbOscOff, 4
	struct_field o_SoundInfo_MidiKeyToCgbFreq, 4
	struct_field o_SoundInfo_MPlayJumpTable, 4
	struct_field o_SoundInfo_plynote, 4
	struct_field o_SoundInfo_ExtVolPit, 4
	struct_field o_SoundInfo_gap2, 16
	struct_field o_SoundInfo_chans, 768
	struct_field o_SoundInfo_pcmBuffer, PCM_DMA_BUF_SIZE * 2
	struct_field SoundInfo_size, 0

	struct_begin
	struct_field o_SoundChannel_statusFlags, 1
	struct_field o_SoundChannel_type, 1
	struct_field o_SoundChannel_rightVolume, 1
	struct_field o_SoundChannel_leftVolume, 1
	struct_field o_SoundChannel_attack, 1
	struct_field o_SoundChannel_decay, 1
	struct_field o_SoundChannel_sustain, 1
	struct_field o_SoundChannel_release, 1
	struct_field o_SoundChannel_key, 1
	struct_field o_SoundChannel_envelopeVolume, 1
	struct_field o_SoundChannel_envelopeVolumeRight, 1
	struct_field o_SoundChannel_envelopeVolumeLeft, 1
	struct_field o_SoundChannel_pseudoEchoVolume, 1
	struct_field o_SoundChannel_pseudoEchoLength, 1
	struct_field o_SoundChannel_dummy1, 1
	struct_field o_SoundChannel_dummy2, 1
	struct_field o_SoundChannel_gateTime, 1
	struct_field o_SoundChannel_midiKey, 1
	struct_field o_SoundChannel_velocity, 1
	struct_field o_SoundChannel_priority, 1
	struct_field o_SoundChannel_rhythmPan, 1
	struct_field o_SoundChannel_dummy3, 3
	struct_field o_SoundChannel_count, 4
	struct_field o_SoundChannel_fw, 4
	struct_field o_SoundChannel_frequency, 4
	struct_field o_SoundChannel_wav, 4
	struct_field o_SoundChannel_currentPointer, 4
	struct_field o_SoundChannel_track, 4
	struct_field o_SoundChannel_prevChannelPointer, 4
	struct_field o_SoundChannel_nextChannelPointer, 4
	struct_field o_SoundChannel_dummy4, 4
	struct_field o_SoundChannel_xpi, 2
	struct_field o_SoundChannel_xpc, 2
	struct_field SoundChannel_size, 0

	struct_begin
	struct_field o_MusicPlayerTrack_flags, 1
	struct_field o_MusicPlayerTrack_wait, 1
	struct_field o_MusicPlayerTrack_patternLevel, 1
	struct_field o_MusicPlayerTrack_repN, 1
	struct_field o_MusicPlayerTrack_gateTime, 1
	struct_field o_MusicPlayerTrack_key, 1
	struct_field o_MusicPlayerTrack_velocity, 1
	struct_field o_MusicPlayerTrack_runningStatus, 1
	struct_field o_MusicPlayerTrack_keyM, 1
	struct_field o_MusicPlayerTrack_pitM, 1
	struct_field o_MusicPlayerTrack_keyShift, 1
	struct_field o_MusicPlayerTrack_keyShiftX, 1
	struct_field o_MusicPlayerTrack_tune, 1
	struct_field o_MusicPlayerTrack_pitX, 1
	struct_field o_MusicPlayerTrack_bend, 1
	struct_field o_MusicPlayerTrack_bendRange, 1
	struct_field o_MusicPlayerTrack_volMR, 1
	struct_field o_MusicPlayerTrack_volML, 1
	struct_field o_MusicPlayerTrack_vol, 1
	struct_field o_MusicPlayerTrack_volX, 1
	struct_field o_MusicPlayerTrack_pan, 1
	struct_field o_MusicPlayerTrack_panX, 1
	struct_field o_MusicPlayerTrack_modM, 1
	struct_field o_MusicPlayerTrack_mod, 1
	struct_field o_MusicPlayerTrack_modT, 1
	struct_field o_MusicPlayerTrack_lfoSpeed, 1
	struct_field o_MusicPlayerTrack_lfoSpeedC, 1
	struct_field o_MusicPlayerTrack_lfoDelay, 1
	struct_field o_MusicPlayerTrack_lfoDelayC, 1
	struct_field o_MusicPlayerTrack_priority, 1
	struct_field o_MusicPlayerTrack_pseudoEchoVolume, 1
	struct_field o_MusicPlayerTrack_pseudoEchoLength, 1
	struct_field o_MusicPlayerTrack_chan, 4
	struct_field o_MusicPlayerTrack_ToneData_type, 1
	struct_field o_MusicPlayerTrack_ToneData_key, 1
	struct_field o_MusicPlayerTrack_ToneData_length, 1
	struct_field o_MusicPlayerTrack_ToneData_pan_sweep, 1
	struct_field o_MusicPlayerTrack_ToneData_wav, 4
	struct_field o_MusicPlayerTrack_ToneData_attack, 1
	struct_field o_MusicPlayerTrack_ToneData_decay, 1
	struct_field o_MusicPlayerTrack_ToneData_sustain, 1
	struct_field o_MusicPlayerTrack_ToneData_release, 1
	struct_field o_MusicPlayerTrack_gap, 10
	struct_field o_MusicPlayerTrack_unk_3A, 2
	struct_field o_MusicPlayerTrack_unk_3C, 4
	struct_field o_MusicPlayerTrack_cmdPtr, 4
	struct_field o_MusicPlayerTrack_patternStack, 12
	struct_field MusicPlayerTrack_size, 0

	.equiv o_MusicPlayerTrack_ToneData_keySplitTable, o_MusicPlayerTrack_ToneData_attack

	struct_begin
	struct_field o_MusicPlayerInfo_songHeader, 4
	struct_field o_MusicPlayerInfo_status, 4
	struct_field o_MusicPlayerInfo_trackCount, 1
	struct_field o_MusicPlayerInfo_priority, 1
	struct_field o_MusicPlayerInfo_cmd, 1
	struct_field o_MusicPlayerInfo_unk_B, 1
	struct_field o_MusicPlayerInfo_clock, 4
	struct_field o_MusicPlayerInfo_gap, 8
	struct_field o_MusicPlayerInfo_memAccArea, 4
	struct_field o_MusicPlayerInfo_tempoD, 2
	struct_field o_MusicPlayerInfo_tempoU, 2
	struct_field o_MusicPlayerInfo_tempoI, 2
	struct_field o_MusicPlayerInfo_tempoC, 2
	struct_field o_MusicPlayerInfo_fadeOI, 2
	struct_field o_MusicPlayerInfo_fadeOC, 2
	struct_field o_MusicPlayerInfo_fadeOV, 2
	struct_field o_MusicPlayerInfo_padding, 2
	struct_field o_MusicPlayerInfo_tracks, 4
	struct_field o_MusicPlayerInfo_tone, 4
	struct_field o_MusicPlayerInfo_ident, 4
	struct_field o_MusicPlayerInfo_func, 4
	struct_field o_MusicPlayerInfo_intp, 4
	struct_field MusicPlayerInfo_size, 0

	struct_begin
	struct_field o_CgbChannel_statusFlags, 1
	struct_field o_CgbChannel_type, 1
	struct_field o_CgbChannel_rightVolume, 1
	struct_field o_CgbChannel_leftVolume, 1
	struct_field o_CgbChannel_attack, 1
	struct_field o_CgbChannel_decay, 1
	struct_field o_CgbChannel_sustain, 1
	struct_field o_CgbChannel_release, 1
	struct_field o_CgbChannel_key, 1
	struct_field o_CgbChannel_envelopeVolume, 1
	struct_field o_CgbChannel_envelopeGoal, 1
	struct_field o_CgbChannel_envelopeCounter, 1
	struct_field o_CgbChannel_pseudoEchoVolume, 1
	struct_field o_CgbChannel_pseudoEchoLength, 1
	struct_field o_CgbChannel_dummy1, 1
	struct_field o_CgbChannel_dummy2, 1
	struct_field o_CgbChannel_gateTime, 1
	struct_field o_CgbChannel_midiKey, 1
	struct_field o_CgbChannel_velocity, 1
	struct_field o_CgbChannel_priority, 1
	struct_field o_CgbChannel_rhythmPan, 1
	struct_field o_CgbChannel_dummy3, 3
	struct_field o_CgbChannel_dummy5, 1
	struct_field o_CgbChannel_sustainGoal, 1
	struct_field o_CgbChannel_n4, 1
	struct_field o_CgbChannel_pan, 1
	struct_field o_CgbChannel_panMask, 1
	struct_field o_CgbChannel_modify, 1
	struct_field o_CgbChannel_length, 1
	struct_field o_CgbChannel_sweep, 1
	struct_field o_CgbChannel_frequency, 4
	struct_field o_CgbChannel_wavePointer, 4
	struct_field o_CgbChannel_currentPointer, 4
	struct_field o_CgbChannel_track, 4
	struct_field o_CgbChannel_prevChannelPointer, 4
	struct_field o_CgbChannel_nextChannelPointer, 4
	struct_field o_CgbChannel_dummy4, 8
	struct_field CgbChannel_size, 0