Select Mode

Memory Regions in Grue

In this post, I’ll talk about the idea of “regions” of memory. These are the areas that zcode program data are stored in and can be accessed from. These regions are a key part of the Z-Machine memory map.

Regions of the Map

The Z-Machine specification, referring to the memory map, says:

This is divided into three regions: “dynamic”, “static” and “high”.

The concepts of “pages” and “banks” that I talked about in the previous post are related to the memory regions of the Z-Machine. In particular, the memory management scheme of the Z-Machine involved dividing the memory into these different regions, each with its own characteristics and limitations.

Since this seemed important for aspects of the memory that I would be reading from and possibly writing to, I put in place some variables and used my helper methods on the Memory module:

But how did I know to read those particular addresses? That’s from the specification:

Dynamic memory begins from byte address $00000 and runs up to the byte before the byte address stored in the word at $0e in the header.

Also:

High memory begins at the “high memory mark” (the byte address stored in the word at $04 in the header) …

In my context post, I mentioned the Infodump utility and the zork1.z3.infodump.txt that I generated from the Zork1.z3 zcode program. In that output, I see the following:


Size of resident memory:  4e37
Size of dynamic memory:   2e53

But, wait a minute, this gets confusing. The tool shows “dynamic” memory (that’s at least consistent) and something called “resident” memory. Yet, with my logic above, when I run my code, the self.static is 0x2E53 and the high memory is 0x4E37.

So I’m getting values that seem to match but the static memory I get seems to be the dynamic memory reported by Infodump. And the high memory seems to be the start of the so-called “resident memory,” whatever that is.

Regarding the dynamic memory, remember that the specification says that dynamic memory “runs up to the byte before the byte address stored in the word at $0e in the header” (emphasis mine). The memory map essentially looks like this:


Dynamic

Static

High

What all this means is that dynamic runs up to address 0x0E. Static starts at 0x0E. Given this, I can create some tests:

Those tests do pass and that does match what I see from the Infodump for the Zork 3 zcode program as well as reconciling what I’m reading in the specification.

Breaking Down the Memory

Let’s break down the memory regions, at least as I currently understand them.

  • Dynamic Memory: This is where mutable data resides. In a text adventure, this would indeed include things like the player’s location, the state of objects (like whether a door is open or closed), the player’s inventory, and other game states that can change during play. This part of memory is writable during gameplay, and changes are reflected as the player interacts with the game world.
  • Static Memory: This is read-only and contains immutable data. This region would include things like the game’s text strings, which describe locations, objects, and other game elements. Since this data doesn’t change during the game, it stays constant in the static region. The game’s code can reference this information, but it can’t alter it.
  • High Memory: This region typically contains the actual machine code (or bytecode) for the Z-Machine. It’s the part of memory that executes instructions, such as parsing input, updating game state, or generating output. This area isn’t directly manipulated by the game logic in the same way dynamic memory is; it’s more about running the interpreter.

All memory in the Z-Machine is allocated and addressed using those 16-bit pointers talked about in the previous post, regardless of whether it’s dynamic memory, static memory, or high memory.

Addressing Memory Regions

So here’s where you have to start looking at what the Z-Machine itself specified and what the Z-Machine interpreters did. All the Z-Machine specification did was assume that the machine was operating in a 16-bit address space.

Since dynamic memory holds the game’s mutable state (inventory, object states, etc.), it would need to remain resident in physical memory during gameplay, allowing for quick access and frequent modifications. That part seems pretty solid.

What you will often hear is that she static memory was divided into “pages,” and each page was loaded from the zcode program into memory when it was needed. The concept of paging static memory in and out could be true for some interpreters, particularly on machines with limited RAM, but this wasn’t part of the Z-Machine specification itself. Instead, it’s a clever strategy interpreters might have used. Static memory, which is read-only, could theoretically be divided into pages and loaded from the story file as needed.

For example, interpreters running on systems with limited memory could store static memory (which could be quite large) on disk or in ROM and load portions (pages) of it into RAM when needed. Crucially, however, this would be invisible to the Z-Machine bytecode itself, with the interpreter managing which pages of static memory were resident.

All of these memory considerations are something I’m learning on the fly. I still find some of it confusing, much of which I attribute to how the specification is written. As I indicated when I started this series, the specification is not exactly a model of clarity.

My hope is that I will learn more by attempting to implement what the specification is saying and then seeing how that aligns with information I get from known oracles, like the Zork 1 zcode program. In the next post, I’ll continue by looking at some of the constraints that exist on all this memory.

Share

This article was written by Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.