0 value opcode-jumptable-end 0 value opcode-jumptable \ vm helpers : find-instruction-by-opcode cells opcode-jumptable + dup opcode-jumptable-end >= if ." illegal opcode" cr abort then @ ; stack-index-start value stack-index rstack-index-start value rstack-index 0 value pc-index 0 value here-index true value cpu-running 0 value cycles 0 value postponed-instruction : .w dup $7fff > if $10000 - then . ; : dump-stack-impl 2dup = if 2drop ." empty" else 2dup ." { " swap - 2 / . ." } " 2 - do i read-word .w -2 +loop then ; : dump-stack stack-index stack-index-start dump-stack-impl ; : dump-rstack rstack-index rstack-index-start dump-stack-impl ; : flush-stack stack-index-start to stack-index ; : flush-rstack rstack-index-start to rstack-index ; : >stack stack-index data-index <= if ." stack overflow" abort then stack-index 2 - to stack-index stack-index write-word ; : stack> stack-index stack-index-start >= if ." stack underflow" abort then stack-index read-word stack-index 2 + to stack-index dup $7fff > if $10000 - then ; : >rstack rstack-index stack-index-start <= if ." rstack overflow" abort then rstack-index 2 - to rstack-index rstack-index write-word ; : rstack> rstack-index rstack-index-start >= if ." rstack underflow" abort then rstack-index read-word rstack-index 2 + to rstack-index ; : pc-index+1 pc-index 1+ to pc-index ; : pc-index+2 pc-index 2 + to pc-index ; \ implementation of the virtual machine instructions : v-lit pc-index read-word >stack pc-index+2 ; : v-@ stack> read-word >stack ; : v-c@ stack> read-byte >stack ; : v-! stack> stack> swap write-word ; : v-c! stack> stack> swap write-byte ; : v-r> rstack> >stack ; : v->r stack> >rstack ; : v-@r rstack> dup >rstack >stack ; : v-dup stack> dup >stack >stack ; : v-swap stack> stack> swap >stack >stack ; : v-drop stack> drop ; : v-over stack> stack> dup >stack swap >stack >stack ; : v-here here-index >stack ; : v-allot stack> here-index + to here-index ; : v-jz stack> 0= if pc-index read-word to pc-index else pc-index+2 then ; : v-jnz stack> 0<> if pc-index read-word to pc-index else pc-index+2 then ; : v-jump pc-index read-word to pc-index ; : v-call pc-index 2 + >rstack pc-index read-word to pc-index ; : v-pop-call pc-index >rstack stack> to pc-index ; : v-ret rstack-index rstack-index-start = if false to cpu-running else rstack> to pc-index then ; : v-+ stack> stack> + >stack ; : v-- stack> stack> swap - >stack ; : v-1+ stack> 1+ >stack ; : v-1- stack> 1- >stack ; : v-* stack> stack> swap * >stack ; : v-/ stack> stack> swap / >stack ; : v-negate stack> negate >stack ; : v-lshift stack> stack> swap lshift >stack ; : v-rshift stack> stack> swap rshift >stack ; : v-invert stack> invert >stack ; : v-and stack> stack> and >stack ; : v-or stack> stack> or >stack ; : v-= stack> stack> = >stack ; : v-< stack> stack> > >stack ; : v-> stack> stack> < >stack ; : v-execute stack> find-instruction-by-opcode to postponed-instruction ; : v-emit stack> emit ; : v-stop false to cpu-running ; : v-. stack> .w ; \ virtual machine instructions here to opcode-jumptable \ stack/memory operations ' v-lit , ' v-@ , ' v-c@ , ' v-! , ' v-c! , ' v-r> , ' v->r , ' v-@r , ' v-dup , ' v-swap , ' v-drop , ' v-over , ' v-here , ' v-allot , \ control flow ' v-jz , ' v-jnz , ' v-jump , ' v-call , ' v-pop-call , ' v-ret , \ arithmetic ' v-+ , ' v-- , ' v-1+ , ' v-1- , ' v-* , ' v-/ , ' v-negate , ' v-lshift , ' v-rshift , \ bit operations ' v-invert , ' v-and , ' v-or , \ compare operations ' v-= , ' v-< , ' v-> , \ I/O and special instructions ' v-execute , ' v-emit , ' v-stop , ' v-. , here to opcode-jumptable-end \ \ simulator \ : c true to cpu-running 0 to postponed-instruction begin cpu-running invert if exit then cycles 10000 > if s" cycle limit reached, start 'c' for continue" type exit then cycles 1+ to cycles postponed-instruction dup if 0 to postponed-instruction execute else drop pc-index read-byte find-instruction-by-opcode pc-index+1 execute then again ; : vm ( vm-address -- ) to pc-index 0 to cycles c ; s" :data-start" search-label drop @ to here-index : scopy ( addr count -- v-stack: simulated-addr count ) locals| word-count word-start | word-count here-index write-byte here-index 1+ dup word-count + dup to here-index over 2dup <> if do word-start c@ i write-byte word-start 1+ to word-start loop else 2drop then >stack word-count >stack ; : skip-input ( count -- ) >in @ + >in ! ; : unparsed-source ( -- addr u ) source >in @ /string ; : read-unparsed-string ( -- addr u ) unparsed-source dup skip-input ; : get-vm-evaluate-address ( -- vm-addr ) s" :evaluate-code" search-label drop @ ; : eval-string ( addr u -- ) scopy get-vm-evaluate-address vm ; : eval ( -- ) read-unparsed-string eval-string dump-stack ;