/* decode.c   14-3-94  decode functions for the Tierra Simulator */
/* Tierra Simulator V4.1: Copyright (c) 1991, 1992, 1993, 1994 */
/* Tom Ray & Virtual Life */

#include "license.h"
#include "tierra.h"
#include "extern.h"


#ifdef MEM_CHK
#include <memcheck.h>
#endif

void pnop(ce) /* do nothing */
Pcells  ce;
{   is.iip = is.dib = 1; }

void dec1s(ce) /* decode one source value */
Pcells  ce;    /* use with: push(), regorder(), getregs() */
{   I32s  tval;

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
#ifdef SHADOW
    if (ce->c.p->sha)
        tval = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
    else
#endif /* SHADOW */
        tval = ce->c.p->re[0] + flaw(ce);
    is.sval = ce->c.a->re[mo(tval, NUMREG)] + flaw(ce);
    switch (ce->c.p->mn[0])
    {   case 'A': case 'B': case 'C': case 'D': /* regorder() */
        {   is.sval = flaw(ce) + ce->c.p->re[0];
            is.sval = mo(is.sval, NUMREG);
            break;
        }
        case 'g': /* getregs() */
        {   is.sval = ce->c.p->re[0];
            break;
        }
        default: /* push(), ok as is */
            break;
    }
}

void dec2s(ce) /* decode two source values */
Pcells  ce;    /* use with: ifz, iffl, equal, less, greater, divide, exch */
{   I32s  tval0, tval1;

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
#ifdef SHADOW
    if (ce->c.p->sha)
    {   tval0 = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
        tval1 = ce->c.a->re[NUMREG + ce->c.p->re[1]] + flaw(ce);
    }
    else
#endif /* SHADOW */
    {   tval0 = ce->c.p->re[0] + flaw(ce);
        tval1 = ce->c.p->re[1] + flaw(ce);
    }
    is.sval  = ce->c.a->re[mo(tval0, NUMREG)] + flaw(ce);
    is.sval2 = ce->c.a->re[mo(tval1, NUMREG)] + flaw(ce);
    switch (ce->c.p->mn[2])
    {   case 'z': /* ifz() */
        {   is.sval  = (is.sval == 0);
            is.sval2 = 2;
            break;
        }
        case 'u': /* equal() */
        {   is.sval  = (is.sval == is.sval2);
            is.sval2 = 2;
            break;
        }
        case 's': /* less() */
        {   is.sval  = (is.sval < is.sval2);
            is.sval2 = 2;
            break;
        }
        case 'e': /* greater() */
        {   is.sval  = (is.sval > is.sval2);
            is.sval2 = 2;
            break;
        }
        case 'f': /* iffl() */
        {   is.sval  = ce->c.a->fl + flaw(ce);
            is.sval2 = 2;
            break;
        }
        case 'v': /* divide() */
        {   is.mode = 2;
            if (ce->c.p->fl)
                is.sval  = ce->c.p->re[0] + flaw(ce);
            break;
        }
        case 'c': /* exch() */
        {   is.dreg  = &(ce->c.a->re[mo(tval0, NUMREG)]);
            is.dran  = SoupSize;
            is.dreg2 = &(ce->c.a->re[mo(tval1, NUMREG)]);
            is.dran2 = SoupSize;
            break;
        }
        default: /* ok as is */
            break;
    }
}

void dec1d(ce) /* decode one destination register */
Pcells  ce;    /* use with: shl, shr, not, not0, pop, ret */
{   I32s  tval;

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
#ifdef SHADOW
    if (ce->c.p->sha)
        tval = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
    else
#endif /* SHADOW */
        tval = ce->c.p->re[0] + flaw(ce);
    is.dreg = &(ce->c.a->re[mo(tval, NUMREG)]);
    is.dran = SoupSize;
    switch (ce->c.p->mn[0])
    {   case 'r': /* ret() */
        {   is.dreg = &(ce->c.a->ip);
            is.iip  = 0;
            break;
        }
        default: /* ok as is: shl, shr, not, not0, pop */
            break;
    }
}

void dec1d1s(ce) /* decode one destination register, one source value */
Pcells  ce;    /* use with: inc(), dec(), rand(), put(), zero() */
{   I32s  a, tval0, tval1;  /* movdd(), split(), get() */

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
#ifdef SHADOW
    if (ce->c.p->sha)
    {   tval0 = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
        tval1 = ce->c.a->re[NUMREG + ce->c.p->re[1]] + flaw(ce);
    }
    else
#endif /* SHADOW */
    {   tval0 = flaw(ce) + ce->c.p->re[0];
        tval1 = flaw(ce) + ce->c.p->re[1];
    }
    is.dreg = &(ce->c.a->re[mo(tval0, NUMREG)]);
    is.dran = SoupSize;
    is.sval = ce->c.a->re[mo(tval1, NUMREG)] + flaw(ce);
    switch (ce->c.p->mn[0])
    {   case 'i': /* inc() */
        {   is.sval2 = 1;
            break;
        }
        case 'd': /* dec() */
        {   is.sval2 = -1;
            break;
        }
        case 'r': /* rand() */
        {   is.sval = tlrand();
            break;
        }
        case 'z': /* zero() */
        {   is.sval = 0;
            break;
        }
#ifdef IO
        case 'p': /* put() */
        {   is.dreg = &ce->c.a->pb[ce->c.a->pb[PUTBUFSIZ]];
            break;
        }
        case 'g': /* get() */
        {   is.sval = ce->c.a->gb[ce->c.a->gb[GETBUFSIZ]];
            a = ad(ce->c.a->ip + 1); /* a = address of start of template */
            while(1) /* find size of template, s = size */
            {
#if PLOIDY == 1
                if(soup[ad(a)] != Nop0 &&
                   soup[ad(a)] != Nop1)
#else /* PLOIDY > 1 */
                if(soup[ad(a)][is.stra] != Nop0 &&
                   soup[ad(a)][is.stra] != Nop1)
#endif /* PLOIDY > 1 */
                    break;
                a++; is.iip++;
            }
            break;
        }
#endif /* IO */
        default: /* movdd(), split() ok as is */
            break;
    }
}

void dec1d2s(ce) /* decode one destination register, two source values */
Pcells  ce;      /* use with: add(), sub() */
{   I32s  tval0, tval1, tval2;

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
#ifdef SHADOW
    if (ce->c.p->sha)
    {   tval0 = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
        tval1 = ce->c.a->re[NUMREG + ce->c.p->re[1]] + flaw(ce);
        tval2 = ce->c.a->re[NUMREG + ce->c.p->re[2]] + flaw(ce);
    }
    else
#endif /* SHADOW */
    {   tval0 = flaw(ce) + ce->c.p->re[0];
        tval1 = flaw(ce) + ce->c.p->re[1];
        tval2 = flaw(ce) + ce->c.p->re[2];
    }
    is.dreg = &(ce->c.a->re[mo(tval0, NUMREG)]);
    is.dran = SoupSize;
    is.sval  = ce->c.a->re[mo(tval1, NUMREG)] + flaw(ce);
    is.sval2 = ce->c.a->re[mo(tval2, NUMREG)];
    switch (ce->c.p->mn[0])
    {   case 's': /* sub() */
        {   is.sval2 = -is.sval2;
            break;
        }
        default: /* add() ok as is */
            break;
    }
}

void dec1d3s(ce) /* decode one destination register, three source values */
Pcells  ce;      /* use with: offset(), mal() */
{   I32s  tval0, tval1, tval2, tval3;

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
#ifdef SHADOW
    if (ce->c.p->sha)
    {   tval0 = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
        tval1 = ce->c.a->re[NUMREG + ce->c.p->re[1]] + flaw(ce);
        tval2 = ce->c.a->re[NUMREG + ce->c.p->re[2]] + flaw(ce);
        tval3 = ce->c.a->re[NUMREG + ce->c.p->re[3]] + flaw(ce);
    }
    else
#endif /* SHADOW */
    {   tval0 = flaw(ce) + ce->c.p->re[0];
        tval1 = flaw(ce) + ce->c.p->re[1];
        tval2 = flaw(ce) + ce->c.p->re[2];
        tval3 = flaw(ce) + ce->c.p->re[3];
    }
    is.dreg  = &(ce->c.a->re[mo(tval0, NUMREG)]);
    is.sval  =   ce->c.a->re[mo(tval1, NUMREG)];
    is.sval2 =   ce->c.a->re[mo(tval2, NUMREG)];
    is.sval3 =   ce->c.a->re[mo(tval3, NUMREG)];
    is.dran = SoupSize;
    switch (ce->c.p->mn[0])
    {   case 'm': /* mal() */
        {   if (MalMode == 6 && is.sval3 < 0)
                is.mode2 = 1; /* better fit */
            else
                is.mode2 = MalMode;
            is.mode = MemModeProt;
            break;
        }
        default: /* offset() ok as is */
            break;
    }
}

/* void puticc(ce) write a value to the input buffer of other cell
 * ce->c.a->pb[PUTBUFSIZ]     == pointer to next output value to be written
 * ce->c.a->pb[PUTBUFSIZ + 1] == pointer to next output value to be read
 * ce->c.a->pb[PUTBUFSIZ + 2] == number of unread output values
 *
 * is.dcel  = destination cell, in whose buffer the value will be put
 * is.dreg  = destination "register" in the put buffer
 * is.dval3 = destination for address returned by adr()
 * is.mode3 = 0 = broadcast to other cells' get buffer
 *            1 = write to other cell's get buffer
 * is.sval  = value to be placed in the dest reg
 *
 * void adr(ce) find address of a template
 * is.mode  = search mode: 1 = forward, 2 = backward, 0 = outward
 * is.mode2 =  preference: 1 = forward, 2 = backward, and return for
 *        direction found: 1 = forward, 2 = backward, 3 = both, 0 = none
 * is.dval  = starting address for forward search
 * is.dval2 = starting address for backward search
 * is.dreg  = destination register where target address will be stored
 * is.dreg2 = destination register where template size will be stored
 * is.dreg3 = destination register where offset of target will be stored
 * is.sval  = return address if template size = 0
 * is.sval2 = template size, 0 = no template
 * is.sval3 = search limit, and return for distance actually searched
 * is.dmod  = modulus value for is.dreg
 * is.dmod2 = modulus value for is.dreg2
 * is.dmod3 = modulus value for is.dreg3
 * is.dran  = range to maintain for is.dreg
 * is.dran2 = range to maintain for is.dreg2
 * is.dran3 = range to maintain for is.dreg3
 */
void pputicc(ce)/* write AX to output port; or if put template, put to input */
Pcells  ce;   /* port of creature(s) with complementary get template */
{   I32s    a, s = 0, adre, tval;
    Pcells  dc;
    I8s     md;

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
    a = ad(ce->c.a->ip + 1); /* a = address of start of template */
    while(1) /* find size of template, s = size */
    {
#if PLOIDY == 1
        if(soup[ad(a + s)] != Nop0 &&
           soup[ad(a + s)] != Nop1)
#else /* PLOIDY > 1 */
        if(soup[ad(a + s)][is.stra] != Nop0 &&
           soup[ad(a + s)][is.stra] != Nop1)
#endif /* PLOIDY > 1 */
            break;
        s++;
    }
#ifdef SHADOW
    if (ce->c.p->sha)
        tval = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
    else
#endif /* SHADOW */
        tval = flaw(ce) + ce->c.p->re[0];
    is.sval = ce->c.a->re[mo(tval, NUMREG)];
    if (s)
    {   is.dreg  = &is.dval3;  /* dest register for address */
        is.dreg2 = &BitBucket; /* dest reg for template size */
        is.dreg3 = &BitBucket; /* dest reg for offset */
        is.sval2 = s;
        is.sval3 = Put_limit;
        is.dval  = ce->mm.p + ce->mm.s;
        is.dval2 = ce->mm.p - 1;
        is.mode  = 0;
        is.mode2 = 1;
        is.mode3 = 0;
        is.iip   = s + 1;
    }
    else
    {
#ifdef SHADOW
        if (ce->c.p->sha)
            tval = ce->c.a->re[NUMREG + ce->c.p->re[1]] + flaw(ce);
        else
#endif /* SHADOW */
            tval = flaw(ce) + ce->c.p->re[1];
        tval = ce->c.a->re[mo(tval, NUMREG)];
        tval = ad(tval);
        if (!IsFree(tval))
            WhichCell(tval, &is.dcel, &md);
        else
            is.dreg = &BitBucket;
        is.mode3 = 1;
    }
}

/* void movdi(ce) *(is.dins) = is.sval + flaw(ce);
 * is.dval  = address of destination instruction
 * is.dins  = pointer to destination instruction
 * is.sval  = value to be moved to destination instruction
 * is.sval2 = original value of destination instruction
 */
void pmovdi(ce) /* soup [R0] = R1 */
Pcells  ce;
{   I32s  tval, tval2, tval3;

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
#ifdef SHADOW
    if (ce->c.p->sha)
    {   tval  = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
        tval2 = ce->c.a->re[NUMREG + ce->c.p->re[1]] + flaw(ce);
        tval3 = ce->c.a->re[NUMREG + ce->c.p->re[2]] + flaw(ce);
    }
    else
#endif /* SHADOW */
    {   tval  = flaw(ce) + ce->c.p->re[0];
        tval2 = flaw(ce) + ce->c.p->re[1];
        tval3 = flaw(ce) + ce->c.p->re[2];
    }
    tval = ce->c.a->re[mo(tval,NUMREG)] + flaw(ce); /* AX */
    if (ce->c.p->fl)
    {   tval3 = ce->c.a->re[mo(tval3,NUMREG)] + flaw(ce);
        is.dval = ad(tval + tval3);
    }
    else
        is.dval = ad(tval);
    is.sval = ce->c.a->re[mo(tval2, NUMREG)] + flaw(ce);
#if PLOIDY == 1
    is.dins = &soup[is.dval];
#else /* PLOIDY > 1 */
    is.dins = &soup[is.dval][is.dtra];
#endif /* PLOIDY > 1 */
    is.sval2 = *(is.dins);
}

/* void movid(ce) *(is.dreg) = *(is.sins) + flaw(ce);
 * is.sins = pointer to source instruction
 * is.sval = address of source instruction
 * is.dreg = destination register, where moved value will be placed
 * is.dmod = value by which to modulus destination register
 * is.dran = range within which to contain destination register
 */
void pmovid(ce) /* R0 = soup [R1] */
Pcells  ce;
{   I32s  tval, tval2, tval3;

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
#ifdef SHADOW
    if (ce->c.p->sha)
    {   tval  = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
        tval2 = ce->c.a->re[NUMREG + ce->c.p->re[1]] + flaw(ce);
        tval3 = ce->c.a->re[NUMREG + ce->c.p->re[2]] + flaw(ce);
    }
    else
#endif /* SHADOW */
    {   tval  = flaw(ce) + ce->c.p->re[0];
        tval2 = flaw(ce) + ce->c.p->re[1];
        tval3 = flaw(ce) + ce->c.p->re[2];
    }
    tval = ce->c.a->re[mo(tval, NUMREG)] + flaw(ce);
    if (ce->c.p->fl)
    {   tval3 = ce->c.a->re[mo(tval3,NUMREG)] + flaw(ce);
        is.sval = ad(tval + tval3);
    }
    else
        is.sval = ad(tval);
    is.dreg = &(ce->c.a->re[mo(tval2, NUMREG)]);
#if PLOIDY == 1
    is.sins = &soup[is.sval];
#else /* PLOIDY > 1 */
    is.sins = &soup[is.sval][is.stra];
#endif /* PLOIDY > 1 */
    is.dran = SoupSize;
}

/* void movii(ce) *(is.dins) = *(is.sins);
 * is.dval  = address of destination instruction
 * is.dins  = pointer to destination instruction
 * is.sval  = address of source instruction
 * is.sins  = pointer to source instruction
 * is.dtra  = track of destination instruction
 * is.sval2 = original value of destination instruction
 */
void pmovii(ce)
Pcells  ce;
{   I32s  tval, tval2, tval3;

#ifdef SHADOW
    if (ce->c.p->sha)
    {   tval  = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
        tval2 = ce->c.a->re[NUMREG + ce->c.p->re[1]] + flaw(ce);
        tval3 = ce->c.a->re[NUMREG + ce->c.p->re[2]] + flaw(ce);
    }
    else
#endif /* SHADOW */
    {   tval  = flaw(ce) + ce->c.p->re[0];
        tval2 = flaw(ce) + ce->c.p->re[1];
        tval3 = flaw(ce) + ce->c.p->re[2];
    }
    tval  = ce->c.a->re[mo(tval,  NUMREG)] + flaw(ce);
    tval2 = ce->c.a->re[mo(tval2, NUMREG)] + flaw(ce);
    if (ce->c.p->fl)
    {   tval3 = ce->c.a->re[mo(tval3, NUMREG)] + flaw(ce);
        is.dval = ad(tval  + tval3);
        is.sval = ad(tval2 + tval3);
    }
    else
    {   is.dval = ad(tval);
        is.sval = ad(tval2);
    }
#if PLOIDY == 1
    is.dins = &soup[is.dval];
    is.sins = &soup[is.sval];
#else /* PLOIDY > 1 */
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
    is.dins = &soup[is.dval][is.dtra];
    is.sins = &soup[is.sval][is.stra];
#endif /* PLOIDY > 1 */
    is.sval2 = *(is.dins);
    is.iip = is.dib = 1;
#ifdef HSEX
    if (ce->d.x_over_addr)
    {   if ((!ce->d.mov_daught) && (!FindMate(ce)))
            ce->d.x_over_addr = ce->d.mate_addr = 0;
        else UseMate(ce);
    }
#endif /* HSEX */
}

/* void tcall(ce) adr(ce); push(ce); */
/* void adr(ce) find address of a template
 * is.mode  = search mode: 1 = forward, 2 = backward, 0 = outward
 * is.mode2 =  preference: 1 = forward, 2 = backward, and return for
 *        direction found: 1 = forward, 2 = backward, 3 = both, 0 = none
 * is.dval  = starting address for forward search
 * is.dval2 = starting address for backward search
 * is.dreg  = destination register where target address will be stored
 * is.dreg2 = destination register where template size will be stored
 * is.dreg3 = destination register where offset of target will be stored
 * is.sval  = return address if template size = 0
 * is.sval2 = template size, 0 = no template
 * is.sval3 = search limit, and return for distance actually searched
 * is.dmod  = modulus value for is.dreg
 * is.dmod2 = modulus value for is.dreg2
 * is.dmod3 = modulus value for is.dreg3
 * is.dran  = range to maintain for is.dreg
 * is.dran2 = range to maintain for is.dreg2
 * is.dran3 = range to maintain for is.dreg3
 */
/* void push(ce) ce->c.a->sp = ++ce->c.a->sp % STACK_SIZE;
 *               ce->c.a->st[ce->c.a->sp] = is.sval + flaw(ce);
 * is.sval = value to be pushed onto the stack
 */
void ptcall(ce) /* push ip to stack, outward template jump */
Pcells  ce;     /* this maps to adr followed by push */
{   I32s    a, s = 0, tval;

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
    a = ad(ce->c.a->ip + 1); /* a = address of start of template */
    while(1) /* find size of template, s = size */
    {
#if PLOIDY == 1
	if(soup[ad(a + s)] != Nop0 &&
           soup[ad(a + s)] != Nop1)
#else /* PLOIDY > 1 */
	if(soup[ad(a + s)][is.stra] != Nop0 &&
           soup[ad(a + s)][is.stra] != Nop1)
#endif /* PLOIDY > 1 */
            break;
        s++;
    }
    is.dreg  = &(ce->c.a->ip); /* destination register for address */
    is.dreg2 = &BitBucket;
    is.dreg3 = &BitBucket;
    is.sval  = ad(ce->c.a->ip + s + 1);/* address to be pushed onto stack */
    is.sval2 = s;  /* size of template */
    is.sval3 = Search_limit;
    is.dmod  = SoupSize;
    is.dval  = ad(a + s + 1); /* start address for forward search */
    is.dval2 = ad(a - s - 1); /* start address for backward search */
    is.mode  = 0; /* outward jump */
    is.mode2 = 1;
    is.dib = 1;
    is.iip = 0;
}

/* void adr(ce) find address of a template
 * is.mode  = search mode: 1 = forward, 2 = backward, 0 = outward
 * is.mode2 =  preference: 1 = forward, 2 = backward, and return for
 *        direction found: 1 = forward, 2 = backward, 3 = both, 0 = none
 * is.dval  = starting address for forward search
 * is.dval2 = starting address for backward search
 * is.dreg  = destination register where target address will be stored
 * is.dreg2 = destination register where template size will be stored
 * is.dreg3 = destination register where offset of target will be stored
 * is.sval  = return address if template size = 0
 * is.sval2 = template size, 0 = no template
 * is.sval3 = search limit, and return for distance actually searched
 * is.stra  = source track for template
 * is.dtra  = destination track for template
 * is.dmod  = modulus value for is.dreg
 * is.dmod2 = modulus value for is.dreg2
 * is.dmod3 = modulus value for is.dreg3
 * is.dran  = range to maintain for is.dreg
 * is.dran2 = range to maintain for is.dreg2
 * is.dran3 = range to maintain for is.dreg3
 */
void decadr(ce) /* search for template, return address in ax */
Pcells  ce;     /* return template size in cx */
{   I32s    a, s = 0, tval, tval2, tval3, tval4;

    is.iip = is.dib = 1;
#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
    a = ad(ce->c.a->ip + 1); /* a = address of start of template */
    while(1) /* find size of template, s = size */
    {
#if PLOIDY == 1
	if(soup[ad(a + s)] != Nop0 &&
           soup[ad(a + s)] != Nop1)
#else /* PLOIDY > 1 */
	if(soup[ad(a + s)][is.stra] != Nop0 &&
           soup[ad(a + s)][is.stra] != Nop1)
#endif /* PLOIDY > 1 */
            break;
        s++;
    }
#ifdef SHADOW
    if (ce->c.p->sha)
    {   if (s)
        {   tval  = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
            tval2 = ce->c.a->re[NUMREG + ce->c.p->re[1]] + flaw(ce);
            tval3 = ce->c.a->re[NUMREG + ce->c.p->re[2]] + flaw(ce);
        }
        tval4 = ce->c.a->re[NUMREG + ce->c.p->re[3]] + flaw(ce);
    }
    else
#endif /* SHADOW */
    {   if (s)
        {   tval  = flaw(ce) + ce->c.p->re[0];
            tval2 = flaw(ce) + ce->c.p->re[1];
            tval3 = flaw(ce) + ce->c.p->re[2];
        }
        tval4 = flaw(ce) + ce->c.p->re[3];
    }
    if (s)
    {
    is.dreg  = &(ce->c.a->re[mo(tval,  NUMREG)]); /* dest reg for address */
    is.dreg2 = &(ce->c.a->re[mo(tval2, NUMREG)]); /* dest reg for templ size */
    is.dreg3 = &(ce->c.a->re[mo(tval3, NUMREG)]); /* dest reg for offset */
    }
    else
        is.dreg = is.dreg2 = is.dreg3 = &BitBucket;
    if (ce->c.p->fl)
    {   if (ce->c.p->re[0] < 0)
            is.dreg  = &BitBucket;
        if (ce->c.p->re[1] < 0)
            is.dreg2 = &BitBucket;
        if (ce->c.p->re[2] < 0)
            is.dreg3 = &BitBucket;
        if (ce->c.p->re[3] < 0)
            tval4 = 0;
        else
            tval4 = ce->c.a->re[mo(tval4, NUMREG)]; /* start at offset */
    }
    else
        tval4 = ce->c.a->re[mo(tval4, NUMREG)]; /* start at offset */
    is.sval2 = s;  /* size of template */
    is.dmod  = SoupSize;
    is.dmod3 = SoupSize;
    is.dran2 = SoupSize;
    is.dval  = ad(a + s + tval4 + 1); /* start address for forward search */
    is.dval2 = ad(a - s - tval4 - 1); /* start address for backward search */
    is.sval3 = Search_limit - tval4;
    is.iip = s + 1; is.dib = 1;
    switch (ce->c.p->mn[3])
    {   case 'o': /* adro() */
        {   is.mode  = 0; /* outward search */
            is.mode2 = 1;
            break;
        }
        case 'b': /* adrb() */
        {   is.mode  = 2; /* backward search */
            is.mode2 = 2;
            break;
        }
        case 'f': /* adrf() */
        {   is.mode  = 1; /* forward search */
            is.mode2 = 1;
            break;
        }
        default: /* ok as is */
            break;
    }
}

/* void adr(ce) find address of a template
 * is.mode  = search mode: 1 = forward, 2 = backward, 0 = outward
 * is.mode2 =  preference: 1 = forward, 2 = backward, and return for
 *        direction found: 1 = forward, 2 = backward, 3 = both, 0 = none
 * is.dval  = starting address for forward search
 * is.dval2 = starting address for backward search
 * is.dreg  = destination register where target address will be stored
 * is.dreg2 = destination register where template size will be stored
 * is.dreg3 = destination register where offset of target will be stored
 * is.sval  = return address if template size = 0
 * is.sval2 = template size, 0 = no template
 * is.sval3 = search limit, and return for distance actually searched
 * is.dmod  = modulus value for is.dreg
 * is.dmod2 = modulus value for is.dreg2
 * is.dmod3 = modulus value for is.dreg3
 * is.dran  = range to maintain for is.dreg
 * is.dran2 = range to maintain for is.dreg2
 * is.dran3 = range to maintain for is.dreg3
 */
void decjmp(ce) /* template jump: jmpo(), jmpb(), jmpf() */
Pcells  ce;
{   I32s    a, s = 0, tval;

#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
    a = ad(ce->c.a->ip + 1); /* a = address of start of template */
    while(1) /* find size of template, s = size */
    {   
#if PLOIDY == 1
	if(soup[ad(a + s)] != Nop0 &&
           soup[ad(a + s)] != Nop1)
#else /* PLOIDY > 1 */
	if(soup[ad(a + s)][is.stra] != Nop0 &&
           soup[ad(a + s)][is.stra] != Nop1)
#endif /* PLOIDY > 1 */
            break;
        s++;
    }
#ifdef SHADOW
    if (ce->c.p->sha)
        tval = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
    else
#endif /* SHADOW */
        tval = flaw(ce) + ce->c.p->re[0];
    tval = ce->c.a->re[mo(tval, NUMREG)] + flaw(ce);
    is.sval  = ad(tval); /* target for IP if s == 0 */
    is.dreg  = &(ce->c.a->ip); /* destination register for address */
    is.dreg2 = &BitBucket; /* destination register for template size */
    is.dreg3 = &BitBucket; /* dest reg for offset */
    is.sval2 = s;  /* size of template */
    is.sval3 = Search_limit;
    is.dval  = ad(a + s + 1); /* start address for forward search */
    is.dval2 = ad(a - s - 1); /* start address for backward search */
    is.dmod  = SoupSize;
    is.dran2 = SoupSize;
    is.dib = 1;
    is.iip = 0;
    switch (ce->c.p->mn[3])
    {   case 'o': /* jmpo() */
        {   is.mode  = 0;   /* outward jump */
            is.mode2 = 1;
            break;
        }
        case 'b': /* jmpb() */
        {   is.mode  = 2;   /* backward jump */
            is.mode2 = 2;
            break;
        }
        case 'f': /* jmpf() */
        {   is.mode  = 1;   /* forward jump */
            is.mode2 = 1;
            break;
        }
        default: /* ok as is */
            break;
    }
}

#ifdef JUNK

/* void adr(ce) find address of a template
 * is.mode  = search mode: 1 = forward, 2 = backward, 0 = outward
 * is.mode2 =  preference: 1 = forward, 2 = backward, and return for
 *        direction found: 1 = forward, 2 = backward, 3 = both, 0 = none
 * is.dval  = starting address for forward search
 * is.dval2 = starting address for backward search
 * is.dreg  = destination register where target address will be stored
 * is.dreg2 = destination register where template size will be stored
 * is.dreg3 = destination register where offset of target will be stored
 * is.sval  = return address if template size = 0
 * is.sval2 = template size, 0 = no template
 * is.sval3 = search limit, and return for distance actually searched
 * is.dmod  = modulus value for is.dreg
 * is.dmod2 = modulus value for is.dreg2
 * is.dmod3 = modulus value for is.dreg3
 * is.dran  = range to maintain for is.dreg
 * is.dran2 = range to maintain for is.dreg2
 * is.dran3 = range to maintain for is.dreg3
 */
void ptjmpb(ce) /* backward template jump */
Pcells  ce;
{   I32s    a, s = 0, tval;

#if PLOIDY > 1
    is.dtra = ce->c.a->de;
    is.stra = ce->c.a->so;
#endif /* PLOIDY > 1 */
    a = ad(ce->c.a->ip + 1); /* a = address of start of template */
    while(1) /* find size of template, s = size */
    {
#if PLOIDY == 1
        if(soup[ad(a + s)] != Nop0 &&
           soup[ad(a + s)] != Nop1)
#else /* PLOIDY > 1 */
        if(soup[ad(a + s)][is.stra] != Nop0 &&
           soup[ad(a + s)][is.stra] != Nop1)
#endif /* PLOIDY > 1 */
            break;
        s++;
    }
    is.dreg  = &(ce->c.a->ip); /* destination register for address */
    tval = ce->c.a->re[mo(tval, NUMREG)] + flaw(ce);
#ifdef SHADOW
    if (ce->c.p->sha)
        tval = ce->c.a->re[NUMREG + ce->c.p->re[0]] + flaw(ce);
    else
#endif /* SHADOW */
        tval = flaw(ce) + ce->c.p->re[0];
    tval = ce->c.a->re[mo(tval, NUMREG)] + flaw(ce);
    is.sval  = ad(tval); /* target for IP if s == 0 */
    is.dreg2 = &BitBucket; /* destination register for template size */
    is.dreg3 = &BitBucket;
    is.sval2 = s;  /* size of template */
    is.sval3 = Search_limit;
    is.dmod  = SoupSize;
    is.dval  = ad(a + s + 1); /* start address for forward search */
    is.dval2 = ad(a - s - 1); /* start address for backward search */
    is.mode  = 2; /* backward jump */
    is.mode2 = 2;
    is.dib = 1;
    is.iip = 0;
}

#endif /* JUNK */
