introduction ------------ badnop is an experiment in tethered forth developement. instead of using standard tools, i've started from scratch. the reason is obvious: i'd like to understand the whole system, and the only way is to write it and keep it small. this project is an intermediate step in building a reasonably general purpose tool to interface microcontrollers to pure data through mole or packet forth. (see zwizwa.goto10.org). the basic idea is to be able to interact with a program on a microcontroller. this is mainly done using a host forth, written in C, which is used to implement a (native code) compiler for the target. the target language is currently an 8bit forth, optimized for speed and direct mapping to the hardware. this in turn can be used to implement a more general virtual 16bit machine later. all this is very experimental. i'm trying to find out if an 8bit forth is workable, or workaroundable if you so please. dictionaries ------------ there are 2 (virtual) dictionaries, mapping names to addresses. the semantics of the words depends on the last character in their name. this is a small syntactic extension used to avoid 'postpone'. (see the file MACROS) * host dict, contains references to host indirect threaded code ( codefield datafield ) host macros (ending in _) target macros (ending in ,) macro mode immediates (ending in %) target mode words (ending in #) misc host words (not ending in any of the above) * target dict, contains references to target native code in the target buffer. the dictionaries are virtual, meaning they are in one physicial dictionary, which enables us to redefine macros and words. i.e. : x ... ; followed by : x, ... ; replaces the word x by a macro. compiling a call to a non-existing macro compiles an auto- macro: i.e. if the word 'x' exists, and not the macro 'x_', and 'x_' is referred to in another macro definition, code is compiled that will compile a call to x, which is the same as the behaviour standard forth idom 'postpone x'. interpreter modes ----------------- the list below explains how WORD will be interpreted, depending on host/target/macro and interpret/compile states. (link mode is not implemented yet.) * host mode interpret: look up up literal word in host dict. if found, execute it, if not found, parse as number and load on stack. execute a remote call if WORD has extension & compile: if WORD_ exists in host dictionaray, execute it. (host macro) if WORD exists in host dictionary, compile it. (xt) compile a host automacro if WORD has extension _ compile a target automacro if WORD has extension , compile a remote call if WORD has extension & else compile a literal number. * target mode interpret: if WORD# exists in host dictionary, execute it execute a remote (target) word if WORD as extension& else fall back to host interpret. this enables host forth as macro processor for [ ] compile->interpret escapes. compile: if WORD, exists in host dictionary, execute it. (target macro) if WORD exists in target dictionary, compie it (native call/jmp) else compile a native literal number. * macro mode interpret: if WORD% exists in host dictionary, execute it else fall back to host interpret. compile: if WORD, exists in host dictionary, postpone it if WORD exists in target dictionary, postpone it else compile a postponed literal stc target forth architecture ----------------------------- the 18fxxx is a 8 bit data, 16 bit instruction architecture. since our main goal is speed, not code density (or ease of use :) we will not work around this difference by emulating a 16bit machine. this has several consequences: * data stack = 8bit, and needs special care to deal with addresses * user variables (@/!) are in access bank * forth stacks (data + aux) are bank 0, upper half * other banks are for buffers and indirect access using a reg interrupts ---------- most of the forth is interrupt safe, except for the FSR2 register, which is used to implement indirect addressing. local variables are allocated on the return stack (i.e. swap 2dup rot). the temp stack is interrupt safe. words that cannot be used in (fast) interrupt routines are: * non-literal @ ! * anything else modifying FSR2 (the a reg) host words ---------- .hex ( start endx -- ) dump target hex file _ ( cell -- ) add cell to host memory , ( cell -- ) add cell to (local) target memory target words ------------ standard semantics, 8 bit version: + - * and or xor @ ! +! -! optimization ------------ a lot of primitive target macros support peephole optimization. (dup drop) -> () (drop save) -> () save is dup followed by load to WREG (call return) -> (jump) tail call optimization (lit op) -> (litop) literal access (esp for @ and !)