SearchA-ZF › FM-7

FM-7

2026 Open source Online

FM-7 is a compact emulator built here in JavaScript around a genuine Motorola 6809 core, running Fujitsu's 1982 home computer in the browser so it boots straight to the F-BASIC 3.0 "Ready" prompt with no downloads. The FM-7 is a dual-6809 design, so this build runs two copies of the core: a main 6809 for F-BASIC and the boot ROM, and a sub 6809 for the subsystem monitor that owns the 48 KB of video RAM and the keyboard. Every register, chip and byte of memory on both processors is a plain JavaScript object, so the whole machine can be paused, single-stepped and inspected live in the shared debugger.

Runs on: Web browser

FM-7 Online Emulator

Play FM-7 using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
F-BASICFM-7Fujitsu FM-7greyOpen ⛶

Machines emulated

Chips

Notes

Embedding

There is no ready-made pure-JavaScript FM-7, so this build reuses the proven JavaScript Motorola 6809 core from JSVecX (e6809.js, a port of Valavan Manohararajah's e6809.c) and wraps the whole FM-7 around it. The FM-7 is a dual-6809 machine, so we run two copies of the core: a MAIN 6809 that runs F-BASIC and the boot ROM, and a SUB 6809 that runs the subsystem monitor ROM — the SUB owns all 48 KB of video RAM, draws the 8×8 ANK font in software and scans the keyboard.

Boot. Give each 6809 its own bus object with read8 / write8, map the ROMs, reset both, and drive them from an interleaved loop you own — one main instruction, then enough sub instructions to keep pace — so neither core hides a run loop from the debugger:

var main = new e6809(); main.init(mainBus);   // F-BASIC + boot ROM
var sub  = new e6809(); sub.init(subBus);    // subsystem monitor ROM
main.e6809_reset(); sub.e6809_reset();
(function field(){
  for (var c = 0; c < 33600; ) {          // ~2 MHz / 60 Hz
    c += main.e6809_sstep(mainIRQ(), mainFIRQ(), 0);
    if (!subHalt) sub.e6809_sstep(subIRQ(), subFIRQ(), subNMI());
  }
  render(); requestAnimationFrame(field);
})();

The whole machine is plain objects. Everything the debugger needs is a field or method on the two e6809 instances or on window.EMU_BOOT — there is no wasm heap:

MemberKindWhat it does
mainCpu.e6809_sstep(irq, firq, nmi)methodExecute exactly one 6809 instruction with the current interrupt lines; returns its cycle count. The single-step primitive (a third nmi argument was added for the sub's display timer).
mainCpu.reg_a / reg_b / reg_dp / reg_cc / reg_pcfieldThe 8- and 16-bit registers as numbers; reg_x/y/u/s are boxed (.value).
EMU_BOOT.mainRead(a) / subRead(a)methodSide-effect-free reads of either CPU's 64K bus (used by the debugger's memory views).
EMU_BOOT.vram (48K) / shared (128B) / mainRAM (32K)fieldRaw byte arrays — the three video planes, the main/sub shared block and user RAM.
EMU_BOOT.pressKey(code)methodInject one FM-7 keyboard code (drives the same latch the physical keyboard does).

Because both CPUs, both buses and all RAM are ordinary JavaScript, the debugger single-steps the main 6809, reads and writes its registers directly, and implements breakpoints and watchpoints as host-side checks around the loop — no changes to the reused core beyond the added NMI entry.

Debugger integration

The plug-in (fm7-debug.js) reads the live machine from window.EMU_BOOT and hands the shared framework a description of the FM-7. Nothing is patched into the emulator; the whole surface is ordinary field access.

  • Registers are the MAIN 6809's — A B D X Y U S DP PC CC plus the E F H I N Z V C condition flags decoded from reg_cc — read each refresh and written back the same way. Single-step and watch them change.
  • Memory is four chips: a side-effect-free MAIN CPU bus, the 32K user RAM, a side-effect-free SUB CPU bus and the 48K VRAM. Reads run with I/O side effects suppressed (so an auto-refreshing view never clears an interrupt flag or flips the CRT-enable strobe). Disassembly uses the shared m6809 decoder.
  • Single step is mainCpu.e6809_sstep — one MAIN 6809 instruction, with the SUB 6809 advanced in lockstep so the shared-RAM handshake stays coherent.
  • Breakpoints are host-side: with any set, the loop compares mainCpu.reg_pc before each instruction. Watchpoints wrap both CPUs' bus-write paths and pause on a write to a watched address.
  • Input is the real FM-7 encoder: the physical keyboard maps each character to its FM-7 code, and an on-screen FM-7 keyboard drives the same codes for touch.

Architecture

The FM-7 is a dual-6809 machine, and this build keeps each block as its own object:

  • Two e6809 cores — a MAIN 6809 (F-BASIC + boot ROM) and a SUB 6809 (subsystem monitor ROM), run by one interleaved host loop and single-stepped by e6809_sstep.
  • Main bus — 32K RAM at $0000, the F-BASIC 3.0 ROM at $8000 (switchable to RAM via $FD0F), the shared-RAM window at $FC80, the $FD00 I/O page and the boot ROM at $FE00.
  • Sub bus — 48K VRAM at $0000 (blue/green/red planes, 16K each), console and work RAM, the shared RAM at $D380, the display and keyboard ports at $D400, and the subsystem monitor ROM at $D800.
  • The handshake — the main CPU halts the sub through $FD05 to take the shared-RAM bus, drops a graphics command in, releases the sub and polls a busy flag ($D40A) until it is done. The sub raises an "attention" FIRQ on the main by reading $D404; the main's 2 ms timer and the sub's 20 ms display NMI keep both sides ticking.
  • Video — the sub software-renders the 8×8 ANK font into VRAM; the three planes are combined into a 640×200, eight-colour picture and drawn to the canvas. With no cassette or disk, F-BASIC sizes memory, prints its banner and drops to Ready — a complete, inspectable machine that boots straight to BASIC.

Sound

This is a synthesis (Pattern S) integration: the reused 6809 core is CPU-only, so the FM-7's sound hardware is modelled from scratch and driven by the program's own writes to the sound ports the MAIN 6809 decodes. The base FM-7 has two sound sources, both on the main I/O page, and both are emulated:

  • AY-3-8910 PSG — the machine's three-voice programmable sound generator, used by F-BASIC's PLAY and SOUND. It is addressed with the standard General-Instrument BDIR/BC1 bus protocol: a write to $FD0D sets the bus mode (3 = latch register address, 2 = write data) and $FD0E is the data latch. Those writes are routed straight into a faithful, self-authored AY-3-8910 (fm7-ay.js, the same chip first written for Time Pilot): three square-wave tone channels (f = clock / (16 · period)), a 17-bit-LFSR noise generator, a 16-step hardware envelope and the 4-bit logarithmic volume DAC.
  • Buzzer — the single-bit beeper gated by a write to $FD03 (used by BEEP), rendered as a fixed ~1200 Hz square while enabled.

Sample rate / pitch. The PSG is clocked at the FM-7's 1.2288 MHz and the chip renders directly at EmuAudio.sampleRate (it advances its internal generators by (clock/8)/sampleRate ticks per output sample and averages), so pitch is exact with no separate resampling stage. Each video frame the run loop asks the chip for exactly Math.round(EmuAudio.sampleRate / 60) mono samples, mixes in the buzzer, duplicates the result to left and right and pushes one round(sampleRate/60)-pair interleaved-stereo Int16 frame to the shared sink via EmuAudio.push.

Mute contract. window.EMU_BOOT.transport.isMuted() / setMute(m) delegate to EmuAudio. It starts muted (browsers block audio before a user gesture); the shared Sound button resumes the context and unmutes from a real click. Sound plays whenever the software makes it: type an F-BASIC PLAY, SOUND or BEEP and it comes straight out of the PSG and buzzer.