From 99134c3a326f02b0c6f9b86dc7f6f2b4cd0acd49 Mon Sep 17 00:00:00 2001 From: Aryadev Chavali Date: Mon, 16 Mar 2026 14:44:55 +0000 Subject: [PATCH] program_iter -> bf, simulation to be redone --- src/base.h | 10 -- src/bf.c | 169 ++++++++++++++++++++++++++++++++++ src/{program_iter.h => bf.h} | 19 ++-- src/program_iter.c | 172 ----------------------------------- src/simulation.c | 159 -------------------------------- src/simulation.h | 49 ---------- 6 files changed, 180 insertions(+), 398 deletions(-) create mode 100644 src/bf.c rename src/{program_iter.h => bf.h} (71%) delete mode 100644 src/program_iter.c delete mode 100644 src/simulation.c delete mode 100644 src/simulation.h diff --git a/src/base.h b/src/base.h index 835dc00..ff21b9e 100644 --- a/src/base.h +++ b/src/base.h @@ -27,20 +27,10 @@ typedef double f64; #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define SAFE_SUB(A, B) ((A) < (B) ? 0 : (A) - (B)) -// 64 byte programs -#define SIZEOF_PROGRAM (1LU << 6) - -#define NUM_PROGRAMS_POW_2 17 -#define NUM_PROGRAMS (1LU << NUM_PROGRAMS_POW_2) -#define SIMULATION_SIZE (SIZEOF_PROGRAM * NUM_PROGRAMS) -#define THREAD_POOL 4 // GUI stuff #define WIDTH 800 #define HEIGHT 600 -// Our grid will be of length sqrt(NUM_PROGRAMS). This is the same as -// 1LU<<(NUM_PROGRAMS_POW_2/2). -static const size_t GRID_WIDTH = 1LU << (NUM_PROGRAMS_POW_2 / 2); #endif diff --git a/src/bf.c b/src/bf.c new file mode 100644 index 0000000..62371d7 --- /dev/null +++ b/src/bf.c @@ -0,0 +1,169 @@ +/* bf.c: Program iteration implementation + * Created: 2026-03-10 + * Author: Aryadev Chavali + * License: See end of file + */ + +#include + +#include "bf.h" +#include "vec.h" + +void program_concat(struct ProgramConcat *ret, bf_token *a, bf_token *b) +{ + assert(a && b); + memset(ret, 0, sizeof(*ret)); + ret->a = a; + ret->b = b; + memcpy(ret->tape, a, SIZEOF_PROGRAM); + memcpy(ret->tape + SIZEOF_PROGRAM, b, SIZEOF_PROGRAM); +} + +struct MachineContext +{ + u64 ip, head0, head1; + u64 total_iters; +}; + +// This function implements the jump-forward, given the current state of the +// machine. The main thing to concern us here is setting up the cond_stack +// correctly. +void loop_begin(struct ProgramConcat *prg, struct MachineContext *ctx, + vec_t *cond_stack) +{ + // Add to cond_stack if not already present. + if (vec_find(cond_stack, &ctx->ip, sizeof(ctx->ip)) > cond_stack->size) + { + vec_append(cond_stack, &ctx->ip, sizeof(ctx->ip)); + } + + // If tape at head0 is nonzero, then go to the next instruction. + if (prg->tape[ctx->head0]) + { + ++ctx->ip; + return; + } + + // Otherwise, we need to find the corresponding closed bracket and jump to it. + u64 square_brackets = 1; + u64 close_ip; + for (close_ip = ctx->ip + 1; + square_brackets != 0 && close_ip < sizeof(prg->tape); ++close_ip) + { + switch (prg->tape[close_ip]) + { + case '[': + ++square_brackets; + break; + case ']': + --square_brackets; + break; + } + } + + if (!square_brackets) + { + ctx->ip = close_ip; + } + else + { + // NOTE: as per paper, terminate. + ctx->ip = sizeof(prg->tape); + } +} + +void program_execute(struct ProgramConcat *prg) +{ + vec_t cond_stack = {0}; + vec_ensure_capacity(&cond_stack, sizeof(prg->tape) * sizeof(u64)); + + for (struct MachineContext ctx = {0}; + ctx.ip < sizeof(prg->tape) && ctx.total_iters < (1LU << 13); + ++ctx.total_iters) + { + u8 opcode = prg->tape[ctx.ip]; + switch (opcode) + { + case '<': + ctx.head0 = SAFE_SUB(ctx.head0, 1); + ++ctx.ip; + break; + case '>': + ctx.head0++; + ++ctx.ip; + break; + case '{': + ctx.head1 = SAFE_SUB(ctx.head1, 1); + ++ctx.ip; + break; + case '}': + ctx.head1++; + ++ctx.ip; + break; + case '-': + prg->tape[ctx.head0]--; + ++ctx.ip; + break; + case '+': + prg->tape[ctx.head0]++; + ++ctx.ip; + break; + case '.': + prg->tape[ctx.head1] = prg->tape[ctx.head0]; + ++ctx.ip; + break; + case ',': + prg->tape[ctx.head0] = prg->tape[ctx.head1]; + ++ctx.ip; + break; + case '[': + { + loop_begin(prg, &ctx, &cond_stack); + break; + } + case ']': + { + if (!prg->tape[ctx.head0]) + { + ++ctx.ip; + continue; + } + else if (cond_stack.size < sizeof(u64)) + { + // NOTE: as per paper, terminate. + ctx.ip = sizeof(prg->tape); + } + else + { + ctx.ip = *(u64 *)vec_pop(&cond_stack, sizeof(ctx.ip)); + } + break; + } + default: + ++ctx.ip; + break; + } + } + + vec_free(&cond_stack); +} + +void program_split(struct ProgramConcat *prg) +{ + assert(prg->a && prg->b); + memcpy(prg->a, prg->tape, SIZEOF_PROGRAM); + memcpy(prg->b, prg->tape + SIZEOF_PROGRAM, SIZEOF_PROGRAM); +} + +/* Copyright (C) 2026 Aryadev Chavali + + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for + * details. + + * You may distribute and modify this code under the terms of the GNU General + * Public License Version 2, which you should have received a copy of along with + * this program. If not, please go to . + + */ diff --git a/src/program_iter.h b/src/bf.h similarity index 71% rename from src/program_iter.h rename to src/bf.h index 5be1b80..c4be5aa 100644 --- a/src/program_iter.h +++ b/src/bf.h @@ -1,24 +1,27 @@ -/* program_iter.h: Program iteration procedure +/* bf.h: Brainfuck implementation * Created: 2026-03-10 * Author: Aryadev Chavali * License: See end of file */ -#ifndef PROGRAM_ITER_H -#define PROGRAM_ITER_H +#ifndef BF_H +#define BF_H #include "base.h" #include "sv.h" -// Result of concatenating two programs. Maintains a concatenated tape of the -// two programs fed for ease of use. +typedef i8 bf_token; + +// All "programs" are 64 bytes. +#define SIZEOF_PROGRAM 64 + struct ProgramConcat { - sv_t A, B; - u8 tape[SIZEOF_PROGRAM * 2]; + bf_token *a, *b; + bf_token tape[SIZEOF_PROGRAM * 2]; }; -void program_concat(struct ProgramConcat *, sv_t, sv_t); +void program_concat(struct ProgramConcat *, bf_token *a, bf_token *b); void program_execute(struct ProgramConcat *); void program_split(struct ProgramConcat *); diff --git a/src/program_iter.c b/src/program_iter.c deleted file mode 100644 index 4bdd578..0000000 --- a/src/program_iter.c +++ /dev/null @@ -1,172 +0,0 @@ -/* program_iter.c: Program iteration implementation - * Created: 2026-03-10 - * Author: Aryadev Chavali - * License: See end of file - */ - -#include - -#include "program_iter.h" -#include "vec.h" - -void program_concat(struct ProgramConcat *ret, sv_t a, sv_t b) -{ - assert(a.size == SIZEOF_PROGRAM && b.size == SIZEOF_PROGRAM); - memset(ret, 0, sizeof(*ret)); - ret->A = a; - ret->B = b; - memcpy(ret->tape, a.data, SIZEOF_PROGRAM); - memcpy(ret->tape + SIZEOF_PROGRAM, b.data, SIZEOF_PROGRAM); -} - -u64 vec_pop(vec_t *vec) -{ - u64 ret = 0; - if (vec->size < sizeof(ret)) - return ret; - vec->size -= sizeof(ret); - memcpy(&ret, (typeof(ret) *)(((u8 *)vec_data(vec)) + vec->size), sizeof(ret)); - return ret; -} - -bool vec_in(vec_t *vec, u64 n) -{ - for (u64 i = 0; i < vec->size / sizeof(n); ++i) - { - if (VEC_GET(vec, i, typeof(n)) == n) - { - return true; - } - } - return false; -} - -void program_execute(struct ProgramConcat *prg) -{ - vec_t cond_stack = {0}; - vec_ensure_capacity(&cond_stack, sizeof(prg->tape) * sizeof(u64)); - - for (u64 ip = 0, head0 = 0, head1 = 0, total_iters = 0; - ip < sizeof(prg->tape) && total_iters < (1LU << 13); ++total_iters) - { - u8 opcode = prg->tape[ip]; - switch (opcode) - { - case '<': - head0 = SAFE_SUB(head0, 1); - ++ip; - break; - case '>': - head0++; - ++ip; - break; - case '{': - head1 = SAFE_SUB(head1, 1); - ++ip; - break; - case '}': - head1++; - ++ip; - break; - case '-': - prg->tape[head0]--; - ++ip; - break; - case '+': - prg->tape[head0]++; - ++ip; - break; - case '.': - prg->tape[head1] = prg->tape[head0]; - ++ip; - break; - case ',': - prg->tape[head0] = prg->tape[head1]; - ++ip; - break; - case '[': - { - if (!vec_in(&cond_stack, ip)) - { - vec_append(&cond_stack, &ip, sizeof(ip)); - } - if (!prg->tape[head0]) - { - // Iterate forward, trying to find a matching closed bracket - u64 square_brackets = 0; - u64 close_ip; - for (close_ip = ip + 1; close_ip < sizeof(prg->tape); ++close_ip) - { - if (prg->tape[close_ip] == '[') - { - ++square_brackets; - } - else if (prg->tape[close_ip] == ']') - { - if (square_brackets == 0) - { - break; - } - --square_brackets; - } - } - if (square_brackets != 0) - { - // NOTE: as per paper, terminate. - ip = sizeof(prg->tape); - } - else - { - ip = close_ip; - } - } - break; - } - case ']': - { - if (prg->tape[head0]) - { - if (cond_stack.size < sizeof(u64)) - { - // NOTE: as per paper, terminate. - ip = sizeof(prg->tape); - } - else - { - ip = vec_pop(&cond_stack); - } - } - else - { - ++ip; - } - break; - } - default: - ++ip; - break; - } - } - - vec_free(&cond_stack); -} - -void program_split(struct ProgramConcat *prg) -{ - assert(prg->A.data && prg->B.data); - memcpy((char *)prg->A.data, prg->tape, SIZEOF_PROGRAM); - memcpy((char *)prg->B.data, prg->tape + SIZEOF_PROGRAM, SIZEOF_PROGRAM); -} - -/* Copyright (C) 2026 Aryadev Chavali - - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for - * details. - - * You may distribute and modify this code under the terms of the GNU General - * Public License Version 2, which you should have received a copy of along with - * this program. If not, please go to . - - */ diff --git a/src/simulation.c b/src/simulation.c deleted file mode 100644 index 37c8de2..0000000 --- a/src/simulation.c +++ /dev/null @@ -1,159 +0,0 @@ -/* simulation.c: Simulation implementation - * Created: 2026-03-10 - * Author: Aryadev Chavali - * License: See end of file - */ - -#include -#include - -#include "simulation.h" - -bool any_threads_using(const struct ThreadState *const states, u64 n) -{ - for (u64 i = 0; i < THREAD_POOL; ++i) - { - if (states[i].p1 == n || states[i].p2 == n) - { - return true; - } - } - return false; -} - -void get_neighbours(u64 index, u64 ret[4]) -{ - memset(ret, 0xFF, sizeof(*ret) * 4); - u64 x = index / GRID_WIDTH; - u64 y = index % GRID_WIDTH; - u64 ptr = 0; - if (x > 0) - { - ret[ptr++] = ((x - 1) * GRID_WIDTH) + y; - } - if (x < GRID_WIDTH - 1) - { - ret[ptr++] = ((x + 1) * GRID_WIDTH) + y; - } - if (y > 0) - { - ret[ptr++] = (x * GRID_WIDTH) + (y + 1); - } - if (y < GRID_WIDTH - 1) - { - ret[ptr++] = (x * GRID_WIDTH) + (y - 1); - } -} - -void thread_pick(struct ThreadState *state) -{ - struct Simulation *sim = state->sim; - u64 p1 = 0, p2 = 0; - while (true) - { - p1 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); - if (any_threads_using(sim->states, p1)) - { - continue; - } - u64 neighbours[4]; - get_neighbours(p1, neighbours); - - u64 p2 = -1; - for (u64 i = 0; i < 4; ++i) - { - if (neighbours[i] == UINT64_MAX || - any_threads_using(sim->states, neighbours[i])) - continue; - p2 = neighbours[i]; - break; - } - - if (p2 < GRID_WIDTH) - { - break; - } - - // Otherwise pick randomly. - p2 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); - while ((p1 * 8 <= ((p2 * 8) + SIZEOF_PROGRAM) && - p2 * 8 <= ((p1 * 8) + SIZEOF_PROGRAM)) || - any_threads_using(sim->states, p2)) - { - p2 = rand() % (SIMULATION_SIZE / SIZEOF_PROGRAM); - } - break; - } - state->p1 = p1; - state->p2 = p2; -} - -const struct timespec THREAD_DEFAULT_SLEEP = {.tv_sec = 1}; - -int thread_update(void *rawptr) -{ - struct ThreadState *state = rawptr; - struct Simulation *simulation = state->sim; - - while (!simulation->stopped) - { - while (simulation->paused) - { - thrd_sleep(&THREAD_DEFAULT_SLEEP, NULL); - } - - // We only need to lock when picking the programs - mtx_lock(&simulation->mutex); - thread_pick(state); - mtx_unlock(&simulation->mutex); - - sv_t a = SV(simulation->buffer + (state->p1 * SIZEOF_PROGRAM), 64); - sv_t b = SV(simulation->buffer + (state->p2 * SIZEOF_PROGRAM), 64); - - struct ProgramConcat prog_concat = {0}; - program_concat(&prog_concat, a, b); - program_execute(&prog_concat); - program_split(&prog_concat); - } - return 0; -} - -void simulation_start(struct Simulation *sim) -{ - for (u64 i = 0; i < SIMULATION_SIZE / sizeof(u16); ++i) - { - ((u16 *)(sim->buffer))[i] = rand() % UINT16_MAX; - } - - sim->stopped = false; - sim->paused = true; - mtx_init(&sim->mutex, mtx_plain); - for (u64 i = 0; i < THREAD_POOL; ++i) - { - memset(&sim->states[i], 0, sizeof(sim->states[i])); - sim->states[i].sim = sim; - thrd_create(&sim->threads[i], thread_update, &sim->states[i]); - } -} - -void simulation_stop(struct Simulation *sim) -{ - sim->stopped = true; - for (u64 i = 0; i < THREAD_POOL; ++i) - { - thrd_join(sim->threads[i], NULL); - } -} - -/* Copyright (C) 2026 Aryadev Chavali - - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for - * details. - - * You may distribute and modify this code under the terms of the GNU General - * Public License Version 2, which you should have received a copy of along with - * this program. If not, please go to . - - */ diff --git a/src/simulation.h b/src/simulation.h deleted file mode 100644 index 05f6aac..0000000 --- a/src/simulation.h +++ /dev/null @@ -1,49 +0,0 @@ -/* simulation.h: Simulation handlers and helpers - * Created: 2026-03-10 - * Author: Aryadev Chavali - * License: See end of file - * Commentary: - */ - -#ifndef SIMULATION_H -#define SIMULATION_H - -#include "program_iter.h" -#include -#include - -struct ThreadState -{ - u64 p1, p2; - void *sim; -}; - -// Simulation is simply a massive tape. We pick two 64 byte portions of this -// buffer for our update procedure, which is based on program_iter. -struct Simulation -{ - char buffer[SIMULATION_SIZE]; - - bool paused, stopped; - mtx_t mutex; - thrd_t threads[THREAD_POOL]; - struct ThreadState states[THREAD_POOL]; -}; - -void simulation_start(struct Simulation *sim); -void simulation_stop(struct Simulation *sim); - -#endif - -/* Copyright (C) 2026 Aryadev Chavali - - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for - * details. - - * You may distribute and modify this code under the terms of the GNU General - * Public License Version 2, which you should have received a copy of along with - * this program. If not, please go to . - - */