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
78 lines
2.6 KiB
C
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;
|
|
}
|