* debugger/mcs51/break.[ch], debugger/mcs51/cmd.c,
[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 }
367
368 void openSimulator (char **args, int nargs)
369 {
370     struct sockaddr_in sin;
371     int retry = 0;
372     int i;
373     Dprintf(D_simi, ("simi: openSimulator\n"));
374 #ifdef SDCDB_DEBUG
375     if (D_simi & sdcdbDebug)
376     {
377         printf("simi: openSimulator: ");
378         for (i=0; i < nargs; i++ )
379         {
380             printf("arg%d: %s ",i,args[i]);
381         }
382         printf("\n");
383     }
384 #endif
385     invalidateCache(XMEM_CACHE);
386     invalidateCache(IMEM_CACHE);
387     invalidateCache(SREG_CACHE);
388
389     if ((sock = socket(AF_INET,SOCK_STREAM,0)) < 0)
390     {
391         perror("cannot create socket");
392         exit(1);
393     }
394
395     memset(&sin,0,sizeof(sin));
396     sin.sin_family = AF_INET;
397     sin.sin_addr.s_addr = inet_addr("127.0.0.1");
398     sin.sin_port = htons(9756);
399
400  try_connect:
401     /* connect to the simulator */
402     if (connect(sock,(struct sockaddr *) &sin, sizeof(sin)) < 0)
403     {
404         /* if failed then wait 1 second & try again
405            do this for 10 secs only */
406         if (retry < 10)
407         {
408             if ( !retry )
409             {
410                 simPid = execSimulator(args, nargs);
411             }
412             retry ++;
413             sleep (1);
414             goto try_connect;
415         }
416         perror("connect failed :");
417         exit(1);
418     }
419     /* go the socket now turn it into a file handle */
420     if (!(simin = fdopen(sock,"r")))
421     {
422         fprintf(stderr,"cannot open socket for read\n");
423         exit(1);
424     }
425
426     if (!(simout = fdopen(sock,"w")))
427     {
428         fprintf(stderr,"cannot open socket for write\n");
429         exit(1);
430     }
431     /* now that we have opened, wait for the prompt */
432     waitForSim(200,NULL);
433     simactive = 1;
434 }
435 #endif
436
437 /*-----------------------------------------------------------------*/
438 /* simResponse - returns buffer to simulator's response            */
439 /*-----------------------------------------------------------------*/
440 char *simResponse(void)
441 {
442     return simibuff;
443 }
444
445 /*-----------------------------------------------------------------*/
446 /* sendSim - sends a command to the simuator                 */
447 /*-----------------------------------------------------------------*/
448 void sendSim(char *s)
449 {
450     if ( ! simout )
451         return;
452
453     Dprintf(D_simi, ("simi: sendSim-->%s", s));  // s has LF at end already
454     fputs(s,simout);
455     fflush(simout);
456 }
457
458
459 static int getMemString(char *buffer, char wrflag,
460                         unsigned int *addr, char mem, int size )
461 {
462     int cachenr = NMEM_CACHE;
463     char *prefix;
464     char *cmd ;
465
466     if ( wrflag )
467         cmd = "set mem";
468     else
469         cmd = "dump";
470     buffer[0] = '\0' ;
471
472     switch (mem)
473     {
474         case 'A': /* External stack */
475         case 'F': /* External ram */
476             prefix = "xram";
477             cachenr = XMEM_CACHE;
478             break;
479         case 'C': /* Code */
480         case 'D': /* Code / static segment */
481             prefix = "rom";
482             break;
483         case 'B': /* Internal stack */
484         case 'E': /* Internal ram (lower 128) bytes */
485         case 'G': /* Internal ram */
486             prefix = "iram";
487             cachenr = IMEM_CACHE;
488             break;
489         case 'H': /* Bit addressable */
490         case 'J': /* SBIT space */
491             cachenr = BIT_CACHE;
492             if ( wrflag )
493             {
494                 cmd = "set bit";
495             }
496             sprintf(buffer,"%s 0x%x\n",cmd,*addr);
497             return cachenr;
498             break;
499         case 'I': /* SFR space */
500             prefix = "sfr" ;
501             cachenr = SREG_CACHE;
502             break;
503         case 'R': /* Register space */
504             prefix = "iram";
505             /* get register bank */
506             cachenr = simGetValue (0xd0,'I',1);
507             *addr  += cachenr & 0x18 ;
508             cachenr = IMEM_CACHE;
509             break;
510         default:
511         case 'Z': /* undefined space code */
512             return cachenr;
513     }
514     if ( wrflag )
515         sprintf(buffer,"%s %s 0x%x\n",cmd,prefix,*addr);
516     else
517         sprintf(buffer,"%s %s 0x%x 0x%x\n",cmd,prefix,*addr,*addr+size-1);
518     return cachenr;
519 }
520
521 void simSetPC( unsigned int addr )
522 {
523     char buffer[40];
524     sprintf(buffer,"pc %d\n", addr);
525     sendSim(buffer);
526     waitForSim(100,NULL);
527     simResponse();
528 }
529
530 int simSetValue (unsigned int addr,char mem, int size, unsigned long val)
531 {
532     char cachenr, i;
533     char buffer[40];
534     char *s;
535
536     if ( size <= 0 )
537         return 0;
538
539     cachenr = getMemString(buffer,1,&addr,mem,size);
540     if ( cachenr < NMEM_CACHE )
541     {
542         invalidateCache(cachenr);
543     }
544     s = buffer + strlen(buffer) -1;
545     for ( i = 0 ; i < size ; i++ )
546     {
547         sprintf(s," 0x%x", val & 0xff);
548         s += strlen(s);
549         val >>= 8;
550     }
551     sprintf(s,"\n");
552     sendSim(buffer);
553     waitForSim(100,NULL);
554     simResponse();
555     return 0;
556 }
557
558
559 /*-----------------------------------------------------------------*/
560 /* simGetValue - get value @ address for mem space                 */
561 /*-----------------------------------------------------------------*/
562 unsigned long simGetValue (unsigned int addr,char mem, int size)
563 {
564     unsigned int b[4] = {0,0,0,0}; /* can be a max of four bytes long */
565     char cachenr, i;
566     char buffer[40];
567     char *resp;
568
569     if ( size <= 0 )
570         return 0;
571
572     cachenr = getMemString(buffer,0,&addr,mem,size);
573
574     resp = NULL;
575     if ( cachenr < NMEM_CACHE )
576     {
577         resp = getMemCache(addr,cachenr,size);
578     }
579     if ( !resp )
580     {
581         /* create the simulator command */
582         sendSim(buffer);
583         waitForSim(100,NULL);
584         resp = simResponse();
585
586         /* got the response we need to parse it the response
587            is of the form
588            [address] [v] [v] [v] ... special case in
589            case of bit variables which case it becomes
590            [address] [assembler bit address] [v] */
591         /* first skip thru white space */
592         resp = trim_left(resp);
593
594         if (strncmp(resp, "0x",2) == 0)
595             resp += 2;
596
597         /* skip thru the address part */
598         while (isxdigit(*resp)) resp++;
599
600     }
601     /* make the branch for bit variables */
602     if ( cachenr == BIT_CACHE)
603     {
604         /* skip until newline */
605         while (*resp && *resp != '\n' ) resp++ ;
606         if ( *--resp != '0' )
607             b[0] = 1;
608     }
609     else
610     {
611         for (i = 0 ; i < size ; i++ )
612         {
613             /* skip white space */
614             resp = trim_left(resp);
615
616             b[i] = strtol(resp,&resp,16);
617         }
618     }
619
620     return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24 ;
621
622 }
623
624 /*-----------------------------------------------------------------*/
625 /* simSetBP - set break point for a given address                  */
626 /*-----------------------------------------------------------------*/
627 void simSetBP (unsigned int addr)
628 {
629     char buff[50];
630
631     sprintf(buff,"break 0x%x\n",addr);
632     sendSim(buff);
633     waitForSim(100,NULL);
634 }
635
636 /*-----------------------------------------------------------------*/
637 /* simClearBP - clear a break point                                */
638 /*-----------------------------------------------------------------*/
639 void simClearBP (unsigned int addr)
640 {
641     char buff[50];
642
643     sprintf(buff,"clear 0x%x\n",addr);
644     sendSim(buff);
645     waitForSim(100,NULL);
646 }
647
648 /*-----------------------------------------------------------------*/
649 /* simLoadFile - load the simulator file                           */
650 /*-----------------------------------------------------------------*/
651 void simLoadFile (char *s)
652 {
653     char buff[128];
654
655     sprintf(buff,"file \"%s\"\n",s);
656     printf(buff);
657     sendSim(buff);
658     waitForSim(500,NULL);
659 }
660
661 /*-----------------------------------------------------------------*/
662 /* simGoTillBp - send 'go' to simulator till a bp then return addr */
663 /*-----------------------------------------------------------------*/
664 unsigned int simGoTillBp ( unsigned int gaddr)
665 {
666     char *sr;
667     unsigned addr ;
668     char *sfmt;
669     int wait_ms = 1000;
670
671     invalidateCache(XMEM_CACHE);
672     invalidateCache(IMEM_CACHE);
673     invalidateCache(SREG_CACHE);
674     if (gaddr == 0) {
675         /* initial start, start & stop from address 0 */
676         //char buf[20];
677
678            // this program is setting up a bunch of breakpoints automatically
679            // at key places.  Like at startup & main() and other function
680            // entry points.  So we don't need to setup one here..
681         //sendSim("break 0x0\n");
682         //sleep(1);
683         //waitForSim();
684
685         sendSim("reset\n");
686         waitForSim(wait_ms, NULL);
687         sendSim("run 0x0\n");
688     } else      if (gaddr == -1) { /* resume */
689         sendSim ("run\n");
690         wait_ms = 100;
691     }
692     else        if (gaddr == 1 ) { /* nexti or next */
693         sendSim ("next\n");
694         wait_ms = 100;
695     }
696     else        if (gaddr == 2 ) { /* stepi or step */
697         sendSim ("step\n");
698         wait_ms = 100;
699     }
700     else  {
701         printf("Error, simGoTillBp > 0!\n");
702         exit(1);
703     }
704
705     waitForSim(wait_ms, NULL);
706
707     /* get the simulator response */
708     sr = simResponse();
709     /* check for errors */
710     while ( *sr )
711     {
712         while ( *sr && *sr != 'E' ) sr++ ;
713         if ( !*sr )
714             break;
715         if ( ! strncmp(sr,"Error:",6))
716         {
717             fputs(sr,stdout);
718             break;
719         }
720         sr++ ;
721     }
722
723     nointerrupt = 1;
724     /* get answer of stop command */
725     if ( userinterrupt )
726         waitForSim(wait_ms, NULL);
727
728     /* better solution: ask pc */
729     sendSim ("pc\n");
730     waitForSim(100, NULL);
731     sr = simResponse();
732     nointerrupt = 0;
733
734     gaddr = strtol(sr+3,0,0);
735     return gaddr;
736 }
737
738 /*-----------------------------------------------------------------*/
739 /* simReset - reset the simulator                                  */
740 /*-----------------------------------------------------------------*/
741 void simReset (void)
742 {
743     invalidateCache(XMEM_CACHE);
744     invalidateCache(IMEM_CACHE);
745     invalidateCache(SREG_CACHE);
746     sendSim("res\n");
747     waitForSim(100,NULL);
748 }
749
750
751 /*-----------------------------------------------------------------*/
752 /* closeSimulator - close connection to simulator                  */
753 /*-----------------------------------------------------------------*/
754 void closeSimulator (void)
755 {
756 #ifdef _WIN32
757     if ( ! simin || ! simout || INVALID_SOCKET == sock )
758 #else
759     if ( ! simin || ! simout || sock == -1 )
760 #endif
761     {
762         simactive = 0;
763         return;
764     }
765     simactive = 0;
766     sendSim("quit\n");
767     fclose (simin);
768     fclose (simout);
769     shutdown(sock,2);
770 #ifdef _WIN32
771     closesocket(sock);
772     sock = -1;
773     if (NULL != simPid)
774         TerminateProcess(simPid->hProcess, 0);
775     // Close process and thread handles.
776     CloseHandle(simPid->hProcess);
777     CloseHandle(simPid->hThread);
778 #else
779     close(sock);
780     sock = -1;
781     if ( simPid > 0 )
782         kill (simPid,SIGKILL);
783 #endif
784 }