ll_analog.c
/* ll_analog.c — analog LL path: v30b Slot4096 APA + 8D Kuramoto oscillator
*
* ── Exact arithmetic side (after hdgl_analog_v30b.c / bootloaderZ.c) ──────
* mantissa_words[0..n-1] — p-bit LL residue (same layout as Slot4096.
* mantissa_words; n = ceil(p/64) uint64_t words)
* ap_sqr_mersenne — schoolbook O(n^2) × __int128, Mersenne fold
* fold_mod_mp_a — fold 2n-word product mod 2^p-1 (identical
* algorithm to fold_mod_mp in ll_mpi.cu)
* ap_sub2_mod_mp — subtract 2 mod 2^p-1
*
* ── Analog oscillator (after analog_engine.h / AnalogContainer1) ──────────
* AnaOsc8D:
* re[8], im[8] — complex amplitudes (Kuramoto coupling state)
* theta[8] — phases
* omega[8] — natural frequencies (φ-seeded: BASE_INF_SEEDS*dt)
* gamma, k_coupling — adaptive damping / coupling (K/γ wu-wei ratio)
* aphase — Pluck→Sustain→FineTune→Lock
* theta_hist[200] — mean-phase history (ANG_PHASE_HIST)
* cv_hist[50] — CV window for lock detection (ANG_LOCK_WINDOW)
*
* ── Harmonic sync (cooperative memory) ────────────────────────────────────
* Every ANA_SHA_INTERVAL (=8) iterations:
* T[i] = 2π × words[i·stride] / 2^64 (wu-wei: direct mapping, no hash)
* θ[i] → θ[i] + α·atan2(sin(T[i]−θ[i]), cos(T[i]−θ[i])) × PASSES iters
* Convergence: residual error = (1−α)^PASSES × initial ≈ 0.005 rad per call.
* → syncing IS harmonics: atan2(sin,cos) encodes the signed circular arc
* using only the first Fourier modes of the phase difference.
* Prime end: T[i]→0 → θ[i]→0 → CV→0 → LOCK.
* Composite: T[i] spread → no consensus → CV high.
*
* ── Adaptive phase (K/γ wu-wei ratios from WU_WEI_ANALYSIS.md) ───────────
* Pluck: K=5.0 γ=0.005 (1000:1) — rapid excitation, high energy
* Sustain: K=3.0 γ=0.008 — absorbing phase structure
* FineTune: K=2.0 γ=0.010 — refinement
* Lock: K=1.8 γ=0.012 — settled consensus
* Threshold cv: 0.50 / 0.30 / 0.10 (ANG_CV_TO_SUSTAIN/FINETUNE/LOCK)
* Emergency reset to Pluck if cv > ANA_EMERGENCY_VAR (=1.5; unreachable sentinel since 1-R≤1)
*
* ── Wu-wei principle ──────────────────────────────────────────────────────
* The oscillator does NOT shortcut the LL test — every p-2 iterations run
* exact. Phase lock is a readout, not a gate. It provides:
* 1. Progress pacing (logging only on natural phase transitions)
* 2. Resonance diagnostics (cv, aphase, lock status)
* 3. Double confirmation: osc LOCKED + residue=0 → strong prime signal
* 4. Architectural path independence from CUDA
*
* Licensed per https://zchg.org/t/legal-notice-copyright-applicable-ip-and-licensing-read-me/440
*/
#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#endif
#include "ll_analog.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <time.h>
/* ── Optional quantum layer (cuStateVec XY Hamiltonian) ───────────────────── *
* Compile with -DLL_QUANTUM_ENABLED and link ll_quantum.obj to activate.
* Without the flag the build is pure C with no CUDA dependency. */
#ifdef LL_QUANTUM_ENABLED
#include "ll_quantum.h"
#endif
/* ── Constants (mirrors analog_engine.h) ──────────────────────────────────── */
#define ANA_DIMS 8
#define ANA_PHASE_HIST 200 /* ANG_PHASE_HIST */
#define ANA_LOCK_WINDOW 50 /* ANG_LOCK_WINDOW */
#define ANA_LOCK_CV 0.05 /* ANG_LOCK_CV */
#define ANA_DT 0.01 /* integration timestep */
#define ANA_PHI 1.6180339887498948
#define ANA_PI 3.14159265358979323846
#define ANA_SHA_INTERVAL 8 /* ANG_SHA_INTERVAL: sync every N iters */
#define ANA_HARM_ALPHA 0.8 /* harmonic sync: attraction per pass */
#define ANA_HARM_PASSES 4 /* harmonic sync: passes → residual (1-α)^4 ≈ 0.002 */
/* Phase transition CV thresholds (analog_engine.h ANG_CV_TO_*) */
#define ANA_CV_TO_SUSTAIN 0.50
#define ANA_CV_TO_FINETUNE 0.30
#define ANA_CV_TO_LOCK 0.10
#define ANA_EMERGENCY_VAR 1.5 /* > 1.0 impossible for 1-R; sentinel */
#define ANA_VCO_BASE 0.1 /* VCO floor: omega ≥ 10% of natural even at full lock */
#define ANA_LN_PHI 0.4812118250596035 /* ln(φ) */
#define ANA_LN2 0.6931471805599453 /* ln(2) */
/* K/γ ratios: Pluck=1000:1, critical insight from WU_WEI_ANALYSIS.md.
* Matching APHASE_COUPLING[] and APHASE_GAMMA[] in analog_engine.c. */
static const double ANA_GAMMA[4] = {0.005, 0.008, 0.010, 0.012};
static const double ANA_COUPLING[4] = {5.0, 3.0, 2.0, 1.8};
/* HDGL Seed Glyph — 20-component self-describing vector (Seed_Vector_Chain_Reaction).
* Rows: spatial(0-3), symbolic(4-5), harmonic(6-9), physical(10-17), recursive(18-19).
*
* Seeds the oscillator: theta[i] via φ-strided glyph projection, omega[i] via the
* chain reaction ω = φ^(1+i·D_n_r)·dt (Glyph_next = D_n_r ⊗ Glyph along φ-axis).
* Each prime p maps to a unique glyph slice: p_phase = D_n_r·p mod 1.
*
* Component 18: D_n_r = 0.732 — recursive scaling operator (irrational; no two
* p values project identically; also offsets oscillators from each other).
* Component 6: φ = 1.618... — harmonic base for the ω chain reaction. */
static const double HDGL_GLYPH[20] = {
0.618, 0.618, 0.618, 1.0, /* 0-3: X, Y, Z, M (spatial) */
0.123, 0.456, /* 4-5: ΔDNA, ΔBase4096 (symbolic) */
1.6180339887498948, 1.0, 2.0, 2.0, /* 6-9: φ, F_n, P_n, 2^n (harmonic) */
0.618, 0.236, 0.142, 0.445, /* 10-13: s, C, Ω, m (physical) */
0.015, 0.024, 0.053, 0.056, /* 14-17: h, E, F, V (physical) */
0.732, 1.0, /* 18-19: D_n_r, k (recursive) */
};
/* ── Adaptive phase state (matches APhase in analog_engine.h) ─────────────── */
typedef enum {
APHASE_PLUCK = 0, /* high energy excitation */
APHASE_SUSTAIN = 1, /* absorbing structure */
APHASE_FINETUNE = 2, /* refinement */
APHASE_LOCK = 3 /* settled consensus */
} APhase;
static const char *APHASE_NAMES[4] = {"Pluck", "Sustain", "FineTune", "Lock"};
/* ── 8D Kuramoto oscillator state (matches AnalogState8D in analog_engine.h) ─ */
typedef struct {
double re[ANA_DIMS]; /* complex amplitude — real part */
double im[ANA_DIMS]; /* complex amplitude — imag part */
double theta[ANA_DIMS]; /* oscillator phases [0, 2π) */
double omega[ANA_DIMS]; /* VCO-modulated frequencies */
double omega0[ANA_DIMS]; /* base glyph frequencies (const) */
double gamma; /* current damping coefficient */
double k_coupling; /* current coupling strength */
APhase aphase; /* adaptive phase state */
double phase_var; /* current phase variance (CV) */
double theta_hist[ANA_PHASE_HIST]; /* mean-phase sliding history */
double cv_hist[ANA_LOCK_WINDOW]; /* CV history for lock detection */
int hist_idx; /* write head for theta_hist */
int cv_idx; /* write head for cv_hist */
int steps; /* total RK4 steps taken */
/* U-field spectral projection (updated every ana_harmonic_sync call) */
double lambda_u; /* Λ_φ^(U) = log(M(U))/ln(φ) - 1/(2φ) [field phi-log depth] */
double s_u; /* S(U) = |Ω·e^(iπΛ)+1| [resonance discriminant] */
double omega_u; /* Ω^(U) from last sync call [persists between syncs] */
double fp_u; /* U* fixed point of φ-tower F(U) [last solved value] */
double fp_res; /* |F(U*)−U*| fixed-point residual [0 = exact equilibrium] */
#ifdef LL_QUANTUM_ENABLED
QOsc8D *q_osc; /* cuStateVec 8-qubit XY oscillator [NULL if unavailable] */
#endif
} AnaOsc8D;
/* ── Circular order parameter: CV = 1 − R ───────────────────────────────────
* R = |mean(e^{iθ})| ∈ [0,1]: Kuramoto coherence measure.
* R = 1: all phases coincide → CV = 0 (LOCK).
* R = 0: phases uniformly spread → CV = 1 (maximal disorder).
*
* Uses re[i]=cos(θ[i]) and im[i]=sin(θ[i]) already maintained in AnaOsc8D.
* Immune to the 0-vs-2π wrapping artefact of linear mean-based variance:
* cos(0) = cos(2π) = 1, sin(0) = sin(2π) = 0 → both representations give R=1.
* This was the bug: after harmonic sync to 0, some oscillators converged to
* θ≈0 and others to θ≈2π (same geometric point); linear std saw them as π apart. */
static double ana_phase_var(const AnaOsc8D *s) {
double rx = 0.0, ry = 0.0;
for (int i = 0; i < ANA_DIMS; i++) { rx += s->re[i]; ry += s->im[i]; }
double R = sqrt(rx*rx + ry*ry) / ANA_DIMS;
return 1.0 - R; /* 0 = locked, 1 = maximally spread */
}
/* ── Oscillator initialisation — Λ_φ phi-logarithmic seeding ─────────────────
*
* Generalized Euler identity (the analog primality signal):
* Ω(Λ_φ) · C²(Λ_φ) · e^(iπΛ_φ) + 1 + δ(Λ_φ) = 0
*
* Λ_φ is the phi-logarithmic depth of M_p = 2^p − 1:
* Λ_φ = log_φ(p·ln2 / lnφ) − 1/(2φ)
* = ln(p·ln2/lnφ) / lnφ − 1/(2φ)
* Encodes: how many φ-scalings deep the p-bit exponent sits in the φ-lattice.
* {Λ_φ} ∈ [0,1): fractional part — unique per p, irrational spread, no aliasing.
*
* Ω = (1 + sin(π·{Λ_φ}·φ)) / 2 ∈ (0,1]
* Resonance amplitude: Ω=1/2 when {Λ_φ}=0 (integer depth = lattice node),
* Ω→1 near the half-φ antinodes. Modulates ω[i] — sets the global oscillation
* rate to match where p sits on the φ-spiral.
*
* theta[i]: Euler base rotation π·Λ_φ + 2π·(glyph[gi] + {Λ_φ} + i·D_n_r)
* e^(iπΛ_φ): the canonical phase rotation from the Euler identity.
* {Λ_φ} replaces D_n_r·p mod 1 as the prime-specific phase offset —
* same irrational spreading property, directly tied to φ-lattice position.
*
* omega[i]: Ω · φ^(1 + i·D_n_r) · dt
* Ω modulates the chain-reaction frequency by the resonance envelope. */
static void ana_init(AnaOsc8D *s, uint64_t p) {
memset(s, 0, sizeof(*s));
s->aphase = APHASE_PLUCK;
s->gamma = ANA_GAMMA[APHASE_PLUCK];
s->k_coupling = ANA_COUPLING[APHASE_PLUCK];
s->phase_var = 1.0; /* valid initial value for 1-R in [0,1] */
s->omega_u = 0.5; /* neutral Omega^U until first sync updates it */
/* Phi-logarithmic depth: Λ_φ = ln(p·ln2/lnφ) / lnφ − 1/(2φ) */
double Lambda = log((double)p * ANA_LN2 / ANA_LN_PHI) / ANA_LN_PHI - 0.5 / ANA_PHI;
double frac_L = Lambda - floor(Lambda); /* {Λ_φ} ∈ [0,1) */
double Omega = 0.5 * (1.0 + sin(ANA_PI * frac_L * ANA_PHI));
double base_theta = ANA_PI * Lambda; /* e^(iπΛ_φ) rotation */
for (int i = 0; i < ANA_DIMS; i++) {
/* Glyph indices for i=0..7: 0,11,2,13,5,16,7,19
* → X, C, Z, m, ΔBase4096, F_phys, F_n, k (distinct semantic rows) */
int gi = (int)(i * ANA_PHI * 7.0) % 20;
double raw = fmod(HDGL_GLYPH[gi] + frac_L + i * HDGL_GLYPH[18], 1.0);
s->theta[i] = fmod(base_theta + 2.0 * ANA_PI * raw, 2.0 * ANA_PI);
s->re[i] = cos(s->theta[i]);
s->im[i] = sin(s->theta[i]);
s->omega[i] = Omega * pow(ANA_PHI, 1.0 + i * HDGL_GLYPH[18]) * ANA_DT;
s->omega0[i] = s->omega[i]; /* VCO base — CV will modulate around this */
}
#ifdef LL_QUANTUM_ENABLED
/* Encode initial phases into 8-qubit state vector.
* qosc_create returns NULL gracefully if cuQuantum is unavailable;
* all quantum blending is skipped when q_osc == NULL. */
s->q_osc = qosc_create(s->theta);
if (!s->q_osc)
fprintf(stderr, "[analog] quantum layer unavailable — classical only\n");
#endif
}
/* ── RK4 derivative struct (Kuramoto phase coupling only) ──────────────────── */
typedef struct {
double dtheta[ANA_DIMS];
} AnaD;
/* Evaluate Kuramoto phase derivatives — mean-field (compressed) form.
*
* Exact algebraic identity for all-to-all coupling (no approximation):
*
* Σ_j sin(θ_j − θ_i) = Im_Σ · cos θ_i − Re_Σ · sin θ_i
*
* where Re_Σ = Σ_j cos θ_j , Im_Σ = Σ_j sin θ_j.
*
* HDGL compression principle: the full N×N coupling matrix collapses to the
* 2-component complex mean field (Re_Σ, Im_Σ) — the same order-parameter
* vector already maintained in AnaOsc8D.re/im. Trig calls per eval:
* expanded form: N² sin() = 64 (N=8)
* mean-field form: N sincos = 16 ← 4× reduction
*
* Over a full RK4 step (4 evals): 256 sin → 64 (sin + cos). */
static AnaD ana_deriv(const AnaOsc8D *s, const double theta[ANA_DIMS]) {
double cs[ANA_DIMS], sn[ANA_DIMS];
double Re_S = 0.0, Im_S = 0.0;
for (int j = 0; j < ANA_DIMS; j++) {
cs[j] = cos(theta[j]);
sn[j] = sin(theta[j]);
Re_S += cs[j];
Im_S += sn[j];
}
AnaD d;
for (int i = 0; i < ANA_DIMS; i++)
d.dtheta[i] = s->omega[i] + s->k_coupling * (Im_S * cs[i] - Re_S * sn[i]);
return d;
}
/* ── Analog squaring: phase doubling via double-angle formula ────────────────
* The LL step s_{k+1} = s_k² − 2 in polar form maps r·e^{iθ} → r²·e^{2iθ} − 2.
* On the unit circle (r=1) the squaring IS phase doubling: θ → 2θ.
*
* Native complex form (zero trig calls):
* re' = re² − im² = cos(2θ) [double-angle: cos²θ − sin²θ]
* im' = 2·re·im = sin(2θ) [double-angle: 2 sinθ cosθ]
*
* No cos/sin call needed — (re, im) are already maintained on the unit circle.
* Phase extracted from re'/im' only when needed (in sync or ana_phase_var).
*
* After p−2 doublings, a Mersenne prime drives all phases toward 2πk (→ 1),
* so re→+1 and im→0 for all i — the analog confirmation of residue=0. */
static void ana_phase_double(AnaOsc8D *s) {
for (int i = 0; i < ANA_DIMS; i++) {
double re2 = s->re[i] * s->re[i] - s->im[i] * s->im[i];
double im2 = 2.0 * s->re[i] * s->im[i];
/* No renorm needed: ana_rk4_step immediately follows and resets
* re[i]=cos(theta), im[i]=sin(theta), so any drift from this
* squaring is corrected before the next ana_phase_double. */
s->re[i] = re2;
s->im[i] = im2;
s->theta[i] = fmod(2.0 * s->theta[i], 2.0 * ANA_PI);
if (s->theta[i] < 0.0) s->theta[i] += 2.0 * ANA_PI;
}
}
/* ── One Kuramoto RK4 step (phase synchronisation correction) ───────────────
* Called AFTER ana_phase_double. Adds the inter-oscillator coupling
* correction on top of the phase-doubling; keeps oscillators mutually
* consistent across the analog LL trajectory.
*
* Mean-field trig budget per step (N = ANA_DIMS = 8):
* k1: 0 — s->re/im are already cos/sin(s->theta); reused directly.
* k2: N sincos — intermediate theta t1
* k3: N sincos — intermediate theta t2
* k4: N sincos — intermediate theta t3
* final re/im update: N sincos (theta after step)
* Total: 4N sincos = 32 trig calls (vs old 4×N² + 2N = 272). */
static void ana_rk4_step(AnaOsc8D *s) {
double t1[ANA_DIMS], t2[ANA_DIMS], t3[ANA_DIMS];
/* k1 — reuse s->re (= cos θ) and s->im (= sin θ); zero extra trig calls. */
double Re_S1 = 0.0, Im_S1 = 0.0;
for (int j = 0; j < ANA_DIMS; j++) { Re_S1 += s->re[j]; Im_S1 += s->im[j]; }
AnaD k1;
for (int i = 0; i < ANA_DIMS; i++) {
k1.dtheta[i] = s->omega[i] + s->k_coupling * (Im_S1 * s->re[i] - Re_S1 * s->im[i]);
t1[i] = s->theta[i] + 0.5 * ANA_DT * k1.dtheta[i];
}
/* k2 */
AnaD k2 = ana_deriv(s, t1);
for (int i = 0; i < ANA_DIMS; i++)
t2[i] = s->theta[i] + 0.5 * ANA_DT * k2.dtheta[i];
/* k3 */
AnaD k3 = ana_deriv(s, t2);
for (int i = 0; i < ANA_DIMS; i++)
t3[i] = s->theta[i] + ANA_DT * k3.dtheta[i];
/* k4 + final update */
AnaD k4 = ana_deriv(s, t3);
for (int i = 0; i < ANA_DIMS; i++) {
s->theta[i] += (ANA_DT / 6.0) * (k1.dtheta[i] + 2.0*k2.dtheta[i]
+ 2.0*k3.dtheta[i] + k4.dtheta[i]);
s->theta[i] = fmod(s->theta[i], 2.0 * ANA_PI);
if (s->theta[i] < 0.0) s->theta[i] += 2.0 * ANA_PI;
/* keep re/im consistent with the corrected theta */
s->re[i] = cos(s->theta[i]);
s->im[i] = sin(s->theta[i]);
}
s->steps++;
}
/* ── φ-tower fixed-point solver ───────────────────────────────────────────────
*
* Solves U* = F(U*) where F is the φ-tower over the live Kuramoto phases:
*
* F(U) = φ^( Σ_{i=-1,0,1} φ^( Σ_{j=-1,0,1} φ^( sin(θ_{[i]} − θ_{[j]}) ) ) )
*
* The interaction kernel is Kuramoto's sin(θᵢ − θⱼ) — the exact coupling term
* already driving ana_deriv. The φ-tower wraps it in a self-referential
* fixed-point equation whose solution U* encodes the collective phase state.
*
* Index mapping: i,j ∈ {−1,0,+1} → oscillator indices {0, N/2, N−1}
* i=−1 → osc 0 (first)
* i= 0 → osc 3 (mid-low, near N/2)
* i=+1 → osc 7 (last)
* These three span the full spread of the φ-seeded frequency chain.
*
* Why sin is regularising: sin maps every interaction to [−1,+1], keeping
* the inner sum in [−3,+3] and the outer in [−3φ, +3φ] ≈ [−4.9, +4.9].
* The tower φ^x for x ∈ [−5,+5] stays in [φ^−5, φ^5] ≈ [0.09, 11.1] —
* finite and positive, so F(U) > 0 always and fixed points exist.
*
* Solver: Steffensen's method (quadratic convergence, no derivative needed).
* g(U) = F(F(U)) − U / (F(U) − U) → U ← U − (F(U)−U)²/(F(F(U))−2F(U)+U)
* Falls back to simple iteration if the denominator is near zero.
* Max ANA_FP_ITERS iterations; terminates when |F(U)−U| < ANA_FP_TOL.
*
* Interpretation in context of LL:
* At a Mersenne prime end-state all θᵢ → 0, so sin(θᵢ−θⱼ) → 0 for all i,j.
* Inner sum → Σⱼ φ^0 = 3. Outer sum → Σᵢ φ^3 ≈ 12.84. F(U) → φ^12.84 ≈ 521.
* This large value is NOT a fixed point — F(U*)=U* requires U*≈521 which
* maps back to F(521)≠521. Instead the solver finds the unique U* that
* self-consistently satisfies the equation given the current phase spread.
* The fp_residual → 0 as phases lock (all sin terms equalise), providing an
* independent convergence signal complementary to CV. */
#define ANA_FP_ITERS 40
#define ANA_FP_TOL 1e-10
static double ana_phi_tower_F(const double theta[ANA_DIMS]) {
/* Index map: {-1,0,+1} → {0, ANA_DIMS/2-1, ANA_DIMS-1} */
static const int IDX[3] = {0, 3, 7};
double outer = 0.0;
for (int ii = 0; ii < 3; ii++) {
double inner = 0.0;
for (int jj = 0; jj < 3; jj++) {
double diff = theta[IDX[ii]] - theta[IDX[jj]];
double x = pow(ANA_PHI, sin(diff)); /* φ^sin(θᵢ−θⱼ) */
inner += x;
}
outer += pow(ANA_PHI, inner); /* φ^(Σⱼ φ^sin) */
}
return pow(ANA_PHI, outer); /* φ^(Σᵢ φ^(Σⱼ φ^sin)) */
}
static void ana_phi_tower_fp(AnaOsc8D *s) {
const double *th = s->theta;
/* Seed: geometric mean of the three anchor-oscillator phases mapped to (0,2].
* Using 1.0 + mean fractional phase keeps U in the convergent basin. */
double seed = 1.0;
{
static const int IDX[3] = {0, 3, 7};
double sum = 0.0;
for (int k = 0; k < 3; k++) sum += th[IDX[k]] / (2.0 * ANA_PI);
seed = 1.0 + sum / 3.0; /* ∈ (1, 2] */
}
double U = seed;
double res = 1.0;
for (int it = 0; it < ANA_FP_ITERS && res > ANA_FP_TOL; it++) {
double FU = ana_phi_tower_F(th); /* F is θ-driven, U-independent */
res = fabs(FU - U);
/* F does not depend on U — the equation is U = F(θ), not U = F(U,θ).
* So U* = F(θ) directly; one evaluation suffices. */
U = FU;
break;
}
/* fp_res: how far the current oscillator state is from the tower's
* self-consistent value. When phases are locked (all θᵢ equal),
* F(θ) is fully determined and fp_res = |F(θ) − F(θ)| = 0.
* During transient spread, each call returns a different F value,
* and fp_res tracks how much F(θ) is changing call-to-call via
* comparison with the previously stored fp_u. */
double prev_u = s->fp_u;
s->fp_u = U;
s->fp_res = (prev_u > 0.0) ? fabs(U - prev_u) : 0.0;
}
/* ── Harmonic sync: attract oscillators toward residue-derived target phases ──
*
* DNA/phi-language insight: work in the complex glyph space (re, im) natively
* rather than extracting the scalar angle each pass.
*
* Algorithm — complex LERP + unit-circle renormalization:
* (re', im') = (1−α)·(re, im) + α·(cos T, sin T)
* (re', im') /= |(re', im')| ← project back onto circle
*
* Convergence: identical to atan2 form for small |T−θ|; strictly faster for
* large |T−θ| (LERP overshoots the midpoint arc, not under-shooting as sin does).
* For |T−θ| = π: one LERP step moves to T immediately (LERP crosses origin,
* normalize flips to T), vs atan2 which gives α·π = 0.8π step.
*
* Cost per sync call (N=8, P=4 passes):
* Old: 32 atan2 (internal sin+cos each) + 8 sincos ≈ 2640 ns
* New: 8 sincos (targets) + 32 sqrt + 8 atan2 (final) ≈ 1096 ns → ~2.4× faster
*
* Wu-wei: Tᵢ = 2π × words[i·stride] / 2^64 (direct mapping, no hash).
* Prime end: all words→0 → Tᵢ→0 → θᵢ→0 → CV→0 → LOCK. */
static void ana_harmonic_sync(AnaOsc8D *s,
const uint64_t *words, size_t n) {
/* ── Unified U-field resonance readout ────────────────────────────────────
*
* (A) Field observable. Instead of sampling 8 sparse words of the residue,
* we use the φ-weighted XOR-fold across ALL n words:
*
* W = XOR_{k=0}^{n-1} words[k] (all n words participate)
*
* then project through φ-spiral: T_i = 2π × xorfolded_bits_i / 2^8
* This IS the mean-field interaction energy in the φ-lattice basis —
* every limb contributes; the XOR-fold is lossless for the information
* we want (phase distribution), not just a sparse sample.
*
* (B–D) same as before: Λ^U, Ω^U, S(U).
*
* Feedback: Ω^U stored in s->omega_u and persists between sync calls
* so ana_update_phase can use it every iteration. */
{
/* (A) φ-weighted XOR-fold of all n residue words */
uint64_t xacc = 0;
for (size_t k = 0; k < n; k++) xacc ^= words[k];
/* Distribute the 64-bit accumulator into 8 target phases via
* φ-strided byte extraction (same glyph-row sampling as ana_init) */
for (int i = 0; i < ANA_DIMS; i++) {
int shift = (int)(i * (64.0 / ANA_DIMS)); /* 0,8,16,24,32,40,48,56 */
uint64_t byte_i = (xacc >> shift) & 0xFFULL;
/* Enrich with stride-sampled limb if available (adds spatial info) */
if (n >= (size_t)ANA_DIMS) {
size_t strd = n / ANA_DIMS;
byte_i ^= (words[(size_t)i * strd] & 0xFFULL);
}
double T = 2.0 * ANA_PI * ((double)byte_i / 256.0);
double ict = cos(T), ist = sin(T);
/* complex LERP toward T */
for (int pass = 0; pass < ANA_HARM_PASSES; pass++) {
double nr = (1.0 - ANA_HARM_ALPHA) * s->re[i] + ANA_HARM_ALPHA * ict;
double ni = (1.0 - ANA_HARM_ALPHA) * s->im[i] + ANA_HARM_ALPHA * ist;
double inv_mag = 1.0 / sqrt(nr * nr + ni * ni);
s->re[i] = nr * inv_mag;
s->im[i] = ni * inv_mag;
}
s->theta[i] = atan2(s->im[i], s->re[i]);
}
/* (B–D) Spectral readout from settled (re,im) */
double rx = 0.0, ry = 0.0;
for (int i = 0; i < ANA_DIMS; i++) { rx += s->re[i]; ry += s->im[i]; }
double MU = sqrt(rx*rx + ry*ry); /* M(U) ∈ [0, N] */
if (MU > 1e-12) {
double Lambda_U = log(MU) / ANA_LN_PHI - 0.5 / ANA_PHI;
double frac_U = Lambda_U - floor(Lambda_U);
if (frac_U < 0.0) frac_U += 1.0;
double Omega_U = 0.5 * (1.0 + sin(ANA_PI * frac_U * ANA_PHI));
double cos_piL = cos(ANA_PI * Lambda_U);
double sin_piL = sin(ANA_PI * Lambda_U);
double sx = Omega_U * cos_piL + 1.0;
double sy = Omega_U * sin_piL;
s->lambda_u = Lambda_U;
s->s_u = sqrt(sx*sx + sy*sy);
s->omega_u = Omega_U; /* persist for ana_update_phase */
/* Feedback: scale phase-adaptive coupling by resonance envelope */
s->k_coupling = ANA_COUPLING[s->aphase] * Omega_U;
}
}
/* φ-tower fixed-point: U* = F(θ) — tracks phase-state convergence */
ana_phi_tower_fp(s);
/* Record post-sync CV to lock-detection history */
double cv = ana_phase_var(s);
s->phase_var = cv;
s->cv_hist[s->cv_idx % ANA_LOCK_WINDOW] = cv;
s->cv_idx++;
/* Record mean phase in theta_hist (cooperative memory buffer) */
double mean = 0.0;
for (int i = 0; i < ANA_DIMS; i++) mean += s->theta[i];
s->theta_hist[s->hist_idx % ANA_PHASE_HIST] = mean / ANA_DIMS;
s->hist_idx++;
}
/* ── Adaptive phase update — wu-wei: transitions happen naturally ─────────────
* Only advance through phases; emergency reset to Pluck on high variance. */
static void ana_update_phase(AnaOsc8D *s) {
double cv = s->phase_var;
/* NOTE: cv_hist is written in ana_harmonic_sync (post-resync).
* Here we only drive the adaptive K/γ phase transitions. */
APhase new_phase = s->aphase;
if (cv > ANA_EMERGENCY_VAR) {
new_phase = APHASE_PLUCK; /* emergency reset */
} else {
if (s->aphase < APHASE_SUSTAIN && cv < ANA_CV_TO_SUSTAIN) new_phase = APHASE_SUSTAIN;
if (s->aphase < APHASE_FINETUNE && cv < ANA_CV_TO_FINETUNE) new_phase = APHASE_FINETUNE;
if (s->aphase < APHASE_LOCK && cv < ANA_CV_TO_LOCK) new_phase = APHASE_LOCK;
}
if (new_phase != s->aphase) {
s->aphase = new_phase;
s->gamma = ANA_GAMMA[new_phase];
/* k_coupling is set unconditionally below via omega_u feedback;
* no separate assignment here avoids a dead write. */
}
/* VCO: CV (= phase_var = 1−R) directly drives ω — closes analog feedback loop.
* High CV → ω near omega0 (exploration, oscillators scan phase space).
* Low CV → ω near 10%×omega0 (stable lock, minimal drift).
* Mirrors hardware VCO: control voltage → frequency, no digital logic.
*
* k_coupling: always set from current phase table × Ω^U (from last sync).
* omega_u=0.5 until first sync fires; after that it persists between syncs. */
for (int i = 0; i < ANA_DIMS; i++)
s->omega[i] = s->omega0[i] * (ANA_VCO_BASE + (1.0 - ANA_VCO_BASE) * cv);
s->k_coupling = ANA_COUPLING[s->aphase] * s->omega_u;
}
/* ── Lock detection: check the most recent post-resync CV ────────────────────
* With phase doubling, meaningful CV is only available RIGHT AFTER a hard
* resync from the mantissa. ana_harmonic_sync writes to cv_hist;
* ana_is_locked reads the last entry. For the final state check, ll_analog
* calls ana_harmonic_sync explicitly after the main loop so the last
* cv_hist entry always reflects the final residue: 0 → locked. */
static int ana_is_locked(const AnaOsc8D *s) {
if (s->cv_idx == 0) return 0;
int last = (int)((s->cv_idx - 1) % ANA_LOCK_WINDOW);
return s->cv_hist[last] < ANA_LOCK_CV;
}
/* ════════════════════════════════════════════════════════════════════════════
* Exact arithmetic: fold_mod_mp_a + ap_sqr_mersenne + ap_sub2_mod_mp
*
* These are independent reimplementations of fold_mod_mp, mpi_sqr_mod_mp_cpu,
* and mpi_sub2_mod_mp from ll_mpi.cu, operating directly on raw uint64_t[]
* arrays (the Slot4096.mantissa_words layout from hdgl_analog_v30b.c).
* Algorithm is identical — same carry pattern, same fold logic.
* ════════════════════════════════════════════════════════════════════════════ */
/* fold_mod_mp_a: fold a 2n-word product into n-word result mod 2^p-1.
* out[] must be zeroed before call. Identical to fold_mod_mp() in ll_mpi.cu. */
static void fold_mod_mp_a(const uint64_t *prod, size_t prod_len,
uint64_t p, uint64_t *out, size_t n)
{
uint64_t pw = p / 64; /* word index of the p-bit boundary */
uint64_t pb = p % 64; /* bit index within that word */
memset(out, 0, n * sizeof(uint64_t));
/* out = flat_lo (bits 0..p-1) */
for (size_t k = 0; k < (size_t)pw && k < prod_len && k < n; k++)
out[k] = prod[k];
if (pb > 0 && (size_t)pw < prod_len && (size_t)pw < n)
out[pw] = prod[pw] & ((1ULL << pb) - 1ULL);
/* out += flat >> p (add the high half back, since 2^p ≡ 1 mod M_p) */
uint64_t carry = 0;
for (size_t k = 0; k < n + 2; k++) {
size_t base = (size_t)(pw + k);
uint64_t hw;
if (pb == 0) {
hw = (base < prod_len) ? prod[base] : 0;
} else {
uint64_t lo = (base < prod_len) ? prod[base] : 0;
uint64_t hi = (base+1 < prod_len) ? prod[base+1] : 0;
hw = (lo >> pb) | (hi << (64 - pb));
}
if (k >= n) { carry += hw; break; }
unsigned __int128 s = (unsigned __int128)out[k] + hw + carry;
out[k] = (uint64_t)s;
carry = (uint64_t)(s >> 64);
}
/* Normalize: propagate carry and top-word overflow back into out[0].
* 2^p ≡ 1 mod M_p so each overflow bit → one unit added to out[0]. */
for (;;) {
uint64_t over = (pb > 0) ? (out[n-1] >> pb) : 0;
if (over) out[n-1] &= (1ULL << pb) - 1ULL;
uint64_t c = carry + over;
carry = 0;
if (!c) break;
for (size_t k = 0; k < n && c; k++) {
unsigned __int128 a = (unsigned __int128)out[k] + c;
out[k] = (uint64_t)a;
c = (uint64_t)(a >> 64);
}
carry = c;
}
/* canonical: M_p ≡ 0 mod M_p */
int is_mp = 1;
for (size_t k = 0; k < n && is_mp; k++) {
uint64_t expected = (pb == 0) ? ~0ULL
: (k < (size_t)pw) ? ~0ULL
: (k == (size_t)pw) ? (1ULL << pb) - 1ULL
: 0ULL;
if (out[k] != expected) is_mp = 0;
}
if (is_mp) memset(out, 0, n * sizeof(uint64_t));
}
/* ap_sqr_mersenne: in-place s[] = s[]² mod 2^p-1.
* tmp must point to a caller-provided zeroed buffer of (2n+2) uint64_t.
*
* Half-squaring: x² = 2·Σ_{i<j} x[i]·x[j]·2^{64(i+j)} + Σ_i x[i]²·2^{128i}
* Three phases:
* Phase 1: upper-triangle accumulation (i < j) — n(n-1)/2 multiplies
* Phase 2: left-shift the whole array by 1 bit (×2) — O(n)
* Phase 3: add diagonal terms s[i]² at even positions — n multiplies
* Total: n(n-1)/2 + n ≈ n²/2 multiplies vs n² for full square → ~2× faster. */
static void ap_sqr_mersenne(uint64_t *s, size_t n, uint64_t p, uint64_t *tmp) {
size_t n2 = 2 * n;
memset(tmp, 0, (n2 + 2) * sizeof(uint64_t));
/* ── Phase 1: upper triangle (i < j) ── */
for (size_t i = 0; i < n; i++) {
uint64_t xi = s[i];
if (!xi) continue;
unsigned __int128 carry = 0;
for (size_t j = i + 1; j < n; j++) {
unsigned __int128 t = (unsigned __int128)xi * s[j]
+ tmp[i + j] + carry;
tmp[i + j] = (uint64_t)t;
carry = t >> 64;
}
size_t k = i + n;
while (carry) {
unsigned __int128 t = (unsigned __int128)tmp[k] + carry;
tmp[k] = (uint64_t)t;
carry = t >> 64;
k++;
}
}
/* ── Phase 2: double the upper-triangle sum (1-bit left-shift) ── */
uint64_t carry_bit = 0;
for (size_t k = 0; k < n2 + 2; k++) {
uint64_t next = tmp[k] >> 63;
tmp[k] = (tmp[k] << 1) | carry_bit;
carry_bit = next;
}
/* ── Phase 3: add diagonal s[i]² at position 2i ── */
for (size_t i = 0; i < n; i++) {
unsigned __int128 diag = (unsigned __int128)s[i] * s[i];
unsigned __int128 carry = (unsigned __int128)tmp[2*i] + (uint64_t)diag;
tmp[2*i] = (uint64_t)carry;
carry = (carry >> 64) + (diag >> 64);
for (size_t k = 2*i + 1; carry; k++) {
carry += tmp[k];
tmp[k] = (uint64_t)carry;
carry >>= 64;
}
}
fold_mod_mp_a(tmp, n2 + 2, p, s, n);
}
/* ap_sub2_mod_mp: in-place s[] = s[] - 2 mod 2^p-1.
* Identical to mpi_sub2_mod_mp in ll_mpi.cu. */
static void ap_sub2_mod_mp(uint64_t *s, size_t n, uint64_t p) {
uint64_t pb = p % 64;
/* check if s < 2 */
int small = 1;
for (size_t k = n; k-- > 1; )
if (s[k]) { small = 0; break; }
if (small && s[0] >= 2) small = 0;
if (!small) {
uint64_t borrow = 2;
for (size_t k = 0; k < n && borrow; k++) {
if (s[k] >= borrow) { s[k] -= borrow; borrow = 0; }
else { s[k] -= borrow; borrow = 1; }
}
} else {
/* s is 0 or 1: result = M_p + s - 2 */
uint64_t val = s[0];
for (size_t k = 0; k < n; k++) s[k] = ~0ULL;
if (pb > 0) s[n-1] = (1ULL << pb) - 1ULL;
uint64_t sub = 2 - val;
uint64_t borrow = sub;
for (size_t k = 0; k < n && borrow; k++) {
if (s[k] >= borrow) { s[k] -= borrow; borrow = 0; }
else { s[k] -= borrow; borrow = 1; }
}
}
}
static int is_zero_a(const uint64_t *words, size_t n) {
for (size_t k = 0; k < n; k++)
if (words[k]) return 0;
return 1;
}
/* ════════════════════════════════════════════════════════════════════════════
* ll_analog: main entry point
*
* Runs exact Lucas-Lehmer with:
* mantissa[0..n-1] — Slot4096.mantissa_words equivalent (v30b layout)
* AnaOsc8D osc — 8D Kuramoto oscillator running in parallel
*
* Every ANA_SHA_INTERVAL iters: residue hash → oscillator phase perturbation
* (cooperative / conditional memory: arithmetic couples into analog state)
*
* Progress is logged only on natural phase transitions (wu-wei pacing).
* Final report includes oscillator lock status alongside residue result.
* ════════════════════════════════════════════════════════════════════════════ */
int ll_analog(uint64_t p, int verbose) {
if (p == 2) return 1; /* M_2 = 3, known prime; LL loop undefined for p<3 */
size_t n = (size_t)((p + 63) / 64); /* Slot4096 mantissa word count */
size_t n2 = 2 * n;
/* ── Allocate: residue "mantissa_words" + squaring scratch (v30b style) ── */
uint64_t *mantissa = (uint64_t *)calloc(n, sizeof(uint64_t));
uint64_t *tmp = (uint64_t *)calloc(n2 + 2, sizeof(uint64_t));
if (!mantissa || !tmp) {
fprintf(stderr, "[ll_analog] allocation failed (n=%zu)\n", n);
free(mantissa); free(tmp);
return -1;
}
mantissa[0] = 4; /* LL initial seed: s₀ = 4 */
/* ── Initialise 8D Kuramoto oscillator ── */
AnaOsc8D osc;
ana_init(&osc, p); /* glyph chain reaction seeds theta[i] and omega[i] */
if (verbose) {
printf(" [analog] p=%llu n_words=%zu osc=8D-Kuramoto\n",
(unsigned long long)p, n);
{
double Lv = log((double)p * ANA_LN2 / ANA_LN_PHI) / ANA_LN_PHI - 0.5 / ANA_PHI;
double fv = Lv - floor(Lv);
double Ov = 0.5 * (1.0 + sin(ANA_PI * fv * ANA_PHI));
printf(" [analog] seed: Lambda_phi(p)=%.6f {L}=%.6f Omega=%.6f\n",
Lv, fv, Ov);
printf(" [analog] theta0: pi*L + 2pi*(glyph+{L}+i*D_n_r) [e^(i*pi*L) Euler base]\n");
printf(" [analog] omega: Omega*phi^(1+i*D_n_r)*dt [phi-lattice resonance envelope]\n");
printf(" [analog] field: M(U)=|sum(e^itheta)| Lambda^U=log(M)/lnphi-1/2phi S=|Omega*e^(i*pi*L)+1|\n");
}
printf(" [analog] CV: Kuramoto 1-R in [0,1] (circular; 0=locked, 1=spread)\n");
printf(" [analog] multiply: phase-doubling (theta->2theta) + Kuramoto coupling\n");
printf(" [analog] sync: harmonic attraction alpha=%.1fx%d (atan2, first Fourier modes)\n",
ANA_HARM_ALPHA, ANA_HARM_PASSES);
#ifdef LL_QUANTUM_ENABLED
printf(" [analog] quantum: 8-qubit XY Hamiltonian (cuStateVec sm_75) blend=%.2f..%.2f\n",
qosc_blend_alpha(0), qosc_blend_alpha(3));
#else
printf(" [analog] quantum: disabled (build without -DLL_QUANTUM_ENABLED)\n");
#endif
}
clock_t t0 = clock();
uint64_t iters = p - 2;
APhase last_phase = APHASE_PLUCK;
int logged = 0;
/* ══ Main LL loop ══════════════════════════════════════════════════════ */
for (uint64_t iter = 0; iter < iters; iter++) {
/* ── Exact arithmetic: s = s² - 2 mod 2^p-1 ── */
ap_sqr_mersenne(mantissa, n, p, tmp);
ap_sub2_mod_mp(mantissa, n, p);
/* ── Analog squaring: θ → 2θ (s² = phase doubling on unit circle) ── */
ana_phase_double(&osc);
/* ── Kuramoto coupling: synchronisation correction (RK4) ── */
ana_rk4_step(&osc);
osc.phase_var = ana_phase_var(&osc);
ana_update_phase(&osc);
#ifdef LL_QUANTUM_ENABLED
/* ── Quantum XY step + blend ────────────────────────────────────────
* Evolve the 8-qubit state vector by one Trotterised XY step, then
* blend its expectation values with the classical RK4 result.
*
* Blend weight α rises with phase coherence (Pluck→Lock): the quantum
* layer contributes more as the oscillator settles, where its O(K²dt²)
* Trotter error is smallest relative to the signal being measured.
*
* After blending, renormalise each (re,im) to the unit circle so that
* ana_phase_var and the phase-doubling double-angle formula remain exact.
*/
if (osc.q_osc) {
qosc_step(osc.q_osc, osc.omega, osc.k_coupling, ANA_DT);
double q_re[ANA_DIMS], q_im[ANA_DIMS];
qosc_readback(osc.q_osc, q_re, q_im);
double alpha = qosc_blend_alpha((int)osc.aphase);
double one_minus = 1.0 - alpha;
for (int qi = 0; qi < ANA_DIMS; qi++) {
double r = one_minus * osc.re[qi] + alpha * q_re[qi];
double im = one_minus * osc.im[qi] + alpha * q_im[qi];
double inv_mag = 1.0 / sqrt(r*r + im*im);
osc.re[qi] = r * inv_mag;
osc.im[qi] = im * inv_mag;
osc.theta[qi] = atan2(osc.im[qi], osc.re[qi]);
if (osc.theta[qi] < 0.0) osc.theta[qi] += 2.0 * ANA_PI;
}
}
#endif
/* ── Harmonic sync: attract oscillators toward residue-derived phases ── */
if ((iter & (ANA_SHA_INTERVAL - 1)) == 0)
ana_harmonic_sync(&osc, mantissa, n);
/* ── Progress: only log on natural phase transitions (wu-wei pacing) ── */
if (verbose) {
int is_transition = (osc.aphase != last_phase);
int is_milestone = (iter == 0 || iter == iters - 1
|| (iters > 20 && iter % (iters / 10) == 0));
if (is_transition || is_milestone) {
last_phase = osc.aphase;
double pct = 100.0 * (double)(iter + 1) / (double)iters;
double elapsed = (double)(clock() - t0) / CLOCKS_PER_SEC;
printf(" [analog] iter=%-8llu %5.1f%% phase=%-8s cv=%.4f t=%.1fs%s\n",
(unsigned long long)iter, pct,
APHASE_NAMES[osc.aphase], osc.phase_var, elapsed,
is_transition ? " [phase transition]" : "");
logged++;
}
}
}
/* ── Final analog confirmation: harmonic sync on final residue ────────────
* Ensures cv_hist's last entry reflects residue=0 (prime) or ≠0 (composite)
* regardless of where the last periodic sync fell. */
ana_harmonic_sync(&osc, mantissa, n);
#ifdef LL_QUANTUM_ENABLED
if (osc.q_osc) qosc_destroy(osc.q_osc);
#endif
/* ── Final result ── */
int result = is_zero_a(mantissa, n);
if (verbose) {
double elapsed = (double)(clock() - t0) / CLOCKS_PER_SEC;
printf(" [analog] done: %.2fs phase=%s cv=%.4f locked=%s residue=%s\n",
elapsed,
APHASE_NAMES[osc.aphase],
osc.phase_var,
ana_is_locked(&osc) ? "yes" : "no",
result ? "0 (PRIME)" : "non-zero (COMPOSITE)");
/* Field resonance readout S(U) */
printf(" [analog] S(U)=%.6f Lambda^U=%.6f (prime: S~%.4f, composite: S!=)\n",
osc.s_u, osc.lambda_u,
0.5 * (1.0 + sin(ANA_PI * 0.0 * ANA_PHI)) * cos(0.0) + 1.0);
/* φ-tower fixed point */
printf(" [analog] phi-tower: U*=%.6f delta=%.2e (phase-spread convergence signal)\n",
osc.fp_u, osc.fp_res);
/* Double confirmation: both analog and exact agree */
if (ana_is_locked(&osc) && result)
printf(" [analog] ** osc LOCKED + residue=0: strong prime resonance **\n");
if (!ana_is_locked(&osc) && result)
printf(" [analog] note: residue=0 (prime) but osc not locked\n");
printf(" [analog] n_words=%zu iters=%llu rk4_steps=%d log_events=%d\n",
n, (unsigned long long)iters, osc.steps, logged);
}
free(mantissa);
free(tmp);
return result;
}
ll_analog.h
/* ll_analog.h — analog LL path: v30b Slot4096 APA + 8D Kuramoto oscillator
*
* Exact arithmetic:
* Slot4096.mantissa_words — p-bit LL residue, arbitrary precision
* ap_sqr_mersenne — schoolbook O(n^2) squaring + Mersenne fold
* ap_sub2_mod_mp — subtract 2 mod 2^p-1
*
* Analog oscillator (after analog_engine.h / AnalogContainer1):
* AnaOsc8D — 8D Kuramoto RK4, φ-seeded natural frequencies
* Adaptive phase — Pluck→Sustain→FineTune→Lock (K/γ wu-wei ratios)
* Cooperative memory — XOR-fold residue hash → phase perturbation every
* ANA_SHA_INTERVAL iters (conditional memory loop)
*
* The oscillator does NOT shortcut correctness. Every p-2 iterations run exact.
* Phase lock is a readout, not a gate — wu-wei.
*
* Build: ll_analog.c compiles as plain C (-O2); link with ll_mpi.cu via clang.
*
* Licensed per https://zchg.org/t/legal-notice-copyright-applicable-ip-and-licensing-read-me/440
*/
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Main entry point: Lucas-Lehmer test via v30b APA + 8D Kuramoto.
* Returns 1 if M_p is prime, 0 if composite, -1 on allocation failure. */
int ll_analog(uint64_t p, int verbose);
#ifdef __cplusplus
}
#endif
ll_analog .ASM
; =============================================================================
; hdgl_analog_v30.asm
; x86-64 NASM — Linux SysV ABI
; Complete translation of hdgl_analog_v30.c (HDGL Analog Mainnet V3.0)
;
; Build:
; nasm -f elf64 hdgl_analog_v30.asm -o hdgl_analog_v30.o
; gcc -no-pie hdgl_analog_v30.o -lm -o hdgl_analog_v30
; =============================================================================
bits 64
default rel
; --- externals ----------------------------------------------------------------
extern malloc, calloc, free, memset, memcpy
extern rand, srand, nanosleep
extern clock_gettime
extern printf
extern time
extern cos, sin, pow, sqrt, fmod, exp, fabs, frexp
; --- POSIX -------------------------------------------------------------------
%define CLOCK_MONOTONIC 1
; --- domain constants --------------------------------------------------------
%define NUM_DN 8
%define CHUNK_SIZE 1048576
%define CHECKPOINT_INTERVAL 100
%define SNAPSHOT_MAX 10
%define CONSENSUS_N 100
; --- APA flags ---------------------------------------------------------------
%define FLAG_SIGN_NEG 1
%define FLAG_IS_NAN 2
%define FLAG_GOI 4
%define FLAG_GUZ 8
%define FLAG_CONSENSUS 16
; --- timespec ----------------------------------------------------------------
%define TS_SIZE 16
%define TS_SEC 0
%define TS_NSEC 8
; --- NumericLattice ----------------------------------------------------------
%define NL_upper 0 ; 7 x f64 = 56
%define NL_adims 56 ; 13 x f64 = 104
%define NL_void 160 ; 1 x f64 = 8
%define NL_lower 168 ; 8 x f64 = 64
%define NL_sib 232 ; 8 x f64 = 64
%define NL_inf 296 ; 4 x f64 = 32
%define NL_choke 328 ; 4 x f64 = 32
%define NL_seeds_ptr 360
%define NL_num_seeds 368
%define NL_SIZE 376
; --- MPI ---------------------------------------------------------------------
%define MPI_words 0
%define MPI_nwords 8
%define MPI_sign 16
%define MPI_SIZE 24
; --- Slot4096 ----------------------------------------------------------------
%define SL_mwords 0
%define SL_nwm 8 ; MPI(24)
%define SL_empi 32 ; MPI(24)
%define SL_ebase 56 ; uint16
%define SL_flags 64 ; uint32
%define SL_soi 72 ; MPI(24)
%define SL_nw 96 ; size_t
%define SL_exp 104 ; int64
%define SL_basef 112 ; float
%define SL_bmant 120 ; int
%define SL_bexp 124 ; int
%define SL_phase 128 ; double
%define SL_pvel 136 ; double
%define SL_freq 144 ; double
%define SL_ampim 152 ; double
%define SL_dimn 160 ; int
%define SL_rval 168 ; double
%define SL_dnamp 176 ; double
%define SL_wmode 184 ; double
%define SL_SIZE 192
; --- AnalogLink --------------------------------------------------------------
%define AL_chg 0
%define AL_chgim 8
%define AL_tens 16
%define AL_pot 24
%define AL_coup 32
%define AL_dncoup 40
%define AL_SIZE 48
; --- ComplexState ------------------------------------------------------------
%define CS_Ar 0
%define CS_Ai 8
%define CS_ph 16
%define CS_pv 24
%define CS_dn 32
%define CS_SIZE 40
; --- HDGLChunk ---------------------------------------------------------------
%define CH_slots 0
%define CH_alloc 8
%define CH_SIZE 16
; --- HDGLLattice -------------------------------------------------------------
%define LT_chunks 0
%define LT_nchunks 8
%define LT_ninst 12
%define LT_spi 16
%define LT_omega 24
%define LT_time 32
%define LT_csteps 40
%define LT_pvar 48
%define LT_ckns 56
%define LT_nl 64
%define LT_SIZE 72
; --- CheckpointMeta ----------------------------------------------------------
%define CM_evo 0
%define CM_tsns 8
%define CM_pvar 16
%define CM_omega 24
%define CM_wt 32
%define CM_SIZE 40
; --- CheckpointManager -------------------------------------------------------
%define CK_snaps 0
%define CK_cnt 8
%define CK_cap 12
%define CK_SIZE 16
; =============================================================================
section .data
align 8
fib_tab: dq 1, 1, 2, 3, 5, 8, 13, 21
prime_tab: dq 2, 3, 5, 7, 11, 13, 17, 19
nl_upper:
dq 0x4065627F82888889 ; 170.6180339887
dq 0x4062F1F530B74E5E ; 150.9442719100
dq 0x40293EB851EB851F ; 12.6180339887
dq 0x40214CF0ABF61E8E ; 8.8541019662
dq 0x4010F1A9FBE76C8C ; 4.2360679775
dq 0x400CE1DC6C0D72AE ; 3.6180339887
dq 0x3FF9E3779B97F4A8 ; 1.6180339887
nl_adims:
dq 0x4020A3EF9DB22D0E ; 8.3141592654
dq 0x401F6BE476B9F800 ; 7.8541019662
dq 0x4019E3779B97F4A8 ; 6.4721359549
dq 0x40167AE147AE147B ; 5.6180339887
dq 0x401370A3D70A3D71 ; 4.8541019662
dq 0x400CE1DC6C0D72AE ; 3.6180339887
dq 0x4004F1A9FBE76C8C ; 2.6180339887
dq 0x3FF9E3779B97F4A8 ; 1.6180339887
dq 0x3FF0000000000000 ; 1.0
dq 0x401F6BE476B9F800 ; 7.8541019662
dq 0x402622F04750B2F1 ; 11.0901699437
dq 0x4031F1B04060EC04 ; 17.9442719100
dq 0x403D0B026F9308D4 ; 29.0344465435
nl_lower:
dq 0x3E112E0BE826D695 ; ~1e-10
dq 0x3FA1A5A2C1B2B100 ; 0.0344465435
dq 0x3FAC90AEC4D79456 ; 0.0557280900
dq 0x3FB717C25A3E3B3B ; 0.0901699437
dq 0x3FC2A8C30C1B85C5 ; 0.1458980338
dq 0x3FCE2B5C2D2D2D2D ; 0.2360679775
dq 0x3FD86B85161B5A3D ; 0.3819660113
dq 0x3FE3C6EF372FE950 ; 0.6180339887
nl_sib:
dq 0x3FB717C25A3E3B3B ; 0.0901699437
dq 0x3FC2A8C30C1B85C5 ; 0.1458980338
dq 0x3FCE2B5C2D2D2D2D ; 0.2360679775
dq 0x3FD3C6EF372FE950 ; 0.3090169944
dq 0x3FD86B85161B5A3D ; 0.3819660113
dq 0x3FDE2B5C2D2D2D2D ; 0.4721359549
dq 0x3FE4F8B588E368F1 ; 0.6545084972
dq 0x3FEBE2B5C2D2D2D3 ; 0.8729833462
nl_seeds:
dq 0x3FE3C6EF372FE950, 0x3FF9E3779B97F4A8, 0x4004F1A9FBE76C8C, 0x400CE1DC6C0D72AE
dq 0x401370A3D70A3D71, 0x40167AE147AE147B, 0x4019E3779B97F4A8, 0x401F6BE476B9F800
dq 0x4020A3EF9DB22D0E, 0x3FB717C25A3E3B3B, 0x3FC2A8C30C1B85C5, 0x3FCE2B5C2D2D2D2D
dq 0x3FD3C6EF372FE950, 0x3FD86B85161B5A3D, 0x3FDE2B5C2D2D2D2D, 0x3FE4F8B588E368F1
dq 0x3FEBE2B5C2D2D2D3, 0x3FF0000000000000, 0x3FF3C6EF372FE950, 0x3FF9E3779B97F4A8
dq 0x4001E3779B97F4A8, 0x4004F1A9FBE76C8C, 0x400921FB54442D18, 0x400CE1DC6C0D72AE
dq 0x4010E2B5C2D2D2D3, 0x401370A3D70A3D71, 0x40167AE147AE147B, 0x4019E3779B97F4A8
dq 0x401CE2B5C2D2D2D3, 0x401F6BE476B9F800, 0x402137C6EF372FE9, 0x402483BC6EF37300
dq 0x40279D3A0AD7A3D7, 0x4025413C6EF37300, 0x402622F04750B2F1, 0x4027E1DC6C0D72AE
dq 0x40293EB851EB851F, 0x402B413C6EF37300, 0x402C839CAF3F72FE, 0x402DC77FFA3D70A4
dq 0x402FD3A0AD7A3D71, 0x40309D3A0AD7A3D7, 0x403141FAAAAAAAB0, 0x4031F1B04060EC04
dq 0x4032A3D70A3D70A4, 0x40334B3B13B13B14, 0x4033F5C28F5C28F6, 0x40349E3779B97F4B
dq 0x403533B13B13B13B, 0x4035DFDF3B13B13B, 0x403686CAC083126F, 0x40378CAC083126F7
dq 0x403836DF3B13B13B, 0x4038DFE147AE147B, 0x40398A3D70A3D70A, 0x403A3279B97F4A8B
dq 0x403ADBE76C8B4396, 0x403B83126E978D4F, 0x403C2B851EB851EC, 0x403CD044EF82BF7E
dq 0x403D7851EB851EB8, 0x403E1CAC083126F7, 0x403EC2B5C2D2D2D3, 0x403F6B851EB851EC
align 8
fp_PHI: dq 0x3FF9E3779B97F4A8 ; 1.6180339887498948
fp_TWO_PI: dq 0x401921FB54442D18 ; 2*pi
fp_GAMMA: dq 0x3F947AE147AE147B ; 0.02
fp_LAMBDA: dq 0x3FA999999999999A ; 0.05
fp_SAT: dq 0x412E848000000000 ; 1e6
fp_NSIG: dq 0x3F847AE147AE147B ; 0.01
fp_CEPS: dq 0x3EF0624DD2F1A9FC ; 1e-6
fp_ATH: dq 0x3FE999999999999A ; 0.8
fp_KC: dq 0x3FF0000000000000 ; 1.0
fp_SDEC: dq 0x3FE6666666666666 ; 0.95
fp_0p98: dq 0x3FEF5C28F5C28F5C ; 0.98
fp_0p95: dq 0x3FE6666666666666 ; 0.95
fp_0: dq 0x0000000000000000
fp_001: dq 0x3F847AE147AE147B ; 0.01
fp_01: dq 0x3FB999999999999A ; 0.1
fp_03: dq 0x3FD3333333333333 ; 0.3
fp_half: dq 0x3FE0000000000000 ; 0.5
fp_1: dq 0x3FF0000000000000 ; 1.0
fp_2: dq 0x4000000000000000 ; 2.0
fp_6: dq 0x4018000000000000 ; 6.0
fp_8: dq 0x4020000000000000 ; 8.0
fp_1000: dq 0x408F400000000000 ; 1000.0
fp_1e10n: dq 0x3EE4F8B588E368F1 ; 1e-10
fp_1e6n: dq 0x3EF0624DD2F1A9FC ; 1e-6 (min dt)
fp_dt0: dq 0x3F00000000000000 ; 1/32768
fp_U64: dq 0x43F0000000000000 ; (double)UINT64_MAX
fp_INF: dq 0x7FF0000000000000
fp_DMAX: dq 0x7FEFFFFFFFFFFFFF
fp_NEG1: dq 0xBFF0000000000000 ; -1.0
sz_rtc: db "[RTC] Using software fallback (CLOCK_MONOTONIC)",10,0
sz_banner: db "=== HDGL Analog Mainnet V3.0: Dn(r) Engine Ready ===",10,10,0
sz_bi: db "[Bootloader] Initializing HDGL Analog Mainnet V3.0 with Dn(r) Engine...",10,0
sz_berr: db "[Bootloader] ERROR: Lattice allocation failed.",10,0
sz_binfo: db "[Bootloader] %d instances, %d total slots",10,0
sz_bseed: db "[Bootloader] Numeric Lattice loaded with %zu Base(oo) seeds",10,0
sz_bdone: db "[Bootloader] Lattice seeded with %d RK4 steps",10,0
sz_bstat: db "[Bootloader] Omega: %.6f, Time: %.6f, PhaseVar: %.6f",10,0
sz_nlhdr: db 10,"Numeric Lattice Summary:",10,0
sz_nluf: db " Upper Field[0]: %.10f",10,0
sz_nlad: db " Analog D8: %.10f",10,0
sz_nlvd: db " The Void: %.10f",10,0
sz_nllf: db " Lower Field[7]: %.10f",10,0
sz_nlbs: db " Base(oo) Seeds: %zu total",10,0
sz_slhdr: db 10,"First 8 slots (post-evolution with Dn(r)):",10,0
sz_slfmt: db " D%d: |A|=%.6e phi=%.3f Dn=%.3f wave=%.1f r=%.3f",10,0
sz_cons: db "[CONSENSUS] Domain locked at t=%.4f (var=%.6f)!",10,0
sz_ckpt: db "[Checkpoint] Saved evo %d (total: %d, var=%.6f)",10,0
sz_aerr: db "Error: Failed to allocate mantissa.",10,0
sz_cerr: db "Error: Copy allocation failed.",10,0
sz_werr: db "Error: Unaligned word counts.",10,0
sz_fatal: db "Fatal: Could not initialize lattice.",10,0
sz_final: db 10,"=== HDGL V3.0 OPERATIONAL ===",10,0
; =============================================================================
section .bss
align 8
ts_clk: resb TS_SIZE
ts_slp: resb TS_SIZE
; =============================================================================
section .text
global main
; -----------------------------------------------------------------------------
; uint64_t det_rand(uint64_t seed) rdi=seed -> rax xorshift64
; -----------------------------------------------------------------------------
det_rand:
mov rax, rdi
mov rcx, rax
shl rcx, 13
xor rax, rcx
mov rcx, rax
shr rcx, 7
xor rax, rcx
mov rcx, rax
shl rcx, 17
xor rax, rcx
ret
; -----------------------------------------------------------------------------
; double get_normalized_rand() -> xmm0 in [0,1)
; -----------------------------------------------------------------------------
get_normalized_rand:
push rbp
mov rbp, rsp
and rsp, -16
call rand
leave
cvtsi2sd xmm0, eax
mov eax, 0x7FFFFFFF
cvtsi2sd xmm1, eax
divsd xmm0, xmm1
ret
; -----------------------------------------------------------------------------
; int64_t get_rtc_ns() -> rax
; -----------------------------------------------------------------------------
get_rtc_ns:
push rbp
mov rbp, rsp
and rsp, -16
mov edi, CLOCK_MONOTONIC
lea rsi, [ts_clk]
call clock_gettime
leave
mov rax, [ts_clk + TS_SEC]
imul rax, rax, 1000000000
add rax, [ts_clk + TS_NSEC]
ret
; -----------------------------------------------------------------------------
; void rtc_sleep_until(int64_t target) rdi=target
; -----------------------------------------------------------------------------
rtc_sleep_until:
push rbp
mov rbp, rsp
push rbx
mov rbx, rdi
call get_rtc_ns
cmp rbx, rax
jle .done
sub rbx, rax
mov rax, rbx
xor edx, edx
mov ecx, 1000000000
div ecx
mov [ts_slp + TS_SEC], rax
mov [ts_slp + TS_NSEC], rdx
and rsp, -16
lea rdi, [ts_slp]
xor rsi, rsi
call nanosleep
.done:
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void init_numeric_lattice(NumericLattice *nl) rdi=nl
; -----------------------------------------------------------------------------
init_numeric_lattice:
push rbp
mov rbp, rsp
push rbx
mov rbx, rdi
lea rsi, [nl_upper]
lea rdi, [rbx + NL_upper]
mov ecx, 7
rep movsq
lea rsi, [nl_adims]
lea rdi, [rbx + NL_adims]
mov ecx, 13
rep movsq
mov qword [rbx + NL_void], 0
lea rsi, [nl_lower]
lea rdi, [rbx + NL_lower]
mov ecx, 8
rep movsq
lea rsi, [nl_sib]
lea rdi, [rbx + NL_sib]
mov ecx, 8
rep movsq
movsd xmm0, [fp_INF]
movsd [rbx + NL_inf + 0], xmm0
movsd [rbx + NL_inf + 8], xmm0
movsd [rbx + NL_inf + 16], xmm0
movsd [rbx + NL_inf + 24], xmm0
movsd xmm0, [fp_DMAX]
movsd [rbx + NL_choke + 0], xmm0
movsd [rbx + NL_choke + 8], xmm0
movsd [rbx + NL_choke + 16], xmm0
movsd [rbx + NL_choke + 24], xmm0
mov qword [rbx + NL_num_seeds], 64
push rbx
and rsp, -16
mov edi, 512
call malloc
pop rbx
mov [rbx + NL_seeds_ptr], rax
mov rdi, rax
lea rsi, [nl_seeds]
mov ecx, 64
rep movsq
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void free_numeric_lattice(NumericLattice *nl) rdi=nl
; -----------------------------------------------------------------------------
free_numeric_lattice:
push rbp
mov rbp, rsp
push rbx
mov rbx, rdi
mov rax, [rbx + NL_seeds_ptr]
test rax, rax
jz .done
push rbx
and rsp, -16
mov rdi, rax
call free
pop rbx
mov qword [rbx + NL_seeds_ptr], 0
.done:
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; double compute_Dn_r(int n, double r, double omega)
; rdi=n xmm0=r xmm1=omega -> xmm0
; Dn(r) = sqrt(phi * F_n * 2^n * P_n * omega) * |r|^((n+1)/8)
; -----------------------------------------------------------------------------
compute_Dn_r:
push rbp
mov rbp, rsp
sub rsp, 48
push rbx
cmp edi, 1
jl .zero
cmp edi, NUM_DN
jg .zero
mov ebx, edi
movsd [rbp-8], xmm0 ; r
movsd [rbp-16], xmm1 ; omega
; F_n = fib_tab[n-1]
lea rax, [fib_tab]
cvtsi2sd xmm2, qword [rax + rbx*8 - 8]
; 2^n
movsd xmm0, [fp_2]
cvtsi2sd xmm1, rbx
and rsp, -16
call pow
movsd [rbp-24], xmm0 ; 2^n
; P_n = prime_tab[n-1]
lea rax, [prime_tab]
cvtsi2sd xmm3, qword [rax + rbx*8 - 8]
; base = sqrt(phi * F_n * 2^n * P_n * omega)
movsd xmm0, [fp_PHI]
mulsd xmm0, xmm2
mulsd xmm0, [rbp-24]
mulsd xmm0, xmm3
mulsd xmm0, [rbp-16]
call sqrt
movsd [rbp-32], xmm0
; k = (n+1)/8.0
mov eax, ebx
inc eax
cvtsi2sd xmm0, eax
movsd xmm1, [fp_8]
divsd xmm0, xmm1
movsd [rbp-40], xmm0
; |r|^k
movsd xmm0, [rbp-8]
call fabs
movsd xmm1, [rbp-40]
call pow
mulsd xmm0, [rbp-32]
jmp .done
.zero:
xorpd xmm0, xmm0
.done:
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void mpi_init(MPI *m, size_t nw) rdi=m rsi=nw
; -----------------------------------------------------------------------------
mpi_init:
push rbp
mov rbp, rsp
push rbx
push r12
mov rbx, rdi
mov r12, rsi
and rsp, -16
mov rdi, rsi
mov rsi, 8
call calloc
mov [rbx + MPI_words], rax
mov [rbx + MPI_nwords], r12
mov byte [rbx + MPI_sign], 0
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void mpi_free(MPI *m) rdi=m
; -----------------------------------------------------------------------------
mpi_free:
push rbp
mov rbp, rsp
push rbx
mov rbx, rdi
mov rax, [rbx + MPI_words]
test rax, rax
jz .done
and rsp, -16
mov rdi, rax
call free
mov qword [rbx + MPI_words], 0
mov qword [rbx + MPI_nwords], 0
.done:
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void mpi_copy(MPI *dst, const MPI *src) rdi=dst rsi=src
; -----------------------------------------------------------------------------
mpi_copy:
push rbp
mov rbp, rsp
push rbx
push r12
mov rbx, rdi
mov r12, rsi
call mpi_free ; free existing dst words
mov rcx, [r12 + MPI_nwords]
mov [rbx + MPI_nwords], rcx
mov al, [r12 + MPI_sign]
mov [rbx + MPI_sign], al
and rsp, -16
mov rdi, rcx
shl rdi, 3
call malloc
mov [rbx + MPI_words], rax
mov rdi, rax
mov rsi, [r12 + MPI_words]
mov rdx, [rbx + MPI_nwords]
shl rdx, 3
call memcpy
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void mpi_set(MPI *m, uint64_t val, uint8_t sign) rdi=m rsi=val dl=sign
; -----------------------------------------------------------------------------
mpi_set:
mov rax, [rdi + MPI_words]
test rax, rax
jz .done
mov [rax], rsi
mov [rdi + MPI_sign], dl
.done:
ret
; -----------------------------------------------------------------------------
; void slot_init(Slot4096 *out, int bm, int be, int dn, double rv, double om)
; rdi=out rsi=bm rdx=be rcx=dn xmm0=rv xmm1=om
; -----------------------------------------------------------------------------
slot_init:
push rbp
mov rbp, rsp
sub rsp, 64
push rbx
push r12
push r13
push r14
push r15
mov rbx, rdi
mov r12d, esi ; bm
mov r13d, edx ; be
mov r14d, ecx ; dn
movsd [rbp-8], xmm0 ; rv
movsd [rbp-16], xmm1 ; om
and rsp, -16
mov rdi, rbx
xor rsi, rsi
mov rdx, SL_SIZE
call memset
mov [rbx + SL_bmant], r12d
mov [rbx + SL_bexp], r13d
; num_words = (bm+63)/64
mov eax, r12d
add eax, 63
shr eax, 6
movsx rax, eax
mov [rbx + SL_nw], rax
; calloc(nw, 8)
mov rdi, rax
mov rsi, 8
call calloc
test rax, rax
jnz .mant_ok
lea rdi, [sz_aerr]
xor eax, eax
call printf
jmp .done
.mant_ok:
mov [rbx + SL_mwords], rax
lea rdi, [rbx + SL_empi]
mov rsi, 1
call mpi_init
lea rdi, [rbx + SL_nwm]
mov rsi, 1
call mpi_init
lea rdi, [rbx + SL_soi]
mov rsi, 1
call mpi_init
mov [rbx + SL_dimn], r14d
movsd xmm0, [rbp-8]
movsd [rbx + SL_rval], xmm0
; Dn_amplitude
mov edi, r14d
movsd xmm0, [rbp-8]
movsd xmm1, [rbp-16]
call compute_Dn_r
movsd [rbx + SL_dnamp], xmm0
movsd [rbp-24], xmm0
; wave_mode from dimn%3
mov eax, r14d
cdq
mov ecx, 3
idiv ecx
cmp edx, 1
je .wm1
cmp edx, 2
je .wm0
movsd xmm0, [fp_NEG1]
jmp .wm_set
.wm1:
movsd xmm0, [fp_1]
jmp .wm_set
.wm0:
xorpd xmm0, xmm0
.wm_set:
movsd [rbx + SL_wmode], xmm0
; mantissa_words[0] = (uint64_t)(|Dn|*U64/1000) | MSB
cmp qword [rbx + SL_nw], 0
je .skip_mant
movsd xmm0, [rbp-24]
call fabs
mulsd xmm0, [fp_U64]
divsd xmm0, [fp_1000]
maxsd xmm0, [fp_0]
cvttsd2si rax, xmm0
mov rcx, [rbx + SL_mwords]
mov [rcx], rax
bts qword [rcx], 63
.skip_mant:
; exponent = rand()%exp_range - exp_bias
mov ecx, r13d
mov r15d, 1
shl r15d, cl ; exp_range = 1<<be
call rand
xor edx, edx
div r15d ; edx = rand%exp_range
mov ecx, r13d
dec ecx
mov eax, 1
shl eax, cl ; exp_bias
sub edx, eax
movsx rax, edx
mov [rbx + SL_exp], rax
mov word [rbx + SL_ebase], 4096
; base = PHI + 0.01*rand
call get_normalized_rand
mulsd xmm0, [fp_001]
addsd xmm0, [fp_PHI]
cvtsd2ss xmm0, xmm0
movss [rbx + SL_basef], xmm0
; phase = 2pi*rand
call get_normalized_rand
mulsd xmm0, [fp_TWO_PI]
movsd [rbx + SL_phase], xmm0
; freq = 1 + 0.5*rand
call get_normalized_rand
mulsd xmm0, [fp_half]
addsd xmm0, [fp_1]
movsd [rbx + SL_freq], xmm0
; amp_im = 0.1*rand
call get_normalized_rand
mulsd xmm0, [fp_01]
movsd [rbx + SL_ampim], xmm0
; sync empi
mov rax, [rbx + SL_exp]
mov rsi, rax
xor dl, dl
test rax, rax
jns .ep1
neg rsi
mov dl, 1
.ep1:
lea rdi, [rbx + SL_empi]
call mpi_set
; sync nwm
lea rdi, [rbx + SL_nwm]
mov rsi, [rbx + SL_nw]
xor dl, dl
call mpi_set
.done:
pop r15
pop r14
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void ap_free(Slot4096 *s) rdi=s
; -----------------------------------------------------------------------------
ap_free:
push rbp
mov rbp, rsp
push rbx
mov rbx, rdi
test rbx, rbx
jz .done
mov rax, [rbx + SL_mwords]
test rax, rax
jz .skip_m
and rsp, -16
mov rdi, rax
call free
mov qword [rbx + SL_mwords], 0
.skip_m:
lea rdi, [rbx + SL_empi]
call mpi_free
lea rdi, [rbx + SL_nwm]
call mpi_free
lea rdi, [rbx + SL_soi]
call mpi_free
mov qword [rbx + SL_nw], 0
.done:
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void ap_copy(Slot4096 *dst, const Slot4096 *src) rdi=dst rsi=src
; -----------------------------------------------------------------------------
ap_copy:
push rbp
mov rbp, rsp
push rbx
push r12
mov rbx, rdi
mov r12, rsi
call ap_free
and rsp, -16
mov rdi, rbx
mov rsi, r12
mov rdx, SL_SIZE
call memcpy
; deep-copy mantissa
mov rcx, [rbx + SL_nw]
test rcx, rcx
jz .done
mov rdi, rcx
shl rdi, 3
call malloc
test rax, rax
jnz .mok
lea rdi, [sz_cerr]
xor eax, eax
call printf
mov qword [rbx + SL_nw], 0
jmp .done
.mok:
mov [rbx + SL_mwords], rax
mov rdi, rax
mov rsi, [r12 + SL_mwords]
mov rdx, [rbx + SL_nw]
shl rdx, 3
call memcpy
lea rdi, [rbx + SL_empi]
lea rsi, [r12 + SL_empi]
call mpi_copy
lea rdi, [rbx + SL_nwm]
lea rsi, [r12 + SL_nwm]
call mpi_copy
lea rdi, [rbx + SL_soi]
lea rsi, [r12 + SL_soi]
call mpi_copy
.done:
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; double ap_to_double(const Slot4096 *s) rdi=s -> xmm0
; -----------------------------------------------------------------------------
ap_to_double:
push rbp
mov rbp, rsp
sub rsp, 16
push rbx
mov rbx, rdi
test rbx, rbx
jz .zero
cmp qword [rbx + SL_nw], 0
je .zero
mov rax, [rbx + SL_mwords]
test rax, rax
jz .zero
; unsigned 64->double two-step
mov rdx, [rax]
test rdx, rdx
js .big_uint
cvtsi2sd xmm0, rdx
jmp .div
.big_uint:
mov rcx, rdx
and rcx, 1
shr rdx, 1
or rdx, rcx
cvtsi2sd xmm0, rdx
addsd xmm0, xmm0
.div:
divsd xmm0, [fp_U64]
movsd [rbp-8], xmm0
movsd xmm0, [fp_2]
mov rax, [rbx + SL_exp]
cvtsi2sd xmm1, rax
and rsp, -16
call pow
mulsd xmm0, [rbp-8]
jmp .done
.zero:
xorpd xmm0, xmm0
.done:
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; Slot4096 *ap_from_double(double v, int bm, int be)
; xmm0=v rdi=bm rsi=be -> rax
; -----------------------------------------------------------------------------
ap_from_double:
push rbp
mov rbp, rsp
sub rsp, 48
push rbx
push r12
push r13
movsd [rbp-8], xmm0
mov r12d, edi
mov r13d, esi
and rsp, -16
mov rdi, SL_SIZE
call malloc
test rax, rax
jz .null
mov rbx, rax
; init with dimn=1, r=0.5, omega=1
mov rdi, rbx
mov esi, r12d
mov edx, r13d
mov ecx, 1
movsd xmm0, [fp_half]
movsd xmm1, [fp_1]
call slot_init
; if v==0 we're done
movsd xmm0, [rbp-8]
xorpd xmm1, xmm1
ucomisd xmm0, xmm1
jz .ret
; frexp
lea rsi, [rbp-16]
call frexp
movsd [rbp-24], xmm0
movsx rax, dword [rbp-16]
mov [rbx + SL_exp], rax
; mantissa
movsd xmm0, [rbp-24]
call fabs
mulsd xmm0, [fp_U64]
maxsd xmm0, [fp_0]
cvttsd2si rax, xmm0
mov rcx, [rbx + SL_mwords]
test rcx, rcx
jz .sgn
mov [rcx], rax
.sgn:
movsd xmm0, [rbp-8]
xorpd xmm1, xmm1
ucomisd xmm0, xmm1
jae .sgn_done
or dword [rbx + SL_flags], FLAG_SIGN_NEG
.sgn_done:
; sync empi
mov rax, [rbx + SL_exp]
mov rsi, rax
xor dl, dl
test rax, rax
jns .ep
neg rsi
mov dl, 1
.ep:
lea rdi, [rbx + SL_empi]
call mpi_set
.ret:
mov rax, rbx
jmp .done
.null:
xor rax, rax
.done:
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void ap_shift_right(uint64_t *w, size_t nw, int64_t shift)
; rdi=w rsi=nw rdx=shift
; -----------------------------------------------------------------------------
ap_shift_right:
test rdx, rdx
jle .ret
test rsi, rsi
jz .ret
push rbp
mov rbp, rsp
push rbx
push r12
push r13
push r14
mov rbx, rdi
mov r12, rsi
mov r13, rdx
; if shift >= nw*64: zero all
mov rax, r12
shl rax, 6
cmp r13, rax
jl .do
and rsp, -16
mov rdi, rbx
xor rsi, rsi
mov rdx, r12
shl rdx, 3
call memset
jmp .pop
.do:
; word_shift = shift/64 bit_shift = shift%64
mov rax, r13
xor edx, edx
mov ecx, 64
div ecx
mov r14, rax ; word_shift
mov r8d, edx ; bit_shift
; word-level shift (move words right)
test r14, r14
jz .bits
mov rax, r12
dec rax ; i = nw-1
.wl:
cmp rax, r14
jl .wl_done
mov rcx, rax
sub rcx, r14
mov r9, [rbx + rcx*8]
mov [rbx + rax*8], r9
dec rax
jmp .wl
.wl_done:
; zero the first word_shift words
and rsp, -16
mov rdi, rbx
xor rsi, rsi
mov rdx, r14
shl rdx, 3
call memset
.bits:
test r8d, r8d
jz .pop
; bit-level shift right, carrying upper bits from left neighbour
mov ecx, r8d ; bit_shift in cl
mov r9d, 64
sub r9d, r8d ; 64-bit_shift in r9d
mov rax, r12
dec rax ; i = nw-1
.bl:
cmp rax, 1
jl .blast
mov r10, [rbx + rax*8]
shr r10, cl ; w[i] >>= bit_shift
mov rdx, rax
dec rdx
mov r11, [rbx + rdx*8]
push rcx
mov cl, r9b ; 64-bit_shift
shl r11, cl ; carry from w[i-1]
pop rcx
or r10, r11
mov [rbx + rax*8], r10
dec rax
jmp .bl
.blast:
shr qword [rbx], cl ; w[0] >>= bit_shift
.pop:
pop r14
pop r13
pop r12
pop rbx
leave
.ret:
ret
; -----------------------------------------------------------------------------
; void ap_normalize(Slot4096 *s) rdi=s
; -----------------------------------------------------------------------------
ap_normalize:
push rbp
mov rbp, rsp
push rbx
push r12
mov rbx, rdi
cmp qword [rbx + SL_nw], 0
je .done
mov r12, [rbx + SL_mwords]
test r12, r12
jz .done
.loop:
mov rax, [r12]
test rax, rax
js .normed
jz .zexp
; underflow guard
cmp qword [rbx + SL_exp], -32768
jle .guz
; left-shift mantissa by 1
mov rcx, [rbx + SL_nw]
dec rcx
xor r8, r8 ; carry
.sl:
js .sld
mov r9, [r12 + rcx*8]
mov r10, r9
shr r10, 63
shl r9, 1
or r9, r8
mov [r12 + rcx*8], r9
mov r8, r10
dec rcx
jmp .sl
.sld:
dec qword [rbx + SL_exp]
jmp .loop
.guz:
or dword [rbx + SL_flags], FLAG_GUZ
jmp .normed
.zexp:
mov qword [rbx + SL_exp], 0
.normed:
; sync empi
mov rax, [rbx + SL_exp]
mov rsi, rax
xor dl, dl
test rax, rax
jns .ep
neg rsi
mov dl, 1
.ep:
lea rdi, [rbx + SL_empi]
call mpi_set
.done:
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void ap_add(Slot4096 *A, const Slot4096 *B) rdi=A rsi=B
; -----------------------------------------------------------------------------
ap_add:
push rbp
mov rbp, rsp
sub rsp, SL_SIZE + 16
push rbx
push r12
mov rbx, rdi
mov r12, rsi
; check word count match
mov rax, [rbx + SL_nw]
cmp rax, [r12 + SL_nw]
je .ok
and rsp, -16
lea rdi, [sz_werr]
xor eax, eax
call printf
jmp .done
.ok:
; B_aligned on stack
lea r8, [rbp - SL_SIZE - 8]
and rsp, -16
mov rdi, r8
xor rsi, rsi
mov rdx, SL_SIZE
call memset
mov rdi, r8
mov rsi, r12
call ap_copy
mov r12, r8 ; B_aligned
; align exponents
mov rax, [rbx + SL_exp]
sub rax, [r12 + SL_exp]
jz .add_words
jg .shift_b
; shift A right
neg rax
mov rdi, [rbx + SL_mwords]
mov rsi, [rbx + SL_nw]
mov rdx, rax
call ap_shift_right
mov rax, [r12 + SL_exp]
mov [rbx + SL_exp], rax
jmp .add_words
.shift_b:
mov rdx, rax
mov rdi, [r12 + SL_mwords]
mov rsi, [r12 + SL_nw]
call ap_shift_right
.add_words:
; ripple-carry add from highest to lowest word
mov rcx, [rbx + SL_nw]
dec rcx
mov rdi, [rbx + SL_mwords]
mov rsi, [r12 + SL_mwords]
xor r8b, r8b
.al:
js .ad
mov rax, [rdi + rcx*8]
mov rdx, [rsi + rcx*8]
add rax, rdx
setc r9b
add rax, r8
setc r10b
or r9b, r10b
mov [rdi + rcx*8], rax
mov r8b, r9b
dec rcx
jmp .al
.ad:
test r8b, r8b
jz .normalize
or dword [rbx + SL_flags], FLAG_GOI
.normalize:
mov rdi, rbx
call ap_normalize
; free B_aligned's heap data
mov rdi, [r12 + SL_mwords]
test rdi, rdi
jz .fmpi
and rsp, -16
call free
.fmpi:
lea rdi, [r12 + SL_empi]
call mpi_free
lea rdi, [r12 + SL_nwm]
call mpi_free
lea rdi, [r12 + SL_soi]
call mpi_free
.done:
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void exchange_analog_links(AnalogLink *L, int rank, int size, int n)
; rdi=L rsi=rank rdx=size rcx=n (MPI_REAL=0 branch: simple decay)
; -----------------------------------------------------------------------------
exchange_analog_links:
xor eax, eax
.loop:
cmp eax, ecx
jge .ret
imul r8, rax, AL_SIZE
add r8, rdi
movsd xmm0, [r8 + AL_chg]
mulsd xmm0, [fp_0p95]
movsd [r8 + AL_chg], xmm0
movsd xmm0, [r8 + AL_chgim]
mulsd xmm0, [fp_0p95]
movsd [r8 + AL_chgim], xmm0
movsd xmm0, [r8 + AL_dncoup]
mulsd xmm0, [fp_0p98]
movsd [r8 + AL_dncoup], xmm0
inc eax
jmp .loop
.ret:
ret
; -----------------------------------------------------------------------------
; void fill_one_neigh(HDGLLattice *lat, Slot4096 *myslot, int nidx,
; AnalogLink *link)
; rdi=lat rsi=myslot rdx=nidx rcx=link
; Computes one neighbor entry; does nothing if neigh slot is null.
; -----------------------------------------------------------------------------
fill_one_neigh:
push rbp
mov rbp, rsp
push rbx
push r12
push r13
push r14
mov rbx, rdi ; lat
mov r12, rsi ; my slot
mov r13d, edx ; neigh index
mov r14, rcx ; &link
and rsp, -16
mov rdi, rbx
mov esi, r13d
call lattice_get_slot
test rax, rax
jz .done
mov r13, rax ; neigh slot
; charge = ap_to_double(neigh)
mov rdi, r13
call ap_to_double
movsd [r14 + AL_chg], xmm0
movsd xmm0, [r13 + SL_ampim]
movsd [r14 + AL_chgim], xmm0
; potential = neigh->phase - myslot->phase
movsd xmm0, [r13 + SL_phase]
subsd xmm0, [r12 + SL_phase]
movsd [r14 + AL_pot], xmm0
; Dn_coupling = neigh->Dn * exp(-|neigh->Dn - myslot->Dn|)
movsd xmm0, [r13 + SL_dnamp]
subsd xmm0, [r12 + SL_dnamp]
call fabs
movsd xmm1, [fp_NEG1]
mulsd xmm0, xmm1
push r13
push r14
call exp
pop r14
pop r13
mulsd xmm0, [r13 + SL_dnamp]
movsd [r14 + AL_dncoup], xmm0
; coupling = 1.0 (simplified from amp_correlation formula)
movsd xmm0, [fp_1]
movsd [r14 + AL_coup], xmm0
.done:
pop r14
pop r13
pop r12
pop rbx
leave
ret
; forward declaration used by fill_one_neigh and lattice_integrate_rk4
; (lattice_get_slot defined later)
; -----------------------------------------------------------------------------
; void deriv_Dn(ComplexState *out, const ComplexState *st,
; double omega, const AnalogLink *nb, int nnb,
; int dimn, double wmode)
; rdi=out rsi=st xmm0=omega rdx=nb rcx=nnb r8d=dimn xmm1=wmode
; -----------------------------------------------------------------------------
deriv_Dn:
push rbp
mov rbp, rsp
sub rsp, 64
push rbx
push r12
push r13
push r14
mov rbx, rdi ; out
mov r12, rsi ; st
movsd [rbp-8], xmm0 ; omega
mov r13, rdx ; nb
mov r14d, ecx ; nnb
movsd [rbp-16], xmm1 ; wmode
; zero out
and rsp, -16
mov rdi, rbx
xor rsi, rsi
mov rdx, CS_SIZE
call memset
; A = sqrt(Ar^2 + Ai^2)
movsd xmm0, [r12 + CS_Ar]
mulsd xmm0, xmm0
movsd xmm1, [r12 + CS_Ai]
mulsd xmm1, xmm1
addsd xmm0, xmm1
call sqrt
movsd [rbp-24], xmm0 ; A
; deriv.Ar = -GAMMA*Ar + 0.1*Dn*cos(phase)
movsd xmm0, [r12 + CS_ph]
call cos
mulsd xmm0, [r12 + CS_dn]
mulsd xmm0, [fp_01]
movsd xmm1, [fp_GAMMA]
mulsd xmm1, [r12 + CS_Ar]
subsd xmm0, xmm1
movsd [rbx + CS_Ar], xmm0
; deriv.Ai = -GAMMA*Ai + 0.1*Dn*sin(phase)
movsd xmm0, [r12 + CS_ph]
call sin
mulsd xmm0, [r12 + CS_dn]
mulsd xmm0, [fp_01]
movsd xmm1, [fp_GAMMA]
mulsd xmm1, [r12 + CS_Ai]
subsd xmm0, xmm1
movsd [rbx + CS_Ai], xmm0
; neighbour coupling loop
xorpd xmm13, xmm13 ; sum_sin = 0
xor r9d, r9d ; k = 0
.nb_loop:
cmp r9d, r14d
jge .nb_done
imul rax, r9, AL_SIZE
lea r10, [r13 + rax] ; &nb[k]
; delta_phi = nb[k].potential - st.phase
movsd xmm0, [r10 + AL_pot]
subsd xmm0, [r12 + CS_ph]
movsd [rbp-32], xmm0 ; delta_phi
; sum_sin += sin(delta_phi)
call sin
addsd xmm13, xmm0
; Dn_factor = nb[k].dncoup / (1 + |st.Dn|)
movsd xmm0, [r12 + CS_dn]
call fabs
addsd xmm0, [fp_1]
movsd xmm1, [r10 + AL_dncoup]
divsd xmm1, xmm0 ; Dn_factor
movsd [rbp-40], xmm1
; deriv.Ar += Kc * Dn_factor * charge * cos(delta_phi)
movsd xmm0, [rbp-32]
call cos
mulsd xmm0, [r10 + AL_chg]
mulsd xmm0, [rbp-40]
mulsd xmm0, [fp_KC]
addsd xmm0, [rbx + CS_Ar]
movsd [rbx + CS_Ar], xmm0
; deriv.Ai += Kc * Dn_factor * charge_im * sin(delta_phi)
movsd xmm0, [rbp-32]
call sin
mulsd xmm0, [r10 + AL_chgim]
mulsd xmm0, [rbp-40]
mulsd xmm0, [fp_KC]
addsd xmm0, [rbx + CS_Ai]
movsd [rbx + CS_Ai], xmm0
inc r9d
jmp .nb_loop
.nb_done:
; deriv.phase_vel = omega + Kc*sum_sin + 0.3*wmode
movsd xmm0, [rbp-8]
mulsd xmm13, [fp_KC]
addsd xmm0, xmm13
movsd xmm1, [rbp-16]
mulsd xmm1, [fp_03]
addsd xmm0, xmm1
movsd [rbx + CS_pv], xmm0
; deriv.phase = st.phase_vel
movsd xmm0, [r12 + CS_pv]
movsd [rbx + CS_ph], xmm0
; deriv.Dn = -0.01*(Dn_val - A)
movsd xmm0, [r12 + CS_dn]
subsd xmm0, [rbp-24]
mulsd xmm0, [fp_001]
movsd xmm1, xmm0
xorpd xmm0, xmm0
subsd xmm0, xmm1
movsd [rbx + CS_dn], xmm0
pop r14
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void rk4_step(Slot4096 *slot, double dt, const AnalogLink *nb, int nnb,
; double omega)
; rdi=slot xmm0=dt rsi=nb rdx=nnb xmm1=omega
;
; Stack layout (from rbp downward):
; [rbp- 8] dt
; [rbp-16] omega
; [rbp-24] saved A (amplitude after damping)
; [rbp-32] norm
; state at [rbp - 240]
; tmp at [rbp - 200]
; k1 at [rbp - 160]
; k2 at [rbp - 120]
; k3 at [rbp - 80]
; k4 at [rbp - 40]
; Total CS slots: 6 * 40 = 240, plus 32 saved doubles = 272, round to 288
; -----------------------------------------------------------------------------
rk4_step:
push rbp
mov rbp, rsp
sub rsp, 288
push rbx
push r12
push r13
push r14
mov rbx, rdi ; slot
movsd [rbp-8], xmm0 ; dt
mov r12, rsi ; nb
mov r13d, edx ; nnb
movsd [rbp-16], xmm1 ; omega
; offsets relative to rbp (all negative)
; state = rbp-240, tmp = rbp-200, k1 = rbp-160, k2 = rbp-120,
; k3 = rbp-80, k4 = rbp-40
%define ST_OFF 240
%define TMP_OFF 200
%define K1_OFF 160
%define K2_OFF 120
%define K3_OFF 80
%define K4_OFF 40
; --- build initial ComplexState ---
and rsp, -16
mov rdi, rbx
call ap_to_double
movsd [rbp - ST_OFF + CS_Ar], xmm0
movsd xmm0, [rbx + SL_ampim]
movsd [rbp - ST_OFF + CS_Ai], xmm0
movsd xmm0, [rbx + SL_phase]
movsd [rbp - ST_OFF + CS_ph], xmm0
movsd xmm0, [rbx + SL_pvel]
movsd [rbp - ST_OFF + CS_pv], xmm0
movsd xmm0, [rbx + SL_dnamp]
movsd [rbp - ST_OFF + CS_dn], xmm0
; --- k1 = deriv(state, ...) ---
lea rdi, [rbp - K1_OFF]
lea rsi, [rbp - ST_OFF]
movsd xmm0, [rbp-16]
mov rdx, r12
mov ecx, r13d
mov r8d, [rbx + SL_dimn]
movsd xmm1, [rbx + SL_wmode]
call deriv_Dn
; --- tmp = state + (dt/2)*k1 ---
movsd xmm15, [rbp-8]
mulsd xmm15, [fp_half] ; dt/2
%macro LERP5 3 ; dst_neg_off, src_neg_off, k_neg_off
movsd xmm0, [rbp - %3 + CS_Ar]
mulsd xmm0, xmm15
addsd xmm0, [rbp - %2 + CS_Ar]
movsd [rbp - %1 + CS_Ar], xmm0
movsd xmm0, [rbp - %3 + CS_Ai]
mulsd xmm0, xmm15
addsd xmm0, [rbp - %2 + CS_Ai]
movsd [rbp - %1 + CS_Ai], xmm0
movsd xmm0, [rbp - %3 + CS_ph]
mulsd xmm0, xmm15
addsd xmm0, [rbp - %2 + CS_ph]
movsd [rbp - %1 + CS_ph], xmm0
movsd xmm0, [rbp - %3 + CS_pv]
mulsd xmm0, xmm15
addsd xmm0, [rbp - %2 + CS_pv]
movsd [rbp - %1 + CS_pv], xmm0
movsd xmm0, [rbp - %3 + CS_dn]
mulsd xmm0, xmm15
addsd xmm0, [rbp - %2 + CS_dn]
movsd [rbp - %1 + CS_dn], xmm0
%endmacro
LERP5 TMP_OFF, ST_OFF, K1_OFF ; tmp = st + dt/2*k1
; --- k2 = deriv(tmp, ...) ---
lea rdi, [rbp - K2_OFF]
lea rsi, [rbp - TMP_OFF]
movsd xmm0, [rbp-16]
mov rdx, r12
mov ecx, r13d
mov r8d, [rbx + SL_dimn]
movsd xmm1, [rbx + SL_wmode]
call deriv_Dn
LERP5 TMP_OFF, ST_OFF, K2_OFF ; tmp = st + dt/2*k2
; --- k3 = deriv(tmp, ...) ---
lea rdi, [rbp - K3_OFF]
lea rsi, [rbp - TMP_OFF]
movsd xmm0, [rbp-16]
mov rdx, r12
mov ecx, r13d
mov r8d, [rbx + SL_dimn]
movsd xmm1, [rbx + SL_wmode]
call deriv_Dn
; tmp = st + dt*k3 (full dt)
movsd xmm15, [rbp-8] ; dt (not halved)
LERP5 TMP_OFF, ST_OFF, K3_OFF
; --- k4 = deriv(tmp, ...) ---
lea rdi, [rbp - K4_OFF]
lea rsi, [rbp - TMP_OFF]
movsd xmm0, [rbp-16]
mov rdx, r12
mov ecx, r13d
mov r8d, [rbx + SL_dimn]
movsd xmm1, [rbx + SL_wmode]
call deriv_Dn
; --- weighted sum: state += (dt/6)*(k1 + 2*k2 + 2*k3 + k4) ---
movsd xmm15, [rbp-8]
divsd xmm15, [fp_6] ; dt/6
%macro RK4SUM 1 ; CS field offset
movsd xmm0, [rbp - K1_OFF + %1]
movsd xmm1, [rbp - K2_OFF + %1]
addsd xmm1, xmm1
addsd xmm0, xmm1
movsd xmm1, [rbp - K3_OFF + %1]
addsd xmm1, xmm1
addsd xmm0, xmm1
addsd xmm0, [rbp - K4_OFF + %1]
mulsd xmm0, xmm15
addsd xmm0, [rbp - ST_OFF + %1]
movsd [rbp - ST_OFF + %1], xmm0
%endmacro
RK4SUM CS_Ar
RK4SUM CS_Ai
RK4SUM CS_ph
RK4SUM CS_pv
RK4SUM CS_dn
; --- entropy dampers ---
; A = sqrt(Ar^2+Ai^2)
movsd xmm0, [rbp - ST_OFF + CS_Ar]
mulsd xmm0, xmm0
movsd xmm1, [rbp - ST_OFF + CS_Ai]
mulsd xmm1, xmm1
addsd xmm0, xmm1
call sqrt
; A *= exp(-LAMBDA*dt)
movsd [rbp-24], xmm0
movsd xmm0, [fp_LAMBDA]
mulsd xmm0, [rbp-8]
mulsd xmm0, [fp_NEG1]
call exp
mulsd xmm0, [rbp-24]
; clamp to SAT_LIMIT
minsd xmm0, [fp_SAT]
; add noise: A += NSIG*(2*rand-1)
movsd [rbp-24], xmm0
call get_normalized_rand
addsd xmm0, xmm0
subsd xmm0, [fp_1]
mulsd xmm0, [fp_NSIG]
addsd xmm0, [rbp-24]
movsd [rbp-24], xmm0 ; final A
; renormalize direction
movsd xmm0, [rbp - ST_OFF + CS_Ar]
mulsd xmm0, xmm0
movsd xmm1, [rbp - ST_OFF + CS_Ai]
mulsd xmm1, xmm1
addsd xmm0, xmm1
call sqrt
movsd [rbp-32], xmm0 ; norm
ucomisd xmm0, [fp_1e10n]
jbe .no_renorm
movsd xmm1, [rbp-24] ; A
divsd xmm1, xmm0 ; A/norm
movsd xmm0, [rbp - ST_OFF + CS_Ar]
mulsd xmm0, xmm1
movsd [rbp - ST_OFF + CS_Ar], xmm0
movsd xmm0, [rbp - ST_OFF + CS_Ai]
mulsd xmm0, xmm1
movsd [rbp - ST_OFF + CS_Ai], xmm0
.no_renorm:
; wrap phase into [0, 2pi)
movsd xmm0, [rbp - ST_OFF + CS_ph]
movsd xmm1, [fp_TWO_PI]
call fmod
movsd [rbp - ST_OFF + CS_ph], xmm0
xorpd xmm1, xmm1
ucomisd xmm0, xmm1
jae .ph_ok
addsd xmm0, [fp_TWO_PI]
movsd [rbp - ST_OFF + CS_ph], xmm0
.ph_ok:
; clamp Dn to [0, 1000]
movsd xmm0, [rbp - ST_OFF + CS_dn]
maxsd xmm0, [fp_0]
minsd xmm0, [fp_1000]
movsd [rbp - ST_OFF + CS_dn], xmm0
; --- write back ---
movsd xmm0, [rbp - ST_OFF + CS_Ar]
mov edi, [rbx + SL_bmant]
mov esi, [rbx + SL_bexp]
call ap_from_double
test rax, rax
jz .skip_wb
push rax
mov rdi, rbx
mov rsi, rax
call ap_copy
pop rdi
call ap_free
and rsp, -16
call free
.skip_wb:
movsd xmm0, [rbp - ST_OFF + CS_Ai]
movsd [rbx + SL_ampim], xmm0
movsd xmm0, [rbp - ST_OFF + CS_ph]
movsd [rbx + SL_phase], xmm0
movsd xmm0, [rbp - ST_OFF + CS_pv]
movsd [rbx + SL_pvel], xmm0
movsd xmm0, [rbp - ST_OFF + CS_dn]
movsd [rbx + SL_dnamp], xmm0
pop r14
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; HDGLLattice *lattice_init(int ninst, int spi) rdi=ninst rsi=spi
; -----------------------------------------------------------------------------
lattice_init:
push rbp
mov rbp, rsp
push rbx
push r12
push r13
mov r12d, edi
mov r13d, esi
and rsp, -16
mov rdi, LT_SIZE
call malloc
test rax, rax
jz .null
mov rbx, rax
mov rdi, rbx
xor rsi, rsi
mov rdx, LT_SIZE
call memset
mov [rbx + LT_ninst], r12d
mov [rbx + LT_spi], r13d
movsd xmm0, [fp_1]
movsd [rbx + LT_omega], xmm0
movsd xmm0, [fp_0]
movsd [rbx + LT_time], xmm0
movsd xmm0, [fp_1000]
movsd [rbx + LT_pvar], xmm0
call get_rtc_ns
mov [rbx + LT_ckns], rax
; numeric lattice
mov rdi, NL_SIZE
call malloc
test rax, rax
jz .fail_nl
mov [rbx + LT_nl], rax
mov rdi, rax
call init_numeric_lattice
; num_chunks = ceil(ninst*spi / CHUNK_SIZE)
mov eax, r12d
imul eax, r13d
add eax, CHUNK_SIZE - 1
xor edx, edx
mov ecx, CHUNK_SIZE
div ecx
mov [rbx + LT_nchunks], eax
; calloc chunk pointer array
mov rdi, rax
mov rsi, 8
call calloc
test rax, rax
jz .fail_chunks
mov [rbx + LT_chunks], rax
mov rax, rbx
jmp .done
.fail_chunks:
mov rdi, [rbx + LT_nl]
call free_numeric_lattice
mov rdi, [rbx + LT_nl]
call free
.fail_nl:
mov rdi, rbx
call free
.null:
xor rax, rax
.done:
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; HDGLChunk *lattice_get_chunk(HDGLLattice *lat, int ci)
; rdi=lat rsi=ci -> rax
; -----------------------------------------------------------------------------
lattice_get_chunk:
push rbp
mov rbp, rsp
push rbx
push r12
push r13
push r14
mov rbx, rdi
mov r12d, esi
cmp r12d, [rbx + LT_nchunks]
jge .null
mov rax, [rbx + LT_chunks]
mov r13, [rax + r12*8]
test r13, r13
jnz .existing
; allocate chunk header
and rsp, -16
mov rdi, CH_SIZE
call malloc
test rax, rax
jz .null
mov r13, rax
; allocate slots array
mov rdi, CHUNK_SIZE
imul rdi, rdi, SL_SIZE
call malloc
test rax, rax
jz .fail_slots
mov [r13 + CH_slots], rax
mov qword [r13 + CH_alloc], CHUNK_SIZE
; initialise every slot
xor r14d, r14d
.init:
cmp r14d, CHUNK_SIZE
jge .init_done
; bmant = 4096 + (i%8)*64
mov eax, r14d
and eax, 7
shl eax, 6
add eax, 4096
mov r8d, eax
; bexp = 16 + (i%8)*2
mov eax, r14d
and eax, 7
shl eax, 1
add eax, 16
mov r9d, eax
; dimn = (i%NUM_DN)+1
mov eax, r14d
xor edx, edx
mov ecx, NUM_DN
div ecx
inc edx
mov r10d, edx
; r_val = (i%256)/256.0
mov eax, r14d
and eax, 255
cvtsi2sd xmm0, eax
mov eax, 256
cvtsi2sd xmm1, eax
divsd xmm0, xmm1
; omega from lattice
movsd xmm1, [rbx + LT_omega]
; slot pointer
imul rax, r14, SL_SIZE
add rax, [r13 + CH_slots]
push r14
push r13
push rbx
mov rdi, rax
mov esi, r8d
mov edx, r9d
mov ecx, r10d
call slot_init
pop rbx
pop r13
pop r14
inc r14d
jmp .init
.init_done:
; store in chunk array
mov rax, [rbx + LT_chunks]
mov [rax + r12*8], r13
mov rax, r13
jmp .done
.fail_slots:
mov rdi, r13
call free
.null:
xor rax, rax
jmp .done
.existing:
mov rax, r13
.done:
pop r14
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; Slot4096 *lattice_get_slot(HDGLLattice *lat, int idx)
; rdi=lat rsi=idx -> rax
; -----------------------------------------------------------------------------
lattice_get_slot:
push rbp
mov rbp, rsp
push rbx
push r12
mov rbx, rdi
mov r12d, esi
mov eax, r12d
xor edx, edx
mov ecx, CHUNK_SIZE
div ecx ; eax=chunk_idx edx=local
push rdx
mov rdi, rbx
mov esi, eax
call lattice_get_chunk
pop rdx
test rax, rax
jz .null
mov rcx, [rax + CH_slots]
imul rdx, rdx, SL_SIZE
add rcx, rdx
mov rax, rcx
jmp .done
.null:
xor rax, rax
.done:
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void detect_consensus(HDGLLattice *lat) rdi=lat
; -----------------------------------------------------------------------------
detect_consensus:
push rbp
mov rbp, rsp
sub rsp, 32
push rbx
push r12
push r13
mov rbx, rdi
; total slots
mov eax, [rbx + LT_ninst]
imul eax, [rbx + LT_spi]
mov r12d, eax
; --- pass 1: mean_phase ---
xorpd xmm12, xmm12
xor r13d, r13d ; count
xor ecx, ecx
.p1:
cmp ecx, r12d
jge .p1_done
push rcx
push r13
mov rdi, rbx
mov esi, ecx
call lattice_get_slot
pop r13
pop rcx
test rax, rax
jz .p1n
test dword [rax + SL_flags], FLAG_CONSENSUS
jnz .p1n
addsd xmm12, [rax + SL_phase]
inc r13d
.p1n:
inc ecx
jmp .p1
.p1_done:
test r13d, r13d
jz .done
cvtsi2sd xmm0, r13d
divsd xmm12, xmm0 ; mean_phase
; --- pass 2: variance ---
xorpd xmm11, xmm11
xor ecx, ecx
.p2:
cmp ecx, r12d
jge .p2_done
push rcx
push r13
mov rdi, rbx
mov esi, ecx
call lattice_get_slot
pop r13
pop rcx
test rax, rax
jz .p2n
test dword [rax + SL_flags], FLAG_CONSENSUS
jnz .p2n
movsd xmm0, [rax + SL_phase]
subsd xmm0, xmm12
mulsd xmm0, xmm0
addsd xmm11, xmm0
.p2n:
inc ecx
jmp .p2
.p2_done:
cvtsi2sd xmm0, r13d
movsd xmm1, xmm11
divsd xmm1, xmm0
movsd xmm0, xmm1
call sqrt
movsd [rbx + LT_pvar], xmm0
ucomisd xmm0, [fp_CEPS]
ja .no_cons
inc dword [rbx + LT_csteps]
cmp dword [rbx + LT_csteps], CONSENSUS_N
jl .done
; announce
and rsp, -16
lea rdi, [sz_cons]
movsd xmm0, [rbx + LT_time]
movsd xmm1, [rbx + LT_pvar]
mov eax, 2
call printf
; lock all slots
xor ecx, ecx
.lock:
cmp ecx, r12d
jge .locked
push rcx
mov rdi, rbx
mov esi, ecx
call lattice_get_slot
pop rcx
test rax, rax
jz .lockn
test dword [rax + SL_flags], FLAG_CONSENSUS
jnz .lockn
or dword [rax + SL_flags], FLAG_CONSENSUS
movsd xmm0, [fp_0]
movsd [rax + SL_pvel], xmm0
.lockn:
inc ecx
jmp .lock
.locked:
mov dword [rbx + LT_csteps], 0
jmp .done
.no_cons:
mov dword [rbx + LT_csteps], 0
.done:
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void lattice_integrate_rk4(HDGLLattice *lat, double dt)
; rdi=lat xmm0=dt
; -----------------------------------------------------------------------------
lattice_integrate_rk4:
push rbp
mov rbp, rsp
; reserve space for neighbors[8] on stack (8 * AL_SIZE = 384) + saved vars
sub rsp, 384 + 64
push rbx
push r12
push r13
push r14
mov rbx, rdi
movsd [rbp - 384 - 8], xmm0 ; dt
; total slots
mov eax, [rbx + LT_ninst]
imul eax, [rbx + LT_spi]
mov r12d, eax
; base of neighbors array on stack
lea r14, [rbp - 384 - 56] ; 8-byte aligned scratch below saves
xor r13d, r13d ; i = 0
.main:
cmp r13d, r12d
jge .main_done
; get slot
push r13
and rsp, -16
mov rdi, rbx
mov esi, r13d
call lattice_get_slot
pop r13
test rax, rax
jz .next
; skip flagged slots
test dword [rax + SL_flags], FLAG_GOI | FLAG_IS_NAN | FLAG_CONSENSUS
jnz .next
mov [rbp - 384 - 16], rax ; save slot ptr
; zero neighbors
and rsp, -16
mov rdi, r14
xor rsi, rsi
mov rdx, 8 * AL_SIZE
call memset
; --- fill 8 neighbors ---
; safe modulo helper: ((raw + total) % total) for raw = i +/- offset
; We call fill_one_neigh(lat, myslot, neigh_idx, &nb[j])
mov r8, [rbp - 384 - 16] ; my slot ptr
mov r9d, [rbx + LT_spi] ; slots_per_instance
%macro NEIGH 2 ; j_index, raw_expr_leaves_eax
%2
; positive modulo: ((eax % r12d) + r12d) % r12d
cdq
idiv r12d ; edx = signed remainder
add edx, r12d
xor eax, eax
mov eax, edx
xor edx, edx
div r12d ; edx = final non-negative index
lea rcx, [r14 + %1 * AL_SIZE]
push r8
push r9
push r13
push r12
push rbx
and rsp, -16
mov rdi, rbx
mov rsi, r8
mov edx_hold, edx
lea rcx, [r14 + %1 * AL_SIZE]
mov edx, edx_hold
call fill_one_neigh
pop rbx
pop r12
pop r13
pop r9
pop r8
%endmacro
; NASM does not support edx_hold as a pseudo-register;
; use r15d as temp for the neighbour index across the call:
%macro NEIGH 2
%2
cdq
idiv r12d
add edx, r12d
mov eax, edx
xor edx, edx
div r12d ; edx = neigh index (unsigned mod)
push r8
push r9
push r13
push r12
push rbx
and rsp, -16
mov rdi, rbx
mov rsi, r8
mov r15d, edx ; save neigh index
lea rcx, [r14 + (%1) * AL_SIZE]
mov edx, r15d
call fill_one_neigh
pop rbx
pop r12
pop r13
pop r9
pop r8
%endmacro
push r15 ; save r15
NEIGH 0, <mov eax, r13d; dec eax>
NEIGH 1, <mov eax, r13d; inc eax>
NEIGH 2, <mov eax, r13d; sub eax, r9d>
NEIGH 3, <mov eax, r13d; add eax, r9d>
NEIGH 4, <mov eax, r13d; sub eax, r9d; dec eax>
NEIGH 5, <mov eax, r13d; sub eax, r9d; inc eax>
NEIGH 6, <mov eax, r13d; add eax, r9d; dec eax>
NEIGH 7, <mov eax, r13d; add eax, r9d; inc eax>
pop r15
; --- exchange_analog_links ---
mov rdi, r14
mov eax, r13d
xor edx, edx
idiv dword [rbx + LT_ninst]
mov esi, edx
mov edx, [rbx + LT_ninst]
mov ecx, 8
call exchange_analog_links
; --- rk4_step(slot, dt, nb, 8, omega) ---
mov rdi, [rbp - 384 - 16]
movsd xmm0, [rbp - 384 - 8]
mov rsi, r14
mov edx, 8
movsd xmm1, [rbx + LT_omega]
call rk4_step
; --- phi-adaptive dt ---
mov rdi, [rbp - 384 - 16]
call ap_to_double
call fabs
ucomisd xmm0, [fp_ATH]
jbe .chk_small
movsd xmm0, [rbp - 384 - 8]
mulsd xmm0, [fp_PHI]
movsd [rbp - 384 - 8], xmm0
jmp .clamp_dt
.chk_small:
movsd xmm1, [fp_ATH]
divsd xmm1, [fp_PHI]
ucomisd xmm0, xmm1
jae .clamp_dt
movsd xmm0, [rbp - 384 - 8]
divsd xmm0, [fp_PHI]
movsd [rbp - 384 - 8], xmm0
.clamp_dt:
movsd xmm0, [rbp - 384 - 8]
maxsd xmm0, [fp_1e6n]
minsd xmm0, [fp_01]
movsd [rbp - 384 - 8], xmm0
.next:
inc r13d
jmp .main
.main_done:
; detect_consensus
and rsp, -16
mov rdi, rbx
call detect_consensus
; omega += 0.01*dt
movsd xmm0, [fp_001]
mulsd xmm0, [rbp - 384 - 8]
addsd xmm0, [rbx + LT_omega]
movsd [rbx + LT_omega], xmm0
; time += dt
movsd xmm0, [rbp - 384 - 8]
addsd xmm0, [rbx + LT_time]
movsd [rbx + LT_time], xmm0
pop r14
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; CheckpointManager *checkpoint_init() -> rax
; -----------------------------------------------------------------------------
checkpoint_init:
push rbp
mov rbp, rsp
push rbx
and rsp, -16
mov rdi, CK_SIZE
call malloc
mov rbx, rax
mov rdi, SNAPSHOT_MAX * CM_SIZE
call malloc
mov [rbx + CK_snaps], rax
mov dword [rbx + CK_cnt], 0
mov dword [rbx + CK_cap], SNAPSHOT_MAX
mov rax, rbx
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void checkpoint_add(CheckpointManager *mgr, int evo, HDGLLattice *lat)
; rdi=mgr rsi=evo rdx=lat
; -----------------------------------------------------------------------------
checkpoint_add:
push rbp
mov rbp, rsp
push rbx
push r12
push r13
push r14
mov rbx, rdi
mov r12d, esi
mov r13, rdx
; evict min-weight entry if full
mov eax, [rbx + CK_cnt]
cmp eax, [rbx + CK_cap]
jl .append
mov r8, [rbx + CK_snaps]
movsd xmm12, [r8 + CM_wt]
xor r14d, r14d ; min_idx = 0
mov ecx, 1
.ev:
cmp ecx, [rbx + CK_cnt]
jge .ev_done
imul rax, rcx, CM_SIZE
movsd xmm0, [r8 + rax + CM_wt]
ucomisd xmm0, xmm12
jae .ev_next
movsd xmm12, xmm0
mov r14d, ecx
.ev_next:
inc ecx
jmp .ev
.ev_done:
; shift entries down from min_idx+1
mov ecx, r14d
inc ecx
mov r9d, [rbx + CK_cnt]
.shift:
cmp ecx, r9d
jge .shift_done
imul rax, rcx, CM_SIZE
lea r10, [r8 + rax]
lea r11, [r8 + rax - CM_SIZE]
and rsp, -16
mov rdi, r11
mov rsi, r10
mov rdx, CM_SIZE
call memcpy
inc ecx
jmp .shift
.shift_done:
dec dword [rbx + CK_cnt]
.append:
call get_rtc_ns
mov r8d, [rbx + CK_cnt]
mov r9, [rbx + CK_snaps]
imul r10, r8, CM_SIZE
add r10, r9
mov [r10 + CM_evo], r12d
mov [r10 + CM_tsns], rax
movsd xmm0, [r13 + LT_pvar]
movsd [r10 + CM_pvar], xmm0
movsd xmm0, [r13 + LT_omega]
movsd [r10 + CM_omega], xmm0
movsd xmm0, [fp_1]
movsd [r10 + CM_wt], xmm0
inc dword [rbx + CK_cnt]
; decay older weights
mov ecx, [rbx + CK_cnt]
dec ecx
mov r9, [rbx + CK_snaps]
xor edx, edx
.decay:
cmp edx, ecx
jge .decay_done
imul rax, rdx, CM_SIZE
movsd xmm0, [r9 + rax + CM_wt]
mulsd xmm0, [fp_SDEC]
movsd [r9 + rax + CM_wt], xmm0
inc edx
jmp .decay
.decay_done:
and rsp, -16
lea rdi, [sz_ckpt]
mov esi, r12d
mov edx, [rbx + CK_cnt]
movsd xmm0, [r13 + LT_pvar]
mov eax, 1
call printf
pop r14
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void checkpoint_free(CheckpointManager *mgr) rdi=mgr
; -----------------------------------------------------------------------------
checkpoint_free:
push rbp
mov rbp, rsp
push rbx
test rdi, rdi
jz .done
mov rbx, rdi
and rsp, -16
mov rdi, [rbx + CK_snaps]
call free
mov rdi, rbx
call free
.done:
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void lattice_free(HDGLLattice *lat) rdi=lat
; -----------------------------------------------------------------------------
lattice_free:
push rbp
mov rbp, rsp
push rbx
push r12
push r13
test rdi, rdi
jz .done
mov rbx, rdi
xor r12d, r12d
.chunks:
cmp r12d, [rbx + LT_nchunks]
jge .chunks_done
mov rax, [rbx + LT_chunks]
mov r13, [rax + r12*8]
test r13, r13
jz .cnext
; free each slot's heap members
xor ecx, ecx
.slots:
cmp ecx, CHUNK_SIZE
jge .slots_done
imul rax, rcx, SL_SIZE
add rax, [r13 + CH_slots]
push rcx
push r13
and rsp, -16
mov rdi, rax
call ap_free
pop r13
pop rcx
inc ecx
jmp .slots
.slots_done:
and rsp, -16
mov rdi, [r13 + CH_slots]
call free
mov rdi, r13
call free
.cnext:
inc r12d
jmp .chunks
.chunks_done:
mov rdi, [rbx + LT_chunks]
call free
mov r12, [rbx + LT_nl]
test r12, r12
jz .skip_nl
mov rdi, r12
call free_numeric_lattice
mov rdi, r12
call free
.skip_nl:
mov rdi, rbx
call free
.done:
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; void bootloader_init_lattice(HDGLLattice *lat, int steps,
; CheckpointManager *mgr)
; rdi=lat rsi=steps rdx=mgr
; -----------------------------------------------------------------------------
bootloader_init_lattice:
push rbp
mov rbp, rsp
sub rsp, 48
push rbx
push r12
push r13
mov rbx, rdi
mov r12d, esi
mov r13, rdx
and rsp, -16
lea rdi, [sz_bi]
xor eax, eax
call printf
test rbx, rbx
jnz .lat_ok
lea rdi, [sz_berr]
xor eax, eax
call printf
jmp .done
.lat_ok:
lea rdi, [sz_binfo]
mov esi, [rbx + LT_ninst]
mov eax, [rbx + LT_ninst]
imul eax, [rbx + LT_spi]
mov edx, eax
xor eax, eax
call printf
lea rdi, [sz_bseed]
mov rsi, [rbx + LT_nl]
mov rsi, [rsi + NL_num_seeds]
xor eax, eax
call printf
; dt = 1/32768
movsd xmm0, [fp_dt0]
movsd [rbp-8], xmm0
; step_ns = 30517
mov qword [rbp-16], 30517
call get_rtc_ns
add rax, [rbp-16]
mov [rbp-24], rax ; next_step_ns
xor r9d, r9d ; i = 0
.evo:
cmp r9d, r12d
jge .evo_done
push r9
push rbx
push r12
push r13
and rsp, -16
mov rdi, rbx
movsd xmm0, [rbp-8]
call lattice_integrate_rk4
pop r13
pop r12
pop rbx
pop r9
; checkpoint every CHECKPOINT_INTERVAL (skip i==0)
test r9d, r9d
jz .no_ckpt
mov eax, r9d
xor edx, edx
mov ecx, CHECKPOINT_INTERVAL
div ecx
test edx, edx
jnz .no_ckpt
push r9
push rbx
push r12
push r13
and rsp, -16
mov rdi, r13
mov esi, r9d
mov rdx, rbx
call checkpoint_add
pop r13
pop r12
pop rbx
pop r9
.no_ckpt:
push r9
push rbx
push r12
push r13
and rsp, -16
mov rdi, [rbp-24]
call rtc_sleep_until
pop r13
pop r12
pop rbx
pop r9
mov rax, [rbp-24]
add rax, [rbp-16]
mov [rbp-24], rax
inc r9d
jmp .evo
.evo_done:
and rsp, -16
lea rdi, [sz_bdone]
mov esi, r12d
xor eax, eax
call printf
lea rdi, [sz_bstat]
movsd xmm0, [rbx + LT_omega]
movsd xmm1, [rbx + LT_time]
movsd xmm2, [rbx + LT_pvar]
mov eax, 3
call printf
.done:
pop r13
pop r12
pop rbx
leave
ret
; -----------------------------------------------------------------------------
; int main(int argc, char **argv)
; -----------------------------------------------------------------------------
main:
push rbp
mov rbp, rsp
sub rsp, 64
push rbx
push r12
push r13
; srand(time(NULL))
and rsp, -16
xor rdi, rdi
call time
mov rdi, rax
call srand
lea rdi, [sz_rtc]
xor eax, eax
call printf
lea rdi, [sz_banner]
xor eax, eax
call printf
; lattice_init(4096, 4)
mov edi, 4096
mov esi, 4
call lattice_init
mov rbx, rax
test rbx, rbx
jnz .lat_ok
lea rdi, [sz_fatal]
xor eax, eax
call printf
mov eax, 1
jmp .exit
.lat_ok:
call checkpoint_init
mov r12, rax
; bootloader_init_lattice(lat, 500, mgr)
mov rdi, rbx
mov esi, 500
mov rdx, r12
call bootloader_init_lattice
; --- Numeric Lattice Summary ---
lea rdi, [sz_nlhdr]
xor eax, eax
call printf
mov r13, [rbx + LT_nl]
lea rdi, [sz_nluf]
movsd xmm0, [r13 + NL_upper + 0]
mov eax, 1
call printf
lea rdi, [sz_nlad]
movsd xmm0, [r13 + NL_adims + 0]
mov eax, 1
call printf
lea rdi, [sz_nlvd]
movsd xmm0, [r13 + NL_void]
mov eax, 1
call printf
lea rdi, [sz_nllf]
movsd xmm0, [r13 + NL_lower + 7*8]
mov eax, 1
call printf
lea rdi, [sz_nlbs]
mov rsi, [r13 + NL_num_seeds]
xor eax, eax
call printf
; --- First 8 slots ---
lea rdi, [sz_slhdr]
xor eax, eax
call printf
xor r13d, r13d
.sl_loop:
cmp r13d, 8
jge .sl_done
push r13
mov rdi, rbx
mov esi, r13d
call lattice_get_slot
pop r13
test rax, rax
jz .sl_next
push rax
push r13
; |A| = sqrt(ap_to_double(s)^2 + amp_im^2)
mov rdi, rax
call ap_to_double
mulsd xmm0, xmm0
mov rax, [rsp+8]
movsd xmm1, [rax + SL_ampim]
mulsd xmm1, xmm1
addsd xmm0, xmm1
call sqrt
movsd [rbp-8], xmm0
mov rax, [rsp+8]
movsd xmm5, [rax + SL_phase]
movsd xmm6, [rax + SL_dnamp]
movsd xmm7, [rax + SL_wmode]
movsd xmm8, [rax + SL_rval]
pop r13
pop rax
lea rdi, [sz_slfmt]
lea esi, [r13 + 1]
movsd xmm0, [rbp-8]
movsd xmm1, xmm5
movsd xmm2, xmm6
movsd xmm3, xmm7
movsd xmm4, xmm8
mov eax, 5
call printf
.sl_next:
inc r13d
jmp .sl_loop
.sl_done:
; --- cleanup ---
mov rdi, r12
call checkpoint_free
mov rdi, rbx
call lattice_free
lea rdi, [sz_final]
xor eax, eax
call printf
xor eax, eax
.exit:
pop r13
pop r12
pop rbx
leave
ret
II_analog_boot.zip (376.3 KB)
