/*
   Copyright (C) 1998-2005 T. 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 "attributes.h"
#include "processor.h"
#include "symbol.h"
#include "gpsim_time.h"
#include "protocol.h"
#include "../config.h"

//========================================================================
// Attribute wrappers
//
// Attribute wrappers are simple classes that handle specific processor
// attributes. Their primary purpose is to allow for a way to call back
// into the processor classs whenever the attribute changes.



//========================================================================
// WarnMode
//========================================================================

WarnModeAttribute::WarnModeAttribute(Processor *_cpu) :
  Boolean(false) ,cpu(_cpu)
{
  new_name("WarnMode");
  set_description(" enable warning messages when true");
}
void WarnModeAttribute::set(Value *v)
{
  Boolean::set(v);
  bool currentVal;
  get(currentVal);
  cpu->setWarnMode(currentVal);
}
void WarnModeAttribute::get(bool &b)
{
  b = cpu->getWarnMode();
  Boolean::set(b);
}

//========================================================================
// SafeModeAttribute
//========================================================================

SafeModeAttribute::SafeModeAttribute(Processor *_cpu) :
  Boolean(false) ,cpu(_cpu)
{
  new_name("SafeMode");
  set_description(" Model the processor's specification when true. Model the actual\n"
		  " processor when false (e.g. TRIS instruction for mid range PICs\n"
		  " will emit a warning if SafeMode is true).");
}
void SafeModeAttribute::set(Value *v)
{
  Boolean::set(v);
  bool currentVal;
  Boolean::get(currentVal);
  cpu->setSafeMode(currentVal);
}
void SafeModeAttribute::get(bool &b)
{
  b = cpu->getSafeMode();
  Boolean::set(b);
}

//========================================================================
// UnknownModeAttribute
//========================================================================
UnknownModeAttribute::UnknownModeAttribute(Processor *_cpu) :
    Boolean(false) ,cpu(_cpu)
{
  new_name("UnknownMode");
  set_description(" Enable three-state register logic. Unknown values are treated \n"
		  " as 0 when this is false.");

}
void UnknownModeAttribute::set(Value *v)
{
  Boolean::set(v);
  bool currentVal;
  Boolean::get(currentVal);
  cpu->setUnknownMode(currentVal);
}
void UnknownModeAttribute::get(bool &b)
{
  b = cpu->getUnknownMode();
  Boolean::set(b);
}

//========================================================================
// BreakOnResetAttribute
//========================================================================
BreakOnResetAttribute::BreakOnResetAttribute(Processor *_cpu) :
    Boolean(false) ,cpu(_cpu)
{
  new_name("BreakOnReset");
  set_description(" If true, halt simulation when reset occurs \n");

}
void BreakOnResetAttribute::set(Value *v)
{
  Boolean::set(v);
  bool currentVal;
  Boolean::get(currentVal);
  cpu->setBreakOnReset(currentVal);
}
void BreakOnResetAttribute::get(bool &b)
{
  b = cpu->getBreakOnReset();
  Boolean::set(b);
}

//========================================================================
//
// Cycle_Counter attribute
//
// The Cycle_counter attribute exposes the cycle counter through the 
// gpsim attribute interface. This allows for it to be queried from
// the command line or sockets.

class CycleCounterAttribute : public Integer
{
public:
  CycleCounterAttribute() :
    Integer(0) 
  {
    m_bClearableSymbol = false;
    new_name("cycles");
    set_description(" Simulation time in terms of cycles.");
  }
  void set(gint64 i)
  {
    static bool warned = false;
    if(!warned)
      cout << "cycle counter is read only\n";
    warned = true;
  }
  void get(gint64 &i)
  {
    i = cycles.get();
  }
  void get(Packet &p)
  {
    p.EncodeUInt64(cycles.get());
  }
  virtual string toString()
  {
    char buf[256];
    gint64 i;
    get(i);
    long long int j = i;
    snprintf(buf,sizeof(buf),"%" PRINTF_INT64_MODIFIER
	     "d = 0x%08" PRINTF_INT64_MODIFIER "X",j,j);
    return string(buf);
  }

};

//========================================================================
//
// GUI update rate attribute
#ifdef HAVE_GUI
class GUIUpdateRateAttribute : public Integer
{
public:
  GUIUpdateRateAttribute() :
    Integer(0) 
  {
    m_bClearableSymbol = false;
    new_name("sim.gui_update_rate");
    set_description(" Specifies the number of cycles between gui updates");
  }
  void set(gint64 i)
  {
    gi.set_update_rate(i);
  }
  void get(gint64 &i)
  {
    i = gi.get_update_rate();
  }
};
#endif


//========================================================================
//
Integer *verbosity;


//########################################################################
void init_attributes()
{
  
  // Define internal simulator attributes .
  verbosity = new Integer("sim.verbosity",1,"gpsim's verboseness 0=nothing printed 0xff=very verbose");
  verbosity->setClearableSymbol(false);
  get_symbol_table().Initialize();
  get_symbol_table().add(verbosity);
  get_symbol_table().add(new CycleCounterAttribute());
  stop_watch.init();
#ifdef HAVE_GUI
  get_symbol_table().add(new GUIUpdateRateAttribute());
#endif

  get_symbol_table().add_constant("POR_RESET",  POR_RESET, false);    // Power-on reset
  get_symbol_table().add_constant("WDT_RESET",  WDT_RESET, false);    // Watch Dog timer timeout reset
  get_symbol_table().add_constant("IO_RESET",   IO_RESET, false);     // I/O pin reset
  get_symbol_table().add_constant("SOFT_RESET", SOFT_RESET, false);   // Software initiated reset
  get_symbol_table().add_constant("BOD_RESET",  BOD_RESET, false);    // Brown out detection reset
  get_symbol_table().add_constant("SIM_RESET",  SIM_RESET, false);    // Simulation Reset
  get_symbol_table().add_constant("MCLR_RESET", MCLR_RESET, false);   // MCLR (Master Clear) Reset

}


syntax highlighted by Code2HTML, v. 0.9.1