Split the BCI/BCI-base from BCI/BCI-dev

This commit is contained in:
Daniel Knüttel 2018-10-27 19:45:57 +02:00
commit bd0a0bcb74
16 changed files with 1372 additions and 0 deletions

19
Makefile Normal file
View File

@ -0,0 +1,19 @@
CC=gcc
objects= stack.o method_dispatcher/method_dispatcher.o interpreter/core_methods.o interpreter/interpreter.o
all: $(objects) test
CFLAG= -c -O -o
%.o: %.c
$(CC) $(CFLAG) $@ $<
.PHONY: test
test:
cd test && make
cd method_dispatcher/test && make
cd interpreter/test && make
clean:
- rm $(objects)

20
base.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef bci_base_h__
#define bci_base_h__
#include <inttypes.h>
#include "stack.h"
#define BCI_CORE_NUM_REG 40
// Note that void * state will later be casted to
// machine_state_t.
typedef char (* bci_core_method_t)(uint8_t small_arg
, void * state);
#define BCI_CORE_RESULT_RESERVED_BITS 0b11000000
#define BCI_CORE_RESULT_APPLICATION_BITS 0b00111111
#define BCI_CORE_SMALL_ARG_MASK 0b0000000000111111
#define BCI_CORE_OPCODE_MASK 0b1111111111000000
#endif

370
interpreter/core_methods.c Normal file
View File

@ -0,0 +1,370 @@
#include "core_methods.h"
#define BCI_CORE_REGISTER_CHECK(var) if(var > BCI_CORE_NUM_REG) return 1
// #1 -> $0
char bci_cm_ldi(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
uint16_t arg;
char res;
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
if(res)
{
return res;
}
state->data_reg[small_arg] = arg;
return machine_state_t_default_afterexec(state, 1);
}
// @($1) -> $0
char bci_cm_ld(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
uint16_t arg;
char res;
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
if(res)
{
return res;
}
BCI_CORE_REGISTER_CHECK(arg);
arg = state->data_reg[arg];
res = machine_state_t_get_mem(state, arg, &arg);
if(res)
{
return res;
}
state->data_reg[small_arg] = arg;
return machine_state_t_default_afterexec(state, 1);
}
// $0 -> @($1)
char bci_cm_st(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
char res;
uint16_t arg;
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
if(res)
{
return res;
}
BCI_CORE_REGISTER_CHECK(arg);
arg = state->data_reg[arg];
res = machine_state_t_set_mem(state, arg, state->data_reg[small_arg]);
if(res)
{
return res;
}
return machine_state_t_default_afterexec(state, 1);
}
// $0 + 1 -> $0
char bci_cm_inc(uint8_t small_arg, machine_state_t state)
{
int32_t result;
BCI_CORE_REGISTER_CHECK(small_arg);
result = state->data_reg[small_arg] + 1;
state->data_reg[small_arg] = result & 0xffff;
state->status_reg = result >> 16;
return machine_state_t_default_afterexec(state, 0);
}
// $0 - 1 -> $0
char bci_cm_dec(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
int32_t result = state->data_reg[small_arg] - 1;
state->data_reg[small_arg] = result & 0xffff;
state->status_reg = result >> 16;
return machine_state_t_default_afterexec(state, 0);
}
// $0 + $1 -> $0
char bci_cm_add(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
uint16_t arg;
char res;
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
if(res)
{
return res;
}
BCI_CORE_REGISTER_CHECK(arg);
int32_t result = state->data_reg[small_arg] + state->data_reg[arg];
state->data_reg[small_arg] = result & 0xffff;
state->status_reg = result >> 16;
return machine_state_t_default_afterexec(state, 1);
}
// $0 - $1 -> $0
char bci_cm_sub(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
uint16_t arg;
char res;
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
if(res)
{
return res;
}
BCI_CORE_REGISTER_CHECK(arg);
int32_t result = state->data_reg[small_arg] - state->data_reg[arg];
state->data_reg[small_arg] = result & 0xffff;
state->status_reg = result >> 16;
return machine_state_t_default_afterexec(state, 1);
}
// $0 * $1 -> $0
char bci_cm_mul(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
uint16_t arg;
char res;
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
if(res)
{
return res;
}
BCI_CORE_REGISTER_CHECK(arg);
int32_t result = state->data_reg[small_arg] * state->data_reg[arg];
state->data_reg[small_arg] = result & 0xffff;
state->status_reg = result >> 16;
return machine_state_t_default_afterexec(state, 1);
}
// $0 / $1 -> $0
char bci_cm_div(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
uint16_t arg;
char res;
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
if(res)
{
return res;
}
BCI_CORE_REGISTER_CHECK(arg);
int32_t result = state->data_reg[small_arg] / state->data_reg[arg];
state->data_reg[small_arg] = result & 0xffff;
state->status_reg = result >> 16;
return machine_state_t_default_afterexec(state, 1);
}
// if($0 > 0): 1 -> $st_reg
// else: 0 -> $st_reg
char bci_cm_gt(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
if(state->data_reg[small_arg] > 0)
{
state->status_reg = 1;
}
else
{
state->status_reg = 0;
}
return machine_state_t_default_afterexec(state, 0);
}
// if($0 >= 0): 1 -> $st_reg
// else: 0 -> $st_reg
char bci_cm_ge(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
if(state->data_reg[small_arg] >= 0)
{
state->status_reg = 1;
}
else
{
state->status_reg = 0;
}
return machine_state_t_default_afterexec(state, 0);
}
// if($0 < 0): 1 -> $st_reg
// else: 0 -> $st_reg
char bci_cm_lt(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
if(state->data_reg[small_arg] < 0)
{
state->status_reg = 1;
}
else
{
state->status_reg = 0;
}
return machine_state_t_default_afterexec(state, 0);
}
// if($0 <= 0): 1 -> $st_reg
// else: 0 -> $st_reg
char bci_cm_le(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
if(state->data_reg[small_arg] <= 0)
{
state->status_reg = 1;
}
else
{
state->status_reg = 0;
}
return machine_state_t_default_afterexec(state, 0);
}
// if($0 == 0): 1 -> $st_reg
// else: 0 -> $st_reg
char bci_cm_eq(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
if(state->data_reg[small_arg] == 0)
{
state->status_reg = 1;
}
else
{
state->status_reg = 0;
}
return machine_state_t_default_afterexec(state, 0);
}
// $0 -> $pc; 0 -> $st_reg
char bci_cm_jmp(uint8_t small_arg, machine_state_t state)
{
BCI_CORE_REGISTER_CHECK(small_arg);
uint16_t arg = state->data_reg[arg];
state->status_reg = 0;
state->program_counter = arg;
return 0;
}
// if($st_reg): $0 -> $pc; 0 -> $st_reg
// else: do nothing
char bci_cm_cjmp(uint8_t small_arg, machine_state_t state)
{
uint16_t arg = small_arg;
BCI_CORE_REGISTER_CHECK(small_arg);
#ifdef DEBUG
printf("MSG: cjmp: arg=0x%x (=0x%x)\n", arg, state->data_reg[arg]);
#endif
arg = state->data_reg[arg];
if(state->status_reg)
{
state->program_counter = arg;
state->status_reg = 0;
return 0;
}
return machine_state_t_default_afterexec(state, 0);
}
// $pc -> @stack
// $0 -> $pc
char bci_cm_call(uint8_t small_arg, machine_state_t state)
{
uint16_t arg;
BCI_CORE_REGISTER_CHECK(small_arg);
arg = state->data_reg[arg];
char res = bci_stack_t_push(&(state->stack), state->program_counter);
if(res)
{
return res;
}
state->program_counter = arg;
return 0;
}
// if($st_reg): $pc -> @stack; $0 -> $pc; 0 -> $st_reg
// else: do nothing
char bci_cm_ccall(uint8_t small_arg, machine_state_t state)
{
uint16_t arg;
char res;
BCI_CORE_REGISTER_CHECK(small_arg);
arg = state->data_reg[small_arg];
if(state->status_reg)
{
state->program_counter = arg;
res = bci_stack_t_push(&(state->stack), state->program_counter);
if(res)
{
return res;
}
return 0;
}
state->status_reg = 0;
return machine_state_t_default_afterexec(state, 0);
}
// @stack -> $pc
char bci_cm_ret(uint8_t small_arg, machine_state_t state)
{
uint16_t result;
char res = bci_stack_t_pop(&(state->stack), &result);
if(res)
{
return res;
}
state->program_counter = result;
return 0;
}
// 0 -> $st_reg
char bci_cm_cl(uint8_t small_arg, machine_state_t state)
{
state->status_reg = 0;
return machine_state_t_default_afterexec(state, 0);
}
// 1 -> $su_reg
char bci_cm_stop(uint8_t small_arg, machine_state_t state)
{
state->shutdown_reg = 1;
return machine_state_t_default_afterexec(state, 0);
}
// if($st_reg): 0 -> $st_reg
// else: 1 -> $st_reg
char bci_cm_not(uint8_t small_arg, machine_state_t state)
{
if(state->status_reg)
{
state->status_reg = 0;
}
else
{
state->status_reg = 1;
}
return machine_state_t_default_afterexec(state, 0);
}

114
interpreter/core_methods.h Normal file
View File

@ -0,0 +1,114 @@
#ifndef bci_core_methods_h__
#define bci_core_methods_h__
#include "interpreter.h"
/*
* This library brings a set of essential core methods.
* */
/*
* Naming conventions:
*
* x = 0, 1, 2, 3...: arguments.
* 0: small_arg (6 bit)
* 1, 2, ...: 16 bit optional arguments
*
* $x: value of data register x
* @x: value of memory word x
* #x: value of argument x
* 0, 1, 2, ...: integer 0, 1, 2, ...
*
* -> write result in register/word on the right
*
* st_reg: status register
* su_reg: shutdown register
* pc: program counter
*
* stack: the builtin stack
* */
// #1 -> $0
char bci_cm_ldi(uint8_t small_arg, machine_state_t state);
// @($1) -> $0
char bci_cm_ld(uint8_t small_arg, machine_state_t state);
// $0 -> @($1)
char bci_cm_st(uint8_t small_arg, machine_state_t state);
// NOTES on inc, dec, add, sub, mul, div:
//
// These methods will store the overflow-word in $st_reg.
// $0 + 1 -> $0
char bci_cm_inc(uint8_t small_arg, machine_state_t state);
// $0 - 1 -> $0
char bci_cm_dec(uint8_t small_arg, machine_state_t state);
// $0 + $1 -> $0
char bci_cm_add(uint8_t small_arg, machine_state_t state);
// $0 - $1 -> $0
char bci_cm_sub(uint8_t small_arg, machine_state_t state);
// $0 * $1 -> $0
char bci_cm_mul(uint8_t small_arg, machine_state_t state);
// $0 / $1 -> $0
char bci_cm_div(uint8_t small_arg, machine_state_t state);
// if($0 > 0): 1 -> $st_reg
// else: 0 -> $st_reg
char bci_cm_gt(uint8_t small_arg, machine_state_t state);
// if($0 >= 0): 1 -> $st_reg
// else: 0 -> $st_reg
char bci_cm_ge(uint8_t small_arg, machine_state_t state);
// if($0 < 0): 1 -> $st_reg
// else: 0 -> $st_reg
char bci_cm_lt(uint8_t small_arg, machine_state_t state);
// if($0 <= 0): 1 -> $st_reg
// else: 0 -> $st_reg
char bci_cm_le(uint8_t small_arg, machine_state_t state);
// if($0 == 0): 1 -> $st_reg
// else: 0 -> $st_reg
char bci_cm_eq(uint8_t small_arg, machine_state_t state);
// if($st_reg): 0 -> $st_reg
// else: 1 -> $st_reg
char bci_cm_not(uint8_t small_arg, machine_state_t state);
// $1 -> $pc
char bci_cm_jmp(uint8_t small_arg, machine_state_t state);
// if($st_reg): $1 -> $pc
// else: do nothing
char bci_cm_cjmp(uint8_t small_arg, machine_state_t state);
// $pc -> @stack
// $0 -> $pc
char bci_cm_call(uint8_t small_arg, machine_state_t state);
// if($st_reg): $pc -> @stack; $0 -> $pc
// else: do nothing
char bci_cm_ccall(uint8_t small_arg, machine_state_t state);
// @stack -> $pc
char bci_cm_ret(uint8_t small_arg, machine_state_t state);
// 0 -> $st_reg
char bci_cm_cl(uint8_t small_arg, machine_state_t state);
// 1 -> $su_reg
char bci_cm_stop(uint8_t small_arg, machine_state_t state);
#endif

217
interpreter/interpreter.c Normal file
View File

@ -0,0 +1,217 @@
#include <stdlib.h>
#include <stdio.h>
#include "interpreter.h"
machine_state_t machine_state_t_new( void * cache_function_data
, size_t program_size
, size_t cache_size
, size_t memory_size
, size_t (* cache_block)(uint16_t * cache
, uint16_t offset
, size_t cache_size
, void * cache_function_data)
, dispatch_tree_t method_dispatcher)
{
machine_state_t state = malloc(sizeof(struct machine_state_s));
if(!state)
{
return NULL;
}
uint16_t * cache = calloc(sizeof(uint16_t), cache_size);
if(!cache)
{
free(state);
return NULL;
}
uint16_t * memory = calloc(sizeof(uint16_t), memory_size);
if(!memory)
{
free(state);
free(cache);
return NULL;
}
state->program_size = program_size;
state->cache = cache;
state->cache_block = cache_block;
state->cache_size = cache_size;
state->cache_loaded = 0;
state->cache_offset = 0;
state->cache_function_data = cache_function_data;
state->program_counter = 0;
state->status_reg = 0;
state->shutdown_reg = 0;
int i;
for(i = 0; i < BCI_CORE_NUM_REG; i++)
{
state->data_reg[i] = 0;
}
state->stack = NULL;
state->memory = memory;
state->memory_size = memory_size;
state->method_dispatcher = method_dispatcher;
return state;
}
void machine_state_t_del(machine_state_t state)
{
free(state->cache);
free(state->memory);
dispatch_tree_t_del(state->method_dispatcher);
bci_stack_t_del(&(state->stack));
free(state);
}
char update_cache(machine_state_t state, uint16_t offset)
{
// Calculate a clever offset for caching.
uint16_t cache_offset = offset;
if((cache_offset + state->cache_size)
> state->program_size)
{
if(state->program_size < state->cache_size)
{
cache_offset = 0;
}
else
{
cache_offset = state->program_size - state->cache_size;
}
}
size_t cached = state->cache_block(state->cache
, cache_offset
, state->cache_size
, state->cache_function_data);
if(cached != state->cache_size)
{
#ifdef DEBUG
printf("ERROR: should have cached %zu words, but got %zu.\n", state->cache_size, cached);
#endif
return 1;
}
state->cache_offset = cache_offset;
state->cache_loaded = 1;
return 0;
}
char machine_state_t_get_word(machine_state_t state, uint16_t offset, uint16_t * result)
{
// This would be bad.
if(offset >= state->program_size)
{
return 0b01000000 | 1;
}
// Calculate the in-cache offset of the desired offset.
int32_t in_cache_offset = offset - state->cache_offset;
// Check if we need to update the cache.
if( in_cache_offset < 0
|| !(state->cache_loaded)
)
{
if(update_cache(state, offset))
{
#ifdef DEBUG
printf("ERROR: failed to update cache\n");
#endif
state->error = 0b01000000 | 2;
return 0b01000000 | 2;
}
// Re-calculate the in-cache offset
in_cache_offset = offset - state->cache_offset;
}
*result = state->cache[in_cache_offset];
return 0;
}
char machine_state_t_exec_cycle(machine_state_t state)
{
char res = 0;
uint16_t opcode;
res = machine_state_t_get_word(state, state->program_counter, &opcode);
if(res)
{
return res;
}
#ifdef DEBUG
printf("MSG: opcode = 0x%x, small_arg = 0x%x\n"
, opcode & BCI_CORE_OPCODE_MASK
, opcode & BCI_CORE_SMALL_ARG_MASK);
#endif
bci_core_method_t method = dispatch_tree_t_dispatch(
state->method_dispatcher
, opcode & BCI_CORE_OPCODE_MASK);
if(!method)
{
state->error = res;
return 0b10000000 | 1;
}
return BCI_CORE_RESULT_APPLICATION_BITS
& method( opcode & BCI_CORE_SMALL_ARG_MASK
, state);
}
char machine_state_t_default_afterexec(machine_state_t state, uint8_t argc)
{
state->program_counter += 1 + argc;
return 0;
}
char machine_state_t_get_mem(machine_state_t state, uint16_t offset, uint16_t * result)
{
if(offset > state->memory_size)
{
state->error = 0b01000000 | 15;
return 0b01000000 | 15;
}
*result = state->memory[offset];
return 0;
}
char machine_state_t_set_mem(machine_state_t state, uint16_t offset, uint16_t data)
{
if(offset > state->memory_size)
{
state->error = 0b01000000 | 15;
return 0b01000000 | 15;
}
state->memory[offset] = data;
return 0;
}
char machine_state_t_exec(machine_state_t state)
{
char status = 0;
while((!status) && (!state->shutdown_reg))
{
status = machine_state_t_exec_cycle(state);
}
state->error = status;
return status;
}

121
interpreter/interpreter.h Normal file
View File

@ -0,0 +1,121 @@
#ifndef bci_interpreter_h__
#define bci_interpreter_h__
#include <stddef.h>
#include "../base.h"
#include "../method_dispatcher/method_dispatcher.h"
#include "../stack.h"
typedef struct machine_state_s
{
// The size of the program in 16-bit words
uint16_t program_size;
void * cache_function_data;
size_t cache_size;
uint16_t cache_offset;
uint16_t * cache;
size_t (* cache_block)(uint16_t * cache
, uint16_t offset
, size_t cache_size
, void * cache_function_data);
char cache_loaded;
uint16_t program_counter;
uint16_t status_reg;
// Any non-zero value in this register will
// break the program execution.
uint16_t shutdown_reg;
uint16_t data_reg[BCI_CORE_NUM_REG];
bci_stack_t stack;
size_t memory_size;
uint16_t * memory;
dispatch_tree_t method_dispatcher;
// Possible Error Codes:
// 0b01xxxxxx: memory related internal error
// 0b10xxxxxx: core method related internal error
// 0b00xxxxxx: application related internal error
//
//
// 0b01000000 | 1: Program offset out of bounds
// 0b01000000 | 2: Failed to cache new data
// 0b01000000 | 15: Memory offset out of bounds
//
//
// 0b10000000 | 1: Unknown opcode
char error;
} * machine_state_t;
machine_state_t machine_state_t_new( void * cache_function_data
, size_t program_size
, size_t cache_size
, size_t memory_size
, size_t (* cache_block)(uint16_t * cache
, uint16_t offset
, size_t cache_size
, void * cache_function_data)
, dispatch_tree_t method_dispatcher);
void machine_state_t_del(machine_state_t state);
/*
* This function essentially executes one cycle of the machine execution.
* It will fetch the opcode and argument, dispatch the method and execute it.
*
* Also this will update the cache if needed.
*
* Possible return codes:
*
* - 0bxyXXXXXX
* Error while executing the cycle.
* - 0b01XXXXXX
* Error in the internal memory management (i.e. program counter out
* of bounds)
* - 0b01000000 | 1: program_counter or argument offset > program_size
* - 0b01000000 | 2: failed to cache new data
*
* - 0b10XXXXXX
* Error while dispatching the method
* - 0b10000000 | 1: unknown opcode
*
* - 0b00XXXXXX
* XXXXXX is the return value of the bci_core_method_t method.
* */
char machine_state_t_exec_cycle(machine_state_t state);
/*
* Runs ``machine_state_t_exec_cycle`` until either this function
* returns a non-zero value or a non-zero value is stored in
* ``state->shutdown_reg``.
* Sets ``state->error`` to the last return value of ``machine_state_t_exec_cycle``
* and returns it.
* */
char machine_state_t_exec(machine_state_t state);
/*
* Do the default updates on the machine state.
* This will be basically increasing the program counter.
* */
char machine_state_t_default_afterexec(machine_state_t state, uint8_t argc);
/*
* Get the word at offset in the program memory.
* Returns 0 on success, a non-zero value otherwise.
*
* It will set state->error appropiately.
* */
char machine_state_t_get_word(machine_state_t state, uint16_t offset, uint16_t * result);
/*
* Get the word at offset in the RAM-alike memory.
* Works like machine_state_t_get_word.
* */
char machine_state_t_get_mem(machine_state_t state, uint16_t offset, uint16_t * result);
char machine_state_t_set_mem(machine_state_t state, uint16_t offset, uint16_t data);
#endif

14
interpreter/test/Makefile Normal file
View File

@ -0,0 +1,14 @@
CC=gcc
all: test_interpreter
interpreter: clean
$(CC) -g ../../stack.c ../interpreter.c ../core_methods.c ../../method_dispatcher/method_dispatcher.c test_interpreter.c -o interpreter
test_interpreter: interpreter
valgrind ./interpreter
clean:

View File

@ -0,0 +1,69 @@
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "../interpreter.h"
#include "../core_methods.h"
#include "../../method_dispatcher/method_dispatcher.h"
size_t copy_cache(uint16_t * cache
, uint16_t offset
, size_t cache_size
, void * cache_function_data);
int main(void)
{
dispatch_tree_t tree = dispatch_tree_t_new();
dispatch_tree_autoinserter_t inserter = dispatch_tree_autoinserter_t_new(tree);
uint16_t ldi = dispatch_tree_autoinserter_t_insert(inserter, (bci_core_method_t) bci_cm_ldi);
uint16_t add = dispatch_tree_autoinserter_t_insert(inserter, (bci_core_method_t) bci_cm_add);
uint16_t * program = calloc(sizeof(uint16_t), 20);
program[0] = ldi;
program[1] = 0xfefe;
program[2] = ldi | 1;
program[3] = 2;
program[4] = ldi | 2;
program[5] = 3;
program[6] = add | 1;
program[7] = 2;
machine_state_t state = machine_state_t_new(
program
, 8
, 20
, 20
, copy_cache
, tree);
machine_state_t_exec_cycle(state);
machine_state_t_exec_cycle(state);
machine_state_t_exec_cycle(state);
machine_state_t_exec_cycle(state);
printf("data_reg[0]: %x\n", state->data_reg[0]);
assert(state->data_reg[0] == 0xfefe);
printf("data_reg[1]: %x\n", state->data_reg[1]);
assert(state->data_reg[1] == 5);
printf("data_reg[2]: %x\n", state->data_reg[2]);
assert(state->data_reg[2] == 3);
printf("program_counter: %d\n", state->program_counter);
assert(state->program_counter == 8);
dispatch_tree_autoinserter_t_del(inserter);
machine_state_t_del(state);
free(program);
return 0;
}
size_t copy_cache(uint16_t * cache
, uint16_t offset
, size_t cache_size
, void * cache_function_data)
{
size_t i;
for(i = 0; i < cache_size; i++)
{
printf("\tCP [%zd]->[%zd]: %x\n", i + offset, i, ((uint16_t *) cache_function_data)[i + offset]);
cache[i] = ((uint16_t *) cache_function_data)[i + offset];
}
return i;
}

View File

@ -0,0 +1,158 @@
#include <stdlib.h>
#include "method_dispatcher.h"
dispatch_tree_t dispatch_tree_t_new(void)
{
dispatch_tree_t tree = malloc(sizeof(struct dispatch_tree_s));
tree->root = NULL;
return tree;
}
void dispatch_tree_t_del(dispatch_tree_t tree)
{
dispatch_tree_node_t_del(tree->root);
free(tree);
}
dispatch_tree_node_t dispatch_tree_node_t_new(uint16_t word
, bci_core_method_t method)
{
dispatch_tree_node_t node = malloc(sizeof(struct dispatch_tree_node_s));
node->higher = NULL;
node->lower = 0;
node->method = method;
node->word = word;
return node;
}
void dispatch_tree_node_t_del(dispatch_tree_node_t node)
{
if(node->higher)
{
dispatch_tree_node_t_del(node->higher);
}
if(node->lower)
{
dispatch_tree_node_t_del(node->lower);
}
free(node);
}
char dispatch_tree_t_insert(dispatch_tree_t tree
, uint16_t word
, bci_core_method_t method)
{
dispatch_tree_node_t new_node = dispatch_tree_node_t_new(word, method);
if(!new_node)
{
return 1;
}
// explicitly handle empty tree
if(!tree->root)
{
tree->root = new_node;
return 0;
}
// non-empty tree
dispatch_tree_node_t this_node = tree->root;
dispatch_tree_node_t parent_node = NULL;
// search for place
do
{
parent_node = this_node;
if(parent_node->word < word)
{
this_node = parent_node->higher;
continue;
}
if(parent_node->word > word)
{
this_node = parent_node->lower;
continue;
}
if(parent_node->word == word)
{
// we already have that key.
return 2;
}
}
while(this_node);
if(parent_node->word < word)
{
parent_node->higher = new_node;
}
if(parent_node->word > word)
{
parent_node->lower = new_node;
}
return 0;
}
bci_core_method_t dispatch_tree_t_dispatch(dispatch_tree_t tree
, uint16_t word)
{
dispatch_tree_node_t this_node = tree->root;
while(this_node)
{
if(this_node->word < word)
{
this_node = this_node->higher;
continue;
}
if(this_node->word > word)
{
this_node = this_node->lower;
continue;
}
if(this_node->word == word)
{
return this_node->method;
}
}
return NULL;
}
dispatch_tree_autoinserter_t dispatch_tree_autoinserter_t_new(dispatch_tree_t tree)
{
dispatch_tree_autoinserter_t autoinserter = malloc(
sizeof(struct dispatch_tree_autoinserter_s));
if(!autoinserter)
{
return NULL;
}
autoinserter->mayor = 2;
autoinserter->minor = 1;
autoinserter->tree = tree;
return autoinserter;
}
void dispatch_tree_autoinserter_t_del(dispatch_tree_autoinserter_t autoinserter)
{
free(autoinserter);
}
uint16_t dispatch_tree_autoinserter_t_insert(
dispatch_tree_autoinserter_t autoinserter
, bci_core_method_t method)
{
uint16_t opcode = 0b1111111111;
opcode *= autoinserter->minor;
opcode /= autoinserter->mayor;
opcode <<= 6;
dispatch_tree_t_insert(autoinserter->tree, opcode, method);
autoinserter->minor = (autoinserter->minor + 2) % autoinserter->mayor;
if(autoinserter->minor == 1)
{
autoinserter->mayor *= 2;
}
return opcode;
}

View File

@ -0,0 +1,87 @@
#ifndef bci_method_dispatcher_h__
#define bci_method_dispatcher_h__
#include <inttypes.h>
#include "../base.h"
typedef struct dispatch_tree_node_s
{
struct dispatch_tree_node_s * higher;
struct dispatch_tree_node_s * lower;
uint16_t word;
bci_core_method_t method;
} * dispatch_tree_node_t;
typedef struct dispatch_tree_s
{
dispatch_tree_node_t root;
} * dispatch_tree_t;
dispatch_tree_t dispatch_tree_t_new(void);
/*
* This deletes the tree and will invoke dispatch_tree_node_t_del on
* tree->root (which will delete all the other nodes recursively).
* If you want to keep nodes you have to explicityl remove the reference to
* them by setting them to NULL.
* */
void dispatch_tree_t_del(dispatch_tree_t tree);
dispatch_tree_node_t dispatch_tree_node_t_new(uint16_t word
, bci_core_method_t method);
/*
* This deletes the node an will invoke dispatch_tree_node_t_del on
* node->higher and node->lower. If you want to keep those nodes
* you have to explicitly clear the reference by setting them to NULL.
* */
void dispatch_tree_node_t_del(dispatch_tree_node_t node);
/*
* Insert a new key-value-pair into the tree.
*
* Return codes:
* 0: OK
* 1: out of memory
* 2: key already in tree
* */
char dispatch_tree_t_insert(dispatch_tree_t tree
, uint16_t word
, bci_core_method_t method);
bci_core_method_t dispatch_tree_t_dispatch(dispatch_tree_t tree
, uint16_t word);
typedef struct dispatch_tree_autoinserter_s
{
uint16_t mayor;
uint16_t minor;
dispatch_tree_t tree;
} * dispatch_tree_autoinserter_t;
dispatch_tree_autoinserter_t dispatch_tree_autoinserter_t_new(dispatch_tree_t tree);
void dispatch_tree_autoinserter_t_del(dispatch_tree_autoinserter_t autoinserter);
/*
* This function inserts a new method into the tree and automatically
* chooses the optimal word to prevent degeneration.
*
* NOTE:
* When inserting mutliple methods this function acts deterministic,
* IF AND ONLY IF the order of the methods is not changed.
*
* The assembler will bring an analogous function that allows one
* to determine the opcodes of the methods.
*
* NOTE:
* This algorithm will not work for more that 1023 registered opcodes.
* This limit is however considered acceptable.
*
* */
uint16_t dispatch_tree_autoinserter_t_insert(
dispatch_tree_autoinserter_t autoinserter
, bci_core_method_t method);
#endif

View File

@ -0,0 +1,14 @@
CC=gcc
all: test_method_dispatcher
method_dispatcher: clean
$(CC) -g ../method_dispatcher.c test_method_dispatcher.c -o method_dispatcher
test_method_dispatcher: method_dispatcher
valgrind ./method_dispatcher
clean:
-rm method_dispatcher

View File

@ -0,0 +1,63 @@
#include <stdio.h>
#include "../method_dispatcher.h"
char m1(uint8_t small_arg, void * state);
char m2(uint8_t small_arg, void * state);
char m3(uint8_t small_arg, void * state);
char m4(uint8_t small_arg, void * state);
char m5(uint8_t small_arg, void * state);
int main(void)
{
printf("sizeof struct dispatch_tree_node_s: %zd\n", sizeof(struct dispatch_tree_node_s));
dispatch_tree_t tree = dispatch_tree_t_new();
dispatch_tree_t_insert(tree, 3 << 6, m3);
dispatch_tree_t_insert(tree, 2 << 6, m2);
dispatch_tree_t_insert(tree, 1 << 6, m1);
dispatch_tree_t_insert(tree, 4 << 6, m4);
dispatch_tree_t_insert(tree, 5 << 6, m5);
int i;
for(i = 1; i < 6; i++)
{
dispatch_tree_t_dispatch(tree, i << 6)(i, NULL);
}
dispatch_tree_t_del(tree);
bci_core_method_t methods[5] = {m1, m2, m3, m4, m5};
tree = dispatch_tree_t_new();
dispatch_tree_autoinserter_t inserter = dispatch_tree_autoinserter_t_new(tree);
for(i = 0; i < 5; i++)
{
printf("%u\n", dispatch_tree_autoinserter_t_insert(inserter, methods[i]));
}
dispatch_tree_autoinserter_t_del(inserter);
dispatch_tree_t_del(tree);
return 0;
}
char m1(uint8_t small_arg, void * state)
{
printf("m1: %d\n", small_arg);
}
char m2(uint8_t small_arg, void * state)
{
printf("m2: %d\n", small_arg);
}
char m3(uint8_t small_arg, void * state)
{
printf("m3: %d\n", small_arg);
}
char m4(uint8_t small_arg, void * state)
{
printf("m4: %d\n", small_arg);
}
char m5(uint8_t small_arg, void * state)
{
printf("m5: %d\n", small_arg);
}

40
stack.c Normal file
View File

@ -0,0 +1,40 @@
#include <stdlib.h>
#include "stack.h"
char bci_stack_t_push(bci_stack_t * stack, uint16_t value)
{
bci_stack_t node = malloc(sizeof(struct bci_stack_s));
if(!node)
{
return 1;
}
node->next = *stack;
node->value = value;
*stack = node;
return 0;
}
char bci_stack_t_pop(bci_stack_t * stack, uint16_t * result)
{
bci_stack_t this_node;
if(!*stack)
{
return 1;
}
this_node = *stack;
*result = this_node->value;
*stack = this_node->next;
free(this_node);
return 0;
}
void bci_stack_t_del(bci_stack_t * stack)
{
bci_stack_t this_node;
while(*stack)
{
this_node = *stack;
*stack = this_node->next;
free(this_node);
}
}

20
stack.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef bci_stack_h__
#define bci_stack_h__
#include <inttypes.h>
typedef struct bci_stack_s
{
struct bci_stack_s * next;
uint16_t value;
} * bci_stack_t;
char bci_stack_t_push(bci_stack_t * stack, uint16_t value);
char bci_stack_t_pop(bci_stack_t * stack, uint16_t * result);
/*
* Deletes the entire (!) stack.
*
* */
void bci_stack_t_del(bci_stack_t * stack);
#endif

12
test/Makefile Normal file
View File

@ -0,0 +1,12 @@
CC=gcc
all: test_stack
stack: clean
$(CC) -g ../stack.c test_stack.c -o stack
test_stack: stack
valgrind ./stack
clean:
-rm stack

34
test/test_stack.c Normal file
View File

@ -0,0 +1,34 @@
#include <stdio.h>
#include "../stack.h"
#include <assert.h>
int main(void)
{
bci_stack_t stack = NULL;
int i;
uint16_t res;
char status = 0;
for(i = 0; i < 10; i++)
{
bci_stack_t_push(&stack, (uint16_t) i);
}
--i;
while(!status)
{
status = bci_stack_t_pop(&stack, &res);
if(!status)
{
assert(res == i--);
}
}
for(i = 0; i < 10; i++)
{
bci_stack_t_push(&stack, (uint16_t) i);
}
bci_stack_t_del(&stack);
return 0;
}