From 2d30f6138773b2f7fd213ab47719862ab1df1dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 15 Nov 2021 21:48:20 +0100 Subject: [PATCH] use one buffer for both compiled code and data --- include/fh_config.h | 4 +++- include/fh_mem.h | 20 ++++++++++-------- include/fh_runtime.h | 19 +++++++++++------- src/fh_builtins.c | 48 ++++++++++++++++++++++---------------------- src/fh_mem.c | 48 +++++--------------------------------------- src/fh_runtime.c | 28 +++++++++++++------------- src/main.c | 4 ++-- 7 files changed, 72 insertions(+), 99 deletions(-) diff --git a/include/fh_config.h b/include/fh_config.h index c24b488..723ffd3 100644 --- a/include/fh_config.h +++ b/include/fh_config.h @@ -12,9 +12,11 @@ #define RETURN_STACK_DEPTH 1024 #define MAX_NAME_LEN 32 #define DICT_SIZE 1024 -#define COMPILED_BUFFER_SIZE (1024*1024) #define HEAP_SIZE (1024*1024) #define MAXLINE 65535 +#define PAD_SIZE 256 +#define WORDBUF_SIZE 128 +#define INPUT_BUFFER_SIZE 256 #define CELL 4 diff --git a/include/fh_mem.h b/include/fh_mem.h index 26a1938..2b25f18 100644 --- a/include/fh_mem.h +++ b/include/fh_mem.h @@ -24,14 +24,18 @@ enum fh_error fh_heap_reserve( ); void fh_heap_write(struct fh_thread_s *fh, uint32_t addr, const void *src, uint32_t len); enum fh_error fh_heap_put(struct fh_thread_s *fh, const void *src, uint32_t len); -void fh_heap_copy_from_compile(struct fh_thread_s *fh, uint32_t addr, uint32_t srcaddr, uint32_t len); +void fh_heap_copy(struct fh_thread_s *fh, uint32_t addr, uint32_t srcaddr, uint32_t len); -enum fh_error fh_compile_reserve( - struct fh_thread_s *fh, - size_t len, - uint32_t *addr -); -void fh_compile_write(struct fh_thread_s *fh, uint32_t addr, const void *src, uint32_t len); -enum fh_error fh_compile_put(struct fh_thread_s *fh, const void *src, uint32_t len); +static inline char *fh_str_at(struct fh_thread_s *fh, uint32_t addr) { + return (char *) &fh->heap[addr]; +} + +static inline struct fh_instruction_s *fh_instr_at(struct fh_thread_s *fh, uint32_t addr) { + return (void *) &fh->heap[addr]; +} + +static inline struct fh_word_s *fh_word_at(struct fh_thread_s *fh, uint32_t addr) { + return (struct fh_word_s *) &fh->heap[addr]; +} #endif //FORTH_FH_MEM_H diff --git a/include/fh_runtime.h b/include/fh_runtime.h index 6144cf7..2210d70 100644 --- a/include/fh_runtime.h +++ b/include/fh_runtime.h @@ -108,8 +108,7 @@ struct fh_word_s { word_exec_t handler; /** Indicates that this is a built-in instruction and not a word call */ bool builtin; - /** Indicates that this instruction should always be treated as interpreted, - * in practice this is only used for `;` */ + /** Indicates that this instruction should always be treated as interpreted */ bool immediate; /** Start address in case of user words, or param for builtins */ union { @@ -140,13 +139,10 @@ struct fh_thread_s { size_t return_stack_top; size_t return_stack_hwm; - /** Data heap */ + /** Data buffer used for everything */ uint8_t heap[HEAP_SIZE]; - size_t heap_top; // aka "HERE" + size_t here; - /** Compile buffer, used for both word data and literals */ - uint8_t compile[COMPILED_BUFFER_SIZE]; - size_t compile_top; /** Pointer into the compile buffer for execution */ uint32_t execptr; @@ -154,6 +150,15 @@ struct fh_thread_s { struct fh_word_s dict[DICT_SIZE]; uint32_t dict_top; + /** Pad buffer */ + uint8_t pad[PAD_SIZE]; + /** WORD and pictured output buffer */ + uint8_t wordbuf[WORDBUF_SIZE]; + + /** Input buffer */ + uint8_t inbuf[INPUT_BUFFER_SIZE]; + uint32_t inbuf_ptr; + /** Forth state */ enum fh_state state; diff --git a/src/fh_builtins.c b/src/fh_builtins.c index 8cd80b7..147a648 100644 --- a/src/fh_builtins.c +++ b/src/fh_builtins.c @@ -368,7 +368,7 @@ static enum fh_error w_colon(struct fh_thread_s *fh, const struct fh_word_s *w) } struct fh_word_s *new_word = &fh->dict[fh->dict_top]; new_word->index = fh->dict_top; - new_word->start = fh->compile_top; + new_word->start = fh->here; new_word->handler = w_user_word; return FH_OK; @@ -409,7 +409,7 @@ static enum fh_error w_literal(struct fh_thread_s *fh, const struct fh_word_s *w uint32_t val; TRY(ds_pop(fh, &val)); instr_init(&instr, FH_INSTR_NUMBER, val); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); return FH_OK; } @@ -423,7 +423,7 @@ static enum fh_error w_semicolon(struct fh_thread_s *fh, const struct fh_word_s ENSURE_STATE(FH_STATE_COMPILE); instr_init(&instr, FH_INSTR_ENDWORD, 0); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); /* Return to interpret state */ fh_setstate(fh, FH_STATE_INTERPRET, 0); @@ -472,7 +472,7 @@ static enum fh_error w_recurse(struct fh_thread_s *fh, const struct fh_word_s *w ENSURE_STATE(FH_STATE_COMPILE); instr_init(&instr, FH_INSTR_WORD, fh->dict_top); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); return FH_OK; } @@ -724,7 +724,7 @@ static enum fh_error w_type(struct fh_thread_s *fh, const struct fh_word_s *w) TRY(ds_pop(fh, &count)); TRY(ds_pop(fh, &addr)); - FHPRINT("%.*s", count, &fh->heap[addr]); + FHPRINT("%.*s", count, fh_str_at(fh, addr)); return FH_OK; } @@ -850,9 +850,9 @@ static enum fh_error w_if(struct fh_thread_s *fh, const struct fh_word_s *w) ENSURE_STATE(FH_STATE_COMPILE); - TRY(cs_push(fh, fh->compile_top)); + TRY(cs_push(fh, fh->here)); instr_init(&instr, FH_INSTR_JUMPZERO, MAGICADDR_UNRESOLVED); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); return FH_OK; } @@ -866,17 +866,17 @@ static enum fh_error w_else(struct fh_thread_s *fh, const struct fh_word_s *w) uint32_t ifaddr = 0; TRY(cs_pop(fh, &ifaddr)); - struct fh_instruction_s *if_instr = (void *) &fh->compile[ifaddr]; + struct fh_instruction_s *if_instr = fh_instr_at(fh, ifaddr); if (if_instr->data != MAGICADDR_UNRESOLVED) { LOGE("IF-ELSE control stack corruption"); return FH_ERR_INTERNAL; } - if_instr->data = fh->compile_top + INSTR_SIZE; + if_instr->data = fh->here + INSTR_SIZE; - TRY(cs_push(fh, fh->compile_top)); + TRY(cs_push(fh, fh->here)); instr_init(&instr, FH_INSTR_JUMP, MAGICADDR_UNRESOLVED); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); return FH_OK; } @@ -889,13 +889,13 @@ static enum fh_error w_then(struct fh_thread_s *fh, const struct fh_word_s *w) uint32_t ifaddr = 0; TRY(cs_pop(fh, &ifaddr)); - struct fh_instruction_s *if_instr = (void *) &fh->compile[ifaddr]; + struct fh_instruction_s *if_instr = fh_instr_at(fh, ifaddr); if (if_instr->data != MAGICADDR_UNRESOLVED) { LOGE("IF-ELSE control stack corruption"); return FH_ERR_INTERNAL; } - if_instr->data = fh->compile_top; + if_instr->data = fh->here; return FH_OK; } @@ -911,7 +911,7 @@ static enum fh_error w_until(struct fh_thread_s *fh, const struct fh_word_s *w) TRY(cs_pop(fh, &destaddr)); instr_init(&instr, FH_INSTR_JUMPZERO, destaddr); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); return FH_OK; } @@ -920,7 +920,7 @@ static enum fh_error w_begin(struct fh_thread_s *fh, const struct fh_word_s *w) (void) w; enum fh_error rv; ENSURE_STATE(FH_STATE_COMPILE); - TRY(cs_push(fh, fh->compile_top)); /* dest */ + TRY(cs_push(fh, fh->here)); /* dest */ return FH_OK; } @@ -935,11 +935,11 @@ static enum fh_error w_while(struct fh_thread_s *fh, const struct fh_word_s *w) uint32_t destaddr = 0; TRY(cs_pop(fh, &destaddr)); - TRY(cs_push(fh, fh->compile_top)); // orig + TRY(cs_push(fh, fh->here)); // orig TRY(cs_push(fh, destaddr)); // dest instr_init(&instr, FH_INSTR_JUMPZERO, MAGICADDR_UNRESOLVED); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); return FH_OK; } @@ -956,15 +956,15 @@ static enum fh_error w_repeat(struct fh_thread_s *fh, const struct fh_word_s *w) TRY(cs_pop(fh, &destaddr)); TRY(cs_pop(fh, &origaddr)); - struct fh_instruction_s *branch_instr = (void *) &fh->compile[origaddr]; + struct fh_instruction_s *branch_instr = fh_instr_at(fh, origaddr); if (branch_instr->data != MAGICADDR_UNRESOLVED) { LOGE("REPEAT control stack corruption"); return FH_ERR_INTERNAL; } - branch_instr->data = fh->compile_top + INSTR_SIZE; + branch_instr->data = fh->here + INSTR_SIZE; instr_init(&instr, FH_INSTR_JUMP, destaddr); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); return FH_OK; } @@ -981,7 +981,7 @@ static enum fh_error w_again(struct fh_thread_s *fh, const struct fh_word_s *w) TRY(cs_pop(fh, &destaddr)); instr_init(&instr, FH_INSTR_JUMP, destaddr); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); return FH_OK; } @@ -1031,7 +1031,7 @@ static enum fh_error w_unused(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; - TRY(ds_push(fh, HEAP_SIZE - fh->heap_top)); + TRY(ds_push(fh, HEAP_SIZE - fh->here)); return FH_OK; } @@ -1126,7 +1126,7 @@ static enum fh_error w_comma(struct fh_thread_s *fh, const struct fh_word_s *w) (void) w; enum fh_error rv; - if (fh->heap_top & 3) { + if (fh->here & 3) { LOGE("HERE not aligned before 'comma'"); return FH_ERR_ILLEGAL_STORE; } @@ -1141,7 +1141,7 @@ static enum fh_error w_align(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; - fh->heap_top = WORDALIGNED(fh->heap_top); + fh->here = WORDALIGNED(fh->here); return FH_OK; } diff --git a/src/fh_mem.c b/src/fh_mem.c index a0ebeae..02a1476 100644 --- a/src/fh_mem.c +++ b/src/fh_mem.c @@ -18,7 +18,7 @@ enum fh_error fh_fetch(struct fh_thread_s *fh, uint32_t addr, uint32_t *dst) break; case MAGICADDR_HERE: - *dst = fh->heap_top; + *dst = fh->here; break; default: @@ -95,7 +95,7 @@ enum fh_error fh_heap_reserve( uint32_t *addr ) { - uint32_t p = fh->heap_top; + uint32_t p = fh->here; if (p + len > HEAP_SIZE) { return FH_ERR_HEAP_FULL; @@ -105,7 +105,7 @@ enum fh_error fh_heap_reserve( *addr = p; } - fh->heap_top = WORDALIGNED(p + len); + fh->here = WORDALIGNED(p + len); return FH_OK; } @@ -127,45 +127,7 @@ enum fh_error fh_heap_put(struct fh_thread_s *fh, const void *src, uint32_t len) } /** Copy bytes from compile area to heap. The region must have been previously allocated! */ -void fh_heap_copy_from_compile(struct fh_thread_s *fh, uint32_t addr, uint32_t srcaddr, uint32_t len) +void fh_heap_copy(struct fh_thread_s *fh, uint32_t addr, uint32_t srcaddr, uint32_t len) { - memcpy(&fh->heap[addr], &fh->compile[srcaddr], len); -} - -/** Reserve space in the compile memory area */ -enum fh_error fh_compile_reserve( - struct fh_thread_s *fh, - size_t len, - uint32_t *addr -) -{ - uint32_t p = fh->compile_top; // FIXME this shouldn't be needed - - if (p + len > COMPILED_BUFFER_SIZE) { - return FH_ERR_HEAP_FULL; - } - - if (addr) { - *addr = p; - } - - fh->compile_top = WORDALIGNED(p + len); - - return FH_OK; -} - -/** Write bytes to compile area at a given location. The region must have been previously allocated! */ -void fh_compile_write(struct fh_thread_s *fh, uint32_t addr, const void *src, uint32_t len) -{ - memcpy(&fh->compile[addr], src, len); -} - -/** Allocate compile region and write bytes to it */ -enum fh_error fh_compile_put(struct fh_thread_s *fh, const void *src, uint32_t len) -{ - enum fh_error rv; - uint32_t addr; - TRY(fh_compile_reserve(fh, len, &addr)); - fh_compile_write(fh, addr, src, len); - return FH_OK; + memcpy(&fh->heap[addr], &fh->heap[srcaddr], len); } diff --git a/src/fh_runtime.c b/src/fh_runtime.c index 004a17e..db662f1 100644 --- a/src/fh_runtime.c +++ b/src/fh_runtime.c @@ -93,7 +93,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) } // make sure it's aligned fh->execptr = WORDALIGNED(fh->execptr); - const struct fh_instruction_s *instr = (const struct fh_instruction_s *) &fh->compile[fh->execptr]; + const struct fh_instruction_s *instr = fh_instr_at(fh, fh->execptr); fh->execptr += INSTR_SIZE; uint32_t strl; @@ -115,7 +115,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) } else { LOG("Add postponed word: %s", w2->name); instr_init(&instr2, FH_INSTR_WORD, instr->data); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); } } else { LOGE("Postpone in interpret mode!"); @@ -169,13 +169,13 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) strl = instr->data; if (instr->kind == FH_INSTR_ALLOCSTR) { TRY(fh_heap_reserve(fh, strl, &addr)); - fh_heap_copy_from_compile(fh, addr, fh->execptr, strl); - LOG("Exec: alloc-str \"%.*s\"", strl, &fh->heap[addr]); + LOG("Exec: alloc-str \"%.*s\"", strl, fh_str_at(fh, fh->execptr)); + fh_heap_copy(fh, addr, fh->execptr, strl); TRY(ds_push(fh, addr)); TRY(ds_push(fh, strl)); } else { - LOG("Exec: type-str \"%.*s\"", strl, &fh->compile[fh->execptr]); - FHPRINT("%.*s", (int) strl, &fh->compile[fh->execptr]); + LOG("Exec: type-str \"%.*s\"", strl, fh_str_at(fh, fh->execptr)); + FHPRINT("%.*s", (int) strl, fh_str_at(fh, fh->execptr)); } fh->execptr += strl; goto instr; @@ -242,8 +242,8 @@ static enum fh_error fh_handle_quoted_string( } else { instr_init(&instr, FH_INSTR_TYPESTR, len); } - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); - TRY(fh_compile_put(fh, start, len)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, start, len)); } return FH_OK; } @@ -255,7 +255,7 @@ enum fh_error fh_handle_word(struct fh_thread_s *fh, const struct fh_word_s *w) if (fh->state == FH_STATE_COMPILE && !w->immediate) { LOG("Compile word call: %s", w->name); instr_init(&instr, FH_INSTR_WORD, w->index); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); } else { /* interpret or immediate in compiled code */ LOG("Run word: %s", w->name); @@ -324,7 +324,7 @@ enum fh_error fh_handle_ascii_word( if (fh->state == FH_STATE_COMPILE) { LOG("Compile number: %ld", v); instr_init(&instr, FH_INSTR_NUMBER, (uint32_t) v); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); } else { /* interpret */ LOG("Interpret number: %ld", v); @@ -343,7 +343,7 @@ static void show_word(struct fh_thread_s *fh, const struct fh_word_s *w) // make sure it's aligned execptr = WORDALIGNED(execptr); FHPRINT("0x%08x: ", execptr); - const struct fh_instruction_s *instr = (const struct fh_instruction_s *) &fh->compile[execptr]; + const struct fh_instruction_s *instr = fh_instr_at(fh, execptr); execptr += INSTR_SIZE; uint32_t strl; @@ -385,10 +385,10 @@ static void show_word(struct fh_thread_s *fh, const struct fh_word_s *w) case FH_INSTR_TYPESTR: strl = instr->data; if (instr->kind == FH_INSTR_ALLOCSTR) { - FHPRINT("AllocStr(\"%.*s\")\n", strl, &fh->compile[execptr]); + FHPRINT("AllocStr(\"%.*s\")\n", strl, fh_str_at(fh, execptr)); execptr += strl; } else { - FHPRINT("PrintStr(\"%.*s\")\n", strl, &fh->compile[execptr]); + FHPRINT("PrintStr(\"%.*s\")\n", strl, fh_str_at(fh, execptr)); execptr += strl; } goto instr; @@ -434,7 +434,7 @@ static enum fh_error fh_postpone_word( struct fh_instruction_s instr; LOG("Postpone %s", w->name); instr_init(&instr, FH_INSTR_POSTPONED_WORD, w->index); - TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); return FH_OK; } diff --git a/src/main.c b/src/main.c index d6278e0..621236d 100644 --- a/src/main.c +++ b/src/main.c @@ -84,9 +84,9 @@ int main(int argc, char *argv[]) } // Show resource usage - LOG("\nResources used: DS %dW, RS %dW, CS %dW, heap %dB, program %dB, dict %dx\n", + LOG("\nResources used: DS %dW, RS %dW, CS %dW, memory %dB\n", (int) fh.data_stack_hwm, (int) fh.return_stack_hwm, (int) fh.control_stack_hwm, - (int) fh.heap_top, (int) fh.compile_top, (int) fh.dict_top); + (int) fh.here); FHPRINT_SVC("Bye.\n"); return 0;