So you want to write a VIC 20 emulator? I have a feeling that the VIC 20 may be one of the easiest 8-bit home computers to emulate. I am no where near the best programmer and at the start of this project I had no idea at all how to write an emulator. The following information is based on how I did it and is not likely to be the best way. What this information might do is help someone to get started on the way to learning about the the methods involved.
In this page I will take you through the steps that I took in writing V20. I will also attempt to make available documentation on how some of the VIC 20's hardware works for those who don't have such details in manuals at home.
Where to start is always a problem no matter what the task. I began by observing other existing emulators and how they operated. The most revealing sources of information are those emulators whose source code is also available. You will find the BBC emulator BeebWin of particular interest because the BBC uses the same 6502 processor and 6522 VIA chips. The source code for VICE is also very useful. If you are looking for a good example of graphics emulation, check out the source code for Frodo (the C64 emulator) because the C64 has very similar graphics modes to the VIC 20.
These emulators gave me a general idea, but to fully understand what needed to be done, I asked the author of an existing emulator for a broad overview. I will now give you such an overview of my emulator.
I have a 64K area of memory which represents the VIC's memory. A main emulation routine gets the instruction byte from the program counter, and with a huge switch() statement jumps to the appropriate routine for that opcode. Memory accesses to main memory go through a 'write memory' routine; if the memory-maped I/O is being accessed then another routine is called which will emulate the writing of that particular byte (change screen parameters, timers etc). If RAM is being accessed then that address is changed; and ROM writes are masked out.
The VIC also has some timers which need updating, polling of hardware such as the keyboard, IRQ's that need to be processed and a scanline needs to be drawn at regular intervals. I achieve this by breaking out of the main loop every so often. My emulator is currently scanline based, so after a scanlines worth of cycles, it will:
It really depends how accurate you want the emulation to be. If you want to get raster effects working properly, then you will probably want to update the timers and check for interrupts after every instruction.
This is probably the very first thing that you need to emulate. The reason for this is that everything else uses the memory. To start off with you need a 64Kb array to hold the VIC 20's memory. Your emulator will allocate this memory and then load the BASIC, KERNEL, and character ROMs into memory at their relevant places. You then need some way of reading and writing to this memory. This is not simply a matter of storing and retrieving data from the array in the normal way. You have to go through a function that will behave in the way that the VIC would behave if that bit of memory is being written to or read from. For example, writing to some of the VIC chip registers will change the appearance of the screen or change the sound that's being produced, and reading from some of the VIA registers causes certain events to take place.
So what you typically have is a set of functions that read and write to particular parts of memory. For example, readRom(), readRam(), readVIC(), or whatever. You then need some way of knowing which read and write routines to call for each memory location in memory. Have a look at the source code for M.A.M.E to see how they deal with this, especially the driver information for each game. What I do for the current version of V20 is have two arrays of function pointers, one for the read functions and one for the write functions. When a read or write occurs, the relevant function pointer is used depending on the memory location. Note that when your emulator is reading opcodes from memory, it should be able to access the memory array directly since the programs are not stored in memory mapped I/O locations. This can speed up your emulation quite a bit.
Now, the next thing you have to emulate is the memory expansion capabilities. The VIC 20 determines how much memory it has got by writing values to memory and seeing if those addresses retain their value. If they don't, then it knows that there is no RAM at that location. The memory addresses concerned are given in the memory maps in the links below. It is simply a matter of mask out writes to the relevant address ranges so that the correct expansion is represented. The VIC 20 roms that you have loaded will take care of the rest.
Once you have your memory routines in place, you can start coding your 6502 emulation. Of course, you don't have to bother with this if you don't want to. There is plenty of source code available for doing this already. Marat Fayzullin has some very good C code that emulates the 6502, and there are many others as well including the emulators that I mentioned earlier. There are even a number of assembler versions around.
Despite all this, you might still want to have total control. I can't cover all the details here, so I suggest reading the documentation on the 6502 and have a look at the source code I mentioned above. What I can give here are a few tips. Yes, you do need to emulate the ADC and SBC BCD modes perfectly. These two instructions are probably the most complex, so make sure you've got them working correctly. Most of the other instructions are relatively straight forward.
When the 6502 code is complete, you will want some way of checking each instruction to see if it is working correctly. The best way to do this is probably to write a little debugger that you can step through some 6502 code with.
I always like to write the graphics functions very early on, in fact you don't need to have the 6502 to test whether the graphics routines are working. There are a number of approaches to graphics emulation. You could have full screen emulation, scanline based emulation, instruction based emulation, or cycle based emulation. Once again it all depends on whether you want to run programs that use raster effects or similar techniques that need absolute accuracy.
Read the relevant VIC 20 graphics documentation to get the details of how to interpret the screen, character, and colour memory when drawing a scanline or whatever method you decide upon. Check out this Wikipedia page for a good explanation of terms such as "blanking", "retrace", "back porch", etc. that are commonly used in emulator circles. This information is also of benefit if you plan to create some tweaked modes of your own with something like Robert Schmidts tweak utility.
A more aesthetic problem with graphics emulation is that the VIC 20 uses a very strange graphics resolution. The visual dimensions that I measured are about 208x264, i.e. this is the size that I see on my TV. So to make the emulator output look like the original TV screen, you have to find some way of making this resolution full up the whole screen. I created a tweaked mode for doing this but it only seems to work with some peoples graphics cards and monitors (it no longer works with my new S3 card).
At this stage you should be able to combine the memory, 6502, and graphics emulation together and you will actually get through to the boot up message. However, in order to see the cursor flashing, you need to emulate the timer that controls this. The VIC 20 contains two 6522 VIA chips that provide these timing facilities. They also provide most of the I/O such as the joystick, keyboard, user port, and serial port. The emulation of these chips can be the source of many problems, so make sure that you get it quite accurate. There are a lot text documents on the Internet that explain the operation of this chip. Check out the 6522 documents below.
If you have completed the 6522 emulation but havn't yet emulated the hardware such as the keyboard that interfaces with this chip, then your emulator will show a flashing cursor but you will be unable to type anything in. The operation of the keyboard is best described in the following text document that I put together.
The VICE source code will show you how you might go about implementing this part.
Once your emulator emulates everything mentioned above, i.e. the memory, 6502, VIC chip, 6522 chips, and keyboard, then you will be able to interact with BASIC in much the same way as you did with your real VIC 20. At this stage the emulator is very close to being complete. What you will want to emulate now are the luxuries such as joystick control and sound. Read the following two documents for information on how to do this.
With these two features implemented, you will be able to play the vast majority of games that are available.
It is all very fine to has a nice functioning emulator, but how on earth do you load the games into memory so that they can be run on the emulator? Well, there are a number of different types of program available with different extensions, but most of them come under the title of either cartridge or BASIC program. They are listed below:
|$2B, $2C||Start of text|
|$2D, $2E||Start of variables|
|$2F, $30||End of variables|
|$31, $32||End of arrays|
|$33, $34||End of strings|
|$37, $38||Top of memory|
|$AE, $AF||End of Program|
If you want to see an example of how to adjust these pointers, the VICE source code has an example of this. When these pointers are adjusted, then you resume the emulation and the user will type RUN to execute the program.