├── LICENSE ├── README.md ├── constants.asm ├── main.asm └── palettes.asm /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 alexsteb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tetris_disassembly 2 | Disassembly of Tetris for the Gameboy. 3 | 4 | Compiles 1:1 to the official Tetris (World) GB ROM. 5 | 6 | To-dos: 7 | - finish code annotation 8 | - annotate data sections (and solve discrepancies) 9 | 10 | To build, simply use RGBDS: 11 | 12 | Linux: 13 | ``` 14 | rgbasm -o main.o main.asm 15 | rgblink -o tetris.gb main.o 16 | ``` 17 | 18 | Windows: 19 | ``` 20 | rgbasm.exe -o main.o main.asm 21 | rgblink.exe -o tetris.gb main.o 22 | ``` 23 | -------------------------------------------------------------------------------- /constants.asm: -------------------------------------------------------------------------------- 1 | ; Initializing 2 | SP_INIT EQU $cfff ; Initial location of Stack Pointer 3 | 4 | ; Screen constants 5 | SCREEN_HEIGHT EQU 144 ; Visible Pixels before VBlank ($90) 6 | SCREEN_WIDTH EQU 160 ; Visible Pixels before HBlank ($A0) 7 | LCDC_ON EQU $80 ; Turn LCDC on 8 | LCDC_STANDARD EQU $d3 ; LCDC, BG, Sprites on, Window Tile Map starts at $9c00, 9 | ; BG & Window Tile Data starts at $8000, 10 | ; BG Tile Map Display starts at $9800, 11 | ; OBJ (Sprite) Size is set to 8x8 pixels 12 | 13 | ; Joypad constants (internal meaning: directional buttons in the upper nibble, numbers equal the bit set) 14 | BTN_RIGHT EQU 4 ; Directional Right 15 | BTN_LEFT EQU 5 ; Directional Left 16 | BTN_UP EQU 6 ; Directional Up 17 | BTN_DOWN EQU 7 ; Directional Down 18 | BTN_A EQU 0 ; Button A 19 | BTN_B EQU 1 ; Button B 20 | BTN_SELECT EQU 2 ; Button Select 21 | BTN_START EQU 3 ; Button Start 22 | 23 | 24 | 25 | 26 | ; Sound constants 27 | SOUND_ON EQU $80 28 | USE_ALL_CHANNELS EQU $FF ; Set all audio channels to both output terminals (stereo) 29 | MASTER_VOLUME_MAX EQU $77 ; Set both output terminals to highest volume 30 | ENVELOPE_NO_SOUND EQU $08 ; Sets an envelope to no sound and direction to "increase" 31 | 32 | 33 | ; RAM constants 34 | ; c000-c09f is the OAM data source 35 | 36 | rSCORE1 EQU $c0a0 ; score, smallest digits, highest value = 99 37 | rSCORE2 EQU $c0a1 ; score, middle digits, highest value = 99 (= 9900) 38 | rSCORE3 EQU $c0a2 ; score, highest digits, highest value = 99 (= 990000) 39 | rLINE_CLEAR_START EQU $c0a3 ; $ca after clearing 1-3 line(s), $c9 after clearing 4 lines 40 | 41 | rUNKNOWN3 EQU $c0a4 ; .. 42 | 43 | rHIDE_NEXT_BLOCK EQU $c0de ; 0 = normal, 1 = next block display hidden (toggled by select button. Keeps value even if hidden in pause menu.) 44 | 45 | rBLOCK_VISIBILITY EQU $c200 ; 80 = invisible, 0 = visible 46 | rBLOCK_Y EQU $c201 ; Y location of falling block 47 | rBLOCK_X EQU $c202 ; X location of falling block 48 | rBLOCK_TYPE EQU $c203 ; Block type of falling block (see list below) 49 | 50 | rNEXT_BLOCK_VISIBILITY EQU $c210 ; 80 = invisible, 0 = visible 51 | rNEXT_BLOCK_Y EQU $c211 ; Y location of next block (always $80) 52 | rNEXT_BLOCK_X EQU $c212 ; X location of next block (always $8f) 53 | rNEXT_BLOCK_TYPE EQU $c213 ; Block type of next block (see list below, always the first unrotated variant) 54 | 55 | ; Block types: (higher numbers mean counter-clockwise rotation. A-Button decreases number -> clockwise rotation) 56 | ; ### 57 | rL_SHAPE_0 EQU $00 ; # 58 | rL_SHAPE_1 EQU $01 59 | rL_SHAPE_2 EQU $02 60 | rL_SHAPE_3 EQU $03 61 | ; ### 62 | rREVERSE_L_SHAPE_0 EQU $04 ; # 63 | rREVERSE_L_SHAPE_1 EQU $05 64 | rREVERSE_L_SHAPE_2 EQU $06 65 | rREVERSE_L_SHAPE_3 EQU $07 66 | 67 | rI_SHAPE_0 EQU $08 ; #### 68 | rI_SHAPE_1 EQU $09 69 | rI_SHAPE_2 EQU $0a 70 | rI_SHAPE_3 EQU $0b 71 | ; ## 72 | rSQUARE_SHAPE_0 EQU $0c ; ## 73 | rSQUARE_SHAPE_1 EQU $0d ; (Yes the square can be rotated!) 74 | rSQUARE_SHAPE_2 EQU $0e 75 | rSQUARE_SHAPE_3 EQU $0f 76 | ; ## 77 | rZ_SHAPE_0 EQU $10 ; ## 78 | rZ_SHAPE_1 EQU $11 79 | rZ_SHAPE_2 EQU $12 80 | rZ_SHAPE_3 EQU $13 81 | ; ## 82 | rS_SHAPE_0 EQU $14 ; ## 83 | rS_SHAPE_1 EQU $15 84 | rS_SHAPE_2 EQU $16 85 | rS_SHAPE_3 EQU $17 86 | ; ### 87 | rT_SHAPE_0 EQU $18 ; # 88 | rT_SHAPE_1 EQU $19 89 | rT_SHAPE_2 EQU $1a 90 | rT_SHAPE_3 EQU $1b 91 | 92 | 93 | rHIDE_NEXT_BLOCK_DISPLAY EQU $c210 ; 0 = normal, $80 = next block display hidden - DISPLAY (always $80 in pause menu) 94 | 95 | rPAUSED EQU $df7f ; 00 = normal / paused, 01 = pause pressed, 02 = unpause pressed 96 | rPAUSE_CHIME EQU $df7e ; 00 = normal, 11 = final value in pause menu after countdown, 30 = initial value when pause pressed 97 | 98 | rSOUND1 EQU $dfe1 ; (Set whenever a new sound is about to be played) 99 | rSOUND2 EQU $dfe9 ; ? 100 | rSOUND3 EQU $dff1 ; ? 101 | rSOUND4 EQU $dff9 ; ? 102 | rSOUND5 EQU $df9f ; ? 103 | rSOUND6 EQU $dfaf ; ? 104 | rSOUND7 EQU $dfbf ; ? 105 | rSOUND8 EQU $dfcf ; ? 106 | rSOUND9 EQU $df78 ; ? 107 | 108 | 109 | ; Hardware registers 110 | rMBC EQU $2000 ; MBC Controller - Select ROM bank 0 (not needed in Tetris) 111 | rJOYP EQU $ff00 ; Joypad (R/W) 112 | rSB EQU $ff01 ; Serial transfer data (R/W) 113 | rSC EQU $ff02 ; Serial Transfer Control (R/W) 114 | rSC_ON EQU 7 115 | rSC_CGB EQU 1 116 | rSC_CLOCK EQU 0 117 | rDIV EQU $ff04 ; Divider Register (R/W) 118 | rTIMA EQU $ff05 ; Timer counter (R/W) 119 | rTMA EQU $ff06 ; Timer Modulo (R/W) 120 | rTAC EQU $ff07 ; Timer Control (R/W) 121 | rTAC_ON EQU 2 122 | rTAC_4096_HZ EQU 0 123 | rTAC_262144_HZ EQU 1 124 | rTAC_65536_HZ EQU 2 125 | rTAC_16384_HZ EQU 3 126 | rIF EQU $ff0f ; Interrupt Flag (R/W) 127 | rNR10 EQU $ff10 ; Channel 1 Sweep register (R/W) 128 | rNR11 EQU $ff11 ; Channel 1 Sound length/Wave pattern duty (R/W) 129 | rNR12 EQU $ff12 ; Channel 1 Volume Envelope (R/W) 130 | rNR13 EQU $ff13 ; Channel 1 Frequency lo (Write Only) 131 | rNR14 EQU $ff14 ; Channel 1 Frequency hi (R/W) 132 | rNR21 EQU $ff16 ; Channel 2 Sound Length/Wave Pattern Duty (R/W) 133 | rNR22 EQU $ff17 ; Channel 2 Volume Envelope (R/W) 134 | rNR23 EQU $ff18 ; Channel 2 Frequency lo data (W) 135 | rNR24 EQU $ff19 ; Channel 2 Frequency hi data (R/W) 136 | rNR30 EQU $ff1a ; Channel 3 Sound on/off (R/W) 137 | rNR31 EQU $ff1b ; Channel 3 Sound Length 138 | rNR32 EQU $ff1c ; Channel 3 Select output level (R/W) 139 | rNR33 EQU $ff1d ; Channel 3 Frequency's lower data (W) 140 | rNR34 EQU $ff1e ; Channel 3 Frequency's higher data (R/W) 141 | rNR41 EQU $ff20 ; Channel 4 Sound Length (R/W) 142 | rNR42 EQU $ff21 ; Channel 4 Volume Envelope (R/W) 143 | rNR43 EQU $ff22 ; Channel 4 Polynomial Counter (R/W) 144 | rNR44 EQU $ff23 ; Channel 4 Counter/consecutive; Initial (R/W) 145 | rNR50 EQU $ff24 ; Channel control / ON-OFF / Volume (R/W) 146 | rNR51 EQU $ff25 ; Selection of Sound output terminal (R/W) 147 | rNR52 EQU $ff26 ; Sound on/off 148 | rLCDC EQU $ff40 ; LCD Control (R/W) 149 | 150 | rLCDC_STAT EQU $ff41 ; LCDC Status (R/W) 151 | rSCY EQU $ff42 ; Scroll Y (R/W) 152 | rSCX EQU $ff43 ; Scroll X (R/W) 153 | rLY EQU $ff44 ; LCDC Y-Coordinate (R) 154 | rLYC EQU $ff45 ; LY Compare (R/W) 155 | rDMA EQU $ff46 ; DMA Transfer and Start Address (W) 156 | rBGP EQU $ff47 ; BG Palette Data (R/W) 157 | rOBP0 EQU $ff48 ; Object Palette 0 Data (R/W) 158 | rOBP1 EQU $ff49 ; Object Palette 1 Data (R/W) 159 | rWY EQU $ff4a ; Window Y Position (R/W) 160 | rWX EQU $ff4b ; Window X Position minus 7 (R/W) 161 | rIE EQU $ffff ; Interrupt Enable (R/W) 162 | 163 | 164 | ; HRAM variables 165 | rBUTTON_DOWN EQU $ff80 ; buttons currently pressed (lower nibble = buttons, higher nibble = directional keys) 166 | rBUTTON_HIT EQU $ff81 ; buttons pressed for the first time 167 | rVBLANK_DONE EQU $ff85 ; 1 = VBlank interrupt executed; 0 = Not executed yet 168 | 169 | rOAM_TILE_NO EQU $ff89 ; temporary storage for OAM data of next transfer to $c000 - $c09f 170 | rOAM_ATTRIBUTE_NO EQU $ff8a ; " 171 | rUNKNOWN4 EQU $ff8b ; " 172 | rUNKNOWN5 EQU $ff8c ; 173 | 174 | rOAM_TILE_ADDRESS_1 EQU $ff8d ; higher byte of target OAM storage address (in $c000 - $c09f) for transfer from temporary storage in HRAM 175 | rOAM_TILE_ADDRESS_2 EQU $ff8e ; lower byte " " 176 | rAMOUNT_SPRITES_TO_DRAW EQU $ff8f ; draws X amount of sprites starting at $c200, incrementing by $10 177 | 178 | rOAM_X_POS EQU $ff92 ; temporary storage for OAM data of next transfer to $c000 - $c09f 179 | rOAM_Y_POS EQU $ff93 ; " 180 | rUNKNOWN6 EQU $ff94 ; " 181 | rOAM_VISIBLE EQU $ff95 ; " - $80 = invisible, $00 = visible 182 | 183 | rSPRITE_ORIGINAL_ADDRESS_1 EQU $ff96 ; higher byte of starting address of sprite info in $c200+ 184 | rSPRITE_ORIGINAL_ADDRESS_2 EQU $ff97 ; lower byte of starting address of sprite info in $c200+ 185 | 186 | 187 | 188 | rBLOCK_STATUS EQU $ff98 ; runs from 1 to 3 when block hits ground; back to 0 before chime and line clear handling 189 | 190 | rGRAVITY EQU $ff99 ; loops from $0a to $00, block falls down by one when transitioning from $0a to $09 191 | 192 | rCLEAR_PROGRESS EQU $ff9c ; runs from 1 to 7 during line clear animation 193 | 194 | rLINES_CLEARED1 EQU $ff9e ; smallest digits of cleared line number in decimal, so highest value = 99 - or lines left in game type B 195 | rLINES_CLEARED2 EQU $ff9f ; highest digits, highest value also 99 (meaning 9900), making 9999 the highest line number possible. 196 | 197 | rIE_TEMP EQU $ffa1 ; used for temporary storage of IE ($ffff) 198 | 199 | rUNKNOWN1 EQU $ffa4 ; probably unused 200 | rCOUNTDOWN EQU $ffa6 ; various uses - counts down one per VBlank (~59.7 times a second) 201 | rCOUNTDOWN2 EQU $ffa7 ; various uses - counts down one per VBlank = 4 seconds per byte (256 values) 202 | 203 | rPAUSE_MENU EQU $ffab ; 0 = normal, 1 = in pause menu 204 | 205 | rDEMO_STATUS EQU $ffb0 ; $0 = normal, $03 - $0f = # of block in demo 1, $10 = back in main menu (between games) 206 | ; $11 - $1c = # of block in demo 2, $1d = back in main menu (after demo 2, before demo 1 again) 207 | 208 | ; $ffb6 - $ffb7 = DMA transfer routine 209 | 210 | rGAME_TYPE EQU $ffc0 ; $37 = Type A, $77 = Type B 211 | rMUSIC_TYPE EQU $ffc1 ; $1c = Music A, $1d = Music B, $1e = Music C, $1f = Music off 212 | rLEVEL_A EQU $ffc2 ; current level (type A) 213 | rLEVEL_B EQU $ffc3 ; current level (type B) 214 | rINITIAL_HEIGHT EQU $ffc4 ; height of blocks (Type B) 215 | rPLAYERS EQU $ffc5 ; 0 = 1 player, 1 = 2 players 216 | rMUSIC_COUNTDOWN EQU $ffc6 ; countdown for title screen music - until demo game starts playing (reduces by one whenever rCOUNTDOWN reaches 0) 217 | rUNKNOWN7 EQU $ffca ; related to hiscore entry 218 | rUNKNOWN8 EQU $ffcb ; ?Must be $29 to consider sending data in VBlank.. 219 | rREQUEST_SERIAL_TRANSFER EQU $ffce ; Request serial connection data transfer 220 | rSB_DATA EQU $ffcf ; Holds the data to be sent via link cable 221 | rGAME_STATUS EQU $ffe1 ; See table below: 222 | ; $00 = in-game (both game types) 223 | ; $01 = shortly before game over screen 224 | ; $02 = !rocket launch 4 225 | ; $03 = !rocket launch 5 226 | ; $04 = game over screen 227 | ; $05 = type B winning chime 228 | ; $06 = shortly before title screen 229 | ; $07 = title screen 230 | ; $08 = shortly before game type selection 231 | ; $09 = nothing 232 | ; $0a = shortly before in-game 233 | ; $0b = showing score (type B) 234 | ; $0c = !leads to 02 235 | ; $0d = game lost animation (screen filling with bricks) 236 | ; $0e = game type selection (top screen) 237 | ; $0f = music selection (bottom screen) 238 | ; $10 = shortly before choose level (type A) 239 | ; $11 = choose level (type A) 240 | ; $12 = shortly before choose level (type B) 241 | ; $13 = choose level (type B) 242 | ; $14 = select "high" / initial random block height (type B) 243 | ; $15 = enter hiscore name (type A & B) 244 | ; $16 = !shortly before "Mario vs. Luigi" screen 245 | ; $17 = !"Mario vs. Luigi" screen 246 | ; $18 = !shortly before "Mario vs. Luigi" gameplay 247 | ; $19 = !"Mario vs. Luigi" gameplay 248 | ; $1A = !before 1B 249 | ; $1B = !before Luigi won 250 | ; $1C = !also before 1B 251 | ; $1D = !shortly before Luigi won screen 252 | ; $1E = !shortly before Luigi lost screen 253 | ; $1F = !before 16 254 | ; $20 = !Luigi won screen 255 | ; $21 = !Luigi lost screen 256 | ; $22 = !Shortly before congratulations animation 1 257 | ; $23 = !congratulations animation 1 258 | ; $24 = initial value copyright screen (very short) 259 | ; $25 = copyright screen during first countdown 260 | ; $26 = !rocket launch init 261 | ; $27 = !rocket launch 1 262 | ; $28 = !rocket launch 2 263 | ; $29 = !rocket launch 3 264 | ; $2A = !before 2B 265 | ; $2B = !before 16 266 | ; $2C = !rocket launch 6 267 | ; $2D = !rocket launch 7 268 | ; $2E = !rocket launch b1 269 | ; $2F = !rocket launch b2 270 | ; $30 = !rocket launch b3 271 | ; $31 = !rocket launch b4 272 | ; $32 = !rocket launch b5 273 | ; $33 = !rocket launch b6 274 | ; $34 = !shortly before rocket launch b 275 | ; $35 = copyright screen during second countdown 276 | 277 | 278 | rCOUNT_UP EQU $ffe2 ; Counts from $00 to $FF (once per frame) - various uses 279 | rROW_UPDATE EQU $ffe3 ; current line to move down (after removing line(s)) 280 | rDEMO_GAME EQU $ffe4 ; 0 = normal game, 2 = first demo game (type A), 1 = second demo game (type B) 281 | 282 | rUNUSED EQU $ffe9 ; set only in unused function. but tested everywhere. What a waste. 283 | rDEMO_ACTION_COUNTDOWN EQU $ffea ; counts down the frames a button press (or none) is required acc. to storyboard (gravity works anyway) 284 | rDEMO_STORYBOARD_1 EQU $ffeb ; upper address of demo storyboard 285 | rDEMO_STORYBOARD_2 EQU $ffec ; lower address of demo storyboard 286 | rDEMO_BUTTON_HIT EQU $ffed ; simulated button presses (see joypad constants above) 287 | rDEMO_ACTUAL_BUTTON EQU $ffee ; saves the actual button presses (after handling simulated ones), and then handles them (= Start btn to quit demo) 288 | 289 | rHARD_MODE EQU $fff4 ; 0 = off, 88 = on 290 | 291 | ; Variable value constants: 292 | GAME_TYPE_A EQU $37 293 | GAME_TYPE_B EQU $77 294 | 295 | MUSIC_TYPE_A EQU $1c 296 | MUSIC_TYPE_B EQU $1d 297 | MUSIC_TYPE_C EQU $1e 298 | MUSIC_TYPE_OFF EQU $1f 299 | 300 | MENU_IN_GAME EQU $00 301 | MENU_GAME_OVER_INIT EQU $01 302 | MENU_GAME_OVER EQU $04 303 | MENU_TYPE_B_WON EQU $05 304 | MENU_TITLE_INIT EQU $06 305 | MENU_TITLE EQU $07 306 | MENU_SELECT_TYPE_INIT EQU $08 307 | MENU_IN_GAME_INIT EQU $0a 308 | MENU_SCORE_B EQU $0b 309 | MENU_LOST_ANIM EQU $0d 310 | MENU_SELECT_TYPE EQU $0e 311 | MENU_SELECT_MUSIC EQU $0f 312 | MENU_LEVEL_A_INIT EQU $10 313 | MENU_LEVEL_A EQU $11 314 | MENU_LEVEL_B_INIT EQU $12 315 | MENU_LEVEL_B EQU $13 316 | MENU_HIGH_B EQU $14 317 | MENU_HISCORE EQU $15 318 | MENU_COPYRIGHT_INIT EQU $24 319 | MENU_COPYRIGHT_1 EQU $25 320 | MENU_COPYRIGHT_2 EQU $35 321 | MENU_ROCKET_1_INIT EQU $26 322 | MENU_ROCKET_1A EQU $27 323 | MENU_ROCKET_1B EQU $28 324 | MENU_ROCKET_1C EQU $29 325 | MENU_ROCKET_1D EQU $02 326 | MENU_ROCKET_1E EQU $03 327 | MENU_ROCKET_1F EQU $2C 328 | MENU_ROCKET_1G EQU $2D 329 | MENU_ROCKET_2_INIT EQU $34 330 | MENU_ROCKET_2A EQU $2E 331 | MENU_ROCKET_2B EQU $2F 332 | MENU_ROCKET_2C EQU $30 333 | MENU_ROCKET_2D EQU $31 334 | MENU_ROCKET_2E EQU $32 335 | MENU_ROCKET_2F EQU $33 336 | MENU_CELEBRATE EQU $22 337 | MENU_VS_INIT EQU $16 338 | MENU_VS_MODE EQU $17 339 | MENU_VS_GAME_INIT EQU $18 340 | MENU_VS_GAME EQU $19 341 | MENU_LUIGI_WON_INIT EQU $1d 342 | MENU_LUIGI_LOST_INIT EQU $1e 343 | MENU_LUIGI_WON EQU $20 344 | MENU_LUIGI_LOST EQU $21 345 | 346 | 347 | -------------------------------------------------------------------------------- /palettes.asm: -------------------------------------------------------------------------------- 1 | PALETTE_1 EQU %11100100 ;00 = white, 01 = light grey, 10 = dark grey, 11 = black (read RTL) 2 | PALETTE_2 EQU %11000100 ;white, light grey, white, black 3 | --------------------------------------------------------------------------------