User Tools

Site Tools



Zeta is an 8086 emulator dedicated for running ZZT and Super ZZT written by Adrian “asie” Siekierka from 2018 onward. It was initially developed for the purpose of providing a lightweight, small HTML5-friendly emulator for the Museum of ZZT, but over time gained an additional purpose of working around some of ZZT's quirks. It is available, with source code, under the terms of the MIT license.


Idle detection

ZZT, being a 1991-era DOS program, generally runs at 100% CPU time, without means of yielding control to the operating system. This would be unfavorable in a modern environment (laptop, web browser, etc.) As such, Zeta uses the following calls for idle detection:

  • A call of INT 16h AH=0x01 (check for keystroke) to detect the execution of InputUpdate, as done once per player tick and/or once per window tick.
  • A call of INT 21h AH=0x25 (systime) to detect the execution of SoundHasTimeElapsed.

Obviously, these are tailored for ZZT/Super ZZT's code logic, and may cause erratic delays in forks (or with a very high number of player clones). Currently, the interrupt 0xA5 extensions may be used to disable idle hacks and yield control to the operating system on Zeta.

Audio handling

Zeta does the following hacks in audio-related logic:

  • Remove any sound played for a duration lower than 32 instructions - this removes the player movement tick, which lasts 30 instructions.
  • Assume any sound played within the same PIT tick without being disabled prior takes exactly 1 millisecond - this is in line with the behaviour of ZZT drums on old DOS machines; newer DOS machines play drums too quickly due to a deficiency in Turbo Pascal pre-7.0's Delay() function implementation. (Other short sounds in ZZT are rapidly disabled.)
  • Insert short pauses between two identical notes - this is to provide expected #PLAY behaviour for repeated notes (as opposed to a longer note duration).


Interrupt 0xA5

As of beta 27, Zeta has started allocating custom hooks under the INT A5h interrupt call. In order to detect the presence of a compatible version of Zeta, it is recommended to use the following code:

Show code example

To call an INT A5h interrupt, one must additionally set the register CX to one of the following values:

  • 0xBABA - detect feature presence; if CX is set to 0x1515 after calling the interrupt with a given AH value, the feature is present.
  • 0x1515 - run feature.

All calls also modify the carry flag - it will be cleared on success, and set on failure.

The following functions are provided by interrupt 0xA5:


Available since: Zeta beta 27.


  • AL = 0x00 to disable idle hacks, any other value to enable idle hacks.


Nothing. Note that disabling idle hacks requires you to modify ZZT's source code to insert FORCE IDLE WAIT calls in the correct places! Example implementation.


Available since: Zeta beta 27.


  • AL = Type of idle wait:
    • 0x00 - wait until next frame,
    • 0x01 - wait until next PIT tick.


Nothing. Stalls code execution (without incurring unnecessary CPU usage for emulation) for a period of time not longer than the next frame or PIT tick. Note that the engine does not guarantee the next frame or PIT tick occuring! For PIT ticks in particular, you still want to check TimerTicks.

AH=0x03, DELAY

Available since: Zeta beta 27.


  • DX = Time, in milliseconds.


Nothing. Stalls code execution (without incurring unnecessary CPU usage for emulation) for a period of time roughly matching DX milliseconds.


Available since: Zeta beta 30.


  • BX = First keypress repeat delay, in milliseconds.
  • CX = Subsequent keypresses repeat delay, in milliseconds.


Nothing. Please note that the repeat delays will be rounded up to the nearest PIT tick.

release/zeta.txt · Last modified: 2021/02/28 21:14 by asie