Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / tracemod / tm_api.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: tm_api.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named 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.
//
// The above named 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 work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
/*
* Copyright (C) 1991, 2001 Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "@(#)1.4 01/11/06 tm_api.cc"
/*
* Copyright (c) 1989, Sun Microsystems, Inc. All Rights Reserved. Sun
* considers its source code as an unpublished, proprietary trade secret, and
* it is available only under strict license provisions. This copyright
* notice is placed here only to protect Sun in the event the source is
* deemed a published work. Disassembly, decompilation, or other means of
* reducing the object code to human readable form is prohibited by the
* license agreement under which this code is provided to the user or company
* in possession of this copy
*
* RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the
* Government is subject to restrictions as set forth in subparagraph
* (c) (1) (ii) of the Rights in Technical Data and Computer Software clause
* at DFARS 52.227-7013 and in similar clauses in the FAR and NASA FAR
* Supplement
*/
#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <synch.h>
#include <dlfcn.h>
#include <limits.h>
#include "types.h"
#include "blaze_globals.h"
#include "system.h"
typedef void* TM_OPAQUE_DATA;
#include "tracemod.h"
#include "ui.h"
#include "tm_impl.h"
LdmNode *head_ldm = NULL; // The head of tracing LDM's
LdmNode *head_spec_ldm = NULL; // The head of the list of BLAZE extensions
uint64_t tm_time_target = 0xffffffffffffffffLLU; // Is used for global time interval event handler
uint64_t tm_time_interval = 0; // Is used for global time interval event handler
static LdmCmdNode *head_ldm_cmd = NULL;
static char help_string [] = "usage : mod load <type> <sofile> [<arglist>] | mod unload <name>\n\
type ::= analyzer | py | remote\n";
static char mmi_help_string_1 [] = "usage : ldm <dev name> <instance name> [<sofile><arglist>]";
static char mmi_help_string_2 [] = "usage : uldm <instance name>";
static char mmi_help_string_3 [] = "usage : ioa <ADDR1> <ADDR2> ";
static char mmi_help_string_4 [] = "usage : sysconf [-p <modpath> ] <modname> "
"[ <instance_name> [ args... ] ]";
static char mmi_help_string_5 [] = "usage : module [<modname> ...]";
//////////////////////////////////////////////////
//
//TODO: commands which require STOP
//
//////////////////////////////////////////////////
Ldm * ldm_add_spec (char * name, const char *soname)
{
int ii;
Ldm *pldm;
LdmNode *pnode;
if (soname) {
for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (strcmp (name, pldm->name) == NULL) {
ui->error("module %s - %s is already loaded !\n", name, soname);
return NULL;
}
if (pldm->soname && (strcmp(soname, pldm->soname) == NULL )) {
ui->error("module %s - %s is already loaded !\n", name, soname);
return NULL;
}
}
}
else {
for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (strcmp (name, pldm->name) == NULL) {
return NULL;
}
}
}
pnode = LdmNode::CreateInstance ("MOD list");
if (pnode == NULL) {
ui->error("Unable to load %s-%s : unable to allocate memory\n",
soname ? soname : "**", name);
return NULL;
}
pldm = pnode->GetData ();
pldm->name = (char*)strdup(name);
pldm->soname = soname ? (char*)strdup(soname) : NULL;
pldm->mode = TM_CBMODE;
for (ii = 0; ii < MAX_MP; ii++)
pldm->memop[ii] = TM_CONST_BADMEM;
pldm->type = TM_TYPE_EXT_UNKNOWN;
LdmNode::AddTail (&head_spec_ldm, pnode);
return pldm;
} // ldm_add_spec()
//////////////////////////////////////////////////
static Ldm * ldm_add (char * name, const char *soname)
{
int ii;
LdmNode *pnode;
for (pnode=head_ldm; pnode; pnode=pnode->Next()) {
Ldm * pldm = pnode->GetData();
if ((strcmp (name, pldm->name) == NULL) || (strcmp (soname, pldm->soname) == NULL)) {
ui->error("module %s - %s is already loaded !\n", name, soname);
return NULL;
}
}
pnode = LdmNode::CreateInstance ("MOD list");
if (pnode == NULL) {
ui->error("Unable to register MODULE <%s>\n", name);
return NULL;
}
Ldm * pldm = pnode->GetData ();
pldm->name = (char*)strdup(name);
pldm->soname = (char*)strdup(soname);
pldm->mode = TM_CBMODE;
for (ii = 0; ii < MAX_MP; ii++)
pldm->memop[ii] = TM_CONST_BADMEM;
pldm->type = TM_TYPE_LDM;
LdmNode::AddTail (&head_ldm, pnode);
return pldm;
}
//////////////////////////////////////////////////////
static void ldm_delete_head ()
{
LdmNode::DeleteHead(&head_ldm);
}
//////////////////////////////////////////////////////
void ldm_delete_head_spec ()
{
LdmNode::DeleteHead(&head_spec_ldm);
}
//////////////////////////////////////////////////
static LdmCmd * ldm_cmd_add (const char * name, fn_ui_1 action1, fn_ui_2 action2)
{
LdmCmd *pldm_cmd;
LdmCmdNode *pnode = LdmCmdNode::CreateInstance ("CMD list");
if (pnode == NULL) {
ui->error("Unable to register UI CMD <%s>\n", name);
return NULL;
}
pldm_cmd = pnode->GetData ();
pldm_cmd->name = (char*)strdup(name);
pldm_cmd->cmd_action_1 = action1;
pldm_cmd->cmd_action_2 = action2;
LdmCmdNode::AddHead (&head_ldm_cmd, pnode);
return pldm_cmd;
}
//////////////////////////////////////////////////
// ----------------------------------------------------------------------------
struct mod_list {
char * name;
struct mod_list * next;
} mod_list = {"$ORIGIN/../lib/", NULL}; /* $ORIGIN always at end of search */
void mod_setdefault (char * subdir) /* change "../lib/" to "../lib-obp/" */
{ /* in the $origin search path */
static char new_default[PATH_MAX];
sprintf (new_default, "$ORIGIN/../%s/", subdir);
mod_list.name = new_default;
}
struct mod_list * mod_head = & mod_list;
struct mod_list * mod_tail = & mod_list;
// hmmm, shouldn't mod_addpath() do a "push" rather than an "insert"...
void mod_addpath (char * path) /* subsequent dirs are inserted in */
{ /* front of the $ORIGIN last entry */
struct mod_list * p;
p = (struct mod_list*) malloc (sizeof (struct mod_list));
p->name = strdup (path);
p->next = mod_tail;
if (mod_head == mod_tail) {
mod_head = p;
} else {
struct mod_list * q = mod_head;
while (q->next != mod_tail) q = q->next;
q->next = p;
}
}
void * mod_dlopen (char * pathp, char * fname, int flags)
{
void * result = NULL;
char temp[PATH_MAX];
const char * dlerr;
if ( (fname[0] == '/') /* don't mess with absolute file paths */
||(fname[0] == '.' && fname[1] == '/')
||(fname[0] == '.' && fname[1] == '.' && fname[2] == '/')) {
sprintf (temp, "%s", fname);
result = dlopen (temp, flags);
if (result == NULL) {
dlerr = dlerror();
if (dlerr != NULL) {
ui->error("dlopen(%s)...\n %s\n", temp, dlerr);
}
}
} else if (pathp != NULL) { /* use explicit path if provided */
sprintf (temp, "%s/%s", pathp, fname);
result = dlopen (temp, flags);
if (result == NULL) {
dlerr = dlerror();
if (dlerr != NULL) {
ui->error("dlopen(%s)...\n %s\n", temp, dlerr);
}
}
} else { /* otherwise use searchlist */
for (struct mod_list * p = mod_head; p != NULL; p = p->next) {
sprintf (temp, "%s/%s", p->name, fname);
result = dlopen (temp, flags);
if (result == NULL) {
dlerr = dlerror();
if(dlerr) {
ui->output("dlopen(%s): trying path %s...\n %s\n", fname, temp, dlerr);
}
} else
break; /* <-- found it ! */
}
}
if (result != NULL)
ui->verbose("dlopen(%s): loaded successfully\n", temp);
else {
ui->error("dlopen(%s): failed (unresolved symbols or sysconf search path incorrect)\n",fname);
}
return result;
}
// ----------------------------------------------------------------------------
// the following mod commands are currently supported:
// mod load <modname> <module.so>
// mod unload <modname>
//
const char mod_cmd_usage[] = "Usage: mod <load|unload> <analyzer|py> [path/lib_name.so]\n";
//
static void * dlhandle = NULL;
//
void *(*vtracer_initfn)(const char *) = NULL;
void (*vtracer_finifn)() = NULL;
//
int init_tracer(char* fname, char* modname, void* lib_handle)
{
dlhandle = lib_handle;
// FIXME: currently, only one vtrace module is supported. 2005.09.27
if (g_vcpu[0]->sys_intf.vtrace != NULL) {
ui->error("a vtracer is already loaded. Only one vtracer is supported at this time\n");
return 0;
}
vtracer_initfn = (void *(*)(const char *)) dlsym(dlhandle, "vtracer_init");
if (vtracer_initfn == NULL) {
ui->error("mod load: could not find symbol vtracer_init() in %s: %s\n", fname, dlerror());
dlclose(dlhandle);
return 0;
}
vtracer_finifn = (void (*)()) dlsym(dlhandle, "vtracer_fini");
if (vtracer_finifn == NULL) {
ui->error("mod load: could not find symbol vtracer_fini() in %s: %s\n", fname, dlerror());
dlclose(dlhandle);
return 0;
}
VTracer * the_vtracer = (VTracer *) vtracer_initfn(modname);
for (int i=0; i<=g_vcpu_id_max; i++)
{
Vcpu *vcpu = get_vcpu(i);
if (vcpu)
{
vcpu->sys_intf.vtrace = the_vtracer;
vcpu->config.trace_on = 1;
}
}
return 1;
}
int close_tracer()
{
if (dlhandle != NULL) {
if (vtracer_finifn != NULL) {
vtracer_finifn();
}
dlclose(dlhandle);
dlhandle = NULL;
int i;
for (i=0; i<=g_vcpu_id_max; i++)
{
Vcpu *vcpu = get_vcpu(i);
if (!vcpu)
continue;
vcpu->sys_intf.vtrace = NULL;
vcpu->config.trace_on = 0;
}
return 0;
}
else
{
ui->error("mod unload: no vtracer module is currently loaded\n");
return 1;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// py init
typedef int (*init_py_t)(char*, char*, void*);
int init_py(char* fname, char* modname, void* lib_handle)
{
init_py_t py_initfn = (init_py_t)dlsym(lib_handle, "init_py_interface");
if (py_initfn == NULL)
{
ui->error("mod load: could not find symbol init_py_interface() in %s: %s\n", fname, dlerror());
dlclose(dlhandle);
return 0;
}
return py_initfn (fname, modname, lib_handle);
}
///////////////////////////////////////////////////////////////////////
//
int mod_cmd_action(void*, int argc, char **argv)
{
if (argc == 1) {
ui->output(mod_cmd_usage);
return 1;
}
char * modname = NULL;
char * fname = NULL;
if (strcmp(argv[1], "load") == 0)
{
if (argc != 4 && argc != 3)
{
ui->output(mod_cmd_usage);
return 0;
}
modname = argv[2];
char suffixedname[PATH_MAX];
if (argc == 4) fname = argv[3];
else
{ /* if there isn't an argv[3] then construct one from argv[2] */
sprintf (suffixedname, "%s.so", argv[2]);
fname = suffixedname;
}
if (ANY_RUNNING_STATE(blaze_run_state)) {
ui->error("not in stop state, use stop command first\n");
return 0;
}
void *dlib_handle = mod_dlopen (NULL, fname, RTLD_LAZY|RTLD_GLOBAL);
if (dlib_handle == NULL)
{
return 0;
}
if (strcmp(modname,"analyzer")==0)
{
return init_tracer(fname, modname, dlib_handle);
}
else if(strcmp(modname,"py")==0)
{
ui->verbose("loading python interpreter....\n");
return init_py(fname, modname, dlib_handle);
}
else if(strcmp(modname,"remote")==0)
{
extern int init_remote_debugger_interface (char*, char*, void*);
ui->verbose(" loading interface for remote debugger....\n");
return init_remote_debugger_interface(fname, modname, dlib_handle);
}
else if (strcmp(modname,"lib")==0)
{
ui->verbose("lib %s was loaded. \n", fname);
return 1;
}
else
{
ui->error(" %s : unknown module name\n%s\n", modname, mod_cmd_usage);
dlclose(dlib_handle);
return 0;
}
}
else if (strcmp(argv[1], "unload") == 0)
{
if (argc < 3)
{
ui->output(mod_cmd_usage);
return 0;
}
modname = argv[2];
if (strcmp(modname,"analyzer")==0)
{
return close_tracer ();
}
else if(strcmp(modname,"py")==0)
{
ui->error("cannot unload python interpreter module\n");
return 0;
}
else if(strcmp(modname,"remote")==0)
{
ui->error("cannot unload remote interface module\n");
return 0;
}
else
{
ui->error("%s: unknown module name\n%s\n", modname, mod_cmd_usage);
return 0;
}
} /* if argv[1] eq ? */
else
{
ui->error("Invalid argument %s\n%s\n", argv[1], mod_cmd_usage);
return 1;
}
} // int mod_cmd_action(void*, int argc, char **argv)
//////////////////////////////////////////////////
int extra_cmd_action_1 (void*, int /*argc*/, char **argv)
{
LdmCmdNode *pnode = head_ldm_cmd;
LdmCmd *pldm_cmd;
for (;pnode;pnode = pnode->Next()) {
pldm_cmd = pnode->GetData ();
if (strcmp(argv[0], pldm_cmd->name) == NULL) {
if (pldm_cmd->cmd_action_1)
return pldm_cmd->cmd_action_1 (pldm_cmd->ldm->client_data, argv[1]);
}
}
return 1;
}
//////////////////////////////////////////////////
int extra_cmd_action_2 (void*, int argc, char **argv)
{
LdmCmdNode *pnode = head_ldm_cmd;
LdmCmd *pldm_cmd;
for (;pnode; pnode = pnode->Next()) {
pldm_cmd = pnode->GetData ();
if (strcmp(argv[0], pldm_cmd->name) == NULL) {
if (pldm_cmd->cmd_action_2)
return pldm_cmd->cmd_action_2 (pldm_cmd->ldm->client_data, argc, argv);
}
}
return 1;
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
extern int mmi_cmd_action (void*, int argc, char **argv) ;
void init_tm ()
{
UI_register_cmd_2 ((char*)"mod", help_string, mod_cmd_action, NULL);
UI_register_cmd_2 ((char*)"mmi", mmi_help_string_1, mmi_cmd_action, NULL);
UI_register_cmd_2 ((char*)"ldm", mmi_help_string_1, mmi_cmd_action, NULL);
UI_register_cmd_2 ((char*)"ioa", mmi_help_string_1, mmi_cmd_action, NULL);
UI_register_cmd_2 ((char*)"uldm",mmi_help_string_2, mmi_cmd_action, NULL);
UI_register_cmd_2 ((char*)"cfg", mmi_help_string_4, mmi_cmd_action, NULL);
UI_register_cmd_2 ((char*)"sysconf", mmi_help_string_4, mmi_cmd_action, NULL);
UI_register_cmd_2 ((char*)"modinfo", mmi_help_string_5, mmi_cmd_action, NULL);
ldm_tick_ext_init();
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
//// TM API routines ////
//////////////////////////////////////////////////
//////////////////////////////////////////////////
void TM_enable_interval (uint64_t ti)
{
tm_time_interval = ti;
tm_time_target = ti + SYSTEM_get_ticks ();
}
void TM_disable_interval ()
{
tm_time_target = 0xffffffffffffffffLLU;
tm_time_interval = 0;
}
//////////////////////////////////////////////////
void TM_invalidate (tracemod_t *pmod)
{
pmod->valid = 0;
}
//////////////////////////////////////////////////
static void delete_args(Ldm *pldm)
{
for (int i = 0; i < pldm->argc; i++)
free(pldm->argv[i]);
if (pldm->argv)
free(pldm->argv);
}
//////////////////////////////////////////////////
void TM_clean_mod ()
{
Ldm *pldm;
LdmNode *pnode, *prv = NULL;
bool_t rem = FALSE;
while (TRUE) {
for (pnode=head_ldm; pnode!=NULL; pnode = pnode->Next()) {
pldm = pnode->GetData ();
if (!pldm->valid) {
ui->error("TM: invalidating module <%s>\n", pldm->name);
if (pldm->so_handle) {
if (dlclose (pldm->so_handle))
ui->error("TM: dlclose failed: %s\n", dlerror());
}
delete_args(pldm);
LdmNode::DeleteNode (&head_ldm, prv);
rem = TRUE;
break;
}
prv = pnode;
}
if (rem) {
rem = FALSE;
continue;
}
else {
break;
}
}
}
//////////////////////////////////////////////////
Ldm * TM_find_mod_spec (char * name)
{
Ldm *pldm;
LdmNode *pnode;
if (!name)
return NULL;
for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (strcmp(pldm->name, name) == NULL) {
return pldm;
}
}
return NULL;
}
//////////////////////////////////////////////////
Ldm * TM_find_mod_spec_instance (tracemod_t *parent, char * name)
{
Ldm *pldm;
LdmNode *pnode;
for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if ((pldm->parent == parent) && (!name || !strcmp(pldm->name, name))) {
return pldm;
}
}
return NULL;
}
//////////////////////////////////////////////////
void TM_clean_mod_spec ()
{
Ldm *pldm;
LdmNode *pnode, *prv = NULL;
bool_t rem = FALSE;
while (TRUE) {
for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (!pldm->valid) {
ui->error("TM: invalidating module <%s>\n", pldm->name);
if (pldm->so_handle) {
if (dlclose (pldm->so_handle))
ui->error("TM: dlclose failed: %s\n", dlerror());
}
delete_args(pldm);
LdmNode::DeleteNode (&head_spec_ldm, prv);
rem = TRUE;
break;
}
prv = pnode;
}
if (rem) {
rem = FALSE;
continue;
}
else {
break;
}
}
}
//////////////////////////////////////////////////
bool_t TM_verify (tracemod_t *pmod)
{
Ldm *pldm;
LdmNode *pnode;
if (!pmod)
return FALSE;
for (pnode=head_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (pmod == pldm) {
return TRUE;
}
}
for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (pmod == pldm) {
return TRUE;
}
}
return FALSE;
}
//////////////////////////////////////////////////
tracemod_t *TM_self_register (const char* mod_name,
const char *help, TM_OPAQUE_DATA client_data)
{
Ldm *pldm;
LdmNode *pnode;
for (pnode=head_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (strcmp(mod_name, pldm->name) == NULL) {
pldm->help = (char*) help;
pldm->client_data = client_data;
pldm->valid = TRUE;
return pldm;
}
}
ui->error("TM : unable to find MODULE <%s> \n", mod_name);
return NULL;
}
//////////////////////////////////////////////////
tracemod_t *TM_self_register_spec (const char* mod_name, TM_OPAQUE_DATA client_data)
{
Ldm *pldm;
LdmNode *pnode;
for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (strcmp(mod_name, pldm->name) == NULL) {
pldm->help = NULL;
pldm->client_data = client_data;
pldm->valid = TRUE;
return pldm;
}
}
ui->error("TM : unable to find MODULE <%s> \n", mod_name);
return NULL;
}
//////////////////////////////////////////////////
void TM_ui_register_1 (tracemod_t* pmod, const char* name,
const char */*shelp*/, const char * lhelp, fn_ui_1 fn)
{
LdmNode *pnode;
Ldm *pldm;
LdmCmd *pldm_cmd;
for (pnode=head_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (pmod == pldm) {
if (pldm_cmd = ldm_cmd_add (name, fn, NULL)) {
UI_register_cmd_1 ((char*)name, (char*)lhelp, extra_cmd_action_1, NULL);
pldm_cmd->ldm = pldm;
}
return;
}
}
for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (pmod == pldm) {
if (pldm_cmd = ldm_cmd_add (name, fn, NULL)) {
UI_register_cmd_1 ((char*)name, (char*)lhelp, extra_cmd_action_1, NULL);
pldm_cmd->ldm = pldm;
}
return;
}
}
ui->error("TM: module <%s> not found\n", pldm->name);
}
//////////////////////////////////////////////////
void TM_ui_register_2 (tracemod_t* pmod, const char* name,
const char */*shelp*/, const char * lhelp, fn_ui_2 fn)
{
LdmNode *pnode;
Ldm *pldm;
LdmCmd *pldm_cmd;
for (pnode=head_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (pmod == pldm) {
if (pldm_cmd = ldm_cmd_add (name, NULL, fn)) {
UI_register_cmd_2 ((char*)name, (char*)lhelp, extra_cmd_action_2, NULL);
pldm_cmd->ldm = pldm;
}
return;
}
}
for (pnode=head_spec_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (pmod == pldm) {
if (pldm_cmd = ldm_cmd_add (name, NULL, fn)) {
UI_register_cmd_2 ((char*)name, (char*)lhelp, extra_cmd_action_2, NULL);
pldm_cmd->ldm = pldm;
}
return;
}
}
ui->error("TM: module <%s> not found\n", pldm->name);
}
//////////////////////////////////////////////////
void TM_time_interval_register (tracemod_t *pmod, fn_time_interval fn)
{
pmod->ti_action = fn;
}
//////////////////////////////////////////////////
void TM_ui_unregister (tracemod_t* /*pmod*/, const char *name)
{
LdmCmdNode *pnode = head_ldm_cmd, *prv = NULL;
LdmCmd *pldm_cmd;
for (;pnode; pnode = pnode->Next()) {
pldm_cmd = pnode->GetData();
if (strcmp(name, pldm_cmd->name) == NULL) {
if (prv == NULL) {
LdmCmdNode::DeleteHead (&pnode);
UI_invalidate_cmd ((char*)name);
return;
}
else {
LdmCmdNode::DeleteNode ((LdmCmdNode**)&head_ldm_cmd, prv);
UI_invalidate_cmd ((char*)name);
return;
}
}
prv = pnode;
}
}
//////////////////////////////////////////////////
void TM_set_type_ext (tracemod_t *pmod, Byte type)
{
if (
(type != TM_TYPE_EXT_CPU) &&
(type != TM_TYPE_EXT_DEVICE) &&
(type != TM_TYPE_EXT_SIM)
) {
ui->error("TM : TM_set_type_ext (unknown type = 0x%x) \n", type);
return;
}
pmod->type = type;
}
//////////////////////////////////////////////////
void TM_cpustate_register (tracemod_t* pmod, fn_cpustat fn)
{
pmod->cpustat_action = fn;
}
void TM_cpustate_registerB (tracemod_t* pmod, fn_cpustatB fn)
{
pmod->cpustat_actionB = fn;
}
void TM_set_mode (tracemod_t *pmod, Byte mode)
{
pmod->mode |= mode;
if (mode & TM_EXT_IO) {
return;
}
}
bool_t TM_mt_safe ()
{
Ldm *pldm;
LdmNode *pnode;
for (pnode=head_ldm; pnode!=NULL; pnode=pnode->Next()) {
pldm = pnode->GetData ();
if (!(pldm->mode & TM_MT_SAFE)) {
return FALSE;
}
}
return TRUE;
}