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