Got any tips for Early NES Emulator Development?

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

User avatar
MottZilla
Posts: 2835
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

Well, what you're saying can't be entirely true. Battletoads runs on my emulator and doesn't lock up. However, that's probably because Sprite Hit is faked. "Lockups" with the game seem to happen because it's stuck waiting for the flag to be set.

Like I said the game runs, and I managed to get the scroll updates partially correct. It's always the correct scroll, give or take 8 pixels. I tried to get it to work with those 8 pixels. But these scrolling tricks seem to tell me that I may be handling drawing the screen in a way that won't work out so well for these tricky games. Forinstance, I do have Scroll X and Scroll Y registers I draw the screen by. I don't keep track of the VRAM Pointer other than for I/O. It seems though that you should be using VRAM's Pointer to base your rendering off of and such.

I've been thinking with Sprite Hit that I'd have to redo the whole rendering anyway. But I'm pretty sure these changes to the VRAM pointer are the reason for all the scroll issues in games on my emulator.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Disch wrote:Plus inline (which is a standard keyword) does the same job. The only difference is that __forceinline doesn't detect conditions where inlining isn't favorable. You say it's favorable for CPU functions and I don't disagree -- but the truth is you shouldn't substitute your judgement for the compiler's.
Unless the compiler's judgment is failing. Compilers have become smarter over the past couple decades, but they're still not perfect at determining which functions could benefit from inlining. It's entirely possible that with a given combination of compiler and CPU, #define FORCEINLINE __forceinline might produce a faster time for the test suite than #define FORCEINLINE inline. But before you start doing funny stuff like this, make sure your test suite works.
But again -- this is another reason to #define calling conventions
Agreed. The tradeoffs vary based on instruction set, microarchitecture, and compiler. When compiler flags aren't enough, macros are a comparatively clean way to abstract over this.

But why even care about speed? My 7-year-old PC runs a game in Nestopia with NTSC filter at 60 fps. Maybe you want to make a ROM picker that looks like PS1 demo discs or Wii Menu, emulating 12 systems at once.
WedNESday
Posts: 1231
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Post by WedNESday »

MottZilla wrote:Well, what you're saying can't be entirely true. Battletoads runs on my emulator and doesn't lock up. However, that's probably because Sprite Hit is faked. "Lockups" with the game seem to happen because it's stuck waiting for the flag to be set.
Well since your Sprite #0 code is faked, then the results cannot be relied upon no matter whether all games work perfectly or not. It's no good saying 'Oh, game X works fine but game X doesn't' or 'I've had no problems so far with my Sprite #0 code'. It just doesn't count.
tepples wrote:But why even care about speed? My 7-year-old PC runs a game in Nestopia with NTSC filter at 60 fps. Maybe you want to make a ROM picker that looks like PS1 demo discs or Wii Menu, emulating 12 systems at once.
It's good practice to make an emulator as fast as possible. In fact it's necessary. If you had to choose between a fast emulator and a slow emulator with the same compatibility, which one would you use?. And frankly, if you make a NES emulator that requires a Pentium Quad-Core 2.66Ghz with 4GB RAM, then to put it politely, your programming skills blow big time. Plus I think it's good fun too. I could write an emulator for any console very quickly, but it would be full of switch/case statements and such and would have 1FPS at most. When writing an emulator, I believe it's speed that dictates most of our time and effort.
User avatar
MottZilla
Posts: 2835
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

Well that's true, but I just think it's misleading not to point out that the game gets locked up because of an endless S0Hit loop. Afterall Nesticle played the game. ;p

I do agree that you should make atleast a reasonable effort to make your code efficant so the requirements aren't up in space. Though you could always do some optimization later on.
WedNESday
Posts: 1231
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Post by WedNESday »

MottZilla wrote:...Afterall Nesticle played the game. ;p
:lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol:
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

MottZilla wrote:Well that's true, but I just think it's misleading not to point out that the game gets locked up because of an endless S0Hit loop. Afterall Nesticle played the game. ;p
You are joking. Anyway, go ahead and write your stuff. Once it's working, congrats. It's enough for me.
User avatar
MottZilla
Posts: 2835
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

Yes I'm joking. Because we all know Nesticle is the best. >:p

But back to things that matter. Do you guys have your emulators keeping track of a VRAM Pointer, or VRAM Pointer and a Reload value for it? And then do you go along updating the pointer as you render and then update it according to various things like register writes? And ofcourse do you use it for rendering?

I ask because when I started I didn't know much, so I just assumed you have Scroll X register and Scroll Y register, which I know now that they don't exist. But my emulator takes Scroll X and Scroll Y from $2005 register writes and that is how I base what is drawn from. This worked until I got to games that are manipulating the VRAM pointer manually to adjust the scroll.

The way I see it, if I rewrite the rendering so that it uses the VRAM Pointer, it would make handling scrolling virtually automatic, and I guess should make alot of things easier. So I'm just wondering how you guys do it.
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

PocketNES doesn't track the VRAM address as the screen renders, but PocketNES isn't an ordinary NES emulator.

If you properly track the VRAM address, emulating MMC3 IRQs becomes much easier.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

VRAM address? I though it was loopy_t (latch)... as loopy_v being the real. Oh no, wait... it's like *another* VRAM address, as the PPU renders & accesses tiles. Weird.
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

Yes, the phrase "The VRAM Address" is referring to loopy_v, if you want to call it that.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

Dwedit wrote:Yes, the phrase "The VRAM Address" is referring to loopy_v, if you want to call it that.
Actually no. It's an internal address build when the ppu is accessing its memory. I never understood it 100%, but that's it.
User avatar
MottZilla
Posts: 2835
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

Well the only thing important other than your obvious I/O through $2007, is for manipulating things for the scroll effects used in games. That's what I'm having trouble with besides needing to implement accurate Sprite Hit. Does anyone have some easy to understand explanation of how scrolling updates by games mid-frame are handled?

From what I've read you can manipulate an address that is formed by $2005 and $2006 writes, and on the 2nd (according to latch) write to $2006, the scrolls and nametables are set to reflect the value you wrote into the registers.

The thing is that I tried implementing this in various ways but none functioned quite right. Though it's perfectly possible my sprite 0 being wrong is responsible.
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

1. You must follow loopy's ppu logic (docs on nesdev).
2. Once it's done, go to the screen rendering. It's easy, but I had to figure it out by myself. With a few lines of code, it works nicely.
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

The thing I don't like about Loopy's document: He uses 1's and 0's instead of x's and .'s to indicate which bits are affected.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

Dwedit wrote:The thing I don't like about Loopy's document: He uses 1's and 0's instead of x's and .'s to indicate which bits are affected.
An hexadecimal format would be fine. ^_^;;
Post Reply