Search › A-Z › D › Donkey Kong
Donkey Kong
Donkey Kong (Nintendo, 1981), designed by Shigeru Miyamoto, is the platform game that introduced Mario (as “Jumpman”) and gave the golden age of arcades one of its defining machines. This build runs the original Zilog Z80 board in the browser, the real program ROMs on a JavaScript Z80 core plus a hand-written model of Nintendo’s tile-and-sprite video hardware, and boots straight into the attract-mode demo. It is wired to the emulators.org in-frame debugger so you can single-step the Z80, read and write the registers and the full 64K memory (tile RAM sits at 0x7400, sprite RAM at 0x7000), and set execution breakpoints and write watchpoints.
Runs on: Web browser
Donkey Kong Online Emulator
Play Donkey Kong using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| Donkey Kong | Donkey Kong | Donkey Kong | grey | Open ⛶ |
Machine emulated
The Donkey Kong arcade board (Nintendo, 1981) - a Zilog Z80 at 3.072 MHz with 16 KB of program ROM and 4 KB of work/video RAM, a 32×32 background tilemap, 16×16 hardware sprites and colour-PROM palettes, driving a 256×224 raster rotated 90° in the upright cabinet. An i8035 handles sound on the real machine.
Chips
Notes
Embedding
Donkey Kong is Nintendo's 1981 arcade machine: a Zilog Z80 at 3.072 MHz driving a 256×224 raster, rotated 90° in the upright cabinet. This build runs the original program ROMs on DrGoldfire/Z80.js (MIT), an instruction-at-a-time Z80 interpreter, wrapped in a hand-written model of the Donkey Kong board (memory map, tile/sprite video and input latches). The graphics-ROM decode, colour-PROM palette and renderer are ported from the galagino project.
Boot. The four 4 KB program ROMs are loaded into 0x0000–0x3FFF and the Z80 starts at 0x0000, dropping straight into the attract-mode demo:
var dk = new DKong(); // decodes gfx ROMs + PROMs, wires the Z80
dk.reset(); // PC = 0x0000 -> attract mode
The machine object. DKong exposes the whole cabinet as ordinary methods, so the host page can render, step and inject input:
| Member | Kind | What it does |
|---|---|---|
stepInsn() | method | Fetch, decode and run one Z80 instruction; returns its T-cycle count. |
frameInterrupt() | method | Pulse the vertical-blank NMI (gated by the 0x7D84 mask latch the game writes) once per field. |
render(buf32) | method | Paint the 224×256 frame: the 28×32 background tilemap plus up to 96 hardware sprites, DMA-copied from 0x6900 to 0x7000. |
peek(a) / poke(a,v) | method | Side-effect-free access to the address space — what the debugger's memory views read and poke. |
setInput(id,down) | method | Drive the joystick / jump / coin / start latches read on ports 0x7C00 and 0x7D00. |
reset() | method | Clear RAM and reset the Z80 — the cabinet's power-cycle. |
Video. Each animation frame the loop runs one field's worth of Z80 cycles, pulses the NMI, then re-renders: the background is a 32×32 tilemap of 8×8 characters (video RAM at 0x7400), and the sprites are 16×16, four bytes each, taken from the block the game DMA-copies to 0x7000. Colours come from the two palette PROMs and the character/sprite colour-map PROM, banked by the 0x7D86/0x7D87 latches.
Debugger integration
The debugger drives a host-owned run loop: because the Z80 interpreter runs one instruction at a time in JavaScript, the loop can pause, single-step and check breakpoints between any two instructions — no changes to the CPU core are needed.
window.EMU_BOOT.transport exposes the controls the shared debugger calls:
- pause / resume / isPaused — stop or restart the
requestAnimationFrameloop. - stepInsn(n) — call the core's
stepInsn()exactly n times and redraw, so a single step advances the PC by one Z80 instruction. - step(n) — advance n whole 60 Hz fields (each with its NMI).
- breakpoints — a
Setof PC values. When it is non-empty the loop reads the Z80's PC (viagetState()) before each instruction and pauses before executing an address in the set; when empty it runs a full field at speed, so an idle debugger costs nothing. - watchpoints — the Z80 core's memory-write callback is wrapped, so a write to a watched RAM address sets a flag that pauses the loop after that instruction.
The plug-in (donkeykong-debug.js) reads these hooks and calls EmuKit.defineMachine with the full Z80 register file (AF/BC/DE/HL and their bytes, the alternate set via IX/IY, SP, PC, I, R and the S Z H P/V N C flags), each read live from getState() and written back through setState(). It reuses the shared z80 disassembler (/debugger/src/cpus/z80.js) for the hex/disasm views over the 64 KB bus, the 16 KB program ROM, the tile RAM (rendered as tiles) and the sprite RAM.
Architecture
The Donkey Kong board is a single Zilog Z80 at 3.072 MHz with 16 KB of program ROM, 4 KB of work/video RAM and Nintendo's tile-and-sprite video, all modelled here as plain JavaScript hanging off DKong:
- CPU — a Z80 interpreter.
0x0000–0x3FFFis program ROM;0x6000–0x6FFFand0x7000–0x77FFare RAM (work RAM, sprite RAM at0x6900, tile RAM at0x7400). - Video — a 32×32 background tilemap of 8×8 2bpp characters, plus 16×16 sprites with per-object X/Y flip. Two 256-byte palette PROMs give the 8-bit-per-channel colours and a third PROM maps tile/sprite pixels to palette groups; a two-bit bank (
0x7D86/0x7D87) selects one of four colour tables. - DMA — writing
0x7D85copies 384 bytes of sprite attributes from0x6900to0x7000, exactly as the board's DMA does each field. - Input — the player-one joystick and jump button are read on
0x7C00; coin and start on0x7D00; the DIP switches on0x7D80. - Interrupt — a single NMI per field at vertical blank, gated by the
0x7D84mask latch, is the only timing the game depends on. - Sound — a full Intel i8035 (MCS-48) sound CPU is emulated from scratch and runs the original sound program and waveform ROMs, driving its DAC to real PCM (see the Sound note). The main CPU talks to it through the
0x7C00command latch, the0x7D00–0x7D07"6H" latch and the0x7D80sound interrupt.
Sound
Pattern: the real sound hardware. Donkey Kong's audio board is an Intel i8035 (MCS-48) sound CPU running its own program ROM, reading a digitised waveform/tune ROM and driving an 8-bit DAC. This build emulates that CPU for real: i8035.js is a from-scratch MCS-48 core (accumulator, PSW with the two register banks in the 64-byte internal RAM, the prescaled timer, the external and timer interrupts, the BUS/P1/P2/T0/T1 pins and the SEL MB program-bank bit) whose opcode dispatch mirrors MAME's s_mcs48_opcodes table one-for-one, including per-instruction machine-cycle counts. It executes the original sound ROMs, so the intro “How high can you get?” climb, the hammer theme, the running background music, the death spiral and the coin/point jingles are the sound program's own samples — not a synthesiser.
The ROMs. Two sound ROMs are vendored, both byte-verified against MAME's ROM_START( dkong ): s_3i_b.bin (2 KB, CRC32 45a4ed06, SHA1 144d24464c1f9f01894eb12f846952290e6e32ef) is the i8035 program, mirrored across the 4 KB program space; s_3j_b.bin (2 KB, CRC32 4743fe92, SHA1 6c82b57637c0212a580591397e6a5a1718f19fd2) is the waveform/tune ROM.
Board wiring (from MAME nintendo/dkong_a.cpp). dkong.js's setSoundHook forwards the main-CPU sound latches to donkeykong-sound.js: 0x7C00 is the LS175 command latch (low nibble, inverted); 0x7D00–0x7D07 is the LS259 “6H” latch, whose bit 5 → i8035 T0, bit 4 → T1 and bit 3 → P2.5 drive the CPU while bits 0/1/2 drive the discrete Walk/Jump/Stomp circuits; 0x7D80 is the sound interrupt. The i8035 reads the command latch or the waveform ROM through its BUS/MOVX port — page = P2 & 0x47; if bit 6 is set it reads the command, otherwise s_3j[(page & 7) × 256 + offset] with P2 bits 0–2 selecting the 256-byte bank — and writes each output byte to the DAC on P1.
Timing & mixing. The i8035 runs at its real 6 MHz / 15 = 400 kHz machine-cycle rate; each video field the core is advanced one field's worth of cycles and the held DAC value is sampled at EmuAudio.sampleRate (zero-order hold, DC-blocked to emulate the AC-coupled DAC-08/discharge output stage), then exactly Math.round(EmuAudio.sampleRate/60) interleaved-stereo Int16 pairs are pushed to the shared sink per field. Attract mode issues no sound commands, so it is quiet; insert a coin and press 1P-Start and the real sound program plays.
Mute contract. window.EMU_BOOT.transport exposes isMuted()/setMute(m), delegated to EmuAudio; audio starts muted (browsers block audio before a gesture) and the shell's Sound button resumes the AudioContext and unmutes from a real click.
Discrete Walk / Jump / Stomp. The three effects on 6H bits 0/1/2 have no ROM behind them; they are the analog network on the board, now synthesised from MAME's netlist (nintendo/dkong_a.cpp, dkong2b_discrete) with every frequency and time-constant derived from the real component values: the Walk is an NE555 astable VCO (R 47k/27k, C 33n → 432 Hz) warbled by a 4049 inverter-oscillator LFO; the Jump is an NE555 VCO (47 nF → 303 Hz) swept up by the R38/C26 charge into a rising whoop; the Stomp is the 2VF (4 kHz) LFSR noise divided by the LS161 mod-8 counter, enveloped and low-passed by R5/C19 (212 Hz) into a thud.
Honest limitation. Everything that flows through the i8035 DAC is the real sound program running the real ROM. The Walk/Jump/Stomp voices are a netlist-derived DSP model (component values → oscillator frequencies, RC time-constants → envelopes and filters) rather than a full nodal solve of the op-amp/transistor network; the audible character follows the real topology.