/*
Copyright (C) 1998 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. */
//-------------------------------------------------------------------
// interface.cc
//
// interface.cc provides a layer of code on top of the simulator
// portion of gpsim. It's purpose is to provide an abstract interface
// that hides the details of the simulator. Currently only the gui
// interfaces to gpsim through this layer. However, since the simulator
// 'engine' is built as a library, it's possible for other code to
// interface through here as well.
//
//-------------------------------------------------------------------
#include <stdio.h>
#include "../config.h"
#define GPSIM_VERSION VERSION
#include "gpsim_def.h"
#include "sim_context.h"
#include "processor.h"
#include "xref.h"
#include "interface.h"
#include "trace.h"
#include "eeprom.h"
#include "icd.h"
#include "cmd_manager.h"
extern Integer *verbosity; // in ../src/init.cc
// Flag to tell us when all of the init stuff is done.
unsigned int gpsim_is_initialized = 0;
/**************************************************************************
*
* Here's the gpsim interface class instantiation. It's through this class
* that gpsim will notify the gui and/or modules of internal gpsim changes.
*
**************************************************************************/
gpsimInterface gi;
// create an instance of inline get_interface() method by taking its address
gpsimInterface &(*dummy_gi)(void) = get_interface;
//------------------------------------------------------------------------
// Temporary -- provide a flag to inihibit multithreaded support.
bool gUsingThreads()
{
return false;
}
//---------------------------------------------------------------------------
// void gpsim_set_bulk_mode(int flag)
//---------------------------------------------------------------------------
void gpsim_set_bulk_mode(int flag)
{
if(get_use_icd())
{
icd_set_bulk(flag);
}
}
void initialization_is_complete(void)
{
gpsim_is_initialized = 1;
}
//========================================================================
//========================================================================
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
/*
* Module Interface
*
*
*/
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
ModuleInterface::ModuleInterface(Module *new_module)
{
module = new_module;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
/*
* Processor Interface
*
*
*/
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
ProcessorInterface::ProcessorInterface(Processor *new_cpu) : ModuleInterface(new_cpu)
{
}
//--------------------------------------------------------------------------
//
// callback registration functions
//
//
//--------------------------------------------------------------------------
Interface::Interface(gpointer new_object)
{
objectPTR = new_object;
}
//--------------------------------------------------------------------------
//
// gpsimInterface
//
// Here are where the member functions for the gpsimInterface class are
// defined.
//
// The gpsimInterface class contains a singly-linked-list of Interface objects.
// Interface objects are structures that primarily contain pointers to a whole
// bunch of functions. The purpose is to have some external entity, like the
// gui code, define where these functions point. gpsim will then use these
// functions as a means of notifying the gui when something has changed.
// In addition to the gui, this class also provides the support for interfacing
// to modules. When a module is loaded from a module library, a new Interface
// object is created for it. The module will be given the opportunity to
// register functions (e.g. provide pointers to functions) that gpsim can
// then call.
//
//--------------------------------------------------------------------------
void gpsimInterface::update (void)
{
GSList *external_interfaces = interfaces;
while(external_interfaces) {
if(external_interfaces->data) {
Interface *an_interface = (Interface *)(external_interfaces->data);
an_interface->Update(an_interface->objectPTR);
}
external_interfaces = external_interfaces->next;
}
}
void gpsimInterface::callback(void)
{
if(update_rate) {
future_cycle = get_cycles().value + update_rate;
get_cycles().set_break(future_cycle, this);
}
update();
}
void gpsimInterface::clear(void)
{
}
void gpsimInterface::print(void)
{
cout << "Interface update rate " << update_rate << endl;
}
void gpsimInterface::callback_print(void)
{
cout << "gpsim Interface callback\n";
}
void update_gui(void)
{
gi.update();
}
gpsimInterface::gpsimInterface (void )
{
interfaces = 0;
future_cycle = 0;
interface_seq_number = 0;
socket_interface = 0;
mbSimulating = false;
mbUseGUI = false;
}
ISimConsole & gpsimInterface::GetConsole()
{
// The static ISimConsole object is currently in the
// CCommandManger class because it initially was used
// to enable external modules to write to the console.
// We may want to put it somewhere else someday.
return CCommandManager::m_CommandManger.GetConsole();
}
//--------------------------------------------------------------------------
//
// A xref, or cross reference, object is an arbitrary thing that gpsim
// will pass back to the gui or module. The gui (or module) will then
// interpret the contents of the xref and possibly update some state
// with 'new_value'. An example is when one of the pic registers changes;
// if there's a xref object associated with the register gpsim will
// then notify the gui (or module) through the xref.
void gpsimInterface::update_object (gpointer xref,int new_value)
{
GSList *interface_list = interfaces;
while(interface_list) {
if(interface_list->data) {
Interface *an_interface = (Interface *)(interface_list->data);
an_interface->UpdateObject(xref, new_value);
}
interface_list = interface_list->next;
}
}
void gpsimInterface::remove_object (gpointer xref)
{
GSList *interface_list = interfaces;
while(interface_list) {
if(interface_list->data) {
Interface *an_interface = (Interface *)(interface_list->data);
an_interface->RemoveObject(xref);
}
interface_list = interface_list->next;
}
}
void gpsimInterface::simulation_has_stopped (void)
{
GSList *interface_list = interfaces;
profile_keeper.catchup(); // FIXME: remove this!
while(interface_list) {
if(interface_list->data) {
Interface *an_interface = (Interface *)(interface_list->data);
an_interface->SimulationHasStopped(an_interface->objectPTR);
}
interface_list = interface_list->next;
}
}
#if GLIB_MAJOR_VERSION >= 2
GMutex *muRunMutex;
GCond *cvRunCondition;
static Processor *tcpu=0;
static void *run_thread( void *ptr )
{
printf("run thread\n");
while(1) {
g_mutex_lock(muRunMutex);
printf("running waiting for condition\n");
g_cond_wait(cvRunCondition, muRunMutex);
if(tcpu) {
printf("running\n");
tcpu->run();
printf("stopped running\n");
}
g_mutex_unlock(muRunMutex);
}
}
void start_run_thread(void)
{
std::cout << "starting run thread....\n";
muRunMutex = g_mutex_new ();
cvRunCondition = g_cond_new ();
g_mutex_lock (muRunMutex);
GError *err = NULL ;
if( g_thread_create((GThreadFunc)run_thread,
(void *)0,
TRUE,
&err) == NULL)
{
printf("Thread create failed: %s!!\n", err->message );
g_error_free ( err ) ;
}
g_mutex_unlock (muRunMutex);
std::cout << " started thread\n";
}
#endif
void gpsimInterface::start_simulation (void)
{
Processor *cpu = get_active_cpu();
mbSimulating = true;
if(cpu) {
#if GLIB_MAJOR_VERSION >= 2
if(gUsingThreads()) {
static bool thread_initialized=false;
if(!thread_initialized) {
start_run_thread();
g_usleep(10000);
thread_initialized = true;
}
g_mutex_lock (muRunMutex);
tcpu = cpu;
printf("signalling run thread\n");
g_cond_signal (cvRunCondition);
g_mutex_unlock (muRunMutex);
printf("leaving start_simulation\n");
} else
#endif
{
if(verbosity && verbosity->getVal()) {
cout << "running...\n";
cpu->run(true);
} else
cpu->run(false);
}
}
mbSimulating = false;
}
void gpsimInterface::reset (void)
{
CSimulationContext::GetContext()->Reset(SIM_RESET);
}
bool gpsimInterface::bSimulating()
{
return mbSimulating;
}
bool gpsimInterface::bUsingGUI()
{
return mbUseGUI;
}
void gpsimInterface::setGUImode(bool bnewGUImode)
{
// We can only turn the gui on we can't turn it off.
mbUseGUI |= bnewGUImode;
}
void gpsimInterface::new_processor (Processor *new_cpu)
{
GSList *interface_list = interfaces;
while(interface_list) {
if(interface_list->data) {
Interface *an_interface = (Interface *)(interface_list->data);
an_interface->NewProcessor(new_cpu);
}
interface_list = interface_list->next;
}
}
void gpsimInterface::new_module (Module *module)
{
GSList *interface_list = interfaces;
while(interface_list) {
if(interface_list->data) {
Interface *an_interface = (Interface *)(interface_list->data);
an_interface->NewModule(module);
}
interface_list = interface_list->next;
}
}
void gpsimInterface::node_configuration_changed (Stimulus_Node *node)
{
GSList *interface_list = interfaces;
while(interface_list) {
if(interface_list->data) {
Interface *an_interface = (Interface *)(interface_list->data);
an_interface->NodeConfigurationChanged(node);
}
interface_list = interface_list->next;
}
}
void gpsimInterface::new_program (Processor *cpu)
{
GSList *interface_list = interfaces;
while(interface_list) {
if(interface_list->data) {
Interface *an_interface = (Interface *)(interface_list->data);
an_interface->NewProgram(cpu);
}
interface_list = interface_list->next;
}
}
unsigned int gpsimInterface::add_interface (Interface *new_interface)
{
interface_seq_number++;
new_interface->set_id(interface_seq_number);
gi.interfaces = g_slist_append(gi.interfaces, new_interface);
return interface_seq_number;
}
unsigned int gpsimInterface::add_socket_interface (Interface *new_interface)
{
if(!socket_interface)
return add_interface(new_interface);
return 0;
}
void gpsimInterface::remove_interface (unsigned int interface_id)
{
GSList *interface_list = interfaces;
while(interface_list) {
if(interface_list->data) {
Interface *an_interface = (Interface *)(interface_list->data);
if(an_interface->get_id()==interface_id)
{
gi.interfaces = g_slist_remove(gi.interfaces, an_interface);
if(an_interface == socket_interface)
socket_interface = 0;
delete an_interface;
return;
}
}
interface_list = interface_list->next;
}
return;
}
void gpsimInterface::set_update_rate (guint64 _update_rate)
{
guint64 fc = get_cycles().value + _update_rate;
update_rate = _update_rate;
if(fc) {
if(future_cycle)
get_cycles().reassign_break(future_cycle, fc, this);
else
get_cycles().set_break(fc, this);
future_cycle = fc;
}
}
guint64 gpsimInterface::get_update_rate()
{
return update_rate;
}
const char *get_dir_delim(const char *path)
{
#ifdef _WIN32
const char *p = path + strlen(path);
do
{
if (--p < path)
return 0;
}
while (*p != '/' && *p != '\\');
return p;
#else
return strrchr(path, '/');
#endif
}
// For libgpsim.dll
// The console now owns the verbose flags. At some point as set
// of functions called TraceDisplayXXX() the conditionally
// display message depending on the verbose flags.
// I'll leave this it as it for now because I'm in the middle
// of making the src project its own DLL on windows and I have
// enough changes for now.
// Replaced the int verbose = 0; with GlobalVerbosityAccessor verbose.
// GlobalVerbosityAccessor that has overridden operators for 'if(verbose)'
// and 'if(verbose&4)' to still work as desired.
// The purpose was to decouple verbose from cli and gui. Now these
// modules (acutally gpsim.exe) will allocate there own
// GlobalVerbosityAccessor verbose object to gain access to the
// verbose flags and for the overridden operators.
GlobalVerbosityAccessor verbose;
syntax highlighted by Code2HTML, v. 0.9.1