Emulating NES CPU and PPU on PIC32, too slow?

Let's talk about anything related to the 6502 microprocessor.
sburrow
Posts: 833
Joined: 09 Oct 2021
Location: Texas

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by sburrow »

Here's an update!

I've slowly added features to my 'fake' PPU. In fact, I'm by-passing the whole PPU idea entirely! This might not be accurate later, but it seems to work really well right now. I now have backgrounds and sprites and most of their associated features.

On top of this, I figured out a way to 'double buffer' my screen so that I can draw to one while it draws the other, then switch. At 70 FPS (my screen's refresh rate) the game seems to run at 100% speed. If I drop it to 35 FPS it's definitely too fast which is a good sign.

But, as you might see with the attached GIF, Mario isn't moving, Donkey Kong gets him every time! He wants to run, but cannot. I've also tried Mario Bros, and the Kuppas just fall right through the ground, as does Mario. Very strange behavior. I'm thinking one of my instructions isn't right. I've tried a few test roms, and I think they are saying my CMP function isn't right.

Remind me again, is CMP the same as SBC but without changing A? On NesDev.org they have two different 'formulas': one for CMP and one for SBC. That might be because of optimization purposes, but a good reminder would be nice :)

Thank you everyone! It seems this project just might work in the end!

Chad

Edit:

Here is the code I'm using for CMP and SBC.

Code: Select all

#define CPU_CMP { \
	cpu_flag_c = (cpu_reg_a>=cpu_temp_memory); \
	cpu_flag_z = (cpu_reg_a==cpu_temp_memory); \
	cpu_temp_memory = ((cpu_reg_a-cpu_temp_memory)&0x00FF); \
	cpu_flag_n = (cpu_temp_memory>>7); }

#define CPU_SBC { \
	cpu_temp_result = cpu_reg_a-cpu_temp_memory+cpu_flag_c-0x01; \
	cpu_flag_c = !(cpu_temp_result>0x8000); \
	cpu_temp_result = (cpu_temp_result&0x00FF); \
	cpu_flag_z = (cpu_temp_result==0x0000); \
	cpu_flag_v = ((cpu_temp_result^cpu_reg_a)&(cpu_temp_result^(cpu_temp_memory^0xFF))&0x80); \
	cpu_flag_n = (cpu_temp_result>>7); \
	cpu_reg_a = cpu_temp_result; }

Attachments
DK_VID.gif
DK_VID.gif (3.68 MiB) Viewed 3064 times
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by BigEd »

Run the Dormann test suite! It’s the best way
barnacle
Posts: 1831
Joined: 19 Jan 2004
Location: Potsdam, DE
Contact:

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by barnacle »

CMP doesn't care about decimal mode but SBC does; does the NES cpu have decimal mode? (I don't know anything about the NES)

Neil
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by BigEd »

(No, the NES famously chopped out the decimal mode)
barnacle
Posts: 1831
Joined: 19 Jan 2004
Location: Potsdam, DE
Contact:

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by barnacle »

Ah, I knew one of the consoles had, but I couldn't recall which. In which case, ignore my comment.

Neil

p.s. ah, doh, of course, the CMP doesn't care about the carry and the SBC does.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by barrym95838 »

Code: Select all

   cpu_flag_c = !(cpu_temp_result>0x8000); \
I haven't finished my first coffee yet, but something here seems a bit "off" to me ... and does your other code expect cpu_flag_v to be 0x80 occasionally?
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)
sburrow
Posts: 833
Joined: 09 Oct 2021
Location: Texas

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by sburrow »

barrym95838 wrote:
does your other code expect cpu_flag_v to be 0x80 occasionally?
Oh wow, good eye! I was directly copying it from NesDev.org (here https://www.nesdev.org/wiki/Instruction_reference#SBC), but they meant it as a boolean. I just used >>7 to make it result in 0 or 1 now. Thank you Mike!
BigEd wrote:
Run the Dormann test suite! It’s the best way
I found that, but I didn't see an NES rom equivalent. I know it wouldn't be *too* much work to re-create for the NES, but I haven't ever used CA65 and it the macros are making my head spin :)

Small update: I got Mario to move in Donkey Kong now! It was something silly with my zero-page instructions I think, where I was sending a memory value instead of an address. Oh well! But Mario and the Koopas are still falling through the floor in Mario Bros. I've run a few other tests but I haven't found anything conclusive yet. I'm sure it's something small.

So, do I try to fix this issue with Mario Bros now? Or do I move on to other features like scrolling, controller input, and audio? I'm really wanting to make sure all of these basic games work well, and I have heard Mario Bros is one of the easier ones to emulate, so I do feel fairly obligated to sit on this one until I can get it to work right.

Anyways, thank you everyone!

Chad
John West
Posts: 383
Joined: 03 Sep 2002

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by John West »

An alternative to running a test suite is to write your CPU simulator twice. You have your main one, written with whatever constraints you have in mind (I'm guessing in this case it'd be speed), and the other one which is as simple and obviously correct as you can make it. The key is that they are completely independent implementations - don't be tempted to share anything between them. Have the second written by a different person if you want/can.

Run them in parallel, and compare register values and memory accesses after every instruction. If they differ, it doesn't matter which is wrong - you know exactly what to investigate.

And also run a test suite. It'll catch things that other programs won't.
sburrow
Posts: 833
Joined: 09 Oct 2021
Location: Texas

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by sburrow »

Well! THAT was a long time debugging :) Can you see what I was doing wrong?

Old Code:

Code: Select all

#define CPU_ROL { \
	cpu_temp_memory = cpu_read(cpu_temp_address); \
	cpu_flag_c = (cpu_temp_memory>>7); \
	cpu_temp_memory = (((cpu_temp_memory<<1)&0x00FF)|cpu_flag_c); \
	cpu_write(cpu_temp_address,(unsigned char)cpu_temp_memory); \
	cpu_flag_z = (cpu_temp_memory==0x0000); \
	cpu_flag_n = (cpu_temp_memory>>7); }

#define CPU_ROR { \
	cpu_temp_memory = cpu_read(cpu_temp_address); \
	cpu_flag_c = (cpu_temp_memory&0x01); \
	cpu_temp_memory = ((cpu_temp_memory>>1)|(cpu_flag_c<<7)); \
	cpu_write(cpu_temp_address,(unsigned char)cpu_temp_memory); \
	cpu_flag_z = (cpu_temp_memory==0x0000); \
	cpu_flag_n = (cpu_temp_memory>>7); }
New Code:

Code: Select all

#define CPU_ROL { \
	cpu_temp_memory = cpu_read(cpu_temp_address); \
	cpu_temp_memory = (((cpu_temp_memory<<1)&0x01FF)|cpu_flag_c); \
	cpu_flag_c = (cpu_temp_memory>>8); \
	cpu_temp_memory = (cpu_temp_memory&0x00FF); \
	cpu_write(cpu_temp_address,(unsigned char)cpu_temp_memory); \
	cpu_flag_z = (cpu_temp_memory==0x0000); \
	cpu_flag_n = (cpu_temp_memory>>7); }

#define CPU_ROR { \
	cpu_temp_memory = cpu_read(cpu_temp_address); \
	cpu_temp_memory = (cpu_temp_memory|(cpu_flag_c<<8)); \
	cpu_flag_c = (cpu_temp_memory&0x01); \
	cpu_temp_memory = (cpu_temp_memory>>1); \
	cpu_write(cpu_temp_address,(unsigned char)cpu_temp_memory); \
	cpu_flag_z = (cpu_temp_memory==0x0000); \
	cpu_flag_n = (cpu_temp_memory>>7); }
Answer at bottom!

Mario and Luigi are now running around smoothly, bopping Koopa's (and themselves)! Here's a short story of the journey:

So all of the sprite would just fall immediately to the bottom of the screen. Eventually they even started corrupting memory! In the disassembled code, I found where they check if a block is solid or not solid. I traced it backwards to a place where it was reading from PPU memory to know what that block ID was. I investigated and indeed all the block ID's were there, so it must have been accessing the wrong ones. Since I've programmed 6502 games before, I knew that the X and Y positions were being used to find which block, and the math to get to the correct result must have been wrong. What math do you need to convert 256x240 xy-position to a 32x30 coordinate system? Bit shifting! I checked ASL and LSR and they seemed fine, so I really honed in on the ROL and ROR instructions, and eventually found my mistake. Hm!

That was about 3 days of debugging I'd say. Wow. And I'm happy for it, because I fixed some other PPU issues along the way, so later games will work better now too.

There we have it :) Now onto more features. Thanks everyone!

Chad


****


Answer: I was overwriting the carry bit before shifting.
sburrow
Posts: 833
Joined: 09 Oct 2021
Location: Texas

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by sburrow »

John West wrote:
An alternative to running a test suite is to write your CPU simulator twice.

And also run a test suite. It'll catch things that other programs won't.
That actually is a really good idea! Sometimes when something isn't working, I literally scrap the entire thing and start over. Sometimes that's actually faster.

I haven't got any test rom to run and give me useful feedback yet. They all lock up or just spit out weird things I don't understand. Hopefully that'll change over time.

Thanks!

Chad
sburrow
Posts: 833
Joined: 09 Oct 2021
Location: Texas

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by sburrow »

Howdy :)

See attached! I put in the video of the Mario Bros demo just for fun, but the real update is my attached code. I added controller support and everything is working very smoothly! My PIC32 boards use the Sega Genesis controllers, so I had to remap the buttons a bit, but it still works really well.

I have also been trying to make the code very portable. I have a small handful of functions that are system specific (and labelled so), but the majority of the code is universal.

This still only supports NROM games, that is simple games without a mapper. Second, it does not yet have PPU scrolling. Third, the V-SYNC signal is free-running, meaning how fast a game goes is really up in the air at this point. Lastly, it also does not yet have audio, but that's next on my list. My goal is to make Mario Bros and Donkey Kong 100% solid, then move on to scrolling for things like Excitebike or Ice Climbers. Super Mario Bros is apparently hard to emulate, so that's not on the immediate radar.

It is fun being back in 6502-land for a while! Thanks for having me back :)

Chad
Attachments
MarioBros.gif
MarioBros.gif (6.95 MiB) Viewed 2911 times
nes.c
(34.87 KiB) Downloaded 141 times
John West
Posts: 383
Joined: 03 Sep 2002

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by John West »

sburrow wrote:
I haven't got any test rom to run and give me useful feedback yet. They all lock up or just spit out weird things I don't understand.
"Locking up" is the way Klaus Dormann's test suite tells you about errors. If there's a jmp or a branch to itself, the test it is currently doing has failed. It keeps track of the currently running test in test_case, but I found it easier to just print out the address when the simulator noticed one of these branches, and look up in the assembler's listing file to see what that bit of the code is doing.

Even if everything works fine, it can look like it has locked up. These tests take a while to run.
sburrow
Posts: 833
Joined: 09 Oct 2021
Location: Texas

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by sburrow »

Way over a week in total, 6 straight hours just this morning, and now IT FREAKIN' WORKS! :)

I was debugging Ice Climber because the fruit in the bonus stage was not turning invisible when I touched it. Using Mesen debugger, my UART, and a bunch of testing, I finally found out my issue. I was not setting the N and Z flags after using PLA. That was it. Wow, SOOO many hours just on that :) After that, I switched games and Super Mario Bros suddenly worked 'properly'!

And by properly, I mean it needs a lot of help. The Sprite 0 Hit isn't perfect yet, so the stats bar at the top flashes sometimes. Also, I think the audio envelope or timing is off or not stopping or something because stomping on a goomba is like "WoooooOOOOOOOO!!!!!!!!" instead of a simple "Womp" sound effect. Also you can see the classic "black sky" feature which means I haven't figured out the PPU palette well enough or something, IDK.

Well there ya have it. Another day in 6502 land :) Thanks everyone!

Chad
Attachments
SMB.jpg
sburrow
Posts: 833
Joined: 09 Oct 2021
Location: Texas

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by sburrow »

Alright! I have a "really nice" NES Emulator now! It currently only runs a bunch of NROM games, though even Super Mario Bros is pretty solid! The only issues left are that the audio makes a humming/clicking noise constantly, and there are some minor graphical issues still. Overall though it really is doing very well for what I previously had thought was impossible on this PIC32.

And I know what the issues are with the audio and graphics. The humming/clicking is due to an audio buffer overflow, which in theory shouldn't happen, but it is anyways. The graphical issues are mainly due to cycle and v-sync timing. I have to play with it a lot more to get it perfect.

For the past couple of days I have been REALLY figuring out this APU thing. I had to whittle down each tiny issue with each audio channel, and one of them took nearly 12 hours of debugging to figure out. Nothing is perfect, but at least it's close enough. I haven't been able to test the DMC audio yet, I'll try some specific game intros that use it soon.

If you want to see my full code, it's located here temporarily:

https://github.com/stevenchadburrow/Aco ... in/Testing

Check back at the main project folder later when I fully implement it. Right now I have a really basic menu to select from pre-placed games on the SD Card.

The next step is MMC1 mapper games, such as Legend of Zelda, Metroid, Dragon Warrior, Final Fantasy, Bionic Commando, etc.

That's all I got for now! Thanks everyone :)

Chad

EDIT: You can see in the GIF that the top stats are flickering a bit. That's one of those minor graphical issues :)
Attachments
nes.c
(57.44 KiB) Downloaded 123 times
SMB.gif
SMB.gif (7.88 MiB) Viewed 2763 times
User avatar
AndrewP
Posts: 368
Joined: 30 Aug 2021
Location: South Africa

Re: Emulating NES CPU and PPU on PIC32, too slow?

Post by AndrewP »

Looking really good! It must be so satisfying to have that up and running 8)
Post Reply