a new function for startup (_main)
[fw/sdcc] / debugger / mcs51 / simi.c
1 /*-------------------------------------------------------------------------
2   simi.c - source file for simulator interaction
3
4               Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19    
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!  
23 -------------------------------------------------------------------------*/
24 #include "sdcdb.h"
25 #include "simi.h"
26
27 #ifdef HAVE_SYS_SOCKET_H
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <unistd.h>
33 #include <signal.h>
34 #else
35 #error "Cannot build debugger without socket support"
36 #endif
37 FILE *simin ; /* stream for simulator input */
38 FILE *simout; /* stream for simulator output */
39
40 int sock = -1; /* socket descriptor to comm with simulator */
41 pid_t simPid = -1;
42 static char simibuff[MAX_SIM_BUFF];    /* sim buffer       */
43 static char regBuff[MAX_SIM_BUFF];
44 static char *sbp = simibuff;           /* simulator buffer pointer */
45 extern char **environ;
46 char simactive = 0;
47
48 static memcache_t memCache[NMEM_CACHE];
49
50 /*-----------------------------------------------------------------*/
51 /* get data from  memory cache/ load cache from simulator          */
52 /*-----------------------------------------------------------------*/
53 static char *getMemCache(unsigned int addr,int cachenum, int size)
54 {
55     char *resp, *buf;
56     unsigned int laddr;
57     memcache_t *cache = &memCache[cachenum];
58
59     if ( cache->size <=   0 ||
60          cache->addr > addr ||
61          cache->addr + cache->size < addr + size )
62     {
63         if ( cachenum == IMEM_CACHE )
64         {
65             sendSim("di 0x0 0xff\n");
66         }
67         else if ( cachenum == SREG_CACHE )
68         {
69             sendSim("ds 0x80 0xff\n");
70         }
71         else
72         {
73             laddr = addr & 0xffffffc0;
74             sprintf(cache->buffer,"dx 0x%x 0x%x\n",laddr,laddr+0xff );
75             sendSim(cache->buffer);
76         }
77         waitForSim(100,NULL);
78         resp = simResponse();
79         cache->addr = strtol(resp,0,0);
80         buf = cache->buffer;
81         cache->size = 0;
82         while ( *resp && *(resp+1) && *(resp+2))
83         {
84             /* cache is a stringbuffer with ascii data like
85                " 00 00 00 00 00 00 00 00"
86             */
87             resp += 2;
88             laddr = 0;
89             /* skip thru the address part */
90             while (isxdigit(*resp)) resp++;
91             while ( *resp && *resp != '\n')
92             {
93                 if ( laddr < 24 )
94                 {
95                     laddr++ ;
96                     *buf++ = *resp ;
97                 }
98                 resp++;
99             }
100             resp++ ;
101             cache->size += 8;
102         }
103         *buf = '\0';
104         if ( cache->addr > addr ||
105              cache->addr + cache->size < addr + size )
106             return NULL;
107     }
108     return cache->buffer + (addr - cache->addr)*3;
109 }
110
111 /*-----------------------------------------------------------------*/
112 /* invalidate memory cache                                         */
113 /*-----------------------------------------------------------------*/
114 static void invalidateCache( int cachenum )
115 {
116     memCache[cachenum].size = 0;  
117 }
118
119 /*-----------------------------------------------------------------*/
120 /* waitForSim - wait till simulator is done its job                */
121 /*-----------------------------------------------------------------*/
122 void waitForSim(int timeout_ms, char *expect)
123 {
124   int i=0;
125   int ch;
126
127 Dprintf(D_simi, ("simi: waitForSim start(%d)\n", timeout_ms));
128     sbp = simibuff;
129
130     while ((ch = fgetc(simin)) > 0 ) {
131       *sbp++ = ch;
132     }
133     *sbp = 0;
134     Dprintf(D_simi, ("waitForSim(%d) got[%s]\n", timeout_ms, simibuff));
135
136 }
137
138 /*-----------------------------------------------------------------*/
139 /* openSimulator - create a pipe to talk to simulator              */
140 /*-----------------------------------------------------------------*/
141 void openSimulator (char **args, int nargs)
142 {
143     struct sockaddr_in sin;     
144     int retry = 0;
145     int i ;
146     Dprintf(D_simi, ("simi: openSimulator\n"));
147 #ifdef SDCDB_DEBUG
148     if (D_simi & sdcdbDebug)
149     {
150         printf("simi: openSimulator: ");
151         for (i=0; i < nargs; i++ )
152         {
153             printf("arg%d: %s ",i,args[i]);
154         }
155         printf("\n");
156     }
157 #endif
158     invalidateCache(XMEM_CACHE);
159     invalidateCache(IMEM_CACHE);
160     invalidateCache(SREG_CACHE);
161     
162  try_connect:
163     sock = socket(AF_INET,SOCK_STREAM,0);
164     
165     memset(&sin,0,sizeof(sin));
166     sin.sin_family = AF_INET;
167     sin.sin_addr.s_addr = inet_addr("127.0.0.1");
168     sin.sin_port = htons(9756);
169     
170     /* connect to the simulator */
171     if (connect(sock,(struct sockaddr *) &sin, sizeof(sin)) < 0) {
172         /* if failed then wait 1 second & try again
173            do this for 10 secs only */
174         if (retry < 10) {
175         if ( !retry )
176         {
177             /* fork and start the simulator as a subprocess */
178             if ((simPid = fork())) {
179                 Dprintf(D_simi, ("simi: simulator pid %d\n",(int) simPid));
180             }
181             else {
182                 /* we are in the child process : start the simulator */
183                 signal(SIGHUP , SIG_IGN );
184                 signal(SIGINT , SIG_IGN );
185                 signal(SIGABRT, SIG_IGN );
186                 signal(SIGCHLD, SIG_IGN );
187
188                 if (execvp(args[0],args) < 0) {
189                     perror("cannot exec simulator");
190                     exit(1);
191                 }
192             }
193         }
194             retry ++;
195         sleep (1);
196             goto try_connect;
197         }
198         perror("connect failed :");
199         exit(1);
200     }
201     /* go the socket now turn it into a file handle */
202     if (!(simin = fdopen(sock,"r"))) {
203         fprintf(stderr,"cannot open socket for read\n");
204         exit(1);
205     }
206
207     if (!(simout = fdopen(sock,"w"))) {
208         fprintf(stderr,"cannot open socket for write\n");
209         exit(1);
210     }
211
212     /* now that we have opened, wait for the prompt */
213     waitForSim(200,NULL);
214     simactive = 1;
215 }
216 /*-----------------------------------------------------------------*/
217 /* simResponse - returns buffer to simulator's response            */
218 /*-----------------------------------------------------------------*/
219 char *simResponse()
220 {
221     return simibuff;
222 }
223
224 /*-----------------------------------------------------------------*/
225 /* sendSim - sends a command to the simuator                 */
226 /*-----------------------------------------------------------------*/
227 void sendSim(char *s)
228 {
229     if ( ! simout ) 
230         return;
231
232     Dprintf(D_simi, ("simi: sendSim-->%s", s));  // s has LF at end already
233     fputs(s,simout);
234     fflush(simout);
235 }
236
237
238 static int getMemString(char *buffer, char wrflag, 
239                         unsigned int *addr, char mem, int size )
240 {
241     int cachenr = NMEM_CACHE;
242     char *prefix;
243     char *cmd ;
244
245     if ( wrflag )
246         cmd = "set mem";
247     else
248         cmd = "dump";
249     buffer[0] = '\0' ;
250
251     switch (mem) 
252     {
253         case 'A': /* External stack */
254         case 'F': /* External ram */
255             prefix = "xram";
256             cachenr = XMEM_CACHE;
257             break;
258         case 'C': /* Code */
259         case 'D': /* Code / static segment */
260             prefix = "rom";
261             break;
262         case 'B': /* Internal stack */  
263         case 'E': /* Internal ram (lower 128) bytes */
264         case 'G': /* Internal ram */
265             prefix = "iram";
266             cachenr = IMEM_CACHE;
267             break;
268         case 'H': /* Bit addressable */
269         case 'J': /* SBIT space */
270             cachenr = BIT_CACHE;
271             if ( wrflag )
272             {
273                 cmd = "set bit";
274             }
275             sprintf(buffer,"%s 0x%x\n",cmd,*addr);
276             return cachenr;
277             break;
278         case 'I': /* SFR space */
279             prefix = "sfr" ;
280             cachenr = SREG_CACHE;
281             break;
282         case 'R': /* Register space */ 
283             prefix = "iram";
284             /* get register bank */
285             cachenr = simGetValue (0xd0,'I',1); 
286             *addr  += cachenr & 0x18 ;
287             cachenr = IMEM_CACHE;
288             break;
289         default: 
290         case 'Z': /* undefined space code */
291             return cachenr;
292     }
293     if ( wrflag )
294         sprintf(buffer,"%s %s 0x%x\n",cmd,prefix,*addr);
295     else
296         sprintf(buffer,"%s %s 0x%x 0x%x\n",cmd,prefix,*addr,*addr+size-1);
297     return cachenr;
298 }
299
300 void simSetPC( unsigned int addr )
301 {
302     char buffer[40];
303     sprintf(buffer,"pc %d\n", addr);
304     sendSim(buffer);
305     waitForSim(100,NULL);
306     simResponse();   
307 }
308
309 int simSetValue (unsigned int addr,char mem, int size, unsigned long val)
310 {
311     char cachenr, i;
312     char buffer[40];
313     char *s;
314
315     if ( size <= 0 )
316         return 0;
317
318     cachenr = getMemString(buffer,1,&addr,mem,size);
319     if ( cachenr < NMEM_CACHE )
320     {
321         invalidateCache(cachenr);
322     }
323     s = buffer + strlen(buffer) -1;
324     for ( i = 0 ; i < size ; i++ )
325     {
326         sprintf(s," 0x%x", val & 0xff);
327         s += strlen(s);
328         val >>= 8;
329     }
330     sprintf(s,"\n");
331     sendSim(buffer);
332     waitForSim(100,NULL);
333     simResponse();   
334     return 0;
335 }
336
337
338 /*-----------------------------------------------------------------*/
339 /* simGetValue - get value @ address for mem space                 */
340 /*-----------------------------------------------------------------*/
341 unsigned long simGetValue (unsigned int addr,char mem, int size)
342 {
343     unsigned int b[4] = {0,0,0,0}; /* can be a max of four bytes long */
344     char cachenr, i;
345     char buffer[40];
346     char *resp;
347
348     if ( size <= 0 )
349         return 0;
350
351     cachenr = getMemString(buffer,0,&addr,mem,size);
352
353     resp = NULL;
354     if ( cachenr < NMEM_CACHE )
355     {
356         resp = getMemCache(addr,cachenr,size);
357     }
358     if ( !resp )
359     {
360         /* create the simulator command */
361         sendSim(buffer);
362         waitForSim(100,NULL);
363         resp = simResponse();
364
365         /* got the response we need to parse it the response
366            is of the form 
367            [address] [v] [v] [v] ... special case in
368            case of bit variables which case it becomes
369            [address] [assembler bit address] [v] */
370         /* first skip thru white space */
371         while (isspace(*resp)) resp++ ;
372
373         if (strncmp(resp, "0x",2) == 0)
374             resp += 2;
375
376         /* skip thru the address part */
377         while (isxdigit(*resp)) resp++;
378
379     }   
380     /* make the branch for bit variables */
381     if ( cachenr == BIT_CACHE) 
382     {
383         /* skip until newline */
384         while (*resp && *resp != '\n' ) resp++ ;
385         if ( *--resp != '0' )
386             b[0] = 1;
387     }
388     else 
389     {   
390         for (i = 0 ; i < size ; i++ ) 
391         {
392             /* skip white space */
393             while (isspace(*resp)) resp++ ;
394             
395             b[i] = strtol(resp,&resp,16);
396         }
397     }
398
399     return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24 ;
400         
401 }
402
403 /*-----------------------------------------------------------------*/
404 /* simSetBP - set break point for a given address                  */
405 /*-----------------------------------------------------------------*/
406 void simSetBP (unsigned int addr)
407 {
408     char buff[50];
409
410     sprintf(buff,"break 0x%x\n",addr);
411     sendSim(buff);
412     waitForSim(100,NULL);
413 }
414
415 /*-----------------------------------------------------------------*/
416 /* simClearBP - clear a break point                                */
417 /*-----------------------------------------------------------------*/
418 void simClearBP (unsigned int addr)
419 {
420     char buff[50];
421
422     sprintf(buff,"clear 0x%x\n",addr);
423     sendSim(buff);
424     waitForSim(100,NULL);
425 }
426
427 /*-----------------------------------------------------------------*/
428 /* simLoadFile - load the simulator file                           */
429 /*-----------------------------------------------------------------*/
430 void simLoadFile (char *s)
431 {
432     char buff[128];
433
434     sprintf(buff,"file \"%s\"\n",s);
435     printf(buff);
436     sendSim(buff);
437     waitForSim(500,NULL);
438 }
439
440 /*-----------------------------------------------------------------*/
441 /* simGoTillBp - send 'go' to simulator till a bp then return addr */
442 /*-----------------------------------------------------------------*/
443 unsigned int simGoTillBp ( unsigned int gaddr)
444 {
445     char *sr;
446     unsigned addr ; 
447     char *sfmt;
448     int wait_ms = 1000;
449
450     invalidateCache(XMEM_CACHE);
451     invalidateCache(IMEM_CACHE);
452     invalidateCache(SREG_CACHE);
453     if (gaddr == 0) {
454       /* initial start, start & stop from address 0 */
455       //char buf[20];
456
457          // this program is setting up a bunch of breakpoints automatically
458          // at key places.  Like at startup & main() and other function
459          // entry points.  So we don't need to setup one here..
460       //sendSim("break 0x0\n");
461       //sleep(1);
462       //waitForSim();
463
464       sendSim("reset\n");
465       waitForSim(wait_ms, NULL);
466       sendSim("run 0x0\n");
467     } else      if (gaddr == -1) { /* resume */
468       sendSim ("run\n");
469       wait_ms = 100;
470     }
471     else        if (gaddr == 1 ) { /* nexti or next */
472       sendSim ("next\n");
473       wait_ms = 100;
474     }
475     else        if (gaddr == 2 ) { /* stepi or step */
476       sendSim ("step\n");
477       wait_ms = 100;
478     }
479     else  { 
480       printf("Error, simGoTillBp > 0!\n");
481       exit(1);
482     }
483
484     waitForSim(wait_ms, NULL);
485     
486     /* get the simulator response */
487     sr = simResponse();
488     /* check for errors */
489     while ( *sr )
490     {
491         while ( *sr && *sr != 'E' ) sr++ ;
492         if ( !*sr )
493             break;
494         if ( ! strncmp(sr,"Error:",6))
495         {
496             fputs(sr,stdout);
497             break;
498         }
499         sr++ ;
500     }
501
502     nointerrupt = 1;
503     /* get answer of stop command */
504     if ( userinterrupt )
505         waitForSim(wait_ms, NULL);
506
507     /* better solution: ask pc */
508     sendSim ("pc\n");
509     waitForSim(100, NULL);
510     sr = simResponse();
511     nointerrupt = 0;
512
513     gaddr = strtol(sr+3,0,0);
514     return gaddr;
515 }
516
517 /*-----------------------------------------------------------------*/
518 /* simReset - reset the simulator                                  */
519 /*-----------------------------------------------------------------*/
520 void simReset ()
521 {
522     invalidateCache(XMEM_CACHE);
523     invalidateCache(IMEM_CACHE);
524     invalidateCache(SREG_CACHE);
525     sendSim("res\n");
526     waitForSim(100,NULL);
527 }
528
529
530 /*-----------------------------------------------------------------*/
531 /* closeSimulator - close connection to simulator                  */
532 /*-----------------------------------------------------------------*/
533 void closeSimulator ()
534 {
535     if ( ! simin || ! simout || sock == -1 )
536     {
537         simactive = 0;
538         return;
539     }
540     simactive = 0;
541     sendSim("quit\n");
542     fclose (simin);
543     fclose (simout);
544     shutdown(sock,2);   
545     close(sock);    
546     sock = -1;
547     if ( simPid > 0 )
548         kill (simPid,SIGKILL);
549 }
550
551