Status: Specs-foundation saga (saga 2) is current. Relaunch (saga 1) closed 2026-04-18. Lexer and line parsing, formerly saga 2, is now saga 3; all subsequent sagas shifted by +1. Scope: Living roadmap. The current saga is detailed; later sagas are stubs to be fleshed out when they become current.
- One saga = one reviewable unit of work ending in a rename from
feat/<slug>topr/<slug>. - Sagas are tracked in
.agentrail/; archived sagas land in.agentrail-archive/. - The feature branch (
feat/relaunch-projectfor saga 1) accumulates commits throughout a saga. At saga completion, the dev agent runsgit branch -m feat/<slug> pr/<slug>-- that rename IS the handoff. A separate release engineer agent picks up thepr/branch, merges it intodev, and pushes to GitHub. Dev agents have no write access to the remote and do not invokegit push,gh pr create, or any other GitHub-side command.
Land repo-local, authoritative specifications so that every downstream saga (lexer, encoder, symbol table, regression, self- host) implements against this repo rather than deferring to sibling repos for ISA / language / format details.
Goal: six specification documents live under docs/, each
authoritative for one axis of sw-as24's behaviour, each with a
provenance footer naming its sources.
Outputs:
docs/isa.md-- COR24 ISA: registers (r0, r1, r2, fp, sp, z, iv, ir, c -- selectors 0..7 are internal only), memory map, I/O, 34-mnemonic instruction set, decode ROM byte-level mapping, addressing modes, calling convention.docs/as24-language.md--.ssource language: lexical rules, literals (decimal +0...hhex), labels on own line, symbols, directives (.text/.data/.bss/.byte/.word/.comm/.globl/. = . + N), branch-too-far rewriting, error format, optional-Opeephole optimizer.docs/output-formats.md--.lgo(as24.c default, hex-ASCII load + go),.lst(listing layout),.obj(linkable records),.sroundtrip, plus the raw.binconvention cor24-run uses today.docs/fpga-runtime.md-- runtime environment: SRAM/EBR/MMIO map, UART protocol, reset, the multi-binary loading model (cor24-run--load-binary @addr,--patch,_mainentry convention) established by sws+swye.docs/self-host-toolchain.md-- editor/linker/loader/monitor contract; mostly open questions; points at sw-cor24-script + sw-cor24-yocto-ed as the existing multi-binary precedent.docs/oracle-protocol.md-- REST oracle served by as24.c (URL / request-shape TBD), test corpus inventory (per-opcode, directive coverage, edge cases), regression-procedure sketch.
Plus: CLAUDE.md index; docs/architecture.md §2 repointed
from sibling-repo references to in-repo specs; this plan
renumbered.
Exit: all six docs committed, referenced from CLAUDE.md and
docs/architecture.md. No sw-as24 behavioural change in this
saga -- it is documentation only. The vendor repoint from
cor24-rs to sw-cor24-x-assembler is not part of this saga;
it is blocked on upstream x-assembler landing a [[bin]]
target, and tracked for a later saga once that unblocks.
Goal met: replaced the obsolete C-based scope with a .s-based
scaffolding that passes a byte-identical single-mnemonic smoke test
end-to-end, on a cold vendor + build from just vendor-fetch +
just build + just test.
Exit criteria (as shipped):
docs/{prd,architecture,design,plan,utility}.mdpresent and consistent. (utility.mdadded mid-saga to document the future device-side hex decoder.)- Directory layout from
design.mdinstantiated. just vendor-fetchresolves a vendoredcor24-runvia the siblingcor24-rsrepo (or$SW_EM24_BINoverride, or system PATH); manifest pins commit40033d90e80dcef1a420bd3db7c8fd22fb9f181f. (The step prompt originally namedsw-cor24-emulatoras the sibling; discovered mid-saga thatcor24-rsis the stabilized upstream andsw-cor24-emulatoris an as-yet-undiverged fork.)just testpasses byte-identical:cor24-run --assemble nop.sproduces0xFF;sw-as24emits hex-ASCII"SFF"on UART TX; after banner-strip +scripts/hex2bin.sh, candidate =0xFF. (The step prompt assumednopencodes to0x00; empirically it's0xFF, corrected mid-saga.)- README, CLAUDE.md, and
.gitignorerewritten for the new scope.
Design decisions that landed:
- Vendoring pattern mirrors
sw-cor24-ocaml.vendor/active.envas single source of truth for versions.vendor-fetch.shresolves binaries via three strategies (env override, sibling source build, system PATH). - sw-as24 emits hex-ASCII on UART TX rather than raw bytes,
because
cor24-runfilters0x00from every observation path.scripts/hex2bin.shis the host-side decoder;sw-hexload(future) is the device-side decoder. - Saga-1 sw-as24 is deliberately minimal: no labels, no comments in input, no operands, no directives, no symbol table, no two-pass. Every one of those is a later saga.
Steps (as run):
| # | Slug | Outcome |
|---|---|---|
| 1 | docs-foundation | docs/{prd,architecture,design,plan}.md (587 lines). |
| 2 | layout-skeleton | src/ tests/smoke/ scripts/ + .gitignore. |
| 3 | vendor-manifest | vendor/active.env, vendor/sw-em24/v0.1.0/version.json. |
| 4 | vendor-fetch-script | scripts/vendor-fetch.sh ported from ocaml; later extended with $SW_EM24_BIN override and system-PATH fallback. |
| 5 | justfile | Six recipes + default list. |
| 6 | build-script | scripts/build.sh with assembly-error propagation. |
| 7 | smoke-input | tests/smoke/nop.s + scripts/test.sh (multiple rewrites). |
| 8 | sw-as24-skeleton | src/sw-as24.s (106 bytes assembled). Adopted hex-ASCII output mid-step. |
| 9 | readme-revamp | README.md rewrite + ASCII cleanup sweep across all docs/*.md. |
| 10 | claude-md-revamp | CLAUDE.md rewrite; AgentRail protocol preserved byte-identical. |
| 11 | saga-close | This. |
Non-goals delivered-as-expected (from saga 1's design.md):
labels, comments in input, multiple mnemonics, operands, directives,
symbol table, two passes. All deferred to sagas 3-10 (renumbered
after saga 2 was inserted; originally written as sagas 2-9).
The ordering below is a current best guess. A stub may be split, merged, or reordered when it becomes current.
Not yet planned in detail. Authoritative step list will be written
into .agentrail/ when this saga starts.
Anticipated goal: move sw-as24 from its saga-1 "three-byte compare against the literal nop" to a real line-oriented parser. Outputs of this saga, in rough order of priority:
- Comment stripping (
;to end of line) so header-commented.sfiles can be fed without pre-processing. Restores the comment line that was stripped fromtests/smoke/nop.sin saga 1. - Line reader with a proper line-buffer size (pins Q2 from
architecture.mdfor the input buffer; symbol-table size still deferred). - Simple tokeniser: whitespace-separated mnemonic + operands, comma-separated operands.
- Expand recognised mnemonic set from 1 to a small handful
(
nop, and enough printable-zero-operand peers likehalt/ register-onlypush r0/pop r0that the saga is non-trivial). - Extend
src/sw-as24.swith a properbyte_to_hex_pairhelper (currently hard-coded to emit "FF" or "00"); grows as soon as more than two output byte values exist. - First shared bit-fiddling primitive that
sw-hexload(future, seedocs/utility.md) can also consume: nibble_to_ascii and ascii_to_nibble. - Pick up Q3 (pass-1 caching strategy) from
architecture.mdwhen the tokeniser begins to retain state.
Anticipated non-goals: symbol tables, forward references, the full register parser, addressing-mode parsing, two-pass scanning, directives. Those land in sagas 4-7.
Parse the legal register names (r0, r1, r2, fp, sp,
z, iv, ir, and the c condition flag where applicable),
and the offset(base) addressing form. Exercises the first real
operand decoding logic. The selector integers 0..7 used by the
decode ROM are an implementation detail; never accept r3..r7
as input tokens.
Encode every mnemonic that has only register (or no) operands.
Includes the ALU group (add, sub, mul, and, or, xor,
shl, sra, srl), the comparison group (ceq, cls, clu),
the extension group (sxt, zxt), and mov / push / pop.
nop (byte 0xFF) lands here too.
Encode mnemonics that carry immediate operands or offset-base
addressing: lc, lcu, la, lb, lbu, lw, sb, sw.
Implement pass 1 (label collection + address assignment) and pass 2 (emission with known-symbol resolution). Forward references still unsupported; they error rather than silently mis-encode.
Record and patch forward references for branches (rel8) and la
(abs24). Report unresolved symbols and out-of-range branches.
Encode bra, brt, brf, jmp, jal (depending on operand form
and whether the symbol table already resolves the target from
saga 7 / 8 -- exact split pinned when this saga becomes current).
Includes the branch-too-far rewrite (docs/as24-language.md §5.4)
that as24.c's fixbra() implements.
Implement .byte, .word, .comm; silently accept the
no-op directives (.text, .data, .bss, .globl). Handle the
location-counter bump . = . + N.
Line numbers on every error, aggregation, non-zero exit on failure,
exhaustive error-category taxonomy. Match as24.c's ? Line N:
error format (docs/as24-language.md §6). Tests with deliberately
malformed inputs.
Resolve Q1 from architecture.md and the open questions in
docs/self-host-toolchain.md. Choose standalone UART or
monitor-hosted and wire the chosen I/O path into sw-as24.s.
Wire up the REST oracle per docs/oracle-protocol.md. Collect
.s inputs from sw-cor24-forth, sw-cor24-macrolisp,
sw-cor24-pascal, sw-cor24-pcode, sw-cor24-script,
sw-cor24-yocto-ed, and the emulator examples. Assemble each
with both sw-as24 and the oracle (as24.c via REST); require
byte-identical output. Fix divergences.
sw-as24 assembles its own source (src/sw-as24.s) and the
resulting binary is byte-identical to the oracle's output for the
same source. Triggers the PRD's S3 success criterion.
Tag a 0.1.0, write CHANGES.md, update
sw-cor24-project/docs/status.md to mark the native assembler
complete, and publish to GitHub. The vendor pin in active.env
moves from cor24-rs to a real sw-cor24-x-assembler release
artifact once one exists (assuming x-assembler has landed a
[[bin]] target by then).
- 2026-04-18: Initial draft landed as part of the Relaunch saga.
- 2026-04-18: Relaunch saga (saga 1) closed.
just testgreen end-to-end from cold vendor state. sw-as24 recognisesnopand emits hex-ASCII "SFF" on UART, decoded to the byte-identical0xFFmachine code thatcor24-run --assembleproduces. Saga 2 (Lexer and line parsing) promoted to current. Feature branchfeat/relaunch-projectrenamed topr/relaunchfor the release engineer to merge intodev. - 2026-04-18: Specs-foundation saga inserted as the new saga 2. The lexer saga previously labelled saga 2 is now saga 3; every downstream saga shifts by +1 (final count = 15). Motivation: the ISA / language / format / runtime specs serve multiple downstream sagas and warrant their own close rather than being bundled into lexer work.
- 2026-05-16: Assemblers-checkpoint doc landed
(
docs/assemblers-checkpoint.md). Captures the three-project cross-repo bootstrap model (dcxas, dcasm, dchla), the demo ladder (Rungs 1–3), and current blockers. Does not change the saga roadmap.