d7f12392625e74ed4bd745caedf2496a02aac722
[debian/pforth] / csrc / pf_inner.c
1 /* @(#) pf_inner.c 98/03/16 1.7 */\r
2 /***************************************************************\r
3 ** Inner Interpreter for Forth based on 'C'\r
4 **\r
5 ** Author: Phil Burk\r
6 ** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom\r
7 **\r
8 ** The pForth software code is dedicated to the public domain,\r
9 ** and any third party may reproduce, distribute and modify\r
10 ** the pForth software code or any derivative works thereof\r
11 ** without any compensation or license.  The pForth software\r
12 ** code is provided on an "as is" basis without any warranty\r
13 ** of any kind, including, without limitation, the implied\r
14 ** warranties of merchantability and fitness for a particular\r
15 ** purpose and their equivalents under the laws of any jurisdiction.\r
16 **\r
17 ****************************************************************\r
18 **\r
19 ** 940502 PLB Creation.\r
20 ** 940505 PLB More macros.\r
21 ** 940509 PLB Moved all stack stuff into pfCatch.\r
22 ** 941014 PLB Converted to flat secondary strusture.\r
23 ** 941027 rdg added casts to ID_SP_FETCH, ID_RP_FETCH, \r
24 **             and ID_HERE for armcc\r
25 ** 941130 PLB Made w@ unsigned\r
26 **\r
27 ***************************************************************/\r
28 \r
29 #include "pf_all.h"\r
30 #include <crtdbg.h>\r
31 \r
32 #define SYSTEM_LOAD_FILE "system.fth"\r
33 \r
34 /***************************************************************\r
35 ** Macros for data stack access.\r
36 ** TOS is cached in a register in pfCatch.\r
37 ***************************************************************/\r
38 \r
39 #define STKPTR   (DataStackPtr)\r
40 #define M_POP    (*(STKPTR++))\r
41 #define M_PUSH(n) {*(--(STKPTR)) = (cell) (n);}\r
42 #define M_STACK(n) (STKPTR[n])\r
43 \r
44 #define TOS      (TopOfStack)\r
45 #define PUSH_TOS M_PUSH(TOS)\r
46 #define M_DUP    PUSH_TOS;\r
47 #define M_DROP   { TOS = M_POP; }\r
48 \r
49 \r
50 /***************************************************************\r
51 ** Macros for Floating Point stack access.\r
52 ***************************************************************/\r
53 #ifdef PF_SUPPORT_FP\r
54 #define FP_STKPTR   (FloatStackPtr)\r
55 #define M_FP_SPZERO (gCurrentTask->td_FloatStackBase)\r
56 #define M_FP_POP    (*(FP_STKPTR++))\r
57 #define M_FP_PUSH(n) {*(--(FP_STKPTR)) = (PF_FLOAT) (n);}\r
58 #define M_FP_STACK(n) (FP_STKPTR[n])\r
59 \r
60 #define FP_TOS      (fpTopOfStack)\r
61 #define PUSH_FP_TOS M_FP_PUSH(FP_TOS)\r
62 #define M_FP_DUP    PUSH_FP_TOS;\r
63 #define M_FP_DROP   { FP_TOS = M_FP_POP; }\r
64 #endif\r
65 \r
66 /***************************************************************\r
67 ** Macros for return stack access.\r
68 ***************************************************************/\r
69 \r
70 #define TORPTR (ReturnStackPtr)\r
71 #define M_R_DROP {TORPTR++;}\r
72 #define M_R_POP (*(TORPTR++))\r
73 #define M_R_PICK(n) (TORPTR[n])\r
74 #define M_R_PUSH(n) {*(--(TORPTR)) = (cell) (n);}\r
75 \r
76 /***************************************************************\r
77 ** Misc Forth macros\r
78 ***************************************************************/\r
79                         \r
80 #define M_BRANCH   { InsPtr = (cell *) (((uint8 *) InsPtr) + READ_LONG_DIC(InsPtr)); }\r
81 \r
82 /* Cache top of data stack like in JForth. */\r
83 #ifdef PF_SUPPORT_FP\r
84 #define LOAD_REGISTERS \\r
85         { \\r
86                 STKPTR = gCurrentTask->td_StackPtr; \\r
87                 TOS = M_POP; \\r
88                 FP_STKPTR = gCurrentTask->td_FloatStackPtr; \\r
89                 FP_TOS = M_FP_POP; \\r
90                 TORPTR = gCurrentTask->td_ReturnPtr; \\r
91          }\r
92          \r
93 #define SAVE_REGISTERS \\r
94         { \\r
95                 gCurrentTask->td_ReturnPtr = TORPTR; \\r
96                 M_PUSH( TOS ); \\r
97                 gCurrentTask->td_StackPtr = STKPTR; \\r
98                 M_FP_PUSH( FP_TOS ); \\r
99                 gCurrentTask->td_FloatStackPtr = FP_STKPTR; \\r
100          }\r
101          \r
102 #else\r
103 /* Cache top of data stack like in JForth. */\r
104 #define LOAD_REGISTERS \\r
105         { \\r
106                 STKPTR = gCurrentTask->td_StackPtr; \\r
107                 TOS = M_POP; \\r
108                 TORPTR = gCurrentTask->td_ReturnPtr; \\r
109          }\r
110          \r
111 #define SAVE_REGISTERS \\r
112         { \\r
113                 gCurrentTask->td_ReturnPtr = TORPTR; \\r
114                 M_PUSH( TOS ); \\r
115                 gCurrentTask->td_StackPtr = STKPTR; \\r
116          }\r
117 #endif\r
118 \r
119 #define M_DOTS \\r
120         SAVE_REGISTERS; \\r
121         ffDotS( ); \\r
122         LOAD_REGISTERS;\r
123         \r
124 #define DO_VAR(varname) { PUSH_TOS; TOS = (cell) &varname; }\r
125 \r
126 #ifdef PF_SUPPORT_FP\r
127 #define M_THROW(err) \\r
128         { \\r
129                 ExceptionReturnCode = (ThrowCode)(err); \\r
130                 TORPTR = InitialReturnStack; /* Will cause return to 'C' */ \\r
131                 STKPTR = InitialDataStack; \\r
132                 FP_STKPTR = InitialFloatStack; \\r
133         }\r
134 #else\r
135 #define M_THROW(err) \\r
136         { \\r
137                 ExceptionReturnCode = (err); \\r
138                 TORPTR = InitialReturnStack; /* Will cause return to 'C' */ \\r
139                 STKPTR = InitialDataStack; \\r
140         }\r
141 #endif\r
142 \r
143 /***************************************************************\r
144 ** Other macros\r
145 ***************************************************************/\r
146 \r
147 #define BINARY_OP( op ) { TOS = M_POP op TOS; }\r
148 #define endcase break\r
149                 \r
150 #if defined(PF_NO_SHELL) || !defined(PF_SUPPORT_TRACE)\r
151         #define TRACENAMES /* no names */\r
152 #else\r
153 /* Display name of executing routine. */\r
154 static void TraceNames( ExecToken Token, int32 Level )\r
155 {\r
156         char *DebugName;\r
157         int32 i;\r
158         \r
159         if( ffTokenToName( Token, &DebugName ) )\r
160         {\r
161                 cell NumSpaces;\r
162                 if( gCurrentTask->td_OUT > 0 ) EMIT_CR;\r
163                 EMIT( '>' );\r
164                 for( i=0; i<Level; i++ )\r
165                 {\r
166                         MSG( "  " );\r
167                 }\r
168                 TypeName( DebugName );\r
169 /* Space out to column N then .S */\r
170                 NumSpaces = 30 - gCurrentTask->td_OUT;\r
171                 for( i=0; i < NumSpaces; i++ )\r
172                 {\r
173                         EMIT( ' ' );\r
174                 }\r
175                 ffDotS();\r
176 /* No longer needed?            gCurrentTask->td_OUT = 0; */ /* !!! Hack for ffDotS() */\r
177                 \r
178         }\r
179         else\r
180         {\r
181                 MSG_NUM_H("Couldn't find Name for ", Token);\r
182         }\r
183 }\r
184 \r
185 #define TRACENAMES \\r
186         if( (gVarTraceLevel > Level) ) \\r
187         { SAVE_REGISTERS; TraceNames( Token, Level ); LOAD_REGISTERS; }\r
188 #endif /* PF_NO_SHELL */\r
189 \r
190 /* Use local copy of CODE_BASE for speed. */\r
191 #define LOCAL_CODEREL_TO_ABS( a ) ((cell *) (((int32) a) + CodeBase))\r
192 \r
193 /**************************************************************/\r
194 const char *pfSelectFileMode( int fam )\r
195 {\r
196         char *famText = NULL;\r
197         switch( fam )\r
198         {\r
199         case (PF_FAM_READ_ONLY + PF_FAM_BINARY_FLAG):\r
200                 famText = PF_FAM_BIN_OPEN_RO;\r
201                 break;\r
202         case (PF_FAM_WRITE_ONLY + PF_FAM_BINARY_FLAG):\r
203                 famText = PF_FAM_BIN_CREATE_WO;\r
204                 break;\r
205         case (PF_FAM_READ_WRITE + PF_FAM_BINARY_FLAG):\r
206                 famText = PF_FAM_BIN_OPEN_RW;\r
207                 break;\r
208         case PF_FAM_READ_ONLY:\r
209                 famText = PF_FAM_OPEN_RO;\r
210                 break;\r
211         case PF_FAM_WRITE_ONLY:\r
212                 famText = PF_FAM_CREATE_WO;\r
213                 break;\r
214         case PF_FAM_READ_WRITE:\r
215         default:\r
216                 famText = PF_FAM_OPEN_RW;\r
217                 break;\r
218         }\r
219         return famText;\r
220 }\r
221 \r
222 /**************************************************************/\r
223 int pfCatch( ExecToken XT )\r
224 {\r
225         register cell  TopOfStack;    /* Cache for faster execution. */\r
226         register cell *DataStackPtr;\r
227         register cell *ReturnStackPtr;\r
228         register cell *InsPtr = NULL;\r
229         register cell  Token;\r
230         cell           Scratch;\r
231         \r
232 #ifdef PF_SUPPORT_FP\r
233         PF_FLOAT       fpTopOfStack;\r
234         PF_FLOAT      *FloatStackPtr;\r
235         PF_FLOAT       fpScratch;\r
236         PF_FLOAT       fpTemp;\r
237         PF_FLOAT      *InitialFloatStack;\r
238 #endif\r
239 #ifdef PF_SUPPORT_TRACE\r
240         int32 Level = 0;\r
241 #endif\r
242         cell          *LocalsPtr = NULL;\r
243         cell           Temp;\r
244         cell          *InitialReturnStack;\r
245         cell          *InitialDataStack;\r
246         cell           FakeSecondary[2];\r
247         char          *CharPtr;\r
248         cell          *CellPtr;\r
249         FileStream    *FileID;\r
250         uint8         *CodeBase = CODE_BASE;\r
251         ThrowCode      ExceptionReturnCode = 0;\r
252         \r
253 /* FIXME\r
254         gExecutionDepth += 1;\r
255         PRT(("pfCatch( 0x%x ), depth = %d\n", XT, gExecutionDepth ));\r
256 */\r
257 \r
258 /*\r
259 ** Initialize FakeSecondary this way to avoid having stuff in the data section,\r
260 ** which is not supported for some embedded system loaders.\r
261 */\r
262         FakeSecondary[0] = 0;\r
263         FakeSecondary[1] = ID_EXIT; /* For EXECUTE */\r
264 \r
265 /* Move data from task structure to registers for speed. */\r
266         LOAD_REGISTERS;\r
267 \r
268 /* Save initial stack depths for THROW */\r
269         InitialReturnStack = TORPTR;\r
270         InitialDataStack   = STKPTR ;\r
271 #ifdef PF_SUPPORT_FP\r
272         InitialFloatStack  = FP_STKPTR;\r
273 #endif\r
274 \r
275         Token = XT;\r
276 \r
277         do\r
278         {\r
279 DBUG(("pfCatch: Token = 0x%x\n", Token ));\r
280 \r
281 /* --------------------------------------------------------------- */\r
282 /* If secondary, thread down code tree until we hit a primitive. */\r
283                 while( !IsTokenPrimitive( Token ) )\r
284                 {\r
285 #ifdef PF_SUPPORT_TRACE\r
286                         if((gVarTraceFlags & TRACE_INNER) )\r
287                         {\r
288                                 MSG("pfCatch: Secondary Token = 0x");\r
289                                 ffDotHex(Token);\r
290                                 MSG_NUM_H(", InsPtr = 0x", InsPtr);\r
291                         }\r
292                         TRACENAMES;\r
293 #endif\r
294 \r
295 /* Save IP on return stack like a JSR. */\r
296                         M_R_PUSH( InsPtr );\r
297                         \r
298 /* Convert execution token to absolute address. */\r
299                         InsPtr = (cell *) ( LOCAL_CODEREL_TO_ABS(Token) );\r
300 \r
301 /* Fetch token at IP. */\r
302                         Token = READ_LONG_DIC(InsPtr++);\r
303                         \r
304 #ifdef PF_SUPPORT_TRACE\r
305 /* Bump level for trace display */\r
306                         Level++;\r
307 #endif\r
308                 }\r
309 \r
310                 \r
311 #ifdef PF_SUPPORT_TRACE\r
312                 TRACENAMES;\r
313 #endif\r
314                         \r
315 /* Execute primitive Token. */\r
316                 switch( Token )\r
317                 {\r
318                         \r
319         /* Pop up a level in Forth inner interpreter.\r
320         ** Used to implement semicolon.\r
321         ** Put first in switch because ID_EXIT==0 */\r
322                 case ID_EXIT:\r
323                         InsPtr = ( cell *) M_R_POP;\r
324 #ifdef PF_SUPPORT_TRACE\r
325                         Level--;\r
326 #endif\r
327                         endcase;\r
328                                                 \r
329                 case ID_1MINUS:  TOS--; endcase;\r
330                         \r
331                 case ID_1PLUS:   TOS++; endcase;\r
332                         \r
333 #ifndef PF_NO_SHELL\r
334                 case ID_2LITERAL:\r
335                         ff2Literal( TOS, M_POP );\r
336                         M_DROP;\r
337                         endcase;\r
338 #endif  /* !PF_NO_SHELL */\r
339 \r
340                 case ID_2LITERAL_P:\r
341 /* hi part stored first, put on top of stack */\r
342                         PUSH_TOS;\r
343                         TOS = READ_LONG_DIC(InsPtr++);\r
344                         M_PUSH(READ_LONG_DIC(InsPtr++));\r
345                         endcase;\r
346                         \r
347                 case ID_2MINUS:  TOS -= 2; endcase;\r
348                         \r
349                 case ID_2PLUS:   TOS += 2; endcase;\r
350                 \r
351                 \r
352                 case ID_2OVER:  /* ( a b c d -- a b c d a b ) */\r
353                         PUSH_TOS;\r
354                         Scratch = M_STACK(3);\r
355                         M_PUSH(Scratch);\r
356                         TOS = M_STACK(3);\r
357                         endcase;\r
358                         \r
359                 case ID_2SWAP:  /* ( a b c d -- c d a b ) */\r
360                         Scratch = M_STACK(0);    /* c */\r
361                         M_STACK(0) = M_STACK(2); /* a */\r
362                         M_STACK(2) = Scratch;    /* c */\r
363                         Scratch = TOS;           /* d */\r
364                         TOS = M_STACK(1);        /* b */\r
365                         M_STACK(1) = Scratch;    /* d */\r
366                         endcase;\r
367                         \r
368                 case ID_2DUP:   /* ( a b -- a b a b ) */\r
369                         PUSH_TOS;\r
370                         Scratch = M_STACK(1);\r
371                         M_PUSH(Scratch);\r
372                         endcase;\r
373                         \r
374                 case ID_2_R_FETCH:\r
375                         PUSH_TOS;\r
376                         M_PUSH( (*(TORPTR+1)) );\r
377                         TOS = (*(TORPTR));\r
378                         endcase;\r
379 \r
380                 case ID_2_R_FROM:\r
381                         PUSH_TOS;\r
382                         TOS = M_R_POP;\r
383                         M_PUSH( M_R_POP );\r
384                         endcase;\r
385 \r
386                 case ID_2_TO_R:\r
387                         M_R_PUSH( M_POP );\r
388                         M_R_PUSH( TOS );\r
389                         M_DROP;\r
390                         endcase;\r
391                 \r
392                 case ID_ACCEPT_P: /* ( c-addr +n1 -- +n2 ) */\r
393                         CharPtr = (char *) M_POP;\r
394                         TOS = ioAccept( CharPtr, TOS );\r
395                         endcase;\r
396                         \r
397 #ifndef PF_NO_SHELL\r
398                 case ID_ALITERAL:\r
399                         ffALiteral( ABS_TO_CODEREL(TOS) );\r
400                         M_DROP;\r
401                         endcase;\r
402 #endif  /* !PF_NO_SHELL */\r
403 \r
404                 case ID_ALITERAL_P:\r
405                         PUSH_TOS;\r
406                         TOS = (cell) LOCAL_CODEREL_TO_ABS( READ_LONG_DIC(InsPtr++) );\r
407                         endcase;\r
408                         \r
409 /* Allocate some extra and put validation identifier at base */\r
410 #define PF_MEMORY_VALIDATOR  (0xA81B4D69)\r
411                 case ID_ALLOCATE:\r
412                         /* Allocate at least one cell's worth because we clobber first cell. */\r
413                         if ( TOS < sizeof(cell) )\r
414                         {\r
415                                 Temp = sizeof(cell);\r
416                         }\r
417                         else\r
418                         {\r
419                                 Temp = TOS;\r
420                         }\r
421                         /* Allocate extra cells worth because we store validation info. */\r
422                         CellPtr = (cell *) pfAllocMem( Temp + sizeof(cell) );\r
423                         if( CellPtr )\r
424                         {\r
425 /* This was broken into two steps because different compilers incremented\r
426 ** CellPtr before or after the XOR step. */\r
427                                 Temp = (int32)CellPtr ^ PF_MEMORY_VALIDATOR;\r
428                                 *CellPtr++ = Temp;\r
429                                 M_PUSH( (cell) CellPtr );\r
430                                 TOS = 0;\r
431                         }\r
432                         else\r
433                         {\r
434                                 M_PUSH( 0 );\r
435                                 TOS = -1;  /* FIXME Fix error code. */\r
436                         }\r
437                         endcase;\r
438 \r
439                 case ID_AND:     BINARY_OP( & ); endcase;\r
440                 \r
441                 case ID_ARSHIFT:     BINARY_OP( >> ); endcase;  /* Arithmetic right shift */\r
442                 \r
443                 case ID_BODY_OFFSET:\r
444                         PUSH_TOS;\r
445                         TOS = CREATE_BODY_OFFSET;\r
446                         endcase;\r
447                         \r
448 /* Branch is followed by an offset relative to address of offset. */\r
449                 case ID_BRANCH:\r
450 DBUGX(("Before Branch: IP = 0x%x\n", InsPtr ));\r
451                         M_BRANCH;\r
452 DBUGX(("After Branch: IP = 0x%x\n", InsPtr ));\r
453                         endcase;\r
454 \r
455                 case ID_BYE:\r
456                         M_THROW( THROW_BYE );\r
457                         endcase;\r
458 \r
459                 case ID_BAIL:\r
460                         MSG("Emergency exit.\n");\r
461                         EXIT(1);\r
462                         endcase;\r
463                 \r
464                 case ID_CATCH:\r
465                         Scratch = TOS;\r
466                         TOS = M_POP;\r
467                         SAVE_REGISTERS;\r
468                         Scratch = pfCatch( Scratch );\r
469                         LOAD_REGISTERS;\r
470                         M_PUSH( TOS );\r
471                         TOS = Scratch;\r
472                         endcase;\r
473 \r
474                 case ID_CALL_C:\r
475                         SAVE_REGISTERS;\r
476                         Scratch = READ_LONG_DIC(InsPtr++);\r
477                         CallUserFunction( Scratch & 0xFFFF,\r
478                                 (Scratch >> 31) & 1,\r
479                                 (Scratch >> 24) & 0x7F );\r
480                         LOAD_REGISTERS;\r
481                         endcase;\r
482 \r
483                 case ID_CFETCH:   TOS = *((uint8 *) TOS); endcase;\r
484 \r
485                 case ID_CMOVE: /* ( src dst n -- ) */\r
486                         {\r
487                                 register char *DstPtr = (char *) M_POP; /* dst */\r
488                                 CharPtr = (char *) M_POP;    /* src */\r
489                                 for( Scratch=0; (uint32) Scratch < (uint32) TOS ; Scratch++ )\r
490                                 {\r
491                                         *DstPtr++ = *CharPtr++;\r
492                                 }\r
493                                 M_DROP;\r
494                         }\r
495                         endcase;\r
496                         \r
497                 case ID_CMOVE_UP: /* ( src dst n -- ) */\r
498                         {\r
499                                 register char *DstPtr = ((char *) M_POP) + TOS; /* dst */\r
500                                 CharPtr = ((char *) M_POP) + TOS;;    /* src */\r
501                                 for( Scratch=0; (uint32) Scratch < (uint32) TOS ; Scratch++ )\r
502                                 {\r
503                                         *(--DstPtr) = *(--CharPtr);\r
504                                 }\r
505                                 M_DROP;\r
506                         }\r
507                         endcase;\r
508                 \r
509 #ifndef PF_NO_SHELL\r
510                 case ID_COLON:\r
511                         SAVE_REGISTERS;\r
512                         ffColon( );\r
513                         LOAD_REGISTERS;\r
514                         endcase;\r
515                 case ID_COLON_P:  /* ( $name xt -- ) */\r
516                         CreateDicEntry( TOS, (char *) M_POP, 0 );\r
517                         M_DROP;\r
518                         endcase;\r
519 #endif  /* !PF_NO_SHELL */\r
520 \r
521                 case ID_COMPARE:\r
522                         {\r
523                                 const char *s1, *s2;\r
524                                 int32 len1;\r
525                                 s2 = (const char *) M_POP;\r
526                                 len1 = M_POP;\r
527                                 s1 = (const char *) M_POP;\r
528                                 TOS = ffCompare( s1, len1, s2, TOS );\r
529                         }\r
530                         endcase;\r
531                         \r
532 /* ( a b -- flag , Comparisons ) */\r
533                 case ID_COMP_EQUAL:\r
534                         TOS = ( TOS == M_POP ) ? FTRUE : FFALSE ;\r
535                         endcase;\r
536                 case ID_COMP_NOT_EQUAL:\r
537                         TOS = ( TOS != M_POP ) ? FTRUE : FFALSE ;\r
538                         endcase;\r
539                 case ID_COMP_GREATERTHAN:\r
540                         TOS = ( M_POP > TOS ) ? FTRUE : FFALSE ;\r
541                         endcase;\r
542                 case ID_COMP_LESSTHAN:\r
543                         TOS = (  M_POP < TOS ) ? FTRUE : FFALSE ;\r
544                         endcase;\r
545                 case ID_COMP_U_GREATERTHAN:\r
546                         TOS = ( ((uint32)M_POP) > ((uint32)TOS) ) ? FTRUE : FFALSE ;\r
547                         endcase;\r
548                 case ID_COMP_U_LESSTHAN:\r
549                         TOS = ( ((uint32)M_POP) < ((uint32)TOS) ) ? FTRUE : FFALSE ;\r
550                         endcase;\r
551                 case ID_COMP_ZERO_EQUAL:\r
552                         TOS = ( TOS == 0 ) ? FTRUE : FFALSE ;\r
553                         endcase;\r
554                 case ID_COMP_ZERO_NOT_EQUAL:\r
555                         TOS = ( TOS != 0 ) ? FTRUE : FALSE ;\r
556                         endcase;\r
557                 case ID_COMP_ZERO_GREATERTHAN:\r
558                         TOS = ( TOS > 0 ) ? FTRUE : FFALSE ;\r
559                         endcase;\r
560                 case ID_COMP_ZERO_LESSTHAN:\r
561                         TOS = ( TOS < 0 ) ? FTRUE : FFALSE ;\r
562                         endcase;\r
563                         \r
564                 case ID_CR:\r
565                         EMIT_CR;\r
566                         endcase;\r
567                 \r
568 #ifndef PF_NO_SHELL\r
569                 case ID_CREATE:\r
570                         SAVE_REGISTERS;\r
571                         ffCreate();\r
572                         LOAD_REGISTERS;\r
573                         endcase;\r
574 #endif  /* !PF_NO_SHELL */\r
575 \r
576                 case ID_CREATE_P:\r
577                         PUSH_TOS;\r
578 /* Put address of body on stack.  Insptr points after code start. */\r
579                         TOS = (cell) ((char *)InsPtr - sizeof(cell) + CREATE_BODY_OFFSET );\r
580                         endcase;\r
581         \r
582                 case ID_CSTORE: /* ( c caddr -- ) */\r
583                         *((uint8 *) TOS) = (uint8) M_POP;\r
584                         M_DROP;\r
585                         endcase;\r
586 \r
587 /* Double precision add. */\r
588                 case ID_D_PLUS:  /* D+ ( al ah bl bh -- sl sh ) */ \r
589                         {\r
590                                 register ucell ah,al,bl,sh,sl;\r
591 #define bh TOS\r
592                                 bl = M_POP;\r
593                                 ah = M_POP;\r
594                                 al = M_POP;\r
595                                 sh = 0;\r
596                                 sl = al + bl;\r
597                                 if( sl < bl ) sh = 1; /* Carry */\r
598                                 sh += ah + bh;\r
599                                 M_PUSH( sl );\r
600                                 TOS = sh;\r
601 #undef bh\r
602                         }\r
603                         endcase;\r
604         \r
605 /* Double precision subtract. */\r
606                 case ID_D_MINUS:  /* D- ( al ah bl bh -- sl sh ) */ \r
607                         {\r
608                                 register ucell ah,al,bl,sh,sl;\r
609 #define bh TOS\r
610                                 bl = M_POP;\r
611                                 ah = M_POP;\r
612                                 al = M_POP;\r
613                                 sh = 0;\r
614                                 sl = al - bl;\r
615                                 if( al < bl ) sh = 1; /* Borrow */\r
616                                 sh = ah - bh - sh;\r
617                                 M_PUSH( sl );\r
618                                 TOS = sh;\r
619 #undef bh\r
620                         }\r
621                         endcase;\r
622                         \r
623 /* Perform 32*32 bit multiply for 64 bit result, by factoring into 16 bit quantities. */\r
624 /* Using an improved algorithm suggested by Steve Green. */\r
625                 case ID_D_UMTIMES:  /* M* ( a b -- pl ph ) */ \r
626                         {\r
627                                 ucell ahi, alo, bhi, blo, temp;\r
628                                 ucell pl, ph;\r
629 /* Get values from stack. */\r
630                                 ahi = M_POP;\r
631                                 bhi = TOS;\r
632 /* Break into hi and lo 16 bit parts. */\r
633                                 alo = ahi & 0xFFFF;\r
634                                 ahi = ahi>>16;\r
635                                 blo = bhi & 0xFFFF;\r
636                                 bhi = bhi>>16;\r
637                                 ph = 0;\r
638 /* ahi * bhi */\r
639                                 pl = ahi * bhi;\r
640                                 ph = pl >> 16;  /* shift 64 bit value by 16 */\r
641                                 pl = pl << 16;\r
642 /* ahi * blo */\r
643                                 temp = ahi * blo;\r
644                                 pl += temp;\r
645                                 if( pl < temp ) ph += 1; /* Carry */\r
646 /* alo * bhi  */\r
647                                 temp = alo * bhi;\r
648                                 pl += temp;\r
649                                 if( pl < temp ) ph += 1; /* Carry */\r
650                                 ph = (ph << 16) | (pl >> 16); /* shift 64 bit value by 16 */\r
651                                 pl = pl << 16;\r
652 /* alo * blo */\r
653                                 temp = alo * blo;\r
654                                 pl += temp;\r
655                                 if( pl < temp ) ph += 1; /* Carry */\r
656 \r
657                                 M_PUSH( pl );\r
658                                 TOS = ph;\r
659                         }\r
660                         endcase;\r
661                         \r
662 /* Perform 32*32 bit multiply for 64 bit result, using shift and add. */\r
663                 case ID_D_MTIMES:  /* M* ( a b -- pl ph ) */ \r
664                         {\r
665                                 cell a,b;\r
666                                 ucell ap,bp, ahi, alo, bhi, blo, temp;\r
667                                 ucell pl, ph;\r
668 /* Get values from stack. */\r
669                                 a = M_POP;\r
670                                 b = TOS;\r
671                                 ap = (a < 0) ? -a : a ; /* Positive A */\r
672                                 bp = (b < 0) ? -b : b ; /* Positive B */\r
673 /* Break into hi and lo 16 bit parts. */\r
674                                 alo = ap & 0xFFFF;\r
675                                 ahi = ap>>16;\r
676                                 blo = bp & 0xFFFF;\r
677                                 bhi = bp>>16;\r
678                                 ph = 0;\r
679 /* ahi * bhi */\r
680                                 pl = ahi * bhi;\r
681                                 ph = pl >> 16;  /* shift 64 bit value by 16 */\r
682                                 pl = pl << 16;\r
683 /* ahi * blo */\r
684                                 temp = ahi * blo;\r
685                                 pl += temp;\r
686                                 if( pl < temp ) ph += 1; /* Carry */\r
687 /* alo * bhi  */\r
688                                 temp = alo * bhi;\r
689                                 pl += temp;\r
690                                 if( pl < temp ) ph += 1; /* Carry */\r
691                                 ph = (ph << 16) | (pl >> 16); /* shift 64 bit value by 16 */\r
692                                 pl = pl << 16;\r
693 /* alo * blo */\r
694                                 temp = alo * blo;\r
695                                 pl += temp;\r
696                                 if( pl < temp ) ph += 1; /* Carry */\r
697 \r
698 /* Negate product if one operand negative. */\r
699                                 if( ((a ^ b) & 0x80000000) )\r
700                                 {\r
701                                         pl = 0-pl;\r
702                                         if( pl & 0x80000000 )\r
703                                         {\r
704                                                 ph = -1 - ph;   /* Borrow */\r
705                                         }\r
706                                         else\r
707                                         {\r
708                                                 ph = 0 - ph;\r
709                                         }\r
710                                 }\r
711 \r
712                                 M_PUSH( pl );\r
713                                 TOS = ph;\r
714                         }\r
715                         endcase;\r
716 \r
717 #define DULT(du1l,du1h,du2l,du2h) ( (du2h<du1h) ? FALSE : ( (du2h==du1h) ? (du1l<du2l) : TRUE) )\r
718 /* Perform 64/32 bit divide for 32 bit result, using shift and subtract. */\r
719                 case ID_D_UMSMOD:  /* UM/MOD ( al ah bdiv -- rem q ) */ \r
720                         {\r
721                                 ucell ah,al, q,di, bl,bh, sl,sh;\r
722                                 ah = M_POP;\r
723                                 al = M_POP;\r
724                                 bh = TOS;\r
725                                 bl = 0;\r
726                                 q = 0;\r
727                                 for( di=0; di<32; di++ )\r
728                                 {\r
729                                         if( !DULT(al,ah,bl,bh) )\r
730                                         {\r
731                                                 sh = 0;\r
732                                                 sl = al - bl;\r
733                                                 if( al < bl ) sh = 1; /* Borrow */\r
734                                                 sh = ah - bh - sh;\r
735                                                 ah = sh;\r
736                                                 al = sl;\r
737                                                 q |= 1;\r
738                                         }\r
739                                         q = q << 1;\r
740                                         bl = (bl >> 1) | (bh << 31);\r
741                                         bh = bh >> 1;\r
742                                 }\r
743                                 if( !DULT(al,ah,bl,bh) )\r
744                                 {\r
745                                 \r
746                                         al = al - bl;\r
747                                         q |= 1;\r
748                                 }\r
749                                 M_PUSH( al );  /* rem */\r
750                                 TOS = q;\r
751                         }\r
752                         endcase;\r
753 \r
754 /* Perform 64/32 bit divide for 64 bit result, using shift and subtract. */\r
755                 case ID_D_MUSMOD:  /* MU/MOD ( al am bdiv -- rem ql qh ) */ \r
756                         {\r
757                                 register ucell ah,am,al,ql,qh,di;\r
758 #define bdiv ((ucell)TOS)\r
759                                 ah = 0;\r
760                                 am = M_POP;\r
761                                 al = M_POP;\r
762                                 qh = ql = 0;\r
763                                 for( di=0; di<64; di++ )\r
764                                 {\r
765                                         if( bdiv <= ah )\r
766                                         {\r
767                                                 ah = ah - bdiv;\r
768                                                 ql |= 1;\r
769                                         }\r
770                                         qh = (qh << 1) | (ql >> 31);\r
771                                         ql = ql << 1;\r
772                                         ah = (ah << 1) | (am >> 31);\r
773                                         am = (am << 1) | (al >> 31);\r
774                                         al = al << 1;\r
775 DBUG(("XX ah,m,l = 0x%8x,%8x,%8x - qh,l = 0x%8x,%8x\n", ah,am,al, qh,ql ));\r
776                                 }\r
777                                 if( bdiv <= ah )\r
778                                 {\r
779                                         ah = ah - bdiv;\r
780                                         ql |= 1;\r
781                                 }\r
782                                 M_PUSH( ah ); /* rem */\r
783                                 M_PUSH( ql );\r
784                                 TOS = qh;\r
785 #undef bdiv\r
786                         }\r
787                         endcase;\r
788 \r
789 #ifndef PF_NO_SHELL\r
790                 case ID_DEFER:\r
791                         ffDefer( );\r
792                         endcase;\r
793 #endif  /* !PF_NO_SHELL */\r
794 \r
795                 case ID_DEFER_P:\r
796                         endcase;\r
797 \r
798                 case ID_DEPTH:\r
799                         PUSH_TOS;\r
800                         TOS = gCurrentTask->td_StackBase - STKPTR;\r
801                         endcase;\r
802                         \r
803                 case ID_DIVIDE:     BINARY_OP( / ); endcase;\r
804                         \r
805                 case ID_DOT:\r
806                         ffDot( TOS );\r
807                         M_DROP;\r
808                         endcase;\r
809                         \r
810                 case ID_DOTS:\r
811                         M_DOTS;\r
812                         endcase;\r
813                         \r
814                 case ID_DROP:  M_DROP; endcase;\r
815                         \r
816                 case ID_DUMP:\r
817                         Scratch = M_POP;\r
818                         DumpMemory( (char *) Scratch, TOS );\r
819                         M_DROP;\r
820                         endcase;\r
821 \r
822                 case ID_DUP:   M_DUP; endcase;\r
823                 \r
824                 case ID_DO_P: /* ( limit start -- ) ( R: -- start limit ) */\r
825                         M_R_PUSH( TOS );\r
826                         M_R_PUSH( M_POP );\r
827                         M_DROP;\r
828                         endcase;\r
829                         \r
830                 case ID_EOL:    /* ( -- end_of_line_char ) */\r
831                         PUSH_TOS;\r
832                         TOS = (cell) '\n';\r
833                         endcase;\r
834                         \r
835                 case ID_ERRORQ_P:  /* ( flag num -- , quit if flag true ) */\r
836                         Scratch = TOS;\r
837                         M_DROP;\r
838                         if(TOS)\r
839                         {\r
840                                 M_THROW(Scratch);\r
841                         }\r
842                         else\r
843                         {\r
844                                 M_DROP;\r
845                         }\r
846                         endcase;\r
847                         \r
848                 case ID_EMIT_P:\r
849                         EMIT( (char) TOS );\r
850                         M_DROP;\r
851                         endcase;\r
852                         \r
853                 case ID_EXECUTE:\r
854 /* Save IP on return stack like a JSR. */\r
855                         M_R_PUSH( InsPtr );\r
856 #ifdef PF_SUPPORT_TRACE\r
857 /* Bump level for trace. */\r
858                         Level++;\r
859 #endif\r
860                         if( IsTokenPrimitive( TOS ) )\r
861                         {\r
862                                 WRITE_LONG_DIC( (cell *) &FakeSecondary[0], TOS);   /* Build a fake secondary and execute it. */\r
863                                 InsPtr = &FakeSecondary[0];\r
864                         }\r
865                         else\r
866                         {\r
867                                 InsPtr = (cell *) LOCAL_CODEREL_TO_ABS(TOS);\r
868                         }\r
869                         M_DROP;\r
870                         endcase;\r
871                         \r
872                 case ID_FETCH:\r
873 #if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC))\r
874                         if( IN_DICS( TOS ) )\r
875                         {\r
876                                 TOS = (cell) READ_LONG_DIC((cell *)TOS);\r
877                         }\r
878                         else\r
879                         {\r
880                                 TOS = *((cell *)TOS);\r
881                         }\r
882 #else\r
883                         TOS = *((cell *)TOS);\r
884 #endif\r
885                         endcase;\r
886                 \r
887                 case ID_FILE_CREATE: /* ( c-addr u fam -- fid ior ) */\r
888 /* Build NUL terminated name string. */\r
889                         Scratch = M_POP; /* u */\r
890                         Temp = M_POP;    /* caddr */\r
891                         if( Scratch < TIB_SIZE-2 )\r
892                         {\r
893                                 const char *famText = pfSelectFileMode( TOS );\r
894                                 pfCopyMemory( gScratch, (char *) Temp, (uint32) Scratch );\r
895                                 gScratch[Scratch] = '\0';\r
896                                 DBUG(("Create file = %s\n", gScratch ));\r
897                                 FileID = sdOpenFile( gScratch, famText );\r
898                                 TOS = ( FileID == NULL ) ? -1 : 0 ;\r
899                                 M_PUSH( (cell) FileID );\r
900                         }\r
901                         else\r
902                         {\r
903                                 ERR("Filename too large for name buffer.\n");\r
904                                 M_PUSH( 0 );\r
905                                 TOS = -2;\r
906                         }\r
907                         endcase;\r
908 \r
909                 case ID_FILE_OPEN: /* ( c-addr u fam -- fid ior ) */\r
910 /* Build NUL terminated name string. */\r
911                         Scratch = M_POP; /* u */\r
912                         Temp = M_POP;    /* caddr */\r
913                         if( Scratch < TIB_SIZE-2 )\r
914                         {\r
915                                 const char *famText = pfSelectFileMode( TOS );\r
916                                 pfCopyMemory( gScratch, (char *) Temp, (uint32) Scratch );\r
917                                 gScratch[Scratch] = '\0';\r
918                                 DBUG(("Open file = %s\n", gScratch ));\r
919                                 FileID = sdOpenFile( gScratch, famText );\r
920 \r
921                                 TOS = ( FileID == NULL ) ? -1 : 0 ;\r
922                                 M_PUSH( (cell) FileID );\r
923                         }\r
924                         else\r
925                         {\r
926                                 ERR("Filename too large for name buffer.\n");\r
927                                 M_PUSH( 0 );\r
928                                 TOS = -2;\r
929                         }\r
930                         endcase;\r
931                         \r
932                 case ID_FILE_CLOSE: /* ( fid -- ior ) */\r
933                         TOS = sdCloseFile( (FileStream *) TOS );\r
934                         endcase;\r
935                                 \r
936                 case ID_FILE_READ: /* ( addr len fid -- u2 ior ) */\r
937                         FileID = (FileStream *) TOS;\r
938                         Scratch = M_POP;\r
939                         CharPtr = (char *) M_POP;\r
940                         Temp = sdReadFile( CharPtr, 1, Scratch, FileID );\r
941                         M_PUSH(Temp);\r
942                         TOS = 0;\r
943                         endcase;\r
944                                 \r
945                 case ID_FILE_SIZE: /* ( fid -- ud ior ) */\r
946 /* Determine file size by seeking to end and returning position. */\r
947                         FileID = (FileStream *) TOS;\r
948                         Scratch = sdTellFile( FileID );\r
949                         sdSeekFile( FileID, 0, PF_SEEK_END );\r
950                         M_PUSH( sdTellFile( FileID ));\r
951                         sdSeekFile( FileID, Scratch, PF_SEEK_SET );\r
952                         TOS = (Scratch < 0) ? -4 : 0 ; /* !!! err num */\r
953                         endcase;\r
954 \r
955                 case ID_FILE_WRITE: /* ( addr len fid -- ior ) */\r
956                         FileID = (FileStream *) TOS;\r
957                         Scratch = M_POP;\r
958                         CharPtr = (char *) M_POP;\r
959                         Temp = sdWriteFile( CharPtr, 1, Scratch, FileID );\r
960                         TOS = (Temp != Scratch) ? -3 : 0;\r
961                         endcase;\r
962 \r
963                 case ID_FILE_REPOSITION: /* ( pos fid -- ior ) */\r
964                         FileID = (FileStream *) TOS;\r
965                         Scratch = M_POP;\r
966                         TOS = sdSeekFile( FileID, Scratch, PF_SEEK_SET );\r
967                         endcase;\r
968 \r
969                 case ID_FILE_POSITION: /* ( pos fid -- ior ) */\r
970                         M_PUSH( sdTellFile( (FileStream *) TOS ));\r
971                         TOS = 0;\r
972                         endcase;\r
973 \r
974                 case ID_FILE_RO: /* (  -- fam ) */\r
975                         PUSH_TOS;\r
976                         TOS = PF_FAM_READ_ONLY;\r
977                         endcase;\r
978                                 \r
979                 case ID_FILE_RW: /* ( -- fam ) */\r
980                         PUSH_TOS;\r
981                         TOS = PF_FAM_READ_WRITE;\r
982                         endcase;\r
983 \r
984                 case ID_FILE_WO: /* ( -- fam ) */\r
985                         PUSH_TOS;\r
986                         TOS = PF_FAM_WRITE_ONLY;\r
987                         endcase;\r
988 \r
989                 case ID_FILE_BIN: /* ( -- fam ) */\r
990                         TOS = TOS | PF_FAM_BINARY_FLAG;\r
991                         endcase;\r
992                                 \r
993                 case ID_FILL: /* ( caddr num charval -- ) */\r
994                         {\r
995                                 register char *DstPtr;\r
996                                 Temp = M_POP;    /* num */\r
997                                 DstPtr = (char *) M_POP; /* dst */\r
998                                 for( Scratch=0; (uint32) Scratch < (uint32) Temp ; Scratch++ )\r
999                                 {\r
1000                                         *DstPtr++ = (char) TOS;\r
1001                                 }\r
1002                                 M_DROP;\r
1003                         }\r
1004                         endcase;\r
1005                         \r
1006 #ifndef PF_NO_SHELL\r
1007                 case ID_FIND:  /* ( $addr -- $addr 0 | xt +-1 ) */\r
1008                         TOS = ffFind( (char *) TOS, (ExecToken *) &Temp );\r
1009                         M_PUSH( Temp );\r
1010                         endcase;\r
1011                         \r
1012                 case ID_FINDNFA:\r
1013                         TOS = ffFindNFA( (const ForthString *) TOS, (const ForthString **) &Temp );\r
1014                         M_PUSH( (cell) Temp );\r
1015                         endcase;\r
1016 #endif  /* !PF_NO_SHELL */\r
1017 \r
1018                 case ID_FLUSHEMIT:\r
1019                         sdTerminalFlush();\r
1020                         endcase;\r
1021                         \r
1022 /* Validate memory before freeing. Clobber validator and first word. */\r
1023                 case ID_FREE:   /* ( addr -- result ) */\r
1024                         if( TOS == 0 )\r
1025                         {\r
1026                                 ERR("FREE passed NULL!\n");\r
1027                                 TOS = -2; /* FIXME error code */\r
1028                         }\r
1029                         else\r
1030                         {\r
1031                                 CellPtr = (cell *) TOS;\r
1032                                 CellPtr--;\r
1033                                 if( ((uint32)*CellPtr) != ((uint32)CellPtr ^ PF_MEMORY_VALIDATOR))\r
1034                                 {\r
1035                                         TOS = -2; /* FIXME error code */\r
1036                                 }\r
1037                                 else\r
1038                                 {\r
1039                                         CellPtr[0] = 0xDeadBeef;\r
1040                                         pfFreeMem((char *)CellPtr);\r
1041                                         TOS = 0;\r
1042                                 }\r
1043                         }\r
1044                         endcase;\r
1045                         \r
1046 #include "pfinnrfp.h"\r
1047 \r
1048                 case ID_HERE:\r
1049                         PUSH_TOS;\r
1050                         TOS = (cell)CODE_HERE;\r
1051                         endcase;\r
1052                 \r
1053                 case ID_NUMBERQ_P:   /* ( addr -- 0 | n 1 ) */\r
1054 /* Convert using number converter in 'C'.\r
1055 ** Only supports single precision for bootstrap.\r
1056 */\r
1057                         TOS = (cell) ffNumberQ( (char *) TOS, &Temp );\r
1058                         if( TOS == NUM_TYPE_SINGLE)\r
1059                         {\r
1060                                 M_PUSH( Temp );   /* Push single number */\r
1061                         }\r
1062                         endcase;\r
1063                         \r
1064                 case ID_I:  /* ( -- i , DO LOOP index ) */\r
1065                         PUSH_TOS;\r
1066                         TOS = M_R_PICK(1);\r
1067                         endcase;\r
1068 \r
1069 #ifndef PF_NO_SHELL\r
1070                 case ID_INCLUDE_FILE:\r
1071                         FileID = (FileStream *) TOS;\r
1072                         M_DROP;    /* Drop now so that INCLUDE has a clean stack. */\r
1073                         SAVE_REGISTERS;\r
1074                         Scratch = ffIncludeFile( FileID );\r
1075                         LOAD_REGISTERS;\r
1076                         if( Scratch ) M_THROW(Scratch)\r
1077                         endcase;\r
1078 #endif  /* !PF_NO_SHELL */\r
1079                         \r
1080 #ifndef PF_NO_SHELL\r
1081                 case ID_INTERPRET:\r
1082                         SAVE_REGISTERS;\r
1083                         Scratch = ffInterpret();\r
1084                         LOAD_REGISTERS;\r
1085                         if( Scratch ) M_THROW(Scratch)\r
1086                         endcase;\r
1087 #endif  /* !PF_NO_SHELL */\r
1088 \r
1089                 case ID_J:  /* ( -- j , second DO LOOP index ) */\r
1090                         PUSH_TOS;\r
1091                         TOS = M_R_PICK(3);\r
1092                         endcase;\r
1093 \r
1094                 case ID_KEY:\r
1095                         PUSH_TOS;\r
1096                         TOS = ioKey();\r
1097                         endcase;\r
1098                         \r
1099 #ifndef PF_NO_SHELL\r
1100                 case ID_LITERAL:\r
1101                         ffLiteral( TOS );\r
1102                         M_DROP;\r
1103                         endcase;\r
1104 #endif /* !PF_NO_SHELL */\r
1105 \r
1106                 case ID_LITERAL_P:\r
1107                         DBUG(("ID_LITERAL_P: InsPtr = 0x%x, *InsPtr = 0x%x\n", InsPtr, *InsPtr ));\r
1108                         PUSH_TOS;\r
1109                         TOS = READ_LONG_DIC(InsPtr++);\r
1110                         endcase;\r
1111         \r
1112 #ifndef PF_NO_SHELL\r
1113                 case ID_LOCAL_COMPILER: DO_VAR(gLocalCompiler_XT); endcase;\r
1114 #endif /* !PF_NO_SHELL */\r
1115 \r
1116                 case ID_LOCAL_FETCH: /* ( i <local> -- n , fetch from local ) */\r
1117                         TOS = *(LocalsPtr - TOS);\r
1118                         endcase;\r
1119 \r
1120 #define LOCAL_FETCH_N(num) \\r
1121                 case ID_LOCAL_FETCH_##num: /* ( <local> -- n , fetch from local ) */ \\r
1122                         PUSH_TOS; \\r
1123                         TOS = *(LocalsPtr -(num)); \\r
1124                         endcase;\r
1125 \r
1126                 LOCAL_FETCH_N(1);\r
1127                 LOCAL_FETCH_N(2);\r
1128                 LOCAL_FETCH_N(3);\r
1129                 LOCAL_FETCH_N(4);\r
1130                 LOCAL_FETCH_N(5);\r
1131                 LOCAL_FETCH_N(6);\r
1132                 LOCAL_FETCH_N(7);\r
1133                 LOCAL_FETCH_N(8);\r
1134                 \r
1135                 case ID_LOCAL_STORE:  /* ( n i <local> -- , store n in local ) */\r
1136                         *(LocalsPtr - TOS) = M_POP;\r
1137                         M_DROP;\r
1138                         endcase;\r
1139 \r
1140 #define LOCAL_STORE_N(num) \\r
1141                 case ID_LOCAL_STORE_##num:  /* ( n <local> -- , store n in local ) */ \\r
1142                         *(LocalsPtr - (num)) = TOS; \\r
1143                         M_DROP; \\r
1144                         endcase;\r
1145 \r
1146                 LOCAL_STORE_N(1);\r
1147                 LOCAL_STORE_N(2);\r
1148                 LOCAL_STORE_N(3);\r
1149                 LOCAL_STORE_N(4);\r
1150                 LOCAL_STORE_N(5);\r
1151                 LOCAL_STORE_N(6);\r
1152                 LOCAL_STORE_N(7);\r
1153                 LOCAL_STORE_N(8);\r
1154                 \r
1155                 case ID_LOCAL_PLUSSTORE:  /* ( n i <local> -- , add n to local ) */\r
1156                         *(LocalsPtr - TOS) += M_POP;\r
1157                         M_DROP;\r
1158                         endcase;\r
1159                         \r
1160                 case ID_LOCAL_ENTRY: /* ( x0 x1 ... xn n -- ) */\r
1161                 /* create local stack frame */\r
1162                         {\r
1163                                 int32 i = TOS;\r
1164                                 cell *lp;\r
1165                                 DBUG(("LocalEntry: n = %d\n", TOS));\r
1166                                 /* End of locals. Create stack frame */\r
1167                                 DBUG(("LocalEntry: before RP@ = 0x%x, LP = 0x%x\n",\r
1168                                         TORPTR, LocalsPtr));\r
1169                                 M_R_PUSH(LocalsPtr);\r
1170                                 LocalsPtr = TORPTR;\r
1171                                 TORPTR -= TOS;\r
1172                                 DBUG(("LocalEntry: after RP@ = 0x%x, LP = 0x%x\n",\r
1173                                         TORPTR, LocalsPtr));\r
1174                                 lp = TORPTR;\r
1175                                 while(i-- > 0)\r
1176                                 {\r
1177                                         *lp++ = M_POP;    /* Load local vars from stack */\r
1178                                 }\r
1179                                 M_DROP;\r
1180                         }\r
1181                         endcase;\r
1182 \r
1183                 case ID_LOCAL_EXIT: /* cleanup up local stack frame */\r
1184                         DBUG(("LocalExit: before RP@ = 0x%x, LP = 0x%x\n",\r
1185                                 TORPTR, LocalsPtr));\r
1186                         TORPTR = LocalsPtr;\r
1187                         LocalsPtr = (cell *) M_R_POP;\r
1188                         DBUG(("LocalExit: after RP@ = 0x%x, LP = 0x%x\n",\r
1189                                 TORPTR, LocalsPtr));\r
1190                         endcase;\r
1191                         \r
1192 #ifndef PF_NO_SHELL\r
1193                 case ID_LOADSYS:\r
1194                         MSG("Load "); MSG(SYSTEM_LOAD_FILE); EMIT_CR;\r
1195                         FileID = sdOpenFile(SYSTEM_LOAD_FILE, "r");\r
1196                         if( FileID )\r
1197                         {\r
1198                                 SAVE_REGISTERS;\r
1199                                 Scratch = ffIncludeFile( FileID );\r
1200                                 LOAD_REGISTERS;\r
1201                                 sdCloseFile( FileID );\r
1202                                 if( Scratch ) M_THROW(Scratch);\r
1203                         }\r
1204                         else\r
1205                         {\r
1206                                  ERR(SYSTEM_LOAD_FILE); ERR(" could not be opened!\n");\r
1207                         }\r
1208                         endcase;\r
1209 #endif  /* !PF_NO_SHELL */\r
1210 \r
1211                 case ID_LEAVE_P: /* ( R: index limit --  ) */\r
1212                         M_R_DROP;\r
1213                         M_R_DROP;\r
1214                         M_BRANCH;\r
1215                         endcase;\r
1216 \r
1217                 case ID_LOOP_P: /* ( R: index limit -- | index limit ) */\r
1218                         Temp = M_R_POP; /* limit */\r
1219                         Scratch = M_R_POP + 1; /* index */\r
1220                         if( Scratch == Temp )\r
1221                         {\r
1222                                 InsPtr++;   /* skip branch offset, exit loop */\r
1223                         }\r
1224                         else\r
1225                         {\r
1226 /* Push index and limit back to R */\r
1227                                 M_R_PUSH( Scratch );\r
1228                                 M_R_PUSH( Temp );\r
1229 /* Branch back to just after (DO) */\r
1230                                 M_BRANCH;\r
1231                         }\r
1232                         endcase;\r
1233                                 \r
1234                 case ID_LSHIFT:     BINARY_OP( << ); endcase;\r
1235                 \r
1236                 case ID_MAX:\r
1237                         Scratch = M_POP;\r
1238                         TOS = ( TOS > Scratch ) ? TOS : Scratch ;\r
1239                         endcase;\r
1240                         \r
1241                 case ID_MIN:\r
1242                         Scratch = M_POP;\r
1243                         TOS = ( TOS < Scratch ) ? TOS : Scratch ;\r
1244                         endcase;\r
1245                         \r
1246                 case ID_MINUS:     BINARY_OP( - ); endcase;\r
1247                         \r
1248 #ifndef PF_NO_SHELL\r
1249                 case ID_NAME_TO_TOKEN:\r
1250                         TOS = (cell) NameToToken((ForthString *)TOS);\r
1251                         endcase;\r
1252                         \r
1253                 case ID_NAME_TO_PREVIOUS:\r
1254                         TOS = (cell) NameToPrevious((ForthString *)TOS);\r
1255                         endcase;\r
1256 #endif\r
1257                         \r
1258                 case ID_NOOP:\r
1259                         endcase;\r
1260                         \r
1261                 case ID_OR:     BINARY_OP( | ); endcase;\r
1262                 \r
1263                 case ID_OVER:\r
1264                         PUSH_TOS;\r
1265                         TOS = M_STACK(1);\r
1266                         endcase;\r
1267                         \r
1268                 case ID_PICK: /* ( ... n -- sp(n) ) */\r
1269                         TOS = M_STACK(TOS);\r
1270                         endcase;\r
1271 \r
1272                 case ID_PLUS:     BINARY_OP( + ); endcase;\r
1273                 \r
1274                 case ID_PLUS_STORE:   /* ( n addr -- , add n to *addr ) */\r
1275 #if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC))\r
1276                         if( IN_DICS( TOS ) )\r
1277                         {\r
1278                                 Scratch = READ_LONG_DIC((cell *)TOS);\r
1279                                 Scratch += M_POP;\r
1280                                 WRITE_LONG_DIC((cell *)TOS,Scratch);\r
1281                         }\r
1282                         else\r
1283                         {\r
1284                                 *((cell *)TOS) += M_POP;\r
1285                         }\r
1286 #else\r
1287                         *((cell *)TOS) += M_POP;\r
1288 #endif\r
1289                         M_DROP;\r
1290                         endcase;\r
1291 \r
1292                 case ID_PLUSLOOP_P: /* ( delta -- ) ( R: index limit -- | index limit ) */\r
1293                         {\r
1294                                 ucell OldIndex, NewIndex, Limit;\r
1295 \r
1296                                 Limit = M_R_POP;\r
1297                                 OldIndex = M_R_POP;\r
1298                                 NewIndex = OldIndex + TOS; /* add TOS to index, not 1 */\r
1299 /* Do indices cross boundary between LIMIT-1 and LIMIT ? */\r
1300                                 if( ( (OldIndex - Limit) & ((Limit-1) - NewIndex) & 0x80000000 ) ||\r
1301                                     ( (NewIndex - Limit) & ((Limit-1) - OldIndex) & 0x80000000 ) )\r
1302                                 {\r
1303                                         InsPtr++;   /* skip branch offset, exit loop */\r
1304                                 }\r
1305                                 else\r
1306                                 {\r
1307 /* Push index and limit back to R */\r
1308                                         M_R_PUSH( NewIndex );\r
1309                                         M_R_PUSH( Limit );\r
1310 /* Branch back to just after (DO) */\r
1311                                         M_BRANCH;\r
1312                                 }\r
1313                                 M_DROP;\r
1314                         }\r
1315                         endcase;\r
1316 \r
1317                 case ID_QDO_P: /* (?DO) ( limit start -- ) ( R: -- start limit ) */\r
1318                         Scratch = M_POP;  /* limit */\r
1319                         if( Scratch == TOS )\r
1320                         {\r
1321 /* Branch to just after (LOOP) */\r
1322                                 M_BRANCH;\r
1323                         }\r
1324                         else\r
1325                         {\r
1326                                 M_R_PUSH( TOS );\r
1327                                 M_R_PUSH( Scratch );\r
1328                                 InsPtr++;   /* skip branch offset, enter loop */\r
1329                         }\r
1330                         M_DROP;\r
1331                         endcase;\r
1332 \r
1333                 case ID_QDUP:     if( TOS ) M_DUP; endcase;\r
1334 \r
1335                 case ID_QTERMINAL:  /* WARNING: Typically not fully implemented! */\r
1336                         PUSH_TOS;\r
1337                         TOS = sdQueryTerminal();\r
1338                         endcase;\r
1339                 \r
1340                 case ID_QUIT_P: /* Stop inner interpreter, go back to user. */\r
1341 #ifdef PF_SUPPORT_TRACE\r
1342                         Level = 0;\r
1343 #endif\r
1344                         M_THROW(THROW_QUIT);\r
1345                         endcase;\r
1346                         \r
1347                 case ID_R_DROP:\r
1348                         M_R_DROP;\r
1349                         endcase;\r
1350 \r
1351                 case ID_R_FETCH:\r
1352                         PUSH_TOS;\r
1353                         TOS = (*(TORPTR));\r
1354                         endcase;\r
1355                 \r
1356                 case ID_R_FROM:\r
1357                         PUSH_TOS;\r
1358                         TOS = M_R_POP;\r
1359                         endcase;\r
1360                         \r
1361                 case ID_REFILL:\r
1362                         PUSH_TOS;\r
1363                         TOS = (ffRefill() > 0) ? FTRUE : FFALSE;\r
1364                         endcase;\r
1365                         \r
1366 /* Resize memory allocated by ALLOCATE. */\r
1367                 case ID_RESIZE:  /* ( addr1 u -- addr2 result ) */\r
1368                         {\r
1369                                 cell *FreePtr;\r
1370                                 \r
1371                                 FreePtr = (cell *) ( M_POP - sizeof(cell) );\r
1372                                 if( ((uint32)*FreePtr) != ((uint32)FreePtr ^ PF_MEMORY_VALIDATOR))\r
1373                                 {\r
1374                                         M_PUSH( 0 );\r
1375                                         TOS = -3;\r
1376                                 }\r
1377                                 else\r
1378                                 {\r
1379                                         /* Try to allocate. */\r
1380                                         CellPtr = (cell *) pfAllocMem( TOS + sizeof(cell) );\r
1381                                         if( CellPtr )\r
1382                                         {\r
1383                                                 /* Copy memory including validation. */\r
1384                                                 pfCopyMemory( (char *) CellPtr, (char *) FreePtr, TOS + sizeof(cell) );\r
1385                                                 *CellPtr = (cell)(((uint32)CellPtr) ^ (uint32)PF_MEMORY_VALIDATOR);\r
1386                                                 CellPtr++;\r
1387                                     M_PUSH( (cell) ++CellPtr );\r
1388                                                 TOS = 0;\r
1389                                                 FreePtr[0] = 0xDeadBeef;\r
1390                                                 pfFreeMem((char *) FreePtr);\r
1391                                         }\r
1392                                         else\r
1393                                         {\r
1394                                                 M_PUSH( 0 );\r
1395                                                 TOS = -4;  /* FIXME Fix error code. */\r
1396                                         }\r
1397                                 }\r
1398                         }\r
1399                         endcase;\r
1400                                 \r
1401 /*\r
1402 ** RP@ and RP! are called secondaries so we must\r
1403 ** account for the return address pushed before calling.\r
1404 */\r
1405                 case ID_RP_FETCH:    /* ( -- rp , address of top of return stack ) */\r
1406                         PUSH_TOS;\r
1407                         TOS = (cell)TORPTR;  /* value before calling RP@ */\r
1408                         endcase;\r
1409                         \r
1410                 case ID_RP_STORE:    /* ( rp -- , address of top of return stack ) */\r
1411                         TORPTR = (cell *) TOS;\r
1412                         M_DROP;\r
1413                         endcase;\r
1414                         \r
1415                 case ID_ROLL: /* ( xu xu-1 xu-1 ... x0 u -- xu-1 xu-1 ... x0 xu ) */\r
1416                         {\r
1417                                 int32 ri;\r
1418                                 cell *srcPtr, *dstPtr;\r
1419                                 Scratch = M_STACK(TOS);\r
1420                                 srcPtr = &M_STACK(TOS-1);\r
1421                                 dstPtr = &M_STACK(TOS);\r
1422                                 for( ri=0; ri<TOS; ri++ )\r
1423                                 {\r
1424                                         *dstPtr-- = *srcPtr--;\r
1425                                 }\r
1426                                 TOS = Scratch;\r
1427                                 STKPTR++;\r
1428                         }\r
1429                         endcase;\r
1430 \r
1431                 case ID_ROT:  /* ( a b c -- b c a ) */\r
1432                         Scratch = M_POP;    /* b */\r
1433                         Temp = M_POP;       /* a */\r
1434                         M_PUSH( Scratch );  /* b */\r
1435                         PUSH_TOS;           /* c */\r
1436                         TOS = Temp;         /* a */\r
1437                         endcase;\r
1438 \r
1439 /* Logical right shift */\r
1440                 case ID_RSHIFT:     { TOS = ((uint32)M_POP) >> TOS; } endcase;   \r
1441                 \r
1442 #ifndef PF_NO_SHELL\r
1443                 case ID_SAVE_FORTH_P:   /* ( $name Entry NameSize CodeSize -- err ) */\r
1444                         {\r
1445                                 int32 NameSize, CodeSize, EntryPoint;\r
1446                                 CodeSize = TOS;\r
1447                                 NameSize = M_POP;\r
1448                                 EntryPoint = M_POP;\r
1449                                 ForthStringToC( gScratch, (char *) M_POP );\r
1450                                 TOS =  ffSaveForth( gScratch, EntryPoint, NameSize, CodeSize );\r
1451                         }\r
1452                         endcase;\r
1453 #endif\r
1454 \r
1455 /* Source     Stack\r
1456 ** EVALUATE    >IN  SourceID=(-1)  1111\r
1457 ** keyboard    >IN  SourceID=(0)   2222\r
1458 ** file        >IN  lineNumber filePos  SourceID=(fileID)\r
1459 */\r
1460                 case ID_SAVE_INPUT:  /* FIXME - finish */\r
1461                         {\r
1462                         }\r
1463                         endcase;\r
1464 \r
1465                 case ID_SP_FETCH:    /* ( -- sp , address of top of stack, sorta ) */\r
1466                         PUSH_TOS;\r
1467                         TOS = (cell)STKPTR;\r
1468                         endcase;\r
1469                         \r
1470                 case ID_SP_STORE:    /* ( sp -- , address of top of stack, sorta ) */\r
1471                         STKPTR = (cell *) TOS;\r
1472                         M_DROP;\r
1473                         endcase;\r
1474                         \r
1475                 case ID_STORE: /* ( n addr -- , write n to addr ) */\r
1476 #if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC))\r
1477                         if( IN_DICS( TOS ) )\r
1478                         {\r
1479                                 WRITE_LONG_DIC((cell *)TOS,M_POP);\r
1480                         }\r
1481                         else\r
1482                         {\r
1483                                 *((cell *)TOS) = M_POP;\r
1484                         }\r
1485 #else\r
1486                         *((cell *)TOS) = M_POP;\r
1487 #endif\r
1488                         M_DROP;\r
1489                         endcase;\r
1490 \r
1491                 case ID_SCAN: /* ( addr cnt char -- addr' cnt' ) */\r
1492                         Scratch = M_POP; /* cnt */\r
1493                         Temp = M_POP;    /* addr */\r
1494                         TOS = ffScan( (char *) Temp, Scratch, (char) TOS, &CharPtr );\r
1495                         M_PUSH((cell) CharPtr);\r
1496                         endcase;\r
1497                         \r
1498 #ifndef PF_NO_SHELL\r
1499                 case ID_SEMICOLON:\r
1500                         SAVE_REGISTERS;\r
1501                         Scratch = ffSemiColon();\r
1502                         LOAD_REGISTERS;\r
1503                         if( Scratch ) M_THROW( Scratch );\r
1504                         endcase;\r
1505 #endif /* !PF_NO_SHELL */\r
1506                         \r
1507                 case ID_SKIP: /* ( addr cnt char -- addr' cnt' ) */\r
1508                         Scratch = M_POP; /* cnt */\r
1509                         Temp = M_POP;    /* addr */\r
1510                         TOS = ffSkip( (char *) Temp, Scratch, (char) TOS, &CharPtr );\r
1511                         M_PUSH((cell) CharPtr);\r
1512                         endcase;\r
1513 \r
1514                 case ID_SOURCE:  /* ( -- c-addr num ) */\r
1515                         PUSH_TOS;\r
1516                         M_PUSH( (cell) gCurrentTask->td_SourcePtr );\r
1517                         TOS = (cell) gCurrentTask->td_SourceNum;\r
1518                         endcase;\r
1519                         \r
1520                 case ID_SOURCE_SET: /* ( c-addr num -- ) */\r
1521                         gCurrentTask->td_SourcePtr = (char *) M_POP;\r
1522                         gCurrentTask->td_SourceNum = TOS;\r
1523                         M_DROP;\r
1524                         endcase;\r
1525                         \r
1526                 case ID_SOURCE_ID:\r
1527                         PUSH_TOS;\r
1528                         TOS = ffConvertStreamToSourceID( gCurrentTask->td_InputStream ) ;\r
1529                         endcase;\r
1530                         \r
1531                 case ID_SOURCE_ID_POP:\r
1532                         PUSH_TOS;\r
1533                         TOS = ffConvertStreamToSourceID( ffPopInputStream() ) ;\r
1534                         endcase;\r
1535                         \r
1536                 case ID_SOURCE_ID_PUSH:  /* ( source-id -- ) */\r
1537                         TOS = (cell)ffConvertSourceIDToStream( TOS );\r
1538                         Scratch = ffPushInputStream((FileStream *) TOS );\r
1539                         if( Scratch )\r
1540                         {\r
1541                                 M_THROW(Scratch);\r
1542                         }\r
1543                         else M_DROP;\r
1544                         endcase;\r
1545                         \r
1546                 case ID_SWAP:\r
1547                         Scratch = TOS;\r
1548                         TOS = *STKPTR;\r
1549                         *STKPTR = Scratch;\r
1550                         endcase;\r
1551                         \r
1552                 case ID_TEST1:\r
1553                         PUSH_TOS;\r
1554                         M_PUSH( 0x11 );\r
1555                         M_PUSH( 0x22 );\r
1556                         TOS = 0x33;\r
1557                         endcase;\r
1558 \r
1559                 case ID_TEST2:\r
1560                         endcase;\r
1561 \r
1562                 case ID_THROW:  /* ( k*x err -- k*x | i*x err , jump to where CATCH was called ) */\r
1563                         if(TOS)\r
1564                         {\r
1565                                 M_THROW(TOS);\r
1566                         }\r
1567                         else M_DROP;\r
1568                         endcase;\r
1569 \r
1570 #ifndef PF_NO_SHELL\r
1571                 case ID_TICK:\r
1572                         PUSH_TOS;\r
1573                         CharPtr = (char *) ffWord( (char) ' ' );\r
1574                         TOS = ffFind( CharPtr, (ExecToken *) &Temp );\r
1575                         if( TOS == 0 )\r
1576                         {\r
1577                                 ERR("' could not find ");\r
1578                                 ioType( (char *) CharPtr+1, *CharPtr );\r
1579                                 M_THROW(-13);\r
1580                         }\r
1581                         else\r
1582                         {\r
1583                                 TOS = Temp;\r
1584                         }\r
1585                         endcase;\r
1586 #endif  /* !PF_NO_SHELL */\r
1587                         \r
1588                 case ID_TIMES: BINARY_OP( * ); endcase;\r
1589                         \r
1590                 case ID_TYPE:\r
1591                         Scratch = M_POP; /* addr */\r
1592                         ioType( (char *) Scratch, TOS );\r
1593                         M_DROP;\r
1594                         endcase;\r
1595 \r
1596                 case ID_TO_R:\r
1597                         M_R_PUSH( TOS );\r
1598                         M_DROP;\r
1599                         endcase;\r
1600 \r
1601                 case ID_VAR_BASE: DO_VAR(gVarBase); endcase;\r
1602                 case ID_VAR_CODE_BASE: DO_VAR(gCurrentDictionary->dic_CodeBase); endcase;\r
1603                 case ID_VAR_CODE_LIMIT: DO_VAR(gCurrentDictionary->dic_CodeLimit); endcase;\r
1604                 case ID_VAR_CONTEXT: DO_VAR(gVarContext); endcase;\r
1605                 case ID_VAR_DP: DO_VAR(gCurrentDictionary->dic_CodePtr.Cell); endcase;\r
1606                 case ID_VAR_ECHO: DO_VAR(gVarEcho); endcase;\r
1607                 case ID_VAR_HEADERS_BASE: DO_VAR(gCurrentDictionary->dic_HeaderBase); endcase;\r
1608                 case ID_VAR_HEADERS_LIMIT: DO_VAR(gCurrentDictionary->dic_HeaderLimit); endcase;\r
1609                 case ID_VAR_HEADERS_PTR: DO_VAR(gCurrentDictionary->dic_HeaderPtr.Cell); endcase;\r
1610                 case ID_VAR_NUM_TIB: DO_VAR(gCurrentTask->td_SourceNum); endcase;\r
1611                 case ID_VAR_OUT: DO_VAR(gCurrentTask->td_OUT); endcase;\r
1612                 case ID_VAR_STATE: DO_VAR(gVarState); endcase;\r
1613                 case ID_VAR_TO_IN: DO_VAR(gCurrentTask->td_IN); endcase;\r
1614                 case ID_VAR_TRACE_FLAGS: DO_VAR(gVarTraceFlags); endcase;\r
1615                 case ID_VAR_TRACE_LEVEL: DO_VAR(gVarTraceLevel); endcase;\r
1616                 case ID_VAR_TRACE_STACK: DO_VAR(gVarTraceStack); endcase;\r
1617                 case ID_VAR_RETURN_CODE: DO_VAR(gVarReturnCode); endcase;\r
1618 \r
1619                 case ID_WORD:\r
1620                         TOS = (cell) ffWord( (char) TOS );\r
1621                         endcase;\r
1622 \r
1623                 case ID_WORD_FETCH: /* ( waddr -- w ) */\r
1624 #if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC))\r
1625                         if( IN_DICS( TOS ) )\r
1626                         {\r
1627                                 TOS = (uint16) READ_SHORT_DIC((uint16 *)TOS);\r
1628                         }\r
1629                         else\r
1630                         {\r
1631                                 TOS = *((uint16 *)TOS);\r
1632                         }\r
1633 #else\r
1634                         TOS = *((uint16 *)TOS);\r
1635 #endif\r
1636                         endcase;\r
1637 \r
1638                 case ID_WORD_STORE: /* ( w waddr -- ) */\r
1639                         \r
1640 #if (defined(PF_BIG_ENDIAN_DIC) || defined(PF_LITTLE_ENDIAN_DIC))\r
1641                         if( IN_DICS( TOS ) )\r
1642                         {\r
1643                                 WRITE_SHORT_DIC((uint16 *)TOS,(uint16)M_POP);\r
1644                         }\r
1645                         else\r
1646                         {\r
1647                                 *((uint16 *)TOS) = (uint16) M_POP;\r
1648                         }\r
1649 #else\r
1650                         *((uint16 *)TOS) = (uint16) M_POP;\r
1651 #endif\r
1652                         M_DROP;\r
1653                         endcase;\r
1654 \r
1655                 case ID_XOR: BINARY_OP( ^ ); endcase;\r
1656                                 \r
1657                                 \r
1658 /* Branch is followed by an offset relative to address of offset. */\r
1659                 case ID_ZERO_BRANCH:\r
1660 DBUGX(("Before 0Branch: IP = 0x%x\n", InsPtr ));\r
1661                         if( TOS == 0 )\r
1662                         {\r
1663                                 M_BRANCH;\r
1664                         }\r
1665                         else\r
1666                         {\r
1667                                 InsPtr++;      /* skip over offset */\r
1668                         }\r
1669                         M_DROP;\r
1670 DBUGX(("After 0Branch: IP = 0x%x\n", InsPtr ));\r
1671                         endcase;\r
1672                         \r
1673                 default:\r
1674                         ERR("pfCatch: Unrecognised token = 0x");\r
1675                         ffDotHex(Token);\r
1676                         ERR(" at 0x");\r
1677                         ffDotHex((int32) InsPtr);\r
1678                         EMIT_CR;\r
1679                         InsPtr = 0;\r
1680                         endcase;\r
1681                 }\r
1682                 \r
1683                 if(InsPtr) Token = READ_LONG_DIC(InsPtr++);   /* Traverse to next token in secondary. */\r
1684                 \r
1685 #ifdef PF_DEBUG\r
1686                 M_DOTS;\r
1687 #endif\r
1688 \r
1689 #if 0\r
1690                 if( _CrtCheckMemory() == 0 )\r
1691                 {\r
1692                         ERR("_CrtCheckMemory abort: InsPtr = 0x");\r
1693                         ffDotHex((int)InsPtr);\r
1694                         ERR("\n");\r
1695                 }\r
1696 #endif\r
1697 \r
1698         } while( (InitialReturnStack - TORPTR) > 0 );\r
1699 \r
1700         SAVE_REGISTERS;\r
1701         \r
1702         return ExceptionReturnCode;\r
1703 }\r