A historical question - why was Z machine version 8 invented?

Version 7 supports the same size of file (512k) but seems like it could support less average alignment waste between adjacent routines or high strings. The only downside I can think of is if the total size of the routines was substantially different from the total size of the strings, since each is limited to 256k total of the 512k maximum story file? It would also of course require all routines to be stored together and all strings to be stored together.

With the Version 6/7 scheme, you can create a 512 KB game, but only if you carefully design your code so that code + strings + low memory ≤ 512 KB, code ≤ 256 KB, and strings ≤ 256 KB. With the Version 8 scheme you never have to think about this.

3 Likes

Back then there was little to no support for the Z-code version 6 games in the Infocom interpreters then available. Supporting version 7 would have involved significant changes to the then widely used interpreters, while version 8 was generally only a few simple changes.

3 Likes

That makes a lot of sense, David … my own interpreter doesn’t support z7 for exactly that reason (that, and relatively few examples of .z7 files in the wild). And I guess the cumulative waste due to alignment wasn’t significant enough to matter.

Adding support for version 7 to an interpreter is easy.

The extension of the Z-machine into version 7 and 8 was driven by the desire by Graham Nelson and other Inform authors (some Inform version before 6) to make bigger games.

Inform was already dividing routines and strings into different areas, so that part was never a problem. What I believe is the problem with version 7, is that we can’t examine a value at runtime and decide if it’s a string or a routine, unless we use the same offset for strings and routines. Being able to decide if a value is a string or a routine is critical to Inform’s ability to use different kinds of values for a property, i.e. this wouldn’t be possible otherwise:

Object Room "Room"
  with
    n_to OtherRoom,
    s_to "There's a fire that way!",
    e_to [; if(bridge_discovered) return SecretRoom; ];

If we use the same offset for strings and routines, the maximum file size is a little less than 320 KB. Version 8 of the Z-machine lets us have larger games than this, with no other drawback than that a little more space is lost to padding, and this probably didn’t seem like a big problem as the 8-bit era was already over.

(Why a little less than 320 KB?: For a version 7 story file that works for Inform 6, we can use 256 KB of strings + routines minus the number of objects times 4, minus 2*4, because we need to be able to tell these values apart:

  • -1 (NULL)
  • 0 (false)
  • Object numbers
  • Strings
  • Routines

So, we can have 64 KB of dynmem, and typically about 254 KB of strings and routines (if we have ~500 objects), i.e. 318 KB of story file)

2 Likes

Not as easy as v8!

1 Like

It’s really not a big difference. I think I spent an hour or so adding v7 support to Ozmoo. It would be much faster than this in any reasonably well structured interpreter code in a high-level language.

Just looked at the Ozmoo code. In a high-level language, if you already have support for z5 and z8, this is all the code you need to add to support z7:

In game initialization:

routine_offset = header-->$14;
string_offset = header-->$15;

When calling a routine:

routine_address += routine_offset;

When calculating a string address:

string_address += string_offset;
1 Like

When Graham posted the V7/V8 proposal, all our interpreters were buckets of messy C code…

(Okay, I think the Java applet existed too.)

What I’m getting at is that if you only had v1-5 support – which was true of many interpreters at the time – then your code didn’t have separate routine_offset and string_offset variables. There was just a function somewhere that turned a packed address into a real address by multiplying by scale_factor. So V8 just mean setting scale_factor to 8 instead of 4.

For interpreters that supported v1-5 and v6, then yes, v7 was trivial.

3 Likes

I’m sure there are ways to minimize padding losses in z8 without breaking existing interpreters by doing crazy stuff during compilation (or in a post-compilation optimizer).

Crazy stuff: Split routines in chunks and inserting jumps to the different end-chunk. You get a lot of routines with length dividable by 8, ending with a jump to the end of the routine. Think like old time newspapers where every article started on page one but continued somewhere inside the paper.

(Jumps are not limited by the scale factor, only by the distance it can jump (a signed 2-byte word). All the small end chunks can be consecutive without padding between them.)

2 Likes

Given that the padding losses are at most seven bytes per routine, I doubt they’ll ever be that much of a concern, no? Having only half the space for strings and half the space for routines instead of being able to allocate more space to whichever of the two needed more seems far more constraining.

3 Likes

What’s a good test for Z7 support? All I have found so far is Custard…

That’s the only game I know of that uses z7.

1 Like

You can compile Advent.inf with the 6/11 library and -v7. (Probably 6.12 library too but I haven’t tested that.) Should run correctly.

Yeah adding z7 support took me 10 minutes, but I didn’t have a good test case, and I’m stuck behind the UK banhammer for ifdb access.

May I suggest VPN?

Otherwise GitHub should have quite a few inf-sources to build for v7.

Henrik, as awesome as that splitting idea sounds – If I had a routine that was 33 bytes long, and I split it into a 32 byte routine and say a 3 byte routine, how am I actually saving any space?

33 bytes means 7 bytes padding. The jump cost 3 bytes so you save 4 bytes. Remember that jump doesn’t need to jump to an address dividable by 8, so the z-code can have a couple of areas packed with routine endings. It is just a theoretical thought experiment, the code would be very messy for a small saving.

1 Like

Ah, of course. So that 3 byte bit of a routine doesn’t have to start on an 8-byte boundary. Brilliant!

The Inform 5.5 release notes even came with instructions for how to add v8 support to Zip, and a note that version 8 is the preferred one: https://www.ifarchive.org/if-archive/infocom/compilers/inform5/release-note.txt

I guess Jigsaw was the immediate reason that v7 and v8 were added in the first place: https://groups.google.com/g/rec.games.int-fiction/c/2jxuvTDnpRA/m/knr12rzbDK0J

2 Likes

Yes, that’s how I remember it.