Visual Nes - C++/C# port of Visual 2A03 + 2C02

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Visual Nes - C++/C# port of Visual 2A03 + 2C02

Post by Sour »

Edit: Now also contains the visual 2A03's core - see posts below for more info.

I originally intended to modify the Visual 2C02's code to improve its performance and add a few features, but after a day of trying to optimize every single detail of the JS code, I realized it wasn't going to be fast no matter what I tried.

So here I am, 2 days later with a C++/C# port that runs ~20 times faster than the original JS version does in Chrome (on my computer at least).
On my old i5, it simulates the chip at 6000-9000hz, while tracing a bunch of stuff. (A full frame takes about 30 seconds)
In comparison, I usually got to about 400hz on the JS version with similar tracing (~10 minutes for a frame).

Obviously, this is all based on Quietust's work, which is based on the Visual 6502 - so all credits to him and the folks behind the Visual 6502.
I simply converted the JS code to C++, with relatively few modifications (aside a few optimizations).

This version adds a few features: log the trace to a file, select nodes to trace from a list, load/save state to files, load/save ram content
It also emulates the full $0000-$2FFF memory range for the PPU.
It's still missing some things, though - most notably, I did not port the code that draws/animates the actual chip yet.

Code: https://github.com/SourMesen/VisualNes/
Windows binary: http://www.mesen.ca/VisualNes.zip
Linux: There is a makefile included, it seems to run fine on Mono from the few tests I did.

Hopefully this is useful for someone else!
Let me know if you find any issues.

EDIT: Replaced download link with a statically linked version (no longer requires the VC2015 runtime to be installed to run)
Visual2C02.png
Last edited by Sour on Wed Jan 18, 2017 9:56 pm, edited 2 times in total.
fred
Posts: 67
Joined: Fri Dec 30, 2011 7:15 am
Location: Sweden

Re: Visual 2C02 - C++/C# port

Post by fred »

Cool! Gonna give it a try. I wanted to look into sprite hits anyway!

Edit: Tried it out, seems to work well! I really like the regex node search, haha. Some things -

The "next scanline" button jumps a whole scanline instead of to the beginning of the next scanline. This goes for all the "next x" buttons. I don't really mind, but it differs from the JS "next x" buttons.

Secondary OAM isn't viewable.

Some sprite values get destroyed during the first cycles of running, but this might be intentional? The JS version does it too.
Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Re: Visual 2C02 - C++/C# port

Post by Sour »

Yea, I'm aware of the difference between the next pixel/scanline buttons - the way I have it now was just easier to implement, so I was lazy. In the end, I feel like having both options available would probably be best (at least for the scanline/frame options)

I don't think the secondary OAM is visible on the JS version, either? Adding this would probably require finding out which nodes correspond to the secondary OAM (this is how the code works for the sprite & palette ram). I don't know enough about chips to ever hope to find this information myself, though.

The sprite ram being overridden is because of the "Program" (bottom left) that's loaded up by default - it makes some writes to registers and fills up some of the sprite ram with preset values. You can erase the program and then reset to make sure it doesn't do that.

Also, I just finished porting some more features over - the chip is now visible and you can highlight nodes/zoom/pan it.
-Double-click to zoom in, right click to zoom out (or use the mouse wheel for both)
-Click and drag to pan
-Click on a node to get its name/highlight, Shift-click to select a group of connected nodes

I updated the download link in the first post.
Visual2C02.png
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: Visual 2C02 - C++/C# port

Post by thefox »

Sour wrote:I don't think the secondary OAM is visible on the JS version, either?
Secondary OAM is at S100..S11F in Visual 2C02.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Re: Visual 2C02 - C++/C# port

Post by Sour »

thefox wrote:Secondary OAM is at S100..S11F in Visual 2C02.
Whoops, you're absolutely correct. Fixed!
fred
Posts: 67
Joined: Fri Dec 30, 2011 7:15 am
Location: Sweden

Re: Visual 2C02 - C++/C# port

Post by fred »

Sour wrote:The sprite ram being overridden is because of the "Program" (bottom left) that's loaded up by default - it makes some writes to registers and fills up some of the sprite ram with preset values. You can erase the program and then reset to make sure it doesn't do that.
That's the thing, some values just gets destroyed even if you remove the program. I think it's just intentional, but why I don't know.
Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Re: Visual 2C02 - C++/C# port

Post by Sour »

About the OAM values being destroyed - the 3rd byte of every entry loses some of the bits, this is normal. But beyond that, I'm not too sure.

I decided to push this whole thing one step further:
visualnes.png
A 2A03 & 2C02 running in the same simulation, connected to the same CLK and RESET lines. Still far from being done, though.
Technically, couldn't I just connect some of the data/address buses (not quite sure which!) and have a working "NES"?
If I go that far, wouldn't it be simple to run NROM test roms & get a "perfect" trace of what happens?

It still runs at ~5000Hz even with both chips in the simulation, so it should be able to run about 1 frame per minute. An hour for a second, that's not too bad considering most test roms take only a second or 2 to complete.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Visual 2C02 - C++/C# port

Post by Quietust »

fred wrote:Some sprite values get destroyed during the first cycles of running, but this might be intentional? The JS version does it too.
If you don't fully initialize every byte of Sprite RAM, then this sort of thing will happen because the DRAM cells themselves initialize (and would normally decay) to an "indeterminate" state in which they are neither 0 nor 1 and will acquire a new value during refresh.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
fred
Posts: 67
Joined: Fri Dec 30, 2011 7:15 am
Location: Sweden

Re: Visual 2C02 - C++/C# port

Post by fred »

I see!

Sour: Haha! That would be quite something.
Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Re: Visual 2C02 - C++/C# port

Post by Sour »

Still not quite finished, UI-wise, but I've managed to hook up both cores together.

I loaded up one of blargg's NROM tests into it - the code waited for the vblank flag in a loop reading $2002 until the PPU set the flag, at which point the CPU continued its execution. I'd imagine the cores are working properly if this much works.
Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Re: Visual 2C02 - C++/C# port

Post by Sour »

I've mostly finished integrating the Visual 2A03 core into it. Renamed the whole thing to "Visual NES", since that just makes more sense at this point (the name may very well be taken by something else, but I'm not too worried about it :p)

It supports loading .nes ROMs and is meant to reproduce the NES' environment - $800 ram with mirroring, NT mirroring, etc.
A lot of this hasn't been tested that much, so if you find issues, please let me know.

Code: https://github.com/SourMesen/VisualNes/
Windows binary: http://www.mesen.ca/VisualNes.zip
visualnes.png
Rahsennor
Posts: 479
Joined: Thu Aug 20, 2015 3:09 am

Re: Visual Nes - C++/C# port of Visual 2A03 + 2C02

Post by Rahsennor »

Didn't think I'd live to see a transistor-level NES emulator. How long before we can do it in realtime? :lol:
Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Re: Visual Nes - C++/C# port of Visual 2A03 + 2C02

Post by Sour »

Rahsennor wrote:How long before we can do it in realtime? :lol:
Currently runs at about 1/1000th of the speed of the NES. If you could somehow speed up the code 10 times over by splitting the workload onto multiple cores and optimizing the code, and then use a more recent CPU than mine, you might be down to around 1/50th of the speed. So.. I guess somewhere around 2040 we might be able to get it done!

For now I'm mostly interested in using this to compare execution traces with Mesen for the couple of tests it still doesn't pass and try to figure out why.
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: Visual Nes - C++/C# port of Visual 2A03 + 2C02

Post by Memblers »

I don't have much to say other than good job, the performance upgrade with this port is fantastic. And I always thought it would be cool to see Visual 2A03 and 2C02 combined.

Seems that it doesn't like loading 16kB NES files, but that's not a big problem (easily solved by making it 32kB).

From what I understand, the NES CPU and PPU has several different clock alignment possibilities determined at power-on (or is it reset?). Maybe that's something that could be included in this? I'm not saying that I need it myself though, or that I know what would be involved exactly.
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Visual Nes - C++/C# port of Visual 2A03 + 2C02

Post by calima »

This is exactly the kind of project that would benefit greatly from PGO. Perhaps even 2x or more.
Post Reply