The Å-machine

The Å-machine is a virtual machine for delivering interactive stories. It is designed for stories implemented in the Dialog programming language.

As the name suggests, the Å-machine is inspired by the Z-machine. The letter Å (pronounced [ɔː], like the English word “awe”) follows Z in the Swedish alphabet. In international contexts, å can be transcribed into aa, as in “The Aa-machine”.

The Dialog compiler can produce Å-machine story files starting with version 0g/01. The filename ending is .aastory. Support for the widely used and historically important Z-machine remains, and will not go away. But stories compiled for the Å-machine look better on the web, and are smaller and faster on vintage hardware.

In a sense, the Å-machine is to Dialog what Glulx is to Inform 7. It eliminates the tight restrictions on story size, and extends the basic functionality with a carefully balanced set of new features. But the Å-machine is designed to run the same stories on everything from 8-bit systems to modern web browsers. Data structures and encodings are economical, and the overall word size has not increased. Large stories are supported, but small stories still have a very compact binary representation.

Compared to the Z-machine and Glulx, the Å-machine operates at a higher level of abstraction. This improves performance on vintage hardware, both by making story files smaller, which improves loading times, and by allowing larger chunks of computation to be implemented as native machine code. The downside is that the virtual machine is more tightly coupled to the idiosyncracies of a particular high-level language, in this case Dialog.

Currently, two separate Å-machine interpreters exist. One is implemented in Javascript, and the other is implemented in 6502 assembler. Each must be combined with a frontend that handles input, output, and other platform-specific details. Available frontends include a web frontend based on jquery for the Javascript interpreter, and a Commodore 64 frontend for the 6502 interpreter.

Use the included tool, aambundle, to convert your .aastory file into a web-friendly directory structure, including story and interpreter, ready for deployment on a server. The same tool can create disk images for the Commodore 64.


The release archive includes:

  • The Å-machine specification.
  • A Javascript interpreter, with two frontends.
  • A 6502 interpreter, with two frontends.
  • Source code and prebuilt binaries for the Å-machine tools aamshow and aambundle.

This software is distributed under a 2-clause BSD license.


My IFComp 2018 game Tethered and my IFComp 2019 game Pas De Deux running on the Å-machine.

Here is Cloak of Darkness (Dialog source code) on the Å-machine.

Posted Tuesday 4-Jun-2019 05:28

Discuss this page

Disclaimer: I am not responsible for what people (other than myself) write in the forums. Please report any abuse, such as insults, slander, spam and illegal material, and I will take appropriate actions. Don't feed the trolls.

Jag tar inget ansvar för det som skrivs i forumet, förutom mina egna inlägg. Vänligen rapportera alla inlägg som bryter mot reglerna, så ska jag se vad jag kan göra. Som regelbrott räknas till exempel förolämpningar, förtal, spam och olagligt material. Mata inte trålarna.

Wed 5-Jun-2019 22:55
Cool stuff!! :)
Thu 13-Jun-2019 06:58
What you are doing is simply awesome. Keep on going.
Bert Jerred
Sun 16-Jun-2019 06:45
Fascinating and fun. Thank you for sharing this!
Sun 30-Jun-2019 08:53
Hi! I have a "?" signs for non-Latin characters in the debugger. Is there some way to get around this problem?
Tue 17-Sep-2019 19:42
hackernews sent me here
Tue 17-Sep-2019 19:46
Q is dead...#Anastasius
Tue 17-Sep-2019 21:23
hackernews sent me here
so what?
Mon 30-Sep-2019 13:50
I have found several possible mistakes in the Aa-machine specification 0.2:

Important differences between the specification and the JS reference implementation:
- IF_FLAG, IFN_FLAG, SET_FLAG, and RESET_FLAG: "1 <<" should be "0x8000 >>" (that is, the spec starts shifting from the least-significant bit, but the ref impl starts shifting from the most-significant bit)
- JMPL_MULTI: "SIM = 0" should be "SIM = 0xffff"
- JMP_TAIL: "SIM < 0x8000" should be "SIM >= 0x8000"
- UNLINK, SET_PARENT: seven occurrences of "value - 1" should be "value" (the ref impl never subtracts 1 from those object values, not even in fieldaddr() or unlink())
- LOAD_VAL: the result of get_longterm() should not be stored in arg3 if it is zero (that is, according to the spec "arg3 <- get_longterm(...)" is executed even if "!arg3" is true; a solution might be to introduce a local variable)

Minor things:
- IF_CWL, IFN_CWL: use "arg2" even though there is only one argument
- STORE_WORD, STORE_BYTE, STORE_VAL, SET_FLAG, RESET_FLAG, UNLINK, IF_MEM_EQ, IFN_MEM_EQ, IF_FLAG, IFN_FLAG: opcode index lists first argument as "VALUE/0", but opcode details have "0/VALUE"
- unbox_int(): "v.tag != integer" should be "v.tag != number" (this is the only occurrence of "integer" as a tag type)
- store_longterm(), push_longterm(): "HEAP.ramsz" should be "HEAD.ramsz"

- The initial state of the special-purpose registers is never defined (except for INST, though even that is somewhat hidden)
- FIELD_PARENT (=0), FIELD_CHILD (=1), FIELD_SIBLING (=2) are never defined
- It would be useful if pseudo-code invocations of runtime_error() explicitly defined the error_code (as it is probably not meant to be implementation-defined)
- input_get_line() is never defined (according to the Dialog manual this function works in a very specific way, so it is probably better to explicitly define it in the spec instead of leaving it up to the implementation)
Linus Åkesson
Mon 30-Sep-2019 23:00
I have found several possible mistakes in the Aa-machine specification 0.2

Thank you very much! I was aware of a few of these issues, because I've started to work on a second implementation (in 6502 assembler) based on the specification document, but I didn't realize that somebody else was having a detailed look at it too. I should make a 0.3 that fixes the errors, without adding any new features.

Also, for what it's worth, the current Dialog compiler never emits AUX_POP_VAL, and I'm thinking about deprecating that instruction. But it ought to remain in the specification until it's time to increment the major version number.
Wed 30-Oct-2019 01:18
Interesting. waiting for an implementation that matches the specs :)
Mon 6-Jan-2020 09:25
Some more things I discovered in the specification 0.3:

Important differences between the specification and the reference implementation:
- STORE_BYTE: "ram[arg1]" should be "ram[field_addr(arg2 / 2, deref(arg1))]" (2x)
- GET_KEY: should start with "if(SPC == auto || SPC == pendingspace) output_space()" (similar to GET_INPUT)

Minor things in the specification:
- MAKE_PAIR, AUX_PUSH_VAL, AUX_POP_VAL: "local variable addr <- TOP", "v <- 0xe000 + count", "v <- pop_serialized()", and "v <- empty list" should use "=" instead of "<-"
- PUSH_ENV: arguments are given as "BYTE/0" in the index but "BYTE" in the detailed description
- def unlink: useless "return" at the end

- output_value() is another function which should probably be explicitly defined in the specification (e.g. the non-obvious $ syntax for references is never mentioned in the specification)
- The definition of the "SPC" register suggests that only the order of the enum values matters, not their actual values. While this is true during execution, save files store all the registers, so using anything but the values 0-5 would make saves non-portable. It might therefore be better to assign fixed numbers to the enum values in the specification.
Linus Åkesson
Tue 7-Jan-2020 17:19
Thank you!
Wed 15-Jan-2020 20:19
Are there any plans to create a C implementation? I would love to get Å-machine games running on devices such as the TI Nspire, which already has frotz ported to it.
Linus Åkesson
Fri 24-Jan-2020 08:09

Ivoah wrote:

Are there any plans to create a C implementation?

Yes, I certainly intend to do that at some point. A platform-independent engine, calling out to an I/O layer that in turn could be implemented using the Glk library, for instance.

But I have some improvements to the Å-machine in mind, and I would prefer to get those in place first, while there are still only two official interpreters to maintain.
marcel schleier
Tue 13-Oct-2020 18:00
mmmmhhh... outaphonY?
noprob<=0> useaolskoolasthaisnonototherSCHOOLY, BABY!

bum.mmmmBum-bUkKmMmM...bum-di-didi-duDUM ...öööhhmmm: PENG? YEP: PENG<!


Sun 17-Oct-2021 05:08
Show more! Congratulations!