Virtual II

From Wikipedia, the free encyclopedia

Contents

[edit] Overview

Virtual ][ (pronounced "virtual two"), is a software application that emulates the Apple II series of computers on an Apple Macintosh computer running Mac OS X. The emulator supports these 8-bit Apple II machines:

The main purpose of the program is to let its users experience, on a modern computer, the nostalgic fun of the early days of home computing. To that purpose one of the design principles of the program is to emulate the original machines as accurately as possible in all respects. Because it emulates the hardware of the original computer, including many expansion cards, it can run almost any Apple II program. Furthermore, the program uses pictures to represent the original hardware components, plays sound effects (such as the boot sequence), has accurate timing, and can be configured by "inserting" or "removing" emulated expansion cards.
Virtual ][ does not try to "improve" on the original machines, although it does implement additional features for integration with the host computer, such as copy/paste between the host and the emulated machine, and mounting a Macintosh folder as a ProDOS hard disk in the emulated machine.

Apart from emulating the actual computer, Virtual ][ also emulates two matrix printers: the Epson FX-80 and the Apple ImageWriter II. The output produced on the emulated printers can be saved as a PDF file.

Virtual ][ emulates the original Apple II game paddles or joystick using any USB game pad / joystick, or, alternatively, with the Macintosh mouse and keyboard.

The program is integrated with Apple's Spotlight search feature, providing a way to instantaneously find a specific Apple II file on any of the disk image files on the host computer.

Virtual ][ contains an embedded utility, A2V2, able to convert original Apple II 5¼-inch floppy disks to the Macintosh, using a real Apple II connected to the Macintosh via a serial interface cable.

For the technically interested, Virtual ][ implements an "Inspector" feature, which can be used to inspect the internal state of the virtual machine, and to debug Apple II programs.

[edit] Screen shots

Virtual ][ window with the emulated screen and several devices
Virtual ][ window with the emulated screen and several devices
Virtual ][ window with configuration sheet
Virtual ][ window with configuration sheet
Virtual ][ window with a preview of matrix printer output
Virtual ][ window with a preview of matrix printer output
Virtual ][ window showing the Inspector feature
Virtual ][ window showing the Inspector feature

[edit] Sound sample

[edit] Technical background

This section is intended for software developers who are interested in the way the Virtual ][ application works.

[edit] The core library

The core of the program is formed by a C++ library that implements the hardware of the Apple II. The classes in the library represent the hardware parts as described in the Apple ][ Reference Manual, such as the MOS Technology 6502 processor, RAM and ROM memory, the video generator, the sound generator, different peripheral cards (one class for every type of card), and the bus structure (data, address and interrupt). The bus structure is the medium used by the other components to communicate with each other. For example, in the real Apple II most components observe the address bus and when certain addresses appear, the component reacts by performing some action. RAM memory reacts by providing or accepting a byte on the data bus; a slot device might react by performing I/O; the sound generator reacts by toggling the speaker, etc. This model of independent components observing the address bus, and using the data bus to communicate data, is implemented in Virtual ][ as well. It would however not be practical to have every component observe the bus in a separate thread (this would cause tremendous threading overhead and synchronization nightmares). Instead, there is one object that observes the address bus (on the processor thread), and dispatches the event to the responsible component. This is an efficient solution, because the responsible component can easily be determined on the basis of the address, and can directly be called on the same thread. And due to the thin interface, new hardware components can be added without affecting other components; only the address bus dispatcher needs to be modified.

The implementation of the core library relies heavily on multi-threading, implemented using POSIX threads. Obvious threads are the processor thread, the video generator thread and the sound generator threads (one for the speaker and one for the cassette output). Apart from that, most peripheral cards need a thread as well, for example to perform I/O (the timing of the processor thread is critical, so it must not be involved in I/O). All in all, a virtual machine with the default configuration has some 14 threads running in the core library. All threads are essentially synchronized using one mutex that is acquired by the processor thread while a 6502 instruction is being executed. Every thread that wants to access the bus needs to acquire the instruction mutex, to guarantee that an instruction has completely finished. Experimental versions of the program tried to actually lock and unlock the instruction mutex before and after each individual 6502 instruction, which means on average some 250,000 locks and unlocks per second. Although the Macintosh computer can keep up with this, it causes much unnecessary overhead. In the released product the processor thread is allowed to execute about 1000 cycles (1 millisecond) uninterrupted, and then unlocks the mutex to give other threads a chance. This is unlike the real Apple II, where the video generator even works in between the cycles of each instruction, but it is a good enough solution to emulate realistic behavior.

The emulation of the 6502 processor has been developed for Virtual ][ from scratch. Because the instruction opcode is 8 bits, the emulation works with a function pointer table with 256 entries; the opcode is used as the index. Each function implements one instruction and returns the number of processor cycles the instruction is supposed to consume, taking into account subtleties like an address calculation that crosses a page boundary. By adding the return values, the main loop knows the processor time, and can synchronize with real time by including a pause every now and then. This scheme assumes the Macintosh host is fast enough to emulate at least 1,023,000 emulated cycles a second. If it is too slow, the emulation will slow down as well. All modern Macintosh computers easily meet the requirements to run the emulation at the intended speed; this can easily be verified with the performance monitor feature.

The core library uses only standard libraries, and does not depend on any Macintosh specific features. As a result the core library is theoretically compatible with other platforms as well (this has never been tested though).

[edit] The application layer

The second part of the program is the application layer, written in Objective-C and using the Cocoa class library. The application layer is responsible for the implementation of the user interface and the implementation of the Apple II peripheral devices in the Macintosh world. The application layer uses the core library to emulate the virtual machine. The other way around, the core library also calls the application layer in order to modify the screen, produce sound, read diskette data from a file, etc. This is accomplished by defining pure virtual C++ interfaces in the core library, which are implemented by classes in the application layer. As a result, the application layer contains Objective C and C++ classes. Cooperation between Objective C and C++ is a feature of the GCC compiler, and is sometimes referred to as Objective-C++. Although threads from the core library extend into the application layer, they do not perform user interface actions or I/O, so the virtual machine cannot be slowed down by this. Some I/O is done by buffering data in memory (an entire diskette for example, or even an entire cassette tape). When "real" I/O is required, for example to emulate the serial port, the I/O is performed on a dedicated thread. The user interface is always performed on the main thread.

[edit] External links