[HN Gopher] Emulating Nintendo Switch Games on Linux
       ___________________________________________________________________
        
       Emulating Nintendo Switch Games on Linux
        
       Author : podiki
       Score  : 139 points
       Date   : 2020-07-24 14:47 UTC (8 hours ago)
        
 (HTM) web link (boilingsteam.com)
 (TXT) w3m dump (boilingsteam.com)
        
       | ikeboy wrote:
       | Some googling turns up https://github.com/PrincessAkira/road-to-
       | yuzu-without-switch, which doesn't require access to a switch.
       | Disclaimer: haven't tried this myself.
        
         | PaulBGD_ wrote:
         | Just a warning, this method is considered piracy. Not that I'm
         | placing judgement on anyone who goes his route.
        
           | popinman322 wrote:
           | Yeah, if you file a bug with Yuzu, or join their chat
           | channels and request support, and there's any hint that you
           | didn't use your own switch you'll be banned instantly. They
           | really do have a 0 tolerance policy.
        
             | saagarjha wrote:
             | Most projects of this sort are fairly touchy about that
             | kind of thing, because they're at the risk of being canned
             | if it seems like they are promoting piracy.
        
             | BurningCycles wrote:
             | For good reason, this is an emulator for a current-gen
             | system, and from what I've seen on Youtube, a lot of games
             | are fully playable.
             | 
             | Companies are likely not that bothered by legacy systems
             | being emulated, but this is the current Nintendo flagship
             | console. Thankfully the Switch seems to be selling
             | amazingly, which should mean Nintendo don't really care
             | that much.
             | 
             | Another factor is that you will likely need a pretty beefy
             | PC to play games in full speed, and compatible controllers.
        
               | ghostpepper wrote:
               | Not to mention that a significant portion of the value
               | prop of the switch is its unique hardware, and the
               | ability to seamlessly transfer an in-progress game
               | between your TV and handheld.
        
           | [deleted]
        
       | crispyporkbites wrote:
       | That's a lot of steps upfront to avoid any hint of piracy, but
       | you're almost certainly breaking the license agreement by dumping
       | the cartridge, so what's the point in trying to avoid piracy.
       | 
       | Just because you bought a cartridge with a binary and a license
       | to execute that binary on a switch doesn't mean you have the
       | legal right to back it up and play it on your PC.
        
         | SifJar wrote:
         | Probably more to do with morality than lethality. Pretty
         | subjective, but there are definitely plenty of people who are
         | morally opposed to piracy but have no problem with illegal
         | backups/rips/dumps of stuff they have legally purchased.
        
         | saagarjha wrote:
         | > Just because you bought a cartridge with a binary and a
         | license to execute that binary on a switch doesn't mean you
         | have the legal right to back it up and play it on your PC.
         | 
         | Do you in fact! As long as it is _your_ cartridge and you
         | backed it up yourself, you can legally emulate it. (You cannot
         | use someone else 's dump, nor can you share yours.)
        
         | gambiting wrote:
         | Depends where you live,but in a lot of places the ability to
         | make backups of your own digital media is enshrined in law. And
         | in EU "license agreements" are usually worth as much as toilet
         | paper, especially if they are implied rather than explicit
         | (like, saying "by using this software you agree to this
         | agreement" is essentially worthless, you can agree to literally
         | anything and it won't hold up in court)
        
       | ddevault wrote:
       | Of these two emulators, Ryujinx is almost certainly never going
       | to achieve a good level of performance, because they chose to
       | write it in C# of all languages. Take my advice: if you're going
       | to write an emulator, do it in C or C++, preferrably C. Ryujinx
       | is a mind bogglingly massive amount of wasted effort.
        
         | b0b_d0e wrote:
         | The other sibling comments were talking about general C++ vs C#
         | performance, but I wanna get into some emulation specific
         | context here that's missing. I was one of the contributors to
         | the yuzu project since it was first started, and so I'm fairly
         | familiar with the challenges of switch emulation, albeit I'm
         | not going to pretend like I was one of the all-star devs
         | responsible for making the magic happen. (I've recently stopped
         | contributing to the project in order to pursue other interests,
         | so i'm going to keep the information here general and not
         | specific in case somethings changed in the last month.)
         | 
         | Let's start off by breaking the core performance portions of
         | emulation into a few broad categories. There's CPU emulation,
         | for running the actual guest exe, Kernel and OS emulation for
         | handling the system calls that games make, and GPU emulation
         | for translating the guest's GPU work into modern graphics API
         | that your PC can use. Now let's compare how language overhead
         | will affect each of these main scopes.
         | 
         | CPU Emulation - Both yuzu and Ryujinx use JIT compilation to
         | recompile the guest ARMv8 instructions into x64 at runtime. The
         | specifics of the two emulators JITs are pretty different, and
         | it'd be cool to go into more details, but the mile high view is
         | a comparison of C# vs C++ isn't going to have much of an effect
         | on the runtime difference. At least not near as much
         | performance gap between techniques and optimization levels that
         | the JIT is capable of. The goal of JIT compilation for CPU code
         | is to remove as much interpreter overhead as possible, so if
         | your choice of programming language is slowing down the JIT,
         | that suggests that you have somewhere else to improve in the
         | JIT ;)
         | 
         | Kernel/OS - This is the area that will have the largest
         | performance difference between implementation languages, but
         | with the major caveat that Kernel and OS emulation requires the
         | least amount of processing power out of the 3 categories
         | mentioned here. The Kernel and OS are responsible for managing
         | and scheduling threads, handling network connections, and etc,
         | but really most of these things have fairly low impact on final
         | application performance in comparison to CPU and GPU emulation.
         | As a side note, emulators aren't the only groups interested in
         | switch OS/Kernel work. The open source Atmosphere custom
         | firmware for the switch is working through recreating an open
         | source kernel/os for the switch, and the two emulators benefit
         | from their work too. (See the licensing exemptions here
         | https://github.com/Atmosphere-NX/Atmosphere#licensing)
         | 
         | GPU Emulation - This is probably the trickiest part of Switch
         | emulation, and once again, it comes down to how you emulate it,
         | and not the language you use to write the emulator. The biggest
         | performance differences between the GPU emulation of the two
         | emulators will boil down to technique differences, and not the
         | programming language. GPU emulation performance can be roughly
         | broken into two parts, the "actual" gpu running time, and the
         | state management/conversion. There's only so much an emulator
         | can do about the actual GPU running time since at some level,
         | you are going to need to run the game's GPU code, but the other
         | half is a whole lotta code to avoid doing more work, and much
         | of the GPU performance optimizations goes here. Things like
         | managing the game's GPU memory, avoiding changing or querying
         | GPU state unless necessary, converting nvidia shader ASM into
         | SPIR-V or GLSL, and so on, are not generally going to be
         | bottlenecked on the emulator's language of choice, but on the
         | algorithms and designs that you use. Also a side note, the
         | average comment about how "easy" switch emulation is because of
         | "off the shelf nvidia parts" really misunderstands just how
         | much work goes into this part. Switch emulation benefits
         | greatly from the open source nvidia reverse engineering efforts
         | from teams like nouveau, and others working on open source GPU
         | acceleration on the switch like
         | https://github.com/devkitPro/deko3d but also a great deal of
         | effort from the switch emu devs themselves, writing tests cases
         | to run on the switch to find edge cases and document behavior.
         | It definitely is not easy work.
         | 
         | At the end of the day, every drop of performance counts, but
         | some drops are much much larger than others. As such, the
         | advantages of any language's performance characteristics will
         | be heavily offset by the design choices the emulator uses. The
         | creator of ryujinx is very comfortable with C#, and with good
         | development practices, there's no intrinsic reason that one
         | cannot achieve good performance in a C# emulator. And if one
         | decides that it's worth the tradeoff to do some extra work for
         | performance in exchange for a more comfortable development
         | environment, then I say let them do what they want.
         | 
         | Shoutouts to both the yuzu and Ryujinx teams for all their hard
         | work. I loved working on emulators a lot, and highly recommend
         | anyone who's interested in contributing to give it a shot, its
         | a really challenging and rewarding kind of project where
         | there's _always_ something new to learn about in a broad array
         | of subjects.
        
         | jeroenhd wrote:
         | As sibling comments indicate, the overhead of C# isn't what it
         | used to be and certainly isn't comparable to other languages
         | like Python/Ruby/PHP.
         | 
         | Of course, there's always performance left on the table when
         | you write in a language like C# or Java (and even a little
         | performance matters a lot when it comes to emulation), but the
         | memory safety that C# can provide over C++ can save the
         | developers a lot of debugging.
         | 
         | I think such an application can perform perfectly well in a
         | hardware generation or two and until that point compatibility
         | matters more than speed anyway; that's where ease of
         | development will shine. Running an unplayable game well is not
         | a very interesting project for end users.
         | 
         | When the project reaches significant compatibility, other
         | emulators can take ideas from its code and port them to
         | C/C++/Rust/assembly if they desire to do so.
        
           | banachtarski wrote:
           | C# is consistently a worse performer than most javascript
           | runtimes currently, and it's not much better than Python,
           | Ruby, and PHP.
           | 
           | It's not just that. Basic patterns in C# are known to have
           | pathological performance problems (implicit boxing, implicit
           | heap allocations) that you simply don't run into programming
           | in C or C++. These are things that tank performance in day-
           | to-day programming that do not show up in carefully tuned
           | benchmarks.
           | 
           | Source: Helped profile lots of C# games (not IL2CPP with
           | Unity, although that's pretty bad IMO as well), not pleased
           | with what I saw.
        
             | askingforproof wrote:
             | > C# is consistently a worse performer than most javascript
             | runtimes currently
             | 
             | This is a bold claim. Please provide evidence that the most
             | current .NET implementation (.NET Core 3.1) is slower than
             | any JavaScript implementation.
             | 
             | This doesn't pass the smell test since you're comparing an
             | ahead-of-time statically typed approach to a dynamic
             | scripting language, both of which have had highly tuned JIT
             | implementations, both of which are using garbage
             | collection. You can implement things poorly in C#, sure,
             | but you're making a much stronger claim of consistently
             | poor performance.
             | 
             | Saying 'dude trust me' is not a source.
        
           | ddevault wrote:
           | >Of course, there's always performance left on the table when
           | you write in a language like C# or Java (and even a little
           | performance matters a lot when it comes to emulation), but
           | the memory safety that C# can provide over C++ can save the
           | developers a lot of debugging.
           | 
           | It really doesn't matter how much headache it saves you in
           | debugging. The problem simply cannot be solved at the
           | required level of performance if you use C#.
           | 
           | >When the project reaches significant compatibility, other
           | emulators can take ideas from its code and port them to
           | C/C++/Rust/assembly if they desire to do so.
           | 
           | The only legitimate use of this project is as a research bed
           | for future emulators, so I agree with you there.
        
         | CJefferson wrote:
         | Are any significant current emulators written in C?
         | 
         | The main emulators off the top of my head, MAME, bsnes (and the
         | related higan) and dolphin, are all in C++.
        
           | ddevault wrote:
           | qemu, a dozen gameboy emulators, dosbox, the 9front emulators
           | (NES, SNES, GB, GBA, C64, 2600), xemu, z80e, and many, many
           | more. Lots of the C++ emulators you're familiar with have the
           | performance critical parts written in C as well, excepting
           | some newer emulators which leverage something like LLVM for
           | JIT emulation.
        
           | b0b_d0e wrote:
           | redream is a Dreamcast emulator written in C only. libretro
           | (the core API behind Retroarch) and Retroarch itself are
           | primarily C. mupen64plus is in C, although the common 3rd
           | party plugins and frontends are not always in C.
        
         | faheywf wrote:
         | Why are you so certain? It seems that even a decade ago C#
         | performance wasn't far off from C++, if not slightly faster[0].
         | 
         | [0] https://journal.stuffwithstuff.com/2009/01/03/debunking-c-
         | vs...
        
           | ddevault wrote:
           | Building contrived tests which "prove" the performance of C#
           | in the face of mountains of evidence to the contrary is on a
           | much different scale from emulating an entire complicated
           | hardware system.
        
             | chrisoverzero wrote:
             | The editor ate your links to the evidence. Can you repost
             | them?
        
         | lukevp wrote:
         | Why the hate on C#? Are you perhaps thinking of languages like
         | Ruby and Python and grouping them into the same bucket as C#?
         | This[0] shows an example of C# vs C++ having a 10% performance
         | gap on ray tracing. There is also no reason that extremely
         | performance sensitive parts couldn't be rewritten in Rust or C
         | or C++ and called from C# over a FFI.
         | 
         | [0]: https://mattwarren.org/2019/03/01/Is-CSharp-a-low-level-
         | lang...
        
           | bananaface wrote:
           | C# is garbage collected. _Even if_ the performance potential
           | was as high to begin with (it 's not), that's a non-starter
           | for heavy games because you need to be able to control &
           | predict the performance spikes that GC creates. That's even
           | more important for an emulator, which needs _more_
           | predictability than a regular game.
        
             | striking wrote:
             | There are a number of ways to control the GC in comfortable
             | ways in C#. https://adamsitnik.com/Array-Pool/ comes to
             | mind, especially for games. So you can lean into GC when
             | possible, and switch to an unmanaged approach when you are
             | seeing perf issues.
        
               | [deleted]
        
             | Jach wrote:
             | There are more things in Garbage and Collection,
             | bananaface, than are dreamt of in your philosophy.
             | 
             | http://gchandbook.org/
             | 
             | https://www.cs.rice.edu/~javaplt/411/15-spring/Readings/wil
             | s...
             | 
             | https://web.archive.org/web/20191108025442/http://home.pipe
             | l...
             | 
             | https://web.archive.org/web/20191008134612/http://home.pipe
             | l...
             | 
             | https://web.archive.org/web/20191231120253/http://home.pipe
             | l...
             | 
             | https://en.wikipedia.org/wiki/Fragmentation_(computing)
        
             | JeanSebTr wrote:
             | Yes. But C# also supports struct which are stack allocated.
             | 
             | C# allows to optimise memory allocation when that matters
             | and to rely on the GC for less critical parts.
        
               | [deleted]
        
             | jerf wrote:
             | Emulation involves a lot of large byte arrays and static
             | structs that your code updates a lot to represent the
             | hardware. It isn't necessarily creating a ton of objects
             | all the time. I do not have specifics on hand for these
             | emulators but it's not hard to imagine that they could well
             | be running the GC for a few microseconds every few minutes
             | or something [1]. It is a _very_ different type of program
             | than a traditional game, or, indeed, almost any other kind
             | of program.
             | 
             | There does seem to be this odd semi-subconscious idea in
             | the "GCs aren't appropriate for any high-performance" world
             | that they intrinsically work by stopping the world for 50ms
             | several times per second or something, but that does not
             | have to be the case.
             | 
             | [1]: I actually have a number of servers in Go that run on
             | about this schedule. If you eliminated 100% of my GC cost
             | for these servers, I wouldn't care at all, or even notice.
        
               | b0b_d0e wrote:
               | > Emulation involves a lot of large byte arrays and
               | static structs that your code updates a lot to represent
               | the hardware
               | 
               | Things work a bit differently for "modern" emulators,
               | where the emulators recreate the kernel/OS at a high
               | level. In these emulators, the games will call into the
               | system, and the kernel will be expected to do all thats
               | necessary for the call. In the high level approach, this
               | means that if a call allocates, so does the emulator
               | (edit: note that this is a simplified view, as both
               | emulators map a 4GB page that they work in for the guest
               | system memory, but theres still a ton of side allocations
               | that happen "outside" of the guest kernel). There is a
               | lot of work that goes on in this layer of emulation, and
               | theres going to be objects that the emulator allocates
               | and later destroys. Process tables, thread lists,
               | scheduler information, timing events, kernel
               | synchronization primitives like mutexs, and so on to name
               | some. I'm not intimately familiar with Ryujinx to make
               | any statements about how they handle GC of course, but
               | its something that they'll need to take into
               | consideration. That said, there's plenty of other things
               | like JIT compilation, shader compilation, caches filling
               | up, and on and on that all also cause micro stuttering,
               | so its not uncommon for even C or C++ emulators to have
               | annoying pauses too.
        
         | wtetzner wrote:
         | > preferrably C
         | 
         | Why?
        
           | ddevault wrote:
           | C++ is a bad programming language used by bad programmers to
           | write bad programs. The only reason I mention it at all is
           | because it _can_ achieve the level of performance necessary
           | for an emulator.
        
             | saagarjha wrote:
             | You can do better than that, Drew.
        
             | VRay wrote:
             | Easy there, Linus
        
           | 1tCKV3QfIo wrote:
           | Cniles don't want to invest in modern C++.
        
       | TAForObvReasons wrote:
       | Next step: emulating nintendo switch games on linux on their
       | nintendo switch. Switchroot (https://download.switchroot.org/)
       | makes Ubuntu (based on L4T) and android releases available for
       | running on older switches.
        
         | b0b_d0e wrote:
         | fail0verflow did this exact thing when they first got linux
         | working on the switch actually!
         | https://twitter.com/fail0verflow/status/988543541403160576 It'd
         | be a pain and a half to get a "proper" fast port with CPU
         | emulation (either some lightweight JITing or natively running
         | the code with hooks on SVC and such) and a GPU backend for the
         | switch graphics. Not nearly simple enough to attract someone to
         | do it on a whim with no other reason that to say it happened
         | haha
        
         | entropicdrifter wrote:
         | It sure feels like an ARM based Switch Emulator should
         | eliminate a lot of the complexity that comes with the emulation
         | process
        
           | KMnO4 wrote:
           | That's a good point. I wonder if Apple Silicon will give game
           | console emulators a leg up.
        
             | saagarjha wrote:
             | It does not, DeSmuME on iOS goes through the same JIT.
        
             | novok wrote:
             | I was about to say then you would think a PS4 emulator
             | would be out by now then, but lo and behold, it exists!
             | https://pcsx4.com/
        
               | reaperhulk wrote:
               | PCSX4 is a fake, see:
               | https://www.pcgamer.com/ps4-emulator-pc/
        
       | gtsnexp wrote:
       | Have people tried this? Any thoughts, comments?
        
         | striking wrote:
         | I would have loved to give this a try but it appears to require
         | RCM on my existing Switch... and it's not vulnerable. :(
        
           | novok wrote:
           | And that point you might as well just use your switch then.
        
             | zzo38computer wrote:
             | There are various reasons you may wish to use it on another
             | computer, and you may have the cartridge, but if you can't
             | dump/decrypt it, then that won't work, so they will need to
             | figure out how to work such a thing, so that if you do not
             | have a compatible Nintendo Switch system then you can still
             | dump the cartridge and use the necessary keys to decrypt as
             | needed.
        
               | novok wrote:
               | Pretty much every single switch game has already been
               | dumped and will continue to be dumped and every single
               | game +updates fits on a 5TB HDD. And I've never heard of
               | any particular RCM vulnerable switch not being able to
               | play specific switch games either.
               | 
               | So what you've said doesn't make much sense to me.
        
       | criddell wrote:
       | How do you get around the need for a controller with an
       | accelerometer in it?
        
         | jhardy54 wrote:
         | Since you're using your own Switch for this method (right? :))
         | then I'd imagine you could use your joycons?
        
       | saagarjha wrote:
       | Since it's relevant, I should probably note that dumping your own
       | game cartridges is perfectly legal. Using someone else's dumps or
       | sharing yours is not legal. Many emulator projects have had
       | issues with the latter and are extremely testy if you look like
       | you are doing it.
        
         | wodenokoto wrote:
         | Using? So I can dump my games but not play them?
        
           | saagarjha wrote:
           | Ah, I don't know how I slipped up there. Fixed, you can play
           | them all you want :)
        
         | gambiting wrote:
         | I should also note that law is not universal and when advising
         | people on the internet it should be noted as such. In Poland
         | for instance downloading games dumped by others is perfectly
         | legal, only sharing isn't.
        
           | Wowfunhappy wrote:
           | > In Poland for instance downloading games dumped by others
           | is perfectly legal, only sharing isn't.
           | 
           | Wait, really? Are you sure?
           | 
           | I ask primarily because, this sounds a little too close to
           | "Downloading roms you don't own is legal as long you delete
           | them within 24 hours." ;)
        
             | jamie_ca wrote:
             | Yes, some locales pin the crime specifically on
             | _distribution_ of copyrighted material. Downloading or
             | possessing aren't restricted in the same fashion.
        
               | dlhavema wrote:
               | So is this kind of the idea of going after the dealers
               | and not the users?
        
             | kalium-xyz wrote:
             | Just because the americans are lobbying to make piracy as a
             | concept a thing doesnt mean that european countries all
             | have anti-piracy laws.
        
           | saagarjha wrote:
           | Belated disclaimer: I am not a lawyer, and I am certainly not
           | _your_ lawyer :) If you are interested in this kind of thing
           | there is a lot of interesting casework in this area.
        
       | tobyhinloopen wrote:
       | I wonder if switch emulation would be more efficient on ARM
       | systems
        
         | saagarjha wrote:
         | Usually, no. Emulation generally goes through a JIT that
         | couldn't really care less; there are some processor features
         | that can be difficult to emulate sometimes but often even on a
         | similar ISA you cannot just "use your processor directly".
        
         | DCKing wrote:
         | One of the suspected main reasons why we don't have proper
         | original Xbox emulation yet on the PC is because of the fallacy
         | that "it should be easy to emulate an x86 console on x86 PCs".
         | This has lead to many failed attempts to attempt "shortcuts" of
         | running Xbox games on PCs, like converting executables
         | statically, or extremely high-level emulation approaches like
         | only emulating graphics calls. None turned out not to be so
         | easy in practice. The notion "it should be easy to emulate
         | architecture X on architecture X" does not tend to hold up very
         | well, at least not for game consoles that _also_ have
         | complicated graphics and sound.
         | 
         | Compare this to Dolphin, which has been wildly successful in
         | emulating the Nintendo GameCube. Besides the big popularity of
         | Nintendo games, the GameCube was comparable in complexity and
         | sales figures to the OG Xbox. But since it had a relatively
         | non-standard CPU architecture and a non-standard GPU setup, it
         | guided emulation developers to not put too much effort in
         | shortcuts and tackle the emulation problem head on.
         | 
         | It's worth noting some recent progress has been made in OG Xbox
         | emulation by the Xqemu and Cxbx-reloaded projects. The former
         | tries to use qemu for x86 emulation (or even virtualization?)
         | while "low level" emulating the rest of the Xbox hardware,
         | whereas the latter started life as an extreme high level
         | emulator that is going more and more low level over time.
        
           | [deleted]
        
           | pantaloony wrote:
           | I think almost all the interesting games on the X-Box either
           | already being available for Windows or else having a just-as-
           | good version available for another console is a lot of what
           | kills interest for emulating it. You can play Halo and such
           | just fine on a PC without an emulator.
        
         | MarioMan wrote:
         | It should be. Look at DraStic, for instance, a DS emulator
         | which runs ARM code on Android. It's a fairly performant and
         | accurate emulation option.
         | https://play.google.com/store/apps/details?id=com.dsemu.dras...
         | 
         | Now if you're talking about trying to run one of these
         | emulators on an ARM build of Linux, you wouldn't see these
         | performance improvements since their designs are optimized
         | around x86 CPUs, not ARM.
         | 
         | Edit: Several far more informed comments than mine have
         | mentioned that running on ARM is only one small piece of the
         | performance coming from DraStic.
        
           | DCKing wrote:
           | The DraStic developers have commented that they don't gain
           | much if anything because it runs on ARM [1]. It's just an
           | efficient emulator. If/when it is open sourced as promised,
           | it will run very fast on x86 systems too most likely.
           | 
           | In any case, DraStic is a completely different style of
           | emulator compared to Yuzu. The Nintendo DS is nothing more
           | than a pair of microcontrollers with (from a modern
           | perspective) primitive 2D+3D acceleration hardware, whereas
           | the Nintendo Switch is a multiprocessor system with a modern
           | GPU and mulitasking operating system. The DS CPUs are
           | actually quite far removed from modern smartphone chips,
           | whereas the Switch chip should be mostly standard ARMv8.
           | Things that apply to one don't necessarily apply to the
           | other.
           | 
           | [1]: https://drastic-ds.com/viewtopic.php?f=5&t=1939
        
           | b0b_d0e wrote:
           | The fact that its performant is tangential to the fact that
           | its running on ARM android. IIRC Drastic still does a
           | traditional JIT to recompile the guest ARM code into ARMv7a
           | for phones (I might be misremembering, but I _recall_ they
           | had a whole lotta headache trying to update to support 64 bit
           | ARM in time for the Android deadline for that. Also I
           | remember them talking about tons of headaches dealing with
           | the new storage APIs for Android)
           | 
           | Its really fast because of the tons of optimization that went
           | into the application. It does many cool things to cut out
           | overhead on the CPU side, but also it does a lot on the
           | graphics emulation side, including hand rolled ARM NEON code
           | for SIMD processing polygons. I'm not very familiar with DS
           | emulation, but one of the devs for Drastic contributed to
           | another project I worked on, so I had some chats here and
           | there about these sort of things.
        
       ___________________________________________________________________
       (page generated 2020-07-24 23:00 UTC)