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
120 lines
3.7 KiB
C
120 lines
3.7 KiB
C
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
|
* Copyright (c) 2023-2026 Robert A. James
|
|
*/
|
|
/* stack.c -- F18 circular hardware stacks.
|
|
*
|
|
* The two decompositions (T/S + 8-ring, R + 8-ring) are exactly equivalent to
|
|
* flat circular buffers of depth 10 and 9 respectively. The argument, since
|
|
* the ISA is specified in terms of the decomposition and the differential
|
|
* test in tests/test_stack.c is written against the flat form:
|
|
*
|
|
* Data stack, 10 deep. Read the stack top to bottom as
|
|
*
|
|
* T, S, ring[(head-1) mod 8], ring[(head-2) mod 8], ..., ring[head mod 8]
|
|
*
|
|
* -- that is, ring[(head-1) mod 8] sits immediately below S, and head names
|
|
* the oldest slot. push(x) does ring[head]=S; S=T; T=x; head=(head+1) mod 8,
|
|
* which appends at the top and rotates the oldest entry into the ring.
|
|
* pop() takes T, promotes S, and pulls ring[(head-1) mod 8] up into S while
|
|
* stepping head back one -- so the element that was third becomes second and
|
|
* the ring is re-seated one position earlier. That is a 10-slot circular
|
|
* buffer whose slot 0 is T and slot 1 is S, and the head arithmetic is
|
|
* bookkeeping for which ring slot is oldest.
|
|
*
|
|
* Return stack, 9 deep, same argument with one register instead of two: the
|
|
* stack reads R, ring[(head-1) mod 8], ..., ring[head mod 8].
|
|
*
|
|
* "No overflow or underflow; pushing past the bottom silently overwrites the
|
|
* oldest entry" (D-2) is not an extra rule here -- it is what a fixed-depth
|
|
* circular buffer with no bounds check does on its own, once the pointer is
|
|
* allowed to wrap. Nothing below tests head against anything.
|
|
*/
|
|
#include "v4/stack.h"
|
|
|
|
void v4_dstack_reset(v4_dstack *st)
|
|
{
|
|
st->t = 0;
|
|
st->s = 0;
|
|
st->head = 0;
|
|
st->depth = 0;
|
|
for (unsigned i = 0; i < V4_DATA_RING; i++) st->ring[i] = 0;
|
|
v4_guard_fill(st->guard_head, V4_DATA_BOUND, V4_GUARD_PATTERN_HEAD);
|
|
v4_guard_fill(st->guard_tail, V4_DATA_BOUND, V4_GUARD_PATTERN_TAIL);
|
|
}
|
|
|
|
int v4_dstack_guards_intact(const v4_dstack *st)
|
|
{
|
|
return v4_guard_intact(st->guard_head, V4_DATA_BOUND, V4_GUARD_PATTERN_HEAD)
|
|
&& v4_guard_intact(st->guard_tail, V4_DATA_BOUND, V4_GUARD_PATTERN_TAIL);
|
|
}
|
|
|
|
void v4_dstack_push(v4_dstack *st, v4_cell x)
|
|
{
|
|
st->ring[st->head] = st->s;
|
|
st->s = st->t;
|
|
st->t = x;
|
|
st->head = (st->head + 1u) % V4_DATA_RING;
|
|
if (st->depth < V4_DATA_DEPTH) st->depth++;
|
|
}
|
|
|
|
void v4_dstack_clear(v4_dstack *st) { st->depth = 0; }
|
|
void v4_rstack_clear(v4_rstack *st) { st->depth = 0; }
|
|
|
|
v4_cell v4_dstack_pop(v4_dstack *st)
|
|
{
|
|
v4_cell x = st->t;
|
|
st->t = st->s;
|
|
st->head = (st->head + V4_DATA_RING - 1u) % V4_DATA_RING;
|
|
st->s = st->ring[st->head];
|
|
if (st->depth > 0) st->depth--;
|
|
return x;
|
|
}
|
|
|
|
v4_cell v4_dstack_peek(const v4_dstack *st)
|
|
{
|
|
return st->t;
|
|
}
|
|
|
|
v4_cell v4_dstack_peek2(const v4_dstack *st)
|
|
{
|
|
return st->s;
|
|
}
|
|
|
|
void v4_rstack_reset(v4_rstack *st)
|
|
{
|
|
st->r = 0;
|
|
st->head = 0;
|
|
st->depth = 0;
|
|
for (unsigned i = 0; i < V4_RET_RING; i++) st->ring[i] = 0;
|
|
v4_guard_fill(st->guard_head, V4_RET_BOUND, V4_GUARD_PATTERN_HEAD);
|
|
v4_guard_fill(st->guard_tail, V4_RET_BOUND, V4_GUARD_PATTERN_TAIL);
|
|
}
|
|
|
|
int v4_rstack_guards_intact(const v4_rstack *st)
|
|
{
|
|
return v4_guard_intact(st->guard_head, V4_RET_BOUND, V4_GUARD_PATTERN_HEAD)
|
|
&& v4_guard_intact(st->guard_tail, V4_RET_BOUND, V4_GUARD_PATTERN_TAIL);
|
|
}
|
|
|
|
void v4_rstack_push(v4_rstack *st, v4_cell x)
|
|
{
|
|
st->ring[st->head] = st->r;
|
|
st->r = x;
|
|
st->head = (st->head + 1u) % V4_RET_RING;
|
|
if (st->depth < V4_RET_DEPTH) st->depth++;
|
|
}
|
|
|
|
v4_cell v4_rstack_pop(v4_rstack *st)
|
|
{
|
|
v4_cell x = st->r;
|
|
st->head = (st->head + V4_RET_RING - 1u) % V4_RET_RING;
|
|
st->r = st->ring[st->head];
|
|
if (st->depth > 0) st->depth--;
|
|
return x;
|
|
}
|
|
|
|
v4_cell v4_rstack_peek(const v4_rstack *st)
|
|
{
|
|
return st->r;
|
|
}
|