#ifndef __PFE_DEF_REGS_H
#define __PFE_DEF_REGS_H "%full_filespec: def-regs.h~bln_mpt1!5.35:incl:bln_12xx!1 %"

/** 
 * -- Declares types and variables of the virtual machine.
 *
 *  Copyright (C) Tektronix, Inc. 1998 - 2001. All rights reserved.
 *
 *  @see     GNU LGPL
 *  @author  Tektronix CTE             @(#) %derived_by: guidod %
 *  @version %version: bln_mpt1!5.35 %
 *    (%date_modified: Wed Sep 11 17:01:27 2002 %)
 *
 *  @description
 *         Declares the types and variables for the Forth Virtual Machine.
 *         Using GCC these can be put into CPU registers that are
 *         valid across function calls.
 */
/*@{*/

#include <pfe/def-config.h>

/* First the register assignments if GNU-C is used. ======================== */

#if !defined __GNUC__ || defined  __STRICT_ANSI__ || defined __cplusplus
# undef PFE_USE_REGS
#elif defined PFE_WITH_REGS
# define PFE_USE_REGS PFE_WITH_REGS
#elif defined USE_REGS /* TODO: shall vanish soon*/
# define PFE_USE_REGS USE_REGS
#endif

#if defined  PFE_WITH_STATIC_REGS
#define PFE_NEED_NO_REGTH
#endif

#ifdef PFE_CALL_THREADING
# undef P4_NEED_NO_REGW
#endif

#if defined PFE_SBR_CALL_THREADING && defined __GNUC__
#define PFE_SBR_REAL_RETURN ((P4_REGIP_T) (__builtin_return_address(0)))
#define PFE_SBR_REAL_RFRAME ((P4_REGRP_T) (__builtin_frame_address(0)))
#endif

#if defined PFE_USE_REGS && PFE_USE_REGS

/* ___________________________________________________  ARCH_I386  ______ */
# if defined HOST_CPU_I386 || defined HOST_CPU_I486 \
  || defined HOST_CPU_I586 || defined HOST_CPU_I686 \
  || defined HOST_ARCH_I386 || defined __target_arch_i386
# define PFE_HOST_ARCH_I386 1
# ifdef  PFE_SBR_CALL_THREADING
# define PFE_NEED_NO_REGIP
# define PFE_NEED_NO_REGRP
# endif

/* gcc 2.95.x is broken !!! it will just mark global-regs as not being
 * in use for a scratch-register - which makes him believe that one can
 * save the thing to the stack and reuse it, even across calls. #$%&!
 * If you need performance on ia32-gcc, use gcc 2.8.x, here we will
 * just take care to be atleast multithreaded. It seems that gcc 2.95.x
 * does not like the %ebp register for some other reasons. Then again,
 * who cares, we have a need for it, so we can use it here 
 */

/* register %esi/%edi is used for many builtin operations in gcc 2.9x 
 * (e.g. strcpy), so may be one has to use -fno-builtin with gcc 2.9x.
 */
#  if (__GNUC__ == 2 && __GNUC_MINOR__ >= 9)
#   define PFE_DO_OMIT_EDI
#   define PFE_DO_OMIT_ESI
#  endif

/* %ebx is used by shared-lib handling on linux - avoid it */
# if defined HOST_WIN32 || ! defined PFE_ENABLE_SHARED
# define PFE_CAN_USE_EBX
# endif

/* -fomit-frame-pointer interferes heavily with the needed gcc 
 *  extensions __builtin_frame_pointer /__builtin_return_addres 
 */
# if defined PFE_SBR_CALL_THREADING && ! defined PFE_SBR_CALL_ARG_PREFIXING
# define PFE_DO_OMIT_EBP
# endif

# if defined HOST_OS_AIX1 && !defined PFE_DO_OMIT_EBP
# define PFE_DO_OMIT_EBP
# endif

# if defined __newstuff__
# if !defined PFE_DO_OMIT_EBP && !defined PFE_OMIT_FRAME_POINTER
# define PFE_DO_OMIT_EBP
# endif
# endif

# ifndef PFE_DO_OMIT_EBP
# define PFE_CAN_USE_EBP  /* needs -fomit-frame-pointer */
# endif

# ifndef PFE_DO_OMIT_EDI
# define PFE_CAN_USE_EDI  /* needs -fomit-frame-pointer */
# endif

# ifndef PFE_DO_OMIT_ESI
# define PFE_CAN_USE_ESI  /* needs -fomit-frame-pointer */
# endif

/* the register-starved i386 architecture needs a loooong ifdef series */
#  if PFE_USE_REGS >= 1
#    if   ! defined PFE_NEED_NO_REGTH
#      if   defined PFE_CAN_USE_EBP
#             undef PFE_CAN_USE_EBP
#            define P4_REGTH  "%ebp"  
#      elif defined PFE_CAN_USE_EBX
#             undef PFE_CAN_USE_EBX
#            define P4_REGTH  "%ebx" 
#      else
#      error no cpu register found for regTH
#      endif
#    elif ! defined PFE_NEED_NO_REGIP
#      if   defined PFE_CAN_USE_EBP
#             undef PFE_CAN_USE_EBP
#            define P4_REGIP  "%ebp"  
#      elif defined PFE_CAN_USE_EBX
#             undef PFE_CAN_USE_EBX
#            define P4_REGIP  "%ebx" 
#      endif
#    else
#      if   defined PFE_CAN_USE_EBP
#             undef PFE_CAN_USE_EBP
#            define P4_REGSP  "%ebp"  
#      elif defined PFE_CAN_USE_EBX
#             undef PFE_CAN_USE_EBX
#            define P4_REGSP  "%ebx" 
#      endif
#    endif
#  endif

#  if PFE_USE_REGS >= 2
#    if   ! defined PFE_NEED_NO_REGIP && !defined P4_REGIP
#      if   defined PFE_CAN_USE_EBX
#             undef PFE_CAN_USE_EBX
#            define P4_REGIP  "%ebx"  
#      elif defined PFE_CAN_USE_ESI
#             undef PFE_CAN_USE_ESI
#            define P4_REGIP  "%esi" 
#      endif
#    elif ! defined PFE_NEED_NO_REGSP && !defined P4_REGSP
#      if   defined PFE_CAN_USE_EBX
#             undef PFE_CAN_USE_EBX
#            define P4_REGSP  "%ebx"  
#      elif defined PFE_CAN_USE_ESI
#             undef PFE_CAN_USE_ESI
#            define P4_REGSP  "%esi" 
#      endif
#    elif ! defined PFE_NEED_NO_REGRP && !defined P4_REGRP
#      if   defined PFE_CAN_USE_EBX
#             undef PFE_CAN_USE_EBX
#            define P4_REGRP  "%ebx"  
#      elif defined PFE_CAN_USE_ESI
#             undef PFE_CAN_USE_ESI
#            define P4_REGRP  "%esi" 
#      endif
#    endif
#  endif

#  if PFE_USE_REGS >= 3
#    if   ! defined PFE_NEED_NO_REGSP && !defined P4_REGSP
#      if   defined PFE_CAN_USE_EDI
#             undef PFE_CAN_USE_EDI
#            define P4_REGSP  "%edi"  
#      elif defined PFE_CAN_USE_ESI
#             undef PFE_CAN_USE_ESI
#            define P4_REGSP  "%esi" 
#      endif
#    elif ! defined PFE_NEED_NO_REGRP && !defined P4_REGRP
#      if   defined PFE_CAN_USE_EDI
#             undef PFE_CAN_USE_EDI
#            define P4_REGRP  "%edi"  
#      elif defined PFE_CAN_USE_ESI
#             undef PFE_CAN_USE_ESI
#            define P4_REGRP  "%esi" 
#      endif
#    endif
#  endif

/* and the SBR assembler snippets.... */
# define PFE_TAKE_CODE_RP    /* RP is taken via local setup code */
# define PFE_TAKE_IP_VIA_RP  /* IP is taken dereferencing our RP */

/* CALL-near uses relative address (from next instruction) */
#  define PFE_SBR_COMPILE_EXIT(X) *((p4char*)(X))++ = '\xC3' /* RET near    */
#  define PFE_SBR_COMPILE_CALL(X,V) { \
                                  *((p4char*)(X))++ = '\xE8' ; \
                                  *((void**)(X))++ = (void*)(V) ; \
         (((p4cell*)(X))[-1]) = (((p4char**)(X))[-1]) -  ((p4char*)(X)); }
#  define _PFE_SBR_COMPILE_CALL(X,V) { \
                                  *((p4char*)(X))++ = '\xE8' ; \
                                  *((void**)(X))++ = (void*)(V) ; \
                                (((p4char**)(X))[-1]) -= ((p4char*)(X)); }

/* #  define PFE_SBR_SET_RP(X,V) { \
 *             asm volatile ("movl %0, %%esp" :: "r" ((X)-1)); \
 *             asm volatile ("movl %0, (%%esp)" :: "r" (V)); }
 */
#     define PFE_SBR_SET_RP(X,V) { \
               asm volatile ("movl %0, %%esp" :: "r" (X)); \
               asm volatile ("push %0" :: "r" (V)); }

#  define PFE_SBR_RP (PFE_SBR_REAL_RFRAME+1)
/*#define PFE_SBR_RP (&PFE_SBR_REAL_RETURN)  */

#  ifdef  PFE_SBR_CALL_ARG_PREFIXING
#  define PFE_SBR_CALL_ARG_THREADING 1
/* "mov $imm, %eax" */
#  define P4_SBR_TAKE_BODY       asm ("%eax")
#  define FX_SBR_TAKE_BODY       /* nothing - it's an argument... */
#  define FX_SBR_GIVE_BODY(X,A)  *((p4char*)(X))++ = '\xb8' ; \
                                  *((void**)(X))++ = (void*)(A);
/* "mov %esp, %eax" */
#  define P4_SBR_TAKE_CODE       asm ("%eax")
#  define FX_SBR_TAKE_CODE       /* nothing - it's an argument... */
#  define FX_SBR_GIVE_CODE(X)    *((p4char*)(X))++ = '\x89' ; \
                                 *((p4char*)(X))++ = '\xe0' ; 
#  endif 

/* _________________________________________________  ARCH_POWERPC _____ */
# elif defined HOST_OS_AIX3 || defined HOST_CPU_POWERPC \
    || defined __target_os_aix3 || defined __target_cpu_powerpc \
    || defined HOST_ARCH_POWERPC
#   define PFE_HOST_ARCH_POWERPC 1
#   ifdef  PFE_SBR_CALL_THREADING
#   define PFE_NEED_NO_REGIP
/* #define PFE_NEED_NO_REGRP */
#   endif


#   define P4_REGTH "14"
#   define P4_REGSP "15"
#   define P4_REGRP "16"
#   define P4_REGIP "17"
#  if !defined _K12_SOURCE && PFE_USE_REGS > 2
#   define P4_REGW  "18"
#   define P4_REGLP "19"
#   define P4_REGFP "20"
#  endif

#if defined PFE_SBR_CALL_THREADING
/* and the SBR assembler snippets.... */

/* mflr r0 ; stwu r0, -4(r16) ( r16 = REGRP ) */
#  define PFE_SBR_COMPILE_PROC(X) *((p4cell*)(X))++ = 0x7c0802a6; \
                                  *((p4cell*)(X))++ = 0x9410fffc;
/* lwz r0, 0(r16) ; mtlr r0 ; addi r16,r16,4 ; blr */
#  define PFE_SBR_COMPILE_EXIT(X) *((p4cell*)(X))++ = 0x80100000; \
                                  *((p4cell*)(X))++ = 0x7c0803a6; \
                                  *((p4cell*)(X))++ = 0x3a100004; \
                                  *((p4cell*)(X))++ = 0x4e800020; 

/* opcode 0x48 is branch,  0x03 is absolute, 0x01 is relative (from the
 * branch instruction itself!), addresses have 26bit max range (no longcall) */
#  define PFE_SBR_COMPILE_CALL(X,V)  \
          { *(void**)(X) = (void*)(V); \
            if ( ((p4char*)(X))[0] <  0x02) goto __sbr_absolute; \
            if ( ((p4char*)(X))[0] >= 0x0E) goto __sbr_absolute_upper; \
            (*(p4cell*)(X)) = (*(p4char**)(X)) - ((p4char*)(X)); \
            if ( ((p4char*)(X))[0] <  0x02) goto __sbr_relative; \
            if ( ((p4char*)(X))[0] >= 0x0E) goto __sbr_relative_back; \
            P4_fail ("could not 'COMPILE,' sbr-call - using NOOP"); \
            (*(p4cell*)(X))  = 0x01; \
            goto __sbr_finalize; \
          __sbr_relative_back: \
            ((p4char*)(X))[0] &= 0x03; \
          __sbr_relative: \
            ((p4char*)(X))[3] |= 0x01; \
            goto __sbr_finalize; \
          __sbr_absolute_upper: \
            ((p4char*)(X))[0] &= 0x03; \
          __sbr_absolute: \
            ((p4char*)(X))[3] |= 0x03; \
            \
          __sbr_finalize: \
            ((p4char*)(X))[0] |= 0x48; \
            ((void**)(X))++; \
          }

#  define PFE_SBR_RP (PFE_SBR_REAL_RFRAME+1)
/*#define PFE_SBR_RP (&PFE_SBR_REAL_RETURN)  */

/* the PPC ABI is a bit weird - before calling a routine, the caller
 * is responsible to push the arguments *and* make additional room for
 * one return-address cell on top *under* its own frame-pointer savearea
 * all this is just because the branch-opcode will not save the IP into
 * the stack and the callee will not use it - unless the callee wants to
 * call another routine (or use some locals) in which case it can use 
 * the additional cell on top of the callframe. To get the caller's IP
 * we have to fetch the LR register, and changing RP must take into
 * account the additional blank cell since the C routines will expect
 * to be able to use it.
 *
 * Here we choose another model which is not along the traditional way
 * of direct-threading - we choose an extra forth RP. This makes a lot 
 * of routines easier and bypasses the weird ABI - but you can not
 * anymore place the routine as a direct callback of a system function.
 * however you did not want to do that anyway, right...
 */

# ifdef  PFE_SBR_CALL_ARG_PREFIXING
# define PFE_SBR_CALL_ARG_THREADING 1
/* # define PFE_SBR_CALL_ARG_IS_GLOBAL 1 ** not a scratch register */

#define PFE_TAKE_CODE_IP       /* the IP is taken via local setup code */
#ifndef P4_REGRP
#error  P4_REGRP still needed with this SBR-CALL-ARG threading variant
#endif

/* "load r2, $imm -> lis r2,upper ; ori r2, lower" */
#  define P4_SBR_TAKE_BODY       asm ("2")
#  define FX_SBR_TAKE_BODY       /* nothing - it's an argument... */
#  define FX_SBR_GIVE_BODY(X,A)  { register p4ucell _u = (A); \
               *((unsigned short*)(X))++ = 0x3c40 ; \
               *((unsigned short*)(X))++ = _u>>16; \
               *((unsigned short*)(X))++ = 0x6042 ; \
               *((unsigned short*)(X))++ = (unsigned short)_u ; }

/* "mr r2, r1" */
#  define P4_SBR_TAKE_CODE
#  define FX_SBR_GIVE_CODE(X)    *((p4cell*)(X))++ = 0x7c220b78;
#  define FX_SBR_TAKE_CODE  \
          register P4_REGIP_T p4IP  asm ("2"); \
          asm volatile ("mr 1,%0" :: "r" (p4IP)); \
          asm volatile ("mflr %0" : "=r" (p4IP)); 
#  define FX_SBR_EXIT_CODE { \
          asm volatile ("mtlr %0" :: "r" (p4IP)); \
          asm volatile ("blr"); }
#  endif /* SBR_CALL_ARG */
# endif /* SBR_CALL */

/* ____________________________________________________  ARCH_M68K _____ */
# elif defined HOST_CPU_M68K || defined __target_cpu_m68k \
    || defined HOST_ARCH_M68K
#   define PFE_HOST_ARCH_M68K 1
#   ifdef PFE_SBR_CALL_THREADING
#   define PFE_NEED_NO_REGIP
#   define PFE_NEED_NO_REGRP
#   endif

#   define P4_REGTH "%a4" 
#   define P4_REGSP "%a5"
#  if !defined _K12_SOURCE && PFE_USE_REGS > 2
#   if !defined PFE_NEED_NO_REGIP
#   define P4_REGIP "%a6"
#   endif
#   if !defined PFE_NEED_NO_REGRP
#   define P4_REGRP "%a7"
#   endif
#   if !defined PFE_NEED_NO_REGW
#   define P4_REGW  "%d6" 
#   endif
#   if !defined PFE_NEED_NO_REGRP
#   define P4_REGLP "%d7" 
#   endif
#  endif

/* and the SBR assembler snippets.... */
# define PFE_TAKE_CODE_RP    /* RP is taken via local setup code */
# define PFE_TAKE_IP_VIA_RP  /* IP is taken dereferencing our RP */

#  define PFE_SBR_COMPILE_EXIT(X) *((short*)(X))++ = 0x4E75 
/* 32bit immediate address for sbr-call */
#  define PFE_SBR_COMPILE_CALL(X,V) { \
                                  *((short*)(X))++ = 0x4EB9 ; \
                                  *((void**)(X))++ = (void*)(V); }
/* #  define PFE_SBR_SET_RP(X,V) { \
 *             asm volatile ("movl %0, %%esp" :: "r" ((X)-1)); \
 *             asm volatile ("movl %0, (%%esp)" :: "r" (V)); }
 */
#     define PFE_SBR_SET_RP(X,V) { \
               asm volatile ("movl %0, %%a7" :: "r" (X)); \
               asm volatile ("movl %0, %%a7@-" :: "r" (V)); }

#  define PFE_SBR_RP (PFE_SBR_REAL_RFRAME+1)
/*#define PFE_SBR_RP (&PFE_SBR_REAL_RETURN)  */
#  define PFE_SBR_GET_IP (PFE_SBR_REAL_RETURN)

# ifdef  PFE_SBR_CALL_ARG_PREFIXING
# define PFE_SBR_CALL_ARG_THREADING 1
/* # define PFE_SBR_CALL_ARG_IS_GLOBAL 1 ** not a scratch register */

#  if 0   /* the use of %a0 seems to irritate the compiler */
/* "mov $imm, %a0" */
#  define P4_SBR_TAKE_BODY       asm ("%a0")
#  define FX_SBR_TAKE_BODY       /* nothing - it's an argument... */
#  define FX_SBR_GIVE_BODY(X,A)  *((short*)(X))++ = 0x207C ; \
                                  *((void**)(X))++ = (void*)(A);
/* "mov %a7, %a0" */
#  define P4_SBR_TAKE_CODE       asm ("%a0")
#  define FX_SBR_TAKE_CODE       /* nothing - it's an argument... */
#  define FX_SBR_GIVE_CODE(X)    *((short*)(X))++ = 0x204F ; 

#  else  /* however %a1 is a scratch register too */
/* "mov $imm, %a1" */
#  define P4_SBR_TAKE_BODY       asm ("%a1")
#  define FX_SBR_TAKE_BODY       /* nothing - it's an argument... */
#  define FX_SBR_GIVE_BODY(X,A)  *((short*)(X))++ = 0x227C ; \
                                  *((void**)(X))++ = (void*)(A);
/* "mov %a7, %a1" */
#  define P4_SBR_TAKE_CODE       asm ("%a1")
#  define FX_SBR_TAKE_CODE       /* nothing - it's an argument... */
#  define FX_SBR_GIVE_CODE(X)    *((short*)(X))++ = 0x224F ; 
#  endif 

# endif

/* _________________________________________________  ARCH_I960 ________ */
# elif defined HOST_CPU_I960 || defined __target_cpu_i960 \
    || defined HOST_ARCH_I960
#   define PFE_HOST_ARCH_I960 1

#  define P4_UPPER_REGS  /* i960 has register based calling - if you use too */
#  define P4_REGTH "g10" /* many args, these registers will be clobbered - */
#  define P4_REGSP "g11" /* this is actually a gcc-bug, where the system */
#  define P4_REGIP "g12" /* call sequence generator doesn't save these regs */

/* _________________________________________________  ARCH_HPPA ________ */
# elif defined HOST_CPU_HPPA1 || defined HOST_CPU_HPPA \
    || defined HOST_ARCH_HPPA || defined __target_cpu_hppa
#   define PFE_HOST_ARCH_HPPA 1

#   define P4_REGTH "%r12"
#   define P4_REGSP "%r13"
#   define P4_REGRP "%r14"
#   define P4_REGIP "%r15"
#   define P4_REGW  "%r16"
#   define P4_REGLP "%r17"
#   define P4_REGFP "%r18"

/* _________________________________________________  ARCH_SPARC _______ */
# elif defined HOST_CPU_SPARC || defined __target_cpu_sparc \
    || defined HOST_ARCH_SPARC
#   define PFE_HOST_ARCH_SPARC 1
#   define P4_REGTH  "%g2"
#   define P4_REGSP  "%g3"

#if defined PFE_SBR_CALL_THREADING

/* "sub %o6, 4, %o6" "st %o7, [ %o6 ]" a.k.a. "push %o7, %sp" */
#define PFE_SBR_COMPILE_PROC(X)   *((p4cell*)(X))++ = 0x9c03bffc ; \
                                  *((p4cell*)(X))++ = 0xde238000 ;

/* "ld [ %o6 ], %o7" "retl" "add %o6, 4, %o6" a.k.a. "pop %sp, %o7" "ret %o7"*/
#define PFE_SBR_COMPILE_EXIT(X)   *((p4cell*)(X))++ = 0xde038000 ; \
                                  *((p4cell*)(X))++ = 0x81c3e008 ; \
                                  *((p4cell*)(X))++ = 0x9c03a004 ;

/* fill the delay-slot with the decr-%sp half of the "push %o7, %sp" operation
 * - that will probably not work for C compiled primitives but just for forth
 * compiled colon-routines - the sbr-threading is double-size anyway due to the
 * ("nop") delay-slot and we can use it to spare a memory-access on runtime */
#define PFE_SBR_COMPILE_CALL(X,V) { \
             if ( *(p4cell*)(V) == 0x9c03bffc ) { \
                  *((p4cell**)(X))++ = ((p4cell*)V)+1; \
                  *((p4cell*)(X))++ = 0x9c04bffc; \
             }else{ \
                  *((p4cell**)(X))++ = ((p4cell*)V); \
                  *((p4cell*)(X))++ = 0x01000000; \
             } }

#  define PFE_SBR_RP (PFE_SBR_REAL_RFRAME+1)
/*#define PFE_SBR_RP (&PFE_SBR_REAL_RETURN)  */
#  define PFE_SBR_GET_IP (PFE_SBR_REAL_RETURN)
#  define PFE_TAKE_IP_VIA_RP  /* IP is taken dereferencing our RP */

#endif

/* _________________________________________________  SOME ULTRIX ______ */
# elif defined HOST_OS_ULTRIX || defined __target_os_ultrix

#   define P4_REGTH "$17"
#   define P4_REGSP "$18"
#   define P4_REGRP "$19"
#   define P4_REGIP "$20"
#   define P4_REGW  "$21"
#   define P4_REGLP "$22"
#   define P4_REGFP "$23"

/* _________________________________________________  SOME OSF1 ________ */
# elif defined HOST_OS_OSF1 || defined __target_os_osf1

#   define P4_REGTH "$9"
#   define P4_REGSP "$10"
#   define P4_REGRP "$11"
#   define P4_REGIP "$12"
#   define P4_REGW  "$13"
#   define P4_REGLP "$14"
#   define P4_REGFP "$15"

/* _________________________________________________  UNKNOWN ARCH _____ */
# else

#   undef PFE_USE_REGS

# endif
#endif

/* ---------------------------------------------------- END ARCH -------- */
/* ----- CLEAR EASY ARCHs ----------------------------------------------- */


#ifdef PFE_NEED_NO_REGTH
# undef P4_REGTH
#endif

#ifdef PFE_NEED_NO_REGW
# undef P4_REGW
#endif

#ifdef PFE_NEED_NO_REGIP
# undef P4_REGIP
#endif

#ifdef PFE_NEED_NO_REGRP
# undef P4_REGRP
#endif

#ifndef PFE_SBR_COMPILE_PROC
#define PFE_SBR_COMPILE_PROC(X)
#endif

#define FX_COMPILE_PROC PFE_SBR_COMPILE_PROC(p4_DP)

/* ---------------------------------------------------------------------- */

#if !defined PFE_SBR_CALL_THREADING
#define FX_COMPILE1_CALL(X,V)      { *((void**)(X))++ = (void*)(V); }
#define FX_COMPILE1_p4_exit        FX_COMPILE1(p4_exit)
#define FX_COMPILE2_p4_exit        FX_COMPILE2(p4_exit)
#define FX_COMPILE1_p4_semicolon   FX_COMPILE1(p4_semicolon)
#define FX_COMPILE2_p4_semicolon   FX_COMPILE2(p4_semicolon)
#define FX_RP_ENTER 
#define FX_RP_LEAVE
#else
#define FX_COMPILE1_CALL(X,V)      PFE_SBR_COMPILE_CALL(X,V) 
#define FX_COMPILE1_p4_exit        PFE_SBR_COMPILE_EXIT(p4_DP) 
#define FX_COMPILE2_p4_exit        PFE_SBR_COMPILE_EXIT(p4_DP) 
#define FX_COMPILE1_p4_semicolon   PFE_SBR_COMPILE_EXIT(p4_DP) 
#define FX_COMPILE2_p4_semicolon   PFE_SBR_COMPILE_EXIT(p4_DP) 
#define FX_RP_ENTER                PFE_SBR_RP_ENTER 
#define FX_RP_LEAVE                PFE_SBR_RP_LEAVE
#endif

/* @name The basic types

   note that TYPEOF_CELL is either long or int.
   It must be atleast as big as a pointer.
 */
 
typedef unsigned char  p4char; /* hopefully an 8-bit type */
typedef unsigned short p4word; /* hopefully a 16-bit type */

typedef PFE_TYPEOF_CELL			p4cell;	 /* a stack item */
typedef unsigned PFE_TYPEOF_CELL	p4ucell; /* dito unsigned */

typedef struct
{ 
    p4cell hi; 
    p4ucell lo; 
} p4dcell;	/* dito, double precision signed */
typedef struct 
{ 
    p4ucell hi;
    p4ucell lo; 
} p4udcell;	/* dito, double precision unsigned */

typedef void (*p4code) (void);		/* pointer to executable code */
#if !defined PFE_CALL_THREADING
typedef p4code *p4xt;			/* type of the "execution token" */
typedef p4xt    p4xcode;                /* compiled "execution token" */
#else
typedef union p4_ExecToken* p4xt;       /* runtime definition hints */
typedef p4code  p4xcode;                /* compiled "execution token" */
#endif

typedef struct { p4cell  quot, rem; } fdiv_t;
typedef struct { p4ucell quot, rem; } udiv_t;

typedef struct				/* "map" of a cell */
{
#if PFE_BYTEORDER == 4321
    unsigned PFE_TYPEOF_HALFCELL hi;
    unsigned PFE_TYPEOF_HALFCELL lo;
#else
    unsigned PFE_TYPEOF_HALFCELL lo;
    unsigned PFE_TYPEOF_HALFCELL hi;
#endif
} p4ucell_hi_lo;

struct p4_Thread;

#ifdef P4_REGTH                 /* forth thread pointer */
register struct p4_Thread* p4TH asm (P4_REGTH);
#else
# ifdef PFE_WITH_STATIC_REGS
extern struct p4_Thread p4_reg;
# define p4TH (&p4_reg)
# else
extern struct p4_Thread* p4TH; 
# endif


# if defined PFE_WITH_REGS && (defined REENTRANT || defined _REENTRANT)
#  ifdef __GNUC__
#  warning pfe lost reentrance capability
#  else
#  error pfe lost reentrance capability here
#  endif
# endif
#endif

/* Virtual machine registers, declared as variables: ======================= */

/*_____________________________*/
#define P4_REGSP_T p4cell*

#ifdef P4_REGSP		/* the stack pointer */
register P4_REGSP_T p4SP asm (P4_REGSP);
#else
#define p4SP (PFE.sp)
#endif

/*_____________________________*/
#define P4_REGRP_T p4xcode**

/* choose P4_RP_IN_VM to detect extra forth RP stack, otherwise system stack */

#ifdef P4_REGRP		/* the return stack pointer */
register P4_REGRP_T  p4RP asm (P4_REGRP);
#define P4_RP_IN_VM
#elif ! defined PFE_SBR_CALL_THREADING
#define p4RP (PFE.rp)
#define P4_RP_IN_VM
#elif ! defined PFE_SBR_CALL_ARG_THREADING
/* always use FX_RP_WORK + FX_RP_DONE to modify the RP */
#define p4RP (&(PFE_SBR_RP[1]))
#elif   defined PFE_TAKE_CODE_RP
 /* SBR_CALL_ARG_THREADING uses only local p4RP */
#else
# ifdef __GNUC__
# warning NO RP ARG GIVEN
# else
# error   NO RP ARG GIVEN
# endif
#endif

#ifndef PFE_SBR_RP_OFFSET
#define PFE_SBR_RP_OFFSET 0
#endif

/*_____________________________*/
#define P4_REGIP_T  p4xcode*

#ifdef P4_REGIP			/* the instruction pointer */
register P4_REGIP_T p4IP asm (P4_REGIP);
#define PFE_IP_IN_VM
#elif ! defined PFE_SBR_CALL_THREADING
#define p4IP   (PFE.ip)
#define P4_IP_IN_VM
#elif ! defined PFE_SBR_CALL_ARG_THREADING
#define p4IP   (*PFE_SBR_RP)
#define P4_IP_VIA_RP
#elif   defined PFE_TAKE_CODE_RP && defined PFE_TAKE_IP_VIA_RP
/* #def p4IP   (PFE_SBR_RP[PFE_SBR_IP_OFFSET])*/
#define p4IP   (p4RP[PFE_SBR_IP_OFFSET])
#define P4_IP_VIA_RP
#else
 /* NO RP ARG GIVEN - the IP is a firsthand copy */
#endif

/* how much is the IP above the forth RP when forth-RP is derived f/ cpu-RP */
#ifndef PFE_SBR_IP_OFFSET
#define PFE_SBR_IP_OFFSET -1
#endif

#ifndef PFE_SBR_GET_IP
#define PFE_SBR_GET_IP (p4IP)
#endif

/*_____________________________*/
#define P4_REGW_T p4xt

/* the word pointer may be always accessed like this, but
   having an additional register will speed up the inner interpreter
   (and some other words, too)
*/
#define P4_WP (p4IP[-1])

#ifdef P4_REGW			/* used inside the inner interpreter */
register P4_REGW_T p4WP asm (P4_REGW);
#else
# ifdef P4_REGIP
# define p4WP	  P4_WP
# define P4_WP_VIA_IP 1
# else
# define p4WP (PFE.wp)
# endif
#endif


/*_____________________________*/
#define P4_REGLP_T p4cell*

#ifdef P4_REGLP		/* pointer to local variables */
register P4_REGLP_T	p4LP asm (P4_REGLP);
#else
#define p4LP (PFE.lp)
#endif

/*_____________________________*/
#define P4_REGFP_T double*

#ifndef P4_NO_FP
# ifdef P4_REGFP	/* the floating point stack pointer */
register P4_REGFP_T p4FP asm (P4_REGFP);
# else
# define p4FP (PFE.fp)
# endif
#endif

/*----------------------------*/

#ifdef _P4_SOURCE
/* variables from the Forth Virtual Machine */
# define WP P4_WP
# define IP p4IP
# define SP p4SP
# define RP p4RP
# define LP p4LP
# define FP p4FP
#endif

/* both SBR_CALL and SBR_CALL_ARG use IP_VIA_RP - and before anyone wants to
 * modify the RP, the return_address must be saved away
 */
#ifdef   P4_IP_VIA_RP
#define  FX_SAVE_IP_  register P4_REGIP_T p4_return_address = p4IP;
#define  FX_DONE_IP_               p4IP = p4_return_address;
#else
#define  FX_SAVE_IP_
#define  FX_DONE_IP_
#endif

# if defined   PFE_SBR_CALL_THREADING
#  if defined P4_RP_IN_VM
#  define  FX_NEW_RP_PREP 
#  define  FX_NEW_RP_WORK      
#  define  FX_NEW_RP_CHAR      ((p4char*)p4RP)
#  define  FX_NEW_RP_CELL      ((p4cell*)p4RP)
#  define  FX_NEW_RP_CODE      (p4RP)
#  define  FX_NEW_RP_DONE      
#  define  FX_NEW_RETVAL       (p4IP)
#  else
/* ifdef  P4_IP_VIA_RP */
#  define  FX_NEW_RP_PREP      register P4_REGIP_T __p4_RETVAL = p4IP
#   if defined   PFE_SBR_CALL_ARG_THREADING
#   define FX_NEW_RP_WORK    { FX_NEW_RP_PREP;
#   define p4_NEW_RP           p4RP             /* the argument is a copy */
#   else
#   define FX_NEW_RP_WORK    { FX_NEW_RP_PREP; \
                              P4_REGRP_T p4_NEW_RP = p4RP;
#   endif
#  define  FX_NEW_RP_CELL     ((p4cell*)(p4_NEW_RP))
#  define  FX_NEW_RP_CHAR     ((p4char*)(p4_NEW_RP))
#  define  FX_NEW_RP_CODE     (p4_NEW_RP)
#  define  FX_NEW_RP_DONE      PFE_SBR_SET_RP(p4_NEW_RP,__p4_RETVAL); }
#  define  FX_NEW_RETVAL       __p4_RETVAL
#  endif
# define  FX_NEW_RP_CELL_POSH (*--(FX_NEW_RP_CELL))
# define  FX_NEW_RP_CODE_POSH (*--(FX_NEW_RP_CODE))

# define  FX_ALIGN(X)    X = (( ((p4cell)(X)) + \
                               (PFE_SIZEOF_CELL-1) ) &~ (PFE_SIZEOF_CELL-1) )

#  if defined P4_IP_IN_VM || defined PFE_TAKE_CODE_IP
#  define  FX_NEW_IP_PREP 
#  define  FX_NEW_IP_WORK      
#  define  FX_NEW_IP_CHAR      ((p4char*)p4IP)
#  define  FX_NEW_IP_CELL      ((p4cell*)p4IP)
#  define  FX_NEW_IP_CODE      ((p4xcode*)p4IP)
#  define  FX_NEW_IP_DONE      
#  elif defined PFE_TAKE_IP_VIA_RP
#  define  FX_NEW_IP_PREP      register P4_REGIP_T* __p4_IP_REF = p4RP; \
                              __p4_IP_REF -= PFE_SBR_IP_OFFSET;
#  define  FX_NEW_IP_WORK      { FX_NEW_IP_PREP {
#  define  FX_NEW_IP_CHAR      (*(p4char**)__p4_IP_REF)
#  define  FX_NEW_IP_CELL      (*(p4cell**)__p4_IP_REF)
#  define  FX_NEW_IP_CODE      (*(p4xcode**)__p4_IP_REF)
#  define  FX_NEW_IP_DONE      }}
#  else
#  error   no NEW_IP defined
#  endif /* _TAKEN_IP_VIA_RP */
# define  FX_NEW_IP_SKIP_STRING FX_NEW_IP_CHAR += 1 + *FX_NEW_IP_CHAR; \
                               FX_ALIGN(FX_NEW_IP_CHAR);
# endif /* _SBR_CALL */

# if defined P4_RP_IN_VM
# define FX_RP_DROP(X)  { p4RP += (X); }
# define FX_RP_ROOM(X)  { p4RP -= (X); }
# elif defined PFE_SBR_CALL_THREADING 
# define FX_RP_DROP(X) { FX_NEW_RP_WORK; FX_NEW_RP_CELL +=(X); FX_NEW_RP_DONE;}
# define FX_RP_ROOM(X) { FX_NEW_RP_WORK; FX_NEW_RP_CELL -=(X); FX_NEW_RP_DONE;}
# endif

#if ! defined PFE_SBR_CALL_ARG_THREADING
#define P4_SBR_TAKE_BODY_T    
#define P4_SBR_TAKE_CODE_T    
#define P4_USE_CODE_ADDR
#define FX_USE_CODE_ADDR
#define FX_USE_CODE_EXIT
#define FX_ARG_CODE_ADDR(X)
#define FX_PUT_CODE_ADDR(X)
#define P4_USE_BODY_ADDR
#define FX_USE_BODY_ADDR
#define FX_ARG_BODY_ADDR(X,A)
#define FX_PUT_BODY_ADDR(X,A) *((p4cell**)(X))++ = (A)
#else
#define P4_USE_BODY_ADDR      /*P4_ARG_TAKE_BODY_T p4_BODY P4_SBR_TAKE_BODY*/
#define FX_USE_BODY_ADDR      P4_ARG_TAKE_BODY_T p4_BODY P4_SBR_TAKE_BODY;
#define FX_ARG_BODY_ADDR(X,A) FX_SBR_GIVE_BODY(X,A)
#define FX_PUT_BODY_ADDR(X,A) 
#define P4_ARG_TAKE_BODY_T    register p4cell* 
#define P4_ARG_TAKE_CODE_T    register P4_REGRP_T
# if ! defined FX_SBR_EXIT_CODE
#define P4_USE_CODE_ADDR      /*P4_ARG_TAKE_CODE_T p4RP   P4_SBR_TAKE_CODE*/
#define FX_USE_CODE_ADDR      P4_REGRP_T p4RP   P4_SBR_TAKE_CODE; 
#define FX_USE_CODE_EXIT
#define FX_ARG_CODE_ADDR(X)   FX_SBR_GIVE_CODE(X)
#define FX_PUT_CODE_ADDR(X)
# else
#define P4_USE_CODE_ADDR      /*P4_ARG_TAKE_CODE_T p4RP   P4_SBR_TAKE_CODE*/
#define FX_USE_CODE_ADDR      FX_SBR_TAKE_CODE
#define FX_USE_CODE_EXIT      FX_SBR_EXIT_CODE
#define FX_ARG_CODE_ADDR(X)   FX_SBR_GIVE_CODE(X)
#define FX_PUT_CODE_ADDR(X)
# endif
#endif

#if defined HAVE_VXWORKS_H || defined PFE_HAVE_VXWORKS_H
# include <types/vxCpu.h>
# if defined HOST_CPU_M68K || defined __target_cpu_m68k
# define CPU_FAMILY MC680X0
# elif defined HOST_CPU_I960 || defined __target_cpu_i960
# define CPU_FAMILY I960
# elif defined HOST_CPU_POWERPC || defined __target_cpu_powerpc
# define CPU_FAMILY PPC
# endif
# include <vxWorks.h>
# if defined __GNUC__ && (_ARCH_INT_MIN+0) == (-2147483648)
# undef  _ARCH_INT_MIN
# define _ARCH_INT_MIN (-2147483647-1)
# endif
# if defined __GNUC__ && (_ARCH_INT_MAX+0) == (2147483647)
# undef  _ARCH_INT_MAX
# define _ARCH_INT_MAX 2147483647u
# endif
# if defined __GNUC__ && (_ARCH_UINT_MAX+0) == (4294967295u)
# undef  _ARCH_UINT_MAX
# define _ARCH_UINT_MAX 4294967295u
# endif
# if defined __GNUC__ && (_ARCH_ULONG_MAX+0) == (4294967295u)
# undef  _ARCH_ULONG_MAX
# define _ARCH_ULONG_MAX 4294967295u
# endif
#endif

/*@}*/
#endif 
