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