/*
Copyright (C) 1998-2003 Scott Dattalo
This file is part of gpsim.
gpsim 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, or (at your option)
any later version.
gpsim 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 gpsim; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include "processor.h"
#include "value.h"
#include "errors.h"
#include "operator.h"
#include "protocol.h"
#include "../config.h"
#include "cmd_gpsim.h"
char * TrimWhiteSpaceFromString(char * pBuffer) {
size_t iPos = 0;
char * pChar = pBuffer;
while(*pChar != 0 && ::isspace(*pChar)) {
pChar++;
}
if(pBuffer != pChar) {
memmove(pBuffer, pChar, strlen(pBuffer) - iPos);
}
iPos = strlen(pBuffer);
if(iPos > 0) {
pChar = pBuffer + iPos - 1;
while(pBuffer != pChar && ::isspace(*pChar)) {
*pChar = 0;
pChar--;
}
}
return pBuffer;
}
char * UnquoteString(char * pBuffer) {
char cQuote;
if(*pBuffer == '\'') {
cQuote = '\'';
}
else if(*pBuffer == '"') {
cQuote = '"';
}
else {
return pBuffer;
}
int iLen = strlen(pBuffer);
if(iLen > 1) {
if(pBuffer[iLen - 1] == cQuote) {
memmove(&pBuffer[0], &pBuffer[1], iLen - 2);
pBuffer[iLen - 2] = 0;
}
}
return pBuffer;
}
string &toupper(string & sStr) {
string::iterator it;
string::iterator itEnd = sStr.end();
for(it = sStr.begin(); it != itEnd; it++) {
if(isalpha(*it)) {
*it = toupper((int)*it);
}
}
return sStr;
}
//------------------------------------------------------------------------
Value::Value()
: xref(0), m_bClearableSymbol(true)
{
}
Value::Value(const char *_name, const char *desc)
: gpsimObject(_name,desc), xref(0), m_bClearableSymbol(true)
{
}
Value::~Value()
{
delete xref;
}
void Value::set(const char *cP,int i)
{
throw new Error(" cannot assign string to a " + showType());
}
void Value::set(double d)
{
throw new Error(" cannot assign a double to a " + showType());
}
void Value::set(gint64 i)
{
throw new Error(" cannot assign an integer to a " + showType());
}
void Value::set(bool v)
{
throw new Error(" cannot assign a boolean to a " + showType());
}
void Value::set(int i)
{
gint64 i64 = i;
set(i64);
}
void Value::set(Value *v)
{
throw new Error(" cannot assign a Value to a " + showType());
}
// JRH - Note: If this function Value::set(Expression) is ever
// used anywhere besides yyparse() you may want to move
// the delete expr; statement into the calling code.
void Value::set(Expression *expr)
{
try {
Value *v=0;
if(!expr)
throw new Error(" null expression ");
v = expr->evaluate();
if(!v)
throw new Error(" cannot evaluate expression ");
set(v);
delete v;
}
catch (Error *err) {
if(err)
cout << "ERROR:" << err->toString() << endl;
delete err;
}
delete expr;
}
void Value::set(Packet &pb)
{
cout << "Value,"<<name()<<" is ignoring packet buffer for set()\n";
}
void Value::get(gint64 &i)
{
throw new Error(showType() +
" cannot be converted to an integer ");
}
void Value::get(int &i)
{
gint64 i64;
get(i64);
i = (int) i64;
}
void Value::get(guint64 &i)
{
// FIXME - casting a signed int to an unsigned int -- probably should issue a warning
gint64 i64;
get(i64);
i = (gint64) i64;
}
void Value::get(bool &b)
{
throw new Error(showType() +
" cannot be converted to a boolean");
}
void Value::get(double &d)
{
throw new Error(showType() +
" cannot be converted to a double ");
}
// get as a string - no error is thrown if the derived class
// does not provide a method for converting to a string -
// instead we'll return a bogus value.
void Value::get(char *buffer, int buf_size)
{
if(buffer)
strncpy(buffer,"INVALID",buf_size);
}
void Value::get(Packet &pb)
{
cout << "Value,"<<name()<<" is ignoring packet buffer for get()\n";
}
bool Value::compare(ComparisonOperator *compOp, Value *rvalue)
{
throw new Error(compOp->showOp() +
" comparison is not defined for " + showType());
}
Value *Value::copy()
{
throw new Error(" cannot copy " + showType());
}
void Value::set_xref(Value *v)
{
delete xref;
xref = v;
}
void Value::setClearableSymbol(bool bClear) {
m_bClearableSymbol = bClear;
}
bool Value::isClearable() {
return m_bClearableSymbol;
}
Value *Value::get_xref()
{
return xref;
}
//------------------------------------------------------------------------
// gpsimValue
gpsimValue::gpsimValue(void)
: cpu(0)
{
}
gpsimValue::gpsimValue(Module *_cpu)
: cpu(_cpu)
{
}
gpsimValue::~gpsimValue(void)
{
}
void gpsimValue::update(void)
{
_xref._update();
}
void gpsimValue::add_xref(void *an_xref)
{
_xref._add(an_xref);
}
void gpsimValue::remove_xref(void *an_xref)
{
_xref.clear(an_xref);
}
string gpsimValue::toString()
{
char buff[64];
snprintf(buff,sizeof(buff), " = 0x%x",get_value());
string s = name() + string(buff);
return s;
}
Processor *gpsimValue::get_cpu() const
{
return static_cast<Processor *>(cpu);
}
void gpsimValue::set_cpu(Processor *new_cpu)
{
cpu = new_cpu;
}
/*****************************************************************
* The AbstractRange class.
*/
AbstractRange::AbstractRange(unsigned int newLeft, unsigned int newRight)
{
left = newLeft;
right = newRight;
}
AbstractRange::~AbstractRange()
{
}
string AbstractRange::toString()
{
char buff[256];
string str = "";
snprintf(buff,sizeof(buff),"%d:%d",left,right);
return (string(buff));
}
string AbstractRange::toString(char* format)
{
char cvtBuf[1024];
sprintf(cvtBuf, format, left, right);
return (string(&cvtBuf[0]));
}
char *AbstractRange::toString(char *return_str, int len)
{
if(return_str) {
snprintf(return_str,len,"%d:%d",left,right);
}
return return_str;
}
unsigned int AbstractRange::get_leftVal()
{
return(left);
}
unsigned int AbstractRange::get_rightVal()
{
return(right);
}
AbstractRange* AbstractRange::typeCheck(Value* val, string valDesc)
{
if (typeid(*val) != typeid(AbstractRange)) {
throw new TypeMismatch(valDesc, "AbstractRange", val->showType());
}
// This static cast is totally safe in light of our typecheck, above.
return((AbstractRange*)(val));
}
bool AbstractRange::compare(ComparisonOperator *compOp, Value *rvalue)
{
throw new Error(compOp->showOp() +
" comparison is not defined for " + showType());
}
Value *AbstractRange::copy()
{
return new AbstractRange(get_leftVal(),get_rightVal());
}
void AbstractRange::set(Value *v)
{
AbstractRange *ar=typeCheck(v, string(""));
left = ar->get_leftVal();
right = ar->get_rightVal();
}
/*
bool AbstractRange::operator<(Value *rv)
{
AbstractRange *_rv = typeCheck(rv,"OpLT");
return right < _rv->left;
}
*/
/*****************************************************************
* The Boolean class.
*/
Boolean::Boolean(bool newValue)
{
value = newValue;
}
Boolean::Boolean(const char *_name, bool newValue,const char *_desc)
: Value(_name,_desc)
{
value = newValue;
}
bool Boolean::Parse(const char *pValue, bool &bValue) {
if(strncmp("true", pValue, sizeof("true")-1) == 0) {
bValue = true;
return true;
}
else if(strncmp("false", pValue, sizeof("false")-1) == 0) {
bValue = false;
return true;
}
return false;
}
Boolean * Boolean::NewObject(const char *_name, const char *pValue, const char *desc) {
bool bValue;
if(Parse(pValue, bValue)) {
return new Boolean(_name, bValue);
}
return NULL;
}
Boolean::~Boolean()
{
}
string Boolean::toString()
{
bool b;
get(b);
return (string(b ? "true" : "false"));
}
string Boolean::toString(bool value)
{
return (string(value ? "true" : "false"));
}
char *Boolean::toString(char *return_str, int len)
{
if(return_str) {
bool b;
get(b);
snprintf(return_str,len,"%s",(b ? "true" : "false"));
}
return return_str;
}
char *Boolean::toBitStr(char *return_str, int len)
{
if(return_str) {
bool b;
get(b);
snprintf(return_str,len,"%d",(b ? 1 : 0));
}
return return_str;
}
string Boolean::toString(char* format)
{
char cvtBuf[1024];
bool b;
get(b);
sprintf(cvtBuf, format, b);
return (string(&cvtBuf[0]));
}
Boolean* Boolean::typeCheck(Value* val, string valDesc)
{
if (typeid(*val) != typeid(Boolean)) {
throw new TypeMismatch(valDesc, "Boolean", val->showType());
}
// This static cast is totally safe in light of our typecheck, above.
return((Boolean*)(val));
}
bool Boolean::compare(ComparisonOperator *compOp, Value *rvalue)
{
Boolean *rv = typeCheck(rvalue,"");
switch(compOp->isa()) {
case ComparisonOperator::eOpEq:
return value == rv->value;
case ComparisonOperator::eOpNe:
return value != rv->value;
default:
Value::compare(compOp, rvalue); // error
}
return false; // keep the compiler happy.
}
Value *Boolean::copy()
{
bool b;
get(b);
return new Boolean(b);
}
// get(bool&) - primary method for accessing the value.
void Boolean::get(bool &b)
{
b = value;
}
// get(int&) - type cast an integer into a boolean. Note
// that we call get(bool &) instead of directly accessing
// the member value. The reason for this is so that derived
// classes can capture the access.
void Boolean::get(int &i)
{
bool b;
get(b);
i = b ? 1 : 0;
}
/*
void Boolean::get(double &d)
{
bool b;
get(b);
d = b ? 1.0 : 0.0;
}
*/
void Boolean::get(char *buffer, int buf_size)
{
if(buffer) {
bool b;
get(b);
if(b)
strncpy(buffer,"true",buf_size);
else
strncpy(buffer,"false",buf_size);
}
}
void Boolean::get(Packet &pb)
{
bool b;
get(b);
pb.EncodeBool(b);
}
void Boolean::set(Value *v)
{
Boolean *bv = typeCheck(v,string("set "));
bool b = bv->getVal();
set(b);
}
void Boolean::set(bool v)
{
value = v;
if(get_xref())
get_xref()->set(v);
}
void Boolean::set(const char *buffer, int buf_size)
{
if(buffer) {
bool bValue;
if(Parse(buffer, bValue)) {
set(bValue);
}
}
}
void Boolean::set(Packet &p)
{
bool b;
if(p.DecodeBool(b))
set(b);
}
/*
bool Boolean::operator&&(Value *rv)
{
Boolean *_rv = typeCheck(rv,"Op&&");
return value && _rv->value;
}
bool Boolean::operator||(Value *rv)
{
Boolean *_rv = typeCheck(rv,"Op||");
return value || _rv->value;
}
bool Boolean::operator==(Value *rv)
{
Boolean *_rv = typeCheck(rv,"OpEq");
return value == _rv->value;
}
bool Boolean::operator!=(Value *rv)
{
Boolean *_rv = typeCheck(rv,"OpNe");
return value != _rv->value;
}
*/
/*****************************************************************
* The Integer class.
*/
Integer::Integer(const Integer &new_value) {
Integer & nv = (Integer&)new_value;
nv.get(value);
bitmask = new_value.bitmask;
}
Integer::Integer(gint64 newValue)
{
value = newValue;
bitmask = def_bitmask;
}
Integer::Integer(const char *_name, gint64 newValue,const char *_desc)
: Value(_name,_desc)
{
value = newValue;
bitmask = def_bitmask;
}
gint64 Integer::def_bitmask = 0xffffffff;
Integer::~Integer()
{
}
void Integer::setDefaultBitmask(gint64 bitmask) {
def_bitmask = bitmask;
}
Value *Integer::copy()
{
gint64 i;
get(i);
return new Integer(i);
}
void Integer::set(double d)
{
gint64 i = (gint64)d;
set(i);
}
void Integer::set(gint64 i)
{
value = i;
if(get_xref())
get_xref()->set(i);
}
void Integer::set(int i)
{
gint64 ii = i;
set(ii);
}
void Integer::set(Value *v)
{
gint64 iv = 0;
if (v)
v->get(iv);
set(iv);
}
void Integer::set(Packet &p)
{
unsigned int i;
if(p.DecodeUInt32(i)) {
set((int)i);
return;
}
guint64 i64;
if(p.DecodeUInt64(i64)) {
set((gint64)i64);
return;
}
}
void Integer::set(const char *buffer, int buf_size)
{
if(buffer) {
gint64 i;
if(Parse(buffer, i)) {
set(i);
}
}
}
bool Integer::Parse(const char *pValue, gint64 &iValue) {
if(::isdigit(*pValue)) {
if(strchr(pValue, '.')) {
return false;
}
else {
// decimal or 0x integer
return sscanf(pValue, "%" PRINTF_INT64_MODIFIER "i", &iValue) == 1;
}
}
else if(*pValue == '$' && ::isxdigit(*(pValue+1))) {
// hexidecimal integer
char szHex[10] = "0x";
strcat(&szHex[0], pValue + 1);
return sscanf(szHex, "%" PRINTF_INT64_MODIFIER "i" , &iValue) == 1;
}
return false;
}
Integer * Integer::NewObject(const char *_name, const char *pValue, const char *desc) {
gint64 iValue;
if(Parse(pValue, iValue)) {
return new Integer(_name, iValue, desc);
}
return NULL;
}
void Integer::get(gint64 &i)
{
i = value;
}
void Integer::get(double &d)
{
gint64 i;
get(i);
d = (double)i;
}
void Integer::get(char *buffer, int buf_size)
{
if(buffer) {
gint64 i;
get(i);
long long int j = i;
snprintf(buffer,buf_size,"%" PRINTF_INT64_MODIFIER "d",j);
}
}
void Integer::get(Packet &pb)
{
gint64 i;
get(i);
unsigned int j = (unsigned int) (i &0xffffffff);
pb.EncodeUInt32(j);
}
int Integer::set_break(ObjectBreakTypes bt, ObjectActionTypes at, Expression *expr)
{
Processor *pCpu = get_active_cpu();
if (pCpu) {
// Legacy code compatibility!
if ( bt == eBreakWrite || bt == eBreakRead ) {
// Cast the integer into a register and set a register break point
unsigned int iRegAddress = (unsigned int) value;
Register *pReg = &pCpu->rma[iRegAddress];
return get_bp().set_break(bt, at, pReg, expr);
} else if ( bt == eBreakExecute) {
unsigned int iProgAddress = (unsigned int) value;
return get_bp().set_execution_break(pCpu, iProgAddress, expr);
}
}
return -1;
}
string Integer::toString()
{
gint64 i;
get(i);
IUserInterface & TheUI = GetUserInterface();
return string(TheUI.FormatValue(i, (unsigned int)bitmask));
}
string Integer::toString(char* format)
{
char cvtBuf[1024];
gint64 i;
get(i);
snprintf(cvtBuf,sizeof(cvtBuf), format, i);
return (string(&cvtBuf[0]));
}
string Integer::toString(char* format, gint64 value)
{
char cvtBuf[1024];
snprintf(cvtBuf,sizeof(cvtBuf), format, value);
return (string(&cvtBuf[0]));
}
string Integer::toString(gint64 value)
{
char cvtBuf[1024];
long long int v=value;
snprintf(cvtBuf,sizeof(cvtBuf), "%" PRINTF_INT64_MODIFIER "d", v);
return (string(&cvtBuf[0]));
}
char *Integer::toString(char *return_str, int len)
{
if(return_str) {
gint64 i;
get(i);
IUserInterface & TheUI = GetUserInterface();
strncpy(return_str, TheUI.FormatValue(i), len);
// snprintf(return_str,len,"%" PRINTF_INT64_MODIFIER "d",i);
}
return return_str;
}
char *Integer::toBitStr(char *return_str, int len)
{
if(return_str) {
gint64 i;
get(i);
int j=0;
int mask=1<<31;
for( ; mask ; mask>>=1, j++)
if(j<len)
return_str[j] = ( (i & mask) ? 1 : 0);
if(j<len)
return_str[j]=0;
}
return return_str;
}
Integer* Integer::typeCheck(Value* val, string valDesc)
{
if (typeid(*val) != typeid(Integer)) {
throw new TypeMismatch(valDesc, "Integer", val->showType());
}
// This static cast is totally safe in light of our typecheck, above.
return((Integer*)(val));
}
Integer* Integer::assertValid(Value* val, string valDesc, gint64 valMin)
{
Integer* iVal;
gint64 i;
iVal = Integer::typeCheck(val, valDesc);
iVal->get(i);
if (i < valMin) {
throw new Error(valDesc +
" must be greater than " + Integer::toString(valMin) +
", saw " + Integer::toString(i)
);
}
return(iVal);
}
Integer* Integer::assertValid(Value* val, string valDesc, gint64 valMin, gint64 valMax)
{
Integer* iVal;
gint64 i;
iVal = (Integer::typeCheck(val, valDesc));
iVal->get(i);
if ((i < valMin) || (i>valMax)) {
throw new Error(valDesc +
" must be be in the range [" + Integer::toString(valMin) + ".." +
Integer::toString(valMax) + "], saw " + Integer::toString(i)
);
}
return(iVal);
}
bool Integer::compare(ComparisonOperator *compOp, Value *rvalue)
{
Integer *rv = typeCheck(rvalue,"");
gint64 i,r;
get(i);
rv->get(r);
if(i < r)
return compOp->less();
if(i > r)
return compOp->greater();
return compOp->equal();
}
/*
bool Integer::operator<(Value *rv)
{
Integer *_rv = typeCheck(rv,"OpLT");
return value < _rv->value;
}
bool Integer::operator>(Value *rv)
{
Integer *_rv = typeCheck(rv,"OpGT");
return value > _rv->value;
}
bool Integer::operator<=(Value *rv)
{
Integer *_rv = typeCheck(rv,"OpLE");
return value <= _rv->value;
}
bool Integer::operator>(Value *rv)
{
Integer *_rv = typeCheck(rv,"OpGT");
return value > _rv->value;
}
*/
/*****************************************************************
* The Float class.
*/
Float::Float(double newValue)
{
value = newValue;
}
Float::Float(const char *_name, double newValue,const char *_desc)
: Value(_name,_desc)
{
value = newValue;
}
bool Float::Parse(const char *pValue, double &fValue)
{
return pValue ? sscanf(pValue,"%lg",&fValue) == 1 : false;
}
Float * Float::NewObject(const char *_name, const char *pValue, const char *desc) {
double fValue;
if(Parse(pValue, fValue)) {
return new Float(_name, fValue);
}
return NULL;
}
Float::~Float()
{
}
void Float::set(double d)
{
value = d;
if(get_xref())
get_xref()->set(d);
}
void Float::set(gint64 i)
{
double d = (double)i;
set(d);
}
void Float::set(Value *v)
{
Float *fv = typeCheck(v,string("set "));
double d = fv->getVal();
set(d);
}
void Float::set(const char *buffer, int buf_size)
{
if(buffer) {
double d;
if(Parse(buffer, d)) {
set(d);
}
}
}
void Float::set(Packet &p)
{
double d;
if(p.DecodeFloat(d)) {
set(d);
}
}
void Float::get(gint64 &i)
{
double d;
get(d);
i = (gint64)d;
}
void Float::get(double &d)
{
d = value;
}
void Float::get(char *buffer, int buf_size)
{
if(buffer) {
double d;;
get(d);
snprintf(buffer,buf_size,"%g",d);
}
}
void Float::get(Packet &pb)
{
double d;
get(d);
pb.EncodeFloat(d);
}
Value *Float::copy() {
double d;
get(d);
return new Float(d);
}
string Float::toString()
{
return toString("%#-16.16g");
}
string Float::toString(char* format)
{
char cvtBuf[1024];
double d;
get(d);
sprintf(cvtBuf, format, d);
return (string(&cvtBuf[0]));
}
char *Float::toString(char *return_str, int len)
{
if(return_str) {
double d;
get(d);
snprintf(return_str,len,"%g",d);
}
return return_str;
}
Float* Float::typeCheck(Value* val, string valDesc)
{
if (typeid(*val) != typeid(Float)) {
throw new TypeMismatch(valDesc, "Float", val->showType());
}
// This static cast is totally safe in light of our typecheck, above.
return((Float*)(val));
}
bool Float::compare(ComparisonOperator *compOp, Value *rvalue)
{
Float *rv = typeCheck(rvalue,"");
double d,r;
get(d);
rv->get(r);
if(d < r)
return compOp->less();
if(d > r)
return compOp->greater();
return compOp->equal();
}
/*
bool Float::operator<(Value *rv)
{
Float *_rv = typeCheck(rv,"OpLT");
return value < _rv->value;
}
*/
/*****************************************************************
* The String class.
*/
String::String(const char *newValue)
{
if(newValue)
value = strdup(newValue);
else
value = 0;
}
String::String(const char *_name, const char *newValue,const char *_desc)
: Value(_name,_desc)
{
if(newValue)
value = strdup(newValue);
else
value = 0;
}
String::~String()
{
if(value)
free(value);
}
string String::toString()
{
if(value)
return string(value);
else
return string("");
}
char *String::toString(char *return_str, int len)
{
if(return_str) {
if(value)
snprintf(return_str,len,"%s",value);
else
*return_str = 0;
}
return return_str;
}
void String::set(Value *v)
{
char buf[1024];
if(v) {
v->get(buf, sizeof(buf));
set(buf);
}
}
void String::set(Packet &p)
{
cout << " fixme String::set(Packet &) is not implemented\n";
}
void String::set(const char *s,int len)
{
if(value)
free(value);
if(s)
value = strdup(s);
else
value = 0;
}
void String::get(char *buf, int len)
{
if(buf && value) {
strncpy(buf,value,len);
}
else if(buf) {
buf[0] = 0;
}
}
void String::get(Packet &p)
{
p.EncodeString(value);
}
/*
string String::toString(char* format)
{
char cvtBuf[1024];
sprintf(cvtBuf, format, value.c_str());
return (string(&cvtBuf[0]));
}
*/
/**
String* String::typeCheck(Value* val, string valDesc)
{
if (typeid(*val) != typeid(String)) {
throw new TypeMismatch(valDesc, "String", val->showType());
}
// This static cast is totally safe in light of our typecheck, above.
return((String*)(val));
}
*/
/*
bool String::compare(ComparisonOperator *compOp, Value *rvalue)
{
String *rv = typeCheck(rvalue,"");
if(value < rv->value)
return compOp->less();
if(value > rv->value)
return compOp->greater();
return compOp->equal();
}
*/
const char *String::getVal()
{
return value;
}
Value *String::copy()
{
return new String(value);
}
syntax highlighted by Code2HTML, v. 0.9.1