#ifndef STACK_H
#define STACK_H 1
/* $Id: stack.h,v 1.2 1999/01/03 02:06:23 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved */

/************************************************************************/
/*									*/
/*	(C) Copyright 1989-98 Venue. All Rights Reserved.		*/
/*	Manufactured in the United States of America.			*/
/*									*/
/************************************************************************/
#include "version.h"  /* for BIGVM, UNSIGNED */
#include "adr68k.h"   /* for LAddrFromNative, NativeAligned4FromLAddr */
#include "address.h"  /* for LOLOC */
#include "commondefs.h" /* for error */
#include "lispemul.h" /* for LispPTR, DLword, FRAMESIZE, DLWORDSPER_CELL */

/* ContextSW frame number */
#define CurrentFXP 0
#define ResetFXP 1
#define SubovFXP 2
#define KbdFXP 3
#define HardReturnFXP 4
#define GCFXP 5
#define FAULTFXP 6

#define STK_FSB_WORD 0xA000u
#define STK_GUARD_WORD 0xE000u
#define BF_MARK 0x8000u
#define BF_MARK32 0x80000000
#define FX_MARK 0xc000u

#define STK_GUARD 7
#define STK_FX 6
#define STK_FSB 5
#define STK_BF 4
#define STK_NOTFLG 0

#define STK_SAFE 32 /* added with stkmin */
#define MINEXTRASTACKWORDS 32
#define STACKAREA_SIZE 768

/* For Fvar operations */
#define FVSTACK 2
#define FVGLOBAL 6
#define FVUBNBOUND 3
#define FVIVAR 0x0
#define FVPVAR 0x80
#define FVFVAR 0xC0
#define ENDSTACKMARK 0xb

#define FXPTR(base) ((struct frameex1 *)WORDPTR(base))

#ifndef BYTESWAP

/*******************************************************/
/*      Normal definitions for structures on stack     */
/*******************************************************/
typedef struct fnhead {
  DLword stkmin; /* ?? */
  short na;      /* Numbers of arguments */
  short pv;      /* ?? */
  DLword startpc;
  /* head of ByteCodes, DLword offset from stkmin */
  unsigned nil4 : 1;        /* not used, prev: native translated? */
  unsigned byteswapped : 1; /* code was reswapped.	 */
  unsigned argtype : 2;     /* ?? */
#ifdef BIGVM
  unsigned framename : 28; /* index in AtomSpace */
#else
  unsigned nil2 : 2;       /* not used */
  unsigned nil3 : 2;       /* not used */
  unsigned framename : 24; /* index in AtomSpace */
#endif /* BIGVM */
  DLword ntsize;        /* size of NameTable */
  unsigned nlocals : 8; /* ?? */
  unsigned fvaroffset : 8;
  /* DLword offset from head of NameTable */
  /* NameTable of variable length is following with this structure. */
} FNHEAD;

typedef struct frameex1 {
  DLword flags : 3;
  DLword fast : 1;
  DLword nil2 : 1; /* not used, prev: This frame treats N-func */
  DLword incall : 1;
  DLword validnametable : 1;
  /* 0: look for FunctionHeader
     1: look for NameTable on this FrameEx */
  DLword nopush : 1;
  DLword usecount : 8;
  DLword alink; /* alink pointer (Low addr) */
#ifdef BIGVM
  LispPTR fnheader; /* pointer to FunctionHeader (Hi2 addr) */
#else
  DLword lofnheader;        /* pointer to FunctionHeader (Low addr) */
  DLword hi1fnheader : 8; /* pointer to FunctionHeader (Hi1 addr) */
  DLword hi2fnheader : 8; /* pointer to FunctionHeader (Hi2 addr) */
#endif /* BIGVM */
  DLword nextblock; /* pointer to FreeStackBlock */
  DLword pc;        /* Program counter */
#ifdef BIGVM
  LispPTR nametable; /* ptr to NameTable of this FrameEx (Hi2 addr) */
#else
  DLword lonametable;        /* ptr to NameTable of this FrameEx (Low addr) */
  DLword hi1nametable : 8; /* ptr to NameTable of this FrameEx (Hi1 addr) */
  DLword hi2nametable : 8; /* ptr to NameTable of this FrameEx (Hi2 addr) */
#endif /* BIGVM */
  DLword blink; /* blink pointer (Low addr) */
  DLword clink; /* clink pointer (Low addr) */
} FX;

typedef struct frameex2 {
  DLword flags : 3;
  DLword fast : 1;
  DLword nil2 : 1; /* not used, prev: This frame treats N-func */
  DLword incall : 1;
  DLword validnametable : 1;
  /* 0: look for FunctionHeader
     1: look for NameTable on this FrameEx */
  DLword nopush : 1;
  DLword usecount : 8;
  DLword alink;      /* alink pointer (Low addr) */
  LispPTR fnheader;  /* pointer to FunctionHeader */
  DLword nextblock;  /* pointer to FreeStackBlock */
  DLword pc;         /* Program counter */
  LispPTR nametable; /* address of NameTable */
  DLword blink;      /* blink pointer (Low addr) */
  DLword clink;      /* clink pointer (Low addr) */
} FX2;

typedef struct fxblock {
  unsigned flagbyte : 8;
  unsigned nil : 23;
  unsigned slowp : 1;
} FXBLOCK;

typedef struct basic_frame {
  DLword flags : 3;
  DLword nil : 3;
  DLword residual : 1;
  DLword padding : 1;
  DLword usecnt : 8;
  DLword ivar; /* stk offset of IVARs for this frame ?? */

} Bframe;

typedef struct stkword {
  DLword flags : 3;
  DLword nil : 5;
  DLword usecount : 8;
} StackWord;

typedef struct stack_block {
  DLword flagword;
  DLword size;
} STKBLK;

/* Lisp DATATYPE STACKP */
typedef struct stackp {
  DLword stackp0;
  DLword edfxp;
} STACKP;

/*************************************************************/
/*  Pointer-dereferencing macros for one-word structure ptrs */
/*************************************************************/
#define BFRAMEPTR(ptr) ((Bframe *)(void *)(ptr))
#define STKWORDPTR(ptr) ((StackWord *)(ptr))

#else

/*******************************************************/
/*    Byte-swapped/Word-swapped definitions of stack   */
/*******************************************************/
typedef struct fnhead {
  short na;      /* Numbers of arguments */
  DLword stkmin; /* ?? */
  DLword startpc;
  /* head of ByteCodes, DLword offset from stkmin */
  short pv; /* ?? */
#ifdef BIGVM
  unsigned framename : 28; /* index in AtomSpace */
#else
  unsigned framename : 24; /* index in AtomSpace */
  unsigned nil3 : 2;       /* not used */
  unsigned nil2 : 2;       /* not used */
#endif /* BIGVM */
  DLword argtype : 2;     /* ?? */
  DLword byteswapped : 1; /* code was reswapped.	*/
  DLword nil4 : 1;        /* not used, prev: native translated? */
  DLword fvaroffset : 8;
  /* DLword offset from head of NameTable */
  DLword nlocals : 8; /* ?? */
  DLword ntsize;        /* size of NameTable */
                        /* NameTable of variable length is following with this structure. */
} FNHEAD;

typedef struct frameex1 {
  DLword alink; /* alink pointer (Low addr) */
  DLword usecount : 8;
  DLword nopush : 1;
  DLword validnametable : 1;
  /* 0: look for FunctionHeader
     1: look for NameTable on this FrameEx */
  DLword incall : 1;
  DLword nil2 : 1; /* not used, prev: This frame treats N-func */
  DLword fast : 1;
  DLword flags : 3; /* hi word */

#ifdef BIGVM
  LispPTR fnheader; /* pointer to FunctionHeader (Hi2 addr) */
#else
  DLword hi2fnheader : 8; /* pointer to FunctionHeader (Hi2 addr) */
  DLword hi1fnheader : 8; /* pointer to FunctionHeader (Hi1 addr) */
  DLword lofnheader;        /* pointer to FunctionHeader (Low addr) */
#endif /* BIGVM */

  DLword pc;        /* Program counter */
  DLword nextblock; /* pointer to FreeStackBlock */

#ifdef BIGVM
  LispPTR nametable; /* pointer to NameTable of this FX (Hi2 addr) */
#else
  DLword hi2nametable : 8; /* pointer to NameTable of this FX (Hi2 addr) */
  DLword hi1nametable : 8; /* pointer to NameTable of this FX (Hi1 addr) */
  DLword lonametable;        /* pointer to NameTable of this FX (Low addr) */
#endif /* BIGVM */

  DLword clink; /* clink pointer (Low addr) */
  DLword blink; /* blink pointer (Low addr) */
} FX;

typedef struct frameex2 {
  DLword alink; /* alink pointer (Low addr) */
  DLword usecount : 8;
  DLword nopush : 1;
  DLword validnametable : 1;
  /* 0: look for FunctionHeader
     1: look for NameTable on this FrameEx */
  DLword incall : 1;
  DLword nil2 : 1; /* not used, prev: This frame treats N-func */
  DLword fast : 1;
  DLword flags : 3;

  LispPTR fnheader; /* pointer to FunctionHeader (swapped) */

  DLword pc;        /* Program counter */
  DLword nextblock; /* pointer to FreeStackBlock */

  LispPTR nametable; /* address of NameTable (swapped) */

  DLword clink; /* clink pointer (Low addr) */
  DLword blink; /* blink pointer (Low addr) */
} FX2;

typedef struct fxblock {
  unsigned slowp : 1;
  unsigned nil : 23;
  unsigned flagbyte : 8;
} FXBLOCK;

typedef struct basic_frame {
  DLword ivar;
  DLword usecnt : 8;
  DLword padding : 1;
  DLword residual : 1;
  DLword nil : 3;
  DLword flags : 3;

} Bframe;

typedef struct stkword {
  DLword usecount : 8;
  DLword nil : 5;
  DLword flags : 3;
} StackWord;

typedef struct stack_block {
  DLword size;
  DLword flagword;
} STKBLK;

/* Lisp DATATYPE STACKP */
typedef struct stackp {
  DLword edfxp;
  DLword stackp0;
} STACKP;

/*************************************************************/
/*  Pointer-dereferencing macros for one-word structure ptrs */
/*************************************************************/
#define BFRAMEPTR(ptr) ((Bframe *)(void *)(ptr))
#define STKWORDPTR(ptr) ((StackWord *)(2 ^ (UNSIGNED)(ptr)))

#endif

#define STKWORD(stkptr) ((StackWord *)WORDPTR(stkptr))

#define FX_INVALIDP(fx68k) (((fx68k) == 0) || ((DLword *)(fx68k) == Stackspace))
#define FX_size(fx68k) (((FX *)(void *)(fx68k))->nextblock - LOLOC(LAddrFromNative(fx68k)))
#define FSBP(ptr68k) (((STKBLK *)(void *)(ptr68k))->flagword == STK_FSB_WORD)
#define FSB_size(ptr68k) (((STKBLK *)(void *)(ptr68k))->size)
/** Following suff assumes fx is 68kptr and val is LISP_LO_OFFSET **/
#define DUMMYBF(fx) (((DLword *)(fx)) - DLWORDSPER_CELL)
#define SLOWP(fx) (((FXBLOCK *)(void *)(fx))->slowp)
#define FASTP(fx) (!SLOWP(fx))
#define SET_FASTP_NIL(fx68k)                                       \
  do {                                                             \
    if (FASTP(fx68k)) {                                            \
      ((FX *)(fx68k))->blink = StackOffsetFromNative(DUMMYBF(fx68k)); \
      ((FX *)(fx68k))->clink = ((FX *)(fx68k))->alink;             \
      SLOWP(fx68k) = T;                                            \
    }                                                              \
  } while (0)

#define GETALINK(fx) ((((fx)->alink) & 0xfffe) - FRAMESIZE)
#define SETALINK(fx, val)                                \
  do {                                                   \
    if (FASTP(fx)) {                                     \
      ((FX *)(fx))->blink = LAddrFromNative(DUMMYBF(fx)); \
      ((FX *)(fx))->clink = ((FX *)(fx))->alink;         \
    }                                                    \
    ((FX *)(fx))->alink = (val) + FRAMESIZE + 1;         \
  } while (0)

#define GETBLINK(fx) (SLOWP(fx) ? ((FX *)(fx))->blink : LOLOC(LAddrFromNative(DUMMYBF(fx))))
#define SETBLINK(fx, val)                        \
  do {                                           \
    ((FX *)(fx))->blink = (val);                 \
    if (FASTP(fx)) {                             \
      ((FX *)(fx))->clink = ((FX *)(fx))->alink; \
      SLOWP(fx) = 1;                             \
    }                                            \
  } while (0)

#define GETCLINK(fx) \
  (SLOWP(fx) ? (((FX *)(fx))->clink - FRAMESIZE) : (((FX *)(fx))->alink - FRAMESIZE))
#define SETCLINK(fx, val)                                \
  do {                                                   \
    ((FX *)(fx))->clink = (val) + FRAMESIZE;             \
    if (FASTP((fx))) {                                   \
      ((FX *)(fx))->blink = LAddrFromNative(DUMMYBF(fx)); \
      SLOWP(fx) = 1;                                     \
    }                                                    \
  } while (0)

#define SETACLINK(fx, val)                                                \
  do {                                                                    \
    if (FASTP(fx)) { ((FX *)(fx))->blink = LAddrFromNative(DUMMYBF(fx)); } \
    ((FX *)(fx))->clink = (val) + FRAMESIZE;                              \
    ((FX *)(fx))->alink = ((FX *)(fx))->clink + 1;                        \
  } while (0)

#ifdef BIGVM
#define SWAP_FNHEAD
#else
#define SWAP_FNHEAD(x) swapx(x)
#endif /* BIGVM */

#define GETNAMETABLE(fx)                                                                          \
  ((struct fnhead *)NativeAligned4FromLAddr(                                                      \
      SWAP_FNHEAD(                                                                                \
        ((((FX2 *)(fx))->validnametable) ? ((FX2 *)(fx))->nametable : ((FX2 *)(fx))->fnheader)) & \
      POINTERMASK))

#define MAKEFREEBLOCK(ptr68k, size)                                   \
  do {                                                                \
    if ((size) <= 0) error("creating 0 length free stack block");      \
    if ((size) & 1) error("creating odd length free stack block");	\
    *((LispPTR *)(void *)(ptr68k)) = (STK_FSB_WORD << 16) | ((DLword)(size)); \
  } while (0)

#define SETUPGUARDBLOCK(ptr68k, size)                                     \
  do {                                                                    \
    if ((size) <= 0) error("creating 0 length stack guard block");        \
    if ((size) & 1) error("creating odd sized stack guard block");        \
    (*((LispPTR *)(void *)(ptr68k)) = (STK_GUARD_WORD << 16) | ((DLword)(size))); \
  } while (0)

/************************************************************************/
/*									*/
/*			   Stack-checking macros			*/
/*									*/
/*	Enabled when STACKCHECK compile flag is set.			*/
/*									*/
/************************************************************************/

#ifdef STACKCHECK

#include <stdio.h>
#include "testtooldefs.h"

#define S_CHECK(condition, msg)                          \
  do {                                                   \
    if (!(condition)) {                                  \
      printf("\n\nStack check failed:  %s.\n\n", (msg)); \
      error("S_Check..");                                \
    }                                                    \
  } while (0)

#define S_WARN(condition, msg, scanptr)                                                       \
  do {                                                                                           \
    if (!(condition)) { printf("\n\nStack check failed at %p:  %s.\n\n", (scanptr), (msg)); } \
  } while (0)

#define CHECK_BF(bf68k) check_BF(bf68k)

#define CHECK_FX(fx68k) check_FX(fx68k)

#define PreMoveFrameCheck(fx68k)                                                \
  do {                                                                          \
    LispPTR *tos_on_stack;                                                      \
    if (check_stack_rooms(fx68k) > 1000) {                                      \
      warn("moveframe:there is more than 100 words SPACE for FX");              \
      printf("# When calling ");                                                \
      tos_on_stack = (LispPTR *)NativeAligned4FromStackOffset((fx68k)->nextblock - 2); \
      print_atomname(*tos_on_stack);                                            \
      printf("\n");                                                             \
      stack_check(0);                                                           \
    }                                                                           \
    } while (0)

#else /* STACKCHECK */

#define S_CHECK(condition, msg) \
  do {} while (0)
#define S_WARN(condition, msg, scanptr) \
  do {} while (0)
#define PreMoveFrameCheck(fx68k) \
  do {} while (0)
#define CHECK_BF(bf68k) \
  do {} while (0)
#define CHECK_FX(fx68k) \
  do {} while (0)

#endif /* STACKCHECK */

#define STK_MIN(fnobj) (((fnobj)->stkmin /* NOT NEEDED in stkmin +STK_SAFE */) << 1)

#define STK_END_COMPUTE(stk_end, fnobj) ((UNSIGNED)(stk_end)-STK_MIN(fnobj))

#define CLR_IRQ	\
  Irq_Stk_Check = STK_END_COMPUTE((Irq_Stk_End = (UNSIGNED) EndSTKP), FuncObj)
#endif
