#include #include "interpreter.h" machine_state_t machine_state_t_new( void * cache_function_data , size_t cache_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; } state->cache = cache; state->cache_block = cache_block; state->cache_size = cache_size; state->cache_loaded = 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[BCI_CORE_NUM_REG] = 0; } state->stack = NULL; state->method_dispatcher = method_dispatcher; return state; } void machine_state_t_del(machine_state_t state) { free(state->cache); dispatch_tree_t_del(state->method_dispatcher); free(state); } char update_cache(machine_state_t state) { // Calculate a clever offset for caching. uint16_t cache_offset = state->program_counter; 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) { return 1; } return 0; } char machine_state_t_exec_cycle(machine_state_t state) { uint16_t opcode, arg; // This would be bad. if(state->program_counter >= state->program_size) { return 0b01000000 | 1; } // Calculate the in-cache offset of the program counter. int32_t offset = state->program_counter - state->cache_offset; // Check if we need to update the cache. if( offset < 0 || !(state->cache_loaded) // Note: // +1 for cache starting with 0 // +1 for the argument || (offset + 2) > state->cache_size) { if(update_cache(state)) { return 0b01000000 | 2; } // Re-calculate the in-cache offset offset = state->program_counter - state->cache_offset; } // Check if the argument is cached. if(offset + 2 > state->cache_size) { // Because we have cached the program memory above // there is no way that we can include the argument // now. There is something wrong. return 0b01000000 | 3; } opcode = state->cache[offset]; arg = state->cache[offset + 1]; bci_core_method_t method = dispatch_tree_t_dispatch( state->method_dispatcher , opcode & BCI_CORE_OPCODE_MASK); if(!method) { return 0b10000000 | 1; } return BCI_CORE_RESULT_APPLICATION_BITS & method(arg , 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; }