Logo Search packages:      
Sourcecode: felt version File versions  Download package

code.c

/*
    This file is part of the FElt finite element analysis package.
    Copyright (C) 1993-2000 Jason I. Gobat and Darren C. Atkinson

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/************************************************************************
 * File:    code.c                                          *
 *                                                    *
 * Description:   This file contains the public and private function and      *
 *          type definitions for the stack machine code.          *
 ************************************************************************/

# include <stdio.h>
# include <math.h>
# include "code.h"
# include "allocate.h"
# include VAR_ARGS_INCLUDE


# define MaxStackDepth  1024
# define MaxCodeSize    1024

# define push(x)  (* ++ sp = (x))
# define pop()          (* sp --)
# define top()          (* sp)

# define deg2rad(x)     ((x) * M_PI / 180.0)


# define None      0
# define Integer 1
# define Double  2
# define Array     3

static struct {
    char *opcode;
    int   arg_type;
} data [ ] = {
    {"jmp",   Integer},
    {"jnz",   Integer},
    {"jz",    Integer},
    {"push",  Double},
    {"pop",   None},
    {"copy",  None},
    {"test",  None},
    {"neg",   None},
    {"not",   None},
    {"inv",   None},
    {"mul",   None},
    {"div",   None},
    {"mod",   None},
    {"add",   None},
    {"sub",   None},
    {"lsft",  None},
    {"rsht",  None},
    {"lt",    None},
    {"gt",    None},
    {"lteq",  None},
    {"gteq",  None},
    {"eq",    None},
    {"neq",   None},
    {"and",   None},
    {"xor",   None},
    {"or",    None},
    {"time",  None},
    {"sin",   None},
    {"cos",   None},
    {"tan",   None},
    {"exp",   None},
    {"ln",    None},
    {"log",   None},
    {"pow",   None},
    {"sqrt",  None},
    {"hypot", None},
    {"floor", None},
    {"ceil",  None},
    {"fmod",  None},
    {"fabs",  None},
    {"table", Array},
    {"cycle", Array},
    {"halt",  None},
};


typedef union instruction {
    Opcode op;
    int    offset;
    double arg;
} Instruction;


static Instruction in_core [MaxCodeSize];
static Code    ip = in_core;

static double        stack [MaxStackDepth];
static double       *sp;

Code InCore = in_core;


/************************************************************************
 * Function:      EmitCode                                  *
 *                                                    *
 * Description:   Adds an instruction to the current piece of code.     *
 ************************************************************************/

# ifdef UseFunctionPrototypes
void EmitCode (Opcode op, ...)
# else
void EmitCode (op, va_alist)
    Opcode op;
    va_dcl
# endif
{
    va_list ap;
    int     i;
    int     length;
    double *array;


    ip ++ -> op = op;

    switch (data [op].arg_type) {
    case Integer:
      VA_START (ap, op);
      ip ++ -> offset = va_arg (ap, int);
      va_end (ap);
      break;

    case Double:
      VA_START (ap, op);
      ip ++ -> arg = va_arg (ap, double);
      va_end (ap);
      break;

    case Array:
      VA_START (ap, op);
      array = va_arg (ap, double *);
      ip ++ -> offset = length = va_arg (ap, int);
      va_end (ap);
      for (i = 0; i < length; i ++)
          ip ++ -> arg = array [i];
      break;
    }
}


/************************************************************************
 * Function:      CopyCode                                  *
 *                                                    *
 * Description:   Copies a piece of code.                         *
 ************************************************************************/

Code CopyCode (code)
    Code code;
{
    Code     pc;
    Code     ptr;
    Code     copy;
    Opcode   op;
    unsigned size;


    size = 0;
    if (!(pc = code))
      return NULL;

    while (1) {
      size ++;
      if ((op = pc ++ -> op) == HaltOp)
          break;
      if (data [op].arg_type == Array) {
          size += pc -> offset;
          pc += pc -> offset;
      }
      if (data [op].arg_type != None) {
          size ++;
          pc ++;
      }
    }

    if (!(copy = Allocate (Instruction, size)))
      return NULL;

    pc = code;
    ptr = copy;

    while (size --)
      *ptr ++ = *pc ++;

    return copy;
}


/************************************************************************
 * Function:      FreeCode                                  *
 *                                                    *
 * Description:   Deallocates a copied program.                   *
 ************************************************************************/

void FreeCode (code)
    Code code;
{
    if (code != InCore)
      Deallocate (code);
}


/************************************************************************
 * Function:      SetIP                                     *
 *                                                    *
 * Description:   Sets the address of the instruction pointer.          *
 ************************************************************************/

void SetIP (new_ip)
    int new_ip;
{
    ip = InCore + new_ip;
}


/************************************************************************
 * Function:      GetIP                                     *
 *                                                    *
 * Description:   Returns the address of the instruction pointer.       *
 ************************************************************************/

int GetIP ( )
{
    return ip - InCore;
}


/************************************************************************
 * Function:      EvalTable                                 *
 *                                                    *
 * Description:   Evaluates a table or cycle opcode.              *
 ************************************************************************/

static double EvalTable (array, length, time, flag)
    double *array;
    int     length;
    double  time;
    int     flag;
{
    int    i1;
    int    i2;
    double max;
    double t1;
    double t2;
    double x1;
    double x2;


    if (length == 2)
      return time == array [0] ? array [1] : 0;

    if (flag) {
      max = array [length - 2];
      while (time > max)
          time -= max;
    }

    for (i1 = 0; i1 < length; i1 += 2)
      if (time <= array [i1])
          break;

    if (i1 == length) {
      i1 = i1 - 2;
      i2 = i1 - 2;
    } else if (i1)
      i2 = i1 - 2;
    else
      i2 = i1 + 2;

    t1 = array [i1];
    t2 = array [i2];
    x1 = array [i1 + 1];
    x2 = array [i2 + 1];

    /*printf ("(%g,%g) %g (%g,%g)\n", t1, x1, time, t2, x2);*/
    return t1 != t2 ? (x2 - x1) / (t2 - t1) * (time - t1) + x1 : x2;
}


/************************************************************************
 * Function:      EvalCode                                  *
 *                                                    *
 * Description:   Evaluates a piece of code.                      *
 ************************************************************************/

double EvalCode (code, time)
    Code code;
    double time;
{
    int    x;
    int    y;
    double a;
    double b;
    Code   pc;


    sp = stack;
    if (!(pc = code))
      return 0;

    while (1)
      switch (pc ++ -> op) {
      case JmpOp:
          y = pc ++ -> offset;
          pc += y;
          break;

      case JnzOp:
          x = pop ( );
          y = pc ++ -> offset;
          if (x) pc += y;
          break;

      case JzOp:
          x = pop ( );
          y = pc ++ -> offset;
          if (!x) pc += y;
          break;

      case PushOp:
          push (pc ++ -> arg);
          break;

      case PopOp:
          a = pop ( );
          break;

      case CopyOp:
          a = top ( );
          push (a);
          break;

      case TestOp:
          a = pop ( );
          push (a != 0);
          break;

      case NegOp:
          a = pop ( );
          push (-a);
          break;

      case NotOp:
          a = pop ( );
          push (!a);
          break;

      case InvOp:
          x = pop ( );
          push (~x);
          break;

      case MulOp:
          b = pop ( );
          a = pop ( );
          push (a * b);
          break;

      case DivOp:
          b = pop ( );
          a = pop ( );
          push (b ? a / b : 0);
          break;

      case ModOp:
          y = pop ( );
          x = pop ( );
          push (y ? x % y : 0);
          break;

      case AddOp:
          b = pop ( );
          a = pop ( );
          push (a + b);
          break;

      case SubOp:
          b = pop ( );
          a = pop ( );
          push (a - b);
          break;

      case LsftOp:
          y = pop ( );
          x = pop ( );
          push (x << y);
          break;

      case RsftOp:
          y = pop ( );
          x = pop ( );
          push (x >> y);
          break;

      case LtOp:
          b = pop ( );
          a = pop ( );
          push (a < b);
          break;

      case GtOp:
          b = pop ( );
          a = pop ( );
          push (a > b);
          break;

      case LteqOp:
          b = pop ( );
          a = pop ( );
          push (a <= b);
          break;

      case GteqOp:
          b = pop ( );
          a = pop ( );
          push (a >= b);
          break;

      case EqOp:
          b = pop ( );
          a = pop ( );
          push (a == b);
          break;

      case NeqOp:
          b = pop ( );
          a = pop ( );
          push (a != b);
          break;

      case AndOp:
          y = pop ( );
          x = pop ( );
          push (x & y);
          break;

      case XorOp:
          y = pop ( );
          x = pop ( );
          push (x ^ y);
          break;

      case OrOp:
          y = pop ( );
          x = pop ( );
          push (x | y);
          break;

      case TimeOp:
          push (time);
          break;

      case SinOp:
          a = pop ( );
          push (sin (a));
          break;

      case CosOp:
          a = pop ( );
          push (cos (a));
          break;

      case TanOp:
          a = pop ( );
          push (tan (a));
          break;

      case ExpOp:
          a = pop ( );
          push (exp (a));
          break;

      case LnOp:
          a = pop ( );
          push (a > 0 ? log (a) : 0);
          break;

      case LogOp:
          a = pop ( );
          push (a > 0 ? log10 (a) : 0);
          break;

      case PowOp:
          b = pop ( );
          a = pop ( );
          push (a >= 0 || b == (int) b ? pow (a, b) : 0);
          break;

      case SqrtOp:
          a = pop ( );
          push (a >= 0 ? sqrt (a) : 0);
          break;

      case HypotOp:
          b = pop ( );
          a = pop ( );
          push (hypot (a, b));
          break;

      case FloorOp:
          a = pop ( );
          push (floor (a));
          break;

      case CeilOp:
          a = pop ( );
          push (ceil (a));
          break;

      case FmodOp:
          b = pop ( );
          a = pop ( );
          push (b ? fmod (a, b) : 0);
          break;

      case FabsOp:
          a = pop ( );
          push (fabs (a));
          break;

      case TableOp:
          y = pc ++ -> offset;
          push (EvalTable (pc, y, time, 0));
          pc += y;
          break;

      case CycleOp:
          y = pc ++ -> offset;
          push (EvalTable (pc, y, time, 1));
          pc += y;
          break;

      case HaltOp:
          return pop ( );
      }
}


/************************************************************************
 * Function:      DebugCode                                 *
 *                                                    *
 * Description:   Print a piece of stack code as instructions.          *
 ************************************************************************/

void DebugCode (code)
    Code code;
{
    int     i;
    int     x;
    Opcode  op;
    Code    pc;


    if (!(pc = code))
      return;

    while (1) {
      op = pc -> op;
      printf ("%x\t%s", (int) (pc ++), data [op].opcode);

      switch (data [op].arg_type) {
      case Integer:
          x = pc ++ -> offset;
          printf ("\t%x\n", (int) (pc + x));
          break;

      case Double:
          printf ("\t%g\n", pc ++ -> arg);
          break;

      case Array:
          x = pc ++ -> offset;
          printf ("\t");
          for (i = 0; i < x; i ++)
            printf ("%g ", pc ++ -> arg);
          printf ("\n");
          break;

      default:
          printf ("\n");
      }

      if (op == HaltOp)
          return;
    }
}


/************************************************************************
 * Function:      IsConstant                                *
 *                                                    *
 * Description:   Determines if a piece of code is constant.            *
 ************************************************************************/

int IsConstant (code)
    Code code;
{
    Opcode op;
    Code   pc;


    if (!(pc = code))
      return 1;

    while (1)
      switch (op = pc ++ -> op) {
      case TimeOp:
      case TableOp:
      case CycleOp:
          return 0;

      case HaltOp:
          return 1;

      default:
          if (data [op].arg_type != None)
            pc ++;
    }
}

Generated by  Doxygen 1.6.0   Back to index