Search › A-Z › K › Robotron KC85/3
Robotron KC85/3
The KC85/3 is an 8-bit home computer built by VEB Mikroelektronik Mühlhausen (Robotron) in East Germany, based on the U880, an unlicensed Zilog Z80 clone, running at 1.75 MHz. This emulator is floooh's header-only chips KC85/3 core compiled to WebAssembly, self-hosting the CAOS 3.1 operating system and HC-BASIC ROMs, so it boots straight to the CAOS menu with no downloads. Because the whole machine lives in one WebAssembly memory with small state-sampling hooks, its Z80 registers and memory can be inspected and single-stepped live in the shared debugger.
Runs on: Web browser
Robotron KC85/3 Online Emulator
Play Robotron KC85/3 using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| KC85/3 CAOS | Robotron KC85/3 | Robotron KC85/3 | grey | Open ⛶ |
Machines emulated
Chips
Notes
Embedding
The KC85/3 core is floooh's header-only chips emulator compiled to WebAssembly with Emscripten. One .wasm holds the Z80 (U880) CPU, the CTC/PIO, the video decoder and all RAM/ROM; a tiny .js loader (an Emscripten MODULARIZE factory) instantiates it. We self-host both files plus the two system ROMs, which are baked into the WASM at build time. There is no CDN and no external asset.
Boot. Instantiate the module, call our kc85dbg_init() (which runs kc85_init with the CAOS 3.1 + HC-BASIC ROMs), then own a requestAnimationFrame loop that advances the machine one 20 ms frame at a time and blits the decoded framebuffer to a canvas:
createKC85({ locateFile: function (p) { return SRC + p; } }).then(function (M) {
M._kc85dbg_init(); // kc85_init with the KC85/3 ROMs
var imgData = ctx.createImageData(320, 256);
(function frame() {
if (M._kc85dbg_exec(20000)) running = false; // run 20ms; stop if a breakpoint hit
paint(); // render() -> read HEAPU8 -> putImageData
if (running) requestAnimationFrame(frame);
})();
});
The screen is a palette-indexed framebuffer. The core renders into an internal 8 bits-per-pixel buffer; our kc85dbg_render() hook expands the visible 320×256 area through the KC85 palette into an RGBA buffer, and JS copies that straight out of the WASM heap into an ImageData - the byte order already matches what putImageData wants.
| Member | Kind | What it does |
|---|---|---|
M._kc85dbg_exec(us) | export | Run the machine for us microseconds. Returns 1 if a PC breakpoint was hit. The play loop's advance. |
M._kc85dbg_step_insn() | export | Advance exactly one Z80 instruction (ticks the core until the opcode boundary). The single-step primitive. |
M._kc85dbg_reg(i) / _kc85dbg_set_reg(i,v) | export | Sample / poke one Z80 register by index (PC SP AF BC DE HL IX IY IR, the shadow bank, IFF). |
M._kc85dbg_read(a) / _kc85dbg_write(a,v) | export | Side-effect-free read / write of the CPU-mapped 64 KB address space (banked RAM/ROM). |
M._kc85dbg_key_down(k) / _kc85dbg_key_up(k) | export | Feed a KC85 key code into the emulator's own keyboard matrix. |
The boot script wraps these exports in small helpers on window.EMU_BOOT (reg, setReg, rd, wr, pc, pressKey) plus a transport, so the debugger plug-in never has to know the machine is WASM.
Debugger integration
This is the point of the build: a compiled WASM core with the same live debugger as the JavaScript emulators. A stock chips WASM keeps its CPU state inside the module where JS cannot see it. Rather than add a callback to the per-cycle loop (which would tax the emulator even with the debugger closed), we rebuilt the core with a few sampling functions that copy state out only when called; the debugger calls them about ten times a second and once per Step.
What was changed in the source. One new translation unit, kc85_wasm.c, includes systems/kc85.h with CHIPS_IMPL (so the static core is in the same unit) and adds these EMSCRIPTEN_KEEPALIVE hooks - nothing in kc85.h itself was edited:
// registers: read the z80_t struct fields on demand
kc85dbg_reg(i) // PC/SP/AF/BC/DE/HL/IX/IY/IR, shadow AF'..HL', IFF1/2
kc85dbg_set_reg(i, v)
kc85dbg_pc()
// memory: side-effect-free, via the core's own banked mem_rd/mem_wr
kc85dbg_read(addr)
kc85dbg_write(addr, val)
// control
kc85dbg_step_insn() // tick the static _kc85_tick() until z80_opdone()
kc85dbg_exec(us) // run us; checks PC breakpoints only when some are armed
kc85dbg_bp_set(addr, on)
- Registers are read straight off the
z80_tstruct (cpu.pc,cpu.af,cpu.bc…cpu.af2,cpu.iff1) each refresh, and written back throughset_reg. The Z80 flag byte is unpacked to S Z H P/V N C. - Disassembly uses the shared
z80decoder, the U880 is a Z80 clone, so every opcode (including the DD/FD/ED/CB prefixes) renders correctly. - Memory is the full CPU-visible 64 KB read through the core's own
mem_rd, so the banked RAM, the IRM video RAM, HC-BASIC and the CAOS ROM all appear exactly as the CPU sees them, with no I/O side effects. - Single step is real:
kc85dbg_step_insnticks the core's static_kc85_tickuntilz80_opdone()- one true Z80 instruction, not a burst. - Breakpoints are a 64 KB PC-flag table checked at each instruction boundary inside
kc85dbg_exec, and only when at least one is armed, so a running machine with no breakpoints pays nothing. - Write watchpoints use the same zero-cost trick:
kc85dbg_execonly drops into instruction-by-instruction mode when a breakpoint or watchpoint is armed, and after each instruction it compares the watched bytes against a snapshot: a change means that instruction wrote the address, so it pauses. No memory-write hook sits on the hot path.
Play / pause are pure JavaScript: we own the frame loop, so pause just stops calling kc85dbg_exec and resume restarts it - the transport's isPaused() drives both the debugger's Run window and the shell's Play button.
Architecture
The KC85/3 (Robotron, Dresden, 1987) is an East-German 8-bit home computer built around the U880 - an unlicensed Zilog Z80 clone - running at 1.75 MHz with 16 KB RAM, 16 KB colour video RAM (the IRM), an 8 KB CAOS 3.1 operating system and an 8 KB HC-BASIC in ROM. Video, sound and keyboard hang off a Z80 CTC and Z80 PIO. It boots to the CAOS menu; typing BASIC enters the built-in interpreter.
kc85.wasm- the whole machine (U880 CPU core, CTC, PIO, beeper, video decoder, banked memory) compiled from floooh'schipsC to WebAssembly, with the debug sampling hooks linked in.kc85.js- the Emscripten loader/factory that instantiates the WASM and exposes the exported functions and heap views.- The two system ROMs - CAOS 3.1 (
caos31_853) and HC-BASIC (basic_c0_853), the KC85/3's original firmware - are baked into the WASM. They are East-German system software, freely redistributed among preservationists (grey); self-hosted, takedowns honoured.
How to rebuild. Clone github.com/floooh/chips (MIT) for chips/*.h + systems/kc85.h, and github.com/floooh/chips-test for examples/roms/kc85-roms.h (the ROM dumps). Put kc85_wasm.c (the wrapper with the hooks above) beside them and, with Homebrew Emscripten on PATH, build:
emcc kc85_wasm.c -I chips -O2 \
-sMODULARIZE=1 -sEXPORT_NAME=createKC85 -sENVIRONMENT=web \
-sALLOW_MEMORY_GROWTH=1 \
-sEXPORTED_RUNTIME_METHODS=ccall,cwrap,getValue,setValue,HEAPU8,HEAPU32 \
-sEXPORTED_FUNCTIONS=_kc85dbg_init,_kc85dbg_exec,_kc85dbg_step_insn,_kc85dbg_pc,\
_kc85dbg_reg,_kc85dbg_set_reg,_kc85dbg_read,_kc85dbg_write,_kc85dbg_bp_set,\
_kc85dbg_bp_clear,_kc85dbg_wp_set,_kc85dbg_wp_clear,_kc85dbg_key_down,\
_kc85dbg_key_up,_kc85dbg_disp_w,_kc85dbg_disp_h,_kc85dbg_fb_ptr,\
_kc85dbg_render,_malloc,_free \
-o kc85.js
The wrapper defines CHIPS_KC85_TYPE_3 before including kc85.h, so the same source can target the KC85/2 or /4. The two output files (kc85.js, kc85.wasm) are the only artefacts vendored here.