Monday, 4 July 2022

Lunchtime Coder #13 - Space Invaders Colour Overlay Part 2

Yup Still Garish And Vomit Inducing !

I have been putting up with this awful colour overlay scheme in my Space Invaders emulator for some time, and every time that I use it, I find it deeply unsatisfying.

The original overlay effect pictured above is done by placing a large sprite textured with the colour overlay image on top of the sprite with the Space Invaders screen texture placed on it.

The overlay sprite is masked in the black areas and then alpha'd down some so that the graphics from the Space Invaders sprite beneath it show through it and are tinted by the overlays colours.

Unfortunately, the alpha needs to be reasonably high so that it tints the graphics at a noticable level. Too low and the graphics still look white but unfortunately too high and you get tinted graphics but garish stripes across the screen, and the tint stripes on the real machines just weren't that bright.

After some experimenting, I came up with a half decent solution that requires more code, but gives a much better asthetic. See the before and after below.


Before - Bright stripes and lightly tinted Space Invaders graphics.

After - Less obvious stripes and better colour on the graphics.

The overlay sprite is still used, but at a much lower alpha to reduce its appearance. The graphics are then coloured as they draw to match the colours on the overlay. This requires a colour map to tint each line as it draws so additional code is required, but the effect looks far better and closer to the original appearance.


The Updated Space Invaders Cocktail Overlay

The updated Space Invaders Cocktail overlay also looks much better in this style. There are more colour bands for this overlay so some more calculation was required but unlike the Upright overlay, there is no small gaps between stripes so not matching gaps in overlay to lines of uncoloured bits.



Monday, 20 June 2022

How to write a Space Invaders Emulator - Part 2


Part 2


The Intel 8080 Processor


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.



I thoroughly recommend the freely available PDF manual linked here as a reference guide for use while writing the processor emulator. It contains detailed descriptions about every aspect of the Intel 8080 including very simple straight explanations of what each part of it and each opcode does.


The Intel 8080a processor is an 8-bit processor with 16-bit memory addressing. This means that it reads instructions or "Opcodes" that are 1 byte in length, but it can read from, and write to memory addresses that are 2 bytes or 16 bits in length meaning that it can support up to 64 kB of memory area. Lets look at some of the other features that this processor has.


Registers

Registers are small areas of memory within the processor where values can be stored, used and manipulated. The Intel 8080 processor has eight 8-bit registers (A, B, C, D, E, H, L and Flags) and two 16-bit registers (Program Counter and Stack Pointer).

As you would expect, 8 bit registers deal with bytes of data, and 16 bit registers deal with memory addresses, however some of the 8 bit registers are often used in pairs to store memory addresses e.g. BC, DE and HL.

Program Counter - This 16 bit register points to the memory location of the current Opcode being executed. On completion, it increments to the next instruction address.

Stack Pointer - This points to the current memory location of the stack. The stack is an area of RAM where the processor stores useful stuff that it will need later. I will talk more about the stack further on.

Register A - Register A, also known as the Accumulator, is a special register that allows the processor to carry out all sorts of logical functions on the 8 bit value being stroed in there, as well as other standard register functions.

Registers B, C, D, E, H and L - These registers are similar to the Accumulator, being able to store an 8 bit value in each, but lack the functionality of the Accumulator when it comes to what the processor can do to these values.

Flags - This register stores the state of the five "Conditional Flags" within the processor. These will be explained later.

Note: I get all of my information from google and manuals. I have read two opposing explanations of "Flags"; one states that they are contained in an eight bit register, the other states that they ar just individual bits / switches in the processor. It doesn't matter which is correct as we can still emulate them.

To further explain how registers work, lets have a couple of examples.

Example 1:

You have just started a game and have shot your first invader. Your current score needs to have the score of that invader added to it.

1. Read the memory location of your current score in registers D and E. This will be somewhere in the general purpose RAM.
2. Read the memory location of the value of that invader into registers H and L. This may be in general purpose RAM or somewhere in the ROM.
3. Read the value stored at the memory location stored in register pair DE into register A.
4. Read the value stored at the memory location stored in register pair HL into register B.
5. Add the value in Register B to the value in Register A. 6. Write the value stored in Register A to the memory location stored in register pair DE.


Example 2:

You are copying a 100 byte area of ROM to the general purpose RAM.

1. Set register pair DE to the first memory location to be cread from in ROM.
2. Set register pair HL to the first memory location to be written to in RAM.
3. Set register B to 100.
4. Read the value stored at the memory location stored in register pair DE into register A.
5. Write the value stored in Register A to the memory location stored in register pair HL.
6. Increment DE by 1.
7. Increment HL by 1.
8. Decrement Register B by 1.
9. Repeat until Register B=0.


As far as coding goes, all of the registers can be variables within our emulator.

; 8 Bit Registers

Local A=0
Local B=0
Local C=0
Local D=0
Local E=0
Local H=0
Local L=0

Local flags=0

; 16 Bit Registers

Local PC=0
Local SP=0

Note: Program Counter can start at 0 because the space invaders code is executed from memory location 0, but this is not always the case with all Intel 8080 programs.


Conditional Flags

Conditional flags are single bits that are set or reset depending on the output of a processor function.

The conditional flags are:

1. Zero or Z flag - Set to 1 if the result of an operation is 0, otherwise its reset to 0.

2. Sign or S flag - Set to 1 if the result of an operation is a minus value, otherwise its reset to 0.

3. Carry/Borrow or C flag - Set to 1 if there is a carry i.e. if the result is greater than 255, or if there is a borrow i.e. if the result is less than 0, otherwise its reset to 0.

4. Parity or P flag - Set to 1 if the number of 1's in the byte is an odd number, otherwise its reset to 0.

5. Auxiliary Carry flag - Difficult to explain in a one liner. This flag is used in conjunction with Binary Coded Decimal and is only really used by one Opcode, so is better explained when we come to code the opcode itself.


Again as far as coding goes, all of the conditional flags can be variables within our emulator. Despite the fact that they exist in an 8-bit register, it is easier to have them as individual values and then calculate the value of the register as a whole only when we need to.

; Conditional Flags:

Local Z=0
Local S=0
Local P=0
Local C=0
Local AC=0


Opcodes

A stated above, Opcodes are processor instructions. They are read from the code in the memory area and then carried out by the processor. The Intel 8080 is an 8-bit processor so it can only take 8-bit instructions. This means that it is capable of carrying out 256 different instructions. DON'T PANIC! Most of these instructions are very simple and repeats of previous instructions with very minor changes.

Some Opcodes have a byte of data attached to it so for example if the Opcode basically broke down as "Put this value in register A.", the second byte would be "This value".

Some Opcodes have two bytes of data attached to them so again for example if the Opcode basically broke down to "Put the value in register A into this address.", then the two bytes after would be "This address".

The bytes following the instruction are called "Operands" and the overall length of the Opcode is counted in "Opbytes".

Example - Opcode 0x00 (Opcode 0 in decimal) which is a "NOP" or "No Operation" has no operands and a length of one opbyte. Example - Opcode 0xC6 (Opcode 198 in decimal) which is an "ADI" or "Add Immediate" has one operand and a length of two opbytes. The data immediately after the opcode is added to Register A.


Processor Speed / Clock Cycles

The processors speed is dictated by its "Clock". The clock feeds the processor pulses at a specific rate, and for each pulse the processor carrys out part of an Opcode. The Intel 8080a is clocked at around 2 MHz or 2 million pulses per second. Each Opcode takes a certain amount of pulses or clock cycles to complete e.g. our "NOP" opcode takes 4 clock cycles to execute, whilst our "ADI" opcode takes 7.

There are some really good websites around with Opcode tables that show each Opcode, how many Opbytes and how many clock cycles for each Opcode.

Below is an Opcode table from www.pastraiser.com which shows the name of each Opcode, how many Opbytes, how many clock cycles and what conditional flags are affected for each Intel 8080 Opcode.

The Space Invaders screen runs at 60 Hz, or 60 updates a second (60 FPS) and therefore if the processor is clocked at 2000000 cycles a second, and the screen is 60 FPS then we need to update the screen every 33333 clocks of processor time and so as we run opcodes, we must count how many clocks have been used so that we can time the screen refresh accurately.

So with all of the above in mind, we can now start writing our processor emulator code. We have already stated the register and conditional flag variables, but we need some more variables to be able to start and then we need an outer processor shell to put our opcode interpreters into.

; Processor Variables:
Local opcode
Local opbytes
Local clock_cycles
Local clock_cycle_counter
Local display_update_constant=33333

repeat

repeat

opcode=memory_array(PC,0)

; Insert Opcode Interpreter Here.

pc=pc+opbytes

clock_cycle_counter=clock_cycle_counter+clock_cycles

until clock_cycle_counter>=33333

clock_cycle_counter=clock_cycle_counter-33333

; Insert Display Update Routine Here.

Until keyhit(1)

We read the opcode value at memory location (program counter). On completion of executing the opcode we increment program counter ready to read the next opcode, and we keep a count of how many clock cycles we have used. When we have used enough clock cycles, we stop executing opcodes and update the display.

Note: Program Counter will not always increment by the number of opbytes. There may be cases where we need to skip this, or modify it to change program counter to a different location in the memory, but for now, this will do.


Lets now do some code for a typical opcode. We will do a really simple one, a "NOP" or No operation. All that this opcode does is waste 4 cycles of processor time. Its the first opcode called up in the space invaders code.
; Insert Opcode Interpreter Here.

select true

; Opcode 0x00 or 0 - "NOP"
case opcode=0
opbytes=1
clock_cycles=4

end select

And thats our first opcode done. 255 to go...Actually thats not quite true as if you check the opcode table above, you will see that there's 13 NOPs at opcodes 0x00 (0), 0x08 (8), 0x10 (16), 0x18 (24), 0x20 (32), 0x28 (40), 0x30 (48) and 0x38 (56). In this case, its more like:

; Insert Opcode Interpreter Here.

select true

; Opcode 0x00 or 0 - "NOP"
case opcode=0
opbytes=1
clock_cycles=4

; Opcode 0x08 or 8 - "NOP"
case opcode=0
opbytes=1
clock_cycles=4

; Opcode 0x10 or 16 - "NOP"
case opcode=0
opbytes=1
clock_cycles=4

; Opcode 0x18 or 24 - "NOP"
case opcode=0
opbytes=1
clock_cycles=4

; Opcode 0x20 or 32 - "NOP"
case opcode=0
opbytes=1
clock_cycles=4

; Opcode 0x28 or 40 - "NOP"
case opcode=0
opbytes=1
clock_cycles=4

; Opcode 0x30 or 38 - "NOP"
case opcode=0
opbytes=1
clock_cycles=4

; Opcode 0x38 or 56 - "NOP"
case opcode=0
opbytes=1
clock_cycles=4

end select

Ok, I think we can wrap up part 2 there. Look out for part 3 where we will be looking into opcodes that are a bit more complex than our NOP opcode above.





Friday, 28 January 2022

How to write a Space Invaders Emulator - Part 1


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.