Click here to Skip to main content
Click here to Skip to main content

My Nes - Nes Emulator

By , 19 Dec 2009
 
Main.JPG

Introduction

Famicom (Family Computer) is a Nintendo® Entertainment System. It was the world’s most widely used videogames console during the 1980s. From its initial release in 1983 until it was discontinued in 1995, the console brought gaming into more homes than ever before and paved the way for the videogame industry as it stands today.

For more information about the Nintendo® Entertainment System, please visit http://nesdev.parodius.com.

Emulation is the process of simulating hardware to enable the software developed for it to be used on an otherwise incompatible system.

My Nes is an emulator for this system. At this time, it covers the popular games and it closed to cover over than 1000 games.

My Nes is completely portable, which means that you can port it into another platform or system like Xbox. Although it uses windows codes in some places for drawing and rendering sound but not the main NES engine.

This article should cover what you need to understand this project, also My Nes can be found at http://sourceforge.net/projects/mynes/ for developing, downloading what's new ...

But before you start reading this article or looking at the code, I recommended that you get a good knowledge about the real NES hardware and the other stuff.

And sorry if I'll abasing you when I say that you should get a knowledge about the "byte" and how to get a "bit" from the "byte" and what is the "short" ......

Background

My Nes includes three projects:

  1. The launcher called "My NES", it just the main EXE for the program and it initialize the main window form.
  2. The Core which includes the Windows forms and the classes for its like settings. I decided to add the windows forms in this library so that it will be lonesome from the NES engine. When you want to port into another platform or system, you should take care of this first.
  3. The NES project: it's a DLL library includes the classes that work together to emulate the NES system. these classes are completely lonesome with windows (exapt drawing, input handling and sound rendering).

The purpos of My Nes project is to use the engine (3rd project) to emulate the NES.

How does My Nes engine emulate?

Central Processing Unit (CPU)

The NES uses the NMOS processor based on the 6502, the 2A03, The chip differed from a standard 6502 in that it had the ability to handle sound, but in this engine i made the sound work done at APU class.

However, like any system, CPU is the heart and it controls everything using the registers.

The 6502 has five 8-bit registers and one 16-bit register. In each system cycle, the cpu fetch the instruction from the memory to execute, and the execution decides what's gonna happen at the next cycle and what's every part of the system has to do.

So 6502 emulation done at CPU6502.cs class, just take a look :

//Registers 
public byte a_register; 
public byte x_index_register; 
public byte y_index_register; 
public byte sp_register; 
public ushort pc_register;
//Flags 
public byte carry_flag; 
public byte zero_flag;
.......//methods for addrissing modes, opcodes ...
 
//the cycles are done here in the "while" loop
//don't forget that the Thread will handle it.
public void RunProcessor()
{
   previousPC = pc_register;
   while (!_NesEmu.isQuitting) 
   {
    currentOpcode = _NesEmu.ReadMemory8(pc_register);//get the next opcode from the memory
    switch (currentOpcode) //do the opcode
    {
     case (0x00): OpcodeBRK(); break; 
     case (0x01): OpcodeORA(); break; 
     case (0x05): OpcodeORA(); break;
     ........
    }
    if (tick_count >= _NesEmu.Ticks_Per_Scanline) 
    //if the cpu done the required cycles for the scanline
    //and this depending on NTSC or PAL.
    { 
     if (_NesEmu.myPPU.RenderNextScanline()) //tell the picture unit to render the scanline
     { 
       //do the interrupt routine.
       Push16(pc_register); 
       PushStatus(); 
       pc_register = _NesEmu.ReadMemory16(0xFFFA); 
     } 
     tick_count = tick_count - _NesEmu.Ticks_Per_Scanline; 
    }
   }
}

The Memory

All the memory is located at the NesEmulator.cs class, and the CPU access the memory using ReadMemory8, WriteMemory8 and ReadMemory16 methods.

Also NesEmulator.cs class handles everything about the ROM (cart memory) including the access of mappers. Mappers are the most important stuff in the memory, 'cause the access of the cart is depending on the mapper. In the real NES cart, the mapper comes inside of it. But the INES format does not has the ability to handle a mapper, so we have to write each mapper (256 one) inside the emulator.

Mem_Diagram.jpg

"This figure taken from http://nesdev.parodius.com/NESDoc.pdf"

There's no buses in the emulator, you know, just the read and write methods.

Take a look at the mapper # 2 code:

internal class Mapper2 : IMapper //IMapper is the interface !!
{ 
   Mappers Map;//Mappers is the general class for bank switching 
   //and the engine depends on Mappers class for accessing any mapper.
   //It includes a field called "CurrentMapper" and it will hold this 
   //mapper when the cart is mapper 2.
   public Mapper2(Mappers Maps) 
   { Map = Maps; } 
   //When the system ask to write into cart (and rom is read only you know)
   //it asks to tell the mapper something . 
   public void Write(ushort address, byte data) 
   { 
     if ((address >= 0x8000) && (address <= 0xFFFF)) 
     {
      Map.Switch16kPrgRom(data * 4, 0); //this means :
      //attach the prg bank # (data * 4) in the cart into the
      //address 0x8000 in the main memory.
     } 
   } 
   //At the reset or start of the system, it calls this method
   //to setup the mapper.
   public void SetUpMapperDefaults() 
   {    
      //last prg rom into address 0xC000.
      Map.Switch16kPrgRom((Map.mapperCartridge.prg_rom_pages - 1) * 4, 1);
      Map.Switch8kChrRom(0); 
      
   } 
   //some mappers needs to tick in each scanline and the system calls this method
   //every scanline even that mapper (like this) doesn't have a ticker.
   public void TickTimer() { } 
}

Picture Processing Unit (PPU)

The NES has the 2C02 processor to serve as PPU. This processor handles the graphics and the CPU access the PPU via memory addresses 0x2000 to 0x4020 and this area of memory called I/O registers.

Also in My Nes engine, the PPU emulation done at class called PPU, and it render each scanline like the follow:

public bool RenderNextScanline()
{
  int i; 
  if (currentScanline < 240)
  {
   //Clean up the line from before 
   //Remember everything done on the offscreenBuffer array which holds
   //the 256 * 240 pixels in 16-bit color format.
   if ((uint)nameTables[0x1f00] > 63) 
   { 
    for (i = 0; i < 256; i++) 
    { offscreenBuffer[(currentScanline * 256) + i] = 0; sprite0Buffer[i] = 0; } 
   } 
   else 
   { 
    for (i = 0; i < 256; i++) 
    { offscreenBuffer[(currentScanline * 256) + i] = (
        short)Nes_Palette[(uint)nameTables[0x1f00]]; sprite0Buffer[i] = 0; } }
  
 
  //We are in visible territory, so render to our offscreen buffer 
  if (spritesVisible) 
     RenderSprites(0x20); 
  if (backgroundVisible) 
     RenderBackground(); 
  if (spritesVisible) 
     RenderSprites(0);
  if (!noBackgroundClipping) 
  { for (i = 0; i < 8; i++) 
     offscreenBuffer[(currentScanline * 256) + i] = 0;
  } 
  if (sprite0Hit == 0) 
  { for (i = 0; i < 256; i++) { if (sprite0Buffer[i] > 4) sprite0Hit = 1; } }
 
  //The mapper timer !! 
  if (backgroundVisible || spritesVisible) 
     myEngine.myMapper.TickTimer();
  }
  
  //The moment of truth, render the buffer into the screen !!
  if (currentScanline == 240) { myVideo.CurrentDrawer.RenderFrame(offscreenBuffer); }
  
  currentScanline++;
  //Render the sound ...
  if (currentScanline == Scanlinesperframe) 
  { if (myEngine.SoundEnabled) { myEngine.myAPU.Render(myEngine.my6502.total_cycles);..... }
 
  //Are we about to NMI on vblank? 
  if ((currentScanline == ScanlinesOfVBLANK) && (executeNMIonVBlank)) 
  { return true; } 
  else { return false; }
}

Audio Processing Unit (APU)

The APU.cs renders the sound of the NES, and I will not write any thing about the APU because I'm still confused about this part of the NES and I really include it in the engine hoping someone help me on it. However, take a look at the source.

Cool but, how does it work?

The RunProcessor() method at the CPU loops to execute, and as I say before, this execution may tells every part what to do. Also the I/O registers is the most important area in the memory, so when the CPU access this area (Read or Write), the other parts do their job depending on the values of the registers. For example, a write anto address 0x2000 will change the sprite size (8x8 or 8x16), background address .... in the PPU.

Stop that method "RunProcessor()" and the system will stop. Run it and the system will run -_-

How to use the engine?

The main window (in the Core) uses the engine like this :

NesEmulator _Nes;
Thread gameThread; 
ThreadStart myThreadCreator;
public void OpenRom(string FileName)
{
  CartHeaderReader rom = new CartHeaderReader(FileName);//used to check the validate of the rom
  if (rom.validRom)
  {
   if (rom.SupportedMapper()) 
   {
    _Nes.QuitEngine();
    _Nes = new NesEmulator(panel1, statusStrip1);
    _Nes.InitializeEngine();
    _Nes.LoadCart(rom.FilePath);
    //Setup
    //region 
    _Nes.CurrentSystem = MainCore.Settings.NesRegion;
    ......
 
    //Launch ... 
    myThreadCreator = new ThreadStart(_Nes.DoFrame); 
    gameThread = new Thread(myThreadCreator); 
    gameThread.Priority = ThreadPriority.Highest; 
    gameThread.Start();
   }
  }
}

I think that's easy :)

Rendering the Video

I written 2 GDI renderer class for video, and it directly renders the offscreenBuffer from the PPU.

I used to draw it into a Bitmap image first then draw it into a Control which will be the screen surface and that to make TakeScreenShot() done easily.

Graphics GR;//The drawer
Control _Surface;//the drawing surface like "panel" control.
//These 4 values changed depending on NTSC, PAL and DrawSize.
int Screen_X = 0; 
int Screen_Y = 0; 
int Screen_W = 0;//width 
int Screen_H = 0;//height
Bitmap bmp = new Bitmap(256, 240);
public unsafe void RenderFrame(short[] ScreenBuffer) 
{ 
  if (Surface != null & !_IsRendering & _CanRender) 
  { 
   _IsRendering = true; 
   //Render the bitmap 
   BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, 256, _ScanLines),
       ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb565); 
   short* numPtr = (short*)bmpData.Scan0;//using the pointer is the best way to make it fast. 
   for (int i = _FirstLinesTCut; i < ScreenBuffer.Length - _FirstLinesTCut; i++) 
   { 
     //ScreenBuffer is an array of 16-bit color format so we don't have to convert it
     //so that saves speed.
     numPtr[i - _FirstLinesTCut] = ScreenBuffer[i];
   } 
   bmp.UnlockBits(bmpData); 
   //Draw it !! 
   GR.DrawImage(bmp, Screen_X, Screen_Y, Screen_W, Screen_H);
   //Draw the text if we have to 
   if (TextApperance > 0) 
   { 
   GR.DrawString(TextToRender, new System.Drawing.Font("Tohama", 16, FontStyle.Bold), 
   new SolidBrush(Color.White), new PointF(30, Surface.Height - 50)); 
   TextApperance--;
   } 
   _IsRendering = false; 
  } 
}

That code taken from Vid_GDI_16Bit class and using it makes My Nes runs at 80 ~ 100 fps (after enabling the Speed Throttling).

Point Of Interest

Playing the NES is realy cool but emulating the NES in your hands, that's a different story !!
My Nes can be the start point of your emulator for the NES or any system , all have the same principles.

Also My Nes is closing to be a REAL emulator, it's cool to play using it since it covers the most nice NES games which can be playable perfectly.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

About the Author

Ala Hadid
Software Developer
Syrian Arab Republic Syrian Arab Republic
Member
Start programming at 2008, my first successful project was AHD Subtitles Maker "ahd-subtitles-maker.webnode.com".
I'm studying Physics in Hims university.
Programming is my favorite hobby that fill my empty times.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionwelcome to: http://www.netetrader.commemberkuif8sa9s9 Aug '12 - 14:54 
welcome to: http://www.netetrader.com
 
The website wholesale for many kinds of
fashion shoes, like the nike,jordan,prada,****, also including the jeans,shirts,bags,hat and the decorations. All the products are free shipping, and the the price is competitive, and also can accept the paypal payment.,after the payment, can ship within short time.
 

free shipping
 
competitive price
 
any size available
 
accept the paypal
 
http://www.mineokmalls.com
GeneralMy vote of 5memberMember 89327415 May '12 - 8:44 
Very helpful
Generalممتاز يعطيك العافيةmemberMazen el Senih14 Mar '12 - 9:08 
خمس نقاط ونورنا كمان ! Thumbs Up | :thumbsup:
GeneralRe: ممتاز يعطيك العافيةmemberAla Hadid22 Mar '12 - 9:20 
الله يعافيك Smile | :)
QuestionMy NES doesn't work on any computer I ownmemberMifdongs24 Nov '11 - 18:25 
Every single version (I've tried about 6 or them) on every single computer I own, just crashes before anything shows up. This is across Windows XP, Vista, and 7. It's been tried on a Pentium 3, a Pentium 4, a netbook with an Intel Atom, tried it on a Phenom II X4, a Turion 64, and a Pentium M.
 
Same result with all versions, on all systems. Crash before anything else shows up. That's what you get for using .NET and SlimDX. Please learn another programming language, like regular C/C++. You will be very glad you did.
 
Aside from the speed gains you would see (My NES needs a 2 GHz CPU?? What!? The NES emu I've been writing runs on a Pentium 2 at full speed.), Microsoft's got you locked in if all you know is C#. Totally non-portable.
 
The future (and the present) is cross-platform software. This is why I wrote my x86 PC emu and my NES emu in C with libSDL for video/sound/input. It compiles the same on practically any platform there is. I even compiled a version of both of them for my old Xbox! Big Grin | :-D
 
I'm not trying to be an ass, you're clearly a skilled programmer. Just making a suggestion.
AnswerRe: My NES doesn't work on any computer I own [modified]memberAla Hadid26 Nov '11 - 22:22 
Mifdongs wrote:
Every single version (I've tried about 6 or them) on every single computer I own, just crashes before anything shows up. This is across Windows XP, Vista, and 7. It's been tried on a Pentium 3, a Pentium 4, a netbook with an Intel Atom, tried it on a Phenom II X4, a Turion 64, and a Pentium M.

Try version 3, install .net 4, install slimdx (March 2011) then try again, it work fine for me, I tested it in virtual machine and real old pc (1 GH speed, 512 mb ram).
 

 
Mifdongs wrote:
Same result with all versions, on all systems. Crash before anything else shows up. That's what you get for using .NET and SlimDX. Please learn another programming language, like regular C/C++. You will be very glad you did.

My Nes created to be in C#, the first powerful nes emulator written in .net c#.
 
Mifdongs wrote:
Aside from the speed gains you would see (My NES needs a 2 GHz CPU?? What!? The NES emu I've been writing runs on a Pentium 2 at full speed.), Microsoft's got you locked in if all you know is C#. Totally non-portable.

My Nes is portable, run in Windows and Linux as My Nes GTK, a port of My Nes that use gtk# and .net sdl.
 

Mifdongs wrote:
I'm not trying to be an ass, you're clearly a skilled programmer. Just making a suggestion.

No problem, suggestions are important to make the project grows better.Thumbs Up | :thumbsup:

modified 27 Nov '11 - 4:32.

AnswerRe: My NES doesn't work on any computer I ownmembersgraves10 Jan '12 - 16:51 
Your little rant is not only ludicrous but entirely incorrect.
http://www.mono-project.com/Main_Page[^]
GeneralRe: My NES doesn't work on any computer I ownmemberAla Hadid11 Jan '12 - 11:16 
sgraves wrote:
Your little rant is not only ludicrous but entirely incorrect.

http://www.mono-project.com/Main_Page[^]

 
http://sourceforge.net/projects/mynes/files/My%20Nes%20GTK/v%201.0/[^]
Download this then try again.
NewsVersion 2.3 is out !!memberAla Hadid29 Mar '11 - 11:49 
New version 2.3 released:
* Added mapper # 40, 42, 44, 67, 68 and 72.
* Added disassembly for debugging cpu and important registers.
* Fixed mapper # 41, 64, 65 and 90.
* Fixed apu's length counter timing in mode 0 and 1.
* Fixed APU irq timing.
* Fixed save state which hang sometimes due to cpu timing.
* Fixed: browser doesn't run at startup after you check that option.
 
Download binaris and source from here.
GeneralاعجبنيmemberTheDevelopper12 Feb '11 - 23:28 
ممتاز . شكرا لك يا علاء
GeneralRe: اعجبنيmemberAla Hadid13 Feb '11 - 1:31 
على رأسي يا معلم Shucks | :->
تحية إلى الجالية العربية في أمريكا Thumbs Up | :thumbsup:
NewsNew version 0.8.1.15memberAla Hadid14 Jan '10 - 22:19 
New version released and here are the changes :
 
* APU fixed (new sound engine that increase the emulator speed to 150 fps generaly when you enable the Speed Throttling.)
All sound channels rewritten and the Triangle, Noize and DMC channels work 100%. Still some small bugs with the Rectangle 1 and 2.
Now some games work (like Karateka).
* Added wave recorder that records the sound with one audio format in this version (PCM 16-bit, 44100 Hz, MONO).
* Save / Load state fixed (100% works with any game and the ability to save in different 10 state slots).
* New video mode "SlimDX ARGB 32-Bit"
* Added debugger (BETA).
 
Go ahead and download it here[^].
GeneralNew ver 0.6.4.6 releasedmemberAla Hadid7 Nov '09 - 23:09 
A new version of My Nes released and here are the great updates :
 
* Add support for mappers # : 13, 15, 16, 18, 32, 34, 41 and 225.
* Browser is sizeable now (and other improvements).
* Bugs fixed:
> Mapper # 4 IRQ timer (Teenage Mutant Ninja Turtles - Tournament Fighters game works great!!)
> Sprite0 hit, Super Mario Bros (Orginal ver) works now.
> VBLANK (which caused a bad scroll in some games like Castlequest and Castlevania)
> Rename folder in the browser (when you enter nothing)
 
For more, please visit:
www.sourceforge.net/projects/mynes/ [^]
Rose | [Rose] Rose | [Rose] Rose | [Rose] Rose | [Rose] Rose | [Rose] Rose | [Rose] Rose | [Rose] Rose | [Rose] Rose | [Rose] Rose | [Rose] Rose | [Rose] Rose | [Rose] Rose | [Rose]
NewsVer 0.5.2.3 released !!memberAla Hadid30 Oct '09 - 0:41 
I've just released the ver 0.5.2.3 (BETA) Big Grin | :-D
 
* Browser improved !!
* Added save / load state
* Sound improvement (mario sounds good)
* PAL, NTSC & speed throttling
* Frame limiter
Rose | [Rose] Rose | [Rose] Rose | [Rose] Shucks | :->
Please visit www.sourceforge.net/projects/mynes/ [^] for more.
 
Greetings.
NewsNew Release Ver 0.4.1.2memberAla Hadid17 Oct '09 - 14:12 
A new version (0.4.1.2) of My Nes released !! Cool | :cool:
 
I made the APU (sound) in this release Thumbs Up | :thumbsup: , but it still wrongfuly and needs work. However it can generate sound Big Grin | :-D
 
Please visit http://sourceforge.net/projects/mynes/[^]
for downloads, reviews , screenshots .....
GeneralRe: New Release Ver 0.4.1.2membermaxim galayko29 Oct '09 - 8:23 
Hi,
Do you plan to use WPF instead WinForms?
AnswerRe: New Release Ver 0.4.1.2memberAla Hadid29 Oct '09 - 23:39 
Never , My Nes is for Windows only. But you can use the Nes Engine (if you like) on other platforms but then you have to make some changes in that engine (remove everything about System.Windows namespace,also DirectX..... )
 
It's very easy to use the engine, it completly individual from user interface stuffs (forms, dialogs ...) and i explained about using it in this article.Suspicious | :suss:
GeneralRe: New Release Ver 0.4.1.2membermaxim galayko31 Oct '09 - 11:27 
WPF is Windows only technology. The main point of using WPF in this case is performance : with Image+WriteableBitmap for rendering videobuffer data with stretch size & 32bit mode i`ve got 130 fps against 20 fps with PictureBox+Bitmap+Graphics on my machine. It`s require a few simple changes in code. Why you shouldnt want to include this changes in your emul? I can help you with it.
AnswerRe: New Release Ver 0.4.1.2memberAla Hadid5 Nov '09 - 6:17 
Thanks man, that's a great help !! Cool | :cool:
 
I've got a little acknowledge about WPF until now, if you say is true (20 to 130) it will be great change Thumbs Up | :thumbsup:
please send me the source 'cause now i'm working on mappers (wait for the new ver Rose | [Rose] )
 
THANKS Big Grin | :-D
GeneralNDSgroupNorm .net7 Oct '09 - 23:38 
Waiting for NDS emulator Wink | ;)
 
BTW good work - 5!
 

GeneralRe: NDSmemberAla Hadid8 Oct '09 - 4:25 
I can't promise, that needs more time than i have.
 
Thanks Smile | :)
GeneralROMSmemberGabPsy18 Aug '09 - 6:56 
Can you share your roms to test it...
 
By the way, excelent work!
 
Best regards
 
Where's the "Any" key on my Keyboard? H.S

AnswerRe: ROMS [modified]memberAla Hadid21 Aug '09 - 6:04 
GabPsy wrote:
Can you share your roms to test it...

 
No, sorry ...
download some from:
http://www.romnation.net/srv/roms/nes.html[^]
 
GabPsy wrote:
By the way, excelent work!
 
Best regards

 
Thanks Big Grin | :-D
 

GabPsy wrote:
Where's the "Any" key on my Keyboard? H.S

 
mmmm.....press one of "a,b,c,d,e,f,g,h,i,j ....... etc"
 
modified on Thursday, October 8, 2009 1:01 PM

GeneralRe: ROMSmemberThe_Mega_ZZTer7 Oct '09 - 16:09 
You may want to replace those links with links to Public Domain roms, or advice to use Google. You may get into trouble linking to rom torrents... :/
GeneralRe: ROMS [modified]memberAla Hadid8 Oct '09 - 4:23 
Sorry about the links, changed 'em Thumbs Up | :thumbsup:
however, google is the better one Wink | ;)
 
modified on Thursday, October 8, 2009 1:04 PM

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 19 Dec 2009
Article Copyright 2009 by Ala Hadid
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid