Got any tips for Early NES Emulator Development?
Moderator: Moderators
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.
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.
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.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.
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 again -- this is another reason to #define calling conventions
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.
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.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.
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.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.
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.
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.
You are joking. Anyway, go ahead and write your stuff. Once it's working, congrats. It's enough for me.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
Zepper
RockNES author
RockNES author
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.
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.
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.
Zepper
RockNES author
RockNES author
Actually no. It's an internal address build when the ppu is accessing its memory. I never understood it 100%, but that's it.Dwedit wrote:Yes, the phrase "The VRAM Address" is referring to loopy_v, if you want to call it that.
Zepper
RockNES author
RockNES author
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.
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.
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.
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.
Zepper
RockNES author
RockNES author
An hexadecimal format would be fine. ^_^;;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.
Zepper
RockNES author
RockNES author