Repository navigation
ogar-r2il: R2IL as an ogar-loco Vocabulary + the masked lane projection - #285
Merged
Merged
Conversation
New ConceptDomain::Mmio at 0xC6 (one hex digit short of the C64, the deliberate slot choice — same naming move as C4's blast radius). Four container-KIND slots per the 0x08XX OCR precedent: mmio_chip (0xC601), mmio_register (0xC602), rom_image (0xC603), machine_memory_map (0xC604). Concrete VIC-II/SID/CIA registers and the 6502 mnemonics stay CONTENT rows — $D021 is data read through the ClassView, never a classid. Provenance fence mirrors C4's, widened deliberately: MIT implementations (rust64) and vendor datasheets are lawful mint sources; GPL emulators remain behavioral reference only. Both ALL-count pins bumped 93 -> 97; domain-routing tests pin C600/C6FF and the C5/C7 edges (the C5 hole stays open by intent). The lance-graph ogar_codebook mirror needs the same four rows before its assert_codebook_parity consumer gate re-runs against this vocab — noted here, landed as its own PR there.
ogar-loco's own doc names the seam this fills: it is "everything that is the
same no matter what the bytes mean", with "a vocabulary per domain, declared
by whoever owns it" plugging into the Vocabulary trait. R2IL is such a
domain. This crate mints no node layout, no lane carving, no call encoding
and no second addressing system - it is the sibling codebook that seam was
cut for.
ALWAYS ON: no feature gate, no optional dep, no cfg. A vocabulary that must
be switched on is one a caller can forget to switch on. R2ILVocabulary is
zero-sized, so the cheapness is real rather than asserted.
NO r2sleigh DEPENDENCY, deliberately. What loco needs from r2il's opcode
enum is an arity table, and depending on the crate would drag its
Varnode/SpaceId/ArchSpec object graph into every consumer that only wanted
to know IntAdd pops two - the graph ruff_r2il's own docs call "structurally
still stage-1 pointer chasing". The coupling is by NAME, guarded by a test
that parses r2il/src/opcode.rs.
THE TABLE IS DERIVED, NOT REMEMBERED - and the first draft proves why that
matters. It was written from memory: 77 entries against an enum of 82, five
variants missing (LoadGuarded, Subpiece, Float2Int, Multiequal, Extract, ...)
and nine invented (Switch, Halt, AtomicRmw, ...). The shipped table is
generated from the enum's own field structure: arity = count of Varnode
INPUT fields, pushes_result = presence of dst/output/result. CallOther and
Multiequal carry Vec<Varnode>, so their arity is None (Vocabulary's own
"not covered - refused"), never 0 - a 0 would have read as nullary.
Arithmetic opcodes are NOT aliased onto the shared core's ADD. The core's
ADD is loco's semantics; R2IL's IntAdd carries a machine's flag/width
behaviour the core never promised. Same word, two contracts - aliasing them
is the "same name, different semantics" trap I-LEGACY-API-FEATURE-GATED
catalogues.
THE MASKED LANE PROJECTION ("reshuffling"). call_in_slab already reads call
i under a shape; this adds the masked, lazy form: project(slab, shape, mask)
-> Iterator<(index, Call)>. Nothing outside the mask is decoded, no Vec is
built. CallMask is Box<[u64]> over call indices with the same algebra and
the same single named materializer as every other mask plane here. Indices
are shape-relative, so the shape is carried rather than inferred.
Reshuffling is a re-READ, never a re-WRITE: project takes &[u8] and returns
an iterator, so the same slab under two shapes is two reads of unchanged
bytes. A shape is a lens, not a migration.
10 tests. Five disable runs verified red-then-green: a mnemonic reverted to
the invented name, variadic reported as nullary, complement keeping phantom
tail bits, the mask ignored, the vocabulary claiming shared-core bytes. The
drift test was confirmed to actually parse r2sleigh rather than hit its
skip-if-absent path, and asserts a plausible variant count before comparing
so a moved file degrades to a loud skip instead of a silent pass.
clippy --all-targets -D warnings clean; fmt clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCfrD5y19cvFc4AoyydXYv
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_60936d32-8a03-4152-b508-d9da37e2d43e) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The seam this fills was already cut
ogar-loco's own module doc names it: the crate is "everything that is the same no matter what the bytes mean", with "a vocabulary per domain, declared by whoever owns it" plugging into theVocabularytrait. R2IL is such a domain. This crate mints no node layout, lane carving, call encoding or second addressing system — it is the sibling codebook that seam exists for.Always on: no feature gate, no
optional = true, nocfg. A vocabulary that must be switched on is one a caller can forget to switch on.R2ILVocabularyis zero-sized, so the cheapness is real rather than asserted.No r2sleigh dependency, deliberately
What loco needs from
r2il's opcode enum is an arity table. Depending on the crate would drag itsVarnode/SpaceId/ArchSpecobject graph into every consumer that only wanted to know thatIntAddpops two — the graphruff_r2il's own doc calls "structurally still stage-1 pointer chasing". The coupling is by name, guarded by a test that parsesr2il/src/opcode.rs.The table is derived, and the first draft proves why that matters
I wrote it from memory first. Against an enum of 82 it had 77 entries — five variants missing (
LoadGuarded,Subpiece,Float2Int,Multiequal,Extract, …) and nine invented (Switch,Halt,AtomicRmw, …). That is the invented-data failure the data-as-config rule exists for, caught before it shipped.The shipped table is generated from the enum's own field structure: arity = count of
Varnodeinput fields (dst/output/resultexcluded, being the push side);pushes_result= presence of one.Nonemeans variadic, not zero.CallOtherandMultiequalcarryinputs: Vec<Varnode>— their operand count is a per-site property no table can hold.NoneisVocabulary's own "not covered (refused)", so a body using them is refused rather than silently treated as nullary, which a0would have meant.Arithmetic is not aliased onto the shared core's
ADD. The core'sADDis loco's semantics; R2IL'sIntAddcarries a machine's flag/width behaviour the core never promised. Same word, two contracts — aliasing them is the "same name, different semantics" trapI-LEGACY-API-FEATURE-GATEDcatalogues five instances of.The masked lane projection
call_in_slabalready reads calliunder a shape — the reshuffle primitive existed. This adds the masked, lazy form:Nothing outside the mask is decoded; no
Vec<Call>is built.CallMaskisBox<[u64]>over call indices with the same algebra and the same single named materializer as every other mask plane in this workspace. Indices are shape-relative, so the shape is carried rather than inferred.Reshuffling is a re-READ, never a re-WRITE —
projectborrows&[u8]and returns an iterator, so the same slab under two shapes is two reads of unchanged bytes. A shape is a lens, not a migration, andthe_same_bytes_project_differently_under_two_shapespins exactly that.Falsifiers
10 tests. Five disable runs, each verified red-then-green:
the_table_matches_r2il_s_own_enumvariadic_opcodes_are_refused_rather_than_called_nullaryNone→unwrap_or(0)a_complement_never_invents_call_slotsthe_projection_yields_exactly_the_masked_callsa_body_with_no_r2il_calls_masks_to_nothingThe drift test was confirmed to actually parse r2sleigh rather than hit its skip-if-absent path, and asserts a plausible variant count (>40) before comparing — so a moved file degrades to a loud skip instead of a silent pass.
Gates
cargo test -p ogar-r2il10/10 ·clippy --all-targets -D warningsclean ·fmt --checkclean.🤖 Generated with Claude Code
https://claude.ai/code/session_01DCfrD5y19cvFc4AoyydXYv
Generated by Claude Code