diff --git a/include/fh_error.h b/include/fh_error.h index c1c947e..755fc6f 100644 --- a/include/fh_error.h +++ b/include/fh_error.h @@ -24,6 +24,7 @@ enum fh_error { FH_ERR_INTERNAL, FH_ERR_UNKNOWN_WORD, FH_ERR_ILLEGAL_FETCH, + FH_ERR_ILLEGAL_STORE, FH_ERR_DIV_BY_ZERO, FH_ERR_MAX, }; diff --git a/include/fh_runtime.h b/include/fh_runtime.h index eb79313..d5e6e0a 100644 --- a/include/fh_runtime.h +++ b/include/fh_runtime.h @@ -141,7 +141,7 @@ struct fh_thread_s { /** Data heap */ uint8_t heap[HEAP_SIZE]; - size_t heap_top; + size_t heap_top; // aka "HERE" /** Compile buffer, used for both word data and literals */ uint8_t compile[COMPILED_BUFFER_SIZE]; @@ -175,6 +175,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w); // SFR and magic addresses are "negative" #define MAGICADDR_INTERACTIVE 0xFFFFFFFFULL #define MAGICADDR_BASE 0xFFFFBA5EULL +#define MAGICADDR_HERE 0xFFFF4E7EULL #define MAGICADDR_UNRESOLVED 0xFFFFFBADULL /** Get a value rounded up to multiple of word size */ diff --git a/src/fh_builtins.c b/src/fh_builtins.c index f967f3e..5fc9650 100644 --- a/src/fh_builtins.c +++ b/src/fh_builtins.c @@ -99,6 +99,39 @@ static enum fh_error w_star(struct fh_thread_s *fh, const struct fh_word_s *w) return FH_OK; } +static enum fh_error w_and(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint32_t a = 0, b = 0; + TRY(ds_pop(fh, &a)); + TRY(ds_pop(fh, &b)); + TRY(ds_push(fh, a & b)); + return FH_OK; +} + +static enum fh_error w_or(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint32_t a = 0, b = 0; + TRY(ds_pop(fh, &a)); + TRY(ds_pop(fh, &b)); + TRY(ds_push(fh, a | b)); + return FH_OK; +} + +static enum fh_error w_xor(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint32_t a = 0, b = 0; + TRY(ds_pop(fh, &a)); + TRY(ds_pop(fh, &b)); + TRY(ds_push(fh, a ^ b)); + return FH_OK; +} + static enum fh_error w_zero_less(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; @@ -268,6 +301,41 @@ static enum fh_error w_slash(struct fh_thread_s *fh, const struct fh_word_s *w) return FH_OK; } +static enum fh_error w_abs(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint32_t a = 0; + TRY(ds_pop(fh, &a)); + + int32_t sa = (int32_t) a; // TODO is this right? + + if (sa < 0) { sa = -sa; } + + TRY(ds_push(fh, sa)); + return FH_OK; +} + +static enum fh_error w_invert(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint32_t a = 0; + TRY(ds_pop(fh, &a)); + TRY(ds_push(fh, ~a)); + return FH_OK; +} + +static enum fh_error w_negate(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint32_t a = 0; + TRY(ds_pop(fh, &a)); + TRY(ds_push(fh, (uint32_t) (-(uint32_t) a))); + return FH_OK; +} + static enum fh_error w_slash_mod(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; @@ -863,6 +931,23 @@ static enum fh_error w_repeat(struct fh_thread_s *fh, const struct fh_word_s *w) return FH_OK; } +static enum fh_error w_again(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + struct fh_instruction_s instr; + + ENSURE_STATE(FH_STATE_COMPILE); + + uint32_t destaddr = 0; + TRY(cs_pop(fh, &destaddr)); + + instr_init(&instr, FH_INSTR_JUMP, destaddr); + TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); + + return FH_OK; +} + static enum fh_error wp_setbase(struct fh_thread_s *fh, const struct fh_word_s *w) { fh_setbase(fh, w->param); @@ -980,6 +1065,40 @@ static enum fh_error w_aligned(struct fh_thread_s *fh, const struct fh_word_s *w return FH_OK; } +static enum fh_error w_allot(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint32_t count = 0; + TRY(ds_pop(fh, &count)); + TRY(fh_heap_reserve(fh, count, NULL)); + return FH_OK; +} + +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) { + LOGE("HERE not aligned before 'comma'"); + return FH_ERR_ILLEGAL_STORE; + } + + uint32_t value = 0; + TRY(ds_pop(fh, &value)); + TRY(fh_heap_put(fh, &value, CELL)); + return FH_OK; +} + +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); + return FH_OK; +} + /** Add pointers to built-in word handlers to a runtime struct */ enum fh_error register_builtin_words(struct fh_thread_s *fh) { @@ -1002,6 +1121,9 @@ enum fh_error register_builtin_words(struct fh_thread_s *fh) {"2!", w_two_store, 0, 0}, {"2@", w_two_fetch, 0, 0}, {"aligned", w_aligned, 0, 0}, + {"allot", w_allot, 0, 0}, + {"align", w_align, 0, 0}, + {",", w_comma, 0, 0}, // TODO +! // TODO pictured numbers (#) // TODO tick @@ -1011,16 +1133,22 @@ enum fh_error register_builtin_words(struct fh_thread_s *fh) {"decimal", wp_setbase, 0, 10}, {"hex", wp_setbase, 0, 16}, {"base", wp_const, 0, MAGICADDR_BASE}, + {"here", wp_const, 0, MAGICADDR_HERE}, {"false", wp_const, 0, 0}, {"true", wp_const, 0, 0xFFFFFFFF}, - {"depth", w_depth, 0, 0}, {"+", w_plus, 0, 0}, {"-", w_minus, 0, 0}, {"*", w_star, 0, 0}, {"*/", w_star_slash, 0, 0}, {"*/mod", w_star_slash_mod, 0, 0}, + {"or", w_or, 0, 0}, + {"and", w_and, 0, 0}, + {"xor", w_xor, 0, 0}, {"/", w_slash, 0, 0}, + {"abs", w_abs, 0, 0}, {"/mod", w_slash_mod, 0, 0}, + {"invert", w_invert, 0, 0}, + {"negate", w_negate, 0, 0}, {"0<", w_zero_less, 0, 0}, {"0=", w_zero_equals, 0, 0}, {"0<>", w_zero_not_equals, 0, 0}, @@ -1042,8 +1170,8 @@ enum fh_error register_builtin_words(struct fh_thread_s *fh) /* Stack manip */ {"drop", w_drop, 0, 0}, {"dup", w_dupe, 0, 0}, - {"nip", w_nip, 0, 0}, {"?dup", w_question_dupe, 0, 0}, + {"nip", w_nip, 0, 0}, {"over", w_over, 0, 0}, {"swap", w_swap, 0, 0}, {"rot", w_rot, 0, 0}, @@ -1082,6 +1210,7 @@ enum fh_error register_builtin_words(struct fh_thread_s *fh) {"begin", w_begin, 1, 0}, {"while", w_while, 1, 0}, {"repeat", w_repeat, 1, 0}, + {"again", w_again, 1, 0}, {"until", w_until, 1, 0}, /* Syntax */ {":", w_colon, 0, 0}, diff --git a/src/fh_error.c b/src/fh_error.c index f0d7ae3..bf065c7 100644 --- a/src/fh_error.c +++ b/src/fh_error.c @@ -17,6 +17,7 @@ static const char *errornames[FH_ERR_MAX] = { [FH_ERR_INTERNAL] = "INTERNAL", [FH_ERR_UNKNOWN_WORD] = "UNKNOWN_WORD", [FH_ERR_ILLEGAL_FETCH] = "ILLEGAL_FETCH", + [FH_ERR_ILLEGAL_STORE] = "ILLEGAL_STORE", [FH_ERR_DIV_BY_ZERO] = "DIV_BY_ZERO", }; diff --git a/src/fh_mem.c b/src/fh_mem.c index e2b4b76..a0ebeae 100644 --- a/src/fh_mem.c +++ b/src/fh_mem.c @@ -16,7 +16,10 @@ enum fh_error fh_fetch(struct fh_thread_s *fh, uint32_t addr, uint32_t *dst) case MAGICADDR_BASE: *dst = fh->base; break; - // TODO more magic + + case MAGICADDR_HERE: + *dst = fh->heap_top; + break; default: if (addr & 3) { @@ -52,18 +55,21 @@ enum fh_error fh_store(struct fh_thread_s *fh, uint32_t addr, uint32_t val) case MAGICADDR_BASE: fh_setbase(fh, val); break; - // TODO more magic + + case MAGICADDR_HERE: + LOGE("HERE is read-only!"); + return FH_ERR_ILLEGAL_STORE; default: if (addr & 3) { LOGE("Address 0x%08x is not aligned!", addr); - return FH_ERR_ILLEGAL_FETCH; + return FH_ERR_ILLEGAL_STORE; } if (addr <= HEAP_SIZE - 4) { *((uint32_t*)&fh->heap[addr]) = val; } else { LOGE("Address 0x%08x too high!", addr); - return FH_ERR_ILLEGAL_FETCH; + return FH_ERR_ILLEGAL_STORE; } } @@ -95,7 +101,9 @@ enum fh_error fh_heap_reserve( return FH_ERR_HEAP_FULL; } - *addr = p; + if (addr) { + *addr = p; + } fh->heap_top = WORDALIGNED(p + len); @@ -137,7 +145,9 @@ enum fh_error fh_compile_reserve( return FH_ERR_HEAP_FULL; } - *addr = p; + if (addr) { + *addr = p; + } fh->compile_top = WORDALIGNED(p + len);