Home

Awesome

LLVM-MOS SDK

The LLVM-MOS compiler toolchain and platform libraries.

API Reference

Supported platforms

Notable features

Notably missing features

Getting started

Download

First, download and extract the archive for your platform.

(macOS Only) Remove Quarantine

On macOS, downloading a package automatically applies a quarantine to the file. This will also affect the extracted binaries from the package, which causes GateKeeper to prevent them from running. To avoid this, run the following on the downloaded package before extracting it:

$ xattr -d com.apple.quarantine llvm-mos-macos.tar.xz

(Optional) Add LLVM-MOS to PATH

If you like, you can add LLVM-MOS to your path. This will make accessing LLVM-MOS from the command line easier.

WARNING: Don't install LLVM-MOS into your path if you already have LLVM/Clang installed. LLVM-MOS conflicts with other LLVM/Clang installations.

POSIX

Add the following line to your shell profile (~/.bashrc, ~/.zshrc, etc...):

export PATH=$PATH:<arbitrary-install-directory>/bin

To work with CMake-enabled IDEs, it may also need to be added to your desktop profile (~/.gnomerc, KDE, etc...).

Windows

rundll32.exe sysdm.cpl,EditEnvironmentVariables
# Edit "Path" user variable
# Add entry for "<arbitrary-install-directory>\bin"

Afterwards, new shells will have direct access to LLVM-MOS.

Compile an Example

Once installed, you can compile a sample program with a direct command. You will need to prefix clang (or clang++) with a specific MOS platform provided by the SDK. This will ensure clang loads the correct configuration to generate executables and libraries for that target.

PlatformVariantCommand
Atari 26004Kmos-atari2600-4k-clang
Atari 2600TigerVision 3Emos-atari2600-3e-clang
Atari 5200Super Cartmos-atari5200-supercart-clang
Atari 8-bitDOSmos-atari8-dos-clang
Atari 8-bitMegaCart cartridgemos-atari8-cart-megacart-clang
Atari 8-bitStandard cartridgemos-atari8-cart-std-clang
Atari 8-bitXEGS cartridgemos-atari8-cart-xegs-clang
Atari LynxBLL executablemos-lynx-bll-clang
Ben Eater's 6502 Breadboard Kit-mos-eater-clang
Commander X16-mos-cx16-clang
Commodore64mos-c64-clang
Commodore128mos-c128-clang
CommodorePETmos-pet-clang
CommodoreVIC-20mos-vic20-clang
CP/M-65-mos-cpm65-clang
Dodo 6502 Game System-mos-dodo-clang
Commodore GEOS64, 128mos-geos-cbm-clang
MEGA65-mos-mega65-clang
NESAction53 mappermos-nes-action53-clang
NESCNROM mappermos-nes-cnrom-clang
NESGTROM mappermos-nes-gtrom-clang
NESMMC1 mappermos-nes-mmc1-clang
NESMMC3 mappermos-nes-mmc3-clang
NESNROM mappermos-nes-nrom-clang
NESUNROM mappermos-nes-unrom-clang
NESUNROM-512 mappermos-nes-unrom-512-clang
Ohio Scientific Challenger 1P-mos-osi-c1p-clang
OLIMEX Neo6502-mos-neo6502-clang
Picocomputer 6502-mos-rp6502-clang
PC EngineStandardmos-pce-clang
PC EngineCDmos-pce-cd-clang
RPC/8e (RedPower 2)-mos-rpc8e-clang
Watara Supervision-mos-supervision-clang
6502 simulator-mos-sim-clang
$ cat <install_dir>/examples/hello-putchar.c
#include <stdio.h>

int main(void) {
  const char *cur = "HELLO, PUTCHAR!\n";
  while (*cur)
    putchar(*cur++);
  return 0;
}

$ mos-c64-clang -Os -o hello.prg <install_dir>/examples/hello-putchar.c

$ llvm-objdump -d hello.elf
...

$ mos-c64-clang -Os -o hello.s -Wl,--lto-emit-asm <install_dir>/examples/hello-putchar.c

Developing for 6502 with CMake

A CMake package and toolchain file are provided to make targeting MOS from CMake easy.

Create a new source directory with a CMakeLists.txt like the following where LLVM_MOS_PLATFORM is set to any platform supported by the SDK:

cmake_minimum_required(VERSION 3.18)
set(LLVM_MOS_PLATFORM c64)
find_package(llvm-mos-sdk REQUIRED)
project(llvm-mos-sdk-foo)
add_executable(foo foo.c)

Note: If LLVM-MOS was not added to PATH, set -DCMAKE_PREFIX_PATH=<arbitrary-install-directory> to match the install prefix of LLVM-MOS so find_package will work correctly.

Development

To modify the SDK, you'll need to be able to build it yourself. This requires a working LLVM-MOS compiler, which can be found in the current SDK release. Accordingly, make sure to install the SDK first using the instructions above.

Install ninja

For the steps below to work as-is, you'll need to install Ninja, the fast, parallel build tool favored by LLVM developers. Instructions for your platform will vary; see https://ninja-build.org/.

Alternatively, you can set -G "Makefile" in each CMake command to use standard UNIX Makefiles, or you can substitute any other CMake-supported generator. Your compile times may take a hit, and LLVM is already very slow to build, so Ninja is highly recommended.

Build and Install LLVM-MOS-SDK

Set CMAKE_INSTALL_PREFIX below to the LLVM-MOS installation directory. This will replace the SDK portion of the installation with the newly built artifacts on ninja install.

$ git clone https://github.com/llvm-mos/llvm-mos-sdk.git
$ cd llvm-mos-sdk
$ mkdir build
$ cd build
$ cmake -G "Ninja" -DCMAKE_INSTALL_PREFIX=<sdk-install-directory> ..
$ ninja install

The complete SDK will now be present in the install prefix.

Run Unit Tests

NES (legacy Mesen Mono version tests)

Install Mesen-X and its dependencies.

Set the MESEN_DIR environment variable to the folder containing the Mesen.exe executable before running CMake for the first time. Copy test/mesen_settings.xml to this folder.

Libretro tests (Atari 2600, etc.)

Install emutest (requires Go 1.21):

$ go install github.com/kivutar/emutest@latest

Make sure $GOBIN (usually ~/go/bin) is included in your PATH environment variable so that CMake can find the binary, or set the EMUTEST_DIR environment variable to point to this directory before running cmake -G for the first time.

You can verify emutest with emutest -h on the command-line.

You should see -T Test runner mode (script must call os.exit) in the output.

Build Libretro cores for desired target(s):

Copy the output Libretro core library files (they have extensions .so | .dylib | .dll) to a shared directory, maybe $HOME/libretro. Set the LIBRETRO_CORES_DIR environment variable to this folder before running cmake -G for the first time.

Run a test project

$ ninja test            # run all test projects
$ ninja test-nes-nrom   # run a specific test project, e.g. nes-nrom