changes from Martin
[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 int simSetValue (unsigned int addr,char mem, int size, unsigned long val)
291 {
292     char cachenr, i;
293     char buffer[40];
294     char *s;
295
296     if ( size <= 0 )
297         return 0;
298
299     cachenr = getMemString(buffer,1,&addr,mem,size);
300     if ( cachenr < NMEM_CACHE )
301     {
302         invalidateCache(cachenr);
303     }
304     s = buffer + strlen(buffer) -1;
305     for ( i = 0 ; i < size ; i++ )
306     {
307         sprintf(s," 0x%x", val & 0xff);
308         s += strlen(s);
309         val >>= 8;
310     }
311     sprintf(s,"\n");
312     sendSim(buffer);
313     waitForSim(100,NULL);
314     simResponse();   
315 }
316
317
318 /*-----------------------------------------------------------------*/
319 /* simGetValue - get value @ address for mem space                 */
320 /*-----------------------------------------------------------------*/
321 unsigned long simGetValue (unsigned int addr,char mem, int size)
322 {
323     unsigned int b[4] = {0,0,0,0}; /* can be a max of four bytes long */
324     char cachenr, i;
325     char buffer[40];
326     char *resp;
327
328     if ( size <= 0 )
329         return 0;
330
331     cachenr = getMemString(buffer,0,&addr,mem,size);
332
333     resp = NULL;
334     if ( cachenr < NMEM_CACHE )
335     {
336         resp = getMemCache(addr,cachenr,size);
337     }
338     if ( !resp )
339     {
340         /* create the simulator command */
341         sendSim(buffer);
342         waitForSim(100,NULL);
343         resp = simResponse();
344
345         /* got the response we need to parse it the response
346            is of the form 
347            [address] [v] [v] [v] ... special case in
348            case of bit variables which case it becomes
349            [address] [assembler bit address] [v] */
350         /* first skip thru white space */
351         while (isspace(*resp)) resp++ ;
352
353         if (strncmp(resp, "0x",2) == 0)
354             resp += 2;
355
356         /* skip thru the address part */
357         while (isxdigit(*resp)) resp++;
358
359     }   
360     /* make the branch for bit variables */
361     if ( cachenr == BIT_CACHE) 
362     {
363         /* skip until newline */
364         while (*resp && *resp != '\n' ) resp++ ;
365         if ( *--resp != '0' )
366             b[0] = 1;
367     }
368     else 
369     {   
370         for (i = 0 ; i < size ; i++ ) 
371         {
372             /* skip white space */
373             while (isspace(*resp)) resp++ ;
374             
375             b[i] = strtol(resp,&resp,16);
376         }
377     }
378
379     return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24 ;
380         
381 }
382
383 /*-----------------------------------------------------------------*/
384 /* simSetBP - set break point for a given address                  */
385 /*-----------------------------------------------------------------*/
386 void simSetBP (unsigned int addr)
387 {
388     char buff[50];
389
390     sprintf(buff,"break 0x%x\n",addr);
391     sendSim(buff);
392     waitForSim(100,NULL);
393 }
394
395 /*-----------------------------------------------------------------*/
396 /* simClearBP - clear a break point                                */
397 /*-----------------------------------------------------------------*/
398 void simClearBP (unsigned int addr)
399 {
400     char buff[50];
401
402     sprintf(buff,"clear 0x%x\n",addr);
403     sendSim(buff);
404     waitForSim(100,NULL);
405 }
406
407 /*-----------------------------------------------------------------*/
408 /* simLoadFile - load the simulator file                           */
409 /*-----------------------------------------------------------------*/
410 void simLoadFile (char *s)
411 {
412     char buff[128];
413
414     sprintf(buff,"l \"%s\"\n",s);
415     printf(buff);
416     sendSim(buff);
417     waitForSim(500,NULL);
418 }
419
420 /*-----------------------------------------------------------------*/
421 /* simGoTillBp - send 'go' to simulator till a bp then return addr */
422 /*-----------------------------------------------------------------*/
423 unsigned int simGoTillBp ( unsigned int gaddr)
424 {
425     char *sr;
426     unsigned addr ; 
427     char *sfmt;
428     int wait_ms = 1000;
429
430     invalidateCache(XMEM_CACHE);
431     invalidateCache(IMEM_CACHE);
432     invalidateCache(SREG_CACHE);
433     if (gaddr == 0) {
434       /* initial start, start & stop from address 0 */
435       //char buf[20];
436
437          // this program is setting up a bunch of breakpoints automatically
438          // at key places.  Like at startup & main() and other function
439          // entry points.  So we don't need to setup one here..
440       //sendSim("break 0x0\n");
441       //sleep(1);
442       //waitForSim();
443
444       sendSim("run 0x0\n");
445     } else      if (gaddr == -1) { /* resume */
446       sendSim ("run\n");
447       wait_ms = 100;
448     }
449     else        if (gaddr == 1 ) { /* nexti or next */
450       sendSim ("next\n");
451       wait_ms = 100;
452     }
453     else        if (gaddr == 2 ) { /* stepi or step */
454       sendSim ("step\n");
455       wait_ms = 100;
456     }
457     else  { 
458       printf("Error, simGoTillBp > 0!\n");
459       exit(1);
460     }
461
462     waitForSim(wait_ms, NULL);
463     
464     /* get the simulator response */
465     sr = simResponse();
466     /* check for errors */
467     while ( *sr )
468     {
469         while ( *sr && *sr != 'E' ) sr++ ;
470         if ( !*sr )
471             break;
472         if ( ! strncmp(sr,"Error:",6))
473         {
474             fputs(sr,stdout);
475             break;
476         }
477         sr++ ;
478     }
479
480     /* better solution: ask pc */
481     sendSim ("pc\n");
482     waitForSim(100, NULL);
483     sr = simResponse();
484
485     gaddr = strtol(sr+3,0,0);
486     return gaddr;
487 }
488
489 /*-----------------------------------------------------------------*/
490 /* simReset - reset the simulator                                  */
491 /*-----------------------------------------------------------------*/
492 void simReset ()
493 {
494     invalidateCache(XMEM_CACHE);
495     invalidateCache(IMEM_CACHE);
496     invalidateCache(SREG_CACHE);
497     sendSim("res\n");
498     waitForSim(100,NULL);
499 }
500
501
502 /*-----------------------------------------------------------------*/
503 /* closeSimulator - close connection to simulator                  */
504 /*-----------------------------------------------------------------*/
505 void closeSimulator ()
506 {
507     if ( ! simin || ! simout || sock == -1 )
508     {
509         simactive = 0;
510         return;
511     }
512     sendSim("quit\n");
513     fclose (simin);
514     fclose (simout);
515     shutdown(sock,2);   
516     close(sock);    
517     sock = -1;
518     if ( simPid > 0 )
519         kill (simPid,SIGKILL);
520 }
521
522