Slashdot Mirror


Building an NES Emulator

An anonymous reader writes: Programmer Michael Fogleman recently built his own emulator for the original Nintendo Entertainment System. He's now put up a post sharing many technical insights he learned along the way. For example: "The NES used the MOS 6502 (at 1.79 MHz) as its CPU. The 6502 is an 8-bit microprocessor that was designed in 1975. ... The 6502 had no multiply or divide instructions. And, of course, no floating point. There was a BCD (Binary Coded Decimal) mode but this was disabled in the NES version of the chip—possibly due to patent concerns. The 6502 had a 256-byte stack with no overflow detection. The 6502 had 151 opcodes (of a possible 256). The remaining 105 values are illegal / undocumented opcodes. Many of them crash the processor. But some of them perform possibly useful results by coincidence. As such, many of these have been given names based on what they do." It's an interesting look at how software and hardware interacted back then, and what it takes to emulate that in modern times. Fogleman released the source code on GitHub.

25 of 140 comments (clear)

  1. Re:Nice Project, But... by aardvarkjoe · · Score: 5, Informative

    The story isn't that somebody made an NES emulator. Those have been around forever, and this is going to be uninteresting if all you want to do is play Mario. The story is that somebody wrote an article about it for anyone who is curious about some of the details.

    The article does focus mostly on the NES hardware, though, and I was expecting some insight on interesting or difficult points of writing the emulator itself.

    --

    How can we continue to believe in a just universe and freedom to eat crackers if we have no ale?
  2. BCD mode by flargleblarg · · Score: 3, Interesting

    BCD (Binary-Coded Decimal) mode was cool because it changed the way adding and subtracting worked. If you added 0x01 to 0x29, you'd get 0x30 instead of 0x2A. This was possible because there were actually two carry flags on the 6502 — one (named C) which was set upon overflow of values greater than 255, and the other (named D) which was set upon overflow of the low nybble (e.g., the low 4 bits).

    6502.org Tutorials: Decimal Mode

    1. Re:BCD mode by flargleblarg · · Score: 2

      Hmm, you know what? Damn. I misremembered how it worked, and I didn't read closely enough at the link I provided. So, to stand corrected, the D flag was something you set (or cleared) proactively using the SED or CLD instruction. It actually indicated a mode you were in, rather than being a flag in the usual sense (such as a carry or a zero flag).

    2. Re:BCD mode by Anonymous Coward · · Score: 4, Informative

      To those of you wondering why BCD instructions would be useful, it has a lot to do with doing math with character-based input.

      Today, we're accustomed to parsing strings of digits to turn them into numeric types. However, this is actually quite costly, and it turns out that there's a much cheaper way to accomplish the same goals if you're only doing simple arithmetic with these values.

      Let's say you want to compute "2" + "3". "2" is 0x32 in ASCII or 0xF2 in EBCDIC, while "3" is 0x33 in ASCII or 0xF3 in EBCDIC. It is no coincidence that the low 4 bits of a digit's character encoding (in either of the two most popular encodings) correspond to that digit itself; it is specifically to support BCD math.

      I'll focus on ASCII for the remainder of this post, though this all applies equally to EBCDIC. All you need to do is mask things correctly (0x32 & 0x0F is 0x02, and 0x33 & 0x0F is 0x03) to "parse" character-encoded digits. Then you can just add them together (0x02 + 0x03 = 0x05) and OR the appropriate high 4 bits (0x30 for ASCII) to get back to character encoding land: 0x05 | 0x30 is 0x35, or ASCII "5". Much cheaper than contemporary number parsing and string building algorithms.

      Of course, if we had values that summed to 10 or more, we'd need to use the BCD-overflow flag to handle results properly (as 0x05 + 0x05 would yield 0x0A, which when transformed back to ASCII is ":", not "10") . This gets us into packed-BCD territory, which is beyond the scope of this post (but which can be summed up as packing two BCD values into a single byte ((a4) | b), which means we'd want 0x05 + 0x05 to give us 0x10, the packed-BCD value that represents the decimal number 10), as that's how BCD values with more than a single digit tend to be stored.

      BCD was a clever hack that enabled crappy computers to do a lot of work despite their slow speeds. Today, we just parse numbers in software, because it's no longer cost-effective to squeeze this level of efficiency out of our hardware. They don't make 'em like they used to.

    3. Re:BCD mode by itzly · · Score: 2

      The D flag was just for the programmer to switch between decimal and binary. The extra nibble carry was an invisible internal signal.

  3. Re:Little-known fact by Anonymous Coward · · Score: 5, Insightful

    I don't understand how this makes them bastards.

  4. Re:Little-known fact by kheldan · · Score: 2, Interesting

    You misunderstand my post; everything I'm talking about is on the PCB in the coin-operated game. Literally two shift registers with copper traces connecting them. If you are sufficiently enabled electronically-speaking, then google 'nintendo vs system schematic, find the VS system operator's manual, which contains the PCB schematic; look for the player inputs, they go to 74LS165's, which are shift registers, which then lead to other shift registers converting the serial data back to parallel, which is then gated onto the data bus. Literally no reason to design it this way. Coin switch inputs (that detect a coin inserted) and DIP-switch inputs aren't gated onto the bus this way, only player inputs.

    --
    Are YOU using the TOOL, or is the TOOL using YOU? Think about it!
  5. Re:Little-known fact by tuffy · · Score: 4, Informative

    Nintendo VS system was an adaptation of their home hardware for arcade use, not the other way around. The Famicom predates it by years, remember.

    --

    Ita erat quando hic adveni.

  6. Good for them. by halivar · · Score: 2

    I for one, am very thankful for the money I saved having an NES and not having to pump endless quarters into my local arcade, and I am most especially thankful that I never had to wait in line for my favorite game. It is not Nintendo's responsibility (or mine as a consumer) to protect someone else's outdated business model. Arcades lost, and consumers won.

    1. Re:Good for them. by halivar · · Score: 2

      The "outdated business model" I speak of is having gaming as a gated resource. You had to be at the mall or the movie theater, you had to have quarters on hand for every round, and you had to share your machines. God help you if you wanted to play the popular games; the line was a mile long. Home gaming was inevitable; that it so thoroughly wrecked arcade gaming is a testament to the fact that the arcade model for gaming was survived on consumer captivity alone; as soon as consumers had an economical home option, they took it.

  7. Re:Little-known fact by Joehonkie · · Score: 3, Funny

    I logged on to say just this. OP can shut up.

  8. Re:Little-known fact by bsolar · · Score: 4, Insightful

    Everyone except millions of gamers finally able to play at home.

  9. Re:Little-known fact by itzly · · Score: 2

    I see two LS165 chips with a serial output that goes into a LS240 octal bus driver. Where's the serial to parallel converter you're talking about ?

  10. Re:Little-known fact by The+Rizz · · Score: 2

    Maybe they were just smart and saw the writing on the wall for coin operated games.

    I think Nintendo were the ones who wrote it on the wall - the NES was the first real competition for coin-op arcades. Sure, other home systems already existed, but they were far, far behind arcade hardware's level of quality. The NES wasn't there yet, either, but it brought quality levels a lot closer than anything in the past ever had, and expanded into areas the arcade machines couldn't, with the concept of epic games with save/load features (Zelda, Metroid, etc.).

  11. Re:6502 - illegal opcodes by NJRoadfan · · Score: 2

    Those illegal opcodes caused problems on the Apple II. Later machines starting with the Apple IIc used the 65c02 which defined new functions for some of the previously unused opcodes.

  12. Am I that old? by William+Baric · · Score: 4, Funny

    I read the summary and thought : why the fuck does it tell those common facts about the 6502. I mean who doesn't know this? And then there was this awkward moment when I thought to myself : am I that old?

    1. Re:Am I that old? by dannycim · · Score: 3, Funny

      Funny coincidence, four days ago I woke up in an ambulance (long boring story) and the number on the inside door was 6502. I smiled stupidly and said "Hah! 6502!" and looked at the two EMTs sitting next to me. They looked quizzically at me.

      "Oh right, I'm old." I said.

  13. Illegal example by spaceyhackerlady · · Score: 2

    I wouldn't have minded seeing an example of one of those illegal opcodes and how what it did was useful.

    Brooks called such things "curios". Side-effects of invalid operations that people had started to use, and that had to be considered part of the specification.

    My policy (seconded by my boss) is that I do not document such things. If a hack is documented people start to use it, then we have to support and maintain it.

    ...laura

  14. Opcodes still burned in my brain by m.dillon · · Score: 4, Interesting

    I started serious programming (at around age 14) on the Pet. First in BASIC, but once I found out you could break into a machine language monitor by wiring up a NMI button (we called it the two-button salute), there began my machine coding. In HEX, directly. Didn't even have a relocator at the beginning. It was a year before I could buy the expansion rom to add disassembly and relocation features to the machine language monitor.

    Ultimately I wrote an assmbler too. I don't think I have any of that code any more, it's been lost in time. Kinda makes me sad.

    The PETs 8-bit IEEE-488 bus was pretty awesome. The PET had a 1 MHz 6502. The external floppy drive also had a 1 MHz 6502 in it, and you could reprogram it. So one of my many projects was to speed up the data transfer between the two by synchronizing the processors with a series of handshakes and then pushing or pulling the sector data without any further handshakes (using processor timing).

    My friend did the same thing for the C64's serial interface (which didn't even have a uart) and sold a product called '1514 Flash!' that sped up the serial interface. Basically a little messing around at the beginning of each transfer to get the two sides synchronized within 1 clock cycle of each other and then pushing/pulling bits as fast as the little cpus would go without any further handshaking. The clocks would stay synchronized long enough to copy a whole sector.

    Other projects on the PET... it had a character generator rom which I replaced with a static ram. so when I powered it up I had to load a copy of the original rom into the ram blindly (because the display was total garbage due to it being an uninitialized ram).

    The PET had built-in CRT screen but the key was that the data input for the screen was actually a TTL input! So I could pop the wire off the connector and use it like a digital oscilloscope to probe various TTL-based projects (as well as the PET's motherboard itself).

    Another project...the character generator rom had something called quarter-block graphics. Basically 16 characters that had all 16 combinations of four quarter-blocks (2x2), so you could (I think) 320x200 graphics on it. I spent many hours optimizing the machine code to generate a pixel pusher.

    I got so good at writing editors from scratch, once when I went to computer camp and forgot to bring the tape I rewrote the text editor in machine code in less than an hour.

    Met Richard Garriott at that camp too, we were both on staff. He was working on (I think) Ultima II at the time (on an Apple II I think) and had an awesome ram disk for storing code temporarily while he was working on it. Once his computer stopped responding and after unsuccessfully trying to resurrect it he finally gave up and power cycled it, losing his work in the ram disk. It turned out he had accidentally disconnected the keyboard and the computer was actually fine. Oh well! Richard taught a class at that camp on human-interface parsing... basically had people write a dungeon game where you typed in what you wanted to do in English. Primitive of course, but the kids had a blast.

    I wrote a centipede game in machine code, incredibly fast and awesome (the last level the centipede was invisible and only blinked into existence for a second or two every few seconds), and submitted it to Cursor magazine. They rejected it because they thought I had stolen it from someone :-(. The only thing I ever tried to get published, rejected because the code was *too* good!

    The 6502 had two awesome indirect EA modes. (TABLE,X) and (ADDR),Y, along with the standard modes.

    Decimal mode wasn't as interesting, I wound up not using it for display conversion at all.

    The 6522 I/O chip was an incredibly powerful chip for its time, with multiple timers and timer-driven events. It had a few bugs, too.

    I remember all the unsupported machine codes the 6502 had. It was a hardwired cpu so all instruction codes did *something* (even if it was mostly to just crash the cpu). LDAX was my favorite. Mostly, though, the hidden codes were not very useful.

    The list goes on. Twas an awesome time, a time before PCs took over the world.

    -Matt

  15. Not a fact by Millennium · · Score: 2

    Are you suggesting that the Famicom was based on a system that wasn't released until two years after its own release (1983 for the Famicom, 1985 for the VS. System)?

    Or are you suggesting that Nintendo abandoned the home market after making the VS. System, despite having released not one but three arcade systems after it, (the Playchoice-10, the Super System, and the Triforce board)?

  16. Re:Little-known fact by SeaFox · · Score: 2

    Nintendo are bastards because ... they abandoned the coin-op industry entirely, leaving everyone with aging games and no new ones being developed. Back in the day it caused quite a bit of controversy. Some operators had hundreds of Nintendo VS System games, which no one wanted to play when they could play the SAME games at home for FREE. Nintendo fucked everyone.

    Did these operators have some sort of contract with Nintendo where they were guaranteed new titles for a set period of years? Were they told the titles would be exclusives for the VS system, which Nintendo later released for the home systems? I doubt it on both. Sounds like a bunch of whiny arcade owners upset a company exercised its freedom to not do business in a given segment anymore for new opportunities they weren't a party to. They were a middle-man to game players and Nintendo started selling to them direct. The operators just bought a bunch of hardware and unfortunately bid on the wrong pony. Could have happened with any vendor/platform.

    TL/DR: Operators getting caught in changing times; who moved my cheese?

  17. Re:Little-known fact by MightyYar · · Score: 4, Informative

    The VS system didn't come out until after the NES (well, the Famikon version from Japan). You have the timeline backwards.

    Many of the cabinets on VS machines are older because they were converted Donkey Kong or Mario Bros cabinets.

    --
    W..w..W - Willy Waterloo washes Warren Wiggins who is washing Waldo Woo.
  18. What the hell? by ckatko · · Score: 2, Informative

    That's not even factually correct. It doesn't have a 6502. The NES had a Ricoh 2A03, which was a modified 6502 which REMOVED the BCD so they could put IO hardware registers in its place for controllers, sound, and DMA. The SNES did the exact same thing with the Ricoh 5A22, which is derived from the WDC 65C816--the same CPU as the Apple IIGS, which is why the development kid for SNES was an Apple IIGS.

    How are we supposed to learn something from this submission if they can't even be bothered to check Wikipedia first? Fun-fact: If your information isn't better than what Wikipedia already has, it's useless.

    1. Re:What the hell? by itzly · · Score: 2

      The NES had a Ricoh 2A03, which was a modified 6502 which REMOVED the BCD so they could put IO hardware registers in its place

      No. They left the BCD in place, but just disabled it. Also, the BCD logic is fairly small, and in the middle of the CPU, where there would be no room to add extra features. The extra IO registers were put around the original 6502 core. Here's an explanation: http://forums.nesdev.com/viewt...

      And here you can see the 2A03 chip, with the 6502 core sitting in the corner:
      http://www.vgmpf.com/Wiki/inde...

  19. NES? There are lots of those... by Karmashock · · Score: 2

    ... here is what I want, Xbox and PS emulators.

    The PS1 has some pretty good emulators but the PS2 doesn't really... and I think the PS3 doesn't have them at all.

    As to the xbox, I've yet to see even one xbox emulator that was worth a damn.

    Not even the first xbox. Which makes me sad because I want to be able to play Halo 3 and 4 but I refuse to buy an xbox just for those games. I'm a PC gamer. MS released Halo 1 and 2 for the PC. Cool. And I don't mind waiting a couple years. That's fine too. But release them EVENTUALLY for the PC. Don't tell me the porting process isn't easy. We all know it is. So just do it and make me happy.

    That or I'm going to be one of those people skulking around looking for xbox emulators and cruising torrent sites for the game files.

    I will BUY your game for the PC. If you don't let me do that... then I'm sawing off my leg, wearing a eye patch, adopting a parrot, and developing an annoying love of the sound "ARRRRR".

    you have been warned.

    --
    I've decided to stop wasting my time responding to AC trolls/sockpuppets... so if you want a response from me... login.