//============================================================================== // FLI TX/RX UART Interface // // Set up socket, transmit/receive string to/from UART. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This library 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 Lesser General Public // License for more details. See http://www.gnu.org/copyleft/lesser.txt // //------------------------------------------------------------------------------ // Version Author Date Changes // 0.1 Hans Tiggeler 03 Aug 2003 Tested on Modelsim SE 5.7e //============================================================================== #include <stdio.h> #include <math.h> #include <fcntl.h> #include <sys/types.h> #include <stdlib.h> #include <string.h> #include <mti.h> // MTI Headers & Prototypes //========================== Sockets Definitions ====================== #define WIN32 #define ASK_SERVER_NAME #ifndef ASK_SERVER_NAME #define PORTNUMBER 2000 #define SERVERNAME "achilles" #endif #ifdef WIN32 #include <winsock.h> #else #include <unistd.h> #include <sys/time.h> #include <sys/param.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> // defines gethostbyname() #endif #ifdef WIN32 #define MAXHOSTNAMELEN MAXGETHOSTSTRUCT #else #define SOCKET_ERROR -1 #define INVALID_SOCKET -1 #define NO_ERROR 0 typedef int SOCKET; #endif #define MAXBUFFER 64 // Maximum number of characters per packet typedef enum { // std_logic enumerated type STD_LOGIC_U, STD_LOGIC_X, STD_LOGIC_0, STD_LOGIC_1, STD_LOGIC_Z, STD_LOGIC_W, STD_LOGIC_L, STD_LOGIC_H, STD_LOGIC_D } StdLogicType; typedef struct { // Entity ports mtiSignalIdT clk ; mtiSignalIdT resetn; mtiSignalIdT tdre; // '1' if ready to transmit mtiSignalIdT rdrf; // '1' if character received mtiSignalIdT dbusout; // RX databus mtiDriverIdT wr; mtiDriverIdT rd; mtiSignalIdT dbusin; // TX databus mtiDriverIdT * drv_elems; SOCKET sd; // Socket Descriptor SOCKET sd_current; // Socket Descriptor } inst_rec; int debug=0; // set to 1 to enable debug //char rxchar; // Receive character //int rxflag=0; // Receive character flag (!=0 if char received) int tx_in_progress=0; // TX character in progress int rx_in_progress=0; // RX character in progress int quit=0; // set to !0 to quit char *buffer; // Receive buffer (FIFO) int fifocount=0; int rdptr=0; // Read Pointer int wrptr=0; // Write Pointer // Prototypes static void tx_fli(void *param); // From terminal to UART static void rx_fli(void *param); // From UART to terminal int init_sockets(char *hostname, int port, inst_rec *ip); int send_packet(SOCKET sd,char *msg,int msg_size); int rec_packet(SOCKET sd, char *msg, int msg_size); void close_socket(inst_rec *ip); static long char2stdlogic(char value); char * stdlogic2char(char sigval); mtiUInt32T conv_std_logic_vector(mtiSignalIdT stdvec); void drive_stdlogicvector(mtiSignalIdT bus, mtiDriverIdT * drivers, char *strarray, mtiDelayT delay); void sockCB(void * sock ); // Receive socket callback void loadDoneCB(void * sock); // Add socket callback void restartCallback(void *param); // User types quit/restart char * char2str(char ch); // Convert char to boolean string void cif_init( mtiRegionIdT region, char *param, mtiInterfaceListT *generics, mtiInterfaceListT *ports) { inst_rec *ip; // Declare ports mtiProcessIdT rxproc,txproc; // current process id char str[80]; // used for stdinput char hostname[80]; int port=2000; mtiDriverIdT drvid; ip = (inst_rec *)mti_Malloc(sizeof(inst_rec)); // allocate memory for ports mti_AddRestartCB(mti_Free, ip); // restart entry point ip->clk = mti_FindPort(ports, "clk"); // Get entity ports ip->resetn = mti_FindPort(ports, "resetn"); ip->tdre = mti_FindPort(ports, "tdre"); ip->rdrf = mti_FindPort(ports, "rdrf"); ip->wr = mti_CreateDriver(mti_FindPort(ports, "wr")); ip->rd = mti_CreateDriver(mti_FindPort(ports, "rd")); ip->dbusout = mti_FindPort(ports, "dbusout"); ip->dbusin = mti_FindPort(ports, "dbusin"); drvid = mti_CreateDriver(ip->dbusin); ip->drv_elems=mti_GetDriverSubelements(drvid, 0); rxproc = mti_CreateProcess("rx_fli", rx_fli, ip); mti_Sensitize(rxproc, ip->clk, MTI_EVENT); // Add sensitivity signals mti_Sensitize(rxproc, ip->resetn, MTI_EVENT); txproc = mti_CreateProcess("tx_fli", tx_fli, ip); mti_Sensitize(txproc, ip->clk, MTI_EVENT); // Add sensitivity signals mti_Sensitize(txproc, ip->resetn, MTI_EVENT); // Ask the user for the machinename & portnumber #ifdef ASK_SERVER_NAME mti_AskStdin(str,"\nEnter hostname:"); strcpy(hostname,str); mti_AskStdin(str,"Enter port id:"); port=atoi(str); #else // Use fixed server and portnumber strcpy(hostname,SERVERNAME); port=PORTNUMBER; #endif mti_PrintFormatted("Opening socket %d on %s\nWaiting for connection.....\n",port,hostname); if ((init_sockets(hostname,port,ip))==SOCKET_ERROR) { // Get socket descriptor mti_PrintMessage("*** Socket init error ***\n"); mti_FatalError(); // Do not continue if fail } // Allocate memory for Receive buffer if ((buffer=(char *)mti_Malloc(MAXBUFFER*sizeof(char)))==NULL) { mti_PrintMessage("*** MTI Memory Allocation Failure for Receive Buffer***\n"); mti_FatalError(); // Do not continue } mti_AddQuitCB(restartCallback, ip); mti_AddRestartCB(restartCallback, ip); // Add quit or restart CallBack mti_AddLoadDoneCB((mtiVoidFuncPtrT)loadDoneCB, (void *)ip->sd_current); if (debug) mti_PrintMessage("\ncif_init (socket version) called\n"); } void restartCallback(void *param) // User types quit/restart { fifocount=0; // Receive character flag (!=0 if char received) rdptr=0; // Read Pointer wrptr=0; // Write Pointer tx_in_progress=0; rx_in_progress=0; close_socket(param); free(param); } static void rx_fli(void *param) // from uart to terminal (No fifo) { inst_rec * ip = (inst_rec *)param; mtiUInt32T i; if (mti_GetSignalValue(ip->resetn)==STD_LOGIC_0) { // Check reset asserted mti_ScheduleDriver(ip->rd, STD_LOGIC_1, 0, MTI_INERTIAL); // rd<='1'; } else if (mti_GetSignalValue(ip->clk)==STD_LOGIC_1) { // rising edge if (rx_in_progress) { // second rising edge i=conv_std_logic_vector(ip->dbusout); // if 0x03-> CTRL-C if (debug) mti_PrintFormatted("**** UART->TERM %c(%d) ****\n",(char) i,(char) i); send(ip->sd_current,(const char *)(&i),1,0); mti_ScheduleDriver(ip->rd, STD_LOGIC_1, 0, MTI_INERTIAL); // rd<='1'; rx_in_progress=0; } else { if (mti_GetSignalValue(ip->rdrf)==STD_LOGIC_1) { // character pending mti_ScheduleDriver(ip->rd, STD_LOGIC_0, 0, MTI_INERTIAL); // rd<='0' rx_in_progress=1; } } } } static void tx_fli(void *param) // from terminal to uart (Fifo) { inst_rec * ip = (inst_rec *)param; if (mti_GetSignalValue(ip->resetn)==STD_LOGIC_0) { // Check reset mti_ScheduleDriver(ip->wr, STD_LOGIC_1, 0, MTI_INERTIAL); // wr<='1'; drive_stdlogicvector(ip->dbusin, ip->drv_elems, "HHHHHHHH",0); } else if (mti_GetSignalValue(ip->clk)==STD_LOGIC_1) { if (tx_in_progress) { // Transmit in progress wait for tdre to go low mti_ScheduleDriver(ip->wr, STD_LOGIC_1, 0, MTI_INERTIAL); // wr<='1' if (mti_GetSignalValue(ip->tdre)==STD_LOGIC_0) { // WR acknowledged? tx_in_progress=0; } } else { if (fifocount) { // fifo is not empty if (mti_GetSignalValue(ip->tdre)==STD_LOGIC_1) { // Ready to tx? if (debug) mti_PrintFormatted("**** TERM->UART %c(%d) FIFO=%d ****\n",buffer[rdptr],buffer[rdptr],fifocount); mti_ScheduleDriver(ip->wr, STD_LOGIC_0, 0, MTI_INERTIAL); // wr<='0' drive_stdlogicvector(ip->dbusin, ip->drv_elems, char2str(buffer[rdptr]),2); tx_in_progress=1; rdptr=(rdptr+1)%MAXBUFFER; fifocount--; } } } } } void sockCB(void * sock ) // Triggered when socket character available { int i; char rxchar; #ifdef WIN32 i = recv((SOCKET)sock, &rxchar, sizeof(rxchar),0); #else i = read((SOCKET)sock, &rxchar, sizeof(rxchar)); #endif if (i == 0) { // terminate if 0 characters received #ifdef WIN32 mti_AddSocketInputReadyCB((SOCKET)sock, (mtiVoidFuncPtrT)0, 0); #else mti_AddInputReadyCB((SOCKET)sock, (mtiVoidFuncPtrT)0, 0); #endif mti_PrintMessage("Closing socket\n"); close((SOCKET)sock ); } else { if (fifocount==MAXBUFFER) { mti_PrintMessage("*** FIFO FULL ****"); } else { if (debug) mti_PrintFormatted("RX(%d)%c i=%d ",rxchar,rxchar,i); buffer[wrptr]=rxchar; wrptr=(wrptr+1)%MAXBUFFER; fifocount++; } } } char * char2str(char ch) // Convert char to boolean string { int t; unsigned int shift; static char str[9]="HHHHHHHH"; shift=0x80; for (t=0;t<8;t++) { if (ch & (shift >> t)) str[t]='1'; else str[t]='0'; } str[9]='\0'; return str; } int init_sockets(char *hostname, int port, inst_rec *ip) { int statusFlags; int status; int addrlen; struct sockaddr_in sin; struct sockaddr_in pin; struct hostent *hp; // Do some windows stuff, copied from FLI manual #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { mti_PrintMessage("**** Cannot find a useable winsock.dll ***\n" ); return SOCKET_ERROR; } /* Confirm that the Windows Sockets DLL supports 1.1. Note that if * the DLL supports versions greater than 1.1 in addition to 1.1, * it will still return 1.1 in wVersion since that is the version * we requested. */ if ( (LOBYTE( wsaData.wVersion ) != 1) || (HIBYTE( wsaData.wVersion ) != 1) ) { mti_PrintMessage("*** Cannot find a useable winsock.dll ***\n" ); WSACleanup(); return SOCKET_ERROR; } /* The Windows Sockets DLL is acceptable. Proceed. */ #endif // Request Stream socket from OS using default protocol if ((ip->sd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { #ifdef WIN32 DWORD le = GetLastError(); mti_PrintFormatted("*** Error opening socket. Error=%d ***\n", le ); #else mti_PrintMessage("*** Error opening socket ***\n" ); #endif return SOCKET_ERROR; } // get host machine info if ((hp = gethostbyname(hostname)) == 0) { mti_PrintFormatted( "%s: Unknown host.\n", hostname ); close_socket(ip); return SOCKET_ERROR; } // fill in the socket structure with host information memset(&sin, 0, sizeof(sin)); // Clear Structure sin.sin_family = AF_INET; // Specify Address format sin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr; sin.sin_port = htons((unsigned short)port); // set port number // bind the socket to the port number if (bind(ip->sd, (struct sockaddr *) &sin, sizeof(sin)) == -1) { mti_PrintMessage("*** Error: Bind\n"); close_socket(ip); return SOCKET_ERROR; } // Enable connection request on the socket, 5 should be enough :-) if (listen(ip->sd, 5) == -1) { mti_PrintMessage("*** Error: Listen\n"); close_socket(ip); return SOCKET_ERROR; } // Accept connection from client, create new socket for communication addrlen = sizeof(struct sockaddr_in); if ((ip->sd_current = accept(ip->sd, (struct sockaddr *) &pin, &addrlen)) == -1) { mti_PrintMessage("*** Error: Accept\n"); close_socket(ip); return SOCKET_ERROR; } #ifdef WIN32 { unsigned long non_blocking = 1; status = ioctlsocket(ip->sd, FIONBIO, &non_blocking ); if (status == SOCKET_ERROR ) { perror("Setting tx socket status"); } status = ioctlsocket(ip->sd_current, FIONBIO, &non_blocking ); if (status == SOCKET_ERROR ) { perror( "Setting listen socket status" ); } } #else statusFlags = fcntl(ip->sd, F_GETFL ); if ( statusFlags == SOCKET_ERROR ) { perror( "Getting socket status" ); } else { int ctlValue; statusFlags |= O_NONBLOCK; ctlValue = fcntl( ip->sd, F_SETFL, statusFlags ); if (ctlValue == SOCKET_ERROR ) { perror("Setting listen socket status"); } } statusFlags = fcntl(ip->sd_current, F_GETFL ); if ( statusFlags == SOCKET_ERROR ) { perror("Getting listen socket status"); } else { int ctlValue; statusFlags |= O_NONBLOCK; ctlValue = fcntl( ip->sd_current, F_SETFL, statusFlags ); if (ctlValue == SOCKET_ERROR ) { perror("Setting listen socket status"); } } #endif // Display some info mti_PrintFormatted("Server: connect from host %s, port %hd.\n", inet_ntoa (pin.sin_addr), ntohs (pin.sin_port)); return (NO_ERROR); // Return OK } //============================================================================== // Drive std_logic_vector // Example (bus, drvbus,"01110ZZU", 5); // bus<=01110ZZU after 5*time_resolution // Length bus must be equal to length("01110ZZU") //============================================================================== void drive_stdlogicvector(mtiSignalIdT bus, mtiDriverIdT * drivers, char *strarray, mtiDelayT delay) { char * sigval; int i; sigval = (char *)mti_GetArraySignalValue(bus, 0); for (i=0;i<8;i++) { sigval[i]=char2stdlogic(strarray[i]); // set bit to '0'/'1'/'z' etc mti_ScheduleDriver( drivers[i], (long)sigval[i], delay, MTI_INERTIAL ); } } void close_socket(inst_rec *ip) { #ifdef WIN32 closesocket(ip->sd_current); closesocket(ip->sd); #else close(ip->sd_current); close(ip->sd); #endif mti_PrintMessage("**** Socket removed ****\n"); } //============================================================================== // Convert character to StdLogicType // example input 'Z' output STD_LOGIC_Z //============================================================================== static long char2stdlogic(char value) { switch ( value) { // toupper() case 'U': case 'u':return STD_LOGIC_U; case 'X': case 'x':return STD_LOGIC_X; case '0':return STD_LOGIC_0; case '1':return STD_LOGIC_1; case 'Z': case 'z':return STD_LOGIC_Z; case 'W': case 'w':return STD_LOGIC_W; case 'L': case 'l':return STD_LOGIC_L; case 'H': case 'h':return STD_LOGIC_H; case 'D': case 'd':return STD_LOGIC_D; default : { mti_PrintFormatted("*** ERROR: Incorrect input char (%c) in drive_array()\n"); mti_FatalError(); // Do not continue } } } //============================================================================== // Convert StdLogicType to character // example input STD_LOGIC_Z output 'Z' //============================================================================== char * stdlogic2char(char sigval) { char * retval; switch (sigval) { case STD_LOGIC_U: retval = "U"; break; case STD_LOGIC_X: retval = "X"; break; case STD_LOGIC_0: retval = "0"; break; case STD_LOGIC_1: retval = "1"; break; case STD_LOGIC_Z: retval = "Z"; break; case STD_LOGIC_W: retval = "W"; break; case STD_LOGIC_L: retval = "L"; break; case STD_LOGIC_H: retval = "H"; break; case STD_LOGIC_D: retval = "-"; break; default: retval = "?"; break; } return retval; } // Convert std_logic_vector into an integer mtiUInt32T conv_std_logic_vector(mtiSignalIdT stdvec) { mtiSignalIdT * elem_list; mtiTypeIdT sigtype; mtiInt32T i,num_elems; mtiUInt32T retvalue,shift; sigtype = mti_GetSignalType(stdvec); // signal type num_elems = mti_TickLength(sigtype); // Get number of elements // if (debug) mti_PrintFormatted("\nSignal X has %d elements\n",num_elems); elem_list = mti_GetSignalSubelements(stdvec, 0); shift=(mtiUInt32T) pow(2.0,(double)num_elems-1);// start position retvalue=0; for (i=0; i < num_elems; i++ ) { if (mti_GetSignalValue(elem_list[i])==3) { retvalue=retvalue+shift; } shift=shift>>1; } mti_VsimFree(elem_list); return(retvalue); } void loadDoneCB(void * sock) // Add socket callback { mti_PrintMessage("Load Done: Adding socket callback.\n"); #ifdef WIN32 mti_AddSocketInputReadyCB((SOCKET)sock, (mtiVoidFuncPtrT)sockCB, sock); #else mti_AddInputReadyCB((SOCKET)sock, (mtiVoidFuncPtrT)sockCB, sock); #endif }