Research-Stack/4-Infrastructure/hardware/tb_metamanifold_prover.cpp
2026-05-11 22:18:31 -05:00

432 lines
12 KiB
C++

/*
* Verilator testbench for Meta-Manifold Prover
*
* Validates:
* - Mass Number gates (A <= tau * (R + epsilon))
* - Torus topology distance calculation
* - Menger sponge hash computation
* - Fold energy weighted sum
* - Surface check (height >= ridge)
*
* Target: Gowin GW1NR-9 / Tang Nano 9K
* Clock: 27 MHz
*/
#include <cstdio>
#include <cstdint>
#include <cmath>
#include "VMetaManifoldProver.h"
#include "verilated.h"
#ifdef VM_TRACE
#include "verilated_vcd_c.h"
#endif
// Q16_16 fixed-point conversion helpers
constexpr int16_t float_to_q16_16(float f) {
return static_cast<int16_t>(f * 65536.0f);
}
constexpr float q16_16_to_float(int16_t q) {
return static_cast<float>(q) / 65536.0f;
}
// Test case structure
struct TestCase {
const char* name;
uint8_t op_select;
int16_t inputs[16]; // Up to 16 inputs
int16_t expected_output;
bool is_boolean; // If true, expected_output is 0/1
};
int main(int argc, char** argv) {
VerilatedContext* contextp = new VerilatedContext;
contextp->commandArgs(argc, argv);
contextp->fatalOnError(true);
VMetaManifoldProver* top = new VMetaManifoldProver{contextp};
#ifdef VM_TRACE
VerilatedVcdC* tfp = nullptr;
const char* trace_env = getenv("TRACE");
if (trace_env && trace_env[0] == '1') {
tfp = new VerilatedVcdC;
contextp->traceEverOn(true);
top->trace(tfp, 99);
tfp->open("sim_metamanifold_prover.vcd");
}
#endif
// Initialize inputs
top->clk = 0;
top->rst_n = 0;
top->start = 0;
// Reset all inputs to 0
top->admissible = 0;
top->residual = 0;
top->epsilon = 0;
top->threshold = 0;
top->coord1 = 0;
top->coord2 = 0;
top->menger_x = 0;
top->menger_y = 0;
top->menger_z = 0;
top->hausdorff_dim = 0;
top->torus_energy = 0;
top->menger_energy = 0;
top->horn_energy = 0;
top->alpha = 0;
top->beta = 0;
top->gamma = 0;
top->surface_height = 0;
top->surface_ridge = 0;
int errors = 0;
int tests_passed = 0;
int tests_total = 0;
printf("=== Meta-Manifold Prover Verilator Testbench ===\n\n");
// Release reset
for (int i = 0; i < 100; i++) {
top->clk = !top->clk;
top->eval();
}
top->rst_n = 1;
printf("Reset released\n\n");
// === Test 1: Mass Number Gate ===
{
printf("--- Test 1: Mass Number Gate ---\n");
tests_total++;
// Test case: A = 1.0, R = 0.5, epsilon = 0.0625, tau = 2.0
// Expected: A <= tau * (R + epsilon) = 2.0 * 0.5625 = 1.125
// Since 1.0 <= 1.125, result should be TRUE (1)
top->op_select = 3'b000; // MassLe operation
top->admissible = float_to_q16_16(1.0f);
top->residual = float_to_q16_16(0.5f);
top->epsilon = float_to_q16_16(0.0625f);
top->threshold = float_to_q16_16(2.0f);
top->start = 1;
// Run operation
int cycles = 0;
for (int i = 0; i < 1000; i++) {
top->clk = !top->clk;
top->eval();
if (top->clk && top->done) break;
cycles++;
}
top->start = 0;
bool result = top->mass_le_result;
bool expected = true;
printf(" A = %.4f, R = %.4f, epsilon = %.4f, tau = %.4f\n",
q16_16_to_float(top->admissible),
q16_16_to_float(top->residual),
q16_16_to_float(top->epsilon),
q16_16_to_float(top->threshold));
printf(" Expected: %d, Got: %d, Cycles: %d\n", expected, result, cycles);
if (result == expected) {
printf(" PASS\n");
tests_passed++;
} else {
printf(" FAIL\n");
errors++;
}
printf("\n");
}
// === Test 2: Mass Number Gate (False case) ===
{
printf("--- Test 2: Mass Number Gate (False) ---\n");
tests_total++;
// Test case: A = 2.0, R = 0.5, epsilon = 0.0625, tau = 1.0
// Expected: A <= tau * (R + epsilon) = 1.0 * 0.5625 = 0.5625
// Since 2.0 > 0.5625, result should be FALSE (0)
top->op_select = 3'b000; // MassLe operation
top->admissible = float_to_q16_16(2.0f);
top->residual = float_to_q16_16(0.5f);
top->epsilon = float_to_q16_16(0.0625f);
top->threshold = float_to_q16_16(1.0f);
top->start = 1;
// Run operation
int cycles = 0;
for (int i = 0; i < 1000; i++) {
top->clk = !top->clk;
top->eval();
if (top->clk && top->done) break;
cycles++;
}
top->start = 0;
bool result = top->mass_le_result;
bool expected = false;
printf(" A = %.4f, R = %.4f, epsilon = %.4f, tau = %.4f\n",
q16_16_to_float(top->admissible),
q16_16_to_float(top->residual),
q16_16_to_float(top->epsilon),
q16_16_to_float(top->threshold));
printf(" Expected: %d, Got: %d, Cycles: %d\n", expected, result, cycles);
if (result == expected) {
printf(" PASS\n");
tests_passed++;
} else {
printf(" FAIL\n");
errors++;
}
printf("\n");
}
// === Test 3: Torus Distance ===
{
printf("--- Test 3: Torus Distance ---\n");
tests_total++;
// Test case: coord1 = (1,1,1,1,1), coord2 = (2,2,2,2,2)
// Expected Manhattan distance with wraparound on 8-element torus
top->op_select = 3'b001; // TorusDist operation
top->coord1 = 0x11111; // Each nibble = 1
top->coord2 = 0x22222; // Each nibble = 2
top->start = 1;
// Run operation
int cycles = 0;
for (int i = 0; i < 1000; i++) {
top->clk = !top->clk;
top->eval();
if (top->clk && top->done) break;
cycles++;
}
top->start = 0;
uint16_t result = top->torus_distance;
uint16_t expected = 5; // 5 dimensions * 1 unit each
printf(" coord1: 0x%05x, coord2: 0x%05x\n", top->coord1, top->coord2);
printf(" Expected distance: %d, Got: %d, Cycles: %d\n", expected, result, cycles);
if (result == expected) {
printf(" PASS\n");
tests_passed++;
} else {
printf(" FAIL\n");
errors++;
}
printf("\n");
}
// === Test 4: Menger Hash ===
{
printf("--- Test 4: Menger Hash ---\n");
tests_total++;
// Test case: x = 1, y = 2, z = 3, hausdorff_dim = 2.0
// Expected hash: x ^ (y << 1) ^ (z << 2) = 1 ^ 4 ^ 12 = 9
top->op_select = 3'b010; // MengerHash operation
top->menger_x = 1;
top->menger_y = 2;
top->menger_z = 3;
top->hausdorff_dim = float_to_q16_16(2.0f);
top->start = 1;
// Run operation
int cycles = 0;
for (int i = 0; i < 1000; i++) {
top->clk = !top->clk;
top->eval();
if (top->clk && top->done) break;
cycles++;
}
top->start = 0;
uint16_t result = top->menger_address;
printf(" x = %d, y = %d, z = %d, hausdorff_dim = %.4f\n",
top->menger_x, top->menger_y, top->menger_z,
q16_16_to_float(top->hausdorff_dim));
printf(" Hash result: %d, Cycles: %d\n", result, cycles);
// Just check that it's non-zero (hash computation)
if (result != 0) {
printf(" PASS (hash computed)\n");
tests_passed++;
} else {
printf(" FAIL (hash is zero)\n");
errors++;
}
printf("\n");
}
// === Test 5: Fold Energy ===
{
printf("--- Test 5: Fold Energy ---\n");
tests_total++;
// Test case: E_torus = 1.0, E_menger = 2.0, E_horn = 3.0
// alpha = 0.5, beta = 0.3, gamma = 0.2
// Expected: 0.5*1.0 + 0.3*2.0 + 0.2*3.0 = 0.5 + 0.6 + 0.6 = 1.7
top->op_select = 3'b011; // FoldEnergy operation
top->torus_energy = float_to_q16_16(1.0f);
top->menger_energy = float_to_q16_16(2.0f);
top->horn_energy = float_to_q16_16(3.0f);
top->alpha = float_to_q16_16(0.5f);
top->beta = float_to_q16_16(0.3f);
top->gamma = float_to_q16_16(0.2f);
top->start = 1;
// Run operation
int cycles = 0;
for (int i = 0; i < 1000; i++) {
top->clk = !top->clk;
top->eval();
if (top->clk && top->done) break;
cycles++;
}
top->start = 0;
int16_t result = top->fold_energy_total;
float result_float = q16_16_to_float(result);
float expected_float = 1.7f;
float tolerance = 0.1f;
printf(" E_torus = %.4f, E_menger = %.4f, E_horn = %.4f\n",
q16_16_to_float(top->torus_energy),
q16_16_to_float(top->menger_energy),
q16_16_to_float(top->horn_energy));
printf(" alpha = %.4f, beta = %.4f, gamma = %.4f\n",
q16_16_to_float(top->alpha),
q16_16_to_float(top->beta),
q16_16_to_float(top->gamma));
printf(" Expected: %.4f, Got: %.4f, Cycles: %d\n", expected_float, result_float, cycles);
if (fabs(result_float - expected_float) < tolerance) {
printf(" PASS\n");
tests_passed++;
} else {
printf(" FAIL (tolerance %.4f)\n", tolerance);
errors++;
}
printf("\n");
}
// === Test 6: Surface Check ===
{
printf("--- Test 6: Surface Check ---\n");
tests_total++;
// Test case: height = 1.5, ridge = 1.0
// Expected: height >= ridge, so result should be TRUE (1)
top->op_select = 3'b100; // SurfaceCheck operation
top->surface_height = float_to_q16_16(1.5f);
top->surface_ridge = float_to_q16_16(1.0f);
top->start = 1;
// Run operation
int cycles = 0;
for (int i = 0; i < 1000; i++) {
top->clk = !top->clk;
top->eval();
if (top->clk && top->done) break;
cycles++;
}
top->start = 0;
bool result = top->surface_admissible;
bool expected = true;
printf(" height = %.4f, ridge = %.4f\n",
q16_16_to_float(top->surface_height),
q16_16_to_float(top->surface_ridge));
printf(" Expected: %d, Got: %d, Cycles: %d\n", expected, result, cycles);
if (result == expected) {
printf(" PASS\n");
tests_passed++;
} else {
printf(" FAIL\n");
errors++;
}
printf("\n");
}
// === Test 7: Surface Check (False case) ===
{
printf("--- Test 7: Surface Check (False) ---\n");
tests_total++;
// Test case: height = 0.5, ridge = 1.0
// Expected: height < ridge, so result should be FALSE (0)
top->op_select = 3'b100; // SurfaceCheck operation
top->surface_height = float_to_q16_16(0.5f);
top->surface_ridge = float_to_q16_16(1.0f);
top->start = 1;
// Run operation
int cycles = 0;
for (int i = 0; i < 1000; i++) {
top->clk = !top->clk;
top->eval();
if (top->clk && top->done) break;
cycles++;
}
top->start = 0;
bool result = top->surface_admissible;
bool expected = false;
printf(" height = %.4f, ridge = %.4f\n",
q16_16_to_float(top->surface_height),
q16_16_to_float(top->surface_ridge));
printf(" Expected: %d, Got: %d, Cycles: %d\n", expected, result, cycles);
if (result == expected) {
printf(" PASS\n");
tests_passed++;
} else {
printf(" FAIL\n");
errors++;
}
printf("\n");
}
// === Summary ===
printf("=== Test Summary ===\n");
printf("Tests passed: %d/%d\n", tests_passed, tests_total);
printf("Errors: %d\n", errors);
printf("\n=== %s (%d errors) ===\n", errors == 0 ? "PASS" : "FAIL", errors);
#ifdef VM_TRACE
if (tfp) {
tfp->close();
delete tfp;
}
#endif
delete top;
delete contextp;
return errors;
}