[HN Gopher] Project-Nested: An NES Emulator Running on the SNES ___________________________________________________________________ Project-Nested: An NES Emulator Running on the SNES Author : hutrdvnj Score : 161 points Date : 2021-07-11 16:40 UTC (6 hours ago) (HTM) web link (github.com) (TXT) w3m dump (github.com) | ionwake wrote: | No sure if this is the right place to ask, but are there any | retro emulator setups which allow you to play 2 player games over | the internet? | | Ive heard something maybe possible with retroarch but Im | surprised there is no pi zero with an easy multiplayer setup yet | ( for instance to play 2 player Mario Tennis on the Gameboy ) | jsd1982 wrote: | Not a general solution, but there are communities where we play | ALttP in various multiplayer modes: https://discord.gg/AVQ2yKd | https://discord.gg/rJ9n6rJb | hauxir wrote: | snes.party :) | s_m_t wrote: | Yes, but you need very good latency to the other player for it | to work well. The typical setup is to use something like parsec | where one person hosts the emulator and streams audio/video and | the other person sends keyboard commands. | | You can add a small delay to the host to even things out but to | properly account for latency is a major reverse engineering | project which afaik off the top of my head has only been done | for super smash bros melee | jogu wrote: | Yes, look into retroarch netplay. They have a rollback netplay | implementation that works great from my experience. | raldi wrote: | The reverse is also possible: | https://youtube.com/v/ar9WRwCiSr0?t=17m | detaro wrote: | that's something quite different. | raldi wrote: | As it would have to be ;) | derefr wrote: | I saw this mentioned by a YouTuber, who went on to say that many | people believe that the SNES was originally intended to be | backward-compatible with the NES. | | IMHO that's not quite right -- there's a lot of simple things | Nintendo could have done to make the SNES a lot _more_ backward- | compatible with the NES, that would have had to have been done | right at the beginning (and so stuck around as additional | evidence of this), just as the few places that _do_ line up (e.g. | controller read-out + MMIO address) were certainly done right at | the beginning. | | Instead, I think what Nintendo was imagining, was that -- as long | as the NES and SNES were still both "alive" in the market | concurrently -- then companies would want to concurrently release | both NES and SNES versions of their games. And, with some careful | planning, development studios would be able to have a _single | 6502 macro-assembler codebase_ that _compiled_ to either a NES or | SNES _target_. Developers could either add MMIO address pokes / | JSRs inside #ifdef-like macro structures; or just write two | subroutines, one for NES and one for SNES, and then compile-time | branch to determine which would get compiled in. | | This makes sense of where the NES and SNES line up in | compatibility, and where they diverge: they line up where there's | an obvious way to support both consoles with one block of | instructions; they diverge where developers would have to write | separate subroutines to support the different hardware anyway, so | instruction-level / memory-map-level compatibility isn't so | crucial. | | This seems so obviously "possible" (though definitely | challenging!) that I've always wondered whether there are any | games that are actual examples of this -- where the game came out | at the same time in both NES/FC and SNES/SFC releases, and binary | analysis reveals that the majority of the game's engine code is | shared between the two, with differences mostly in the | subroutines/coroutines composing the "graphics engine", and in | the static data. | | ---------- | | On a separate note, I feel like it would be even simpler -- and a | lot more performant! -- to _ahead-of-time recompile_ a NES game | to run on the SNES. The NES doesn 't tend to do tricks with | dynamic runtime code generation, so NES games are good candidates | for being statically analyzed and transpiled. (And the SNES has | such a similar architecture, that even those dynamic runtime | tricks might map cleanly onto the SNES, too.) | hnlmorg wrote: | I wouldn't have thought so. Back then version control was | making copies on a floppy disk. A lot of developers didn't even | have dedicated build machines let alone the fancy CI/CD | pipelines we do these days. Plus most studios had pretty tight | deadlines. So if they did any code sharing it would have been | more like copying/pasting rather than assembly macros. In fact | I wouldn't be surprised if the "copying/pasting" was literally | someone printing out (to a dot matrix printer) and an office | junior manually punching those instructions back in on another | machine. | | It was a very different era back then. Tooling sucked and | everything was a lot more manual. But we didn't mind as were | still pushing boundaries of our imaginations and didn't know | any better. | wk_end wrote: | I think you'd find the opposite - that NES games use lots of | weird unstructured or dynamic code tricks that make automated | AOT static recompilation very difficult or impossible, in most | cases. These things tend to be _more_ common on older CPUs and | in hand-written assembly code, not less. | derefr wrote: | You're talking about this stuff: | https://andrewkelley.me/post/jamulator.html#dirty- | assembly-t... | | Personally, I disagree with the author of that article's | conclusion here, that the [only] "solution is to embed an | interpreter runtime in the generated binary." You _can_ | statically recompile this code! | | You "just" need to run a concolic interpreter over the code, | generating out new static instruction streams for each | possible phi-node (branch) state, and then coalescing them | back together where you find you've generated the same | instruction stream. You can early-terminate these spec-exec | paths when you find yourself back at an instruction | postdominated by entirely static code [within the body of the | unrolled runtime coroutine sequence]. | | Might sound like an unbounded exponential check, but in | practice 1. merging back together will usually happen within, | at most, five instructions, because these are almost always | last-minute bit-packing-hacks to get code to fit within a | given constrained ROM image size; and 2. there are always | _only two_ concolically-discoverable valid interpretations of | a given instruction stream (if doing mid-instruction jumps), | and _only one_ concolically-discoverable valid interpretation | of data-as-code / RAM-as-code. (NES games don't assemble and | JIT arbitrary code streams. They don't have the work RAM for | it. They're at most _unpacking_ existing, non-arbitrary code | streams; or taking something that is primarily a code stream, | and then reusing it as data elsewhere, maybe a PRNG seed, or | a 1-bit noise texture.) | | A large part of my job lately is decompiling and | "reconstructing meaning" for object code compiled for lousy | underspecified abstract-machine architectures. There are a | _lot_ of modern compiler-theoretic tools and tricks that can | make short work of "statically" recompiling any but the | hardest of hard cases. They're sadly virtually unknown | outside of academia, though (probably because they're based | on various graphical transformations of the code proposed | after the Dragon Book was published, which is the point in | history where most people in industry's knowledge of | compilers seems to stop.) | wk_end wrote: | Well, I know a good deal about old video game systems but | you clearly know more about (re/de)compilers than I do, so | although still skeptical I'll defer to your expertise, | while vaguely gesturing towards "lots of people would love | the performance gains of static recompilation in our | emulators, if it's feasible please advance the state of the | art" :) | | Pretty sure you're still going to be stymied by things like | cycle-counted code to line up I/O writes with the state of | the hardware, though. I don't suppose there's tricks for | that. | anyfoo wrote: | Cycle-accurate transpiling, now that sounds like a fun | project. I think it would "only" have to be cycle- | accurate between specific events, e.g. access to specific | registers. (No idea how feasible this whole thing could | be.) | monocasa wrote: | I remain skeptical (but would love to be proven wrong!). | | Most of the point of recompiling (JIT or AOT) is to | amortize instruction decode and dispatch costs versus an | interpreter. If you have to do the cycle accurate | bookkeeping anyway, you're most of the way to the | overhead of an interpreter again. There'll be some | savings around partial instruction streams that don't | have effects outside the CPU core that can just be run as | a burst, but I'm not sure it'll be a game changing | amount. | [deleted] | bonzini wrote: | I expect that some games would put subroutines once in the | zero page and then self-modify addresses in there. | | Instructions are only written once but could potentially be | written by any store with zero page indirect[1] or indexed | addressing. | | [1] that is ($AA,X) or ($AA),Y | stormbrew wrote: | The zero page is very small, I don't think this was done | that much. You'd constantly be writing large gobs of | stuff into it and that'd be very slow. | | That said, the stack was used as a fast indirect jump | address location pretty frequently, as described here, | essentially abusing the fact that PHS and RTS are 1 byte | instructions: | http://www.6502.org/tutorials/6502opcodes.html#RTS | | And really since basically all PC-modifying instructions | operate on either relative (b*), absolute-indirect (jmp), | absolute (jmp, jsr), or stack-indirect (rts, rti) there's | no special benefit you get from having code in the zero | page anyways afaik. | a1369209993 wrote: | > there's no special benefit you get from having code in | the zero page anyways afaik. | | You save one cycle off each instruction that modifies | another instruction, which can important for inner loops. | See eg http://www.linusakesson.net/programming/gcr- | decoding/index.p..., although that's a disk-induced | realtime requirement, rather than hblank/beam-induced. | stormbrew wrote: | I don't think this was really a practical thing and I think | there'd be other signs of an attempt at if if so. The final | version of the SNES PPU probably would have resembled the NES | PPU more, for example, in small ways like tile sizes at the | very least. There's at least one mode on the snes ppu that's | kiiiinda like the nes ppu's standard behaviour but it's just | off enough to make reusing code for it fairly hard I think. | | And then I think you'd have seen a mapper for the NES that more | closely resembled the 65816's native addressing, since that | would definitely have eased such porting efforts. But even the | MMC5, which was first used the same year the SNES came out | didn't move much in that direction. | | Tbh I think you're also overestimating the assemblers they used | at the time as well, both in terms of the expressiveness of the | macros they had available and and kind of dead code removal you | might be imagining happening. | | I think a much simpler explanation is just that they had it in | mind as a possibility from the start and they made some design | choices that were both easy and would have allowed it. They may | have been leaving open the possibility of an adapter cart like | the genesis power base converter (which had much less work to | do) too. But they also decided fairly early on that it wasn't | really worth it economically and nixed it early enough that it | didn't make a huge impact on the architecture. | 0xcde4c3db wrote: | > The NES doesn't tend to do tricks with dynamic runtime code | generation, so NES games are good candidates for being | statically analyzed and transpiled. | | Runtime code generation is rare, but dynamic dispatch (i.e. | "JMP indirect" through RAM), jump tables, and certain | instruction-level hacks are fairly common. This can make it | tricky to reliably identify all subroutines or traces [1]. | | [1] https://andrewkelley.me/post/jamulator.html | djur wrote: | Nintendo also tends to be pretty conservative when selecting | technology for new products (Gunpei Yokoi's "lateral thinking | with withered technology"[1]). It's entirely possible that the | similarities between the NES and SNES are that they wanted to | avoid any needless innovation -- keeps costs down, makes | sourcing parts easier, you already have a lot of expertise in | at least some of the hardware you're using, and your developers | don't need to relearn as much. | | Nintendo stuck with pretty similar PowerPC chips for three | generations while Sony went MIPS->PowerPC->x86. And when they | finally switched off of PowerPC, they went to ARM, which they'd | been using for handheld systems for two decades. | | [1]: | https://en.wikipedia.org/wiki/Gunpei_Yokoi#Lateral_Thinking_... | neuronexmachina wrote: | I'm also curious about how what architectural similarities | there might've been between NES/SNES and Gameboy, since there | were quite a few common releases. | einr wrote: | The GameBoy is distinctly different from the (S)NES. It uses | an 8080/Z80-ish CPU core instead of the 6502/65816, the audio | and graphics hardware have different capabilities than the | NES, etc. There were a lot of games that were both on the NES | and the GB but they were rarely 1:1 ports for these and other | reasons. | coldacid wrote: | Probably not as many as you might assume. There's also the | issue of the Game Boy running on an 8080 derivative, unlike | the NES and Super NES, which ran on 6502 (and 65816) | derivatives. | | You might be interested in these articles covering each | console's architecture: | | * NES https://www.copetti.org/writings/consoles/nes/ | | * SNES https://www.copetti.org/writings/consoles/super- | nintendo/ | | * Game Boy https://www.copetti.org/writings/consoles/game- | boy/ | truthwhisperer wrote: | very cool link | codebolt wrote: | The Super GameBoy comes to mind. Was it a full-fledged | emulator or did it use any neat tricks to run GB code | directly on the SNES? | einr wrote: | The Super GameBoy is essentially full GameBoy hardware in a | cart, that hijacks the SNES PPU for video output and uses | SNES controllers for input. There is no hardware emulation | going on. | monocasa wrote: | It wasn't even an emulator, it was a complete gameboy SoC | with the pixel stream routed to the SNES's VRAM rather than | an LCD screen. | [deleted] | monocasa wrote: | They're basically completely different other than broad | architectural strokes. Different CPU ISA, the keys are | sampled through a matrix rather than a bit banged shift | register setup, audio channels are pretty different, GPU is | internally pretty different (LCD allows pauses in the pixel | stream unlike a CRT so the GPU uses that), etc. | daneel_w wrote: | Former SNES and GBA hobbyist developer here. The different | CPUs aside - Z80 in the GB, 6502 in the NES, 65816 in the | SNES and ARM in the GBA - the GB, just like the NES, shares | very little with the SNES. The GBA is a different story: it | is in so many ways like the SNES' sibling, but an improved | sibling, most distinctly because of its open memory | architecture allowing convenient and fast access to all of | its custom hardware, whereas in the SNES the video and sound | chip RAM is tucked away behind single-byte-sized memory | channels you have to access by shoveling bytes manually (or | by programmable DMA) back and forth between CPU-accessible | RAM and video/sound chip RAM etc. This architectural choice | was in my opinion the largest improvement the GBA brought, | more so than moving away from the SNES' custom "sound | computer" which was a bit of a hurdle. | pezezin wrote: | Now that you mention the sound, I always had this question: | was the GBA sound system any good? My understanding is that | the GBA only has the original GB sound chip plus two PCM | channels, without any dedicated hardware synthesis or | mixing, so all sound effects need to run on software. Now | the CPU was so much faster than the SNES or Megadrive, but | was it fast enough to make up for it? | djur wrote: | GBA games were generally regarded as having lower sound | quality than SNES games, although this perception was | somewhat exaggerated by the poor quality of some | SNES->GBA ports. It took a lot more CPU to get good audio | out of the GBA, and I'm sure developers were taking the | GBA's tinny speaker into account when deciding how much | effort to invest in polishing the soundtrack. Hell, the | GBA SP needed an adapter to use headphones! | RetroSpark wrote: | The Game Boy is much more similar to the Sega Master System & | Game Gear than to the NES. Some games (e.g. Lemmings 2, | Pinball Dreams, Spirou) were developed for both handhelds (or | even for all 3 platforms) using a single assembly-language | codebase. | monocasa wrote: | What I think really happened is that they originally planned on | it being backwards compatible, but then realized how many games | depended on undocumented opcodes and bugs that had been 'fixed' | in the 6502 mode of the 65816. At that point, go back to your | bread boards and go nuts removing anything that was there for | NES compat but was holding back the SNES in some way. A few | iterations of that and you have a pretty much what an SNES was | on launch. | | Edit: Thinking about it more, that all would also make sense | given their strategy past the SNES for back compat. On the GBA | they literally just have a complete GameBoy SoC on the die. | It's not accessible to GBA software, is probably clock gated in | GBA mode, but is there with as few changes as possible from GB | hardware to run GB software. Then for the Wii, the companion | ARM processor (Starlet as it's known by the Wii hackers) will | go so far as to patch problematic GameCube games on load even | though it's very nearly identical hardware with a few | extensions. It seems like they either drop down gate for gate | compat, leave a back door for themselves to get really dirty | with patching, or these days just keep an emulator around that | they've re-QAed each game on that they'll allow. They're very | intentional with back compat in a way that feels like an | ancient learned lesson internalized by the company. | Wowfunhappy wrote: | Curious, is there a reason to think the 65816 wasn't just a | good CPU? From a supplier Nintendo had a good working | relationship with? | | I mean, we'll never know for sure, but what was the cpu | landscape like? Were the other options clearly better? | christkv wrote: | The Motorola 68000 is the only other one I can think off. | phire wrote: | This has always been my view; It's the only CPU I know | about that met the requirements. | | Other 16bit consoles used an off-the-shelf 68000, combined | with custom support chips. Nintendo made their own custom | cpu silicon, an off-the-shelf soft-cpu and custom support | logic for bus control and DMAs. | | And there simply weren't that many 16bit soft-cpus | available for Nintendo to license. You couldn't license the | 68000 HDL, nor the 8086 HDL. | Wowfunhappy wrote: | While not quite the same thing, I've read that the games in | Super Mario All-Stars use basically the same assembly code as | the original NES versions, just with updated graphics. | pfranz wrote: | I'd be curious to know more about the development of Super | Mario All-Stars. I've been playing both the original and All- | Stars (on the Switch--if that matters) and the acceleration | of Mario in SMB1 feels different. The original SMB and All- | Stars were only released 8 years apart. If they didn't use | the original code base they likely had access to the original | dev team. | Wowfunhappy wrote: | It feels different because of a one-bit screwup! | | https://www.romhacking.net/hacks/167/ | Tarsul wrote: | your link is about the behavior when Mario hits a brick | whereas OP was talking about acceleration of Mario (I | think he means running?!). Quite interesting link, | nonetheless! | Wowfunhappy wrote: | Yes, but we often don't feel what we think we're feeling! | The patch changes Mario's speed when he hits a brick, | which will have implications for when he hits the ground. | | I'm far from an expert player, but I really think the | physics are identical once the patch is in place. I | sometimes wonder if it was really a mistake at the | factory--something they didn't catch until 20,000 PCB's | in, and didn't want to change in revisions for | consistency. | sciolistse wrote: | They did use the original source, the All Stars source is | included in the recent leaks of Nintendo software.. You can | see a lot of the original code and see what they changed. | It seemed when I glanced at it that the SNES developers | used a different level of indentation so it was noticeable | when some new code was added in. | hypertele-Xii wrote: | This one I presume: | | https://www.youtube.com/watch?v=TthFh27Mx5k | TillE wrote: | Pretty cool, but it definitely can't quite keep up. Just tried | the Legend of Zelda, and it lags with flickering horizontal lines | (not drawing fast enough?) on both snes9x and original hardware | (via FXPAK Pro). | einr wrote: | Just to put the achievement into perspective, this is code | written for a console with a 1.79 MHz 6502 running on a 3.58 | MHz 65816 (a 6502 with 16-bit capabilities crudely bolted on) | -- that it even runs anywhere _close_ to native speed and with | so relatively few bugs is a monumental achievement considering | that even though the SNES will run 6502 code, the audio and | graphics hardware, etc., are entirely different between the | consoles and have to be emulated. | dehrmann wrote: | I think my microcontroller class used a variant of the | 68HC08. I didn't realize it's a cousin of the NES chip. | torgoguys wrote: | I haven't tried this, but there is so much awesomeness in this | idea. I wonder how many layers down one could pull off in the | Nintendo line, even if you had to skip generations. For example | could one do a Wii emulating GameCube emulating a SNES (skipping | N64 as presumably too hard), emulating a NES. | pezezin wrote: | The GameCube could emulate the N64, that's how games like | Ocarina of Time were brought to the GameCube. Remember that the | first N64 emulator, UltraHLE, was released in 1999 and could | run on a computer less powerful than the GameCube: | https://en.wikipedia.org/wiki/UltraHLE | hnlmorg wrote: | The Wii already runs GC games (even centres the GC's miniature | DVDs if they're loaded into the Wii's slot off centre), and | supports GC controllers and GC memory cards. | | https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2F... | simcop2387 wrote: | > Wii emulating GameCube | | No need for this, it's natively supported and runs game cube | games (and with the right setup, GC homebrew) | j1elo wrote: | This is because largely speaking, the Wii is the same | hardware than the GameCube (but with improved speed). That's | why the Dophin emulator, originally a GC emu, was able to | extend easily to also cover the Wii. | xerox13ster wrote: | Hi friend, it's same as, different than. | [deleted] | j1elo wrote: | Thanks! must have slipped. | fridif wrote: | Your sentence is a run-on sentence. | torgoguys wrote: | Right. That's why I didn't skip that generation in my | example. My hunch was that as a general rule for those | earlier generations that it's not possible to emulate the | immediately previous generation unless there was special | support, but maybe you could go back 2 generations. This | project being an exception. That's what lead to the | | Wii -> GameCube (similar hardware) -> [not N64] SNES -> NES | (demonstrated by this project) | | example. Heck, if console manufacturers kept two separate | branches "every other generation" emulation (odd/even | generations) and then made sure each console generation had | extra hardware to play the immediately prior generation's | games (as some sometimes do), then every generation could | play every other generation. That would be nice for players, | but maybe not nice for the companies though. | monocasa wrote: | Arguably the Wii is emulating parts of the GameCube. I was | pretty sure that certain MMIO banks on the GameCube were | being emulated by starlet rather than having hardware blocks | like the GameCube probably did. That's how custom MIOS hacks | floating around the internet allow for USB controllers and | mass storage from GameCube games. | [deleted] | azinman2 wrote: | The readme is quite light on details. What is the performance? | What's the snes emulator.. is it this as well? Could this run on | the real thing given it sounds .exe driven? | hypertele-Xii wrote: | Yes it runs on stock hardware. Near full performance. | andrewmcwatters wrote: | Spent at least three years of development, but couldn't be | bothered to spend 15 minutes to write up how any living soul | would use it without downloading and compiling the project to see | help text from the .exe. | capableweb wrote: | It's almost like the author of this project didn't spend 3 | years on this for you, but for themselves... | andrewmcwatters wrote: | It's almost like the author published it on GitHub, where | people expect a modicum of explanation as to how to get | started with something. Weird. Wild. | undershirt wrote: | It converts an NES rom to an SNES rom. Here are the | instructions from the source[1]: Step 1, | click "Open Nes" and select a game. Step 2, (optional) | select or create a profile. Step 3, click "Save Snes", | a file will be created in the same folder as your Nes game. | Step 4, play on Snes hardware or Snes emulator. Step 5, | (Optional) click "Load SRM" and select the SRM file(s) | generated by the Nes emulator, feedback will be saved | to the profile so the game can run faster after repeating steps | 1-4. | | [1]:https://github.com/Myself086/Project- | Nested/blob/fc108119/Pr... | CyberRabbi wrote: | Very cool and something that has been in demand for many years. | Ideally this would be bundled into the SD2SNES firmware so you | could load NES roms onto the SNES. https://sd2snes.de (it's open | source as well) ___________________________________________________________________ (page generated 2021-07-11 23:00 UTC)