From ca118555214a176728b9aab87849391344306d6d Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Thu, 29 Feb 2024 02:29:13 +0100 Subject: Initial commit. --- src/evolver.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 src/evolver.c (limited to 'src/evolver.c') diff --git a/src/evolver.c b/src/evolver.c new file mode 100644 index 0000000..e3b6ef7 --- /dev/null +++ b/src/evolver.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include "types.h" +#include "getter.h" +#include "instset.h" +#include "memory.h" +#include "evolver.h" + +static boolean g_is_init; +static uint32 g_last_changed_address; +static uint32 g_calls_on_last_cycle; +static uint32 g_state[4]; + +void _sal_evo_init(void) +{ + /* Start up the evolver module. We simply set the 128 bits into a random + state by calling 'rand()'. + */ + assert(!g_is_init); + srand((uint32)time(NULL)); + g_state[0] = rand(); + g_state[1] = rand(); + g_state[2] = rand(); + g_state[3] = rand(); + g_is_init = TRUE; +} + +void _sal_evo_quit(void) +{ + /* Quit the evolver module. Reset everything back to zero. + */ + assert(g_is_init); + g_is_init = FALSE; + g_last_changed_address = 0; + g_calls_on_last_cycle = 0; + memset(g_state, 0, sizeof(uint32) * 4); +} + +void _sal_evo_load_from(FILE *file) +{ + /* Load evolver state from a binary file. + */ + assert(!g_is_init); + assert(file); + fread(&g_is_init, sizeof(boolean), 1, file); + fread(&g_last_changed_address, sizeof(uint32), 1, file); + fread(&g_calls_on_last_cycle, sizeof(uint32), 1, file); + fread(&g_state, sizeof(uint32), 4, file); +} + +void _sal_evo_save_into(FILE *file) +{ + /* Save evolver state into a binary file. + */ + assert(g_is_init); + assert(file); + fwrite(&g_is_init, sizeof(boolean), 1, file); + fwrite(&g_last_changed_address, sizeof(uint32), 1, file); + fwrite(&g_calls_on_last_cycle, sizeof(uint32), 1, file); + fwrite(&g_state, sizeof(uint32), 4, file); +} + +/* Getter methods for the evolver module. +*/ +UINT32_GETTER(evo, last_changed_address) +UINT32_GETTER(evo, calls_on_last_cycle) + +uint32 sal_evo_get_state(uint8 state_index) +{ + /* Get part of the evolver's internal state (32 bits of 128 total bits) as + an unsigned int. + */ + assert(g_is_init); + assert(state_index < 4); + return g_state[state_index]; +} + +static uint32 generate_random_number(void) +{ + /* Generate a single 32 bit random number. This module makes use of the + XOR-Shift pseudo-rng. We use XOR-Shift because it's extremely lightweight + and fast, while providing quite good results. Find more info about it here: + >>> https://en.wikipedia.org/wiki/Xorshift + */ + uint32 tmp1; + uint32 tmp2; + assert(g_is_init); + tmp2 = g_state[3]; + tmp2 ^= tmp2 << 11; + tmp2 ^= tmp2 >> 8; + g_state[3] = g_state[2]; + g_state[2] = g_state[1]; + g_state[1] = tmp1 = g_state[0]; + tmp2 ^= tmp1; + tmp2 ^= tmp1 >> 19; + g_state[0] = tmp2; + g_calls_on_last_cycle++; + return tmp2; +} + +void _sal_evo_randomize_at(uint32 address) +{ + /* Place a random instruction into a given address. + */ + uint8 inst; + assert(g_is_init); + assert(sal_mem_is_address_valid(address)); + inst = generate_random_number() % INST_COUNT; + g_last_changed_address = address; + sal_mem_set_inst(address, inst); +} + +void _sal_evo_cycle(void) +{ + /* During each simulation cycle, a random 32 bit integer is generated. If + this integer represents a 'valid' address in memory + (i.e. new_rand < memory_size), this address becomes hit by a cosmic ray + (randomized). This simple mutation scheme is enough to drive evolution in + Salis. + */ + uint32 address; + assert(g_is_init); + g_calls_on_last_cycle = 0; + address = generate_random_number(); + + if (sal_mem_is_address_valid(address)) { + _sal_evo_randomize_at(address); + } +} -- cgit v1.2.1