clownmdemu – High Level Emulation

In the last post, I mentioned that my emulator does not use the Mega CD’s BIOS program because it favours the ‘High-Level Emulation’ approach. In this post, I’ll go over what that means and how it will affect my emulator.

Other emulators, such as Genesis Plus GX and Kega Fusion, require that the user provide their own copy of the Mega CD’s BIOS, which has to be extracted from a Mega CD. Without this, the emulator will be unable to play Mega CD games. I cannot bundle this BIOS with my emulator because of copyright limitations (Sega owns the BIOS and I don’t have the legal right to distribute it). However, expecting the user to provide their own copy of the BIOS is not an acceptable solution to me, as it creates busywork for the user: good software should be as easy to use as possible, and expecting the user to buy a Mega CD, extract its BIOS, and then configure the emulator to use it, is the furthest thing from easy. Likewise, expecting the user to download the BIOS from some random website is also unnecessary busywork (though, legal or not, a person certainly has a moral right to download software that they already own a physical copy of).

This means that the most user-friendly option is to forgo requiring the original BIOS entirely. This leaves me with two options: make my own open-source BIOS, or make my emulator not need a BIOS at all.

Making my own BIOS should not require much explanation: I just have to create my own BIOS that implements the same API. If I am able to do so without copying any copyrighted material (code, graphics, or sound) from the original BIOS, then my BIOS will legally be my property, and I can freely distribute it with my emulator.

Making my emulator not require a BIOS at all is a bit more complicated: typically, an emulator recreates the behaviour of a console’s hardware, and then runs the console’s software on top of it. This is known as Low-Level Emulation (LLE), because the ‘lower layer’ (the hardware) is the part that is being recreated by the emulator. However, it is possible for an emulator to instead recreate the ‘higher layer’ (the software), performing what is called High-Level Emulation (HLE). This is how an emulator can be made to not require a BIOS: instead of recreating the behaviour of the underlying hardware, and then running the original BIOS, which interacts with said hardware, the emulator can instead recreate the behaviour of the BIOS itself, making the original BIOS (as well as its underlying hardware) redundant.

There are various trade-offs between using the original BIOS, making my own BIOS, and making my emulator not need a BIOS:

Using the original BIOS is the most accurate solution, as it is the same software that is used by a real Mega CD. This means that all of the behaviours and bugs will be the same. However, the original BIOS is burdened by copyright issues, making it the most awkward option for the user. In addition, it is an awkward solution for me, the emulator developer, as I have to make my emulator emulate parts of the Mega CD hardware that are used by the BIOS. This includes the CDC, CDD, and BuRAM. The final downside of this approach is that the BIOS remains a ‘black box’ – obscure, obfuscated software. This makes it difficult for the user to understand what the BIOS is doing and how to make modifications to it. If a person is given software, then they deserve to be able to understand and modify it as easily as is feasible, and relying on a binary blob completely undermines that.

Making my own BIOS rids the user of the difficulty of obtaining a copy of the original BIOS, but places a burden on me by requiring that I program an entire BIOS from scratch. The new BIOS may be inaccurate to the original one, differing in intended behaviour, suffering from bugs that the original did not, and missing bugs that the original had. For the new BIOS to act as a true replacement for the original, it should provide all of the same features and interact with the same underlying hardware. Because of the latter requirement, I would still have to make my emulator emulate the CDC, CDD, and BuRAM hardware, among others. On the upside, my new BIOS would be open-source, fully documented, and deobfuscated, allowing the user to understand, modify, and even distribute it with relative ease. However, I say only ‘relative’ ease because the BIOS would be at least partly written in Motorola 68000 assembly language, which is a fairly unknown language in today’s world. The rest of the emulator is written in ANSI C, so it may be too much to expect the average person browsing the emulator’s source code to comprehend the BIOS’s code. One last upside of creating my own BIOS is that it could be used outside of my emulator: it could be used with other emulators, or even with a real Mega CD!

Making my emulator not need a BIOS at all also rids the user of the burden of sourcing a copy of the original BIOS, and has the same downside of having questionable accuracy. However, it bypasses the need for my emulator to emulate the CDC, CDD, and BuRAM hardware, as it is (at least mostly) encapsulated by the BIOS. No BIOS; no hardware. This is similar to how WINE doesn’t need to emulate a whole PC just to run a Windows program. I think some of the CDC’s registers are interacted with directly by games’ SUB-CPU programs, but that shouldn’t require emulating the entire CDC. Code related to replacing the functionality of the BIOS would be part of the emulator itself, and therefore would be written in the same language as the rest of the emulator – ANSI C. That would make this the best option when it comes to users being able to read and modify the code. However, naturally, this code is tied to my emulator and cannot be used with other emulators nor a real Mega CD. To some extent, there may be a performance upside to this approach, as my emulator would be running native code instead of running emulated code in a CPU interpreter and emulating a variety of additional hardware components. HLE code is also significantly easier to write than a custom BIOS, as HLE code does not need to interact with the underlying hardware that a true BIOS would, making me to free to implement functionality as I see fit.

I hope that this comparison has made it clear why I have opted for High-Level Emulation.

Performing Low-Level Emulation of either an original or custom BIOS is straightforward enough: just emulate the underlying hardware as with any other part of the Mega Drive and Mega CD hardware and then run the BIOS just like it were a game. While it is not simple in execution, it is simple in concept. High-Level Emulation is more complicated, due to it crossing the line between software and hardware. So, how exactly does one make a Mega CD emulator not require a Mega CD BIOS?

First, let’s go over the boot process: using a real BIOS, this would be very simple: just boot the BIOS by resetting the Mega Drive’s 68000 CPU with the BIOS’s vector table mapped to address 0x000000, and the BIOS will handle communicating with the CDC and other hardware to load and execute the Initial Program (IP) and System Program (SP) from the CD. With HLE, however, the emulator must do this manually: when an attempt is made to reset the Mega Drive’s 68000 CPU, the emulator must intercept this and load the IP and SP on its own, configure the Mega Drive and Mega CD to the expected state, and then allow the 68000 CPU to resume execution.

The BIOS is also responsible for interrupt handling, however it appears to mostly just bounce the interrupts to a secondary interrupt table in RAM, which can be modified by the game in order for it to install its own interrupt handlers. This can be recreated by simply populating the vector table and secondary table in RAM with the expected values on boot.

Next is the BIOS call process: when a SUB-CPU program wants the BIOS to do something, it stores a value into data register 0 and then jumps to address 0x5F22. In the original BIOS, the code at 0x5F22 is the start of a function which uses the value in data register 0 to select an action, which it then performs. These actions include lighting-up the LEDs on the front of the Mega CD, opening and closing the disc drive, playing music from the CD, and reading data from the CD. To recreate this with High-Level Emulation, I have to detect when the SUB-CPU has jumped to address 0x5F22. The way I do this is by exploiting the emulated 68000 CPU’s bus mechanism. As a real 68000 CPU runs, it is constantly fetching code through ‘bus events’, which involves the CPU essentially pausing itself, signalling that it wants some data from an address, signalling that address, and then waiting for it to be given that data. This is very similar to a function call, and that is exactly what my emulator uses to emulate bus events. In the function, my emulator will check if the address and the CPU’s program counter (the address of the code currently being executed) are both 0x5F22, and if so, it performs the action that corresponds to the value inside data register 0. The function will then return the machine code for an ‘rts’ instruction, causing the emulated 68000 CPU to immediately return to the code that it came from, as if it had ran a proper BIOS function.

Under-the-hood, my emulator is free to perform its actions however it wants, regardless of how the original BIOS did it, so long as it provides the same API. This allows me to make certain quality-of-life improvements that would not be possible if the emulator were using the original BIOS. For instance, Genesis Plus GX stores all of its Mega CD save data in a single file, which contains the contents of BuRAM. Because my emulator does not emulate BuRAM, however, it is free to deviate from what a real Mega CD does: notably, because the BIOS’s BuRAM API is file-oriented, I can make each game’s save data its own file on the user’s PC!

And that’s everything I can think of to say about High-Level Emulation: its upsides, its downsides, how it differs from Low-Level Emulation, and how it is done. I hope that this has been interesting. I realised that I really skimmed over this in my last post, which is unfortunate because the nitty-gritty technical stuff is my favourite part of the Dolphin, Citra, and Yuzu progress reports, and it’s what I hoped to provide by starting this blog in the first place.

Leave a comment

Design a site like this with WordPress.com
Get started