Fix asm label generation. Suppress some warning
[fw/sdcc] / src / avr / gen.c
1 /*-------------------------------------------------------------------------
2   avrgen.c - source file for code generation for ATMEL AVR
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (2000)
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
25 -------------------------------------------------------------------------*/
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include "SDCCglobl.h"
32 #include "newalloc.h"
33
34 #ifdef HAVE_SYS_ISA_DEFS_H
35 #include <sys/isa_defs.h>
36 #else
37 #ifdef HAVE_ENDIAN_H
38 #include <endian.h>
39 #else
40 #if !defined(__BORLANDC__) && !defined(_MSC_VER)
41 #warning "Cannot determine ENDIANESS of this machine assuming LITTLE_ENDIAN"
42 #warning "If you running sdcc on an INTEL 80x86 Platform you are okay"
43 #endif
44 #endif
45 #endif
46
47 #include "common.h"
48 #include "SDCCpeeph.h"
49 #include "ralloc.h"
50 #include "gen.h"
51
52 char *aopLiteral (value *val, int offset);
53 extern int allocInfo;
54
55 /* this is the down and dirty file with all kinds of
56    kludgy & hacky stuff. This is what it is all about
57    CODE GENERATION for a specific MCU . some of the
58    routines may be reusable, will have to see */
59
60 static char *zero = "0x00";
61 static char *one  = "0x01";
62 static char *spname ;
63
64 char *fReturnAVR[] = {"r16","r17","r18","r19" };
65 unsigned fAVRReturnSize = 4; /* shared with ralloc.c */
66 char **fAVRReturn = fReturnAVR;
67 static short rbank = -1;
68 static char *larray[4] = {"lo8","hi8","hlo8","hhi8"};
69 static char *tscr[4] = {"r0","r1","r24","r25"};
70 static struct {
71   short xPushed;
72   short zPushed;
73   short accInUse;
74   short inLine;
75   short debugLine;
76   short nRegsSaved;
77   set *sendSet;
78 } _G;
79
80 extern int avr_ptrRegReq ;
81 extern int avr_nRegs;
82 extern FILE *codeOutFile;
83 static void saverbank (int, iCode *,bool);
84 #define RESULTONSTACK(x) \
85                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
86                          IC_RESULT(x)->aop->type == AOP_STK )
87
88 #define MOVR0(x) if (strcmp(x,"r0")) emitcode("mov","r0,%s",x);
89 #define CLRC    emitcode("clc","")
90 #define SETC    emitcode("stc","")
91 #define MOVA(x)
92 #define IS_REGIDX(a,r) (a->type == AOP_REG && a->aopu.aop_reg[0]->rIdx == r)
93
94 static lineNode *lineHead = NULL;
95 static lineNode *lineCurr = NULL;
96
97 static unsigned char   SLMask[] = {0xFF ,0xFE, 0xFC, 0xF8, 0xF0,
98            0xE0, 0xC0, 0x80, 0x00};
99 static unsigned char   SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
100            0x07, 0x03, 0x01, 0x00};
101
102 #define LSB     0
103 #define MSB16   1
104 #define MSB24   2
105 #define MSB32   3
106
107 /*-----------------------------------------------------------------*/
108 /* emitcode - writes the code into a file : for now it is simple    */
109 /*-----------------------------------------------------------------*/
110 static void emitcode (char *inst,char *fmt, ...)
111 {
112   va_list ap;
113   char lb[MAX_INLINEASM];
114   char *lbp = lb;
115
116   va_start(ap,fmt);
117
118   if (inst && *inst) {
119     if (fmt && *fmt)
120       sprintf(lb,"%s\t",inst);
121     else
122       sprintf(lb,"%s",inst);
123     vsprintf(lb+(strlen(lb)),fmt,ap);
124   }  else
125     vsprintf(lb,fmt,ap);
126
127   while (isspace(*lbp)) lbp++;
128
129   if (lbp && *lbp)
130     lineCurr = (lineCurr ?
131           connectLine(lineCurr,newLineNode(lb)) :
132           (lineHead = newLineNode(lb)));
133   lineCurr->isInline = _G.inLine;
134   lineCurr->isDebug  = _G.debugLine;
135   va_end(ap);
136 }
137
138 /*-----------------------------------------------------------------*/
139 /* getFreePtr - returns X or Z whichever is free or can be pushed  */
140 /*-----------------------------------------------------------------*/
141 static regs *getFreePtr (iCode *ic, asmop **aopp, bool result, bool zonly)
142 {
143   bool xiu = FALSE , ziu = FALSE;
144   bool xou = FALSE , zou = FALSE;
145
146   /* the logic: if x & z used in the instruction
147      then we are in trouble otherwise */
148
149   /* first check if x & z are used by this
150      instruction, in which case we are in trouble */
151   if ((xiu = bitVectBitValue(ic->rUsed,X_IDX)) &&
152       (ziu = bitVectBitValue(ic->rUsed,Z_IDX)))
153     {
154       goto endOfWorld;
155     }
156
157   xou = bitVectBitValue(ic->rMask,X_IDX);
158   zou = bitVectBitValue(ic->rMask,Z_IDX);
159
160   /* if no usage of Z then return it */
161   if (!ziu && !zou) {
162     ic->rUsed = bitVectSetBit(ic->rUsed,Z_IDX);
163     (*aopp)->type = AOP_Z;
164
165     (*aopp)->aop_ptr2 = avr_regWithIdx(R31_IDX);
166     return (*aopp)->aopu.aop_ptr = avr_regWithIdx(R30_IDX);
167   }
168
169   /* if no usage of X then return it */
170   if (!xiu && !xou && !zonly) {
171     ic->rUsed = bitVectSetBit(ic->rUsed,X_IDX);
172     (*aopp)->type = AOP_X;
173
174     (*aopp)->aop_ptr2 = avr_regWithIdx(R27_IDX);
175     return (*aopp)->aopu.aop_ptr = avr_regWithIdx(R26_IDX);
176   }
177
178   /* if z not used then */
179
180   if (!ziu) {
181     /* push it if not already pushed */
182     if (!_G.zPushed) {
183       emitcode ("push","%s",
184           avr_regWithIdx(R30_IDX)->dname);
185       emitcode ("push","%s",
186           avr_regWithIdx(R31_IDX)->dname);
187       _G.zPushed++ ;
188     }
189
190     ic->rUsed = bitVectSetBit(ic->rUsed,Z_IDX);
191     (*aopp)->type = AOP_Z;
192     (*aopp)->aop_ptr2 = avr_regWithIdx(R31_IDX);
193     return (*aopp)->aopu.aop_ptr = avr_regWithIdx(R30_IDX);
194   }
195
196   /* now we know they both have usage */
197   /* if x not used in this instruction */
198   if (!xiu && !zonly) {
199     /* push it if not already pushed */
200     if (!_G.xPushed) {
201       emitcode ("push","%s",
202           avr_regWithIdx(R26_IDX)->dname);
203       emitcode ("push","%s",
204           avr_regWithIdx(R27_IDX)->dname);
205       _G.xPushed++ ;
206     }
207
208     ic->rUsed = bitVectSetBit(ic->rUsed,X_IDX);
209     (*aopp)->type = AOP_X;
210
211     (*aopp)->aop_ptr2 = avr_regWithIdx(R27_IDX);
212     return (*aopp)->aopu.aop_ptr = avr_regWithIdx(R26_IDX);
213   }
214
215
216   endOfWorld :
217     /* I said end of world but not quite end of world yet */
218     /* if this is a result then we can push it on the stack*/
219     if (result) {
220       (*aopp)->type = AOP_STK;
221       return NULL;
222     }
223
224   piCode(ic,stdout);
225   /* other wise this is true end of the world */
226   werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
227          "getFreePtr should never reach here");
228   exit(0);
229 }
230
231 /*-----------------------------------------------------------------*/
232 /* newAsmop - creates a new asmOp                                  */
233 /*-----------------------------------------------------------------*/
234 static asmop *newAsmop (short type)
235 {
236   asmop *aop;
237
238   aop = Safe_calloc(1,sizeof(asmop));
239   aop->type = type;
240   return aop;
241 }
242
243 /*-----------------------------------------------------------------*/
244 /* pointerCode - returns the code for a pointer type               */
245 /*-----------------------------------------------------------------*/
246 static int pointerCode (sym_link *etype)
247 {
248
249   return PTR_TYPE(SPEC_OCLS(etype));
250
251 }
252
253 /*-----------------------------------------------------------------*/
254 /* aopForSym - for a true symbol                                   */
255 /*-----------------------------------------------------------------*/
256 static asmop *aopForSym (iCode *ic,symbol *sym,bool result)
257 {
258   asmop *aop;
259   memmap *space= SPEC_OCLS(sym->etype);
260
261   /* if already has one */
262   if (sym->aop)
263     return sym->aop;
264
265   /* assign depending on the storage class */
266   /* if it is on the stack */
267   if (sym->onStack) {
268     sym->aop = aop = newAsmop(0);
269     aop->size = getSize(sym->type);
270
271     /* we can use std / ldd instruction */
272     if (sym->stack > 0 && (sym->stack + getSize(sym->type) - 1) <= 63) {
273       aop->type = AOP_STK_D;
274       aop->aopu.aop_stk = sym->stack;
275       return aop;
276     }
277
278     /* otherwise get a free pointer register X/Z */
279     aop->aopu.aop_ptr = getFreePtr(ic,&aop,result,FALSE);
280
281     /* now assign the address of the variable to
282        the pointer register */
283     if (aop->type != AOP_STK) {
284       emitcode("movw","%s,r28",aop->aopu.aop_ptr->name);
285       if (sym->stack < 0) {
286         if ((sym->stack - _G.nRegsSaved) > -63) {
287           emitcode("sbiw","%s,0x%02x",
288              aop->aopu.aop_ptr->name,
289              (sym->stack - _G.nRegsSaved));
290         } else {
291           emitcode("subi","%s,lo8(%d)", aop->aopu.aop_ptr->name,
292              sym->stack - _G.nRegsSaved);
293           emitcode("sbci","%s,hi8(%d)",aop->aop_ptr2->name,
294              sym->stack - _G.nRegsSaved);
295         }
296       } else {
297         if (sym->stack <= 63) {
298           emitcode("adiw","%s,0x%02x",aop->aopu.aop_ptr->name,sym->stack);
299         } else {
300           emitcode("subi","%s,lo8(-%d)",aop->aopu.aop_ptr->name,sym->stack);
301           emitcode("sbci","%s,hi8(-%d)",aop->aop_ptr2->name,sym->stack);
302         }
303       }
304     }
305     return aop;
306   }
307
308   /* if in bit space */
309   if (IN_BITSPACE(space)) {
310     sym->aop = aop = newAsmop (AOP_CRY);
311     aop->aopu.aop_dir = sym->rname ;
312     aop->size = getSize(sym->type);
313     return aop;
314   }
315   /* if it is in direct space */
316   if (IN_DIRSPACE(space)) {
317     sym->aop = aop = newAsmop (AOP_DIR);
318     aop->aopu.aop_dir = sym->rname ;
319     aop->size = getSize(sym->type);
320     return aop;
321   }
322
323   /* special case for a function */
324   if (IS_FUNC(sym->type)) {
325     sym->aop = aop = newAsmop(AOP_IMMD);
326     aop->aopu.aop_immd = Safe_calloc(1,strlen(sym->rname)+1);
327     strcpy(aop->aopu.aop_immd,sym->rname);
328     aop->size = FPTRSIZE;
329     return aop;
330   }
331
332   /* only remaining is code / eeprom which will need pointer reg */
333   /* if it is in code space */
334
335   sym->aop = aop = newAsmop(0);
336
337   if (IN_CODESPACE(space))
338     aop->code = 1;
339
340   aop->aopu.aop_ptr = getFreePtr(ic,&aop,result,aop->code);
341   aop->size = getSize(sym->type);
342   emitcode ("ldi","%s,lo8(%s)",aop->aopu.aop_ptr->name,sym->rname);
343   emitcode ("ldi","%s,hi8(%s)",aop->aop_ptr2);
344
345   return aop;
346 }
347
348 /*-----------------------------------------------------------------*/
349 /* aopForRemat - rematerialzes an object                           */
350 /*-----------------------------------------------------------------*/
351 static asmop *aopForRemat (symbol *sym)
352 {
353   iCode *ic = sym->rematiCode;
354   asmop *aop = newAsmop(AOP_IMMD);
355   int val = 0;
356
357   for (;;) {
358     if (ic->op == '+')
359       val += (int) operandLitValue(IC_RIGHT(ic));
360     else if (ic->op == '-')
361       val -= (int) operandLitValue(IC_RIGHT(ic));
362     else
363       break;
364
365     ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
366   }
367
368   if (val)
369     sprintf(buffer,"(%s %c 0x%04x)",
370       OP_SYMBOL(IC_LEFT(ic))->rname,
371       val >= 0 ? '+' : '-',
372       abs(val) & 0xffff);
373   else
374     strcpy(buffer,OP_SYMBOL(IC_LEFT(ic))->rname);
375
376   aop->aopu.aop_immd = Safe_calloc(1,strlen(buffer)+1);
377   strcpy(aop->aopu.aop_immd,buffer);
378   return aop;
379 }
380
381 /*-----------------------------------------------------------------*/
382 /* regsInCommon - two operands have some registers in common       */
383 /*-----------------------------------------------------------------*/
384 static bool regsInCommon (operand *op1, operand *op2)
385 {
386   symbol *sym1, *sym2;
387   int i;
388
389   /* if they have registers in common */
390   if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
391     return FALSE ;
392
393   sym1 = OP_SYMBOL(op1);
394   sym2 = OP_SYMBOL(op2);
395
396   if (sym1->nRegs == 0 || sym2->nRegs == 0)
397     return FALSE ;
398
399   for (i = 0 ; i < sym1->nRegs ; i++) {
400     int j;
401     if (!sym1->regs[i])
402       continue ;
403
404     for (j = 0 ; j < sym2->nRegs ;j++ ) {
405       if (!sym2->regs[j])
406         continue ;
407
408       if (sym2->regs[j] == sym1->regs[i])
409         return TRUE ;
410     }
411   }
412
413   return FALSE ;
414 }
415
416 /*-----------------------------------------------------------------*/
417 /* operandsEqu - equivalent                                        */
418 /*-----------------------------------------------------------------*/
419 static bool operandsEqu ( operand *op1, operand *op2)
420 {
421   symbol *sym1, *sym2;
422
423   /* if they not symbols */
424   if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
425     return FALSE;
426
427   sym1 = OP_SYMBOL(op1);
428   sym2 = OP_SYMBOL(op2);
429
430   /* if both are itemps & one is spilt
431      and the other is not then false */
432   if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
433       sym1->isspilt != sym2->isspilt )
434     return FALSE ;
435
436   /* if they are the same */
437   if (sym1 == sym2)
438     return TRUE ;
439
440   if (strcmp(sym1->rname,sym2->rname) == 0)
441     return TRUE;
442
443
444   /* if left is a tmp & right is not */
445   if (IS_ITEMP(op1)  &&
446       !IS_ITEMP(op2) &&
447       sym1->isspilt  &&
448       (sym1->usl.spillLoc == sym2))
449     return TRUE;
450
451   if (IS_ITEMP(op2)  &&
452       !IS_ITEMP(op1) &&
453       sym2->isspilt  &&
454       sym1->level > 0 &&
455       (sym2->usl.spillLoc == sym1))
456     return TRUE ;
457
458   return FALSE ;
459 }
460
461 /*-----------------------------------------------------------------*/
462 /* sameRegs - two asmops have the same registers                   */
463 /*-----------------------------------------------------------------*/
464 static bool sameRegs (asmop *aop1, asmop *aop2 )
465 {
466   int i;
467
468   if (aop1 == aop2)
469     return TRUE ;
470
471   if (aop1->type != AOP_REG ||
472       aop2->type != AOP_REG )
473     return FALSE ;
474
475   if (aop1->size != aop2->size )
476     return FALSE ;
477
478   for (i = 0 ; i < aop1->size ; i++ )
479     if (aop1->aopu.aop_reg[i] !=
480         aop2->aopu.aop_reg[i] )
481       return FALSE ;
482
483   return TRUE ;
484 }
485
486 /*-----------------------------------------------------------------*/
487 /* isRegPair - for size 2 if this operand has a register pair      */
488 /*-----------------------------------------------------------------*/
489 static int isRegPair (asmop *aop)
490 {
491   if (!aop || aop->size != 2) return 0;
492   if (aop->type == AOP_X || aop->type == AOP_Z) return 1;
493   if (aop->type != AOP_REG) return 0;
494   if ((aop->aopu.aop_reg[1]->rIdx -
495        aop->aopu.aop_reg[0]->rIdx) == 1) return 1;
496   return 0;
497 }
498
499 /*-----------------------------------------------------------------*/
500 /* aopOp - allocates an asmop for an operand  :                    */
501 /*-----------------------------------------------------------------*/
502 static void aopOp (operand *op, iCode *ic, bool result)
503 {
504   asmop *aop;
505   symbol *sym;
506   int i;
507
508   if (!op)
509     return ;
510
511   /* if this a literal */
512   if (IS_OP_LITERAL(op)) {
513     op->aop = aop = newAsmop(AOP_LIT);
514     aop->aopu.aop_lit = op->operand.valOperand;
515     aop->size = getSize(operandType(op));
516     return;
517   }
518
519   /* if already has a asmop then continue */
520   if (op->aop)
521     return ;
522
523   /* if the underlying symbol has a aop */
524   if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
525     op->aop = OP_SYMBOL(op)->aop;
526     return;
527   }
528
529   /* if this is a true symbol */
530   if (IS_TRUE_SYMOP(op)) {
531     op->aop = aopForSym(ic,OP_SYMBOL(op),result);
532     return ;
533   }
534
535   /* this is a temporary : this has
536      only four choices :
537      a) register
538      b) spillocation
539      c) rematerialize
540      d) conditional
541      e) can be a return use only */
542
543   sym = OP_SYMBOL(op);
544
545
546   /* if the type is a conditional */
547   if (sym->regType == REG_CND) {
548     aop = op->aop = sym->aop = newAsmop(AOP_CRY);
549     aop->size = 0;
550     return;
551   }
552
553   /* if it is spilt then two situations
554      a) is rematerialize
555      b) has a spill location */
556   if (sym->isspilt || sym->nRegs == 0) {
557
558     /* rematerialize it NOW */
559     if (sym->remat) {
560       sym->aop = op->aop = aop =
561         aopForRemat (sym);
562       aop->size = getSize(sym->type);
563       return;
564     }
565
566     if (sym->accuse) {
567       assert("ACC_USE cannot happen in AVR\n");
568     }
569
570     if (sym->ruonly ) {
571       int i;
572       aop = op->aop = sym->aop = newAsmop(AOP_STR);
573       aop->size = getSize(sym->type);
574       for ( i = 0 ; i < (int) fAVRReturnSize ; i++ )
575         aop->aopu.aop_str[i] = fAVRReturn[i];
576       return;
577     }
578
579     /* else spill location  */
580     sym->aop = op->aop = aop =
581       aopForSym(ic,sym->usl.spillLoc,result);
582     aop->size = getSize(sym->type);
583     return;
584   }
585
586   /* must be in a register */
587   sym->aop = op->aop = aop = newAsmop(AOP_REG);
588   aop->size = sym->nRegs;
589   for ( i = 0 ; i < sym->nRegs ;i++)
590     aop->aopu.aop_reg[i] = sym->regs[i];
591 }
592
593 /*-----------------------------------------------------------------*/
594 /* freeAsmop - free up the asmop given to an operand               */
595 /*----------------------------------------------------------------*/
596 static void freeAsmop (operand *op, asmop *aaop, iCode *ic, bool pop)
597 {
598   asmop *aop ;
599
600   if (!op)
601     aop = aaop;
602   else
603     aop = op->aop;
604
605   if (!aop)
606     return ;
607
608   if (aop->freed)
609     goto dealloc;
610
611   aop->freed = 1;
612
613   /* depending on the asmop type only three cases need work AOP_RO
614      , AOP_R1 && AOP_STK */
615   switch (aop->type) {
616         case AOP_X :
617     if (_G.xPushed ) {
618       if (pop) {
619         emitcode ("pop","r26");
620         emitcode ("pop","r27");
621         _G.xPushed--;
622       }
623     }
624     bitVectUnSetBit(ic->rUsed,X_IDX);
625     break;
626
627         case AOP_Z :
628     if (_G.zPushed ) {
629       if (pop) {
630         emitcode ("pop","r30");
631         emitcode ("pop","r31");
632         _G.zPushed--;
633       }
634     }
635     bitVectUnSetBit(ic->rUsed,Z_IDX);
636     break;
637
638         case AOP_STK :
639     {
640       int sz = aop->size;
641       int stk = aop->aopu.aop_stk + aop->size;
642       bitVectUnSetBit(ic->rUsed,X_IDX);
643       bitVectUnSetBit(ic->rUsed,Z_IDX);
644
645       getFreePtr(ic,&aop,FALSE,0);
646
647       emitcode ("movw","%s,r28");
648       if (stk) {
649         if (stk <= 63 && stk > 0) {
650           emitcode ("adiw","%s,0x%02x",aop->aopu.aop_ptr->name,stk+1);
651         } else {
652           emitcode ("subi","%s,lo8(%d)",aop->aopu.aop_ptr->name,-(stk+1));
653           emitcode ("sbci","%s,hi8(%d)",aop->aop_ptr2->name,-(stk+1));
654         }
655       }
656
657       while (sz--) {
658         emitcode("pop","r24");
659         emitcode("st","-%s,r24",aop->type == AOP_X ? "X" : "Z");
660         if (!sz) break;
661       }
662       op->aop = aop;
663       freeAsmop(op,NULL,ic,TRUE);
664       if (_G.xPushed) {
665         emitcode("pop","r26");
666         emitcode("pop","r27");
667         _G.xPushed--;
668       }
669
670       if (_G.zPushed) {
671         emitcode("pop","r30");
672         emitcode("pop","r31");
673         _G.zPushed--;
674       }
675     }
676   }
677
678  dealloc:
679   /* all other cases just dealloc */
680   if (op ) {
681     op->aop = NULL;
682     if (IS_SYMOP(op)) {
683       OP_SYMBOL(op)->aop = NULL;
684       /* if the symbol has a spill */
685       if (SPIL_LOC(op))
686         SPIL_LOC(op)->aop = NULL;
687     }
688   }
689 }
690
691 /*-----------------------------------------------------------------*/
692 /* aopGet - for fetching value of the aop                          */
693 /*-----------------------------------------------------------------*/
694 static char *aopGet (asmop *aop, int offset)
695 {
696   char *s = buffer ;
697   char *rs;
698
699   /* offset is greater than
700      size then zero */
701   if (offset > (aop->size - 1) &&
702       aop->type != AOP_LIT)
703     return zero;
704
705   /* depending on type */
706   switch (aop->type) {
707
708   case AOP_X:
709     if (offset > aop->coff) {
710       emitcode ("adiw","%s,%d",aop->aopu.aop_ptr->name,offset - aop->coff);
711     }
712
713     if (offset < aop->coff) {
714       emitcode("sbiw","%s,%d",aop->aopu.aop_ptr->name,aop->coff - offset);
715     }
716
717     aop->coff = offset ;
718     emitcode("ld","%s,x",
719        (rs = ((offset & 1) ? "r25" : "r24")));
720     return rs;
721
722   case AOP_Z:
723     if (aop->code) {
724       if (offset > aop->coff) {
725         emitcode("adiw","r30,%d",offset - aop->coff);
726       } else {
727         emitcode("sbiw","r30,%d",aop->coff - offset);
728       }
729       emitcode("lpm","%s,z",(rs = ((offset & 1) ? "r25" : "r24")));
730     } else {
731       /* we can use lds */
732       if (offset  > aop->coff) {
733         emitcode ("ldd","%s,z+%d",(rs = ((offset & 1) ? "r25" : "r24")),
734             offset - aop->coff);
735       } else {
736         emitcode("sbiw","%s,%d",aop->aopu.aop_ptr->name,aop->coff - offset);
737         aop->coff = offset;
738         emitcode ("ld","%s,z",(rs = ((offset & 1) ? "r25" : "r24")));
739       }
740     }
741     return rs;
742
743   case AOP_IMMD:
744
745     emitcode ("lds","%s,(%s)+%d",
746         (rs = ((offset & 1) ? "r25" : "r24")),
747         aop->aopu.aop_immd, offset);
748     return rs;
749
750   case AOP_DIR:
751     emitcode ("lds","%s,(%s)+%d",
752         (rs = ((offset & 1) ? "r25" : "r24")),
753         aop->aopu.aop_dir, offset);
754     return rs;
755
756   case AOP_REG:
757     return aop->aopu.aop_reg[offset]->name;
758
759   case AOP_CRY:
760     assert("cannot be in bit space AOP_CRY\n");
761     break;
762
763   case AOP_LIT:
764     s = aopLiteral(aop->aopu.aop_lit,offset);
765     emitcode("ldi","%s,lo8(%s)",(rs = ((offset & 1)?"r24" : "r25")),s);
766     return rs;
767
768   case AOP_STR:
769     aop->coff = offset ;
770     return aop->aopu.aop_str[offset];
771
772   case AOP_STK_D:
773     emitcode ("ldd","%s,Y+%d",
774         (rs = ((offset & 1) ? "r25" : "r24")),
775         aop->aopu.aop_stk+offset);
776     return rs;
777   }
778
779   werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
780          "aopget got unsupported aop->type");
781   exit(0);
782 }
783 /*-----------------------------------------------------------------*/
784 /* aopPut - puts a string for a aop                                */
785 /*-----------------------------------------------------------------*/
786 static void aopPut (asmop *aop, char *s, int offset)
787 {
788   char *d = buffer ;
789
790   if (aop->size && offset > ( aop->size - 1)) {
791     werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
792            "aopPut got offset > aop->size");
793     exit(0);
794   }
795
796   /* will assign value to value */
797   /* depending on where it is ofcourse */
798   switch (aop->type) {
799   case AOP_DIR:
800     if (offset) {
801       sprintf(d,"(%s)+%d", aop->aopu.aop_dir,offset);
802     }
803     else {
804       sprintf(d,"%s",aop->aopu.aop_dir);
805     }
806
807     emitcode("sts","%s,%s",d,s);
808     break;
809
810   case AOP_REG:
811     if (toupper(*s) != 'R') {
812       if (s == zero) {
813         emitcode("clr","%s",aop->aopu.aop_reg[offset]->name);
814       } else {
815         emitcode("ldi","r25,%s",s);
816         emitcode("mov","%s,r35",aop->aopu.aop_reg[offset]->name);
817       }
818     } else {
819       if (strcmp( aop->aopu.aop_reg[offset]->name,s)) {
820         emitcode("mov","%s,%s", aop->aopu.aop_reg[offset]->name,s);
821       }
822     }
823     break;
824
825   case AOP_X:
826     if (offset > aop->coff) {
827       emitcode ("adiw","%s,%d",aop->aopu.aop_ptr->name,offset - aop->coff);
828     }
829
830     if (offset < aop->coff) {
831       emitcode("sbiw","%s,%d",aop->aopu.aop_ptr->name,aop->coff - offset);
832     }
833
834     aop->coff = offset ;
835     emitcode("st","x,%s", s);
836     break;
837
838   case AOP_Z:
839     if (aop->code) {
840       if (offset > aop->coff) {
841         emitcode("adiw","r30,%d",offset - aop->coff);
842       } else {
843         emitcode("sbiw","r30,%d",aop->coff - offset);
844       }
845       emitcode("lpm","%s,z",s);
846     } else {
847       /* we can use lds */
848       if (offset  > aop->coff) {
849         emitcode ("sdd","z+%d,%s",offset - aop->coff,s);
850       } else {
851         emitcode("sbiw","%s,%d",aop->aopu.aop_ptr->name,aop->coff - offset);
852         aop->coff = offset;
853         emitcode ("ld","%s,z",s);
854       }
855     }
856     break;
857
858   case AOP_STK:
859     emitcode("push","%s",s);
860     break;
861
862   case AOP_CRY:
863     /* if used only for a condition code check */
864     assert(toupper(*s) == 'R');
865     if (offset == 0) {
866       emitcode("xrl","r0,r0");
867       emitcode("cpi","%s,0",s);
868     }
869     else {
870       emitcode("cpc","r0,%s",s);
871     }
872     break;
873
874   case AOP_STR:
875     aop->coff = offset;
876     if (strcmp(aop->aopu.aop_str[offset],s))
877       emitcode ("mov","%s,%s",aop->aopu.aop_str[offset],s);
878     break;
879
880   case AOP_STK_D:
881     emitcode ("std","y+%d,%s",offset,s);
882     break;
883
884   default :
885     werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
886            "aopPut got unsupported aop->type");
887     exit(0);
888   }
889
890 }
891
892 /*-----------------------------------------------------------------*/
893 /* reAdjustPreg - points a register back to where it should        */
894 /*-----------------------------------------------------------------*/
895 static void reAdjustPreg (asmop *aop)
896 {
897   int size ;
898
899   aop->coff = 0;
900   if ((size = aop->size) <= 1)
901     return ;
902   size-- ;
903   switch (aop->type) {
904         case AOP_X :
905         case AOP_Z :
906     emitcode("sbiw","%s,%d",aop->aopu.aop_ptr->name,size);
907     break;
908   }
909
910 }
911
912 #define AOP(op) op->aop
913 #define AOP_TYPE(op) AOP(op)->type
914 #define AOP_SIZE(op) AOP(op)->size
915 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_X || \
916                        AOP_TYPE(x) == AOP_Z))
917 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                      \
918                       (x->aopu.aop_reg[0] == avr_regWithIdx(R26_IDX) || \
919                       x->aopu.aop_reg[0] == avr_regWithIdx(R30_IDX) )))
920
921 /*-----------------------------------------------------------------*/
922 /* genNotFloat - generates not for float operations                */
923 /*-----------------------------------------------------------------*/
924 static void genNotFloat (operand *op, operand *res)
925 {
926   int size, offset;
927   char *l;
928   symbol *tlbl ;
929
930   /* we will put 127 in the first byte of
931      the result */
932   aopPut(AOP(res),"127",0);
933   size = AOP_SIZE(op) - 1;
934   offset = 1;
935
936   l = aopGet(op->aop,offset++);
937   MOVR0(l);
938
939   while(size--) {
940     emitcode("or","R0,%s", aopGet(op->aop, offset++));
941   }
942   tlbl = newiTempLabel(NULL);
943
944   tlbl = newiTempLabel(NULL);
945   aopPut(res->aop,zero,1);
946   emitcode("cpi","r0,0");
947   emitcode("breq","L%05d",tlbl->key);
948   aopPut(res->aop,one,1);
949   emitcode("","L%05d:",tlbl->key);
950
951   size = res->aop->size - 2;
952   offset = 2;
953   /* put zeros in the rest */
954   while (size--)
955     aopPut(res->aop,zero,offset++);
956 }
957
958 /*-----------------------------------------------------------------*/
959 /* opIsGptr: returns non-zero if the passed operand is       */
960 /* a generic pointer type.             */
961 /*-----------------------------------------------------------------*/
962 static int opIsGptr(operand *op)
963 {
964   sym_link *type = operandType(op);
965
966   if ((AOP_SIZE(op) == GPTRSIZE) && IS_GENPTR(type))
967     {
968       return 1;
969     }
970   return 0;
971 }
972
973 /*-----------------------------------------------------------------*/
974 /* getDataSize - get the operand data size                         */
975 /*-----------------------------------------------------------------*/
976 static int getDataSize(operand *op)
977 {
978   int size;
979   size = AOP_SIZE(op);
980   if (size == GPTRSIZE)
981     {
982       sym_link *type = operandType(op);
983       if (IS_GENPTR(type))
984         {
985           /* generic pointer; arithmetic operations
986            * should ignore the high byte (pointer type).
987            */
988           size--;
989         }
990     }
991   return size;
992 }
993
994 /*-----------------------------------------------------------------*/
995 /* outAcc - output Acc                                             */
996 /*-----------------------------------------------------------------*/
997 static void outAcc(operand *result)
998 {
999   int size, offset;
1000   size = getDataSize(result);
1001   if(size){
1002     aopPut(AOP(result),"r0",0);
1003     size--;
1004     offset = 1;
1005     /* unsigned or positive */
1006     while(size--){
1007       aopPut(AOP(result),zero,offset++);
1008     }
1009   }
1010 }
1011
1012 /*-----------------------------------------------------------------*/
1013 /* outBitC - output a bit C                                        */
1014 /*-----------------------------------------------------------------*/
1015 static void outBitC(operand *result)
1016 {
1017   emitcode("clr","r0");
1018   emitcode("rol","r0");
1019   outAcc(result);
1020 }
1021
1022 /*-----------------------------------------------------------------*/
1023 /* toBoolean - emit code for orl a,operator(sizeop)                */
1024 /*-----------------------------------------------------------------*/
1025 static void toBoolean(operand *oper, char *r, bool clr)
1026 {
1027   int size = AOP_SIZE(oper) ;
1028   int offset = 0;
1029   if (clr) emitcode ("clr","%s",r);
1030   while (size--)
1031     emitcode("or","%s,%s",r,aopGet(AOP(oper),offset++));
1032 }
1033
1034
1035 /*-----------------------------------------------------------------*/
1036 /* genNot - generate code for ! operation                          */
1037 /*-----------------------------------------------------------------*/
1038 static void genNot (iCode *ic)
1039 {
1040   symbol *tlbl;
1041   sym_link *optype = operandType(IC_LEFT(ic));
1042   int size, offset = 1;
1043
1044   /* assign asmOps to operand & result */
1045   aopOp (IC_LEFT(ic),ic,FALSE);
1046   aopOp (IC_RESULT(ic),ic,TRUE);
1047
1048   /* if type float then do float */
1049   if (IS_FLOAT(optype)) {
1050     genNotFloat(IC_LEFT(ic),IC_RESULT(ic));
1051     goto release;
1052   }
1053   emitcode("clr","r0");
1054   tlbl = newiTempLabel(NULL);
1055   size = AOP_SIZE(IC_LEFT(ic));
1056   offset = 0;
1057   if (size == 1) {
1058     emitcode("cpse","%s,r0",aopGet(AOP(IC_LEFT(ic)),0));
1059   }
1060   else {
1061     while (size--) {
1062       if (offset) emitcode("cpc","%s,r0",aopGet(AOP(IC_LEFT(ic)),offset));
1063       else emitcode("cpi","%s,0",aopGet(AOP(IC_LEFT(ic)),offset));
1064       offset++;
1065     }
1066     emitcode("bne","L%05d",tlbl->key);
1067   }
1068   emitcode("ldi","r0,1");
1069   emitcode("","L%05d:",tlbl->key);
1070   aopPut(AOP(IC_RESULT(ic)),"r0",0);
1071   size = AOP_SIZE(IC_RESULT(ic)) -1;
1072   offset = 1;
1073   while (size--) aopPut(AOP(IC_RESULT(ic)),zero,offset++);
1074
1075
1076  release:
1077   /* release the aops */
1078   freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1));
1079   freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
1080 }
1081
1082
1083 /*-----------------------------------------------------------------*/
1084 /* genCpl - generate code for complement                           */
1085 /*-----------------------------------------------------------------*/
1086 static void genCpl (iCode *ic)
1087 {
1088   int offset = 0;
1089   int size ;
1090   int samer;
1091
1092   /* assign asmOps to operand & result */
1093   aopOp (IC_LEFT(ic),ic,FALSE);
1094   aopOp (IC_RESULT(ic),ic,TRUE);
1095   samer = sameRegs(AOP(IC_LEFT(ic)),AOP(IC_RESULT(ic)));
1096   size = AOP_SIZE(IC_RESULT(ic));
1097   while (size--) {
1098     char *l = aopGet(AOP(IC_LEFT(ic)),offset);
1099     if (samer) {
1100       emitcode ("com","%s",l);
1101     } else {
1102       aopPut(AOP(IC_RESULT(ic)),l,offset);
1103       emitcode ("com","%s",aopGet(AOP(IC_RESULT(ic)),offset));
1104     }
1105     offset++;
1106   }
1107
1108   /* release the aops */
1109   freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1));
1110   freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
1111 }
1112
1113 /*-----------------------------------------------------------------*/
1114 /* genUminusFloat - unary minus for floating points                */
1115 /*-----------------------------------------------------------------*/
1116 static void genUminusFloat(operand *op,operand *result)
1117 {
1118   int size ,offset =0 ;
1119   char *l;
1120   /* for this we just need to flip the
1121      first it then copy the rest in place */
1122   size = AOP_SIZE(op) - 1;
1123   l = aopGet(AOP(op),3);
1124
1125   emitcode("ldi","r24,0x80");
1126   if (sameRegs(AOP(op),AOP(result))) {
1127     emitcode("eor","%s,r24",l);
1128   } else {
1129     aopPut(AOP(result),l,3);
1130     emitcode("eor","%s,r24",aopGet(AOP(result),3));
1131   }
1132   while(size--) {
1133     aopPut(AOP(result), aopGet(AOP(op),offset), offset);
1134     offset++;
1135   }
1136 }
1137
1138 /*-----------------------------------------------------------------*/
1139 /* genUminus - unary minus code generation                         */
1140 /*-----------------------------------------------------------------*/
1141 static void genUminus (iCode *ic)
1142 {
1143   int offset ,size ;
1144   sym_link *optype, *rtype;
1145   int samer ;
1146
1147   /* assign asmops */
1148   aopOp(IC_LEFT(ic),ic,FALSE);
1149   aopOp(IC_RESULT(ic),ic,TRUE);
1150
1151   optype = operandType(IC_LEFT(ic));
1152   rtype = operandType(IC_RESULT(ic));
1153
1154   /* if float then do float stuff */
1155   if (IS_FLOAT(optype)) {
1156     genUminusFloat(IC_LEFT(ic),IC_RESULT(ic));
1157     goto release;
1158   }
1159
1160   /* otherwise subtract from zero */
1161   size = AOP_SIZE(IC_LEFT(ic));
1162   offset = 0 ;
1163   samer = sameRegs(AOP(IC_LEFT(ic)),AOP(IC_RESULT(ic)));
1164   if (size == 1) {
1165     if (samer) {
1166       emitcode("neg","%s",aopGet(AOP(IC_LEFT(ic)),0));
1167     } else {
1168       aopPut(AOP(IC_RESULT(ic)),aopGet(AOP(IC_LEFT(ic)),0),0);
1169       emitcode("neg","%s",aopGet(AOP(IC_RESULT(ic)),0));
1170     }
1171   } else {
1172     offset = size - 1;
1173     while(size--) {
1174       char *l = aopGet(AOP(IC_LEFT(ic)),offset);
1175       if (!samer) {
1176         aopPut(AOP(IC_RESULT(ic)),l,offset);
1177         l = aopGet(AOP(IC_RESULT(ic)),offset);
1178       }
1179       if (offset) emitcode("com","%s",l);
1180       else emitcode("neg","%s",l);
1181       offset--;
1182     }
1183     size = AOP_SIZE(IC_LEFT(ic)) -1;
1184     offset = 1 ;
1185     while (size--) {
1186       emitcode("sbci","%s,lo8(-1)",aopGet(AOP(IC_RESULT(ic)),offset++));
1187     }
1188   }
1189
1190   /* if any remaining bytes in the result */
1191   /* we just need to propagate the sign   */
1192   if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1193     symbol *tlbl = newiTempLabel(NULL);
1194     emitcode("clr","r0");
1195     emitcode("brcc","L%05d",tlbl->key);
1196     emitcode("com","r0");
1197     emitcode("","L%05d:",tlbl->key);
1198     while (size--)
1199       aopPut(AOP(IC_RESULT(ic)),"r0",offset++);
1200   }
1201
1202  release:
1203   /* release the aops */
1204   freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1));
1205   freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
1206 }
1207
1208 /*-----------------------------------------------------------------*/
1209 /* assignResultValue -               */
1210 /*-----------------------------------------------------------------*/
1211 static void assignResultValue(operand * oper)
1212 {
1213   int offset = 0;
1214   int size = AOP_SIZE(oper);
1215   while (size--) {
1216     aopPut(AOP(oper),fAVRReturn[offset],offset);
1217     offset++;
1218   }
1219 }
1220
1221 /*-----------------------------------------------------------------*/
1222 /* saveZreg - if indirect call then save z-pointer register        */
1223 /*-----------------------------------------------------------------*/
1224 static void saveZreg (iCode *ic)
1225 {
1226   /* only if live accross this call */
1227   if (ic->regsSaved == 0 &&
1228       (bitVectBitValue(ic->rMask,R30_IDX) ||
1229        bitVectBitValue(ic->rMask,R31_IDX))) {
1230     ic->regsSaved = 1;
1231     emitcode("push","r30");
1232     emitcode("push","r31");
1233   }
1234 }
1235
1236 /*-----------------------------------------------------------------*/
1237 /* popZreg - restore values of zreg                                */
1238 /*-----------------------------------------------------------------*/
1239 static void popZreg (iCode *ic)
1240 {
1241   if (ic->regsSaved) {
1242     emitcode ("pop","r31");
1243     emitcode ("pop","r30");
1244   }
1245 }
1246
1247 /*-----------------------------------------------------------------*/
1248 /* genIpush - genrate code for pushing this gets a little complex  */
1249 /*-----------------------------------------------------------------*/
1250 static void genIpush (iCode *ic)
1251 {
1252   int size, offset = 0 ;
1253   char *l;
1254
1255
1256   if (!ic->parmPush) {
1257     /* and the item is spilt then do nothing */
1258     if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1259       return ;
1260   } else {
1261     iCode *lic ;
1262     for (lic = ic->next ; lic ; lic = lic->next)
1263       if (lic->op == PCALL) break;
1264     if (lic) saveZreg(lic);
1265   }
1266
1267   /* this is a paramter push */
1268   aopOp(IC_LEFT(ic),ic,FALSE);
1269   size = AOP_SIZE(IC_LEFT(ic));
1270   while (size--) {
1271     l = aopGet(AOP(IC_LEFT(ic)),offset++);
1272     emitcode("push","%s",l);
1273   }
1274
1275   freeAsmop(IC_LEFT(ic),NULL,ic,TRUE);
1276 }
1277
1278 /*-----------------------------------------------------------------*/
1279 /* genIpop - recover the registers: can happen only for spilling   */
1280 /*-----------------------------------------------------------------*/
1281 static void genIpop (iCode *ic)
1282 {
1283   int size,offset ;
1284
1285
1286   /* if the temp was not pushed then */
1287   if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1288     return ;
1289
1290   aopOp(IC_LEFT(ic),ic,FALSE);
1291   size = AOP_SIZE(IC_LEFT(ic));
1292   offset = (size-1);
1293   while (size--)
1294     emitcode("pop","%s",aopGet(AOP(IC_LEFT(ic)),offset--));
1295
1296   freeAsmop(IC_LEFT(ic),NULL,ic,TRUE);
1297 }
1298
1299 /*-----------------------------------------------------------------*/
1300 /* genCall - generates a call statement                            */
1301 /*-----------------------------------------------------------------*/
1302 static void genCall (iCode *ic)
1303 {
1304
1305   /* if send set is not empty the assign */
1306   if (_G.sendSet) {
1307     iCode *sic ;
1308     int rnum = 16;
1309     for (sic = setFirstItem(_G.sendSet) ; sic ;
1310          sic = setNextItem(_G.sendSet)) {
1311       int size, offset = 0;
1312       aopOp(IC_LEFT(sic),sic,FALSE);
1313       size = AOP_SIZE(IC_LEFT(sic));
1314       while (size--) {
1315         char *l = aopGet(AOP(IC_LEFT(sic)),offset);
1316         char *b = buffer;
1317         sprintf(buffer,"r%d",rnum++);
1318         if (strcmp(l,b))
1319           emitcode("mov","%s,%s",b,l);
1320         offset++;
1321       }
1322       freeAsmop (IC_LEFT(sic),NULL,sic,TRUE);
1323     }
1324     _G.sendSet = NULL;
1325   }
1326   /* make the call */
1327   emitcode("call","%s",(OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1328             OP_SYMBOL(IC_LEFT(ic))->rname :
1329             OP_SYMBOL(IC_LEFT(ic))->name));
1330
1331   /* if we need assign a result value */
1332   if ((IS_ITEMP(IC_RESULT(ic)) &&
1333        (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1334         OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1335       IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1336
1337     aopOp(IC_RESULT(ic),ic,FALSE);
1338     assignResultValue(IC_RESULT(ic));
1339     freeAsmop(IC_RESULT(ic),NULL, ic,TRUE);
1340   }
1341
1342   /* adjust the stack for parameters if required */
1343   if (IC_LEFT(ic)->parmBytes) {
1344     if (IC_LEFT(ic)->parmBytes > 63) {
1345       emitcode("sbiw","r28,%d",IC_LEFT(ic)->parmBytes);
1346     } else {
1347       emitcode("subi","r28,lo8(%d)",IC_LEFT(ic)->parmBytes);
1348       emitcode("sbci","r29,hi8(%d)",IC_LEFT(ic)->parmBytes);
1349     }
1350   }
1351
1352 }
1353
1354 /*-----------------------------------------------------------------*/
1355 /* genPcall - generates a call by pointer statement                */
1356 /*-----------------------------------------------------------------*/
1357 static void genPcall (iCode *ic)
1358 {
1359
1360   if (!ic->regsSaved) saveZreg(ic);
1361
1362   aopOp(IC_LEFT(ic),ic,FALSE);
1363   emitcode("mov","r30",aopGet(AOP(IC_LEFT(ic)),0));
1364   emitcode("mov","r31",aopGet(AOP(IC_RIGHT(ic)),0));
1365   freeAsmop(IC_LEFT(ic),NULL,ic,TRUE);
1366
1367   /* if send set is not empty the assign */
1368   if (_G.sendSet) {
1369     iCode *sic ;
1370     int rnum = 16;
1371     for (sic = setFirstItem(_G.sendSet) ; sic ;
1372          sic = setNextItem(_G.sendSet)) {
1373       int size, offset = 0;
1374       aopOp(IC_LEFT(sic),sic,FALSE);
1375       size = AOP_SIZE(IC_LEFT(sic));
1376       while (size--) {
1377         char *l = aopGet(AOP(IC_LEFT(sic)),offset);
1378         char *b = buffer;
1379         sprintf(b,"r%d",rnum++);
1380         if (strcmp(l,b))
1381           emitcode("mov","%s,%s",b,l);
1382         offset++;
1383       }
1384       freeAsmop (IC_LEFT(sic),NULL,sic,TRUE);
1385     }
1386     _G.sendSet = NULL;
1387   }
1388
1389   emitcode("icall","");
1390
1391   /* if we need assign a result value */
1392   if ((IS_ITEMP(IC_RESULT(ic)) &&
1393        (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1394         OP_SYMBOL(IC_RESULT(ic))->spildir)) ||
1395       IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1396
1397     aopOp(IC_RESULT(ic),ic,FALSE);
1398
1399     assignResultValue(IC_RESULT(ic));
1400     freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
1401   }
1402
1403   /* adjust the stack for parameters if
1404      required */
1405   if (IC_LEFT(ic)->parmBytes) {
1406     int i;
1407     if (IC_LEFT(ic)->parmBytes > 3) {
1408       emitcode("mov","a,%s",spname);
1409       emitcode("add","a,#0x%02x", (- IC_LEFT(ic)->parmBytes) & 0xff);
1410       emitcode("mov","%s,a",spname);
1411     } else
1412       for ( i = 0 ; i <  IC_LEFT(ic)->parmBytes ;i++)
1413         emitcode("dec","%s",spname);
1414
1415   }
1416
1417   /* adjust the stack for parameters if required */
1418   if (IC_LEFT(ic)->parmBytes) {
1419     if (IC_LEFT(ic)->parmBytes > 63) {
1420       emitcode("sbiw","r28,%d",IC_LEFT(ic)->parmBytes);
1421     } else {
1422       emitcode("subi","r28,lo8(%d)",IC_LEFT(ic)->parmBytes);
1423       emitcode("sbci","r29,hi8(%d)",IC_LEFT(ic)->parmBytes);
1424     }
1425   }
1426   if (ic->regsSaved) popZreg(ic);
1427 }
1428
1429 /*-----------------------------------------------------------------*/
1430 /* resultRemat - result  is rematerializable                       */
1431 /*-----------------------------------------------------------------*/
1432 static int resultRemat (iCode *ic)
1433 {
1434   if (SKIP_IC(ic) || ic->op == IFX)
1435     return 0;
1436
1437   if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1438     symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1439     if (sym->remat && !POINTER_SET(ic))
1440       return 1;
1441   }
1442
1443   return 0;
1444 }
1445
1446 #if defined(__BORLANDC__) || defined(_MSC_VER)
1447 #define STRCASECMP stricmp
1448 #else
1449 #define STRCASECMP strcasecmp
1450 #endif
1451
1452 /*-----------------------------------------------------------------*/
1453 /* inExcludeList - return 1 if the string is in exclude Reg list   */
1454 /*-----------------------------------------------------------------*/
1455 static bool inExcludeList(char *s)
1456 {
1457   int i =0;
1458
1459   if (options.excludeRegs[i] &&
1460       STRCASECMP(options.excludeRegs[i],"none") == 0)
1461     return FALSE ;
1462
1463   for ( i = 0 ; options.excludeRegs[i]; i++) {
1464     if (options.excludeRegs[i] &&
1465         STRCASECMP(s,options.excludeRegs[i]) == 0)
1466       return TRUE;
1467   }
1468   return FALSE ;
1469 }
1470
1471 /*-----------------------------------------------------------------*/
1472 /* genFunction - generated code for function entry                 */
1473 /*-----------------------------------------------------------------*/
1474 static void genFunction (iCode *ic)
1475 {
1476   symbol *sym;
1477   sym_link *fetype;
1478   int i = 0;
1479
1480   _G.nRegsSaved = 0;
1481   /* create the function header */
1482   emitcode(";","-----------------------------------------");
1483   emitcode(";"," function %s",(sym = OP_SYMBOL(IC_LEFT(ic)))->name);
1484   emitcode(";","-----------------------------------------");
1485
1486   emitcode("","%s:",sym->rname);
1487   fetype = getSpec(operandType(IC_LEFT(ic)));
1488
1489   /* if critical function then turn interrupts off */
1490   if (SPEC_CRTCL(fetype))
1491     emitcode("cli","");
1492
1493   if (IS_ISR(sym->etype)) {
1494   }
1495
1496   /* save the preserved registers that are used in this function */
1497   for (i = R2_IDX ; i <= R15_IDX ; i++ ) {
1498     if (bitVectBitValue(sym->regsUsed,i)) {
1499       _G.nRegsSaved++;
1500       emitcode("push","%s",avr_regWithIdx(i)->name);
1501     }
1502   }
1503   /* now for the pointer registers */
1504   if (bitVectBitValue(sym->regsUsed,R26_IDX)) {
1505     _G.nRegsSaved++;
1506     emitcode("push","r26");
1507   }
1508   if (bitVectBitValue(sym->regsUsed,R27_IDX)) {
1509     _G.nRegsSaved++;
1510     emitcode("push","r27");
1511   }
1512   if (bitVectBitValue(sym->regsUsed,R30_IDX)) {
1513     _G.nRegsSaved++;
1514     emitcode("push","r30");
1515   }
1516   if (bitVectBitValue(sym->regsUsed,R31_IDX)) {
1517     _G.nRegsSaved++;
1518     emitcode("push","r31");
1519   }
1520   /* adjust the stack for the function */
1521   if (sym->stack) {
1522     emitcode ("push","r28");
1523     emitcode ("push","r29");
1524     emitcode ("in","r28,__SP_L__");
1525     emitcode ("in","r29,__SP_H__");
1526     if (sym->stack <= 63) {
1527       emitcode("sbiw","r28,%d",sym->stack);
1528     } else {
1529       emitcode ("subi","r28,lo8(%d)",sym->stack);
1530       emitcode ("sbci","r29,hi8(%d)",sym->stack);
1531     }
1532     emitcode("out","__SP_L__,r28");
1533     emitcode("out","__SP_H__,r29");
1534   }
1535 }
1536
1537 /*-----------------------------------------------------------------*/
1538 /* genEndFunction - generates epilogue for functions               */
1539 /*-----------------------------------------------------------------*/
1540 static void genEndFunction (iCode *ic)
1541 {
1542   symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1543   int i;
1544
1545   /* restore stack pointer */
1546   if (sym->stack) {
1547     if (sym->stack <= 63) {
1548       emitcode("adiw","r28,%d",sym->stack);
1549     } else {
1550       emitcode ("subi","r28,lo8(-%d)",sym->stack);
1551       emitcode ("sbci","r29,hi8(-%d)",sym->stack);
1552     }
1553     emitcode("out","__SP_L__,r28");
1554     emitcode("out","__SP_H__,r29");
1555
1556     /* pop frame pointer */
1557     emitcode ("pop","r29");
1558     emitcode ("pop","r28");
1559   }
1560   /* restore preserved registers */
1561   if (bitVectBitValue(sym->regsUsed,R31_IDX)) {
1562     _G.nRegsSaved--;
1563     emitcode("pop","r31");
1564   }
1565   if (bitVectBitValue(sym->regsUsed,R30_IDX)) {
1566     _G.nRegsSaved--;
1567     emitcode("pop","r30");
1568   }
1569   if (bitVectBitValue(sym->regsUsed,R27_IDX)) {
1570     _G.nRegsSaved--;
1571     emitcode("push","r27");
1572   }
1573   if (bitVectBitValue(sym->regsUsed,R26_IDX)) {
1574     _G.nRegsSaved--;
1575     emitcode("push","r26");
1576   }
1577   for (i = R15_IDX ; i >= R2_IDX ; i-- ) {
1578     if (bitVectBitValue(sym->regsUsed,i)) {
1579       _G.nRegsSaved--;
1580       emitcode("pop","%s",avr_regWithIdx(i)->name);
1581     }
1582   }
1583
1584   if (SPEC_CRTCL(sym->etype))
1585     emitcode("sti","");
1586
1587   if (IS_ISR(sym->etype)) {
1588     emitcode("rti","");
1589   } else {
1590     emitcode("ret","");
1591   }
1592
1593 }
1594
1595 /*-----------------------------------------------------------------*/
1596 /* genRet - generate code for return statement                     */
1597 /*-----------------------------------------------------------------*/
1598 static void genRet (iCode *ic)
1599 {
1600   int size,offset = 0 ;
1601
1602   /* if we have no return value then
1603      just generate the "ret" */
1604   if (!IC_LEFT(ic))
1605     goto jumpret;
1606
1607   /* we have something to return then
1608      move the return value into place */
1609   aopOp(IC_LEFT(ic),ic,FALSE);
1610   size = AOP_SIZE(IC_LEFT(ic));
1611
1612   while (size--) {
1613     if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
1614       emitcode("ldi","%s,%s(%d)",fAVRReturn[offset],larray[offset],
1615          (int)floatFromVal (AOP(IC_LEFT(ic))->aopu.aop_lit),offset);
1616     } else {
1617       char *l ;
1618       l = aopGet(AOP(IC_LEFT(ic)),offset);
1619       if (strcmp(fAVRReturn[offset],l))
1620         emitcode("mov","%s,%s",fAVRReturn[offset],l);
1621     }
1622     offset++;
1623   }
1624
1625   freeAsmop (IC_LEFT(ic),NULL,ic,TRUE);
1626
1627  jumpret:
1628   /* generate a jump to the return label
1629      if the next is not the return statement */
1630   if (!(ic->next && ic->next->op == LABEL &&
1631         IC_LABEL(ic->next) == returnLabel))
1632
1633     emitcode("rjmp","L%05d",returnLabel->key);
1634
1635 }
1636
1637 /*-----------------------------------------------------------------*/
1638 /* genLabel - generates a label                                    */
1639 /*-----------------------------------------------------------------*/
1640 static void genLabel (iCode *ic)
1641 {
1642   /* special case never generate */
1643   if (IC_LABEL(ic) == entryLabel)
1644     return ;
1645
1646   emitcode("","L%05d:",IC_LABEL(ic)->key);
1647 }
1648
1649 /*-----------------------------------------------------------------*/
1650 /* genGoto - generates a ljmp                                      */
1651 /*-----------------------------------------------------------------*/
1652 static void genGoto (iCode *ic)
1653 {
1654   emitcode ("rjmp","L%05d:",(IC_LABEL(ic)->key+100));
1655 }
1656
1657 /*-----------------------------------------------------------------*/
1658 /* findLabelBackwards: walks back through the iCode chain looking  */
1659 /* for the given label. Returns number of iCode instructions     */
1660 /* between that label and given ic.          */
1661 /* Returns zero if label not found.          */
1662 /*-----------------------------------------------------------------*/
1663 static int findLabelBackwards(iCode *ic, int key)
1664 {
1665   int count = 0;
1666
1667   while (ic->prev)
1668     {
1669       ic = ic->prev;
1670       count++;
1671
1672       if (ic->op == LABEL && IC_LABEL(ic)->key == key)
1673         {
1674           /* printf("findLabelBackwards = %d\n", count); */
1675           return count;
1676         }
1677     }
1678
1679   return 0;
1680 }
1681
1682 /*-----------------------------------------------------------------*/
1683 /* genPlusIncr :- does addition with increment if possible         */
1684 /*-----------------------------------------------------------------*/
1685 static bool genPlusIncr (iCode *ic)
1686 {
1687   unsigned int icount ;
1688
1689   /* will try to generate an increment */
1690   /* if the right side is not a literal
1691      we cannot */
1692   if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1693     return FALSE ;
1694
1695   icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit);
1696
1697   /* if the sizes are greater than 2 or they are not the same regs
1698      then we cannot */
1699   if (!sameRegs(AOP(IC_LEFT(ic)),AOP(IC_RESULT(ic))))
1700     return FALSE ;
1701
1702   /* so we know LEFT & RESULT in the same registers and add
1703      amount <= 63 */
1704   /* for short & char types */
1705   if (AOP_SIZE(IC_RESULT(ic)) < 2) {
1706     if (icount == 1) {
1707       emitcode("inc","%s",aopGet(AOP(IC_LEFT(ic)),0));
1708       return TRUE;
1709     }
1710     emitcode("subi","%s,lo8(%d)",aopGet(AOP(IC_LEFT(ic)),0),-icount);
1711     return TRUE;
1712   }
1713
1714   if (AOP_SIZE(IC_RESULT(ic)) <= 3) {
1715     /* if register pair and starts with 26/30 then adiw */
1716     if (isRegPair(AOP(IC_RESULT(ic))) && icount > 0 && icount < 64 &&
1717         ( IS_REGIDX(AOP(IC_RESULT(ic)),R26_IDX) ||
1718           IS_REGIDX(AOP(IC_RESULT(ic)),R30_IDX) )) {
1719       emitcode("adiw","%s,%d",aopGet(AOP(IC_RESULT(ic)),0),icount);
1720       return TRUE;
1721     }
1722
1723     /* use subi */
1724     emitcode("subi","%s,lo8(%d)",aopGet(AOP(IC_RESULT(ic)),0),-icount);
1725     emitcode("sbci","%s,hi8(%d)",aopGet(AOP(IC_RESULT(ic)),1),-icount);
1726     return TRUE;
1727   }
1728
1729   /* for 32 bit longs */
1730   emitcode("subi","%s,lo8(%d)",aopGet(AOP(IC_RESULT(ic)),0),-icount);
1731   emitcode("sbci","%s,hi8(%d)",aopGet(AOP(IC_RESULT(ic)),1),-icount);
1732   emitcode("sbci","%s,hlo8(%d)",aopGet(AOP(IC_RESULT(ic)),2),-icount);
1733   emitcode("sbci","%s,hhi8(%d)",aopGet(AOP(IC_RESULT(ic)),3),-icount);
1734   return TRUE;
1735
1736 }
1737
1738 /* This is the pure and virtuous version of this code.
1739  * I'm pretty certain it's right, but not enough to toss the old
1740  * code just yet...
1741  */
1742 static void adjustArithmeticResult  (iCode *ic)
1743 {
1744   if (opIsGptr(IC_RESULT(ic)) &&
1745       opIsGptr(IC_LEFT(ic))   &&
1746       !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1747     {
1748       aopPut(AOP(IC_RESULT(ic)),
1749              aopGet(AOP(IC_LEFT(ic)), GPTRSIZE - 1),
1750              GPTRSIZE - 1);
1751     }
1752
1753   if (opIsGptr(IC_RESULT(ic)) &&
1754       opIsGptr(IC_RIGHT(ic))   &&
1755       !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
1756     {
1757       aopPut(AOP(IC_RESULT(ic)),
1758              aopGet(AOP(IC_RIGHT(ic)),GPTRSIZE - 1),
1759              GPTRSIZE - 1);
1760     }
1761
1762   if (opIsGptr(IC_RESULT(ic))      &&
1763       AOP_SIZE(IC_LEFT(ic)) < GPTRSIZE   &&
1764       AOP_SIZE(IC_RIGHT(ic)) < GPTRSIZE  &&
1765       !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) &&
1766       !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) {
1767     char buffer[5];
1768     sprintf(buffer,"%d",pointerCode(getSpec(operandType(IC_LEFT(ic)))));
1769     aopPut(AOP(IC_RESULT(ic)),buffer,GPTRSIZE - 1);
1770   }
1771 }
1772
1773 /*-----------------------------------------------------------------*/
1774 /* genPlus - generates code for addition                           */
1775 /*-----------------------------------------------------------------*/
1776 static void genPlus (iCode *ic)
1777 {
1778   int size, offset = 0;
1779   int samer;
1780   char *l;
1781
1782   /* special cases :- */
1783
1784   aopOp (IC_LEFT(ic),ic,FALSE);
1785   aopOp (IC_RIGHT(ic),ic,FALSE);
1786   aopOp (IC_RESULT(ic),ic,TRUE);
1787
1788   /* if I can do an increment instead
1789      of add then GOOD for ME */
1790   if (genPlusIncr (ic) == TRUE)
1791     goto release;
1792
1793   size = getDataSize(IC_RESULT(ic));
1794   samer = sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic)));
1795
1796   while(size--) {
1797     if (!samer)
1798       aopPut(AOP(IC_RESULT(ic)),aopGet(AOP(IC_LEFT(ic)),offset),offset);
1799
1800     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
1801
1802       if(offset == 0) l = "add";
1803       else l = "adc";
1804
1805       emitcode(l,"%s,%s",aopGet(AOP(IC_RESULT(ic)),offset),
1806          aopGet(AOP(IC_RIGHT(ic)),offset));
1807     } else {
1808       if (offset == 0) l = "subi";
1809       else l = "sbci";
1810
1811       emitcode(l,"%s,%s(-%d)",aopGet(AOP(IC_RESULT(ic)),offset),
1812          larray[offset],
1813          (int)floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit));
1814     }
1815     offset++;
1816   }
1817
1818   adjustArithmeticResult(ic);
1819
1820  release:
1821   freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
1822   freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
1823   freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
1824 }
1825
1826 /*-----------------------------------------------------------------*/
1827 /* genMinusDec :- does subtraction with deccrement if possible     */
1828 /*-----------------------------------------------------------------*/
1829 static bool genMinusDec (iCode *ic)
1830 {
1831   unsigned int icount ;
1832
1833   /* will try to generate an increment */
1834   /* if the right side is not a literal
1835      we cannot */
1836   if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1837     return FALSE ;
1838
1839   icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit);
1840
1841   /* if the sizes are greater than 2 or they are not the same regs
1842      then we cannot */
1843   if (!sameRegs(AOP(IC_LEFT(ic)),AOP(IC_RIGHT(ic))))
1844     return FALSE ;
1845
1846   /* so we know LEFT & RESULT in the same registers and add
1847      amount <= 63 */
1848   /* for short & char types */
1849   if (AOP_SIZE(IC_RESULT(ic)) < 2) {
1850     if (icount == 1) {
1851       emitcode("dec","%s",aopGet(AOP(IC_LEFT(ic)),0));
1852       return TRUE;
1853     }
1854     emitcode("subi","%s,lo8(%d)",aopGet(AOP(IC_LEFT(ic)),0),icount);
1855     return TRUE;
1856   }
1857
1858   if (AOP_SIZE(IC_RESULT(ic)) <= 3) {
1859     /* if register pair and starts with 26/30 then adiw */
1860     if (isRegPair(AOP(IC_RESULT(ic))) && icount > 0 && icount < 64 &&
1861         ( IS_REGIDX(AOP(IC_RESULT(ic)),R26_IDX) ||
1862           IS_REGIDX(AOP(IC_RESULT(ic)),R30_IDX) )) {
1863       emitcode("sbiw","%s,%d",aopGet(AOP(IC_RESULT(ic)),0),icount);
1864       return TRUE;
1865     }
1866
1867     /* use subi */
1868     emitcode("subi","%s,lo8(%d)",aopGet(AOP(IC_RESULT(ic)),0),icount);
1869     emitcode("sbci","%s,hi8(%d)",aopGet(AOP(IC_RESULT(ic)),1),icount);
1870     return TRUE;
1871   }
1872   /* for 32 bit longs */
1873   emitcode("subi","%s,lo8(%d)",aopGet(AOP(IC_RESULT(ic)),0),icount);
1874   emitcode("sbci","%s,hi8(%d)",aopGet(AOP(IC_RESULT(ic)),1),icount);
1875   emitcode("sbci","%s,hlo8(%d)",aopGet(AOP(IC_RESULT(ic)),2),icount);
1876   emitcode("sbci","%s,hhi8(%d)",aopGet(AOP(IC_RESULT(ic)),3),icount);
1877   return TRUE;
1878
1879 }
1880
1881 /*-----------------------------------------------------------------*/
1882 /* addSign - complete with sign                                    */
1883 /*-----------------------------------------------------------------*/
1884 static void addSign(operand *result, int offset, int sign)
1885 {
1886   int size = (getDataSize(result) - offset);
1887   if(size > 0){
1888     if(sign){
1889       emitcode("rlc","a");
1890       emitcode("subb","a,acc");
1891       while(size--)
1892         aopPut(AOP(result),"a",offset++);
1893     } else
1894       while(size--)
1895         aopPut(AOP(result),zero,offset++);
1896   }
1897 }
1898
1899 /*-----------------------------------------------------------------*/
1900 /* genMinus - generates code for subtraction                       */
1901 /*-----------------------------------------------------------------*/
1902 static void genMinus (iCode *ic)
1903 {
1904   int size, offset = 0, samer;
1905   char *l;
1906
1907   aopOp (IC_LEFT(ic),ic,FALSE);
1908   aopOp (IC_RIGHT(ic),ic,FALSE);
1909   aopOp (IC_RESULT(ic),ic,TRUE);
1910
1911   /* if I can do an decrement instead
1912      of subtract then GOOD for ME */
1913   if (genMinusDec (ic) == TRUE)
1914     goto release;
1915
1916   size = getDataSize(IC_RESULT(ic));
1917   samer = sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic)));
1918   while (size--) {
1919     if (!samer)
1920       aopPut(AOP(IC_RESULT(ic)),aopGet(AOP(IC_LEFT(ic)),offset),offset);
1921
1922     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
1923
1924       if(offset == 0) l = "sub";
1925       else l = "sbc";
1926
1927       emitcode(l,"%s,%s",aopGet(AOP(IC_RESULT(ic)),offset),
1928          aopGet(AOP(IC_RIGHT(ic)),offset));
1929     } else {
1930       if (offset == 0) l = "subi";
1931       else l = "sbci";
1932
1933       emitcode(l,"%s,%s(%d)",aopGet(AOP(IC_RESULT(ic)),offset),
1934          larray[offset],
1935          (int)floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit));
1936     }
1937     offset++;
1938   }
1939
1940   adjustArithmeticResult(ic);
1941
1942  release:
1943   freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
1944   freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
1945   freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
1946 }
1947
1948 /*-----------------------------------------------------------------*/
1949 /* genMultOneByte : 8 bit multiplication & division                */
1950 /*-----------------------------------------------------------------*/
1951 static void genMultOneByte (operand *left,
1952                             operand *right,
1953                             operand *result)
1954 {
1955   sym_link *opetype = operandType(result);
1956   symbol *lbl ;
1957   int size,offset;
1958
1959   /* (if two literals, the value is computed before) */
1960   /* if one literal, literal on the right */
1961   if (AOP_TYPE(left) == AOP_LIT){
1962     operand *t = right;
1963     right = left;
1964     left = t;
1965   }
1966
1967   size = AOP_SIZE(result);
1968
1969   if (SPEC_USIGN(opetype)) {
1970     emitcode("mul","%s,%s", aopGet(AOP(left),0),aopGet(AOP(right),0));
1971   } else {
1972     emitcode("muls","%s,%s", aopGet(AOP(left),0),
1973        aopGet(AOP(right),0));
1974   }
1975   aopPut(AOP(result),"r0",0);
1976   if (size > 1){
1977     aopPut(AOP(result),"r1",1);
1978     offset = 2;
1979     size -= 2;
1980     if (SPEC_USIGN(opetype)) {
1981       while(size--) {
1982         aopPut(AOP(result),zero,offset++);
1983       }
1984     } else {
1985       if (size) {
1986         lbl = newiTempLabel(NULL);
1987         emitcode("ldi","r24,0");
1988         emitcode("brcc","L%05d",lbl->key);
1989         emitcode("ldi","r24,lo8(-1)");
1990         emitcode("","L%05d:",lbl->key);
1991         while (size--) aopPut(AOP(result),"r24",offset++);
1992       }
1993     }
1994   }
1995   return;
1996 }
1997
1998 /*-----------------------------------------------------------------*/
1999 /* genMult - generates code for multiplication                     */
2000 /*-----------------------------------------------------------------*/
2001 static void genMult (iCode *ic)
2002 {
2003   operand *left = IC_LEFT(ic);
2004   operand *right = IC_RIGHT(ic);
2005   operand *result= IC_RESULT(ic);
2006
2007   /* assign the amsops */
2008   aopOp (left,ic,FALSE);
2009   aopOp (right,ic,FALSE);
2010   aopOp (result,ic,TRUE);
2011
2012   /* if both are of size == 1 */
2013   if (AOP_SIZE(left) == 1 &&
2014       AOP_SIZE(right) == 1 ) {
2015     genMultOneByte(left,right,result);
2016     goto release ;
2017   }
2018
2019   /* should have been converted to function call */
2020   assert(1) ;
2021
2022   release :
2023     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
2024   freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
2025   freeAsmop(result,NULL,ic,TRUE);
2026 }
2027
2028 /*-----------------------------------------------------------------*/
2029 /* genDiv - generates code for division                            */
2030 /*-----------------------------------------------------------------*/
2031 static void genDiv (iCode *ic)
2032 {
2033   /* should have been converted to function call */
2034   assert(1);
2035 }
2036
2037 /*-----------------------------------------------------------------*/
2038 /* genMod - generates code for division                            */
2039 /*-----------------------------------------------------------------*/
2040 static void genMod (iCode *ic)
2041 {
2042   /* should have been converted to function call */
2043   assert(1);
2044
2045 }
2046
2047 enum {
2048   AVR_EQ = 0,
2049   AVR_NE,
2050   AVR_LT,
2051   AVR_GE
2052 };
2053
2054 /*-----------------------------------------------------------------*/
2055 /* revavrcnd - reverse a conditional for avr                       */
2056 /*-----------------------------------------------------------------*/
2057 static int revavrcnd(int type)
2058 {
2059   static struct {
2060     int type, rtype;
2061   } rar[] = { { AVR_EQ, AVR_NE}, {AVR_LT, AVR_GE}};
2062   int i;
2063
2064   for (i = 0 ; i < (sizeof(rar)/sizeof(rar[0]));i++) {
2065     if (rar[i].type == type) return rar[i].rtype;
2066     if (rar[i].rtype== type) return rar[i].type;
2067   }
2068   assert(1); /* cannot happen */
2069   return 0;  /* makes the compiler happy */
2070 }
2071
2072 static char *br_name[4] = {"breq","brne","brlt","brge"};
2073 static char *br_uname[4]= {"breq","brne","brlo","brcc"};
2074
2075 /*-----------------------------------------------------------------*/
2076 /* genBranch - generate the branch instruction                     */
2077 /*-----------------------------------------------------------------*/
2078 static void genBranch (iCode *ifx, int br_type, int sign)
2079 {
2080   int tj = (IC_TRUE(ifx) ? 1 : 0) ;
2081
2082   if (tj) { /* if true jump */
2083     char *nm = (sign ? br_name[br_type] : br_uname[br_type]);
2084     emitcode(nm,"L%05d",IC_TRUE(ifx)->key);
2085   } else { /* if false jump */
2086     int rtype = revavrcnd(br_type);
2087     char *nm = (sign ? br_name[rtype] : br_uname[rtype]);
2088     emitcode(nm,"L%05d",IC_FALSE(ifx)->key);
2089   }
2090   ifx->generated = 1;
2091 }
2092
2093 /*-----------------------------------------------------------------*/
2094 /* genCmp - compare & jump                                         */
2095 /*-----------------------------------------------------------------*/
2096 static void genCmp (iCode *ic, iCode *ifx, int br_type)
2097 {
2098   operand *left, *right, *result;
2099   sym_link *letype , *retype;
2100   symbol *lbl;
2101   int sign, size, offset =0;
2102
2103   left = IC_LEFT(ic);
2104   right= IC_RIGHT(ic);
2105   result = IC_RESULT(ic);
2106
2107   letype = getSpec(operandType(left));
2108   retype =getSpec(operandType(right));
2109   sign =  !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2110
2111   /* assign the amsops */
2112   aopOp (left,ic,FALSE);
2113   aopOp (right,ic,FALSE);
2114   aopOp (result,ic,TRUE);
2115   size = AOP_SIZE(left);
2116
2117   if (ifx) {
2118     if (size == 1) {
2119       if (AOP_TYPE(right) == AOP_LIT) {
2120         emitcode("cpi","%s,lo8(%d)",aopGet(AOP(left),0),
2121            (int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit));
2122         genBranch(ifx,br_type,sign);
2123       } else { /* right != literal */
2124         emitcode("cp","%s,%s",aopGet(AOP(left),0),aopGet(AOP(right),0));
2125         genBranch(ifx,br_type,sign);
2126       }
2127     } else { /* size != 1 */
2128       while (size--) {
2129         if (offset == 0)
2130           emitcode("cp","%s,%s",aopGet(AOP(left),0),aopGet(AOP(right),0));
2131         else
2132           emitcode("cpc","%s,%s",aopGet(AOP(left),offset),aopGet(AOP(right),offset));
2133         offset++;
2134       }
2135       genBranch(ifx,br_type,sign);
2136     }
2137   } else { /* no ifx */
2138     emitcode("clr","r0");
2139     while (size--) {
2140       if (offset == 0)
2141         emitcode("cp","%s,%s",aopGet(AOP(left),0),aopGet(AOP(right),0));
2142       else
2143         emitcode("cpc","%s,%s",aopGet(AOP(left),offset),aopGet(AOP(right),offset));
2144       offset++;
2145     }
2146     lbl = newiTempLabel(NULL);
2147     br_type = revavrcnd(br_type);
2148     if (sign) emitcode(br_uname[br_type],"L%05d",lbl->key);
2149     else emitcode(br_name[br_type],"L%05d",lbl->key);
2150     emitcode("inc","r0");
2151     emitcode("","L%05d:",lbl->key);
2152     aopPut(AOP(result),"r0",0);
2153     size = AOP_SIZE(result) - 1;
2154     offset = 1;
2155     while (size--) aopPut(AOP(result),zero,offset++);
2156   }
2157
2158   freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
2159   freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
2160   freeAsmop(result,NULL,ic,TRUE);
2161 }
2162
2163 /*-----------------------------------------------------------------*/
2164 /* genCmpGt :- greater than comparison                             */
2165 /*-----------------------------------------------------------------*/
2166 static void genCmpGt (iCode *ic, iCode *ifx)
2167 {
2168   /* should have transformed by the parser */
2169   assert(1);
2170 }
2171
2172 /*-----------------------------------------------------------------*/
2173 /* genCmpLt - less than comparisons                                */
2174 /*-----------------------------------------------------------------*/
2175 static void genCmpLt (iCode *ic, iCode *ifx)
2176 {
2177   genCmp(ic,ifx,AVR_LT);
2178 }
2179
2180 /*-----------------------------------------------------------------*/
2181 /* genCmpEq - generates code for equal to                          */
2182 /*-----------------------------------------------------------------*/
2183 static void genCmpEq (iCode *ic, iCode *ifx)
2184 {
2185   genCmp(ic,ifx,AVR_EQ);
2186 }
2187
2188 /*-----------------------------------------------------------------*/
2189 /* genCmpNe - generates code for not equal to                      */
2190 /*-----------------------------------------------------------------*/
2191 static void genCmpNe (iCode *ic, iCode *ifx)
2192 {
2193   genCmp(ic,ifx,AVR_NE);
2194 }
2195
2196 /*-----------------------------------------------------------------*/
2197 /* genCmpGe - generates code for greater than equal to             */
2198 /*-----------------------------------------------------------------*/
2199 static void genCmpGe (iCode *ic, iCode *ifx)
2200 {
2201   genCmp(ic,ifx,AVR_GE);
2202 }
2203
2204 /*-----------------------------------------------------------------*/
2205 /* genCmpLe - generates code for less than equal to                */
2206 /*-----------------------------------------------------------------*/
2207 static void genCmpLe (iCode *ic, iCode *ifx)
2208 {
2209   operand *left = IC_LEFT(ic);
2210   operand *right= IC_RIGHT(ic);
2211
2212   IC_RIGHT(ic) = left;
2213   IC_LEFT(ic)  = right;
2214   genCmp(ic,ifx,AVR_GE);
2215 }
2216
2217 /*-----------------------------------------------------------------*/
2218 /* ifxForOp - returns the icode containing the ifx for operand     */
2219 /*-----------------------------------------------------------------*/
2220 static iCode *ifxForOp ( operand *op, iCode *ic )
2221 {
2222   /* if true symbol then needs to be assigned */
2223   if (IS_TRUE_SYMOP(op))
2224     return NULL ;
2225
2226     /* if this has register type condition and
2227     the next instruction is ifx with the same operand
2228     and live to of the operand is upto the ifx only then */
2229   if (ic->next &&
2230       ic->next->op == IFX &&
2231       IC_COND(ic->next)->key == op->key &&
2232       OP_SYMBOL(op)->liveTo <= ic->next->seq )
2233     return ic->next;
2234
2235   return NULL;
2236 }
2237 /*-----------------------------------------------------------------*/
2238 /* genAndOp - for && operation                                     */
2239 /*-----------------------------------------------------------------*/
2240 static void genAndOp (iCode *ic)
2241 {
2242   operand *left,*right, *result;
2243   symbol *tlbl;
2244   int size , offset;
2245
2246   /* note here that && operations that are in an
2247      if statement are taken away by backPatchLabels
2248      only those used in arthmetic operations remain */
2249   aopOp((left=IC_LEFT(ic)),ic,FALSE);
2250   aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2251   aopOp((result=IC_RESULT(ic)),ic,FALSE);
2252
2253   tlbl = newiTempLabel(NULL);
2254   toBoolean(left,"r0",TRUE);
2255   toBoolean(right,"r1",TRUE);
2256   emitcode("and","r0,r1");
2257   emitcode("ldi","r24,1");
2258   emitcode("breq","L%05d",tlbl->key);
2259   emitcode("dec","r24");
2260   emitcode("","L%05d:",tlbl->key);
2261   aopPut(AOP(result),"r24",0);
2262   size = AOP_SIZE(result) -1;
2263   offset = 1;
2264   while (size--) aopPut(AOP(result),zero,offset++);
2265
2266   freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
2267   freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
2268   freeAsmop(result,NULL,ic,TRUE);
2269 }
2270
2271
2272 /*-----------------------------------------------------------------*/
2273 /* genOrOp - for || operation                                      */
2274 /*-----------------------------------------------------------------*/
2275 static void genOrOp (iCode *ic)
2276 {
2277   operand *left,*right, *result;
2278   symbol *tlbl;
2279   int size , offset;
2280
2281   /* note here that || operations that are in an
2282      if statement are taken away by backPatchLabels
2283      only those used in arthmetic operations remain */
2284   aopOp((left=IC_LEFT(ic)),ic,FALSE);
2285   aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2286   aopOp((result=IC_RESULT(ic)),ic,FALSE);
2287
2288   tlbl = newiTempLabel(NULL);
2289   toBoolean(left,"r0",TRUE);
2290   toBoolean(right,"r0",FALSE);
2291   emitcode("ldi","r24,1");
2292   emitcode("breq","L%05d",tlbl->key);
2293   emitcode("dec","r24");
2294   emitcode("","L%05d:",tlbl->key);
2295   aopPut(AOP(result),"r24",0);
2296   size = AOP_SIZE(result) -1;
2297   offset = 1;
2298   while (size--) aopPut(AOP(result),zero,offset++);
2299
2300   freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
2301   freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
2302   freeAsmop(result,NULL,ic,TRUE);
2303 }
2304
2305 /*-----------------------------------------------------------------*/
2306 /* isLiteralBit - test if lit == 2^n                               */
2307 /*-----------------------------------------------------------------*/
2308 static int isLiteralBit(unsigned long lit)
2309 {
2310   unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2311         0x100L,0x200L,0x400L,0x800L,
2312         0x1000L,0x2000L,0x4000L,0x8000L,
2313         0x10000L,0x20000L,0x40000L,0x80000L,
2314         0x100000L,0x200000L,0x400000L,0x800000L,
2315         0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2316         0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2317   int idx;
2318
2319   for(idx = 0; idx < 32; idx++)
2320     if(lit == pw[idx])
2321       return idx+1;
2322   return 0;
2323 }
2324
2325 enum { AVR_AND = 0, AVR_OR, AVR_XOR };
2326 static char *bopnames_lit[] = {"andi","ori"};
2327 static char *bopnames[] = {"and","or","eor"};
2328 /*-----------------------------------------------------------------*/
2329 /* genBitWise - generate bitwise operations                        */
2330 /*-----------------------------------------------------------------*/
2331 static void genBitWise(iCode *ic, iCode *ifx, int bitop)
2332 {
2333   operand *left, *right, *result;
2334   int size, offset=0;
2335   char *l;
2336   symbol *lbl, *lbl1;
2337   int samerl, samerr ;
2338
2339   aopOp((left = IC_LEFT(ic)),ic,FALSE);
2340   aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2341   aopOp((result=IC_RESULT(ic)),ic,TRUE);
2342
2343   size = AOP_SIZE(left);
2344   offset = 0;
2345   if (ifx) { /* used only for jumps */
2346     if (AOP_TYPE(right) == AOP_LIT &&
2347         (bitop == AVR_AND || bitop == AVR_OR)) {
2348       int lit = (int) floatFromVal (AOP(right)->aopu.aop_lit);
2349       int p2 = powof2(lit);
2350       if (bitop == AVR_AND && p2) { /* right side is a power of 2 */
2351         l = aopGet(AOP(left),p2 / 8);
2352         if (IC_TRUE(ifx)) {
2353           emitcode("sbrc","%s,%d",l,(p2 % 8));
2354           emitcode("rjmp","L%05d",IC_TRUE(ifx)->key);
2355         } else {
2356           emitcode("sbrs","%s,%d",l,(p2 % 8));
2357           emitcode("rjmp","L%05d",IC_FALSE(ifx)->key);
2358         }
2359       } else { /* right not power of two */
2360         int eh = OP_SYMBOL(left)->liveTo <= ic->seq;
2361         if (size == 1) {
2362           if (eh) {
2363             emitcode(bopnames_lit[bitop],"%s,lo8(%d)",
2364                aopGet(AOP(IC_LEFT(ic)),0), lit);
2365           } else {
2366             MOVR0(aopGet(AOP(IC_LEFT(ic)),0));
2367             emitcode(bopnames_lit[bitop],"r0,lo8(%d)",lit);
2368           }
2369           lbl = newiTempLabel(NULL);
2370           if (IC_TRUE(ifx)) {
2371             emitcode("breq","L%05d",lbl->key);
2372             emitcode("rjmp","L%05d",IC_TRUE(ifx)->key);
2373           } else {
2374             emitcode("brne","L%05d",lbl->key);
2375             emitcode("rjmp","L%05d",IC_FALSE(ifx)->key);
2376           }
2377           emitcode("","L%05d:",lbl->key);
2378         } else if (size == 2) {
2379           emitcode("mov","r24,%s",aopGet(AOP(IC_LEFT(ic)),0));
2380           emitcode("mov","r25,%s",aopGet(AOP(IC_LEFT(ic)),1));
2381           emitcode(bopnames_lit[bitop],"r24,lo8(%d)",lit);
2382           emitcode(bopnames_lit[bitop],"r25,hi8(%d)",lit);
2383           emitcode("sbiw","r24,0");
2384           lbl = newiTempLabel(NULL);
2385           if (IC_TRUE(ifx)) {
2386             emitcode("breq","L%05d",lbl->key);
2387             emitcode("rjmp","L%05d",IC_TRUE(ifx)->key);
2388           } else {
2389             emitcode("brne","L%05d",lbl->key);
2390             emitcode("rjmp","L%05d",IC_FALSE(ifx)->key);
2391           }
2392           emitcode("","L%05d:",lbl->key);
2393         } else {
2394           lbl = newiTempLabel(NULL);
2395           lbl1 = newiTempLabel(NULL);
2396           while (size--) {
2397             if (eh) {
2398               emitcode(bopnames_lit[bitop],"%s,lo8(%d)",
2399                aopGet(AOP(IC_LEFT(ic)),offset), lit);
2400             } else {
2401               MOVR0(aopGet(AOP(IC_LEFT(ic)),offset));
2402               emitcode("andi","r0,lo8(%d)",lit);
2403             }
2404             emitcode("brne","L%05d",lbl->key);
2405             offset++;
2406           }
2407           /* all are zero */
2408           if (IC_FALSE(ifx)) emitcode("rjmp","L%05d",IC_FALSE(ifx)->key);
2409           else emitcode("rjmp","L%05d",lbl1->key);
2410           emitcode("","L%05d:",lbl->key);
2411           /* not zero */
2412           if (IC_TRUE(ifx)) emitcode("rjmp","L%05d",IC_TRUE(ifx)->key);
2413           emitcode("","L%05d:",lbl1->key);
2414
2415         }
2416       }
2417     } else { /* right is not a literal */
2418       int eh = OP_SYMBOL(left)->liveTo <= ic->seq;
2419       int reh = OP_SYMBOL(right)->liveTo <= ic->seq;
2420       if (size == 1) {
2421         if (eh) {
2422           emitcode(bopnames[bitop],"%s,%s",
2423              aopGet(AOP(IC_LEFT(ic)),0),
2424              aopGet(AOP(IC_RIGHT(ic)),0));
2425         } else if (reh) {
2426           emitcode(bopnames[bitop],"%s,%s",
2427              aopGet(AOP(IC_RIGHT(ic)),0),
2428              aopGet(AOP(IC_LEFT(ic)),0));
2429         } else {
2430           MOVR0(aopGet(AOP(IC_LEFT(ic)),0));
2431           emitcode(bopnames[bitop],"r0,%s",aopGet(AOP(IC_RIGHT(ic)),0));
2432         }
2433         lbl = newiTempLabel(NULL);
2434         if (IC_TRUE(ifx)) {
2435           emitcode("breq","L%05d",lbl->key);
2436           emitcode("rjmp","L%05d",IC_TRUE(ifx)->key);
2437         } else {
2438           emitcode("brne","L%05d",lbl->key);
2439           emitcode("rjmp","L%05d",IC_FALSE(ifx)->key);
2440         }
2441         emitcode("","L%05d:",lbl->key);
2442       } else if (size == 2) {
2443         emitcode("mov","r24,%s",aopGet(AOP(IC_LEFT(ic)),0));
2444         emitcode("mov","r25,%s",aopGet(AOP(IC_LEFT(ic)),1));
2445         emitcode(bopnames[bitop],"r24,%s",aopGet(AOP(IC_RIGHT(ic)),0));
2446         emitcode(bopnames[bitop],"r25,%s",aopGet(AOP(IC_RIGHT(ic)),1));
2447         emitcode("sbiw","r24,0");
2448         lbl = newiTempLabel(NULL);
2449         if (IC_TRUE(ifx)) {
2450           emitcode("breq","L%05d",lbl->key);
2451           emitcode("rjmp","L%05d",IC_TRUE(ifx)->key);
2452         } else {
2453           emitcode("brne","L%05d",lbl->key);
2454           emitcode("rjmp","L%05d",IC_FALSE(ifx)->key);
2455         }
2456         emitcode("","L%05d:",lbl->key);
2457       } else {
2458         lbl = newiTempLabel(NULL);
2459         lbl1 = newiTempLabel(NULL);
2460         while (size--) {
2461           if (eh) {
2462             emitcode(bopnames[bitop],"%s,%s",
2463                aopGet(AOP(IC_LEFT(ic)),offset),
2464                aopGet(AOP(IC_RIGHT(ic)),offset));
2465           } else if (reh) {
2466             emitcode(bopnames[bitop],"%s,%s",
2467                aopGet(AOP(IC_RIGHT(ic)),offset),
2468                aopGet(AOP(IC_LEFT(ic)),offset));
2469           } else {
2470             MOVR0(aopGet(AOP(IC_LEFT(ic)),offset));
2471             emitcode(bopnames[bitop],"r0,%s",aopGet(AOP(IC_RIGHT(ic)),offset));
2472           }
2473           emitcode("brne","L%05d",lbl->key);
2474           offset++;
2475         }
2476         /* all are zero */
2477         if (IC_FALSE(ifx)) emitcode("rjmp","L%05d",IC_FALSE(ifx)->key);
2478         else emitcode("rjmp","L%05d",lbl1->key);
2479         emitcode("","L%05d:",lbl->key);
2480         /* not zero */
2481         if (IC_TRUE(ifx)) emitcode("rjmp","L%05d",IC_TRUE(ifx)->key);
2482         emitcode("","L%05d:",lbl1->key);
2483
2484       }
2485     }
2486     goto release ;
2487   }
2488
2489   /* result needs to go a register */
2490   samerl = sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic)));
2491   samerr = sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)));
2492   while (size--) {
2493     if (AOP_TYPE(right) == AOP_LIT) {
2494       unsigned int lit = (int) floatFromVal (AOP(right)->aopu.aop_lit);
2495       if (((lit >> (8*offset)) & 0xff) == 0) {
2496         if (bitop == AVR_AND) {
2497           aopPut(AOP(result),zero,offset++);
2498           continue;
2499         } else if (bitop == AVR_OR) {
2500           if (!samerl)
2501             aopPut(AOP(result),aopGet(AOP(left),offset),offset);
2502           offset++;
2503           continue;
2504         }
2505       }
2506     }
2507     if (samerl) {
2508       if (AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT && (bitop == AVR_AND || bitop == AVR_OR)) {
2509         emitcode(bopnames_lit[bitop],"%s,%s(%d)",aopGet(AOP(IC_LEFT(ic)),offset),
2510            larray[offset],(int) floatFromVal (AOP(right)->aopu.aop_lit));
2511       } else {
2512         emitcode(bopnames[bitop],"%s,%s",aopGet(AOP(IC_LEFT(ic)),offset),
2513            aopGet(AOP(IC_RIGHT(ic)),offset));
2514       }
2515     } else if (samerr) {
2516       emitcode(bopnames[bitop],"%s,%s",aopGet(AOP(IC_RIGHT(ic)),offset),
2517          aopGet(AOP(IC_LEFT(ic)),offset));
2518     } else {
2519       aopPut(AOP(IC_RESULT(ic)),aopGet(AOP(IC_LEFT(ic)),offset),offset);
2520       emitcode(bopnames[bitop],aopGet(AOP(IC_RESULT(ic)),offset),
2521          aopGet(AOP(IC_RIGHT(ic)),offset));
2522     }
2523     offset++;
2524   }
2525 release :
2526   freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
2527   freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
2528   freeAsmop(result,NULL,ic,TRUE);
2529 }
2530
2531 /*-----------------------------------------------------------------*/
2532 /* genAnd  - code for and                                          */
2533 /*-----------------------------------------------------------------*/
2534 static void genAnd (iCode *ic, iCode *ifx)
2535 {
2536   genBitWise(ic,ifx,AVR_AND);
2537 }
2538
2539 /*-----------------------------------------------------------------*/
2540 /* genOr  - code for or                                            */
2541 /*-----------------------------------------------------------------*/
2542 static void genOr (iCode *ic, iCode *ifx)
2543 {
2544   genBitWise(ic,ifx,AVR_OR);
2545 }
2546
2547 /*-----------------------------------------------------------------*/
2548 /* genXor - code for xclusive or                                   */
2549 /*-----------------------------------------------------------------*/
2550 static void genXor (iCode *ic, iCode *ifx)
2551 {
2552   genBitWise(ic,ifx,AVR_XOR);
2553 }
2554
2555 /*-----------------------------------------------------------------*/
2556 /* genInline - write the inline code out                           */
2557 /*-----------------------------------------------------------------*/
2558 static void genInline (iCode *ic)
2559 {
2560   char buffer[MAX_INLINEASM];
2561   char *bp = buffer;
2562   char *bp1= buffer;
2563
2564   _G.inLine += (!options.asmpeep);
2565   strcpy(buffer,IC_INLINE(ic));
2566
2567   /* emit each line as a code */
2568   while (*bp) {
2569     if (*bp == '\n') {
2570       *bp++ = '\0';
2571       emitcode(bp1,"");
2572       bp1 = bp;
2573     } else {
2574       if (*bp == ':') {
2575         bp++;
2576         *bp = '\0';
2577         bp++;
2578         emitcode(bp1,"");
2579         bp1 = bp;
2580       } else
2581         bp++;
2582     }
2583   }
2584   if (bp1 != bp)
2585     emitcode(bp1,"");
2586   /*     emitcode("",buffer); */
2587   _G.inLine -= (!options.asmpeep);
2588 }
2589
2590 /*-----------------------------------------------------------------*/
2591 /* genRotC - rotate right/left with carry , lr = 1 rotate right    */
2592 /*-----------------------------------------------------------------*/
2593 static void genRotC (iCode *ic, int lr)
2594 {
2595   operand *left , *result ;
2596   int size, offset = 0;
2597
2598   /* rotate right with carry */
2599   left = IC_LEFT(ic);
2600   result=IC_RESULT(ic);
2601   aopOp (left,ic,FALSE);
2602   aopOp (result,ic,FALSE);
2603
2604   /* move it to the result */
2605   size = AOP_SIZE(result);
2606   if (!sameRegs(AOP(left),AOP(result))) {
2607     offset = 0;
2608     while (size--) {
2609       aopPut(AOP(result),
2610              aopGet(AOP(left),offset),
2611              offset);
2612       offset++;
2613     }
2614     size = AOP_SIZE(result);
2615   }
2616   if (lr) offset = size - 1;
2617   else offset = 0;
2618
2619   CLRC;
2620   emitcode ("sbrc","%s,%d",aopGet(AOP(result),offset),
2621       (lr ? 0 : 7));
2622   emitcode("sec","");
2623
2624   while (size--) {
2625     emitcode((lr ? "ror" : "rol"),"%s",aopGet(AOP(result),offset));
2626     if (lr) offset--;
2627     else offset++;
2628   }
2629   freeAsmop(left,NULL,ic,TRUE);
2630   freeAsmop(result,NULL,ic,TRUE);
2631 }
2632
2633 /*-----------------------------------------------------------------*/
2634 /* genRRC - rotate right with carry                                */
2635 /*-----------------------------------------------------------------*/
2636 static void genRRC (iCode *ic)
2637 {
2638   genRotC(ic,1);
2639 }
2640
2641 /*-----------------------------------------------------------------*/
2642 /* genRLC - generate code for rotate left with carry               */
2643 /*-----------------------------------------------------------------*/
2644 static void genRLC (iCode *ic)
2645 {
2646   genRotC(ic,0);
2647 }
2648
2649 /*-----------------------------------------------------------------*/
2650 /* genGetHbit - generates code get highest order bit               */
2651 /*-----------------------------------------------------------------*/
2652 static void genGetHbit (iCode *ic)
2653 {
2654   operand *left, *result;
2655   int size, offset ;
2656
2657   left = IC_LEFT(ic);
2658   result=IC_RESULT(ic);
2659   aopOp (left,ic,FALSE);
2660   aopOp (result,ic,FALSE);
2661
2662   size = AOP_SIZE(result);
2663   if (!sameRegs(AOP(left),AOP(result))) {
2664     emitcode("clr","%s",aopGet(AOP(result),size -1));
2665     emitcode("sbrc","%s,7",aopGet(AOP(left),size -1));
2666     emitcode("subi","%s,lo8(-1)",aopGet(AOP(result),size-1));
2667   } else {
2668     emitcode("clr","r0");
2669     emitcode("sbrc","%s,7",aopGet(AOP(left),size-1));
2670     emitcode("subi","r0,lo8(-1)");
2671     aopPut(AOP(result),"r0",0);
2672   }
2673   offset = 1;
2674   size --;
2675   while (size--) {
2676     emitcode("clr",aopGet(AOP(result),offset++));
2677   }
2678   freeAsmop(left,NULL,ic,TRUE);
2679   freeAsmop(result,NULL,ic,TRUE);
2680 }
2681
2682 /*-----------------------------------------------------------------*/
2683 /* genShiftLeftLit - shift left by a known amount                  */
2684 /*-----------------------------------------------------------------*/
2685 static void genShiftLeftLit (iCode *ic)
2686 {
2687   operand *left,*right, *result;
2688   int size , shCount, offset =0;
2689   int lByteZ=0;
2690
2691   right = IC_RIGHT(ic);
2692   left  = IC_LEFT(ic);
2693   result = IC_RESULT(ic);
2694
2695   aopOp(left,ic,FALSE);
2696   aopOp(result,ic,FALSE);
2697   size = AOP_SIZE(result);
2698   shCount = (int)floatFromVal (AOP(right)->aopu.aop_lit);
2699
2700   if (shCount > (size*8 -1)) {
2701     while (size--) aopPut(AOP(result),zero,offset++);
2702     goto release;
2703   }
2704   switch(size) {
2705   case 1:
2706     if (!sameRegs(AOP(left),AOP(result)))
2707       aopPut(AOP(result),aopGet(AOP(left),0),0);
2708     if (shCount >= 4) {
2709       emitcode("swap","%s",aopGet(AOP(result),0));
2710       emitcode("andi","%s,0xf0");
2711       shCount -= 4;
2712     }
2713     if (shCount == 1) {
2714       emitcode("add","%s,%s",aopGet(AOP(result),0),aopGet(AOP(result),0));
2715       shCount--;
2716     }
2717     while (shCount--)
2718       emitcode("lsl","%s",aopGet(AOP(result),0));
2719     break;
2720   case 2:
2721     if (shCount >= 12) {
2722       aopPut(AOP(result),aopGet(AOP(left),0),1);
2723       aopPut(AOP(result),zero,0);
2724       emitcode("swap","%s",aopGet(AOP(result),1));
2725       emitcode("andi","%s,0xf0",aopGet(AOP(result),1));
2726       shCount -= 12;
2727       lByteZ = 1;
2728     }
2729     if (shCount >= 8) {
2730       aopPut(AOP(result),aopGet(AOP(left),0),1);
2731       aopPut(AOP(result),zero,0);
2732       shCount -= 8;
2733       lByteZ = 1;
2734     }
2735     if (shCount >= 4) {
2736       shCount -= 4;
2737       if (!sameRegs(AOP(left),AOP(result))) {
2738         aopPut(AOP(result),aopGet(AOP(left),0),0);
2739         aopPut(AOP(result),aopGet(AOP(left),1),1);
2740       }
2741       emitcode("mov","r1,%s",aopGet(AOP(result),0));
2742       emitcode("swap","%s",aopGet(AOP(result),0));
2743       emitcode("andi","%s,0xf0",aopGet(AOP(result),0));
2744       emitcode("andi","r1,0x0f");
2745       emitcode("swap","%s",aopGet(AOP(result),1));
2746       emitcode("andi","%s,0xf0",aopGet(AOP(result),1));
2747       emitcode("or","%s,r1",aopGet(AOP(result),1));
2748       while(shCount--) {
2749         emitcode("lsl","%s",aopGet(AOP(result),0));
2750         emitcode("rol","%s",aopGet(AOP(result),1));
2751       }
2752     }
2753     if (!lByteZ && !sameRegs(AOP(result),AOP(left)) && shCount) {
2754       offset = 0;
2755       while(size--) {
2756         aopPut(AOP(result),aopGet(AOP(left),offset),offset);
2757         offset++;
2758       }
2759     }
2760     while (shCount--) {
2761       if (lByteZ) {
2762         emitcode("lsl","%s",aopGet(AOP(result),1));
2763       } else {
2764         emitcode("lsl","%s",aopGet(AOP(result),0));
2765         emitcode("rol","%s",aopGet(AOP(result),1));
2766       }
2767     }
2768     break;
2769   case 3:
2770     assert("shifting generic pointer ?\n");
2771     break;
2772   case 4:
2773     /* 32 bits we do only byte boundaries */
2774     if (shCount >= 24) {
2775       aopPut(AOP(result),aopGet(AOP(left),0),3);
2776       aopPut(AOP(result),zero,2);
2777       aopPut(AOP(result),zero,1);
2778       aopPut(AOP(result),zero,0);
2779       lByteZ = 3;
2780       shCount -= 24;
2781     }
2782     if (shCount >= 16) {
2783       aopPut(AOP(result),aopGet(AOP(left),0),3);
2784       aopPut(AOP(result),aopGet(AOP(left),1),2);
2785       aopPut(AOP(result),zero,1);
2786       aopPut(AOP(result),zero,0);
2787       lByteZ = 2;
2788       shCount -= 16;
2789     }
2790     if (shCount >= 8) {
2791       aopPut(AOP(result),aopGet(AOP(left),0),3);
2792       aopPut(AOP(result),aopGet(AOP(left),1),2);
2793       aopPut(AOP(result),aopGet(AOP(left),2),1);
2794       aopPut(AOP(result),zero,0);
2795       shCount -= 8;
2796       lByteZ = 1;
2797     }
2798     if (!lByteZ && !sameRegs(AOP(left),AOP(right))) {
2799       offset = 0;
2800       while (size--) {
2801         aopPut(AOP(result),aopGet(AOP(left),offset),offset);
2802         offset++;
2803       }
2804       offset = 0;
2805       size = AOP_SIZE(result);
2806     }
2807     if (shCount) {
2808       switch (lByteZ) {
2809       case 0:
2810         while (shCount--) {
2811           emitcode("lsl","%s",aopGet(AOP(result),0));
2812           emitcode("rol","%s",aopGet(AOP(result),1));
2813           emitcode("rol","%s",aopGet(AOP(result),2));
2814           emitcode("rol","%s",aopGet(AOP(result),3));
2815         }
2816         break;
2817       case 1:
2818         while (shCount--) {
2819           emitcode("lsl","%s",aopGet(AOP(result),1));
2820           emitcode("rol","%s",aopGet(AOP(result),2));
2821           emitcode("rol","%s",aopGet(AOP(result),3));
2822         }
2823         break;
2824       case 2:
2825         while (shCount--) {
2826           emitcode("lsl","%s",aopGet(AOP(result),2));
2827           emitcode("rol","%s",aopGet(AOP(result),3));
2828         }
2829         break;
2830       case 3:
2831         while (shCount--) {
2832           emitcode("lsl","%s",aopGet(AOP(result),3));
2833         }
2834         break;
2835       }
2836     }
2837   }
2838
2839  release:
2840   freeAsmop(left,NULL,ic,TRUE);
2841   freeAsmop(right,NULL,ic,TRUE);
2842   freeAsmop(result,NULL,ic,TRUE);
2843 }
2844
2845 /*-----------------------------------------------------------------*/
2846 /* genLeftShift - generates code for left shifting                 */
2847 /*-----------------------------------------------------------------*/
2848 static void genLeftShift (iCode *ic)
2849 {
2850   operand *left,*right, *result;
2851   int size, offset;
2852   symbol *tlbl;
2853
2854   right = IC_RIGHT(ic);
2855   left  = IC_LEFT(ic);
2856   result = IC_RESULT(ic);
2857
2858   aopOp(right,ic,FALSE);
2859
2860   if (AOP_TYPE(right) == AOP_LIT) {
2861     genShiftLeftLit(ic);
2862     return ;
2863   }
2864
2865   /* unknown count */
2866   aopOp(left,ic,FALSE);
2867   aopOp(result,ic,FALSE);
2868   size = AOP_SIZE(result);
2869   offset = 0;
2870   if (AOP_SIZE(right) > 1) {
2871     if (isRegPair(AOP(right))) {
2872       emitcode("movw","r24,%s",aopGet(AOP(right),0));
2873     } else {
2874       emitcode("mov","r24,%s",aopGet(AOP(right),0));
2875       emitcode("mov","r25,%s",aopGet(AOP(right),1));
2876     }
2877   } else {
2878     emitcode("mov","r24,%s",aopGet(AOP(right),0));
2879   }
2880   if (!sameRegs(AOP(left),AOP(result))) {
2881     while (size--) {
2882       aopPut(AOP(result),aopGet(AOP(left),offset),offset);
2883       offset++;
2884     }
2885     size = AOP_SIZE(result);
2886   }
2887   tlbl = newiTempLabel(NULL);
2888   emitcode("","L%05d:",tlbl->key);
2889   offset = 0;
2890         while (size--) {
2891     if (offset) emitcode("rol","%s",aopGet(AOP(result),offset));
2892     else emitcode("lsl","%s",aopGet(AOP(result),0));
2893     offset++;
2894   }
2895   if (AOP_SIZE(right) > 1) emitcode("sbiw","r24,1");
2896   else emitcode("dec","r24");
2897   emitcode("brne","L%05d",tlbl->key);
2898
2899   freeAsmop(left,NULL,ic,TRUE);
2900   freeAsmop(right,NULL,ic,TRUE);
2901   freeAsmop(result,NULL,ic,TRUE);
2902 }
2903
2904 /*-----------------------------------------------------------------*/
2905 /* genShiftRightLit - generate for right shift with known count    */
2906 /*-----------------------------------------------------------------*/
2907 static void genShiftRightLit (iCode *ic)
2908 {
2909   operand *left = IC_LEFT(ic)
2910     ,*right= IC_RIGHT(ic)
2911     ,*result=IC_RESULT(ic);
2912   int size , shCount, offset =0;
2913   int hByteZ=0;
2914   sym_link *letype = getSpec(operandType(left));
2915   int sign = !SPEC_USIGN(letype);
2916
2917   right = IC_RIGHT(ic);
2918   left  = IC_LEFT(ic);
2919   result = IC_RESULT(ic);
2920
2921   aopOp(left,ic,FALSE);
2922   aopOp(result,ic,FALSE);
2923   size = AOP_SIZE(result);
2924   shCount = (int)floatFromVal (AOP(right)->aopu.aop_lit);
2925
2926   /* if signed then give up and use a loop to shift */
2927   if (sign) {
2928     symbol *tlbl ;
2929     if (!sameRegs(AOP(left),AOP(result))) {
2930       while (size--) {
2931         aopPut(AOP(result),aopGet(AOP(left),offset),offset);
2932         offset++;
2933       }
2934       size =  size = AOP_SIZE(result);
2935       offset = 0;
2936     }
2937     /* be as economical as possible */
2938     if (shCount <= 4) {
2939       offset = size -1;
2940       while (shCount--) {
2941         offset = size -1;
2942         size = AOP_SIZE(result);
2943         while (size--) {
2944           if (offset == (size-1))
2945             emitcode("asr","%s",aopGet(AOP(result),offset));
2946           else
2947             emitcode("lsr","%s",aopGet(AOP(result),offset));
2948           offset--;
2949         }
2950       }
2951     } else {
2952       emitcode("ldi","r24,lo8(%d)",shCount);
2953       tlbl = newiTempLabel(NULL);
2954       emitcode("","L%05d:",tlbl->key);
2955       offset = size -1;
2956       while (size--) {
2957         if (offset == (size-1)) emitcode("asr","%s",aopGet(AOP(result),offset));
2958         else emitcode("lsr","%s",aopGet(AOP(result),offset));
2959         offset--;
2960       }
2961       emitcode("dec","r24");
2962       emitcode("brne","L%05d",tlbl->key);
2963     }
2964     goto release;
2965   }
2966   if (shCount > (size*8 -1)) {
2967     while (size--) aopPut(AOP(result),zero,offset++);
2968     goto release;
2969   }
2970   /* for unsigned we can much more efficient */
2971   switch (size) {
2972   case 1:
2973     if (!sameRegs(AOP(left),AOP(result)))
2974       aopPut(AOP(result),aopGet(AOP(left),0),0);
2975     if (shCount >= 4) {
2976       emitcode("swap","%s",aopGet(AOP(result),0));
2977       emitcode("andi","%s,0x0f");
2978       shCount -= 4;
2979     }
2980     while (shCount--)
2981       emitcode("lsr","%s",aopGet(AOP(result),0));
2982     break;
2983   case 2:
2984     if (shCount >= 12) {
2985       aopPut(AOP(result),aopGet(AOP(left),1),0);
2986       aopPut(AOP(result),zero,1);
2987       emitcode("swap","%s",aopGet(AOP(result),0));
2988       emitcode("andi","%s,0x0f",aopGet(AOP(result),0));
2989       shCount -= 12;
2990       hByteZ = 1;
2991     }
2992     if (shCount >= 8) {
2993       aopPut(AOP(result),aopGet(AOP(left),1),0);
2994       aopPut(AOP(result),zero,1);
2995       shCount -= 8;
2996       hByteZ = 1;
2997     }
2998     if (shCount >= 4) {
2999       shCount -= 4;
3000       if (!sameRegs(AOP(left),AOP(result))) {
3001         aopPut(AOP(result),aopGet(AOP(left),0),0);
3002         aopPut(AOP(result),aopGet(AOP(left),1),1);
3003       }
3004       emitcode("mov","r1,%s",aopGet(AOP(result),1));
3005       emitcode("swap","%s",aopGet(AOP(result),0));
3006       emitcode("andi","%s,0x0f",aopGet(AOP(result),0));
3007       emitcode("andi","r1,0xf0");
3008       emitcode("or","%s,r1",aopGet(AOP(result),0));
3009       emitcode("swap","%s",aopGet(AOP(result),1));
3010       emitcode("andi","%s,0x0f",aopGet(AOP(result),1));
3011       while(shCount--) {
3012         emitcode("lsr","%s",aopGet(AOP(result),1));
3013         emitcode("ror","%s",aopGet(AOP(result),0));
3014       }
3015
3016     }
3017     if (!hByteZ && !sameRegs(AOP(result),AOP(left)) && shCount) {
3018       offset = 0;
3019       while(size--) {
3020         aopPut(AOP(result),aopGet(AOP(left),offset),offset);
3021         offset++;
3022       }
3023     }
3024     while (shCount--) {
3025       if (hByteZ) {
3026         emitcode("lsr","%s",aopGet(AOP(result),0));
3027       } else {
3028         emitcode("lsr","%s",aopGet(AOP(result),1));
3029         emitcode("ror","%s",aopGet(AOP(result),0));
3030       }
3031     }
3032     break;
3033
3034   case 3:
3035     assert("shifting generic pointer ?\n");
3036     break;
3037   case 4:
3038     /* 32 bits we do only byte boundaries */
3039     if (shCount >= 24) {
3040       aopPut(AOP(result),aopGet(AOP(left),3),0);
3041       aopPut(AOP(result),zero,1);
3042       aopPut(AOP(result),zero,2);
3043       aopPut(AOP(result),zero,3);
3044       hByteZ = 3;
3045       shCount -= 24;
3046     }
3047     if (shCount >= 16) {
3048       aopPut(AOP(result),aopGet(AOP(left),3),1);
3049       aopPut(AOP(result),aopGet(AOP(left),2),0);
3050       aopPut(AOP(result),zero,2);
3051       aopPut(AOP(result),zero,3);
3052       hByteZ = 2;
3053       shCount -= 16;
3054     }
3055     if (shCount >= 8) {
3056       aopPut(AOP(result),aopGet(AOP(left),1),0);
3057       aopPut(AOP(result),aopGet(AOP(left),2),1);
3058       aopPut(AOP(result),aopGet(AOP(left),3),2);
3059       aopPut(AOP(result),zero,3);
3060       shCount -= 8;
3061       hByteZ = 1;
3062     }
3063     if (!hByteZ && !sameRegs(AOP(left),AOP(right))) {
3064       offset = 0;
3065       while (size--) {
3066         aopPut(AOP(result),aopGet(AOP(left),offset),offset);
3067         offset++;
3068       }
3069       offset = 0;
3070       size = AOP_SIZE(result);
3071     }
3072     if (shCount) {
3073       switch (hByteZ) {
3074       case 0:
3075         while (shCount--) {
3076           emitcode("lsr","%s",aopGet(AOP(result),3));
3077           emitcode("ror","%s",aopGet(AOP(result),2));
3078           emitcode("ror","%s",aopGet(AOP(result),1));
3079           emitcode("ror","%s",aopGet(AOP(result),0));
3080         }
3081         break;
3082       case 1:
3083         while (shCount--) {
3084           emitcode("lsr","%s",aopGet(AOP(result),2));
3085           emitcode("ror","%s",aopGet(AOP(result),1));
3086           emitcode("ror","%s",aopGet(AOP(result),0));
3087         }
3088         break;
3089       case 2:
3090         while (shCount--) {
3091           emitcode("lsr","%s",aopGet(AOP(result),1));
3092           emitcode("ror","%s",aopGet(AOP(result),0));
3093         }
3094         break;
3095       case 3:
3096         while (shCount--) {
3097           emitcode("lsr","%s",aopGet(AOP(result),0));
3098         }
3099         break;
3100       }
3101     }
3102   }
3103  release:
3104   freeAsmop(left,NULL,ic,TRUE);
3105   freeAsmop(right,NULL,ic,TRUE);
3106   freeAsmop(result,NULL,ic,TRUE);
3107 }
3108
3109 /*-----------------------------------------------------------------*/
3110 /* genRightShift - generate code for right shifting                */
3111 /*-----------------------------------------------------------------*/
3112 static void genRightShift (iCode *ic)
3113 {
3114   operand *right, *left, *result;
3115   sym_link *letype ;
3116   int size, offset;
3117   int sign = 0, first =1;
3118   symbol *tlbl;
3119
3120   aopOp(right=IC_RIGHT(ic),ic,FALSE);
3121   if (AOP_TYPE(right) == AOP_LIT) {
3122     genShiftRightLit(ic);
3123     return ;
3124   }
3125   /* unknown count */
3126   if (AOP_SIZE(right) > 1) {
3127     if (isRegPair(AOP(right))) {
3128       emitcode("movw","r24,%s",aopGet(AOP(right),0));
3129     } else {
3130       emitcode("mov","r24,%s",aopGet(AOP(right),0));
3131       emitcode("mov","r25,%s",aopGet(AOP(right),1));
3132     }
3133   } else {
3134     emitcode("mov","r24,%s",aopGet(AOP(right),0));
3135   }
3136   aopOp(left=IC_LEFT(ic),ic,FALSE);
3137   aopOp(result=IC_RESULT(ic),ic,FALSE);
3138   size = AOP_SIZE(result);
3139   tlbl = newiTempLabel(NULL);
3140   emitcode("","L%05d:",tlbl->key);
3141   offset = size -1;
3142   letype = getSpec(operandType(left));
3143   sign = !SPEC_USIGN(letype);
3144   if (!sameRegs(AOP(left),AOP(result))) {
3145     while (size--) {
3146       aopPut(AOP(result),aopGet(AOP(left),offset),offset);
3147       offset++;
3148     }
3149     size = AOP_SIZE(result);
3150   }
3151   size = AOP_SIZE(result);
3152   while (size--) {
3153     if (first) {
3154       if (sign) emitcode("asr","%s",aopGet(AOP(result),offset));
3155       else emitcode("lsr","%s",aopGet(AOP(result),offset));
3156       first = 0;
3157     }
3158     else emitcode("ror","%s",aopGet(AOP(result),offset));
3159     offset--;
3160   }
3161   if (AOP_SIZE(right) > 1) emitcode("sbiw","r24,1");
3162   else emitcode("dec","r24");
3163   emitcode("brne","L%05d",tlbl->key);
3164
3165   freeAsmop(left,NULL,ic,TRUE);
3166   freeAsmop(result,NULL,ic,TRUE);
3167 }
3168
3169 /*-----------------------------------------------------------------*/
3170 /* R0Rsh - shift right r0 by known count                           */
3171 /*-----------------------------------------------------------------*/
3172 static void R0Rsh (int shCount)
3173 {
3174   shCount &= 0x0007;              // shCount : 0..7
3175   switch(shCount){
3176         case 0 :
3177     break;
3178         case 1 :
3179     emitcode("lsr","r0");
3180     break;
3181         case 2 :
3182     emitcode("lsr","r0");
3183     emitcode("lsr","r0");
3184     break;
3185         case 3 :
3186     emitcode("swap","r0");
3187     emitcode("lsl","r0");
3188     break;
3189         case 4 :
3190     emitcode("swap","r0");
3191     break;
3192         case 5 :
3193     emitcode("swap","r0");
3194     emitcode("lsr","r0");
3195     break;
3196         case 6 :
3197     emitcode("swap","r0");
3198     emitcode("lsr","r0");
3199     emitcode("lsr","r0");
3200     break;
3201         case 7 :
3202     emitcode("swap","r0");
3203     emitcode("lsr","r0");
3204     emitcode("lsr","r0");
3205     emitcode("lsr","r0");
3206     break;
3207   }
3208 }
3209
3210 /*-----------------------------------------------------------------*/
3211 /* genUnpackBits - generates code for unpacking bits               */
3212 /*-----------------------------------------------------------------*/
3213 static void genUnpackBits (operand *result, char *rname, int ptype)
3214 {
3215   int shCnt ;
3216   int rlen = 0 ;
3217   sym_link *etype;
3218   int offset = 0 ;
3219
3220   etype = getSpec(operandType(result));
3221
3222   /* read the first byte  */
3223   switch (ptype) {
3224
3225   case POINTER:
3226   case IPOINTER:
3227   case PPOINTER:
3228   case FPOINTER:
3229     emitcode("ld","r0,%s+",rname);
3230     break;
3231
3232   case CPOINTER:
3233     emitcode("ldm","r0,%s+",rname);
3234     break;
3235
3236   case GPOINTER:
3237     emitcode("call","__gptrget_pi");
3238     break;
3239   }
3240
3241   /* if we have bitdisplacement then it fits   */
3242   /* into this byte completely or if length is */
3243   /* less than a byte                          */
3244   if ((shCnt = SPEC_BSTR(etype)) || (SPEC_BLEN(etype) <= 8))  {
3245
3246     /* shift right r0 */
3247     R0Rsh(shCnt);
3248     emitcode("andi","r0,0x%02x",
3249        ((unsigned char) -1)>>(8 - SPEC_BLEN(etype)));
3250
3251     aopPut(AOP(result),"r0",offset);
3252     return ;
3253   }
3254
3255   /* bit field did not fit in a byte  */
3256   rlen = SPEC_BLEN(etype) - 8;
3257   aopPut(AOP(result),"a",offset++);
3258
3259   while (1)  {
3260
3261     switch (ptype) {
3262     case POINTER:
3263     case IPOINTER:
3264     case PPOINTER:
3265     case FPOINTER:
3266       emitcode("ld","r0,%s+",rname);
3267       break;
3268
3269     case CPOINTER:
3270       emitcode("ldm","r0,%s+",rname);
3271       break;
3272
3273     case GPOINTER:
3274       emitcode("lcall","__gptrget_pi");
3275       break;
3276     }
3277
3278     rlen -= 8;
3279         /* if we are done */
3280     if ( rlen <= 0 )
3281       break ;
3282
3283     aopPut(AOP(result),"r0",offset++);
3284
3285   }
3286
3287   if (rlen) {
3288     emitcode("andi","r0,#0x%02x",((unsigned char)-1)>>(-rlen));
3289     aopPut(AOP(result),"r0",offset);
3290   }
3291
3292   return ;
3293 }
3294
3295
3296 /*-----------------------------------------------------------------*/
3297 /* genDataPointerGet - generates code when ptr offset is known     */
3298 /*-----------------------------------------------------------------*/
3299 static void genDataPointerGet (operand *left,
3300              operand *result,
3301              iCode *ic)
3302 {
3303   char *l;
3304   char buffer[256];
3305   int size , offset = 0;
3306   aopOp(result,ic,TRUE);
3307
3308   /* get the string representation of the name */
3309   l = aopGet(AOP(left),0);
3310   size = AOP_SIZE(result);
3311   while (size--) {
3312     if (offset)
3313       sprintf(buffer,"(%s + %d)",l+1,offset);
3314     else
3315       sprintf(buffer,"%s",l+1);
3316     emitcode("lds","%s,%s",aopGet(AOP(result),offset++),buffer);
3317   }
3318
3319   freeAsmop(left,NULL,ic,TRUE);
3320   freeAsmop(result,NULL,ic,TRUE);
3321 }
3322
3323 /*-----------------------------------------------------------------*/
3324 /* genNearPointerGet - emitcode for near pointer fetch             */
3325 /*-----------------------------------------------------------------*/
3326 static void genNearPointerGet (operand *left,
3327              operand *result,
3328              iCode *ic)
3329 {
3330   asmop *aop = NULL;
3331   regs *preg = NULL ;
3332   char *rname ;
3333   sym_link *rtype, *retype;
3334   sym_link *ltype = operandType(left);
3335   char buffer[80];
3336
3337   rtype = operandType(result);
3338   retype= getSpec(rtype);
3339
3340   aopOp(left,ic,FALSE);
3341
3342   /* if left is rematerialisable and
3343      result is not bit variable type and
3344      the left is pointer to data space i.e
3345      lower 128 bytes of space */
3346   if (AOP_TYPE(left) == AOP_IMMD &&
3347       !IS_BITVAR(retype)         &&
3348       DCL_TYPE(ltype) == POINTER) {
3349     genDataPointerGet (left,result,ic);
3350     return ;
3351   }
3352
3353   /* if the value is already in a pointer register
3354      then don't need anything more */
3355   if (!AOP_INPREG(AOP(left))) {
3356         /* otherwise get a free pointer register */
3357     aop = newAsmop(0);
3358     preg = getFreePtr(ic,&aop,FALSE,0);
3359     emitcode("mov","%s,%s",
3360        preg->name,
3361        aopGet(AOP(left),0));
3362     rname = preg->name ;
3363   } else
3364     rname = aopGet(AOP(left),0);
3365
3366   freeAsmop(left,NULL,ic,TRUE);
3367   aopOp (result,ic,FALSE);
3368
3369   /* if bitfield then unpack the bits */
3370   if (IS_BITVAR(retype))
3371     genUnpackBits (result,rname,POINTER);
3372   else {
3373         /* we have can just get the values */
3374     int size = AOP_SIZE(result);
3375     int offset = 0 ;
3376
3377     while (size--) {
3378       if (IS_AOP_PREG(result) || AOP_TYPE(result) == AOP_STK ) {
3379
3380         emitcode("mov","a,@%s",rname);
3381         aopPut(AOP(result),"a",offset);
3382       } else {
3383         sprintf(buffer,"@%s",rname);
3384         aopPut(AOP(result),buffer,offset);
3385       }
3386       offset++ ;
3387       if (size)
3388         emitcode("inc","%s",rname);
3389     }
3390   }
3391
3392   /* now some housekeeping stuff */
3393   if (aop) {
3394         /* we had to allocate for this iCode */
3395     freeAsmop(NULL,aop,ic,TRUE);
3396   } else {
3397         /* we did not allocate which means left
3398            already in a pointer register, then
3399            if size > 0 && this could be used again
3400            we have to point it back to where it
3401            belongs */
3402     if (AOP_SIZE(result) > 1 &&
3403         !OP_SYMBOL(left)->remat &&
3404         ( OP_SYMBOL(left)->liveTo > ic->seq ||
3405           ic->depth )) {
3406       int size = AOP_SIZE(result) - 1;
3407       while (size--)
3408         emitcode("dec","%s",rname);
3409     }
3410   }
3411
3412   /* done */
3413   freeAsmop(result,NULL,ic,TRUE);
3414
3415 }
3416
3417 /*-----------------------------------------------------------------*/
3418 /* genPagedPointerGet - emitcode for paged pointer fetch           */
3419 /*-----------------------------------------------------------------*/
3420 static void genPagedPointerGet (operand *left,
3421         operand *result,
3422         iCode *ic)
3423 {
3424   asmop *aop = NULL;
3425   regs *preg = NULL ;
3426   char *rname ;
3427   sym_link *rtype, *retype;
3428
3429   rtype = operandType(result);
3430   retype= getSpec(rtype);
3431
3432   aopOp(left,ic,FALSE);
3433
3434   /* if the value is already in a pointer register
3435      then don't need anything more */
3436   if (!AOP_INPREG(AOP(left))) {
3437         /* otherwise get a free pointer register */
3438     aop = newAsmop(0);
3439     preg = getFreePtr(ic,&aop,FALSE,0);
3440     emitcode("mov","%s,%s",
3441        preg->name,
3442        aopGet(AOP(left),0));
3443     rname = preg->name ;
3444   } else
3445     rname = aopGet(AOP(left),0);
3446
3447   freeAsmop(left,NULL,ic,TRUE);
3448   aopOp (result,ic,FALSE);
3449
3450   /* if bitfield then unpack the bits */
3451   if (IS_BITVAR(retype))
3452     genUnpackBits (result,rname,PPOINTER);
3453   else {
3454         /* we have can just get the values */
3455     int size = AOP_SIZE(result);
3456     int offset = 0 ;
3457
3458     while (size--) {
3459
3460       emitcode("movx","a,@%s",rname);
3461       aopPut(AOP(result),"a",offset);
3462
3463       offset++ ;
3464
3465       if (size)
3466         emitcode("inc","%s",rname);
3467     }
3468   }
3469
3470   /* now some housekeeping stuff */
3471   if (aop) {
3472         /* we had to allocate for this iCode */
3473     freeAsmop(NULL,aop,ic,TRUE);
3474   } else {
3475         /* we did not allocate which means left
3476            already in a pointer register, then
3477            if size > 0 && this could be used again
3478            we have to point it back to where it
3479            belongs */
3480     if (AOP_SIZE(result) > 1 &&
3481         !OP_SYMBOL(left)->remat &&
3482         ( OP_SYMBOL(left)->liveTo > ic->seq ||
3483           ic->depth )) {
3484       int size = AOP_SIZE(result) - 1;
3485       while (size--)
3486         emitcode("dec","%s",rname);
3487     }
3488   }
3489
3490   /* done */
3491   freeAsmop(result,NULL,ic,TRUE);
3492
3493
3494 }
3495
3496 /*-----------------------------------------------------------------*/
3497 /* genFarPointerGet - gget value from far space                    */
3498 /*-----------------------------------------------------------------*/
3499 static void genFarPointerGet (operand *left,
3500             operand *result, iCode *ic)
3501 {
3502   int size, offset ;
3503   sym_link *retype = getSpec(operandType(result));
3504
3505   aopOp(left,ic,FALSE);
3506
3507   /* if the operand is already in dptr
3508      then we do nothing else we move the value to dptr */
3509   if (AOP_TYPE(left) != AOP_STR) {
3510         /* if this is remateriazable */
3511     if (AOP_TYPE(left) == AOP_IMMD)
3512       emitcode("mov","dptr,%s",aopGet(AOP(left),0));
3513     else { /* we need to get it byte by byte */
3514       emitcode("mov","dpl,%s",aopGet(AOP(left),0));
3515       emitcode("mov","dph,%s",aopGet(AOP(left),1));
3516       if (options.model == MODEL_FLAT24)
3517         {
3518           emitcode("mov", "dpx,%s",aopGet(AOP(left),2));
3519         }
3520     }
3521   }
3522   /* so dptr know contains the address */
3523   freeAsmop(left,NULL,ic,TRUE);
3524   aopOp(result,ic,FALSE);
3525
3526   /* if bit then unpack */
3527   if (IS_BITVAR(retype))
3528     genUnpackBits(result,"dptr",FPOINTER);
3529   else {
3530     size = AOP_SIZE(result);
3531     offset = 0 ;
3532
3533     while (size--) {
3534       emitcode("movx","a,@dptr");
3535       aopPut(AOP(result),"a",offset++);
3536       if (size)
3537         emitcode("inc","dptr");
3538     }
3539   }
3540
3541   freeAsmop(result,NULL,ic,TRUE);
3542 }
3543
3544 /*-----------------------------------------------------------------*/
3545 /* emitcodePointerGet - gget value from code space                  */
3546 /*-----------------------------------------------------------------*/
3547 static void emitcodePointerGet (operand *left,
3548         operand *result, iCode *ic)
3549 {
3550   int size, offset ;
3551   sym_link *retype = getSpec(operandType(result));
3552
3553   aopOp(left,ic,FALSE);
3554
3555   /* if the operand is already in dptr
3556      then we do nothing else we move the value to dptr */
3557   if (AOP_TYPE(left) != AOP_STR) {
3558         /* if this is remateriazable */
3559     if (AOP_TYPE(left) == AOP_IMMD)
3560       emitcode("mov","dptr,%s",aopGet(AOP(left),0));
3561     else { /* we need to get it byte by byte */
3562       emitcode("mov","dpl,%s",aopGet(AOP(left),0));
3563       emitcode("mov","dph,%s",aopGet(AOP(left),1));
3564       if (options.model == MODEL_FLAT24)
3565         {
3566           emitcode("mov", "dpx,%s",aopGet(AOP(left),2));
3567         }
3568     }
3569   }
3570   /* so dptr know contains the address */
3571   freeAsmop(left,NULL,ic,TRUE);
3572   aopOp(result,ic,FALSE);
3573
3574   /* if bit then unpack */
3575   if (IS_BITVAR(retype))
3576     genUnpackBits(result,"dptr",CPOINTER);
3577   else {
3578     size = AOP_SIZE(result);
3579     offset = 0 ;
3580
3581     while (size--) {
3582       emitcode("clr","a");
3583       emitcode("movc","a,@a+dptr");
3584       aopPut(AOP(result),"a",offset++);
3585       if (size)
3586         emitcode("inc","dptr");
3587     }
3588   }
3589
3590   freeAsmop(result,NULL,ic,TRUE);
3591 }
3592
3593 /*-----------------------------------------------------------------*/
3594 /* genGenPointerGet - gget value from generic pointer space        */
3595 /*-----------------------------------------------------------------*/
3596 static void genGenPointerGet (operand *left,
3597             operand *result, iCode *ic)
3598 {
3599   int size, offset ;
3600   sym_link *retype = getSpec(operandType(result));
3601
3602   aopOp(left,ic,FALSE);
3603
3604   /* if the operand is already in dptr
3605      then we do nothing else we move the value to dptr */
3606   if (AOP_TYPE(left) != AOP_STR) {
3607         /* if this is remateriazable */
3608     if (AOP_TYPE(left) == AOP_IMMD) {
3609       emitcode("mov","dptr,%s",aopGet(AOP(left),0));
3610       emitcode("mov","b,#%d",pointerCode(retype));
3611     }
3612     else { /* we need to get it byte by byte */
3613       emitcode("mov","dpl,%s",aopGet(AOP(left),0));
3614       emitcode("mov","dph,%s",aopGet(AOP(left),1));
3615       if (options.model == MODEL_FLAT24)
3616         {
3617           emitcode("mov", "dpx,%s",aopGet(AOP(left),2));
3618           emitcode("mov","b,%s",aopGet(AOP(left),3));
3619         }
3620       else
3621         {
3622           emitcode("mov","b,%s",aopGet(AOP(left),2));
3623         }
3624     }
3625   }
3626   /* so dptr know contains the address */
3627   freeAsmop(left,NULL,ic,TRUE);
3628   aopOp(result,ic,FALSE);
3629
3630   /* if bit then unpack */
3631   if (IS_BITVAR(retype))
3632     genUnpackBits(result,"dptr",GPOINTER);
3633   else {
3634     size = AOP_SIZE(result);
3635     offset = 0 ;
3636
3637     while (size--) {
3638       emitcode("lcall","__gptrget");
3639       aopPut(AOP(result),"a",offset++);
3640       if (size)
3641         emitcode("inc","dptr");
3642     }
3643   }
3644
3645   freeAsmop(result,NULL,ic,TRUE);
3646 }
3647
3648 /*-----------------------------------------------------------------*/
3649 /* genPointerGet - generate code for pointer get                   */
3650 /*-----------------------------------------------------------------*/
3651 static void genPointerGet (iCode *ic)
3652 {
3653   operand *left, *result ;
3654   sym_link *type, *etype;
3655   int p_type;
3656
3657   left = IC_LEFT(ic);
3658   result = IC_RESULT(ic) ;
3659
3660   /* depending on the type of pointer we need to
3661      move it to the correct pointer register */
3662   type = operandType(left);
3663   etype = getSpec(type);
3664   /* if left is of type of pointer then it is simple */
3665   if (IS_PTR(type) && !IS_FUNC(type->next))
3666     p_type = DCL_TYPE(type);
3667   else {
3668         /* we have to go by the storage class */
3669     p_type = PTR_TYPE(SPEC_OCLS(etype));
3670
3671         /*  if (SPEC_OCLS(etype)->codesp ) { */
3672         /*      p_type = CPOINTER ;  */
3673         /*  } */
3674         /*  else */
3675         /*      if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */
3676         /*    p_type = FPOINTER ; */
3677         /*      else */
3678         /*    if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */
3679         /*        p_type = PPOINTER; */
3680         /*    else */
3681         /*        if (SPEC_OCLS(etype) == idata ) */
3682         /*      p_type = IPOINTER; */
3683         /*        else */
3684         /*      p_type = POINTER ; */
3685   }
3686
3687   /* now that we have the pointer type we assign
3688      the pointer values */
3689   switch (p_type) {
3690
3691   case POINTER:
3692   case IPOINTER:
3693     genNearPointerGet (left,result,ic);
3694     break;
3695
3696   case PPOINTER:
3697     genPagedPointerGet(left,result,ic);
3698     break;
3699
3700   case FPOINTER:
3701     genFarPointerGet (left,result,ic);
3702     break;
3703
3704   case CPOINTER:
3705     emitcodePointerGet (left,result,ic);
3706     break;
3707
3708   case GPOINTER:
3709     genGenPointerGet (left,result,ic);
3710     break;
3711   }
3712
3713 }
3714
3715 /*-----------------------------------------------------------------*/
3716 /* genPackBits - generates code for packed bit storage             */
3717 /*-----------------------------------------------------------------*/
3718 static void genPackBits (sym_link    *etype ,
3719        operand *right ,
3720        char *rname, int p_type)
3721 {
3722   int shCount = 0 ;
3723   int offset = 0  ;
3724   int rLen = 0 ;
3725   int blen, bstr ;
3726   char *l ;
3727
3728   blen = SPEC_BLEN(etype);
3729   bstr = SPEC_BSTR(etype);
3730
3731   l = aopGet(AOP(right),offset++);
3732   MOVA(l);
3733
3734   /* if the bit lenth is less than or    */
3735   /* it exactly fits a byte then         */
3736   if (SPEC_BLEN(etype) <= 8 )  {
3737     shCount = SPEC_BSTR(etype) ;
3738
3739         /* shift left acc */
3740     //    AccLsh(shCount);
3741
3742     if (SPEC_BLEN(etype) < 8 ) { /* if smaller than a byte */
3743
3744
3745       switch (p_type) {
3746       case POINTER:
3747         emitcode ("mov","b,a");
3748         emitcode("mov","a,@%s",rname);
3749         break;
3750
3751       case FPOINTER:
3752         emitcode ("mov","b,a");
3753         emitcode("movx","a,@dptr");
3754         break;
3755
3756       case GPOINTER:
3757         emitcode ("push","b");
3758         emitcode ("push","acc");
3759         emitcode ("lcall","__gptrget");
3760         emitcode ("pop","b");
3761         break;
3762       }
3763
3764       emitcode ("anl","a,#0x%02x",(unsigned char)
3765           ((unsigned char)(0xFF << (blen+bstr)) |
3766            (unsigned char)(0xFF >> (8-bstr)) ) );
3767       emitcode ("orl","a,b");
3768       if (p_type == GPOINTER)
3769         emitcode("pop","b");
3770     }
3771   }
3772
3773   switch (p_type) {
3774   case POINTER:
3775     emitcode("mov","@%s,a",rname);
3776     break;
3777
3778   case FPOINTER:
3779     emitcode("movx","@dptr,a");
3780     break;
3781
3782   case GPOINTER:
3783     emitcode("lcall","__gptrput");
3784     break;
3785   }
3786
3787   /* if we r done */
3788   if ( SPEC_BLEN(etype) <= 8 )
3789     return ;
3790
3791   emitcode("inc","%s",rname);
3792   rLen = SPEC_BLEN(etype) ;
3793
3794   /* now generate for lengths greater than one byte */
3795   while (1) {
3796
3797     l = aopGet(AOP(right),offset++);
3798
3799     rLen -= 8 ;
3800     if (rLen <= 0 )
3801       break ;
3802
3803     switch (p_type) {
3804     case POINTER:
3805       if (*l == '@') {
3806         MOVA(l);
3807         emitcode("mov","@%s,a",rname);
3808       } else
3809         emitcode("mov","@%s,%s",rname,l);
3810       break;
3811
3812     case FPOINTER:
3813       MOVA(l);
3814       emitcode("movx","@dptr,a");
3815       break;
3816
3817     case GPOINTER:
3818       MOVA(l);
3819       emitcode("lcall","__gptrput");
3820       break;
3821     }
3822     emitcode ("inc","%s",rname);
3823   }
3824
3825   MOVA(l);
3826
3827   /* last last was not complete */
3828   if (rLen)   {
3829         /* save the byte & read byte */
3830     switch (p_type) {
3831     case POINTER:
3832       emitcode ("mov","b,a");
3833       emitcode("mov","a,@%s",rname);
3834       break;
3835
3836     case FPOINTER:
3837       emitcode ("mov","b,a");
3838       emitcode("movx","a,@dptr");
3839       break;
3840
3841     case GPOINTER:
3842       emitcode ("push","b");
3843       emitcode ("push","acc");
3844       emitcode ("lcall","__gptrget");
3845       emitcode ("pop","b");
3846       break;
3847     }
3848
3849     emitcode ("anl","a,#0x%02x",((unsigned char)-1 << -rLen) );
3850     emitcode ("orl","a,b");
3851   }
3852
3853   if (p_type == GPOINTER)
3854     emitcode("pop","b");
3855
3856   switch (p_type) {
3857
3858   case POINTER:
3859     emitcode("mov","@%s,a",rname);
3860     break;
3861
3862   case FPOINTER:
3863     emitcode("movx","@dptr,a");
3864     break;
3865
3866   case GPOINTER:
3867     emitcode("lcall","__gptrput");
3868     break;
3869   }
3870 }
3871 /*-----------------------------------------------------------------*/
3872 /* genDataPointerSet - remat pointer to data space                 */
3873 /*-----------------------------------------------------------------*/
3874 static void genDataPointerSet(operand *right,
3875             operand *result,
3876             iCode *ic)
3877 {
3878   int size, offset = 0 ;
3879   char *l, buffer[256];
3880
3881   aopOp(right,ic,FALSE);
3882
3883   l = aopGet(AOP(result),0);
3884   size = AOP_SIZE(right);
3885   while (size--) {
3886     if (offset)
3887       sprintf(buffer,"(%s + %d)",l+1,offset);
3888     else
3889       sprintf(buffer,"%s",l+1);
3890     emitcode("mov","%s,%s",buffer,
3891        aopGet(AOP(right),offset++));
3892   }
3893
3894   freeAsmop(right,NULL,ic,TRUE);
3895   freeAsmop(result,NULL,ic,TRUE);
3896 }
3897
3898 /*-----------------------------------------------------------------*/
3899 /* genNearPointerSet - emitcode for near pointer put                */
3900 /*-----------------------------------------------------------------*/
3901 static void genNearPointerSet (operand *right,
3902              operand *result,
3903              iCode *ic)
3904 {
3905   asmop *aop = NULL;
3906   regs *preg = NULL ;
3907   char *rname , *l;
3908   sym_link *retype;
3909   sym_link *ptype = operandType(result);
3910
3911   retype= getSpec(operandType(right));
3912
3913   aopOp(result,ic,FALSE);
3914
3915   /* if the result is rematerializable &
3916      in data space & not a bit variable */
3917   if (AOP_TYPE(result) == AOP_IMMD &&
3918       DCL_TYPE(ptype) == POINTER   &&
3919       !IS_BITVAR(retype)) {
3920     genDataPointerSet (right,result,ic);
3921     return;
3922   }
3923
3924   /* if the value is already in a pointer register
3925      then don't need anything more */
3926   if (!AOP_INPREG(AOP(result))) {
3927         /* otherwise get a free pointer register */
3928     aop = newAsmop(0);
3929     preg = getFreePtr(ic,&aop,FALSE,0);
3930     emitcode("mov","%s,%s",
3931        preg->name,
3932        aopGet(AOP(result),0));
3933     rname = preg->name ;
3934   } else
3935     rname = aopGet(AOP(result),0);
3936
3937   freeAsmop(result,NULL,ic,TRUE);
3938   aopOp (right,ic,FALSE);
3939
3940   /* if bitfield then unpack the bits */
3941   if (IS_BITVAR(retype))
3942     genPackBits (retype,right,rname,POINTER);
3943   else {
3944         /* we have can just get the values */
3945     int size = AOP_SIZE(right);
3946     int offset = 0 ;
3947
3948     while (size--) {
3949       l = aopGet(AOP(right),offset);
3950       if (*l == '@' ) {
3951         MOVA(l);
3952         emitcode("mov","@%s,a",rname);
3953       } else
3954         emitcode("mov","@%s,%s",rname,l);
3955       if (size)
3956         emitcode("inc","%s",rname);
3957       offset++;
3958     }
3959   }
3960
3961   /* now some housekeeping stuff */
3962   if (aop) {
3963         /* we had to allocate for this iCode */
3964     freeAsmop(NULL,aop,ic,TRUE);
3965   } else {
3966         /* we did not allocate which means left
3967            already in a pointer register, then
3968            if size > 0 && this could be used again
3969            we have to point it back to where it
3970            belongs */
3971     if (AOP_SIZE(right) > 1 &&
3972         !OP_SYMBOL(result)->remat &&
3973         ( OP_SYMBOL(result)->liveTo > ic->seq ||
3974           ic->depth )) {
3975       int size = AOP_SIZE(right) - 1;
3976       while (size--)
3977         emitcode("dec","%s",rname);
3978     }
3979   }
3980
3981   /* done */
3982   freeAsmop(right,NULL,ic,TRUE);
3983
3984
3985 }
3986
3987 /*-----------------------------------------------------------------*/
3988 /* genPagedPointerSet - emitcode for Paged pointer put             */
3989 /*-----------------------------------------------------------------*/
3990 static void genPagedPointerSet (operand *right,
3991         operand *result,
3992         iCode *ic)
3993 {
3994   asmop *aop = NULL;
3995   regs *preg = NULL ;
3996   char *rname , *l;
3997   sym_link *retype;
3998
3999   retype= getSpec(operandType(right));
4000
4001   aopOp(result,ic,FALSE);
4002
4003   /* if the value is already in a pointer register
4004      then don't need anything more */
4005   if (!AOP_INPREG(AOP(result))) {
4006         /* otherwise get a free pointer register */
4007     aop = newAsmop(0);
4008     preg = getFreePtr(ic,&aop,FALSE,0);
4009     emitcode("mov","%s,%s",
4010        preg->name,
4011        aopGet(AOP(result),0));
4012     rname = preg->name ;
4013   } else
4014     rname = aopGet(AOP(result),0);
4015
4016   freeAsmop(result,NULL,ic,TRUE);
4017   aopOp (right,ic,FALSE);
4018
4019   /* if bitfield then unpack the bits */
4020   if (IS_BITVAR(retype))
4021     genPackBits (retype,right,rname,PPOINTER);
4022   else {
4023         /* we have can just get the values */
4024     int size = AOP_SIZE(right);
4025     int offset = 0 ;
4026
4027     while (size--) {
4028       l = aopGet(AOP(right),offset);
4029
4030       MOVA(l);
4031       emitcode("movx","@%s,a",rname);
4032
4033       if (size)
4034         emitcode("inc","%s",rname);
4035
4036       offset++;
4037     }
4038   }
4039
4040   /* now some housekeeping stuff */
4041   if (aop) {
4042         /* we had to allocate for this iCode */
4043     freeAsmop(NULL,aop,ic,TRUE);
4044   } else {
4045         /* we did not allocate which means left
4046            already in a pointer register, then
4047            if size > 0 && this could be used again
4048            we have to point it back to where it
4049            belongs */
4050     if (AOP_SIZE(right) > 1 &&
4051         !OP_SYMBOL(result)->remat &&
4052         ( OP_SYMBOL(result)->liveTo > ic->seq ||
4053           ic->depth )) {
4054       int size = AOP_SIZE(right) - 1;
4055       while (size--)
4056         emitcode("dec","%s",rname);
4057     }
4058   }
4059
4060   /* done */
4061   freeAsmop(right,NULL,ic,TRUE);
4062
4063
4064 }
4065
4066 /*-----------------------------------------------------------------*/
4067 /* genFarPointerSet - set value from far space                     */
4068 /*-----------------------------------------------------------------*/
4069 static void genFarPointerSet (operand *right,
4070             operand *result, iCode *ic)
4071 {
4072   int size, offset ;
4073   sym_link *retype = getSpec(operandType(right));
4074
4075   aopOp(result,ic,FALSE);
4076
4077   /* if the operand is already in dptr
4078      then we do nothing else we move the value to dptr */
4079   if (AOP_TYPE(result) != AOP_STR) {
4080         /* if this is remateriazable */
4081     if (AOP_TYPE(result) == AOP_IMMD)
4082       emitcode("mov","dptr,%s",aopGet(AOP(result),0));
4083     else { /* we need to get it byte by byte */
4084       emitcode("mov","dpl,%s",aopGet(AOP(result),0));
4085       emitcode("mov","dph,%s",aopGet(AOP(result),1));
4086       if (options.model == MODEL_FLAT24)
4087         {
4088           emitcode("mov", "dpx,%s",aopGet(AOP(result),2));
4089         }
4090     }
4091   }
4092   /* so dptr know contains the address */
4093   freeAsmop(result,NULL,ic,TRUE);
4094   aopOp(right,ic,FALSE);
4095
4096   /* if bit then unpack */
4097   if (IS_BITVAR(retype))
4098     genPackBits(retype,right,"dptr",FPOINTER);
4099   else {
4100     size = AOP_SIZE(right);
4101     offset = 0 ;
4102
4103     while (size--) {
4104       char *l = aopGet(AOP(right),offset++);
4105       MOVA(l);
4106       emitcode("movx","@dptr,a");
4107       if (size)
4108         emitcode("inc","dptr");
4109     }
4110   }
4111
4112   freeAsmop(right,NULL,ic,TRUE);
4113 }
4114
4115 /*-----------------------------------------------------------------*/
4116 /* genGenPointerSet - set value from generic pointer space         */
4117 /*-----------------------------------------------------------------*/
4118 static void genGenPointerSet (operand *right,
4119             operand *result, iCode *ic)
4120 {
4121   int size, offset ;
4122   sym_link *retype = getSpec(operandType(right));
4123
4124   aopOp(result,ic,FALSE);
4125
4126   /* if the operand is already in dptr
4127      then we do nothing else we move the value to dptr */
4128   if (AOP_TYPE(result) != AOP_STR) {
4129         /* if this is remateriazable */
4130     if (AOP_TYPE(result) == AOP_IMMD) {
4131       emitcode("mov","dptr,%s",aopGet(AOP(result),0));
4132       emitcode("mov","b,%s + 1",aopGet(AOP(result),0));
4133     }
4134     else { /* we need to get it byte by byte */
4135       emitcode("mov","dpl,%s",aopGet(AOP(result),0));
4136       emitcode("mov","dph,%s",aopGet(AOP(result),1));
4137       if (options.model == MODEL_FLAT24)
4138         {
4139           emitcode("mov", "dpx,%s",aopGet(AOP(result),2));
4140           emitcode("mov","b,%s",aopGet(AOP(result),3));
4141         }
4142       else
4143         {
4144           emitcode("mov","b,%s",aopGet(AOP(result),2));
4145         }
4146     }
4147   }
4148   /* so dptr know contains the address */
4149   freeAsmop(result,NULL,ic,TRUE);
4150   aopOp(right,ic,FALSE);
4151
4152   /* if bit then unpack */
4153   if (IS_BITVAR(retype))
4154     genPackBits(retype,right,"dptr",GPOINTER);
4155   else {
4156     size = AOP_SIZE(right);
4157     offset = 0 ;
4158
4159     while (size--) {
4160       char *l = aopGet(AOP(right),offset++);
4161       MOVA(l);
4162       emitcode("lcall","__gptrput");
4163       if (size)
4164         emitcode("inc","dptr");
4165     }
4166   }
4167
4168   freeAsmop(right,NULL,ic,TRUE);
4169 }
4170
4171 /*-----------------------------------------------------------------*/
4172 /* genPointerSet - stores the value into a pointer location        */
4173 /*-----------------------------------------------------------------*/
4174 static void genPointerSet (iCode *ic)
4175 {
4176   operand *right, *result ;
4177   sym_link *type, *etype;
4178   int p_type;
4179
4180   right = IC_RIGHT(ic);
4181   result = IC_RESULT(ic) ;
4182
4183   /* depending on the type of pointer we need to
4184      move it to the correct pointer register */
4185   type = operandType(result);
4186   etype = getSpec(type);
4187   /* if left is of type of pointer then it is simple */
4188   if (IS_PTR(type) && !IS_FUNC(type->next)) {
4189     p_type = DCL_TYPE(type);
4190   }
4191   else {
4192         /* we have to go by the storage class */
4193     p_type = PTR_TYPE(SPEC_OCLS(etype));
4194
4195         /*  if (SPEC_OCLS(etype)->codesp ) { */
4196         /*      p_type = CPOINTER ;  */
4197         /*  } */
4198         /*  else */
4199         /*      if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */
4200         /*    p_type = FPOINTER ; */
4201         /*      else */
4202         /*    if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */
4203         /*        p_type = PPOINTER ; */
4204         /*    else */
4205         /*        if (SPEC_OCLS(etype) == idata ) */
4206         /*      p_type = IPOINTER ; */
4207         /*        else */
4208         /*      p_type = POINTER ; */
4209   }
4210
4211   /* now that we have the pointer type we assign
4212      the pointer values */
4213   switch (p_type) {
4214
4215   case POINTER:
4216   case IPOINTER:
4217     genNearPointerSet (right,result,ic);
4218     break;
4219
4220   case PPOINTER:
4221     genPagedPointerSet (right,result,ic);
4222     break;
4223
4224   case FPOINTER:
4225     genFarPointerSet (right,result,ic);
4226     break;
4227
4228   case GPOINTER:
4229     genGenPointerSet (right,result,ic);
4230     break;
4231   }
4232
4233 }
4234
4235 /*-----------------------------------------------------------------*/
4236 /* genIfx - generate code for Ifx statement                        */
4237 /*-----------------------------------------------------------------*/
4238 static void genIfx (iCode *ic, iCode *popIc)
4239 {
4240   operand *cond = IC_COND(ic);
4241   int isbit =0;
4242
4243   aopOp(cond,ic,FALSE);
4244
4245   /* get the value into acc */
4246   if (AOP_TYPE(cond) != AOP_CRY)
4247     toBoolean(cond,"",0);
4248   else
4249     isbit = 1;
4250   /* the result is now in the accumulator */
4251   freeAsmop(cond,NULL,ic,TRUE);
4252
4253   /* if there was something to be popped then do it */
4254   if (popIc)
4255     genIpop(popIc);
4256
4257   /* if the condition is  a bit variable */
4258   /*     if (isbit && IS_ITEMP(cond) && SPIL_LOC(cond)) { */
4259   /*  //  genIfxJump(ic,SPIL_LOC(cond)->rname); */
4260       /*     } */
4261       /*     else */
4262       /*  if (isbit && !IS_ITEMP(cond)) */
4263       /*    //      genIfxJump(ic,OP_SYMBOL(cond)->rname); */
4264       /*  else */
4265       /*    // genIfxJump(ic,"a"); */
4266
4267       ic->generated = 1;
4268 }
4269
4270 /*-----------------------------------------------------------------*/
4271 /* genAddrOf - generates code for address of                       */
4272 /*-----------------------------------------------------------------*/
4273 static void genAddrOf (iCode *ic)
4274 {
4275   symbol *sym = OP_SYMBOL(IC_LEFT(ic));
4276   int size, offset ;
4277
4278   aopOp(IC_RESULT(ic),ic,FALSE);
4279
4280   /* if the operand is on the stack then we
4281      need to get the stack offset of this
4282      variable */
4283   if (sym->onStack) {
4284         /* if it has an offset then we need to compute
4285            it */
4286     if (sym->stack) {
4287       emitcode("mov","a,_bp");
4288       emitcode("add","a,#0x%02x",((char) sym->stack & 0xff));
4289       aopPut(AOP(IC_RESULT(ic)),"a",0);
4290     } else {
4291       /* we can just move _bp */
4292       aopPut(AOP(IC_RESULT(ic)),"_bp",0);
4293     }
4294         /* fill the result with zero */
4295     size = AOP_SIZE(IC_RESULT(ic)) - 1;
4296
4297
4298     if (options.stack10bit && size < (FPTRSIZE - 1))
4299       {
4300         fprintf(stderr,
4301           "*** warning: pointer to stack var truncated.\n");
4302       }
4303
4304     offset = 1;
4305     while (size--)
4306       {
4307         /* Yuck! */
4308         if (options.stack10bit && offset == 2)
4309           {
4310             aopPut(AOP(IC_RESULT(ic)),"#0x40", offset++);
4311           }
4312         else
4313           {
4314             aopPut(AOP(IC_RESULT(ic)),zero,offset++);
4315           }
4316       }
4317
4318     goto release;
4319   }
4320
4321   /* object not on stack then we need the name */
4322   size = AOP_SIZE(IC_RESULT(ic));
4323   offset = 0;
4324
4325   while (size--) {
4326     char s[SDCC_NAME_MAX];
4327     if (offset)
4328       sprintf(s,"#(%s >> %d)",
4329         sym->rname,
4330         offset*8);
4331     else
4332       sprintf(s,"#%s",sym->rname);
4333     aopPut(AOP(IC_RESULT(ic)),s,offset++);
4334   }
4335
4336  release:
4337   freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
4338
4339 }
4340
4341 /*-----------------------------------------------------------------*/
4342 /* genFarFarAssign - assignment when both are in far space         */
4343 /*-----------------------------------------------------------------*/
4344 static void genFarFarAssign (operand *result, operand *right, iCode *ic)
4345 {
4346   int size = AOP_SIZE(right);
4347   int offset = 0;
4348   char *l ;
4349   /* first push the right side on to the stack */
4350   while (size--) {
4351     l = aopGet(AOP(right),offset++);
4352     MOVA(l);
4353     emitcode ("push","acc");
4354   }
4355
4356   freeAsmop(right,NULL,ic,FALSE);
4357   /* now assign DPTR to result */
4358   aopOp(result,ic,FALSE);
4359   size = AOP_SIZE(result);
4360   while (size--) {
4361     emitcode ("pop","acc");
4362     aopPut(AOP(result),"a",--offset);
4363   }
4364   freeAsmop(result,NULL,ic,FALSE);
4365
4366 }
4367
4368 /*-----------------------------------------------------------------*/
4369 /* genAssign - generate code for assignment                        */
4370 /*-----------------------------------------------------------------*/
4371 static void genAssign (iCode *ic)
4372 {
4373   operand *result, *right;
4374   int size, offset ;
4375   unsigned long lit = 0L;
4376
4377   result = IC_RESULT(ic);
4378   right  = IC_RIGHT(ic) ;
4379
4380   /* if they are the same */
4381   if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic)))
4382     return ;
4383
4384   aopOp(right,ic,FALSE);
4385
4386   /* special case both in far space */
4387   if (AOP_TYPE(right) == AOP_DPTR &&
4388       IS_TRUE_SYMOP(result)       &&
4389       isOperandInFarSpace(result)) {
4390
4391     genFarFarAssign (result,right,ic);
4392     return ;
4393   }
4394
4395   aopOp(result,ic,TRUE);
4396
4397   /* if they are the same registers */
4398   if (sameRegs(AOP(right),AOP(result)))
4399     goto release;
4400
4401   /* if the result is a bit */
4402   if (AOP_TYPE(result) == AOP_CRY) {
4403
4404         /* if the right size is a literal then
4405            we know what the value is */
4406     if (AOP_TYPE(right) == AOP_LIT) {
4407       if (((int) operandLitValue(right)))
4408         aopPut(AOP(result),one,0);
4409       else
4410         aopPut(AOP(result),zero,0);
4411       goto release;
4412     }
4413
4414         /* the right is also a bit variable */
4415     if (AOP_TYPE(right) == AOP_CRY) {
4416       emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
4417       aopPut(AOP(result),"c",0);
4418       goto release ;
4419     }
4420
4421         /* we need to or */
4422     toBoolean(right,"",0);
4423     aopPut(AOP(result),"a",0);
4424     goto release ;
4425   }
4426
4427   /* bit variables done */
4428   /* general case */
4429   size = AOP_SIZE(result);
4430   offset = 0 ;
4431   if(AOP_TYPE(right) == AOP_LIT)
4432     lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4433   if((size > 1) &&
4434      (AOP_TYPE(result) != AOP_REG) &&
4435      (AOP_TYPE(right) == AOP_LIT) &&
4436      !IS_FLOAT(operandType(right)) &&
4437      (lit < 256L)){
4438     emitcode("clr","a");
4439     while (size--) {
4440       if((unsigned int)((lit >> (size*8)) & 0x0FFL)== 0)
4441         aopPut(AOP(result),"a",size);
4442       else
4443         aopPut(AOP(result),
4444                aopGet(AOP(right),size),
4445                size);
4446     }
4447   } else {
4448     while (size--) {
4449       aopPut(AOP(result),
4450              aopGet(AOP(right),offset),
4451              offset);
4452       offset++;
4453     }
4454   }
4455
4456  release:
4457   freeAsmop (right,NULL,ic,FALSE);
4458   freeAsmop (result,NULL,ic,TRUE);
4459 }
4460
4461 /*-----------------------------------------------------------------*/
4462 /* genJumpTab - genrates code for jump table                       */
4463 /*-----------------------------------------------------------------*/
4464 static void genJumpTab (iCode *ic)
4465 {
4466   symbol *jtab;
4467   char *l;
4468
4469   aopOp(IC_JTCOND(ic),ic,FALSE);
4470   /* get the condition into accumulator */
4471   l = aopGet(AOP(IC_JTCOND(ic)),0);
4472   MOVA(l);
4473   /* multiply by three */
4474   emitcode("add","a,acc");
4475   emitcode("add","a,%s",aopGet(AOP(IC_JTCOND(ic)),0));
4476   freeAsmop(IC_JTCOND(ic),NULL,ic,TRUE);
4477
4478   jtab = newiTempLabel(NULL);
4479   emitcode("mov","dptr,#%05d$",jtab->key+100);
4480   emitcode("jmp","@a+dptr");
4481   emitcode("","%05d$:",jtab->key+100);
4482   /* now generate the jump labels */
4483   for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
4484        jtab = setNextItem(IC_JTLABELS(ic)))
4485     emitcode("ljmp","%05d$",jtab->key+100);
4486
4487 }
4488
4489 /*-----------------------------------------------------------------*/
4490 /* genCast - gen code for casting                                  */
4491 /*-----------------------------------------------------------------*/
4492 static void genCast (iCode *ic)
4493 {
4494   operand *result = IC_RESULT(ic);
4495   sym_link *ctype = operandType(IC_LEFT(ic));
4496   sym_link *rtype = operandType(IC_RIGHT(ic));
4497   operand *right = IC_RIGHT(ic);
4498   int size, offset ;
4499
4500   /* if they are equivalent then do nothing */
4501   if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
4502     return ;
4503
4504   aopOp(right,ic,FALSE) ;
4505   aopOp(result,ic,FALSE);
4506
4507   /* if the result is a bit */
4508   if (AOP_TYPE(result) == AOP_CRY) {
4509         /* if the right size is a literal then
4510            we know what the value is */
4511     if (AOP_TYPE(right) == AOP_LIT) {
4512       if (((int) operandLitValue(right)))
4513         aopPut(AOP(result),one,0);
4514       else
4515         aopPut(AOP(result),zero,0);
4516
4517       goto release;
4518     }
4519
4520         /* the right is also a bit variable */
4521     if (AOP_TYPE(right) == AOP_CRY) {
4522       emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
4523       aopPut(AOP(result),"c",0);
4524       goto release ;
4525     }
4526
4527         /* we need to or */
4528     toBoolean(right,"",0);
4529     aopPut(AOP(result),"a",0);
4530     goto release ;
4531   }
4532
4533   /* if they are the same size : or less */
4534   if (AOP_SIZE(result) <= AOP_SIZE(right)) {
4535
4536         /* if they are in the same place */
4537     if (sameRegs(AOP(right),AOP(result)))
4538       goto release;
4539
4540         /* if they in different places then copy */
4541     size = AOP_SIZE(result);
4542     offset = 0 ;
4543     while (size--) {
4544       aopPut(AOP(result),
4545              aopGet(AOP(right),offset),
4546              offset);
4547       offset++;
4548     }
4549     goto release;
4550   }
4551
4552
4553   /* if the result is of type pointer */
4554   if (IS_PTR(ctype)) {
4555
4556     int p_type;
4557     sym_link *type = operandType(right);
4558     sym_link *etype = getSpec(type);
4559
4560         /* pointer to generic pointer */
4561     if (IS_GENPTR(ctype)) {
4562       char *l = zero;
4563
4564       if (IS_PTR(type))
4565         p_type = DCL_TYPE(type);
4566       else {
4567         /* we have to go by the storage class */
4568         p_type = PTR_TYPE(SPEC_OCLS(etype));
4569       }
4570
4571       /* the first two bytes are known */
4572       size = GPTRSIZE - 1;
4573       offset = 0 ;
4574       while (size--) {
4575         aopPut(AOP(result),
4576                aopGet(AOP(right),offset),
4577                offset);
4578         offset++;
4579       }
4580       /* the last byte depending on type */
4581       switch (p_type) {
4582       case IPOINTER:
4583       case POINTER:
4584         l = zero;
4585         break;
4586       case FPOINTER:
4587         l = one;
4588         break;
4589       case CPOINTER:
4590         l = "#0x02";
4591         break;
4592       case PPOINTER:
4593         l = "#0x03";
4594         break;
4595
4596       default:
4597         /* this should never happen */
4598         werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4599                "got unknown pointer type");
4600         exit(1);
4601       }
4602       aopPut(AOP(result),l, GPTRSIZE - 1);
4603       goto release ;
4604     }
4605
4606         /* just copy the pointers */
4607     size = AOP_SIZE(result);
4608     offset = 0 ;
4609     while (size--) {
4610       aopPut(AOP(result),
4611              aopGet(AOP(right),offset),
4612              offset);
4613       offset++;
4614     }
4615     goto release ;
4616   }
4617
4618   /* so we now know that the size of destination is greater
4619      than the size of the source */
4620   /* we move to result for the size of source */
4621   size = AOP_SIZE(right);
4622   offset = 0 ;
4623   while (size--) {
4624     aopPut(AOP(result),
4625            aopGet(AOP(right),offset),
4626            offset);
4627     offset++;
4628   }
4629
4630   /* now depending on the sign of the source && destination */
4631   size = AOP_SIZE(result) - AOP_SIZE(right);
4632   /* if unsigned or not an integral type */
4633   if (SPEC_USIGN(rtype) || !IS_SPEC(rtype)) {
4634     while (size--)
4635       aopPut(AOP(result),zero,offset++);
4636   } else {
4637         /* we need to extend the sign :{ */
4638     char *l = aopGet(AOP(right),AOP_SIZE(right) - 1);
4639     MOVA(l);
4640     emitcode("rlc","a");
4641     emitcode("subb","a,acc");
4642     while (size--)
4643       aopPut(AOP(result),"a",offset++);
4644   }
4645
4646   /* we are done hurray !!!! */
4647
4648  release:
4649   freeAsmop(right,NULL,ic,TRUE);
4650   freeAsmop(result,NULL,ic,TRUE);
4651
4652 }
4653
4654 /*-----------------------------------------------------------------*/
4655 /* genDjnz - generate decrement & jump if not zero instrucion      */
4656 /*-----------------------------------------------------------------*/
4657 static int genDjnz (iCode *ic, iCode *ifx)
4658 {
4659   symbol *lbl, *lbl1;
4660   if (!ifx)
4661     return 0;
4662
4663   /* if the if condition has a false label
4664      then we cannot save */
4665   if (IC_FALSE(ifx))
4666     return 0;
4667
4668   /* if the minus is not of the form
4669      a = a - 1 */
4670   if (!isOperandEqual(IC_RESULT(ic),IC_LEFT(ic)) ||
4671       !IS_OP_LITERAL(IC_RIGHT(ic)))
4672     return 0;
4673
4674   if (operandLitValue(IC_RIGHT(ic)) != 1)
4675     return 0;
4676
4677   /* if the size of this greater than one then no
4678      saving */
4679   if (getSize(operandType(IC_RESULT(ic))) > 1)
4680     return 0;
4681
4682   /* otherwise we can save BIG */
4683   lbl = newiTempLabel(NULL);
4684   lbl1= newiTempLabel(NULL);
4685
4686   aopOp(IC_RESULT(ic),ic,FALSE);
4687
4688   if (IS_AOP_PREG(IC_RESULT(ic))) {
4689     emitcode("dec","%s",
4690        aopGet(AOP(IC_RESULT(ic)),0));
4691     emitcode("mov","a,%s",aopGet(AOP(IC_RESULT(ic)),0));
4692     emitcode("jnz","%05d$",lbl->key+100);
4693   } else {
4694     emitcode ("djnz","%s,%05d$",aopGet(AOP(IC_RESULT(ic)),0),
4695         lbl->key+100);
4696   }
4697   emitcode ("sjmp","%05d$",lbl1->key+100);
4698   emitcode ("","%05d$:",lbl->key+100);
4699   emitcode ("ljmp","%05d$",IC_TRUE(ifx)->key+100);
4700   emitcode ("","%05d$:",lbl1->key+100);
4701
4702   freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
4703   ifx->generated = 1;
4704   return 1;
4705 }
4706
4707 static char *recvregs[8] =
4708 {
4709   "r16","r17","r18","r19","r20","r21","r22","r23"
4710 };
4711 static recvCnt = 0;
4712
4713 /*-----------------------------------------------------------------*/
4714 /* genReceive - generate code for a receive iCode                  */
4715 /*-----------------------------------------------------------------*/
4716 static void genReceive (iCode *ic)
4717 {
4718   int size , offset =0;
4719   aopOp(IC_RESULT(ic),ic,FALSE);
4720   size = AOP_SIZE(IC_RESULT(ic));
4721   while (size--) {
4722     aopPut(AOP(IC_RESULT(ic)),recvregs[recvCnt++],offset);
4723     offset++;
4724   }
4725   freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
4726 }
4727
4728 /*-----------------------------------------------------------------*/
4729 /* gen51Code - generate code for 8051 based controllers            */
4730 /*-----------------------------------------------------------------*/
4731 void genAVRCode (iCode *lic)
4732 {
4733   iCode *ic;
4734   int cln = 0;
4735
4736   lineHead = lineCurr = NULL;
4737   recvCnt =0;
4738   /* print the allocation information */
4739   if (allocInfo)
4740     printAllocInfo( currFunc, codeOutFile);
4741   /* if debug information required */
4742   /*     if (options.debug && currFunc) { */
4743   if (currFunc) {
4744     cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
4745     _G.debugLine = 1;
4746     if (IS_STATIC(currFunc->etype))
4747       emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
4748     else
4749       emitcode("","G$%s$0$0 ==.",currFunc->name);
4750     _G.debugLine = 0;
4751   }
4752   /* stack pointer name */
4753   if (options.useXstack)
4754     spname = "_spx";
4755   else
4756     spname = "sp";
4757
4758
4759   for (ic = lic ; ic ; ic = ic->next ) {
4760
4761     if ( cln != ic->lineno ) {
4762       if ( options.debug ) {
4763         _G.debugLine = 1;
4764         emitcode("","C$%s$%d$%d$%d ==.",
4765            FileBaseName(ic->filename),ic->lineno,
4766            ic->level,ic->block);
4767         _G.debugLine = 0;
4768       }
4769       emitcode(";","%s %d",ic->filename,ic->lineno);
4770       cln = ic->lineno ;
4771     }
4772         /* if the result is marked as
4773            spilt and rematerializable or code for
4774            this has already been generated then
4775            do nothing */
4776     if (resultRemat(ic) || ic->generated )
4777       continue ;
4778
4779         /* depending on the operation */
4780     switch (ic->op) {
4781     case '!' :
4782       genNot(ic);
4783       break;
4784
4785     case '~' :
4786       genCpl(ic);
4787       break;
4788
4789     case UNARYMINUS:
4790       genUminus (ic);
4791       break;
4792
4793     case IPUSH:
4794       genIpush (ic);
4795       break;
4796
4797     case IPOP:
4798       /* IPOP happens only when trying to restore a
4799          spilt live range, if there is an ifx statement
4800          following this pop then the if statement might
4801          be using some of the registers being popped which
4802          would destory the contents of the register so
4803          we need to check for this condition and handle it */
4804       if (ic->next            &&
4805           ic->next->op == IFX &&
4806           regsInCommon(IC_LEFT(ic),IC_COND(ic->next)))
4807         genIfx (ic->next,ic);
4808       else
4809         genIpop (ic);
4810       break;
4811
4812     case CALL:
4813       genCall (ic);
4814       break;
4815
4816     case PCALL:
4817       genPcall (ic);
4818       break;
4819
4820     case FUNCTION:
4821       genFunction (ic);
4822       break;
4823
4824     case ENDFUNCTION:
4825       genEndFunction (ic);
4826       break;
4827
4828     case RETURN:
4829       genRet (ic);
4830       break;
4831
4832     case LABEL:
4833       genLabel (ic);
4834       break;
4835
4836     case GOTO:
4837       genGoto (ic);
4838       break;
4839
4840     case '+' :
4841       genPlus (ic) ;
4842       break;
4843
4844     case '-' :
4845       if ( ! genDjnz (ic,ifxForOp(IC_RESULT(ic),ic)))
4846         genMinus (ic);
4847       break;
4848
4849     case '*' :
4850       genMult (ic);
4851       break;
4852
4853     case '/' :
4854       genDiv (ic) ;
4855       break;
4856
4857     case '%' :
4858       genMod (ic);
4859       break;
4860
4861     case '>' :
4862       genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
4863       break;
4864
4865     case '<' :
4866       genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4867       break;
4868
4869     case LE_OP:
4870       genCmpLe (ic,ifxForOp(IC_RESULT(ic),ic));
4871       break;
4872
4873     case GE_OP:
4874       genCmpGe (ic,ifxForOp(IC_RESULT(ic),ic));
4875       break;
4876
4877     case NE_OP:
4878       genCmpNe (ic,ifxForOp(IC_RESULT(ic),ic));
4879       break;
4880
4881     case EQ_OP:
4882       genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4883       break;
4884
4885     case AND_OP:
4886       genAndOp (ic);
4887       break;
4888
4889     case OR_OP:
4890       genOrOp (ic);
4891       break;
4892
4893     case '^' :
4894       genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4895       break;
4896
4897     case '|' :
4898       genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4899       break;
4900
4901     case BITWISEAND:
4902       genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4903       break;
4904
4905     case INLINEASM:
4906       genInline (ic);
4907       break;
4908
4909     case RRC:
4910       genRRC (ic);
4911       break;
4912
4913     case RLC:
4914       genRLC (ic);
4915       break;
4916
4917     case GETHBIT:
4918       genGetHbit (ic);
4919       break;
4920
4921     case LEFT_OP:
4922       genLeftShift (ic);
4923       break;
4924
4925     case RIGHT_OP:
4926       genRightShift (ic);
4927       break;
4928
4929     case GET_VALUE_AT_ADDRESS:
4930       genPointerGet(ic);
4931       break;
4932
4933     case '=' :
4934       if (POINTER_SET(ic))
4935         genPointerSet(ic);
4936       else
4937         genAssign(ic);
4938       break;
4939
4940     case IFX:
4941       genIfx (ic,NULL);
4942       break;
4943
4944     case ADDRESS_OF:
4945       genAddrOf (ic);
4946       break;
4947
4948     case JUMPTABLE:
4949       genJumpTab (ic);
4950       break;
4951
4952     case CAST:
4953       genCast (ic);
4954       break;
4955
4956     case RECEIVE:
4957       genReceive(ic);
4958       break;
4959
4960     case SEND:
4961       addSet(&_G.sendSet,ic);
4962       break;
4963
4964     default :
4965       ic = ic;
4966       /*      piCode(ic,stdout); */
4967
4968     }
4969   }
4970
4971
4972   /* now we are ready to call the
4973      peep hole optimizer */
4974   if (!options.nopeep)
4975     peepHole (&lineHead);
4976
4977   /* now do the actual printing */
4978   printLine (lineHead,codeOutFile);
4979   return;
4980 }