provide scaf-execute # support module for scaf (simple cellular automaton forth) # scaf is implemented as a small forth which executes # 1-bit logic operations. yet another vm.. # the virtual machine is a SIMD machine, effectively working # on bits in parallel using the native machine word size. # the binary object implements the vm and provides some # basic functionality (lookup, link, execute, comma). # this script implements the rest of the compiler "scaf.pfo" pfo # the symbol table to map symbol to scafxt scaf-boot-kernel variable! scaf-symbol-table : scaf-find scaf-symbol-table @find @ ; : scaf-compile scaf-comma ; # compile an xt : scaf-literal # compile a literal ` lit scaf-find scaf-compile >int scaf-comma ; # convert to int before compileing # interpreter. compilation only # this is a bit of a hack: need to figure out the exact # meaning of target interpret/compile states for macros # and such.. (compilation is not done by target, so true # immediate words are out of the question) : scaf-leave ` leave scaf-find scaf-compile runwind ; # leave scaf-interpreter loop : scaf-symbol ` ; route scaf-leave # leave interpeter try scaf-find scaf-compile # try to compile target xt recover drop find execute endtry ; # try to execute host word (macro) : scaf-interpret type ` int = if scaf-literal leave then type ` symbol = if scaf-symbol leave then drop runwind e_type throw ; : scaf-interpreter rwind begin read scaf-interpret again ; : :scaf scaf-here read 2 pack # get cfa (xt) and symbol scaf-symbol-table push # add to symbol table scaf-enter-comma # compile 'enter' codefield scaf-interpreter ;; # start interpreter # anonymous function : ::scaf scaf-here scaf-enter-comma scaf-interpreter ; # in pf, the compilation semantics is implemented with a word that # has a ( xt -- ) stack effect. the default is ',' # this brings us to the following compile semantics for a scafxt : scaf-host>target xt>body follow @ ; # convert wrapper xt to target xt # a target word has the following execution semantics on the host # : word # scaf-execute ; # this word generates such a wrapper : scaf-link-wrapper link enter, postpone literal # compile scaf xt postpone do-pass # tail call postpone scaf-execute # pass to xt ; "( scafxt symbol -- )\tCreates a scaf xt wrapper word." , # wrap a scaf word in a pf word : scaf-wrap read dup scaf-find swap scaf-link-wrapper ; # enter scaf namespace variable scaf-saved-: : defer-xt@ xt>body @ ; : scaf-begin ['] : defer-xt@ scaf-saved-: ! ['] :scaf [is] : ; : scaf-end scaf-saved-: @ [is] : ; # scaf words in pf behave as ( bitgrid -- bitgrid ) # the bit generators behave as ( -- bit ) # so the write is implicit in the vm, the read is explicit # the vm runs the bit generators for each bit in the grid # and stores the item on TOS to the destination grid # the input grid can be accessed through the 'read' # primitive. this reads from current point. initial point # is center, and the words 'up', 'down', 'left', 'right' # can be used. turtle bit graphics. # the machine's runtime memory layout is: # 0x00: free memory # 0x10: topx of DS # 0x18: topx of RS # this memory is present on the c stack in the main # interpreter function. # stacks grow downward # the first couple of words can be used for state storage # we use this for a (parallel) bit counter # note that the DS/RS and memory have a cell size = the machine word # this can cointain integers, pointers, and bits. # a bit is actually a bit vector. operations are in parallel. (see adder) scaf-begin # ( bit -- ) Add bit to 4bit counter, drop carry. # uses the half-adder @+ ( bit var -- carry ) # this is included in the kernel now. much faster. # : c+ 0 @+ 1 @+ 2 @+ 3 @+ drop ; # ( -- ) Reset counter : 0c! 0 0 ! 0 1 ! 0 2 ! 0 3 ! ; # ( -- bit ) move point and read : up> up read ; : down> down read ; : left> left read ; : right> right read ; : center> center read ; # count neighbours (excluding center) # using the internal 4bit counter : count-neighbours center 0c! up> c+ right> c+ down> c+ down> c+ left> c+ left> c+ up> c+ up> c+ ; # tests for counter state : count=2or3? # 001x 1 @ 2 @ not and 3 @ not and ; : count=3? # 0011 count=2or3? 0 @ and ; # alive: 2 or 3 neighbours -> survival # dead: 3 neighbours -> birth : game-of-life count-neighbours count=2or3? >r center> r and # alive + 2or3 -> alive r> 0 @ and or ; # 3 -> alive scaf-end