Files
LithosAnanke/v4/src/asm.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

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;
}