Zeugma
Zeugma is a modern, highly optimised, open-source Z-machine implementation for the 6502 processor family. It is designed around a virtual memory model, where pages are retrieved on demand from an external storage resource, 512 KB in size, which must be preloaded with the game file.
There are tools to extract story files from Infocom's C64 releases, and if you load those files into zeugma you will experience a dramatic speed improvement compared to the original, despite the fact that text is now rendered using bitmap graphics in order to fit more characters on the screen. Apart from the obvious benefits of loading from REU rather than floppy, the increased responsiveness is the result of highly optimised code, with extensive use of redundant decoding look-up tables, inlining, self-modifying zero-page code and other trickery. But see below for some depressing facts about recent games.
While the Z-code engine itself is written in generic 6502 assembly language, the virtual memory solution and input/output facilities are platform-dependent. Currently, there is only one implementation, Zeugma-C64-REU, for a Commodore 64 (or a C128 in C64 mode) with a 512 KB RAM Expansion Unit. Today, most active C64 users own a multi-function cartridge such as the 1541 Ultimate, which can be configured to provide REU functionality. For now, zeugma requires the game file to be preloaded into the REU before the program is run, something which is easily done via the menu system of the 1541 Ultimate. Should you wish to use this program with a vintage REU from Commodore, you'll have to devise some alternative way of getting the story file into the REU.
Note
Added 131001: To run Zeugma on a 1541 Ultimate II, configure the Ultimate for a 16 MB REU and use at least version 1.2 of Zeugma.
Download
- zeugma-c64-reu-1.2 (C64 executable file, 16.5 kB)
- zeugma-c64-reu-src-1.2 (Source tarball, 29.1 kB)
- zeugma-c64-reu-1.1 (C64 executable file, 16.5 kB)
- zeugma-c64-reu-src-1.1 (Source tarball, 29.0 kB)
- zeugma-c64-reu-1.0 (C64 executable file, 16.5 kB)
- zeugma-c64-reu-widehack-1.0 (C64 executable file, 16.5 kB)
- zeugma-c64-reu-src-1.0 (Source tarball, 29.0 kB)
The widehack version is required for the Infocom game Trinity.
Zeugma is released under the MIT license (included in the source tarball). The font (Schumacher Clean 6x8) is redistributed in compliance with its license, also included in the source tarball, and a copyright notice is displayed when the program starts.
Background
Being active in the C64 demoscene, and more of a lurker in the world of interactive fiction, it struck me that the two communities have certain things in common. Both are about exploring an obscure art form and finding joy in constraints that appear stifling or pointless to outsiders. Both have formed around some once-blossoming technology — commercially viable years ago, now overtaken by shinier gadgets and left by the wayside — that has been picked up by amateurs and nourished into sprouting more beautiful flowers than ever. Likewise, both communities attract the kind of patient, intelligent people who understand the distinction between vivid imagery and photorealistic graphics, and for whom instant gratification has about as much appeal as instant coffee.
The history of the Z-machine goes as follows: Drafted in 1979 on a coffee table in Pittsburgh, with the aim of making the game Zork (hence 'Z') platform independent, it went on to give the company Infocom a competitive edge: Their text adventure games could be developed once, and then released for an assortment of computer systems. In the mid-1990s, thanks to Graham Nelson, Mark Howell and several other enthusiasts, the format was reverse-engineered. A high-level language, Inform, was invented for writing interactive fiction that would run on all the existing Z-code interpreters.
As technology marched on, people got their hands on more powerful computers, and Z-code interpreters were implemented for them. Newly written games were larger, because computer memory had become plentiful. The file format was extended, and at some point backwards-compatibility with the old interpreters was abandoned. Furthermore, as computers got faster, games got slower, but nobody noticed.
Fans of interactive fiction and vintage computer enthusiasts flocked together into separate subcultures. Zeugma is an attempt to bridge the gap between them. C64 aficionados now have access to a wide selection of interactive fiction, some of very high quality. For the interactive fiction crowd, the benefits are not as obvious. However, I personally find that the vintage hardware brings back something to the playing experience that got lost along the way. You sit down in front of a physical machine that is running nothing but the game. There are no distractions, popups, forums, inboxes, reminders, instant messages and what have you. Every turn takes a few seconds, so you think before you type. You don't speed-read for keywords while fluttering aimlessly around the map, instead taking the time to actually read the text and let it sink in. I find that this does wonders for the sense of immersion. Also, because there's no scrollback, and because you can't conveniently have a text-editor running in another window like on a modern computer, you'll find yourself drawing maps and making notes in pencil. All of this makes the exploration of the game delightfully tangible, and the notes become an embodiment of your personal view of the fictional world.
Fiction compatibility
Zeugma supports Z-code versions 4, 5 and 8 (story files with filename extensions .z4, .z5 and .z8). Some games come in blorb files, from which the story file must be extracted. Here are some tools for that.
Old Infocom games fly. Inform 6 games walk. Inform 7 games are unfortunately way too slow to be playable (unless you happen to have a 20 MHz SuperCPU). I might elaborate on the technical reasons for this in a later post.
Recommendations
If you are familiar with interactive fiction, you probably already know what games you'd like to try out. Otherwise, head to the Interactive Fiction Archive, and look in the zcode directory, as well as the zcode subdirectories of the yearly competition directories. Most games begin in medias res, after which they display a banner with version information. If this banner contains the text "Inform 7" anywhere, you'll find the game unbearably slow. Inform 7 was released in 2006, so earlier competition directories are safe. Wikipedia has a list of notable Inform 6 games. A few personal recommendations follow; these are some of the games that I played while testing zeugma:
- Spiral (Justin Morgan, 2012). This game ranked #6 in the 2012 Interactive Fiction Competition, proving that high-quality games are still being developed in Inform 6.
- Varicella (Adam Cadre, 1999). This is a difficult game, but many agree that it's a masterpiece.
- Trinity (Brian Moriarty, 1986) and Bureaucracy (Douglas Adams et al., 1987) are two lovely games from Infocom. Activision, the owner of the copyrights, has been re-releasing Infocom games as recently as 2012 (for iOS), so these titles can't really be regarded as abandonware. If you own the original disks, there are tools to extract the .z4 files from them.
Trinity refuses to run in the relatively cramped screen space provided by Zeugma-C64-REU (53 x 25 characters). Use the widehack version of the interpreter to get around this; it will lie to the game about the size of the screen, so some quote boxes will end up in strange places, but the game is playable.
Limitations
As mentioned, Inform 7 games are too slow to play. This is the greatest limitation in my opinion.
In addition, zeugma currently doesn't support file system operations. This means you can't save or restore games, and you can't work with transcripts. Also, for reasons of performance and memory conservation, undo and restart are not supported. To restart the game, you have to preload the REU again, and relaunch zeugma.
Zeugma-C64-REU is monochrome, but provides bold and reverse text styles. Non-ASCII characters are currently not displayed correctly.
The name
A zeugma is a rhetorical device that, much like a virtual machine, lets you re-use a piece of meaning in several contexts without having to write it all over again: With zeugma, authors have access to an antique type-saving device; an antique tape-loading device, authors.
Version history
130822 | 1.0 | Initial release. |
130915 | 1.1 | Bugfix in op_tokenise. Tolerate invalid property numbers. |
131001 | 1.2 | Bugfix for REU > 512 kB |
Posted Thursday 22-Aug-2013 23:14
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.
Ralph Corderoy
Fri 23-Aug-2013 14:43
Please do, the nitty-gritty in your posts is often very interesting.
Wed 28-Aug-2013 11:13
Now we all await a C64 REU version of ScummVM ;^)
//P-a Bäckström
Mon 2-Sep-2013 02:49
Sat 14-Sep-2013 00:25
It didn't exactly go to plan. I get "That's not a verb I recognise." in response to anything. Except "oops" and "o", oddly enough. (Screenshot: http://sphere.chronosempire.org.uk/~HEx/shots/zeugma-fail.png)
Several hours of debugging later, I still have no idea what's wrong with your code but I am now very confused.
What is "dictordered" for? The spec (§13.5) requires the dictionary to be ordered. (No mention is made of whether this is required for user dictionaries; I assume so.)
In particular the code between "nowrap5" and "noneg" eludes me. It seems to set dictordered to zero iff the MSB of the number of dictionary entries is set. (This number is fetched correctly by the preceding code.) This seems an utterly bizarre thing to do, and the code if this is true is even more bizarre (invert the number of dictionary entries?!). The only possible thing I can think of is that for some reason you were manually inverting dictionary tables in games and testing (and reverting) that at runtime to determine whether to use a binary search, perhaps for debugging the search code (but then why modify the game rather than the code?).
Also, why does mulloop iterate 8 times? Surely finishing the loop early (suggested code below) would save several iterations in the common case where the dictionary entry size is small (guaranteed to be 9 bytes for Inform games, for example). I can't imagine you would begrudge four extra bytes for this.
mulloop
lsr temp3+2
bcs yesadd
bne noadd
bcc aftermul
yesadd
lda temp3
[...]
noadd
asl temp3
rol temp3+1
dex
bne mulloop
aftermul
ldx #0
[...]
(Gah, how do you format code fragments using this thing?)
Some documentation really would be nice. At this rate of reverse engineering I'll never get a BBC Micro port done :(
Also a github project maybe?
Linus Åkesson
Sun 15-Sep-2013 15:30
It didn't exactly go to plan. I get "That's not a verb I recognise." in response to anything. Except "oops" and "o", oddly enough. (Screenshot: http://sphere.chronosempire.org.uk/~HEx/shots/zeugma-fail.png)
Thanks for the bug report! This is now fixed in v1.1.
What is "dictordered" for? The spec (§13.5) requires the dictionary to be ordered. (No mention is made of whether this is required for user dictionaries; I assume so.)
The same code is used for the tokenise opcode, which does allow unsorted dictionaries, indicated by a negated number of entries.
Yep, I didn't bother to optimise this multiplication as it doesn't happen very often. The regular mul opcode is optimised.
I might have to add support for that. Thanks for persevering.
Also a github project maybe?
I'll think about it. Thanks for showing an interest!
Thu 19-Sep-2013 08:33
I load the file renamed (.REU) into the REU and then I load the Zeugma.prg but it doesn't work. What do I do wrong?
Bieno.
Fri 20-Sep-2013 17:09
REU is enabled, set to 512KB, loading a REU-file (ie. spiral.z8.reu), and then loading and running zeugmav1.1.prg results in 'Z-machine version (anything between 0 and 255) not supported.'
Sat 21-Sep-2013 15:00
For some reason, Spiral gives me all sorts of messages and I get to press [more] a couple of times inbetween those errors.
Fri 27-Sep-2013 13:03
Linus Åkesson
Tue 1-Oct-2013 21:52
Sat 5-Oct-2013 02:57
Sun 15-Dec-2013 05:43
I get an [Illegal opcode] error.
Tue 31-Dec-2013 08:00
John Byrd
Tue 25-Feb-2014 22:47
There is a padbin.exe file in http://www.pineight.com/gba/gbfs.zip which can be used to do this padding, with the following command line for a 512 KB emulated REU:
padbin.exe 524288 your-story-file.z8
Then you can load the padded file into the emulated REU and start zeugma.
John Byrd
Tue 25-Feb-2014 23:03
I confess however that for us emulator users, part of the attraction is the ability to have a "true" C64 experience... I would like to therefore politely request the ability to revert Zeugma back to classic C64 fonts and colors, perhaps via one of the function keys.
Sun 6-Apr-2014 22:01
I am most impressed with the speed and clear font of this interpreter. It's even faster than the official Infocom games on my Atari ST!
I would like to change the default colors to green on black, as black on white is a little hard on my eyes.
I have tried changing the values for 'black' and 'white' in the source code, and recompiling it, but that doesn't seem to do anything. (It compiles fine, but the colors don't change.)
Unfortunately, I don't understand assembler at the best of times, and am getting a bit lost!
Sat 10-May-2014 15:58
Fri 3-Apr-2015 23:27
Here's hello world:
https://sphere.chronosempire.org.uk/~HEx/shots/zeugmab.png
(Story was the smallest, simplest file I had to hand, namely that discussed in https://groups.google.com/forum/#!topic/parchment/CeUK2Ry6Yvk .)
Adventures so far: the Beeb, which has an actual OS[1], uses the top of zero page for its own purposes, so the code residing there on the C64 needed splitting out into the self-modifying bit at the bottom, and the rest, which can usefully be stored at the bottom of page 1. Current zp usage is 153 bytes.
Then there was figuring out why the VM was trying to access addresses starting at 5fff00 and working downwards, well beyond the extent of the story file. Hmm, "property cache", you say?
Most recent facepalm was when I was single-stepping a crash and came across the instruction "jmp ($3dff)". This is a self-modifying jump table (jumptbl_oper) at $3d00 ($3300 on the C64 version) indexed by odd values. Early 6502s (including the 6510) perform the wraparound incorrectly, and indeed you have put the high byte at the beginning of the table as the buggy CPU in the C64 expects.
But not the more recent, non-buggy 65SC12 in the BBC Master[2] I was emulating! It does wraparound correctly, and thus loads the "wrong" value. Does this code really work on a SuperCPU?
[1] More to the point, an actual OS that can't be paged out, so any help it can provide is useful in alleviating the critical address space shortage. Also I can understand writing your own display routines, but your own *keyboard scanning code*? Is this what life is like on the C64?
[2] I would like to support a plain model B (32K should be enough for everybody, right?). But, well, if you can require a Commodore 576, I can probably get away with suggesting a Master 128 :)
Linus Åkesson
Fri 10-Apr-2015 22:48
As for keyboard scanning, there's a routine in the OS, but mine supports 3-key rollover and flexible key-repeat functionality. Besides, to use the stock routine, some research would be necessary to figure out what memory areas to leave intact. With 64 kB of RAM at hand, it was easier to just implement it.
Sun 5-Jul-2015 02:32
Man, that was a hassle to compile/assemble on winderps...
Also, why have black on light grey in the first place, just hurts both eyes and screens?
Sun 20-Sep-2015 13:37
Go to the Settings menu and select Cartridge/IO settings
Select REU settings
Enable REU and set size to 16mb
Browse to the z-file you want to play. (You may need to rename the extension to .reu first.)
Run the Zeugma program.
So far I have not got a game to run, but the error message I see - "z-machine version 0 not supported" - gives me hope I am making some progress.
Linus Åkesson
Sun 20-Sep-2015 14:07
So far I have not got a game to run, but the error message I see - "z-machine version 0 not supported" - gives me hope I am making some progress.
Check the earlier comment from johnwbyrd. VICE requires you to pad the file to the correct size.
Tobias Hellgren
Sun 15-May-2016 11:23
Sat 24-Dec-2016 07:21
Do you know if they will work with z8 files?. It would be cool to play current IF games on the C64. Thanks.
--KMBR
Wed 15-Feb-2017 16:46
Do you know if they will work with z8 files?. It would be cool to play current IF games on the C64. Thanks.
--KMBR
Varicella (shown in the screenshot at the top of the page) is a z8 game. That doesn't automatically mean that all z8 games work.
-- Fredrik
Wed 15-Feb-2017 16:56
thanius wrote:
Drog in Stugan, men fonten verkar sakna ÅÄÖ. Något för framtida versioner?Det är troligen betydligt mer än fonten som skapar problem. Inmatning och utmatning av svenska tecken, användandet av en alternativ alfabetstabell, och tidsstyrd inmatning är exempel på områden som måste funka för att köra Stugan, och som krånglar även i många ganska mogna speltolkar.
/Fredrik (som skapade Z-kodsversionen av Stugan)
Wed 22-Aug-2018 16:17
BeebSCUMM -> https://stardot.org.uk/forums/viewtopic.php?t=15273
Fri 18-Jan-2019 14:48
I have downloaded and run some of the examples from your dialog program and am working through the docs (prolog newbie)
How would I get a v7 *.gblorb file into zeugma ?
I've tried using babel, but it only generates a blorb and / or ulx file.
Mike
Fri 18-Jan-2019 14:50
mstram wrote:
Although you say v7 is too slow to play, I'm more interested in just exploring how the system works.I have downloaded and run some of the examples from your dialog program and am working through the docs (prolog newbie)
How would I get a v7 *.gblorb file into zeugma ?
I've tried using babel, but it only generates a blorb and / or ulx file.
Mike
Sorry for any confusion, I realize that dialog has nothing to do with v7 / babel :) Just meant that I'm trying all the tool chains.
Sat 24-Apr-2021 16:43
How slowly does it play, or: have you tried it?
https://ifarchive.org/if-archive/games/zcode/Advent.z5
What would it take to port this over to the Apple II?