1 /*-------------------------------------------------------------------------
2 rtrack.c - tracking content of registers on an mcs51
4 Copyright 2007 Frieder Ferlemann (Frieder Ferlemann AT web.de)
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
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.
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, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 -------------------------------------------------------------------------*/
21 /*-------------------------------------------------------------------------
23 - passes regression test suite, still bugs are likely
24 - only active if environment variable SDCC_RTRACK is set
27 - does not track symbols as in "mov a,#_my_int" or "mov a,#(_my_int+1)"
28 - only used with moves to acc so chances to use: "inc dptr",
29 "inc r2", "add a,r2" or "mov r2,a" would not be detected)
30 - a label causes loss of tracking (no handling of information of blocks
31 known to follow/preceed the current block)
32 - not used in aopGet or genRet
33 -------------------------------------------------------------------------*/
38 #include "SDCCglobl.h"
49 #define REGS8051_SET(idx,val) do{ \
50 regs8051[idx].value = (val) & 0xff; \
51 regs8051[idx].valueKnown = 1; \
52 DEBUG(printf("%s:0x%02x\n",regs8051[idx].name, \
53 regs8051[idx].value);) \
56 #define REGS8051_UNSET(idx) do{ \
57 regs8051[idx].valueKnown = 0; \
58 DEBUG(printf("%s:*\n",regs8051[idx].name);) \
61 /* r0..r7 are not in numerical order in struct regs: r2..r7,r0,r1 */
62 #define Rx_NUM_TO_IDX(num) (R2_IDX+((num-2)&0x07))
65 /* move this (or rtrackGetLit() and rtrackMoveALit()
66 elsewhere? stealing emitcode from gen.c */
67 void emitcode (const char *inst, const char *fmt,...);
70 static int enable = -1;
78 for (i=0; i<END_IDX; i++)
80 if (regs8051[i].valueKnown)
84 DEBUG(printf("know:");)
86 DEBUG(printf(" %s:0x%02x",regs8051[i].name,regs8051[i].value);)
98 static void invalidateAllRx()
101 DEBUG(printf("R0..7:*\n");)
102 regs8051[R2_IDX].valueKnown = 0;
103 regs8051[R3_IDX].valueKnown = 0;
104 regs8051[R4_IDX].valueKnown = 0;
105 regs8051[R5_IDX].valueKnown = 0;
106 regs8051[R6_IDX].valueKnown = 0;
107 regs8051[R7_IDX].valueKnown = 0;
108 regs8051[R0_IDX].valueKnown = 0;
109 regs8051[R1_IDX].valueKnown = 0;
112 static void invalidateAll()
114 DEBUG(printf("All:* ");)
116 regs8051[DPL_IDX].valueKnown = 0;
117 regs8051[DPH_IDX].valueKnown = 0;
118 regs8051[B_IDX].valueKnown = 0;
119 regs8051[A_IDX].valueKnown = 0;
123 /* tracking values within registers by looking
124 at the line passed to the assembler.
125 Tries to keep regs8051[] up to date */
126 void rtrackUpdate (const char *line)
129 enable = (NULL != getenv("SDCC_RTRACK"));
132 *line == ';' || /* comment */
133 (NULL != strstr( line, "==."))) /* dirty check for _G.debugLine */
134 return; /* nothing to do */
136 DEBUG(printf("%s\n",line);)
138 if (!strncmp (line,"mov",3))
140 /* check literal mov to accumulator */
141 if(!strncmp (line,"mov\ta,#0x",9))
146 value = strtol (line+7, &s, 16);
148 REGS8051_SET (A_IDX, value); /* valid hex found */
150 REGS8051_UNSET (A_IDX); /* probably a symbol (not handled) */
155 if (!strncmp (line,"mov\ta,r",7))
157 /* handle mov from Rx if Rx is known */
161 regNum = strtol (line+7, &s, 16);
164 regs *r = ®s8051[Rx_NUM_TO_IDX(regNum)];
167 REGS8051_SET (A_IDX, r->value);
171 REGS8051_UNSET (A_IDX);
175 if (!strncmp (line,"mov\ta",5))
177 REGS8051_UNSET (A_IDX);
181 if (!strncmp (line,"movc\ta",6) ||
182 !strncmp (line,"movx\ta",6))
184 REGS8051_UNSET (A_IDX);
188 /* move direct to symbol, do not care */
189 if (!strncmp (line,"mov\t_",5) ||
190 !strncmp (line,"mov\t(_",6))
193 /* check literal mov to register */
194 if (!strncmp (line,"mov\tr",5))
200 regNum = strtol (line+5, &s, 16);
203 value = strtol (line+8, &s, 16);
204 if ((s != line+8) && !strncmp (line+6,",#0x",4))
205 REGS8051_SET (Rx_NUM_TO_IDX(regNum), value);
207 REGS8051_UNSET (Rx_NUM_TO_IDX(regNum));
212 /* mov to psw can change register bank */
213 if (!strncmp (line,"mov\tpsw,",8))
219 /* no tracking of these, so we do not care */
220 if (!strncmp (line,"mov\tdptr,#",10) ||
221 !strncmp (line,"mov\tdpl,",8) ||
222 !strncmp (line,"mov\tdph,",8) ||
223 !strncmp (line,"mov\tsp,",7) ||
224 !strncmp (line,"mov\tb,",6))
227 /* mov to xdata memory does not change registers */
228 if (!strncmp (line,"movx\t@",6))
231 if (!strncmp (line,"mov\t@",5))
238 /* no tracking of SP */
239 if (!strncmp (line,"push",4))
242 if (!strncmp (line,"pop\ta",5))
244 if (!strncmp (line+4,"acc",3)){ REGS8051_UNSET (A_IDX); return; }
245 if (!strncmp (line+4,"ar2",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (2)); return; }
246 if (!strncmp (line+4,"ar3",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (3)); return; }
247 if (!strncmp (line+4,"ar4",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (4)); return; }
248 if (!strncmp (line+4,"ar5",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (5)); return; }
249 if (!strncmp (line+4,"ar6",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (6)); return; }
250 if (!strncmp (line+4,"ar7",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (7)); return; }
251 if (!strncmp (line+4,"ar0",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (0)); return; }
252 if (!strncmp (line+4,"ar1",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (1)); return; }
255 if (!strncmp (line,"inc",3))
257 /* no tracking of dptr, ignore */
258 if (!strcmp (line,"inc\tdptr") ||
259 !strcmp (line,"inc\tdph") ||
260 !strcmp (line,"inc\tdpl"))
263 if (!strcmp (line,"inc\ta"))
265 if (regs8051[A_IDX].valueKnown)
266 REGS8051_SET (A_IDX, regs8051[A_IDX].value+1);
270 if(!strncmp (line,"inc\tr",5))
275 regNum = strtol (line+5, &s, 16);
278 regs *r = ®s8051[Rx_NUM_TO_IDX(regNum)];
281 REGS8051_SET (Rx_NUM_TO_IDX(regNum), r->value+1);
288 /* unfortunately the label typically following these
289 will cause loss of tracking */
290 if (!strncmp (line,"jc\t",3) ||
291 !strncmp (line,"jnc\t",4) ||
292 !strncmp (line,"jb\t",3) ||
293 !strncmp (line,"jnb\t",4) ||
294 !strncmp (line,"jbc\t",4))
297 /* if branch not taken in "cjne r2,#0x08,somewhere"
298 r2 is known to be 8 */
299 if (!strncmp (line,"cjne",4))
302 /* acc eventually known to be zero */
303 if (!strncmp (line,"jz\t",3) ||
304 !strncmp (line,"jnz\t",4))
307 if (!strncmp (line,"djnz\tr",6))
312 regNum = strtol (line+6, &s, 16);
315 REGS8051_UNSET (Rx_NUM_TO_IDX(regNum));
316 // REGS8051_SET (Rx_NUM_TO_IDX(regNum), 0x00); // branch not taken
321 /* only carry bit, so we do not care */
322 if (!strncmp (line,"setb\tc",6) ||
323 !strncmp (line,"clr\tc",5) ||
324 !strncmp (line,"cpl\tc",5))
327 if (!strncmp (line,"add\ta,",6) ||
328 !strncmp (line,"addc\ta,",7)||
329 !strncmp (line,"subb\ta,",7)||
330 !strncmp (line,"xrl\ta,",6) ||
331 !strncmp (line,"orl\ta,",6) ||
332 !strncmp (line,"anl\ta,",6) ||
333 !strncmp (line,"da\ta",4) ||
334 !strncmp (line,"rlc\ta,",6) ||
335 !strncmp (line,"rrc\ta,",6) ||
336 !strncmp (line,"setb\ta",6) ||
337 !strncmp (line,"clrb\ta,",7))
339 /* could also handle f.e. "add a,Rx" if a, Rx are known or "xrl a,#0x08" */
340 REGS8051_UNSET (A_IDX);
345 if (!strncmp (line,"dec",3))
347 /* no tracking of dptr, so we would not care */
348 if (!strcmp (line,"dec\tdph") ||
349 !strcmp (line,"dec\tdpl"))
352 if (!strcmp (line,"dec\ta"))
354 if (regs8051[A_IDX].valueKnown)
355 REGS8051_SET (A_IDX, regs8051[A_IDX].value-1);
359 if(!strncmp (line,"dec\tr",5))
364 regNum = strtol (line+5, &s, 16);
367 regs *r = ®s8051[Rx_NUM_TO_IDX(regNum)];
370 REGS8051_SET (Rx_NUM_TO_IDX(regNum), r->value-1);
378 if (!strcmp (line,"clr\ta"))
380 REGS8051_SET (A_IDX, 0);
384 if (!strcmp (line,"cpl\ta"))
386 if (regs8051[A_IDX].valueKnown)
387 REGS8051_SET (A_IDX, ~regs8051[A_IDX].value);
390 if (!strcmp (line,"rl\ta"))
392 if (regs8051[A_IDX].valueKnown)
393 REGS8051_SET (A_IDX, (regs8051[A_IDX].value<<1) |
394 (regs8051[A_IDX].value>>7) );
397 if (!strcmp (line,"rr\ta"))
399 if (regs8051[A_IDX].valueKnown)
400 REGS8051_SET (A_IDX, (regs8051[A_IDX].value>>1) |
401 (regs8051[A_IDX].value<<7));
404 if (!strcmp (line,"swap\ta"))
406 if (regs8051[A_IDX].valueKnown)
407 REGS8051_SET (A_IDX, (regs8051[A_IDX].value>>4) |
408 (regs8051[A_IDX].value<<4));
412 if (!strncmp (line,"mul",3) ||
413 !strncmp (line,"div",3)
416 REGS8051_UNSET (A_IDX);
417 REGS8051_UNSET (B_IDX);
421 /* assuming these library functions have no side-effects */
422 if (!strcmp (line,"lcall"))
424 if (!strcmp (line,"lcall\t__gptrput"))
426 /* invalidate R0..R7 because they might have been changed */
430 if (!strcmp (line,"lcall\t__gptrget"))
432 REGS8051_UNSET (A_IDX);
435 if (!strcmp (line,"lcall\t__decdptr"))
441 /* all others unrecognized, invalidate */
446 /* expects f.e. "#0x01" and returns either "#0x01"
447 if the value is not known to be within registers
448 or "a" or "r0".."r7".
449 (mov a,r7 or add a,r7 need one byte whereas
450 mov a,#0x01 or add a,#0x01 would take two
452 char * rtrackGetLit(const char *x)
461 /* was it a numerical literal? */
464 int val = strtol (x+1, &s, 16);
467 /* try to get from acc */
468 regs *r = ®s8051[A_IDX];
472 D(emitcode (";", "genFromRTrack 0x%02x=%s", val, r->name));
475 /* try to get from register R0..R7 */
478 regs *r = ®s8051[Rx_NUM_TO_IDX(i)];
482 D(emitcode (";", "genFromRTrack 0x%02x=%s", val, r->name));
489 /* probably a symbolic literal as in "mov r3,#(_i+1)",
497 /* Similar to the above function
498 As the destination is the accumulator try harder yet and
499 try to generate the result with arithmetic operations */
500 int rtrackMoveALit (const char *x)
506 /* if it is a literal mov try to get it cheaper */
509 regs *a = ®s8051[A_IDX];
512 int val = strtol (x+1, &s, 16);
514 /* was it a numerical literal? */
517 /* prefer mov a,#0x00 */
519 ((a->valueKnown && a->value != 0) ||
522 /* peepholes convert to clr a */
523 emitcode ("mov", "a,#0x00");
532 D(emitcode (";", "genFromRTrack acc=0x%02x", a->value));
536 /* can be calculated with an instruction
537 that does not change flags from acc itself? */
538 if (val == ((a->value+1) & 0xff) )
540 D(emitcode (";", "genFromRTrack 0x%02x=0x%02x+1", val, a->value));
541 emitcode ("inc", "a");
544 if (val == ((a->value-1) & 0xff) )
546 D(emitcode (";", "genFromRTrack 0x%02x=0x%02x-1", val, a->value));
547 emitcode ("dec", "a");
550 if (val == ((~a->value) & 0xff) )
552 D(emitcode (";", "genFromRTrack 0x%02x=~0x%02x", val, a->value));
553 emitcode ("cpl", "a");
556 if (val == (((a->value>>1) |
557 (a->value<<7)) & 0xff))
559 D(emitcode (";", "genFromRTrack 0x%02x=rr(0x%02x)", val, a->value));
560 emitcode ("rr", "a");
563 if (val == (((a->value<<1) |
564 (a->value>>7)) & 0xff ))
566 D(emitcode (";", "genFromRTrack 0x%02x=rl(0x%02x)", val, a->value));
567 emitcode ("rl", "a");
570 if (val == ( ((a->value & 0x0f)<<4) |
571 ((a->value & 0xf0)>>4) ))
573 D(emitcode (";", "genFromRTrack 0x%02x=swap(0x%02x)", val, a->value));
574 emitcode ("swap", "a");
577 /* Decimal Adjust Accumulator (da a) changes flags so not used */
583 char *ptr= rtrackGetLit(x);
587 /* could get from register, fine */
588 emitcode ("mov", "a,%s", ptr);
592 /* not yet giving up - try to calculate from register R0..R7 */
595 regs *r = ®s8051[Rx_NUM_TO_IDX(i)];
597 if (a->valueKnown && r->valueKnown)
599 /* calculate with a single byte instruction from R0..R7? */
600 if (val == (a->value | r->value))
602 D(emitcode (";", "genFromRTrack 0x%02x=0x%02x|0x%02x",
603 val, a->value, r->value));
604 emitcode ("orl", "a,%s",r->name);
607 if (val == (a->value & r->value))
609 D(emitcode (";", "genFromRTrack 0x%02x=0x%02x&0x%02x",
610 val, a->value, r->value));
611 emitcode ("anl", "a,%s", r->name);
614 if (val == (a->value ^ r->value))
616 D(emitcode (";", "genFromRTrack 0x%02x=0x%02x^0x%02x",
617 val, a->value, r->value));
618 emitcode ("xrl", "a,%s", r->name);
621 /* changes flags (does that matter?)
622 if (val == (a->value + r->value))
624 D(emitcode (";", "genFromRTrack 0x%02x=0x%02x+%0x02x",
625 val, a->value, r->value));
626 emitcode ("add", "a,%s",r->name);