SearchA-ZT › TI-84 Plus Emulator (Wabbitemu)

TI-84 Plus Emulator (Wabbitemu)

2007 MIT Online

An in-browser emulator of the TI-84 Plus, the Zilog Z80 graphing calculator. It runs the portable Wabbitemu core (the reference Texas Instruments Z80 emulator, by Spencer Putt and Chris Shappell) compiled to WebAssembly, and boots straight to the TI-84 Plus home screen. Type on the on-screen calculator keypad or your physical keyboard.

Because the core is driven through a small set of exported functions, the emulator plugs into the shared in-page debugger: single-step the Z80, read and write the registers and memory, and set breakpoints and watchpoints, all live.

Visit the Wabbitemu project ↗

Visit the official site ↗

Runs on: Web browser

TI-84 Plus Emulator (Wabbitemu) Online Emulator

Play TI-84 Plus Emulator (Wabbitemu) using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
TI-84 Plus home screenTI-84 Plus Emulator (Wabbitemu)greyOpen ⛶

Chips

Notes

Embedding

The Wabbitemu core is the reference Texas Instruments Z80 emulator. Its GUI is Windows-only, but the emulation core is portable C, so we compile just that to WebAssembly with Emscripten and drive it ourselves. Wabbitemu's own calc_run_frame loop runs free, which the debugger cannot pause or step.

Boot. Set up the 84+ hardware, copy the ROM into flash, then reproduce Wabbitemu's power-on (reset, then tap the ON key):

wabbit_init();                       // memory_init_84p + CPU_init + device_init_83pse
wabbit_load_rom(ptr, len);            // memcpy the 1 MB image into mem_c.flash
wabbit_boot();                       // CPU_reset, run 1s, press/release ON, run to HALT
(function frame(){
  wabbit_run_frame();                  // run one video frame of CPU_step()s
  blitLCD();                          // wabbit_lcd() -> ImageData -> canvas
  requestAnimationFrame(frame);
})();

The core is reached through a handful of exported C functions (all in wabbit.c), each called on demand from JavaScript, never per instruction:

ExportKindWhat it does
wabbit_step()fnRun exactly one Z80 instruction (CPU_step). The single-step primitive.
wabbit_run_frame()fnRun one video frame's worth of T-states at full speed.
wabbit_reg(i) / wabbit_set_reg(i,v)fnRead / write a register by index: AF BC DE HL IX IY SP PC, the shadows, I R, IM and the interrupt / halt flags, straight off the live CPU_t.
wabbit_read(a) / wabbit_write(a,v)fnThe banked 64K CPU bus. Reads resolve the current page mapping directly, with no flash-command side effects, so an auto-polling hex view is safe.
wabbit_flash_read / wabbit_ram_readfnThe raw 1 MB flash and 128 KB RAM chips.
wabbit_lcd(out)fnCopy the 96×64 grayscale LCD image (from the T6A04 driver) into a buffer for the canvas.
wabbit_key_down(g,b) / wabbit_key_up(g,b)fnPress / release a key in the hardware matrix by group and bit.
wabbit_reset()fnFull power-on reset: rebuild the ASIC, restore the ROM, tap ON.

Emscripten resolves ti84wabbit.wasm next to its loader script; the ROM is fetched from the same directory. Because every handle is a plain function call, the debugger reads registers and memory each refresh, single-steps with wabbit_step(), and implements breakpoints and watchpoints host-side, with no change to the emulator's hot path.

Debugger integration

The plug-in (ti84-debug.js) reads the live core from window.EMU_BOOT and calls EmuKit.defineMachine with a transport, the Z80 register set and the memory chips. It reuses the shared z80 disassembler (/debugger/src/cpus/z80.js).

Exactly what was changed in the source. The only file added to Wabbitemu is wabbit.c - a thin layer of EMSCRIPTEN_KEEPALIVE functions over the existing core API. It reads the register union CPU_t (cpu.af, cpu.pc, …), resolves the bus through mem_c.banks[addr>>14], copies the LCD via lcd->image(), and forwards keys to keypad_press/keypad_release. The three audio functions the 83+SE link handler references (FlippedLeft, FlippedRight, nextsample) are stubbed, since sound is out of scope. Nothing in the per-instruction path was touched, so with the debugger closed the emulator runs at full speed.

Single-step is CPU_step(). Breakpoints are a host-side Set of PC values: when any are set the JavaScript loop runs one instruction at a time (bounded by wabbit_tstates()) and compares the PC before each; no per-cycle hook is added to the wasm core. Watchpoints sample the watched addresses after each stepped instruction and halt on a change. Wabbitemu already emulates the flash command state machine, boot-page mapping and protected pages faithfully, which is why the official TI operating system boots to its home screen here where lighter cores stall.

How to rebuild. With Emscripten on PATH, from a Wabbitemu checkout with wabbit.c beside it:

emcc core/{core,alu,control,indexcb,device,*_reverse,reverse_info}.c \
     hardware/{83phw,83psehw,lcd,colorlcd,keys,link}.c wabbit.c \
     -O2 -D_LINUX '-D__pragma(x)=' -I. -Icore -Ihardware -IInterface -Iutilities \
     -s MODULARIZE=1 -s EXPORT_NAME=WABBIT -s 'EXPORTED_FUNCTIONS=[_wabbit_init,...,_malloc,_free]' \
     -s 'EXPORTED_RUNTIME_METHODS=[ccall,cwrap,HEAPU8]' \
     -s ALLOW_MEMORY_GROWTH=1 -s ENVIRONMENT=web --no-entry -o ti84wabbit.js

-D_LINUX selects the portable branch of stdafx.h; '-D__pragma(x)=' neutralises the one MSVC pragma in lcd.c. The full recipe and source are vendored in src/README.txt and src/wabbit.c.

Architecture

The TI-84 Plus is a Zilog Z80 graphing calculator: a 6/15 MHz Z80, 1 MB of Flash (64 pages of 16 KB), 128 KB of RAM, and a 96×64 monochrome LCD driven by a Toshiba T6A04 controller.

  • Z80 core - Wabbitemu's cycle-accurate interpreter (core/core.c), with the register banks held in a regpair union so cpu.af and cpu.a/cpu.f alias.
  • Memory - a five-bank mapping context. $0000 is a fixed flash page, $4000 and $8000 are paged via ports 06/07, $C000 is RAM. The context emulates the AMD flash command sequences, RAM execution protection and the special boot-page mapping, the fidelity the TI OS boot depends on.
  • Display - the T6A04 LCD driver (hardware/lcd.c); its image() composites the black-and-white frame into a 128-stride grayscale buffer whose visible 96 columns we blit.
  • Keypad - an 8×8 matrix read through port 01 (hardware/keys.c); each key is a (group, bit) pair.
  • ROM - the TI-84 Plus operating system (2.55MP), a system image © Texas Instruments, installed into the flash pages.

Every part is reached from JavaScript through the small wabbit.c shim, which is what makes an otherwise Windows-bound emulator a live, steppable debugging target in the browser.