fubarNES NES emulator

Hi!

I’m currently coding an NES emulator, and need some feedback on whether it will run/how fast on different systems…

http://www.stud.ntnu.no/~erlinga/nesemu/fubarNES_03.zip

Edit: Webstart version now available:
http://www.stud.ntnu.no/~erlinga/nesapplet/webstart/launch.jnlp

I’ve tried underclocking my own system, trying out different cpu speeds, but that’s not likely to resemble the performance on a system with slower memory, etc. I want to know what is the lowest specs it will run on.
There is no FPS counter, but if the sound is ok, it should be locked on 60FPS.

The emulation is far from perfect yet, but a lot of games do actually work (like the Super Mario and Adventure Island games, Journey To Silius, Ducktales, etc). You’ll have to get ROMs to test it with yourself, though :stuck_out_tongue:

Runs very well on my machine, solid 60fps. In comparison, I can just barely get 10fps with NesCafe (another Java NES emulator). I have an Athlon 1.1ghz, 640megs of ram, WinXP, Sun Java 1.4.2.

Runs horrible (sry :)) on my machine with 2-5 fps (I can count em).

K7 500, 128mb, gf2mx, win98se, java 1.4.2 (it would be nice to know if it works with 700 or 800 mhz)

Oh and no sound at all… I expected to get ugly noise n stuff but it was just silent (sound was default-ish enabled).

Webstart would be nice (autoupdates n stuff… /me points at that 0.3 :))

The filechooser should start in the current working directory (usually the way to the roms is shorter then).

Well looks nice so far. GJ :slight_smile:

Ooooh and a small nice NSF player would be cool (little spinoff project for the next rainy sunday)

It could be either a problem with the timing (I’m using the perftimer), or the sound code…
I’ve tested it on some 700 MHz pc’s at university, and it seems to run at almost full speed with sound disabled, so I expect you should get more than 2-5 FPS if the code was correct…

I’ll probably take a look at it after christmas, right now there are some horrible exams I have to study full time for ???

Hadn’t noticed a big speed increase after disabling sound… unlikely that it’s the fault of the sound code.

Well good luck with your exams :slight_smile:

I don’t get this… I’m testing the emu on a system with 1.2 GHz AMD Athlon CPU, and it’s slow as hell… Why does it run faster on a 750 MHz machine?? What’s up with java? (BTW I’m using 1.4.2_03).

I tried profiling the app, but it gave the exact same results as on the systems it works with. There’s some garbage collecting going on, but not on that scale… Any ideas? ???

Can you post the profiler output of both systems?

[quote]I don’t get this… I’m testing the emu on a system with 1.2 GHz AMD Athlon CPU, and it’s slow as hell… Why does it run faster on a 750 MHz machine?? What’s up with java? (BTW I’m using 1.4.2_03).
[/quote]
Different graphics cards? Different graphics drivers? Different operating systems (winXP vs win98)? Different anything other than CPU??

As the other guys have said. Job one for any performance analysis is a profile.

Once you’ve done that you may even answer your own question.

(sorry for not posting in this thread for a while, but I’ve been busy…)

It seems like the performance problem is in the timing code. When the app needs to pause for a specified number of microsecs, this code is run:

public void sleep(long timeMicros){

        t1 = currentMicros();
        t2 = t1;
                    
        while(t2-t1 < timeMicros){
              if((t1+timeMicros)-t2 > 500){
                    try{
                          thr.sleep(1);
                    }catch(Exception e){}
              }
              t2 = currentMicros();
        }

  }

currentMicros() uses the sun.misc.Perf counter.

Earlier, this ran very smoothly, but after some optimization of the cpu emulation, I got the same problems as I mentioned in the posts above. The speed drops by factor of at least 4. It seems like the looping is the problem, when I use this code instead:

try{
thr.sleep(timeMicros/1000);
}catch(Exception e){}

it runs at normal speed (but not as smooth).
I tried combining the two, having it always sleep at least once, and adjusting the sleeping time, but it didn’t help any. As long as it loops at the end of the interval, the speed drop occurs. Do you know of any solutions to this problem?

BTW, an applet version is now available here: http://www.stud.ntnu.no/~erlinga/nesapplet/fubarnes.php

Hi again,

I’ve done some changes to the rendering and sound code of the emulator, and now it seems to run a lot faster, at least on my computer. In fullscreen (without scaling) I get ~140 FPS with sound disabled (now, if only it wouldn’t crash horribly on entering fullscreen mode the second time :-/) I’d appreciate feedback on whether you get it to run any faster now than before :slight_smile:

I’ve also made it webstartable:
http://www.stud.ntnu.no/~erlinga/nesapplet/webstart/launch.jnlp

There’s still some trouble with syncing the sound, though :-[
If the sound seems to be ok while the graphics stutter, it’s probably because it runs too fast, causing the sound line to block.

Mac OS X 10.3.4 Java 1.4.2

Creating papu channels…
…finished.
Starting PAPU sound lines…
Sound buffer size: 65536
…finished.
Creating new PPU tiles.
HiRes frequency = 33330231
Native library jxinput not loaded due to an UnsatisfiedLinkError.
apple.awt.EventQueueExceptionHandler Caught Throwable : java.lang.NullPointerException
java.lang.NullPointerException
at GUI.loadRom(GUI.java:814)
at GUI.actionPerformed(GUI.java:615)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1819)
at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1872)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
at javax.swing.AbstractButton.doClick(AbstractButton.java:321)
at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1113)
at javax.swing.plaf.basic.BasicMenuItemUI$MouseInputHandler.mouseReleased(BasicMenuItemUI.java:943)
at java.awt.Component.processMouseEvent(Component.java:5100)
at java.awt.Component.processEvent(Component.java:4897)
at java.awt.Container.processEvent(Container.java:1569)
at java.awt.Component.dispatchEventImpl(Component.java:3615)
at java.awt.Container.dispatchEventImpl(Container.java:1627)
at java.awt.Component.dispatchEvent(Component.java:3477)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3483)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3198)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3128)
at java.awt.Container.dispatchEventImpl(Container.java:1613)
at java.awt.Window.dispatchEventImpl(Window.java:1606)
at java.awt.Component.dispatchEvent(Component.java:3477)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:481)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:234)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:178)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:170)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:100)

Weird, I can’t understand what can wrong there…

The code looks like this:


public void loadRom(){
            
            if(filechooser==null)filechooser=new JFileChooser();
            filechooser.setDialogTitle("Load ROM File..");
            filechooser.setAcceptAllFileFilterUsed(true);
            MyRomFileFilter romFilter = new MyRomFileFilter();
            filechooser.addChoosableFileFilter(romFilter);
            
            if(lastDirectory != null){
                  filechooser.setCurrentDirectory(lastDirectory);
            }
            
            int retVal = filechooser.showOpenDialog(this);
            filechooser.removeChoosableFileFilter(romFilter);
            
            if(retVal == JFileChooser.APPROVE_OPTION){
                  lastDirectory = filechooser.getCurrentDirectory();
                  String romFile = filechooser.getSelectedFile().getAbsolutePath();
                  boolean running = nes.getCpu().isRunning();
                  stopEmulation();
                  nes.reset();
                  initBufferViews();
                  if(!nes.loadRom(romFile)){
                        JOptionPane.showMessageDialog(this, "Invalid ROM file!");
                        disableComponents();
                        return;
                  }
                  windowCaption = "fubarNES - "+filechooser.getSelectedFile().getName();
                  setTitle(windowCaption);
                  enableComponents();
                  if(running){
                        startEmulation();
                  }
            }
      }

Do you see anything that could go wrong there? (I’ve changed the code a bit, so the line numbers don’t match) I have no problems running it on any windows machine…

BTW, I checked off ‘Notify of Replies’, but it doesn’t seem to work…

which line is line 814? That’s where the null pointer happned.

I know, but I’ve been modifying the code a bit, so it’s not line 814 any longer…

is this emulator based on IMBNes for playstation? it seems to work very similarly to that.

btw webstart no longer works, i dl’d the code, works a little slow. also i take it the save ram system isnt working? smb3 which seems to be constantly using some sort of save ram (probably just a custom chip they put in the cart) keeps spitting out heaps of errors over and over.

The code is written from scratch, not based on anything other than the documentation from http://nesdev.parodius.com/.
The webstart version won’t work with games that use saveram unless a save directory can be created on the desktop (uses default directory). You could try creating that folder manually.

I’ve noticed it runs markably slower on some machines. The 1.2 GHz AMD Athlon family PC gives about the same performance as a 750 MHz PC at university (~55 FPS without sound and scaling), so I’ll have to compare the specs some time. My own 2.0 GHz system performs a lot better, ~140 FPS. Maybe it’s the cache size that’s the problem, the CPU emulation code is quite big, and it also does a horrible amount of method calls (the picture processing unit and the sound unit is being clocked for every CPU instruction that’s executed).