/** * Forth runtime internals * * Created on 2021/11/13. */ #ifndef FORTH_FH_RUNTIME_H #define FORTH_FH_RUNTIME_H #include #include #include #include #include "fh_config.h" struct fh_word_s; struct fh_instruction_s; struct fh_thread_s; /** Word handler typedef */ typedef enum fh_error (*word_exec_t)(struct fh_thread_s *fh, const struct fh_word_s *w); /** Bytecode instruction type marker */ enum fb_instruction_kind { /* Data = word pointer (dict index) */ FH_INSTR_WORD, /* Data = numeric value to push onto the data stack */ FH_INSTR_NUMBER, }; /** Bytecode word indices that are not in the dict, have special effect */ enum compiler_word { /** End of a user defined word, pop address and jump back */ CPLWORD_ENDWORD = DICT_SIZE + 1, /** This is the `s"` instruction, the length (u32) and string data immediately follow */ CPLWORD_ALLOCSTR, /** This is the `."` instruction, same format as above. */ CPLWORD_TYPESTR, }; /** One instruction in bytecode */ struct fh_instruction_s { /** What is the meaning of data? */ enum fb_instruction_kind kind; /** Data word */ uint32_t data; }; static inline void instr_init(struct fh_instruction_s *instr, enum fb_instruction_kind kind, uint32_t data) { instr->kind = kind; instr->data = data; } #define INSTR_SIZE (sizeof(struct fh_instruction_s)) _Static_assert(sizeof(struct fh_instruction_s) % 4 == 0, "Instruction struct is aligned"); /** Forth runtime major state */ enum fh_state { FH_STATE_INTERPRET = 0, FH_STATE_COMPILE, FH_STATE_QUIT, FH_STATE_SHUTDOWN, FH_STATE_MAX, }; /** Forth runtime minor state */ enum fh_substate { FH_SUBSTATE_NONE = 0, FH_SUBSTATE_COLONNAME, FH_SUBSTATE_SQUOTE, FH_SUBSTATE_DOTQUOTE, FH_SUBSTATE_PARENCOMMENT, FH_SUBSTATE_LINECOMMENT, FH_SUBSTATE_MAX, }; /** Word struct as they are stored in the dictionary */ struct fh_word_s { /** Word name */ char name[MAX_NAME_LEN]; /** * Handler function. * Builtin functions use pre-defined native handlers. * User words use a shared handler that executes compiled * bytecode at 'start' address of the compile-memory area. */ 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 `;` */ bool immediate; /** Start address in case of user words, or param for builtins */ union { uint32_t start; uint32_t param; }; }; /** * Forth runtime instance - state variables and memory areas. * * Some memory areas, such as the dict or heap, could be moved * to a shared pointer if multi-threading and synchronization is added. */ struct fh_thread_s { /** Control stack */ uint32_t control_stack[CONTROL_STACK_DEPTH]; size_t control_stack_top; size_t control_stack_hwm; /** Data stack */ uint32_t data_stack[DATA_STACK_DEPTH]; size_t data_stack_top; size_t data_stack_hwm; /** Return stack */ uint32_t return_stack[RETURN_STACK_DEPTH]; size_t return_stack_top; size_t return_stack_hwm; /** Data heap */ uint8_t heap[HEAP_SIZE]; size_t heap_top; /** 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; /** Word dict */ struct fh_word_s dict[DICT_SIZE]; uint32_t dict_top; /** Forth state */ enum fh_state state; /** Forth sub-state */ enum fh_substate substate; /** The numeric base register */ uint32_t base; }; enum fh_error fh_add_word(const struct fh_word_s *w, struct fh_thread_s *fh); void fh_setstate(struct fh_thread_s *fh, enum fh_state state, enum fh_substate substate); void fh_setsubstate(struct fh_thread_s *fh, enum fh_substate substate); enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w); /* if the return address is this, we should drop back to interactive mode */ // SFR and magic addresses are "negative" #define MAGICADDR_INTERACTIVE 0xFFFFFFFFULL #define MAGICADDR_BASE 0xFFFBA5EFULL /** Get a value rounded up to multiple of word size */ #define WORDALIGNED(var) (((var) + 3) & ~3) _Static_assert(WORDALIGNED(0) == 0, "word align"); _Static_assert(WORDALIGNED(1) == 4, "word align"); _Static_assert(WORDALIGNED(2) == 4, "word align"); _Static_assert(WORDALIGNED(3) == 4, "word align"); _Static_assert(WORDALIGNED(4) == 4, "word align"); _Static_assert(WORDALIGNED(5) == 8, "word align"); _Static_assert(WORDALIGNED(1023) == 1024, "word align"); _Static_assert(WORDALIGNED(1024) == 1024, "word align"); #define TRY(x) \ do { \ if (FH_OK != (rv = (x))) return rv; \ } while (0) #endif //FORTH_FH_RUNTIME_H