Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / py / py_interface.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: py_interface.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) 2006 Sun Microsystems, Inc.
// All rights reserved.
//
// py_interface.cc
//
// implementation file for python user interface
/* standard C includes */
// must be before other includes
#include "Python.h"
#include "abstract.h"
#include <stdio.h>
#include <thread.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <libgen.h>
/* solaris includes */
#include <signal.h>
#include <sys/types.h>
#include <sys/exec.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/procfs.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <stropts.h>
#include <dlfcn.h>
#include <map>
#include "types.h"
#include "blaze_globals.h"
#include "system.h"
#include "mem.h"
#include "ui.h"
#include "ui_cmd_struct.h"
// declarations from ui_cmds.cc
extern Ui_cmd ui_cmd_list[];
extern void UI_register_cmd_2 (char * name, char *help, int (*efn)(void *, int, char **), int (*hfn)());
extern void UI_invalidate_cmd (char * name);
extern int sstep_cmd (int vcpu_id);
extern uint32_t BLAZE_restore_from_checkpoint();
extern int exec_cmd(char *s);
// ui does not accept command which length exceeds
// max_cmd_length param defined in ui_cmds.cc
const int max_cmd_line_size = 2048;
// globals
static void *py_lib_handle = NULL;
char *sam_dir = NULL;
// map for new command registered from py module
std::map<std::string,PyObject*> *py_cmd_map = NULL;
static PyObject * pyCBdelfn = 0;
static PyObject * pyCBaddfn = 0;
// the externally callable interface function from SAM UI
typedef void (*Py_Intf_fn)(const char *);
extern Py_Intf_fn addPycmd;
extern Py_Intf_fn delPycmd;
void delPyUI(const char * n){
PyObject * rslt;
PyObject * args = Py_BuildValue((char*)"(s)",n);
if(pyCBdelfn)
rslt = PyEval_CallObject(pyCBdelfn,args);
Py_DECREF(args);
if(rslt)
Py_DECREF(rslt);
else
printf("ERROR: could not delete %s\n",n);
return;
}
void addPyUI(const char * n){
Ui_cmd * next = &ui_cmd_list[0];
while(next){
if(!strcmp(n,next->name))
break;
next = next->next;
}
if(!next)
assert(0);
PyObject * arg = Py_BuildValue((char*)"(ss)",next->help,n);
PyObject * rslt = 0;
if(pyCBaddfn)
rslt = PyEval_CallObject(pyCBaddfn,arg);
Py_DECREF(arg);
if (rslt)
Py_DECREF(rslt);
else
printf("ERROR: could not add %s\n",n);
return;
}
// send command string to build-in ui interpreter
extern "C" PyObject* sam_exec( PyObject* self, PyObject* args )
{
char *cmd;
char rsp[2];
if (!PyArg_ParseTuple(args,(char*)"s",&cmd))
return 0;
// Don't need to mutex exec_cmd() here as python can only be
// executed from the ui which means we should already hold
// the mutex ui_thread_lock (see ui_cmds.cc)
exec_cmd( cmd );
return Py_BuildValue("");
}
// add string s2 to s1
static inline char *stradd(char *s1, char *s2, int len=0)
{
if (!len) len = strlen(s2);
strncpy(s1,s2,len);
return s1+len;
}
// send command to py interpreter
int exec_py_cmd(void * /* usrdata */, int argc, char **argv)
{
if (!IN_STOP_STATE (blaze_run_state))
{
fprintf(stderr, "ERROR: not in stop state, use stop command first\n");
return 0;
}
// check if command was registered before
PyObject *py_cmd_fn = py_cmd_map->find(argv[0])->second;
if(!py_cmd_fn)
{
fprintf(stderr, "unknown py command %s\n", argv[0]);
return 0;
}
// build arguments
PyObject * arg = PyTuple_New(argc);
for (int i=0; i<argc; i++)
PyTuple_SetItem(arg, i, PyString_FromString(argv[i]));
// call py routine
PyObject * rslt = PyEval_CallObject(py_cmd_fn,arg);
Py_DECREF(arg);
if (rslt)
Py_DECREF(rslt);
return 1;
}
// register a new py command with ui
extern "C" PyObject* sam_register( PyObject* self, PyObject* args )
{
char *cmd_name, *help_str;
PyObject *py_command_fn;
// get command name, help string and a pointer to py command routine
if (!PyArg_ParseTuple(args,(char*)"ssO:sam_register",&cmd_name, &help_str,&py_command_fn))
return 0;
if (!PyCallable_Check(py_command_fn))
{
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return 0;
}
Py_XINCREF(py_command_fn);
// register new command
if (!py_cmd_map) // keep map for new py commands
{
py_cmd_map = new std::map<std::string,PyObject*>;
}
if (py_cmd_map->find(cmd_name) == py_cmd_map->end())
{
py_cmd_map->insert(std::pair<std::string,PyObject *>(cmd_name,py_command_fn));
UI_register_cmd_2(cmd_name, help_str, exec_py_cmd, NULL);
}
else
{
fprintf(stderr, "ERROR: cannot register a new command, %s command exist already \n",cmd_name);
}
return Py_BuildValue("");
}
// unregister ui command
extern "C" PyObject* sam_unregister( PyObject* self, PyObject* args )
{
char *cmd_name;
// get command name
if (!PyArg_ParseTuple(args,(char*)"s",&cmd_name))
return 0;
if (py_cmd_map && cmd_name) // check new py commands
{
if (py_cmd_map->erase(cmd_name))
{
// unregister the command
UI_invalidate_cmd (cmd_name);
ui->verbose("command %s, was removed\n", cmd_name);
}
else
{
fprintf(stderr, "ERROR: cannot unregister command %s \n", cmd_name);
}
}
return Py_BuildValue("");
}
extern "C" uint_t vcpu_get_sys_type();
extern "C" uint_t vcpu_get_sys_size();
extern "C" void* vcpu_get_sys_pntr( uint_t i );
extern "C" PyObject* vcpu_sys_type( PyObject* self, PyObject* args )
{
uint_t type;
type = vcpu_get_sys_type();
return Py_BuildValue((char*)"i", type);
}
extern "C" PyObject* vcpu_sys_size( PyObject* self, PyObject* args )
{
uint_t size;
size = vcpu_get_sys_size();
return Py_BuildValue((char*)"i", size);
}
extern "C" PyObject* set_cmd_del_fn( PyObject* self, PyObject* args )
{
PyObject *result = 0;
if(PyArg_ParseTuple(args,"O:set_cmd_del_fn",&pyCBdelfn)){
if (!PyCallable_Check(pyCBdelfn)){
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return 0;
}
Py_XINCREF(pyCBdelfn);
Py_INCREF(Py_None);
result = Py_None;
delPycmd = delPyUI;
}
return result;
}
extern "C" PyObject* set_cmd_add_fn( PyObject* self, PyObject* args )
{
PyObject *result = 0;
if(PyArg_ParseTuple(args,"O:set_cmd_add_fn",&pyCBaddfn)){
if (!PyCallable_Check(pyCBaddfn)){
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return 0;
}
Py_XINCREF(pyCBaddfn);
Py_INCREF(Py_None);
result = Py_None;
addPycmd = addPyUI;
}
return result;
}
extern "C" PyObject* vcpu_sys_pntr( PyObject* self, PyObject* args )
{
uint_t i;
uint64_t sysp;
if (!PyArg_ParseTuple(args,(char*)"i",&i))
return 0;
sysp = (uint64_t)vcpu_get_sys_pntr(i);
return Py_BuildValue((char*)"l", sysp);
}
extern "C" PyObject* mem_ld64( PyObject* self, PyObject* args )
{
uint64_t addr, data;
if (!PyArg_ParseTuple(args,(char*)"l",&addr))
return 0;
addr &= ~uint64_t(7); // align
data = mm1->ld64(addr);
return PyLong_FromUnsignedLong(data);
}
extern "C" PyObject* mem_st64( PyObject* self, PyObject* args )
{
uint64_t addr, data;
if (!PyArg_ParseTuple(args,(char*)"ll",&addr,&data))
return 0;
addr &= ~uint64_t(7); // align
mm1->st64(addr,data);
return Py_BuildValue((char*)"");
}
extern "C" PyObject* mem_ld32( PyObject* self, PyObject* args )
{
uint64_t addr, data;
if (!PyArg_ParseTuple(args,(char*)"l",&addr))
return 0;
addr &= ~uint64_t(3); // align
data = mm1->ld32u(addr);
return Py_BuildValue((char*)"l",data);
}
extern "C" PyObject* mem_st32( PyObject* self, PyObject* args )
{
uint64_t addr, data;
if (!PyArg_ParseTuple(args,(char*)"ll",&addr,&data))
return 0;
addr &= ~uint64_t(3); // align
mm1->st32(addr,data);
return Py_BuildValue((char*)"");
}
extern "C" PyObject* mem_ld16( PyObject* self, PyObject* args )
{
uint64_t addr, data;
if (!PyArg_ParseTuple(args,(char*)"l",&addr))
return 0;
addr &= ~uint64_t(1); // align
data = mm1->ld16u(addr);
return Py_BuildValue((char*)"l",data);
}
extern "C" PyObject* mem_st16( PyObject* self, PyObject* args )
{
uint64_t addr, data;
if (!PyArg_ParseTuple(args,(char*)"ll",&addr,&data))
return 0;
addr &= ~uint64_t(1); // align
mm1->st16(addr,data);
return Py_BuildValue((char*)"");
}
extern "C" PyObject* mem_ld8( PyObject* self, PyObject* args )
{
uint64_t addr, data;
if (!PyArg_ParseTuple(args,(char*)"l",&addr))
return 0;
data = mm1->ld8u(addr);
return Py_BuildValue((char*)"l",data);
}
extern "C" PyObject* mem_st8( PyObject* self, PyObject* args )
{
uint64_t addr, data;
if (!PyArg_ParseTuple(args,(char*)"ll",&addr,&data))
return 0;
mm1->st8(addr,data);
return Py_BuildValue((char*)"");
}
extern "C" PyObject* is_stopped( PyObject* self, PyObject* args )
{
bool_t stop = SYSTEM_is_stopped();
if (!PyArg_ParseTuple(args,(char*)""))
return 0;
return Py_BuildValue((char*)"i",stop);
}
extern "C" PyObject* is_restored_simulation( PyObject* self, PyObject* args )
{
bool_t restore = BLAZE_restore_from_checkpoint();
if (!PyArg_ParseTuple(args,(char*)""))
return 0;
return Py_BuildValue((char*)"i",restore);
}
// methods used to run verification diags
extern "C" PyObject* s_step( PyObject* self, PyObject* args )
{
uint_t vcpu_id;
if (!PyArg_ParseTuple(args,(char*)"i",&vcpu_id))
return 0;
uint_t done = sstep_cmd(vcpu_id);
return Py_BuildValue((char*)"i",done);
}
extern "C" PyObject* get_cmd_dict( PyObject* self, PyObject* args )
{
const int bufSize = 64 * 1024; // largest possible string - no error checks ahead!!!
char buf2[bufSize];
buf2[0] = 0;
// create a dictionary of {cmd_name:definition}
Ui_cmd * next = &ui_cmd_list[0];
// build the python dictionary
PyObject* pyDict = Py_BuildValue((char*)"{s:s}","","");
while(next){
// Force use of _ iso - or . for example
char * cmd_name = strdup(next->name);
for(int i = 0; i < strlen(cmd_name); i++)
if(!isalnum(cmd_name[i]))
cmd_name[i]='_';
// special case the SAM break command as it is a python keyword
if(!strcmp(cmd_name,"break")){
free((void*)cmd_name);
cmd_name = strdup("brk");
}
sprintf(buf2,"def sam_%s(args=\"\"):\n",cmd_name);
sprintf(buf2 + strlen(buf2)," \"\"\"%s\n \"\"\"\n",next->help);
sprintf(buf2 + strlen(buf2)," sam.ui_exec(\"%s \" + args)\n\n",next->name);
PyObject* pyStr = Py_BuildValue((char*)"s",buf2);
PyMapping_SetItemString(pyDict,cmd_name,pyStr);
next = next->next;
free((void*)cmd_name);
}
return pyDict;
}
static PyMethodDef py_methods [] =
{
{"ui_exec", sam_exec, METH_VARARGS, "ui_exec <cmd>\n"},
{"ui_register", sam_register, METH_VARARGS, "ui_register (cmd_name, help_str,cmd_func)\n"},
{"ui_unregister", sam_unregister, METH_VARARGS, "ui_unregister (cmd_name)\n"},
{"sys_type", vcpu_sys_type, METH_VARARGS, "vcpu_sys_type <>\n"},
{"sys_size", vcpu_sys_size, METH_VARARGS, "vcpu_sys_size <>\n"},
{"sys_pntr", vcpu_sys_pntr, METH_VARARGS, "vcpu_sys_pntr <i>\n"},
{"mem_ld64", mem_ld64, METH_VARARGS, "mem_ld64(addr)\n"},
{"mem_st64", mem_st64, METH_VARARGS, "mem_st64(addr,data)\n"},
{"mem_ld32", mem_ld32, METH_VARARGS, "mem_ld32(addr)\n"},
{"mem_st32", mem_st32, METH_VARARGS, "mem_st32(addr,data)\n"},
{"mem_ld16", mem_ld16, METH_VARARGS, "mem_ld16(addr)\n"},
{"mem_st16", mem_st16, METH_VARARGS, "mem_st16(addr,data)\n"},
{"mem_ld8", mem_ld8, METH_VARARGS, "mem_ld8(addr)\n"},
{"mem_st8", mem_st8, METH_VARARGS, "mem_st8(addr,data)\n"},
{"is_stopped", is_stopped, METH_VARARGS, "is_stopped()\n"},
{"is_restored_simulation", is_restored_simulation, METH_VARARGS, "is_restored_simulation()\n"},
{"sstep", s_step, METH_VARARGS, "sstep(vcpu_id)\n"},
{"get_cmd_dict", get_cmd_dict, METH_VARARGS, "get_cmd_dict()\n"},
{"set_cmd_del_fn", set_cmd_del_fn, METH_VARARGS, "set_cmd_del_fn(Fn)\n"},
{"set_cmd_add_fn", set_cmd_add_fn, METH_VARARGS, "set_cmd_add_fn(Fn)\n"},
{0, 0, 0, 0} // end of the list
};
////////////////////////////////////////////////////////////////
//
// py source command
//
extern int (*py_source)( int argc, char** argv );
int py_source_cmd( int argc, char **argv )
{
assert (argc > 0);
ui->verbose("loading py module %s...\n", argv[0]);
char cmd[max_cmd_line_size];
char *s=cmd;
s=stradd(s,"execfile(\"");
char* filename = argv[0];
if (strncmp(filename,"$SAM/",5) == 0)
{
// replace $SAM with dir path
char *fname = s;
s=stradd(s,sam_dir);
s=stradd(s,&filename[4]);
filename = fname;
}
else // file name
s=stradd(s,filename);
stradd(s,"\0",1);
// check if file exist
struct stat sfile;
if (stat(filename, &sfile))
{
fprintf(stderr, "ERROR: %s : No such file or directory\n", filename);
return 0;
}
if ((sfile.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0)
{
fprintf(stderr, "ERROR: %s : file is not readable \n", filename);
return 0;
}
stradd(s,"\")\0",3);
ui->verbose("%s\n", cmd);
// set pythons sys.argv to arguments of py_source
PySys_SetArgv(argc,argv);
PyRun_SimpleString(cmd);
return 1;
}
/////////////////////////////////////////////////////////////////
//
// start py user interface
//
extern void setenv_pythonhome(); // Defined in pythonhome.cc
extern "C" int init_py_interface(char* fname, char* modname, void* lib_handle)
{
if (py_lib_handle != NULL)
{
ui->error("py lib was loaded already. \n" );
return 0;
}
py_lib_handle = lib_handle;
if(py_lib_handle==NULL)
{
fprintf (stderr, "cannot obtain py lib handle\n" );
return 0;
}
extern bool python_UI;
python_UI = true;
setenv_pythonhome();
// set PYTHONPATH to the known python directories in our
// sam releases.
const char* env_var = "PYTHONPATH=";
const char* pfe_dir = "/pfe";
const char* sam = getexecname();
// Do we expect getexecname() to fail ... geeesh that would be
// a disaster if $0 is blank. In case it is just assume sam.
if (!sam) sam = "./sam";
// Expect that sam was executed from our release. So expect
// $sam_dir/bin/sam and grab $sam_dir. If not then things have
// been moved around ... well though.
char* origin = dirname(strdup(sam));
sam_dir = dirname(strdup(origin));
char* str;
size_t len = strlen(env_var) + strlen(sam_dir) + strlen(pfe_dir);
// Before setting PYTHONPATH, check if one is set already and prepend
// our paths to it. Otherwise assume PYTHONPATH was '.'
char* pythonpath = getenv(env_var);
if (pythonpath == 0)
pythonpath = ".";
str = (char*)malloc(len + strlen(pythonpath) + 2);
sprintf(str,"%s%s%s:%s",env_var,sam_dir,pfe_dir,pythonpath);
ui->verbose("%s\n",str);
putenv(str);
if ( !Py_IsInitialized() )
{
Py_Initialize();
Py_InitModule((char*)"sam", py_methods);
PyEval_InitThreads();
}
// The "run-python-file" ui command needs this py_source
py_source = py_source_cmd;
return 1;
}
extern "C" int close_py_interface()
{
// when return back to sam ui don't call this method
// during the session otherwise sam ui hangs;
if ( Py_IsInitialized() )
{
Py_Finalize();
}
pyCBdelfn = 0;
pyCBaddfn = 0;
if(py_cmd_map)
{
delete py_cmd_map;
py_cmd_map = NULL;
}
return 0;
}