4. Desktop Application - Planet Virtual Boy Emulator
One of the target platforms for the emulator initiative is the desktop workstation. In order to support as many users as possible, Java was selected for application development. This allows the application to be used by users on the most common operating systems, including Microsoft Windows, Mac OS X and assorted "Unix-like" platforms.
There are various desktop emulators for Virtual Boy already, so this initiative will not be unique in that regard. However, it contains features that are specifically tailored to users interested in reverse engineering and "TAS" projects, which are key features that are not well-supported by other emulators.
While Java solves many problems with its support on various systems, it presents a new challenge in that the C emulation core library cannot be used directly like it can in most situations. Fortunately, Java does support using native code in some capacity, so the C library can still be used in the desktop application.
The Java Native Interface (JNI) is a mechanism that allows Java code to interoperate with native code built for use on the current operating system. Individual modules can be bundled with the Java application for each system for which the native C library is desired. For any system that does not have a corresponding native C library available, an alternate Java implementation will be used instead, and the application will still function correctly.
There is a non-trivial amount of overhead associated with the JNI that makes it poorly suited for rapid, tiny operations like the kind provided by the emulation core's callback feature. If not handled carefully, using the JNI can introduce a significant performance impact and counteract the point of supplying native code in the first place. The solution is to instead offload as much processing as possible to the native library, communicating with the Java program as little as possible.
Similar to the C emulation core, the Java application operates on a state context that represents a simulated Virtual Boy. An abstract class is provided for state contexts that defines all of the methods that are available to the Java program. This class supplies a static factory method for producing complete state context instances, which may be backed by native code or by a Java implementation.
Only high-level operations are provided in the state context class, such as the Emulate command or configuring a ROM buffer. Operations that require more granular control over emulation state, such as breakpoints or cheat codes, must be handled within the context object itself and be configured with higher-level descriptors instead of program code. The reason for this is because the state context object may be backed by native code, and JNI performance considerations necessitate that communications with the Java program be kept to a minimum.
Native modules therefore must contain functionality in excess of a simple interface with the emulation core: they must implement all of the operations of the state context class.
Various tools exist to assist in the reverse engineering of Virtual Boy software. These features were designed based on experience using other debuggers and emulators for various architectures. As development progresses, additional features are sure to follow.
Debugger - Various interfaces with the CPU and hardware state. Includes a disassembler, register editor, memory hex editor, VRAM viewer/editor and other similar interfaces. By allowing the user to inspect and modify software operations at the hardware level, the overall logic and structure of the program itself can worked out.
Breakpoints - Can be configured to automatically pause emulation when specific conditions are encountered. This might be accessing a certain memory address or executing a specific instruction. Additional conditions can be configured for each breakpoint--for example, a memory write breakpoint might be configured to only trigger if the value being written is zero. With a little ingenuity, specific situations in program state can be captured with breakpoints and identify which parts of the program works with what data and memory.
Function Tracker - Automatically identifies functions in ROM data. The program is monitored at runtime to discover function addresses, and the instructions within those functions are parsed to determine their size. The user can assign names to functions, which are then displayed in the disassembler when function calls are made. The user can also supply notes for each function, such as equivalent high-level program code as a reference.
The "tool-assisted speedrun" (TAS) is a presentation engineered by a user that makes use of tools (such as emulators) in order to produce game footage that cannot be reliably performed by any human. In its simplest form, this is a script of user inputs, but exactly when to supply an input is an art in and of itself. A TAS can manipulate the program state in various ways, such as producing desired pseudorandom sequences or exploiting bugs to execute user-defined code.
Features associated with TAS production can of course be used for any number of applications, but the speedrun is the most common. This project refers to the overall presentation as a "record". A record in its simplest form is a list of user inputs for each frame in a segment of game footage. This list can branch out into additional lists of inputs, which in turn produce different outcomes in the simulation state. These branches are called "threads" and there can be any number of them in a record.
Each thread can be previewed independently from the others in its own window, and multiple threads can be previewed side-by-side in order to gauge which one has the most desireable result. Once a presentation is finalized, the single, "best" thread is selected as the primary thread and the resulting movie file will use it by default. The full set of threads can be retained, or only the primary thread can be saved when sharing with others.
When editing threads, individual frames can be stepped through in either a forwards or backwards direction. On any given frame, the current input state can be configured. Additionally, a game can be played as normal, simply recording the inputs of a player in real-time.