Hi there. This post will be long and nuanced.

The TLDR is: there is some limited LLM use in Emusyne emulator cores, mostly for testing, and a LOT of it for the (crappy) GUI (if you can do better non-LLM, please do! I’d love to get rid of it). There is more LLM use in the XBox/PC-LLE development, as explained below. However, I do not condone slop-coded projects, and other nuances. I am a domain expert using LLMs carefully.

Emusyne is my multi-emulator, developed Mac-first. It’s developed Mac-first because, in recognition of my work in the emulation community, someone sponsored me with a Mac to replace my cheap crappy Windows laptop.

My nuanced general stance on LLMs

I think LLM’s are a cool technology. They have their limits, and in my opinion, there’s no way they can make GAI (general Artificial Intelligence). It’s a fundamental limitation of their technology which cannot be solved with scale. However, they have some uses for software developers, the same way that calculators have uses to mathematicians.

I do not believe it’s a good idea to trust them with anything having to do with human safety, lives, livelihood, or health. They’re fundamentally a probabilistic technology and can and do make stupid mistakes just because. They also are terrible at reasoning about things that weren’t in their training.

The companies that train and sell them are mostly pure evil. They’re being incredibly reckless with our environment and bringing down everyone’s standards of living, as well as contributing to the sloppification of everything. 99% of what they say about them is hype, and they’re lying liar scam artists. Further, as one whose FOSS projects were used as training by these LLM companies, I am angered at the current state of things. I think it immoral and wrong that they’ve ripped off all of our culture and knowledge to be able to sell a product that they want to replace us with.

SHOULD LLM’s be a thing? I don’t know. I do know that I’m morally opposed to their current training and the behavior of their owners. HOWEVER, I am a full-time software developer with a wife and kids. I don’t have the luxury of burying my head in the sand and never using them. Even though my current job doesn’t force the use of them, the reality of our world is that I can’t count on that for long, and I need to be employable. So I started working with LLM’s in Emusyne.

What are LLM’s capable of? I’ll write a whole commentary on this below for those of you who’d like an experienced emu dev’s opinion on that. But first….

LLM usage in Emusyne

Emusyne started out as JSMoo, a JavaScript-based project whose first emulator was for Super Nintendo. I coded it in response to an article by Near (who I respect and appreciate the contributions of) that claimed SNES had to have a very fast processor to emulate accurately. I read Ares/bsnes/higan soruce and decided that I thought the problem was coroutines, and I could do it faster, even in JavaScript.

I proved to myself it was possible, writing a cycle-granular SNES core in JavaScript. It needed multi-threaded scanline-based rendering, and it wasn’t nearly as good as any of Near’s work, but it was cycle-granular and ran in real-time on my mid-range Ryzen laptop of the time (early 2020), so I felt vindicated. (the source can be found here: https://github.com/raddad772/jsmoo )

I got the emulation bug. I started adding more systems with better accuracy: NES, GB, Master System/GameGear, ZX Spectrum. I eventually got tired of JavaScript, and ported some cores to AssemblyScript, a TypeScript-inspired WebAssembly-native compiled language. I started PS1 development, and got fed up with AssemblyScript as well - mostly due to its lack of multi-threading support at the time. I have no idea how it’s doing now, and other than that I found it a joy to use.

In 2023, I started porting my cores to C, under “JSmooCh”. This later got renamed to jocasta-emu, then Emusyne, and a flattened commit can be found at the current Emusyne repo, https://codeberg.org/raddad772/emusyne .

I eventually upgraded to C++ after a few years, and have been going strong since.

Throughout this time, I also started contributing back to the emulation community in the form of “SingleStep Tests” for emulator developers, for ARM7TDMI, R3000, SPC700, Z80, M68000, and more. These are fuzz tests, in the style of some put out by TomHarte years ago. I based these on open-source emulators considered highly accurate at the time of their creation; they are used by many emulator developers to refine or help start projects, or for automated regression testing.

LLM’s did not enter the Emusyne picture until early or mid 2026.

This entire time, I’d had no user-useful GUI. To test a game, I’d have to re-compile the emulator with a selected core and ROM file. I do a lot of UI work in my job, and in my very little spare time to work on emulators, I can’t be bothered to work on GUI. I did have a GUI, filled with debug views, but not with “a user can actually use this” kinda stuff.

So, I mostly had an LLM vibe-code a GUI. I say mostly, because although I’ve never read some of the GUI code, I have read a lot of it, and I was very involved with design and implementation decisions as it has evolved. And it has, over time, especially since I added PC emulation and its complex configuration and transitioned how emulator cores were even advertised and constructed by the back-end.

I also experimented having an LLM vibe-code a whole emulator core for a system, purely for experimentation. This never got into the Emusyne code and I threw it away after making my conclusions.

So the GUI is like 92% LLM-coded now. I’m not super happy about that, and if anyone good at UIs wants to come along and replace it, I’d love that! Keep in mind however that it services over 20 diverse emulation cores, from atari 2600 to XBox as well as various home computers such as IBM PC (8086-pentium 3), Mac Quadra, and others, so it’s no small feat.

The actual emulation cores, and do they involve any LLM?

The whole reason I’m into writing emulators is, until fairly recently, for myself. I like to understand how the hardware works on a fundamental level. I usually don’t even play my emulators that much, which is why until recently they were mostly untested despite many being fairly decent and accurate.

Then, I decided it’d be fun to play emulated games, on my emulators, with my kids. This was the reason I pushed on the GUI. Since then, I’ve pushed emulation forward on Mac, at least in theory, some. For instance, as I write this, I recently topped out at around 1.3GHz speed for an LLE-emulated Pentium 3 computer (in my specific benchmarks). This speed also applies to XBox emulation, which I’m working on. This is far and above anything else currently available to my knowledge on Macs with LLE emulation. I’m also getting very encouraging results on a mid-range Ryzen using a totally different, mostly novel JIT technique. So I’m going to be releasing that sort of thing soon, and wanted to clear the air due to the controversy around LLMs in emulator development.

One thing I feel it’s important to point out here: I think that slop-coded projects are ones where people don’t understand what or why the LLM does what it does. They are typically disappointing and far below the quality a human could achieve. (This applies a little bit to my GUI, though that also suffers from a severe lack of testing). My track record proves I do understand, and where I’ve used LLMs is mostly to assist me in tasks I didn’t want to do or didn’t have time for, but never anything I hadn’t already done and understood myself.

1) Automated testing of libraries of games, including making “goldens” and doing regression tests 2) Reading through huge tracelogs and writing tools for this as well 3) My NES core was the first I ported from JS to C, and I was never happy with its structure compared to the way all my other cores are structured. But it worked so I never changed it, even though it annoyed me. I had an LLM go through and re-structure it like the other cores. This is not a logic or functionality change, more of a syntax, naming, and organizaton conventions change. 4) LLMs have added save state serialization to several cores I could not be bothered to. It’s a tedious and repetitive task 5) Windows and Linux cross-build and initial ports were done by LLM. I say “initial port” because this refers MOSTLY to the GUI, the emulator cores themselves are (mostly) platform-agnostic (except Dreamcast and XBox/PC, which have JITs) 6) I used an LLM to port my SPC700 from instruction-stepped to cycle-stepped in the style of my other 8- and some 16-bit cores such as m6502 and z80. Both the shape, the existing impl path, and all the source it used was pre-existing, this was mostly just a tedious step I didn’t want to do, and it helped me fix up some SNES timing-sensitive games like Donkey Kong Country 7) I wrote an SDL3 GPU renderer for Dreamcast, but hit up against limitations when I wanted to do accurate Order-Independent Transparency with good speed. I considered just stopping my DC emu HW render work there, but decided to use an LLM to convert my code to Vulkan, which was much more about the back-end and boilerplate. I then extended it from there myself. 8) Automated regression testing of in-development cores 9) Writing unit tests 10) Assistance in reverse-engineering things such as SH-2 bus contention 11) In some limited cases, more extensive code-writing. Specifically, this applies to PC-LLE and XBox, see below.

Here’s a break-down of all the cores and how much llm assidtance they have and how much code is LLM generated:

Atari 2600

Code 100% human. Development 100% human. Not a very great core though… relies heavily on old Ares impl.

Apple IIe

Code 100% human. Development 100% human

Commodore64

Code 100% human. Development mostly human, I used LLMs to do some automated testing with the VICE tests and then fixed the code myself. Note this core is very much WIP

Cosmac VIP

Code 100% human. Development 100% human

Dreamcast

Back-end code 92% human. Development much less toward “mostly” human. The original foundations for Dreamcast up to before 3d rendering started was all before LLMs were a thing and then I put it on hold. I later picked it back up, and have used LLM’s to help reverse-engineer the BIOS and a few games, as well as do automated testing and write tests for the SH4, ARM32, and DSP JITs.

The renderer is hard to give a % on. As noted above, an LLM translated my SDL3 GPU code to Vulkan, where I continued work on it after that.

Also, as an experiment, I used an LLM to write the poor attempt at an ARM32 JIT, with only light planning and supervision. This was mostly an afterthought for the Windows port, which needed all the CPU cycles it could get at first (it’s gotten a LOT faster). It was patterned on my DSP and SH4 work, but isn’t really my work. And it’s also by far the “sloppiest” part of the whole emulator.

Also, the GD-ROM file parsing and loading code is mostly LLM. This is not the GD-ROM emulation code, but the code that loads it into memory, including CHD files, .GDI and .CUE.

Oh, also, LLMs worked on the Render Inspector debug view, helping to make it as cool and useful as it is. This was patterned after the human-made PS1 one.

Galaksija

100% human, from a YouTube video mostly. Little testing since I can’t even speak the language…

GameBoy/Color

Code 100% human, development 100% human outside automated gameplay testing and helping find a bug in sprite handling for one game (which I then fixed myself).

GameBoy Advance

Code 100% human, development 100% human

Sega Genesis

Code 100% human, development 100% human outside, again, automated testing. With the exception of the m68000-fast core, discussed under “Mac Classic & Quadra”

Sega 32X

95%? of this code is human. I used LLMs to do some research on very low-level bus timing details, including writing ROMs for people to run on real 32X’s, and trying out theories. This is the reason that (in slow mode) my 32x CPU emulation is so accurate. (Yes my 32x is not perfect, a few games have graphics issues).

Mac Classic & Quadra

The original m68000 cycle-stepped and cycle-accurate core is mine, as is the original Mac Classic core, and the Quadra core.

I used LLMs to generate the 68010, 68020, and 68040 test corpuses, as well as used LLM assistance during refactoring into my “m68000-fast” core. This was limited to laborious and tedious work. I also used LLMs to help troubleshoot various issues booting Quadras.

Note, these cores have little testing and use compared even to most other cores. They are likely super fragile and challenging to use. I was able to boot & run Quadra games such as Doom and Mario’s FUNdamentals.

Furthermore, LLMs added more disk format support than the basic raw binary one I’d originally made up and manually converted disks with. You may be seeing a theme here with file format support…

Nintendo DS

100% human code, 95% human development. I have used LLMs to help troubleshoot a few graphical issues and then written the fixes myself.

LLMs worked on the Render Inspector debug view, helping to make it as cool and useful as it is, patterned after the human-made PS1 one.

NeoGeo AES

99% human code, except the use of the m68000-fast core, described above under “Mac Classic & Quadra.” I did get assistance with ROM format loading, I hate that in general and NeoGeo was in such a bad spot for it that I just couldn’t.

NES

100% human, but then re-organized by LLM, as noted above, to conform better with standards I made later in development.

NeoGeo Pocket

100% human, though I owe a LOT to Ares on this one. There wasn’t a lot of good documentation on this one.

PS1

100% human code. Mostly human development, LLMs for automated testing and some RE (I did most of the RE for fixing PS1 emu bugs myself, it’s how I learned it). LLMs also worked on CDROM format loading as for Dreamcast.

Casio PV-1000

This atrocity is 100% me

Sega MasterSystem/GameGear

100% me, but LLM automated game testing

SNES

100% me, except that I used LLM to re-factor the SPC700 CPU core from instruction-stepped to cycle-stepped, following the pattern of my many other human-made cycle-stepped 8-bit cores.

My SNES support is a mixed bag, though. That’s mostly due to my lack of interest in “finishing” the long tail of it.

TurboGraFX-16 / CD / Super

100% me, except for automated game testing and CDROM format loading.

ZX Spectrum

Once again, 100% me

XBox/IBM PC

This is where the story gets a little more complicated.

I’d already written an SH4 and AICA DSP JIT, and didn’t want to go through that again.

I wrote the x86 interpreter and used LLMs to expand some of it, as well as for a refactor.

I designed and wrote the initial x86 cached interpreter and used LLMs to expand it from there.

I designed almost every detail of the x86-64 para-recompiler, the Aarch64/x86-64 Mir recompiler, and the AArch64 baseline copy-and-patch recompiler. I designed the MMU aperture dispatch which allows such amazing speed which, as far as I can tell, is unique to my emulator. I designed the MMU virtualization, etc. I took inspiration for the Control-Flow Graphs, as well as the MMU-protected “check-in” used in the hybrid HLE timing mode, from Fex.

I used xemu’s NV2A core documentation extensively, as well as Cromwell (an open-source BIOS replacement), various FOSS drivers, and other FOSS projects that had worked with or on the nVidia hardware.

Note again, that this is something I’ve already done. I wrote my own SH4 MMU virtualization and JIT, my own whole 3d system renderer, etc. I did not want to re-do all of these things. I coded the start of but not all of these systems. Specifically, I laid out the structure and beginnings, and in-depth design, and had LLMs fill in the tedious bits. And in some cases I worked with LLMs to refine and optimize things.

However, they were NOT vibe- or slop-coded. The parts that were the result of LLM were the result of weeks of careful, in-depth co-development.

I’ve also used LLMs to help me get as far as I have on GeForce3. I already had a lot of the core code from XBox, that I started to back-port to PC. I used LLMs to do a bunch of testing and reverse engineering to get it working with a real GeForce3 BIOS and driver on Win98SE.

This has allowed me, in the matter of about a month, and with great emulation knowledge and experience, to bring up my own unique PC-LLE and XBox emulation projects and push the boundaries of what’s possible in terms of performance.

What’s possible with LLMs

I’d like to reiterate here that I’m against slop-coded emulation and porting projects, as well as the commercial usage and training of LLMs.

You could not one-shot a revolutionary emulator with them. You could not do a quality port with them - slop-coded ports are genuinely disappointing, in general.

If you told an LLM to make you a gameboy emulator from scratch and gave it source references and good documentation, it could get most of the way there nowadays. However it’s important to understand that this is a problem well-represented in its training set: there are literally hundreds of GB emulator projects out there. And it wouldn’t give you anything exceptional or novel.

LLMs make a lot of bad and even non-sensical decisions, even the “frontier” models. If you don’t keep careful control of them you’ll find out they ran away without you and made parts of your gameboy emulator in CUDA (true story from inspected vibe-code of one GB core) or something else ridiculous. This only gets a thousand times worse as you get to the “emulation frontier,” or when trying novel techniques.

On the other hand, some of my emulator-dev friends are using LLMs to push boundaries. In the Dreamcast scene, for instance, there’s now a speedy FPGA implementation of the Dreamcast 3d chip, with an accurate CPU core on the way, largely coded using LLMs by some of the original Dreamcast emulator developers. They’ve done in weeks what they failed to do in years, because LLM’s do not tire or give up when reverse engineering. They keep hitting their heads against the brick walls until they crack.

But the other component to this is that they’re experts in the domain. They’ve written real Dreamcast emulators used by real people. They were part of the original Dreamcast reverse engineering to make emulators. And that’s where LLM’s can shine at challenging tasks: in the hands of an expert.

PC & XBox emulator LLM usage

My PC & XBox emulation saga has been similar. I could’ve spent months on it to get it where it is now, but that didn’t appeal to me. I still did a great deal of the work myself, but leaned on LLMs for tasks they excel at, such as reverse engineering, automated testing, some iteration, writing large amounts of repetitive or boilerplate code and tests, etc. The breakthroughs, however, are still mine, not even suggested by LLM.

The things that make my PC emulator different from other available LLE PC or XBox emulators:

1) The MMU dispatch aperture, allowing extremely fast block-to-block chaining as well as multi-modal dispatching by using MMU acceleration. Various emulators use basically a precursor to this sort of thing. I use the host MMU: physical dispatch pages are aliased into a per-address-space virtual aperture at the guest’s linear addresses. So one unconditional jmp [aperture + eip*8] follows x86 paging, context switches, and more. Invalidation and revalidation are fast because they’re mostly just pointer replacement. Etc. 2) The para-recompiler for Windows. In retrospect, I found the idea was done before by VMWare and Valgrind, kind of. I’ve been unable to find other projects that do it, despite how obvious it feels. The idea is mostly to leave x86-32 code alone, only translating the things that are different or sensitive in x86-64, running under x86-64 with important information and scratch registers in the “new” upper registers, and adding in scheduler checks. This, combined with the MMU aperture dispatch, allows largely-native code execution, and runs fast even on modest hardware. Currently, up to 700+Mhz pentium-3 timings on my old, mid-range, 15W Ryzen laptop with full LLE timing, though it doesn’t yet sustain that. 3) The EL1 (MacOS) and WHP (Windows) hypervisors. Using a VM allows for really fast faults, which is great for low-level emulation. It also allows for 4k MMU pages on Mac (although this is no longer necessary in recent MacOS) 4) The hybrid LLE/HLE timing system. Qemu comes closest to it, though I only found that in retrospect. My innovation is using it in an LLE emulator, as ones like Yuzu and Qemu are HLE emulators. All of the hardware is still emulated LLE, but the scheduler works against host time instead of guest time. It takes advantage of the VM to do low-latency interrupts for scheduler events, and the dispatch aperture to control exits for events. Initial results are 750Mhz->1.3GHz performance on my M4 Air, and promising results on my mid-range 15W Ryzen laptop as well. I’m experimenting with a paced mode to allow control of the frequency down near a target. Basically, it puts real-time XBox LLE emulation in reach on lower-end hardware where it wasn’t beforehand.

And I’m nowhere near done optimizing and developing these emulators. I literally have a list 10+ items long of new things to try.

These are my ideas, dreamed up in the shower or in bed as I tried to imagine ways to get closer to HLE (such as Fex) performance for LLE emulation. They were planned out in detail and sweated over and even argued with the LLMs at times. They are the survivors of a larger group of ideas that mostly failed, and I had a direct hand in implementing all of them. In addition, there’s the GeForce3 Ti500 emulation on Windows: I’ve only tested against one DirectX7 game so far (Deus Ex was my obsession for a while), but it’s running and playing. It needs more development and testing. It’s enabled by back-porting the NV2A with ubershaders work from XBox and adapting it to all the PC details like bus and separate VRAM and some features that I at least didn’t get to needing yet in XBox like a 2d engine.

It’s important to note that LLMs ended up generating thousands of lines of code for PC-LLE and XBox. A lot of it was boilerplate or tedious work, that would’ve taken me months more to do on my own, especially given the full-time job and such. I feel that they enabled rapid research and development, which has kept me motivated and engaged and creative.

And here I’m going to reiterate: I don’t like low-effort or low-understanding slop projects. I think most vibe-coded emulation stuff is a detriment to the community. And I do not condone the actions of the LLM companies.

In parting, and contributions

If you’re totally morally opposed to LLM usage, I get it. If you don’t like emulation projects that have any LLM usage, I get it! I won’t condemn you, and you’re not forced to use this emulator. I hope the ideas and techniques I’ve come up with will be helpful to others.

Also, it may seem hypocritical, but I won’t be accepting LLM-generated patches to Emusyne, or if I do it will be rare. Any LLM usage inside it has been done by a domain expert and to certain code quality standards. It has also been documented. Most people using an LLM are not doing that, and I don’t want slop in the project.


<
Previous Post
I’m a JIT 4 W(indows)
>
Blog Archive
Archive of all previous blog posts