Reorganize source tree: kernel/, v3/, v4/ split and board infrastructure

Source tree reorganization:
- Move StarForth v3 engine to v3/ (src/, include/, Makefile)
- Move kernel to kernel/ (src/, include/, linker/, Makefile)
- Create v4/ skeleton for F18-ISA golden model (DECOMPOSITION.md, JUSTIFICATION.md)
- Move FABRIC-0..4.md to docs/fabric/
- Move ONTOLOGY.md and ROADMAP.md to docs/

Board infrastructure:
- Add boards/ser5/, boards/raspi/, boards/milkv/, boards/zynq7020/
- Each board has board.mk (ISA, CPU flags, boot recipe) and README.md
- Root Makefile becomes thin dispatcher: boot_image, all, clean, docs take TARGET
- make boot_image TARGET=SER5|RASPI|MILKV builds one GPT/MBR image per board
- ZYNQ7020 target exists but stops with clear error (ARMv7 port not built yet)
- scripts/mkdiskimage.sh builds disk images for all boards

Docs pipeline:
- docs/book/ with LaTeX master (main.tex) and Makefile
- pandoc converts Markdown to LaTeX at build time
- Two Lua filters: table-widths.lua (wide tables wrap), code-breaks.lua (inline code breaks)
- make docs builds single PDF (754 pages, 0 missing characters)
- make docs TARGET=<board> adds board appendix
- build/docs/<book|board>/meta.tex stamps git commit into PDF

Bug fixes:
- 42 include paths that only worked by accident now use correct relative paths
- clang-18 hardcode replaced with configurable CC variable (fixed aarch64 build)
- Pi 5: kernel_2712.img linked at 0x80000, .bss zeroed, memory reserved
- Doxyfile, .clang-tidy, README.md, Kconfig paths updated

Verified:
- Hosted v3 build passes 1012 tests, 0 failures
- SER5 image boots in QEMU (OVMF), POST passes, K exact (65536 = Q48_ONE)
- Milk-V image boots in QEMU (OpenSBI + U-Boot + bootefi), POST passes
- make clean TARGET=<board> removes only that board and its ISA objects
- make all builds all boards, hosted v3, and docs in one run

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
rajames
2026-10-01 15:40:09 -04:00
co-authored by Junie
parent 3c709c115b
commit a8b70e88d3
630 changed files with 2646 additions and 2036 deletions
+5
View File
@@ -0,0 +1,5 @@
# src/starkernel/hash/
- `xxhash64.c` — XXHash64 implementation used for capsule content
addressing (a capsule's ID is the XXHash64 of its content; any mutation
is detectable) and for dictionary-hash comparison in parity records.
+285
View File
@@ -0,0 +1,285 @@
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 2023–2025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* xxhash64.c - Freestanding xxHash64 Implementation
*
* Based on xxHash by Yann Collet (BSD-2-Clause).
* Adapted for freestanding kernel use - no libc dependency.
*
* xxHash is an extremely fast non-cryptographic hash algorithm.
* https://github.com/Cyan4973/xxHash
*/
#include "starkernel/xxhash64.h"
/*===========================================================================
* xxHash64 Constants
*===========================================================================*/
#define XXHASH64_PRIME1 0x9E3779B185EBCA87ULL
#define XXHASH64_PRIME2 0xC2B2AE3D27D4EB4FULL
#define XXHASH64_PRIME3 0x165667B19E3779F9ULL
#define XXHASH64_PRIME4 0x85EBCA77C2B2AE63ULL
#define XXHASH64_PRIME5 0x27D4EB2F165667C5ULL
/*===========================================================================
* Helper Functions
*===========================================================================*/
/**
* Rotate left 64-bit
*/
static inline uint64_t xxh64_rotl(uint64_t x, int r) {
return (x << r) | (x >> (64 - r));
}
/**
* Read 64-bit little-endian (unaligned safe)
*/
static inline uint64_t xxh64_read64(const uint8_t *p) {
return ((uint64_t)p[0]) |
((uint64_t)p[1] << 8) |
((uint64_t)p[2] << 16) |
((uint64_t)p[3] << 24) |
((uint64_t)p[4] << 32) |
((uint64_t)p[5] << 40) |
((uint64_t)p[6] << 48) |
((uint64_t)p[7] << 56);
}
/**
* Read 32-bit little-endian (unaligned safe)
*/
static inline uint32_t xxh64_read32(const uint8_t *p) {
return ((uint32_t)p[0]) |
((uint32_t)p[1] << 8) |
((uint32_t)p[2] << 16) |
((uint32_t)p[3] << 24);
}
/**
* Round function
*/
static inline uint64_t xxh64_round(uint64_t acc, uint64_t input) {
acc += input * XXHASH64_PRIME2;
acc = xxh64_rotl(acc, 31);
acc *= XXHASH64_PRIME1;
return acc;
}
/**
* Merge accumulator
*/
static inline uint64_t xxh64_merge_round(uint64_t acc, uint64_t val) {
val = xxh64_round(0, val);
acc ^= val;
acc = acc * XXHASH64_PRIME1 + XXHASH64_PRIME4;
return acc;
}
/**
* Avalanche finalization
*/
static inline uint64_t xxh64_avalanche(uint64_t h) {
h ^= h >> 33;
h *= XXHASH64_PRIME2;
h ^= h >> 29;
h *= XXHASH64_PRIME3;
h ^= h >> 32;
return h;
}
/*===========================================================================
* One-Shot Hashing
*===========================================================================*/
uint64_t xxhash64(const void *data, size_t len, uint64_t seed) {
const uint8_t *p = (const uint8_t *)data;
const uint8_t *end = p + len;
uint64_t h64;
if (len >= 32) {
const uint8_t *limit = end - 32;
uint64_t v1 = seed + XXHASH64_PRIME1 + XXHASH64_PRIME2;
uint64_t v2 = seed + XXHASH64_PRIME2;
uint64_t v3 = seed + 0;
uint64_t v4 = seed - XXHASH64_PRIME1;
do {
v1 = xxh64_round(v1, xxh64_read64(p));
p += 8;
v2 = xxh64_round(v2, xxh64_read64(p));
p += 8;
v3 = xxh64_round(v3, xxh64_read64(p));
p += 8;
v4 = xxh64_round(v4, xxh64_read64(p));
p += 8;
} while (p <= limit);
h64 = xxh64_rotl(v1, 1) + xxh64_rotl(v2, 7) +
xxh64_rotl(v3, 12) + xxh64_rotl(v4, 18);
h64 = xxh64_merge_round(h64, v1);
h64 = xxh64_merge_round(h64, v2);
h64 = xxh64_merge_round(h64, v3);
h64 = xxh64_merge_round(h64, v4);
} else {
h64 = seed + XXHASH64_PRIME5;
}
h64 += (uint64_t)len;
/* Process remaining 8-byte chunks */
while (p + 8 <= end) {
uint64_t k1 = xxh64_round(0, xxh64_read64(p));
h64 ^= k1;
h64 = xxh64_rotl(h64, 27) * XXHASH64_PRIME1 + XXHASH64_PRIME4;
p += 8;
}
/* Process remaining 4-byte chunk */
if (p + 4 <= end) {
h64 ^= (uint64_t)xxh64_read32(p) * XXHASH64_PRIME1;
h64 = xxh64_rotl(h64, 23) * XXHASH64_PRIME2 + XXHASH64_PRIME3;
p += 4;
}
/* Process remaining bytes */
while (p < end) {
h64 ^= (uint64_t)(*p) * XXHASH64_PRIME5;
h64 = xxh64_rotl(h64, 11) * XXHASH64_PRIME1;
p++;
}
return xxh64_avalanche(h64);
}
/*===========================================================================
* Streaming API
*===========================================================================*/
void xxhash64_reset(XXHash64State *state, uint64_t seed) {
state->total_len = 0;
state->v1 = seed + XXHASH64_PRIME1 + XXHASH64_PRIME2;
state->v2 = seed + XXHASH64_PRIME2;
state->v3 = seed + 0;
state->v4 = seed - XXHASH64_PRIME1;
state->buffer_size = 0;
state->seed = seed;
}
void xxhash64_update(XXHash64State *state, const void *data, size_t len) {
const uint8_t *p = (const uint8_t *)data;
const uint8_t *end = p + len;
state->total_len += len;
/* Fill buffer if we have leftover data */
if (state->buffer_size + len < 32) {
/* Not enough to process, just buffer it */
while (p < end) {
state->buffer[state->buffer_size++] = *p++;
}
return;
}
/* Process buffered data first */
if (state->buffer_size > 0) {
uint32_t fill = 32 - state->buffer_size;
for (uint32_t i = 0; i < fill; i++) {
state->buffer[state->buffer_size + i] = p[i];
}
p += fill;
state->v1 = xxh64_round(state->v1, xxh64_read64(state->buffer));
state->v2 = xxh64_round(state->v2, xxh64_read64(state->buffer + 8));
state->v3 = xxh64_round(state->v3, xxh64_read64(state->buffer + 16));
state->v4 = xxh64_round(state->v4, xxh64_read64(state->buffer + 24));
state->buffer_size = 0;
}
/* Process 32-byte blocks */
if (p + 32 <= end) {
const uint8_t *limit = end - 32;
do {
state->v1 = xxh64_round(state->v1, xxh64_read64(p));
p += 8;
state->v2 = xxh64_round(state->v2, xxh64_read64(p));
p += 8;
state->v3 = xxh64_round(state->v3, xxh64_read64(p));
p += 8;
state->v4 = xxh64_round(state->v4, xxh64_read64(p));
p += 8;
} while (p <= limit);
}
/* Buffer remaining bytes */
while (p < end) {
state->buffer[state->buffer_size++] = *p++;
}
}
uint64_t xxhash64_digest(const XXHash64State *state) {
const uint8_t *p = state->buffer;
const uint8_t *end = p + state->buffer_size;
uint64_t h64;
if (state->total_len >= 32) {
h64 = xxh64_rotl(state->v1, 1) + xxh64_rotl(state->v2, 7) +
xxh64_rotl(state->v3, 12) + xxh64_rotl(state->v4, 18);
h64 = xxh64_merge_round(h64, state->v1);
h64 = xxh64_merge_round(h64, state->v2);
h64 = xxh64_merge_round(h64, state->v3);
h64 = xxh64_merge_round(h64, state->v4);
} else {
h64 = state->seed + XXHASH64_PRIME5;
}
h64 += state->total_len;
/* Process remaining 8-byte chunks */
while (p + 8 <= end) {
uint64_t k1 = xxh64_round(0, xxh64_read64(p));
h64 ^= k1;
h64 = xxh64_rotl(h64, 27) * XXHASH64_PRIME1 + XXHASH64_PRIME4;
p += 8;
}
/* Process remaining 4-byte chunk */
if (p + 4 <= end) {
h64 ^= (uint64_t)xxh64_read32(p) * XXHASH64_PRIME1;
h64 = xxh64_rotl(h64, 23) * XXHASH64_PRIME2 + XXHASH64_PRIME3;
p += 4;
}
/* Process remaining bytes */
while (p < end) {
h64 ^= (uint64_t)(*p) * XXHASH64_PRIME5;
h64 = xxh64_rotl(h64, 11) * XXHASH64_PRIME1;
p++;
}
return xxh64_avalanche(h64);
}