Files
LithosAnanke/v4/include/v4/iword.h
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

105 lines
4.9 KiB
C

/* SPDX-License-Identifier: LicenseRef-Starship-1.0
* Copyright (c) 2023-2026 Robert A. James
*/
/* iword.h -- the 32-bit instruction word and its decode.
*
* DECOMPOSITION.md section 1.2:
*
* 31 27 26 22 21 17 16 12 11 7 6 2 1 0
* +--------+--------+--------+--------+--------+--------+----+
* | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | xx |
* +--------+--------+--------+--------+--------+--------+----+
*
* "Slots execute left to right. A branch (jump, call, next, if, -if) takes
* its target from all bits to the right of its slot, and that target replaces
* the same low bits of P (page-relative, as in the F18). Branches are
* therefore legal in slots 0-3 only", with reach 27 / 22 / 17 / 12 bits.
*
* That reach column is not a separate rule, it falls out of the layout: slot k
* sits at bits [31-5k : 27-5k], so the bits to its right are [26-5k : 0],
* which is 27-5k bits -- 27, 22, 17, 12 for slots 0..3. This header derives
* the masks from that one formula rather than hard-coding four of them, so the
* decode cannot drift from the reach table.
*
* THE SPARE BITS ARE ADDRESS BITS. "Spare" means only that they are never
* *executed*: they are below every slot, so "all bits to the right of its
* slot" includes them, and they are the low bits of the address of a branch in
* any slot. They are inert for opcode decode and live in a branch target.
* This is easy to assume otherwise and get wrong -- an earlier revision of
* this header subtracted them from the branch width, which silently cost two
* address bits off every branch and was caught by tests/test_iword.c. They
* exist because 6*5 = 30 does not fill a 32-bit word, and on the F18 those low
* bits are simply the bottom of the address space.
*
* The consequence for the compiler is worth stating: a non-branch slot's low
* bits are free to carry a compressed argument, but a branch slot's are not,
* because they are address.
*
* NOTE ON WIDTH. The word format is 32 bits regardless of V4_CELL_BITS: the
* diagram is 32 bits wide and 6*5+2 = 32 exactly. D-5 makes the *cell* width
* a build parameter, but the instruction word is not a payload and does not
* follow the cell. At 32-bit cells a word is a cell. At 64-bit cells it is
* the low 32 bits of the cell and the high half is ignored (D-9), so compiled
* code is identical at both widths. The decode below operates on a distinct
* 32-bit type; the fetch in exec.c does the narrowing.
*/
#ifndef V4_IWORD_H
#define V4_IWORD_H
#include <stdint.h>
#include "v4/cell.h"
#include "v4/opcode.h"
/* The instruction word is 32 bits at every cell width. */
typedef uint32_t v4_iword;
#define V4_SLOT_COUNT 6u /* six 5-bit slots, DECOMPOSITION.md 1.1 */
#define V4_SPARE_BITS 2u /* "plus 2 spare bits" */
/* C99 has no _Static_assert, so the "6*5+2 == 32" identity is enforced with
* the negative-array-size idiom. If the slot count, the spare-bit count or the
* word width ever stop adding up to 32, this fails to compile. */
typedef char v4_iword_layout_is_exact
[((V4_SLOT_COUNT * 5u + V4_SPARE_BITS) == 32u) ? 1 : -1];
/* Bit range of slot k: high bit 31-5k, low bit 27-5k. */
#define V4_SLOT_HIGH_BIT(k) (31u - 5u * (k))
#define V4_SLOT_LOW_BIT(k) (27u - 5u * (k))
/* Number of address bits a branch in slot k carries: all bits to the right of
* the slot. Slot k's low bit is 27-5k, so the bits below it are 0..(26-5k),
* which is 27-5k bits -- equal to the slot's own low bit. This is the single
* source of the reach column, and it is why the spare bits are *not* subtracted
* here: see the note on the spare bits below. */
#define V4_BRANCH_ADDR_BITS(k) (V4_SLOT_LOW_BIT(k))
/* Mask of the low address bits a branch in slot k replaces in P. */
uint32_t v4_iword_slot_mask(unsigned slot);
/* The 5-bit opcode in slot k, 0..31. */
unsigned v4_iword_op(v4_iword w, unsigned slot);
/* The 2 spare low bits. Never executed. */
unsigned v4_iword_spare(v4_iword w);
/* The branch target carried by a branch in slot k: all bits to the right of
* the slot, zero-extended. Meaningful only for the five branch opcodes. */
v4_iword v4_iword_target(v4_iword w, unsigned slot);
/* Assemble a word from six 5-bit opcodes and the 2 spare bits. Opcode values
* above 31 or spare bits above 3 are rejected, because a golden model must not
* paper over an out-of-range encoding. */
v4_iword v4_iword_assemble(const unsigned op[V4_SLOT_COUNT], unsigned spare);
/* Apply a branch: replace the low V4_BRANCH_ADDR_BITS(slot) bits of P with the
* target, preserving the bits above (page-relative, F18-style). */
v4_cell v4_iword_branch(v4_cell p, v4_iword w, unsigned slot);
/* Branches are legal in slots 0-3 only (section 1.2). Slots 4 and 5 have 7 and
* 2 address bits respectively, which is not a useful reach and is not
* sanctioned by the table. */
int v4_iword_branch_legal(unsigned slot);
#endif /* V4_IWORD_H */