Search › A-Z › A › Atari ST (EstyJS)
Atari ST (EstyJS)
This is the in-browser Atari 1040ST, powered by EstyJS - a pure-JavaScript Atari ST emulator by Darren Coles and Kai Eckert whose CPU is a from-source JavaScript Motorola 68000 core. It renders the ST's Shifter video straight to an HTML5 canvas and boots on the open-source EmuTOS replacement ROM, so it reaches the colour GEM desktop with no proprietary Atari firmware and no downloads.
Because the whole machine is ordinary JavaScript, it plugs into the shared in-browser debugger: live Motorola 68000 registers (D0-D7, A0-A7, PC, SR), side-effect-free memory, a real single-instruction step, one-frame step and pause/resume. Type on the physical keyboard or the on-screen ST keyboard, and drive the GEM pointer with the mouse.
Runs on: Web browser
Atari ST (EstyJS) Online Emulator
Play Atari ST (EstyJS) using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| Atari 1040ST (EmuTOS) | Atari ST (EstyJS) | Atari 1040ST | open | Open ⛶ |
Machines
Operating systems
Chips
Notes
Embedding
EstyJS is a set of plain-global JavaScript modules (no bundler). Vendor src/estyjs/*.js, load them in EstyJS's dependency order, then construct the machine on a <canvas> that already exists in the page. Construction starts the run loop and fetches the EmuTOS ROM by itself:
var estyjs = EstyJs('screen'); // the canvas id; grabs its 2D context + key/mouse
window.estyjs = estyjs; // the core references a global 'estyjs' on TOS change
estyjs.setRowSkip(false); // draw every scanline (no fake scanline gaps)
estyjs.setMonoMonitor(false); // colour monitor -> boots to the colour GEM desktop
The machine is plain globals. Because EstyJS is ordinary JavaScript, every part of the ST is reachable through the handles the core exposes, no wasm heap to reach into:
| Member | Kind | What it does |
|---|---|---|
estyjs.getProcessor() | handle | The 68000 core. Its dbgRegs() returns the live register file (d[8], a[8], pc, the CCR booleans x n z v c, the supervisor bit s, intmask, usp, isp). |
getProcessor().stepOne() | method | Run exactly one 68000 instruction (added). Our single-instruction step. |
estyjs.getMemory() | handle | The 24-bit bus: readByte/writeByte over RAM at $000000, EmuTOS at $E00000, and the hardware registers at $FF0000. |
estyjs.dbgStepFrame() | method | Run one whole video frame while paused (added). Our frame-step. |
estyjs.dbgPause() / dbgResume() | method | Stop / start the self-scheduling run loop deterministically. Our pause / resume. |
estyjs.getKeyboard() | handle | The IKBD. pressCode(kc) / releaseCode(kc) feed a browser keyCode through the ST keymap, the on-screen keyboard path. |
The boot script publishes these to the debugger as window.EMU_BOOT (register accessors, a side-effect-free read8/write8, the keyboard injectors, and a transport). Rendering is the core's own: display.processRow() blits straight to the 2D canvas each scanline.
Debugger integration
EstyJS is a pure-JavaScript emulator, so it plugs into the shared debugger the same way the other JS machines do, but its run loop and register file are private closures, so a handful of additive accessors were appended to the vendored core to expose them. No emulation hot path was changed.
1 · Exactly what was changed (the only source edits). Four files, all additive:
// processor.js: sampling + control over the closure-local 'regs' + run body
self.dbgRegs = function(){ return regs; }; // live D0-D7/A0-A7/pc/flags
self.dbgGetSR = function(){ return getSR(); };
self.dbgSetPC = function(v){ setPC(v); }; // setPC refills the prefetch
self.stepOne = function(){ /* one iteration of runCode()'s inner loop */
var op = prefetch1; prefetch1 = prefetch2; fault.pc = regs.pc;
regs.pc += 2; prefetch2 = memory.readWord(regs.pc + 2);
var cycles = iTab[op].f(iTab[op].p); tot_cycles += cycles[0]; };
// estyjs.js, factor one frame out of runframe(), add loop control
self.dbgStepFrame = function(){ if (memory.loaded==1) doFrame(); };
self.dbgPause = function(){ running = false; };
// keyboard.js, on-screen keyboard injection through the real keymap
self.pressCode = function(kc){ registerKeyDown(kc); };
2 · What is REAL here. Because the 68000 core is JavaScript with a genuine per-instruction dispatch, this integration has:
- Real live registers - D0-D7, A0-A7, PC, SR (with X N Z V C S flags) and USP/SSP, read straight off the register file each refresh and written back live (the S toggle swaps the active stack pointer, via
setSR). - Real single-instruction step -
Step icalls the CPU'sstepOne(), which executes exactly one 68000 instruction (the same fetch/execute body the free-running loop uses). PC and registers advance by one instruction per click. - Real one-frame step -
Stepruns one whole video frame (dbgStepFrame), the full scanline-interleaved CPU + display + MFP + FDC + sound path. - Side-effect-free memory - the hex/disasm reader skips the $FF0000 hardware window and the illegal $F00040–$F9FFFF region, so auto-polling a view never touches a hardware register or triggers a bus fault.
3 · What is surfaced but not enforced. Execution breakpoints and watchpoints appear in the UI but are not honoured by the dispatch loop. EstyJS runs a whole scanline of instructions inside processor.runCode() with no external per-instruction hook, and the project's performance rule forbids adding a PC check to that hot path just to get breakpoints. Registers, memory, disassembly, instruction-step, frame-step, pause/resume and reset are all real.
4 · Keyboard. EstyJS ships its own physical-keyboard handling (a document key listener that maps keyCode to the ST key matrix); it is enabled as-is, and guarded so typing in a debugger field does not reach the ST. The on-screen keyboard reuses the exact same keymap by calling keyboard.pressCode(keyCode), so the two input paths are identical.
Architecture
EstyJS emulates an Atari 1040ST (68000, 1 MB) entirely in JavaScript. Each part of the machine is its own module hung off the emulator instance:
processor.js- the Motorola 68000 interpreter, a from-source port of the SAE / WinUAE / UAE core: a generated opcode-function table, a prefetch pair, and theregsregister file.runCode()runs a scanline's worth of cycles; the addedstepOne()runs a single instruction.memory.js- the 24-bit address map: 1 MB RAM at $000000, the EmuTOS system ROM mirrored at $E00000 and $FC0000, the cartridge window, and the $FF0000 hardware registers dispatched toio.js.display.js- the Shifter: it reads ST screen RAM each scanline and blits the low/medium/high-res picture to the 2D canvas.mfp.js- the MC68901 Multi-Function Peripheral: timers and interrupts that drive the 200 Hz system clock and much of the ST's timing.keyboard.js- the IKBD (keyboard, mouse and joystick), producing the ACIA byte stream the ST polls.fdc.js/sound.js- the WD1772 floppy controller (ST/MSA images) and the YM2149 three-voice sound chip.
Boot ROM. The default firmware is EmuTOS 1.3 (256K, US English) - the open-source (GPL-2.0) TOS/GEM replacement - so the whole stack is redistributable with no proprietary Atari TOS. With that ROM and no floppy, the ST boots straight to the colour GEM desktop.
How to rebuild this artefact. There is no compile step; EstyJS is plain JavaScript. Vendoring recipe:
# 1. fetch the core
git clone https://github.com/kaiec/EstyJS.git
cp EstyJS/estyjs/*.js emulator/atari-st/src/estyjs/
cp EstyJS/etos256us.img emulator/atari-st/src/roms/
# 2. apply the four additive edits above (processor.js, estyjs.js, keyboard.js)
# and point memory.js's ROM loader at src/roms/etos256us.img (absolute path).
The only edits are the additive debug API and the ROM path; nothing in the emulation core's behaviour changes.