SearchA-ZA › Acorn Archimedes

Acorn Archimedes

1987 Open source · GPL-2.0 Online

The Acorn Archimedes was the first desktop computer built around the ARM, Acorn's own 32-bit RISC processor. This is Sarah Walker's Arculator emulator compiled to WebAssembly, running an A3000 (Acorn ARM2, 4 MB) and booting RISC OS 3.11 straight to the desktop in your browser.

Visit the official site ↗

Runs on: Web browser

Acorn Archimedes Online Emulator

Play Acorn Archimedes using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
RISC OS 3Acorn ArchimedesAcorn ArchimedesAcorn RISC OSgreyOpen ⛶

Machines emulated

Operating systems

Chips

Notes

Embedding

Arculator is a C emulator that uses SDL2 for video, sound and input. We compiled it to WebAssembly with Emscripten (-sUSE_SDL=2 -sUSE_WEBGL2=1); the emulator owns its own emscripten_set_main_loop, and we drive/inspect it from JavaScript through exported EMSCRIPTEN_KEEPALIVE functions. We self-host everything (no CDN): arculator.js (Emscripten glue), arculator.wasm (the emulator), and arculator.data (a preloaded MEMFS image holding the RISC OS 3.11 ROM, the extension ROM and CMOS).

// Module is configured BEFORE the glue loads; the canvas MUST have id="canvas"
// for Emscripten SDL2. The preloaded arculator.data.js is loaded first, then the
// glue auto-runs main() -> arc_init() -> RISC OS boots on the default arc.cfg.
var Module = {
  canvas: document.getElementById('canvas'),
  onRuntimeInitialized: function () { publishEmuBoot(Module); }  // wire the debugger
};
Exported hookWhat it does
arc_pause_main_thread() / arc_resume_main_thread()Stock Arculator hooks: set/clear the flag the main loop checks once per frame.
arc_dbg_step(n)Run the ARM core for exactly n instructions (true single step), then stop.
arc_dbg_run_ms(ms)Advance one ~50 Hz frame (the debugger "step frame" control).
arc_key_set(scancode, down)Set/clear a host key (SDL scancode) for the on-screen keyboard.
arc_do_reset()Reset the machine.

The physical keyboard and mouse need no extra wiring: Emscripten's SDL2 port maintains SDL_GetKeyboardState from the browser's key events, and the mouse runs in RISC OS's absolute-pointer mode over the canvas.

Debugger integration

This is a Tier-4 "WASM core, full debugger" integration: Arculator keeps the ARM state inside the wasm module, so we rebuilt the core with tiny state-export hooks (a new emscripten_debug.c plus four one-line edits). The golden rule holds - the getters only sample state when the debugger asks (~10×/s and once per step); the per-instruction path pays one predictable branch (if (dbg_trap)), and only when a breakpoint, watchpoint or step is actually armed.

What the debugger needsHow the hook provides it
R0-R15 (r15 = PC + PSR on this 26-bit core)arc_dbg_get_reg(i) / arc_dbg_set_reg(i,v) read & write the core's uint32_t armregs[16] directly - fully writable.
Disassembly origin (current PC)arc_dbg_pc() = (PC-8)&0x3fffffc, matching Arculator's own debugger.
Memory (side-effect-free)arc_dbg_read(addr) wraps the core's readmemf_debug(), which reads RAM/ROM only and never touches an I/O latch.
Single steparc_dbg_step(n) runs the real ARM core for exactly n instructions - a true per-instruction advance, not a time-slice.
Execution breakpointsAn address set checked at the end of each instruction (only while armed); on a hit the main loop pauses.
Write watchpointsThe core's inline CPU store path (writememb/writememl in arc.h - the fast path RAM writes actually take) flags a hit when a watched word is written; the loop stops after that instruction.

Exactly what we changed. One new file src/emscripten_debug.c (the exports + the break/watch/step logic) and one header src/emu_dbg.h, plus four minimal edits guarded by #ifdef ARCWEB:

// src/arm.c  - end of the execarm() instruction loop
if (dbg_trap && dbg_post_execute()) { total_cycles = 0; break; }   // bp/wp/step halt

// src/arc.h  - the inline writememb()/writememl() CPU store path
if (dbg_trap) dbg_on_write(a);                                    // watchpoint check

// src/emscripten_main.c  - arcloop(), after arc_run()
if (arc_dbg_take_halt()) pause_main_thread = 1;               // pause on halt

// src/input_sdl2.c  - keyboard_poll_host(), so on-screen keys survive
key[c] = state[c] | vkey[c];                                   // OR in the overlay

What is real vs approximate. Registers, the PC+PSR word, memory, disassembly, play/pause, single-step, execution breakpoints and write watchpoints are all real and come from Arculator's own core. Register write-back covers the full r0-r15 file and the PSR flag bits. Memory is shown through the MEMC logical map (the addresses the ARM sees); I/O windows read back as 0xff rather than perturbing hardware.

Architecture

The Acorn Archimedes (1987) was the first desktop computer built around the ARM - Acorn's own 32-bit RISC processor. Arculator models the A305-A5000 family; the default here is an A3000: an Acorn ARM2 (ARMv2, a 26-bit machine where r15 holds both the program counter and the processor status), the MEMC1a memory controller, the VIDC video controller and the IOC I/O controller, with 4 MB of RAM, running RISC OS 3.11 from ROM.

  • arculator.wasm / arculator.js - Arculator 2.2 (Sarah Walker) compiled with Emscripten + our debug hooks.
  • arculator.data - preloaded MEMFS: roms/riscos311/ros311 (RISC OS 3.11, 2 MB), roms/arcrom_ext (extension ROM), and CMOS defaults.

How to rebuild from scratch (reproducible).

# toolchain: Homebrew emscripten 6.0.3 on PATH (/opt/homebrew/bin), python3, node
# 1. clone the Emscripten Arculator port (powers archi.medes.live)
git clone https://github.com/pdjstone/arculator-wasm.git && cd arculator-wasm
# 2. fetch the grey RISC OS ROMs from Sarah Walker's official distribution
curl -Ls https://b-em.bbcmicro.com/arculator/Arculator_V2.2_Linux.tar.gz | tar xz roms
# 3. add src/emscripten_debug.c + src/emu_dbg.h and the four #ifdef ARCWEB edits
#    (arm.c, mem.c, emscripten_main.c, input_sdl2.c); add emscripten_debug to OBJS.
# 4. modern-clang fixes: CFLAGS += -std=gnu17 -Wno-error; guard hostfs.c bool
#    typedef with #ifndef bool; point the file_packager rule at Homebrew's copy.
# 5. build the wasm target (FULL_FAT bundles ROMs + cmos into arculator.data):
make -j8 FULL_FAT=1 wasm
# artefacts: build/wasm/arculator.{js,wasm,data,data.js} -> emulator/archimedes/src/