c44b40718ff2047a48350343c94c1b12f9b54f6c
[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 static void init_winsock(void)
157 {
158     static int is_initialized = 0;
159
160     if (!is_initialized)
161     {
162         WSADATA wsaData;
163         int iResult;
164
165         // Initialize Winsock
166         if (0 != WSAStartup(MAKEWORD(2,2), &wsaData))
167         {
168             fprintf(stderr, "WSAStartup failed: %d\n", iResult);
169             exit(1);
170         }
171     }
172 }
173
174 static char *argsToCmdLine(char **args, int nargs)
175 {
176 #define CHUNCK  256
177     int i;
178     int cmdPos = 0;
179     char *cmd = Safe_malloc(CHUNCK);
180     int cmdLen = CHUNCK;
181
182     for (i = 0; i < nargs; i++)
183     {
184         int quote = 0;
185         int argLen = strlen(args[i]);
186
187         if (NULL != strchr(args[i], ' '))
188         {
189             quote = 1;
190             argLen += 2;
191         }
192
193         if (0 < i)
194             ++argLen;
195
196         if (cmdPos + argLen >= cmdLen)
197         {
198             do
199             {
200                 cmdLen += cmdLen;
201             }
202             while (cmdPos + argLen >= cmdLen);
203             cmd = Safe_realloc(cmd, cmdLen);
204         }
205
206         if (0 < i)
207         {
208             cmd[cmdPos++] = ' ';
209             --argLen;
210         }
211
212         if (quote)
213         {
214             cmd[cmdPos++] = '"';
215             --argLen;
216         }
217
218         memcpy(&cmd[cmdPos], args[i], argLen);
219         cmdPos += argLen;
220
221         if (quote)
222             cmd[cmdPos++] = '"';
223     }
224
225     cmd[cmdPos] = '\0';
226
227     return cmd;
228 }
229
230 static PROCESS_INFORMATION *execSimulator(char **args, int nargs)
231 {
232     STARTUPINFO si;
233     static PROCESS_INFORMATION pi;
234     char *cmdLine = argsToCmdLine(args, nargs);
235
236     memset(&si, 0, sizeof(si));
237     si.cb = sizeof(si);
238     memset(&pi, 0, sizeof(pi));
239
240     // Start the child process.
241     if (!CreateProcess(NULL,   // No module name (use command line)
242         cmdLine, // Command line
243         NULL,           // Process handle not inheritable
244         NULL,           // Thread handle not inheritable
245         FALSE,          // Set handle inheritance to FALSE
246         0,              // No creation flags
247         NULL,           // Use parent's environment block
248         NULL,           // Use parent's starting directory
249         &si,            // Pointer to STARTUPINFO structure
250         &pi)            // Pointer to PROCESS_INFORMATION structure
251     )
252     {
253         Safe_free(cmdLine);
254         printf( "CreateProcess failed (%d).\n", GetLastError() );
255         return NULL;
256     }
257
258     Safe_free(cmdLine);
259     return &pi;
260 }
261
262 void openSimulator (char **args, int nargs)
263 {
264     struct sockaddr_in sin;
265     int retry = 0;
266     int i;
267     int fh;
268
269     init_winsock();
270
271     Dprintf(D_simi, ("simi: openSimulator\n"));
272 #ifdef SDCDB_DEBUG
273     if (D_simi & sdcdbDebug)
274     {
275         printf("simi: openSimulator: ");
276         for (i=0; i < nargs; i++ )
277         {
278             printf("arg%d: %s ",i,args[i]);
279         }
280         printf("\n");
281     }
282 #endif
283     invalidateCache(XMEM_CACHE);
284     invalidateCache(IMEM_CACHE);
285     invalidateCache(SREG_CACHE);
286
287     if (INVALID_SOCKET == (sock = WSASocket(PF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0))) {
288         fprintf(stderr, "cannot create socket: %d\n", WSAGetLastError());
289         exit(1);
290     }
291
292     memset(&sin,0,sizeof(sin));
293     sin.sin_family = AF_INET;
294     sin.sin_addr.s_addr = inet_addr("127.0.0.1");
295     sin.sin_port = htons(9756);
296
297  try_connect:
298     /* connect to the simulator */
299     if (SOCKET_ERROR == connect(sock, (struct sockaddr *)&sin, sizeof(sin)))
300     {
301         /* if failed then wait 1 second & try again
302            do this for 10 secs only */
303         if (retry < 10)
304         {
305             if ( !retry )
306                 simPid = execSimulator(args, nargs);
307             retry ++;
308             Sleep(1000);
309             goto try_connect;
310         }
311         perror("connect failed :");
312         exit(1);
313     }
314
315     fh = _open_osfhandle((intptr_t)sock, _O_TEXT);
316     if (-1 == fh)
317     {
318         perror("cannot _open_osfhandle");
319         exit(1);
320     }
321
322     /* go the socket now turn it into a file handle */
323     if (!(simin = fdopen(fh, "r")))
324     {
325         perror("cannot open socket for read");
326         exit(1);
327     }
328
329     fh = _open_osfhandle((intptr_t)sock, _O_TEXT);
330     if (-1 == fh)
331     {
332         perror("cannot _open_osfhandle");
333         exit(1);
334     }
335
336     if (!(simout = fdopen(fh, "w")))
337     {
338         perror("cannot open socket for write");
339         exit(1);
340     }
341     /* now that we have opened, wait for the prompt */
342     waitForSim(200, NULL);
343     simactive = 1;
344 }
345 #else
346 static int execSimulator(char **args, int nargs)
347 {
348     if ((simPid = fork()))
349     {
350         Dprintf(D_simi, ("simi: simulator pid %d\n",(int) simPid));
351     }
352     else
353     {
354         /* we are in the child process : start the simulator */
355         signal(SIGINT , SIG_IGN );
356         signal(SIGABRT, SIG_IGN );
357         signal(SIGHUP , SIG_IGN );
358         signal(SIGCHLD, SIG_IGN );
359
360         if (execvp(args[0],args) < 0)
361         {
362             perror("cannot exec simulator");
363             exit(1);
364         }
365     }
366     return simPid;
367 }
368
369 void openSimulator (char **args, int nargs)
370 {
371     struct sockaddr_in sin;
372     int retry = 0;
373     int i;
374     Dprintf(D_simi, ("simi: openSimulator\n"));
375 #ifdef SDCDB_DEBUG
376     if (D_simi & sdcdbDebug)
377     {
378         printf("simi: openSimulator: ");
379         for (i=0; i < nargs; i++ )
380         {
381             printf("arg%d: %s ",i,args[i]);
382         }
383         printf("\n");
384     }
385 #endif
386     invalidateCache(XMEM_CACHE);
387     invalidateCache(IMEM_CACHE);
388     invalidateCache(SREG_CACHE);
389
390     if ((sock = socket(AF_INET,SOCK_STREAM,0)) < 0)
391     {
392         perror("cannot create socket");
393         exit(1);
394     }
395
396     memset(&sin,0,sizeof(sin));
397     sin.sin_family = AF_INET;
398     sin.sin_addr.s_addr = inet_addr("127.0.0.1");
399     sin.sin_port = htons(9756);
400
401  try_connect:
402     /* connect to the simulator */
403     if (connect(sock,(struct sockaddr *) &sin, sizeof(sin)) < 0)
404     {
405         /* if failed then wait 1 second & try again
406            do this for 10 secs only */
407         if (retry < 10)
408         {
409             if ( !retry )
410             {
411                 simPid = execSimulator(args, nargs);
412             }
413             retry ++;
414             sleep (1);
415             goto try_connect;
416         }
417         perror("connect failed :");
418         exit(1);
419     }
420     /* go the socket now turn it into a file handle */
421     if (!(simin = fdopen(sock,"r")))
422     {
423         fprintf(stderr,"cannot open socket for read\n");
424         exit(1);
425     }
426
427     if (!(simout = fdopen(sock,"w")))
428     {
429         fprintf(stderr,"cannot open socket for write\n");
430         exit(1);
431     }
432     /* now that we have opened, wait for the prompt */
433     waitForSim(200,NULL);
434     simactive = 1;
435 }
436 #endif
437
438 /*-----------------------------------------------------------------*/
439 /* simResponse - returns buffer to simulator's response            */
440 /*-----------------------------------------------------------------*/
441 char *simResponse(void)
442 {
443     return simibuff;
444 }
445
446 /*-----------------------------------------------------------------*/
447 /* sendSim - sends a command to the simuator                 */
448 /*-----------------------------------------------------------------*/
449 void sendSim(char *s)
450 {
451     if ( ! simout )
452         return;
453
454     Dprintf(D_simi, ("simi: sendSim-->%s", s));  // s has LF at end already
455     fputs(s,simout);
456     fflush(simout);
457 }
458
459
460 static int getMemString(char *buffer, char wrflag,
461                         unsigned int *addr, char mem, int size )
462 {
463     int cachenr = NMEM_CACHE;
464     char *prefix;
465     char *cmd ;
466
467     if ( wrflag )
468         cmd = "set mem";
469     else
470         cmd = "dump";
471     buffer[0] = '\0' ;
472
473     switch (mem)
474     {
475         case 'A': /* External stack */
476         case 'F': /* External ram */
477             prefix = "xram";
478             cachenr = XMEM_CACHE;
479             break;
480         case 'C': /* Code */
481         case 'D': /* Code / static segment */
482             prefix = "rom";
483             break;
484         case 'B': /* Internal stack */
485         case 'E': /* Internal ram (lower 128) bytes */
486         case 'G': /* Internal ram */
487             prefix = "iram";
488             cachenr = IMEM_CACHE;
489             break;
490         case 'H': /* Bit addressable */
491         case 'J': /* SBIT space */
492             cachenr = BIT_CACHE;
493             if ( wrflag )
494             {
495                 cmd = "set bit";
496             }
497             sprintf(buffer,"%s 0x%x\n",cmd,*addr);
498             return cachenr;
499             break;
500         case 'I': /* SFR space */
501             prefix = "sfr" ;
502             cachenr = SREG_CACHE;
503             break;
504         case 'R': /* Register space */
505             prefix = "iram";
506             /* get register bank */
507             cachenr = simGetValue (0xd0,'I',1);
508             *addr  += cachenr & 0x18 ;
509             cachenr = IMEM_CACHE;
510             break;
511         default:
512         case 'Z': /* undefined space code */
513             return cachenr;
514     }
515     if ( wrflag )
516         sprintf(buffer,"%s %s 0x%x\n",cmd,prefix,*addr);
517     else
518         sprintf(buffer,"%s %s 0x%x 0x%x\n",cmd,prefix,*addr,*addr+size-1);
519     return cachenr;
520 }
521
522 void simSetPC( unsigned int addr )
523 {
524     char buffer[40];
525     sprintf(buffer,"pc %d\n", addr);
526     sendSim(buffer);
527     waitForSim(100,NULL);
528     simResponse();
529 }
530
531 int simSetValue (unsigned int addr,char mem, int size, unsigned long val)
532 {
533     char cachenr, i;
534     char buffer[40];
535     char *s;
536
537     if ( size <= 0 )
538         return 0;
539
540     cachenr = getMemString(buffer,1,&addr,mem,size);
541     if ( cachenr < NMEM_CACHE )
542     {
543         invalidateCache(cachenr);
544     }
545     s = buffer + strlen(buffer) -1;
546     for ( i = 0 ; i < size ; i++ )
547     {
548         sprintf(s," 0x%lx", val & 0xff);
549         s += strlen(s);
550         val >>= 8;
551     }
552     sprintf(s,"\n");
553     sendSim(buffer);
554     waitForSim(100,NULL);
555     simResponse();
556     return 0;
557 }
558
559
560 /*-----------------------------------------------------------------*/
561 /* simGetValue - get value @ address for mem space                 */
562 /*-----------------------------------------------------------------*/
563 unsigned long simGetValue (unsigned int addr,char mem, int size)
564 {
565     unsigned int b[4] = {0,0,0,0}; /* can be a max of four bytes long */
566     char cachenr, i;
567     char buffer[40];
568     char *resp;
569
570     if ( size <= 0 )
571         return 0;
572
573     cachenr = getMemString(buffer,0,&addr,mem,size);
574
575     resp = NULL;
576     if ( cachenr < NMEM_CACHE )
577     {
578         resp = getMemCache(addr,cachenr,size);
579     }
580     if ( !resp )
581     {
582         /* create the simulator command */
583         sendSim(buffer);
584         waitForSim(100,NULL);
585         resp = simResponse();
586
587         /* got the response we need to parse it the response
588            is of the form
589            [address] [v] [v] [v] ... special case in
590            case of bit variables which case it becomes
591            [address] [assembler bit address] [v] */
592         /* first skip thru white space */
593         resp = trim_left(resp);
594
595         if (strncmp(resp, "0x",2) == 0)
596             resp += 2;
597
598         /* skip thru the address part */
599         while (isxdigit(*resp)) resp++;
600
601     }
602     /* make the branch for bit variables */
603     if ( cachenr == BIT_CACHE)
604     {
605         /* skip until newline */
606         while (*resp && *resp != '\n' ) resp++ ;
607         if ( *--resp != '0' )
608             b[0] = 1;
609     }
610     else
611     {
612         for (i = 0 ; i < size ; i++ )
613         {
614             /* skip white space */
615             resp = trim_left(resp);
616
617             b[i] = strtol(resp,&resp,16);
618         }
619     }
620
621     return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24 ;
622
623 }
624
625 /*-----------------------------------------------------------------*/
626 /* simSetBP - set break point for a given address                  */
627 /*-----------------------------------------------------------------*/
628 void simSetBP (unsigned int addr)
629 {
630     char buff[50];
631
632     sprintf(buff,"break 0x%x\n",addr);
633     sendSim(buff);
634     waitForSim(100,NULL);
635 }
636
637 /*-----------------------------------------------------------------*/
638 /* simClearBP - clear a break point                                */
639 /*-----------------------------------------------------------------*/
640 void simClearBP (unsigned int addr)
641 {
642     char buff[50];
643
644     sprintf(buff,"clear 0x%x\n",addr);
645     sendSim(buff);
646     waitForSim(100,NULL);
647 }
648
649 /*-----------------------------------------------------------------*/
650 /* simLoadFile - load the simulator file                           */
651 /*-----------------------------------------------------------------*/
652 void simLoadFile (char *s)
653 {
654     char buff[128];
655
656     sprintf(buff,"file \"%s\"\n",s);
657     printf("%s",buff);
658     sendSim(buff);
659     waitForSim(500,NULL);
660 }
661
662 /*-----------------------------------------------------------------*/
663 /* simGoTillBp - send 'go' to simulator till a bp then return addr */
664 /*-----------------------------------------------------------------*/
665 unsigned int simGoTillBp ( unsigned int gaddr)
666 {
667     char *sr;
668     unsigned addr ;
669     char *sfmt;
670     int wait_ms = 1000;
671
672     invalidateCache(XMEM_CACHE);
673     invalidateCache(IMEM_CACHE);
674     invalidateCache(SREG_CACHE);
675     if (gaddr == 0) {
676         /* initial start, start & stop from address 0 */
677         //char buf[20];
678
679            // this program is setting up a bunch of breakpoints automatically
680            // at key places.  Like at startup & main() and other function
681            // entry points.  So we don't need to setup one here..
682         //sendSim("break 0x0\n");
683         //sleep(1);
684         //waitForSim();
685
686         sendSim("reset\n");
687         waitForSim(wait_ms, NULL);
688         sendSim("run 0x0\n");
689     } else      if (gaddr == -1) { /* resume */
690         sendSim ("run\n");
691         wait_ms = 100;
692     }
693     else        if (gaddr == 1 ) { /* nexti or next */
694         sendSim ("next\n");
695         wait_ms = 100;
696     }
697     else        if (gaddr == 2 ) { /* stepi or step */
698         sendSim ("step\n");
699         wait_ms = 100;
700     }
701     else  {
702         printf("Error, simGoTillBp > 0!\n");
703         exit(1);
704     }
705
706     waitForSim(wait_ms, NULL);
707
708     /* get the simulator response */
709     sr = simResponse();
710     /* check for errors */
711     while ( *sr )
712     {
713         while ( *sr && *sr != 'E' ) sr++ ;
714         if ( !*sr )
715             break;
716         if ( ! strncmp(sr,"Error:",6))
717         {
718             fputs(sr,stdout);
719             break;
720         }
721         sr++ ;
722     }
723
724     nointerrupt = 1;
725     /* get answer of stop command */
726     if ( userinterrupt )
727         waitForSim(wait_ms, NULL);
728
729     /* better solution: ask pc */
730     sendSim ("pc\n");
731     waitForSim(100, NULL);
732     sr = simResponse();
733     nointerrupt = 0;
734
735     gaddr = strtol(sr+3,0,0);
736     return gaddr;
737 }
738
739 /*-----------------------------------------------------------------*/
740 /* simReset - reset the simulator                                  */
741 /*-----------------------------------------------------------------*/
742 void simReset (void)
743 {
744     invalidateCache(XMEM_CACHE);
745     invalidateCache(IMEM_CACHE);
746     invalidateCache(SREG_CACHE);
747     sendSim("res\n");
748     waitForSim(100,NULL);
749 }
750
751
752 /*-----------------------------------------------------------------*/
753 /* closeSimulator - close connection to simulator                  */
754 /*-----------------------------------------------------------------*/
755 void closeSimulator (void)
756 {
757 #ifdef _WIN32
758     if ( ! simin || ! simout || INVALID_SOCKET == sock )
759 #else
760     if ( ! simin || ! simout || sock == -1 )
761 #endif
762     {
763         simactive = 0;
764         return;
765     }
766     simactive = 0;
767     sendSim("quit\n");
768     fclose (simin);
769     fclose (simout);
770     shutdown(sock,2);
771 #ifdef _WIN32
772     closesocket(sock);
773     sock = -1;
774     if (NULL != simPid)
775         TerminateProcess(simPid->hProcess, 0);
776     // Close process and thread handles.
777     CloseHandle(simPid->hProcess);
778     CloseHandle(simPid->hThread);
779 #else
780     close(sock);
781     sock = -1;
782     if ( simPid > 0 )
783         kill (simPid,SIGKILL);
784 #endif
785 }