Monday, 30 December 2013

Neo Kong the Movie

Firstly I wanted to know how far off the mark I was with getting the tilemap rendered every frame. So I started rendering only part of the screen and it turns out it was only missing the mark by a few lines of tiles. In fact, if I had reduced the width from 32 to the visible 28, it would have scraped in. But I wanted more headroom than that; separating the rotated and non-rotated rendering routines was the obvious start. There were also a few other very simple, very obvious optimisations.

I've no easy way to profile the rendering code that I'm running, so the next best thing is to count instructions. The original, unoptimised tilemap render routine took 20,818 instructions per frame. After the above-mentioned simple optimisations, that's now down to 11,571, an almost 50% reduction. More than enough to continue with development without further ado.

After fixing one last bug - the sprite colour for an animated Mario - I've captured a small video of the Neo Geo boot-up and straight into the game-play, with Mario running back-and-forth along the bottom girder. Even the sprite priorities are correct, as you see him run behind the oil barrel.

video

And so from here-on in, I'll be adding code to allow Mario to traverse the entire girder level - including jumping of course - until he can reach Pauline waiting at the top. And although I've already encountered code specifically for the girder level, I suspect when it's all said and done, I'll be able to manoeuvre Mario around all of the 4 different levels.

Slowdown

OK, so I now at least know the cause of the slowdown - the tilemap render code that is running every VBLANK (and re-renders the entire tilemap every frame), in conjunction with the sprite render code that is running every VBLANK, in conjunction with the Donkey Kong code that is running every VBLANK - takes more than 16.7ms to run!

If I eliminate the tilemap render code, it runs at the correct speed.

The tilemap render code was always a quick 'n' dirty solution; something that would ultimately be replaced by code that directly writes to the Neo Geo 'tilemap' via macros. It was also written with absolutely no regard to speed optimisation, and one option I have in the short term is to try to speed up the code just enough to get past this issue atm. I think I will have a quick go at it (I can immediately see several ways to improve it), but if it fails without too much effort I'll just bite the bullet and implement the macros that I'm using for somewhere between 50-75% of tilemap accesses. The rest I'll have to hunt down and replace with the macros one-by-one.

Sunday, 29 December 2013

There was movement at the... errr... building site

In a nutshell, Mario runs left and right now.

The areas in the other listings that tend to be completely devoid of any analysis are the 'mechanics' of game-play, such as animations - and the animation of Mario himself is certainly no exception. Tonight I managed to decode the basic left-right animation logic and now Mario can run back-and-forth along the bottom girder, and even changes height correctly.

The sprite animation logic is - interesting - to put it mildly. For some inexplicable reason, rather than a simple look-up table, animation sequences are represented by bit pairs packed into hard-coded bytes strewn amongst the code and look-up requires loops of rotations, masks, compares and register copies. The same routine also (reportedly) handles barrel sprite animation (that have their own animation cell sequences) just to further complicate matters. Hmm...

Also, it's not noticeable during game-play but Mario actually 'slides' for 2 frames between sprite changes when moving left/right.

I also tried to fix the 'slow' speed, without luck, so everything is running about 50% atm. Once I find the reason and a fix for it, I'll upload a short video of Mario running across the screen.

Friday, 27 December 2013

Your name in lights

Still trying to find 10 minutes here and there to work on the port. Managed to get name registration done, although I had to hack the score handling for the moment due to the fact that you can't actually score any points - so ignore that aspect for now...


You can also start a 2-player game and it runs right through to the end game for both now. Still a few minor issues to sort, like player 2 shows the wrong height on the "How high can you climb" screen, and those pesky ladder tops, but I'm getting closer to the point where there's only game-play code that remains to be ported.

I suspect the next few weeks won't be conducive to spending any significant amount of time on Neo Kong. I've got a week up the coast coming up but will probably leave the laptop at home in favour of the tablet and drinking with my cousin!

On a different but perhaps related note; I scored the Mega Pack for my Neo Geo X for Xmas, and I'm pretty happy that I can now play Blue's Journey on it! That'll be going up the coast with me for when my wife is playing Scrabble on her tablet! Maybe one day I'll jailbreak it and be able to play Neo Kong on it!

Thursday, 19 December 2013

Just Silly

Despite the fact that we're fast approaching the silly season, time to spend on 'silly' pursuits seems to be getting harder to find, not easier. And so in my spare 10 minutes here and there I'm still chipping away at the port...

And despite the fact that I had intentions of finishing off the non-gameplay sections of the code, I found myself looking for the code that ticks down the bonus timer. Interestingly, the timer on the barrel/girder level is handled differently and is inter-twined with the barrel deployment timers. Eventually I quickly gave up on that as I'm not ready to dive into that area of the code, but at least now I have the bonus timer ticking down... albeit it too quickly on the 1st level.

Bonus timer displayed and ticking down

And putting off the less interesting bits yet again, I wanted to see if I could make Mario at least move without much effort. But alas, although now it detects left/right movement and updates the sprite, the code to adjust the coordinates was too convoluted with too many unknown variables to hack quickly.

At least I have a starting point for the game-play, but for now I'll return to the high score update and name registration screens. Then I'll do one final audit of the non-gameplay code and then I can start to make the game playable!

Tuesday, 17 December 2013

Wading through the boring bits

Not a lot to show for it, but I've been plugging away at lunchtime again. Mario's death spin is fully animated now, and I'm slowly working my way through the sundry routines that get called during game initialisation and/or clean-up, or from the main loop. This includes the various timers and housekeeping routines that don't affect much on the display. I've still got some scoring and bonus routines to do, and the high score name registration screen. Probably a few more days before I can get into the actual game-play.

In the process of Mario's death spin I had to implement sprite flipx (I had only implemented flipy previously). That comprised about 5 extra instructions. I had previously re-ordered the sprites, thinking there'd be gaps in the sprite memory map for unused sprites, but there's a only a few. Trouble is, Mario's death routine wipes a lot of the sprite objects en masse, so I reverted all the sprites to their original indices; not too painful because I use macros to address them.

I also fixed a bug in the initialisation routines that were clobbering variables that shouldn't have been clobbered; and I haven't seen the START crash since. Fingers crossed that was the source of the issue...

Interestingly, the non-Neo Geo portion of the 68K code/data is $2B1C bytes now. Although I am optimising some of the code slightly, I suspect the end result will exceed the 16KB of the Z80 ROM. I'm loathe to estimate the percentage of code I have ported at this point, but I'm hoping by now I've hit the 50% mark. And FWIW the Neo Geo PRG ROM for Neo Kong is $3888 - a few bytes short of KOF2003!

Monday, 16 December 2013

Introductions are in order

Despite the lack of updates on this blog, I've been plugging away at Neo Kong at every opportunity.
 
I jumped the gun a bit on the game-play; I thought I'd fast-track the game initialisation and get into the actual game, but it turns out that there's too much logic dependent on the initialisation. So I stepped back and ported all the initialisation routines properly. And then I realised that I had forgotten altogether about the introduction screens...

Coin-up and watch the intro screens

So now you can coin up, start a game, watch the intro, and when the game is over (I set Mario to die immediately) it returns to the attract mode loop. All that is missing outside the game-play now is the high score registration routine - which I'll probably finish off next just to get it out of the way. Once that's complete, it should mean that the only code remaining is in-game game-play code.

I do have one intermittent bug; occasionally the Neo Geo will reset when you start a game. I suspect it's an issue with a register having non-zero high-order bits due to BIOS routines where I have forgotten to zero them first - I've already made that mistake a few times. I'll track it down at some point when it starts to get too annoying.

Although I do 99% of my testing under MAME running un-throttled, I have noticed that the game runs too slow when it is throttled. I guess that's not too surprising, given that I'm rendering the entire tilemap, plus 64 sprites, plus calling the BIOS handler every VBLANK. At some point I'll do some further analysis but right now I suspect every 2nd VBLANK is being missed and it's running at half-speed. Not an issue atm since there's plenty of display optimisation to be done.

I've also been thinking ahead about what bells 'n' whistles might be nice. I'll add a (soft) dipswitch setting to select either US/Japanese level sequence. I guess I should also look at supporting loading and saving of high scores.

Thursday, 12 December 2013

Coins and dipswitches

Some more integration into Neo Geo, bugfixes and tidy-ups tonight.

I got curious about the soft dipswitches on the Neo Geo; now the Donkey Kong dipswitches are all implemented on the Neo Geo. I've replaced the cabinet upright/cocktail switch with a horizontal/vertical switch that controls the screen rotation.


I got thrown for a while because the game name wouldn't appear correctly on the setup screen. After scratching my head for a while before relenting and tracing through BIOS calls, I discovered that it is read from the backup RAM, not the dipswitch settings table in ROM! And because I had run Neo Kong previously with garbage in the table, it had saved a rubbish game name in the backup RAM (everything is keyed from the NGH number in the ROM header). Deleting the saveram file and running it again fixed the issue.

I also fixed the coin-up issue, which was a bug in the 68K port; comes from reading Z80 instructions which are <dest>,<src> and translating to 68K which is <src>,<dest>. Not the first time I've made that mistake, and it won't be the last. So I can coin-up and start a 1P or 2P game (which I've now hooked up to the actual START buttons on the Neo Geo)...

...which brings me to another Z80 Donkey Kong bug. The routine to detect 1P and 2P start buttons stores a mask in the B register, depending on whether there is one or more credits. Then the routine periodically prints the 'PRESS 1P or 2P START' message, depending on a timer value, before reading the hardware and testing the input against the mask. The bug is that if the messages are displayed, then the B register is not preserved, and is always set to 0. It doesn't matter, because invariably the button is detected on the next loop, and the message not displayed and it all works.

This in turn resulted in a related but different bug on the 68K port; the mask register wasn't being set to 0, but 0xff - meaning that pressing 2P start with only 1 credit was being accepted. Anyway, all fixed on the 68K port now.

Next session I can well and truly get into the game-play code. First order of business will be getting Mario to move on the 1st level. But I have a feeling that I won't get the opportunity tomorrow, so it'll have to wait a few days...

Wednesday, 11 December 2013

Do you want to play a game?

Lunchtime progress: can insert (only 1) coin and select START1P.

Not sure if the issue with it accepting only a single coin is a Neo Geo issue or a Donkey Kong porting issue. Either way, it's likely a trivial problem (I always regret saying that!)

For now I've hooked the START1P to Neo Geo BUTTONC, only because after the experience I had with the coin-ups it was always going to be quicker and easier. I'll look at what's required to hook it up properly tonight if I get the opportunity.

But the big news is - it's now executing the main game-play loop!!!

Right now I've got the loop executing the attract mode initialisation - just to see something happening - but I've also verified it in the MAME debugger. And at this point, the attract mode and game-play modes merge again, so I can test either.

But first, I've got bills to pay...

Coins and housekeeping

Last night I did a few tidy-ups; reviewed (again) any missing functionality in the execution path thus far and found a small routine that 'fixes' the moving ladders on the 2nd (cement pie) level. Still a few sundry items and sprites which I'm yet to port, but they don't seem too important atm. And for some reason, the ladder-tops have appeared again on the title screen (although the transition from demo mode to title screen is a hack atm, so I'm not too fussed).

I also decided to code the coin-up logic, and found that the Neo Geo does things very differently to other arcade games. All the title, demo, credit and start functions are handled by the BIOS. I had to fill in a few missing vector functions in the cartridge header, and also had to set the USER_MODE variable in the system work area before I could get the coin-up function working, but now I can add a credit (not sure yet how this will translate to the non-MVS platforms). That's still WIP so you can't actually start a game yet.

I also took a quick look through the rest of the code, in particular the game-play loop. It all looks fairly straight-forward, and I should be able to get Mario moving about without having to worry about porting the rest of the game logic. There's quite a bit of crank-the-handle type porting to be done, which might be a little tedious but shouldn't throw up any surprises and will hopefully be straightforward to test as I go.

 But first, I'd like to be able to start a game.

Tuesday, 10 December 2013

Neo Kong is not Donkey Kong

Just playing around, since 'DONKEY' contains the letters 'N', 'E' & 'O':


Now I really have to get back to work...

4 on the floor.

Managed to find the bug in the rivet level. The dangers of local labels and unfinished code...


The game's data structures are starting to become a little clearer now. Aside from the expected jumble of timers, temporary and sundry variables there's a table of objects @$6400 to the end of memory. This table keeps track of objects like fireballs, springs, elevators, hammers, barrels, etc - basically anything that moves or can be interacted with. Everything's also nicely aligned; objects are either 16 or 32 bytes depending on how much data is required to store their state.

I've also found what appear to be two bugs in the level initialisation code!

In the 2nd (cement pie) level there's a call to the routine that initialises the spring sprites from the elevator level. The sprites themselves are located off-screen so there's no visible side-effects, but none-the-less there's no reason it should be called.

In the 3rd (elevator) level the code that initialises the elevators appears to have a bug. The code to initialise the 6 elevator objects instead uses two nested loops to overwrite a byte (with the same value) in the first 3 objects twice, instead of looping through all 6. It looks like the code used to use a different value for the 4th-6th objects and was quickly patched... either way there's still a bug as the start address is initialised inside the outer loop. I don't know (yet) what this byte represents, so I don't know the effects of the bug.

So now the real fun begins!

Monday, 9 December 2013

Elevators and crashes.

Tonight I got the 3rd (elevator) level finished:


But the problem now is that the 4th (rivet) level is crashing, and for some reason I can't work out exactly where it's going wrong, or the reason (eg. BUS ERROR) for the crash. A trace shows it crashing in the middle of drawing ladder segments, but removing that logic still causes a crash. Thus far crashes have been caused by misaligned word/long reads, or word operands with only the lower byte initialised, and they've been relatively easy to fix, as the bug is invariably in code I've just added. But this one is totally unexpected, in code that was running yesterday!

It's very, very annoying and it's going to have to wait until tomorrow now.

Two down, two to go!

The results from lunchtime today:


As well as completing the initialisation routines for the 1st two levels, I've also fixed the background and sprite placements for the rotated mode. In rotated mode, there's absolutely no scaling (or clipping, on MAME at least) required so for an MVS board in a vertical cabinet, Neo Kong will be a pixel-perfect clone of Donkey Kong!

Thus far, Donkey Kong is using 41 sprites. I don't think there's many more sprites to be added, so I'd be surprised if it tops 64 of the 96 total that gets DMA'd to the registers.

The remaining two levels should be straightforward, as they'll mostly use routines that have already been ported. So I'll finish those off (possibly tonight) before things will start to get really interesting!

Hammer time!

Again, weekends aren't the most conducive to working on Neo Kong, but I have managed to get the hammers coded up.

Ignore the sprite offsets, I'll fix them soon!

Perhaps a little more work than you'd expect just to display two hammers, but now we're getting into the meat of the code; objects (such as hammers) are represented by 14-byte data structures which are initialised in several stages from different data sources.

I've been doing my own reverse-engineering at this point because thus far I've encountered a few minor errors in the other disassemblies and have been thrown a little off course by them. I should note here that you can't really fault them - it's one thing to comment a disassembly and another thing altogether to actually re-write every single instruction for another CPU! It takes me a little more time but I guess it's worth the independent verification- though it's not something I'll need to do for every instruction as once the data structures are identified, the rest of the code should fall out quite easily.

And this is way too premature, but I've also been thinking of my next porting project... and I think I've got a candidate that is perhaps a better fit to the Neo Geo than Donkey Kong.

Saturday, 7 December 2013

Even more spritely!

Not a lot of time on the weekends, but a little more progress..


Fixed a bug in the tilemap render routine that was cutting off the top row when rotated. Now you see the 1UP and HIGH SCORE text, which was absent from the last screenshot. Oh and the sprites aren't scaled yet, so the placement was never going to be right, but they're approximate atm.

I've been working on the level/game-play initialisation routine, which as you can imagine is not trivial. The background renders are done, as I mentioned, in a generic routine with a 2nd level-specific routine. Then all the game-play data is initialised, including sprite positions. Here each level has its own sprite initialisation routine as well, which is where Kong's barrels, the oil barrel and hammers (not ported yet) are done. You might also notice a couple of errant ladder tiles at the top of the screen are now missing - for some unknown reason black sprites are used to cover them!?!

I'll probably spend the time now and complete all the sprite routines for the other levels, since they are tightly coupled to other in-game data structures like the fireball locations. Then at least I can see all screens in their entirety and maybe even at least start to run them in attract mode. So Mario will have to wait a little longer before he can run!

There's life, Jim!

The wife went out for dinner so I got to play some more. Still haven't sorted the sprite placement properly, but in rotated mode, at least these look right with fudge factors.

Attract mode, Kong, Pauline & Mario
I've skipped the code to draw level-specific sprites (oil barrel etc), so I'll probably go back now and do that. Maybe, just maybe, it won't be too long before Mario moves!?!

Friday, 6 December 2013

Let there be sprites! And when X=Y...

I've got the 1st sprites showing in Donkey Kong - Kong himself on the title page.

Now with added sprites - albeit in the wrong location

You will, no doubt, notice that the sprites are not in the right location - more about that later...

But first, after hooking up the palette to the sprites, I discovered that the bitplanes were reversed in the Donkey Kong sprite ROM's w.r.t. the tilemap ROM's... something that may simply be a 'bug' in MAME as the ROM's are organised in the driver arbitrarily to some extent. Either way, a simple fix to my conversion tool and I was up-and-running with correct colours just a minute or so later.

In the process I fixed a bug (which was disabled anyway) in my tilemap rendering routine and did a few minor optimisations. I'm still not convinced that a complete rendering of both tilemap and sprites every VBLANK is going to cut it on the final version, but gee it'd be nice - very nice - if it did!

So, about those sprite locations; stepping back a bit the whole X-Y issue has been somewhat clouded from the beginning, given that the display on the Donkey Kong cabinet is rotated 90 degrees. I've referred to coordinates as 'X' & 'Y' and also referred to 'rows' and 'columns' throughout my commented disassembly and, to be honest, I'm not sure I haven't been inconsistent in some areas. And whilst it's easier to think about Mario's X coordinate changing as he runs across a girder, it is in fact his sprite's Y coordinate that is changing in the hardware. And of course, a row of text spanning multiple columns is actually a single column of text on the display spanning multiple rows. So what convention do you choose, and how do you make it clear? My brain started hurting right about now.

So when mapping all this to the Neo Geo hardware, it complicates the issue. And to make matters (much) worse - at least where sprites are concerned - it's not a nice 0-N range on one/both axes on either hardware platform! The sprite rendering code in MAME, for example, looks like a veritable dog's breakfast, somehow involving the current scan line! Arrggh! And of course, supporting both orientations means I have to solve the problem twice. If my brain was hurting before, it's throbbing now!

As a result, thus far I've managed to place the sprites somewhere on the screen for now.

To be honest, I haven't decided my plan of attack from here (sprite coordinate issues aside). I'll have to take some time to study the uncommented areas of code to work out how best to proceed. Ideally, it'd be nice to get Mario running and climbing, without the distractions/complications of timers, barrels and fireballs, and possibly easier to understand the sprite coordinate issues. Having said that, I have no idea at this stage what proportion of the remaining code would need to be ported to achieve that.

To give some very vague idea of what I've done so far, the PDF listing from IDA is approximately 80 pages of code. But that can be rather verbose with comment lines between functions, and added lines for cross-references - let's say 20%, so maybe 60 pages of Z80 code. My main.68k file, which contains (mostly) non-Neo Geo specific code, is currently 8 pages of code. However, operations can be done rather more efficiently in 68K code, so I'm going to estimate that would represent at least 10 pages of Z80 code. Using these very rough figures, I might say that I've ported about 1/6th or 17% of the code; doesn't sound like much when you put it like that. But there is an awful lot of 'grunt work' code remaining - code that will simply be a matter of turning the handle. Tedious but straighforward.

Wednesday, 4 December 2013

Sprites

Tonight I converted the Donkey Kong sprites to Neo Geo format.

Next task is to write the sprite rendering code for the Neo Geo. In theory DK has two (2) banks of 128 sprites, although according to MAME only 16 sprites are visible on each line. Regardless, from what I've gleaned from the code thus far, nowhere near that many are actually used. For now I'll need to devise some algorithm for selectively displaying only those sprites that are actually used. Ultimately I'll probably rationalise and condense the sprites that are used on the 68K port.

Tidy-up, bug fixes and the GCW-ZERO

I decided to give my 68K code a once-over before I move onto sprites; fill in any missing functionality in the execution path of the attract mode that I've already commented but not ported.

In the process I fixed a few minor bugs; the score and high-score display routines were always showing "000000", and the palette for the conveyor/cement level was wrong.

I also decided to finish off commenting and porting the level background rendering routines, which were decidedly simpler than the girder and ladder drawing routines; each level is a mixture of generic and special-case routines, the latter being simpler to reverse-engineer. As a result, here are the four levels as rendered before any sprites are added:

All 4 screens, fully rendered before adding sprites
I really am at the stage now where I need sprites to see what is happening in the code. Again, the conversion to Neo Geo sprite format should be straightforward, and shouldn't take me more than an hour or so. Then I need to write the sprite rendering routines for the Neo Geo hardware. One interesting aspect of the Donkey Kong hardware is that the sprite registers are shadowed in ordinary RAM and then DMA'd to the hardware registers each VBLANK interrupt. That actually makes my job really easy (for the initial implementation) as I can essentially do the same (although I'll be using the CPU to move the data). It's not necessarily how I'll implement the final version, but again, makes it very easy to debug and also rotate the screen!

I do have a particular issue with sprite placement due to the fact that I'm scaling the tiles (Neo Geo sprites) to fit the entire Donkey Kong screen on the Neo Geo display, but I'm pretty sure I have a solution for that issue.

As an aside, I received my GCW-ZERO yesterday and have spent a bit of time installing emulators - including the Neo Geo of course - and playing a few things. Whilst the emulations themselves are excellent, and the screen is nice and bright, the build quality is absolute, complete and utter GARBAGE! The controls are so horribly crappy and sticky, it's almost unusable. I'm not sure what my options are given that it's a Kickstarter project, but I'm sure as hell not happy about it! Consider this a Public Service Announcement.


Monday, 2 December 2013

Every man and his dog...

It seems Donkey Kong is a ripe candidate for (commented) disassembly - I now know of possibly three (3) disassemblies which would make mine the 4th!

The first as I mentioned is Sockmaster's listing, created when he ported it to the 6809-based TRS-80 Color Computer (aka Coco). The 2nd I learned about only yesterday, Jeff Kulczycki's listing, created when he added the 5th Foundry level. AFAIK this listing hasn't been released in the public domain. The 3rd I discovered today on the Donkey Kong forums; a reasonably comprehensive disassembly from what I've seen so far.

With all these available you may wonder (as do I) why I'm bothering to do my own. You can be certain I will be using all the information from the latter, just as I have Sockmaster's, but even that is lacking in some key areas I've already encountered. For example, the code to draw the levels is relatively uncommented (save for rather pointless comments such as 'subtract 10 from A'). So I will be taking everything available, verifying it to my own satisfaction, and merging it into my own IDAPro disassembly. Ultimately I aim to have the most comprehensive disassembly, and I should be able to generate fully-relocatable Z80 code (alongside my 68K port of course).

For instance, tonight I have been working on the aforementioned code that draws the levels, and thus far have deciphered the routines for drawing girders and ladders. The rest of the draw routines should follow quite easily from here. I suspect Jeff has managed to do as much (as he added a 5th level) but no-one else seems to have done so before.

But enough words and more eye-candy. The attract mode now cycles through all three screens, but of course the game-play demo is currently a static, tilemap-only, rendering.

The Neo Geo cycles through all 3 in attract mode

On par with the disassembly, I have coded the girder and ladder drawing routines, and made use of the ability to specify any level for the attract mode. The results vary from level-to-level, but it's a good indication that I've got these routines working correctly.

The 4 levels, girders and ladders only

And that's about as far as I'm going to get without any sprites. So it's back to my ripping software to convert Donkey Kong's sprites to Neo Geo format; nothing too different than the tiles so I'm expecting that to be a straightforward process. Then I can get Kong rendered on the title screen, before the infinitely more daunting task of delving into the game-play (attract mode).