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:
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* platform/alloc_host.c - Host (Linux/POSIX) memory allocator
|
||||
*
|
||||
* Simple wrapper around standard malloc/free with statistics tracking.
|
||||
*/
|
||||
|
||||
#include "../../include/platform_alloc.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Statistics tracking */
|
||||
static sf_alloc_stats_t g_stats = {0};
|
||||
|
||||
/**
|
||||
* @brief Initialise the host allocator statistics.
|
||||
*
|
||||
* Resets the @c g_stats struct to zero. Safe to call multiple times;
|
||||
* subsequent calls simply reset the counters. No heap memory is allocated
|
||||
* by this function — the underlying allocator is the system @c malloc.
|
||||
*
|
||||
* @return 0 always (cannot fail on the hosted path)
|
||||
*/
|
||||
int sf_alloc_init(void)
|
||||
{
|
||||
memset(&g_stats, 0, sizeof(g_stats));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate @c size bytes from the system heap.
|
||||
*
|
||||
* Delegates to @c malloc(). On success, increments @c g_stats.used_bytes
|
||||
* and @c g_stats.alloc_count, and updates @c g_stats.peak_bytes if the
|
||||
* new used total exceeds the recorded peak.
|
||||
*
|
||||
* @param size Number of bytes to allocate; 0 returns NULL
|
||||
* @return Pointer to allocated memory, or NULL on allocation failure or zero size
|
||||
*/
|
||||
void* sf_malloc(size_t size)
|
||||
{
|
||||
if (size == 0) return NULL;
|
||||
|
||||
void* ptr = malloc(size);
|
||||
if (ptr)
|
||||
{
|
||||
g_stats.used_bytes += size;
|
||||
g_stats.alloc_count++;
|
||||
if (g_stats.used_bytes > g_stats.peak_bytes)
|
||||
{
|
||||
g_stats.peak_bytes = g_stats.used_bytes;
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate a zero-initialised array of @c count elements of @c size bytes each.
|
||||
*
|
||||
* Delegates to @c calloc(). Updates statistics the same way as @c sf_malloc():
|
||||
* adds @c count*size to @c used_bytes, increments @c alloc_count, and updates
|
||||
* @c peak_bytes.
|
||||
*
|
||||
* @param count Number of elements; 0 returns NULL
|
||||
* @param size Size of each element in bytes; 0 returns NULL
|
||||
* @return Pointer to zero-filled memory, or NULL on allocation failure or zero arguments
|
||||
*/
|
||||
void* sf_calloc(size_t count, size_t size)
|
||||
{
|
||||
if (count == 0 || size == 0) return NULL;
|
||||
|
||||
void* ptr = calloc(count, size);
|
||||
if (ptr)
|
||||
{
|
||||
size_t total = count * size;
|
||||
g_stats.used_bytes += total;
|
||||
g_stats.alloc_count++;
|
||||
if (g_stats.used_bytes > g_stats.peak_bytes)
|
||||
{
|
||||
g_stats.peak_bytes = g_stats.used_bytes;
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resize a previously allocated block to @c new_size bytes.
|
||||
*
|
||||
* Delegates to @c realloc(). On success, increments @c g_stats.alloc_count.
|
||||
* The exact byte delta is not tracked because the original allocation size is
|
||||
* not stored alongside the pointer — @c used_bytes is therefore approximate
|
||||
* after any @c sf_realloc() call. For accurate accounting, wrap allocations
|
||||
* with size-tracking headers.
|
||||
*
|
||||
* @param ptr Pointer to an existing allocation, or NULL (behaves like @c sf_malloc)
|
||||
* @param new_size Desired new size in bytes; 0 may free the block (platform-defined)
|
||||
* @return Pointer to resized memory, or NULL on failure (original block unchanged)
|
||||
*/
|
||||
void* sf_realloc(void* ptr, size_t new_size)
|
||||
{
|
||||
void* new_ptr = realloc(ptr, new_size);
|
||||
if (new_ptr)
|
||||
{
|
||||
/* Note: Can't track exact delta without size tracking */
|
||||
g_stats.alloc_count++;
|
||||
}
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release a previously allocated block back to the system heap.
|
||||
*
|
||||
* Delegates to @c free(). Increments @c g_stats.free_count on non-NULL @c ptr.
|
||||
* The freed byte count is not subtracted from @c used_bytes because the
|
||||
* original size is not tracked — see @c sf_realloc() note.
|
||||
*
|
||||
* @param ptr Pointer to free; NULL is a safe no-op
|
||||
*/
|
||||
void sf_free(void* ptr)
|
||||
{
|
||||
if (!ptr) return;
|
||||
|
||||
/* Note: We can't track exact bytes freed without size tracking.
|
||||
* For accurate stats, would need to wrap allocations with headers.
|
||||
* For now, just count frees. */
|
||||
g_stats.free_count++;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy the current allocator statistics into @c stats.
|
||||
*
|
||||
* Fills @c *stats with a snapshot of @c g_stats. Note that @c used_bytes
|
||||
* overstates the live total when blocks have been freed or reallocated,
|
||||
* because freed sizes are not tracked. @c free_count is accurate.
|
||||
*
|
||||
* @param stats Output buffer to populate; no-op if NULL
|
||||
*/
|
||||
void sf_alloc_get_stats(sf_alloc_stats_t* stats)
|
||||
{
|
||||
if (!stats) return;
|
||||
*stats = g_stats;
|
||||
}
|
||||
Reference in New Issue
Block a user