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