Split the BCI/BCI-base from BCI/BCI-dev
This commit is contained in:
commit
bd0a0bcb74
19
Makefile
Normal file
19
Makefile
Normal 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
20
base.h
Normal 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
370
interpreter/core_methods.c
Normal 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
114
interpreter/core_methods.h
Normal 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
217
interpreter/interpreter.c
Normal 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
121
interpreter/interpreter.h
Normal 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
14
interpreter/test/Makefile
Normal 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:
|
||||
|
69
interpreter/test/test_interpreter.c
Normal file
69
interpreter/test/test_interpreter.c
Normal 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;
|
||||
}
|
||||
|
158
method_dispatcher/method_dispatcher.c
Normal file
158
method_dispatcher/method_dispatcher.c
Normal 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;
|
||||
}
|
87
method_dispatcher/method_dispatcher.h
Normal file
87
method_dispatcher/method_dispatcher.h
Normal 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
|
14
method_dispatcher/test/Makefile
Normal file
14
method_dispatcher/test/Makefile
Normal 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
|
63
method_dispatcher/test/test_method_dispatcher.c
Normal file
63
method_dispatcher/test/test_method_dispatcher.c
Normal 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
40
stack.c
Normal 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
20
stack.h
Normal 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
12
test/Makefile
Normal 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
34
test/test_stack.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user