/* 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 #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;