I have just finished programming the NES processor in C, and was reading
http://wiki.nesdev.com/w/index.php/PPU_registers#PPUSTATUS for information about the PPU so I can begin programming it. There it says that the VBlank bit gets reset after every read from the $2002 status register. I had already programmed my entire cpu with a structure similar to this:
read = cpu->memory[memlocation];
Anyways, now I would hate to have to replace all of that code, so is there any way that I could get around this? And are there other registers like this that reset when you read them?
Thanks in advance!
PS included my cpu code just in case any of you need it.
This is a characteristic of the PPU, not the CPU. The CPU just goes "hey, whatever hardware is answering for memory location $2002, give me the byte corresponding to this location". The PPU then raises a hand and goes "that's be me, let me prepare the data for you", and as it serves the data, it happens to clear that specific flag as part of its internal logic. This doesn't concern the CPU at all.
EDIT: You can't simply use an array when accessing registers, because memory mapped registers are very different from plain memory. You probably need a method to handle memory accesses instead, and this method will take care of selecting what part of the system will respond depending on the address being accessed. Maybe other emulator authors will give you better tips on how to emulate the memory map of the NES than I can.
Think of a fetch from an address as an opaque function. Memory is mapped to the address space as you'd expect, but other devices are mapped that way as well.
Code:
read = system_read(address);
system_read would then be responsible for returning data from RAM, or info from the PPU (and acting on certain reads like $2002), or even returning the appropriate data for an open-bus situation.
Functions like system_read and system_write would trigger much of the "glue" holding the CPU, PPU, and peripherals.
Right, but just reading straight from the register using an array like the way I said is problematic still because now I have no way of telling when the cpu reads from $2002, right? Is there any way I can avoid having to rewrite so much of my code?
Precisely. That's why you will want to abstract all reads and writes from the CPU address space, so these cases can be handled.
Instead of accessing the "memory" array directly, you should call a "read" function, that will handle all the interactions between the different parts of the system. CPU, PPU, APU, RAM, ROM, mappers... all of them are mapped to the same address space, and simply accessing an array will not trigger all the consequences of accessing them.
Oh, and one more question: The reads that reset the register include reads performed by indirect addressing etc. right?
Yes. From the point of view of the hardware, it doesn't matter how the read came to be: if the address of the register ended up on the address bus, and the read signal was asserted, the PPU will respond to it.
If you want some ideas:
I have a 'Cpu' class and a 'Bus' class. When reading/writing, the Cpu class will call into the Bus class which will actually perform the read/write.
Other parts of the system can hook into the Bus by adding callbacks for a specific range of addresses. So your PPU can tell the Bus that it wants callbacks for all addresses in the $2000-3FFF range. Then, when the CPU reads/writes those addresses, the bus checks to see what callbacks are assigned to them, and calls them.
Welp, going pure C for pure speed. So using classes won't work, but I'll definitely think about making a Bus structure. Thanks!
if C just replace 'class' with 'struct'.
C++ is basically just C with goodies.