Aeon Emulator Blog

October 30, 2009

Planar Video Memory

Filed under: Aeon, Graphics — Greg Divis @ 3:19 pm

In a previous post, I gave a brief overview of the components of a VGA card, but I didn’t talk about the two components that most affect how data flows from the CPU to video RAM. Let’s start with some background information.

In the early days of computing, monochrome displays were pretty common. Video memory for such a simple system could require as little as 1 bit per pixel if only one color intensity is needed. This means that to fit a 1-bit color 320×200 pixel resolution image in video memory, you only needed about 8 KB of dedicated video memory. When the time came to introduce color displays and what would be called the Color Graphics Adapter (CGA), the design would grow from this.

CGA extended the monochrome video model by adding a second “plane” of bits to represent the same pixels as the first, monochrome plane. Now, there are two bits used for each pixel on the screen, and they are used as an index into a 4-color palette. Although two bits are used to form one index, the bits are not contiguous in memory because they are in separate planes.

Eventually, the Enhanced Graphics Adapter (EGA) came along, and another two planes were added. Now, one pixel consists of a 4-bit index with one bit taken from each of the four planes, so 16 simultaneous colors could be displayed.

The Video Graphics Array (VGA) is compatible with EGA and CGA, but adds higher resolution 4-bit video modes and a low-resolution 8-bit video mode, finally making more realistic graphics possible with the ability to show 256 colors at once. On a CGA, EGA, and VGA card the video memory is still planar, and accessing video RAM in 2 or 4-bit color modes is quite a headache as a result. For 8-bit, though, IBM decided to give developers a break and not add another 4 planes; in fact, the default 256-color display mode on VGA hardware sets up some control registers to make video memory for this mode appear linear. For the first time, instead of complex masking and shifting, all you had to do to write an 8-bit pixel to the screen was to calculate its address and write to it:

pixelAddress = 0xA0000 + (y * ScreenWidth) + x

There was a drawback to this 256-color mode, and that’s that it locked you into a low-resolution 320×200 (which has a weird-looking aspect ratio), and did not leave any off-screen video memory available for page-flipping or hardware scrolling. A number of games disabled this linear addressing, placing the card into “unchained 256-color mode.” It added the complexity of dealing with multiple planes again, but allowed a measure of hardware acceleration that was otherwise impossible, and with further tweaking could allow better resolutions.

Aeon currently handles most of the 16 and 256 color standard EGA/VGA resolutions.

October 25, 2009

Emulators without Borders

Filed under: Aeon, WPF — Greg Divis @ 2:37 pm

One issue I’ve had with authoring a WPF UserControl/CustomControl has been the dashed focus rectangle that gets automatically drawn to indicate keyboard focus. I’m sure there are situations where this is useful, but Aeon’s emulator display control is not one of them.

Control Border

Getting rid of this is pretty easy. Just set the FocusVisualStyle property to null.

<ContentControl FocusVisualStyle=”{x:Null}” />

Of course, most custom controls should probably set it to a more appropriate style rather than null, but in Aeon’s case it doesn’t really make sense to show focus in this way. Somehow I’ve managed to overlook this property since I started this project, but as of version 0.50, that focus rectangle is finally gone!

Aeon version 0.50

Filed under: Aeon, New Version — Greg Divis @ 2:13 pm

The biggest visible change is the addition of a simple command interpreter. You can’t do too much with it at the moment; in addition to running programs, the only supported commands are DIR, ECHO, CD, and TYPE. It’s really only useful if you need to start something with command line arguments, but it gives me a foundation to build upon in future versions. Here’s the major changes:

  • Added simple command interpreter. No batch files yet, but coming soon
  • Rewrote and simplified file system redirection
  • More DOS process management fixes
  • Minor performance tweaks

Download it here.

October 23, 2009

Emulating VGA

Filed under: Aeon, Graphics — Greg Divis @ 2:13 pm

On a normal x86 real-mode PC with a VGA-compatible video card, a 64k region of memory starting at segment 0xA000 is mapped to video RAM. For a DOS application, displaying an image on the screen may or may not be as simple as writing the pixel data to this area. DOS is pretty minimalist, and has no concept of a display driver, so any nontrivial graphical DOS program has to talk to the hardware directly. Ok, what is the hardware besides a region of reserved memory address space? These are the basic components of a VGA device:

  • CRT controller: generates display data and timing signals for the monitor.
  • Attribute controller: performs color palette mapping to maintain compatibility with CGA/EGA.
  • DAC: maps pixel data to RGB values stored in its 256-color palette.
  • Sequencer: generates input data for the DAC based on video RAM.
  • Graphics controller: controls the flow of data between the CPU and video RAM.

So basically, when you write a byte to video memory, the graphics controller decides where (or if!) your byte actually gets stored. Everything else comes into play when it’s time to actually show the data on the monitor. These components can be programmed by sending data to various CPU data ports, but why would you need to?

The DAC is probably the most straightforward component – VGA display modes usually have either 4 or 8 bits per pixel. Each pixel then represents an index into the DAC’s color palette, meaning a 4-bit mode allows no more than 16 colors on the screen at once, and an 8-bit mode allows 256. By programming new RGB data to the DAC, a program can change the current palette. Pretty useful, as otherwise everything would be locked to the same set of 256 colors.

The CRT controller is also pretty straightforward. At the time a CRT monitor was pretty much taken for granted, so this component could be programmed to alter the video output in some clever ways to achieve otherwise computationally expensive effects. It also allows some very low-level manipulation of the monitor’s electron gun behavior and timing.

The attribute controller is mainly there for compatibility and Aeon doesn’t emulate many of its functions at the moment.

There’s a reason I’ve left the graphics controller and sequencer for last; they are responsible for more headaches than the rest of the VGA emulation combined. I still don’t have them quite right, and trying to implement them completely turned my nice design into a tangled mess. I’ll talk about them at great length in another post.

October 22, 2009

Regarding WPF

Filed under: Aeon, WPF — Greg Divis @ 7:58 pm

When I was starting to add VGA emulation to Aeon, I had to decide how the graphics would be presented in a window. I wanted to do the whole thing in C#, so that gave me three obvious choices: Windows Forms, WPF, or XNA. Of the three, I was most familiar with the Windows Forms API, but one of the main reasons I started working on this was to learn, so I really wanted to give either WPF or XNA a shot. Also, WPF and XNA both use significant Direct3D hardware acceleration, which would be nice in something like Aeon. The XNA framework is really designed for making games – sure, games are pretty much the only type of program I run in Aeon, but I pictured the emulator as more of a regular Windows application. This left WPF – it’s very powerful, very efficient, and very hard to learn.

I really have no desire to ramble about what I like and dislike about WPF, so now that I’ve established why I’m using it for Aeon, I’ll talk a little bit about how I’m using it. Nearly all of the interaction between the emulator and the user is enabled by a WPF control called EmulatorDisplay. As far as XAML goes, it’s pretty simple:

<ContentControl x:Class=”Aeon.Presentation.EmulatorDisplay”
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;
    xmlns:local=”clr-namespace:Aeon.Presentation”
    MinWidth=”160″ MinHeight=”100″ Background=”Transparent” Focusable=”True”>
    <ContentControl.Resources>
        <Pen x:Key=”blackPen” Brush=”Black” Thickness=”1″ />
        <DrawingImage x:Key=”defaultArrow”>
            <DrawingImage.Drawing>
                <GeometryDrawing Brush=”White” Geometry=”{x:Static Member=local:Geometries.Arrow}” Pen=”{StaticResource blackPen}” />
            </DrawingImage.Drawing>
        </DrawingImage>
    </ContentControl.Resources>
    <Viewbox Name=”outerViewbox”>
        <Canvas Name=”displayArea”>
            <Image Name=”displayImage” Stretch=”None” MouseDown=”displayImage_MouseDown” MouseUp=”displayImage_MouseUp” MouseMove=”displayImage_MouseMove” />
            <Rectangle Name=”cursorRectangle” Width=”8″ Height=”2″ Fill=”Gray” Visibility=”Collapsed” />
            <Image Name=”mouseImage” Source=”{StaticResource defaultArrow}” Visibility=”Collapsed” />
        </Canvas>
    </Viewbox>
</ContentControl>

This file is pretty short; unusually for a WPF control, most of this one is in procedural code. The displayImage control is used to display the emulated video output, and also to capture input events from the user. Its Source property is set to an instance of a System.Windows.Interop.InteropBitmap in code based on the current video mode. Generating 32-bit pixel data from the various emulated video modes is a topic worthy of its own post, and I’ll cover that later – suffice it to say that the displayImage control hosts the final result.

The cursorRectangle instance is the text-mode keyboard cursor. Right now its size and color are hardcoded, and it’s moved around in code to match the current state of the cursor in the emulator. Similarly, the mouseImage control is used to display the mouse cursor normally provided by a DOS mouse driver. Many games drew their own mouse cursors and didn’t use this, so it’s normally invisible. Technically, the shape of the cursor can be set in DOS by a call to the mouse driver, but right now I just have it locked to the arrow shape defined in the control’s resource dictionary.

The displayArea Canvas is used in code to position the cursor and mouse images in pixel units.

Finally, all of this stuff is wrapped inside a Viewbox. The viewbox provides the nice, smooth scaling of the emulated window and also transforms incoming mouse position coordinates from mouse events.

That’s it. Those are all of the WPF elements used to compose the emulated display area.

October 16, 2009

Wolfenstein 3D

Filed under: Aeon, Fun & Games — Greg Divis @ 10:41 am

Wolfenstein 3D is another classic. It was basically the first FPS game, and has since been ported to pretty much every platform in existence.

Title Screen

I’ve wasted many hours of my life playing this game, and to this day I still remember the layout and secret passages from all of the levels of the first episode.

Because the game is visually so striking compared to most other games of the time, I was expecting it to be difficult to get it to run in Aeon, but once I had the basics in place it turned out to be one of the easiest. Most of the early problems I ran into were from incorrect corner case behavior in some of the more complicated x86 instructions, but Wolfenstein 3D didn’t really do anything crazy at the machine code level. Maybe that’s due to it being largely written in portable C.

Wolfenstein 3D

So having it work so well in Aeon was pretty exciting for me and all, but the best thing to come out of playing it again was that it gave me the idea to rip this:

BJ Blazkowicz

Just look at that and try to say it isn’t awesome. It’s B.J. Blazkowicz!

October 15, 2009

Modeling a PC

Filed under: Aeon — Greg Divis @ 9:08 pm

In addition to emulating the processor, there’s a lot of other components required to run a program written for DOS. You can get by running some very simple applications emulating only the CPU, RAM, and a small subset of DOS, but to run anything more complicated you have to also deal with the interrupt controller, programmable timer, VGA card, BIOS functions, and keyboard. In Aeon, the class responsible for modeling this system of devices is VirtualMachine.

In VirtualMachine’s default constructor, all of these essential components are initialized in a way that leaves its state pretty close to a real MS-DOS PC after you’ve booted it up. At this point, certain core hardware elements are exposed as read-only fields, while devices with more abstraction are exposed via properties and methods. The use of read-only fields was mainly because Aeon relies on a significant amount of dynamically generated IL, and it just made things easier; these hardware elements are pretty fundamental and tightly-coupled with each other, so I don’t think it’s all that unreasonable from a design perspective either. Most external assemblies referencing Aeon will have no need to do things like examine or modify the state of the emulated CPU registers, but there are some cases where this is important.

The following code illustrates what you need to do to get a very simple emulated system up and running using a VirtualMachine instance:

static void Main(string[] args)
{
    // Create an instance which maps C:\Games\DOS\Zork1 on the host computer to C:\ on the emulated system.
    // The final parameter indicates that this is not read-only (DOS is allowed write to this directory).
    var hostPath = new HostDirectory(@”C:\”, @”C:\Games\DOS\Zork1″, false);

    // Create the emulated system.
    using(VirtualMachine vm = new VirtualMachine())
    {
       
// Add the previously defined mapping to the VirtualMachine’s list of file system root paths.
        vm.FileSystem.Roots.Add(hostPath);

        // Read an executable file to a ProgramImage instance that Aeon can understand.
        var program = ProgramImage.Load(@”c:\_zork1.com”, vm);

        // Loads the ProgramImage as if it had been run from a DOS command line.
        vm.LoadImage(program);

        // Run forever!
        while(true)
        {
           
// Decode and emulate the instruction at the CPU’s instruction pointer.
            vm.Emulate();
        }
    }
}

That’s technically all you need to do to emulate Zork, but you won’t get any output displayed on your screen, or be able to provide any input to it. Not terribly useful unless you’re running a non-interactive program that just reads and writes from the disk. Still, even if I had provided redirection of the emulated console input/output streams, the only programs that will work with this configuration are ones that do not patch interrupt vectors. VirtualMachine requires you to manually test for hardware interrupts, then raise the appropriate software interrupt using its RaiseInterrupt method. Also, you have to manually generate hardware timer interrupts from the programmable timer device, and of course gracefully break out of that while(true) when there’s nothing left to do.

To simplify setting up emulation of a more complicated (and complete) system, you can use the EmulatorHost class instead, which wraps a VirtualMachine and creates a dedicated CPU emulation thread to take care of everything I mentioned above:

static void Main(string[] args)
{
    // Create a class which maps C:\Games\DOS\Zork1 on the host computer to C:\ on the emulated system.
    // The final parameter indicates that this is not read-only (DOS is allowed write to this directory).
    var hostPath = new HostDirectory(@”C:\”, @”C:\Games\DOS\Zork1″, false);

    // Create the emulated system.
    using(EmulatorHost emulator = new EmulatorHost())
    {
       
// Add the previously defined mapping to the VirtualMachine’s list of file system root paths.
        emulator.VirtualMachine.FileSystem.Roots.Add(hostPath);

        // Loads the ProgramImage as if it had been run from a DOS command line.
        emulator.LoadProgram(@”c:\_zork1.com”);

        // Start running the loaded program in the background.
        emulator.Run();

        // Run until the program terminates.
        while(emulator.State != EmulatorState.ProgramExited)
        {
            System.Threading.Thread.Sleep(100);
        }
    }
}

It may not look like a huge difference, but this code snippet actually implements a complete system running Zork, complete with hardware interrupts being generated in the background. Typically, a more sophisticated emulator would subscribe to events on VirtualMachine or EmulatorHost to handle things like video mode changes, mouse movement, and other runtime conditions. EmulatorHost also exposes methods like Pause, Run and Halt methods to control emulation and PressKey, ReleaseKey, and MouseEvent to put input events in the emulator’s hardware queues. Unlike VirtualMachine, EmulatorHost’s methods and properties are safe to use from other threads.

This post went on a bit longer than I intended, so I’ll end things right here. I’ll get to how this stuff is implemented eventually…

October 14, 2009

Aeon’s Architecture – Basics

Filed under: Aeon — Greg Divis @ 7:08 pm

Currently, Aeon consists of five .NET assemblies:

  • Aeon.Emulator.dll: This implements the core emulation functions for essential hardware and software; it also defines public classes and interfaces for extending Aeon.
  • Aeon.Emulator.Sound.dll: Provides Adlib, Sound Blaster, and General MIDI emulation.
  • Aeon.Presentation.dll: Contains the WPF graphical presentation layer and exposes Aeon as a WPF-friendly control.
  • Aeon.ZipFiles.dll: Provides simple zip file access.
  • Aeon.exe: Implements the user interface.

The emulator itself is decoupled from the user interface – to run a DOS program all you really need is Aeon.Emulator. To actually see anything on the emulated VGA card or be able to provide any kind of keyboard/mouse input, you’ll need to handle some events raised by the emulator, but this is all optional. It’s the presentation layer’s goal to handle video mode change events and render the data in emulated video RAM to a 32-bit bitmap, and also to capture keyboard/mouse input. The application itself just hosts the control from the presentation layer and wires it up to some UI commands.

The Aeon.Emulator.Sound assembly defines some classes that implement IVirtualDevice, IInputPort, IOutputPort, and IDmaDevice. The application simply registers these classes with the emulator to allow DOS programs to see the Sound Blaster hardware.

Next time, I’ll actually get into some code.

October 12, 2009

Aeon version 0.48

Filed under: Aeon, New Version — Greg Divis @ 9:40 pm

Time for another new build. Download it here.

  • Sound Blaster 16 mostly implemented (still needs more testing)
  • Option to enable/disable aspect-correct video stretching
  • Lots of small fixes with DOS process management
  • Other minor compatibility fixes

October 8, 2009

Zork I: The Great Underground Empire

Filed under: Aeon, Fun & Games — Greg Divis @ 8:49 pm

I probably should have started with this one, as it was the first game I got working in Aeon, but starting things off with a screenshot of an interactive fiction game just seemed too boring. Oh well, here it is:

Zork

There isn’t too much I can say about Zork that hasn’t already been said. It’s a classic, particularly in the realm of text-parser based adventure games. Also, take a look at the copyright date in the screenshot above: it’s been around for almost 30 years, but thanks to the Infocom Z-machine, you can still play it today.

Getting Zork to work was a big deal to me, since the only programs I had tested before were simple assembly or C “hello world” programs. Zork was the real deal, and I encountered a lot of issues on the way. I was practically ecstatic when I finally got it to run, right up until I tried to read any of the text on the screen:

NMUU

It was really weird. The numbers, whitespace, and casing were all correct, but the letters were completely scrambled. I don’t remember the exact cause of this, but I think it involved my incorrect implementation of the ROR instruction.

Anyway, if you’d like to play Zork, you can find the first three episodes free for download here. If you want to play Zork 1 using Aeon, just open _zork1.com and you’re all set.

Alternatively, since Infocom games essentially run inside their own virtual machines, you can elect to use a more modern interpreter instead. No emulator required!

The Z-machine standard is itself a pretty interesting subject; if you’re interested in what it takes to build a compliant interpreter from the ground up, here’s a blog to follow.

Older Posts »

Blog at WordPress.com.