marhel / r68k

A m68k emulator in rust - let r68k = musashi.clone();
MIT License
72 stars 7 forks source link

r68k

r68k is a emulator for the m68k written in Rust, as a port of Karl Stenerud's Musashi. Musashi "has been successfully running in the MAME project (www.mame.net) for years and so has had time to mature." - so unlike most other emulators Musashi is of proven quality to run complex real-world m68k software, which I thought was a good foundation to build on.

The end goal for r68k is to have a complete m68k emulation lib, comparable with Musashi in speed and functionality, which I might later use to build a virtual retro computer in Rust - a project I have not even started on yet (or, well, I have some code, but I got tired of C++, and was inspired enough by Rust to start over). It's built from the start to be able to operate multiple cores independently, with their own RAM, because eventually I want to emulate several independent retro computers in the same process, for an even more ambitious, will-never-see-the-light-of-day, still-very-fuzzy-around-the-edges first-person-hacking gaming idea vaugely inspired by 0x10c. There. I said it. Now mock me! But at least I'll get to learn Rust. And failure. But Rust is good!

Project Layout

common => r68k_common
    constants       common opcode constants
emu => r68k_emu
    cpu             Motorola 68000 emulation
    musashi         Musashi integration tests
tools => r68k_tools
    assembler       simple assembler
    disassembler    simple disassembler
    srecords        support for Motorola SRecord format

The Processor

The Motorola 68000 CPU, commonly referred to as m68k, was a very successful CPU introduced in 1979, that powered several classic personal computers of the 1980s, such as the Apple Macintosh, Commodore Amiga and Atari ST, as well as the first SUN and Apollo UNIX workstations. It was used in several arcade machines and game consoles such as the Sega Genesis/Mega Drive, and was also found in the first laser printers, such as Apple LaserWriter and HP LaserJet printers, and several calculators (such as Texas Instruments' TI-89 and TI-92).

It typically ran at 8MHz and could address up to 16MB of RAM. However, popular home computers in the mid to late 1980s typically only had 512KB.

Usage

Note that the emulator is not a full computer system emulation, it's just a CPU connected to some memory, so on its own it doesn't do anything interesting. You will have to load its memory with some program, which is just a series of bytes representing valid instructions and data, and tell it to start executing those. The CPU starts fetching instructions from memory, executes them one by one, which affects the state of the CPU. Some instructions also write to memory, and you can observe and act on these effects.

One can build a simple computer emulation on top of r68k.

CPU Emulator

The current status of the r68k emulator is usable. Please note that it only implements the original 68000 instruction set. It does not support instructions specific to newer CPUs in the 68k family (such as the 68010, 68020 or 68040) at this time.

The main emulation TODOs are:

Disassembler

The Disassembler support the full instruction set, and has been verified against the emulator so that all valid opcodes can be disassembled, and no invalid opcodes are incorrectly recognized by the disassembler. The Disassembler currently has no command line interface, but can be used programmatically to disassemble a chunk of memory, one instruction at a time.

The main disassembly TODOs are:

Assembler

The Assembler supports the full instruction set. It can assemble all valid instructions, which has been verified by disassembling all 64K possible opcodes, making sure that all valid opcodes assemble back to the same sequence of bytes.

The parser is based on the Pest PEG parser generator and supports the full instruction set, and a few directives (but documentation of supported assembler directives is still missing).

The main disassembly TODOs are:

S-record support

The Motorola S-record formatis a format for representing binary data in a simple ASCII-text format, typically used to contain a "memory image" of microprocessor programs. They contain the compiled microprocessor instructions and data, along the absolute memory addresses where they are to be stored. These files are often produced by a compiler or assembler and then used to upload a program directly into microprocessor memory.

The S-record-support is still in a very early stage, and is write only.

Testing philosophy

All 64k possible opcodes have been A/B-tested against Musashi using BurntSushi's QuickCheck for Rust. There's about 54 000 valid opcodes for the m68k (and the remaining 11 500 does not represent valid instructions).

Using QuickCheck means we first generate a randomized CPU state (including random values for all D and A registers, and the status register which controls Supervisor mode, and includes condition codes such as overflow, zero etc), then both Musashi and r68k is carefully put in this state, and then the instruction under test is executed, and then the resulting state is compared for any differences. All memory accesses made by either emulator are also compared for any differences, including number and order of accesses, the address used, operation size (8, 16 or 32 bits), as well as the value read/written and address space used (user/supervisor + data/program). Then this process is repeated many times for each opcode implemented.

In effect, each instruction is compared thoroughly (with random values) to Musashi, using all combinations possible of the allowed source and destination addressing modes and registers. The number of clock cycles consumed is also reported by Musashi after execution, and is also compared to r68k.

If during execution any exceptions are encountered, such as privilege violations, illegal instruction traps or address errors (word or long accesses on odd addresses) then the actions (and cycles) taken by the emulators are also compared in the same way.

Randomized testing tends to immediately discover any differences in the implementation, and tests not failing gives a fair bit of confidence that the implementation is correct - or at least behaves like Musashi, which (unlike r68k) is in fact battle-tested. I'm also frequently referencing the M68000 Programmer's Reference Manual and M68000 User's Manual.