// @(#) $Header: /home/abrown/public_html/first/first2003chs/software/simulator/RCS/pb_math.c,v 2.9 2006/12/14 19:40:16 abrown Exp $

/***********************************************************************
  * Copyright (C) 2002, 2003  Allen Brown
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  * 
  * 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.
  *   59 Temple Place, Suite 330
  *   Boston, MA  02111-1307  USA
  * 
  * To contact the author of this software:
  *   Allen Brown
  *   PO Box J
  *   Corvallis, OR
  * 
  *   http://brown.armoredpenguin.com/~abrown/contact.html
  ***********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "pb.h"

// The ramarray is memory accessible only via the get and put commands.
#define RAMSIZE 64
static pbvalue ramarray[RAMSIZE];

// --------------------------------------------------------------
// pblet - Basic Stamp Manual p.?
// Set the field of numbera based on its size and index.  The value
// of the field is from numberb, based on its size and index.
// (If numberb comes from a function, its index will always be 0.)
void pblet(struct pbnumber numbera, struct pbnumber numberb, char *linenum)
{
  pbvalue valuebshift;
  valuebshift = pbstrip(numberb);
//  printf("pblet 1: numbera={%x,%hd,%hd,'%s'};\n",
//	 (*numbera.vpoint), numbera.size, numbera.index, numbera.name);
//  printf("pblet 2: numberb={%x,%hd,%hd,'%s'}, valuebshift=%x;\n",
//	 (*numberb.vpoint), numberb.size, numberb.index, numberb.name,
//	 valuebshift);
//  fflush(stdout);
  *numbera.vpoint =
    (makemask(1,numbera.size,numbera.index) & (*numbera.vpoint))
    |
    (makemask(0,numbera.size,numbera.index) & (valuebshift << numbera.index));
//  printf("pblet 3 %s: numbera={%x,%hd,%hd,'%s'};\n", linenum,
//	 (*numbera.vpoint), numbera.size, numbera.index, numbera.name); fflush(stdout);
  if( numbera.name[0] == 'o'  &&  numbera.name[1] == 'u'
      &&  numbera.name[2] == 't')
    {
      if( BASEFORMAT == 16 )
	{
	  printf("output: %x\n", *numbera.vpoint );
	} else {
	  printf("output: %d\n", *numbera.vpoint );
	}
    }
  return;
} // pblet

// --------------------------------------------------------------
// pbabs - Basic Stamp Manual p.64
struct pbnumber pbabs(struct pbnumber numbera)
{
  static char name[] = "pbabs()";
  pbvalue valuea;
  valuea=(pbvalue)pbstrip(numbera);
  if( valuea & 0x8000 )
    {
      valuea = 0x10000 - valuea;
    }
  return( makepbnumber(0,valuea,(pbi)16,(pbi)0,name) );
} // pbabs

// --------------------------------------------------------------
// pbbnot - Basic Stamp Manual p.64
struct pbnumber pbbnot(struct pbnumber numbera)
{
  static char name[] = "pbbnot()";
  pbvalue valuea_;
  valuea_=(~pbstrip(numbera)) & makemask(0,(pbi)16,(pbi)0);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbbnot

// --------------------------------------------------------------
// pbadd - Basic Stamp Manual p.67
struct pbnumber pbadd(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pbadd()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  valuea_ = valuea_ + valueb_;
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbadd

// --------------------------------------------------------------
// pbsub - Basic Stamp Manual p.67
struct pbnumber pbsub(struct pbnumber valuea, struct pbnumber valueb)
{
  static char name[] = "pbsub()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(valuea);
  valueb_=pbstrip(valueb);
  valuea_ = valuea_ - valueb_;
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbsub

// --------------------------------------------------------------
// pbmul - Basic Stamp Manual p.67
struct pbnumber pbmul(struct pbnumber valuea, struct pbnumber valueb)
{
  static char name[] = "pbmul()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(valuea);
  valueb_=pbstrip(valueb);
  valuea_ = valuea_ * valueb_;
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbmul

// --------------------------------------------------------------
// pbdiv - Basic Stamp Manual p.69
struct pbnumber pbdiv(struct pbnumber valuea, struct pbnumber valueb)
{
  static char name[] = "pbdiv()";
  pbvalue valuea_, valueb_, valuec_;
  valuea_=pbstrip(valuea);
  valueb_=pbstrip(valueb);
  valuec_ = valuea_ / valueb_;
  if( (valuea_<0) || (valueb_<=0) )
    {
      printf( "ERROR pb_math.c pbdiv: Negative illegal a=%d, b=%d, a/b=%d.\n",
	       (int)valuea_, (int)valueb_, (int)valuec_ );
    }
  return( makepbnumber(0,valuec_,(pbi)16,(pbi)0,name) );
} // pbdiv

// --------------------------------------------------------------
// pbmin - Basic Stamp Manual p.70
// Note that the min function of pbasic actually is returning the
// max of the two numbers.  Sigh...
struct pbnumber pbmin(struct pbnumber valuea, struct pbnumber valueb)
{
  static char name[] = "pbmin()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(valuea);
  valueb_=pbstrip(valueb);
  valuea_ = (valuea_>valueb_ ? valuea_ : valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbmin

// --------------------------------------------------------------
// pbmax - Basic Stamp Manual p.71
// Note that the max function of pbasic actually is returning the
// min of the two numbers.  Sigh...
struct pbnumber pbmax(struct pbnumber valuea, struct pbnumber valueb)
{
  static char name[] = "pbmax()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(valuea);
  valueb_=pbstrip(valueb);
  valuea_ = (valuea_<valueb_ ? valuea_ : valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbmax

// --------------------------------------------------------------
// pbshl - Basic Stamp Manual p.72
struct pbnumber pbshl(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pbshl()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  valuea_ = (valuea_ << valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbshl

// --------------------------------------------------------------
// pbshr - Basic Stamp Manual p.72
struct pbnumber pbshr(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pbshr()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  valuea_ = (valuea_ >> valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbshr

// --------------------------------------------------------------
// pbband - Basic Stamp Manual p.73
struct pbnumber pbband(struct pbnumber valuea, struct pbnumber valueb)
{
  static char name[] = "pbband()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(valuea);
  valueb_=pbstrip(valueb);
  valuea_ = (valuea_ & valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbband

// --------------------------------------------------------------
// pbbor - Basic Stamp Manual p.73
struct pbnumber pbbor(struct pbnumber valuea, struct pbnumber valueb)
{
  static char name[] = "pbbor()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(valuea);
  valueb_=pbstrip(valueb);
  valuea_ = (valuea_ | valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbbor

// --------------------------------------------------------------
// pbbxor - Basic Stamp Manual p.
struct pbnumber pbbxor(struct pbnumber valuea, struct pbnumber valueb)
{
  static char name[] = "pbbxor()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(valuea);
  valueb_=pbstrip(valueb);
  valuea_ = (valuea_ ^ valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbbxor

// --------------------------------------------------------------
// pbget - Basic Stamp Manual p.127
void pbget(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pbget()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  if( valuea_ >= RAMSIZE )
    {
      fprintf(stderr,"pbget: valuea_=%x > %x.\n", valuea_, RAMSIZE );
    } else {
      *numberb.vpoint =
	(makemask(1,numberb.size,numberb.index) & (*numberb.vpoint))
	|
	(makemask(0,numberb.size,numberb.index) & (ramarray[valuea_] << numberb.index));
      // printf("\tpbget: get %x from [%x].\n", *numberb.vpoint, valuea_);
    }
  return;
} // pbget

// --------------------------------------------------------------
// pbput - Basic Stamp Manual p.245
void pbput(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pbput()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  if( valuea_ >= RAMSIZE )
    {
      fprintf(stderr,"pbput: valuea_=%x > %x.\n", valuea_, RAMSIZE );
    } else {
      // printf("\tpbput: store %x to [%x].\n", valueb_, valuea_);
      ramarray[valuea_] = valueb_;
    }
  return;
} // pbput

// --------------------------------------------------------------
// pbeq - Basic Stamp Manual p.149
struct pbnumber pbeq(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pbeq()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  valuea_ = (valuea_ == valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbeq

// --------------------------------------------------------------
// pblt - Basic Stamp Manual p.149
struct pbnumber pblt(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pblt()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  valuea_ = (valuea_ < valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pblt

// --------------------------------------------------------------
// pble - Basic Stamp Manual p.149
struct pbnumber pble(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pble()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  valuea_ = (valuea_ <= valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pble

// --------------------------------------------------------------
// pbgt - Basic Stamp Manual p.149
struct pbnumber pbgt(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pbgt()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  //  printf("**pbgt: %x/%x/%d + %x/%x/%d",
  //  	 valuea, valuea_, widtha, valueb, valueb_, widthb);
  //  printf(" '>' => %x\n", (valuea_ > valueb_));
  valuea_ = (valuea_ > valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbgt

// --------------------------------------------------------------
// pbge - Basic Stamp Manual p.149
struct pbnumber pbge(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pbge()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  valuea_ = (valuea_ >= valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbge

// --------------------------------------------------------------
// pbne - Basic Stamp Manual p.149
struct pbnumber pbne(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pbne()";
  pbvalue valuea_, valueb_;
  valuea_=pbstrip(numbera);
  valueb_=pbstrip(numberb);
  valuea_ = (valuea_ != valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbne

// --------------------------------------------------------------
// pblor - Basic Stamp Manual p.149
struct pbnumber pblor(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pblor()";
  pbvalue valuea_, valueb_;
  valuea_=(0 != pbstrip(numbera));
  valueb_=(0 != pbstrip(numberb));
  valuea_ = (valuea_ || valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pblor

// --------------------------------------------------------------
// pbland - Basic Stamp Manual p.149
struct pbnumber pbland(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pbland()";
  pbvalue valuea_, valueb_;
  valuea_=(0 != pbstrip(numbera));
  valueb_=(0 != pbstrip(numberb));
  valuea_ = (valuea_ && valueb_);
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pbland

// --------------------------------------------------------------
// pblxor - Basic Stamp Manual p.149
struct pbnumber pblxor(struct pbnumber numbera, struct pbnumber numberb)
{
  static char name[] = "pblxor()";
  pbvalue valuea_, valueb_;
  valuea_=(0 != pbstrip(numbera));
  valueb_=(0 != pbstrip(numberb));
  valuea_ = ( (valuea_ && !valueb_) || (!valuea_ && valueb_) );
  return( makepbnumber(0,valuea_,(pbi)16,(pbi)0,name) );
} // pblxor

// --------------------------------------------------------------
/* TODO:
 * - Implement more functions from the language.
 */

