A cross-platform emulator for TI-84 Plus CE calculators, with native Android, iOS, and Web apps.
calc/
core/ # Rust emulator core (C ABI + WASM)
android/ # Android app (Kotlin + Jetpack Compose)
ios/ # iOS app (Swift + SwiftUI)
web/ # Web app (React + TypeScript + Vite)
scripts/ # Build scripts
docs/ # Architecture and milestone documentation
cemu-ref/ # CEmu reference emulator (git-ignored, optional)
The mobile apps (Android & iOS) and web app are designed to work with two interchangeable emulator backends:
┌─────────────────────────────────────────────────────────┐
│ App (UI) │
│ Android (Kotlin/Compose) │
│ iOS (Swift/SwiftUI) │
│ Web (React/TypeScript) │
├─────────────────────────────────────────────────────────┤
│ C API (emu.h) / WASM Bindings │
│ emu_create, emu_load_rom, emu_run_cycles, │
│ emu_framebuffer, emu_set_key, ... │
├───────────────────────┬─────────────────────────────────┤
│ Rust Core │ CEmu Adapter │
│ (libemu_core.a) │ (libcemu_adapter.a) │
│ (emu_core.wasm) │ (cemu.wasm via Emscripten) │
│ │ │
│ Our implementation │ Wraps CEmu reference │
│ from scratch │ emulator │
└───────────────────────┴─────────────────────────────────┘
Both backends implement the same C API (core/include/emu.h), allowing the apps to switch between them at build time without any code changes.
The Rust core (core/) is our from-scratch implementation of the TI-84 Plus CE hardware:
- eZ80 CPU - Full instruction set with ADL mode (24-bit addressing)
- Memory - Flash (4MB), RAM (256KB), VRAM, memory-mapped I/O
- Peripherals - LCD controller, keypad, timers, RTC, interrupts, SPI
- Scheduler - Cycle-accurate event scheduling
CEmu is the established open-source TI-84 Plus CE emulator. We use it as a reference implementation for:
- Parity testing - Compare our emulation against known-correct behavior
- Debugging - When something doesn't work, check if CEmu behaves the same
- Development - Test app features before Rust implementation is complete
The CEmu adapter (android/app/src/main/cpp/cemu/) wraps CEmu's C code to match our API.
The emulator recreates the TI-84 Plus CE hardware in software:
- Loads ROM - The calculator's operating system (you provide this)
- Executes CPU - Runs eZ80 instructions at ~48MHz emulated speed
- Renders Display - 320x240 16-bit color LCD at 60 FPS
- Handles Input - 8x7 key matrix matching the physical calculator
- Emulates Peripherals - Timers, real-time clock, interrupts, etc.
The apps provide the UI (screen display, keypad, menus) while the backend handles all emulation logic.
- Rust toolchain
- For Android: Android Studio with NDK, Android SDK (API 24+)
- For iOS: Xcode 15+, macOS
- For Web: Node.js 18+, wasm-pack
The project uses a single build script for both platforms:
./scripts/build.sh <platform> [options]Platforms: android, ios
Options:
| Option | Description |
|---|---|
--release |
Release build (default) |
--debug |
Debug build |
--cemu |
Use CEmu backend instead of Rust |
--install |
Android: Install APK after build |
--sim |
iOS: Build for Simulator |
--all-abis |
Android: Build all ABIs (default: arm64 only) |
Note: For iOS, the build script only compiles the backend library. Open
ios/Calc.xcodeprojin Xcode to build and run the app.
Examples:
# Android
./scripts/build.sh android # Release, arm64, Rust
./scripts/build.sh android --debug --install # Debug + install to device
./scripts/build.sh android --cemu # Release with CEmu backend
# iOS (builds backend library, then open Xcode to build app)
./scripts/build.sh ios # Release, device, Rust
./scripts/build.sh ios --sim --debug # Simulator, Debug
./scripts/build.sh ios --sim --cemu # Simulator, CEmu backend# Android
make android # Release, arm64, Rust
make android-debug # Debug, arm64, Rust
make android-cemu # Release, CEmu backend
make android-install # Release + install
make android-cemu-install # CEmu + install
# iOS (builds backend library, then open Xcode to build app)
make ios # Release, device, Rust
make ios-debug # Debug, device, Rust
make ios-cemu # Release, device, CEmu
make ios-sim # Release, simulator, Rust
make ios-sim-cemu # Release, simulator, CEmu
# Web
make web # Build WASM + web app (production)
make web-dev # Start dev server with hot reload
make web-cemu # Build with CEmu WASM backend
# Utilities
make test # Run Rust tests
make clean # Clean all build artifacts
make help # Show all targetsOne-time setup - Install Android targets:
rustup target add aarch64-linux-android # ARM64 (most devices)
rustup target add armv7-linux-androideabi # ARM32 (older devices)
rustup target add x86_64-linux-android # x86_64 emulator
rustup target add i686-linux-android # x86 emulatorManual Gradle build (if not using build.sh):
cd android
./gradlew assembleDebugOne-time setup - Install iOS targets:
rustup target add aarch64-apple-ios # iOS device (arm64)
rustup target add aarch64-apple-ios-sim # iOS Simulator (Apple Silicon)
rustup target add x86_64-apple-ios # iOS Simulator (Intel)Building and Running:
# 1. Build the backend library
./scripts/build.sh ios --sim # For simulator
./scripts/build.sh ios # For device
# 2. Open Xcode and build/run the app
open ios/Calc.xcodeproj
# Press Cmd+R to build and runThe build script compiles the emulator backend (Rust or CEmu) as a static library. Xcode handles building the Swift app and linking against the library.
One-time setup - Install WASM target and wasm-pack:
rustup target add wasm32-unknown-unknown
cargo install wasm-packBuilding and Running:
# Development (with hot reload)
make web-dev
# Production build
make web
# Output in web/dist/The web app runs entirely in the browser using WebAssembly (~96KB gzipped).
Keyboard Controls:
| Key | Function |
|---|---|
| 0-9 | Number keys |
| + - * / | Math operations |
| ( ) | Parentheses |
| Enter | Enter |
| Backspace | Delete |
| Arrow keys | Navigation |
| Escape | Mode |
| Shift | 2nd |
| Alt | Alpha |
| O | ON key |
For rapid iteration on Android:
# Terminal 1: Watch for Kotlin changes and auto-deploy
cd android
./watch.sh
# When changing Rust code, rebuild:
./scripts/build.sh android --debug --installThe watch.sh script requires fswatch (brew install fswatch).
The apps can be built with CEmu instead of our Rust core. This is useful for:
| Use Case | Description |
|---|---|
| Parity Testing | Compare behavior: does our Rust core produce the same results as CEmu? |
| Bug Investigation | If something breaks, check if it's our bug or a ROM/hardware quirk |
| Feature Development | Test new app features (UI, input) before Rust implementation catches up |
| Performance Baseline | Compare frame rates and responsiveness |
Setup:
# Clone CEmu (one-time, git-ignored)
git clone https://github.com/CE-Programming/CEmu.git cemu-refBuild with CEmu:
./scripts/build.sh android --cemu # Android with CEmu backend
./scripts/build.sh ios --sim --cemu # iOS simulator with CEmu backend
./scripts/build.sh ios --cemu # iOS device with CEmu backend
# Then open ios/Calc.xcodeproj in Xcode to build the app
make web-cemu # Web with CEmu WASM backendThe app behavior should be identical regardless of backend - if it differs, that's a bug to investigate.
cd core
cargo testThis runs the test suite covering:
- Memory subsystem (Flash, RAM, VRAM, ports)
- Bus address decoding and wait states
- eZ80 CPU instructions and flag behavior
- ADL mode 24-bit operations
- TI-84 CE memory map verification
To run a specific test:
cargo test test_nameTo see test output:
cargo test -- --nocaptureTest tools in tools/cemu-test/ compare CEmu (reference emulator) behavior with our Rust implementation.
Prerequisites:
- Clone CEmu:
git clone https://github.com/CE-Programming/CEmu.git cemu-ref - Build CEmu core:
cd cemu-ref/core && make - Obtain a TI-84 Plus CE ROM file
Build the tools:
cd tools/cemu-test
makeparity_check - Verifies RTC timing, MathPrint flag, and key state at cycle milestones:
./parity_check # Defaults: 60M cycles, ROM at ../../TI-84 CE.rom
./parity_check /path/to/rom.rom -m 100000000 # Custom ROM and cycle count
./parity_check -v # Verbose modeKey addresses monitored:
0xD000C4- MathPrint flag (bit 5: 1=MathPrint, 0=Classic)0xF80020- RTC control register (bit 6: load in progress)0xF80040- RTC load status (0x00=complete, 0xF8=all pending)
trace_gen - Generates CPU instruction traces for direct comparison:
./trace_gen ../../TI-84\ CE.rom # 1M steps to stdout
./trace_gen ../../TI-84\ CE.rom -n 100000 -o cemu_trace.txt # To fileOutput format: step cycles PC SP AF BC DE HL IX IY ADL IFF1 IFF2 IM HALT opcode
The emulator includes a consolidated debug tool for testing, tracing, and diagnostics.
Run these from the core/ directory:
cd core
cargo boot # Run boot test with progress reporting
cargo screen # Render screen to PNG after boot
cargo vram # Analyze VRAM colors
cargo trace # Generate trace log (100k steps)
cargo dbg # Show debug tool help
cargo t # Run all tests
cargo rb # Release buildFor more options, use the debug tool directly (from core/):
cargo run --release --example debug -- <command>| Command | Description |
|---|---|
boot |
Run boot test with progress reporting |
trace [steps] |
Generate trace log for parity comparison (default: 100k) |
screen [output] |
Render screen to PNG after boot (default: screen.png) |
vram |
Analyze VRAM content (color histogram) |
compare <file> |
Compare our trace with CEmu trace file |
help |
Show help message |
Examples:
# Generate 1M step trace for parity comparison
cargo run --release --example debug -- trace 1000000
# Save screenshot with custom name
cargo run --release --example debug -- screen boot.png
# Compare with CEmu trace
cargo run --release --example debug -- compare ../traces/cemu.logFor detailed parity testing with CEmu:
# 1. Generate CEmu trace
cd tools/cemu-test
./trace_gen ../../TI-84\ CE.rom -n 10000 -o cemu_trace.txt
# 2. Generate Rust trace
cd ../../core
cargo run --release --example debug -- trace 10000 > rust_trace.txt
# 3. Compare
diff ../tools/cemu-test/cemu_trace.txt rust_trace.txt | head -50
# Or use the built-in compare command
cargo run --release --example debug -- compare ../tools/cemu-test/cemu_trace.txt- BYOR (Bring your own ROM) - Obtain a TI-84 Plus CE ROM file legally
- Install the app
- Use "Import ROM" to load your ROM file
- Press Run to start emulation
See LICENSE file.
This emulator does not include any copyrighted ROM or OS images. You must provide your own legally obtained ROM file.
