diff --git a/ain.c b/ain.c index 5eeec69..8e9ba4c 100644 --- a/ain.c +++ b/ain.c @@ -270,11 +270,11 @@ static bool read_tag(struct ain_reader *r, struct ain *ain) int32_t count = read_int32(r); ain->functions = read_functions(r, count, ain); } else if (TAG_EQ("GLOB")) { - int32_t count = read_int32(r); - ain->globals = read_globals(r, count, ain); + ain->nr_globals = read_int32(r); + ain->globals = read_globals(r, ain->nr_globals, ain); } else if (TAG_EQ("GSET")) { - int32_t count = read_int32(r); - ain->global_initvals = read_initvals(r, count); + ain->nr_initvals = read_int32(r); + ain->global_initvals = read_initvals(r, ain->nr_initvals); } else if (TAG_EQ("STRT")) { int32_t count = read_int32(r); ain->structures = read_structures(r, count); diff --git a/ain.h b/ain.h index 2dc19ed..04cdbb0 100644 --- a/ain.h +++ b/ain.h @@ -160,7 +160,9 @@ struct ain { size_t code_size; struct ain_function *functions; struct ain_global *globals; + int32_t nr_globals; struct ain_initval *global_initvals; + int32_t nr_initvals; struct ain_struct *structures; struct string **messages; int32_t main; diff --git a/vm.c b/vm.c index 5b8edfa..87fac8d 100644 --- a/vm.c +++ b/vm.c @@ -162,6 +162,16 @@ static enum ain_data_type local_type(int varno) return f->vars[varno].data_type; } +static int32_t global_get(int varno) +{ + return heap[0].page[varno].i; +} + +static enum ain_data_type global_type(int varno) +{ + return ain->globals[varno].data_type; +} + // Read the opcode at ADDR. static int16_t get_opcode(size_t addr) { @@ -370,6 +380,9 @@ static void execute_instruction(int16_t opcode) stack_push(b); stack_push(c); break; + case PUSHGLOBALPAGE: + stack_push(0); + break; case PUSHLOCALPAGE: stack_push(call_stack[call_stack_ptr-1].page_slot); break; @@ -377,6 +390,17 @@ static void execute_instruction(int16_t opcode) val = stack_pop(); stack_pop_ref()[0] = val; break; + case SH_GLOBALREF: // VARNO + index = get_argument(0); + stack_push(global_get(index)); + switch (global_type(index)) { + case AIN_STRING: + heap_ref(global_get(index)); + break; + default: + break; + } + break; case SH_LOCALREF: // VARNO index = get_argument(0); stack_push(local_get(index)); @@ -615,6 +639,32 @@ void vm_execute(struct ain *program) ain = program; + // Initialize globals + heap[0].page = xmalloc(sizeof(union vm_value) * ain->nr_globals); + for (int i = 0; i < ain->nr_globals; i++) { + switch (ain->globals[i].data_type) { + case AIN_STRING: + heap[0].page[i].i = heap_alloc_slot(VM_STRING); + break; + default: + break; + } + } + for (int i = 0; i < ain->nr_initvals; i++) { + int32_t index; + struct ain_initval *v = &ain->global_initvals[i]; + switch (v->data_type) { + case AIN_STRING: + index = heap_alloc_slot(VM_STRING); + heap[0].page[v->global_index].i = index; + heap[index].s = make_string(v->string_value, strlen(v->string_value)); + break; + default: + heap[0].page[v->global_index].i = v->int_value; + break; + } + } + // Jump to main. We set up a stack frame so that when main returns, // the first instruction past the end of the code section is executed. // (When we read the AIN file, CALLSYS 0x0 was placed there.)