Skip to content

fix(tri27-emu): repair the six pinned TRI-27 emulator defects (#1164) - #1250

Merged
dmitrii-f-t27 merged 1 commit into
mainfrom
fix/tri27-emu-six-defects
Oct 2, 2026
Merged

dmitrii-f-t27 merged 1 commit into
mainfrom
fix/tri27-emu-six-defects

Conversation

@dmitrii-f-t27

@dmitrii-f-t27 dmitrii-f-t27 commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes the six TRI-27 emulator defects tracked in #1164, one commit per defect area:
#1165 (CALL pushes its own address), #1166 (loader writes eight-byte words, run fetches four-byte units),
#1167 (writer and loader disagree by two bytes on the header), #1168 (CONSTANTS parser reads the id as the count),
#1169 (modulus 19683 labeled 3^27), #1170 (SACR mode dropped by the decoder).

Closes #1164
Closes #1165
Closes #1166
Closes #1167
Closes #1168
Closes #1169
Closes #1170

{
  "version": 1,
  "head_sha": "6a9d1ac8dee8c876edd906612f1e1d70e49aaad0",
  "summary": "The six pinned TRI-27 emulator defects from the S05 findings are fixed: CALL pushes the next address, the loader and the fetch agree on one four-byte word per fetch unit at byte 12, the writer and loader share the twelve-byte header, the CONSTANTS parser reads id then count then count*8 bytes, the modulus labels say 3^9, and the SACR mode round-trips through the decoder.",
  "changes": [
    "executor.zig: CALL pushes pc + 1, so RET resumes after the call site (issue 1165).",
    "loader.zig: the CODE payload is repacked one word per four-byte fetch unit at byte 12 + i*4 and pc is set to 3, so a program executes with no padding NOPs and jump targets line up (issue 1166).",
    "loader.zig: the loader skips the two padding bytes the writer emits, so a container written by tri_asm.zig loads at the addresses its labels count from (issue 1167).",
    "loader.zig: the CONSTANTS parser reads the section id, then the count, then count * 8 bytes as documented (issue 1168).",
    "tri_cpu.zig: the modulus comments label 19683 as 3^9 instead of 3^27 (issue 1169).",
    "decoder.zig: SACR is an immediate instruction in both decode and encode, so its mode field is read and written (issue 1170).",
    "tri_emu_main.zig: instruction count and code size count from the twelve-byte header.",
    "specs/tbin_format.md: the container documentation restates the canonical twelve-byte header and the constants layout."
  ],
  "tests": [
    {
      "command": "zig test src/tri27/emu/loader.zig",
      "result": "All 2 tests passed, including container placement and CONSTANTS parsing.",
      "status": "passed",
      "evidence": "zig 0.16.0 on aarch64-macos; the two new regression tests in loader.zig."
    },
    {
      "command": "zig test src/tri27/emu/executor.zig -lc",
      "result": "All 16 tests passed, including CALL/RET resumption.",
      "status": "passed",
      "evidence": "zig 0.16.0 in a scratch copy with the three host-file handlers stubbed (unrelated to the change; the host's zig 0.15.2 cannot link libSystem on macOS 26)."
    },
    {
      "command": "zig test src/tri27/emu/decoder.zig -lc",
      "result": "All 7 tests passed, including the SACR round-trip in every mode.",
      "status": "passed",
      "evidence": "zig 0.16.0 with a scratch shim for std.meta.intToEnum, which 0.16 removed; the repository CI pins zig 0.15.2."
    },
    {
      "command": "zig test -fno-emit-bin for loader, decoder, executor, tri_asm, tri_cpu, tri_emu_main",
      "result": "Semantic analysis passed for all six files.",
      "status": "passed",
      "evidence": "zig 0.15.2, the version the repository CI uses."
    }
  ],
  "limitations": [
    "The emulator tests do not run in this repository's CI; the change is compile-verified there through the tri executable and behavior-verified on a host that can link tests.",
    "The S05 specs in gHashTag/t27 (specs/isa/tri27_machine.t27, tri27_bytecode.t27, ternary_encoding.t27), the Python model in tools/trinity_tri27.py and the conformance vectors still describe the pinned pre-fix behavior and need a matching follow-up pull request in gHashTag/t27.",
    "The CALL stack guard and the sp word/byte semantics were left as pinned; they are outside the six issues."
  ],
  "tags": [
    "tri27",
    "emulator",
    "loader",
    "bugfix"
  ],
  "blog": {
    "title": "The TRI-27 emulator stops lying about its own container",
    "summary": "Six pinned emulator defects from the S05 findings are fixed: calls return, the loader and the fetch agree on word size, the writer and the loader share one header, constants parse as documented, and the sacred operation mode survives the decoder.",
    "outline": [
      "Where the six defects came from: the S05 specs of the pinned TRI-27 emulator recorded them as findings, and each sub-issue quotes the spec, the code at the pin and a conformance vector that reproduces the failure.",
      "Why CALL looped forever: the executor pushed the address of the CALL itself, so RET returned to the call site and every CALL/RET pair spun until the instruction budget; the fix pushes pc + 1 and a regression test drives a full call and return.",
      "One code word per fetch unit: the loader wrote eight-byte memory words while run fetches four-byte units at pc * 4, so programs executed padding NOPs; the loader now repacks the payload at byte 12 + i*4 and pc starts at 3.",
      "The two-byte header disagreement: tri_asm.zig pads its header to twelve bytes while the loader read the code from byte ten; the loader now skips the same padding, so a written container loads at the addresses its labels count from.",
      "The remaining three fixes: the CONSTANTS parser reads the id, then the count, then count * 8 bytes; the modulus labels say 3^9 instead of 3^27; and the SACR mode is an immediate the decoder reads, so every sacred operation mode round-trips."
    ]
  }
}

The S05 findings of #988, tracked in #1164, fixed one by one:

- #1165 CALL pushes the address of the instruction after it, so RET
  resumes past the call site instead of looping on the CALL.
- #1166 loader.load packs one code word per four-byte fetch unit at
  byte 12 + i*4, matching run's fetch at pc * 4.
- #1167 the writer and the loader agree on the twelve-byte header; a
  container written by tri_asm.zig now loads at the addresses its
  labels count from.
- #1168 the CONSTANTS parser reads the id, then the count, then
  count * 8 bytes, as documented.
- #1169 the modulus labels say 3^9, not 3^27: 19683 is 3^9.
- #1170 SACR is an immediate instruction in the decoder, so its mode
  field round-trips through encode and decode.

Regression tests: container placement and CONSTANTS parsing in
loader.zig, CALL/RET resumption in executor.zig, SACR round-trip in
every mode in decoder.zig. tbin_format.md restates the canonical
container the loader now reads.

Русская часть: шесть дефектов эмулятора из находок S05 (#1164)
закрыты правками в loader.zig, executor.zig, decoder.zig и
tri_cpu.zig плюс согласованием tri_emu_main.zig; каждый пункт
покрыт регрессионным тестом, документация контейнера приведена к
каноническому 12-байтному заголовку.
@github-actions github-actions Bot added the status:in-progress 🔵 Agent working label Oct 2, 2026
@dmitrii-f-t27
dmitrii-f-t27 merged commit e7919fd into main Oct 2, 2026
34 of 40 checks passed
@github-actions github-actions Bot added status:completed Done and removed status:in-progress 🔵 Agent working labels Oct 2, 2026
gHashTag pushed a commit to gHashTag/t27 that referenced this pull request Oct 6, 2026
Add FIXED_UPSTREAM section to both tri27_machine.t27 and tri27_bytecode.t27
documenting the six findings fixed in e7919fdc (2026-10-02):
- CALL return address (#1165)
- loader packing and pc (#1166)
- header agreement (#1167)
- CONSTANTS layout (#1168)
- modulus labels (#1169)
- SACR immediate (#1170)

PINNED_REVISION, FINDINGS, and FINDING_COUNT remain unchanged as required.
Run t27c parse and t27c typecheck on both specs, then seal both.

Closes #5614
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment