m-code-summary-64.md 3.7 KB

MC64 — Summary

A 64-bit generalization of the Turbo Modula-2 MCode virtual machine (see mc64-spec.md).

Core model

  • Word = 64 bits; flat, byte-addressable, little-endian address space.
  • Stack machine, single stack shared by values and frames; grows down (Push = SP -= 8).
  • State: IP, SP, FP (frame), GP (current module data window), OFP (static link), MTBL (256 module pointers).

Data types

Type Width Stack slots
BYTE/CHAR/BOOLEAN 8 bits (in a slot) 1
CARDINAL 32 bits (zero-extended) 1
INTEGER 32 bits (sign-extended) 1
SET 64 bits 1
LONGINT / LONGCARD 64 bits 1
REAL 64-bit binary64 1
LONGREAL 128-bit 2 (quad)
pointer 64 bits 1

Slots are always 64 bits; 32-bit values live in the low 32 bits, so 32↔64-bit widening is a value no-op.

Frames & calls

  • Locals at FP[-1], FP[-2], …; param k at FP[k+2]; args pushed in reverse order.
  • ENTER k reserves (255−k)×8 bytes of locals (k=0FFH → none).
  • PROC_LEAVE n: drops n & 0x7F words; bit 7 re-enters the outer module (reloads GP from OFP).

Addressing

Local (FP) / Global (GP) / Extern (MTBL[mod]) / Indirect (popped ptr) / Indexed (ptr + index). Word offsets = bytes × 8.

Opcode map

All 256 opcodes preserved 1:1, positions from MCode/16:

  • 00–1F params, legacy dword (slot) loads/stores, indexed byte/slot/quad
  • 20–3F dup/swap, local/global/extern load+store, memcpy/string copy
  • 40 extended sub-dispatch (ALLOCATE/MARK/MOVE/FILL/BIOS…, LONGCARD uc_* arithmetic, long_negate), 41/51 slot0 aliases, global 2–15
  • 60–7F indirect load/store offsets 0–15
  • 80–9F addresses, leaves, strings, immediates (byte / 8-byte / 16-byte)
  • A0–BF comparisons & arithmetic on the 32-bit CARDINAL/INTEGER types, LONGINT↔CARDINAL/INTEGER/REAL conversions, shifts
  • 12H sub-opcode: the only 128-bit LONGREAL (quad) load/store/compare/arith family
  • C0–DF checked 32-bit arithmetic, SYSTEM host calls, 64-bit LONGINT (long_*) compare/arith, switch, reserve, range checks, short-circuit and_jp/or_jp
  • E0–FF jumps, bitset ops (64-bit SET), procedure calls (call 1..15, extern, nested)

The old MCode/16 "dword/long" (32-bit LONGINT/REAL) groups become the 64-bit LONGINT family; 64-bit unsigned (LONGCARD) uc_* primitives move to the 40H extended dispatch.

Complex instructions

  • Switch (0CDH): low/high u64 bounds + i64 jump table; offset relative to its cell end; negative offset = call-switch (pushes return = end of table).
  • String compare (0C4H): pushes (s1>s2) then (s1<s2).
  • reserve_string: copies pc-relative string const onto the stack, pushes its address.
  • SYSTEM (0C3H): host ABI (0 exit, 1 write string, 2 read line, 3+ host-defined).

Modules & loader

  • .MC4 file: magic header (8) + fileSize, moduleStart, depsOffset, nbDependencies, reserved — then image blob + dependency records (16-char name, version, fixup location).
  • In-memory ModuleDesc: dependencies[32], link, name, loadAddr, checksum, procsAddr, flags/varCount/depCount.
  • Proc k address = procsAddr + k*8 + offset[k].
  • Load: relocate module chain, init globals (zero-filled), run TOINIT initializers in order — the requested module's init runs last.

Exceptions

IllegalInstruction, Unimplemented, Overflow, RangeError, DivideByZero, StackOverflow, OutOfMemory, StringTooLong, LoadError; processes/TRANSFER out of baseline scope.

Key differences from MCode/16

Word 16→64 bits; encoded fields that were 16-bit words widened 2→8 bytes; local addressing in words; MTBL replaces the global-window module table trick; .MCD → .MC4 (magic, 64-bit fields); Enter reserve ×8.