/*$$HEADER*/
|
/*$$HEADER*/
|
/******************************************************************************/
|
/******************************************************************************/
|
/* */
|
/* */
|
/* H E A D E R I N F O R M A T I O N */
|
/* H E A D E R I N F O R M A T I O N */
|
/* */
|
/* */
|
/******************************************************************************/
|
/******************************************************************************/
|
|
|
// Project Name : ORPSoCv2
|
// Project Name : ORPSoCv2
|
// File Name : jp_vpi.c
|
// File Name : jp_vpi.c
|
// Prepared By : jb, jb@orsoc.se
|
// Prepared By : jb, jb@orsoc.se
|
// Project Start : 2009-05-01
|
// Project Start : 2009-05-01
|
|
|
/*$$COPYRIGHT NOTICE*/
|
/*$$COPYRIGHT NOTICE*/
|
/******************************************************************************/
|
/******************************************************************************/
|
/* */
|
/* */
|
/* C O P Y R I G H T N O T I C E */
|
/* C O P Y R I G H T N O T I C E */
|
/* */
|
/* */
|
/******************************************************************************/
|
/******************************************************************************/
|
/*
|
/*
|
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
License as published by the Free Software Foundation;
|
License as published by the Free Software Foundation;
|
version 2.1 of the License, a copy of which is available from
|
version 2.1 of the License, a copy of which is available from
|
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt.
|
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt.
|
|
|
This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
|
|
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
*/
|
*/
|
|
|
/*$$DESCRIPTION*/
|
/*$$DESCRIPTION*/
|
/******************************************************************************/
|
/******************************************************************************/
|
/* */
|
/* */
|
/* D E S C R I P T I O N */
|
/* D E S C R I P T I O N */
|
/* */
|
/* */
|
/******************************************************************************/
|
/******************************************************************************/
|
//
|
//
|
// Implements communication between verilog simulator and RSP server
|
// Implements communication between verilog simulator and RSP server
|
//
|
//
|
//
|
//
|
/*
|
/*
|
Functions used via the Verilog Procedural Interface (VPI), in a verilog
|
Functions used via the Verilog Procedural Interface (VPI), in a verilog
|
simulation of an OpenRISC processor, providing a means of communication to the
|
simulation of an OpenRISC processor, providing a means of communication to the
|
simulatin for a GDB stub.
|
simulatin for a GDB stub.
|
|
|
The communication between the GDB stub and this module is via a "custom"
|
The communication between the GDB stub and this module is via a "custom"
|
protocol, which is decoded into the verilog debug task module and the
|
protocol, which is decoded into the verilog debug task module and the
|
appropriate transactions are performed with the debug interface inside the
|
appropriate transactions are performed with the debug interface inside the
|
OpenRISC design.
|
OpenRISC design.
|
|
|
Operation:
|
Operation:
|
See the verilog file containing the calls to the VPI tasks we outline in this
|
See the verilog file containing the calls to the VPI tasks we outline in this
|
file for exact details of how they are used (debug_vpi_module.v), but
|
file for exact details of how they are used (debug_vpi_module.v), but
|
following is a brief outline of how it is meant to work.
|
following is a brief outline of how it is meant to work.
|
|
|
The RSP GDB stub is initialised after compile via a VPI callback
|
The RSP GDB stub is initialised after compile via a VPI callback
|
(cbEndOfCompile). A process is forked off to run the RSP server, and IPC is via
|
(cbEndOfCompile). A process is forked off to run the RSP server, and IPC is via
|
pipes. Note: This is probably an extremely ineffecient way to do this as the
|
pipes. Note: This is probably an extremely ineffecient way to do this as the
|
fork() creates a copy of the program, including it's ~200MB memory space, so
|
fork() creates a copy of the program, including it's ~200MB memory space, so
|
maybe a different method should be worked out for massive sims, but for smaller
|
maybe a different method should be worked out for massive sims, but for smaller
|
OpenRISC designs on a power machine this is not a problem.
|
OpenRISC designs on a power machine this is not a problem.
|
|
|
The verilog debug module polls for incoming commands from the GDB stub at a
|
The verilog debug module polls for incoming commands from the GDB stub at a
|
#delay rate set in the verilog code.
|
#delay rate set in the verilog code.
|
|
|
The port which the GDB server runs on is #define'd in this file by
|
The port which the GDB server runs on is #define'd in this file by
|
RSP_SERVER_PORT.
|
RSP_SERVER_PORT.
|
|
|
When a GDB connection is established, the state of the processor is downloaded
|
When a GDB connection is established, the state of the processor is downloaded
|
by GDB, so expect a slight delay after connection.
|
by GDB, so expect a slight delay after connection.
|
|
|
To close down the simulation gracefully, issue a "detach" command from GDB.
|
To close down the simulation gracefully, issue a "detach" command from GDB.
|
This will close the connection with the stub and will also send a message to
|
This will close the connection with the stub and will also send a message to
|
$finish the simulation.
|
$finish the simulation.
|
|
|
Note: Simulation reset is untested, but should probably work OK.
|
Note: Simulation reset is untested, but should probably work OK.
|
|
|
Note: Reading uninitialised memory which returns Xs will break things.
|
Note: Reading uninitialised memory which returns Xs will break things.
|
Specifically, the CRC generation breaks, and then many other things. So to help
|
Specifically, the CRC generation breaks, and then many other things. So to help
|
avoid hours of X tracing, ensure you're reading initialised space from GDB.
|
avoid hours of X tracing, ensure you're reading initialised space from GDB.
|
|
|
To Do:
|
To Do:
|
* Comment this better! Sorry, it's a little lacking in this area.
|
* Comment this better! Sorry, it's a little lacking in this area.
|
* Block transfers (ie. what happens when "load"ing from GDB) ignore any bytes
|
* Block transfers (ie. what happens when "load"ing from GDB) ignore any bytes
|
over the word boundary at the end of a transfer. Currently a warning printf
|
over the word boundary at the end of a transfer. Currently a warning printf
|
will appear.
|
will appear.
|
* Make the RSP server process not be a complete copy of the vvp image - ie.
|
* Make the RSP server process not be a complete copy of the vvp image - ie.
|
don't fork() in the sim, maybe compile and exec() a separate app for this.
|
don't fork() in the sim, maybe compile and exec() a separate app for this.
|
|
|
*/
|
*/
|
|
|
|
|
/* EXAMPLE
|
/* EXAMPLE
|
// Associate C Function with a New System Task
|
// Associate C Function with a New System Task
|
voi
|
voi
|
d registerHelloSystfs() {
|
d registerHelloSystfs() {
|
s_vpi_systf_data task_data_s;
|
s_vpi_systf_data task_data_s;
|
p_vpi_systf_data task_data_p = &task_data_s;
|
p_vpi_systf_data task_data_p = &task_data_s;
|
task_data_p->type = vpiSysTask;
|
task_data_p->type = vpiSysTask;
|
task_data_p->tfname = "$hello";
|
task_data_p->tfname = "$hello";
|
task_data_p->calltf = hello;
|
task_data_p->calltf = hello;
|
task_data_p->compiletf = 0;
|
task_data_p->compiletf = 0;
|
|
|
vpi_register_systf(task_data_p);
|
vpi_register_systf(task_data_p);
|
}
|
}
|
|
|
*/
|
*/
|
|
|
|
|
/*
|
/*
|
To associate your C function with a system task, create a
|
To associate your C function with a system task, create a
|
data structure of type s_vpi_systf_data and a pointer to
|
data structure of type s_vpi_systf_data and a pointer to
|
that structure. The vpi_systf_data data type is defined in
|
that structure. The vpi_systf_data data type is defined in
|
the vpi_user.h include file. Below is the data structure
|
the vpi_user.h include file. Below is the data structure
|
of s_vpi_systf_data.
|
of s_vpi_systf_data.
|
|
|
typedef struct t_vpi_systf_data {
|
typedef struct t_vpi_systf_data {
|
PLI_INT32 type; // vpiSysTask, vpiSysFunc - task not return val, Func does
|
PLI_INT32 type; // vpiSysTask, vpiSysFunc - task not return val, Func does
|
PLI_INT32 sysfunctype; // vpiSysTask, vpi[Int,Real,Time,Sized, SizedSigned]Func - if it's a func, this is the typ of return
|
PLI_INT32 sysfunctype; // vpiSysTask, vpi[Int,Real,Time,Sized, SizedSigned]Func - if it's a func, this is the typ of return
|
PLI_BYTE8 *tfname; // First character must be `$'
|
PLI_BYTE8 *tfname; // First character must be `$'
|
PLI_INT32 (*calltf)(PLI_BYTE8 *); //pointer to the function
|
PLI_INT32 (*calltf)(PLI_BYTE8 *); //pointer to the function
|
PLI_INT32 (*compiletf)(PLI_BYTE8 *); // pointer to a function that the simulator calls
|
PLI_INT32 (*compiletf)(PLI_BYTE8 *); // pointer to a function that the simulator calls
|
// when it's compiled - can be NULL
|
// when it's compiled - can be NULL
|
PLI_INT32 (*sizetf)(PLI_BYTE8 *); // For sized function callbacks only, This field is a
|
PLI_INT32 (*sizetf)(PLI_BYTE8 *); // For sized function callbacks only, This field is a
|
// pointer to a routine that returns the size, in bits,
|
// pointer to a routine that returns the size, in bits,
|
// of the value that the system task or function returns.
|
// of the value that the system task or function returns.
|
PLI_BYTE8 *user_data; --optional extra data?
|
PLI_BYTE8 *user_data; --optional extra data?
|
} s_vpi_systf_data, *p_vpi_systf_data;
|
} s_vpi_systf_data, *p_vpi_systf_data;
|
*/
|
*/
|
|
|
|
|
|
|
/*$$CHANGE HISTORY*/
|
/*$$CHANGE HISTORY*/
|
/******************************************************************************/
|
/******************************************************************************/
|
/* */
|
/* */
|
/* C H A N G E H I S T O R Y */
|
/* C H A N G E H I S T O R Y */
|
/* */
|
/* */
|
/******************************************************************************/
|
/******************************************************************************/
|
// Date Version Description
|
// Date Version Description
|
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
// 090501 Imported code from "jp" VPI project jb
|
// 090501 Imported code from "jp" VPI project jb
|
// Changed to use pipes instead of sockets jb
|
// Changed to use pipes instead of sockets jb
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <errno.h>
|
#include <errno.h>
|
#include <unistd.h>
|
#include <unistd.h>
|
#include <sys/types.h>
|
#include <sys/types.h>
|
#include <sys/wait.h>
|
#include <sys/wait.h>
|
#include <sys/select.h>
|
#include <sys/select.h>
|
#include <sys/poll.h>
|
#include <sys/poll.h>
|
#include <sys/stat.h>
|
#include <sys/stat.h>
|
#include <fcntl.h>
|
#include <fcntl.h>
|
#include <ctype.h>
|
#include <ctype.h>
|
#include <string.h>
|
#include <string.h>
|
#include <stdarg.h>
|
#include <stdarg.h>
|
#include <stdint.h>
|
#include <stdint.h>
|
#include <signal.h>
|
#include <signal.h>
|
#include <inttypes.h>
|
#include <inttypes.h>
|
|
|
// VPI includes
|
// VPI includes
|
#include <vpi_user.h>
|
#include <vpi_user.h>
|
|
|
#ifdef CDS_VPI
|
#ifdef CDS_VPI
|
// Cadence ncverilog specific include
|
// Cadence ncverilog specific include
|
#include <vpi_user_cds.h>
|
#include <vpi_user_cds.h>
|
#endif
|
#endif
|
|
|
// Includes for the RSP server side of things
|
// Includes for the RSP server side of things
|
#include "gdb.h"
|
#include "gdb.h"
|
#include "rsp-rtl_sim.h"
|
#include "rsp-rtl_sim.h"
|
#include "rsp-vpi.h"
|
#include "rsp-vpi.h"
|
|
|
// Define the port we open the RSP server on
|
// Define the port we open the RSP server on
|
#define RSP_SERVER_PORT 5555
|
#define RSP_SERVER_PORT 5555
|
|
|
//Function to register the function which sets up the sockets interface
|
//Function to register the function which sets up the sockets interface
|
void register_init_rsp_server_functions() ;
|
void register_init_rsp_server_functions() ;
|
// Function which sets up the socket interface
|
// Function which sets up the socket interface
|
void init_rsp_server();
|
void init_rsp_server();
|
//install a callback on simulation reset which calls setup
|
//install a callback on simulation reset which calls setup
|
void setup_reset_callbacks();
|
void setup_reset_callbacks();
|
//install a callback on simulation compilation finish
|
//install a callback on simulation compilation finish
|
void setup_endofcompile_callbacks();
|
void setup_endofcompile_callbacks();
|
//install a callback on simulation finish
|
//install a callback on simulation finish
|
void setup_finish_callbacks();
|
void setup_finish_callbacks();
|
//callback function which closes and clears the socket file descriptors
|
//callback function which closes and clears the socket file descriptors
|
// on simulation reset
|
// on simulation reset
|
void sim_reset_callback();
|
void sim_reset_callback();
|
void sim_endofcompile_callback();
|
void sim_endofcompile_callback();
|
void sim_finish_callback();
|
void sim_finish_callback();
|
|
|
void register_check_for_command();
|
void register_check_for_command();
|
void register_get_command_address();
|
void register_get_command_address();
|
void register_get_command_data();
|
void register_get_command_data();
|
void register_return_command_block_data();
|
void register_return_command_block_data();
|
void register_return_command_data();
|
void register_return_command_data();
|
void register_get_command_block_data();
|
void register_get_command_block_data();
|
void register_return_response();
|
void register_return_response();
|
|
|
void check_for_command();
|
void check_for_command();
|
void get_command_address();
|
void get_command_address();
|
void get_command_data();
|
void get_command_data();
|
void get_command_block_data();
|
void get_command_block_data();
|
void return_command_data();
|
void return_command_data();
|
void return_command_block_data();
|
void return_command_block_data();
|
void return_response();
|
void return_response();
|
|
|
|
|
#include <time.h>
|
#include <time.h>
|
|
|
int vpi_to_rsp_pipe[2]; // [0] - read, [1] - write
|
uint32_t vpi_to_rsp_pipe[2]; // [0] - read, [1] - write
|
int rsp_to_vpi_pipe[2]; // [0] - read, [1] - write
|
uint32_t rsp_to_vpi_pipe[2]; // [0] - read, [1] - write
|
int command_pipe[2]; // RSP end writes, VPI end reads ONLY
|
uint32_t command_pipe[2]; // RSP end writes, VPI end reads ONLY
|
|
|
/* Global static to store the child rsp server PID if we want to kill it */
|
/* Global static to store the child rsp server PID if we want to kill it */
|
static pid_t rsp_server_child_pid = (pid_t) 0; // pid_t is just a signed int
|
static pid_t rsp_server_child_pid = (pid_t) 0; // pid_t is just a signed int
|
|
|
|
|
/********************************************************************/
|
/********************************************************************/
|
/* init_rsp_server
|
/* init_rsp_server
|
*
|
*
|
* Fork off the rsp server process
|
* Fork off the rsp server process
|
* /
|
* /
|
/********************************************************************/
|
/********************************************************************/
|
void init_rsp_server(){
|
void init_rsp_server(){
|
|
|
|
|
// First get the port number to start the RSP server on
|
// First get the port number to start the RSP server on
|
|
|
vpiHandle systfref, args_iter, argh;
|
vpiHandle systfref, args_iter, argh;
|
|
|
struct t_vpi_value argval;
|
struct t_vpi_value argval;
|
|
|
int value,i;
|
int value,i;
|
|
|
int n;
|
int n;
|
|
|
int portNum;
|
int portNum;
|
|
|
char* send_buf;
|
char* send_buf;
|
|
|
/*
|
/*
|
|
|
// Currently removed - ability to call $rsp_init_server() with a
|
// Currently removed - ability to call $rsp_init_server() with a
|
// port number as parameter. Hardcoded allows us to run this as
|
// port number as parameter. Hardcoded allows us to run this as
|
// a callback after compiile (cbEndOfCompile)
|
// a callback after compiile (cbEndOfCompile)
|
|
|
// Obtain a handle to the argument list
|
// Obtain a handle to the argument list
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
|
|
// Now call iterate with the vpiArgument parameter
|
// Now call iterate with the vpiArgument parameter
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
|
|
// get a handle on the object passed to the function
|
// get a handle on the object passed to the function
|
argh = vpi_scan(args_iter);
|
argh = vpi_scan(args_iter);
|
|
|
// now store the command value back in the sim
|
// now store the command value back in the sim
|
argval.format = vpiIntVal;
|
argval.format = vpiIntVal;
|
|
|
// Now set the data value
|
// Now set the data value
|
vpi_get_value(argh, &argval);
|
vpi_get_value(argh, &argval);
|
|
|
portNum = (int) argval.value.integer;
|
portNum = (int) argval.value.integer;
|
|
|
// Cleanup and return
|
// Cleanup and return
|
vpi_free_object(args_iter);
|
vpi_free_object(args_iter);
|
|
|
// We should now have our port number.
|
// We should now have our port number.
|
|
|
*/
|
*/
|
|
|
// Fork. Let the child run the RSP server
|
// Fork. Let the child run the RSP server
|
pid_t pid;
|
pid_t pid;
|
int rv;
|
int rv;
|
|
|
if(DBG_ON) printf("jp_vpi: init_rsp_server\n");
|
if(DBG_JP_VPI) printf("jp_vpi: init_rsp_server\n");
|
|
|
// Setup pipes
|
// Setup pipes
|
if(pipe(vpi_to_rsp_pipe) == -1)
|
if(pipe(vpi_to_rsp_pipe) == -1)
|
{
|
{
|
perror("jp_vpi: init_rsp_server pipes");
|
perror("jp_vpi: init_rsp_server pipes");
|
exit(1);
|
exit(1);
|
}
|
}
|
if(pipe(rsp_to_vpi_pipe) == -1)
|
if(pipe(rsp_to_vpi_pipe) == -1)
|
{
|
{
|
perror("jp_vpi: init_rsp_server pipes");
|
perror("jp_vpi: init_rsp_server pipes");
|
exit(1);
|
exit(1);
|
}
|
}
|
if(pipe(command_pipe) == -1)
|
if(pipe(command_pipe) == -1)
|
{
|
{
|
perror("jp_vpi: init_rsp_server pipes");
|
perror("jp_vpi: init_rsp_server pipes");
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
// Set command pipe to be non-blocking
|
// Set command pipe to be non-blocking
|
#if defined (STRIDE) || (defined (pfa) && defined (HAVE_PTYS)) || defined (AIX)
|
#if defined (STRIDE) || (defined (pfa) && defined (HAVE_PTYS)) || defined (AIX)
|
{
|
{
|
int one = 1;
|
int one = 1;
|
ioctl (command_pipe[0], FIONBIO, &one);
|
ioctl (command_pipe[0], FIONBIO, &one);
|
}
|
}
|
#endif
|
#endif
|
|
|
#ifdef O_NONBLOCK /* The POSIX way */
|
#ifdef O_NONBLOCK /* The POSIX way */
|
fcntl (command_pipe[0], F_SETFL, O_NONBLOCK);
|
fcntl (command_pipe[0], F_SETFL, O_NONBLOCK);
|
#elif defined (O_NDELAY)
|
#elif defined (O_NDELAY)
|
fcntl (command_pipe[0], F_SETFL, O_NDELAY);
|
fcntl (command_pipe[0], F_SETFL, O_NDELAY);
|
#endif /* O_NONBLOCK */
|
#endif /* O_NONBLOCK */
|
|
|
// Check on the child process. If it has not been started it will
|
// Check on the child process. If it has not been started it will
|
// be 0, else it will be something else and we'll just return
|
// be 0, else it will be something else and we'll just return
|
if ((int) rsp_server_child_pid > 0)
|
if ((int) rsp_server_child_pid > 0)
|
return;
|
return;
|
|
|
switch(pid=fork())
|
switch(pid=fork())
|
{
|
{
|
case -1:
|
case -1:
|
perror("fork");
|
perror("fork");
|
exit(1);
|
exit(1);
|
break;
|
break;
|
case 0: // Child
|
case 0: // Child
|
run_rsp_server(RSP_SERVER_PORT);
|
run_rsp_server(RSP_SERVER_PORT);
|
// exit if it ever returns, which it shouldn't
|
// exit if it ever returns, which it shouldn't
|
exit(0);
|
exit(0);
|
break;
|
break;
|
default:
|
default:
|
// We're the parent process, so continue on.
|
// We're the parent process, so continue on.
|
rsp_server_child_pid = pid;
|
rsp_server_child_pid = pid;
|
break;
|
break;
|
}
|
}
|
|
|
// Parent will only ever get this far...
|
// Parent will only ever get this far...
|
|
|
return;
|
return;
|
|
|
}
|
}
|
|
|
void register_init_rsp_server_functions() {
|
void register_init_rsp_server_functions() {
|
s_vpi_systf_data data = {vpiSysTask,
|
s_vpi_systf_data data = {vpiSysTask,
|
0,
|
0,
|
"$init_rsp_server",
|
"$init_rsp_server",
|
(void *)init_rsp_server,
|
(void *)init_rsp_server,
|
0,
|
0,
|
0,
|
0,
|
0};
|
0};
|
|
|
vpi_register_systf(&data);
|
vpi_register_systf(&data);
|
|
|
return;
|
return;
|
}
|
}
|
|
|
void print_command_string(unsigned char cmd)
|
void print_command_string(unsigned char cmd)
|
{
|
{
|
switch(cmd)
|
switch(cmd)
|
{
|
{
|
case 0x1 :
|
case 0x1 :
|
printf(" TAP instruction register set\n");
|
printf(" TAP instruction register set\n");
|
break;
|
break;
|
case 0x2 :
|
case 0x2 :
|
printf(" set debug chain\n");
|
printf(" set debug chain\n");
|
break;
|
break;
|
case 0x3 :
|
case 0x3 :
|
printf(" CPU control (stall/reset) reg write\n");
|
printf(" CPU control (stall/reset) reg write\n");
|
break;
|
break;
|
case 0x4 :
|
case 0x4 :
|
printf(" CPU control (stall/reset) reg read\n");
|
printf(" CPU control (stall/reset) reg read\n");
|
break;
|
break;
|
case 0x5 :
|
case 0x5 :
|
printf(" CPU reg write\n");
|
printf(" CPU reg write\n");
|
break;
|
break;
|
case 0x6 :
|
case 0x6 :
|
printf(" CPU reg read\n");
|
printf(" CPU reg read\n");
|
break;
|
break;
|
case 0x7 :
|
case 0x7 :
|
printf(" WB write 32\n");
|
printf(" WB write\n");
|
break;
|
break;
|
case 0x8 :
|
case 0x8 :
|
printf(" WB read 32\n");
|
printf(" WB read 32\n");
|
break;
|
break;
|
case 0x9 :
|
case 0x9 :
|
printf(" WB block write 32\n");
|
printf(" WB block write 32\n");
|
break;
|
break;
|
case 0xa :
|
case 0xa :
|
printf(" WB block read 32\n");
|
printf(" WB block read 32\n");
|
break;
|
break;
|
case 0xb :
|
case 0xb :
|
printf(" reset\n");
|
printf(" reset\n");
|
break;
|
break;
|
case 0xc :
|
case 0xc :
|
printf(" read jtag id\n");
|
printf(" read jtag id\n");
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
// See if there's anything on the FIFO for us
|
// See if there's anything on the FIFO for us
|
|
|
void check_for_command(char *userdata){
|
void check_for_command(char *userdata){
|
|
|
vpiHandle systfref, args_iter, argh;
|
vpiHandle systfref, args_iter, argh;
|
|
|
struct t_vpi_value argval;
|
struct t_vpi_value argval;
|
|
|
int value,i;
|
int value,i;
|
|
|
int n;
|
int n;
|
|
|
unsigned char data;
|
unsigned char data;
|
|
|
//if(DBG_ON) printf("check_for_command\n");
|
//if(DBG_JP_VPI) printf("check_for_command\n");
|
|
|
//n = read(rsp_to_vpi_pipe[0], &data, 1);
|
//n = read(rsp_to_vpi_pipe[0], &data, 1);
|
|
|
n = read(command_pipe[0], &data, 1);
|
n = read(command_pipe[0], &data, 1);
|
|
|
if ( ((n < 0) && (errno == EAGAIN)) || (n==0) )
|
if ( ((n < 0) && (errno == EAGAIN)) || (n==0) )
|
{
|
{
|
// Nothing in the fifo this time, let's return
|
// Nothing in the fifo this time, let's return
|
return;
|
return;
|
}
|
}
|
else if (n < 0)
|
else if (n < 0)
|
{
|
{
|
// some sort of error
|
// some sort of error
|
perror("check_for_command");
|
perror("check_for_command");
|
|
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
if (DBG_ON)
|
if (DBG_JP_VPI)
|
{
|
{
|
printf("jp_vpi: c = %x:",data);
|
printf("jp_vpi: c = %x:",data);
|
print_command_string(data);
|
print_command_string(data);
|
fflush(stdout);
|
fflush(stdout);
|
}
|
}
|
|
|
// Return the command to the sim
|
// Return the command to the sim
|
|
|
// Obtain a handle to the argument list
|
// Obtain a handle to the argument list
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
|
|
// Now call iterate with the vpiArgument parameter
|
// Now call iterate with the vpiArgument parameter
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
|
|
// get a handle on the variable passed to the function
|
// get a handle on the variable passed to the function
|
argh = vpi_scan(args_iter);
|
argh = vpi_scan(args_iter);
|
|
|
// now store the command value back in the sim
|
// now store the command value back in the sim
|
argval.format = vpiIntVal;
|
argval.format = vpiIntVal;
|
|
|
// Now set the command value
|
// Now set the command value
|
vpi_get_value(argh, &argval);
|
vpi_get_value(argh, &argval);
|
|
|
argval.value.integer = (unsigned int) data;
|
argval.value.integer = (uint32_t) data;
|
|
|
// And vpi_put_value() it back into the sim
|
// And vpi_put_value() it back into the sim
|
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
|
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
|
|
|
// Cleanup and return
|
// Cleanup and return
|
vpi_free_object(args_iter);
|
vpi_free_object(args_iter);
|
|
|
n = write(vpi_to_rsp_pipe[1],&data,1);
|
n = write(vpi_to_rsp_pipe[1],&data,1);
|
if (DBG_ON) printf("jp_vpi: r");
|
if (DBG_JP_VPI) printf("jp_vpi: r");
|
|
|
if (DBG_ON) printf("\n");
|
if (DBG_JP_VPI) printf("\n");
|
|
|
return;
|
return;
|
}
|
}
|
|
|
void get_command_address(char *userdata){
|
void get_command_address(char *userdata){
|
|
|
vpiHandle systfref, args_iter, argh;
|
vpiHandle systfref, args_iter, argh;
|
|
|
struct t_vpi_value argval;
|
struct t_vpi_value argval;
|
|
|
int value,i;
|
int value,i;
|
|
|
int n;
|
int n;
|
|
|
unsigned int data;
|
uint32_t data;
|
|
|
char* recv_buf;
|
char* recv_buf;
|
|
|
recv_buf = (char *) &data; // cast data as our receive char buffer
|
recv_buf = (char *) &data; // cast data as our receive char buffer
|
|
|
n = read(rsp_to_vpi_pipe[0],recv_buf,4);
|
n = read(rsp_to_vpi_pipe[0],recv_buf,4);
|
if (n<0)
|
if (n<0)
|
{
|
{
|
//client has closed connection
|
//client has closed connection
|
//attempt to close and return gracefully
|
//attempt to close and return gracefully
|
return;
|
return;
|
}
|
}
|
|
|
if (DBG_ON) printf("jp_vpi: get_command_address adr=0x%.8x\n",data);
|
if (DBG_JP_VPI) printf("jp_vpi: get_command_address adr=0x%.8x\n",data);
|
|
|
// now put the address into the argument passed to the task
|
// now put the address into the argument passed to the task
|
|
|
// Obtain a handle to the argument list
|
// Obtain a handle to the argument list
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
|
|
// Now call iterate with the vpiArgument parameter
|
// Now call iterate with the vpiArgument parameter
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
|
|
// get a handle on the variable passed to the function
|
// get a handle on the variable passed to the function
|
argh = vpi_scan(args_iter);
|
argh = vpi_scan(args_iter);
|
|
|
// now store the command value back in the sim
|
// now store the command value back in the sim
|
argval.format = vpiIntVal;
|
argval.format = vpiIntVal;
|
|
|
// Now set the address value
|
// Now set the address value
|
vpi_get_value(argh, &argval);
|
vpi_get_value(argh, &argval);
|
argval.value.integer = (unsigned int) data;
|
argval.value.integer = (uint32_t) data;
|
|
|
// And vpi_put_value() it back into the sim
|
// And vpi_put_value() it back into the sim
|
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
|
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
|
|
|
// Cleanup and return
|
// Cleanup and return
|
vpi_free_object(args_iter);
|
vpi_free_object(args_iter);
|
|
|
return;
|
return;
|
|
|
}
|
}
|
|
|
void get_command_data(char *userdata){
|
void get_command_data(char *userdata){
|
|
|
vpiHandle systfref, args_iter, argh;
|
vpiHandle systfref, args_iter, argh;
|
|
|
struct t_vpi_value argval;
|
struct t_vpi_value argval;
|
|
|
int value,i;
|
int value,i;
|
|
|
int n = 0;
|
int n = 0;
|
|
|
unsigned int data;
|
uint32_t data;
|
|
|
char* recv_buf;
|
char* recv_buf;
|
|
|
recv_buf = (char *) &data; // cast data as our receive char buffer
|
recv_buf = (char *) &data; // cast data as our receive char buffer
|
|
|
read_command_data_again:
|
read_command_data_again:
|
n = read(rsp_to_vpi_pipe[0],recv_buf,4);
|
n = read(rsp_to_vpi_pipe[0],recv_buf,4);
|
|
|
if ((n < 4) && errno==EAGAIN)
|
if ((n < 4) && errno==EAGAIN)
|
goto read_command_data_again;
|
goto read_command_data_again;
|
else if (n < 4)
|
else if (n < 4)
|
{
|
{
|
printf("jp_vpi: get_command_data errno: %d\n",errno);
|
printf("jp_vpi: get_command_data errno: %d\n",errno);
|
perror("jp_vpi: get_command_data read failed");
|
perror("jp_vpi: get_command_data read failed");
|
}
|
}
|
if (DBG_ON) printf("jp_vpi: get_command_data = 0x%.8x\n",data);
|
if (DBG_JP_VPI) printf("jp_vpi: get_command_data = 0x%.8x\n",data);
|
|
|
// Obtain a handle to the argument list
|
// Obtain a handle to the argument list
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
|
|
// Now call iterate with the vpiArgument parameter
|
// Now call iterate with the vpiArgument parameter
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
|
|
// get a handle on the variable passed to the function
|
// get a handle on the variable passed to the function
|
argh = vpi_scan(args_iter);
|
argh = vpi_scan(args_iter);
|
|
|
// now store the command value back in the sim
|
// now store the command value back in the sim
|
argval.format = vpiIntVal;
|
argval.format = vpiIntVal;
|
|
|
// Now set the data value
|
// Now set the data value
|
vpi_get_value(argh, &argval);
|
vpi_get_value(argh, &argval);
|
argval.value.integer = (unsigned int) data;
|
argval.value.integer = (uint32_t) data;
|
|
|
// And vpi_put_value() it back into the sim
|
// And vpi_put_value() it back into the sim
|
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
|
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
|
|
|
// Cleanup and return
|
// Cleanup and return
|
vpi_free_object(args_iter);
|
vpi_free_object(args_iter);
|
|
|
return;
|
return;
|
|
|
}
|
}
|
|
|
|
|
void get_command_block_data(){ // $get_command_block_data(length, mem_array)
|
void get_command_block_data(){ // $get_command_block_data(length, mem_array)
|
|
|
vpiHandle systfref, args_iter, argh;
|
vpiHandle systfref, args_iter, argh;
|
|
|
struct t_vpi_value argval;
|
struct t_vpi_value argval;
|
|
|
int value,i;
|
int value,i;
|
|
|
int n;
|
int n;
|
|
|
unsigned int data;
|
uint32_t data;
|
unsigned int length;
|
uint32_t length;
|
|
|
char* recv_buf;
|
char* recv_buf;
|
|
|
// Now setup the handles to verilog objects and check things
|
// Now setup the handles to verilog objects and check things
|
// Obtain a handle to the argument list
|
// Obtain a handle to the argument list
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
|
|
// Now call iterate with the vpiArgument parameter
|
// Now call iterate with the vpiArgument parameter
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
|
|
// get a handle on the length variable
|
// get a handle on the length variable
|
argh = vpi_scan(args_iter);
|
argh = vpi_scan(args_iter);
|
|
|
argval.format = vpiIntVal;
|
argval.format = vpiIntVal;
|
|
|
// get the value for the length object
|
// get the value for the length object
|
vpi_get_value(argh, &argval);
|
vpi_get_value(argh, &argval);
|
|
|
// now set length
|
// now set length
|
length = argval.value.integer;
|
length = argval.value.integer;
|
|
|
int num_words = length/4;
|
int num_words = length/4;
|
|
|
if((length % 4) != 0) vpi_printf("length of %d bytes is not exactly word-aligned\n",length);
|
//if((length % 4) != 0) vpi_printf("length of %d bytes is not exactly word-aligned\n",length);
|
// If non-word aligned we throw away remainder
|
// If non-word aligned we throw away remainder
|
int throw_away_bytes = length %4;
|
int throw_away_bytes = length %4;
|
|
|
int loaded_words = 0;
|
int loaded_words = 0;
|
|
|
if(DBG_ON)printf("jp_vpi: get_command_block_data: length=%d, num_words=%d\n",length,num_words);
|
if(DBG_JP_VPI)printf("jp_vpi: get_command_block_data: length=%d, num_words=%d\n",length,num_words);
|
|
|
// now get a handle on the next object (memory array)
|
// now get a handle on the next object (memory array)
|
argh = vpi_scan(args_iter);
|
argh = vpi_scan(args_iter);
|
|
|
// check we got passed a memory (array of regs)
|
// check we got passed a memory (array of regs)
|
if (vpi_get(vpiType, argh) != vpiMemory)
|
if (vpi_get(vpiType, argh) != vpiMemory)
|
{
|
{
|
vpi_printf("jp_vpi: ERROR: did not pass a memory to get_command_block_data\n");
|
vpi_printf("jp_vpi: ERROR: did not pass a memory to get_command_block_data\n");
|
return;
|
return;
|
}
|
}
|
|
|
// check the memory we're writing into is big enough
|
// check the memory we're writing into is big enough
|
if (vpi_get(vpiSize, argh) < num_words )
|
if (vpi_get(vpiSize, argh) < num_words )
|
{
|
{
|
vpi_printf("jp_vpi: ERROR: buffer passed to get_command_block_data too small. size is %d words, needs to be %d\n",
|
vpi_printf("jp_vpi: ERROR: buffer passed to get_command_block_data too small. size is %d words, needs to be %d\n",
|
vpi_get(vpiSize, argh), num_words);
|
vpi_get(vpiSize, argh), num_words);
|
return;
|
return;
|
}
|
}
|
|
|
vpiHandle array_word;
|
vpiHandle array_word;
|
|
|
// Loop to load the words
|
// Loop to load the words
|
while (loaded_words < num_words) {
|
while (loaded_words < num_words) {
|
|
|
recv_buf = (char *) &data;
|
recv_buf = (char *) &data;
|
|
|
// blocking receive for data block
|
// blocking receive for data block
|
n = read(rsp_to_vpi_pipe[0],recv_buf,4);
|
n = read(rsp_to_vpi_pipe[0],recv_buf,4);
|
|
|
// now get a handle on the current word we want in the array that was passed to us
|
// now get a handle on the current word we want in the array that was passed to us
|
array_word = vpi_handle_by_index(argh, loaded_words);
|
array_word = vpi_handle_by_index(argh, loaded_words);
|
|
|
if (array_word != NULL)
|
if (array_word != NULL)
|
{
|
{
|
argval.value.integer = (unsigned int) data;
|
argval.value.integer = (uint32_t) data;
|
|
|
// And vpi_put_value() it back into the sim
|
// And vpi_put_value() it back into the sim
|
vpi_put_value(array_word, &argval, NULL, vpiNoDelay);
|
vpi_put_value(array_word, &argval, NULL, vpiNoDelay);
|
}
|
}
|
else
|
else
|
return;
|
return;
|
|
|
loaded_words++;
|
loaded_words++;
|
}
|
}
|
// TODO: This is a quick fix, should be delt with properly!!
|
// TODO: This is a quick fix, should be delt with properly!!
|
if (throw_away_bytes)
|
if (throw_away_bytes)
|
{
|
{
|
//printf("reading off %d extra data bytes\n",throw_away_bytes);
|
//printf("reading off %d extra data bytes\n",throw_away_bytes);
|
n = read(rsp_to_vpi_pipe[0],&data,throw_away_bytes);
|
n = read(rsp_to_vpi_pipe[0],&data,throw_away_bytes);
|
//printf("read off %d bytes \n",n);
|
//printf("read off %d bytes \n",n);
|
}
|
}
|
|
|
// Cleanup and return
|
// Cleanup and return
|
vpi_free_object(args_iter);
|
vpi_free_object(args_iter);
|
|
|
return;
|
return;
|
|
|
}
|
}
|
|
|
void return_command_data(char *userdata){
|
void return_command_data(char *userdata){
|
|
|
vpiHandle systfref, args_iter, argh;
|
vpiHandle systfref, args_iter, argh;
|
|
|
struct t_vpi_value argval;
|
struct t_vpi_value argval;
|
|
|
int value,i;
|
int value,i;
|
|
|
int n;
|
int n;
|
|
|
uint32_t data;
|
uint32_t data;
|
|
|
char* send_buf;
|
char* send_buf;
|
|
|
// Obtain a handle to the argument list
|
// Obtain a handle to the argument list
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
|
|
// Now call iterate with the vpiArgument parameter
|
// Now call iterate with the vpiArgument parameter
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
|
|
// get a handle on the object passed to the function
|
// get a handle on the object passed to the function
|
argh = vpi_scan(args_iter);
|
argh = vpi_scan(args_iter);
|
|
|
// now store the command value back in the sim
|
// now store the command value back in the sim
|
argval.format = vpiIntVal;
|
argval.format = vpiIntVal;
|
|
|
// Now set the data value
|
// Now set the data value
|
vpi_get_value(argh, &argval);
|
vpi_get_value(argh, &argval);
|
|
|
data = (unsigned int) argval.value.integer;
|
data = (uint32_t) argval.value.integer;
|
|
|
// Cleanup and return
|
// Cleanup and return
|
vpi_free_object(args_iter);
|
vpi_free_object(args_iter);
|
|
|
if (DBG_ON) printf("jp_vpi: return_command_data 0x%.8x\n",data);
|
if (DBG_JP_VPI) printf("jp_vpi: return_command_data 0x%.8x\n",data);
|
|
|
send_buf = (char *) &data; //cast our long as a char buf
|
send_buf = (char *) &data; //cast our long as a char buf
|
|
|
// write the data back
|
// write the data back
|
n = write(vpi_to_rsp_pipe[1],send_buf,4);
|
n = write(vpi_to_rsp_pipe[1],send_buf,4);
|
|
|
return;
|
return;
|
|
|
}
|
}
|
|
|
void return_command_block_data(){
|
void return_command_block_data(){
|
|
|
vpiHandle systfref, args_iter, argh;
|
vpiHandle systfref, args_iter, argh;
|
|
|
struct t_vpi_value argval;
|
struct t_vpi_value argval;
|
|
|
int value,i;
|
int value,i;
|
|
|
int n;
|
int n;
|
|
|
unsigned int data;
|
uint32_t data;
|
unsigned int length;
|
uint32_t length;
|
|
|
|
char *block_data_buf;
|
|
uint32_t *block_word_data_buf_ptr;
|
|
|
char* recv_buf;
|
int num_words;
|
|
int sent_words = 0;
|
|
|
|
vpiHandle array_word;
|
|
|
// Now setup the handles to verilog objects and check things
|
// Now setup the handles to verilog objects and check things
|
// Obtain a handle to the argument list
|
// Obtain a handle to the argument list
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
systfref = vpi_handle(vpiSysTfCall, NULL);
|
|
|
// Now call iterate with the vpiArgument parameter
|
// Now call iterate with the vpiArgument parameter
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
args_iter = vpi_iterate(vpiArgument, systfref);
|
|
|
// get a handle on the length variable
|
// get a handle on the length variable
|
argh = vpi_scan(args_iter);
|
argh = vpi_scan(args_iter);
|
|
|
argval.format = vpiIntVal;
|
argval.format = vpiIntVal;
|
|
|
// get the value for the length object
|
// get the value for the length object
|
vpi_get_value(argh, &argval);
|
vpi_get_value(argh, &argval);
|
|
|
// now set length
|
// now set length
|
length = argval.value.integer;
|
length = argval.value.integer;
|
|
|
// now get a handle on the next object (memory array)
|
// now get a handle on the next object (memory array)
|
argh = vpi_scan(args_iter);
|
argh = vpi_scan(args_iter);
|
|
|
// check we got passed a memory (array of regs)
|
// check we got passed a memory (array of regs)
|
if (vpi_get(vpiType, argh) != vpiMemory)
|
if (vpi_get(vpiType, argh) != vpiMemory)
|
{
|
{
|
vpi_printf("jp_vpi: ERROR: did not pass a memory to return_command_block_data\n");
|
vpi_printf("jp_vpi: ERROR: did not pass a memory to return_command_block_data\n");
|
return;
|
return;
|
}
|
}
|
|
|
vpiHandle array_word;
|
// We have to alloc memory here for lengths > 4
|
|
if (length > 4);
|
|
{
|
|
block_data_buf = (char*) malloc(length * sizeof(char));
|
|
if (block_data_buf == NULL)
|
|
{
|
|
vpi_printf("jp_vpi: return_command_block_data: Error. Could not allocate memory\n");
|
|
// Cleanup and return
|
|
vpi_free_object(args_iter);
|
|
return;
|
|
}
|
|
|
int num_words = length/4;
|
// Now cast it as a uint32_t array
|
|
block_word_data_buf_ptr = (uint32_t *) block_data_buf;
|
|
}
|
|
|
int sent_words = 0;
|
num_words = length / 4; // We're always going to be dealing with whole words here
|
|
|
|
if (DBG_JP_VPI) printf("jp_vpi: return_command_block_data: num_words %d\n",
|
|
num_words);
|
|
|
// Loop to load the words
|
// Loop to load the words
|
while (sent_words < num_words) {
|
while (sent_words < num_words) {
|
|
|
// now get a handle on the current word we want in the array that was passed to us
|
// Get a handle on the current word we want in the array that was passed to us
|
array_word = vpi_handle_by_index(argh, sent_words);
|
array_word = vpi_handle_by_index(argh, sent_words);
|
|
|
if (array_word != NULL)
|
if (array_word != NULL)
|
{
|
{
|
vpi_get_value(array_word, &argval);
|
vpi_get_value(array_word, &argval);
|
|
|
data = (unsigned int) argval.value.integer;
|
data = (uint32_t) argval.value.integer;
|
|
|
|
block_word_data_buf_ptr[sent_words] = data;
|
}
|
}
|
else
|
else
|
return;
|
return;
|
|
|
recv_buf = (char *) &data;
|
if (DBG_JP_VPI) printf ( "jp_vpi: return_command_block_data: word %d 0x%.8x\n",
|
|
sent_words, data);
|
|
sent_words++;
|
|
}
|
|
|
n = write(vpi_to_rsp_pipe[1],recv_buf,4);
|
if (!(length > 4))
|
|
{
|
|
block_data_buf = (char *) &data;
|
|
}
|
|
|
sent_words++;
|
n = write(vpi_to_rsp_pipe[1],block_data_buf,length);
|
|
|
|
|
|
if (length > 4)
|
|
{
|
|
// Free the array
|
|
free(block_data_buf);
|
}
|
}
|
|
|
|
|
// Cleanup and return
|
// Cleanup and return
|
vpi_free_object(args_iter);
|
vpi_free_object(args_iter);
|
|
|
return;
|
return;
|
|
|
}
|
}
|
|
|
|
|
|
|
void return_response(char *userdata){
|
void return_response(char *userdata){
|
|
|
int n;
|
int n;
|
|
|
char resp = 0;
|
char resp = 0;
|
|
|
// send a response byte
|
// send a response byte
|
n = write(vpi_to_rsp_pipe[1],&resp,1);
|
n = write(vpi_to_rsp_pipe[1],&resp,1);
|
|
|
if (DBG_ON) printf("jp_vpi: ret\n\n");
|
if (DBG_JP_VPI) printf("jp_vpi: ret\n\n");
|
|
|
return;
|
return;
|
|
|
}
|
}
|
|
|
void register_check_for_command() {
|
void register_check_for_command() {
|
s_vpi_systf_data data = {vpiSysTask,
|
s_vpi_systf_data data = {vpiSysTask,
|
0,
|
0,
|
"$check_for_command",
|
"$check_for_command",
|
(void *)check_for_command,
|
(void *)check_for_command,
|
0,
|
0,
|
0,
|
0,
|
0};
|
0};
|
|
|
vpi_register_systf(&data);
|
vpi_register_systf(&data);
|
|
|
return;
|
return;
|
}
|
}
|
|
|
void register_get_command_address() {
|
void register_get_command_address() {
|
s_vpi_systf_data data = {vpiSysTask,
|
s_vpi_systf_data data = {vpiSysTask,
|
0,
|
0,
|
"$get_command_address",
|
"$get_command_address",
|
(void *)get_command_address,
|
(void *)get_command_address,
|
0,
|
0,
|
0,
|
0,
|
0};
|
0};
|
|
|
vpi_register_systf(&data);
|
vpi_register_systf(&data);
|
|
|
return;
|
return;
|
}
|
}
|
|
|
void register_get_command_data() {
|
void register_get_command_data() {
|
s_vpi_systf_data data = {vpiSysTask,
|
s_vpi_systf_data data = {vpiSysTask,
|
0,
|
0,
|
"$get_command_data",
|
"$get_command_data",
|
(void *)get_command_data,
|
(void *)get_command_data,
|
0,
|
0,
|
0,
|
0,
|
0};
|
0};
|
|
|
vpi_register_systf(&data);
|
vpi_register_systf(&data);
|
|
|
return;
|
return;
|
}
|
}
|
|
|
void register_get_command_block_data() {
|
void register_get_command_block_data() {
|
s_vpi_systf_data data = {vpiSysTask,
|
s_vpi_systf_data data = {vpiSysTask,
|
0,
|
0,
|
"$get_command_block_data",
|
"$get_command_block_data",
|
(void *)get_command_block_data,
|
(void *)get_command_block_data,
|
0,
|
0,
|
0,
|
0,
|
0};
|
0};
|
|
|
vpi_register_systf(&data);
|
vpi_register_systf(&data);
|
|
|
return;
|
return;
|
}
|
}
|
|
|
|
|
void register_return_command_block_data() {
|
void register_return_command_block_data() {
|
s_vpi_systf_data data = {vpiSysTask,
|
s_vpi_systf_data data = {vpiSysTask,
|
0,
|
0,
|
"$return_command_block_data",
|
"$return_command_block_data",
|
(void *)return_command_block_data,
|
(void *)return_command_block_data,
|
0,
|
0,
|
0,
|
0,
|
0};
|
0};
|
|
|
vpi_register_systf(&data);
|
vpi_register_systf(&data);
|
|
|
return;
|
return;
|
}
|
}
|
|
|
void register_return_command_data() {
|
void register_return_command_data() {
|
s_vpi_systf_data data = {vpiSysTask,
|
s_vpi_systf_data data = {vpiSysTask,
|
0,
|
0,
|
"$return_command_data",
|
"$return_command_data",
|
(void *)return_command_data,
|
(void *)return_command_data,
|
0,
|
0,
|
0,
|
0,
|
0};
|
0};
|
|
|
vpi_register_systf(&data);
|
vpi_register_systf(&data);
|
|
|
return;
|
return;
|
}
|
}
|
|
|
void register_return_response() {
|
void register_return_response() {
|
s_vpi_systf_data data = {vpiSysTask,
|
s_vpi_systf_data data = {vpiSysTask,
|
0,
|
0,
|
"$return_response",
|
"$return_response",
|
(void *)return_response,
|
(void *)return_response,
|
0,
|
0,
|
0,
|
0,
|
0};
|
0};
|
|
|
vpi_register_systf(&data);
|
vpi_register_systf(&data);
|
|
|
return;
|
return;
|
}
|
}
|
|
|
|
|
void setup_reset_callbacks()
|
void setup_reset_callbacks()
|
{
|
{
|
|
|
// here we setup and install callbacks for
|
// here we setup and install callbacks for
|
// the setup and management of connections to
|
// the setup and management of connections to
|
// the simulator upon simulation start and
|
// the simulator upon simulation start and
|
// reset
|
// reset
|
|
|
static s_vpi_time time_s = {vpiScaledRealTime};
|
static s_vpi_time time_s = {vpiScaledRealTime};
|
static s_vpi_value value_s = {vpiBinStrVal};
|
static s_vpi_value value_s = {vpiBinStrVal};
|
static s_cb_data cb_data_s =
|
static s_cb_data cb_data_s =
|
{
|
{
|
cbEndOfReset, // or start of simulation - initing socket fds etc
|
cbEndOfReset, // or start of simulation - initing socket fds etc
|
(void *)sim_reset_callback,
|
(void *)sim_reset_callback,
|
NULL,
|
NULL,
|
&time_s,
|
&time_s,
|
&value_s
|
&value_s
|
};
|
};
|
|
|
cb_data_s.obj = NULL; /* trigger object */
|
cb_data_s.obj = NULL; /* trigger object */
|
|
|
cb_data_s.user_data = NULL;
|
cb_data_s.user_data = NULL;
|
|
|
// actual call to register the callback
|
// actual call to register the callback
|
vpi_register_cb(&cb_data_s);
|
vpi_register_cb(&cb_data_s);
|
|
|
}
|
}
|
|
|
void sim_reset_callback()
|
void sim_reset_callback()
|
{
|
{
|
|
|
// nothing to do!
|
// nothing to do!
|
|
|
return;
|
return;
|
|
|
}
|
}
|
|
|
void setup_endofcompile_callbacks()
|
void setup_endofcompile_callbacks()
|
{
|
{
|
|
|
// here we setup and install callbacks for
|
// here we setup and install callbacks for
|
// simulation finish
|
// simulation finish
|
|
|
static s_vpi_time time_s = {vpiScaledRealTime};
|
static s_vpi_time time_s = {vpiScaledRealTime};
|
static s_vpi_value value_s = {vpiBinStrVal};
|
static s_vpi_value value_s = {vpiBinStrVal};
|
static s_cb_data cb_data_s =
|
static s_cb_data cb_data_s =
|
{
|
{
|
cbEndOfCompile, // end of compile
|
cbEndOfCompile, // end of compile
|
(void *)sim_endofcompile_callback,
|
(void *)sim_endofcompile_callback,
|
NULL,
|
NULL,
|
&time_s,
|
&time_s,
|
&value_s
|
&value_s
|
};
|
};
|
|
|
cb_data_s.obj = NULL; /* trigger object */
|
cb_data_s.obj = NULL; /* trigger object */
|
|
|
cb_data_s.user_data = NULL;
|
cb_data_s.user_data = NULL;
|
|
|
// actual call to register the callback
|
// actual call to register the callback
|
vpi_register_cb(&cb_data_s);
|
vpi_register_cb(&cb_data_s);
|
|
|
}
|
}
|
|
|
void sim_endofcompile_callback()
|
void sim_endofcompile_callback()
|
{
|
{
|
// Init the RSP server
|
// Init the RSP server
|
init_rsp_server(); // Start the RSP server from here!
|
init_rsp_server(); // Start the RSP server from here!
|
|
|
}
|
}
|
|
|
|
|
void setup_finish_callbacks()
|
void setup_finish_callbacks()
|
{
|
{
|
|
|
// here we setup and install callbacks for
|
// here we setup and install callbacks for
|
// simulation finish
|
// simulation finish
|
|
|
static s_vpi_time time_s = {vpiScaledRealTime};
|
static s_vpi_time time_s = {vpiScaledRealTime};
|
static s_vpi_value value_s = {vpiBinStrVal};
|
static s_vpi_value value_s = {vpiBinStrVal};
|
static s_cb_data cb_data_s =
|
static s_cb_data cb_data_s =
|
{
|
{
|
cbEndOfSimulation, // end of simulation
|
cbEndOfSimulation, // end of simulation
|
(void *)sim_finish_callback,
|
(void *)sim_finish_callback,
|
NULL,
|
NULL,
|
&time_s,
|
&time_s,
|
&value_s
|
&value_s
|
};
|
};
|
|
|
cb_data_s.obj = NULL; /* trigger object */
|
cb_data_s.obj = NULL; /* trigger object */
|
|
|
cb_data_s.user_data = NULL;
|
cb_data_s.user_data = NULL;
|
|
|
// actual call to register the callback
|
// actual call to register the callback
|
vpi_register_cb(&cb_data_s);
|
vpi_register_cb(&cb_data_s);
|
|
|
}
|
}
|
|
|
void sim_finish_callback()
|
void sim_finish_callback()
|
{
|
{
|
printf("Closing RSP server\n");
|
printf("Closing RSP server\n");
|
// Close down the child process, if it hasn't already
|
// Close down the child process, if it hasn't already
|
kill(rsp_server_child_pid,SIGTERM);
|
kill(rsp_server_child_pid,SIGTERM);
|
}
|
}
|
|
|
|
|
|
|
// Register the new system task here
|
// Register the new system task here
|
void (*vlog_startup_routines[ ] ) () = {
|
void (*vlog_startup_routines[ ] ) () = {
|
register_init_rsp_server_functions,
|
register_init_rsp_server_functions,
|
#ifdef CDS_VPI
|
#ifdef CDS_VPI
|
// this installs a callback on simulator reset - something which
|
// this installs a callback on simulator reset - something which
|
// icarus does not do, so we only do it for cadence currently
|
// icarus does not do, so we only do it for cadence currently
|
setup_reset_callbacks,
|
setup_reset_callbacks,
|
#endif
|
#endif
|
setup_endofcompile_callbacks,
|
setup_endofcompile_callbacks,
|
setup_finish_callbacks,
|
setup_finish_callbacks,
|
register_check_for_command,
|
register_check_for_command,
|
register_get_command_address,
|
register_get_command_address,
|
register_get_command_data,
|
register_get_command_data,
|
register_get_command_block_data,
|
register_get_command_block_data,
|
register_return_command_data,
|
register_return_command_data,
|
register_return_command_block_data,
|
register_return_command_block_data,
|
register_return_response,
|
register_return_response,
|
0 // last entry must be 0
|
0 // last entry must be 0
|
};
|
};
|
|
|
|
|
|
|
// Entry point for testing development of the vpi functions
|
// Entry point for testing development of the vpi functions
|
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
{
|
{
|
|
|
return 0;
|
return 0;
|
|
|
}
|
}
|
|
|
|
|
|
|
|
|