Part 1
Introduction, Overview, Dip Switches, Input Ports and Memory Map.
Disclaimers / Information:
1. I am using Space Invaders ROM sets under the "Fair Use" policy for demonstration purposes only.
2. Blitz3D has no means to directly work with binary or hexadecimal values and therefore all code uses decimal calculations.
3. I am writing this as one single simple longhand piece of code so that all levels can read and understand.
4. I am using Blitz3D for coding which is a derivative of Blitz Basic, an older language but still a capable one for some projects, and its easy for all to read and understand.
Frequently Asked Questions
1. Do I need to be super switched on to understand this and write an emulator?
a. No. I can do it and believe me, I am no genius!
2. Do I need to have any prior understanding of how processors work?
a. No, you can pick it up as you go.
3. Do I need to understand the Space Invaders code?
a. No. We are writing an emulator, not rewriting the game.
When you look at the Space Invaders circuit boards or the Space Invaders circuit diagrams, it looks like an incredibly complicated machine. There are all sorts of electronic components working together to ensure that you can blast away at the oncoming invading hoards, and an emulator of the system can seem like an impossible task.
 |
1979 Space Invaders Circuit Boards |
 |
Space Invaders Circuit Board Schematic |
Fortunately, to write an emulator, you don't need to recreate all of the electronics within the machine, but rather the logic of the machine, and writing an interpreter program that reads the space invaders code in a similar fashion to how the real machine does, and then interpreting it into something that your current system can do, emulation of the machine can become a fairly straight forward task.
From the complex circuit diagrams above, we can water the system down to a simple block diagram which will include all of the parts of the machine that we will need to emulate or simulate. Note there will be some simulation within the emulator. The processor can be emulated however the video output needs to be simulated because the video output involves converting a bitmap within memory into an analogue wave for a CRT monitor to display, something that we cannot do here.
 |
What an Artist! Yup Shit-Block-Diagrams-R-US |
The block diagram above shows all of the different parts of a Space Invaders cabinet that we need to take into account when writing an emulator. Lets go through them one by one:
1. Memory Area (far left) - This is a 16 kB area of ROM space and RAM. The lower 8 kB is the Rom area and the upper 8 kB is the RAM area. Whilst this 16 kB of ROM and RAM would be scattered across the circuit boards in various size chips, the processor addresses this memory area as a 16 kB block.
2. Intel 8080 processor - The intel 8080a processor is an 8 bit processor with a 16 bit memory address bus. It has 8 x input ports and 8 x output ports for communicating with other parts of the Space Invaders hardware. It can execute 256 different instructions (known as Opcodes).
3. Video Output - This part is simulation. The Space Invaders graphics output exists as a 1-bit bitmap in the top 7 kB of RAM. The video output reads this bitmap and converts it into a display. The video output unit also generates processor Interrupts at a rate of 2 interrupts per frame drawn.
4. Processor Dip Switches - These are hardware switches on the processor board and can be used to adjust various parameters of the game being played. For Space Invaders, the number of lives can be set between 3 and 6, the score at which a bonus life can be earned can be either 1000 or 1500, coin info can be displayed or not displayed during attract mode and a diagnostic service mode can be switched on or off. These are read using the Intel 8080 Input Port 0 and Input Port 2.
5. Video Dip Switches - This is a guess. Somewhere in the Space Invaders hardware is a switch that sets the game to upright cabinet mode or table top cabinet mode. I don't know where this switch is but I am guessing its on the video board somewhere.
6. Coin Mechanism - The coin mechanism is read by the Intel 8080 Input Port 1 during one of the two processor Interrupts per frame drawn. This means that if Space Invaders display runs at 60 frames per second, the coin mechanism is checked for a coin deposited 60 times a second. I believe that the coin mechanism also contains a tilt switch which would activate if the machine is tilted during game play and end the game. This may not be located in the coin mechanism...
7. Coin mechanism Dip Switches - Some later coin mechanisms had their own Dip Switches to enable arcade operators to allow multiple credits per coin, or to charge multiple coins per credit.
8. Joystick and Buttons - These are the game controls that allow the player to interact with the game. There is a joystick, a fire button, an 1 player button and a 2 player button. These are read by the Intel 8080 Input Port 1 and Input Port 2. Again they are read like the coin mechanism at a rate of once every display frame update during an interrupt.
9. 16-Bit Shift Register - This is a separate piece of logic hardware that shifts bits quicker than the processor can do. The Intel 8080 input and output ports are used to write to and read from the 16-bit shift register.
10. Sound Output - Sound output for Space invaders uses a specialist chip which is not the easiest thing to emulate. At this point, I will be using the MAME space invaders sound samples for sound output.
11. Watchdog - It is not essential to emulate the Watchdog, however for completeness the Watchdog is essentially a count down to resetting the processor. It counts down from 255 to 0 at a rate of one count per display frame and if the code is running correctly, it will reset the watchdog countdown to stop the reset. If the machine is suffering from a temporary code or hardware glitch, the countdown gets to zero, the processor is reset and hopefully the error is cleared.
That is the list of hardware that we need to consider to write a complete Space Invaders emulator. The Watchdog and Coin Mechanism dip switches are not essential, but pretty much everything else is.
Before we get started, its worth considering that there is more than one Space Invaders ROM set out there, in fact there are six different ROM sets for monochrome space invaders. There are also different variants on the hardware. However, if we write a good emulator, it will run all of the different ROM sets available. The differences between the ROM sets are shown in the diagram below. Its also worth noting that some of the ROM sets are 4 x 2 kB ROMs and others are 6 x 1 kB ROMs. In either case, the ROM set will be in the lower 8 kB of the memory area. For 6 kB rom sets, kB's 5 and 6 are left empty in the ROM area whereas 8 kB ROM sets populate the whole 8 kB ROM area.
To write an emulator, you will need to acquire one of the MAME ROM sets shown above, that is sitv1, sisv2, invaders, sitv, sisv3 or sisv.
https://www.planetemu.net is a good MAME ROM source to try for one of these ROM sets.
And so, armed with a ROM set and a small amount of knowledge, we can start the process of emulation.
Its going to be a while before we have anything that will give us any notable output, but its important to get the first bits in place to avoid false starts.
Before we start writing actual code, I will give you a few quick pointers about the code itself and the notation that I use.
Note 1: Remarks / Comments are prefixed with a ";" and are in cyan. Actual code is in orange.
Note 2: You will see in the remarks below that I am using Intel 8080 hexidecimal notation. "0x00" etc. The "0x" is a prefix to state that its Intel 8080 hexidecimal, the 00 is the hexidecimal value, so 0x00=0, 0x01=1, 0x02=2, 0x04=4, 0x08=8, 0x10=16, 0x20=32, 0x40=64 and 0x80=128. These values relate to each single bit in a byte being set. As I stated above, Blitz3D doesn't have any way of directly using either binary or hexidecimal so in the code, the actual values will be in decimal.
Dip Switches
We will start by setting the Dip Switches to the values that we require. This isn't essential for ROM sets that don't have a Diagnostics mode (see diagram above) but is essential for ROM sets that do have a diagnostic mode. If we don't disable the diagnostics mode before we start, the game will boot into a sweeping bit pattern which could be misunderstood as the emulator not functioning correctly.
There are 8 dip switches on the processor board, and each of these DIP switches will be linked with a bit in one of the Intel 8080 input ports. Depending on the hardware variant you get the dip switch settings from, different dip switches may be assigned to the functions that they do however the function will always be assigned to the same input port bit.
Example:
In one Space Invaders hardware variant, Dip Switches 1 and 2 set the number of lives.
In another hardware variant, Dip Switches 3 and 5 set the number of lives.
In either case, the dip switches setting the number of lives are linked to bits 0 and 1 on Input Port 2.
So you can see from the above example that you can name the dip switches literally anything, as long as you link them to the correct Input Port bit.
I am going to take the Dip Switch numbering from computerarcheology.com's website which states that:
Dip Switch 3 - Number of Lives
Dip Switch 5 - Number of Lives 2
Dip Switch 4 - Diagnostics / service mode On or Off.
Dip Switch 6 - Extra life at 1000 or 1500 score.
Dip Switch 7 - Coin Info On or Off during Attract Mode.
Dip switches are set either to On or Off. When they are set to On, the associated bit in the Input port is at 0, and when they are set to Off, the associated Input Port bit is set to 1.
So if we didn't set the Dip Switches, and then read the settings across to the Input Ports, we would start with the Diagnostic mode set to 0, or ON, and this is what we don't want.
So code time to declare the Dip Switches as Local variables and set them on or off.
; *** SERVICE MODE ***
; Dip Switch 4 On (Input Port 0 - 0x00) - Service Mode On.
; Dip Switch 4 Off (Input Port 0 - 0x01) - Service Mode Off.
Local dip_switch_4=1
; *** NUMBER OF LIVES PER GAME ***
; Dip Switch 3 On (Input Port 2 - 0x00) / Dip Switch 5 On (Input Port 2 - 0x00) = 3 Lives.
; Dip Switch 3 Off (Input Port 2 - 0x01) / Dip Switch 5 On (Input Port 2 - 0x00) = 4 Lives.
; Dip Switch 3 On (Input Port 2 - 0x00) / Dip Switch 5 Off (Input Port 2 - 0x02) = 5 Lives.
; Dip Switch 3 Off (Input Port 2 - 0x01) / Dip Switch 5 Off (Input Port 2 - 0x02) = 6 Lives.
Local dip_switch_3=0
Local dip_switch_5=0
; *** SCORE TO EARN BONUS LIFE ***
; Dip Switch 6 On (Input Port 2 - 0x00) = Bonus Base At Score of 1500
; Dip Switch 6 Off (Input Port 2 - 0x08) = Bonus Base At Score of 1000
Local dip_switch_6=0
; *** COIN INFO ON / OFF ***
; Dip Switch 7 On (Input Port 2 - 0x00) = Display Coin Info
; Dip Switch 7 Off (Input Port 2 - 0x80) = Don't Display Coin Info
Local dip_switch_7=0
; *** Other Dip Switches ***
; Dip Switch 1 - Unknown
; Dip Switch 2 - Unknown
; Dip Switch 8 - Unknown
This has set the Service Mode to off, the number of lives to 3, the score to earn a bonus life at 1500 and the coin info on.
Input Ports
Now that we have the Dip Switches set, we can now set up the Input Ports default values based on the Dip Switch settings. We need a default value as the dip switches won't be changed during the game running, but other things such as coins / game controls will adjust the input port values, so rather than resetting the input port values back to 0 after coins have been inserted or game controls have been used, they are reset back to their default values based on the Dip Switch settings.
; ***** Input Port 0 *****
;0x01 - Sets service / diagnostic mode on or off from Dip Switch 4.
;0x02 - Unknown.
;0x04 - Unknown.
;0x08 - Unknown.
;0x10 - Unknown.
;0x20 - Unknown.
;0x40 - Unknown.
;0x80 - Unknown.
;Default Input Port 0 value is either 0 (Service Mode) or 1 (Game Mode).
in_0_value=0
If dip_switch_4=1 Then in_0_value=in_0_value+1
Input0=in_0_value
; ***** Input Port 1 *****
;0x01 - Coin Slot 1 - Nominally set to 0. Set to 1 when coin inserted.
;0x02 - 2 Player Start Button - Nominally set to 0. Set to 1 when 2P game start button pressed.
;0x04 - 1 Player Start Button - Nominally set to 0. Set to 1 when 1P game start button pressed.
;0x08 - Unknown
;0x10 - Player 1 fire button - Nominally set to 0. Set to 1 when fire button is pressed during Player 1 gameplay.
;0x20 - Player 1 Joystick Right - Nominally set to 0. Set to 1 when Joystick is left during Player 1 gameplay.
;0x40 - Player 1 Joystick Left - Nominally set to 0. Set to 1 when Joystick is right during Player 1 gameplay.
;0x80 - Unknown
;Default Input1 value is 0.
in_1_value=0
input1=in_1_value
; ***** Input Port 2 *****
;0x01 - Coins Per Credit from Dip Switch 3.
;0x02 - Coins Per Credit from Dip Switch 5.
;0x04 - Tilt Switch
;0x08 - Bonus Ship Score from Dip Switch 6.
;0x10 - Player 2 fire button - Nominally set to 0. Set to 1 when fire button is pressed during Player 2 gameplay.
;0x20 - Player 2 Joystick Left - Nominally set to 0. Set to 1 when Joystick is left during Player 2 gameplay.
;0x40 - Player 2 Joystick Right - Nominally set to 0. Set to 1 when Joystick is right during Player 2 gameplay.
;0x80 - Coin Info On / Off from Dip Switch 7.
;Default Input2 value depends on Dip Switch Settings.
in_2_value=0
If dip_switch_3=1 Then in_2_value=in_2_value+1; - Number of lives
If dip_switch_5=1 Then in_2_value=in_2_value+2; - Number of lives
If dip_switch_6=1 Then in_2_value=in_2_value+8; - Bonus Ship
If dip_switch_7=1 Then in_2_value=in_2_value+128; - Coin Info
input2=in_2_value
So now we have Input Ports 0 and 2's default values set. Input Port 1's default value can be 0 as no Dip Switches are linked to this Input Port. Computerarcheology.com states that bit 3 (0x08) in Input Port 1 is permanently set to a 1, however setting this bit to 1 or 0 does not affect the Space Invaders gameplay. It also states that Input Port 0 Bits 1,2 and 3 (0x02, 0x04 and 0x08) are permanently set to 1. Again whether they are set to 1 or 0 has no affect on the Space Invaders gameplay.
So now that we have the Dip Switches set, and the associated Input Port bits set, we can now look at setting up the Space Invaders memory area.
Memory Area
Space Invaders ROM sets come on 6 x 1 kB ROMs or 4 x 2 kB ROMs depending on which ROM set that you have downloaded. Either way, all of the ROMs will sit in the bottom 8 kB of the memory area, and the RAM then sits in the top half.
Despite the ROM and RAM chips being scattered around the Space Invaders board in the real machine, the processor addresses the ROMs and RAM as one 16 kB lump of memory.
So we can start with a 16 kB array, and then load the bytes from the ROM files into the array in the correct order and correct area leaving the top 8 kB available to the emulator as RAM. We should also have a write protect bit in the array to stop the emulator overwriting values in the ROM area.
I will give two examples here, one for the ROM set "sitv1" which is 4 x 2 kB ROMs and one for ROM set "sisv" which is 6 x 1 kB ROMs.
Example 1 - 4 x 2 kB ROM set - sitv1
; Two dimensional array. All array slots with ROM bytes in them have second dimension slot set to 1 to block writes to the ROM.
Dim mem(16384,2)
; Read all of the bytes from the ROMs into the emulators memory array.
rom_size=2048
rom_start=0
number_of_roms=4
For rom_select_loop=1 To number_of_roms
If rom_select_loop=1 Then filein=ReadFile("roms\sitv1\tv01.s1")
If rom_select_loop=2 Then filein=ReadFile("roms\sitv1\tv02.rp1")
If rom_select_loop=3 Then filein=ReadFile("roms\sitv1\tv03.n1")
If rom_select_loop=4 Then filein=ReadFile("roms\sitv1\tv04.m1")
For rom_read_loop=rom_start To rom_start+rom_size-1
mem(rom_read_loop,0)=ReadByte(filein)
; Wherever a ROM byte is entered into the array, set the array second dimension for that array value to 1
mem(rom_read_loop,1)=1
Next
CloseFile(filein)
rom_start=rom_start+rom_size
Next
Example 2 - 6 x 1 kB ROM set - sisv
; Two dimensional array. All array slots with ROM bytes in them have second dimension slot set to 1 to block writes to the ROM.
Dim mem(16384,2)
; Read all of the bytes from the ROMs into the emulators memory array.
rom_size=1024
rom_start=0
number_of_roms=6
For rom_select_loop=1 To number_of_roms
If rom_select_loop=1 Then filein=ReadFile("roms\sisv\sv0h.36")
If rom_select_loop=2 Then filein=ReadFile("roms\sisv\sv11.35")
If rom_select_loop=3 Then filein=ReadFile("roms\sisv\sv12.34")
If rom_select_loop=4 Then filein=ReadFile("roms\sisv\sv04.31")
If rom_select_loop=5 Then filein=ReadFile("roms\sisv\sv13.42")
If rom_select_loop=6 Then filein=ReadFile("roms\sisv\sv14.41")
For rom_read_loop=rom_start To rom_start+rom_size-1
mem(rom_read_loop,0)=ReadByte(filein)
; Wherever a ROM byte is entered into the array, set the second dimension to 1
mem(rom_read_loop,1)=1
Next
CloseFile(filein)
rom_start=rom_start+rom_size
; Skip 2 x 1kB ROM spaces after the first 3 ROMs are in place
if rom_select_loop=3 then rom_start=rom_start+2048
Next
You can see from the code above the order that the ROMs go into the memory area. There are a number of website that will give you arcade game Memory Maps of where each game ROM sits in its respective ROM area. Try arcaderestoration.com or you can look at the MAME drivers in the MAME source code which also list where all of the ROMs for a particular game sit within the memory area.
And that wraps up Part 1 of how to write a Space Invaders emulator. We now have Dip Switches, Input Port Default Values and a Memory Map.
If you have any questions, please post them in the comments below.
In Part 2, we will be dealing with the Processor.