/* $Id: fvar.c,v 1.3 1999/05/31 23:35:29 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved  */

/************************************************************************/
/*									*/
/*	(C) Copyright 1989-95 Venue. All Rights Reserved.		*/
/*	Manufactured in the United States of America.			*/
/*									*/
/************************************************************************/

#include "version.h"

#include <stdio.h>
#include "lispemul.h"
#include "lspglob.h"
#include "adr68k.h"
#include "stack.h"
#include "emlglob.h"
#include "lispmap.h"
#include "lsptypes.h"
#include "gcdata.h"

#include "fvardefs.h"
#include "byteswapdefs.h"
#include "commondefs.h"
#include "gchtfinddefs.h"


#define MaskShift(x) (((x) << 16) & SEGMASK)

#ifdef BIGATOMS
#define NT_OFFSET_MASK 0xFFFFFFF
#define NT_TYPE_MASK 0xFF000000
#define GetNTEntry(X) GetLongWord(X)
#define NAMETABLE LispPTR
#else
#define NT_OFFSET_MASK 0xFF
#define NT_TYPE_MASK 0xFF00
#define GetNTEntry(X) GETWORD(X)
#define NAMETABLE DLword
#endif

#define FVSTACK 2
#define FVGLOBAL 6

#ifdef BIGATOMS
#define FVIVARHI 0x0
#define FVPVARHI (0x80000000)
#define FVFVARHI (0xC0000000)
#else
#define FVIVARHI 0x0
#define FVPVARHI 0x8000
#define FVFVARHI 0xC000
#endif

#define ENDSTACKMARK 0xb

/******************************************************************************
nnewframe

        This routine is used by fvlookup and OP_stkscan.

        1. scan Name table in new function header.
        2. if found, set address of searching variable to chain address.
        3. return the type of var, on stack, or global. (fs: unused, removed)

******************************************************************************/

void nnewframe(register struct frameex1 *newpfra2, register DLword *achain, register int name)
/* pointer to new frame extension */
/* pointer to 1st word of the searching
   FVAR slot in CurrentFrameExtension */
/* Atom index num. of target FVAR slot. */
{
  register NAMETABLE *pindex; /* '90/06/06 osamu changed from DLword *
                               * index to indexs of new name table */
  register UNSIGNED i;        /* temp for control */
  register int nametablesize; /* NameTable size of current function header. */
  register int ph;            /* alink temp, also phase */

newframe:
  /* assume that apframe1 points to the next frame to be scanned */
  ph = newpfra2->alink;
  if (ph == 0) error("alink = 0 in nnewframe");
  if (ph == ENDSTACKMARK) {
/* endStack */
#ifdef BIGATOMS
    if ((name & SEGMASK) != 0) /* New symbol */
    {
      register int result = name + NEWATOM_VALUE_OFFSET;
      /*    printf("NEW-SYMBOL in nnewframe, 0x%x, result = 0x%x\n", name, result); */
      GETBASEWORD(achain, 1) = result >> 16;
      GETBASEWORD(achain, 0) = result & 0xFFFF;
    } else
#endif /* BIGATOMS */

#ifdef BIGVM
        if (name & SEGMASK) { /* It's a big-atom, so just offset from the base to get value */
      register int result = name + NEWATOM_VALUE_OFFSET;
      GETBASEWORD(achain, 1) = result >> 16;
      GETBASEWORD(achain, 0) = result & 0xFFFF;
    } else { /* It's an "old" atom, so offset into the table of atoms */
      register int result = (ATOMS_HI << 16) + (10 * name) + NEWATOM_VALUE_OFFSET;
      GETBASEWORD(achain, 1) = result >> 16;
      GETBASEWORD(achain, 0) = result & 0xFFFF;
    }
#else
    if (name >= 0x8000) {
      GETBASEWORD(achain, 1) = VALS_HI + 1;
      GETBASEWORD(achain, 0) = name * 2;
    } else {
      GETBASEWORD(achain, 1) = VALS_HI;
      GETBASEWORD(achain, 0) = name * 2;
    }
#endif /* BIGVM */
    return;
  }

  ph &= 0xFFFE; /* to mask off SLOW bit */
  newpfra2 = (struct frameex1 *)(-FRAMESIZE + Stackspace + ph);

  {                                  /* open new block to try and conserve address register */
    register struct fnhead *newpfn2; /* ptr to new fn header */

    if (newpfra2->validnametable) /* check VALIDNAMETABLE */
#ifdef BIGVM
      newpfn2 = (struct fnhead *)(Addr68k_from_LADDR(newpfra2->nametable));
    else
      newpfn2 = (struct fnhead *)(Addr68k_from_LADDR(newpfra2->fnheader));
#else
      newpfn2 = (struct fnhead *)(Addr68k_from_LADDR(
          ((newpfra2->hi2nametable) << 16 | newpfra2->lonametable)));
    else
      newpfn2 = (struct fnhead *)(Addr68k_from_LADDR(
          ((newpfra2->hi2fnheader) << 16 | newpfra2->lofnheader)));
#endif /* BIGVM */
    pindex = (NAMETABLE *)((DLword *)newpfn2 + FNHEADSIZE);
/* now pindex points 1st word of Nametable. */
#ifdef BIGATOMS
    nametablesize = (newpfn2->ntsize >> 1); /* ntsize is # of words in NT
                                               not # of element */
#else
    nametablesize = newpfn2->ntsize;
#endif
  }

  i = (UNSIGNED)(pindex + nametablesize);
  for (; (UNSIGNED)i > (UNSIGNED)pindex;) { /* searching in NewFuncHeader */
#ifdef BIGATOMS
/* These used to be GETWORDs, but NAMETABLE is a CELL in 3-byte */
#if 1
    if ((int)*((NAMETABLE *)pindex++) == (int)name) {
      ph = 1;
      goto foundit;
    }
  cont2:
    if ((int)*((NAMETABLE *)pindex++) == (int)name) {
      ph = 0;
      goto foundit;
    }
#else
    if ((int)*((NAMETABLE *)pindex++) == (int)name) {
      ph = 1;
      goto foundit;
    }
  cont2:
    if ((int)*((NAMETABLE *)pindex++) == (int)name) {
      ph = 2;
      goto foundit;
    }
  cont3:
    if ((int)*((NAMETABLE *)pindex++) == (int)name) {
      ph = 3;
      goto foundit;
    }
  cont4:
    if ((int)*((NAMETABLE *)pindex++) == (int)name) {
      ph = 0;
      goto foundit;
    }
#endif

#else
    if (GETWORD((NAMETABLE *)pindex++) == (DLword)name) {
      ph = 1;
      goto foundit;
    }
  cont2:
    if (GETWORD((NAMETABLE *)pindex++) == (DLword)name) {
      ph = 2;
      goto foundit;
    }
  cont3:
    if (GETWORD((NAMETABLE *)pindex++) == (DLword)name) {
      ph = 3;
      goto foundit;
    }
  cont4:
    if (GETWORD((NAMETABLE *)pindex++) == (DLword)name) {
      ph = 0;
      goto foundit;
    }
#endif
    continue;
  foundit : {
    register int fvartype;   /* probing fvar vartype */
    register int fvaroffset; /* probing fvar varoffset */
    register DLword *ppvar;  /* ptr to probing var candidate */
#ifdef BIGATOMS
    fvartype = (int)*(pindex + nametablesize - 1);
#else
    fvartype = GETWORD(pindex + nametablesize - 1);
#endif /* BIGATOMS */

    fvaroffset = NT_OFFSET_MASK & fvartype;
    fvaroffset <<= 1;
    fvartype &= NT_TYPE_MASK;
    switch (fvartype) {
      case FVPVARHI: /* 0x8000 or 0x80000000(BIGATOMS) */
        ppvar = FRAMESIZE + (DLword *)newpfra2 + fvaroffset;
        /* ppvar points to argued Pvar */
        if (WBITSPTR(ppvar)->xMSB) /* check UNBOUND (if *ppvar is negative , unbound) */
          switch (ph) {
            case 0: continue;
            case 1:
              goto cont2;
              /* case 2 : goto cont3;
              case 3 : goto cont4; */
          }
        GETBASEWORD(achain, 1) = STK_HI;
        GETBASEWORD(achain, 0) = 0xFFFF & LADDR_from_68k(ppvar);
        /* save High word of PVAR slot address to FVAR slot */
        /* achain points to target FVAR slot */
        return;
      case FVFVARHI: /* 0xC000 or 0xC0000000(BIGATOMS) */
        ppvar = FRAMESIZE + (DLword *)newpfra2 + fvaroffset;
        if (WBITSPTR(ppvar)->LSB) goto endlookfor;
        /* Not Found in new FnHeader, scan next one. */
        *((int *)achain) = *((int *)ppvar);
        /* save address of FX to FVAR slot */
        /* achain points to target FVAR slot */
        return;
      case FVIVARHI: /* 0x000: */
        ppvar = -1 + (DLword *)newpfra2;
        /* ppvar points to IVAR field in Basic  frame */
        GETBASEWORD(achain, 1) = STK_HI;
        GETBASEWORD(achain, 0) = GETWORD(ppvar) + fvaroffset;
        return;
      default: error("Stack corrupted: bad value in name table");
    } /* end switch */
  }   /* end if */
  }   /* end for */

endlookfor:
  goto newframe; /* scan the next one */
}

/**************************************************************************
 nfvlookup:

        This routine is used by only OP_fvarn.
                ( in addition to N_OP_fvar_() )
        1. get Atom index number of target fvar slot.
        2. call fvlookfor.

****************************************************************************/
void nfvlookup(struct frameex1 *apframe1, register DLword *achain,
               register struct fnhead *apfnhead1)
/* pointer to current frame extension */
/* pointer to 1st word of the searching
   FVAR slot in CurrentFrameExtension */
/* pointer to current function header */
{
  register DLword *pfh;  /* pointer to current function header */
  register int paoffset; /* 2word offset in PVAR AREA */

  pfh = (DLword *)apfnhead1;
  paoffset = ((UNSIGNED)achain - (UNSIGNED)PVar) >> 2;
/* slot to looked for, 2word offset from PVar */
#ifdef BIGATOMS
  nnewframe(apframe1, achain, (*((LispPTR *)((DLword *)pfh + apfnhead1->fvaroffset) + paoffset -
                                 apfnhead1->nlocals)));
#else
  nnewframe(apframe1, achain,
            (GETWORD(pfh + (apfnhead1->fvaroffset + paoffset - apfnhead1->nlocals))));
#endif
}

/*************************************************************************
 N_OP_fvarn
        entry of OPCODE[120b-127b]: FVAR, FVARX

        1. save TopOfStack to evaluation stack.
        2. set address of searching FVAR slot to chain.
        3. call lookfor. (It sets some content to FVAR slot)
        4. get some address by calculation of content of FVAR slot.
        5. set the address to TopOfStack.
**************************************************************************/
LispPTR N_OP_fvarn(register int n)
/* n is word offset */

{
  register DLword *chain; /* keep FVAR slot2 in CurrentFrameExtension */

  chain = PVar + n;

  if (WBITSPTR(chain)->LSB) {
    /* check 15bit of FVAR slot1 in CurrentFrameExtension.
       0: bound
       1: unbound */
    nfvlookup(CURRENTFX, chain, FuncObj);
  }

  return (GetLongWord(
      Addr68k_from_LADDR(POINTERMASK & (((GETBASEWORD(chain, 1)) << 16) | GETBASEWORD(chain, 0)))));
}

/******************************************************************************

N_OP_stkscan
        entry	STKSCAN		OPCODE[057]

        <<Enter>>
        TopOfStack:	Low word - Atom index number of variable to be scanned.
        <<Exit>>
        TopOfStack:	Address of found value.

        1. call fvlookup.
        2. Set *chain to TopOfStack.
        3. Increment Pc by 1.

******************************************************************************/

LispPTR N_OP_stkscan(LispPTR tos) {
  int scratch;
  scratch = tos;
  nnewframe(CURRENTFX, (DLword *)&scratch, POINTERMASK & scratch);
  return (swapx(scratch));
}

/**************************************************
N_OP_fvar_

        Entry:	FVAR_		opcode[0143]


***************************************************/

LispPTR N_OP_fvar_(register LispPTR tos, register int n) {
  register DLword *ppvar;    /* pointer to argued Fvar slot in pvar area */
  register DLword *pfreeval; /* pointer to argued free value */

  ppvar = PVar + n;

  if (WBITSPTR(ppvar)->LSB) /* check unbound ? */
  {                         /* unbound */
    nfvlookup(CURRENTFX, ppvar, FuncObj);
  }

  pfreeval = Addr68k_from_LADDR(MaskShift((GETWORD(ppvar + 1))) | GETWORD(ppvar));

  if (((0xFF & GETWORD(ppvar + 1)) != STK_HI)) {
    GCLOOKUP(*((LispPTR *)pfreeval), DELREF);
    GCLOOKUP(tos, ADDREF);
  }

  *((LispPTR *)pfreeval) = tos;
  return (tos);
}

#ifndef BIGATOMS

#define VALS_HI_RET(x) ((int)(x) << 17) + VALS_HI + ((unsigned short)(x) >> 15)

#define STK_HI_RET(x) (((int)(x) << 16) | 1 | ((unsigned int)(x) >> 16))


#else

#ifdef BIGVM
#define VALS_HI_RET(x)                                                                            \
  ((((int)(x)&SEGMASK) == 0) ? (swapx((ATOMS_HI << 16) + (10 * (int)(x)) + NEWATOM_VALUE_OFFSET)) \
                             : (swapx((int)(x) + NEWATOM_VALUE_OFFSET)))
#else
#define VALS_HI_RET(x)                                                                    \
  ((((int)(x)&SEGMASK) == 0) ? (((int)(x) << 17) + VALS_HI + ((unsigned short)(x) >> 15)) \
                             : (swapx((int)(x) + NEWATOM_VALUE_OFFSET)))
#endif /* BIGVM */

#define STK_HI_RET(x) (((unsigned int)(x) << 16) | 1 | ((unsigned int)(x) >> 16))

#endif /* BIGATOMS */

/******************************************************************************
native_newframe

        1. scan Name table in new function header.
        2. if found, set address of searching variable to chain address.
        3. return the pointer

******************************************************************************/
LispPTR native_newframe(int slot)
/* index of FVAR slot. */
{
  register struct frameex2 *newpfra2; /* pointer to new frame extension */
  register DLword *achain;            /* pointer to 1st word of the searching
                                       FVAR slot in CurrentFrameExtension */
  register int name;                  /* Atom# of target FVAR slot. */

  { /* LOCAL temp regs */
    register int rslot = slot;
    register struct fnhead *fnobj = FuncObj;
    register LispPTR *pvar = (LispPTR *)PVar;

#ifdef BIGATOMS
    name = (int)*((LispPTR *)((DLword *)fnobj + fnobj->fvaroffset) + rslot - fnobj->nlocals);
#else
    name = GETWORD((DLword *)fnobj + (fnobj->fvaroffset + rslot - fnobj->nlocals));
#endif

    newpfra2 = (struct frameex2 *)((DLword *)pvar - FRAMESIZE);
    achain = (DLword *)(pvar + rslot);
  }

  {
    register NAMETABLE *pindex; /* index to indexs of new name table */
    register int i;             /* temp for control */
    register int nametablesize; /* NameTable size of current fnhdr */
    register int alink;

  natnewframe:
    /* assume that apframe1 points to the next frame to be scanned */

    alink = newpfra2->alink;
    if (alink == 0) error("alink is 0 in native_newframe");
    if (alink == ENDSTACKMARK) { /* End of stack, so return top-level-value */
      /*	    if (name & SEGMASK) printf("native_newframe returning name 0x%x, result
         0x%x.\n",
                              name, VALS_HI_RET(name)); */
      return (*((LispPTR *)achain) = VALS_HI_RET(name));
    }
    newpfra2 = (struct frameex2 *)(-FRAMESIZE + Stackspace + (alink & 0xFFFE));

    {                                  /* open new block to try and conserve address register */
      register struct fnhead *newpfn2; /* ptr to new fn header */

      newpfn2 = GETNAMETABLE(newpfra2);

      pindex = (NAMETABLE *)(((DLword *)newpfn2) + FNHEADSIZE);
/* now pindex points 1st word of Nametable. */
#ifdef BIGATOMS
      nametablesize = (newpfn2->ntsize >> 1); /* ntsize is # of words in NT
                                             nametablesize is # of items in NT */
#else
      nametablesize = newpfn2->ntsize;
#endif /* 					    */
    }

    for (i = nametablesize; --i >= 0;) {
/* searching in NewFuncHeader */
#ifdef BIGATOMS
      if ((LispPTR) * ((NAMETABLE *)pindex++) == (LispPTR)name) {
#else
      if (GETWORD((NAMETABLE *)pindex++) == (DLword)name) {
#endif /* BIGATOMS    */


        register int fvartype;   /* probing fvar vartype */
        register int fvaroffset; /* probing fvar varoffset */
        register DLword *ppvar;  /* ptr to probing var candidate */
#ifdef BIGATOMS
        fvartype = (int)*(pindex + nametablesize - 1);
#else
        fvartype = GETWORD(pindex + nametablesize - 1);
#endif /* BIGATOMS */

        fvaroffset = (NT_OFFSET_MASK & fvartype) << 1;
        fvartype &= NT_TYPE_MASK;
        switch (fvartype) {
          case FVPVARHI: /* 0x8000 or 0x80000000(NEWATOM): */
            ppvar = FRAMESIZE + (DLword *)newpfra2 + fvaroffset;
            /* ppvar points to argued Pvar */
            if (WBITSPTR(ppvar)->xMSB) /* check UNBOUND (if *ppvar is negative , unbound) */
            {
              continue;
            }
            /* save High word of PVAR slot address to FVAR slot */
            /* achain points to target FVAR slot */
            return (*((LispPTR *)achain) = STK_HI_RET(LADDR_from_68k(ppvar)));
          case FVFVARHI: /* 0xC000 or 0xC0000000(NEWATOM S) */
            ppvar = FRAMESIZE + (DLword *)newpfra2 + fvaroffset;
            if (WBITSPTR(ppvar)->LSB) { goto endlookfor; }
            /* Not Found in new FuncHeader, scan next one. */
            /* save address of frame extension to FVAR slot */
            /* achain points to target FVAR slot */
            return (*((int *)achain) = *((int *)ppvar));
          case FVIVARHI: /* 0x0000000: */
            ppvar = (DLword *)newpfra2 - 1;
            /* ppvar points to IVAR field in Basic frame */
            return (*((LispPTR *)achain) = STK_HI_RET(GETWORD(ppvar) + fvaroffset));
            ;
          default: error("Stack corrupted: bad value in name table");
        } /* end switch */
      }   /* end if */
    }     /* end for */

  endlookfor:
    goto natnewframe; /* scan the next one */
  }
}
