I've had a few requests to add joystick support to the Coco3 port of Lode Runner. Since I've now had experience writing a joystick input routine for Knight Lore, and the fact that the Sega Gamepad Adapter brings digital joysticks to the Coco - and perhaps more importantly, 2 buttons - I thought I'd go ahead and do it.
In the spirit of the original port, rather than forge ahead and blindly add joystick code to the Coco3 version, I first need to analyse the Apple II code so that I may implement the reads in the same code paths/locations as the original. Easier said than done, considering I never commented the joystick input routines - mainly because I have no idea how the Apple II reads the joystick. Time for more research on the matter...
UPDATE: I've now commented the joystick input routines. It should be fairly trivial now to add the routines from Knight Lore... although it may affect the timing of the game slightly; if it needs tweaking it's a single direct-mode operand in a delay loop. For authenticity I will also add the controls for enabling/disabling the keyboard & joystick (^K and ^J respectively).
I also have a funny feeling that at least one of the Coco3 buttons is already (ghost) mapped to a keyboard control. That will be a PITA if it is.
And whilst I'm dealing with Lode Runner; there are several reports of it crashing on certain (Coco3) hardware configurations. Basically, it either runs, or it doesn't. And now the possibility of GIME revision and/or DRAM speed being a factor have been thrown into the ring. Fun...
This blog chronicles my progress porting various retro games to other retro platforms. The goal in each project - at least when targeting a new CPU - is to effectively replicate the original graphics and the original code line-by-line, to produce a 100% accurate port of the original game.
Pages
▼
Sunday, 18 December 2016
Friday, 2 December 2016
NeoSD, What a Lode of...
With the release of the NeoSD flash cart I've decided to try and finish off Lode Runner; at least it's possible that a few people might now be not only interested, but actually able to, try it out on real hardware.
It's been a long time, and I'm a little surprised to find that it's not quite as finished as I thought it was. Don't get me wrong, it's 100% playable, but a few bells and whistles are either missing, or not working properly - for example, the circular wipe and the high score entry.
Anyway, just coming up to speed with it again and making sure I can still build it. It'll take me a session or two to fill my brain with where I was up to when I left off, which was testing it on my NGCD. Aside from the aforementioned, I do know that the guard AI is a little off, albeit very close. Likely just a bug in a line or two of C code.
If that's a success I might return to Donkey Kong whilst I await the AES version of the NeoSD.
It's been a long time, and I'm a little surprised to find that it's not quite as finished as I thought it was. Don't get me wrong, it's 100% playable, but a few bells and whistles are either missing, or not working properly - for example, the circular wipe and the high score entry.
Anyway, just coming up to speed with it again and making sure I can still build it. It'll take me a session or two to fill my brain with where I was up to when I left off, which was testing it on my NGCD. Aside from the aforementioned, I do know that the guard AI is a little off, albeit very close. Likely just a bug in a line or two of C code.
If that's a success I might return to Donkey Kong whilst I await the AES version of the NeoSD.
Monday, 21 November 2016
Pop*Star Pilot: A Review
Pop*Star Pilot is an old-fashioned sideways scrolling shoot-em-up for the TRS-80 Color Computer 3 recently released by accomplished 8-bit game author Nickolas Marentes. Nick's development blog for the game can be found here.
To give you some perspective on where I'm coming from, I've been a huge fan of shoot-em-ups since the days of Space Invaders and Galaxian. My love of the genre stops short, however, of the so-called "bullet hells" that have been churned out endlessly in more recent years. For me, a shooter is more about positioning, precision and forethought rather than mindlessly dodging a raining curtain of sprites whilst simply holding down the fire button for the entire game. For me, perfection of the genre was Xevious, a game solely responsible for my lackluster uni results.
I've always been a fan of Nickolas Marentes' games, ever since I first encountered Donut Dilemma on the TRS-80 Model I. Particularly on the Model I, game authors had to focus on game play above all else, and Nick was no exception; his games were up there with the best the platform had to offer. Nick went on to develop for the TRS-80 Color Computer, and its obvious that the machine struck a chord with him because he's just released a new game - the subject of this review - for it recently!
Needless to say, when Nick announced the impending release of Pop*Star Pilot, and after reading the development blogs and seeing the screen shots, I knew two things; I was going to buy a copy of this game, and I was only going to play it on real hardware to get a 100% authentic experience (OK, I admit I was never going to use those awful Coco joysticks, and opted instead for a StarCursor digital stick and the Sega Gamepad Adapter, something Nick himself recommends for the game!)
I won't go into the back story - for those interested and/or want some eye candy, see here - but suffice it to say that you're piloting a prop left-to-right through a scrolling landscape armed with just a gun of sorts and your reflexes, popping balloons - as you do. Good retro arcade games don't need a back story; just instructions on how to start the game and 2 minutes play time to figure out the rest!
The graphics are what you'd expect from an 8-bit arcade game, and this game showcases Nick's talents as an 8-bit artist. Very polished, right from the animated title screen, with just the right amount of 'busy' on the screen so as not to distract you from the task at hand. Great use of colours - it's a very pretty game - and it would be easy to believe that it was produced by a team in one of the more established software houses on the 8-bit consoles back in the day.
Of course graphics are secondary to game play, and I'm happy to say that Nick has delivered in this department too! Smooth scrolling and precise 8-way movement; you never feel that the mechanics of the game have let you down. A nicely crafted difficulty level rewards persistence, without creating frustration at impossibly difficult points of the game. There are, naturally, a few points in the game that you will die at the first time, and you need to work out a strategy for moving past them, but that's a pretty essential element in this genre and it doesn't take long to progress through them. After that, it comes down to your planning and your reflexes.
A good game tempts your greed with increased risk, and Pop*Star Pilot includes this element too, rewarding sequences of hits that sometimes requires forgoing other shots and dodging, and maneuvering into dangerous positions for that big score.
What I want from a game is a firm belief that I can beat it, but one that doesn't quite let me do it, at least not without a reasonable investment of my time. Getting that balance just right avoids a game that is either too easy, or so difficult that you'll never see Stage 3. It's still a little early to tell with Pop*Star Pilot exactly where it lies for me, but I will say it's definitely not the latter. I suspect I will get my money's worth from it before I conquer it!
UPDATE: After another hour or so playing it tonight, I finally made it into Zone 5 with sufficient tokens to unlock it. Zone 5 takes the difficulty up a notch, and I lost (IIRC) 4 lives in reasonably short succession. I feel I'm really getting the hang of the earlier stages now, and looking forward to tackling the last zone again next session!
I couldn't honestly say, however, that the sound is this game is more than simply adequate. There's no title tune or in-game music, and what sounds there are, are rather basic. I can fully appreciate the reasoning behind this, and suspect that Nick's priority was maximising the length of the game. Whilst I truly appreciate sound in games, and agree some sound is definitely required, I've never really been as hung-up on them as some, and I can't say that the basic sound in Pop*Star Pilot diminishes my enjoyment to any significant degree.
Now to the warts. There is one bug in the game that I have encountered on two occasions, having played a few dozen games; I actually lost 2 lives at once on Stage 2. Nick has admitted that he had seen this bug during development, but had believed that it had disappeared. It's a trifle annoying, particularly if you're heading to a new high score, but thus far the frequency hasn't soured my experience and I wouldn't choose not to recommend this game because of it.
I was surprised by the lack of explosion graphic when your plane is destroyed. Rather than being vaporised in a ball of exploding fuel, your plane simply flashes as it scrolls off the screen. This seems out of place given the polish on the rest of the game. Not sure if it's a by-product of the non-violent nature of the game, or another technical trade-off?
My last niggle is the lackluster Game Over screen and the lack of (multiple) high score tracking and/or initials entry. You could argue that a list of high scores and initials is largely irrelevant on a home computer system, but together with the simplistic game ending it does contrast with the rest of the game. Perhaps it wouldn't be as noticeable (or even expected) on a lesser title?
I do have one suggestion on the game play for Nick - after reading the instructions I was under the impression that the bonus for popping sequences of white balloons would continue until the sequence was broken. In my opinion that would have been the way to go, tempting greed for higher and higher rewards and correspondingly more risk. As it is, after my last round of plays tonight, I'm still undecided whether chasing the bonus actually results in a higher score, particularly when you frequently forego more points than the bonus is worth. Or maybe that was Nick's intention all along?
UPDATE: If the gods are smiling on you, and you get a good run of white balloons, it's defintely worth the effort. However it's equally possible that they will prove quite rare on occasion, and you could be putting yourself at risk, and dodging valuable points chasing an elusive bonus.
Enough negative, I don't want to leave readers with the impression that this game isn't worth every penny. I would caution anyone from the generations after me though, this is a simple game, but for those that grew up in the 8-bit era, this is exactly what we want from this type of game. No bullet-hells, no screens full of power-ups, no dying and losing all your weapons so that your game is effectively over after your first ship. Progression that rewards practice and forethought, a sprinkling of surprises and a few choices to make, this is a quality 8-bit shoot-em-up on a classic platform in 2016 that would have been a hit back-in-the-day!
If you haven't done so, order a copy from Nick, so that he may be encouraged to write another game!
To give you some perspective on where I'm coming from, I've been a huge fan of shoot-em-ups since the days of Space Invaders and Galaxian. My love of the genre stops short, however, of the so-called "bullet hells" that have been churned out endlessly in more recent years. For me, a shooter is more about positioning, precision and forethought rather than mindlessly dodging a raining curtain of sprites whilst simply holding down the fire button for the entire game. For me, perfection of the genre was Xevious, a game solely responsible for my lackluster uni results.
I've always been a fan of Nickolas Marentes' games, ever since I first encountered Donut Dilemma on the TRS-80 Model I. Particularly on the Model I, game authors had to focus on game play above all else, and Nick was no exception; his games were up there with the best the platform had to offer. Nick went on to develop for the TRS-80 Color Computer, and its obvious that the machine struck a chord with him because he's just released a new game - the subject of this review - for it recently!
Needless to say, when Nick announced the impending release of Pop*Star Pilot, and after reading the development blogs and seeing the screen shots, I knew two things; I was going to buy a copy of this game, and I was only going to play it on real hardware to get a 100% authentic experience (OK, I admit I was never going to use those awful Coco joysticks, and opted instead for a StarCursor digital stick and the Sega Gamepad Adapter, something Nick himself recommends for the game!)
I won't go into the back story - for those interested and/or want some eye candy, see here - but suffice it to say that you're piloting a prop left-to-right through a scrolling landscape armed with just a gun of sorts and your reflexes, popping balloons - as you do. Good retro arcade games don't need a back story; just instructions on how to start the game and 2 minutes play time to figure out the rest!
The graphics are what you'd expect from an 8-bit arcade game, and this game showcases Nick's talents as an 8-bit artist. Very polished, right from the animated title screen, with just the right amount of 'busy' on the screen so as not to distract you from the task at hand. Great use of colours - it's a very pretty game - and it would be easy to believe that it was produced by a team in one of the more established software houses on the 8-bit consoles back in the day.
Of course graphics are secondary to game play, and I'm happy to say that Nick has delivered in this department too! Smooth scrolling and precise 8-way movement; you never feel that the mechanics of the game have let you down. A nicely crafted difficulty level rewards persistence, without creating frustration at impossibly difficult points of the game. There are, naturally, a few points in the game that you will die at the first time, and you need to work out a strategy for moving past them, but that's a pretty essential element in this genre and it doesn't take long to progress through them. After that, it comes down to your planning and your reflexes.
A good game tempts your greed with increased risk, and Pop*Star Pilot includes this element too, rewarding sequences of hits that sometimes requires forgoing other shots and dodging, and maneuvering into dangerous positions for that big score.
What I want from a game is a firm belief that I can beat it, but one that doesn't quite let me do it, at least not without a reasonable investment of my time. Getting that balance just right avoids a game that is either too easy, or so difficult that you'll never see Stage 3. It's still a little early to tell with Pop*Star Pilot exactly where it lies for me, but I will say it's definitely not the latter. I suspect I will get my money's worth from it before I conquer it!
UPDATE: After another hour or so playing it tonight, I finally made it into Zone 5 with sufficient tokens to unlock it. Zone 5 takes the difficulty up a notch, and I lost (IIRC) 4 lives in reasonably short succession. I feel I'm really getting the hang of the earlier stages now, and looking forward to tackling the last zone again next session!
I couldn't honestly say, however, that the sound is this game is more than simply adequate. There's no title tune or in-game music, and what sounds there are, are rather basic. I can fully appreciate the reasoning behind this, and suspect that Nick's priority was maximising the length of the game. Whilst I truly appreciate sound in games, and agree some sound is definitely required, I've never really been as hung-up on them as some, and I can't say that the basic sound in Pop*Star Pilot diminishes my enjoyment to any significant degree.
Now to the warts. There is one bug in the game that I have encountered on two occasions, having played a few dozen games; I actually lost 2 lives at once on Stage 2. Nick has admitted that he had seen this bug during development, but had believed that it had disappeared. It's a trifle annoying, particularly if you're heading to a new high score, but thus far the frequency hasn't soured my experience and I wouldn't choose not to recommend this game because of it.
I was surprised by the lack of explosion graphic when your plane is destroyed. Rather than being vaporised in a ball of exploding fuel, your plane simply flashes as it scrolls off the screen. This seems out of place given the polish on the rest of the game. Not sure if it's a by-product of the non-violent nature of the game, or another technical trade-off?
My last niggle is the lackluster Game Over screen and the lack of (multiple) high score tracking and/or initials entry. You could argue that a list of high scores and initials is largely irrelevant on a home computer system, but together with the simplistic game ending it does contrast with the rest of the game. Perhaps it wouldn't be as noticeable (or even expected) on a lesser title?
I do have one suggestion on the game play for Nick - after reading the instructions I was under the impression that the bonus for popping sequences of white balloons would continue until the sequence was broken. In my opinion that would have been the way to go, tempting greed for higher and higher rewards and correspondingly more risk. As it is, after my last round of plays tonight, I'm still undecided whether chasing the bonus actually results in a higher score, particularly when you frequently forego more points than the bonus is worth. Or maybe that was Nick's intention all along?
UPDATE: If the gods are smiling on you, and you get a good run of white balloons, it's defintely worth the effort. However it's equally possible that they will prove quite rare on occasion, and you could be putting yourself at risk, and dodging valuable points chasing an elusive bonus.
Enough negative, I don't want to leave readers with the impression that this game isn't worth every penny. I would caution anyone from the generations after me though, this is a simple game, but for those that grew up in the 8-bit era, this is exactly what we want from this type of game. No bullet-hells, no screens full of power-ups, no dying and losing all your weapons so that your game is effectively over after your first ship. Progression that rewards practice and forethought, a sprinkling of surprises and a few choices to make, this is a quality 8-bit shoot-em-up on a classic platform in 2016 that would have been a hit back-in-the-day!
If you haven't done so, order a copy from Nick, so that he may be encouraged to write another game!
Thursday, 3 November 2016
The Making Of Kong
Tonight I found myself with snippets of free time between tasks; not so much conducive to extended concentrated effort - such as development - but I did want to at least advance one of the languishing projects...
With all the excitement of the impending commercial release of the Neo Geo flash cartridge (no, not mine unfortunately), I decided to dust off the Neo Kong project and bring it up-to-date with my latest tools and 'best practices' that I've honed during development of Lode Runner and Knight Lore on the Neo Geo.
Specifically, I merged it into the Retro Ports SVN repository and updated the makefile to make it more... well, nice. I won't bore anyone with the details, but the build environment is a little easier to set up and maintain now. I'm not completely happy with the makefile yet, but at least both cartridge and CD targets build and run under MAME now, and there's no need to use another emulator.
The last time I touched the code was 3rd Feb 2013 - fast approaching 4 years ago!!! I was surprised to discover that I am actually assembling with the NEODEV kit assembler; I have been under the misapprehension in more recent times that I was using AS68K.. bit rot in my memory banks! That being so, I'm considering attempting to port it across to AS68K since I'm not linking against any NEODEV libraries.
All that said, I still have Lode Runner, Knight Lore and Space Invaders for the Coco3 to finish too!
With all the excitement of the impending commercial release of the Neo Geo flash cartridge (no, not mine unfortunately), I decided to dust off the Neo Kong project and bring it up-to-date with my latest tools and 'best practices' that I've honed during development of Lode Runner and Knight Lore on the Neo Geo.
Specifically, I merged it into the Retro Ports SVN repository and updated the makefile to make it more... well, nice. I won't bore anyone with the details, but the build environment is a little easier to set up and maintain now. I'm not completely happy with the makefile yet, but at least both cartridge and CD targets build and run under MAME now, and there's no need to use another emulator.
The last time I touched the code was 3rd Feb 2013 - fast approaching 4 years ago!!! I was surprised to discover that I am actually assembling with the NEODEV kit assembler; I have been under the misapprehension in more recent times that I was using AS68K.. bit rot in my memory banks! That being so, I'm considering attempting to port it across to AS68K since I'm not linking against any NEODEV libraries.
All that said, I still have Lode Runner, Knight Lore and Space Invaders for the Coco3 to finish too!
Tuesday, 11 October 2016
I GIVE UP (on the Rawhide lyrics)
Given that this page is my browser 'Home Page' I am actually constantly reminded that Knight Lore is still waiting for me to finish it off. Finding the time, however, has been difficult lately.
We are currently undergoing renovations to the yard and back of the house, and much of those renovations are D.I.Y. They also need to be completed before Christmas for various reasons. What that means is, next-to-no spare time for me at all. I try to make use of the daylight hours when possible to work on the house & yard or, occasionally, getting out and doing some cycling just to save my sanity and my waistline - but that means doing (or completing) my paid work in the evenings. And all that is when I'm not tending to Mr 1 and Miss 4.
So, I can't at this point say when I'll get more time to divert to Knight Lore - I was hoping to have a release before Xmas - but I can't even promise that at this point in time. Eventually it'll all settle down again... one day...
We are currently undergoing renovations to the yard and back of the house, and much of those renovations are D.I.Y. They also need to be completed before Christmas for various reasons. What that means is, next-to-no spare time for me at all. I try to make use of the daylight hours when possible to work on the house & yard or, occasionally, getting out and doing some cycling just to save my sanity and my waistline - but that means doing (or completing) my paid work in the evenings. And all that is when I'm not tending to Mr 1 and Miss 4.
So, I can't at this point say when I'll get more time to divert to Knight Lore - I was hoping to have a release before Xmas - but I can't even promise that at this point in time. Eventually it'll all settle down again... one day...
Wednesday, 21 September 2016
Yah! - or if that's cheating - Soon we'll be livin' high and wide
I'll skip the post on profiling and come back to that next time.
Tonight, at the suggestion of the author of the Atari 800 Pentagram port, I thought I'd look at the masking logic. It certainly seemed like a good candidate, given the amount of time spent in the rendering routines and the fact that the masking requires two table look-ups per byte rendered.
Rather than try to optimise it, I thought I'd disable it altogether and see what effect it had on the performance. I was surprised, and a little disappointed, that it seemed to have very little in fact. Well, perhaps not completely insignificant at 4% in the 'busy' room, taking the frame rate from 8-9fps (see screenshot below) to a solid 9fps.
And because I now had a metric, I disabled the Z-ordering again. I clearly underestimated the effect last time, because the performance jumped to 13fps, and a reduction in the corresponding routine (calc_display_order_and_render) from 25% all the way down to 2%.
I was now a little bummed that disabling masking and Z-order completely still resulted in 13fps, a few frames short of my target 15fps. Curious as to how this compared to the original, I fired up the ZX Spectrum and Coco3 emulators side-by-side and entered the 'busy' room on each.
To my surprise, the Coco3 (with no masking or Z-order) was significantly faster. So I re-enabled Z-order. It was still faster. So I re-enabled masking - back to the complete code - and it was still faster at 8-9fps!!! For this screen at least, I had been trying to optimise something that was already too fast!
So where does that leave the project? What I need to do now is visit a significant number of screens and compare them, side-by-side, with the ZX Spectrum original. If the Coco3 is running faster in every case, then my work here is done! In fact, I'll need to (re-enable and) tweak the throttling function so that the screens are all roughly the same speed.
EDIT: I think I'm going to back-port my fps ISR from the Coco3 to the ZX Spectrum!
Then there's the matter of beefing up the Z80 R register emulation, fixing a graphical glitch that is simply a result of not being able to emulate the Spectrum's attribute bytes, and we're done!
Livin' high and wide, one might even say!
Tonight, at the suggestion of the author of the Atari 800 Pentagram port, I thought I'd look at the masking logic. It certainly seemed like a good candidate, given the amount of time spent in the rendering routines and the fact that the masking requires two table look-ups per byte rendered.
Rather than try to optimise it, I thought I'd disable it altogether and see what effect it had on the performance. I was surprised, and a little disappointed, that it seemed to have very little in fact. Well, perhaps not completely insignificant at 4% in the 'busy' room, taking the frame rate from 8-9fps (see screenshot below) to a solid 9fps.
The infamous 'busy' screen, with fps counter |
And because I now had a metric, I disabled the Z-ordering again. I clearly underestimated the effect last time, because the performance jumped to 13fps, and a reduction in the corresponding routine (calc_display_order_and_render) from 25% all the way down to 2%.
I was now a little bummed that disabling masking and Z-order completely still resulted in 13fps, a few frames short of my target 15fps. Curious as to how this compared to the original, I fired up the ZX Spectrum and Coco3 emulators side-by-side and entered the 'busy' room on each.
To my surprise, the Coco3 (with no masking or Z-order) was significantly faster. So I re-enabled Z-order. It was still faster. So I re-enabled masking - back to the complete code - and it was still faster at 8-9fps!!! For this screen at least, I had been trying to optimise something that was already too fast!
So where does that leave the project? What I need to do now is visit a significant number of screens and compare them, side-by-side, with the ZX Spectrum original. If the Coco3 is running faster in every case, then my work here is done! In fact, I'll need to (re-enable and) tweak the throttling function so that the screens are all roughly the same speed.
EDIT: I think I'm going to back-port my fps ISR from the Coco3 to the ZX Spectrum!
Then there's the matter of beefing up the Z80 R register emulation, fixing a graphical glitch that is simply a result of not being able to emulate the Spectrum's attribute bytes, and we're done!
Livin' high and wide, one might even say!
Saturday, 17 September 2016
My heart's calculatin'
Just a quick update since it's late...
My profiler appears to be working for the most part, although any delusions I had about writing a generic 6809 profiler are pretty much dashed. I'll go into more details next post, but the nature of assembler makes it difficult - nay impossible - to identify the context (subroutine) of the executing code without some comprehensive code analysis (smells like a halting problem to me).
Regardless, with some inside knowledge of Knight Lore, I've got a pretty good handle on what's taking most of the CPU time now.
Addr Routine Count Cycles
---- ---------------- ----- ------
0xE97A calc_pixel_XY_ 1626 15175159 ( 58%)
0xE19E calc_display_o 249 2924962 ( 11%)
0xE8AD blit_to_screen 501 1081830 ( 4%)
0xD858 fill_window 521 845652 ( 3%)
0xE98F print_sprite 129 820025 ( 3%)
0xDB20 upd_16_to_21_2 235 561370 ( 2%)
0xE02E set_draw_objs_ 235 501364 ( 2%)
0xE12B save_2d_info 10210 459450 ( 2%)
0xC852 toggle_audio_h 461 411865 ( 2%)
0xE610 get_ptr_object 12960 401760 ( 2%)
0xE967 flip_sprite 2239 380273 ( 1%)
0xE144 list_objects_t 249 337709 ( 1%)
0xE799 update_screen 2 291910 ( 1%)
0xE7BC render_dynamic 249 249443 ( 1%)
0xE790 clear_scrn_buf 2 172068 ( 1%)
0xD6CF print_sun_moon 248 145080 ( 1%)
0xDA55 upd_2_4 498 131802 ( 1%)
(snip)
0xFEF7 _IRQ_ 904 38264 ( 0%)
(snip)
0xFEF4 _FIRQ_ 58 1334 ( 0%)
(snip)
---------------------- ---------
Total Cycles 26085292
That top routine is actually calc_pixel_XY_and_render(), which does some trivial calcs and then calls into print_sprite, which is obviously where all the time is spent!
More on this topic next post...
My profiler appears to be working for the most part, although any delusions I had about writing a generic 6809 profiler are pretty much dashed. I'll go into more details next post, but the nature of assembler makes it difficult - nay impossible - to identify the context (subroutine) of the executing code without some comprehensive code analysis (smells like a halting problem to me).
Regardless, with some inside knowledge of Knight Lore, I've got a pretty good handle on what's taking most of the CPU time now.
Addr Routine Count Cycles
---- ---------------- ----- ------
0xE97A calc_pixel_XY_ 1626 15175159 ( 58%)
0xE19E calc_display_o 249 2924962 ( 11%)
0xE8AD blit_to_screen 501 1081830 ( 4%)
0xD858 fill_window 521 845652 ( 3%)
0xE98F print_sprite 129 820025 ( 3%)
0xDB20 upd_16_to_21_2 235 561370 ( 2%)
0xE02E set_draw_objs_ 235 501364 ( 2%)
0xE12B save_2d_info 10210 459450 ( 2%)
0xC852 toggle_audio_h 461 411865 ( 2%)
0xE610 get_ptr_object 12960 401760 ( 2%)
0xE967 flip_sprite 2239 380273 ( 1%)
0xE144 list_objects_t 249 337709 ( 1%)
0xE799 update_screen 2 291910 ( 1%)
0xE7BC render_dynamic 249 249443 ( 1%)
0xE790 clear_scrn_buf 2 172068 ( 1%)
0xD6CF print_sun_moon 248 145080 ( 1%)
0xDA55 upd_2_4 498 131802 ( 1%)
(snip)
0xFEF7 _IRQ_ 904 38264 ( 0%)
(snip)
0xFEF4 _FIRQ_ 58 1334 ( 0%)
(snip)
---------------------- ---------
Total Cycles 26085292
That top routine is actually calc_pixel_XY_and_render(), which does some trivial calcs and then calls into print_sprite, which is obviously where all the time is spent!
More on this topic next post...
Thursday, 15 September 2016
Cut 'em out
Whilst I haven't been working on Knight Lore code per se, I have done some work that will ultimately assist in the optimisation.
I need a profiler, and since none of the Coco3 emulators have that functionality, I have to roll my own. My first preference was to hack MAME/MESS, but the barrier-to-entry is rather high. So the next candidate is Vcc.
Unfortunately Vcc currently compiles under Microsoft Visual C, which I actively try to avoid in my own projects, preferring GNU or otherwise open source toolchains. So I decided to try my hand at porting Vcc to GCC/MINGW. After hitting a few roadblocks that had me stumped for a day or two, I managed to finally get it all building and running! Mostly.
There wasn't a lot of code to modify, in fact about 10 lines in a handful of files. One problem I couldn't figure out how to overcome was a call to AfxInitRichEdit() which is part of MFC and therefore not available under GCC. Interestingly there is a RICHED20 library in the GCC/MINGW distribution which supposedly implements AfxInitRichEdit2(), but I had no luck. Somewhat encouragingly though, the documentation suggests that it's not always necessary to call this function.
So the solution for now was - Cut 'em out!
There are a couple of issues with the GCC build - for example the tape configuration dialog is mysteriously blank - but the real stick-in-the-mud for me is the fact that Knight Lore doesn't actually run. Galactic Attack ran just fine, so perhaps it's an issue with 32KB cartridges?
It's never easy, is it?
UPDATE: There was/is an issue with 32KB cartridge images; Vcc expects the two 16KB banks to be swapped - for some unknown reason - unlike MAME/MESS and also unlike you'd burn to FLASH or EEPROM for that matter. I've done a quick hack for myself so that Knight Lore will run as-is.
The tape configuration dialog was blank because it contained rich edit controls; after adding a call to explicitly load riched20.dll that's now sorted too.
That's the last of the obvious GCC/MINGW issues.
Now I should be able to start on the profiling functionality!
I need a profiler, and since none of the Coco3 emulators have that functionality, I have to roll my own. My first preference was to hack MAME/MESS, but the barrier-to-entry is rather high. So the next candidate is Vcc.
Unfortunately Vcc currently compiles under Microsoft Visual C, which I actively try to avoid in my own projects, preferring GNU or otherwise open source toolchains. So I decided to try my hand at porting Vcc to GCC/MINGW. After hitting a few roadblocks that had me stumped for a day or two, I managed to finally get it all building and running! Mostly.
There wasn't a lot of code to modify, in fact about 10 lines in a handful of files. One problem I couldn't figure out how to overcome was a call to AfxInitRichEdit() which is part of MFC and therefore not available under GCC. Interestingly there is a RICHED20 library in the GCC/MINGW distribution which supposedly implements AfxInitRichEdit2(), but I had no luck. Somewhat encouragingly though, the documentation suggests that it's not always necessary to call this function.
So the solution for now was - Cut 'em out!
There are a couple of issues with the GCC build - for example the tape configuration dialog is mysteriously blank - but the real stick-in-the-mud for me is the fact that Knight Lore doesn't actually run. Galactic Attack ran just fine, so perhaps it's an issue with 32KB cartridges?
It's never easy, is it?
UPDATE: There was/is an issue with 32KB cartridge images; Vcc expects the two 16KB banks to be swapped - for some unknown reason - unlike MAME/MESS and also unlike you'd burn to FLASH or EEPROM for that matter. I've done a quick hack for myself so that Knight Lore will run as-is.
The tape configuration dialog was blank because it contained rich edit controls; after adding a call to explicitly load riched20.dll that's now sorted too.
That's the last of the obvious GCC/MINGW issues.
Now I should be able to start on the profiling functionality!
Friday, 26 August 2016
Keep them doggies unrollin'
More incremental optimisations...
The most significant, from an effort point-of-view at least, was unrolling the shifted (non-byte-aligned) sprite rendering routine. That took a bit to get right. Previously it was also reading & writing to each video byte twice; that's now remedied too. FWIW it makes <1fps difference on the 'moving block' screen.
It's worth noting that it requires 75 cycles to render a single (shifted) byte. That entails reading 4 bytes from data memory, performing 4 table lookups (across 2 different tables) before a read-modify-write of a single byte in video memory.
I also opted to duplicate the (small) routine that calculated the video buffer address from X,Y position. It was originally returning the result in U, however the code always then transferred it to either X or Y, depending on whether it was used as a source or destination pointer. 16-bit register transfers are actually surprisingly expensive (6 cycles) and one case required two transfers to preserve U as well. I also optimised the calculation itself to save a few cycles.
I really need to profile the code properly to identify the bottlenecks. Chipping away at the more obvious optimisations isn't having much of an effect on fps.
And just because I haven't posted any pictures for a while...
There's also definitely some subtle graphics corruption, or rather, garbage. It appears to be limited to human->wulf transformations, and only when in certain orientations. I'll do more experimenting to nail down the exact conditions, then see if it can be reproduced on the ZX Spectrum...
EDIT: Another upside of unrolling the sprite rendering loops is that it should be easier to add support for CPC (4-colour) graphics!
The most significant, from an effort point-of-view at least, was unrolling the shifted (non-byte-aligned) sprite rendering routine. That took a bit to get right. Previously it was also reading & writing to each video byte twice; that's now remedied too. FWIW it makes <1fps difference on the 'moving block' screen.
It's worth noting that it requires 75 cycles to render a single (shifted) byte. That entails reading 4 bytes from data memory, performing 4 table lookups (across 2 different tables) before a read-modify-write of a single byte in video memory.
I also opted to duplicate the (small) routine that calculated the video buffer address from X,Y position. It was originally returning the result in U, however the code always then transferred it to either X or Y, depending on whether it was used as a source or destination pointer. 16-bit register transfers are actually surprisingly expensive (6 cycles) and one case required two transfers to preserve U as well. I also optimised the calculation itself to save a few cycles.
I really need to profile the code properly to identify the bottlenecks. Chipping away at the more obvious optimisations isn't having much of an effect on fps.
And just because I haven't posted any pictures for a while...
Showing the fps counter lower right (49fps) |
There's also definitely some subtle graphics corruption, or rather, garbage. It appears to be limited to human->wulf transformations, and only when in certain orientations. I'll do more experimenting to nail down the exact conditions, then see if it can be reproduced on the ZX Spectrum...
EDIT: Another upside of unrolling the sprite rendering loops is that it should be easier to add support for CPC (4-colour) graphics!
Thursday, 25 August 2016
Unrollin' unrollin' unrollin'
Still haven't determined the main bottleneck but have made more progress.
After tweaking a few routines to eliminate unnecessary branches and some direct-page & register juggling I returned my focus to the sprite rendering routine. I was recently reminded that the original Z80 code used a separate execution path for byte-aligned sprites, so I decided to optimise that section.
After adding code to test for and then render specifically byte-aligned sprites, I then unrolled the loop for this case. To make matters worse (or better, depending on how you look at it), I had unnecessarily transferred a loop counter to & from DP memory and register B when I need only decrement the in-memory value. So worst case - the widest sprite is 5 bytes - it was taking 65 cycles per sprite line (the tallest sprite is 64 lines) just to test and loop. Contrast that with just 26 cycles set-up per sprite, and no per-line test and loop!
Empty screens are now too fast to control (turning accurately is problematic) and my troublesome 'moving block' screen, which started out at 5fps, is now 9-10fps - and I'm yet to optimise the non-byte-aligned (shifted) sprite rendering logic! Having said that, patching the code to render all sprites as byte-aligned did little to improve the frame rate on this particular screen, though it does improve on other screens.
The above-mentioned 'moving block' screen appears to be puzzlingly slow, considering there's only a pair of blocks to animate. Patching the code again to remove the blocks did increase the frame rate by around 2fps, but I can see little opportunity to speed up this particular sprite handler.
However during that process, I noticed that a dozen or so routines branched (near/relative) to another routine that simply jumped (far/absolute) to a third routine. Whilst this could conceivably have been done to reduce code size (slightly) it is rather detrimental to performance, so I of course remedied the situation by 'removing the middleman' so-to-speak.
I've not compared the performance with the original Z80 code since starting on the optimisations, but I would guess that it's starting to approach it now. It would be ideal if I could exceed it slightly, then tweak the frame rate smoothing logic to bring it back on par with the ZX Spectrum.
Watch this space!
After tweaking a few routines to eliminate unnecessary branches and some direct-page & register juggling I returned my focus to the sprite rendering routine. I was recently reminded that the original Z80 code used a separate execution path for byte-aligned sprites, so I decided to optimise that section.
After adding code to test for and then render specifically byte-aligned sprites, I then unrolled the loop for this case. To make matters worse (or better, depending on how you look at it), I had unnecessarily transferred a loop counter to & from DP memory and register B when I need only decrement the in-memory value. So worst case - the widest sprite is 5 bytes - it was taking 65 cycles per sprite line (the tallest sprite is 64 lines) just to test and loop. Contrast that with just 26 cycles set-up per sprite, and no per-line test and loop!
Empty screens are now too fast to control (turning accurately is problematic) and my troublesome 'moving block' screen, which started out at 5fps, is now 9-10fps - and I'm yet to optimise the non-byte-aligned (shifted) sprite rendering logic! Having said that, patching the code to render all sprites as byte-aligned did little to improve the frame rate on this particular screen, though it does improve on other screens.
The above-mentioned 'moving block' screen appears to be puzzlingly slow, considering there's only a pair of blocks to animate. Patching the code again to remove the blocks did increase the frame rate by around 2fps, but I can see little opportunity to speed up this particular sprite handler.
However during that process, I noticed that a dozen or so routines branched (near/relative) to another routine that simply jumped (far/absolute) to a third routine. Whilst this could conceivably have been done to reduce code size (slightly) it is rather detrimental to performance, so I of course remedied the situation by 'removing the middleman' so-to-speak.
I've not compared the performance with the original Z80 code since starting on the optimisations, but I would guess that it's starting to approach it now. It would be ideal if I could exceed it slightly, then tweak the frame rate smoothing logic to bring it back on par with the ZX Spectrum.
Watch this space!
Monday, 22 August 2016
Good News is No News
I'm still perplexed, but I do have some 'good' news. I had a typo that resulted in the main loop attempting to smooth the frame rate when profiling was enabled, when it should have been disabled.
So my frame rate for 'empty' screens is actually up around 43fps (not 29fps). Of course on 'busy' screens the frame rate smoothing logic did nothing so it's still limping along around 7-8fps.
What has me completely bamboozled is the fact that disabling the Z-order calculations still results in no more than 1fps improvement (and I had my hopes up when I first saw the above-mentioned typo), whilst another porter (to 6502) has seen significant improvement by optimising the Z-order algorithm. This means either the 6809 code is vastly more efficient than the translated 6502 code or, more likely, I've done something brain-dead in my attempt to circumvent it.
Oh and I think I saw some transient pixel corruption on one of the animated screens... perhaps that's a clue to something I've done wrong, or perhaps only a side-effect of disabling the Z-order calculations - I'm not sure.
So my quest continues to find the bottleneck on busier screens...
So my frame rate for 'empty' screens is actually up around 43fps (not 29fps). Of course on 'busy' screens the frame rate smoothing logic did nothing so it's still limping along around 7-8fps.
What has me completely bamboozled is the fact that disabling the Z-order calculations still results in no more than 1fps improvement (and I had my hopes up when I first saw the above-mentioned typo), whilst another porter (to 6502) has seen significant improvement by optimising the Z-order algorithm. This means either the 6809 code is vastly more efficient than the translated 6502 code or, more likely, I've done something brain-dead in my attempt to circumvent it.
Oh and I think I saw some transient pixel corruption on one of the animated screens... perhaps that's a clue to something I've done wrong, or perhaps only a side-effect of disabling the Z-order calculations - I'm not sure.
So my quest continues to find the bottleneck on busier screens...
Monday, 15 August 2016
1fps
Had a bit of spare time so I started on the optimisation tonight. The focus was the sprite print routine, though from all reports that's actually not one of the hotter spots in the code. Regardless, I managed to find a few cycles here and there which equated to roughly one frame-per-second improvement on a busier screen - instead of 5/6 it's now 6/7 fps.
Nothing too tricky; found a PSHS/PULS inside a loop that was completely unnecessary, pre-computed an LEAX outside a loop, used post-increment to remove an LEAU, and finally moved a few temporary variables from the stack to the direct page.
Also found a bug in the process, but one that doesn't appear to affect the code - a word-sized variable on the direct page was only allocated a single byte, and AFAICT wasn't used at the same time as the next variable.
Next step is to locate and review my correspondence with fellow porters to identify the critical areas I should be looking at!
Nothing too tricky; found a PSHS/PULS inside a loop that was completely unnecessary, pre-computed an LEAX outside a loop, used post-increment to remove an LEAU, and finally moved a few temporary variables from the stack to the direct page.
Also found a bug in the process, but one that doesn't appear to affect the code - a word-sized variable on the direct page was only allocated a single byte, and AFAICT wasn't used at the same time as the next variable.
Next step is to locate and review my correspondence with fellow porters to identify the critical areas I should be looking at!
Thursday, 11 August 2016
New workspaces and frame rates!
Yes, it has been a while, hasn't it! Long days in the office on my recent overseas work trip followed by late night Skype sessions with the family meant that Retro Ports didn't even get a look-in. And when I did have some spare time in my room, I was either watching the TdF live or catching up on previous days' highlights. Quite removed from my previous jaunt over there...
...and back home since hasn't been much different, to be honest. A full work schedule and trying to balance family time, work around the house and physical activity has meant I have little energy or motivation for sitting in front of a computer screen late at night. And yet here I am at a little past midnight!
I've recently cleared my home computer desk - no longer used on a daily basis - and made it my Coco Space. It now houses my home PC (aka the development machine and theoretically Drivewire server), a PAL Coco 3 with CoCoSDC cartridge installed in a space-age acrylic case, and a TerASIC DE1 running Gary Becker's Coco3FPGA with newly-acquired Zippster Analogue Board. However with only a VGA monitor set up currently, and little extra space, I should probably obtain some form of RGB->VGA adapter for the Coco3.
So, tonight with the wife on a girls' night out I finally got motivated to crack open Knight Lore again! To recap, I just need to improve the frame rate and the random number generator before it's ready for final release. And tonight in preparation, I added an ISR to count and print the frames-per-second in real time.
At its best, on all-but-empty screens, I'm getting about 28-29 fps. The worst I saw, although I've only visited a few screens, was down to about 5 fps when entering the screen and then averaging around 8-9 fps on those screens.
You need to keep in mind that in Knight Lore the fps has a direct effect on the speed of both the player and the objects being animated in the room. So it's not about obtaining a high frame rate (fps) to get smooth animation; the game would be unplayable in that case. Indeed, the proper game speed would - and this is purely an estimate at this point - sit around 15-20 fps. If I could achieve 20 fps on the busiest screens I would be very happy indeed, and would likely need to tweak (and enable) the game loop delay routine to throttle the game play.
As I've touched on in previous posts, there are a number of approaches to the optimisation process; some preserving the original rendering algorithm (which I'd prefer to do) and some that modify it but at the same time produce significant performance gain. I've had correspondence - that I need to locate again - from a few authors who have ported Knight Lore to less capable platforms and managed to get it running faster than the original by enhancing the rendering algorithm. So I have little doubt that I'll be able to get it running fast enough - somehow - on the Coco3!
Hopefully now that I've dipped my toe back in the water, I'll maintain the momentum to work on it regularly.
...and back home since hasn't been much different, to be honest. A full work schedule and trying to balance family time, work around the house and physical activity has meant I have little energy or motivation for sitting in front of a computer screen late at night. And yet here I am at a little past midnight!
I've recently cleared my home computer desk - no longer used on a daily basis - and made it my Coco Space. It now houses my home PC (aka the development machine and theoretically Drivewire server), a PAL Coco 3 with CoCoSDC cartridge installed in a space-age acrylic case, and a TerASIC DE1 running Gary Becker's Coco3FPGA with newly-acquired Zippster Analogue Board. However with only a VGA monitor set up currently, and little extra space, I should probably obtain some form of RGB->VGA adapter for the Coco3.
The new Retro Ports workspace! |
At its best, on all-but-empty screens, I'm getting about 28-29 fps. The worst I saw, although I've only visited a few screens, was down to about 5 fps when entering the screen and then averaging around 8-9 fps on those screens.
You need to keep in mind that in Knight Lore the fps has a direct effect on the speed of both the player and the objects being animated in the room. So it's not about obtaining a high frame rate (fps) to get smooth animation; the game would be unplayable in that case. Indeed, the proper game speed would - and this is purely an estimate at this point - sit around 15-20 fps. If I could achieve 20 fps on the busiest screens I would be very happy indeed, and would likely need to tweak (and enable) the game loop delay routine to throttle the game play.
As I've touched on in previous posts, there are a number of approaches to the optimisation process; some preserving the original rendering algorithm (which I'd prefer to do) and some that modify it but at the same time produce significant performance gain. I've had correspondence - that I need to locate again - from a few authors who have ported Knight Lore to less capable platforms and managed to get it running faster than the original by enhancing the rendering algorithm. So I have little doubt that I'll be able to get it running fast enough - somehow - on the Coco3!
Hopefully now that I've dipped my toe back in the water, I'll maintain the momentum to work on it regularly.
Sunday, 19 June 2016
More productrive times ahead!
Almost a month since my last post, and still no progress to report. Real Life - and other less-geeky pursuits - have been taking priority lately and I've been loathe to return to my project(s) before I can be reasonably sure that I'll be able to dedicate time consistently to them again.
It looks like I'm almost certainly US bound again for work at the end of this month for another 2 weeks, so that time may arise sooner than I thought. On my last 2-week trip I managed to implement the core of the Knight Lore port so it's definitely an opportunity to do some significant development.
I will, of course, concentrate on getting Space Invaders finished and, if I do manage to finish that, I'll start looking at optimising Knight Lore, which I'd really like to release sooner rather than later so that I may finally move onto new projects.
I'll also be buying a new laptop for the trip - lugging the old ASUS G73 (at 7kg or 15lbs) back-and-forth across the globe is getting real tired - and I'll need plenty of time beforehand to load up all my development and emulation environments!
It looks like I'm almost certainly US bound again for work at the end of this month for another 2 weeks, so that time may arise sooner than I thought. On my last 2-week trip I managed to implement the core of the Knight Lore port so it's definitely an opportunity to do some significant development.
I will, of course, concentrate on getting Space Invaders finished and, if I do manage to finish that, I'll start looking at optimising Knight Lore, which I'd really like to release sooner rather than later so that I may finally move onto new projects.
I'll also be buying a new laptop for the trip - lugging the old ASUS G73 (at 7kg or 15lbs) back-and-forth across the globe is getting real tired - and I'll need plenty of time beforehand to load up all my development and emulation environments!
Tuesday, 24 May 2016
Cycles of indecision
Absolutely no progress to report. Work has been taking its toll lately and to be honest, atm when I'm not working and the kids are in bed I'm more inclined to chill out in front of the Giro d'Italia than spend even more time sitting in front of a computer screen.
I do have to admit that I've lost a bit of momentum on the project and still undecided on whether to persist with the on-the-fly rotation or just bite the bullet and finish off my original (pre-rotated graphics) attempt. The latter - although more work - is more likely to be able to handle colour and sound... however I will get this tack working perfectly (even if only for demonstration) before I make up my mind for good.
I do have to admit that I've lost a bit of momentum on the project and still undecided on whether to persist with the on-the-fly rotation or just bite the bullet and finish off my original (pre-rotated graphics) attempt. The latter - although more work - is more likely to be able to handle colour and sound... however I will get this tack working perfectly (even if only for demonstration) before I make up my mind for good.
Friday, 20 May 2016
Still in the red... but much improved
Thanks to jmk, the rotation code is much improved - almost twice as fast in fact! So with some renewed enthusiasm, I added the routine to draw the shields and the game display is complete - except for the scores which I need to relocate to the side of the screen.
Still not a lot of headroom for the VBLANK ISR code which, as you can see above, now encroaches on half the frame, where the mid-screen ISR is scheduled to run. Ordinarily that would show as blue but in the above screen shot, it's happening in the black area above the shields.
There are still some graphical glitches to iron out - my dirty rectangle code needs some tweaking - but the game is certainly playable and it's a reasonably accurate representation of the actual Space Invaders display.
I was originally intending on widening the Coco display from 256 to 320 pixels, but that would actually complicate the calculations for the rotated screen address; right now it's a simple byte-swap and an 8-bit and+neg+add sequence. I'll have to evaluate the implications.
The red colour indicates time spent in the VBLANK ISR |
Still not a lot of headroom for the VBLANK ISR code which, as you can see above, now encroaches on half the frame, where the mid-screen ISR is scheduled to run. Ordinarily that would show as blue but in the above screen shot, it's happening in the black area above the shields.
There are still some graphical glitches to iron out - my dirty rectangle code needs some tweaking - but the game is certainly playable and it's a reasonably accurate representation of the actual Space Invaders display.
I was originally intending on widening the Coco display from 256 to 320 pixels, but that would actually complicate the calculations for the rotated screen address; right now it's a simple byte-swap and an 8-bit and+neg+add sequence. I'll have to evaluate the implications.
Thursday, 19 May 2016
Mostly working.
Usual story, busy with work blah blah.
I have managed to get it mostly working though - except for the shields. The rotation code is brain-dead brute-force, and given that the VBLANK ISR now takes most of the frame to execute, there's going to have to be a lot of optimisation if it's going to be playable, let-alone add colour and sound. But I still think it can be done.
I should note that I do appreciate the coding/optimisation suggestions tendered in the comments, and will certainly be visiting those again when the time comes.
But the important part is that I've now wrapped my head around what needs to be done. Tonight, for example, I racked my brains trying to find which routine wiped the invaders as they moved - in particular when they hit the edge of the screen and move down. Finally it dawned on me that they don't get erased, but in fact get redrawn by the shifted sprite routine - with a shift value of 0. This has the effect of wiping the 8 pixels above the invader (each and every time).
There's still a chance that I'll get all this done and then need to return to the original plan though...
I have managed to get it mostly working though - except for the shields. The rotation code is brain-dead brute-force, and given that the VBLANK ISR now takes most of the frame to execute, there's going to have to be a lot of optimisation if it's going to be playable, let-alone add colour and sound. But I still think it can be done.
I should note that I do appreciate the coding/optimisation suggestions tendered in the comments, and will certainly be visiting those again when the time comes.
But the important part is that I've now wrapped my head around what needs to be done. Tonight, for example, I racked my brains trying to find which routine wiped the invaders as they moved - in particular when they hit the edge of the screen and move down. Finally it dawned on me that they don't get erased, but in fact get redrawn by the shifted sprite routine - with a shift value of 0. This has the effect of wiping the 8 pixels above the invader (each and every time).
There's still a chance that I'll get all this done and then need to return to the original plan though...
Tuesday, 17 May 2016
Monday, 16 May 2016
Seeing double
Next-to-no time to work on Space Invaders lately, but managed to find 10 minutes here and there a few times since the last post, and tonight I finished another intermediate task.
The idea was to duplicate the screen, to achieve a few goals. One was to identify each of the routines in the code that will require extending to render the rotated screen. FTR there are 11 such routines. In each case, I simply added code to the end of the routine to (also) re-render the video to the Coco3 display. This code will ultimately rotate the graphics on-the-fly. It should be obvious that during the process, I had to take note to preserve and restore any registers that were assumed to be a certain value on return from the rendering routine.
Another goal was to gauge how much processor time was still available during the interrupts. The good news is that, whilst the VBLANK interrupt now encroaches on the visible display (as it no doubt does on arcade hardware) there still seems to be plenty of headroom for further complexities.
Next step is to add the rotation. Looking at my old Space Invaders TRS-80 Bootleg Project code, it was all done brute-force using a few assembler macros. No harm in at least giving that a go; it should mean there's not a lot of code required to achieve all of the rotations!
UPDATE: A little more progress. Three (3) of the eleven routines are complete; the two clear routines and the routine to draw the line along the bottom. None of these required any graphics rotations and were more-or-less simple rewrites.
As for the remaining eight (8) routines, they've all been modified to draw the graphics at the correct screen location. One of them, the routine that draws the shields, will have to be modified in the caller as well as it sets the video address of each individual shield.
Right now it's crashing, but that's not totally unexpected.
The idea was to duplicate the screen, to achieve a few goals. One was to identify each of the routines in the code that will require extending to render the rotated screen. FTR there are 11 such routines. In each case, I simply added code to the end of the routine to (also) re-render the video to the Coco3 display. This code will ultimately rotate the graphics on-the-fly. It should be obvious that during the process, I had to take note to preserve and restore any registers that were assumed to be a certain value on return from the rendering routine.
Another goal was to gauge how much processor time was still available during the interrupts. The good news is that, whilst the VBLANK interrupt now encroaches on the visible display (as it no doubt does on arcade hardware) there still seems to be plenty of headroom for further complexities.
Next step is to add the rotation. Looking at my old Space Invaders TRS-80 Bootleg Project code, it was all done brute-force using a few assembler macros. No harm in at least giving that a go; it should mean there's not a lot of code required to achieve all of the rotations!
UPDATE: A little more progress. Three (3) of the eleven routines are complete; the two clear routines and the routine to draw the line along the bottom. None of these required any graphics rotations and were more-or-less simple rewrites.
As for the remaining eight (8) routines, they've all been modified to draw the graphics at the correct screen location. One of them, the routine that draws the shields, will have to be modified in the caller as well as it sets the video address of each individual shield.
The Coco3 screen in its correct orientation |
Right now it's crashing, but that's not totally unexpected.
Friday, 13 May 2016
Changing tack
I've been overwhelmed with work the last few days - and still am - but whilst watching Quartus do its thing (it's about as exciting as watching paint dry) and pondering Space Invaders, I'm seriously considering changing tack altogether.
To some extent, the original game was optimised for the rotated display; the player, the invaders and the saucer all move left/right and thus don't require the shifted rendering routine. Even worse, the shields are each offset 45 pixels from the one to the left, which means they too will require shifting.
Way back in 2003 (gosh!) I worked on what I called the Space Invaders TRS-80 'Bootleg' Project, in which I patched the arcade ROMs to run on the TRS-80 Model 4 with the aftermarket uLabs Grafyx Solution high resolution graphics board. It was only partly successful for reasons you can read about on the link if you're interested.
The strategy I took in that project was to retain all of the original rendering, but rather than render to video memory, it was rendered to an off-sceen buffer. The patches then modified each rendering routine to update the Grafyx Solution video memory, rotating each 'dirty rectangle' on-the-fly. It was much, much simpler to implement and, with a 4MHz Z80, there was enough head room for the rotation calculations. It's a pity the Grafyx Solution video bandwidth was the show-stopper.
I think it's worth at least giving it a go on the Coco3. Once the playfield has been drawn at the start of each player's turn, there's really very little rendering per frame. I'm pretty sure the 1.79MHz 6809 is up to the task, especially given the results of the profiling I did recently.
Time to dig out that Z80 code from 2003...
UPDATE: During lunch today I've just backed out the rotation changes and in preparation for the new scheme, moved the Space Invaders video memory (buffer) from $0000 to $2000. I had to fix a couple of latent bugs that weren't apparent when the video memory was based at $0000.
I've also had an idea; now that I'm re-rendering from the original video RAM to the Coco3 display, it should be relatively simple to change to 2BPP and add colour at the same time - effectively killing two birds with one stone!
To some extent, the original game was optimised for the rotated display; the player, the invaders and the saucer all move left/right and thus don't require the shifted rendering routine. Even worse, the shields are each offset 45 pixels from the one to the left, which means they too will require shifting.
Way back in 2003 (gosh!) I worked on what I called the Space Invaders TRS-80 'Bootleg' Project, in which I patched the arcade ROMs to run on the TRS-80 Model 4 with the aftermarket uLabs Grafyx Solution high resolution graphics board. It was only partly successful for reasons you can read about on the link if you're interested.
The strategy I took in that project was to retain all of the original rendering, but rather than render to video memory, it was rendered to an off-sceen buffer. The patches then modified each rendering routine to update the Grafyx Solution video memory, rotating each 'dirty rectangle' on-the-fly. It was much, much simpler to implement and, with a 4MHz Z80, there was enough head room for the rotation calculations. It's a pity the Grafyx Solution video bandwidth was the show-stopper.
I think it's worth at least giving it a go on the Coco3. Once the playfield has been drawn at the start of each player's turn, there's really very little rendering per frame. I'm pretty sure the 1.79MHz 6809 is up to the task, especially given the results of the profiling I did recently.
Time to dig out that Z80 code from 2003...
UPDATE: During lunch today I've just backed out the rotation changes and in preparation for the new scheme, moved the Space Invaders video memory (buffer) from $0000 to $2000. I had to fix a couple of latent bugs that weren't apparent when the video memory was based at $0000.
I've also had an idea; now that I'm re-rendering from the original video RAM to the Coco3 display, it should be relatively simple to change to 2BPP and add colour at the same time - effectively killing two birds with one stone!
Thursday, 12 May 2016
More rotation WIP
Busy with work but managed a few more updates to the rotation.
The aliens are drawn now in the correct position and orientation, as is the bottom line of the screen, the remaining bases icons and the player is sort-of but not-quite right.
As yet I haven't had to change many constants at all; most values are calculated from the original with a macro, which is nice. The main changes have been to the sprite erasing/rendering routines, for which there are about a half-dozen. These are temporary hacks until I optimise the sprite data format.
There will be a few instances where I need to patch the code so that it differs slightly from the original. For example, the saucer sprite is 24 pixels wide, with 4 zero pixels each side to negate the need for erasing it as it moves. However, the Score Advance Table draws only the middle 16 pixels; something I can't do on a rotated screen. For that matter the saucer render will have to call the shifted sprite routine, rather than the simple (non-shifted) sprite routine.
Anyway, coming along, if a little more involved than I first envisaged.
The aliens are drawn now in the correct position and orientation, as is the bottom line of the screen, the remaining bases icons and the player is sort-of but not-quite right.
As yet I haven't had to change many constants at all; most values are calculated from the original with a macro, which is nice. The main changes have been to the sprite erasing/rendering routines, for which there are about a half-dozen. These are temporary hacks until I optimise the sprite data format.
There will be a few instances where I need to patch the code so that it differs slightly from the original. For example, the saucer sprite is 24 pixels wide, with 4 zero pixels each side to negate the need for erasing it as it moves. However, the Score Advance Table draws only the middle 16 pixels; something I can't do on a rotated screen. For that matter the saucer render will have to call the shifted sprite routine, rather than the simple (non-shifted) sprite routine.
Anyway, coming along, if a little more involved than I first envisaged.
Wednesday, 11 May 2016
Rotation
Started on the rotation tonight. There is a build option to specify rotated or non-rotated screen, mainly for prosperity. To this end, I've defined a couple of macros that calculate the correct VRAM address (at assembly time) depending on the rotation option, so the code is still clean.
It's very preliminary atm. I've only rotated 8x8 pixel blocks; although sprites that are wider can be rendered (see above) they really should be reorganised to optimise rendering. That'll come later.
I've retained the 256-pixel-wide screen for now, to simplify the rotation. When it's all done, I'll change it to 320 pixels wide (hopefully just modify a macro or two) and move the scores.
Rotation of 8 & 16-pixel-wide graphics done |
It's very preliminary atm. I've only rotated 8x8 pixel blocks; although sprites that are wider can be rendered (see above) they really should be reorganised to optimise rendering. That'll come later.
I've retained the 256-pixel-wide screen for now, to simplify the rotation. When it's all done, I'll change it to 320 pixels wide (hopefully just modify a macro or two) and move the scores.
Tuesday, 10 May 2016
By popular demand - my Coco3 setup
I've been inundated with requests (at last count, at least 1) to show my development set-up. Of course all my coding and initial testing is done on my desktop PC using AS6809 and MESS, and no point showing that off. But I do have a few pictures of my Coco3 and shiny new CocoSDC.
The CocoSDC allows you to simultaneously use real floppy drives (via an MPI), disk images on a DriveWire server (eg. PC), and of course the disk images stored on the SD card. At the moment I'm just writing the Space Invaders disk image to the SD card each time, but for extended development-test cycles it's much more convenient to use a DriveWire cable (I can't find mine atm). For anyone interested in finding out more about this piece of hardware, here's the link to the homepage.
The perspex case was a limited run. I'm glad I bought one - a year before I even owned a CocoSDC - I think it looks pretty neat!
And here's my Coco3 set-up, balanced on the edge of the desk amid a rat's nest of cables. It's an '87 GIME with a Cloud-9 512KB upgrade, using low-profile SIMMs that were pulled from classic Macintosh machines. One day I'll swap it for a Triad. I'm having trouble finding a display that will work with the Coco; I've commandeered the kids' TV which was stored away for a few weeks whilst the wife paints the playroom, so I'm living on borrowed time in that respect.
There's the obligatory Dilbert mug of course, and to the right is my new EPROM eraser, atop which sits my sole remaining cartridge PCB and a handful of EPROMs that have been used to test Lode Runner, Knight Lore and now Space Invaders.
UPDATE: I've found the issue with interrupts on the real hardware! A temporary hack fixes the issue - just need to work out how to do a proper fix, and then I can release an Alpha!
UPDATE #2: Alpha release available for download.
The issue was related to GIME timer interrupts in MESS vs real hardware - seems there is a discrepancy. More details to follow.
CocoSDC Floppy Disk emulator |
The CocoSDC allows you to simultaneously use real floppy drives (via an MPI), disk images on a DriveWire server (eg. PC), and of course the disk images stored on the SD card. At the moment I'm just writing the Space Invaders disk image to the SD card each time, but for extended development-test cycles it's much more convenient to use a DriveWire cable (I can't find mine atm). For anyone interested in finding out more about this piece of hardware, here's the link to the homepage.
The perspex case was a limited run. I'm glad I bought one - a year before I even owned a CocoSDC - I think it looks pretty neat!
Coco3 running Space Invaders from the CocoSDC |
And here's my Coco3 set-up, balanced on the edge of the desk amid a rat's nest of cables. It's an '87 GIME with a Cloud-9 512KB upgrade, using low-profile SIMMs that were pulled from classic Macintosh machines. One day I'll swap it for a Triad. I'm having trouble finding a display that will work with the Coco; I've commandeered the kids' TV which was stored away for a few weeks whilst the wife paints the playroom, so I'm living on borrowed time in that respect.
There's the obligatory Dilbert mug of course, and to the right is my new EPROM eraser, atop which sits my sole remaining cartridge PCB and a handful of EPROMs that have been used to test Lode Runner, Knight Lore and now Space Invaders.
UPDATE: I've found the issue with interrupts on the real hardware! A temporary hack fixes the issue - just need to work out how to do a proper fix, and then I can release an Alpha!
UPDATE #2: Alpha release available for download.
The issue was related to GIME timer interrupts in MESS vs real hardware - seems there is a discrepancy. More details to follow.
Interrupting my debugging with CocoSDC
Firstly, more experimentation suggests the problems are related to interrupts, but still no solution atm.
Another thing I did was add code to change the palette within the two ISRs, to see how much time was being spent inside them; most of the code is actually running in either or the other. Turns out the Coco isn't even breaking a sweat on Space Invaders. The VBORD (VBLANK) interrupt is finished even before the raster gets to the 1st active line of the display (I only started to see it when I extended it with ballast code), and the TIMER (mid-screen) interrupt varies between about 7 and 15% of the frame. So no chance of missing interrupts and both sound and colour are looking good right now!
Of course, there's the minor issue of the game not running.
One observation I've made is that things move way too quickly in one half (the top half) of the screen, which suggests that perhaps the VBORD interrupt is running more often than it should - which could happen if it isn't acknowledged properly.
Anyway, erasing and burning EPROMs is simply way too painful when debugging code, so I finally bit the bullet and assembled my CocoSDC (bought the case in Nov 2014, the PCB in Nov 2015). And I'm happy to say that the disk version of Space Invaders runs as expected. As does Lode Runner and Knight Lore, with the exception of a glitch on the text-mode splash screens which, oddly, isn't present on the cartridge version.
The CocoSDC is one cool piece of kit!
Another thing I did was add code to change the palette within the two ISRs, to see how much time was being spent inside them; most of the code is actually running in either or the other. Turns out the Coco isn't even breaking a sweat on Space Invaders. The VBORD (VBLANK) interrupt is finished even before the raster gets to the 1st active line of the display (I only started to see it when I extended it with ballast code), and the TIMER (mid-screen) interrupt varies between about 7 and 15% of the frame. So no chance of missing interrupts and both sound and colour are looking good right now!
Of course, there's the minor issue of the game not running.
One observation I've made is that things move way too quickly in one half (the top half) of the screen, which suggests that perhaps the VBORD interrupt is running more often than it should - which could happen if it isn't acknowledged properly.
Anyway, erasing and burning EPROMs is simply way too painful when debugging code, so I finally bit the bullet and assembled my CocoSDC (bought the case in Nov 2014, the PCB in Nov 2015). And I'm happy to say that the disk version of Space Invaders runs as expected. As does Lode Runner and Knight Lore, with the exception of a glitch on the text-mode splash screens which, oddly, isn't present on the cartridge version.
The CocoSDC is one cool piece of kit!
Sunday, 8 May 2016
This is the last bug (said every software engineer ever)
At one point during the port I had to disable (skip) the demo mode because bugs at the time would cause it to crash which of course hampered debugging of the splash animations for one, and also the game play indirectly. Being so focused on completing the game play, I'd completely forgotten about this and when I re-enabled it today, I was reminded of the bug where the player base just moves to the right side of the screen and sits there.
Fortunately it took about 2 minutes to find and fix; yet another endianity bug in a small block of data that is copied to RAM on start-up, that had slipped under the radar, it not being commented in the disassembly. So bug #13 done and dusted.
Rather than pursue the elusive 2-player issue right now, I decided to get the disk version working and add appropriate splash screen and README.TXT content. So the minute I fix what I firmly believe is the final bug, and test on real hardware, I can release an Alpha for general consumption.
Stay tuned, we'll be back shortly.
UPDATE: My daughter wanted to play horse Duplo with my wife, so I snuck away and managed to find the last bug - a register value that was being overwritten by 6809-specific implementation. That register contained the delta-x value for moving the invaders, which should have been either +/-2, but was overwritten with -4 every time (I didn't notice). Hence the invaders not wiping properly. Bug #14 squashed.
Now to fire up my brand new, as-yet unused EPROM eraser and see if it runs on real hardware!
UPDATE #2: I actually found a blank EPROM so no waiting for the eraser, but an unexpected result. The game runs, but the invaders aren't firing back at all, and it seems the player's shot is too fast. Reminds me of an earlier observation during the porting process. Interesting... without looking into it, I do have one guess.
UPDATE #3: Well my theory on why it's not running on real hardware didn't pan out, so right now I'm stumped. Mind you, I've spent about 2 minutes looking at it, so I likely haven't exhausted all avenues just yet. I'll need to spend at least another 2 minutes before I get to that point...
Fortunately it took about 2 minutes to find and fix; yet another endianity bug in a small block of data that is copied to RAM on start-up, that had slipped under the radar, it not being commented in the disassembly. So bug #13 done and dusted.
Rather than pursue the elusive 2-player issue right now, I decided to get the disk version working and add appropriate splash screen and README.TXT content. So the minute I fix what I firmly believe is the final bug, and test on real hardware, I can release an Alpha for general consumption.
Stay tuned, we'll be back shortly.
UPDATE: My daughter wanted to play horse Duplo with my wife, so I snuck away and managed to find the last bug - a register value that was being overwritten by 6809-specific implementation. That register contained the delta-x value for moving the invaders, which should have been either +/-2, but was overwritten with -4 every time (I didn't notice). Hence the invaders not wiping properly. Bug #14 squashed.
Now to fire up my brand new, as-yet unused EPROM eraser and see if it runs on real hardware!
UPDATE #2: I actually found a blank EPROM so no waiting for the eraser, but an unexpected result. The game runs, but the invaders aren't firing back at all, and it seems the player's shot is too fast. Reminds me of an earlier observation during the porting process. Interesting... without looking into it, I do have one guess.
UPDATE #3: Well my theory on why it's not running on real hardware didn't pan out, so right now I'm stumped. Mind you, I've spent about 2 minutes looking at it, so I likely haven't exhausted all avenues just yet. I'll need to spend at least another 2 minutes before I get to that point...
It's Game Over - thankfully!
Literally 10 minutes to work on Space Invaders thus far this weekend, but I did manage to squash bug #12 - the 2-player game not ending. A simple case of using STA instead of CLR.
I think that just leaves the one bug (lucky #13) now; invaders not being erased properly when player 1 or 2 game is restored. At this point I don't have a theory for the cause of the problem, I simply can't think of what bug could manifest itself in this way. Would be ironic, if not really frustrating, if this one (#13) proved elusive for the next few days.
Once this is fixed, and there aren't any further apparent bugs, I'll get the disk image running properly, test it on real hardware, and release an 'alpha' version that people can try just to get a feel for what they can expect on the Coco3 once I rotate the screen.
I've been thinking about the sound support lately and will have to do some research on whether samples, or pre-rendered waveforms (or possibly both) are the way to go. I purposefully coded all the sound routines whilst porting to the Coco3 - short of the actual port I/O - to better facilitate adding sound. On the arcade hardware, the port I/O simply turns on/off each of the discrete sound circuits, so they'll need to be replaced with flags in RAM.
I think that just leaves the one bug (lucky #13) now; invaders not being erased properly when player 1 or 2 game is restored. At this point I don't have a theory for the cause of the problem, I simply can't think of what bug could manifest itself in this way. Would be ironic, if not really frustrating, if this one (#13) proved elusive for the next few days.
Once this is fixed, and there aren't any further apparent bugs, I'll get the disk image running properly, test it on real hardware, and release an 'alpha' version that people can try just to get a feel for what they can expect on the Coco3 once I rotate the screen.
I've been thinking about the sound support lately and will have to do some research on whether samples, or pre-rendered waveforms (or possibly both) are the way to go. I purposefully coded all the sound routines whilst porting to the Coco3 - short of the actual port I/O - to better facilitate adding sound. On the arcade hardware, the port I/O simply turns on/off each of the discrete sound circuits, so they'll need to be replaced with flags in RAM.
Friday, 6 May 2016
1's company, 2's a crowd!
Another lunch break, another bug fixed. I decided to look at the invader shot frequency since I was getting nowhere with the 2-player game issues, and it was yet another endianity issue. The shot frequency is dependent on the MSB of the player's score; having swapped the endianity for all 16-bit values on the 6809, it was looking at the LSB. Bug #11 down.
As far as I can tell, the single player game is now complete and running 100%. So there's just the 2-player game that has issues; I know of one, possibly two different bugs.
Hopefully, an alpha release is imminent!
As far as I can tell, the single player game is now complete and running 100%. So there's just the 2-player game that has issues; I know of one, possibly two different bugs.
Hopefully, an alpha release is imminent!
Thursday, 5 May 2016
One step forward, two steps back
Lunchtime bug fix #8, the game crashing after player 1 dies in a 2-player game. There was an issue with the routine that remembers the shields; the game progresses to player 2 now.
However, after player 2 dies, player 1 subsequently dies immediately and their game ends, printing the "GAME OVER" message on the wrong row of the screen. And ditto then for player 2. We'll call these bugs #10 & #11... so currently 8 down, 3 to go.
UPDATE: Well, I guess I've never actually played 2-players on Space Invaders before; turns out the "GAME OVER" message is actually printed at the correct position on the screen; below the shields! What was in the wrong position though, was the bottom line, because the byte value was hard-coded in-line, and I hadn't reversed the bits for it.
So replacing bug #11 with an actual bug (fixed), that's 9 down, 2 (at least) to go! Now to find out why the 2-player game isn't working properly...
UPDATE #2: Again, fixed bug #10 and bug #12 appears - when player 1 starts up after player 2 dies, the invaders aren't erased properly, and eventually the game resets. 10 down, 2 (still) to go. I suspect there's at least one more bug - the 2-player game never ends even after players run out of bases. Could be parasitic to one of the two remaining bugs, but probably not.
Once the two-player game is working, and it's very close now, it's just the bomb frequency, and there's a routine specifically for that. Agonisingly close now!
However, after player 2 dies, player 1 subsequently dies immediately and their game ends, printing the "GAME OVER" message on the wrong row of the screen. And ditto then for player 2. We'll call these bugs #10 & #11... so currently 8 down, 3 to go.
UPDATE: Well, I guess I've never actually played 2-players on Space Invaders before; turns out the "GAME OVER" message is actually printed at the correct position on the screen; below the shields! What was in the wrong position though, was the bottom line, because the byte value was hard-coded in-line, and I hadn't reversed the bits for it.
So replacing bug #11 with an actual bug (fixed), that's 9 down, 2 (at least) to go! Now to find out why the 2-player game isn't working properly...
UPDATE #2: Again, fixed bug #10 and bug #12 appears - when player 1 starts up after player 2 dies, the invaders aren't erased properly, and eventually the game resets. 10 down, 2 (still) to go. I suspect there's at least one more bug - the 2-player game never ends even after players run out of bases. Could be parasitic to one of the two remaining bugs, but probably not.
Once the two-player game is working, and it's very close now, it's just the bomb frequency, and there's a routine specifically for that. Agonisingly close now!
Wednesday, 4 May 2016
Bonus bugs!
Well my prediction of a half-dozen bugs is looking pretty shaky already. I've had to fix three (3) bugs just to get the saucer to appear, and in the correct position. Then for the first hit of the saucer I got 300 pts (dubious), and for the next hit I got "CLE" points. That'll be bug #4 already...
UPDATE: Bug #4 squashed. Saucer working now.
UPDATE #2: Bug #5 - 2nd and subsequent waves of aliens not appearing in the correct position - squashed at lunchtime. Next bug - extra alien added when player dies.
UPDATE #3: Couldn't help myself, squeezed in another two bug fixes before finishing lunch.
Bug #6 - extra alien added when player dies, as mentioned above, fixed.
Bug #7 - bonus ship icon not displayed, also fixed.
Next bug - program freezes on 2 player game after player 1 dies.
Another bug I've noticed - and I can't explain how it's even possible - the invaders are dropping 3 and (I think) even 4 bombs at a time!?! IIUC there's only provision in the code for two at any one time!?! Certainly an interesting one, and the game is definitely more difficult because of it!
So we're at 9 bugs now, although I'm not aware of any others, so it's close!
UPDATE: Bug #4 squashed. Saucer working now.
UPDATE #2: Bug #5 - 2nd and subsequent waves of aliens not appearing in the correct position - squashed at lunchtime. Next bug - extra alien added when player dies.
UPDATE #3: Couldn't help myself, squeezed in another two bug fixes before finishing lunch.
Bug #6 - extra alien added when player dies, as mentioned above, fixed.
Bug #7 - bonus ship icon not displayed, also fixed.
Next bug - program freezes on 2 player game after player 1 dies.
Another bug I've noticed - and I can't explain how it's even possible - the invaders are dropping 3 and (I think) even 4 bombs at a time!?! IIUC there's only provision in the code for two at any one time!?! Certainly an interesting one, and the game is definitely more difficult because of it!
So we're at 9 bugs now, although I'm not aware of any others, so it's close!
Tuesday, 3 May 2016
Space Invaders in 6809. Now with added bugs.
At lunchtime today I dug in and managed to finish porting the remaining 8080 code to 6809.
There are a number of bugs that make the game less playable than it was in the past, but I'm hoping there's nothing too difficult to track down. That said, it'll probably take a few nights of debugging to get it running 100% correctly.
In the process I'll clean up a few 'nasty' bits of code to make it a bit more relocatable on the Coco; as-is the data - both in ROM and in RAM - is byte-for-byte aligned with the original. That's something that I won't be able to preserve when I rotate the graphics, so I need to make sure it's not going to break when it's not aligned.
Hopefully the next update will be reporting a flawless port!
UPDATE: Well not flawless yet, but much improved. If I absolutely had to guess, I'd say about a half-dozen more bugs to find and fix (I can count 4 off the top of my head) - the game is so simple that most of the bugs should show themselves quite readily.
Fixed a few bugs in the invaders firing and high score calculations. The game crashes now; I suspect at the point that the saucer is to appear (I've yet to see it!)
Added dipswitches - currently build options - but they do work. I'll likely add them to the Coco3 splash screen before the game is launched. Also added the TILT input, which can be initiated on the Coco3 using the <CTRL><BREAK> keyboard combination - to be used for rage-quitting!
There are a number of bugs that make the game less playable than it was in the past, but I'm hoping there's nothing too difficult to track down. That said, it'll probably take a few nights of debugging to get it running 100% correctly.
In the process I'll clean up a few 'nasty' bits of code to make it a bit more relocatable on the Coco; as-is the data - both in ROM and in RAM - is byte-for-byte aligned with the original. That's something that I won't be able to preserve when I rotate the graphics, so I need to make sure it's not going to break when it's not aligned.
Hopefully the next update will be reporting a flawless port!
UPDATE: Well not flawless yet, but much improved. If I absolutely had to guess, I'd say about a half-dozen more bugs to find and fix (I can count 4 off the top of my head) - the game is so simple that most of the bugs should show themselves quite readily.
Fixed a few bugs in the invaders firing and high score calculations. The game crashes now; I suspect at the point that the saucer is to appear (I've yet to see it!)
Added dipswitches - currently build options - but they do work. I'll likely add them to the Coco3 splash screen before the game is launched. Also added the TILT input, which can be initiated on the Coco3 using the <CTRL><BREAK> keyboard combination - to be used for rage-quitting!
Monday, 2 May 2016
Bug fixes that don't!
If there's one thing that I really hate, it's when you finally track down a bug, say to yourself "Ah ha - that would explain it!", duly fix it... and then the bug is still there. Happened to me (again) with the column firing. Having said that, it's better than before (so I did actually fix something) but still not quite right.
And speaking of bugs, in the process of trying to fix the aforementioned, it dawned on me that my shadow Z80 registers - stored in Direct Page memory - weren't preserved when interrupts fired! Fortunately there wasn't much else stored in that memory, so it was a simple matter of changing DP when entering and exiting from an interrupt service routine. Something that wasn't an issue in Knight Lore, for example, as there were no interrupts!
Frustrated with alien firing bugs, I instead implemented the player being destroyed. So now you can start a game that actually does end. At last count there were at least three (3) known bugs - none too major - but at least I've almost ported all the code to 6809. In fact, I'm tempted just to press on and complete the porting process before even attempting to fix any but the most obvious-to-fix bugs...
I've hit 4,000 lines in the source file now, and there really can't be much left; mainly to do with the saucer and I can't think of much else.
Ocne the porting and debugging is done, I need to rotate the screen. That process is going to be a little more involved than I first imagined, but still not too daunting. I am going to attempt to have the screen rotation as a build option, rather than completely abandon the non-rotated screen.
Then there's the issue of 2BPP colour, and then sound & joystick support...
And speaking of bugs, in the process of trying to fix the aforementioned, it dawned on me that my shadow Z80 registers - stored in Direct Page memory - weren't preserved when interrupts fired! Fortunately there wasn't much else stored in that memory, so it was a simple matter of changing DP when entering and exiting from an interrupt service routine. Something that wasn't an issue in Knight Lore, for example, as there were no interrupts!
Frustrated with alien firing bugs, I instead implemented the player being destroyed. So now you can start a game that actually does end. At last count there were at least three (3) known bugs - none too major - but at least I've almost ported all the code to 6809. In fact, I'm tempted just to press on and complete the porting process before even attempting to fix any but the most obvious-to-fix bugs...
I've hit 4,000 lines in the source file now, and there really can't be much left; mainly to do with the saucer and I can't think of much else.
Ocne the porting and debugging is done, I need to rotate the screen. That process is going to be a little more involved than I first imagined, but still not too daunting. I am going to attempt to have the screen rotation as a build option, rather than completely abandon the non-rotated screen.
Then there's the issue of 2BPP colour, and then sound & joystick support...
Saturday, 30 April 2016
Your bullets cannot harm me...
... my wings are like a shield of steel! (Plus I haven't implemented the player blowing up!)
Fixed the scoring and added the two object handlers for the two invader shots/bombs.
As-is, the invaders aren't shooting from the correct columns, and they're only shooting one type of bomb or the other at any one time, but it's close and gives an idea of how the game will play - which is, of course, very much like the arcade original! :)
There can't be too much code left to port - neither of the two new object handlers required any new subroutines to be coded! Most of what's left involves the player blowing up and the saucer.
I would probably have been more productive tonight, but I'm working on my laptop, perched on the breakfast bench whilst my wife makes a "camel" cake for my daughter's 4th birthday party tomorrow. We have absolutely no idea why she asked for a camel cake, but a camel cake it is. If you haven't guessed, she's not a fairy princess type of girl, which is pretty cool if you ask me!
The invaders are firing back now - not fair! |
Fixed the scoring and added the two object handlers for the two invader shots/bombs.
As-is, the invaders aren't shooting from the correct columns, and they're only shooting one type of bomb or the other at any one time, but it's close and gives an idea of how the game will play - which is, of course, very much like the arcade original! :)
There can't be too much code left to port - neither of the two new object handlers required any new subroutines to be coded! Most of what's left involves the player blowing up and the saucer.
I would probably have been more productive tonight, but I'm working on my laptop, perched on the breakfast bench whilst my wife makes a "camel" cake for my daughter's 4th birthday party tomorrow. We have absolutely no idea why she asked for a camel cake, but a camel cake it is. If you haven't guessed, she's not a fairy princess type of girl, which is pretty cool if you ask me!
Friday, 29 April 2016
Like fish in a barrel
Managed to fix a few little bugs at lunchtime today. They've all been quite subtle; another carry flag bug plus a case of me using the 6809 TST instruction where the 8080 code expected A to hold the value after the test. Fortunately (well, in most cases it's fortunate) the 6809 LD instruction affects the zero flag so it was a simple case of changing the opcode.
Aside from the shot speed, one of the other bugs I fixed was the damage done to the shields when shot by the player. Turned out that I hadn't reversed the pixel data for the shot sprite or the explosion. That's sorted now and the shields are destroyed in exactly the same way - pixel-for-pixel - as the original.
Both the player laser base (object 0) and player shot (object 1) handlers are still incomplete; the player doesn't blow up and the shot doesn't affect the saucer score or timing. However I'll press on and implement the first of the alien bombs, the so-called "plunger" shot. Once that's done and I've implemented the player being hit, the game will be somewhat 'playable'.
EDIT: I've just realised that I'm not updating the score.. I might tackle that next.
UPDATE: Scoring happens (was implemented, but a bug meant nothing happened) but now you don't get the right score for each alien. It'll have to wait until another time.
Aside from the shot speed, one of the other bugs I fixed was the damage done to the shields when shot by the player. Turned out that I hadn't reversed the pixel data for the shot sprite or the explosion. That's sorted now and the shields are destroyed in exactly the same way - pixel-for-pixel - as the original.
Both the player laser base (object 0) and player shot (object 1) handlers are still incomplete; the player doesn't blow up and the shot doesn't affect the saucer score or timing. However I'll press on and implement the first of the alien bombs, the so-called "plunger" shot. Once that's done and I've implemented the player being hit, the game will be somewhat 'playable'.
EDIT: I've just realised that I'm not updating the score.. I might tackle that next.
UPDATE: Scoring happens (was implemented, but a bug meant nothing happened) but now you don't get the right score for each alien. It'll have to wait until another time.
Thursday, 28 April 2016
Ready, Player One!
All the stub game object handler routines are in place so the game task scheduler can run.
Added game object #0 - the player. You can coin up, start a game and move left/right. For some reason the demo doesn't appear to be working properly yet - the laser base just moves to the right hand side of the screen - despite the code having being ported.
I need to finish off the player handler (blowing up), then there's four more handlers; player shot, so-called alien rolling shot, so-called alien plunger shot, and finally the handler that does both the squiggly shot in attract mode and the saucer. And that's pretty much the bulk of the code ported!
Can you believe that there's only ever two (2) alien shots on the screen at any time!?! A far cry from the modern bullet-hell schmups - yet the game is still challenging!
UPDATE: You can shoot and destroy invaders. The player shots are too fast though, so they eat through the shields and fly up the screen about twice as fast as they should, by my reckoning.
Added game object #0 - the player. You can coin up, start a game and move left/right. For some reason the demo doesn't appear to be working properly yet - the laser base just moves to the right hand side of the screen - despite the code having being ported.
A game in action, sans bullets/bombs |
I need to finish off the player handler (blowing up), then there's four more handlers; player shot, so-called alien rolling shot, so-called alien plunger shot, and finally the handler that does both the squiggly shot in attract mode and the saucer. And that's pretty much the bulk of the code ported!
Can you believe that there's only ever two (2) alien shots on the screen at any time!?! A far cry from the modern bullet-hell schmups - yet the game is still challenging!
UPDATE: You can shoot and destroy invaders. The player shots are too fast though, so they eat through the shields and fly up the screen about twice as fast as they should, by my reckoning.
Like shooting fish in a barrel - when they don't fire back! |
Wednesday, 27 April 2016
What a difference a flag makes.
When porting between CPUs, some differences are more subtle than others, and can be the cause of some hard-to-find bugs. A case in point is the routine that determines whether the invaders have reached the side of the screen, and need to drop down and change direction.
[An aside here: the game checks this by examining a scan line of pixels at the left or right edge of the screen; any non-zero pixels means the invaders have hit the edge. Tandy Invaders, written originally for the 4KB TRS-80 Model I, and which I reverse-engineered not too long ago to port to the Microbee, does exactly the same. I recall thinking at the time that it was a funny - if not slightly dodgy - way of doing things. Turns out the Real Deal uses exactly the same method. Oops!]
Back to subtle bugs - the routine that checks the above-mentioned line of pixels explicitly sets the carry flag if a non-zero pixel has been detected. Otherwise it simply returns once the scan line has been checked. It should be noted that each time through the loop, it executes the AND A instruction to test for pixels, which incidentally clears the carry flag.
In my porting, I negate the need to load and subsequently test the video memory byte by simply using TST ,X - a nice little 6809 optimisation - except for the fact that it doesn't affect the carry flag. In fact, none of the instructions in the entire routine affected the carry flag. So I was getting the invaders oscillating one step the the left, then right, as they quickly marched down the screen. Of course the fix was to simply clear the carry at the start of the routine.
Knight Lore had a few routines that used the carry flag to signal various conditions, and I was careful to ensure that the 6809 code did the same. However for some reason I found this particular instance to be more subtle, and hence harder to debug.
So with the invaders marching in the demo now it's time to add the player. But first, there's the minor matter of the game crashing when you coin up and start an actual game...
UPDATE: You can now coin up and start a game; it draws the invaders and they start marching across the screen as they should. The main game (background) loop is running, albeit with a few subroutine calls commented-out as they have yet to be ported. Nothing particularly exciting in there.
Next step is to add the handlers for the missing game objects; first on the list is the player. The player laser base should then appear and be able to move and shoot! That'll be the next blog update.
[An aside here: the game checks this by examining a scan line of pixels at the left or right edge of the screen; any non-zero pixels means the invaders have hit the edge. Tandy Invaders, written originally for the 4KB TRS-80 Model I, and which I reverse-engineered not too long ago to port to the Microbee, does exactly the same. I recall thinking at the time that it was a funny - if not slightly dodgy - way of doing things. Turns out the Real Deal uses exactly the same method. Oops!]
Back to subtle bugs - the routine that checks the above-mentioned line of pixels explicitly sets the carry flag if a non-zero pixel has been detected. Otherwise it simply returns once the scan line has been checked. It should be noted that each time through the loop, it executes the AND A instruction to test for pixels, which incidentally clears the carry flag.
In my porting, I negate the need to load and subsequently test the video memory byte by simply using TST ,X - a nice little 6809 optimisation - except for the fact that it doesn't affect the carry flag. In fact, none of the instructions in the entire routine affected the carry flag. So I was getting the invaders oscillating one step the the left, then right, as they quickly marched down the screen. Of course the fix was to simply clear the carry at the start of the routine.
Knight Lore had a few routines that used the carry flag to signal various conditions, and I was careful to ensure that the 6809 code did the same. However for some reason I found this particular instance to be more subtle, and hence harder to debug.
So with the invaders marching in the demo now it's time to add the player. But first, there's the minor matter of the game crashing when you coin up and start an actual game...
UPDATE: You can now coin up and start a game; it draws the invaders and they start marching across the screen as they should. The main game (background) loop is running, albeit with a few subroutine calls commented-out as they have yet to be ported. Nothing particularly exciting in there.
Next step is to add the handlers for the missing game objects; first on the list is the player. The player laser base should then appear and be able to move and shoot! That'll be the next blog update.
Tuesday, 26 April 2016
Invaders... from space...
Haven't been able to spend a lot of time on Space Invaders lately (long weekend here) but tonight I finally got the invaders displaying in the demo mode!
In the process I've had to add the 2nd interrupt - an 8.3ms timer that is started in the VBLANK interrupt - that should (in theory) interrupt somewhere around scan line 96. I haven't checked exactly where that's happening yet, due in part to the fact that the 'BEAMY' value in MESS at the start of the VBLANK ISR increments every frame!!! Taking that into consideration though, the TIMER interrupt appears to be happening around 120 scan lines earlier, which is a good thing.
Now if I could only get someone on MESSDEV to give two hoots about it...
Something else that only sunk in tonight... non-bit-shifted rendering routines use the CPU address map value of the target video byte when referencing display positions. Such values appear in tables and hard-coded throughout the code. OTOH, potentially bit-shifted routines use the pixel offset - but offset not from the start of the video memory as you'd expect, but rather from the start of all RAM. That threw me for a while when trying to work out how to get the invaders to display correctly. Not sure how I got the animated squigggly alien shot to work in the splash animation though...
And this coupled with the endianity changes can do your head in a bit when debugging.
The source file is around 3,300 lines now. Most of the core code has been ported and what remains is mostly concerned with the player movement & firing, invader bombs and the saucer. I've still got plenty of debugging to do in the code I have ported, let alone what's left. But with both ISR's in place, I'm not expecting any major roadblocks.
The demo mode display, finally. A lot of code ported to get here. |
In the process I've had to add the 2nd interrupt - an 8.3ms timer that is started in the VBLANK interrupt - that should (in theory) interrupt somewhere around scan line 96. I haven't checked exactly where that's happening yet, due in part to the fact that the 'BEAMY' value in MESS at the start of the VBLANK ISR increments every frame!!! Taking that into consideration though, the TIMER interrupt appears to be happening around 120 scan lines earlier, which is a good thing.
Now if I could only get someone on MESSDEV to give two hoots about it...
Something else that only sunk in tonight... non-bit-shifted rendering routines use the CPU address map value of the target video byte when referencing display positions. Such values appear in tables and hard-coded throughout the code. OTOH, potentially bit-shifted routines use the pixel offset - but offset not from the start of the video memory as you'd expect, but rather from the start of all RAM. That threw me for a while when trying to work out how to get the invaders to display correctly. Not sure how I got the animated squigggly alien shot to work in the splash animation though...
And this coupled with the endianity changes can do your head in a bit when debugging.
The source file is around 3,300 lines now. Most of the core code has been ported and what remains is mostly concerned with the player movement & firing, invader bombs and the saucer. I've still got plenty of debugging to do in the code I have ported, let alone what's left. But with both ISR's in place, I'm not expecting any major roadblocks.
Sunday, 24 April 2016
Feeling shifty...
Quick update. Splash animations both working. Hardware shift register emulated and working (using Knight Lore tables verbatim). Not much overhead doing it on the 6809, especially considering the shift value is only written once per sprite.
Working through the code that initialises the game for the demo mode. That will likely entail writing almost all the the remaining code once the demo is fully working. I'm not quite to the point where the rack (aliens) is displayed. I'll post some eye candy once I'm there.
On a side note; Brian White has confirmed the Lode Runner Demo cartridge image runs on a stock 128K Coco3. And Knight Lore has been seen - by some at least - at CocoFEST. It'll be time to whip those into shape for cartridge production in the not-too-distant future!
Working through the code that initialises the game for the demo mode. That will likely entail writing almost all the the remaining code once the demo is fully working. I'm not quite to the point where the rack (aliens) is displayed. I'll post some eye candy once I'm there.
On a side note; Brian White has confirmed the Lode Runner Demo cartridge image runs on a stock 128K Coco3. And Knight Lore has been seen - by some at least - at CocoFEST. It'll be time to whip those into shape for cartridge production in the not-too-distant future!
Friday, 22 April 2016
Cosmetics
Again, I've been forging through the code to get the attract screens animated. The first one - where the invader replaces the upside-down 'Y' in 'PLAY' - is complete. The second - where the invader shoots the extra 'C' in 'COIN' - is (finally) coded but not debugged.
To give you an idea of how much code is involved just to get these animations done, the Coco3 ROM image is now more than half the size of the arcade ROM! The source file is now just shy of 3,000 lines, though it includes the comments from the Computer Archeology disassembly (for the code that has been ported) plus data. Taking a quick look at the listing though, I'd say I've definitely completed more than half of the code, if not somewhere approaching two-thirds!
Of course that's not to say that half of the code is concerned with attract screen animations. Aside from the expected low-level print/render routines etc, much of the framework needs to be in-place to allow the task scheduler to run - which controls the animations - and also control the alien shot (bomb) which is treated much like an in-game shot. So in theory, once I debug the 2nd attract animation, a lot of the hard work will have been done, and the rest of the port should go relatively smoothly.
An aside: it's funny how you don't notice things until you're developing/debugging... when the alien replaces the 'Y' it's actually 1 pixel too close to 'PLA' and once you are aware of it, it sticks out like a sore thumb!
UPDATE: First of all, I've (finally) fixed the timezone on the blog.
Tonight has been all about debugging the 2nd animation, and I've managed to more-or-less get it working. However it doesn't exit the task when the 'C' has been bombed, so it sits in a loop executing the same task, but doing nothing. At this point I can't find the code that exits the task or, more specifically, I can't find where it would be called from that task. For another day.
One issue that permeates the code is endianity. There's a bunch of tables that store 16-bit values, a lot of which are accessed via both 8-bit and 16-bit operations. And to further complicate matters, a lot of them are initialised from blocks of data in ROM - sometimes multiple blocks depending on game logic. I need to swap the byte order (labels) in the tables (for 16-bit accesses), adjust the ROM values accordingly, and then inspect each code reference to decide whether or not the code also needs to be modified. Note also that some of these data sections in the disassembly are not commented.
And as I've mentioned previously, the dependence on variable addresses is ghastly.
Once I debug this last animation, I'll need to implement a software emulation of the hardware shift register to see accurate graphics, even in the attract screens. Just like Knight Lore, I'll build shift tables in memory, though the layout will be optimised specifically for Space Invaders.
To give you an idea of how much code is involved just to get these animations done, the Coco3 ROM image is now more than half the size of the arcade ROM! The source file is now just shy of 3,000 lines, though it includes the comments from the Computer Archeology disassembly (for the code that has been ported) plus data. Taking a quick look at the listing though, I'd say I've definitely completed more than half of the code, if not somewhere approaching two-thirds!
Of course that's not to say that half of the code is concerned with attract screen animations. Aside from the expected low-level print/render routines etc, much of the framework needs to be in-place to allow the task scheduler to run - which controls the animations - and also control the alien shot (bomb) which is treated much like an in-game shot. So in theory, once I debug the 2nd attract animation, a lot of the hard work will have been done, and the rest of the port should go relatively smoothly.
An aside: it's funny how you don't notice things until you're developing/debugging... when the alien replaces the 'Y' it's actually 1 pixel too close to 'PLA' and once you are aware of it, it sticks out like a sore thumb!
UPDATE: First of all, I've (finally) fixed the timezone on the blog.
Tonight has been all about debugging the 2nd animation, and I've managed to more-or-less get it working. However it doesn't exit the task when the 'C' has been bombed, so it sits in a loop executing the same task, but doing nothing. At this point I can't find the code that exits the task or, more specifically, I can't find where it would be called from that task. For another day.
One issue that permeates the code is endianity. There's a bunch of tables that store 16-bit values, a lot of which are accessed via both 8-bit and 16-bit operations. And to further complicate matters, a lot of them are initialised from blocks of data in ROM - sometimes multiple blocks depending on game logic. I need to swap the byte order (labels) in the tables (for 16-bit accesses), adjust the ROM values accordingly, and then inspect each code reference to decide whether or not the code also needs to be modified. Note also that some of these data sections in the disassembly are not commented.
And as I've mentioned previously, the dependence on variable addresses is ghastly.
Once I debug this last animation, I'll need to implement a software emulation of the hardware shift register to see accurate graphics, even in the attract screens. Just like Knight Lore, I'll build shift tables in memory, though the layout will be optimised specifically for Space Invaders.
Wednesday, 20 April 2016
Not winning any coding awards...
I've been forging through all the code that is called as part of the demo and/or attract modes from the main line execution path. The only trouble is, I can't actually test any of it because it's all kicked off by events created in the ISR's which currently don't exist except for a simple countdown timer used for delay loops. But at least I know it assembles.
Along the way I coded the attract mode Easter Egg, which I'd completely forgotten about; if you haven't seen it, it's not very exciting at all. I did read that you can't actually trigger it in MAME due to the manner in which the input controls are sampled - so that's one thing the Coco3 port will have over MAME!
As others have noted before me, I would have to agree that Space Invaders doesn't exactly showcase the highest quality of 8080 coding. For example, some of the logic depends on variables being at particular addresses, so simply changing the .org statement in the .ASM file, or even adding or moving variables around, would actually break the code! The dilemma for me is, do I fix these issues, or faithfully reproduce them? Right now my memory map is purposefully identical right down to the byte level, so it makes no difference. But I still have half a mind to do it properly, even if I document the way it was done originally in the source.
It's pretty obvious the assembler they used was quite primitive - if indeed they used one at all! In fact, it wouldn't surprise me if they didn't use one. There's certainly evidence that at least some of the code was patched, rather than re-assembled, although that could have been done only to negate the need to re-image all of the discrete ROM chips.
Now to the interrupts...
UPDATE: You can add a coin. Just one coin for some reason atm...
Along the way I coded the attract mode Easter Egg, which I'd completely forgotten about; if you haven't seen it, it's not very exciting at all. I did read that you can't actually trigger it in MAME due to the manner in which the input controls are sampled - so that's one thing the Coco3 port will have over MAME!
As others have noted before me, I would have to agree that Space Invaders doesn't exactly showcase the highest quality of 8080 coding. For example, some of the logic depends on variables being at particular addresses, so simply changing the .org statement in the .ASM file, or even adding or moving variables around, would actually break the code! The dilemma for me is, do I fix these issues, or faithfully reproduce them? Right now my memory map is purposefully identical right down to the byte level, so it makes no difference. But I still have half a mind to do it properly, even if I document the way it was done originally in the source.
It's pretty obvious the assembler they used was quite primitive - if indeed they used one at all! In fact, it wouldn't surprise me if they didn't use one. There's certainly evidence that at least some of the code was patched, rather than re-assembled, although that could have been done only to negate the need to re-image all of the discrete ROM chips.
Now to the interrupts...
UPDATE: You can add a coin. Just one coin for some reason atm...
Tuesday, 19 April 2016
One timely interruption
Not a lot of time to work on Space Invaders over the last few days, but coming along nicely. I definitely think I'd like to finish it now before returning to Knight Lore.
As-is it loops through the attract screens, complete with punctuated text rendering, although the animations (involving the little invader) are yet to be coded. The demo displays the shields and the line across the bottom of the screen before continuing onto the attract mode.
Source, including data, is around 1,500 lines already. In comparison, the IDA disassembly of the arcade original Z80 code is around 4,200 lines. The translation from 8080 to 6809 has been quite straightforward thus far; I'm using a fairly strict register mapping convention and I've only been forced to use shadow memory registers (for BC) once or twice.
The game uses interrupts heavily, having two (60Hz) interrupts on specific scan lines which drive most of the game logic. I've only enabled one of them - line 224 which is effectively the VBLANK interrupt - and it simply decrements a timer counter (used in the attract mode) at this point.
Rather than attempt to use a HBLANK interrupt and count scan lines for the other interrupt, I'll start the timer in the VBLANK interrupt. The exact timing of the second interrupt isn't critical so it should be accurate enough for the code to run without any noticeable difference.
Once I finish the portions of the attract mode that aren't interrupt-driven, I'll have to start fleshing out the ISR's to see anything else happen.
As-is it loops through the attract screens, complete with punctuated text rendering, although the animations (involving the little invader) are yet to be coded. The demo displays the shields and the line across the bottom of the screen before continuing onto the attract mode.
Source, including data, is around 1,500 lines already. In comparison, the IDA disassembly of the arcade original Z80 code is around 4,200 lines. The translation from 8080 to 6809 has been quite straightforward thus far; I'm using a fairly strict register mapping convention and I've only been forced to use shadow memory registers (for BC) once or twice.
The game uses interrupts heavily, having two (60Hz) interrupts on specific scan lines which drive most of the game logic. I've only enabled one of them - line 224 which is effectively the VBLANK interrupt - and it simply decrements a timer counter (used in the attract mode) at this point.
Rather than attempt to use a HBLANK interrupt and count scan lines for the other interrupt, I'll start the timer in the VBLANK interrupt. The exact timing of the second interrupt isn't critical so it should be accurate enough for the code to run without any noticeable difference.
Once I finish the portions of the attract mode that aren't interrupt-driven, I'll have to start fleshing out the ISR's to see anything else happen.
Sunday, 17 April 2016
Space Invaders
And so it begins... with the Knight Lore ROM image emailed off to John for CocoFEST, I've decided to take a short break from filmation games until it's time to produce cartridges, in which case I'll need to look at code optimisation. However I've been in contact with another programmer who is in the final stages of porting Pentagram to the Atari 8-bit machines, and he's given me some invaluable insight into where the code can be improved. In fact, he has Pentagram running on the Atari slightly faster than the ZX Spectrum, and a lot of the code is still auto-generated from Z80 to 6502!
I was just playing around with the arcade version of Space Invaders, seeing how that would look on the Coco3. I fired up MAME and took a memory dump mid-game, played with the layout a bit, and then loaded it into the Coco3 under MESS.
It looks pretty good to me, and tonight I couldn't resist starting on an actual port. Whether or not I decide to see it through just now will depend on how quickly it proceeds in the initial stages, but if my experience with Knight Lore is any indication, it might not take long to get things well along.
I'll retain the original video memory mapping (including rotated screen) until the game is all-but-ported, to simplify the process. I've done rotation on-the-fly in my TRS-80 Model 4 'bootleg', so it's not a big deal. Running MESS with the 'rol' option will give me the correct display during development. One thing I do need to do though is bit-reverse all the graphics data, as the pixels are laid out in the reverse order within each video RAM byte.
I've also decided to work with the disassembly on Computer Archeology, rather than my own reverse-engineering, for reasons I won't bother to explain.
I'm hoping to knock this one over fairly quickly, given all the reverse-engineering has already been done and it's a relatively small - and simple - program. I'm not going to bother producing a cartridge for Space Invaders; rather I'll make disk and ROM images freely available for download.
I was just playing around with the arcade version of Space Invaders, seeing how that would look on the Coco3. I fired up MAME and took a memory dump mid-game, played with the layout a bit, and then loaded it into the Coco3 under MESS.
Space Invaders (mock up) on the Coco3 under MESS |
It looks pretty good to me, and tonight I couldn't resist starting on an actual port. Whether or not I decide to see it through just now will depend on how quickly it proceeds in the initial stages, but if my experience with Knight Lore is any indication, it might not take long to get things well along.
I'll retain the original video memory mapping (including rotated screen) until the game is all-but-ported, to simplify the process. I've done rotation on-the-fly in my TRS-80 Model 4 'bootleg', so it's not a big deal. Running MESS with the 'rol' option will give me the correct display during development. One thing I do need to do though is bit-reverse all the graphics data, as the pixels are laid out in the reverse order within each video RAM byte.
Space Invaders in 6809 (WIP) |
I've also decided to work with the disassembly on Computer Archeology, rather than my own reverse-engineering, for reasons I won't bother to explain.
I'm hoping to knock this one over fairly quickly, given all the reverse-engineering has already been done and it's a relatively small - and simple - program. I'm not going to bother producing a cartridge for Space Invaders; rather I'll make disk and ROM images freely available for download.
Friday, 15 April 2016
Bit Rot?
I thought I should bring all the C ports up-to-date today; Amiga is there and Neo Geo is all there bar the new (Mick Farrow graphics) sprite tiles being generated (ie. it has the dip-switch setting and the code just needs a simple tile bank offset to be added).
It wasn't all plain sailing though, the Neo Geo port gave me a bit of grief. Not having touched this in months, I just needed to add a few stubs for new palette routines so it would link and fire up MAME. I was a little surprised to be greeted by the cross-hatch screen. I generated a clean build, fired it up again, and same thing. The dreaded bit-rot... hmm...
After checking that the files were all being generated, and grasping at a few other straws, I decided to find out exactly what the cause of a cross-hatch screen is on the MVS. Turns out they're colour-coded, and my blue border meant that a cartridge could not be found! The only thing that could explain that under emulation would be a corrupt P1 (program) ROM.
Loading the P1 ROM into a hex editor revealed immediately that the file was all-but-blank! Time to go back and take a closer look at the compilation output. It's not easy to maintain a clean build on a multi-platform project, especially retro platforms with development toolchains that can be rather old, and as it turns out, the Neo Geo gcc (v2.95.2 circa 1999) complains quite a bit. So much so, that you tend to ignore it after a while. Examining the output more carefully revealed an assembler warning about incorrect attributes being set for .rodata in the newly-added Mick Farrow sprite graphics data arrays.
Without going into too much detail, I have needed to use section attributes to force gcc to place certain data structures into ROM - const just hasn't worked in some instances (yes I know the differences of placement). The confusing thing is, it was never an issue with the original ZX or CPC graphics arrays, and they're not significantly different to the new file. After using some Google Fu it seemed it was a known gcc bug at various times in the past, however the work-around didn't assemble in my toolchain. Again, grasping at straws, having noticed that the existing graphics files had additional arrays defined before the sprite arrays, I instantiated a dummy 1-byte array at the top of the new file and - viola - it worked! And for the record, exactly the same section attributes were still being set for the sprite data!
The whole process was probably a good hour or so.
I'm not about to ponder any further on this issue - it's not broke (anymore) so I won't fix it!
UPDATE: Mick Farrow's graphics on the Neo Geo port.
Incredibly the game now uses no less than six (6) sprite tile ROM's, not quite full but in the order of 40,000 tiles. In reality, at least half are never used by Knight Lore (ie. the VFLIP'ped versions, with the exception of a few border sprites) but at least the framework is there for the other filmation titles that may use them.
As a result, I had to find a larger host game, this time pspikes2. Basically each sprite tile ROM pair holds the sprites for an entire graphical variation. Note that Mick's panel graphics are not available (yet) as the panel is rendered on the FIX layer. I'd need to rip them and allocate another bank in the FIX ROM, which I will probably do soon.
UPDATE #2: Speaking of bit rot, in attempting to add another set of panel tiles for the Mick Farrow graphics, I've broken what was already there. I can't coax my tool into reproducing the existing panel data, let-alone a new one. Annoying...
It wasn't all plain sailing though, the Neo Geo port gave me a bit of grief. Not having touched this in months, I just needed to add a few stubs for new palette routines so it would link and fire up MAME. I was a little surprised to be greeted by the cross-hatch screen. I generated a clean build, fired it up again, and same thing. The dreaded bit-rot... hmm...
After checking that the files were all being generated, and grasping at a few other straws, I decided to find out exactly what the cause of a cross-hatch screen is on the MVS. Turns out they're colour-coded, and my blue border meant that a cartridge could not be found! The only thing that could explain that under emulation would be a corrupt P1 (program) ROM.
Loading the P1 ROM into a hex editor revealed immediately that the file was all-but-blank! Time to go back and take a closer look at the compilation output. It's not easy to maintain a clean build on a multi-platform project, especially retro platforms with development toolchains that can be rather old, and as it turns out, the Neo Geo gcc (v2.95.2 circa 1999) complains quite a bit. So much so, that you tend to ignore it after a while. Examining the output more carefully revealed an assembler warning about incorrect attributes being set for .rodata in the newly-added Mick Farrow sprite graphics data arrays.
Without going into too much detail, I have needed to use section attributes to force gcc to place certain data structures into ROM - const just hasn't worked in some instances (yes I know the differences of placement). The confusing thing is, it was never an issue with the original ZX or CPC graphics arrays, and they're not significantly different to the new file. After using some Google Fu it seemed it was a known gcc bug at various times in the past, however the work-around didn't assemble in my toolchain. Again, grasping at straws, having noticed that the existing graphics files had additional arrays defined before the sprite arrays, I instantiated a dummy 1-byte array at the top of the new file and - viola - it worked! And for the record, exactly the same section attributes were still being set for the sprite data!
The whole process was probably a good hour or so.
I'm not about to ponder any further on this issue - it's not broke (anymore) so I won't fix it!
UPDATE: Mick Farrow's graphics on the Neo Geo port.
Mick Farrow's modified graphics on the Neo Geo |
Incredibly the game now uses no less than six (6) sprite tile ROM's, not quite full but in the order of 40,000 tiles. In reality, at least half are never used by Knight Lore (ie. the VFLIP'ped versions, with the exception of a few border sprites) but at least the framework is there for the other filmation titles that may use them.
As a result, I had to find a larger host game, this time pspikes2. Basically each sprite tile ROM pair holds the sprites for an entire graphical variation. Note that Mick's panel graphics are not available (yet) as the panel is rendered on the FIX layer. I'd need to rip them and allocate another bank in the FIX ROM, which I will probably do soon.
UPDATE #2: Speaking of bit rot, in attempting to add another set of panel tiles for the Mick Farrow graphics, I've broken what was already there. I can't coax my tool into reproducing the existing panel data, let-alone a new one. Annoying...
I 'C' no more bugs!
Continuing on with testing the C port, and you can complete the game and see the end-of-game animation and messages. There were a few more bugs, but none too nasty. For the record, most bugs in the C port have been signed/unsigned issues.
I've also added Mick Farrow's modified graphics as a run-time option.
I need to propagate the changes through to the Amiga and Neo Geo ports. The latter will be more fiddly as it will require the generation of another few thousand sprite tiles, but the tool is already there.
I realised recently it would (probably) be relatively trivial to add an Atari ST port - then I could add another target platform to my CV! I'm also still deciding whether I have the motivation left in me to attempt a Sega Genesis port as well, or whether I'm well-and-truly over Knight Lore by now.
I've also added Mick Farrow's modified graphics as a run-time option.
I need to propagate the changes through to the Amiga and Neo Geo ports. The latter will be more fiddly as it will require the generation of another few thousand sprite tiles, but the tool is already there.
I realised recently it would (probably) be relatively trivial to add an Atari ST port - then I could add another target platform to my CV! I'm also still deciding whether I have the motivation left in me to attempt a Sega Genesis port as well, or whether I'm well-and-truly over Knight Lore by now.
Thursday, 14 April 2016
On optimisations
Over on the AtariAge forums, user mariuszw has been porting the ZX Spectrum version of Pentagram (the 3rd filmation title) to the 6502-based Atari 8-bit computers. He started with an automated translation of Z80 to 6502 which he got running but, not surprisingly, was too slow.
He has spent some time both profiling and analysing the code, and aside from actual pixel rendering has identified areas in the Z-order rendering logic that can be significantly optimised. I was aware that it took a rather brute force approach and that it spent quite a while in there, but was surprised to learn that the code can spend up to 40% of CPU time in that routine!
And to give some idea of the effect of these optimisations, one user observes that the code now runs as least as fast as the Spectrum version, if not slightly faster. And keep in mind that significant portions of the code are still implemented from the auto-translation process. Impressive!
The dilemma I face now is how far do I go with implementing any optimisations on the Coco3? The original intention was to port the game faithfully, warts-and-all. I have no issue rewriting the platform-specific portions of the game - such as rendering routines - but re-implementing the sorting logic encroaches on modifying the way the game works. You could argue that if it doesn't change the outcome (ie. the same objects are rendered each frame) then it's still the same, but the purist in me is struggling with that argument regardless.
Either way, I'll study the code for interest's sake, if nothing else, then make a judgement call. I guess more people are likely to play it if it runs smoothly, and won't really care what's going on underneath the hood.
He has spent some time both profiling and analysing the code, and aside from actual pixel rendering has identified areas in the Z-order rendering logic that can be significantly optimised. I was aware that it took a rather brute force approach and that it spent quite a while in there, but was surprised to learn that the code can spend up to 40% of CPU time in that routine!
And to give some idea of the effect of these optimisations, one user observes that the code now runs as least as fast as the Spectrum version, if not slightly faster. And keep in mind that significant portions of the code are still implemented from the auto-translation process. Impressive!
The dilemma I face now is how far do I go with implementing any optimisations on the Coco3? The original intention was to port the game faithfully, warts-and-all. I have no issue rewriting the platform-specific portions of the game - such as rendering routines - but re-implementing the sorting logic encroaches on modifying the way the game works. You could argue that if it doesn't change the outcome (ie. the same objects are rendered each frame) then it's still the same, but the purist in me is struggling with that argument regardless.
Either way, I'll study the code for interest's sake, if nothing else, then make a judgement call. I guess more people are likely to play it if it runs smoothly, and won't really care what's going on underneath the hood.
Wednesday, 13 April 2016
Back to C
I've managed to find and fix the three known bugs in the C port.
I expect there to be a few more as I continue testing.
I expect there to be a few more as I continue testing.
Monday, 11 April 2016
Use The Source, Luke
I've just uploaded the disassemblies - those of which I am entitled to - of the remaining projects to the download page, with the exception of Donkey Kong, which is very much WIP and I have every intention of completing it.
A few of the earlier projects are rather incomplete, and will probably remain so.
I do have a handful of diassemblies - all very much incomplete - that were used when reverse-engineering the hardware in order to assist with an FPGA implementation. Since they're not really part of any (software) porting project, I won't include them here.
Enjoy.
A few of the earlier projects are rather incomplete, and will probably remain so.
I do have a handful of diassemblies - all very much incomplete - that were used when reverse-engineering the hardware in order to assist with an FPGA implementation. Since they're not really part of any (software) porting project, I won't include them here.
Enjoy.
Finally! Joy after getting past my sticking point!
To say that adding joystick support was frustrating is an understatement!
There's not a whole lot of information on the net about sampling the joysticks, less still about reading the buttons, and some of the information that is available is, well, wrong. And to confuse matters further, I was having issues in MESS with the 2nd joystick button. Not having a physical 2-button joystick to test on real hardware is fraught with impediments to success.
Still at this point unable to test on real hardware, I at least seem to have sorted out the details and MESS finally behaves as I'd expect, given the Coco 3 schematics. I guess I should have gone to them in the first place, rather than as a last resort.
I thought I'd post my joystick code here on the off chance that someone else has similar issues in the future.
Let's define some useful constants.
PIA0 .equ 0xFF00
PIA1 .equ 0xFF20
DATAA .equ 0x00
DDRA .equ DATAA
CRA .equ 0x01
DATAB .equ 0x02
DDRB .equ DATAB
CRB .equ 0x03
; equates to keyboard rows
; - phantom keys appear accordingly
RJOY_BTN1 .equ (1<<0)
LJOY_BTN1 .equ (1<<1)
RJOY_BTN2 .equ (1<<2)
LJOY_BTN2 .equ (1<<3)
;.define LEFT_JOYSTICK
.ifdef LEFT_JOYSTICK
JOY_BTN1 .equ LJOY_BTN1
JOY_BTN2 .equ LJOY_BTN2
.else
.define RIGHT_JOYSTICK
JOY_BTN1 .equ RJOY_BTN1
JOY_BTN2 .equ RJOY_BTN2
.endif
; high and low thresholds
; for 'digital' operation
JOY_LO_TH .equ 0x64 ; ~40%
JOY_HI_TH .equ 0x98 ; ~60%
First up, the one-off initialisation, which sets all the appropriate PIA data-direction registers. Bear in mind that Knight Lore takes full control of the Coco 3 hardware, swapping out ROM and disabling all interrupts except a simple (F)ISR used to emulate the Z80 Refresh register. So the PIA's are immune to any reconfiguration behind-the-scenes.
; configure joystick axis selection as outputs
; and also select left/right joystick
lda PIA0+CRA
ldb PIA0+CRB
ora #(1<<5)|(1<<4) ; CA2 as output
orb #(1<<5)|(1<<4) ; CB2 as output
.ifdef LEFT_JOYSTICK
orb #(1<<3) ; CB2=1 left joystick
.else
andb #~(1<<3) ; CB2=0 right joystick
.endif
sta PIA0+CRA
stb PIA0+CRB
; configure comparator as input
lda PIA0+CRA
anda #~(1<<2) ; select DDRA
sta PIA0+CRA
lda PIA0+DDRA
anda #~(1<<7) ; PA7 as input
sta PIA0+DDRA
lda PIA0+CRA
ora #(1<<2) ; select DATAA
sta PIA0+CRA
; configure sound register as outputs
lda PIA1+CRA
anda #~(1<<2) ; select DDRA
sta PIA1+CRA
lda PIA1+DDRA
ora #0xfc ; PA[7..2] as output
sta PIA1+DDRA
lda PIA1+CRA
ora #(1<<2) ; select DATAA
sta PIA1+CRA
Now the joystick and button sampling. Note that Knight Lore uses a 'digital' joystick so it's only concerned with checking the position on each axis within three zones - left, middle and right.
; select hoizontal axis
lda PIA0+CRA
anda #~(1<<3) ; CA2=0 horizontal
sta PIA0+CRA
; set comparator value to 40%
lda PIA1+DATAA
anda #0x03 ; clear value
ora #JOY_LO_TH ; low threshold
sta PIA1+DATAA
lda PIA0+DATAA ; comparator
bita #(1<<7) ; joystick greater?
bne 1$ ; yes, skip
orb #INP_LEFT ; aka #INP_W
bra 2$
; set comparator value to 60%
1$: lda PIA1+DATAA
anda #3 ; clear value
ora #JOY_HI_TH ; high threshold
sta PIA1+DATAA
lda PIA0+DATAA ; comparator
bita #(1<<7) ; joystick greater?
beq 2$ ; no, skip
orb #INP_RIGHT ; aka #INP_E
; select vertical axis
2$: lda PIA0+CRA
ora #(1<<3) ; CA2=1 vertical
sta PIA0+CRA
; set comparator value to 40%
lda PIA1+DATAA
anda #0x03 ; clear value
ora #JOY_LO_TH ; low threshold
sta PIA1+DATAA
lda PIA0+DATAA ; comparator
bita #(1<<7) ; joystick greater?
bne 3$ ; yes, skip
orb #INP_FORWARD ; aka #INP_N
bra 4$
; set comparator value to 60%
3$: lda PIA1+DATAA
anda #3 ; clear value
ora #JOY_HI_TH ; hi threshold
sta PIA1+DATAA
lda PIA0+DATAA ; comparator
bita #(1<<7) ; joystick greater?
beq 4$ ; no, skip
orb #INP_PICKUP_DROP ; aka #INP_S
; read joystick buttons
4$: lda #0xff ; no keys, only buttons
jsr read_port
bita #JOY_BTN1
beq 5$
orb #INP_JUMP
5$: bita #JOY_BTN2
beq 6$
orb #INP_DIR_PICKUP_DROP
6$: bra finished_input
I haven't done any timing nor studied the BASIC joystick routines but short of hand-picking registers and instructions that minimise clock cycles, I don't think there's much you could do to get a faster sampling routine. Happy to be proven wrong by any astute reader.
Waiting for a 2-button adapter to turn up; hopefully that'll arrive in time for me to test before sending the final version off to John for demonstrating at the CocoFEST. I was going to try to experiment with some optimisation to speed up the rendering, but I think I'll take a short break from Knight Lore - or the 6809 port at least - until after CocoFEST.
I'm already thinking about the next port, which is dangerous before finishing off Knight Lore completely. But I've got a couple of new ideas which I need to investigate further. One is an actual arcade port; not a new game for the Coco (or any platform really) but it would be cool to have the actual arcade code and graphics, effectively, running on the Coco3. And reverse-engineering is already complete, so the port would be relatively quick. We'll see...
There's not a whole lot of information on the net about sampling the joysticks, less still about reading the buttons, and some of the information that is available is, well, wrong. And to confuse matters further, I was having issues in MESS with the 2nd joystick button. Not having a physical 2-button joystick to test on real hardware is fraught with impediments to success.
Still at this point unable to test on real hardware, I at least seem to have sorted out the details and MESS finally behaves as I'd expect, given the Coco 3 schematics. I guess I should have gone to them in the first place, rather than as a last resort.
I thought I'd post my joystick code here on the off chance that someone else has similar issues in the future.
Let's define some useful constants.
PIA0 .equ 0xFF00
PIA1 .equ 0xFF20
DATAA .equ 0x00
DDRA .equ DATAA
CRA .equ 0x01
DATAB .equ 0x02
DDRB .equ DATAB
CRB .equ 0x03
; equates to keyboard rows
; - phantom keys appear accordingly
RJOY_BTN1 .equ (1<<0)
LJOY_BTN1 .equ (1<<1)
RJOY_BTN2 .equ (1<<2)
LJOY_BTN2 .equ (1<<3)
;.define LEFT_JOYSTICK
.ifdef LEFT_JOYSTICK
JOY_BTN1 .equ LJOY_BTN1
JOY_BTN2 .equ LJOY_BTN2
.else
.define RIGHT_JOYSTICK
JOY_BTN1 .equ RJOY_BTN1
JOY_BTN2 .equ RJOY_BTN2
.endif
; high and low thresholds
; for 'digital' operation
JOY_LO_TH .equ 0x64 ; ~40%
JOY_HI_TH .equ 0x98 ; ~60%
First up, the one-off initialisation, which sets all the appropriate PIA data-direction registers. Bear in mind that Knight Lore takes full control of the Coco 3 hardware, swapping out ROM and disabling all interrupts except a simple (F)ISR used to emulate the Z80 Refresh register. So the PIA's are immune to any reconfiguration behind-the-scenes.
; configure joystick axis selection as outputs
; and also select left/right joystick
lda PIA0+CRA
ldb PIA0+CRB
ora #(1<<5)|(1<<4) ; CA2 as output
orb #(1<<5)|(1<<4) ; CB2 as output
.ifdef LEFT_JOYSTICK
orb #(1<<3) ; CB2=1 left joystick
.else
andb #~(1<<3) ; CB2=0 right joystick
.endif
sta PIA0+CRA
stb PIA0+CRB
; configure comparator as input
lda PIA0+CRA
anda #~(1<<2) ; select DDRA
sta PIA0+CRA
lda PIA0+DDRA
anda #~(1<<7) ; PA7 as input
sta PIA0+DDRA
lda PIA0+CRA
ora #(1<<2) ; select DATAA
sta PIA0+CRA
; configure sound register as outputs
lda PIA1+CRA
anda #~(1<<2) ; select DDRA
sta PIA1+CRA
lda PIA1+DDRA
ora #0xfc ; PA[7..2] as output
sta PIA1+DDRA
lda PIA1+CRA
ora #(1<<2) ; select DATAA
sta PIA1+CRA
Now the joystick and button sampling. Note that Knight Lore uses a 'digital' joystick so it's only concerned with checking the position on each axis within three zones - left, middle and right.
; select hoizontal axis
lda PIA0+CRA
anda #~(1<<3) ; CA2=0 horizontal
sta PIA0+CRA
; set comparator value to 40%
lda PIA1+DATAA
anda #0x03 ; clear value
ora #JOY_LO_TH ; low threshold
sta PIA1+DATAA
lda PIA0+DATAA ; comparator
bita #(1<<7) ; joystick greater?
bne 1$ ; yes, skip
orb #INP_LEFT ; aka #INP_W
bra 2$
; set comparator value to 60%
1$: lda PIA1+DATAA
anda #3 ; clear value
ora #JOY_HI_TH ; high threshold
sta PIA1+DATAA
lda PIA0+DATAA ; comparator
bita #(1<<7) ; joystick greater?
beq 2$ ; no, skip
orb #INP_RIGHT ; aka #INP_E
; select vertical axis
2$: lda PIA0+CRA
ora #(1<<3) ; CA2=1 vertical
sta PIA0+CRA
; set comparator value to 40%
lda PIA1+DATAA
anda #0x03 ; clear value
ora #JOY_LO_TH ; low threshold
sta PIA1+DATAA
lda PIA0+DATAA ; comparator
bita #(1<<7) ; joystick greater?
bne 3$ ; yes, skip
orb #INP_FORWARD ; aka #INP_N
bra 4$
; set comparator value to 60%
3$: lda PIA1+DATAA
anda #3 ; clear value
ora #JOY_HI_TH ; hi threshold
sta PIA1+DATAA
lda PIA0+DATAA ; comparator
bita #(1<<7) ; joystick greater?
beq 4$ ; no, skip
orb #INP_PICKUP_DROP ; aka #INP_S
; read joystick buttons
4$: lda #0xff ; no keys, only buttons
jsr read_port
bita #JOY_BTN1
beq 5$
orb #INP_JUMP
5$: bita #JOY_BTN2
beq 6$
orb #INP_DIR_PICKUP_DROP
6$: bra finished_input
I haven't done any timing nor studied the BASIC joystick routines but short of hand-picking registers and instructions that minimise clock cycles, I don't think there's much you could do to get a faster sampling routine. Happy to be proven wrong by any astute reader.
Waiting for a 2-button adapter to turn up; hopefully that'll arrive in time for me to test before sending the final version off to John for demonstrating at the CocoFEST. I was going to try to experiment with some optimisation to speed up the rendering, but I think I'll take a short break from Knight Lore - or the 6809 port at least - until after CocoFEST.
I'm already thinking about the next port, which is dangerous before finishing off Knight Lore completely. But I've got a couple of new ideas which I need to investigate further. One is an actual arcade port; not a new game for the Coco (or any platform really) but it would be cool to have the actual arcade code and graphics, effectively, running on the Coco3. And reverse-engineering is already complete, so the port would be relatively quick. We'll see...