SearchA-ZS › SG-1000

SG-1000

2026 Open source · MIT Online

The Sega SG-1000 (1983) was Sega's first cartridge console: a Zilog Z80, a Texas Instruments TMS9918A video chip and an SN76489 sound chip, with the cartridge mapped straight in from address 0.

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 from the cartridge; the SG-1000 needs no BIOS.

Visit the project ↗

Visit the official site ↗

Runs on: Web browser

SG-1000 Online Emulator

Play SG-1000 using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
Colour Block demoSG-1000sg-1000openOpen ⛶

Chips

Notes

Embedding

The SG-1000 is one of the simplest cartridge consoles: a Zilog Z80 CPU, a Texas Instruments TMS9918A video chip and an SN76489 sound chip, with 1–8 KB of work RAM and the cartridge mapped straight in from address 0. There was no established pure-JavaScript SG-1000 core with an inspectable CPU, so we built 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 exposes getState(), setState(), reset(), run_instruction() and interrupt().
  • tms9918.js - a TMS9918A VDP we wrote: 16 KB VRAM, the eight write-only registers and the read status register, the two-byte control-port protocol, all four background modes (Graphics I, Graphics II, Multicolor, Text) and the sprite engine. It renders a whole 256×192 frame into an RGBA buffer.
  • sega8.js - the machine: the SG-1000 memory map (cartridge at 0x0000, RAM at 0xC000), the I/O ports (VDP at 0xBE/0xBF, controller at 0xDC), the SN76489 (silent here) and a frame loop that raises the VDP vertical-blank interrupt.
var machine = new Sega8Machine({ kind: 'sg1000', rom: cartBytes });
(function loop(){
  machine.runFrameFast();          // one frame of Z80 + VDP + interrupt
  machine.render(img.data); ctx.putImageData(img, 0, 0);
  requestAnimationFrame(loop);
})();

The machine is plain objects. Everything the debugger needs is reachable:

MemberKindWhat it does
machine.cpu.run_instruction()methodFetch and execute exactly one Z80 instruction; returns the T-cycle count. The single-step primitive.
machine.cpu.getState() / setState()methodRead / 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)methodRun a whole frame at speed, or step it instruction-by-instruction halting on an execution-breakpoint Set.
machine.readMem(a) / writeMem(a,v)methodRead/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 / .statusfieldThe TMS9918A's 16 KB VRAM, eight registers and status flags.
machine.press(id) / release(id)methodDrive the joystick latch (active-low) that the game reads at port 0xDC.

Debugger integration

The debugger plug-in (sg1000-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).

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.

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().

Architecture

The SG-1000 (1983) was Sega's first cartridge console and the direct ancestor of the Master System. The machine is small:

  • Z80 - the CPU, clocked at 3.58 MHz. The cartridge is mapped from address 0; work RAM sits at 0xC000.
  • TMS9918A - the video chip: 256×192, 16 fixed colours, a 32-entry sprite table, and the Graphics I / Graphics II / Multicolor / Text modes. Its vertical-blank drives the Z80's maskable interrupt.
  • SN76489 - the PSG (three squares + noise); silent here for headless use.
  • Controllers are read as an active-low byte at port 0xDC (bit 0 up, 1 down, 2 left, 3 right, 4/5 the two buttons).

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.