* configure.in, configure: support for winsock2
[fw/sdcc] / debugger / mcs51 / simi.c
1 /*-------------------------------------------------------------------------
2   simi.c - source file for simulator interaction
3         Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
4
5    This program is free software; you can redistribute it and/or modify it
6    under the terms of the GNU General Public License as published by the
7    Free Software Foundation; either version 2, or (at your option) any
8    later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19    In other words, you are welcome to use, share and improve this program.
20    You are forbidden to forbid anyone else to use, share and improve
21    what you give them.   Help stamp out software-hoarding!
22 -------------------------------------------------------------------------*/
23 #include "sdcdb.h"
24 #include "simi.h"
25 #include "newalloc.h"
26
27 #ifdef _WIN32
28 #include <windows.h>
29 #include <winsock2.h>
30 #include <signal.h>
31 #include <io.h>
32 #include <fcntl.h>
33 #else
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <unistd.h>
40 #include <signal.h>
41 #else
42 #error "Cannot build debugger without socket support"
43 #endif
44 #endif
45
46 FILE *simin ; /* stream for simulator input */
47 FILE *simout; /* stream for simulator output */
48
49 #ifdef _WIN32
50 SOCKET sock = INVALID_SOCKET;
51 PROCESS_INFORMATION *simPid = NULL;
52 #else
53 int sock = -1; /* socket descriptor to comm with simulator */
54 pid_t simPid = -1;
55 #endif
56 static char simibuff[MAX_SIM_BUFF];    /* sim buffer       */
57 static char regBuff[MAX_SIM_BUFF];
58 static char *sbp = simibuff;           /* simulator buffer pointer */
59 extern char **environ;
60 char simactive = 0;
61
62 static memcache_t memCache[NMEM_CACHE];
63
64 /*-----------------------------------------------------------------*/
65 /* get data from  memory cache/ load cache from simulator          */
66 /*-----------------------------------------------------------------*/
67 static char *getMemCache(unsigned int addr,int cachenum, int size)
68 {
69     char *resp, *buf;
70     unsigned int laddr;
71     memcache_t *cache = &memCache[cachenum];
72
73     if ( cache->size <=   0 ||
74          cache->addr > addr ||
75          cache->addr + cache->size < addr + size )
76     {
77         if ( cachenum == IMEM_CACHE )
78         {
79             sendSim("di 0x0 0xff\n");
80         }
81         else if ( cachenum == SREG_CACHE )
82         {
83             sendSim("ds 0x80 0xff\n");
84         }
85         else
86         {
87             laddr = addr & 0xffffffc0;
88             sprintf(cache->buffer,"dx 0x%x 0x%x\n",laddr,laddr+0xff );
89             sendSim(cache->buffer);
90         }
91         waitForSim(100,NULL);
92         resp = simResponse();
93         cache->addr = strtol(resp,0,0);
94         buf = cache->buffer;
95         cache->size = 0;
96         while ( *resp && *(resp+1) && *(resp+2))
97         {
98             /* cache is a stringbuffer with ascii data like
99                " 00 00 00 00 00 00 00 00"
100             */
101             resp += 2;
102             laddr = 0;
103             /* skip thru the address part */
104             while (isxdigit(*resp)) resp++;
105             while ( *resp && *resp != '\n')
106             {
107                 if ( laddr < 24 )
108                 {
109                     laddr++ ;
110                     *buf++ = *resp ;
111                 }
112                 resp++;
113             }
114             resp++ ;
115             cache->size += 8;
116         }
117         *buf = '\0';
118         if ( cache->addr > addr ||
119              cache->addr + cache->size < addr + size )
120             return NULL;
121     }
122     return cache->buffer + (addr - cache->addr)*3;
123 }
124
125 /*-----------------------------------------------------------------*/
126 /* invalidate memory cache                                         */
127 /*-----------------------------------------------------------------*/
128 static void invalidateCache( int cachenum )
129 {
130     memCache[cachenum].size = 0;
131 }
132
133 /*-----------------------------------------------------------------*/
134 /* waitForSim - wait till simulator is done its job                */
135 /*-----------------------------------------------------------------*/
136 void waitForSim(int timeout_ms, char *expect)
137 {
138   int i=0;
139   int ch;
140
141 Dprintf(D_simi, ("simi: waitForSim start(%d)\n", timeout_ms));
142     sbp = simibuff;
143
144     while ((ch = fgetc(simin)) > 0 ) {
145       *sbp++ = ch;
146     }
147     *sbp = 0;
148     Dprintf(D_simi, ("waitForSim(%d) got[%s]\n", timeout_ms, simibuff));
149
150 }
151
152 /*-----------------------------------------------------------------*/
153 /* openSimulator - create a pipe to talk to simulator              */
154 /*-----------------------------------------------------------------*/
155 #ifdef _WIN32
156 char *argsToCmdLine(char **args, int nargs)
157 {
158 #define CHUNCK  256
159     int i;
160     int cmdPos = 0;
161     char *cmd = Safe_malloc(CHUNCK);
162     int cmdLen = CHUNCK;
163
164     for (i = 0; i < nargs; i++)
165     {
166         int quote = 0;
167         int argLen = strlen(args[i]);
168
169         if (NULL != strchr(args[i], ' '))
170         {
171             quote = 1;
172             argLen += 2;
173         }
174
175         if (0 < nargs)
176             ++argLen;
177
178         if (argLen >= cmdLen)
179         {
180             do
181             {
182                 cmdLen += cmdLen;
183             }
184             while (argLen >= cmdLen);
185             cmd = Safe_realloc(cmd, cmdLen);
186         }
187
188         if (0 < nargs)
189         {
190             cmd[cmdPos++] = ' ';
191             --argLen;
192         }
193
194         if (quote)
195         {
196             cmd[cmdPos++] = '"';
197             --argLen;
198         }
199
200         memcpy(&cmd[cmdPos], args[i], argLen);
201         cmdPos += argLen;
202
203         if (quote)
204             cmd[cmdPos++] = '"';
205     }
206
207     return cmd;
208 }
209
210 PROCESS_INFORMATION *execSimulator(char **args, int nargs)
211 {
212     STARTUPINFO si;
213     static PROCESS_INFORMATION pi;
214     char *cmdLine = argsToCmdLine(args, nargs);
215
216     memset(&si, 0, sizeof(si));
217     si.cb = sizeof(si);
218     memset(&pi, 0, sizeof(pi));
219
220     // Start the child process.
221     if (!CreateProcess(NULL,   // No module name (use command line)
222         cmdLine, // Command line
223         NULL,           // Process handle not inheritable
224         NULL,           // Thread handle not inheritable
225         FALSE,          // Set handle inheritance to FALSE
226         0,              // No creation flags
227         NULL,           // Use parent's environment block
228         NULL,           // Use parent's starting directory
229         &si,            // Pointer to STARTUPINFO structure
230         &pi)            // Pointer to PROCESS_INFORMATION structure
231     )
232     {
233         Safe_free(cmdLine);
234         printf( "CreateProcess failed (%d).\n", GetLastError() );
235         return NULL;
236     }
237
238     Safe_free(cmdLine);
239     return &pi;
240 }
241
242 void openSimulator (char **args, int nargs)
243 {
244     struct sockaddr_in sin;
245     int retry = 0;
246     int i;
247     int fh;
248     Dprintf(D_simi, ("simi: openSimulator\n"));
249 #ifdef SDCDB_DEBUG
250     if (D_simi & sdcdbDebug)
251     {
252         printf("simi: openSimulator: ");
253         for (i=0; i < nargs; i++ )
254         {
255             printf("arg%d: %s ",i,args[i]);
256         }
257         printf("\n");
258     }
259 #endif
260     invalidateCache(XMEM_CACHE);
261     invalidateCache(IMEM_CACHE);
262     invalidateCache(SREG_CACHE);
263
264  try_connect:
265     sock = WSASocket(PF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
266
267     memset(&sin,0,sizeof(sin));
268     sin.sin_family = AF_INET;
269     sin.sin_addr.s_addr = inet_addr("127.0.0.1");
270     sin.sin_port = htons(9756);
271
272     /* connect to the simulator */
273     if (INVALID_SOCKET == connect(sock,(struct sockaddr *) &sin, sizeof(sin)))
274     {
275         /* if failed then wait 1 second & try again
276            do this for 10 secs only */
277         if (retry < 10)
278         {
279             if ( !retry )
280                 simPid = execSimulator(args, nargs);
281             retry ++;
282             Sleep(1000);
283             goto try_connect;
284         }
285         perror("connect failed :");
286         exit(1);
287     }
288     fh = _open_osfhandle((intptr_t)socket, _O_TEXT);
289     if (-1 == fh)
290     {
291         fprintf(stderr, "cannot _open_osfhandle\n");
292         exit(1);
293     }
294
295     /* go the socket now turn it into a file handle */
296     if (!(simin = fdopen(sock,"r")))
297     {
298         fprintf(stderr,"cannot open socket for read\n");
299         exit(1);
300     }
301
302     fh = _open_osfhandle((intptr_t)socket, _O_TEXT);
303     if (-1 == fh)
304     {
305         fprintf(stderr, "cannot _open_osfhandle\n");
306         exit(1);
307     }
308
309     if (!(simout = fdopen(sock,"w")))
310     {
311         fprintf(stderr,"cannot open socket for write\n");
312         exit(1);
313     }
314     /* now that we have opened, wait for the prompt */
315     waitForSim(200,NULL);
316     simactive = 1;
317 }
318 #else
319 int execSimulator(char **args, int nargs)
320 {
321     if ((simPid = fork()))
322     {
323         Dprintf(D_simi, ("simi: simulator pid %d\n",(int) simPid));
324     }
325     else
326     {
327         /* we are in the child process : start the simulator */
328         signal(SIGINT , SIG_IGN );
329         signal(SIGABRT, SIG_IGN );
330         signal(SIGHUP , SIG_IGN );
331         signal(SIGCHLD, SIG_IGN );
332
333         if (execvp(args[0],args) < 0)
334         {
335             perror("cannot exec simulator");
336             exit(1);
337         }
338     }
339 }
340
341 void openSimulator (char **args, int nargs)
342 {
343     struct sockaddr_in sin;
344     int retry = 0;
345     int i;
346     Dprintf(D_simi, ("simi: openSimulator\n"));
347 #ifdef SDCDB_DEBUG
348     if (D_simi & sdcdbDebug)
349     {
350         printf("simi: openSimulator: ");
351         for (i=0; i < nargs; i++ )
352         {
353             printf("arg%d: %s ",i,args[i]);
354         }
355         printf("\n");
356     }
357 #endif
358     invalidateCache(XMEM_CACHE);
359     invalidateCache(IMEM_CACHE);
360     invalidateCache(SREG_CACHE);
361
362  try_connect:
363     sock = socket(AF_INET,SOCK_STREAM,0);
364
365     memset(&sin,0,sizeof(sin));
366     sin.sin_family = AF_INET;
367     sin.sin_addr.s_addr = inet_addr("127.0.0.1");
368     sin.sin_port = htons(9756);
369
370     /* connect to the simulator */
371     if (connect(sock,(struct sockaddr *) &sin, sizeof(sin)) < 0)
372     {
373         /* if failed then wait 1 second & try again
374            do this for 10 secs only */
375         if (retry < 10)
376         {
377             if ( !retry )
378             {
379                 simPid = execSimulator(args, nargs);
380             }
381             retry ++;
382             sleep (1);
383             goto try_connect;
384         }
385         perror("connect failed :");
386         exit(1);
387     }
388     /* go the socket now turn it into a file handle */
389     if (!(simin = fdopen(sock,"r")))
390     {
391         fprintf(stderr,"cannot open socket for read\n");
392         exit(1);
393     }
394
395     if (!(simout = fdopen(sock,"w")))
396     {
397         fprintf(stderr,"cannot open socket for write\n");
398         exit(1);
399     }
400     /* now that we have opened, wait for the prompt */
401     waitForSim(200,NULL);
402     simactive = 1;
403 }
404 #endif
405
406 /*-----------------------------------------------------------------*/
407 /* simResponse - returns buffer to simulator's response            */
408 /*-----------------------------------------------------------------*/
409 char *simResponse()
410 {
411     return simibuff;
412 }
413
414 /*-----------------------------------------------------------------*/
415 /* sendSim - sends a command to the simuator                 */
416 /*-----------------------------------------------------------------*/
417 void sendSim(char *s)
418 {
419     if ( ! simout )
420         return;
421
422     Dprintf(D_simi, ("simi: sendSim-->%s", s));  // s has LF at end already
423     fputs(s,simout);
424     fflush(simout);
425 }
426
427
428 static int getMemString(char *buffer, char wrflag,
429                         unsigned int *addr, char mem, int size )
430 {
431     int cachenr = NMEM_CACHE;
432     char *prefix;
433     char *cmd ;
434
435     if ( wrflag )
436         cmd = "set mem";
437     else
438         cmd = "dump";
439     buffer[0] = '\0' ;
440
441     switch (mem)
442     {
443         case 'A': /* External stack */
444         case 'F': /* External ram */
445             prefix = "xram";
446             cachenr = XMEM_CACHE;
447             break;
448         case 'C': /* Code */
449         case 'D': /* Code / static segment */
450             prefix = "rom";
451             break;
452         case 'B': /* Internal stack */
453         case 'E': /* Internal ram (lower 128) bytes */
454         case 'G': /* Internal ram */
455             prefix = "iram";
456             cachenr = IMEM_CACHE;
457             break;
458         case 'H': /* Bit addressable */
459         case 'J': /* SBIT space */
460             cachenr = BIT_CACHE;
461             if ( wrflag )
462             {
463                 cmd = "set bit";
464             }
465             sprintf(buffer,"%s 0x%x\n",cmd,*addr);
466             return cachenr;
467             break;
468         case 'I': /* SFR space */
469             prefix = "sfr" ;
470             cachenr = SREG_CACHE;
471             break;
472         case 'R': /* Register space */
473             prefix = "iram";
474             /* get register bank */
475             cachenr = simGetValue (0xd0,'I',1);
476             *addr  += cachenr & 0x18 ;
477             cachenr = IMEM_CACHE;
478             break;
479         default:
480         case 'Z': /* undefined space code */
481             return cachenr;
482     }
483     if ( wrflag )
484         sprintf(buffer,"%s %s 0x%x\n",cmd,prefix,*addr);
485     else
486         sprintf(buffer,"%s %s 0x%x 0x%x\n",cmd,prefix,*addr,*addr+size-1);
487     return cachenr;
488 }
489
490 void simSetPC( unsigned int addr )
491 {
492     char buffer[40];
493     sprintf(buffer,"pc %d\n", addr);
494     sendSim(buffer);
495     waitForSim(100,NULL);
496     simResponse();
497 }
498
499 int simSetValue (unsigned int addr,char mem, int size, unsigned long val)
500 {
501     char cachenr, i;
502     char buffer[40];
503     char *s;
504
505     if ( size <= 0 )
506         return 0;
507
508     cachenr = getMemString(buffer,1,&addr,mem,size);
509     if ( cachenr < NMEM_CACHE )
510     {
511         invalidateCache(cachenr);
512     }
513     s = buffer + strlen(buffer) -1;
514     for ( i = 0 ; i < size ; i++ )
515     {
516         sprintf(s," 0x%x", val & 0xff);
517         s += strlen(s);
518         val >>= 8;
519     }
520     sprintf(s,"\n");
521     sendSim(buffer);
522     waitForSim(100,NULL);
523     simResponse();
524     return 0;
525 }
526
527
528 /*-----------------------------------------------------------------*/
529 /* simGetValue - get value @ address for mem space                 */
530 /*-----------------------------------------------------------------*/
531 unsigned long simGetValue (unsigned int addr,char mem, int size)
532 {
533     unsigned int b[4] = {0,0,0,0}; /* can be a max of four bytes long */
534     char cachenr, i;
535     char buffer[40];
536     char *resp;
537
538     if ( size <= 0 )
539         return 0;
540
541     cachenr = getMemString(buffer,0,&addr,mem,size);
542
543     resp = NULL;
544     if ( cachenr < NMEM_CACHE )
545     {
546         resp = getMemCache(addr,cachenr,size);
547     }
548     if ( !resp )
549     {
550         /* create the simulator command */
551         sendSim(buffer);
552         waitForSim(100,NULL);
553         resp = simResponse();
554
555         /* got the response we need to parse it the response
556            is of the form
557            [address] [v] [v] [v] ... special case in
558            case of bit variables which case it becomes
559            [address] [assembler bit address] [v] */
560         /* first skip thru white space */
561         while (isspace(*resp)) resp++ ;
562
563         if (strncmp(resp, "0x",2) == 0)
564             resp += 2;
565
566         /* skip thru the address part */
567         while (isxdigit(*resp)) resp++;
568
569     }
570     /* make the branch for bit variables */
571     if ( cachenr == BIT_CACHE)
572     {
573         /* skip until newline */
574         while (*resp && *resp != '\n' ) resp++ ;
575         if ( *--resp != '0' )
576             b[0] = 1;
577     }
578     else
579     {
580         for (i = 0 ; i < size ; i++ )
581         {
582             /* skip white space */
583             while (isspace(*resp)) resp++ ;
584
585             b[i] = strtol(resp,&resp,16);
586         }
587     }
588
589     return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24 ;
590
591 }
592
593 /*-----------------------------------------------------------------*/
594 /* simSetBP - set break point for a given address                  */
595 /*-----------------------------------------------------------------*/
596 void simSetBP (unsigned int addr)
597 {
598     char buff[50];
599
600     sprintf(buff,"break 0x%x\n",addr);
601     sendSim(buff);
602     waitForSim(100,NULL);
603 }
604
605 /*-----------------------------------------------------------------*/
606 /* simClearBP - clear a break point                                */
607 /*-----------------------------------------------------------------*/
608 void simClearBP (unsigned int addr)
609 {
610     char buff[50];
611
612     sprintf(buff,"clear 0x%x\n",addr);
613     sendSim(buff);
614     waitForSim(100,NULL);
615 }
616
617 /*-----------------------------------------------------------------*/
618 /* simLoadFile - load the simulator file                           */
619 /*-----------------------------------------------------------------*/
620 void simLoadFile (char *s)
621 {
622     char buff[128];
623
624     sprintf(buff,"file \"%s\"\n",s);
625     printf(buff);
626     sendSim(buff);
627     waitForSim(500,NULL);
628 }
629
630 /*-----------------------------------------------------------------*/
631 /* simGoTillBp - send 'go' to simulator till a bp then return addr */
632 /*-----------------------------------------------------------------*/
633 unsigned int simGoTillBp ( unsigned int gaddr)
634 {
635     char *sr;
636     unsigned addr ;
637     char *sfmt;
638     int wait_ms = 1000;
639
640     invalidateCache(XMEM_CACHE);
641     invalidateCache(IMEM_CACHE);
642     invalidateCache(SREG_CACHE);
643     if (gaddr == 0) {
644       /* initial start, start & stop from address 0 */
645       //char buf[20];
646
647          // this program is setting up a bunch of breakpoints automatically
648          // at key places.  Like at startup & main() and other function
649          // entry points.  So we don't need to setup one here..
650       //sendSim("break 0x0\n");
651       //sleep(1);
652       //waitForSim();
653
654       sendSim("reset\n");
655       waitForSim(wait_ms, NULL);
656       sendSim("run 0x0\n");
657     } else      if (gaddr == -1) { /* resume */
658       sendSim ("run\n");
659       wait_ms = 100;
660     }
661     else        if (gaddr == 1 ) { /* nexti or next */
662       sendSim ("next\n");
663       wait_ms = 100;
664     }
665     else        if (gaddr == 2 ) { /* stepi or step */
666       sendSim ("step\n");
667       wait_ms = 100;
668     }
669     else  {
670       printf("Error, simGoTillBp > 0!\n");
671       exit(1);
672     }
673
674     waitForSim(wait_ms, NULL);
675
676     /* get the simulator response */
677     sr = simResponse();
678     /* check for errors */
679     while ( *sr )
680     {
681         while ( *sr && *sr != 'E' ) sr++ ;
682         if ( !*sr )
683             break;
684         if ( ! strncmp(sr,"Error:",6))
685         {
686             fputs(sr,stdout);
687             break;
688         }
689         sr++ ;
690     }
691
692     nointerrupt = 1;
693     /* get answer of stop command */
694     if ( userinterrupt )
695         waitForSim(wait_ms, NULL);
696
697     /* better solution: ask pc */
698     sendSim ("pc\n");
699     waitForSim(100, NULL);
700     sr = simResponse();
701     nointerrupt = 0;
702
703     gaddr = strtol(sr+3,0,0);
704     return gaddr;
705 }
706
707 /*-----------------------------------------------------------------*/
708 /* simReset - reset the simulator                                  */
709 /*-----------------------------------------------------------------*/
710 void simReset ()
711 {
712     invalidateCache(XMEM_CACHE);
713     invalidateCache(IMEM_CACHE);
714     invalidateCache(SREG_CACHE);
715     sendSim("res\n");
716     waitForSim(100,NULL);
717 }
718
719
720 /*-----------------------------------------------------------------*/
721 /* closeSimulator - close connection to simulator                  */
722 /*-----------------------------------------------------------------*/
723 void closeSimulator ()
724 {
725 #ifdef _WIN32
726     if ( ! simin || ! simout || INVALID_SOCKET == sock )
727 #else
728     if ( ! simin || ! simout || sock == -1 )
729 #endif
730     {
731         simactive = 0;
732         return;
733     }
734     simactive = 0;
735     sendSim("quit\n");
736     fclose (simin);
737     fclose (simout);
738     shutdown(sock,2);
739 #ifdef _WIN32
740     closesocket(sock);
741     sock = -1;
742     if (NULL != simPid)
743         TerminateProcess(simPid->hProcess, 0);
744     // Close process and thread handles.
745     CloseHandle(simPid->hProcess);
746     CloseHandle(simPid->hThread);
747 #else
748     close(sock);
749     sock = -1;
750     if ( simPid > 0 )
751         kill (simPid,SIGKILL);
752 #endif
753 }