Files
LithosAnanake/v3/include/q48_16.h
T
rajamesandJunie a8b70e88d3 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>
2026-10-01 15:40:09 -04:00

305 lines
9.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
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.
*/
#ifndef Q48_16_H
#define Q48_16_H
#include <stdint.h>
/* ============================================================================
* Q48.16 Fixed-Point Arithmetic
* ============================================================================
*
* Format: uint64_t with fixed decimal point after bit 15
* - Bits 0-15: Fractional part (1/65536 resolution)
* - Bits 16-63: Integer part (up to 2^48-1)
*
* Example: 0x00010000 = 1.0, 0x00018000 = 1.5, 0x00010001 = 1 + 1/65536
*
* All operations are integer-only: no floating-point, no transcendental functions.
* Used for inference engine calculations (variance, regression, diagnostics).
*
* Why Q48.16?
* - 48-bit integer range: 0 to 281,474,976,710,655 (enough for VM metrics)
* - 16-bit fractional: ~0.0000152 resolution (precise enough for statistical calculations)
* - Perfect fit for 64-bit uint64_t: efficient on modern CPUs
*/
typedef uint64_t q48_16_t;
/* ============================================================================
* Core Arithmetic Operations (All Q48.16 ↔ Q48.16)
* ============================================================================
*/
/*
* @brief Multiply two Q48.16 values, keeping result in Q48.16
*
* Math: (a / 2^16) * (b / 2^16) * 2^16 = (a * b) / 2^16
* Returns: (a * b) >> 16
*
* @param a First Q48.16 operand
* @param b Second Q48.16 operand
* @return (a * b) >> 16 in Q48.16 format
*/
q48_16_t q48_mul(q48_16_t a, q48_16_t b);
/*
* @brief Divide two Q48.16 values, keeping result in Q48.16
*
* Math: (a / 2^16) / (b / 2^16) * 2^16 = (a << 16) / b
* Returns: (a << 16) / b
*
* @param a Dividend in Q48.16
* @param b Divisor in Q48.16 (non-zero)
* @return (a << 16) / b in Q48.16 format
*/
q48_16_t q48_div(q48_16_t a, q48_16_t b);
/* Guard: skip static inlines already provided by include/starkernel/q48_16.h
* (both headers share the same definitions; STARKERNEL_Q48_16_H is defined
* by the kernel version so we avoid -Werror redefinition in mixed builds). */
#ifndef STARKERNEL_Q48_16_H
/**
* @brief Add two Q48.16 values
*
* Math: (a / 2^16) + (b / 2^16) = (a + b) / 2^16
* Returns: a + b (no shift needed, both have same scaling)
*
* @param a First Q48.16 operand
* @param b Second Q48.16 operand
* @return a + b in Q48.16 format
*/
static inline q48_16_t q48_add(q48_16_t a, q48_16_t b) {
return a + b;
}
/**
* @brief Subtract two Q48.16 values
*
* Math: (a / 2^16) - (b / 2^16) = (a - b) / 2^16
* Returns: a - b (no shift needed)
*
* @param a Minuend in Q48.16
* @param b Subtrahend in Q48.16
* @return a - b in Q48.16 format
*/
static inline q48_16_t q48_sub(q48_16_t a, q48_16_t b) {
return a - b;
}
/**
* @brief Absolute value of Q48.16
*
* @param a Q48.16 value
* @return |a| in Q48.16 format
*/
static inline q48_16_t q48_abs(q48_16_t a) {
return (a < 0x8000000000000000ULL) ? a : (0ULL - a);
}
/* ============================================================================
* Conversion Operations (u64 ↔ Q48.16)
* ============================================================================
*/
/**
* @brief Convert unsigned 64-bit integer to Q48.16
*
* Math: u * 2^16 (shift left by 16 bits)
* Example: q48_from_u64(1) = 0x10000 (1.0 in Q48.16)
*
* @param u Unsigned 64-bit integer (max 2^48-1 to avoid overflow)
* @return u << 16 in Q48.16 format
*/
static inline q48_16_t q48_from_u64(uint64_t u) {
return u << 16;
}
/**
* @brief Convert Q48.16 to a 64-bit integer (truncate fractional)
*
* Math: q / 2^16 (arithmetic shift right by 16 bits)
* Example: q48_to_u64(0x10000) = 1, q48_to_u64(-0x10000) = -1
*
* q48_16_t values are two's-complement signed under the hood (q48_neg/
* q48_abs already treat them that way); a plain unsigned (logical) shift
* would corrupt negative inputs instead of sign-extending them, so this
* shifts via a signed intermediate. Bit-identical to the old behavior for
* non-negative q (the only case this function's other caller, the
* inference engine's sum-of-squares accumulation, ever produces).
*
* @param q Q48.16 value
* @return q >> 16, sign-extended, reinterpreted as uint64_t
*/
static inline uint64_t q48_to_u64(q48_16_t q) {
return (uint64_t)(((int64_t)q) >> 16);
}
#endif /* STARKERNEL_Q48_16_H */
/*
* @brief Convert double to Q48.16 (for testing/initialization only)
*
* NOT used in inference engine (inference is integer-only).
* Provided for testing and diagnostic tools only.
*
* @param d Double-precision float
* @return d * 2^16 as Q48.16
*/
q48_16_t q48_from_double(double d);
/*
* @brief Convert Q48.16 to double (for testing/diagnostics only)
*
* NOT used in inference engine (inference is integer-only).
* Provided for logging and RStudio dashboard output.
*
* @param q Q48.16 value
* @return q / 2^16 as double
*/
double q48_to_double(q48_16_t q);
/* ============================================================================
* Approximation Operations (Integer-Only)
* ============================================================================
*/
/*
* @brief Approximate natural logarithm in Q48.16 (integer-only)
*
* Purpose: Required for decay slope inference via exponential fitting
* Model: ln(heat[t]) = ln(h0) - slope*t
*
* Method: Piecewise linear approximation or Newton-Raphson iteration
* - Input x must be > 0 (assertion check)
* - Output is ln(x) in Q48.16 format
* - Precision: ~5% error acceptable (tuning parameter)
* - No floating-point operations
*
* Implementation Strategy:
* 1. Use bit position (floor(log2(x))) as coarse estimate
* 2. Refine with Newton iteration (3-4 cycles for Q48.16 precision)
* 3. Keep all arithmetic in integer space
*
* Example: q48_log_approx(65536) = log(1.0) in Q48.16 ≈ 0
* q48_log_approx(131072) = log(2.0) in Q48.16 ≈ 0x0000B172
*
* @param x Value to take logarithm of (x > 0)
* @return ln(x) in Q48.16 format
*/
q48_16_t q48_log_approx(uint64_t x);
/*
* @brief Approximate exponential e^x in Q48.16 (integer-only, future use)
*
* Purpose: Might be needed for inverse operations or model validation
* Status: Defined but not required for Phase 1 inference engine
* Method: Similar to q48_log_approx (piecewise + Newton)
*
* @param q Q48.16 exponent
* @return e^q in Q48.16 format
*/
q48_16_t q48_exp_approx(q48_16_t q);
/*
* @brief Approximate square root in Q48.16 (integer-only)
*
* Purpose: Compute R² (fit quality) for regression diagnostics
* Method: Newton-Raphson for integer-only sqrt
*
* @param q Q48.16 value
* @return sqrt(q) in Q48.16 format
*/
q48_16_t q48_sqrt_approx(q48_16_t q);
/*
* @brief Approximate sin(q) in Q48.16 (integer-only, Taylor series)
*
* Purpose: Console drawing fabric's CIRCLE/ARC/ELLIPSE (FABRIC-0.md item 4.3.3b)
* Method: Range-reduce into [-pi, pi], then Taylor series
*
* @param q Angle in Q48.16 format (radians, any magnitude)
* @return sin(q) in Q48.16 format
*/
q48_16_t q48_sin_approx(q48_16_t q);
/*
* @brief Approximate cos(q) in Q48.16 (integer-only, Taylor series)
*
* Purpose: Console drawing fabric's CIRCLE/ARC/ELLIPSE (FABRIC-0.md item 4.3.3b)
* Method: Range-reduce into [-pi, pi], then Taylor series
*
* @param q Angle in Q48.16 format (radians, any magnitude)
* @return cos(q) in Q48.16 format
*/
q48_16_t q48_cos_approx(q48_16_t q);
/* ============================================================================
* Diagnostic / Testing Utilities
* ============================================================================
*/
/*
* @brief Pretty-print Q48.16 value to string for debugging
*
* Format: "integer.fractional" (e.g., "1.50000")
* Uses internal static buffer - NOT thread-safe
*
* @param q Q48.16 value
* @return Pointer to static string (valid until next call)
*/
const char* q48_to_string(q48_16_t q);
/*
* @brief Validate Q48.16 value is within safe range
*
* Checks: Does not overflow on mul/div operations
* Returns: 1 if valid, 0 if risky
*
* @param q Q48.16 value
* @return 1 if safe, 0 if risky
*/
int q48_is_valid(q48_16_t q);
#endif /* Q48_16_H */