Sord M5
The Sord M5 (1982) was one of the smallest Japanese home computers: a Zilog Z80A, a Texas Instruments TMS9918A video chip and an SN76489A sound chip, coordinated by a Zilog Z80 CTC, with just 4 KB of work RAM. Its BASIC came on a cartridge; the 8 KB internal ROM is only a monitor.
This is a purpose-built pure-JavaScript machine - the MIT-licensed DrGoldfire Z80 interpreter paired with a TMS9918A VDP and machine glue written for emulators.org - so the whole Z80 is single-steppable, register-editable and breakpointable in the shared in-page debugger. It boots directly to the BASIC-I "Ready" prompt with the grey system ROMs self-hosted.
Runs on: Web browser
Sord M5 Online Emulator
Play Sord M5 using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| M5 BASIC-I | Sord M5 | Sord M5 | grey | Open ⛶ | |
| M5 Monitor (no cartridge) | Sord M5 | Sord M5 | grey | Open ⛶ |
Chips
Notes
Embedding
The Sord M5 (1982) is a small Japanese Z80 home computer: a Zilog Z80A, a Texas Instruments TMS9918A VDP and an SN76489A PSG, coordinated by a Zilog Z80 CTC, with just 4 KB of work RAM and 16 KB of VRAM. Its BASIC is not built in — the 8 KB internal ROM is only a monitor/IPL, and BASIC comes on a cartridge. There was no established pure-JavaScript M5 core with an inspectable CPU, so we assembled one from three small, self-hosted parts:
Z80.js— Molly Howell's MIT-licensed Z80 interpreter. Constructed with a core object of four callbacks (mem_read,mem_write,io_read,io_write); it exposesgetState(),setState(),reset(),run_instruction()andinterrupt().tms9918.js— a TMS9918A VDP we wrote (shared with the SG-1000 / ColecoVision builds): 16 KB VRAM, the eight write-only registers and the read status register, the two-byte control-port protocol, all four background modes and the sprite engine. It renders a whole 256×192 frame into an RGBA buffer.m5.js— the machine: the M5 memory map (monitor ROM at 0x0000, cartridge at 0x2000, 4 KB RAM at 0x7000), the I/O ports (CTC at 0x00, VDP at 0x10/0x11, PSG at 0x20, keyboard rows at 0x30–0x37) and a minimal Z80 CTC that turns the VDP vertical-blank into the vectored frame interrupt the keyboard-scan service routine runs on.
var machine = new SordM5Machine({ rom: monitorBytes, cart: basicBytes });
(function loop(){
machine.runFrameFast(); // one frame of Z80 + VDP + CTC interrupt
machine.render(img.data); ctx.putImageData(img, 0, 0);
requestAnimationFrame(loop);
})();
The machine is plain objects. Everything the debugger needs is reachable:
| Member | Kind | What it does |
|---|---|---|
machine.cpu.run_instruction() | method | Fetch and execute exactly one Z80 instruction; returns the T-cycle count. The single-step primitive. |
machine.cpu.getState() / setState() | method | Read / write the entire Z80 state as a plain object (pc, sp, a, b, c, d, e, h, l, ix, iy, i, r, flags{…}, plus the shadow set). How the debugger reads and pokes registers. |
machine.runFrameFast() / runFrameStep(bps) | method | Run a whole frame at speed, or step it instruction-by-instruction halting on an execution-breakpoint Set. |
machine.readMem(a) / writeMem(a,v) | method | Read/write the 64K Z80 address space. I/O is port-mapped, so a memory read is side-effect-free — safe for the auto-polling hex view. |
machine.vdp.vram / .reg / .status | field | The TMS9918A's 16 KB VRAM, eight registers and status flags. |
machine.keyDown(pos) / keyUp(pos) | method | Drive the active-high key matrix (pos = row*8 + bit, rows Y0–Y6 read at ports 0x30–0x36). |
Debugger integration
The debugger plug-in (sordm5-debug.js) reads the live machine from window.EMU_BOOT and calls EmuKit.defineMachine. The Z80 is disassembled by the shared z80 decoder (/debugger/src/cpus/z80.js) — no new decoder was needed.
Owning the loop. The boot shim owns the frame loop, so pause, resume and frame-step are ours directly. With no breakpoints set we run machine.runFrameFast(); with any set we run machine.runFrameStep(bps), which checks the program counter before every instruction and halts the moment it hits a breakpoint. Single-step calls cpu.run_instruction() once. Write watchpoints wrap machine.writeMem and pause when a watched address is written.
The frame interrupt. Unlike the SG-1000, the M5's VDP interrupt line does not reach the Z80 directly — it is wired to trigger channel 3 of the Z80 CTC, which (as an IM 2 daisy-chain device) supplies the interrupt vector. We carry a small CTC in m5.js: it captures the vector word the monitor programs, counts the vertical-blank triggers on channel 3 and, when the channel underflows with interrupts enabled, raises a maskable interrupt with vector (vectorBase | 6). That is the interrupt the monitor's keyboard-scan and cursor-blink routine runs on, so typing and the blinking cursor work.
Registers. The Z80 state comes straight from cpu.getState(); the plug-in presents the 16-bit pairs AF BC DE HL IX IY SP PC and decodes the flag byte (S Z H P/V N C) into individual, writable flag chips, writing back through setState(). Memory is exposed as five chips: the 64K Z80 bus, the monitor ROM, the cartridge ROM, the 4K work RAM and the 16K VDP VRAM.
Architecture
The Sord M5 (1982) was one of the smallest Japanese home computers, sold by Sord and — as the "Sord M5" / "Takara Game Personal Computer" — popular in Japan and, via CGL and Comidor, in Britain and Czechoslovakia. It shares the SG-1000 / MSX video and sound silicon:
Z80A— the CPU, clocked at about 3.58 MHz (10.73863 MHz / 3). The 8 KB monitor ROM sits at 0x0000, the cartridge at 0x2000, and the 4 KB work RAM at 0x7000.TMS9918A— the video chip: 256×192, 16 fixed colours, a sprite table and the Graphics I / Graphics II / Multicolor / Text modes. Its vertical-blank drives the CTC.SN76489A— the PSG (three squares + noise); silent here for headless use.Z80 CTC— the counter/timer that vectors the frame interrupt used for keyboard scanning and timing.- The keyboard is a matrix of seven rows (Y0–Y6) read active-high at ports 0x30–0x36, plus a joystick row at 0x37.
Because the whole machine is ordinary JavaScript objects and the CPU is a straight interpreter, the entire state is inspectable and pokeable at runtime — an ideal debugging target.