/* tag: internal words, inner interpreter and such * * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ /* * execution works as follows: * - PC is pushed on return stack * - PC is set to new CFA * - address pointed by CFA is executed by CPU */ extern void * const words[]; ucell PC; volatile int runforth = 0; #ifdef FCOMPILER extern ucell *trampoline; #else /* instead of pointing to an explicit 0 variable we * point behind the pointer. */ static ucell t[] = { DOCOL, 0, (ucell)(t+3), 0 }; ucell *trampoline = t; #endif #ifndef CONFIG_DEBUG_INTERPRETER #define dbg_interp_printk( a... ) do { } while(0) #else #define dbg_interp_printk( a... ) printk( a ) #endif #ifndef CONFIG_DEBUG_INTERNAL #define dbg_internal_printk( a... ) do { } while(0) #else #define dbg_internal_printk( a... ) printk( a ) #endif static inline void processxt(ucell xt) { void (*tokenp) (void); dbg_interp_printk("processxt: pc=%x, xt=%x\n", PC, xt); tokenp = words[xt]; tokenp(); } static void docol(void) { /* DOCOL */ PUSHR(PC); PC = read_ucell(cell2pointer(PC)); dbg_interp_printk("docol: %s\n", cell2pointer( lfa2nfa(PC - sizeof(cell)) )); } static void semis(void) { PC = POPR(); } static inline void next(void) { PC += sizeof(ucell); dbg_interp_printk("next: PC is now %x\n", PC); processxt(read_ucell(cell2pointer(read_ucell(cell2pointer(PC))))); } int enterforth(xt_t xt) { ucell *_cfa = (ucell*)cell2pointer(xt); cell tmp; if (read_ucell(_cfa) != DOCOL ) { trampoline[1] = target_ucell(xt); _cfa = trampoline; } if (rstackcnt < 0) rstackcnt = 0; tmp = rstackcnt; runforth = 1; PUSHR(PC); PC = pointer2cell(_cfa); while (rstackcnt > tmp && runforth) { dbg_interp_printk("enterforth: NEXT\n"); next(); } #if 0 /* return true if we took an exception. The caller should normally * handle exceptions by returning immediately since the throw * is supposed to abort the execution of this C-code too. */ if( rstackcnt != tmp ) printk("EXCEPTION DETECTED!\n"); #endif return rstackcnt != tmp; } /* called inline thus a slightly different behaviour */ static void lit(void) { /* LIT */ PC += sizeof(cell); PUSH(read_ucell(cell2pointer(PC))); dbg_interp_printk("lit: %x\n", read_ucell(cell2pointer(PC))); } static void docon(void) { /* DOCON */ ucell tmp = read_cell(cell2pointer(read_ucell(cell2pointer(PC)) + sizeof(ucell))); PUSH(tmp); dbg_interp_printk("docon: PC=%x, value=%x\n", PC, tmp); } static void dovar(void) { /* DOVAR */ ucell tmp = read_cell(cell2pointer(PC)) + sizeof(ucell); PUSH(tmp); /* returns address to variable */ dbg_interp_printk("dovar: PC: %x, %x\n", PC, tmp); } static void dobranch(void) { /* unconditional branch */ PC += sizeof(cell); PC += read_cell(cell2pointer(PC)); } static void docbranch(void) { /* conditional branch */ PC += sizeof(cell); if (POP()) { dbg_internal_printk(" ?branch: end loop\n"); } else { dbg_internal_printk(" ?branch: follow branch\n"); PC += read_cell(cell2pointer(PC)); } } static void execute(void) { /* EXECUTE */ ucell address = POP(); dbg_interp_printk("execute: %x\n", address); PUSHR(PC); trampoline[1] = target_ucell(address); PC = pointer2cell(trampoline); } /* * call ( ... function-ptr -- ??? ) */ static void call(void) { #ifdef FCOMPILER printk("Sorry. Usage of Forth2C binding is forbidden during bootstrap.\n"); exit(1); #else void (*funcptr) (void); funcptr=(void *)POP(); dbg_interp_printk("call: %x", funcptr); funcptr(); #endif } /* * sys-debug ( errno -- ) */ static void sysdebug(void) { cell errorno=POP(); #ifdef FCOMPILER exception(errorno); #endif } static void dodoes(void) { /* DODOES */ ucell data = read_ucell(cell2pointer(PC)) + (2 * sizeof(ucell)); ucell word = read_ucell(cell2pointer(read_ucell(cell2pointer(PC)) + sizeof(ucell))); dbg_interp_printk("DODOES data=%x word=%x\n", data, word); PUSH(data); PUSH(word); execute(); } static void dodefer(void) { docol(); } static void dodo(void) { cell startval, endval; startval = POP(); endval = POP(); PUSHR(endval); PUSHR(startval); } static void doisdo(void) { cell startval, endval, offset; startval = POP(); endval = POP(); PC += sizeof(cell); if (startval == endval) { offset = read_cell(cell2pointer(PC)); PC += offset; } else { PUSHR(endval); PUSHR(startval); } } static void doloop(void) { cell offset, startval, endval; startval = POPR() + 1; endval = POPR(); PC += sizeof(cell); if (startval < endval) { offset = read_cell(cell2pointer(PC)); PC += offset; PUSHR(endval); PUSHR(startval); } } static void doplusloop(void) { ucell high, low; cell increment, startval, endval, offset; increment = POP(); startval = POPR(); endval = POPR(); low = (ucell) startval; startval += increment; PC += sizeof(cell); if (increment >= 0) { high = (ucell) startval; } else { high = low; low = (ucell) startval; } if (endval - (low + 1) >= high - low) { offset = read_cell(cell2pointer(PC)); PC += offset; PUSHR(endval); PUSHR(startval); } } /* * instance handling CFAs */ #ifndef FCOMPILER static ucell get_myself(void) { static ucell **myself = 0; if( !myself ) myself = (ucell**)findword("my-self") + 1; return (*myself && **myself) ? (ucell)**myself : 0; } static void doivar(void) { ucell r, *p = (ucell *)(*(ucell *) PC + sizeof(ucell)); ucell ibase = get_myself(); dbg_interp_printk("ivar, offset: %d size: %d (ibase %d)\n", p[0], p[1], ibase ); r = ibase ? ibase + p[0] : (ucell)&p[2]; PUSH( r ); } static void doival(void) { ucell r, *p = (ucell *)(*(ucell *) PC + sizeof(ucell)); ucell ibase = get_myself(); dbg_interp_printk("ivar, offset: %d size: %d\n", p[0], p[1] ); r = ibase ? ibase + p[0] : (ucell)&p[2]; PUSH( *(ucell *)r ); } static void doidefer(void) { ucell *p = (ucell *)(*(ucell *) PC + sizeof(ucell)); ucell ibase = get_myself(); dbg_interp_printk("doidefer, offset: %d size: %d\n", p[0], p[1] ); PUSHR(PC); PC = ibase ? ibase + p[0] : (ucell)&p[2]; PC -= sizeof(ucell); } #else static void noinstances(void) { printk("Opening devices is not supported during bootstrap. Sorry.\n"); exit(1); } #define doivar noinstances #define doival noinstances #define doidefer noinstances #endif /* * $include / $encode-file */ #ifdef FCOMPILER static void string_relay( void (*func)(const char *) ) { int len = POP(); char *name, *p = (char*)cell2pointer(POP()); name = malloc( len + 1 ); memcpy( name, p, len ); name[len]=0; (*func)( name ); free( name ); } #else #define string_relay( dummy ) do { DROP(); DROP(); } while(0) #endif static void do_include( void ) { string_relay( &include_file ); } static void do_encode_file( void ) { string_relay( &encode_file ); }