Monday, 7 November 2022

Finally ready to tackle the Xevious sprites!

A bit more transcoding, scheduling the SUB CPU routines, and hooking up the Neo Geo dipswitches.

In my not-quite-complete RE, I never did find the code that was displaying the 1UP and 2UP text above the player scores. Today I found it - by accident - in the SUB CPU code. I didn't expect it to be in there, but it handles the display and flashing of the respective strings. Incidentally, it was the last and only unidentified main routine in the SUB CPU.


High Score Table, 1UP,2UP flashing

I had tacked a few of the SUB CPU routines onto the end of the MAIN BLANK IRQ handler as a quick hack to implement scrolling, but that started to cause issues when the SUB CPU code wanted to access video memory which disables interrupts. So I took a step backwards and looked at the timing and synchronisation of execution between the two CPUs. Both CPUs execute their main loop once, and then spin waiting for the next VBLANK.

It was a simple matter having the SUB CPU main routine called from the MAIN CPU main routine - I think that should do the trick. It's working for now at least. I also implemented the SUB CPU main routine round-robin function scheduler properly; not that it's doing much atm other than scrolling the display and displaying 1UP/2UP as above. But fleshing that out now should be trivial.

I've defined the Xevious dipswitches for the Neo Geo soft dips settings, and the lives setting has been coded and tested in the core. In order to avoid excessive bit-twiddlng each time the dips are read - once every VBLANK - I'm preserving the switch (bit) ordering in the Neo Geo even if the options aren't "nicely" ordered. Who cares, right?

And with that, it's time to start coding for the Xevious sprites. There's not a lot else that I can transcode that is meaningful without being able to at least play a game. The objects (sprites) in the game comprise the main data structures and the bulk of the code, so I'll need to optimise that for the 68K. It would be silly to attempt to preserve the exact structures used (and optimised for) the Z80. But it should end up more efficient than the Z80 code when all is done.

And sprites being sprites, technically it should be a lot easier on the Neo Geo than trying to emulate the tilemap layers. Just a lot of bit-twiddling to convert Xevious sprite register data to Neo Geo sprite register data.

Milestone 1 complete!

Some free time this morning and I've managed to code the scrolling routine. It's brain-dead and brute-force, but the scrolling is derived directly from the hardware scroll register calculated in the original code. 

Title screen and scrolling map

There's plenty of optimisations that can be done for the video access, but that can be done later. More importantly for now, the tilemap functionality in the OSD (Neo Geo) layer is fully functional, which means I can focus on the transcode itself and not have any technical (Neo Geo) hardware issues to deal with - at least until I have enough of the code in place to start working on Xevious sprite support.

Here's a video of the game running thus far:


I'll work on transcoding more of the high-level code before tackling the sprites. The first instance of a sprite is the sparkle chaser on the logo; that'll probably be the first sprite I try to implement. Or maybe the Solvalou. Then I'll implement the sprites for the ground-based objects on the map...

Cooking with gas!!!

Yah! A few more frustrating bugs squashed and the tilemap layers are now all-but-done. They've been tweaked for proper centering, pixel-perfect alignment between layers, and it's all - finally - looking good to implement the scrolling next.

Title screen, which uses both tile layers for the logo

The map screen is back!

Part of the scrolling implementation is adjusting the visible areas at top and bottom of the background layer. That's trivial, because I use a pair of black opaque sprites to mask the not-visible extents.

I should note that the actual code for updating the colour and video RAM areas are far from optimal at the moment, and I plan to fix that at some point. In order to facilitate getting everything right, I reverted to the original video RAM layout and went through the same steps as the original code in calculating RAM addresses from row and column pairs etc. In my Neo Geo layer, I effectively have to reverse that calculation again. It would be far more efficient to bypass the RAM altogether, and I'll look at doing exactly that at some point.

My previous implementation of the scrolling map hasn't gone to waste either; I'll have to use some of that mechanism in the new implementation. I'm actually hoping I can knock out scrolling in one more session at the keyboard.

I think I've just jinxed myself now...

Saturday, 5 November 2022

Too many sprites spoil the transcode!

A few frustrating hours thinking that my background layer sprites weren't visible, when in fact buggy code elsewhere meant they were being created and then wiped before I could see them. I must have walked through the same routines a half dozen times in the last 48 hrs looking for a bug that didn't exist... though that's arguably par for the course for any software development really.

Background and foreground layers - final implementation?

It may look like I've taken a step backwards from the last screen shot, but I think I've finally nailed down the implementation of the two tilemap layers on the Neo Geo. You'd think that 384 sprites - 96 on any scanline - would be more than adequate for a 1982 Z80-based arcade game with discrete graphics hardware... but when you have to scale down the target system sprites and emulate dual tilemaps it can become an issue! I'm confident though that I've managed code around these limitations with a solution that allows me to coordinate the original scrolling variables with what's happening on the Neo Geo screen relatively easily.

Hopefully - it's yet to be tested!

Coined up and started a game... can you tell?

It may not look very good, but the only thing missing from the latest implementation is the background layer colour/attribute RAM, which is why the tiles aren't rotated correctly or have the correct colours. The code has been implemented in other - obsolete - routines already, I just need to port it across. There is one issue though; 1 bit of the colour index is dependent on the tile code, which means in theory the tile colour needs to be (also) updated whenever a new tile code is written to the background layer video RAM.

Next step is to complete the abovementioned background layer colour/attribute RAM implementation and then I can look at scrolling. If that's as straightforward as I'm hoping it will be with my new implementation, then within a few days I should have complete, perfect, implementation of both layers! Then I can start fleshing out the rest of the code in preparation for adding the Xevious sprites!

And there's the small matter of finishing the RE as well... 😉


Friday, 4 November 2022

Leaning to the left...

Not quite, but getting there. Screen is rotated left now, instead of right.

Original vide RAM mapping, rotated left

I think the the top 4 tile rows of the screen aren't visible on the arcade machine, as the HIGH SCORE text appears on the 4th row in video RAM (confirmed on the original).

I should try to understand the MAME tilemap macros, it would probably give some insight into the visible areas and how it decodes the mapping...

void xevious_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(xevious_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(xevious_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);

m_bg_tilemap->set_scrolldx(-20,288+27);
m_bg_tilemap->set_scrolldy(-16,-16);
m_fg_tilemap->set_scrolldx(-32,288+32);
m_fg_tilemap->set_scrolldy(-18,-10);
m_fg_tilemap->set_transparent_pen(0);
m_xevious_bs[0] = 0;
m_xevious_bs[1] = 0;

save_item(NAME(m_xevious_bs));
}


To be continued...


Thursday, 3 November 2022

One step forward, and 2 steps backward!

Now that I have enough of the high level code in place to coin up and start a game, I've gone back to fix up the background scrolling. The original issue is that I wasn't really emulating the scrolling hardware properly, but rather optimised it for the gameplay scrolling, and as a result it came unstuck when the game was either setting the scrolling offset arbitrarily, or writing non-map data to the background.

There are 3 components to the scrolling that need to be emulated; the software scroll_cntr variable, the video ram mapping, and the hardware scroll register. Ultimately the software modifies the software variable directly and the hardware scroll register value is calculated from that. And the video ram mapping is optimised for a rotated monitor. And I have to admit, I am having trouble wrapping my head around the algorithmic relationship between the three. Hence the initial optimised implementation which simplified the video memory mapping and - I have to say - fudged the hardware scroll variable somewhat.

In attempting to rectify this, I've actually taken a big step backwards and decided to re-think the entire architecture of the scrolling background layer. Not only the above-mentioned aspects, but also the Neo Geo-specific implementation (ie how it uses sprites).

First step was to preserve the original video RAM mapping and transcode the routines that handle map rendering more accurately. In the end it wasn't as painful as I thought, because I can forego the screen flipping considerations and 16-bit operations are a lot simpler on the 68K than the Z80. To give you an example, the routine to calculate the video RAM address from row & column is 22 instructions in the original Z80 code (albeit with flipping), and only 8 instructions on the 68K.

Reverting to my original (test) code to render the background layer, I not only see the map being rendered (correctly again), but I can also now see the Xevious logo that is written directly into the background layer video RAM.

We finally get to see the map again

Tiles written to the background layer are now rendered correctly

Note that because the routines for background and foreground layers share the same calculation routine, the foreground layer tiles are now incorrectly positioned. But that's simply a matter of updating the foreground tile layer access routine to use the original layout. That's what I plan to do next...

As I mentioned, I've re-thought the implementation of the background layer, and it will likely require a few nights and a bit of experimentation to get it right. But I am hoping it will simplify the scrolling and allow the physical display to sync up with the software scroll values used in the code.

One other thing that occurred to me too; the direction of the rotation. I'm not sure how or why I chose to rotate the screen to the right in Donkey Kong (and hence all my other projects since), but I thought I should check against the one (and only) "commercial" tate-mode Neo Geo game; Neo XYX.

As it turns out, Neo XYX rotates the monitor to the left. Programmatically there's little difference; you have to either reverse the X or Y coordinate depending on which way you rotate. The Neo Geo video RAM access mechanism lets you selectively increment or decrement the address after each access, so neither is more preferable to the other. But I do think it's a good idea to use the same orientation as Neo XYX, because people aren't going to want to rotate their monitor different ways for different (tate) games. And if/when Neo Geo tate mode is supported in MiSTer, they're likely to favour the orientation of Neo XYX.

So that's another modification I have to make to my code before I can progress.

[I've just checked my Neo Geo tiles; I've only got one rotation in the set (because you can always toggle the flip bits to rotate the other way) and they're actually rotated to the left. Looking at my code, it does in fact toggle the flip bits when rendering each tile. So I guess I'll save 1 instruction per sprite update now!]

Monday, 31 October 2022

Do you want to play a game?

Not a lot of time spent on it today. Can now start a game after coining up. Scrolling is a bit screwed atm.

Gameplay mode!

Might be enough to fix the scrolling now before I attempt to bring (Xevious) sprites into the picture.