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
+238
View File
@@ -0,0 +1,238 @@
/*
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.
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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cli.h"
#include "version.h"
/* Parse helper for --ram-disk */
static int parse_u32(const char* s, uint32_t* out)
{
if (!s || !*s) return -1;
uint64_t v = 0;
for (const char* p = s; *p; ++p)
{
if (*p < '0' || *p > '9') return -1;
v = v * 10u + (uint32_t)(*p - '0');
if (v > 0xffffffffULL) return -1;
}
*out = (uint32_t)v;
return 0;
}
/**
* @brief Print usage/help information
*/
void cli_print_usage(const char* program_name)
{
printf("Usage: %s [OPTIONS]\n", program_name);
printf("StarForth - A lightweight Forth virtual machine\n\n");
printf("Options:\n");
printf(" -s Script/silent mode - suppress prompts and 'ok' output (for piped input)\n");
printf(" --break-me 🔥 ULTRA-COMPREHENSIVE diagnostic mode - tests EVERYTHING\n");
printf(" --benchmark [N] Run performance benchmarks (default: 1000 iterations)\n");
printf(" --log-error Set logging level to ERROR (only errors)\n");
printf(" --log-warn Set logging level to WARN (warnings and errors)\n");
printf(" --log-info Set logging level to INFO (default)\n");
printf(" --log-test Set logging level to TEST (test results_run_01_2025_12_08 only)\n");
printf(" --log-debug Set logging level to DEBUG (all messages)\n");
printf(" --log-none Disable all logging (maximum performance)\n");
printf(" --fail-fast Stop test suite immediately on first failure\n");
printf(" --doe Run DoE experiment: output CSV metrics to stdout and exit\n");
printf(" --heartbeat-log=<mode> Heartbeat logging mode (off|summary|full)\n");
printf(" off: No heartbeat output (default)\n");
printf(" summary: Bucket aggregates in main CSV\n");
printf(" full: Per-tick CSV to hb/run-<id>.csv\n");
printf(" --disk-img=<path> Use raw disk image file at <path>\n");
printf(" --ram-disk=<MB> RAM fallback size if no --disk-img (default: 1 MB)\n");
printf(" --version, -v Show version information and exit\n");
printf(" --help, -h Show this help message\n\n");
printf("Examples:\n");
printf(" %s # Start REPL with INFO logging\n", program_name);
printf(" %s -s < script.forth # Run script from stdin (no prompts)\n", program_name);
printf(" %s --benchmark # Run benchmarks with 1000 iterations\n", program_name);
printf(" %s --disk-img=./disks/starship.img # Use disk image\n", program_name);
}
/**
* @brief Parse command-line arguments into CLIConfig
*/
CLIConfig cli_parse(int argc, char* argv[])
{
CLIConfig config = {
/* Test modes - all default to 0 */
.run_tests = 0,
.break_me = 0,
.fail_fast = 0,
.run_tests_flag_observed = 0,
/* Benchmark */
.benchmark = 0,
.benchmark_iterations = 1000,
/* Design of Experiments */
.doe_experiment = 0,
.heartbeat_log_mode = HEARTBEAT_LOG_OFF,
/* REPL mode */
.script_mode = 0,
/* Logging */
.log_level = LOG_INFO,
.log_level_explicitly_set = 0,
/* Block I/O */
.disk_img_path = NULL,
.ram_disk_mb = 1,
};
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], "--run-tests") == 0)
{
config.run_tests_flag_observed = 1;
}
else if (strcmp(argv[i], "--break-me") == 0)
{
config.break_me = 1;
}
else if (strcmp(argv[i], "--benchmark") == 0)
{
config.benchmark = 1;
if (i + 1 < argc && atoi(argv[i + 1]) > 0)
{
config.benchmark_iterations = atoi(argv[i + 1]);
i++;
}
}
else if (strcmp(argv[i], "--log-error") == 0)
{
config.log_level = LOG_ERROR;
config.log_level_explicitly_set = 1;
}
else if (strcmp(argv[i], "--log-warn") == 0)
{
config.log_level = LOG_WARN;
config.log_level_explicitly_set = 1;
}
else if (strcmp(argv[i], "--log-info") == 0)
{
config.log_level = LOG_INFO;
config.log_level_explicitly_set = 1;
}
else if (strcmp(argv[i], "--log-test") == 0)
{
config.log_level = LOG_TEST;
config.log_level_explicitly_set = 1;
}
else if (strcmp(argv[i], "--log-debug") == 0)
{
config.log_level = LOG_DEBUG;
config.log_level_explicitly_set = 1;
}
else if (strcmp(argv[i], "--log-none") == 0)
{
config.log_level = LOG_NONE;
config.log_level_explicitly_set = 1;
}
else if (strcmp(argv[i], "--fail-fast") == 0)
{
config.fail_fast = 1;
}
else if (strcmp(argv[i], "--doe-experiment") == 0 || strcmp(argv[i], "--doe") == 0)
{
config.doe_experiment = 1;
}
else if (strncmp(argv[i], "--heartbeat-log=", 16) == 0)
{
const char* mode_str = argv[i] + 16;
if (strcmp(mode_str, "off") == 0) {
config.heartbeat_log_mode = HEARTBEAT_LOG_OFF;
} else if (strcmp(mode_str, "summary") == 0) {
config.heartbeat_log_mode = HEARTBEAT_LOG_SUMMARY;
} else if (strcmp(mode_str, "full") == 0) {
config.heartbeat_log_mode = HEARTBEAT_LOG_FULL;
} else {
fprintf(stderr, "Invalid --heartbeat-log value: %s (expected off|summary|full)\n", mode_str);
exit(1);
}
}
else if (strcmp(argv[i], "-s") == 0)
{
config.script_mode = 1;
}
else if (strncmp(argv[i], "--disk-img=", 11) == 0)
{
config.disk_img_path = argv[i] + 11;
}
else if (strncmp(argv[i], "--ram-disk=", 11) == 0)
{
uint32_t tmp = 0;
if (parse_u32(argv[i] + 11, &tmp) != 0 || tmp == 0)
{
fprintf(stderr, "Invalid --ram-disk value: %s (positive MB expected)\n", argv[i] + 11);
exit(1);
}
config.ram_disk_mb = tmp;
}
else if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0)
{
printf("%s\n", STARFORTH_VERSION_FULL);
exit(0);
}
else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
{
cli_print_usage(argv[0]);
exit(0);
}
else
{
printf("Unknown option: %s\n", argv[i]);
cli_print_usage(argv[0]);
exit(1);
}
}
return config;
}