Wednesday, 30 June 2021

Lunchtime Coder #7 - Space Invaders Emulator - High Score Load / Save

The original Space Invaders arcade cabinet doesn't have a high score save facility built into it.

The high score would be kept until the machine was switched off, and when it was powered up again, the high score would be reset to 0000.

But this is emulation, so we can do what we want, right ? ( providing that the brain power to do it exists... ).

So lets add a High Score save routine into the emulator.

I wanted to do this without any external website help, relying instead on already gained knowledge and educated assumptions.

The plan is for the high score to be saved in a small external file. This would be loaded as you start the game and would be poked into the Space Invaders Emulator memory.

Periodically, the values in the save file would be checked against the live high score values, and the file values updated if required on the fly.

I don't know a massive amount about how the Space Invaders code executes. I mean, I wrote an emulator yes, but that was an Intel 8080 processor machine code interpreter. I didn't actually write Space Invaders itself.

It's akin to writing a German to English book translator. Just because the program you have written translates a German book into an English book, it doesn't mean that you have read and understood the contents of the book.

So how to set about being able to load and save the high score?

Well, Here's what I do know:

  1. The high score displayed is in BCD or Binary Coded Decimal. Its 4 digits long and as the maximum value a byte can store in BCD is 99, this means that there are two bytes to the high score.

  2. The score looks like decimal, but the value is actually a hexadecimal value.

  3. Space Invaders has an 8 kB ROM area and then 8 kB of RAM. This is addressed by the processor as one 16 kB lump of memory. The lower 8 kB being the ROM area, the next 1 kB being general purpose RAM and then the top 7 kB being a 1 bit bitmap of the display.

  4. Early on in the Space Invaders code, an area of ROM is copied byte by byte to an area in the general purpose RAM.

  5. As the high score changes in game, its certain that the two High Score bytes must be in the general purpose RAM area.

Based on what I do know, I can now make some educated guesses to fill in the blanks:

  1. Lets make an assumption that the two bytes are next to each other in the general purpose RAM.

  2. Lets also assume that these two bytes exist in the ROM (as 0 and 0), and are copied across to the RAM area at the beginning of the code execution. (You may ask why I would assume that 0's would be copied from ROM to RAM, when the RAM should already be at 0? Well, I do know that after the ROM area is copied to RAM, the code then writes 0's to the whole of the bitmap RAM area to ensure that the screen is blank to start with, so I am guessing that late 70's RAM wasn't massively reliable on what state it was at on power up.)

With what we do know, and what we have made assumptions on, It should now be possible to play the game and get a known BCD value high score, and then do a reverse BCD conversion from the high score displayed, to what's stored in the two bytes.

We can then do a mid game RAM search for those two High Score bytes.

Once the locations of the high score bytes are identified, we can then go back to the beginning of the code execution when ROM is being copied to RAM, and trace the ROM location that the bytes are copied from.

And finally, we can then test what we have found by poking the two ROM locations with some set values, and seeing if the game starts with a high score equivalent to those values that we have put in the ROM.

Time to test the theory.

Lets say that our high score is 1580.

Split that into two bytes: 15 and 80. Remember these values are Binary Coded Decimal so the maximum value per byte is 99.

But BCD is hexadecimal, so we need to reverse the hexadecimal to find the true decimal value in the bytes. (Note: I am programming in a language that does not allow me to deal with binary values directly, and hence the whole emulator works in decimal).

In the case of 80 we do: 80+(integer(80/10)x6) or 128.

In the case of 15 we do: 15+(integer(15/10)x6) or 21.

Having played a game and achieved a high score of 1580, we now pause the game and do a search across the 1 kB of ram for the two high score values. I don't know which order they would appear, MSB or LSB first, so am looking for the LSB, and if found will check each side for the MSB.

And we have a winner! RAM memory locations 0x20f4 and 0x20f5 contain the High Score LSB and MSB.

Ok, so now to take a slow look at the beginning of the code executing.

The routine that copies bytes from the ROM area to RAM basically goes:

  1. Load the accumulator with the byte value at the 16 bit ROM address stored in register pair DE.

  2. Load the memory location at the 16 bit ROM address stored in register pair HL, with the value in the accumulator.

  3. Increment the value in register pair HL by 1. This moves the RAM destination address up by one byte.

  4. Increment the value in register pair DE by 1. This moves the ROM source address up one byte.

  5. Decrement the value in register B. Register B counts off how many bytes have been copied. When it gets to 0, the copying stops.

By running this routine slowly until register pair HL = 0x20f4, The next instruction in the code should increment register pair DE to the ROM source location of the first byte of the initial high score value.

And this works like a charm. 0x1bf4 and 0x1bf5 are the magic locations in the ROM with the very important task of storing two zeros for the initial high score value.

To use this in a practical way within the emulator, the values need to be poked into the Space Invaders emulator ROM area.

The emulator ROM and RAM area are represented by a 16 kB array. The ROMS are loaded into the bottom 8 kB, and once this is done, the two high score bytes can then be written to the correct ROM area.

Once this is done, the game will start with the high score value already set to the values poked into the ROM area, and these values can be read from a small pre-saved file.

For writing any new high scores to the file; After each screen update, the combined value of the two bytes in the file are compared with the combined value of the two bytes in the RAM at 0x20f4 and 0x20f5, and if the later is a larger quantity, the bytes in the file are replaced with the values in the RAM, and this achieves a continuous high score.

Space Invaders Variants.

As I mentioned at the beginning of this post, this routine has been developed for Space Invaders romsets with a four digit score, but what about other variants of Space Invaders? Will it work for them?

Space Invaders romsets with a five digit Score.

Fortunately, the routine for five digit score Space Invaders is exactly the same as four digit score Space Invaders.

Initially, poking the two ROM bytes with set values seemed to work, but the score was offset by a multiple of 10 i.e. putting in a value of 6 into the LSB got a high score of 60.

And the I twigged what they had done...

All of the scores in Space Invaders are multiples of 10, so the lowest digit is always 0 no matter what.

So, the game always draws a 0 at the lowest end of the high score, and then divides all the scores you actually earn from shooting things by 10.

This means that if you shoot an invader worth 20 points, you now get 2 points in reality, plus the fixed zero at the end of the score which displays 20 points.

Pretty clever really. A five digit score stored in two bytes.

Super Earth Invasion with six digit score.

Again this is much like the 5 digit score.

All scores in Super Earth Invasion are multiples of 100 and therefore the two lowest digits are fixed at 0, and then two bytes are used to store the high score.

Again you would only score two points for a 200 point invader, and the score then puts two fixed zero's after the score to show 200.

Theses bytes are in the exact same rom and ram areas as in Space Invaders.

Space Invaders Colour with five digit Score.

Space Invaders Colour is basically Space Invaders Monochrome with two colour EPROMs included.

So it would be logical to assume that Space Invaders Colour would behave in the same way as Space Invaders Monochrome, when it comes to poking values into the ROM area...

Unfortunately this is not the case. Poking high score values into the ROM area appears to work initially, with the values appearing on the intro screen and attract mode.

But when I start a game, the emulator closes.

To be fair, I coded my "HALT" Opcode to end program. So to be more accurate, the Space Invaders code is calling up the Halt Opcode.

If I disable the halt Opcode, the game just resets back to the intro screen.

I'm not sure exactly why it does this. It runs perfectly if you leave the High Score at 0.

I have several theories as to why this is happening, but it probably comes down to a flag, probably the Z flag being set to 0 rather than 1 because of the High Score in ROM or RAM not being at 0, and this is causing a CNZ or JNZ to Call or JUMP that wouldn't normally happen when the Z flag is set.

There may be a way to hack this on the fly, but for now its a no go.

Space Invaders Part II / Space Invaders Deluxe with five digit Score and 10 character High Scorer Name.

So this variant has a five digit score, and the high score ROM and RAM locations work in the same way as Space Invaders Monochrome 5 digit score.

But... There is also the High Score name to save. This is 10 characters and by default is set to "MIDWAY" or "TAITO" depending on the romset used.

The high score name is stored in 10 bytes, one byte per character. By entering the name "ABCDEFGHIJ" I was able the find the bytes in the RAM area, and then back trace it to the ROM locations that they are written from.

So what's the problem?

Well, the high score name on loading the game has spaces at the front so that the word TAITO or MIDWAY appears centred with the score underneath i.e. the actual bytes stored are space-space-T-A-I-T-O-space-space-space ( A to Z are 0D to 25D, and then full stop is 26D and space is 27D).

If you then earn a high score and enter a name, lets say "ACE", then the letters appear in the first three bytes, but there is also an "X Offset" byte that is located one byte before the characters in the RAM, and this centres the name over the high score.

But the centring byte is only read when a game has been played, not when the game is initially loaded. Its not required initially as the default high score names are already padded at the front with spaces to centre them. This means that if you enter the name "ACE" and then save the 10 bytes as they stand in the RAM, when you load the bytes back in at the beginning of running the emulator the next time, the word "ACE" will be offset from the high score to the left.

The solution to this is that when you save the high score name bytes, you don't save them as you appear in the RAM. You save them by taking half of the spaces from the end of the name, and adding them to the front of the name, so that if its required to be loaded back into the emulator next time its loaded, its already padded with spaces at the front and will appear centred i.e. A-C-E-space-space-space-space-space-space-space in RAM is saved as space-space-space-A-C-E-space-space-space-space in the high score save file.

Its also worth mentioning that the trigger to save the high score values and name should be a change in the high score value, but a change in the name byte value. When the high score value changes, the new high score name has not been entered yet, and the high score name bytes are 10 spaces at that point.

Friday, 23 April 2021

Lunchtime Coder #6 - Space Invaders Part II /Deluxe Emulator in Blitz3D / Blitz Basic

So once you have a few games running on your emulator successfully, the process of adding more games gets easier right? Wrong!

Every game added comes with its own individual issues to resolve, but then that's the fun of writing emulators.

The Space Invaders Part 2 romset comes as five 2 kB roms and two 1 kB eproms.

The first four 2 kB roms go into the bottom 8 kB of the memory area 0x0000 to 0x1FFF (as per Space Invaders and Space Invaders CV). The fifth 2 kB rom goes in above the screen ram area at 0x4000 to 0x47ff.

The two 1 kB eproms are colour maps for "Everything but player two playing" and "Player two playing".

I took a quick peek at the colour map eproms expecting similar / the same as for Space Invaders CV.

This time, the values are offset by 8 so instead of the eight different colours ranging from 0 to 7, they now range from 8 to 15.

The colour maps themselves also differ from Space Invaders CV slightly.

The screen turns red on the fly when a base is hit, so again I used the Intel 8080 Output Port 3 Bit 0x04, the trigger for sound sample for base being hit to control the trigger and duration of screen going red. Basically the same method that I used in Space Invaders CV.

I also used the same method to detect when Player two is on screen as I did with Space Invaders CV. This is the cocktail screen flip bit in Intel 8080 Output Port 5, Bit 0x20. When set to 1, player 2 is playing.

All good so far. So with the roms in place, the eproms integrated into the drawing routine and a few tweaks to the dip switch settings, I ran up the game.

I should point out that my Intel 8080 emulator now has all 256 opcodes and all 5 conditional bits / flags implemented, so no additional opcodes to throw into the code this time.

Issue 1: There was an erroneous manufacturers logo on the opening screen. This shouldn't be there.

Issue 2: When that logo is meant to be there on completion of the opening screen drawing, it should flash between the manufacturers name and the word "HI-SCORE". This wasn't happening either. Just a fixed manufacturers name.

Issue 3: All sorts of bizarre effects when you get in game / attract mode game, from graphic artefacts to resetting back to the opening screen.

It seemed to me that the interrupts were occurring too quickly, as in before the code had reached the point that it was waiting for an interrupt.

My first attempted resolution was to speed up the processor clock by allowing more processor clock pulses between each interrupt. This actually resolved issue 3, and the game became playable without any artefacts. The speed of the processor was now at 3.125 MHz which by chance is the same speed that an Intel 8080b runs at.

However MAME insists that this game should run on a 2 MHz Intel 8080, and I still had the issues with the manufacturers logo on the opening screen. Something was definitely not right.

I decided to go back to basics, and activate the debug log, and this was what saved the day.

I noticed an IN 0 opcode being run which means that the processor is reading Input Port 0. The romset versions of Space Invaders / Space Invaders CV / Super Earth Invasion didn't read Input Port 0, so for emulation purposes, Input 0 can be set to 0, or just ignored.

But...If its being read by the code, then there must be something to read in Input 0.

By a process of elimination, I set each bit in turn on Input 0 to 1, and ran the game... and Bingo! 0x40 set to 1 cleared all 3 issues.

There was some paranoia about people typing in rude names when they achieved the high score, so Taito supplied a "Reset High Score" button which is tied to 0x40 of Input Port 0.

The reason that the emulator hadn't been working correctly was that I was running it with this button permanently pushed down. This meant that additional code was running between interrupts and the program wasn't ready for the interrupts to happen, and this is why running it with more time between interrupts solved some of the issues.

Setting this bit to 1 resolved all of the issues.

Taito also provided a "Preset Mode" which I found by accident by setting what I thought was the bonus score dip switch.

The Preset mode enables you to set a score before you start the game, so in effect, cheat! This was so that arcade operators could set high scores higher and put in their own custom names as the high scorers.

Interestingly, The manuals for Space Invaders part 2 and Space Invaders Deluxe do not mention the High Score reset button. The preset mode is mentioned in the Space Invaders Deluxe manual.

Another game successfully emulated.

Thursday, 25 March 2021

Lunchtime Coder #5 - Space Invaders Colour Emulator in Blitz3D / Blitz Basic

Having written a Space Invaders emulator based around an early and late version of the various romsets available, I decided to up the game and try some other similar romsets in my emulator to see how they ran.

The first different romset I tried was Super Earth Invasion, a UK bootleg/clone of Space Invaders with different graphics for the Invaders, houses instead of shields, and also some code changes that enabled motherships to drop super bombs on you, and for shot invaders to split and multiply. It was designed to run on the Space Invaders Deluxe hardware, and in some ways has more in common with this game than with the original Space Invaders.

There was some minor differences in the DIP switch settings and how they related to the processor input ports, but with a few tweaks and adjustments it ran perfectly.

I added some colour to simulate the coloured gel treated mirror
effect seen in Space Invaders upright cabinets.

On the back of this success, I went for the Space Invaders Colour (CV) romset fully expecting some heavy additional coding to be required, at least in the screen drawing routine.

I was surprised to find that the romset contained 4 x 2 kB roms (similar to the original Space Invaders romset), and when I ran them I got monochrome Space Invaders out of them.

Also included in this romset are 2 x 1 kB eprom images. A bit of on line investigation showed that these two eproms hold the colour maps for a Player 1 and Player 2 game screen. Essentially the 1-bit bitmap is generated in ram, and then the colour is added during the video processing stage of the hardware.

To be more accurate, the player 1 colour map is really everything but player 2 playing colour map. The player 2 colour map changes the colour of the bases and highlights the player two score in white. The rest of the colour map is the same as the 'Everything else' colour map.

I wrote a small program that read the bytes from these eprom images and arranged them in a 32 by 32 square that showed that each square had a value of between 0 and 7 representing one of 8 different colours (Black, Red, Green, Blue, Cyan, Magenta, Yellow and White).

Each byte corresponds to an 8 x 8 pixel square in the game remembering that the Space Invaders screen is rotated 90 degrees anticlockwise so the screen drawing starts from bottom left to top left and continues moving right across the screen.

A quick update of my emulator code to read the eprom map as it was drawing the bits gave me glorious colour-o-vision.

After playing Space Invaders Colour on MAME a few times, I noticed that when a base is hit by an invader bomb, all of the on screen graphics turn red for a short duration. This must mean that the colour video processing can turn the whole screen a single colour 'on the fly'. I also noticed that the player colour maps change pretty much spot on the player change.

Making the colour change to red when a base gets hit was pretty easy. I used Intel 8080 Output Port 3 bit 0x04. This is the trigger for the 'Base Hit' sound sample to play, but this bit is set for a specific duration, so it seems that when its set to 1, all of the on screen graphics are red.

To flip between player colour maps, I used the Intel 8080 Output Port 5, Bit 0x20 which is for tabletop cabinet screen flipping. By default it is set to 0, but when Player 2 is playing, it flips to 1. This means that it must be the trigger for both cocktail mode screen flipping, and for changing between player 1 and Player 2 colour maps.

Player 1 Colour Map
Player 2 Colour Map

Near perfect.. Well you cant have 100 % perfection without having the original arcade machine running in front of you...