Wednesday, October 4, 2017

Emulating Memory

The 2600 emulator is going to need memory. As it is based on the 6502 processor, we know that at most it has 16 bits worth of memory which is very little for modern processors. The obvious solution then is the following code:

unsigned char memory[65536];

Sadly, it is not going to be that easy. This is for several reasons. First, the 2600 used a cheaper version of the 6502 which only had 13 address lines not 16 so only 8192 bytes were addressable. Making this even worse is the fact that only 12 of these were for the cartridge, so cartridges were limited to 4096. Some of you are probably thinking, “Wait a second, Bill, weren’t there 8K, 12K, and 16K cartridges for the 2600?” Yes, there were. This leads to the real problem with the above approach.

Because of the memory restrictions of the cartridges, developers who needed more memory for increasingly complex games had to come up with ways around this. The solution that was used was several different bank-switching types of cartridges. The idea here is that a chip on the cartridge would act as a go-between giving the console different memory based on certain actions by the program. The memory management unit could detect things like reading or writing to a certain address and would use this to determine which bank of memory would be in place. This means that we are going to need to be able to know when memory is read or written to so we can handle such situations.

The next issue is the fact that cartridges were ROM. You cannot write to ROM.

As is common with common with computers, some memory is often mapped out to hardware devices so you communicate with this hardware by reading and especially writing to memory within a certain address range. This is how you set up the TIA chip for displaying things on the screen. There are a few other IO operations that also work this way (though I believe they are handled by different chips).

So emulating memory is not going to be that easy. My initial plan is to break up memory into a cartridge loader and a MMU class that can be overridden to support several types of bank-switching schemes. The cartridge loader would be responsible for determining which MMU to use and then giving the MMU the ROM data. There could be different cartridge loaders as well, and I plan on having two. The first would be a very basic file-based loader that would be used during development and would simply load the ROM file from the hard drive. Emscripten, the tool that I am using to compile C++ into asm.js, does let you load files but does so using a virtual file system. This is a bit of a pain so another cartridge loader which would be more web-friendly and be designed to so that I don’t need to deal with virtual file systems to change cartridges on a web page.

This project is being developed relatively live. This means that I am writing this as I work on the project. I am hoping I can get a few articles ahead of what I am posting but do want to keep what I post on this blog accurate to what I am going through as I develop this project so that readers can learn from both my successes and my failures. Tonight I am going to start coding and hopefully next post we will finally start seeing some of the code.

No comments:

Post a Comment