/* vapi.c -- Verification API Interface
|
/* vapi.c -- Verification API Interface
|
Copyright (C) 2001, Marko Mlinar, markom@opencores.org
|
Copyright (C) 2001, Marko Mlinar, markom@opencores.org
|
|
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
|
|
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
(at your option) any later version.
|
(at your option) any later version.
|
|
|
This program is distributed in the hope that it will be useful,
|
This program 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
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU General Public License for more details.
|
GNU General Public License for more details.
|
|
|
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
#include "config.h"
|
#include "config.h"
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <ctype.h>
|
#include <ctype.h>
|
#include <string.h>
|
#include <string.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <unistd.h>
|
#include <unistd.h>
|
#include <stdarg.h>
|
#include <stdarg.h>
|
#include <signal.h>
|
#include <signal.h>
|
#include <errno.h>
|
#include <errno.h>
|
|
|
/* Added by CZ 24/05/01 */
|
/* Added by CZ 24/05/01 */
|
#include <sys/stat.h>
|
#include <sys/stat.h>
|
#include <sys/types.h>
|
#include <sys/types.h>
|
#include <sys/socket.h>
|
#include <sys/socket.h>
|
#include <netinet/in.h>
|
#include <netinet/in.h>
|
#include <sys/select.h>
|
#include <sys/select.h>
|
#include <sys/poll.h>
|
#include <sys/poll.h>
|
#include <fcntl.h>
|
#include <fcntl.h>
|
#include <netdb.h>
|
#include <netdb.h>
|
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
#include <inttypes.h>
|
#include <inttypes.h>
|
|
|
#include "sim-config.h"
|
#include "sim-config.h"
|
#include "vapi.h"
|
#include "vapi.h"
|
|
|
static unsigned int serverIP = 0;
|
static unsigned int serverIP = 0;
|
|
|
static unsigned int server_fd = 0;
|
static unsigned int server_fd = 0;
|
static unsigned int nhandlers = 0;
|
static unsigned int nhandlers = 0;
|
|
|
static int tcp_level = 0;
|
static int tcp_level = 0;
|
|
|
static struct vapi_handler {
|
static struct vapi_handler {
|
int fd;
|
int fd;
|
unsigned long id;
|
unsigned long base_id, num_ids;
|
void (*read_func)(unsigned long, unsigned long);
|
void (*read_func)(unsigned long, unsigned long);
|
struct vapi_handler *next;
|
struct vapi_handler *next;
|
int temp;
|
int temp;
|
} *vapi_handler = NULL;
|
} *vapi_handler = NULL;
|
|
|
/* Structure for polling, it is cached, that it doesn't have to be rebuilt each time */
|
/* Structure for polling, it is cached, that it doesn't have to be rebuilt each time */
|
static struct pollfd *fds = NULL;
|
static struct pollfd *fds = NULL;
|
static int nfds = 0;
|
static int nfds = 0;
|
|
|
/* Rebuilds the fds structures; see fds. */
|
/* Rebuilds the fds structures; see fds. */
|
void rebuild_fds () {
|
void rebuild_fds () {
|
struct vapi_handler *t;
|
struct vapi_handler *t;
|
if (fds)
|
if (fds)
|
free (fds);
|
free (fds);
|
fds = (struct pollfd *) malloc (sizeof (struct pollfd) * (nhandlers + 1));
|
fds = (struct pollfd *) malloc (sizeof (struct pollfd) * (nhandlers + 1));
|
if (!fds) {
|
if (!fds) {
|
fprintf (stderr, "FATAL: Out of memory.\n");
|
fprintf (stderr, "FATAL: Out of memory.\n");
|
exit (1);
|
exit (1);
|
}
|
}
|
|
|
nfds = 0;
|
nfds = 0;
|
fds[nfds].fd = server_fd;
|
fds[nfds].fd = server_fd;
|
fds[nfds].events = POLLIN;
|
fds[nfds].events = POLLIN;
|
fds[nfds++].revents = 0;
|
fds[nfds++].revents = 0;
|
|
|
for (t = vapi_handler; t; t = t->next) {
|
for (t = vapi_handler; t; t = t->next) {
|
if (t->fd) {
|
if (t->fd) {
|
t->temp = nfds;
|
t->temp = nfds;
|
fds[nfds].fd = t->fd;
|
fds[nfds].fd = t->fd;
|
fds[nfds].events = POLLIN;
|
fds[nfds].events = POLLIN;
|
fds[nfds++].revents = 0;
|
fds[nfds++].revents = 0;
|
} else
|
} else
|
t->temp = -1;
|
t->temp = -1;
|
}
|
}
|
}
|
}
|
|
|
|
/* Determines whether a certain handler handles an ID */
|
|
static inline int handler_fits_id( const struct vapi_handler *t, unsigned long id ) {
|
|
return ((id >= t->base_id) && (id < t->base_id + t->num_ids));
|
|
}
|
|
|
/* Finds a handler with given ID, return it, NULL if not found. */
|
/* Finds a handler with given ID, return it, NULL if not found. */
|
static struct vapi_handler *find_handler (unsigned long id) {
|
static struct vapi_handler *find_handler (unsigned long id) {
|
struct vapi_handler *t = vapi_handler;
|
struct vapi_handler *t = vapi_handler;
|
while (t && t->id != id)
|
while (t && !handler_fits_id (t, id))
|
t = t->next;
|
t = t->next;
|
return t;
|
return t;
|
}
|
}
|
|
|
/* Adds a handler with given id and returns it. */
|
/* Adds a handler with given id and returns it. */
|
static struct vapi_handler *add_handler (unsigned long id) {
|
static struct vapi_handler *add_handler (unsigned long base_id, unsigned long num_ids) {
|
struct vapi_handler **t = &vapi_handler;
|
struct vapi_handler **t = &vapi_handler;
|
struct vapi_handler *tt;
|
struct vapi_handler *tt;
|
while ((*t))
|
while ((*t))
|
t = &(*t)->next;
|
t = &(*t)->next;
|
tt = (struct vapi_handler *)malloc (sizeof (struct vapi_handler));
|
tt = (struct vapi_handler *)malloc (sizeof (struct vapi_handler));
|
tt->next = NULL;
|
tt->next = NULL;
|
tt->id = id;
|
tt->base_id = base_id;
|
|
tt->num_ids = num_ids;
|
tt->read_func = NULL;
|
tt->read_func = NULL;
|
tt->fd = 0;
|
tt->fd = 0;
|
(*t) = tt;
|
(*t) = tt;
|
free (fds);
|
free (fds);
|
fds = NULL;
|
fds = NULL;
|
nhandlers++;
|
nhandlers++;
|
rebuild_fds ();
|
rebuild_fds ();
|
return tt;
|
return tt;
|
}
|
}
|
|
|
void vapi_write_log_file(VAPI_COMMAND command, unsigned long devid, unsigned long data)
|
void vapi_write_log_file(VAPI_COMMAND command, unsigned long devid, unsigned long data)
|
{
|
{
|
if (!runtime.vapi.vapi_file)
|
if (!runtime.vapi.vapi_file)
|
return;
|
return;
|
if (config.vapi.log_device_id && devid <= VAPI_MAX_DEVID)
|
if (!config.vapi.hide_device_id && devid <= VAPI_MAX_DEVID)
|
fprintf (runtime.vapi.vapi_file, "%04x", devid);
|
fprintf (runtime.vapi.vapi_file, "%04x", devid);
|
fprintf (runtime.vapi.vapi_file, "%1x%08x\n", command, data);
|
fprintf (runtime.vapi.vapi_file, "%1x%08x\n", command, data);
|
}
|
}
|
|
|
static int vapi_write_stream(int fd, void* buf, int len)
|
static int vapi_write_stream(int fd, void* buf, int len)
|
{
|
{
|
int n;
|
int n;
|
char* w_buf = (char*)buf;
|
char* w_buf = (char*)buf;
|
struct pollfd block;
|
struct pollfd block;
|
|
|
while(len) {
|
while(len) {
|
if((n = write(fd, w_buf, len)) < 0) {
|
if((n = write(fd, w_buf, len)) < 0) {
|
switch(errno) {
|
switch(errno) {
|
case EWOULDBLOCK: /* or EAGAIN */
|
case EWOULDBLOCK: /* or EAGAIN */
|
/* We've been called on a descriptor marked
|
/* We've been called on a descriptor marked
|
for nonblocking I/O. We better simulate
|
for nonblocking I/O. We better simulate
|
blocking behavior. */
|
blocking behavior. */
|
block.fd = fd;
|
block.fd = fd;
|
block.events = POLLOUT;
|
block.events = POLLOUT;
|
block.revents = 0;
|
block.revents = 0;
|
poll(&block,1,-1);
|
poll(&block,1,-1);
|
continue;
|
continue;
|
case EINTR:
|
case EINTR:
|
continue;
|
continue;
|
case EPIPE:
|
case EPIPE:
|
close(fd);
|
close(fd);
|
fd = 0;
|
fd = 0;
|
return -1;
|
return -1;
|
default:
|
default:
|
return -1;
|
return -1;
|
}
|
}
|
} else {
|
} else {
|
len -= n;
|
len -= n;
|
w_buf += n;
|
w_buf += n;
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static int vapi_read_stream(int fd, void* buf, int len)
|
static int vapi_read_stream(int fd, void* buf, int len)
|
{
|
{
|
int n;
|
int n;
|
char* r_buf = (char*)buf;
|
char* r_buf = (char*)buf;
|
struct pollfd block;
|
struct pollfd block;
|
|
|
while(len) {
|
while(len) {
|
if((n = read(fd,r_buf,len)) < 0) {
|
if((n = read(fd,r_buf,len)) < 0) {
|
switch(errno) {
|
switch(errno) {
|
case EWOULDBLOCK: /* or EAGAIN */
|
case EWOULDBLOCK: /* or EAGAIN */
|
/* We've been called on a descriptor marked
|
/* We've been called on a descriptor marked
|
for nonblocking I/O. We better simulate
|
for nonblocking I/O. We better simulate
|
blocking behavior. */
|
blocking behavior. */
|
block.fd = fd;
|
block.fd = fd;
|
block.events = POLLIN;
|
block.events = POLLIN;
|
block.revents = 0;
|
block.revents = 0;
|
poll(&block,1,-1);
|
poll(&block,1,-1);
|
continue;
|
continue;
|
case EINTR:
|
case EINTR:
|
continue;
|
continue;
|
default:
|
default:
|
return -1;
|
return -1;
|
}
|
}
|
} else if(n == 0) {
|
} else if(n == 0) {
|
close(fd);
|
close(fd);
|
fd = 0;
|
fd = 0;
|
return -1;
|
return -1;
|
} else {
|
} else {
|
len -= n;
|
len -= n;
|
r_buf += n;
|
r_buf += n;
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Added by CZ 24/05/01 */
|
/* Added by CZ 24/05/01 */
|
int get_server_socket(const char* name,const char* proto,int port)
|
int get_server_socket(const char* name,const char* proto,int port)
|
{
|
{
|
struct servent *service;
|
struct servent *service;
|
struct protoent *protocol;
|
struct protoent *protocol;
|
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
struct hostent *hp;
|
struct hostent *hp;
|
int sockfd;
|
int sockfd;
|
char myname[256];
|
char myname[256];
|
int flags;
|
int flags;
|
char sTemp[256];
|
char sTemp[256];
|
|
|
/* First, get the protocol number of TCP */
|
/* First, get the protocol number of TCP */
|
if(!(protocol = getprotobyname(proto))) {
|
if(!(protocol = getprotobyname(proto))) {
|
sprintf(sTemp,"Unable to load protocol \"%s\"",proto);
|
sprintf(sTemp,"Unable to load protocol \"%s\"",proto);
|
perror(sTemp);
|
perror(sTemp);
|
return 0;
|
return 0;
|
}
|
}
|
tcp_level = protocol->p_proto; /* Save for later */
|
tcp_level = protocol->p_proto; /* Save for later */
|
|
|
/* If we weren't passed a non standard port, get the port
|
/* If we weren't passed a non standard port, get the port
|
from the services directory. */
|
from the services directory. */
|
if(!port) {
|
if(!port) {
|
if(service = getservbyname(name,protocol->p_name))
|
if(service = getservbyname(name,protocol->p_name))
|
port = ntohs(service->s_port);
|
port = ntohs(service->s_port);
|
}
|
}
|
|
|
/* Create the socket using the TCP protocol */
|
/* Create the socket using the TCP protocol */
|
if((sockfd = socket(PF_INET,SOCK_STREAM,protocol->p_proto)) < 0) {
|
if((sockfd = socket(PF_INET,SOCK_STREAM,protocol->p_proto)) < 0) {
|
perror("Unable to create socket");
|
perror("Unable to create socket");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
flags = 1;
|
flags = 1;
|
if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(const char*)&flags,sizeof(int)) < 0) {
|
if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(const char*)&flags,sizeof(int)) < 0) {
|
sprintf(sTemp,"Can not set SO_REUSEADDR option on socket %d",sockfd);
|
sprintf(sTemp,"Can not set SO_REUSEADDR option on socket %d",sockfd);
|
perror(sTemp);
|
perror(sTemp);
|
close(sockfd);
|
close(sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* The server should also be non blocking. Get the current flags. */
|
/* The server should also be non blocking. Get the current flags. */
|
if(fcntl(sockfd,F_GETFL,&flags) < 0) {
|
if(fcntl(sockfd,F_GETFL,&flags) < 0) {
|
sprintf(sTemp,"Unable to get flags for socket %d",sockfd);
|
sprintf(sTemp,"Unable to get flags for socket %d",sockfd);
|
perror(sTemp);
|
perror(sTemp);
|
close(sockfd);
|
close(sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Set the nonblocking flag */
|
/* Set the nonblocking flag */
|
if(fcntl(sockfd,F_SETFL, flags | O_NONBLOCK) < 0) {
|
if(fcntl(sockfd,F_SETFL, flags | O_NONBLOCK) < 0) {
|
sprintf(sTemp,"Unable to set flags for socket %d to value 0x%08x",
|
sprintf(sTemp,"Unable to set flags for socket %d to value 0x%08x",
|
sockfd,flags | O_NONBLOCK);
|
sockfd,flags | O_NONBLOCK);
|
perror(sTemp);
|
perror(sTemp);
|
close(sockfd);
|
close(sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Find out what our address is */
|
/* Find out what our address is */
|
memset(&sa,0,sizeof(struct sockaddr_in));
|
memset(&sa,0,sizeof(struct sockaddr_in));
|
gethostname(myname,sizeof(myname));
|
gethostname(myname,sizeof(myname));
|
if(!(hp = gethostbyname(myname))) {
|
if(!(hp = gethostbyname(myname))) {
|
perror("Unable to read hostname");
|
perror("Unable to read hostname");
|
close(sockfd);
|
close(sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Bind our socket to the appropriate address */
|
/* Bind our socket to the appropriate address */
|
sa.sin_family = hp->h_addrtype;
|
sa.sin_family = hp->h_addrtype;
|
sa.sin_port = htons(port);
|
sa.sin_port = htons(port);
|
if(bind(sockfd,(struct sockaddr*)&sa,sizeof(struct sockaddr_in)) < 0) {
|
if(bind(sockfd,(struct sockaddr*)&sa,sizeof(struct sockaddr_in)) < 0) {
|
sprintf(sTemp,"Unable to bind socket %d to port %d",sockfd,port);
|
sprintf(sTemp,"Unable to bind socket %d to port %d",sockfd,port);
|
perror(sTemp);
|
perror(sTemp);
|
close(sockfd);
|
close(sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
serverIP = sa.sin_addr.s_addr;
|
serverIP = sa.sin_addr.s_addr;
|
flags = sizeof(struct sockaddr_in);
|
flags = sizeof(struct sockaddr_in);
|
if(getsockname(sockfd,(struct sockaddr*)&sa,&flags) < 0) {
|
if(getsockname(sockfd,(struct sockaddr*)&sa,&flags) < 0) {
|
sprintf(sTemp,"Unable to get socket information for socket %d",sockfd);
|
sprintf(sTemp,"Unable to get socket information for socket %d",sockfd);
|
perror(sTemp);
|
perror(sTemp);
|
close(sockfd);
|
close(sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
config.vapi.server_port = ntohs(sa.sin_port);
|
config.vapi.server_port = ntohs(sa.sin_port);
|
|
|
/* Set the backlog to 1 connections */
|
/* Set the backlog to 1 connections */
|
if(listen(sockfd,1) < 0) {
|
if(listen(sockfd,1) < 0) {
|
sprintf(sTemp,"Unable to set backlog on socket %d to %d",sockfd,1);
|
sprintf(sTemp,"Unable to set backlog on socket %d to %d",sockfd,1);
|
perror(sTemp);
|
perror(sTemp);
|
close(sockfd);
|
close(sockfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
return sockfd;
|
return sockfd;
|
}
|
}
|
|
|
static void server_request()
|
static void server_request()
|
{
|
{
|
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
struct sockaddr* addr = (struct sockaddr*)&sa;
|
struct sockaddr* addr = (struct sockaddr*)&sa;
|
int n = sizeof(struct sockaddr_in);
|
int n = sizeof(struct sockaddr_in);
|
int fd = accept(server_fd, addr, &n);
|
int fd = accept(server_fd, addr, &n);
|
int on_off = 0; /* Turn off Nagel's algorithm on the socket */
|
int on_off = 0; /* Turn off Nagel's algorithm on the socket */
|
int flags;
|
int flags;
|
char sTemp[256];
|
char sTemp[256];
|
|
|
if(fd < 0) {
|
if(fd < 0) {
|
/* This is valid, because a connection could have started,
|
/* This is valid, because a connection could have started,
|
and then terminated due to a protocol error or user
|
and then terminated due to a protocol error or user
|
initiation before the accept could take place. */
|
initiation before the accept could take place. */
|
if(errno != EWOULDBLOCK && errno != EAGAIN) {
|
if(errno != EWOULDBLOCK && errno != EAGAIN) {
|
perror("accept");
|
perror("accept");
|
close(server_fd);
|
close(server_fd);
|
server_fd = 0;
|
server_fd = 0;
|
config.vapi.enabled = 0;
|
config.vapi.enabled = 0;
|
serverIP = 0;
|
serverIP = 0;
|
}
|
}
|
return;
|
return;
|
}
|
}
|
|
|
if(fcntl(fd,F_GETFL,&flags) < 0) {
|
if(fcntl(fd,F_GETFL,&flags) < 0) {
|
sprintf(sTemp,"Unable to get flags for vapi socket %d",fd);
|
sprintf(sTemp,"Unable to get flags for vapi socket %d",fd);
|
perror(sTemp);
|
perror(sTemp);
|
close(fd);
|
close(fd);
|
return;
|
return;
|
}
|
}
|
|
|
if(fcntl(fd,F_SETFL, flags | O_NONBLOCK) < 0) {
|
if(fcntl(fd,F_SETFL, flags | O_NONBLOCK) < 0) {
|
sprintf(sTemp,"Unable to set flags for vapi socket %d to value 0x%08x",
|
sprintf(sTemp,"Unable to set flags for vapi socket %d to value 0x%08x",
|
fd,flags | O_NONBLOCK);
|
fd,flags | O_NONBLOCK);
|
perror(sTemp);
|
perror(sTemp);
|
close(fd);
|
close(fd);
|
return;
|
return;
|
}
|
}
|
|
|
if(setsockopt(fd,tcp_level,TCP_NODELAY,&on_off,sizeof(int)) < 0) {
|
if(setsockopt(fd,tcp_level,TCP_NODELAY,&on_off,sizeof(int)) < 0) {
|
sprintf(sTemp,"Unable to disable Nagel's algorithm for socket %d.\nsetsockopt",fd);
|
sprintf(sTemp,"Unable to disable Nagel's algorithm for socket %d.\nsetsockopt",fd);
|
perror(sTemp);
|
perror(sTemp);
|
close(fd);
|
close(fd);
|
return;
|
return;
|
}
|
}
|
|
|
/* Install new handler */
|
/* Install new handler */
|
{
|
{
|
unsigned long id;
|
unsigned long id;
|
struct vapi_handler *t;
|
struct vapi_handler *t;
|
if (vapi_read_stream (fd, &id, sizeof (id))) {
|
if (vapi_read_stream (fd, &id, sizeof (id))) {
|
perror ("Cannot get id");
|
perror ("Cannot get id");
|
close (fd);
|
close (fd);
|
return;
|
return;
|
}
|
}
|
t = find_handler (id);
|
t = find_handler (id);
|
if (t) {
|
if (t) {
|
if (t->fd) {
|
if (t->fd) {
|
fprintf (stderr, "WARNING: Test with id %x already connected. Ignoring.\n", id);
|
fprintf (stderr, "WARNING: Test with id %x already connected. Ignoring.\n", id);
|
close (fd);
|
close (fd);
|
return;
|
return;
|
} else {
|
} else {
|
t->fd = fd;
|
t->fd = fd;
|
rebuild_fds ();
|
rebuild_fds ();
|
}
|
}
|
} else {
|
} else {
|
fprintf (stderr, "WARNING: Test with id %x not registered. Ignoring.\n", id);
|
fprintf (stderr, "WARNING: Test with id %x not registered. Ignoring.\n", id);
|
close(fd); /* kill the connection */
|
close(fd); /* kill the connection */
|
return;
|
return;
|
}
|
}
|
if(config.sim.verbose)
|
if(config.sim.verbose)
|
printf ("\nConnection with test (id %x) established.\n", id);
|
printf ("\nConnection with test (id %x) established.\n", id);
|
}
|
}
|
}
|
}
|
|
|
static int write_packet (unsigned long id, unsigned long data) {
|
static int write_packet (unsigned long id, unsigned long data) {
|
struct vapi_handler *t = find_handler (id);
|
struct vapi_handler *t = find_handler (id);
|
if (!t || !t->fd)
|
if (!t || !t->fd)
|
return 1;
|
return 1;
|
id = htonl (id);
|
id = htonl (id);
|
if (vapi_write_stream(t->fd, &id, sizeof (id)) < 0)
|
if (vapi_write_stream(t->fd, &id, sizeof (id)) < 0)
|
return 1;
|
return 1;
|
data = htonl (data);
|
data = htonl (data);
|
if (vapi_write_stream(t->fd, &data, sizeof (data)) < 0)
|
if (vapi_write_stream(t->fd, &data, sizeof (data)) < 0)
|
return 1;
|
return 1;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static int read_packet (int fd, unsigned long *id, unsigned long *data)
|
static int read_packet (int fd, unsigned long *id, unsigned long *data)
|
{
|
{
|
if (fd <= 0)
|
if (fd <= 0)
|
return 1;
|
return 1;
|
if (vapi_read_stream(fd, id, sizeof(unsigned long)) < 0)
|
if (vapi_read_stream(fd, id, sizeof(unsigned long)) < 0)
|
return 1;
|
return 1;
|
*id = ntohl (*id);
|
*id = ntohl (*id);
|
if (vapi_read_stream(fd, data, sizeof(unsigned long)) < 0)
|
if (vapi_read_stream(fd, data, sizeof(unsigned long)) < 0)
|
return 1;
|
return 1;
|
*data = ntohl (*data);
|
*data = ntohl (*data);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static void vapi_request (struct vapi_handler *t)
|
static void vapi_request (struct vapi_handler *t)
|
{
|
{
|
unsigned long id, data;
|
unsigned long id, data;
|
|
|
if (read_packet(t->fd, &id, &data)) {
|
if (read_packet(t->fd, &id, &data)) {
|
if (t->fd >= 0) {
|
if (t->fd > 0) {
|
perror("vapi read");
|
perror("vapi read");
|
close(t->fd);
|
close(t->fd);
|
t->fd = 0;
|
t->fd = 0;
|
rebuild_fds ();
|
rebuild_fds ();
|
}
|
}
|
return;
|
return;
|
}
|
}
|
|
|
vapi_write_log_file (VAPI_COMMAND_REQUEST, id, data);
|
vapi_write_log_file (VAPI_COMMAND_REQUEST, id, data);
|
debug (4, "[%08x, %08x]\n", id, data);
|
debug (4, "[%08x, %08x]\n", id, data);
|
|
|
/* This packet may be for another handler */
|
/* This packet may be for another handler */
|
if (t->id != id)
|
if (!handler_fits_id (t, id))
|
t = find_handler (id);
|
t = find_handler (id);
|
if (!t || !t->read_func)
|
if (!t || !t->read_func)
|
fprintf (stderr, "WARNING: Received packet for undefined id %08x, data %08x\n", id, data);
|
fprintf (stderr, "WARNING: Received packet for undefined id %08x, data %08x\n", id, data);
|
else
|
else
|
t->read_func(id, data);
|
t->read_func(id, data);
|
}
|
}
|
|
|
void vapi_check ()
|
void vapi_check ()
|
{
|
{
|
struct vapi_handler *t;
|
struct vapi_handler *t;
|
|
|
if (!server_fd || !fds) {
|
if (!server_fd || !fds) {
|
fprintf (stderr, "FATAL: Unable to maintain VAPI server.\n");
|
fprintf (stderr, "FATAL: Unable to maintain VAPI server.\n");
|
exit (1);
|
exit (1);
|
}
|
}
|
|
|
debug(5, ".");
|
debug(5, ".");
|
|
|
/* Handle everything in queue. */
|
/* Handle everything in queue. */
|
while(1) {
|
while(1) {
|
switch(poll(fds, nfds, 0)) {
|
switch(poll(fds, nfds, 0)) {
|
case -1:
|
case -1:
|
if(errno == EINTR)
|
if(errno == EINTR)
|
continue;
|
continue;
|
perror("poll");
|
perror("poll");
|
if (server_fd)
|
if (server_fd)
|
close(server_fd);
|
close(server_fd);
|
config.vapi.enabled = 0;
|
config.vapi.enabled = 0;
|
serverIP = 0;
|
serverIP = 0;
|
return;
|
return;
|
case 0: /* Nothing interesting going on */
|
case 0: /* Nothing interesting going on */
|
return;
|
return;
|
default:
|
default:
|
/* Handle the vapi ports first. */
|
/* Handle the vapi ports first. */
|
for (t = vapi_handler; t; t = t->next)
|
for (t = vapi_handler; t; t = t->next)
|
if (t->temp >= 0 && fds[t->temp].revents)
|
if (t->temp >= 0 && fds[t->temp].revents)
|
vapi_request (t);
|
vapi_request (t);
|
|
|
if(fds[0].revents) {
|
if(fds[0].revents) {
|
if(fds[0].revents & POLLIN)
|
if(fds[0].revents & POLLIN)
|
server_request();
|
server_request();
|
else { /* Error Occurred */
|
else { /* Error Occurred */
|
fprintf(stderr,"Received flags 0x%08x on server. Shutting down.\n", fds[0].revents);
|
fprintf(stderr,"Received flags 0x%08x on server. Shutting down.\n", fds[0].revents);
|
if (server_fd)
|
if (server_fd)
|
close(server_fd);
|
close(server_fd);
|
server_fd = 0;
|
server_fd = 0;
|
config.vapi.enabled = 0;
|
config.vapi.enabled = 0;
|
serverIP = 0;
|
serverIP = 0;
|
}
|
}
|
}
|
}
|
break;
|
break;
|
} /* End of switch statement */
|
} /* End of switch statement */
|
} /* End of while statement */
|
} /* End of while statement */
|
}
|
}
|
|
|
/* Inits the VAPI, according to sim-config */
|
/* Inits the VAPI, according to sim-config */
|
int vapi_init ()
|
int vapi_init ()
|
{
|
{
|
nhandlers = 0;
|
nhandlers = 0;
|
vapi_handler = NULL;
|
vapi_handler = NULL;
|
if (!config.vapi.enabled)
|
if (!config.vapi.enabled)
|
return 0; /* Nothing to do */
|
return 0; /* Nothing to do */
|
|
|
if (!config.vapi.server_port) {
|
if (!config.vapi.server_port) {
|
fprintf (stderr, "WARNING: server_port = 0, shutting down VAPI\n");
|
fprintf (stderr, "WARNING: server_port = 0, shutting down VAPI\n");
|
config.vapi.enabled = 0;
|
config.vapi.enabled = 0;
|
return 1;
|
return 1;
|
}
|
}
|
if (server_fd = get_server_socket("or1ksim", "tcp", config.vapi.server_port))
|
if (server_fd = get_server_socket("or1ksim", "tcp", config.vapi.server_port))
|
printf("VAPI Server started on port %d\n", config.vapi.server_port);
|
printf("VAPI Server started on port %d\n", config.vapi.server_port);
|
else {
|
else {
|
perror ("Connection");
|
perror ("Connection");
|
return 1;
|
return 1;
|
}
|
}
|
|
|
rebuild_fds ();
|
rebuild_fds ();
|
|
|
if ((runtime.vapi.vapi_file = fopen (config.vapi.vapi_fn, "wt+")) == NULL)
|
if ((runtime.vapi.vapi_file = fopen (config.vapi.vapi_fn, "wt+")) == NULL)
|
fprintf (stderr, "WARNING: cannot open VAPI log file\n");
|
fprintf (stderr, "WARNING: cannot open VAPI log file\n");
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Closes the VAPI */
|
/* Closes the VAPI */
|
void vapi_done ()
|
void vapi_done ()
|
{
|
{
|
int i;
|
int i;
|
struct vapi_handler *t = vapi_handler;
|
struct vapi_handler *t = vapi_handler;
|
|
|
for (i = 0; i < nfds; i++)
|
for (i = 0; i < nfds; i++)
|
if (fds[i].fd)
|
if (fds[i].fd)
|
close (fds[i].fd);
|
close (fds[i].fd);
|
server_fd = 0;
|
server_fd = 0;
|
config.vapi.enabled = 0;
|
config.vapi.enabled = 0;
|
serverIP = 0;
|
serverIP = 0;
|
free (fds);
|
free (fds);
|
fds = 0;
|
fds = 0;
|
if (runtime.vapi.vapi_file) {
|
if (runtime.vapi.vapi_file) {
|
/* Mark end of simulation */
|
/* Mark end of simulation */
|
vapi_write_log_file (VAPI_COMMAND_END, 0, 0);
|
vapi_write_log_file (VAPI_COMMAND_END, 0, 0);
|
fclose (runtime.vapi.vapi_file);
|
fclose (runtime.vapi.vapi_file);
|
}
|
}
|
|
|
while (vapi_handler) {
|
while (vapi_handler) {
|
t = vapi_handler;
|
t = vapi_handler;
|
vapi_handler = vapi_handler->next;
|
vapi_handler = vapi_handler->next;
|
free (t);
|
free (t);
|
}
|
}
|
}
|
}
|
|
|
/* Installs a vapi handler to VAPI id */
|
/* Installs a vapi handler for one VAPI id */
|
void vapi_install_handler (unsigned long id, void (*read_func) (unsigned long, unsigned long))
|
void vapi_install_handler (unsigned long id, void (*read_func) (unsigned long, unsigned long))
|
{
|
{
|
|
vapi_install_multi_handler (id, 1, read_func);
|
|
}
|
|
|
|
/* Installs a vapi handler for many VAPI id */
|
|
void vapi_install_multi_handler (unsigned long base_id, unsigned long num_ids, void (*read_func) (unsigned long, unsigned long))
|
|
{
|
struct vapi_handler *tt;
|
struct vapi_handler *tt;
|
|
|
debug(4, "vapi_install_handler %08x, %08x\n", id, read_func);
|
debug(4, "vapi_install_handler %08x, %u, %08x\n", base_id, num_ids, read_func);
|
if (read_func == NULL) {
|
if (read_func == NULL) {
|
struct vapi_handler **t = &vapi_handler;
|
struct vapi_handler **t = &vapi_handler;
|
while ((*t) && (*t)->id != id)
|
while ((*t) && !handler_fits_id (*t, base_id))
|
t = &(*t)->next;
|
t = &(*t)->next;
|
if (!t) {
|
if (!t) {
|
fprintf (stderr, "Cannot uninstall VAPI read handler from id %x\n", id);
|
fprintf (stderr, "Cannot uninstall VAPI read handler from id %x\n", base_id);
|
exit (1);
|
exit (1);
|
}
|
}
|
tt = *t;
|
tt = *t;
|
(*t) = (*t)->next;
|
(*t) = (*t)->next;
|
free (tt);
|
free (tt);
|
nhandlers--;
|
nhandlers--;
|
} else {
|
} else {
|
tt = find_handler (id);
|
tt = find_handler (base_id);
|
if (!tt) {
|
if (!tt) {
|
tt = add_handler (id);
|
tt = add_handler (base_id, num_ids);
|
tt->read_func = read_func;
|
tt->read_func = read_func;
|
} else {
|
} else {
|
tt->read_func = read_func;
|
tt->read_func = read_func;
|
rebuild_fds ();
|
rebuild_fds ();
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/* Returns number of unconnected handles. */
|
/* Returns number of unconnected handles. */
|
int vapi_num_unconnected (int printout)
|
int vapi_num_unconnected (int printout)
|
{
|
{
|
struct vapi_handler *t = vapi_handler;
|
struct vapi_handler *t = vapi_handler;
|
int numu = 0;
|
int numu = 0;
|
for (; t; t = t->next) {
|
for (; t; t = t->next) {
|
if (!t->fd) {
|
if (!t->fd) {
|
numu++;
|
numu++;
|
if (printout) printf (" 0x%x", t->id);
|
if (printout) {
|
|
if ( t->num_ids == 1 )
|
|
printf (" 0x%x", t->base_id);
|
|
else
|
|
printf (" 0x%x..0x%x", t->base_id, t->base_id + t->num_ids - 1);
|
|
}
|
}
|
}
|
}
|
}
|
return numu;
|
return numu;
|
}
|
}
|
|
|
/* Sends a packet to specified test */
|
/* Sends a packet to specified test */
|
int vapi_send (unsigned long id, unsigned long data)
|
int vapi_send (unsigned long id, unsigned long data)
|
{
|
{
|
debug (4, "vapi_send [%08x %08x]\n", id, data);
|
debug (4, "vapi_send [%08x %08x]\n", id, data);
|
vapi_write_log_file (VAPI_COMMAND_SEND, id, data);
|
vapi_write_log_file (VAPI_COMMAND_SEND, id, data);
|
write_packet (id, data);
|
write_packet (id, data);
|
}
|
}
|
|
|
/*
|
/*
|
int main ()
|
int main ()
|
{
|
{
|
config.vapi.enabled = 1;
|
config.vapi.enabled = 1;
|
config.vapi.server_port = 9999;
|
config.vapi.server_port = 9999;
|
vapi_init ();
|
vapi_init ();
|
while (1) {
|
while (1) {
|
vapi_check();
|
vapi_check();
|
usleep(1);
|
usleep(1);
|
}
|
}
|
vapi_done ();
|
vapi_done ();
|
}*/
|
}*/
|
|
|