Visual Nes - C++/C# port of Visual 2A03 + 2C02
Moderator: Moderators
Visual Nes - C++/C# port of Visual 2A03 + 2C02
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)
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)
Last edited by Sour on Wed Jan 18, 2017 9:56 pm, edited 2 times in total.
Re: Visual 2C02 - C++/C# port
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.
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.
Re: Visual 2C02 - C++/C# port
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.
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.
Re: Visual 2C02 - C++/C# port
Secondary OAM is at S100..S11F in Visual 2C02.Sour wrote:I don't think the secondary OAM is visible on the JS version, either?
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
Re: Visual 2C02 - C++/C# port
Whoops, you're absolutely correct. Fixed!thefox wrote:Secondary OAM is at S100..S11F in Visual 2C02.
Re: Visual 2C02 - C++/C# port
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 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.
Re: Visual 2C02 - C++/C# port
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: 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.
I decided to push this whole thing one step further: 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.
Re: Visual 2C02 - C++/C# port
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.fred wrote:Some sprite values get destroyed during the first cycles of running, but this might be intentional? The JS version does it too.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
P.S. If you don't get this note, let me know and I'll write you another.
Re: Visual 2C02 - C++/C# port
I see!
Sour: Haha! That would be quite something.
Sour: Haha! That would be quite something.
Re: Visual 2C02 - C++/C# port
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.
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.
Re: Visual 2C02 - C++/C# port
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
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
Re: Visual Nes - C++/C# port of Visual 2A03 + 2C02
Didn't think I'd live to see a transistor-level NES emulator. How long before we can do it in realtime? 

Re: Visual Nes - C++/C# port of Visual 2A03 + 2C02
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!Rahsennor wrote:How long before we can do it in realtime?
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.
Re: Visual Nes - C++/C# port of Visual 2A03 + 2C02
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.
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.
Re: Visual Nes - C++/C# port of Visual 2A03 + 2C02
This is exactly the kind of project that would benefit greatly from PGO. Perhaps even 2x or more.