(original version 4-13-2013, updated 4-22-2013)
Clay Cowgill, April 13th, 2013
The patch files to build your own set of DKP ROMs are HERE. (rev 5, 4-22-2013)
Mike Mika created the "Donkey Kong Pauline Edition" for
the original Nintendo Entertainment System so that his three year old daughter
could play the game as Pauline instead of Mario. This was just too novel to pass
up, so a version to run on the original Donkey Kong arcade machine just
needed to be created.
The main problem to overcome: an arcade Donkey Kong machine is virtually nothing like an NES. They use entirely different processors and have different methods of implementing graphics, so the task would not be as simple as replacing some graphics and calling it good.
Starting with the "Pauline" version of the NES the first step was to get a look at the graphics. The NES uses moveable objects ("sprites") that are 8x8 pixel squares. Using a ROM hacking tool called "YY-CHR" the memory of the NES 'cartridge' was examined. While the graphics were visible, it was pretty hard to tell what was what.
Using the NES Emulator NESTen, the NES game was played and NESTen's 'palette console' was used to see the correct colors in action. Pauline's palette was #4 and Mario's was #5. Using the values from the palette console a correct color map was built to make the graphics easier to interpret.
Another ROM tool named "TilEd 2002" was used to explore the Pauline graphics to determine how they are arranged in the NES cartridge memory. A bit of trial and error revealed that a single 16x16 Pauline sprite is composited from four sequential 8x8 tiles arranged as:
With the layout in hand, a quick trip back to "YY-CHR" with the correct palette allowed small bitmaps of the cartridge memory to be saved to hard disk. These images were then loaded in to Photoshop and the individual tiles were extracted and assembled in to 16x16 sprite images necessary for the arcade game version.
It was time to pay attention to the arcade game graphics. "Turaco" is an old DOS program used to modify arcade game graphics. After getting Turaco working again on a modern OS (thanks to DOSBox!) the original Donkey Kong graphics were examined.
The original Donkey Kong hardware used images that were mirror images compared to the NES, so the Pauline sprites were all flipped in Photoshop and saved as .PCX files. Using Turaco's PCX import capability each Pauline sprite was individually imported and hand-matched to the corresponding Donkey Kong Arcade sprite.
The arcade version has some additional sprites that are
not present in the NES conversion, so those 'missing' graphics were hand drawn
in Turaco and saved as a modified set of 'ROMs' for the arcade game.
With the graphics converted, the Multi Arcade Machine Emulator (MAME) was used to check progress. The graphic shapes looked correct, but the colors were not. The arcade game system of color palettes is different from the NES, so more in depth investigation of the game code would be required.
Using a 'debug' version of MAME, a disassembly (a conversion process that takes the binary 'machine' language of the original game and converts it to human readable text) of Donkey Kong was created for reference. (At this point, this discussion will by necessity become fairly technical!)
The MAME debugger was used to run the original Donkey Kong code and using the basic memory map of the machine (from the MAME source code) the code operation was observed. Using a combination of memory display windows and debugger watchpoints (which stop the program when a particular byte in memory is changed) the memory locations used for the sprite colors of various characters and portions of the screen were determined.
For example, the player's character shape, color, and position are stored in four bytes of memory located starting at address 0x694C (sixteen bit hexadecimal notation).
0x694C = horizontal position of player
0x694D = sprite shape of player
0x694E = sprite 'attribute' of player (which colors to draw it in)
0x694F = vertical position of player
Armed with knowing where the program had to change those values and by using MAME's watchpoints along with the text disassembly and a knowledge of the Z80 CPU used by the game, it was quickly determined that a routine at 0x0054 was copying the 'Mario' shape to the screen from a table of values at address 0x388C. one of those values was setting the player to use the Mario color scheme-- changing one byte in the table pointed the colors to Paulines color set. One problem down!
In the arcade game, Kong's 'hostage' at the top of the screen is two 16x16 sprites tall vs. the single 16x16 character in the NES version. Through some clever positioning of two sprites the 'Mario' shape replaced Pauline, but again the colors were incorrect. Another round of debug with breakpoints (which stop the program when a particular instruction in memory is executed) and watchpoints found that code at 0x0B24 was placing the hostage at the top of the screen using a table at 0x3884 in memory. Patching a few more bytes in memory fixed the color scheme to allow "Mario" colors up top.
At this point a new problem was observed-- the player 'lives' were shown on screen were little Mario shapes! That simply won't do for Pauline, so further investigation was in order. This turned out to be a difficult problem to address because unlike the NES, the arcade game was "hard wired" to show certain colors on that portion of the screen-- it was not possible to make 'Pauline' colors appear there. A simple compromise was made by replacing the tiny 'mario' shape with a heart to signify a player life. Excellent!
With all these changes the game was actually looking and playing pretty nice. In Mike's original version the 'gifts' that Mario collected (parasol, purse, hat) remained the same... But if those are now to be gifts for Mario, shouldn't they be something a plumber could use? The 'gift' graphics were easily changed to new shapes; a pipe wrench, crescent wrench, and toilet plunger.
The colors of the gifts were still set to the whites and pinks of Pauline's presents. Luigi would probably make fun of Mario for using a pink wrench, so more time with the debugger and disassembler unearthed a table at 0x3E54 which was copied to sprite memory through DMA (Direct Memory Access) that included the gift shapes and colors. Three more changes were made to set Mario's new gifts to more appropriate color schemes.
Further play testing revealed that the colors would revert to their pink/white combinations on the 'springs' stage of the game. So more debugging dug up another table at 0x3E48 which was similarly patched to the earlier on making the colors more "suitable".
One last, itty bitty problem remained. The 'hostage' at the top of the screen was built such that the bottom of the two sprites would be Pauline's kicking legs when she yells for "Help!". In order to accommodate that same effect with the shorter Mario sprite the sprite graphics were positioned so that the 'hat' of Mario was the top sprite and the rest of Mario's body was the bottom one. For things to look good we show Mario on profile (handsome, as he is) facing right with a new sprite different from the NES version. The problem, however, is that at the end of the 'rivets/girders' levels it's possible for Pauline to have completed the level on the left side of the screen. With the original 'hostage' graphics for Pauline this was not a problem as the top sprite was Pauline's head and torso and the game would 'flip' the top sprite right for left to face the rescuer.
With our modified version however, Mario's head and body are on the bottom sprite and only his hat is on the top one. If Pauline finished the level on the left side of the screen, this resulted in Mario's hat turning around backwards while he faced away from Pauline. Amusing, but wrong.
This problem couldn't be changed with a single byte or two here and there-- a code patch would be required. Finding where the decision to turn the hostage to face the rescuer was tricky. Since the same memory locations are re-written 60 times a second watchpoints and breakpoints are almost useless. Thankfully, MAME's debugger also include a trace function where the flow of execution of the program can be written to disk in text form for examination. By using this logging capability just as the last rivet was removed, a full capture of all the program behavior was made. With a combination of text searches and experimental memory modifications in the debugger a small routine was found at 0x180f that handled the "flip" of the bottom sprite in the hostage.
Thankfully there was a small chunk of unused memory available in the ROM at address 0x3F30. In order to take control of the program at that point a 'jump' instruction was placed in memory at 0x180F directing the program to continue excution at 0x3F30 instead. The following routine was then created:
ld hl,$6901 ; which direction is the top half sprite facing?
ld a,(hl) ; got the 'top' sprite value including horizontal flip bit (top bit)
inc a ; our "end of level" sprite is three sprites farther in memory than the
inc a ; shape of the 'top' sprite, so we add three to the value we find in
inc a ; the top sprite and then...
ld hl,$6905 ; ...point back to the 'bottom' sprite
ld (hl),a ; write it back out with proper orientation
jp $1814 ; Jump back to the original routine
In the arcade game hardware, the top most bit of the sprite shape says if the sprite is drawn facing right or facing left. Since the program already 'turns' the top of the hostage to face the player, our little shim simply takes that value (located at 0x6901) and changes the bottom sprite (located at 0x6905) to the correct shape while also maintaining the "direction" that the entire shape needs to be facing.
With that, we call the hack done. Donkey Kong Pauline Edition for the original arcade game! All in all it was about an evening's worth of work (I spent longer writing this webpage up than the time on the hack itself!)
... UPDATE 1 ...
OK, seldom does "done" actually mean done for my projects. Since this is way more interesting that finishing our taxes, I decided to mess about some more.
There's a lot of unused space in the Donkey Kong graphics ROMs. That got me thinking-- why not have some more prizes for Pauline to pick up? (What guy doesn' t need more tools?)
A little more time in Photoshop and I had a few more sprites I like:
I located them in memory at tile numbers 0x6B-6D and modified the appropriate color palette values discovered earlier. Playtesting up to the girders/rivets level revealed an unexpected problem-- I couldn't pick up the new prizes!
Back once more in to the debugger, I watched what happened when the player picks up a prize 'normally'. The game appears to just change the horizontal position of the object to zero (moving it off screen) when it's picked up. That made for a handy way to trigger a watchpoint to see when that actually happened-- "wp 6a10,1,w,wpdata==0" only halts execution when a 'zero' it written to the horizontal position of the first prize. Using that result in conjunction with a 'trace' right before and during a prize 'pickup' lead me to code at 0x19DA:
19DA: 3A 03 62 ld a,($6203) ; player X location
19DD: 06 03 ld b,$03 ; number of prizes (second stage anyway?)
19DF: 21 0C 6A ld hl,$6A0C ; start of prize sprite attributes (x position)
19E2: BE cp (hl) ; compare prize position with player
19E3: CA ED 19 jp z,$19ED ; they're equal-- hit!
19E6: 2C inc l ; increment to next prize in sprite attribute memory
19E7: 2C inc l
19E8: 2C inc l
19E9: 2C inc l
19EA: 10 F6 djnz $19E2 ; loop for 'b' prizes
19EC: C9 ret
This is basically the first part of checking if a prize has been picked up. What the code is doing is looking at the player's horizontal position and comparing it to the prize's position. What's interesting here is that it's only looking for an exact match-- basically your player has to cross the left edge of the prize to pick it up. That's why it's possible to overlap most of a prize without picking it up sometimes. Huh.
Looking a little farther we find:
19ED: 3A 05 62 ld a,($6205) ; player is over a prize
19F0: 2C inc l ; increment up to 'y' position
19F1: 2C inc l
19F2: 2C inc l
19F3: BE cp (hl) ; if that's not equal, no hit?
19F4: C0 ret nz ; return if no hit...
19F5: 2D dec l ; but it *is* a hit here, so back up to sprite shape index
19F6: 2D dec l
19F7: CB 5E bit 3,(hl) ; Ah-hah! Only sprites with bit three cleared can be picked up!
19F9: C0 ret nz
This is the second part of a prize pick-up check. If the code is executing here it's already decided that the player's horizontal position indicates it's the same as a prize. The next check is to look at the vertical positions and compare them-- if they don't match the code exits the test (ret nz), but if they're the same it does one final check-- bit 3,(hl).
The interesting part about the last test is that had I simply located the new graphics in a slightly different position it could have worked with no more effort. Essentially, in order for an item to be a 'prize' and be picked up, the 4th bit ("bit 3" counting up from "bit 0") has to be a zero. By chance I had put my prize graphics at locations 0x6B-6D. All those locations have the third bit set, so the code would exit without picking it up!
The fix then was trivial-- simply place the new sprite tiles at 0x62-0x64 instead. With that, problem solved and the prize variety goes up!
... UPDATE 2 ...
Ok, with 2012's taxes safely filed I can't help but think that there's still something... missing. The title screen! Nothing really sets it apart from a regular DK machine now, so time to start poking around again.
The MAME driver for Donkey Kong says that the screen memory for the game is at 0x7400. Sticking value in to the that area with the debugger's memory window reveals that it indeed does change the background graphics, so using that we can visually determine through a bit of trial and error where various things that appear on screen go in memory.
Using a watchpoint to break on the '(c)' character on the title screen leads us to some code at 0x05E9 which appears to be handling printing strings of characters to the screen. (Breakpoints set there result in one line of text being printed for each break. The routine ends up being pretty simple-- a 'string number' is passed in with the 'A' register which ends up essentially being a handle to a final address that stores what should be printed and where it should go. In particular, the "(c) 1980" message is located at 0x3F00 and printed to the screen at address 0x765C.
To make things simple we can just 'borrow' that string ID number (0x1E) and use it for our own tagline. "Pauline Edition" seems to be the most common reference (and it's nice and symetrical), so we'll use that.
The system doesn't use ASCII for characters, instead the character table simple starts with 0=0x00, 1=0x01, A=0x10, B=0x11, etc. so to make our string we construct the following:
F5 76 20 11 25 1C 19 1E 15 10 10 15 14 19 24 19 1F 1E 3F 2E CD A6 3F
Or, in plain english-- place "PAULINE EDITION" at address 0x76F5 in memory and terminate the string with 0x3F. We patch up the string pointer table to our new (longer) string stashed off in some unused memory at the end of the ROM and we're in business.
We probably shouldn't flat-out remove Nintendo's copyright message though, so instead we'll combine it on the bottom line (which normally says "NINTENDO OF AMERICA INC.").
This time we'll just overwrite the existing data and use the same address for the string, so the hack is even simpler-- just change the text values. Another couple minutes in HexWorkshop and the deed is done-- a quick playtest reveals... The game crashes!
Immediately this sets off the "copy protection" alarms in my brain. To test this theory I put the ROM back to the original data and then started modifying one byte at a time and looking for the game to crash (it would hang a few seconds in to the first level). Changing the "N" in Nintendo to a space didn't cause any problem, but as soon as I change the "I" the game would crash. This would have been a bit dicey to figure out in the 1980's, but MAME makes it trivial. Since the hang would occur during the game attract mode as well as during game play, I simply used the MAME debugger's trace capability to log to disk every instruction executed on a "good" ROM then changed the ROM by wiping out the "I" in Nintendo and made another trace with that version.
WinMerge was then used to compare the two text files:
Well there's your problem, right there. Notice that both files are identical until "something happens", then they're very different. Looking at the disassembly we notice this routine at 0x2441:
2441: 21 0C 3F ld hl,$3F0C ;
address of the "I" in "NINTENDO" string
2444: 3E 5E ld a,$5E ; start with this value
2446: 06 06 ld b,$06 ; sum the next six bytes
2448: 86 add a,(hl) ; together in to 'A'
2449: 23 inc hl
244A: 10 FC djnz $2448 ; (loop until six bytes are done)
244C: FD 21 10 63 ld iy,$6310 ; load a 'magic' value in IY
2450: A7 and a ; set Z80 flags
2451: CA 56 24 jp z,$2456 ; unless the checksum is equal to zero...
2454: FD 23 inc iy ; cry havoc and let slip the dogs of war!
In plain English, the game is taking the values of the letters "INTEND" and adding them to the value 0x5E. If the final sum isn't 0x00, it adds one to the value in IY, which apparently causes things to go pear-shaped later on...
This is pretty clever back in the day because although the check is performed at the beginning of the level, the game doesn't actually crash until several seconds later. Since "really good" logic analyzers back in the 1980's were only able to capture maybe a few milliseconds of program execution (unlike MAME which is limited only by the size of your hard drive) this would have probably been pretty annoying to find and fix because by the time the game crashes, the actual check that would end up making it crash had happened long ago. (It's worth noting though, that Donkey Kong was still widely cloned/pirated/copied even back in the 80's!)
We could just 'neuter' this copy protection check by placing 'nop' (do nothing) instructions at address 0x2454-55, but that would result in a slight change to the program timing which would be better to avoid if possible. Instead, it's easier to just change the value at 0x2445 (the 0x5E) to something that when summed with our string equals 0x00. That value happens to be 0x4B, so with that one byte changed we test again-- success! No more crash and a title screen to boot!
... UPDATE 3 ...
Did you know that the arcade Donkey Kong has the pies/conveyor level? Well, I didn't. I thought it was added in the NES cart version. *sigh* That just goes to show you how good of a DK player I am...
Thankfully, the tables used are the same as the earlier levels. By examining sprite memory at the beginning of the level and searching for that data in the ROM files with HexWorkshop we find the values at 0x3E3C (0x0E3c in ROM "c_5at_g.bin", to be exact). A few more bytes patched up and we're done. 'Conveyor' level all spruced up!
Done! For now at least...
P.S. MAME guys-- 0x6900 is not "sprites"; it's just
used as a RAM shadow for the real sprite object attribute memory area residing
at 0x7000. Parts of the 0x6900 region are DMA'd over to the 0x7000 range
in various transactions as desired. The driver source still describes it
incorrectly, although it does *work* right.