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