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