mirror of
https://github.com/pound-emu/ballistic.git
synced 2026-01-31 01:15:21 +01:00
tests: replace fuzzer with exaustive test
Tests the entire 32-bit instruction space (4.29B). Signed-off-by: Ronald Caesar <github43132@proton.me>
This commit is contained in:
@@ -120,9 +120,8 @@ endif()
|
||||
if (BALLISTIC_ENABLE_BUILD_TESTS)
|
||||
set(TESTS_NAME "ballistic_tests")
|
||||
enable_testing()
|
||||
add_executable(${TESTS_NAME} tests/test_decoder_fuzzer.c)
|
||||
add_executable(${TESTS_NAME} tests/test_decoder.c)
|
||||
target_include_directories(${TESTS_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
target_link_libraries(${TESTS_NAME} PRIVATE ${PROJECT_NAME})
|
||||
add_test(NAME DecoderTest COMMAND ${TESTS_NAME})
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
121
tests/test_decoder.c
Normal file
121
tests/test_decoder.c
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "bal_decoder.h"
|
||||
#include "decoder_table_gen.h"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#define POPCOUNT(x) __popcnt(x)
|
||||
#else
|
||||
#define POPCOUNT(x) __builtin_popcount(x)
|
||||
#endif
|
||||
|
||||
#define DECODER_HASH_SHIFT 21
|
||||
#define DECODER_HASH_MASK 0x7FF
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
printf("Starting Decoder Test (0x00000000 - 0xFFFFFFFF)...\n");
|
||||
uint64_t total_decoded = 0;
|
||||
uint64_t total_collisions = 0;
|
||||
uint64_t total_errors = 0;
|
||||
|
||||
for (uint64_t i = 0; i <= UINT32_MAX; ++i)
|
||||
{
|
||||
uint32_t instruction = (uint32_t)i;
|
||||
const bal_decoder_instruction_metadata_t *metadata
|
||||
= bal_decoder_arm64_decode(instruction);
|
||||
|
||||
uint32_t hash_index = (instruction >> DECODER_HASH_SHIFT) & DECODER_HASH_MASK;
|
||||
const decoder_bucket_t *bucket = &g_decoder_lookup_table[hash_index];
|
||||
const bal_decoder_instruction_metadata_t *best_match = NULL;
|
||||
int max_priority = -1;
|
||||
|
||||
if (bucket->instructions != NULL)
|
||||
{
|
||||
for (size_t j = 0; j < bucket->count; ++j)
|
||||
{
|
||||
const bal_decoder_instruction_metadata_t *candidate = bucket->instructions[j];
|
||||
|
||||
if (candidate->expected == (instruction & candidate->mask))
|
||||
{
|
||||
int priority = POPCOUNT(candidate->mask);
|
||||
|
||||
if (priority > max_priority)
|
||||
{
|
||||
max_priority = priority;
|
||||
best_match = candidate;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Two instructions with equal priority claim these bits.
|
||||
// There is a bug in the XML parser.
|
||||
//
|
||||
if (best_match && strcmp(best_match->name, candidate->name) != 0)
|
||||
{
|
||||
++total_collisions;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (metadata != best_match)
|
||||
{
|
||||
printf("[FAIL] Priority Error at 0x%08x\n", instruction);
|
||||
printf(" Decoder returned: %s\n", metadata ? metadata->name : "NULL");
|
||||
printf(" Reference found: %s\n", best_match ? best_match->name : "NULL");
|
||||
|
||||
if (metadata != NULL)
|
||||
{
|
||||
printf(" Decoder Mask: 0x%08x (Priority: %d)\n", metadata->mask, POPCOUNT(metadata->mask));
|
||||
}
|
||||
|
||||
if (best_match != NULL)
|
||||
{
|
||||
printf(" Ref Mask: 0x%08x (Priority: %d)\n", best_match->mask, POPCOUNT(best_match->mask));
|
||||
}
|
||||
|
||||
++total_errors;
|
||||
|
||||
if (total_errors > 10)
|
||||
{
|
||||
printf("[FATAL] Too many errors. Aborting...");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (metadata != NULL)
|
||||
{
|
||||
// The decoder should never return a match that failed the mask.
|
||||
if ((instruction & metadata->mask) != metadata->expected)
|
||||
{
|
||||
printf("[FAIL] Consistency: Inst 0x%08x matched '%s' but failed mask check.\n", instruction, metadata->name);
|
||||
++total_errors;
|
||||
}
|
||||
++total_decoded;
|
||||
}
|
||||
|
||||
if (0 == (instruction & 0x0FFFFFFF))
|
||||
{
|
||||
printf("Progress: %3.0f%% (0x%08x)\n", (double)i / 42949672.96, instruction);
|
||||
}
|
||||
}
|
||||
|
||||
printf("--- Results ---\n");
|
||||
printf("Total Decoded: %" PRIu64 "\n", total_decoded);
|
||||
printf("Total Collisions: %" PRIu64 "\n", total_collisions);
|
||||
printf("Total Errors: %" PRIu64 "\n", total_errors);
|
||||
|
||||
if (total_errors > 0)
|
||||
{
|
||||
printf("[FAILURE] Ballistic Decoder is flawed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("[SUCCESS] Ballistic Decoder is mathematically correct.\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
#include "bal_decoder.h"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
static uint32_t rng_state = 0x87654321;
|
||||
|
||||
/*
|
||||
* Seeding function to set the initial state.
|
||||
*/
|
||||
static void
|
||||
fast_srand (uint32_t seed)
|
||||
{
|
||||
if (seed == 0)
|
||||
{
|
||||
seed = 0x87654321;
|
||||
}
|
||||
rng_state = seed;
|
||||
}
|
||||
/*
|
||||
* Xorshift32 Algorithm
|
||||
*/
|
||||
static inline uint32_t
|
||||
fast_rand (void)
|
||||
{
|
||||
uint32_t x = rng_state;
|
||||
x ^= x << 13;
|
||||
x ^= x >> 17;
|
||||
x ^= x << 5;
|
||||
rng_state = x;
|
||||
return x;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
printf("Starting Decoder Fuzzer Test...\n");
|
||||
fast_srand((uint32_t)time(0));
|
||||
|
||||
int failed = 0;
|
||||
int passed = 0;
|
||||
for (size_t i = 0; i < 10000000; ++i)
|
||||
{
|
||||
uint32_t random_instruction = fast_rand();
|
||||
const bal_decoder_instruction_metadata_t *meta
|
||||
= bal_decoder_arm64_decode(random_instruction);
|
||||
|
||||
if (NULL != meta)
|
||||
{
|
||||
if ((random_instruction & meta->mask) != meta->expected)
|
||||
{
|
||||
printf("[FAIL] %s, 0x%08x & 0x%08x != 0x%08x",
|
||||
meta->name,
|
||||
random_instruction,
|
||||
meta->mask,
|
||||
meta->expected);
|
||||
++failed;
|
||||
continue;
|
||||
}
|
||||
++passed;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed > 0)
|
||||
{
|
||||
printf("FAILED %d tests. \n", failed);
|
||||
return 1;
|
||||
}
|
||||
if (passed > 0)
|
||||
{
|
||||
printf("Decoded %d instructions successfully\n", passed);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[ERROR] No tests passed or failed. Ballistic's decoding logic is flawed\n");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user