summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--audio.asm11
-rw-r--r--audio/engine.asm159
-rw-r--r--constants/audio_constants.asm62
-rw-r--r--constants/hardware_constants.asm4
-rw-r--r--constants/serial.asm17
-rw-r--r--engine/link/place_waiting_text.asm23
-rw-r--r--engine/predef.asm122
-rw-r--r--engine/title.asm14
-rw-r--r--home/audio.asm143
-rw-r--r--home/bankswitch.asm8
-rw-r--r--home/clear_sprites.asm23
-rw-r--r--home/copy.asm68
-rw-r--r--home/copy_tilemap.asm18
-rw-r--r--home/farcall.asm36
-rw-r--r--home/init.asm129
-rw-r--r--home/interrupts.asm26
-rw-r--r--home/lcd.asm77
-rw-r--r--home/oam_dma.asm23
-rw-r--r--home/predef.asm43
-rw-r--r--home/rst.asm25
-rw-r--r--home/serial.asm53
-rw-r--r--home/sram.asm19
-rw-r--r--home/vblank.asm29
-rw-r--r--hram.asm71
-rw-r--r--macros.asm7
-rw-r--r--macros/code.asm101
-rw-r--r--macros/coords.asm52
-rw-r--r--macros/data.asm129
-rw-r--r--macros/farcall.asm22
-rw-r--r--macros/gfx.asm2
-rw-r--r--macros/predef.asm15
-rw-r--r--macros/wram.asm365
-rw-r--r--shim.sym16
-rw-r--r--sram.asm4
-rw-r--r--tools/make_shim.py106
36 files changed, 1974 insertions, 54 deletions
diff --git a/Makefile b/Makefile
index 46c48c4..03dcca3 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@
ROMS := pokegold-spaceworld.gb
BASEROM := baserom.gb
-OBJS := home.o main.o wram.o shim.o
+OBJS := home.o main.o wram.o hram.o shim.o
# Link objects together to build a rom.
all: $(ROMS) compare
@@ -27,10 +27,10 @@ $(foreach obj, $(OBJS), $(eval $(call DEP,$(obj),$(obj:.o=.asm))))
endif
shim.asm: shim.sym
- python3 tools/make_shim.py $^ > $@
+ python3 tools/make_shim.py -w $^ > $@
$(ROMS): $(OBJS)
- rgblink -n $(ROMS:.gb=.sym) -m $(ROMS:.gb=.map) -O $(BASEROM) -o $@ $^
+ rgblink -d -n $(ROMS:.gb=.sym) -m $(ROMS:.gb=.map) -O $(BASEROM) -o $@ $^
rgbfix -f -v -k 01 -l 0x33 -m 0x03 -p 0 -r 3 -t "POKEMON2GOLD" $@
compare: $(ROMS) $(BASEROM)
diff --git a/audio.asm b/audio.asm
new file mode 100644
index 0000000..aec654c
--- /dev/null
+++ b/audio.asm
@@ -0,0 +1,11 @@
+INCLUDE "constants.asm"
+
+
+SECTION "Audio", ROMX[$4000],BANK[$3A]
+
+INCLUDE "audio/engine.asm"
+
+
+SECTION "Cries", ROMX[$51CB],BANK[$3C] ; TODO: Temporary, please map 4000-51CA and move this section's base
+
+CryHeaders:: ; TODO: Rip the data, then INCBIN it
diff --git a/audio/engine.asm b/audio/engine.asm
new file mode 100644
index 0000000..e008e9d
--- /dev/null
+++ b/audio/engine.asm
@@ -0,0 +1,159 @@
+_DisableAudio:: ; 3a:4000
+ push hl
+ push de
+ push bc
+ push af
+ ld hl, rNR50
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld a, $80
+ ld [hli], a
+ ld hl, rNR10
+ ld e, 4
+.init_channel
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld a, 8
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld a, $80
+ ld [hli], a
+ dec e
+ jr nz, .init_channel
+
+ ld hl, wMusic
+ ld de, wMusicInitEnd - wMusic
+.clear
+ xor a
+ ld [hli], a
+ dec de
+ ld a, d
+ or e
+ jr nz, .clear
+
+ ld a, $77
+ ld [wVolume], a
+
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+_UpdateSound:: ; 3a:4037
+ xor a
+ ; So, I'm being told I need to disassemble this...
+ ; OH HELL NO
+
+ ; ... TODO :/
+
+
+
+SECTION "Audio engine, part 2", ROMX[$4CEE],BANK[$3A] ; TODO: disassemble what's above (gulp) and remove this
+
+SetGlobalTempo: ; 3a:4cee
+ push bc
+ ld a, [wCurChannel]
+ cp CHAN5
+ jr nc, .sfxchannels
+ ld bc, wChannel1
+ call Tempo
+ ld bc, wChannel2
+ call Tempo
+ ld bc, wChannel3
+ call Tempo
+ ld bc, wChannel4
+ call Tempo
+ jr .end
+
+.sfxchannels
+ ld bc, wChannel5
+ call Tempo
+ ld bc, wChannel6
+ call Tempo
+ ld bc, wChannel7
+ call Tempo
+ ld bc, wChannel8
+ call Tempo
+
+.end
+ pop bc
+ ret
+
+Tempo: ; 3a:4d2a
+ ld hl, wChannel1Tempo - wChannel1
+ add hl, bc
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ xor a
+ ld hl, wChannel1Field16 - wChannel1
+ add hl, bc
+ ld [hl], a
+ ret
+
+
+StartChannel: ; 3a:4d38
+ call SetLRTracks
+ ld hl, wChannel1Flags - wChannel1
+ add hl, bc
+ set SOUND_CHANNEL_ON, [hl]
+ ret
+
+
+StopChannel: ; 3a:4d42
+ ld hl, wChannel1Flags - wChannel1
+ add hl, bc
+ res SOUND_CHANNEL_ON, [hl]
+ ld hl, wChannel1MusicID - wChannel1
+ add hl, bc
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ret
+
+
+SetLRTracks: ; 3a:4d51
+ push de
+ ld a, [wCurChannel]
+ maskbits NUM_MUSIC_CHANS
+ ld e, a
+ ld d, 0
+ ld hl, 52B3 ; FIXME
+ add hl, de
+ ld a, [hl]
+ ld hl, wChannel1Tracks - wChannel1
+ add hl, bc
+ ld [hl], a
+ pop de
+ ret
+
+
+_PlayMusic:: ; 3a:4d66
+ ld hl, wMusicID
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld hl, Music
+ add hl, de
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld [wMusicBank], a
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ call LoadMusicByte
+ rlca
+ rlca
+ maskbits NUM_MUSIC_CHANS
+ inc a
+.loop
+ push af
+ call LoadChannel
+ call StartChannel
diff --git a/constants/audio_constants.asm b/constants/audio_constants.asm
new file mode 100644
index 0000000..c341e90
--- /dev/null
+++ b/constants/audio_constants.asm
@@ -0,0 +1,62 @@
+
+
+; pitch
+ const_def
+ const __
+ const C_
+ const C#
+ const D_
+ const D#
+ const E_
+ const F_
+ const F#
+ const G_
+ const G#
+ const A_
+ const A#
+ const B_
+
+; channel
+ const_def
+ const CHAN1
+ const CHAN2
+ const CHAN3
+ const CHAN4
+NUM_MUSIC_CHANS EQU const_value
+NUM_NOISE_CHANS EQU const_value
+ const CHAN5
+ const CHAN6
+ const CHAN7
+ const CHAN8
+NUM_CHANNELS EQU const_value
+
+; Flags1
+SOUND_CHANNEL_ON EQU 0
+SOUND_SUBROUTINE EQU 1
+SOUND_LOOPING EQU 2
+SOUND_SFX EQU 3
+SOUND_NOISE EQU 4
+SOUND_REST EQU 5
+
+; Flags2
+
+SOUND_VIBRATO EQU 0
+SOUND_PITCH_WHEEL EQU 1
+SOUND_DUTY EQU 2
+SOUND_UNKN_0B EQU 3
+SOUND_CRY_PITCH EQU 4
+SOUND_UNKN_0D EQU 5
+SOUND_UNKN_0E EQU 6
+SOUND_UNKN_0F EQU 7
+
+; Flags3
+SOUND_VIBRATO_DIR EQU 0
+SOUND_PITCH_WHEEL_DIR EQU 1
+
+; NoteFlags
+NOTE_UNKN_0 EQU 0
+NOTE_UNKN_1 EQU 1
+NOTE_UNKN_3 EQU 3
+NOTE_UNKN_4 EQU 4
+NOTE_REST EQU 5
+NOTE_UNKN_6 EQU 6
diff --git a/constants/hardware_constants.asm b/constants/hardware_constants.asm
index d96672c..b47da72 100644
--- a/constants/hardware_constants.asm
+++ b/constants/hardware_constants.asm
@@ -124,6 +124,10 @@ rLCDC_SPRITE_SIZE EQU 2 ; 0=8x8, 1=8x16
rLCDC_WINDOW_TILEMAP EQU 6 ; 0=9800-9BFF, 1=9C00-9FFF
rLCDC_ENABLE EQU 7 ; 0=Off, 1=On
rSTAT EQU $ff41 ; LCDC Status (R/W)
+rSTAT_HBLANK EQU 3 ; 0=Off, 1=On
+rSTAT_VBLANK EQU 4 ; 0=Off, 1=On
+rSTAT_MODE2 EQU 5 ; 0=Off, 1=On
+rSTAT_LYC EQU 6 ; 0=Off, 1=On
rSCY EQU $ff42 ; Scroll Y (R/W)
rSCX EQU $ff43 ; Scroll X (R/W)
rLY EQU $ff44 ; LCDC Y-Coordinate (R)
diff --git a/constants/serial.asm b/constants/serial.asm
new file mode 100644
index 0000000..e475798
--- /dev/null
+++ b/constants/serial.asm
@@ -0,0 +1,17 @@
+; serial
+
+ESTABLISH_CONNECTION_WITH_INTERNAL_CLOCK EQU $01
+ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK EQU $02
+
+USING_EXTERNAL_CLOCK EQU $01
+USING_INTERNAL_CLOCK EQU $02
+CONNECTION_NOT_ESTABLISHED EQU $ff
+
+; signals the start of an array of bytes transferred over the link cable
+SERIAL_PREAMBLE_BYTE EQU $FD
+
+; this byte is used when there is no data to send
+SERIAL_NO_DATA_BYTE EQU $FE
+
+; signals the end of one part of a patch list (there are two parts) for player/enemy party data
+SERIAL_PATCH_LIST_PART_TERMINATOR EQU $FF
diff --git a/engine/link/place_waiting_text.asm b/engine/link/place_waiting_text.asm
new file mode 100644
index 0000000..19d4a6a
--- /dev/null
+++ b/engine/link/place_waiting_text.asm
@@ -0,0 +1,23 @@
+SECTION "PlaceWaitingText", ROMX[$4000],BANK[1]
+
+PlaceWaitingText:: ; 1:4000
+ hlcoord 3, 10
+ ld b, 1
+ ld c, 11
+ ld a, [wBattleMode]
+ and a
+ jr z, .link_textbox
+ call Textbox
+ jr .textbox_done
+
+.link_textbox
+ predef Predef_LinkTextbox
+.textbox_done
+ hlcoord 4, 11
+ ld de, .Waiting
+ call PlaceString
+ ld c, 50
+ jp DelayFrames
+
+.Waiting:
+ db "Waiting...!@" \ No newline at end of file
diff --git a/engine/predef.asm b/engine/predef.asm
new file mode 100644
index 0000000..dca0283
--- /dev/null
+++ b/engine/predef.asm
@@ -0,0 +1,122 @@
+SECTION "Predef pointers", ROMX[$62B0],BANK[1]
+
+GetPredefPointer:: ; 1:62b0
+ ld a, h
+ ld [wPredefHL], a
+ ld a, l
+ ld [wPredefHL + 1], a
+ ld hl, wPredefDE
+ ld a, d
+ ld [hli], a
+ ld a, e
+ ld [hli], a
+ ld a, b
+ ld [hli], a
+ ld [hl], c
+
+ ld a, [wPredefID]
+ ld e, a
+ ld d, 0
+ ld hl, PredefPointers
+ add hl, de
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ret
+
+PredefPointers:: ; 1:62d3
+ ; To YOU who is reading this:
+ ; Please be a peach and nuke the hell out of these:
+ ; WE NEED LABELS!
+ ; Thank youu~
+
+ dbw 1, $6445 ; 0
+ dbw 1, $5D27
+ dbw 1, $6713
+ dbw 1, $66B1
+ dbw 1, $4031
+ dbw 3, $4E10
+ dbw 3, $4D6F
+ dbw 3, $4DE3
+ dbw 3, $4DE3 ; 8
+ dbw 3, $4DE3
+ dbw 3, $4DF9
+ dbw 3, $4E10
+ dbw 3, $4D33
+ dbw 3, $366C
+ dbw 3, $4E3C
+ dbw 3, $5A28
+ dbw 3, $5886 ; 10
+ dbw 3, $5A4F
+ dbw 3, $5AC8
+ dbw 3, $5CFC
+ dbw 3, $5C16
+ dbw 3, $5D5C
+ dbw 3, $5E79
+ dbw 3, $4E7C
+ dbw 3, $5F7D ; 18
+ dbw 3, $5F91
+ dbw 4, $528F
+ dbw 4, $52C1
+ dbw 10, $4C98
+ dbw 11, $5663
+ dbw 15, $55CE
+ dbw 15, $7019
+ dbw 15, $7068 ; 20
+ dbw 15, $704A
+ dbw 15, $508C
+ dbw 15, $567C
+ dbw 15, $61A4
+ dbw 15, $6F19
+ dbw 15, $6874
+ dbw 15, $691E
+ dbw 15, $6963 ; 28
+ dbw 16, $61F8
+ dbw 16, $6252
+ dbw 16, $5FA1
+ dbw 10, $4DA4
+ dbw 10, $4D6E
+ dbw 16, $4AC7
+ dbw 16, $4000
+ dbw 16, $4B5C ; 30
+ dbw 20, $4000
+ dbw 20, $4BFE
+ dbw 20, $4BCD
+ dbw 20, $4B92
+ dbw 20, $48C4
+ dbw 20, $4771
+ dbw 20, $4774
+ dbw 20, $481F ; 38
+ dbw 20, $46D4
+ dbw 20, $469E
+ dbw 20, $42B5
+ dbw 20, $4244
+ dbw 20, $4248
+ dbw 20, $40C6
+ dbw 20, $40A0
+ dbw 20, $4073 ; 40
+ dbw 20, $4ED9
+ dbw 50, $76FF
+ dbw 50, $7710
+ dbw 50, $7733
+ dbw 5, $45B8
+ dbw 5, $46DC
+ dbw 5, $45DE
+ dbw 50, $4000 ; 48
+ dbw 5, $457A
+ dbw 5, $43E0
+ dbw 2, $5695
+ dbw 2, $528B
+ dbw 2, $4786
+ dbw 35, $44BE
+ dbw 35, $49C6
+ dbw 35, $4940 ; 50
+ dbw 51, $4001
+ dbw 51, $4000
+ dbw 51, $4000
+ dbw 63, $5B66
+ dbw 4, $640B
+ dbw $FF, InexplicablyEmptyFunction
diff --git a/engine/title.asm b/engine/title.asm
new file mode 100644
index 0000000..9df68ed
--- /dev/null
+++ b/engine/title.asm
@@ -0,0 +1,14 @@
+SECTION "Title screen", ROMX[$5D8C],BANK[1]
+
+IntroSequence:: ; 5d8c
+ ; TODO
+
+
+SECTION "Title screen TEMPORARY", ROMX[$62A5],BANK[1] ; TODO: merge this with the section above
+
+GameInit:: ; 62a5
+ call ClearWindowData
+ ld a, $23
+ ld [wce5f], a
+ jp IntroSequence
+
diff --git a/home/audio.asm b/home/audio.asm
new file mode 100644
index 0000000..bb49d42
--- /dev/null
+++ b/home/audio.asm
@@ -0,0 +1,143 @@
+SECTION "Audio", ROM0[$3CBF]
+
+DisableAudio:: ; 3cbf
+ push hl
+ push de
+ push bc
+ push af
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(_DisableAudio)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ call _DisableAudio
+ pop af
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+UpdateSound:: ; 3cdb
+ push hl
+ push de
+ push bc
+ push af
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(_UpdateSound)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ call _UpdateSound
+ pop af
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+LoadMusicByte:: ; 3cf7
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ ld a, [de]
+ push af
+ ld a, BANK(_UpdateSound)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ ret
+
+
+PlayMusic:: ; 3d07
+ push hl
+ push de
+ push bc
+ push af
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(_PlayMusic)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ call _PlayMusic
+ pop af
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+PlayCryHeader:: ; 3d23
+ push hl
+ push de
+ push bc
+ push af
+ ldh a, [hROMBank]
+ push af
+
+ ld a, BANK(CryHeaders)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ ld hl, CryHeaders
+REPT 6
+ add hl, de
+ENDR
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld a, [hli]
+ ld [wCryPitch], a
+ ld a, [hli]
+ ld [wCryPitch + 1], a
+ ld a, [hli]
+ ld [wCryLength], a
+ ld a, [hl]
+ ld [wCryLength + 1], a
+
+ ld a, BANK(_PlayCryHeader)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ call _PlayCryHeader
+
+ pop af
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+
+
+PlaySFX:: ; 3d63
+ push hl
+ push de
+ push bc
+ push af
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(PlaySFX_)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ call PlaySFX_
+ pop af
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
diff --git a/home/bankswitch.asm b/home/bankswitch.asm
new file mode 100644
index 0000000..67fae1a
--- /dev/null
+++ b/home/bankswitch.asm
@@ -0,0 +1,8 @@
+SECTION "Bankswitch", ROM0[$32C2]
+
+; Moved to a rst vector in final US releases (not sure about JP)
+; All rst vectors are unused at this point in development
+Bankswitch:: ; 32c2
+ ldh [hROMBank], a
+ ld [MBC3RomBank], a
+ ret
diff --git a/home/clear_sprites.asm b/home/clear_sprites.asm
new file mode 100644
index 0000000..9ce9a54
--- /dev/null
+++ b/home/clear_sprites.asm
@@ -0,0 +1,23 @@
+SECTION "Sprite clearing", ROM0[$32DC]
+
+ClearSprites:: ; 32dc
+ ld hl, wVirtualOAM
+ ld b, wVirtualOAMEnd - wVirtualOAM
+ xor a
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+HideSprites:: ; 32e7
+ ld hl, wVirtualOAM
+ ld de, SPRITEOAMSTRUCT_LENGTH
+ ld b, NUM_SPRITE_OAM_STRUCTS
+ ld a, $A0
+.loop
+ ld [hli], a
+ add hl, de
+ dec b
+ jr nz, .loop
+ ret
diff --git a/home/copy.asm b/home/copy.asm
new file mode 100644
index 0000000..f89bd49
--- /dev/null
+++ b/home/copy.asm
@@ -0,0 +1,68 @@
+SECTION "Copy functions", ROM0[$32F7]
+
+FarCopyBytes:: ; 32f7
+ ld [wBuffer], a
+ ldh a, [hROMBank]
+ push af
+ ld a, [wBuffer]
+ call Bankswitch
+ call CopyBytes
+ pop af
+ jp Bankswitch
+
+CopyBytes:: ; 330a
+ ld a, b
+ and a
+ jr z, CopyBytesSmall
+ ld a, c
+ and a
+ jr z, .next
+ inc b
+.next
+ call CopyBytesSmall
+ dec b
+ jr nz, .next
+ ret
+
+CopyBytesSmall:: ; 331a
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, CopyBytesSmall
+ ret
+
+
+GetFarByte:: ; 3321
+ ld [wBuffer], a
+ ldh a, [hROMBank]
+ push af
+ ld a, [wBuffer]
+ call Bankswitch
+ ld a, [hl]
+ ld [wBuffer], a
+ pop af
+ call Bankswitch
+ ld a, [wBuffer]
+ ret
+
+
+ByteFill:: ; 3339
+ push af
+ ld a, b
+ and a
+ jr z, .small_fill
+ ld a, c
+ and a
+ jr z, .start_filling
+.small_fill
+ inc b
+.start_filling
+ pop af
+.loop
+ ld [hli], a
+ dec c
+ jr z, .loop
+ dec b
+ jr z, .loop
+ ret
diff --git a/home/copy_tilemap.asm b/home/copy_tilemap.asm
new file mode 100644
index 0000000..950bb24
--- /dev/null
+++ b/home/copy_tilemap.asm
@@ -0,0 +1,18 @@
+SECTION "Tilemap copy/restore funcs", ROM0[$3355]
+
+BackUpTilesToBuffer:: ; 3355
+ hlcoord 0, 0
+ decoord 0, 0, wTileMapBackup
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ jp CopyBytes
+
+ReloadTilesFromBuffer:: ; 3361
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 0, 0, wTileMapBackup
+ decoord 0, 0
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ call CopyBytes
+ ld a, 1
+ ldh [hBGMapMode], a
+ ret
diff --git a/home/farcall.asm b/home/farcall.asm
new file mode 100644
index 0000000..68f8ab0
--- /dev/null
+++ b/home/farcall.asm
@@ -0,0 +1,36 @@
+SECTION "Farcall", ROM0[$2FA8]
+
+FarCall_hl:: ; 2fa8
+ push af
+ ld a, b
+ ld [wFarCallBCBuffer], a
+ ld a, c
+ ld [wFarCallBCBuffer + 1], a
+ pop af
+ ld b, a
+ ldh a, [hROMBank]
+ push af
+ ld a, b
+ call Bankswitch
+ ld bc, .return
+ push bc
+ push hl
+ ld a, [wFarCallBCBuffer]
+ ld b, a
+ ld a, [wFarCallBCBuffer + 1]
+ ld c, a
+ ret
+
+.return
+ ld a, b
+ ld [wFarCallBCBuffer], a
+ ld a, c
+ ld [wFarCallBCBuffer + 1], a
+ pop bc
+ ld a, b
+ call Bankswitch
+ ld a, [wFarCallBCBuffer]
+ ld b, a
+ ld a, [wFarCallBCBuffer + 1]
+ ld c, a
+ ret
diff --git a/home/init.asm b/home/init.asm
new file mode 100644
index 0000000..fcafa3c
--- /dev/null
+++ b/home/init.asm
@@ -0,0 +1,129 @@
+SECTION "Entry point", ROM0[$100]
+ nop
+ jp Init
+
+SECTION "Global check value", ROM0[$14E]
+; The ROM has an incorrect global check, so set it here
+; It is not corrected by RGBFIX
+ db $21, $C6
+
+
+SECTION "Init", ROM0[$52F]
+
+Init: ; 052f
+ di
+ xor a
+ ld [rIF], a
+ ld [rIE], a
+ ld [rSCX], a
+ ld [rSCY], a
+ ld [rSB], a
+ ld [rSC], a
+ ld [rWX], a
+ ld [rWY], a
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld [rOBP1], a
+ ld [rTMA], a
+ ld [rTAC], a
+ ld [wcc38], a ; Useless, since WRAM gets cleared right after
+ ld a, 1 << rTAC_ON | rTAC_4096_HZ
+ ld [rTAC], a
+ ld a, 1 << rLCDC_ENABLE
+ ld [rLCDC], a
+
+ ld sp, wStackBottom
+ call ClearVRAM
+ ld hl, WRAM0_Begin
+ ld bc, WRAM1_End - WRAM0_Begin
+.ByteFill ; 0565
+ ld [hl], 0
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .ByteFill
+ ld hl, HRAM_Begin
+ ld bc, HRAM_End - HRAM_Begin
+ call ByteFill
+ call ClearSprites
+
+ ld a, BANK(WriteOAMDMACodeToHRAM)
+ call Bankswitch
+ call WriteOAMDMACodeToHRAM
+
+ xor a
+ ldh [hMapAnims], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ldh [rJOYP], a
+ ld a, 1 << rSTAT_HBLANK
+ ld [rSTAT], a
+ ld a, SCREEN_HEIGHT_PX
+ ldh [hWY], a
+ ld [rWY], a
+ ld a, 7
+ ldh [hWX], a
+ ld [rWX], a
+
+ ld a, $FF
+ ldh [hLinkPlayerNumber], a
+ ld h, HIGH($9800)
+ call BlankBGMap
+ ld h, HIGH($9800)
+ call BlankBGMap
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+
+ call DisableAudio
+ call _2007
+ ; predef ???
+ ld a, $4B ; TODO: add predefs so the line above can be uncommented
+ call Predef
+ ld a, $1F
+ ld [rIE], a
+ ld a, HIGH($9C00)
+ ldh [hBGMapAddress + 1], a
+ xor a
+ ldh [hBGMapAddress], a
+
+ call DisableLCD
+ call ClearVRAM
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+ ei
+
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+ ld a, RTC_DH
+ ld [MBC3SRamBank], a
+ xor a
+ ld [SRAM_Begin], a
+ ld a, 0 ; Useless
+ ld [MBC3LatchClock], a
+ ld [MBC3SRamEnable], a
+ jp GameInit
+
+ClearVRAM: ; 05e6
+ ld hl, VRAM_Begin
+ ld bc, VRAM_End - VRAM_Begin
+ call ByteFill
+ ret
+
+BlankBGMap:
+ ld a, $7F
+ jr _FillBGMap
+
+FillBGMap:
+ ld a, l
+
+_FillBGMap:
+ ld de, $400
+ ld l, e
+.loop
+ ld [hli], a
+ dec e
+ jr nz, .loop
+ dec d
+ jr nz, .loop
+ ret
diff --git a/home/interrupts.asm b/home/interrupts.asm
new file mode 100644
index 0000000..91610e0
--- /dev/null
+++ b/home/interrupts.asm
@@ -0,0 +1,26 @@
+SECTION "VBlank interrupt vector", ROM0[$040]
+ jp VBlank
+
+SECTION "LCD interrupt vector", ROM0[$048]
+ jp LCD
+
+SECTION "Timer interrupt vector", ROM0[$050]
+ jp TimerDummy
+
+SECTION "Serial interrupt vector", ROM0[$058]
+ jp Serial
+
+SECTION "Joypad interrupt vector", ROM0[$060]
+ jp JoypadDummy
+
+
+SECTION "Timer dummy interrupt", ROM0[$42A]
+
+TimerDummy: ; 042a
+ reti
+
+
+SECTION "Joypad dummy interrupt", ROM0[$7F7]
+
+JoypadDummy: ; 07f7
+ reti \ No newline at end of file
diff --git a/home/lcd.asm b/home/lcd.asm
new file mode 100644
index 0000000..dcf6bfa
--- /dev/null
+++ b/home/lcd.asm
@@ -0,0 +1,77 @@
+SECTION "LCD functions", ROM0[$3AE]
+
+LCD:: ; 03ae
+ push af
+ ldh a, [hLCDCPointer]
+ and a
+ jr z, .done
+ push hl
+ rla
+ jr c, .try_hide_sprites
+ ld a, [rLY]
+ ld l, a
+ ld h, HIGH(wLYOverrides)
+ ld h, [hl]
+ ldh a, [hLCDCPointer]
+ ld l, a
+ ld a, h
+ ld h, $FF
+ ld [hl], a
+ pop hl
+ pop af
+ reti
+
+.try_hide_sprites
+ ld a, [rLY]
+ cp $80
+ jr nz, .dont_hide
+ ld hl, rLCDC
+ res 1, [hl]
+.dont_hide
+ pop hl
+ pop af
+ reti
+
+ ; Seems unused?
+ ldh a, [hSCX]
+ ld [rSCX], a
+ ldh a, [hSCY]
+ ld [rSCY], a
+ pop hl
+.done
+ pop af
+ reti
+
+
+; 0:3e1
+ sine_table 16
+
+
+DisableLCD:: ; 0401
+ ld a, [rLY]
+ bit 7, a
+ ret z
+ xor a
+ ld [rIF], a
+ ld a, [rIE]
+ ld b, a
+ res 0, a
+ ld [rIE], a
+.wait
+ ld a, [rLY]
+ cp LY_VBLANK
+ jr nz, .wait
+ ld a, [rLCDC]
+ and $7F ; Shut LCD down
+ ld [rLCDC], a
+ xor a
+ ld [rIF], a
+ ld a, b
+ ld [rIE], a
+ ret
+
+EnableLCD:: ; 0423
+ ld a, [rLCDC]
+ set 7, a
+ ld [rLCDC], a
+ ret
diff --git a/home/oam_dma.asm b/home/oam_dma.asm
new file mode 100644
index 0000000..958e88c
--- /dev/null
+++ b/home/oam_dma.asm
@@ -0,0 +1,23 @@
+SECTION "OAM DMA", ROMX[$4153],BANK[1]
+
+WriteOAMDMACodeToHRAM:: ; 4153
+ ld c, LOW(hOAMDMA)
+ ld b, .OAMDMAEnd - .OAMDMA
+ ld hl, .OAMDMA
+.loop
+ ld a, [hli]
+ ld [$ff00+c], a
+ inc c
+ dec b
+ jr nz, .loop
+ ret
+
+.OAMDMA ; 4161
+ ld a, HIGH(wVirtualOAM)
+ ldh [rDMA], a
+.wait
+ ld a, $28
+ dec a
+ jr nz, .wait
+ ret
+.OAMDMAEnd ; 416b
diff --git a/home/predef.asm b/home/predef.asm
new file mode 100644
index 0000000..6c85236
--- /dev/null
+++ b/home/predef.asm
@@ -0,0 +1,43 @@
+SECTION "Predef", ROM0[$2FDE]
+
+Predef:: ; 2fde
+ ld [wPredefID], a
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(GetPredefPointer)
+ call Bankswitch
+ call GetPredefPointer
+ call Bankswitch
+ ld hl, .return
+ push hl
+ push de
+ jr .save_regs
+
+.return
+ ld a, h
+ ld [wPredefHL], a
+ ld a, l
+ ld [wPredefHL + 1], a
+ pop hl
+ ld a, h ; Could have used `pop af` instead
+ call Bankswitch
+ ld a, [wPredefHL]
+ ld h, a
+ ld a, [wPredefHL + 1]
+ ld l, a
+ ret
+
+.save_regs
+ ld a, h
+ ld [wPredefHL], a
+ ld a, l
+ ld [wPredefHL + 1], a
+ ld a, d
+ ld [wPredefDE], a
+ ld a, e
+ ld [wPredefDE + 1], a
+ ld a, b
+ ld [wPredefBC], a
+ ld a, c
+ ld [wPredefBC + 1], a
+ ret
diff --git a/home/rst.asm b/home/rst.asm
new file mode 100644
index 0000000..851775b
--- /dev/null
+++ b/home/rst.asm
@@ -0,0 +1,25 @@
+; rst vectors
+
+SECTION "rst00", ROM0[$000]
+ rst $38
+
+SECTION "rst08", ROM0[$008]
+ rst $38
+
+SECTION "rst10", ROM0[$010]
+ rst $38
+
+SECTION "rst18", ROM0[$018]
+ rst $38
+
+SECTION "rst20", ROM0[$020]
+ rst $38
+
+SECTION "rst28", ROM0[$028]
+ rst $38
+
+SECTION "rst30", ROM0[$030]
+ rst $38
+
+SECTION "rst38", ROM0[$038]
+ jp $F080 ; Jumps in the middle of unmapped memory. Probably used to trigger a breakpoint of sorts.
diff --git a/home/serial.asm b/home/serial.asm
new file mode 100644
index 0000000..b474e5d
--- /dev/null
+++ b/home/serial.asm
@@ -0,0 +1,53 @@
+SECTION "Serial handler", ROM0[$602]
+
+Serial::
+ push af
+ push bc
+ push de
+ push hl
+ ldh a, [hLinkPlayerNumber]
+ inc a
+ jr z, .init_player_number
+
+ ld a, [rSB]
+ ldh [hSerialRecieve], a
+ ldh a, [hSerialSend]
+ ld [rSB], a
+ ldh a, [hLinkPlayerNumber]
+ cp 2
+ jr z, .done
+ ld a, 1 << rSC_ON
+ ld [rSC], a
+ jr .done
+
+.init_player_number
+ ld a, [rSB]
+ ldh [hSerialRecieve], a
+ ldh [hLinkPlayerNumber], a
+ cp 2
+ jr z, .master
+ xor a
+ ld [rSB], a
+ ld a, 3
+ ld [rDIV], a
+.wait
+ ld a, [rDIV]
+ bit 7, a
+ jr nz, .wait
+ ld a, 1 << rSC_ON
+ ld [rSC], a
+ jr .done
+.master
+ xor a
+ ld [rSC], a
+
+.done
+ ld a, 1
+ ldh [hSerialRecieved], a
+ ld a, SERIAL_NO_DATA_BYTE
+ ldh [hSerialSend], a
+ pop hl
+ pop de
+ pop bc
+ pop af
+ reti
diff --git a/home/sram.asm b/home/sram.asm
new file mode 100644
index 0000000..c204b9b
--- /dev/null
+++ b/home/sram.asm
@@ -0,0 +1,19 @@
+SECTION "SRAM functions", ROM0[$32A7]
+
+OpenSRAM:: ; 32a7
+ push af
+ ld a, 1
+ ld [MBC3LatchClock], a
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+ pop af
+ ld [MBC3SRamBank], a
+ ret
+
+CloseSRAM:: ; 32b7
+ push af
+ ld a, SRAM_DISABLE
+ ld [MBC3LatchClock], a
+ ld [MBC3SRamEnable], a
+ pop af
+ ret
diff --git a/home/vblank.asm b/home/vblank.asm
new file mode 100644
index 0000000..efa7196
--- /dev/null
+++ b/home/vblank.asm
@@ -0,0 +1,29 @@
+SECTION "VBlank handler", ROM0[$150]
+
+VBlank:: ; 0150
+ push af
+ push bc
+ push de
+ push hl
+ ldh a, [hVBlank]
+ and 3
+ ld e, a
+ ld d, 0
+ ld hl, .blanks
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .return
+ push de
+ jp hl
+.return
+ pop hl
+ pop de
+ pop bc
+ pop af
+ reti
+
+.blanks
+ ; TODO
diff --git a/hram.asm b/hram.asm
new file mode 100644
index 0000000..c2b654d
--- /dev/null
+++ b/hram.asm
@@ -0,0 +1,71 @@
+SECTION "HRAM", HRAM[$FF80]
+
+hOAMDMA:: ; ff80
+ ds 10
+
+
+ ds 14 ; TODO
+
+
+hROMBank:: ; ff98
+ db
+
+
+hVBlank:: ; ff99
+ db
+
+
+ ds 8 ; TODO
+
+
+ ds 3 ; 3 joypad constants, TODO: investigate
+
+
+ ds 47 ; TODO
+
+
+hLCDCPointer:: ; ffd0
+ db
+
+
+ ds 3 ; TODO
+
+
+hSerialRecieved:: ; ffd4
+ db
+
+hLinkPlayerNumber:: ; ffd5
+ db
+
+
+ db ; TODO
+
+
+hSerialSend:: ; ffd7
+ db
+hSerialRecieve:: ; ffd8
+ db
+
+
+hSCX:: db ; ffd9
+hSCY:: db ; ffda
+hWX:: db ; ffdb
+hWY:: db ; ffdc
+
+hBGMapMode:: ; ffde
+ db
+
+ db ; TODO
+
+hBGMapAddress:: ; ffe0
+ dw
+
+
+ ds 6 ; TODO
+
+
+hMapAnims:: ; ffe8
+ ; TODO: figure out size
+
+
+ ; TODO
diff --git a/macros.asm b/macros.asm
index 87fa36d..25c1ed6 100644
--- a/macros.asm
+++ b/macros.asm
@@ -1 +1,6 @@
-INCLUDE "macros/enum.asm" \ No newline at end of file
+INCLUDE "macros/enum.asm"
+INCLUDE "macros/predef.asm"
+INCLUDE "macros/farcall.asm"
+INCLUDE "macros/data.asm"
+INCLUDE "macros/code.asm"
+INCLUDE "macros/coords.asm" \ No newline at end of file
diff --git a/macros/code.asm b/macros/code.asm
new file mode 100644
index 0000000..1fb651f
--- /dev/null
+++ b/macros/code.asm
@@ -0,0 +1,101 @@
+; Syntactic sugar macros
+
+lb: MACRO ; r, hi, lo
+ ld \1, (((\2) & $ff) << 8) | (((\3) & $ff))
+ENDM
+
+ln: MACRO ; r, hi, lo
+ ld \1, (((\2) & $f) << 4) | (((\3) & $f))
+ENDM
+
+ldpixel: MACRO
+if _NARG >= 5
+ lb \1, \2 * 8 + \4, \3 * 8 + \5
+else
+ lb \1, \2 * 8, \3 * 8
+endc
+ENDM
+
+depixel EQUS "ldpixel de,"
+bcpixel EQUS "ldpixel bc,"
+
+
+; Design patterns
+
+jumptable: MACRO
+ ld a, [\2]
+ ld e, a
+ ld d, 0
+ ld hl, \1
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+ENDM
+
+maskbits: MACRO
+; masks just enough bits to cover the argument
+; e.g. "maskbits 26" becomes "and %00011111" (since 26 - 1 = %00011001)
+; example usage in rejection sampling:
+; .loop
+; call Random
+; maskbits 26
+; cp 26
+; jr nc, .loop
+x = 1
+rept 8
+if x + 1 < (\1)
+x = x << 1 | 1
+endc
+endr
+ and x
+ENDM
+
+calc_sine_wave: MACRO
+; input: a = a signed 6-bit value
+; output: a = d * sin(a * pi/32)
+ and %111111
+ cp %100000
+ jr nc, .negative\@
+ call .apply\@
+ ld a, h
+ ret
+.negative\@
+ and %011111
+ call .apply\@
+ ld a, h
+ xor $ff
+ inc a
+ ret
+.apply\@
+ ld e, a
+ ld a, d
+ ld d, 0
+if _NARG == 1
+ ld hl, \1
+else
+ ld hl, .sinetable\@
+endc
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, 0
+.multiply\@ ; factor amplitude
+ srl a
+ jr nc, .even\@
+ add hl, de
+.even\@
+ sla e
+ rl d
+ and a
+ jr nz, .multiply\@
+ ret
+if _NARG == 0
+.sinetable\@
+ sine_table 32
+endc
+ENDM
diff --git a/macros/coords.asm b/macros/coords.asm
new file mode 100644
index 0000000..0833c24
--- /dev/null
+++ b/macros/coords.asm
@@ -0,0 +1,52 @@
+hlcoord EQUS "coord hl,"
+bccoord EQUS "coord bc,"
+decoord EQUS "coord de,"
+
+coord: MACRO
+; register, x, y[, origin]
+ if _NARG < 4
+ ld \1, (\3) * SCREEN_WIDTH + (\2) + wTileMap
+ else
+ ld \1, (\3) * SCREEN_WIDTH + (\2) + \4
+ endc
+ENDM
+
+hlbgcoord EQUS "bgcoord hl,"
+bcbgcoord EQUS "bgcoord bc,"
+debgcoord EQUS "bgcoord de,"
+
+bgcoord: MACRO
+; register, x, y[, origin]
+ if _NARG < 4
+ ld \1, (\3) * BG_MAP_WIDTH + (\2) + vBGMap0
+ else
+ ld \1, (\3) * BG_MAP_WIDTH + (\2) + \4
+ endc
+ENDM
+
+dwcoord: MACRO
+; x, y
+rept _NARG / 2
+ dw (\2) * SCREEN_WIDTH + (\1) + wTileMap
+ shift
+ shift
+endr
+ENDM
+
+ldcoord_a: MACRO
+; x, y[, origin]
+ if _NARG < 3
+ ld [(\2) * SCREEN_WIDTH + (\1) + wTileMap], a
+ else
+ ld [(\2) * SCREEN_WIDTH + (\1) + \3], a
+ endc
+ENDM
+
+lda_coord: MACRO
+; x, y[, origin]
+ if _NARG < 3
+ ld a, [(\2) * SCREEN_WIDTH + (\1) + wTileMap]
+ else
+ ld a, [(\2) * SCREEN_WIDTH + (\1) + \3]
+ endc
+ENDM
diff --git a/macros/data.asm b/macros/data.asm
new file mode 100644
index 0000000..241e52a
--- /dev/null
+++ b/macros/data.asm
@@ -0,0 +1,129 @@
+; Value macros
+
+percent EQUS "* $ff / 100"
+
+
+; Constant data (db, dw, dl) macros
+
+dwb: MACRO
+ dw \1
+ db \2
+ENDM
+
+dbw: MACRO
+ db \1
+ dw \2
+ENDM
+
+dbbw: MACRO
+ db \1, \2
+ dw \3
+ENDM
+
+dbww: MACRO
+ db \1
+ dw \2, \3
+ENDM
+
+dbwww: MACRO
+ db \1
+ dw \2, \3, \4
+ENDM
+
+dn: MACRO ; nybbles
+rept _NARG / 2
+ db ((\1) << 4) | (\2)
+ shift
+ shift
+endr
+ENDM
+
+dc: MACRO ; "crumbs"
+rept _NARG / 4
+ db ((\1) << 6) | ((\2) << 4) | ((\3) << 2) | (\4)
+ shift
+ shift
+ shift
+ shift
+endr
+ENDM
+
+dx: MACRO
+x = 8 * ((\1) - 1)
+rept \1
+ db LOW((\2) >> x)
+x = x + -8
+endr
+ENDM
+
+dt: MACRO ; three-byte (big-endian)
+ dx 3, \1
+ENDM
+
+dd: MACRO ; four-byte (big-endian)
+ dx 4, \1
+ENDM
+
+bigdw: MACRO ; big-endian word
+ dx 2, \1
+ENDM
+
+dba: MACRO ; dbw bank, address
+rept _NARG
+ dbw BANK(\1), \1
+ shift
+endr
+ENDM
+
+dab: MACRO ; dwb address, bank
+rept _NARG
+ dwb \1, BANK(\1)
+ shift
+endr
+ENDM
+
+dba_pic: MACRO ; dbw bank, address
+ db BANK(\1) - PICS_FIX
+ dw \1
+ENDM
+
+
+dbpixel: MACRO
+if _NARG >= 4
+; x tile, x pxl, y tile, y pxl
+ db \1 * 8 + \3, \2 * 8 + \4
+else
+; x, y
+ db \1 * 8, \2 * 8
+endc
+ENDM
+
+dsprite: MACRO
+; y tile, y pxl, x tile, x pxl, vtile offset, flags, attributes
+ db LOW(\1 * 8) + \2, LOW(\3 * 8) + \4, \5, \6
+ENDM
+
+
+menu_coords: MACRO
+; x1, y1, x2, y2
+ db \2, \1 ; start coords
+ db \4, \3 ; end coords
+ENDM
+
+
+bcd: MACRO
+rept _NARG
+ dn LOW(\1) / 10, (\1) % 10
+ shift
+endr
+ENDM
+
+
+sine_table: MACRO
+; \1 samples of sin(x) from x=0 to x<32768 (pi radians)
+x = 0
+rept \1
+ dw HIGH(sin(x) + LOW(sin(x))) ; round up
+x = x + DIV(32768, \1) ; a circle has 65536 "degrees"
+endr
+ENDM
diff --git a/macros/farcall.asm b/macros/farcall.asm
new file mode 100644
index 0000000..e70cff8
--- /dev/null
+++ b/macros/farcall.asm
@@ -0,0 +1,22 @@
+
+farcall: MACRO ; bank, address
+ ld a, BANK(\1)
+ ld hl, \1
+ call FarCall
+ENDM
+
+callfar: MACRO ; address, bank
+ ld hl, \1
+ ld a, BANK(\1)
+ call FarCall
+ENDM
+
+homecall: MACRO
+ ld a, [hROMBank]
+ push af
+ ld a, BANK(\1)
+ call Bankswitch
+ call \1
+ pop af
+ call Bankswitch
+ENDM
diff --git a/macros/gfx.asm b/macros/gfx.asm
new file mode 100644
index 0000000..16c7d9b
--- /dev/null
+++ b/macros/gfx.asm
@@ -0,0 +1,2 @@
+tiles EQUS "* LEN_2BPP_TILE"
+tile EQUS "+ LEN_2BPP_TILE *"
diff --git a/macros/predef.asm b/macros/predef.asm
new file mode 100644
index 0000000..7850350
--- /dev/null
+++ b/macros/predef.asm
@@ -0,0 +1,15 @@
+predef_id: MACRO
+; Some functions load the predef id
+; without immediately calling Predef.
+ ld a, (\1Predef - PredefPointers) / 3
+ENDM
+
+predef: MACRO
+ predef_id \1
+ call Predef
+ENDM
+
+predef_jump: MACRO
+ predef_id \1
+ jp Predef
+ENDM
diff --git a/macros/wram.asm b/macros/wram.asm
new file mode 100644
index 0000000..7e7505f
--- /dev/null
+++ b/macros/wram.asm
@@ -0,0 +1,365 @@
+
+flag_array: MACRO
+ ds ((\1) + 7) / 8
+ENDM
+
+box_struct: MACRO
+\1Species:: db
+\1Item:: db
+\1Moves:: ds NUM_MOVES
+\1ID:: dw
+\1Exp:: ds 3
+\1StatExp::
+\1HPExp:: dw
+\1AtkExp:: dw
+\1DefExp:: dw
+\1SpdExp:: dw
+\1SpcExp:: dw
+\1DVs:: ds 2
+\1PP:: ds NUM_MOVES
+\1Happiness:: db
+\1PokerusStatus:: db
+\1CaughtData::
+\1CaughtTime::
+\1CaughtLevel:: db
+\1CaughtGender::
+\1CaughtLocation:: db
+\1Level:: db
+\1End::
+ENDM
+
+party_struct: MACRO
+ box_struct \1
+\1Status:: db
+\1Unused:: db
+\1HP:: dw
+\1MaxHP:: dw
+\1Stats:: ; big endian
+\1Attack:: dw
+\1Defense:: dw
+\1Speed:: dw
+\1SpclAtk:: dw
+\1SpclDef:: dw
+\1StatsEnd::
+ENDM
+
+red_box_struct: MACRO
+\1Species:: db
+\1HP:: dw
+\1BoxLevel:: db
+\1Status:: db
+\1Type::
+\1Type1:: db
+\1Type2:: db
+\1CatchRate:: db
+\1Moves:: ds NUM_MOVES
+\1OTID:: dw
+\1Exp:: ds 3
+\1HPExp:: dw
+\1AttackExp:: dw
+\1DefenseExp:: dw
+\1SpeedExp:: dw
+\1SpecialExp:: dw
+\1DVs:: ds 2
+\1PP:: ds NUM_MOVES
+ENDM
+
+red_party_struct: MACRO
+ red_box_struct \1
+\1Level:: db
+\1Stats::
+\1MaxHP:: dw
+\1Attack:: dw
+\1Defense:: dw
+\1Speed:: dw
+\1Special:: dw
+ENDM
+
+
+battle_struct: MACRO
+\1Species:: db
+\1Item:: db
+\1Moves:: ds NUM_MOVES
+\1MovesEnd::
+\1DVs:: ds 2
+\1PP:: ds NUM_MOVES
+\1Happiness:: db
+\1Level:: db
+\1Status:: ds 2
+\1HP:: dw
+\1MaxHP:: dw
+\1Stats:: ; big endian
+\1Attack:: dw
+\1Defense:: dw
+\1Speed:: dw
+\1SpclAtk:: dw
+\1SpclDef:: dw
+\1StatsEnd::
+\1Type::
+\1Type1:: db
+\1Type2:: db
+\1StructEnd::
+ENDM
+
+box: MACRO
+\1::
+\1Count:: ds 1
+\1Species:: ds MONS_PER_BOX + 1
+\1Mons::
+\1Mon1:: box_struct \1Mon1
+\1Mon2:: ds BOXMON_STRUCT_LENGTH * (MONS_PER_BOX +- 1)
+\1MonOT:: ds NAME_LENGTH * MONS_PER_BOX
+\1MonNicknames:: ds PKMN_NAME_LENGTH * MONS_PER_BOX
+\1MonNicknamesEnd::
+\1End:: ds 2 ; padding
+ENDM
+
+
+channel_struct: MACRO
+; TODO: CH1 isn't at C101, please rebase all of these
+; Addreses are Channel1 (c101).
+\1MusicID:: dw
+\1MusicBank:: db
+\1Flags:: db ; 0:on/off 1:subroutine 3:sfx 4:noise 5:rest
+\1Flags2:: db ; 0:vibrato on/off 2:duty 4:cry pitch
+\1Flags3:: db ; 0:vibrato up/down
+\1MusicAddress:: dw
+\1LastMusicAddress:: dw
+ dw
+\1NoteFlags:: db ; 5:rest
+\1Condition:: db ; conditional jumps
+\1DutyCycle:: db ; bits 6-7 (0:12.5% 1:25% 2:50% 3:75%)
+\1Intensity:: db ; hi:pressure lo:velocity
+\1Frequency:: ; 11 bits
+\1FrequencyLo:: db
+\1FrequencyHi:: db
+\1Pitch:: db ; 0:rest 1-c:note
+\1Octave:: db ; 7-0 (0 is highest)
+\1StartingOctave:: db ; raises existing octaves (to repeat phrases)
+\1NoteDuration:: db ; frames remaining for the current note
+\1Field16:: ds 1 ; c117
+ ds 1 ; c118
+\1LoopCount:: db
+\1Tempo:: dw
+\1Tracks:: db ; hi:left lo:right
+\1SFXDutyLoop:: ds 1 ; c11d
+\1VibratoDelayCount:: db ; initialized by \1VibratoDelay
+\1VibratoDelay:: db ; number of frames a note plays until vibrato starts
+\1VibratoExtent:: db
+\1VibratoRate:: db ; hi:frames for each alt lo:frames to the next alt
+\1PitchWheelTarget:: dw ; frequency endpoint for pitch wheel
+\1PitchWheelAmount:: db ; c124
+\1PitchWheelAmountFraction:: db ; c125
+\1Field25:: ds 1 ; c126
+ ds 1 ; c127
+\1CryPitch:: dw
+\1Field29:: ds 1
+\1Field2a:: ds 2
+\1Field2c:: ds 1
+\1NoteLength:: db ; frames per 16th note
+\1Field2e:: ds 1 ; c12f
+\1Field2f:: ds 1 ; c130
+\1Field30:: ds 1 ; c131
+ ds 1 ; c132
+ENDM
+
+mailmsg: MACRO
+\1Message:: ds MAIL_MSG_LENGTH
+\1MessageEnd:: ds 1
+\1Author:: ds PLAYER_NAME_LENGTH
+\1AuthorNationality:: ds 2
+\1AuthorID:: ds 2
+\1Species:: ds 1
+\1Type:: ds 1
+\1End::
+endm
+
+hof_mon: MACRO
+\1Species:: ds 1
+\1ID:: ds 2
+\1DVs:: ds 2
+\1Level:: ds 1
+\1Nickname:: ds PKMN_NAME_LENGTH +- 1
+\1End::
+endm
+
+roam_struct: MACRO
+\1Species:: db
+\1Level:: db
+\1MapGroup:: db
+\1MapNumber:: db
+\1HP:: ds 1
+\1DVs:: ds 2
+ENDM
+
+bugcontestwinner: macro
+\1PersonID:: ds 1
+\1Mon:: ds 1
+\1Score:: ds 2
+endm
+
+hall_of_fame: MACRO
+\1::
+\1WinCount:: ds 1
+\1Mon1:: hof_mon \1Mon1
+\1Mon2:: hof_mon \1Mon2
+\1Mon3:: hof_mon \1Mon3
+\1Mon4:: hof_mon \1Mon4
+\1Mon5:: hof_mon \1Mon5
+\1Mon6:: hof_mon \1Mon6
+\1End:: ds 1
+ENDM
+
+trademon: MACRO
+\1Species:: ds 1 ; wc6d0 | wc702
+\1SpeciesName:: ds PKMN_NAME_LENGTH ; wc6d1 | wc703
+\1Nickname:: ds PKMN_NAME_LENGTH ; wc6dc | wc70e
+\1SenderName:: ds NAME_LENGTH ; wc6e7 | wc719
+\1OTName:: ds NAME_LENGTH ; wc6f2 | wc724
+\1DVs:: ds 2 ; wc6fd | wc72f
+\1ID:: ds 2 ; wc6ff | wc731
+\1CaughtData:: ds 1 ; wc701 | wc733
+\1End::
+ENDM
+
+move_struct: MACRO
+\1Animation:: ds 1
+\1Effect:: ds 1
+\1Power:: ds 1
+\1Type:: ds 1
+\1Accuracy:: ds 1
+\1PP:: ds 1
+\1EffectChance:: ds 1
+endm
+
+slot_reel: MACRO
+\1ReelAction:: db
+\1TilemapAddr:: dw
+\1Position:: db
+\1SpinDistance:: db
+\1SpinRate:: db
+\1OAMAddr:: dw
+\1XCoord:: db
+\1Slot09:: ds 1
+\1Slot0a:: ds 1
+\1Slot0b:: ds 1
+\1Slot0c:: ds 1
+\1Slot0d:: ds 1
+\1Slot0e:: ds 1
+\1Slot0f:: ds 1
+endm
+
+object_struct: MACRO
+\1Struct::
+\1Sprite:: ds 1
+\1MapObjectIndex:: ds 1
+\1SpriteTile:: ds 1
+\1MovementType:: ds 1
+\1Flags:: ds 2
+\1Palette:: ds 1
+\1Walking:: ds 1
+\1Direction:: ds 1
+\1StepType:: ds 1
+\1StepDuration:: ds 1
+\1Action:: ds 1
+\1ObjectStepFrame:: ds 1
+\1Facing:: ds 1
+\1StandingTile:: ds 1 ; collision
+\1LastTile:: ds 1 ; collision
+\1StandingMapX:: ds 1
+\1StandingMapY:: ds 1
+\1LastMapX:: ds 1
+\1LastMapY:: ds 1
+\1ObjectInitX:: ds 1
+\1ObjectInitY:: ds 1
+\1Radius:: ds 1
+\1SpriteX:: ds 1
+\1SpriteY:: ds 1
+\1SpriteXOffset:: ds 1
+\1SpriteYOffset:: ds 1
+\1MovementByteIndex:: ds 1
+\1Object28:: ds 1
+\1Object29:: ds 1
+\1Object30:: ds 1
+\1Object31:: ds 1
+\1Range:: ds 1
+ ds 7
+\1StructEnd::
+ENDM
+
+map_object: MACRO
+\1Object::
+\1ObjectStructID:: ds 1
+\1ObjectSprite:: ds 1
+\1ObjectYCoord:: ds 1
+\1ObjectXCoord:: ds 1
+\1ObjectMovement:: ds 1
+\1ObjectRadius:: ds 1
+\1ObjectHour:: ds 1
+\1ObjectTimeOfDay:: ds 1
+\1ObjectColor:: ds 1
+\1ObjectRange:: ds 1
+\1ObjectScript:: ds 2
+\1ObjectEventFlag:: ds 2
+ ds 2
+endm
+
+sprite_anim_struct: MACRO
+\1Index:: ds 1 ; 0
+\1FramesetID:: ds 1 ; 1
+\1AnimSeqID:: ds 1 ; 2
+\1TileID:: ds 1 ; 3
+\1XCoord:: ds 1 ; 4
+\1YCoord:: ds 1 ; 5
+\1XOffset:: ds 1 ; 6
+\1YOffset:: ds 1 ; 7
+\1Duration:: ds 1 ; 8
+\1DurationOffset:: ds 1 ; 9
+\1FrameIndex:: ds 1 ; a
+\1Sprite0b:: ds 1
+\1Sprite0c:: ds 1
+\1Sprite0d:: ds 1
+\1Sprite0e:: ds 1
+\1Sprite0f:: ds 1
+ENDM
+
+battle_anim_struct: MACRO
+; Placeholder until we can figure out what it all means
+\1_Index:: ds 1
+\1_Anim01:: ds 1
+\1_Anim02:: ds 1
+\1_FramesetIndex:: ds 1
+\1_FunctionIndex:: ds 1
+\1_Anim05:: ds 1
+\1_TileID:: ds 1
+\1_XCoord:: ds 1
+\1_YCoord:: ds 1
+\1_XOffset:: ds 1
+\1_YOffset:: ds 1
+\1_Anim0b:: ds 1
+\1_Anim0c:: ds 1
+\1_Anim0d:: ds 1
+\1_AnonJumptableIndex:: ds 1
+\1_Anim0f:: ds 1
+\1_Anim10:: ds 1
+\1_Anim11:: ds 1
+\1_Anim12:: ds 1
+\1_Anim13:: ds 1
+\1_Anim14:: ds 1
+\1_Anim15:: ds 1
+\1_Anim16:: ds 1
+\1_Anim17:: ds 1
+endm
+
+battle_bg_effect: MACRO
+\1_Function:: ds 1
+\1_01:: ds 1
+\1_02:: ds 1
+\1_03:: ds 1
+endm
+
+warp_struct: MACRO
+\1WarpNumber:: ds 1
+\1MapGroup:: ds 1
+\1MapNumber:: ds 1
+ENDM
diff --git a/shim.sym b/shim.sym
index e28c614..1f85ed2 100644
--- a/shim.sym
+++ b/shim.sym
@@ -28,7 +28,6 @@
00:232c LoadMapWarp
00:23e5 OverworldFadeIn
-00:2F97 InexplicablyEmptyFunction
00:2FA8 FarCall_hl
00:2FC8 FarCall_hl.return
00:2FDE Predef
@@ -178,18 +177,3 @@
01:d66a wMapScriptPtr
01:D7D2 wPartyMonOT
01:DA3B wUnk_DA3B ; In final, $DE7D in NamesPointers (6th entry)
-01:DFFF wStackTop
-
-00:FF80 hPushOAM
-00:FF98 hROMBank
-00:FFA3 hUnk_FFA3
-00:FFA4 hUnk_Joypad ; ?
-00:FFD5 hLinkPlayerNumber
-00:FFD9 hSCX
-00:FFDA hSCY
-00:FFDB hWX
-00:FFDC hWY
-00:FFDE hBGMapMode
-00:FFE0 hBGMapAddress
-00:FFE8 hMapAnims
-
diff --git a/sram.asm b/sram.asm
new file mode 100644
index 0000000..3ea96e7
--- /dev/null
+++ b/sram.asm
@@ -0,0 +1,4 @@
+SECTION "Unknown, bank 0", SRAM[$A600],BANK[0]
+
+s0_a600:: ; TODO: properly label this
+ ds 7 ; TODO: figure out exact size
diff --git a/tools/make_shim.py b/tools/make_shim.py
index 67b9f4e..7c60f4f 100644
--- a/tools/make_shim.py
+++ b/tools/make_shim.py
@@ -1,39 +1,77 @@
from sys import argv, stderr
-for line in open(argv[1]):
- line = line.split(";")[0]
- line = line.strip()
- if line and " " in line:
- address, symbol = line.split()
- bank, pointer = address.split(":")
- bank = int(bank, 16)
- pointer = int(pointer, 16)
- section = None
- if bank == 0 and pointer < 0x4000:
- section = "ROM0"
- bank = None
- elif pointer < 0x8000:
- section = "ROMX"
- elif pointer < 0xa000:
- section = "VRAM"
- elif pointer < 0xc000:
- section = "SRAM"
- elif bank == 0 and pointer < 0xd000:
- section = "WRAM0"
- bank = None
- elif pointer < 0xe000:
- section = "WRAMX"
- elif pointer > 0xff80 and pointer <= 0xffff:
- section = "HRAM"
- else:
- stderr.write(f"Unknown section for {line}\n")
-
- if section:
- if bank:
- print(f"SECTION \"Shim for {symbol}\", {section}[${pointer:x}], BANK[${bank:x}]")
- else:
- print(f"SECTION \"Shim for {symbol}\", {section}[${pointer:x}]")
- print(f"{symbol}::\n\n")
+
+section_list = [
+ {'end': 0x4000, 'invalid': False, 'name': "ROM0", 'banked': False},
+ {'end': 0x8000, 'invalid': False, 'name': "ROMX", 'banked': True},
+ {'end': 0xA000, 'invalid': False, 'name': "VRAM", 'banked': True},
+ {'end': 0xC000, 'invalid': False, 'name': "SRAM", 'banked': True},
+ {'end': 0xD000, 'invalid': False, 'name': "WRAM0", 'banked': False},
+ {'end': 0xE000, 'invalid': False, 'name': "WRAMX", 'banked': True},
+ {'end': 0xFE00, 'invalid': True , 'name': "Echo RAM"},
+ {'end': 0xFEA0, 'invalid': False, 'name': "OAM", 'banked': False},
+ {'end': 0xFF80, 'invalid': True , 'name': "FEXX / IO"},
+ {'end': 0xFFFF, 'invalid': False, 'name': "HRAM", 'banked': False}
+]
+
+
+argv_id = 1
+file_list = []
+options = []
+while argv_id < len(argv):
+ arg = argv[argv_id]
+ if arg[0] != '-':
+ file_list.append(arg)
+ elif arg[1] != '-':
+ for option in arg[1:]:
+ options.append(option)
+ else:
+ options.append(option[2:])
+ argv_id += 1
+
+
+if 'w' in options or 'd' in options:
+ section_list[4]['end'] = 0xE000
+
+if 't' in options:
+ section_list[0]['end'] = 0x8000
+
+
+for file_name in file_list:
+ with open(file_name, "rt") as f:
+ for line in f:
+ line = line.split(";")[0]
+ line = line.strip()
+ if line and " " in line:
+ address, symbol = line.split()
+ bank, pointer = address.split(":")
+ bank = int(bank, 16)
+ pointer = int(pointer, 16)
+
+ section = None
+ for section_type in section_list:
+ if pointer < section_type['end']:
+ if section_type['invalid']:
+ stderr.write(f"Warning: cannot shim '{symbol}' in section type '{section_type['name']}'\n")
+ section = False
+ else:
+ section = section_type['name']
+ if not section_type['banked']:
+ bank = None
+ break
+
+ if section == False: # Found section, but cannot shim it
+ continue
+
+ if section == None: # Didn't find a section at all
+ stderr.write(f"Unknown section for {line}\n")
+
+ if section:
+ if bank:
+ print(f"SECTION \"Shim for {symbol}\", {section}[${pointer:x}], BANK[${bank:x}]")
+ else:
+ print(f"SECTION \"Shim for {symbol}\", {section}[${pointer:x}]")
+ print(f"{symbol}::\n\n")