I kind of went down a deep rebbit hole.
As I started to implement the ppu_mmu, I realized that I needed to
finish my mapper, and when I did that, I realized that I didn't
fully understand how VRAM worked, and once I figured that out I
realized that to make my life simpler, I had to rework how some
interfaces works.
I could keep going, but you get the point.
But hey, I think the code is a lot more robust now, so that's good!
honestly, this is just procrastination before I start the PPU.
Golly, that's going to be difficuly, er, that is... fun! Yeah!
It's gonna be so fun! so much fun...
I'll tell ya, figuring addressing modes is hard.
I only really understood them today, after something clicked in my head.
The whole point of addressing modes isn't to provide instructions with
the specific data value for their operation, but to provide addresses
at which instructions can read desired data from!
Basically, I was trying to 'dereference' the address in my addressing
mode decoder function, when in reality, all I needed to do was pass
the address down to instructions, and let them dereference it
themselves (on a case-by-case basis)
I'll tell you one thing, this whole project sure has been a learning
experience :)
Yeah, the fancy way of handling instructions looked annoying to
deal with. Maybe i'll revisit the concept at a later date, but
for now, using a classic instruction lookup table aughta do fine.
In terms of CPU architecture, I think i'm pretty happy with how I
set things up. Sure, there are some parts of the code that i'm not
super happy about, but as a first draft, I think it's not bad. I'm
sure that after implementing more of the 6502, i'll get a better
idea of how to clean up the code.
What's left to do with the CPU?
- Implement the rest of the instructions (duh)
- Implement interruprs (aaaahhh)
And hopefully, once the CPU is passing nestest.nes, I can start
working on the rest of the NES 😄
Although i've tried to keep away from peeking at the implementations
of other NES emualtors, the few glances I have seen all seem to use
a big, dumb lookup table to decode opcodes (i.e: determine the
instruction and the addressing mode)
I thought that there must be a better way, since after all, the
actual hardware does it quite compactly :)
With the help of http://www.llx.com/~nparker/a2/opcodes.html, I
explored the 6502 ISA and tried to find bit patterns that would
give me a clean, compact way to decode instructions.
Alas, the few exceptions to the rule that I am finding are proving
to be quite annoying to work around...
As such, i'm going to go to bed today, and reconsider this approach
tomorrow.
i.e: my current way of encoding opcodes is unsustainable.
I'm just trying to get a feel for how the various addressing modes
work, and how instructions tend to operate.
Also, added a unified Memory interface.
It's pretty basic (just two read / write methods), but it lets me
do some pretty neat stuff with polymorphism.
Eg: I added a Debug object called Memory_Sniffer, which can wrap
any Memory* compliant object, and it will transparently log all
memory operations going across it! Pretty useful IMHO!