Opcode Number and Hex Number Distinction (Z-Machine Spec)

Section refers to “VAR opcodes call_vs2 and call_vn2 (opcode numbers 12 and 26)”

When I look these up in the spec, I see:

VAR:236	-> call_vs2

The hex value for that is 0xC (12).

Likewise, I see:

VAR:250 --> call_vn2

The hex value for that is 0x1A (26).

But … and here’s the question … why is the hex value considered the “opcode number”? Wouldn’t 236 and 250 the opcode number?

Section 4.3 says:

“Which opcode an opcode number refers to generally depends on the operand count, so that there are 0OP, 1OP, 2OP and VAR opcodes.”

This at least seems to suggest that the numbers 236 and 250 are the opcode number. Looking at the tables (for example, One-operand opcodes 1OP) , at the bottom it says:

Opcode numbers 144 to 175: other forms of 1OP with different types.

That would also suggest that the hex numbers are not the opcode number. However, if you look at the “On Disassembly” part of section 4, the calculations there would lead you to the hex number being the opcode number. Specifically with that table reduced to code:

if operand_count == OperandCount.VAR:
            if 0xE0 <= byte <= 0xFF:
                return byte - 0xE0

        if operand_count == OperandCount.OP0:
            if 0xB0 <= byte <= 0xBF:
                return byte - 0xB0

        if operand_count == OperandCount.OP1:
            if 0x80 <= byte <= 0x8F:
                return byte - 0x80
            elif 0x90 <= byte <= 0x9F:
                return byte - 0x90
            elif 0xA0 <= byte <= 0xAF:
                return byte - 0xA0

        if operand_count == OperandCount.OP2:
            if 0xC0 <= byte <= 0xDF:
                return byte - 0xC0
            elif 0x00 <= byte <= 0x1F:
                return byte - 0x00
            elif 0x20 <= byte <= 0x3F:
                return byte - 0x20
            elif 0x40 <= byte <= 0x5F:
                return byte - 0x40
            elif 0x60 <= byte <= 0x7F:
                return byte - 0x60

That would mean the opcode number of call (VAR:224) would actually be 0 (which is the hex value). The opcode number of print_obj (1OP:138) would actually be 10 (0xA in hexadecimal).

Yet note that the 2OP codes actually are identical initially. For example, the opcode number of test_attr (2OP:10) would be 10 (which, as 0xA, is the hex value). So the 2OP table has the number and the hex matching.

So the bit of text that I started off and thought might simply be inaccurate leads me to question how the actual calculation is done and what actually is the opcode number.

1 Like

Oh dear. Some of this text was rewritten recently by me in an attempt to make certain things clearer (mainly that 2OP opcodes encoded as VAR can actually have more than 2 operands). I may have made some things less clear. I’ll have to go over it again to try to make things consistent and clear.

1 Like