annotate org/total-control.org @ 620:1b52b14868d3 tip

merge.
author rlm <rlm@aurellem.org>
date Sun, 07 Feb 2016 23:16:04 -0800
parents 90575d3a64d1 a79e5a852347
children
rev   line source
rlm@608 1 #+title: Pokemon Yellow Total Control Hack
rlm@608 2 #+author: Robert McIntyre
rlm@608 3 #+email: rlm@mit.edu
rlm@608 4 #+description: Taking over Pokemon Yellow from the inside.
rlm@608 5 #+keywords: pokemon, pokemon yellow, rom, gameboy, assembly, hex, pointers, clojure
rlm@608 6 #+SETUPFILE: ../../aurellem/org/setup.org
rlm@608 7 #+INCLUDE: ../../aurellem/org/level-0.org
rlm@608 8 #+BABEL: :exports both :noweb yes :cache no :mkdirp yes
rlm@608 9 #+OPTIONS: num:2
rlm@608 10
rlm@608 11
rlm@609 12 Full Source : http://hg.bortreb.com/vba-clojure
rlm@609 13
rlm@619 14
rlm@619 15 #+BEGIN_HTML html
rlm@619 16 <div class="figure">
rlm@619 17 <p>
rlm@619 18 <iframe width="420" height="315"
rlm@619 19 src="https://www.youtube.com/embed/p5T81yHkHtI"
rlm@619 20 frameborder="0" allowfullscreen></iframe>
rlm@619 21 <p>
rlm@619 22 #+END_HTML
rlm@609 23 Youtube Video w/ Visual Keypresses: http://www.youtube.com/watch?v=p5T81yHkHtI
rlm@619 24 #+BEGIN_HTML
rlm@619 25 </div>
rlm@619 26 #+END_HTML
rlm@609 27
rlm@609 28 Special Thanks to:
rlm@609 29
rlm@609 30 - http://tasvideos.org/2913S.html for the save corruption hack which
rlm@609 31 is used at the start of this run.
rlm@609 32 - http://www.everyponysings.com/ for providing the midi file I used
rlm@609 33 to create the song at the end.
rlm@609 34 - http://www.zophar.net/ for the terminal font.
rlm@609 35
rlm@609 36
rlm@609 37 * Introduction
rlm@609 38
rlm@609 39 Think of pokemon yellow as creating a little universe with certain
rlm@609 40 rules. Inside that universe, you can buy items, defeat rival trainers,
rlm@609 41 and raise your pokemon. But within that universe, you are bound by the
rlm@609 42 rules of pokemon. You can't build new buildings, or change the music,
rlm@609 43 or change your clothes.. There are some games (like chess), where it
rlm@609 44 is not possible to alter the rules of the game from within the
rlm@609 45 game. No matter what moves you make in chess, you can never change the
rlm@609 46 rules of the game so that it becomes checkers or basketball. The point
rlm@609 47 of this run is to show that you CAN change the rules in pokemon
rlm@612 48 yellow. There is a certain sequence of valid actions (like walking
rlm@612 49 from one place to another or buying items) that will allow you to
rlm@612 50 transform pokemon yellow into Pacman, or Tetris, or Pong, or a MIDI
rlm@612 51 player, or anything else you can imagine.
rlm@609 52
rlm@609 53 * Background
rlm@609 54
rlm@609 55 [[http://tasvideos.org/2913S.html][This speedrun]] by Felipe Lopes de Freitas (p4wn3r), beats pokemon
rlm@609 56 yellow in only 1 minute and 36 seconds. It does it by corrupting the
rlm@609 57 in-game item list so that he can advance the list past its normal
rlm@609 58 limit of 20 items. The memory immediately after the item list includes
rlm@609 59 the warp points for the current map, and by treating that data as
rlm@609 60 items and switching and dropping them, he can make the door from his
rlm@609 61 house take him directly to the end of the game.
rlm@609 62
rlm@609 63 When I first saw that speedrun, I was amazed at how fast pokemon
rlm@609 64 yellow could be beaten, and that it was possible to manipulate the
rlm@611 65 game from the inside, using only the item list. I wondered how far I
rlm@609 66 could extend the techniques found in p4wn3r's run.
rlm@609 67
rlm@609 68 The gameboy is an 8 bit computer. That means that ultimately, anything
rlm@609 69 that happens in pokemon is a result of the gameboy's CPU reading a
rlm@609 70 stream of 8 bit numbers and doing whatever those numbers mean. For
rlm@609 71 example, in the gameboy, the numbers:
rlm@609 72
rlm@609 73 [62 16 37 224 47 240 37 230 15 55]
rlm@609 74
rlm@609 75 mean to check which buttons are currently pressed and copy that result
rlm@609 76 into the "A" register. With enough numbers, you can spell out an
rlm@609 77 interactive program that reads input from the buttons and allows you
rlm@609 78 to write any program you want to the gameboy. Once you have assembled
rlm@609 79 such a program and forced the game to run it, you have won, since you
rlm@611 80 can use that program to write any other program (like Tetris or
rlm@611 81 Pacman) over pokemon yellow's code. I call a program that allows you
rlm@609 82 to write any other program a "bootstrapping program". So, the goal is
rlm@609 83 to somehow get a bootstrapping program into pokemon yellow and then
rlm@609 84 force yellow to run that program instead of its own.
rlm@609 85
rlm@609 86 How can we spell out such a program? Everything in the game is
rlm@611 87 ultimately numbers, including all items, pokemon, levels, etc. In
rlm@609 88 particular, the item list looks like:
rlm@609 89
rlm@610 90 #+begin_example
rlm@609 91 item-one-id (0-255)
rlm@609 92 item-one-quantity (0-255)
rlm@609 93 item-two-id (0-255)
rlm@609 94 item-two-quantity (0-255)
rlm@609 95 .
rlm@609 96 .
rlm@609 97 .
rlm@610 98 #+end_example
rlm@609 99
rlm@609 100 Let's consider the button measuring program [37 62 16 37 224 37 240
rlm@609 101 37 230 15 55] from before. Interpreted as items and item quantities, it is
rlm@609 102
rlm@610 103 #+begin_example
rlm@609 104 lemonade x16
rlm@609 105 guard spec. x224
rlm@609 106 leaf stone x240
rlm@609 107 guard spec. x230
rlm@609 108 parlyz heal x55
rlm@610 109 #+end_example
rlm@609 110
rlm@609 111 So, if we can get the right items in the right quantities, we can
rlm@609 112 spell out a bootstrapping program. Likewise, when writing the
rlm@609 113 bootstrapping program, we must be careful to only use numbers that are
rlm@609 114 also valid items and quantities. This is hard because there aren't
rlm@609 115 many different items to work with, and many machine instructions
rlm@609 116 actually take 2 or even 3 numbers in a row, which severely restricts
rlm@609 117 the types of items you can use. I ended up needing about 92 numbers to
rlm@609 118 implement a bootstrap program. Half of those numbers were elaborate
rlm@609 119 ways of doing nothing and were just there so that the entire program
rlm@609 120 was also a valid item list.
rlm@609 121
rlm@609 122 The final part of the hack is getting pokemon yellow to execute the
rlm@609 123 new program after it has been assembled with items. Fortunately,
rlm@609 124 pokemon keeps a number called a function pointer within easy reach of
rlm@609 125 the corrupted item list. This function pointer is the starting point
rlm@609 126 (address) of a program which the game runs every so often to check for
rlm@611 127 poison and do general maintenance. By shifting an item over this
rlm@609 128 function pointer, I can rewrite that address to point to the
rlm@609 129 bootstrapping program, and make the game execute it. Without this
rlm@609 130 function pointer, it would not be possible to take over the game.
rlm@609 131
rlm@609 132 * The Run
rlm@609 133
rlm@611 134 I start off and name my rival Lp/k. These characters will eventually be
rlm@609 135 treated as items and shifted over the function pointer, causing it to
rlm@609 136 execute the bootstrapping program that will soon be constructed. I
rlm@609 137 start the run the same as p4wn3r's and restart the game while saving,
rlm@609 138 so that the pokemon list is corrupted. By switching the 8th and 10th
rlm@609 139 pokemon, I corrupt the item list and can now scroll down past the 20th
rlm@609 140 item. I shift items around to increase the text speed to maximum and
rlm@609 141 rewrite the warp point of my house to Celadon Dept. Store. (p4wn3r
rlm@609 142 used this to go directly to the hall of fame and win the game in his
rlm@609 143 run.) I deposit many 0x00 glitch items into the PC from my corrupted
rlm@611 144 inventory for later use. Then, I withdraw the potion from the
rlm@609 145 PC. This repairs my item list by overflowing the item counter from
rlm@609 146 0xFF back to 0x00, though the potion is obliterated in the process. I
rlm@609 147 then take 255 glitch items with ID 0x00 from the computer into my
rlm@609 148 personal items.
rlm@609 149
rlm@609 150 Leaving my house takes me directly to Celadon Dept. store, where I
rlm@609 151 sell two 0x00 items for 414925 each, giving myself essentially max
rlm@609 152 money. I hit every floor of the department store, gathering the
rlm@609 153 following items:
rlm@609 154
rlm@609 155 #+begin_example
rlm@609 156 +-------------------+----------+
rlm@609 157 |##| Item | Quantity |
rlm@609 158 +--+----------------+----------+
rlm@609 159 |1 | TM02 | 98 |
rlm@609 160 |2 | TM37 | 71 |
rlm@609 161 |3 | TM05 | 1 |
rlm@609 162 |4 | TM09 | 1 |
rlm@609 163 |5 | burn-heal | 12 |
rlm@609 164 |6 | ice-heal | 55 |
rlm@609 165 |7 | parlyz-heal | 99 |
rlm@609 166 |8 | parlyz-heal | 55 |
rlm@609 167 |9 | TM18 | 1 |
rlm@609 168 |10| fire-stone | 23 |
rlm@609 169 |11| water-stone | 29 |
rlm@609 170 |12| x-accuracy | 58 |
rlm@609 171 |13| guard-spec | 99 |
rlm@609 172 |14| guard-spec | 24 |
rlm@609 173 |15| lemonade | 16 |
rlm@609 174 |16| TM13 | 1 |
rlm@609 175 +--+----------------+----------+
rlm@609 176 #+end_example
rlm@609 177
rlm@609 178 After gathering these items, I deposit them in the appropriate order
rlm@609 179 into the item PC to spell out my bootstrapping program. Writing a full
rlm@609 180 bootstrap program in one go using only items turned out to be too
rlm@609 181 hard, so I split the process up into three parts. The program that I
rlm@609 182 actually construct using items is very limited. It reads only from the
rlm@614 183 A, B, start, and select buttons, and writes 4 bits each frame starting
rlm@614 184 at a fixed point in memory. After it writes 200 or so bytes, it jumps
rlm@609 185 directly to what it just wrote. In my run, I use this program to write
rlm@612 186 another bootstrapping program that can write any number of bytes to
rlm@609 187 any location in memory, and then jump to any location in memory. This
rlm@609 188 new program also can write 8 bits per frame by using all the
rlm@609 189 buttons. Using this new bootstrap program, I write a final
rlm@611 190 bootstrapping program that does everything the previous bootstrapping
rlm@609 191 program does except it also displays the bytes it is writing to memory
rlm@609 192 on the screen.
rlm@609 193
rlm@611 194 After completing this bootstrapping program, I go to the Celadon
rlm@609 195 mansion, because I find the metaness of that building to be
rlm@609 196 sufficiently high to serve as an exit point for the pokemon
rlm@609 197 universe. I corrupt my item list again by switching corrupted pokemon,
rlm@611 198 scroll down to my rival's name and discard until it is equal to the
rlm@609 199 address of my bootstrapping program, and then swap it with the
rlm@611 200 function pointer. Once the menu is closed, the bootstrapping program
rlm@609 201 takes over, and I write the payload....
rlm@609 202
rlm@609 203 * Infrastructure
rlm@609 204
rlm@609 205 The entire video was completely produced by bots --- I didn't manually
rlm@609 206 play the game at all to produce this speedrun. Here is a brief account
rlm@618 207 of the infrastructure I built to make the video. The entire source of
rlm@609 208 the project is available at http://hg.bortreb.com/vba-clojure
rlm@609 209
rlm@611 210 The first step was to build a programmatic interface to pokemon
rlm@609 211 yellow. So, I downloaded vba-rerecording from
rlm@609 212 http://code.google.com/p/vba-rerecording/. After repairing their
rlm@609 213 broken auto-tools scripts so that it would compile on GNU/Linux, I
rlm@609 214 added a low level C interface that I could call from Java via
rlm@609 215 JNI. This C interface gives me basic control over the emulator: I can
rlm@609 216 step the emulator either one clock cycle or one frame, and I can get
rlm@609 217 the contents of any memory location or register. The interface also
rlm@609 218 allows me to freeze the state of the emulator, save it to a Java
rlm@609 219 object, and reload that state again at any time.
rlm@609 220
rlm@609 221 I built a layer of [[http://clojure.org/][clojure]] code on top of the JNI bindings to get an
rlm@609 222 entirely functional interface to vba-rerecording. This interface
rlm@609 223 treats state of the emulator as an immutable object, and allows me to
rlm@609 224 do everything I could do with the lower level C interface in a
rlm@609 225 functional manner. Using this functional code, I wrote search programs
rlm@609 226 that take a particular game-state and try out different combinations
rlm@611 227 of button presses to get any desired effect. By combining different
rlm@609 228 styles of search with different initial conditions, I created high
rlm@609 229 level functions that could each accomplish a certain general task,
rlm@609 230 like walking and buying items. For example, here is some actual code:
rlm@609 231
rlm@609 232 #+begin_src clojure
rlm@609 233 (defn-memo viridian-store->oaks-lab
rlm@609 234 ([] (viridian-store->oaks-lab
rlm@609 235 (get-oaks-parcel)))
rlm@609 236 ([script]
rlm@609 237 (->> script
rlm@609 238 (walk [↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
rlm@609 239 ← ← ← ← ← ← ← ← ←
rlm@609 240 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
rlm@609 241 ← ←
rlm@609 242 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
rlm@609 243 ↓ ↓ ↓ ↓ ↓ ↓ ↓
rlm@609 244 → → → → → → → →
rlm@609 245 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
rlm@609 246 ← ← ← ← ←
rlm@609 247 ↓ ↓ ↓ ↓
rlm@609 248 ])
rlm@609 249 (walk-thru-grass
rlm@609 250 [↓ ↓ ↓ ↓ ↓ ↓ ↓])
rlm@609 251 (walk [↓ ↓ ← ↓ ↓ ↓ ←
rlm@609 252 ↓ ↓ ↓ ↓ ↓ ↓
rlm@609 253 → → → ↑])
rlm@609 254
rlm@609 255 (do-nothing 1))))
rlm@609 256 #+end_src
rlm@609 257
rlm@609 258 This script walks from the Viridian City pokemon store to Oak's
rlm@609 259 Lab in the most efficient way possible. The walk-thru-grass function
rlm@611 260 guarantees that no wild battles will happen by manipulating the game's
rlm@609 261 random number generator.
rlm@609 262
rlm@609 263 #+begin_src clojure
rlm@609 264 (defn-memo hacking-10
rlm@609 265 ([] (hacking-10 (hacking-9)))
rlm@609 266 ([script]
rlm@609 267 (->> script
rlm@609 268 begin-deposit
rlm@609 269 (deposit-held-item 17 230)
rlm@609 270 (deposit-held-item-named :parlyz-heal 55)
rlm@609 271 (deposit-held-item 14 178)
rlm@609 272 (deposit-held-item-named :water-stone 29)
rlm@609 273 (deposit-held-item 14 32)
rlm@609 274 (deposit-held-item-named :TM18 1)
rlm@609 275 (deposit-held-item 13 1)
rlm@609 276 (deposit-held-item 13 191)
rlm@609 277 (deposit-held-item-named :TM02 98)
rlm@609 278 (deposit-held-item-named :TM09 1)
rlm@609 279 close-menu)))
rlm@609 280 #+end_src
rlm@609 281
rlm@609 282 This script calculates the fastest sequence of key presses to deposit
rlm@611 283 the requested items into a PC, assuming that the character starts out
rlm@609 284 in front of a computer.
rlm@609 285
rlm@611 286 I also wrote functions that could grovel through the game's memory and
rlm@611 287 present the internal data structures in usable ways. For example, the
rlm@609 288 function =print-inventory= returns the current inventory in a human
rlm@609 289 readable format.
rlm@609 290
rlm@612 291 #+begin_src clojure :results output :exports both
rlm@609 292 (com.aurellem.gb.items/print-inventory)
rlm@609 293 #+end_src
rlm@609 294
rlm@609 295 #+results:
rlm@609 296 #+begin_example
rlm@609 297 +-------------------+----------+
rlm@609 298 |##| Item | Quantity |
rlm@609 299 +--+----------------+----------+
rlm@609 300 |0 | poke-ball | 14 |
rlm@609 301 |1 | TM28 | 1 |
rlm@609 302 |2 | TM11 | 1 |
rlm@609 303 |3 | TM45 | 1 |
rlm@609 304 |4 | nugget | 1 |
rlm@609 305 |5 | s.s.ticket | 1 |
rlm@609 306 |6 | helix-fossil | 1 |
rlm@609 307 |7 | moon-stone | 1 |
rlm@609 308 +--+----------------+----------+
rlm@609 309
rlm@609 310 #+end_example
rlm@609 311
rlm@609 312
rlm@609 313 Armed with these functions, I constructed a bootstrapping program that
rlm@611 314 could be expressed as items. This is particularly hard, since many
rlm@609 315 useful opcodes do not correspond any item, and the item quantities
rlm@609 316 must all be less than 99.
rlm@609 317
rlm@609 318 Here is the first bootstrapping program in all its glory.
rlm@609 319
rlm@609 320 #+begin_src clojure
rlm@609 321 (defn pc-item-writer-program
rlm@609 322 []
rlm@609 323 (let [;;limit 75
rlm@609 324 limit 201 ;; (item-hack 201 is the smallest I could make this.)
rlm@609 325 [target-high target-low] (disect-bytes-2 pokemon-list-start)]
rlm@609 326 (flatten
rlm@609 327 [[0x00 ;; (item-hack) no-op (can't buy repel (1E) at celadon)
rlm@609 328 0x1E ;; load limit into E
rlm@609 329 limit
rlm@609 330 0x3F ;; (item-hack) set carry flag no-op
rlm@609 331
rlm@609 332 ;; load 2 into C.
rlm@609 333 0x0E ;; C == 1 means input-first nybble
rlm@609 334 0x04 ;; C == 0 means input-second nybble
rlm@609 335
rlm@609 336 0x21 ;; load target into HL
rlm@609 337 target-low
rlm@609 338 target-high
rlm@609 339 0x37 ;; (item-hack) set carry flag no-op
rlm@609 340
rlm@609 341 0x00 ;; (item-hack) no-op
rlm@609 342 0x37 ;; (item-hack) set carry flag no-op
rlm@609 343
rlm@609 344 0x00 ;; (item-hack) no-op
rlm@609 345 0xF3 ;; disable interrupts
rlm@609 346 ;; Input Section
rlm@609 347
rlm@609 348 0x3E ;; load 0x20 into A, to measure buttons
rlm@609 349 0x10
rlm@609 350
rlm@609 351 0x00 ;; (item-hack) no-op
rlm@609 352 0xE0 ;; load A into [FF00]
rlm@609 353 0x00
rlm@609 354
rlm@609 355 0xF0 ;; load 0xFF00 into A to get
rlm@609 356 0x00 ;; button presses
rlm@609 357
rlm@609 358 0xE6
rlm@609 359 0x0F ;; select bottom four bits of A
rlm@609 360 0x37 ;; (item-hack) set carry flag no-op
rlm@609 361
rlm@609 362 0x00 ;; (item-hack) no-op
rlm@609 363 0xB8 ;; see if input is different (CP A B)
rlm@609 364
rlm@609 365 0x00 ;; (item-hack) (INC SP)
rlm@609 366 0x28 ;; repeat above steps if input is not different
rlm@609 367 ;; (jump relative backwards if B != A)
rlm@609 368 0xED ;; (literal -19) (item-hack) -19 == egg bomb (TM37)
rlm@609 369
rlm@609 370 0x47 ;; load A into B
rlm@609 371
rlm@609 372 0x0D ;; dec C
rlm@609 373 0x37 ;; (item-hack) set-carry flag
rlm@609 374 ;; branch based on C:
rlm@609 375 0x20 ;; JR NZ
rlm@609 376 23 ;; skip "input second nybble" and "jump to target" below
rlm@609 377
rlm@609 378 ;; input second nybble
rlm@609 379
rlm@609 380 0x0C ;; inc C
rlm@609 381 0x0C ;; inc C
rlm@609 382
rlm@609 383 0x00 ;; (item-hack) no-op
rlm@609 384 0xE6 ;; select bottom bits
rlm@609 385 0x0F
rlm@609 386 0x37 ;; (item-hack) set-carry flag no-op
rlm@609 387
rlm@609 388 0x00 ;; (item-hack) no-op
rlm@609 389 0xB2 ;; (OR A D) -> A
rlm@609 390
rlm@609 391 0x22 ;; (do (A -> (HL)) (INC HL))
rlm@609 392
rlm@609 393 0x1D ;; (DEC E)
rlm@609 394
rlm@609 395 0x00 ;; (item-hack)
rlm@609 396 0x20 ;; jump back to input section if not done
rlm@609 397 0xDA ;; literal -36 == TM 18 (counter)
rlm@609 398 0x01 ;; (item-hack) set BC to literal (no-op)
rlm@609 399
rlm@609 400 ;; jump to target
rlm@609 401 0x00 ;; (item-hack) these two bytes can be anything.
rlm@609 402 0x01
rlm@609 403
rlm@609 404 0x00 ;; (item-hack) no-op
rlm@609 405 0xBF ;; (CP A A) ensures Z
rlm@609 406
rlm@609 407 0xCA ;; (item-hack) jump if Z
rlm@609 408 target-low
rlm@609 409 target-high
rlm@609 410 0x01 ;; (item-hack) will never be reached.
rlm@609 411
rlm@609 412 ;; input first nybble
rlm@609 413 0x00
rlm@609 414 0xCB
rlm@609 415 0x37 ;; swap nybbles on A
rlm@609 416
rlm@609 417 0x57 ;; A -> D
rlm@609 418
rlm@609 419 0x37 ;; (item-hack) set carry flag no-op
rlm@609 420 0x18 ;; relative jump backwards
rlm@609 421 0xCD ;; literal -51 == TM05; go back to input section
rlm@609 422 0x01 ;; (item-hack) will never reach this instruction
rlm@609 423
rlm@609 424 ]
rlm@609 425 (repeat 8 [0x00 0x01]);; these can be anything
rlm@609 426
rlm@609 427 [;; jump to actual program
rlm@609 428 0x00
rlm@609 429 0x37 ;; (item-hack) set carry flag no-op
rlm@609 430
rlm@609 431 0x2E ;; 0x3A -> L
rlm@609 432 0x3A
rlm@609 433
rlm@609 434
rlm@609 435 0x00 ;; (item-hack) no-op
rlm@609 436 0x26 ;; 0xD5 -> L
rlm@609 437 0xD5
rlm@609 438 0x01 ;; (item-hack) set-carry BC
rlm@609 439
rlm@609 440 0x00 ;; (item-hack) these can be anything
rlm@609 441 0x01
rlm@609 442
rlm@609 443 0x00
rlm@609 444 0xE9 ;; jump to (HL)
rlm@609 445 ]])))
rlm@609 446
rlm@609 447 #+end_src
rlm@609 448
rlm@609 449 I use the glitch items 0x00 and 0xFF to great effect in my run. 0x00
rlm@612 450 sells for almost half of maximum money --- I use just 3 of them to
rlm@611 451 finance the purchase of all the other items I need. 0x00 is also a
rlm@609 452 NO-OP in the gameboy's machine language, which means that I can stick
rlm@618 453 them anywhere where I need to break up an otherwise illegal pair of
rlm@609 454 opcodes. 0xFF is also extremely useful because it is the end-of-list
rlm@609 455 sentinel. Normally, the game will "compact" your items whenever you
rlm@609 456 make a purchase or deposit. For example, if you deposit a pokeball,
rlm@609 457 then deposit another pokeball, the item list looks like:
rlm@609 458
rlm@613 459 #+begin_example
rlm@609 460 pokeball x2
rlm@613 461 #+end_example
rlm@609 462
rlm@609 463 instead of:
rlm@609 464
rlm@613 465 #+begin_example
rlm@609 466 pokeball x1
rlm@609 467 pokeball x1
rlm@613 468 #+end_example
rlm@609 469
rlm@609 470 However, the compaction stops after the first 0xFF item, so if there
rlm@609 471 is an 0xFF item at the beginning of the list, it will "shield" all the
rlm@609 472 items below it from compaction. It the beginning of the run, I stick
rlm@609 473 an 0xFF item at the top of the PC item list, allowing me to put items
rlm@609 474 in with impunity. At the end, I toss the 0xFF away to reveal the
rlm@609 475 completed bootstrap program.
rlm@609 476
rlm@614 477 The final payload program is multiple programs. I created a reduced
rlm@614 478 form of MIDI and implemented it in gameboy machine language. Then I
rlm@614 479 translated a midi file from http://www.everyponysings.com/ into this
rlm@614 480 reduced MIDI language. The payload program contains both the music
rlm@614 481 data and the MIDI interpreter to play that data. The picture works in
rlm@614 482 a similar way. There is code to translate a png file into a form that
rlm@614 483 can be displayed on a gameboy, and other code to actually display that
rlm@614 484 image. Both the image and the display code are also written by the
rlm@614 485 final bootstrapping program. Even though my final payload is rather
rlm@614 486 simple, you can write any program at all as the payload. The source
rlm@614 487 for the sound and image displaying code is at
rlm@614 488 http://hg.bortreb.com/vba-clojure.
rlm@609 489
rlm@609 490