Disable mixing of DMA and FIFO messages in the Solaris ESP kernel module.
[openbios.git] / kernel / forth.c
blob0d3b2d29b29692dbe77d75ac8a185354d9214b65
1 /* tag: C implementation of all forth primitives,
2 * internal words, inner interpreter and such
4 * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer
6 * See the file "COPYING" for further information about
7 * the copyright and warranty status of this work.
8 */
10 #include "config.h"
11 #include "sysinclude.h"
12 #include "kernel/stack.h"
13 #include "kernel/kernel.h"
14 #include "dict.h"
17 * cross platform abstraction
20 #include "cross.h"
22 #ifndef FCOMPILER
23 #include "libc/vsprintf.h"
24 #else
25 #include <stdarg.h>
26 #endif
29 * execution works as follows:
30 * - PC is pushed on return stack
31 * - PC is set to new CFA
32 * - address pointed by CFA is executed by CPU
35 typedef void forth_word(void);
37 static forth_word * const words[];
38 ucell PC;
39 volatile int interruptforth = 0;
41 #define DEBUG_MODE_NONE 0
42 #define DEBUG_MODE_STEP 1
43 #define DEBUG_MODE_TRACE 2
44 #define DEBUG_MODE_STEPUP 3
46 #define DEBUG_BANNER "\nStepper keys: <space>/<enter> Up Down Trace Rstack Forth\n"
48 /* Empty linked list of debug xts */
49 struct debug_xt {
50 ucell xt_docol;
51 ucell xt_semis;
52 int mode;
53 struct debug_xt *next;
56 static struct debug_xt debug_xt_eol = { (ucell)0, (ucell)0, 0, NULL};
57 static struct debug_xt *debug_xt_list = &debug_xt_eol;
59 /* Static buffer for xt name */
60 char xtname[MAXNFALEN];
62 #ifndef FCOMPILER
63 /* instead of pointing to an explicit 0 variable we
64 * point behind the pointer.
66 static ucell t[] = { 0, 0, 0, 0 };
67 static ucell *trampoline = t;
70 * Code Field Address (CFA) definitions (DOCOL and the like)
73 void forth_init(void)
75 init_trampoline(trampoline);
77 #endif
79 #ifndef CONFIG_DEBUG_INTERPRETER
80 #define dbg_interp_printk( a... ) do { } while(0)
81 #else
82 #define dbg_interp_printk( a... ) printk( a )
83 #endif
85 #ifndef CONFIG_DEBUG_INTERNAL
86 #define dbg_internal_printk( a... ) do { } while(0)
87 #else
88 #define dbg_internal_printk( a... ) printk( a )
89 #endif
92 void init_trampoline(ucell *tramp)
94 tramp[0] = DOCOL;
95 tramp[1] = 0;
96 tramp[2] = target_ucell(pointer2cell(tramp) + 3 * sizeof(ucell));
97 tramp[3] = 0;
100 static inline void processxt(ucell xt)
102 void (*tokenp) (void);
104 dbg_interp_printk("processxt: pc=%x, xt=%x\n", PC, xt);
105 tokenp = words[xt];
106 tokenp();
109 static void docol(void)
110 { /* DOCOL */
111 PUSHR(PC);
112 PC = read_ucell(cell2pointer(PC));
114 dbg_interp_printk("docol: %s\n", cell2pointer( lfa2nfa(PC - sizeof(cell)) ));
117 static void semis(void)
119 PC = POPR();
122 static inline void next(void)
124 PC += sizeof(ucell);
126 dbg_interp_printk("next: PC is now %x\n", PC);
127 processxt(read_ucell(cell2pointer(read_ucell(cell2pointer(PC)))));
130 static inline void next_dbg(void);
132 int enterforth(xt_t xt)
134 ucell *_cfa = (ucell*)cell2pointer(xt);
135 cell tmp;
137 if (read_ucell(_cfa) != DOCOL) {
138 trampoline[1] = target_ucell(xt);
139 _cfa = trampoline;
142 if (rstackcnt < 0) {
143 rstackcnt = 0;
146 tmp = rstackcnt;
147 interruptforth = FORTH_INTSTAT_CLR;
149 PUSHR(PC);
150 PC = pointer2cell(_cfa);
152 while (rstackcnt > tmp && !(interruptforth & FORTH_INTSTAT_STOP)) {
153 if (debug_xt_list->next == NULL) {
154 while (rstackcnt > tmp && !interruptforth) {
155 dbg_interp_printk("enterforth: NEXT\n");
156 next();
158 } else {
159 while (rstackcnt > tmp && !interruptforth) {
160 dbg_interp_printk("enterforth: NEXT_DBG\n");
161 next_dbg();
165 /* Always clear the debug mode change flag */
166 interruptforth = interruptforth & (~FORTH_INTSTAT_DBG);
169 #if 0
170 /* return true if we took an exception. The caller should normally
171 * handle exceptions by returning immediately since the throw
172 * is supposed to abort the execution of this C-code too.
175 if (rstackcnt != tmp) {
176 printk("EXCEPTION DETECTED!\n");
178 #endif
179 return rstackcnt != tmp;
182 /* called inline thus a slightly different behaviour */
183 static void lit(void)
184 { /* LIT */
185 PC += sizeof(cell);
186 PUSH(read_ucell(cell2pointer(PC)));
187 dbg_interp_printk("lit: %x\n", read_ucell(cell2pointer(PC)));
190 static void docon(void)
191 { /* DOCON */
192 ucell tmp = read_ucell(cell2pointer(read_ucell(cell2pointer(PC)) + sizeof(ucell)));
193 PUSH(tmp);
194 dbg_interp_printk("docon: PC=%x, value=%x\n", PC, tmp);
197 static void dovar(void)
198 { /* DOVAR */
199 ucell tmp = read_ucell(cell2pointer(PC)) + sizeof(ucell);
200 PUSH(tmp); /* returns address to variable */
201 dbg_interp_printk("dovar: PC: %x, %x\n", PC, tmp);
204 static void dobranch(void)
205 { /* unconditional branch */
206 PC += sizeof(cell);
207 PC += read_cell(cell2pointer(PC));
210 static void docbranch(void)
211 { /* conditional branch */
212 PC += sizeof(cell);
213 if (POP()) {
214 dbg_internal_printk(" ?branch: end loop\n");
215 } else {
216 dbg_internal_printk(" ?branch: follow branch\n");
217 PC += read_cell(cell2pointer(PC));
222 static void execute(void)
223 { /* EXECUTE */
224 ucell address = POP();
225 dbg_interp_printk("execute: %x\n", address);
227 PUSHR(PC);
228 trampoline[1] = target_ucell(address);
229 PC = pointer2cell(trampoline);
233 * call ( ... function-ptr -- ??? )
235 static void call(void)
237 #ifdef FCOMPILER
238 printk("Sorry. Usage of Forth2C binding is forbidden during bootstrap.\n");
239 exit(1);
240 #else
241 void (*funcptr) (void);
242 funcptr=(void *)cell2pointer(POP());
243 dbg_interp_printk("call: %x", funcptr);
244 funcptr();
245 #endif
249 * sys-debug ( errno -- )
252 static void sysdebug(void)
254 #ifdef FCOMPILER
255 cell errorno=POP();
256 exception(errorno);
257 #else
258 (void) POP();
259 #endif
262 static void dodoes(void)
263 { /* DODOES */
264 ucell data = read_ucell(cell2pointer(PC)) + (2 * sizeof(ucell));
265 ucell word = read_ucell(cell2pointer(read_ucell(cell2pointer(PC)) + sizeof(ucell)));
267 dbg_interp_printk("DODOES data=%x word=%x\n", data, word);
269 PUSH(data);
270 PUSH(word);
272 execute();
275 static void dodefer(void)
277 docol();
280 static void dodo(void)
282 cell startval, endval;
283 startval = POP();
284 endval = POP();
286 PUSHR(endval);
287 PUSHR(startval);
290 static void doisdo(void)
292 cell startval, endval, offset;
294 startval = POP();
295 endval = POP();
297 PC += sizeof(cell);
299 if (startval == endval) {
300 offset = read_cell(cell2pointer(PC));
301 PC += offset;
302 } else {
303 PUSHR(endval);
304 PUSHR(startval);
308 static void doloop(void)
310 cell offset, startval, endval;
312 startval = POPR() + 1;
313 endval = POPR();
315 PC += sizeof(cell);
317 if (startval < endval) {
318 offset = read_cell(cell2pointer(PC));
319 PC += offset;
320 PUSHR(endval);
321 PUSHR(startval);
326 static void doplusloop(void)
328 ucell high, low;
329 cell increment, startval, endval, offset;
331 increment = POP();
333 startval = POPR();
334 endval = POPR();
336 low = (ucell) startval;
337 startval += increment;
339 PC += sizeof(cell);
341 if (increment >= 0) {
342 high = (ucell) startval;
343 } else {
344 high = low;
345 low = (ucell) startval;
348 if (endval - (low + 1) >= high - low) {
349 offset = read_cell(cell2pointer(PC));
350 PC += offset;
352 PUSHR(endval);
353 PUSHR(startval);
358 * instance handling CFAs
360 #ifndef FCOMPILER
361 static ucell get_myself(void)
363 static ucell *myselfptr = NULL;
364 if (myselfptr == NULL) {
365 myselfptr = (ucell*)cell2pointer(findword("my-self")) + 1;
367 ucell *myself = (ucell*)cell2pointer(*myselfptr);
368 return (myself != NULL) ? *myself : 0;
371 static void doivar(void)
373 ucell r, *p = (ucell *)(*(ucell *) cell2pointer(PC) + sizeof(ucell));
374 ucell ibase = get_myself();
376 dbg_interp_printk("ivar, offset: %d size: %d (ibase %d)\n", p[0], p[1], ibase );
378 r = ibase ? ibase + p[0] : pointer2cell(&p[2]);
379 PUSH( r );
382 static void doival(void)
384 ucell r, *p = (ucell *)(*(ucell *) cell2pointer(PC) + sizeof(ucell));
385 ucell ibase = get_myself();
387 dbg_interp_printk("ivar, offset: %d size: %d\n", p[0], p[1] );
389 r = ibase ? ibase + p[0] : pointer2cell(&p[2]);
390 PUSH( *(ucell *)cell2pointer(r) );
393 static void doidefer(void)
395 ucell *p = (ucell *)(*(ucell *) cell2pointer(PC) + sizeof(ucell));
396 ucell ibase = get_myself();
398 dbg_interp_printk("doidefer, offset: %d size: %d\n", p[0], p[1] );
400 PUSHR(PC);
401 PC = ibase ? ibase + p[0] : pointer2cell(&p[2]);
402 PC -= sizeof(ucell);
404 #else
405 static void noinstances(void)
407 printk("Opening devices is not supported during bootstrap. Sorry.\n");
408 exit(1);
410 #define doivar noinstances
411 #define doival noinstances
412 #define doidefer noinstances
413 #endif
416 * $include / $encode-file
418 #ifdef FCOMPILER
419 static void
420 string_relay(void (*func)(const char *))
422 int len = POP();
423 char *name, *p = (char*)cell2pointer(POP());
424 name = malloc(len + 1);
425 memcpy(name, p, len);
426 name[len] = 0;
427 (*func)(name);
428 free(name);
430 #else
431 #define string_relay(dummy) do { DROP(); DROP(); } while(0)
432 #endif
434 static void
435 do_include(void)
437 string_relay(&include_file);
440 static void
441 do_encode_file( void )
443 string_relay(&encode_file);
447 * Debug support functions
450 static
451 int printf_console(const char *fmt, ...)
453 cell tmp;
455 char buf[512];
456 va_list args;
457 int i;
459 va_start(args, fmt);
460 i = vsnprintf(buf, sizeof(buf), fmt, args);
461 va_end(args);
463 /* Push to the Forth interpreter for console output */
464 tmp = rstackcnt;
466 PUSH(pointer2cell(buf));
467 PUSH((int)strlen(buf));
468 trampoline[1] = findword("type");
470 PUSHR(PC);
471 PC = pointer2cell(trampoline);
473 while (rstackcnt > tmp) {
474 dbg_interp_printk("printf_console: NEXT\n");
475 next();
478 return i;
481 static
482 int getchar_console(void)
484 cell tmp;
486 /* Push to the Forth interpreter for console output */
487 tmp = rstackcnt;
489 trampoline[1] = findword("key");
491 PUSHR(PC);
492 PC = pointer2cell(trampoline);
494 while (rstackcnt > tmp) {
495 dbg_interp_printk("getchar_console: NEXT\n");
496 next();
499 return POP();
502 static void
503 display_dbg_dstack(void)
505 /* Display dstack contents between parentheses */
506 int i;
508 if (dstackcnt == 0) {
509 printf_console(" ( Empty ) ");
510 return;
511 } else {
512 printf_console(" ( ");
513 for (i = 1; i <= dstackcnt; i++) {
514 if (i != 1) {
515 printf_console(" ");
517 printf_console("%" FMT_CELL_x, dstack[i]);
519 printf_console(" ) ");
523 static void
524 display_dbg_rstack(void)
526 /* Display rstack contents between parentheses */
527 int i;
529 if (rstackcnt == 0) {
530 printf_console(" ( Empty ) ");
531 return;
532 } else {
533 printf_console("\nR: ( ");
534 for (i = 1; i <= rstackcnt; i++) {
535 if (i != 1) {
536 printf_console(" ");
538 printf_console("%" FMT_CELL_x, rstack[i]);
540 printf_console(" ) \n");
544 static int
545 add_debug_xt(ucell xt)
547 struct debug_xt *debug_xt_item;
549 /* If the xt CFA isn't DOCOL then issue a warning and do nothing */
550 if (read_ucell(cell2pointer(xt)) != DOCOL) {
551 printf_console("\nprimitive words cannot be debugged\n");
552 return 0;
555 /* If this xt is already in the list, do nothing but indicate success */
556 for (debug_xt_item = debug_xt_list; debug_xt_item->next != NULL;
557 debug_xt_item = debug_xt_item->next)
558 if (debug_xt_item->xt_docol == xt) {
559 return 1;
562 /* We already have the CFA (PC) indicating the starting cell of
563 the word, however we also need the ending cell too (we cannot
564 rely on the rstack as it can be arbitrarily changed by a forth
565 word). Hence the use of findsemis() */
567 /* Otherwise add to the head of the linked list */
568 debug_xt_item = malloc(sizeof(struct debug_xt));
569 debug_xt_item->xt_docol = xt;
570 debug_xt_item->xt_semis = findsemis(xt);
571 debug_xt_item->mode = DEBUG_MODE_NONE;
572 debug_xt_item->next = debug_xt_list;
573 debug_xt_list = debug_xt_item;
575 /* Indicate debug mode change */
576 interruptforth |= FORTH_INTSTAT_DBG;
578 /* Success */
579 return 1;
582 static void
583 del_debug_xt(ucell xt)
585 struct debug_xt *debug_xt_item, *tmp_xt_item;
587 /* Handle the case where the xt is at the head of the list */
588 if (debug_xt_list->xt_docol == xt) {
589 tmp_xt_item = debug_xt_list;
590 debug_xt_list = debug_xt_list->next;
591 free(tmp_xt_item);
593 return;
596 /* Otherwise find this xt in the linked list and remove it */
597 for (debug_xt_item = debug_xt_list; debug_xt_item->next != NULL;
598 debug_xt_item = debug_xt_item->next) {
599 if (debug_xt_item->next->xt_docol == xt) {
600 tmp_xt_item = debug_xt_item->next;
601 debug_xt_item->next = debug_xt_item->next->next;
602 free(tmp_xt_item);
606 /* If the list is now empty, indicate debug mode change */
607 if (debug_xt_list->next == NULL) {
608 interruptforth |= FORTH_INTSTAT_DBG;
612 static void
613 do_source_dbg(struct debug_xt *debug_xt_item)
615 /* Forth source debugger implementation */
616 char k, done = 0;
618 /* Display current dstack */
619 display_dbg_dstack();
620 printf_console("\n");
622 fstrncpy(xtname, lfa2nfa(read_ucell(cell2pointer(PC)) - sizeof(cell)), MAXNFALEN);
623 printf_console("%p: %s ", cell2pointer(PC), xtname);
625 /* If in trace mode, we just carry on */
626 if (debug_xt_item->mode == DEBUG_MODE_TRACE) {
627 return;
630 /* Otherwise in step mode, prompt for a keypress */
631 k = getchar_console();
633 /* Only proceed if done is true */
634 while (!done) {
635 switch (k) {
637 case ' ':
638 case '\n':
639 /* Perform a single step */
640 done = 1;
641 break;
643 case 'u':
644 case 'U':
645 /* Up - unmark current word for debug, mark its caller for
646 * debugging and finish executing current word */
648 /* Since this word could alter the rstack during its execution,
649 * we only know the caller when (semis) is called for this xt.
650 * Hence we mark the xt as a special DEBUG_MODE_STEPUP which
651 * means we run as normal, but schedule the xt for deletion
652 * at its corresponding (semis) word when we know the rstack
653 * will be set to its final parent value */
654 debug_xt_item->mode = DEBUG_MODE_STEPUP;
655 done = 1;
656 break;
658 case 'd':
659 case 'D':
660 /* Down - mark current word for debug and step into it */
661 done = add_debug_xt(read_ucell(cell2pointer(PC)));
662 if (!done) {
663 k = getchar_console();
665 break;
667 case 't':
668 case 'T':
669 /* Trace mode */
670 debug_xt_item->mode = DEBUG_MODE_TRACE;
671 done = 1;
672 break;
674 case 'r':
675 case 'R':
676 /* Display rstack */
677 display_dbg_rstack();
678 done = 0;
679 k = getchar_console();
680 break;
682 case 'f':
683 case 'F':
684 /* Start subordinate Forth interpreter */
685 PUSHR(PC - sizeof(cell));
686 PC = findword("outer-interpreter") + sizeof(ucell);
688 /* Save rstack position for when we return */
689 dbgrstackcnt = rstackcnt;
690 done = 1;
691 break;
693 default:
694 /* Display debug banner */
695 printf_console(DEBUG_BANNER);
696 k = getchar_console();
701 static void docol_dbg(void)
702 { /* DOCOL */
703 struct debug_xt *debug_xt_item;
705 PUSHR(PC);
706 PC = read_ucell(cell2pointer(PC));
708 /* If current xt is in our debug xt list, display word name */
709 debug_xt_item = debug_xt_list;
710 while (debug_xt_item->next) {
711 if (debug_xt_item->xt_docol == PC) {
712 fstrncpy(xtname, lfa2nfa(PC - sizeof(cell)), MAXNFALEN);
713 printf_console("\n: %s ", xtname);
715 /* Step mode is the default */
716 debug_xt_item->mode = DEBUG_MODE_STEP;
719 debug_xt_item = debug_xt_item->next;
722 dbg_interp_printk("docol_dbg: %s\n", cell2pointer(lfa2nfa(PC - sizeof(cell))));
725 static void semis_dbg(void)
727 struct debug_xt *debug_xt_item, *debug_xt_up = NULL;
729 /* If current semis is in our debug xt list, disable debug mode */
730 debug_xt_item = debug_xt_list;
731 while (debug_xt_item->next) {
732 if (debug_xt_item->xt_semis == PC) {
733 if (debug_xt_item->mode != DEBUG_MODE_STEPUP) {
734 /* Handle the normal case */
735 fstrncpy(xtname, lfa2nfa(debug_xt_item->xt_docol - sizeof(cell)), MAXNFALEN);
736 printf_console("\n[ Finished %s ] ", xtname);
738 /* Reset to step mode in case we were in trace mode */
739 debug_xt_item->mode = DEBUG_MODE_STEP;
740 } else {
741 /* This word requires execution of the debugger "Up"
742 * semantics. However we can't do this here since we
743 * are iterating through the debug list, and we need
744 * to change it. So we do it afterwards.
746 debug_xt_up = debug_xt_item;
750 debug_xt_item = debug_xt_item->next;
753 /* Execute debugger "Up" semantics if required */
754 if (debug_xt_up) {
755 /* Only add the parent word if it is not within the trampoline */
756 if (rstack[rstackcnt] != (cell)pointer2cell(&trampoline[1])) {
757 del_debug_xt(debug_xt_up->xt_docol);
758 add_debug_xt(findxtfromcell(rstack[rstackcnt]));
760 fstrncpy(xtname, lfa2nfa(findxtfromcell(rstack[rstackcnt]) - sizeof(cell)), MAXNFALEN);
761 printf_console("\n[ Up to %s ] ", xtname);
762 } else {
763 fstrncpy(xtname, lfa2nfa(findxtfromcell(debug_xt_up->xt_docol) - sizeof(cell)), MAXNFALEN);
764 printf_console("\n[ Finished %s (Unable to go up, hit trampoline) ] ", xtname);
766 del_debug_xt(debug_xt_up->xt_docol);
769 debug_xt_up = NULL;
772 PC = POPR();
775 static inline void next_dbg(void)
777 struct debug_xt *debug_xt_item;
778 void (*tokenp) (void);
780 PC += sizeof(ucell);
782 /* If the PC lies within a debug range, run the source debugger */
783 debug_xt_item = debug_xt_list;
784 while (debug_xt_item->next) {
785 if (PC >= debug_xt_item->xt_docol && PC <= debug_xt_item->xt_semis &&
786 debug_xt_item->mode != DEBUG_MODE_STEPUP) {
787 do_source_dbg(debug_xt_item);
790 debug_xt_item = debug_xt_item->next;
793 dbg_interp_printk("next_dbg: PC is now %x\n", PC);
795 /* Intercept DOCOL and SEMIS and redirect to debug versions */
796 if (read_ucell(cell2pointer(read_ucell(cell2pointer(PC)))) == DOCOL) {
797 tokenp = docol_dbg;
798 tokenp();
799 } else if (read_ucell(cell2pointer(read_ucell(cell2pointer(PC)))) == DOSEMIS) {
800 tokenp = semis_dbg;
801 tokenp();
802 } else {
803 /* Otherwise process as normal */
804 processxt(read_ucell(cell2pointer(read_ucell(cell2pointer(PC)))));
808 static void
809 do_debug_xt(void)
811 ucell xt = POP();
813 /* Add to the debug list */
814 if (add_debug_xt(xt)) {
815 /* Display debug banner */
816 printf_console(DEBUG_BANNER);
818 /* Indicate change to debug mode */
819 interruptforth |= FORTH_INTSTAT_DBG;
823 static void
824 do_debug_off(void)
826 /* Empty the debug xt linked list */
827 while (debug_xt_list->next != NULL) {
828 del_debug_xt(debug_xt_list->xt_docol);
833 * Forth primitives needed to set up
834 * all the words described in IEEE1275-1994.
838 * dup ( x -- x x )
841 static void fdup(void)
843 const cell tmp = GETTOS();
844 PUSH(tmp);
849 * 2dup ( x1 x2 -- x1 x2 x1 x2 )
852 static void twodup(void)
854 cell tmp = GETITEM(1);
855 PUSH(tmp);
856 tmp = GETITEM(1);
857 PUSH(tmp);
862 * ?dup ( x -- 0 | x x )
865 static void isdup(void)
867 const cell tmp = GETTOS();
868 if (tmp)
869 PUSH(tmp);
874 * over ( x y -- x y x )
877 static void over(void)
879 const cell tmp = GETITEM(1);
880 PUSH(tmp);
885 * 2over ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )
888 static void twoover(void)
890 const cell tmp = GETITEM(3);
891 const cell tmp2 = GETITEM(2);
892 PUSH(tmp);
893 PUSH(tmp2);
897 * pick ( xu ... x1 x0 u -- xu ... x1 x0 xu )
900 static void pick(void)
902 const cell u = POP();
903 if (dstackcnt >= u) {
904 ucell tmp = dstack[dstackcnt - u];
905 PUSH(tmp);
906 } else {
907 /* underrun */
913 * drop ( x -- )
916 static void drop(void)
918 POP();
922 * 2drop ( x1 x2 -- )
925 static void twodrop(void)
927 POP();
928 POP();
933 * nip ( x1 x2 -- x2 )
936 static void nip(void)
938 const cell tmp = POP();
939 POP();
940 PUSH(tmp);
945 * roll ( xu ... x1 x0 u -- xu-1... x1 x0 xu )
948 static void roll(void)
950 const cell u = POP();
951 if (dstackcnt >= u) {
952 int i;
953 const cell xu = dstack[dstackcnt - u];
954 for (i = dstackcnt - u; i < dstackcnt; i++) {
955 dstack[i] = dstack[i + 1];
957 dstack[dstackcnt] = xu;
958 } else {
959 /* Stack underrun */
965 * rot ( x1 x2 x3 -- x2 x3 x1 )
968 static void rot(void)
970 const cell tmp = POP();
971 const cell tmp2 = POP();
972 const cell tmp3 = POP();
973 PUSH(tmp2);
974 PUSH(tmp);
975 PUSH(tmp3);
980 * -rot ( x1 x2 x3 -- x3 x1 x2 )
983 static void minusrot(void)
985 const cell tmp = POP();
986 const cell tmp2 = POP();
987 const cell tmp3 = POP();
988 PUSH(tmp);
989 PUSH(tmp3);
990 PUSH(tmp2);
995 * swap ( x1 x2 -- x2 x1 )
998 static void swap(void)
1000 const cell tmp = POP();
1001 const cell tmp2 = POP();
1002 PUSH(tmp);
1003 PUSH(tmp2);
1008 * 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
1011 static void twoswap(void)
1013 const cell tmp = POP();
1014 const cell tmp2 = POP();
1015 const cell tmp3 = POP();
1016 const cell tmp4 = POP();
1017 PUSH(tmp2);
1018 PUSH(tmp);
1019 PUSH(tmp4);
1020 PUSH(tmp3);
1025 * >r ( x -- ) (R: -- x )
1028 static void tor(void)
1030 ucell tmp = POP();
1031 #ifdef CONFIG_DEBUG_RSTACK
1032 printk(" >R: %x\n", tmp);
1033 #endif
1034 PUSHR(tmp);
1039 * r> ( -- x ) (R: x -- )
1042 static void rto(void)
1044 ucell tmp = POPR();
1045 #ifdef CONFIG_DEBUG_RSTACK
1046 printk(" R>: %x\n", tmp);
1047 #endif
1048 PUSH(tmp);
1053 * r@ ( -- x ) (R: x -- x )
1056 static void rfetch(void)
1058 PUSH(GETTORS());
1063 * depth ( -- u )
1066 static void depth(void)
1068 const cell tmp = dstackcnt;
1069 PUSH(tmp);
1074 * depth! ( ... u -- x1 x2 .. xu )
1077 static void depthwrite(void)
1079 ucell tmp = POP();
1080 dstackcnt = tmp;
1085 * rdepth ( -- u )
1088 static void rdepth(void)
1090 const cell tmp = rstackcnt;
1091 PUSH(tmp);
1096 * rdepth! ( u -- ) ( R: ... -- x1 x2 .. xu )
1099 static void rdepthwrite(void)
1101 ucell tmp = POP();
1102 rstackcnt = tmp;
1107 * + ( nu1 nu2 -- sum )
1110 static void plus(void)
1112 cell tmp = POP() + POP();
1113 PUSH(tmp);
1118 * - ( nu1 nu2 -- diff )
1121 static void minus(void)
1123 const cell nu2 = POP();
1124 const cell nu1 = POP();
1125 PUSH(nu1 - nu2);
1130 * * ( nu1 nu2 -- prod )
1133 static void mult(void)
1135 const cell nu2 = POP();
1136 const cell nu1 = POP();
1137 PUSH(nu1 * nu2);
1142 * u* ( u1 u2 -- prod )
1145 static void umult(void)
1147 const ucell tmp = (ucell) POP() * (ucell) POP();
1148 PUSH(tmp);
1153 * mu/mod ( n1 n2 -- rem quot.l quot.h )
1156 static void mudivmod(void)
1158 const ucell b = POP();
1159 const ducell a = DPOP();
1160 #ifdef NEED_FAKE_INT128_T
1161 if (a.hi != 0) {
1162 fprintf(stderr, "mudivmod called (0x%016llx %016llx / 0x%016llx)\n",
1163 a.hi, a.lo, b);
1164 exit(-1);
1165 } else {
1166 ducell c;
1168 PUSH(a.lo % b);
1169 c.hi = 0;
1170 c.lo = a.lo / b;
1171 DPUSH(c);
1173 #else
1174 PUSH(a % b);
1175 DPUSH(a / b);
1176 #endif
1181 * abs ( n -- u )
1184 static void forthabs(void)
1186 const cell tmp = GETTOS();
1187 if (tmp < 0) {
1188 POP();
1189 PUSH(-tmp);
1195 * negate ( n1 -- n2 )
1198 static void negate(void)
1200 const cell tmp = POP();
1201 PUSH(-tmp);
1206 * max ( n1 n2 -- n1|n2 )
1209 static void max(void)
1211 const cell tmp = POP();
1212 const cell tmp2 = POP();
1213 PUSH((tmp > tmp2) ? tmp : tmp2);
1218 * min ( n1 n2 -- n1|n2 )
1221 static void min(void)
1223 const cell tmp = POP();
1224 const cell tmp2 = POP();
1225 PUSH((tmp < tmp2) ? tmp : tmp2);
1230 * lshift ( x1 u -- x2 )
1233 static void lshift(void)
1235 const ucell u = POP();
1236 const ucell x1 = POP();
1237 PUSH(x1 << u);
1242 * rshift ( x1 u -- x2 )
1245 static void rshift(void)
1247 const ucell u = POP();
1248 const ucell x1 = POP();
1249 PUSH(x1 >> u);
1254 * >>a ( x1 u -- x2 ) ??
1257 static void rshifta(void)
1259 const cell u = POP();
1260 const cell x1 = POP();
1261 PUSH(x1 >> u);
1266 * and ( x1 x2 -- x3 )
1269 static void and(void)
1271 const cell x1 = POP();
1272 const cell x2 = POP();
1273 PUSH(x1 & x2);
1278 * or ( x1 x2 -- x3 )
1281 static void or(void)
1283 const cell x1 = POP();
1284 const cell x2 = POP();
1285 PUSH(x1 | x2);
1290 * xor ( x1 x2 -- x3 )
1293 static void xor(void)
1295 const cell x1 = POP();
1296 const cell x2 = POP();
1297 PUSH(x1 ^ x2);
1302 * invert ( x1 -- x2 )
1305 static void invert(void)
1307 const cell x1 = POP();
1308 PUSH(x1 ^ -1);
1313 * d+ ( d1 d2 -- d.sum )
1316 static void dplus(void)
1318 const dcell d2 = DPOP();
1319 const dcell d1 = DPOP();
1320 #ifdef NEED_FAKE_INT128_T
1321 ducell c;
1323 if (d1.hi != 0 || d2.hi != 0) {
1324 fprintf(stderr, "dplus called (0x%016llx %016llx + 0x%016llx %016llx)\n",
1325 d1.hi, d1.lo, d2.hi, d2.lo);
1326 exit(-1);
1328 c.hi = 0;
1329 c.lo = d1.lo + d2.lo;
1330 DPUSH(c);
1331 #else
1332 DPUSH(d1 + d2);
1333 #endif
1338 * d- ( d1 d2 -- d.diff )
1341 static void dminus(void)
1343 const dcell d2 = DPOP();
1344 const dcell d1 = DPOP();
1345 #ifdef NEED_FAKE_INT128_T
1346 ducell c;
1348 if (d1.hi != 0 || d2.hi != 0) {
1349 fprintf(stderr, "dminus called (0x%016llx %016llx + 0x%016llx %016llx)\n",
1350 d1.hi, d1.lo, d2.hi, d2.lo);
1351 exit(-1);
1353 c.hi = 0;
1354 c.lo = d1.lo - d2.lo;
1355 DPUSH(c);
1356 #else
1357 DPUSH(d1 - d2);
1358 #endif
1363 * m* ( ?? -- )
1366 static void mmult(void)
1368 const cell u2 = POP();
1369 const cell u1 = POP();
1370 #ifdef NEED_FAKE_INT128_T
1371 ducell c;
1373 if (0) { // XXX How to detect overflow?
1374 fprintf(stderr, "mmult called (%016llx * 0x%016llx)\n", u1, u2);
1375 exit(-1);
1377 c.hi = 0;
1378 c.lo = u1 * u2;
1379 DPUSH(c);
1380 #else
1381 DPUSH((dcell) u1 * u2);
1382 #endif
1387 * um* ( u1 u2 -- d.prod )
1390 static void ummult(void)
1392 const ucell u2 = POP();
1393 const ucell u1 = POP();
1394 #ifdef NEED_FAKE_INT128_T
1395 ducell c;
1397 if (0) { // XXX How to detect overflow?
1398 fprintf(stderr, "ummult called (%016llx * 0x%016llx)\n", u1, u2);
1399 exit(-1);
1401 c.hi = 0;
1402 c.lo = u1 * u2;
1403 DPUSH(c);
1404 #else
1405 DPUSH((ducell) u1 * u2);
1406 #endif
1411 * @ ( a-addr -- x )
1414 static void fetch(void)
1416 const ucell *aaddr = (ucell *)cell2pointer(POP());
1417 PUSH(read_ucell(aaddr));
1422 * c@ ( addr -- byte )
1425 static void cfetch(void)
1427 const u8 *aaddr = (u8 *)cell2pointer(POP());
1428 PUSH(read_byte(aaddr));
1433 * w@ ( waddr -- w )
1436 static void wfetch(void)
1438 const u16 *aaddr = (u16 *)cell2pointer(POP());
1439 PUSH(read_word(aaddr));
1444 * l@ ( qaddr -- quad )
1447 static void lfetch(void)
1449 const u32 *aaddr = (u32 *)cell2pointer(POP());
1450 PUSH(read_long(aaddr));
1455 * ! ( x a-addr -- )
1458 static void store(void)
1460 const ucell *aaddr = (ucell *)cell2pointer(POP());
1461 const ucell x = POP();
1462 #ifdef CONFIG_DEBUG_INTERNAL
1463 printk("!: %lx : %lx -> %lx\n", aaddr, read_ucell(aaddr), x);
1464 #endif
1465 write_ucell(aaddr,x);
1470 * +! ( nu a-addr -- )
1473 static void plusstore(void)
1475 const ucell *aaddr = (ucell *)cell2pointer(POP());
1476 const cell nu = POP();
1477 write_cell(aaddr,read_cell(aaddr)+nu);
1482 * c! ( byte addr -- )
1485 static void cstore(void)
1487 const u8 *aaddr = (u8 *)cell2pointer(POP());
1488 const ucell byte = POP();
1489 #ifdef CONFIG_DEBUG_INTERNAL
1490 printk("c!: %x = %x\n", aaddr, byte);
1491 #endif
1492 write_byte(aaddr, byte);
1497 * w! ( w waddr -- )
1500 static void wstore(void)
1502 const u16 *aaddr = (u16 *)cell2pointer(POP());
1503 const u16 word = POP();
1504 write_word(aaddr, word);
1509 * l! ( quad qaddr -- )
1512 static void lstore(void)
1514 const u32 *aaddr = (u32 *)cell2pointer(POP());
1515 const u32 longval = POP();
1516 write_long(aaddr, longval);
1521 * = ( x1 x2 -- equal? )
1524 static void equals(void)
1526 cell tmp = (POP() == POP());
1527 PUSH(-tmp);
1532 * > ( n1 n2 -- greater? )
1535 static void greater(void)
1537 cell tmp = ((cell) POP() < (cell) POP());
1538 PUSH(-tmp);
1543 * < ( n1 n2 -- less? )
1546 static void less(void)
1548 cell tmp = ((cell) POP() > (cell) POP());
1549 PUSH(-tmp);
1554 * u> ( u1 u2 -- unsigned-greater? )
1557 static void ugreater(void)
1559 cell tmp = ((ucell) POP() < (ucell) POP());
1560 PUSH(-tmp);
1565 * u< ( u1 u2 -- unsigned-less? )
1568 static void uless(void)
1570 cell tmp = ((ucell) POP() > (ucell) POP());
1571 PUSH(-tmp);
1576 * sp@ ( -- stack-pointer )
1579 static void spfetch(void)
1581 // FIXME this can only work if the stack pointer
1582 // is within range.
1583 ucell tmp = pointer2cell(&(dstack[dstackcnt]));
1584 PUSH(tmp);
1589 * move ( src-addr dest-addr len -- )
1592 static void fmove(void)
1594 ucell count = POP();
1595 void *dest = (void *)cell2pointer(POP());
1596 const void *src = (const void *)cell2pointer(POP());
1597 memmove(dest, src, count);
1602 * fill ( addr len byte -- )
1605 static void ffill(void)
1607 ucell value = POP();
1608 ucell count = POP();
1609 void *src = (void *)cell2pointer(POP());
1610 memset(src, value, count);
1615 * unaligned-w@ ( addr -- w )
1618 static void unalignedwordread(void)
1620 const unsigned char *addr = (const unsigned char *) cell2pointer(POP());
1621 PUSH(unaligned_read_word(addr));
1626 * unaligned-w! ( w addr -- )
1629 static void unalignedwordwrite(void)
1631 const unsigned char *addr = (const unsigned char *) cell2pointer(POP());
1632 u16 w = POP();
1633 unaligned_write_word(addr, w);
1638 * unaligned-l@ ( addr -- quad )
1641 static void unalignedlongread(void)
1643 const unsigned char *addr = (const unsigned char *) cell2pointer(POP());
1644 PUSH(unaligned_read_long(addr));
1649 * unaligned-l! ( quad addr -- )
1652 static void unalignedlongwrite(void)
1654 unsigned char *addr = (unsigned char *) cell2pointer(POP());
1655 u32 l = POP();
1656 unaligned_write_long(addr, l);
1660 * here ( -- dictionary-pointer )
1663 static void here(void)
1665 PUSH(pointer2cell(dict) + dicthead);
1666 #ifdef CONFIG_DEBUG_INTERNAL
1667 printk("here: %x\n", pointer2cell(dict) + dicthead);
1668 #endif
1672 * here! ( new-dict-pointer -- )
1675 static void herewrite(void)
1677 ucell tmp = POP(); /* converted pointer */
1678 dicthead = tmp - pointer2cell(dict);
1679 #ifdef CONFIG_DEBUG_INTERNAL
1680 printk("here!: new value: %x\n", tmp);
1681 #endif
1683 if (dictlimit && dicthead >= dictlimit) {
1684 printk("Dictionary space overflow:"
1685 " dicthead=" FMT_ucellx
1686 " dictlimit=" FMT_ucellx
1687 "\n",
1688 dicthead, dictlimit);
1694 * emit ( char -- )
1697 static void emit(void)
1699 cell tmp = POP();
1700 #ifndef FCOMPILER
1701 putchar(tmp);
1702 #else
1703 put_outputbyte(tmp);
1704 #endif
1709 * key? ( -- pressed? )
1712 static void iskey(void)
1714 PUSH((cell) availchar());
1719 * key ( -- char )
1722 static void key(void)
1724 while (!availchar());
1725 #ifdef FCOMPILER
1726 PUSH(get_inputbyte());
1727 #else
1728 PUSH(getchar());
1729 #endif
1734 * ioc@ ( reg -- val )
1737 static void iocfetch(void)
1739 #ifndef FCOMPILER
1740 cell reg = POP();
1741 PUSH(inb(reg));
1742 #else
1743 (void)POP();
1744 PUSH(0);
1745 #endif
1750 * iow@ ( reg -- val )
1753 static void iowfetch(void)
1755 #ifndef FCOMPILER
1756 cell reg = POP();
1757 PUSH(inw(reg));
1758 #else
1759 (void)POP();
1760 PUSH(0);
1761 #endif
1765 * iol@ ( reg -- val )
1768 static void iolfetch(void)
1770 #ifndef FCOMPILER
1771 cell reg = POP();
1772 PUSH(inl(reg));
1773 #else
1774 (void)POP();
1775 PUSH(0);
1776 #endif
1781 * ioc! ( val reg -- )
1784 static void iocstore(void)
1786 #ifndef FCOMPILER
1787 cell reg = POP();
1788 cell val = POP();
1790 outb(reg, val);
1791 #else
1792 (void)POP();
1793 (void)POP();
1794 #endif
1799 * iow! ( val reg -- )
1802 static void iowstore(void)
1804 #ifndef FCOMPILER
1805 cell reg = POP();
1806 cell val = POP();
1808 outw(reg, val);
1809 #else
1810 (void)POP();
1811 (void)POP();
1812 #endif
1817 * iol! ( val reg -- )
1820 static void iolstore(void)
1822 #ifndef FCOMPILER
1823 ucell reg = POP();
1824 ucell val = POP();
1826 outl(reg, val);
1827 #else
1828 (void)POP();
1829 (void)POP();
1830 #endif
1834 * i ( -- i )
1837 static void loop_i(void)
1839 PUSH(rstack[rstackcnt]);
1843 * j ( -- i )
1846 static void loop_j(void)
1848 PUSH(rstack[rstackcnt - 2]);
1851 /* words[] is a function array of all native code functions used by
1852 * the dictionary, i.e. CFAs and primitives.
1853 * Any change here needs a matching change in the primitive word's
1854 * name list that is kept for bootstrapping in kernel/bootstrap.c
1856 * NOTE: THIS LIST SHALL NOT CHANGE (EXCEPT MANDATORY ADDITIONS AT
1857 * THE END). ANY OTHER CHANGE WILL BREAK COMPATIBILITY TO OLDER
1858 * BINARY DICTIONARIES.
1860 static forth_word * const words[] = {
1862 * CFAs and special words
1864 semis,
1865 docol,
1866 lit,
1867 docon,
1868 dovar,
1869 dodefer,
1870 dodoes,
1871 dodo,
1872 doisdo,
1873 doloop,
1874 doplusloop,
1875 doival,
1876 doivar,
1877 doidefer,
1880 * primitives
1882 fdup, /* dup */
1883 twodup, /* 2dup */
1884 isdup, /* ?dup */
1885 over, /* over */
1886 twoover, /* 2over */
1887 pick, /* pick */
1888 drop, /* drop */
1889 twodrop, /* 2drop */
1890 nip, /* nip */
1891 roll, /* roll */
1892 rot, /* rot */
1893 minusrot, /* -rot */
1894 swap, /* swap */
1895 twoswap, /* 2swap */
1896 tor, /* >r */
1897 rto, /* r> */
1898 rfetch, /* r@ */
1899 depth, /* depth */
1900 depthwrite, /* depth! */
1901 rdepth, /* rdepth */
1902 rdepthwrite, /* rdepth! */
1903 plus, /* + */
1904 minus, /* - */
1905 mult, /* * */
1906 umult, /* u* */
1907 mudivmod, /* mu/mod */
1908 forthabs, /* abs */
1909 negate, /* negate */
1910 max, /* max */
1911 min, /* min */
1912 lshift, /* lshift */
1913 rshift, /* rshift */
1914 rshifta, /* >>a */
1915 and, /* and */
1916 or, /* or */
1917 xor, /* xor */
1918 invert, /* invert */
1919 dplus, /* d+ */
1920 dminus, /* d- */
1921 mmult, /* m* */
1922 ummult, /* um* */
1923 fetch, /* @ */
1924 cfetch, /* c@ */
1925 wfetch, /* w@ */
1926 lfetch, /* l@ */
1927 store, /* ! */
1928 plusstore, /* +! */
1929 cstore, /* c! */
1930 wstore, /* w! */
1931 lstore, /* l! */
1932 equals, /* = */
1933 greater, /* > */
1934 less, /* < */
1935 ugreater, /* u> */
1936 uless, /* u< */
1937 spfetch, /* sp@ */
1938 fmove, /* move */
1939 ffill, /* fill */
1940 emit, /* emit */
1941 iskey, /* key? */
1942 key, /* key */
1943 execute, /* execute */
1944 here, /* here */
1945 herewrite, /* here! */
1946 dobranch, /* dobranch */
1947 docbranch, /* do?branch */
1948 unalignedwordread, /* unaligned-w@ */
1949 unalignedwordwrite, /* unaligned-w! */
1950 unalignedlongread, /* unaligned-l@ */
1951 unalignedlongwrite, /* unaligned-l! */
1952 iocfetch, /* ioc@ */
1953 iowfetch, /* iow@ */
1954 iolfetch, /* iol@ */
1955 iocstore, /* ioc! */
1956 iowstore, /* iow! */
1957 iolstore, /* iol! */
1958 loop_i, /* i */
1959 loop_j, /* j */
1960 call, /* call */
1961 sysdebug, /* sys-debug */
1962 do_include, /* $include */
1963 do_encode_file, /* $encode-file */
1964 do_debug_xt, /* (debug */
1965 do_debug_off, /* (debug-off) */