E16 is a small toolchain for the Ember-16 virtual machine and assembly language. The repository contains a C++ assembler, emulator, disassembler, image and tilemap converters, sample programs, and a Neovim plugin for editing .e16 files.
assembler/: buildse16asm, which compiles.e16assembly into binary programs.emulator/: buildse16emu, an SDL3-based emulator for running compiled programs.disassembler/: buildse16dis, a terminal disassembler for E16 binaries.converter/: buildse16img,e16spritepack, ande16tilemapPNG asset converters.musicMaker/: buildse16musicmaker, a six-channel APU tracker with live SDL3 preview, wavetable design, PCM recording, and callable.e16music export.tests/: example.e16programs and assets.nvim/e16.nvim/: Neovim filetype, syntax highlighting, and LSP support.
- CMake 3.10 or newer
- A C++20 compiler
- SDL3 for the emulator and music maker
- zlib for the image converter
- Python 3 for the Neovim LSP server
On macOS with Homebrew:
brew install cmake sdl3 zlibOn Ubuntu:
sudo apt-get update
sudo apt-get install -y build-essential cmake pkg-config libsdl3-dev zlib1g-dev python3Each tool is currently its own CMake project.
cmake -S assembler -B assembler/build
cmake --build assembler/build
cmake -S emulator -B emulator/build
cmake --build emulator/build
cmake -S musicMaker -B musicMaker/build
cmake --build musicMaker/build
cmake -S disassembler -B disassembler/build
cmake --build disassembler/build
cmake -S converter -B converter/build
cmake --build converter/buildThe binaries are written to each build directory:
assembler/build/e16asmemulator/build/e16emumusicMaker/build/e16musicmakerdisassembler/build/e16disconverter/build/e16imgconverter/build/e16spritepackconverter/build/e16tilemap
Assemble a program:
assembler/build/e16asm tests/solid/main.e16 -o tests/solid/main.binRun it in the emulator:
emulator/build/e16emu tests/solid/main.binRun with debugger mode enabled:
emulator/build/e16emu -s tests/solid/main.binCompose and export E16 music:
musicMaker/build/e16musicmakerThe exported assembly module provides music_play, music_update, and music_stop. Call music_update once per game frame after music_play so the song advances without blocking the game loop.
Disassemble a binary:
disassembler/build/e16dis --plain tests/solid/main.binConvert a small PNG sprite or tile image:
converter/build/e16img sprite.png -o sprite.e16imgThe image converter accepts 8x8, 16x16, and 32x32 PNG files with up to 16 RGB555 colors.
Combine palette-compatible sprite variants:
converter/build/e16spritepack red.png blue.png -o actors.e16spr --inc actors.e16Create a background asset from a PNG tilemap:
converter/build/e16tilemap background.png -o level1.e16bg --inc level1.e16 --wrape16spritepack writes one padded 16-color palette page followed by every packed sprite. It checks that all sprites are the same size and share the same opaque shape unless --force is passed.
e16tilemap splits a PNG into 8x8 tiles, builds one padded 16-color palette page, deduplicates tiles with flip-aware tilemap entries, and writes constants for palette, tile, and map offsets.
Usage: e16asm [--base address] [-o output.bin] [--print-ast] file.e16
-o,--output: choose the output binary path.-b,--base: set the base address. Defaults to0x200000.--print-ast: print parsed expressions before compiling.
usage: e16emu [-s] [-w] [-m] [--headless] [--load-address addr] [--scale n] program.bin
-s: enable debugger mode.-w: run in a window and leave the cursor visible.--headless: run without creating a window, including on Linux systems without a desktop environment.-m: disable audio playback.--load-address: choose where the binary is loaded.--scale: set the initial emulator display scale.- The emulator opens fullscreen by default and letterboxes the 320x180 display.
- If SDL cannot initialize graphical output, the emulator reports the SDL error and exits.
- If a Mesa OpenGL version override is inherited, the emulator uses SDL's software renderer to avoid incompatible OpenGL contexts.
- When
DISPLAYis available, the emulator prefers SDL3'sx11backend. Otherwise it lets SDL select the native video backend for the current environment. - Every launch writes a fresh diagnostic log to the platform temporary directory (
/tmp/e16.logon Linux), including the SDL version, display environment, selected video and render drivers, fallback decisions, runtime faults, fatal exceptions, signals, and the final exit code. - Gamepad and audio initialization failures do not prevent graphical execution. Failed accelerated renderers, unavailable fullscreen modes, and presentation failures automatically use safe fallbacks where possible.
- The graphical emulator uses nearest-neighbor presentation, hides the cursor, and never opens modal SDL message boxes.
- Gamepads are supported for up to two players. D-pads and left sticks map to directions; South/East/West/North map to A/B/X/Y; Start maps to Start; Back maps to Select.
- Escape or Back+Start / Minus+Plus exits the emulator.
Usage: e16dis [--base address] [--plain] [--no-color] [--no-pager] [--no-labels] [--no-bytes] file.bin
-b,--base: set the base address. Defaults to0x200000.--plain: disable color and pager output.--no-color: disable ANSI color output.--no-pager: print directly instead of using a pager.--no-labels: hide generated labels.--no-bytes: hide instruction bytes.
Usage: e16img <image.png> [-o output.e16img]
-o,--output: choose the converted image output path.
Usage: e16spritepack [--yes] [--force] [-o output.e16spr] [--inc output.e16] <sprite.png>...
-o,--output: choose the combined binary output path.--inc,--include: choose the generated.e16constants path.-y,--yes: skip the confirmation prompt.--force: combine sprites even when their opaque shapes differ.
Usage: e16tilemap <background.png> [-o output.e16bg] [--inc output.e16] [--symbol NAME] [--palette n] [--wrap] [--no-flips]
-o,--output: choose the background binary output path.--inc,--include: choose the generated.e16constants path.--symbol: choose the constant prefix.--palette: set the tilemap entry palette number from 0 to 15.--wrap: emit a layer control value with horizontal and vertical wrapping.--no-flips: disable flipped tile deduplication.
The Neovim plugin lives in nvim/e16.nvim and provides:
*.e16filetype detection- syntax highlighting
- completions, hover, go-to-definition, document symbols, semantic tokens, and diagnostics through the included Python LSP server
With lazy.nvim:
{
dir = "/path/to/E16/nvim/e16.nvim",
ft = "e16",
config = function()
require("e16").setup()
end,
}See nvim/e16.nvim/README.md for more editor setup details.
This repository includes workflows for:
- Building all CMake tools on Ubuntu.
- Checking the Neovim plugin's Python LSP server with
py_compile.
This is an experimental toolchain. Interfaces and binary formats may change while the emulator, assembler, and editor tooling evolve together.