Wednesday, October 20, 2010

I have pretty much completed the cpu portion of the emulator. Emulating the cpu isn't very difficult. Its functionality is well known. It fetches an opcode, processes it, and updates multiple flags. Probably the hardest thing is finding documentation on what each opcode does exactly and how each flag is updated. Not too bad. Some documentation might be a little misleading or a little tough to read -- some of it is written by professional writers, but not much -- there's a lot of it, though, so if you don't understand something there are about 50 other places to look.

Emulating the ppu is a lot harder. Now we're getting into the meat of the system. Again, finding documentation is harder. Also, because the exact functionality of this portion of the system isn't as well understood by me I'm a lot more reliant on documentation. Not to mention the fact that the cpu is used all over the place and is well documented by various people. Not so with the ppu. The ppu is proprietary and any documentation that exists was written by individuals who either experimented on an actual NES or read other documentation elsewhere. None of it is written by professional writers and quite frequently is a work in progress. Kind of like this blog.

So now we're getting to the point that my emulator is actually doing something. Not very much, mind you, but something. It runs for the first 20 or so opcodes then it gets into a position where the opcodes are having it read the ppu state registers to determine whether or not the ppu is in a vblank. Because my ppu is largely unwritten and the registers aren't implemented yet, this doesn't happen and the cpu pretty much just sits there waiting.

The systems all interact via various specific positions in memory. For instance, to set various features on the ppu you can write to addresses 0x2000 and 0x2001. To read what state the ppu is currently in you read from 0x2002. In 0x2002 is a number between 0 and 256 (0x00 and 0xFF). Each bit in that number indicates something about the ppu. For instance, the highest bit -- the bit on the furthest left side of the binary number -- indicates whether or not the ppu is in a vblank period, which is the period in which the television is resetting itself so that it's ready for the next frame. Vblank happens 60 times a second. Interestingly, there are some registers that you should only read from or write to during vblank because reading or writing to or from them when the ppu is drawing the frame affects that frame.

So right now I'm in the process of implementing these registers not to mention the timing mechanism for system so that I can attempt to make the system run at the right speed so that lines are being drawn when they're supposed to be drawn and things run at the expected rate. It's tough work and is quite shittily written at this point. The main loop will probably prove to be pretty buggy. It would clearly have been easier to write a 2d game than to try to emulate the NES. That said, in my opinion this is a far cooler project and one that I'm pretty happy to be involved in. I'm trying to be careful in writing my code, but am also of the opinion that writing dirty code that kind of works helps to understand the problem space and helps you to get to the point that you can clean up the code. It's not an efficient process. It's not agile. But it has its benefits. I feel it works pretty well for hobby projects with a large problem space anyway.

No comments:

Post a Comment