Files
LithosAnanke/v4/src/iword.c
T
Claude 3bd81097e1 chore(license): an SPDX header on every source file that had none (LicenseRef-Starship-1.0) [skip ci]
The header scan (Captain Bob, 2026-11-10): 788 source files -- 351 with the
SL-1.0 header, 12 with the old name (docs/working/experiments, kept by
ruling), 31 under someone else's licence (tools/kconfig, Linux's, GPL-2.0:
kept), and 394 with none. Ruled: the SPDX form; capsules (.4th, .f18) and
proofs (.thy) left for a ruling of their own (mkcapsule's 64x16 block format,
content-addressed capsules).

253 files now begin
    SPDX-License-Identifier: LicenseRef-Starship-1.0
    Copyright (c) 2023-2026 Robert A. James
as a /* */ block (C, headers, assembly, linker scripts) or # lines (scripts,
Makefiles, Kconfig; below a shebang or a coding line); tools/mkcapsule.c,
which had the copyright line, gets the SPDX line only.

Not touched: docs/working/ (archive and old campaign material, as the
ruling kept the experiments); v4/system/post_cases.c (generated by
v4/tools/mkpost.py, "do not edit" -- the generator has the header).

Comments only: the kernel builds on amd64, aarch64, riscv64; make -C v4
test-32: 39 programs, 0 failures; every changed script parses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
2026-11-10 04:12:49 +00:00

78 lines
2.6 KiB
C

/* SPDX-License-Identifier: LicenseRef-Starship-1.0
* Copyright (c) 2023-2026 Robert A. James
*/
/* iword.c -- instruction-word decode. See iword.h for the layout. */
#include "v4/iword.h"
/* The five opcodes that consume a target from the low bits of their slot
* (section 1.2): jump, call, next, if, -if. A table rather than a switch so
* that the set is visible in one place and can be counted in the tests. */
int v4_op_is_branch(unsigned op)
{
return op == V4_OP_JUMP || op == V4_OP_CALL || op == V4_OP_NEXT
|| op == V4_OP_IF || op == V4_OP_MINUS_IF;
}
int v4_iword_branch_legal(unsigned slot)
{
return slot < 4u; /* section 1.2: branches are legal in slots 0-3 only */
}
uint32_t v4_iword_slot_mask(unsigned slot)
{
if (slot >= V4_SLOT_COUNT) return 0u;
/* 27-5k address bits, e.g. 0x07FFFFFF for slot 0 down to 0x00000FFF for
* slot 3. For slots 4 and 5 the formula still produces 7 and 2 bits; the
* legality check is separate because those slots are simply not usable. */
return ((uint32_t)1u << V4_BRANCH_ADDR_BITS(slot)) - 1u;
}
unsigned v4_iword_op(v4_iword w, unsigned slot)
{
if (slot >= V4_SLOT_COUNT) return 0u;
return (unsigned)((w >> V4_SLOT_LOW_BIT(slot)) & 0x1Fu);
}
unsigned v4_iword_spare(v4_iword w)
{
return (unsigned)(w & ((1u << V4_SPARE_BITS) - 1u));
}
v4_iword v4_iword_target(v4_iword w, unsigned slot)
{
if (slot >= V4_SLOT_COUNT) return 0u;
return w & v4_iword_slot_mask(slot);
}
v4_iword v4_iword_assemble(const unsigned op[V4_SLOT_COUNT], unsigned spare)
{
v4_iword w = 0u;
for (unsigned k = 0; k < V4_SLOT_COUNT; k++) {
/* An opcode that does not fit in 5 bits is a bug in whoever built the
* word, not something to encode silently. Truncating here would let a
* malformed capsule execute as something else. */
if (op[k] > 0x1Fu) return 0xFFFFFFFFu;
w |= (v4_iword)(op[k] & 0x1Fu) << V4_SLOT_LOW_BIT(k);
}
if (spare > ((1u << V4_SPARE_BITS) - 1u)) return 0xFFFFFFFFu;
w |= (v4_iword)(spare & ((1u << V4_SPARE_BITS) - 1u));
return w;
}
v4_cell v4_iword_branch(v4_cell p, v4_iword w, unsigned slot)
{
uint32_t mask = v4_iword_slot_mask(slot);
v4_ucell up = (v4_ucell)p;
/* Page-relative, as in the F18: the target supplies the low
* V4_BRANCH_ADDR_BITS(slot) bits of P and the bits above them survive. The
* mask is computed in 32 bits and widened, so a 64-bit P keeps its high
* half -- which is the correct reading of "replaces the same low bits of P"
* at any cell width. */
up = (up & ~(v4_ucell)mask) | (v4_ucell)(w & mask);
return (v4_cell)up;
}