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
119 lines
2.9 KiB
C
119 lines
2.9 KiB
C
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
|
* Copyright (c) 2023-2026 Robert A. James
|
|
*/
|
|
/* asm.c -- slot packer for test programs. See asm.h. */
|
|
#include "v4/asm.h"
|
|
|
|
static void put(v4_asm *as, unsigned op)
|
|
{
|
|
as->cur |= (v4_iword)(op & 0x1Fu) << V4_SLOT_LOW_BIT(as->slot);
|
|
as->slot++;
|
|
}
|
|
|
|
static void emit(v4_asm *as, v4_cell value)
|
|
{
|
|
if (as->here < 0 || (v4_ucell)as->here >= V4_NODE_WORDS) {
|
|
as->error = 1;
|
|
return;
|
|
}
|
|
v4_node_store(as->n, as->here, value);
|
|
as->here++;
|
|
}
|
|
|
|
/* Write out the word being built, then the literals it owes. */
|
|
static void flush(v4_asm *as)
|
|
{
|
|
if (as->slot == 0) return;
|
|
while (as->slot < V4_SLOT_COUNT) put(as, V4_OP_NOP);
|
|
emit(as, (v4_cell)as->cur);
|
|
for (unsigned i = 0; i < as->nlit; i++) emit(as, as->lit[i]);
|
|
as->cur = 0;
|
|
as->slot = 0;
|
|
as->nlit = 0;
|
|
}
|
|
|
|
/* 1 if a branch in `slot`, executing with P = p, can reach `target`. */
|
|
static int reachable(v4_cell p, unsigned slot, v4_cell target)
|
|
{
|
|
v4_ucell mask = (v4_ucell)v4_iword_slot_mask(slot);
|
|
return (((v4_ucell)p ^ (v4_ucell)target) & ~mask) == 0;
|
|
}
|
|
|
|
void v4_asm_begin(v4_asm *as, v4_node *n, v4_cell origin)
|
|
{
|
|
as->n = n;
|
|
as->here = origin;
|
|
as->cur = 0;
|
|
as->slot = 0;
|
|
as->nlit = 0;
|
|
as->error = 0;
|
|
}
|
|
|
|
void v4_asm_op(v4_asm *as, unsigned op)
|
|
{
|
|
if (op >= V4_OPCODE_COUNT || v4_op_is_branch(op) || op == V4_OP_FETCH_P) {
|
|
as->error = 1;
|
|
return;
|
|
}
|
|
put(as, op);
|
|
if (op == V4_OP_SEMI || op == V4_OP_EX || as->slot == V4_SLOT_COUNT) flush(as);
|
|
}
|
|
|
|
void v4_asm_lit(v4_asm *as, v4_cell value)
|
|
{
|
|
put(as, V4_OP_FETCH_P);
|
|
as->lit[as->nlit++] = value;
|
|
if (as->slot == V4_SLOT_COUNT) flush(as);
|
|
}
|
|
|
|
v4_asm_ref v4_asm_branch_fwd(v4_asm *as, unsigned op)
|
|
{
|
|
v4_asm_ref ref;
|
|
|
|
if (!v4_op_is_branch(op)) as->error = 1;
|
|
if (!v4_iword_branch_legal(as->slot)) flush(as);
|
|
|
|
ref.addr = as->here;
|
|
ref.slot = as->slot;
|
|
/* The word has been fetched and every literal before the branch consumed
|
|
* by the time the branch executes. */
|
|
ref.p = as->here + 1 + (v4_cell)as->nlit;
|
|
|
|
put(as, op);
|
|
as->slot = V4_SLOT_COUNT; /* the rest of the word is address */
|
|
flush(as);
|
|
return ref;
|
|
}
|
|
|
|
void v4_asm_resolve(v4_asm *as, v4_asm_ref ref, v4_cell target)
|
|
{
|
|
v4_ucell mask = (v4_ucell)v4_iword_slot_mask(ref.slot);
|
|
v4_ucell word;
|
|
|
|
if (as->error) return;
|
|
if (!reachable(ref.p, ref.slot, target)) {
|
|
as->error = 1;
|
|
return;
|
|
}
|
|
word = (v4_ucell)v4_node_load(as->n, ref.addr);
|
|
word = (word & ~mask) | ((v4_ucell)target & mask);
|
|
v4_node_store(as->n, ref.addr, (v4_cell)word);
|
|
}
|
|
|
|
void v4_asm_branch(v4_asm *as, unsigned op, v4_cell target)
|
|
{
|
|
v4_asm_resolve(as, v4_asm_branch_fwd(as, op), target);
|
|
}
|
|
|
|
v4_cell v4_asm_label(v4_asm *as)
|
|
{
|
|
flush(as);
|
|
return as->here;
|
|
}
|
|
|
|
int v4_asm_ok(v4_asm *as)
|
|
{
|
|
flush(as);
|
|
return !as->error;
|
|
}
|