work in progress: bug in lazy DPS evaluation fixed
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for 8051
3   
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7   
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2, or (at your option) any
11   later version.
12   
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17   
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21   
22   In other words, you are welcome to use, share and improve this program.
23   You are forbidden to forbid anyone else to use, share and improve
24   what you give them.   Help stamp out software-hoarding!
25   
26   Notes:
27   000123 mlh    Moved aopLiteral to SDCCglue.c to help the split
28                 Made everything static
29 -------------------------------------------------------------------------*/
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "SDCCglobl.h"
36
37 #ifdef HAVE_SYS_ISA_DEFS_H
38 #include <sys/isa_defs.h>
39 #else
40 #ifdef HAVE_ENDIAN_H
41 #include <endian.h>
42 #else
43 #ifndef __BORLANDC__
44 #warning "Cannot determine ENDIANESS of this machine assuming LITTLE_ENDIAN"
45 #warning "If you running sdcc on an INTEL 80x86 Platform you are okay"
46 #endif
47 #endif
48 #endif
49
50 #include "common.h"
51 #include "SDCCpeeph.h"
52 #include "ralloc.h"
53 #include "gen.h"
54
55 char *aopLiteral (value *val, int offset);
56 extern int allocInfo;
57
58 /* this is the down and dirty file with all kinds of 
59    kludgy & hacky stuff. This is what it is all about
60    CODE GENERATION for a specific MCU . some of the
61    routines may be reusable, will have to see */
62
63 static char *zero = "#0x00";
64 static char *one  = "#0x01";
65 static char *spname ;
66
67 #define D(x) x
68
69 unsigned fReturnSize_390 = 5; /* shared with ralloc.c */
70 static char *fReturn[] = {"dpl","dph","dpx", "b","a" };
71 static char *accUse[] = {"a","b"};
72
73 static short rbank = -1;
74
75 static struct {
76     short r0Pushed;
77     short r1Pushed;
78     short accInUse;
79     short inLine;
80     short debugLine;
81     short nRegsSaved;
82     set *sendSet;
83 } _G;
84
85 extern int ds390_ptrRegReq ;
86 extern int ds390_nRegs;
87 extern FILE *codeOutFile;
88 static void saverbank (int, iCode *,bool);
89 #define RESULTONSTACK(x) \
90                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
91                          IC_RESULT(x)->aop->type == AOP_STK )
92
93 /* #define MOVA(x) if (strcmp(x,"a") && strcmp(x,"acc")) emitcode("mov","a,%s",x); */
94 #define MOVA(x) { char *_mova_tmp = strdup(x); \
95                  if (strcmp(_mova_tmp,"a") && strcmp(_mova_tmp,"acc")) \
96                  { \
97                     emitcode("mov","a,%s",_mova_tmp); \
98                  } \
99                  free(_mova_tmp); \
100                 }
101 #define CLRC    emitcode("clr","c")
102 #define SETC    emitcode("setb","c")
103
104 static lineNode *lineHead = NULL;
105 static lineNode *lineCurr = NULL;
106
107 static unsigned char   SLMask[] = {0xFF ,0xFE, 0xFC, 0xF8, 0xF0,
108 0xE0, 0xC0, 0x80, 0x00};
109 static unsigned char   SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
110 0x07, 0x03, 0x01, 0x00};
111
112 #define LSB     0
113 #define MSB16   1
114 #define MSB24   2
115 #define MSB32   3
116
117 /*-----------------------------------------------------------------*/
118 /* emitcode - writes the code into a file : for now it is simple    */
119 /*-----------------------------------------------------------------*/
120 static void emitcode (char *inst,char *fmt, ...)
121 {
122     va_list ap;
123     char lb[MAX_INLINEASM];  
124     char *lbp = lb;
125
126     va_start(ap,fmt);   
127
128     if (inst && *inst) {
129         if (fmt && *fmt)
130             sprintf(lb,"%s\t",inst);
131         else
132             sprintf(lb,"%s",inst);
133         vsprintf(lb+(strlen(lb)),fmt,ap);
134     }  else
135         vsprintf(lb,fmt,ap);
136
137     while (isspace(*lbp)) lbp++;
138
139     if (lbp && *lbp) 
140         lineCurr = (lineCurr ?
141                     connectLine(lineCurr,newLineNode(lb)) :
142                     (lineHead = newLineNode(lb)));
143     lineCurr->isInline = _G.inLine;
144     lineCurr->isDebug  = _G.debugLine;
145     va_end(ap);
146 }
147
148 /*-----------------------------------------------------------------*/
149 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed*/
150 /*-----------------------------------------------------------------*/
151 static regs *getFreePtr (iCode *ic, asmop **aopp, bool result)
152 {
153     bool r0iu = FALSE , r1iu = FALSE;
154     bool r0ou = FALSE , r1ou = FALSE;
155
156     /* the logic: if r0 & r1 used in the instruction
157     then we are in trouble otherwise */
158
159     /* first check if r0 & r1 are used by this
160     instruction, in which case we are in trouble */
161     if ((r0iu = bitVectBitValue(ic->rUsed,R0_IDX)) &&
162         (r1iu = bitVectBitValue(ic->rUsed,R1_IDX))) 
163     {
164         goto endOfWorld;      
165     }
166
167     r0ou = bitVectBitValue(ic->rMask,R0_IDX);
168     r1ou = bitVectBitValue(ic->rMask,R1_IDX);
169
170     /* if no usage of r0 then return it */
171     if (!r0iu && !r0ou) {
172         ic->rUsed = bitVectSetBit(ic->rUsed,R0_IDX);
173         (*aopp)->type = AOP_R0;
174         
175         return (*aopp)->aopu.aop_ptr = ds390_regWithIdx(R0_IDX);
176     }
177
178     /* if no usage of r1 then return it */
179     if (!r1iu && !r1ou) {
180         ic->rUsed = bitVectSetBit(ic->rUsed,R1_IDX);
181         (*aopp)->type = AOP_R1;
182
183         return (*aopp)->aopu.aop_ptr = ds390_regWithIdx(R1_IDX);
184     }    
185
186     /* now we know they both have usage */
187     /* if r0 not used in this instruction */
188     if (!r0iu) {
189         /* push it if not already pushed */
190         if (!_G.r0Pushed) {
191             emitcode ("push","%s",
192                       ds390_regWithIdx(R0_IDX)->dname);
193             _G.r0Pushed++ ;
194         }
195         
196         ic->rUsed = bitVectSetBit(ic->rUsed,R0_IDX);
197         (*aopp)->type = AOP_R0;
198
199         return (*aopp)->aopu.aop_ptr = ds390_regWithIdx(R0_IDX);
200     }
201
202     /* if r1 not used then */
203
204     if (!r1iu) {
205         /* push it if not already pushed */
206         if (!_G.r1Pushed) {
207             emitcode ("push","%s",
208                       ds390_regWithIdx(R1_IDX)->dname);
209             _G.r1Pushed++ ;
210         }
211         
212         ic->rUsed = bitVectSetBit(ic->rUsed,R1_IDX);
213         (*aopp)->type = AOP_R1;
214         return ds390_regWithIdx(R1_IDX);
215     }
216
217 endOfWorld :
218     /* I said end of world but not quite end of world yet */
219     /* if this is a result then we can push it on the stack*/
220     if (result) {
221         (*aopp)->type = AOP_STK;    
222         return NULL;
223     }
224
225     piCode(ic,stdout);
226     /* other wise this is true end of the world */
227     werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
228            "getFreePtr should never reach here");
229     exit(1);
230 }
231
232 /*-----------------------------------------------------------------*/
233 /* newAsmop - creates a new asmOp                                  */
234 /*-----------------------------------------------------------------*/
235 static asmop *newAsmop (short type)
236 {
237     asmop *aop;
238
239     ALLOC(aop,sizeof(asmop));
240     aop->type = type;
241     return aop;
242 }
243
244 /* #define LAZY_DPS_OPT */  /* turn this on after some more testing. */
245
246 static int _currentDPS;   /* Current processor DPS. */
247 static int _desiredDPS;   /* DPS value compiler thinks we should be using. */
248 static int _lazyDPS = 0;  /* if non-zero, we are doing lazy evaluation of DPS changes. */
249
250 /*-----------------------------------------------------------------*/
251 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
252 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
253 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
254 /*-----------------------------------------------------------------*/
255 static void genSetDPTR(int n)
256 {
257
258 #ifdef LAZY_DPS_OPT
259     /* If we are doing lazy evaluation, simply note the desired
260      * change, but don't emit any code yet.
261      */
262     if (_lazyDPS)
263     {
264         _desiredDPS = n;
265         return;
266     }
267 #endif
268
269     if (!n)
270     {
271         emitcode("mov", "dps, #0x00");
272     }
273     else
274     {
275         emitcode("mov", "dps, #0x01");
276     }
277 }
278
279 /*-----------------------------------------------------------------*/
280 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation*/
281 /*                                                                 */
282 /* Any code that operates on DPTR (NB: not on the individual       */
283 /* components, like DPH) *must* call _flushLazyDPS() before using  */
284 /* DPTR within a lazy DPS evaluation block.                        */
285 /*                                                                 */
286 /* Note that aopPut and aopGet already contain the proper calls to */
287 /* _flushLazyDPS, so it is safe to use these calls within a lazy   */
288 /* DPS evaluation block.                                           */
289 /*                                                                 */
290 /* Also, _flushLazyDPS must be called before any flow control      */
291 /* operations that could potentially branch out of the block.      */
292 /*                                                                 */
293 /* Lazy DPS evaluation is simply an optimization (though an        */
294 /* important one), so if in doubt, leave it out.                   */
295 /*-----------------------------------------------------------------*/
296 static void _startLazyDPSEvaluation(void)
297 {
298    _currentDPS = 0;
299    _desiredDPS = 0;
300    _lazyDPS = 1;
301 }
302
303 /*-----------------------------------------------------------------*/
304 /* _flushLazyDPS: emit code to force the actual DPS setting to the */
305 /* desired one. Call before using DPTR within a lazy DPS evaluation*/
306 /* block.                                                          */
307 /*-----------------------------------------------------------------*/
308 static void _flushLazyDPS(void)
309 {
310     if (!_lazyDPS)
311     {
312         /* nothing to do. */
313         return;
314     }
315     
316     if (_desiredDPS != _currentDPS)
317     {
318         if (_desiredDPS)
319         {
320             emitcode("inc", "dps");
321         }
322         else
323         {
324             emitcode("dec", "dps");
325         }
326         _currentDPS = _desiredDPS;
327     }
328 }
329
330 /*-----------------------------------------------------------------*/
331 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
332 /*                                                                 */
333 /* Forces us back to the safe state (standard DPTR selected).      */
334 /*-----------------------------------------------------------------*/
335 static void _endLazyDPSEvaluation(void)
336 {
337    if (_currentDPS)
338    {
339        genSetDPTR(0);
340        _flushLazyDPS();
341    }
342    _lazyDPS = 0;
343    _currentDPS = 0;
344    _desiredDPS = 0;
345 }
346
347
348
349 /*-----------------------------------------------------------------*/
350 /* pointerCode - returns the code for a pointer type               */
351 /*-----------------------------------------------------------------*/
352 static int pointerCode (link *etype)
353 {
354
355     return PTR_TYPE(SPEC_OCLS(etype));
356
357 }
358
359 /*-----------------------------------------------------------------*/
360 /* aopForSym - for a true symbol                                   */
361 /*-----------------------------------------------------------------*/
362 static asmop *aopForSym (iCode *ic,symbol *sym,bool result, bool useDP2)
363 {
364     asmop *aop;
365     memmap *space= SPEC_OCLS(sym->etype);
366
367     /* if already has one */
368     if (sym->aop)
369         return sym->aop;
370
371     /* assign depending on the storage class */
372     /* if it is on the stack or indirectly addressable */
373     /* space we need to assign either r0 or r1 to it   */    
374     if ((sym->onStack && !options.stack10bit) || sym->iaccess) {
375         sym->aop = aop = newAsmop(0);
376         aop->aopu.aop_ptr = getFreePtr(ic,&aop,result);
377         aop->size = getSize(sym->type);
378
379         /* now assign the address of the variable to 
380         the pointer register */
381         if (aop->type != AOP_STK) {
382
383             if (sym->onStack) {
384                     if ( _G.accInUse )
385                         emitcode("push","acc");
386
387                     emitcode("mov","a,_bp");
388                     emitcode("add","a,#0x%02x",
389                              ((sym->stack < 0) ?
390                               ((char)(sym->stack - _G.nRegsSaved )) :
391                               ((char)sym->stack)) & 0xff);
392                     emitcode("mov","%s,a",
393                              aop->aopu.aop_ptr->name);
394
395                     if ( _G.accInUse )
396                         emitcode("pop","acc");
397             } else
398                 emitcode("mov","%s,#%s",
399                          aop->aopu.aop_ptr->name,
400                          sym->rname);
401             aop->paged = space->paged;
402         } else
403             aop->aopu.aop_stk = sym->stack;
404         return aop;
405     }
406     
407     if (sym->onStack && options.stack10bit)
408     {
409         /* It's on the 10 bit stack, which is located in
410          * far data space.
411          */
412          
413         if ( _G.accInUse )
414                 emitcode("push","acc");
415
416         emitcode("mov","a,_bp");
417         emitcode("add","a,#0x%02x",
418                  ((sym->stack < 0) ?
419                    ((char)(sym->stack - _G.nRegsSaved )) :
420                    ((char)sym->stack)) & 0xff);
421         
422         if (useDP2)
423         {        
424         /* genSetDPTR(1); */
425         emitcode ("mov","dpx1,#0x40");
426         emitcode ("mov","dph1,#0x00");
427         emitcode ("mov","dpl1, a");
428         /* genSetDPTR(0); */
429         }
430         else
431         {
432             emitcode ("mov","dpx,#0x40");
433             emitcode ("mov","dph,#0x00");
434             emitcode ("mov","dpl, a");           
435         }
436         
437         if ( _G.accInUse )
438             emitcode("pop","acc");
439             
440         sym->aop = aop = newAsmop(useDP2 ? AOP_DPTR2 : AOP_DPTR);
441         aop->size = getSize(sym->type); 
442         return aop;
443     }
444
445     /* if in bit space */
446     if (IN_BITSPACE(space)) {
447         sym->aop = aop = newAsmop (AOP_CRY);
448         aop->aopu.aop_dir = sym->rname ;
449         aop->size = getSize(sym->type);
450         return aop;
451     }
452     /* if it is in direct space */
453     if (IN_DIRSPACE(space)) {
454         sym->aop = aop = newAsmop (AOP_DIR);
455         aop->aopu.aop_dir = sym->rname ;
456         aop->size = getSize(sym->type);
457         return aop;
458     }
459
460     /* special case for a function */
461     if (IS_FUNC(sym->type)) {   
462         sym->aop = aop = newAsmop(AOP_IMMD);    
463         ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
464         strcpy(aop->aopu.aop_immd,sym->rname);
465         aop->size = FPTRSIZE; 
466         return aop;
467     }
468
469     /* only remaining is far space */
470     /* in which case DPTR gets the address */
471     sym->aop = aop = newAsmop(useDP2 ? AOP_DPTR2 : AOP_DPTR);
472     if (useDP2)
473     {        
474         genSetDPTR(1);
475         _flushLazyDPS();
476         emitcode ("mov","dptr,#%s", sym->rname);
477         genSetDPTR(0);
478     }    
479     else
480     {
481         emitcode ("mov","dptr,#%s", sym->rname);
482     }
483     aop->size = getSize(sym->type);
484
485     /* if it is in code space */
486     if (IN_CODESPACE(space))
487         aop->code = 1;
488
489     return aop;     
490 }
491
492 /*-----------------------------------------------------------------*/
493 /* aopForRemat - rematerialzes an object                           */
494 /*-----------------------------------------------------------------*/
495 static asmop *aopForRemat (symbol *sym)
496 {
497     iCode *ic = sym->rematiCode;
498     asmop *aop = newAsmop(AOP_IMMD);
499
500     int val = 0;
501
502     for (;;) {
503         if (ic->op == '+')
504             val += operandLitValue(IC_RIGHT(ic));
505         else if (ic->op == '-')
506             val -= operandLitValue(IC_RIGHT(ic));
507         else
508             break;
509         
510         ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
511     }
512
513     if (val)
514         sprintf(buffer,"(%s %c 0x%04x)",
515                 OP_SYMBOL(IC_LEFT(ic))->rname, 
516                 val >= 0 ? '+' : '-',
517                 abs(val) & 0xffff);
518     else
519         strcpy(buffer,OP_SYMBOL(IC_LEFT(ic))->rname);
520
521     ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
522     strcpy(aop->aopu.aop_immd,buffer);    
523     return aop;        
524 }
525
526 /*-----------------------------------------------------------------*/
527 /* regsInCommon - two operands have some registers in common       */
528 /*-----------------------------------------------------------------*/
529 static bool regsInCommon (operand *op1, operand *op2)
530 {
531     symbol *sym1, *sym2;
532     int i;
533
534     /* if they have registers in common */
535     if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
536         return FALSE ;
537
538     sym1 = OP_SYMBOL(op1);
539     sym2 = OP_SYMBOL(op2);
540
541     if (sym1->nRegs == 0 || sym2->nRegs == 0)
542         return FALSE ;
543
544     for (i = 0 ; i < sym1->nRegs ; i++) {
545         int j;
546         if (!sym1->regs[i])
547             continue ;
548
549         for (j = 0 ; j < sym2->nRegs ;j++ ) {
550             if (!sym2->regs[j])
551                 continue ;
552
553             if (sym2->regs[j] == sym1->regs[i])
554                 return TRUE ;
555         }
556     }
557
558     return FALSE ;
559 }
560
561 /*-----------------------------------------------------------------*/
562 /* operandsEqu - equivalent                                        */
563 /*-----------------------------------------------------------------*/
564 static bool operandsEqu ( operand *op1, operand *op2)
565 {
566     symbol *sym1, *sym2;
567
568     /* if they not symbols */
569     if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
570         return FALSE;
571
572     sym1 = OP_SYMBOL(op1);
573     sym2 = OP_SYMBOL(op2);
574
575     /* if both are itemps & one is spilt
576        and the other is not then false */
577     if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
578         sym1->isspilt != sym2->isspilt )
579         return FALSE ;
580
581     /* if they are the same */
582     if (sym1 == sym2)
583         return TRUE ;
584
585     if (strcmp(sym1->rname,sym2->rname) == 0)
586         return TRUE;
587
588
589     /* if left is a tmp & right is not */
590     if (IS_ITEMP(op1)  && 
591         !IS_ITEMP(op2) &&
592         sym1->isspilt  &&
593         (sym1->usl.spillLoc == sym2))
594         return TRUE;
595
596     if (IS_ITEMP(op2)  && 
597         !IS_ITEMP(op1) &&
598         sym2->isspilt  &&
599         sym1->level > 0 &&
600         (sym2->usl.spillLoc == sym1))
601         return TRUE ;
602
603     return FALSE ;
604 }
605
606 /*-----------------------------------------------------------------*/
607 /* sameRegs - two asmops have the same registers                   */
608 /*-----------------------------------------------------------------*/
609 static bool sameRegs (asmop *aop1, asmop *aop2 )
610 {
611     int i;
612
613     if (aop1 == aop2)
614     {
615         if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
616         {
617             return FALSE;
618         }
619         return TRUE ;
620     }
621
622     if (aop1->type != AOP_REG ||
623         aop2->type != AOP_REG )
624         return FALSE ;
625
626     if (aop1->size != aop2->size )
627         return FALSE ;
628
629     for (i = 0 ; i < aop1->size ; i++ )
630         if (aop1->aopu.aop_reg[i] !=
631             aop2->aopu.aop_reg[i] )
632             return FALSE ;
633
634     return TRUE ;
635 }
636
637 /*-----------------------------------------------------------------*/
638 /* aopOp - allocates an asmop for an operand  :                    */
639 /*-----------------------------------------------------------------*/
640 static void aopOp (operand *op, iCode *ic, bool result, bool useDP2)
641 {
642     asmop *aop;
643     symbol *sym;
644     int i;
645
646     if (!op)
647         return ;
648
649     /* if this a literal */
650     if (IS_OP_LITERAL(op)) {
651         op->aop = aop = newAsmop(AOP_LIT);
652         aop->aopu.aop_lit = op->operand.valOperand;
653         aop->size = getSize(operandType(op));
654         return;
655     }
656
657     /* if already has a asmop then continue */
658     if (op->aop)
659         return ;
660
661     /* if the underlying symbol has a aop */
662     if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
663         op->aop = OP_SYMBOL(op)->aop;
664         return;
665     }
666
667     /* if this is a true symbol */
668     if (IS_TRUE_SYMOP(op)) {    
669         op->aop = aopForSym(ic,OP_SYMBOL(op),result, useDP2);
670         return ;
671     }
672
673     /* this is a temporary : this has
674     only four choices :
675     a) register
676     b) spillocation
677     c) rematerialize 
678     d) conditional   
679     e) can be a return use only */
680
681     sym = OP_SYMBOL(op);
682
683
684     /* if the type is a conditional */
685     if (sym->regType == REG_CND) {
686         aop = op->aop = sym->aop = newAsmop(AOP_CRY);
687         aop->size = 0;
688         return;
689     }
690
691     /* if it is spilt then two situations
692     a) is rematerialize 
693     b) has a spill location */
694     if (sym->isspilt || sym->nRegs == 0) {
695
696         /* rematerialize it NOW */
697         if (sym->remat) {
698             sym->aop = op->aop = aop =
699                                       aopForRemat (sym);
700             aop->size = getSize(sym->type);
701             return;
702         }
703
704         if (sym->accuse) {
705             int i;
706             aop = op->aop = sym->aop = newAsmop(AOP_ACC);
707             aop->size = getSize(sym->type);
708             for ( i = 0 ; i < 2 ; i++ )
709                 aop->aopu.aop_str[i] = accUse[i];
710             return;  
711         }
712
713         if (sym->ruonly ) {
714             int i;
715             aop = op->aop = sym->aop = newAsmop(AOP_STR);
716             aop->size = getSize(sym->type);
717             for ( i = 0 ; i < fReturnSize_390 ; i++ )
718                 aop->aopu.aop_str[i] = fReturn[i];
719             return;
720         }
721
722         /* else spill location  */
723         sym->aop = op->aop = aop = 
724                 aopForSym(ic,sym->usl.spillLoc,result, useDP2);
725         aop->size = getSize(sym->type);
726         return;
727     }
728
729     /* must be in a register */
730     sym->aop = op->aop = aop = newAsmop(AOP_REG);
731     aop->size = sym->nRegs;
732     for ( i = 0 ; i < sym->nRegs ;i++)
733         aop->aopu.aop_reg[i] = sym->regs[i];
734 }
735
736 /*-----------------------------------------------------------------*/
737 /* freeAsmop - free up the asmop given to an operand               */
738 /*----------------------------------------------------------------*/
739 static void freeAsmop (operand *op, asmop *aaop, iCode *ic, bool pop)
740 {   
741     asmop *aop ;
742
743     if (!op)
744         aop = aaop;
745     else 
746         aop = op->aop;
747
748     if (!aop)
749         return ;
750
751     if (aop->freed)
752         goto dealloc; 
753
754     aop->freed = 1;
755
756     /* depending on the asmop type only three cases need work AOP_RO
757        , AOP_R1 && AOP_STK */
758     switch (aop->type) {
759         case AOP_R0 :
760             if (_G.r0Pushed ) {
761                 if (pop) {
762                     emitcode ("pop","ar0");     
763                     _G.r0Pushed--;
764                 }
765             }
766             bitVectUnSetBit(ic->rUsed,R0_IDX);
767             break;
768
769         case AOP_R1 :
770             if (_G.r1Pushed ) {
771                 if (pop) {
772                     emitcode ("pop","ar1");
773                     _G.r1Pushed--;
774                 }
775             }
776             bitVectUnSetBit(ic->rUsed,R1_IDX);          
777             break;
778
779         case AOP_STK :
780         {
781             int sz = aop->size;    
782             int stk = aop->aopu.aop_stk + aop->size;
783             bitVectUnSetBit(ic->rUsed,R0_IDX);
784             bitVectUnSetBit(ic->rUsed,R1_IDX);          
785
786             getFreePtr(ic,&aop,FALSE);
787             
788             if (options.stack10bit)
789             {
790                 /* I'm not sure what to do here yet... */
791                 /* #STUB */
792                 fprintf(stderr, 
793                         "*** Warning: probably generating bad code for "
794                         "10 bit stack mode.\n");
795             }
796             
797             if (stk) {
798                 emitcode ("mov","a,_bp");
799                 emitcode ("add","a,#0x%02x",((char)stk) & 0xff);
800                 emitcode ("mov","%s,a",aop->aopu.aop_ptr->name);
801             } else {
802                 emitcode ("mov","%s,_bp",aop->aopu.aop_ptr->name);
803             }
804
805             while (sz--) {
806                 emitcode("pop","acc");
807                 emitcode("mov","@%s,a",aop->aopu.aop_ptr->name);
808                 if (!sz) break;
809                 emitcode("dec","%s",aop->aopu.aop_ptr->name);
810             }
811             op->aop = aop;
812             freeAsmop(op,NULL,ic,TRUE);
813             if (_G.r0Pushed) {
814                 emitcode("pop","ar0");
815                 _G.r0Pushed--;
816             }
817
818             if (_G.r1Pushed) {
819                 emitcode("pop","ar1");
820                 _G.r1Pushed--;
821             }       
822         }
823     }
824
825 dealloc:
826     /* all other cases just dealloc */
827     if (op ) {
828         op->aop = NULL;
829         if (IS_SYMOP(op)) {
830             OP_SYMBOL(op)->aop = NULL;    
831             /* if the symbol has a spill */
832             if (SPIL_LOC(op))
833                 SPIL_LOC(op)->aop = NULL;
834         }
835     }
836 }
837
838 /*------------------------------------------------------------------*/
839 /* aopGet - for fetching value of the aop                           */
840 /*                                                                  */
841 /* Set canClobberACC if you are aure it is OK to clobber the value  */
842 /* in the accumulator. Set it FALSE otherwise; FALSE is always safe,*/
843 /* just less efficient.                                             */
844 /*------------------------------------------------------------------*/
845
846 static char *aopGet (asmop *aop, 
847                      int offset, 
848                      bool bit16,
849                      bool dname,
850                      bool canClobberACC)
851 {
852     char *s = buffer ;
853     char *rs;
854
855     /* offset is greater than
856     size then zero */
857     if (offset > (aop->size - 1) &&
858         aop->type != AOP_LIT)
859         return zero;
860
861     /* depending on type */
862     switch (aop->type) {
863         
864     case AOP_R0:
865     case AOP_R1:
866         /* if we need to increment it */       
867         while (offset > aop->coff) {        
868             emitcode ("inc","%s",aop->aopu.aop_ptr->name);  
869             aop->coff++;
870         }
871         
872         while (offset < aop->coff) {
873             emitcode("dec","%s",aop->aopu.aop_ptr->name);
874             aop->coff--;
875         }
876         
877         aop->coff = offset ;
878         if (aop->paged) {
879             emitcode("movx","a,@%s",aop->aopu.aop_ptr->name);
880             return (dname ? "acc" : "a");
881         }       
882         sprintf(s,"@%s",aop->aopu.aop_ptr->name);
883         ALLOC_ATOMIC(rs,strlen(s)+1);
884         strcpy(rs,s);   
885         return rs;
886         
887     case AOP_DPTR:
888     case AOP_DPTR2:
889     
890         if (aop->type == AOP_DPTR2)
891         {
892             genSetDPTR(1);
893         
894 #ifndef KEVIN_BROKE_IT        
895             if (!canClobberACC)
896 #endif        
897             {
898                 emitcode("xch", "a, ap");
899             }
900         }
901     
902         _flushLazyDPS();
903     
904         while (offset > aop->coff) {
905             emitcode ("inc","dptr");
906             aop->coff++;
907         }
908         
909         while (offset < aop->coff) {        
910             emitcode("lcall","__decdptr");
911             aop->coff--;
912         }
913         
914         aop->coff = offset;
915         if (aop->code) {
916             emitcode("clr","a");
917             emitcode("movc","a,@a+dptr");
918         }
919         else {
920             emitcode("movx","a,@dptr");
921         }
922             
923         if (aop->type == AOP_DPTR2)
924         {
925             genSetDPTR(0);
926
927 #ifndef KEVIN_BROKE_IT        
928             if (!canClobberACC)
929 #endif        
930             {
931                 emitcode("xch", "a, ap");
932                 return "ap";
933             }
934         }
935             
936         return (dname ? "acc" : "a");
937         
938     case AOP_IMMD:
939         if (bit16) 
940             sprintf (s,"#%s",aop->aopu.aop_immd);
941         else
942             if (offset) 
943                 sprintf(s,"#(%s >> %d)",
944                         aop->aopu.aop_immd,
945                         offset*8);
946             else
947                 sprintf(s,"#%s",
948                         aop->aopu.aop_immd);
949         ALLOC_ATOMIC(rs,strlen(s)+1);
950         strcpy(rs,s);   
951         return rs;
952         
953     case AOP_DIR:
954         if (offset)
955             sprintf(s,"(%s + %d)",
956                     aop->aopu.aop_dir,
957                     offset);
958         else
959             sprintf(s,"%s",aop->aopu.aop_dir);
960         ALLOC_ATOMIC(rs,strlen(s)+1);
961         strcpy(rs,s);   
962         return rs;
963         
964     case AOP_REG:
965         if (dname) 
966             return aop->aopu.aop_reg[offset]->dname;
967         else
968             return aop->aopu.aop_reg[offset]->name;
969         
970     case AOP_CRY:
971         emitcode("clr","a");
972         emitcode("mov","c,%s",aop->aopu.aop_dir);
973         emitcode("rlc","a") ;
974         return (dname ? "acc" : "a");
975         
976     case AOP_ACC:
977         if (!offset && dname)
978             return "acc";
979         return aop->aopu.aop_str[offset];
980
981     case AOP_LIT:
982         return aopLiteral (aop->aopu.aop_lit,offset);
983         
984     case AOP_STR:
985         aop->coff = offset ;
986         if (strcmp(aop->aopu.aop_str[offset],"a") == 0 &&
987             dname)
988             return "acc";
989         
990         return aop->aopu.aop_str[offset];
991         
992     }
993
994     werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
995            "aopget got unsupported aop->type");
996     exit(1);
997 }
998 /*-----------------------------------------------------------------*/
999 /* aopPut - puts a string for a aop                                */
1000 /*-----------------------------------------------------------------*/
1001 static void aopPut (asmop *aop, char *s, int offset)
1002 {
1003     char *d = buffer ;
1004     symbol *lbl ;
1005
1006     if (aop->size && offset > ( aop->size - 1)) {
1007         werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1008                "aopPut got offset > aop->size");
1009         exit(1);
1010     }
1011
1012     /* will assign value to value */
1013     /* depending on where it is ofcourse */
1014     switch (aop->type) {
1015     case AOP_DIR:
1016         if (offset)
1017             sprintf(d,"(%s + %d)",
1018                     aop->aopu.aop_dir,offset);
1019         else
1020             sprintf(d,"%s",aop->aopu.aop_dir);
1021         
1022         if (strcmp(d,s))
1023             emitcode("mov","%s,%s",d,s);
1024         
1025         break;
1026         
1027     case AOP_REG:
1028         if (strcmp(aop->aopu.aop_reg[offset]->name,s) != 0 &&
1029             strcmp(aop->aopu.aop_reg[offset]->dname,s)!= 0){
1030             if (*s == '@'           ||
1031                 strcmp(s,"r0") == 0 ||
1032                 strcmp(s,"r1") == 0 ||
1033                 strcmp(s,"r2") == 0 ||
1034                 strcmp(s,"r3") == 0 ||
1035                 strcmp(s,"r4") == 0 ||
1036                 strcmp(s,"r5") == 0 ||
1037                 strcmp(s,"r6") == 0 || 
1038                 strcmp(s,"r7") == 0 )
1039                 emitcode("mov","%s,%s",
1040                          aop->aopu.aop_reg[offset]->dname,s);
1041             else
1042                 emitcode("mov","%s,%s",
1043                          aop->aopu.aop_reg[offset]->name,s);
1044         }
1045         break;
1046         
1047     case AOP_DPTR:
1048     case AOP_DPTR2:
1049     
1050         if (aop->type == AOP_DPTR2)
1051         {
1052             genSetDPTR(1);
1053         }
1054         _flushLazyDPS();
1055     
1056         if (aop->code) {
1057             werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1058                    "aopPut writting to code space");
1059             exit(1);
1060         }
1061         
1062         while (offset > aop->coff) {
1063             aop->coff++;
1064             emitcode ("inc","dptr");
1065         }
1066         
1067         while (offset < aop->coff) {
1068             aop->coff-- ;
1069             emitcode("lcall","__decdptr");
1070         }
1071         
1072         aop->coff = offset;
1073         
1074         /* if not in accumulater */
1075         MOVA(s);        
1076         
1077         emitcode ("movx","@dptr,a");
1078         
1079         if (aop->type == AOP_DPTR2)
1080         {
1081             genSetDPTR(0);
1082         }
1083         break;
1084         
1085     case AOP_R0:
1086     case AOP_R1:
1087         while (offset > aop->coff) {
1088             aop->coff++;
1089             emitcode("inc","%s",aop->aopu.aop_ptr->name);
1090         }
1091         while (offset < aop->coff) {
1092             aop->coff-- ;
1093             emitcode ("dec","%s",aop->aopu.aop_ptr->name);
1094         }
1095         aop->coff = offset;
1096         
1097         if (aop->paged) {
1098             MOVA(s);           
1099             emitcode("movx","@%s,a",aop->aopu.aop_ptr->name);
1100             
1101         } else
1102             if (*s == '@') {
1103                 MOVA(s);
1104                 emitcode("mov","@%s,a",aop->aopu.aop_ptr->name);
1105             } else
1106                 if (strcmp(s,"r0") == 0 ||
1107                     strcmp(s,"r1") == 0 ||
1108                     strcmp(s,"r2") == 0 ||
1109                     strcmp(s,"r3") == 0 ||
1110                     strcmp(s,"r4") == 0 ||
1111                     strcmp(s,"r5") == 0 ||
1112                     strcmp(s,"r6") == 0 || 
1113                     strcmp(s,"r7") == 0 ) {
1114                     char buffer[10];
1115                     sprintf(buffer,"a%s",s);
1116                     emitcode("mov","@%s,%s",
1117                              aop->aopu.aop_ptr->name,buffer);
1118                 } else
1119                     emitcode("mov","@%s,%s",aop->aopu.aop_ptr->name,s);
1120         
1121         break;
1122         
1123     case AOP_STK:
1124         if (strcmp(s,"a") == 0)
1125             emitcode("push","acc");
1126         else
1127             emitcode("push","%s",s);
1128         
1129         break;
1130         
1131     case AOP_CRY:
1132         /* if bit variable */
1133         if (!aop->aopu.aop_dir) {
1134             emitcode("clr","a");
1135             emitcode("rlc","a");
1136         } else {
1137             if (s == zero) 
1138                 emitcode("clr","%s",aop->aopu.aop_dir);
1139             else
1140                 if (s == one)
1141                     emitcode("setb","%s",aop->aopu.aop_dir);
1142                 else
1143                     if (!strcmp(s,"c"))
1144                         emitcode("mov","%s,c",aop->aopu.aop_dir);
1145                     else {
1146                         lbl = newiTempLabel(NULL);
1147                         
1148                         if (strcmp(s,"a")) {
1149                             MOVA(s);
1150                         }
1151                         emitcode("clr","c");
1152                         emitcode("jz","%05d$",lbl->key+100);
1153                         emitcode("cpl","c");
1154                         emitcode("","%05d$:",lbl->key+100);
1155                         emitcode("mov","%s,c",aop->aopu.aop_dir);
1156                     }
1157         }
1158         break;
1159         
1160     case AOP_STR:
1161         aop->coff = offset;
1162         if (strcmp(aop->aopu.aop_str[offset],s))
1163             emitcode ("mov","%s,%s",aop->aopu.aop_str[offset],s);
1164         break;
1165         
1166     case AOP_ACC:
1167         aop->coff = offset;
1168         if (!offset && (strcmp(s,"acc") == 0))
1169             break;
1170         
1171         if (strcmp(aop->aopu.aop_str[offset],s))
1172             emitcode ("mov","%s,%s",aop->aopu.aop_str[offset],s);
1173         break;
1174
1175     default :
1176         werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
1177                "aopPut got unsupported aop->type");
1178         exit(1);    
1179     }    
1180
1181 }
1182
1183
1184 /*-----------------------------------------------------------------*/
1185 /* reAdjustPreg - points a register back to where it should        */
1186 /*-----------------------------------------------------------------*/
1187 static void reAdjustPreg (asmop *aop)
1188 {
1189     int size ;
1190
1191     aop->coff = 0;
1192     if ((size = aop->size) <= 1)
1193         return ;
1194     size-- ;
1195     switch (aop->type) {
1196         case AOP_R0 :
1197         case AOP_R1 :
1198             while (size--)
1199                 emitcode("dec","%s",aop->aopu.aop_ptr->name);
1200             break;          
1201         case AOP_DPTR :
1202         case AOP_DPTR2:
1203             if (aop->type == AOP_DPTR2)
1204             {
1205                 genSetDPTR(1);
1206                 _flushLazyDPS();
1207             } 
1208             while (size--)
1209             {
1210                 emitcode("lcall","__decdptr");
1211             }
1212                 
1213             if (aop->type == AOP_DPTR2)
1214             {
1215                 genSetDPTR(0);
1216             }                
1217             break;  
1218
1219     }   
1220
1221 }
1222
1223 #define AOP(op) op->aop
1224 #define AOP_TYPE(op) AOP(op)->type
1225 #define AOP_SIZE(op) AOP(op)->size
1226 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1227                        AOP_TYPE(x) == AOP_R0))
1228
1229 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1230                         AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
1231                          AOP(x)->paged)) 
1232
1233 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1234                       (x->aopu.aop_reg[0] == ds390_regWithIdx(R0_IDX) || \
1235                       x->aopu.aop_reg[0] == ds390_regWithIdx(R1_IDX) )))
1236
1237 /* Workaround for DS80C390 bug: div ab may return bogus results
1238  * if A is accessed in instruction immediately before the div.
1239  *
1240  * Will be fixed in B4 rev of processor, Dallas claims.
1241  */
1242  
1243 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)                         \
1244     if (!AOP_NEEDSACC(RIGHT))                                   \
1245     {                                                           \
1246         /* We can load A first, then B, since                   \
1247          * B (the RIGHT operand) won't clobber A,               \
1248          * thus avoiding touching A right before the div.       \
1249          */                                                     \
1250         D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
1251         L = aopGet(AOP(LEFT),0,FALSE,FALSE,TRUE);               \
1252         MOVA(L);                                                \
1253         emitcode("mov","b,%s",aopGet(AOP(RIGHT),0,FALSE,FALSE,FALSE));\
1254     }                                                           \
1255     else                                                        \
1256     {                                                           \
1257         /* Just stuff in a nop after loading A. */              \
1258         emitcode("mov","b,%s",aopGet(AOP(RIGHT),0,FALSE,FALSE,FALSE));\
1259         L = aopGet(AOP(LEFT),0,FALSE,FALSE,TRUE);               \
1260         MOVA(L);                                                \
1261         emitcode("nop", "; workaround for DS80C390 div bug.");  \
1262     }
1263
1264 /*-----------------------------------------------------------------*/
1265 /* genNotFloat - generates not for float operations              */
1266 /*-----------------------------------------------------------------*/
1267 static void genNotFloat (operand *op, operand *res)
1268 {
1269     int size, offset;
1270     char *l;
1271     symbol *tlbl ;
1272
1273     D(emitcode(";", "genNotFloat "););
1274
1275     /* we will put 127 in the first byte of 
1276     the result */
1277     aopPut(AOP(res),"#127",0);
1278     size = AOP_SIZE(op) - 1;
1279     offset = 1;
1280
1281     _startLazyDPSEvaluation();
1282     l = aopGet(op->aop,offset++,FALSE,FALSE,TRUE);
1283     MOVA(l);    
1284
1285     while(size--) {
1286         emitcode("orl","a,%s",
1287                  aopGet(op->aop,
1288                         offset++,FALSE,FALSE,FALSE));
1289     }
1290     _endLazyDPSEvaluation();
1291     tlbl = newiTempLabel(NULL);
1292
1293     tlbl = newiTempLabel(NULL);
1294     aopPut(res->aop,one,1);
1295     emitcode("jz","%05d$",(tlbl->key+100));
1296     aopPut(res->aop,zero,1);
1297     emitcode("","%05d$:",(tlbl->key+100));
1298
1299     size = res->aop->size - 2;
1300     offset = 2;    
1301     /* put zeros in the rest */
1302     while (size--) 
1303         aopPut(res->aop,zero,offset++);
1304 }
1305
1306 /*-----------------------------------------------------------------*/
1307 /* opIsGptr: returns non-zero if the passed operand is             */   
1308 /* a generic pointer type.                                         */
1309 /*-----------------------------------------------------------------*/ 
1310 static int opIsGptr(operand *op)
1311 {
1312     link *type = operandType(op);
1313     
1314     if ((AOP_SIZE(op) == GPTRSIZE) && IS_GENPTR(type))
1315     {
1316         return 1;
1317     }
1318     return 0;        
1319 }
1320
1321 /*-----------------------------------------------------------------*/
1322 /* getDataSize - get the operand data size                         */
1323 /*-----------------------------------------------------------------*/
1324 static int getDataSize(operand *op)
1325 {
1326     int size;
1327     size = AOP_SIZE(op);
1328     if (size == GPTRSIZE)
1329     {
1330         link *type = operandType(op);
1331         if (IS_GENPTR(type))
1332         {
1333             /* generic pointer; arithmetic operations
1334              * should ignore the high byte (pointer type).
1335              */
1336             size--;
1337         }
1338     }
1339     return size;
1340 }
1341
1342 /*-----------------------------------------------------------------*/
1343 /* outAcc - output Acc                                             */
1344 /*-----------------------------------------------------------------*/
1345 static void outAcc(operand *result)
1346 {
1347     int size, offset;
1348     size = getDataSize(result);
1349     if(size){
1350         aopPut(AOP(result),"a",0);
1351         size--;
1352         offset = 1;
1353         /* unsigned or positive */
1354         while(size--){
1355             aopPut(AOP(result),zero,offset++);
1356         }
1357     }
1358 }
1359
1360 /*-----------------------------------------------------------------*/
1361 /* outBitC - output a bit C                                        */
1362 /*-----------------------------------------------------------------*/
1363 static void outBitC(operand *result)
1364 {
1365     /* if the result is bit */
1366     if (AOP_TYPE(result) == AOP_CRY) 
1367         aopPut(AOP(result),"c",0);
1368     else {
1369         emitcode("clr","a");
1370         emitcode("rlc","a");
1371         outAcc(result);
1372     }
1373 }
1374
1375 /*-----------------------------------------------------------------*/
1376 /* toBoolean - emit code for orl a,operator(sizeop)                */
1377 /*-----------------------------------------------------------------*/
1378 static void toBoolean(operand *oper)
1379 {
1380     int size = AOP_SIZE(oper) - 1;
1381     int offset = 1;
1382
1383     /* The generic part of a generic pointer should
1384      * not participate in it's truth value.
1385      *
1386      * i.e. 0x10000000 is zero.
1387      */
1388     if (opIsGptr(oper))
1389     {
1390         D(emitcode(";", "toBoolean: generic ptr special case."););
1391         size--;
1392     }
1393
1394     _startLazyDPSEvaluation();
1395     if (AOP_NEEDSACC(oper))
1396     {
1397         emitcode("push", "b");
1398         emitcode("mov", "b, %s", aopGet(AOP(oper),0,FALSE,FALSE,FALSE));
1399     }
1400     else
1401     {
1402         MOVA(aopGet(AOP(oper),0,FALSE,FALSE,TRUE));
1403     }
1404     while (size--) 
1405     {
1406         if (AOP_NEEDSACC(oper))
1407         {
1408             emitcode("orl","b,%s",aopGet(AOP(oper),offset++,FALSE,FALSE,FALSE));
1409         }
1410         else
1411         {
1412             emitcode("orl","a,%s",aopGet(AOP(oper),offset++,FALSE,FALSE,FALSE));
1413         }
1414     }
1415     _endLazyDPSEvaluation();
1416     
1417     if (AOP_NEEDSACC(oper))
1418     {
1419         emitcode("mov", "a,b");
1420         emitcode("pop", "b");
1421     }
1422 }
1423
1424
1425 /*-----------------------------------------------------------------*/
1426 /* genNot - generate code for ! operation                          */
1427 /*-----------------------------------------------------------------*/
1428 static void genNot (iCode *ic)
1429 {
1430     symbol *tlbl;
1431     link *optype = operandType(IC_LEFT(ic));
1432
1433     D(emitcode(";", "genNot "););
1434
1435     /* assign asmOps to operand & result */
1436     aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1437     aopOp (IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR);
1438
1439     /* if in bit space then a special case */
1440     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
1441         emitcode("mov","c,%s",IC_LEFT(ic)->aop->aopu.aop_dir); 
1442         emitcode("cpl","c"); 
1443         outBitC(IC_RESULT(ic));
1444         goto release;
1445     }
1446
1447     /* if type float then do float */
1448     if (IS_FLOAT(optype)) {
1449         genNotFloat(IC_LEFT(ic),IC_RESULT(ic));
1450         goto release;
1451     }
1452
1453     toBoolean(IC_LEFT(ic));
1454
1455     tlbl = newiTempLabel(NULL);
1456     emitcode("cjne","a,#0x01,%05d$",tlbl->key+100);
1457     emitcode("","%05d$:",tlbl->key+100);
1458     outBitC(IC_RESULT(ic));
1459
1460 release:    
1461     /* release the aops */
1462     freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1));
1463     freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
1464 }
1465
1466
1467 /*-----------------------------------------------------------------*/
1468 /* genCpl - generate code for complement                           */
1469 /*-----------------------------------------------------------------*/
1470 static void genCpl (iCode *ic)
1471 {
1472     int offset = 0;
1473     int size ;
1474
1475     D(emitcode(";", "genCpl "););
1476
1477
1478     /* assign asmOps to operand & result */
1479     aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
1480     aopOp (IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR);
1481
1482     /* if both are in bit space then 
1483     a special case */
1484     if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1485         AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) { 
1486
1487         emitcode("mov","c,%s",IC_LEFT(ic)->aop->aopu.aop_dir); 
1488         emitcode("cpl","c"); 
1489         emitcode("mov","%s,c",IC_RESULT(ic)->aop->aopu.aop_dir); 
1490         goto release; 
1491     } 
1492
1493     size = AOP_SIZE(IC_RESULT(ic));
1494     _startLazyDPSEvaluation();
1495     while (size--) {
1496         char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE,TRUE);
1497         MOVA(l);       
1498         emitcode("cpl","a");
1499         aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1500     }
1501     _endLazyDPSEvaluation();
1502
1503
1504 release:
1505     /* release the aops */
1506     freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1));
1507     freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
1508 }
1509
1510 /*-----------------------------------------------------------------*/
1511 /* genUminusFloat - unary minus for floating points                */
1512 /*-----------------------------------------------------------------*/
1513 static void genUminusFloat(operand *op,operand *result)
1514 {
1515     int size ,offset =0 ;
1516     char *l;
1517     /* for this we just need to flip the 
1518     first it then copy the rest in place */
1519     D(emitcode(";", "genUminusFloat"););
1520     
1521     _startLazyDPSEvaluation();
1522     size = AOP_SIZE(op) - 1;
1523     l = aopGet(AOP(op),3,FALSE,FALSE,TRUE);
1524     MOVA(l);    
1525
1526     emitcode("cpl","acc.7");
1527     aopPut(AOP(result),"a",3);    
1528
1529     while(size--) {
1530         aopPut(AOP(result),
1531                aopGet(AOP(op),offset,FALSE,FALSE,FALSE),
1532                offset);
1533         offset++;
1534     }
1535     _endLazyDPSEvaluation();
1536 }
1537
1538 /*-----------------------------------------------------------------*/
1539 /* genUminus - unary minus code generation                         */
1540 /*-----------------------------------------------------------------*/
1541 static void genUminus (iCode *ic)
1542 {
1543     int offset ,size ;
1544     link *optype, *rtype;
1545
1546     D(emitcode(";", "genUminus "););
1547
1548
1549     /* assign asmops */
1550     aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1551     aopOp(IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR);
1552
1553     /* if both in bit space then special
1554     case */
1555     if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1556         AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) { 
1557
1558         emitcode("mov","c,%s",IC_LEFT(ic)->aop->aopu.aop_dir); 
1559         emitcode("cpl","c"); 
1560         emitcode("mov","%s,c",IC_RESULT(ic)->aop->aopu.aop_dir); 
1561         goto release; 
1562     } 
1563
1564     optype = operandType(IC_LEFT(ic));
1565     rtype = operandType(IC_RESULT(ic));
1566
1567     /* if float then do float stuff */
1568     if (IS_FLOAT(optype)) {
1569         genUminusFloat(IC_LEFT(ic),IC_RESULT(ic));
1570         goto release;
1571     }
1572
1573     /* otherwise subtract from zero */
1574     size = AOP_SIZE(IC_LEFT(ic));
1575     offset = 0 ;
1576     //CLRC ;
1577     _startLazyDPSEvaluation();
1578     while(size--) {
1579         char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE,TRUE);
1580         if (!strcmp(l,"a")) {
1581           if (offset==0)
1582             SETC;
1583           emitcode("cpl","a");
1584           emitcode("addc", "a,#0");
1585         } else {
1586           if (offset==0)
1587             CLRC;
1588           emitcode("clr","a");
1589           emitcode("subb","a,%s",l);
1590         }       
1591         aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1592     }
1593     _endLazyDPSEvaluation();
1594
1595     /* if any remaining bytes in the result */
1596     /* we just need to propagate the sign   */
1597     if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1598         emitcode("rlc","a");
1599         emitcode("subb","a,acc");
1600         while (size--) 
1601             aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1602     }       
1603
1604 release:
1605     /* release the aops */
1606     freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1));
1607     freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);    
1608 }
1609
1610 /*-----------------------------------------------------------------*/
1611 /* saveRegisters - will look for a call and save the registers     */
1612 /*-----------------------------------------------------------------*/
1613 static void saveRegisters(iCode *lic) 
1614 {
1615     int i;
1616     iCode *ic;
1617     bitVect *rsave;
1618     link *detype;
1619
1620     /* look for call */
1621     for (ic = lic ; ic ; ic = ic->next) 
1622         if (ic->op == CALL || ic->op == PCALL)
1623             break;
1624
1625     if (!ic) {
1626         fprintf(stderr,"found parameter push with no function call\n");
1627         return ;
1628     }
1629
1630     /* if the registers have been saved already then
1631     do nothing */
1632     if (ic->regsSaved || (OP_SYMBOL(IC_LEFT(ic))->calleeSave))
1633         return ;
1634
1635     /* find the registers in use at this time 
1636     and push them away to safety */
1637     rsave = bitVectCplAnd(bitVectCopy(ic->rMask),
1638                           ic->rUsed);
1639
1640     ic->regsSaved = 1;
1641     if (options.useXstack) {
1642         if (bitVectBitValue(rsave,R0_IDX))
1643             emitcode("mov","b,r0");
1644         emitcode("mov","r0,%s",spname);
1645         for (i = 0 ; i < ds390_nRegs ; i++) {
1646             if (bitVectBitValue(rsave,i)) {
1647                 if (i == R0_IDX)
1648                     emitcode("mov","a,b");
1649                 else
1650                     emitcode("mov","a,%s",ds390_regWithIdx(i)->name);
1651                 emitcode("movx","@r0,a");
1652                 emitcode("inc","r0");
1653             }
1654         }
1655         emitcode("mov","%s,r0",spname);
1656         if (bitVectBitValue(rsave,R0_IDX))
1657             emitcode("mov","r0,b");         
1658     } else
1659         for (i = 0 ; i < ds390_nRegs ; i++) {
1660             if (bitVectBitValue(rsave,i))
1661                 emitcode("push","%s",ds390_regWithIdx(i)->dname);
1662         }
1663
1664     detype = getSpec(operandType(IC_LEFT(ic)));
1665     if (detype        && 
1666         (SPEC_BANK(currFunc->etype) != SPEC_BANK(detype)) &&
1667         IS_ISR(currFunc->etype) &&
1668         !ic->bankSaved) 
1669
1670         saverbank(SPEC_BANK(detype),ic,TRUE);
1671
1672 }
1673 /*-----------------------------------------------------------------*/
1674 /* unsaveRegisters - pop the pushed registers                      */
1675 /*-----------------------------------------------------------------*/
1676 static void unsaveRegisters (iCode *ic)
1677 {
1678     int i;
1679     bitVect *rsave;
1680     /* find the registers in use at this time 
1681     and push them away to safety */
1682     rsave = bitVectCplAnd(bitVectCopy(ic->rMask),
1683                           ic->rUsed);
1684     
1685     if (options.useXstack) {
1686         emitcode("mov","r0,%s",spname); 
1687         for (i =  ds390_nRegs ; i >= 0 ; i--) {
1688             if (bitVectBitValue(rsave,i)) {
1689                 emitcode("dec","r0");
1690                 emitcode("movx","a,@r0");
1691                 if (i == R0_IDX)
1692                     emitcode("mov","b,a");
1693                 else
1694                     emitcode("mov","%s,a",ds390_regWithIdx(i)->name);
1695             }       
1696
1697         }
1698         emitcode("mov","%s,r0",spname);
1699         if (bitVectBitValue(rsave,R0_IDX))
1700             emitcode("mov","r0,b");
1701     } else
1702         for (i =  ds390_nRegs ; i >= 0 ; i--) {
1703             if (bitVectBitValue(rsave,i))
1704                 emitcode("pop","%s",ds390_regWithIdx(i)->dname);
1705         }
1706
1707 }  
1708
1709
1710 /*-----------------------------------------------------------------*/
1711 /* pushSide -                                                      */
1712 /*-----------------------------------------------------------------*/
1713 static void pushSide(operand * oper, int size)
1714 {
1715         int offset = 0;
1716         _startLazyDPSEvaluation();
1717         while (size--) {
1718                 char *l = aopGet(AOP(oper),offset++,FALSE,TRUE,FALSE);
1719                 if (AOP_TYPE(oper) != AOP_REG &&
1720                     AOP_TYPE(oper) != AOP_DIR &&
1721                     strcmp(l,"a") ) {
1722                         emitcode("mov","a,%s",l);
1723                         emitcode("push","acc");
1724                 } else
1725                         emitcode("push","%s",l);
1726         }
1727         _endLazyDPSEvaluation();
1728 }
1729
1730 /*-----------------------------------------------------------------*/
1731 /* assignResultValue -                                             */
1732 /*-----------------------------------------------------------------*/
1733 static void assignResultValue(operand * oper)
1734 {
1735         int offset = 0;
1736         int size = AOP_SIZE(oper);
1737         
1738         _startLazyDPSEvaluation();
1739         while (size--) {
1740                 aopPut(AOP(oper),fReturn[offset],offset);
1741                 offset++;
1742         }
1743         _endLazyDPSEvaluation();
1744 }
1745
1746
1747 /*-----------------------------------------------------------------*/
1748 /* genXpush - pushes onto the external stack                       */
1749 /*-----------------------------------------------------------------*/
1750 static void genXpush (iCode *ic)
1751 {
1752     asmop *aop = newAsmop(0);
1753     regs *r ;
1754     int size,offset = 0;
1755
1756     D(emitcode(";", "genXpush "););
1757
1758     aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1759     r = getFreePtr(ic,&aop,FALSE);
1760
1761     
1762     emitcode("mov","%s,_spx",r->name);
1763
1764     size = AOP_SIZE(IC_LEFT(ic));
1765     _startLazyDPSEvaluation();
1766     while(size--) {
1767
1768         char *l = aopGet(AOP(IC_LEFT(ic)),
1769                          offset++,FALSE,FALSE,TRUE);    
1770         MOVA(l);            
1771         emitcode("movx","@%s,a",r->name);       
1772         emitcode("inc","%s",r->name);
1773
1774     }
1775     _endLazyDPSEvaluation();
1776
1777         
1778     emitcode("mov","_spx,%s",r->name);
1779
1780     freeAsmop(NULL,aop,ic,TRUE);
1781     freeAsmop(IC_LEFT(ic),NULL,ic,TRUE);
1782 }
1783
1784 /*-----------------------------------------------------------------*/
1785 /* genIpush - genrate code for pushing this gets a little complex  */
1786 /*-----------------------------------------------------------------*/
1787 static void genIpush (iCode *ic)
1788 {
1789     int size, offset = 0 ;
1790     char *l;
1791
1792     D(emitcode(";", "genIpush "););
1793
1794
1795     /* if this is not a parm push : ie. it is spill push 
1796     and spill push is always done on the local stack */
1797     if (!ic->parmPush) {
1798
1799         /* and the item is spilt then do nothing */
1800         if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1801             return ;
1802
1803         aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1804         size = AOP_SIZE(IC_LEFT(ic));
1805         /* push it on the stack */
1806         _startLazyDPSEvaluation();
1807         while(size--) {
1808             l = aopGet(AOP(IC_LEFT(ic)),offset++,FALSE,TRUE,TRUE);
1809             if (*l == '#') {
1810                 MOVA(l);
1811                 l = "acc";
1812             }
1813             emitcode("push","%s",l);
1814         }
1815         _endLazyDPSEvaluation();
1816         return ;        
1817     }
1818
1819     /* this is a paramter push: in this case we call
1820     the routine to find the call and save those
1821     registers that need to be saved */   
1822     saveRegisters(ic);
1823
1824     /* if use external stack then call the external
1825     stack pushing routine */
1826     if (options.useXstack) {
1827         genXpush(ic);
1828         return ;
1829     }
1830
1831     /* then do the push */
1832     aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1833
1834
1835         // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
1836     size = AOP_SIZE(IC_LEFT(ic));
1837
1838     _startLazyDPSEvaluation();
1839     while (size--) {
1840         l = aopGet(AOP(IC_LEFT(ic)),offset++,FALSE,TRUE,FALSE);
1841         if (AOP_TYPE(IC_LEFT(ic)) != AOP_REG && 
1842             AOP_TYPE(IC_LEFT(ic)) != AOP_DIR &&
1843             strcmp(l,"a") ) {
1844             emitcode("mov","a,%s",l);
1845             emitcode("push","acc");
1846         } else
1847             emitcode("push","%s",l);
1848     }
1849     _endLazyDPSEvaluation();
1850
1851     freeAsmop(IC_LEFT(ic),NULL,ic,TRUE);
1852 }
1853
1854 /*-----------------------------------------------------------------*/
1855 /* genIpop - recover the registers: can happen only for spilling   */
1856 /*-----------------------------------------------------------------*/
1857 static void genIpop (iCode *ic)
1858 {
1859     int size,offset ;
1860
1861     D(emitcode(";", "genIpop "););
1862
1863
1864     /* if the temp was not pushed then */
1865     if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1866         return ;
1867
1868     aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
1869     size = AOP_SIZE(IC_LEFT(ic));
1870     offset = (size-1);
1871     _startLazyDPSEvaluation();
1872     while (size--)
1873     {
1874         emitcode("pop","%s",aopGet(AOP(IC_LEFT(ic)),offset--,
1875                                    FALSE,TRUE,TRUE));
1876     }
1877     _endLazyDPSEvaluation();
1878
1879     freeAsmop(IC_LEFT(ic),NULL,ic,TRUE);
1880 }
1881
1882 /*-----------------------------------------------------------------*/
1883 /* unsaverbank - restores the resgister bank from stack            */
1884 /*-----------------------------------------------------------------*/
1885 static void unsaverbank (int bank,iCode *ic,bool popPsw)
1886 {
1887     int i;
1888     asmop *aop ;
1889     regs *r = NULL;
1890
1891     if (popPsw) {
1892         if (options.useXstack) {
1893             aop = newAsmop(0);
1894             r = getFreePtr(ic,&aop,FALSE);
1895             
1896             
1897             emitcode("mov","%s,_spx",r->name);
1898             emitcode("movx","a,@%s",r->name);
1899             emitcode("mov","psw,a");
1900             emitcode("dec","%s",r->name);
1901             
1902         }else
1903             emitcode ("pop","psw");
1904     }
1905
1906     for (i = (ds390_nRegs - 1) ; i >= 0 ;i--) {
1907         if (options.useXstack) {       
1908             emitcode("movx","a,@%s",r->name);
1909             emitcode("mov","(%s+%d),a",
1910                      regs390[i].base,8*bank+regs390[i].offset);
1911             emitcode("dec","%s",r->name);
1912
1913         } else 
1914             emitcode("pop","(%s+%d)",
1915                      regs390[i].base,8*bank+regs390[i].offset);
1916     }
1917
1918     if (options.useXstack) {
1919
1920         emitcode("mov","_spx,%s",r->name);
1921         freeAsmop(NULL,aop,ic,TRUE);
1922
1923     } 
1924 }
1925
1926 /*-----------------------------------------------------------------*/
1927 /* saverbank - saves an entire register bank on the stack          */
1928 /*-----------------------------------------------------------------*/
1929 static void saverbank (int bank, iCode *ic, bool pushPsw)
1930 {
1931     int i;
1932     asmop *aop ;
1933     regs *r = NULL;
1934
1935     if (options.useXstack) {
1936
1937         aop = newAsmop(0);
1938         r = getFreePtr(ic,&aop,FALSE);  
1939         emitcode("mov","%s,_spx",r->name);
1940
1941     }
1942
1943     for (i = 0 ; i < ds390_nRegs ;i++) {
1944         if (options.useXstack) {
1945             emitcode("inc","%s",r->name);
1946             emitcode("mov","a,(%s+%d)",
1947                      regs390[i].base,8*bank+regs390[i].offset);
1948             emitcode("movx","@%s,a",r->name);           
1949         } else 
1950             emitcode("push","(%s+%d)",
1951                      regs390[i].base,8*bank+regs390[i].offset);
1952     }
1953     
1954     if (pushPsw) {
1955         if (options.useXstack) {
1956             emitcode("mov","a,psw");
1957             emitcode("movx","@%s,a",r->name);   
1958             emitcode("inc","%s",r->name);
1959             emitcode("mov","_spx,%s",r->name);       
1960             freeAsmop (NULL,aop,ic,TRUE);
1961             
1962         } else
1963             emitcode("push","psw");
1964         
1965         emitcode("mov","psw,#0x%02x",(bank << 3)&0x00ff);
1966     }
1967     ic->bankSaved = 1;
1968
1969 }
1970
1971 /*-----------------------------------------------------------------*/
1972 /* genCall - generates a call statement                            */
1973 /*-----------------------------------------------------------------*/
1974 static void genCall (iCode *ic)
1975 {
1976     link *detype;   
1977
1978     D(emitcode(";", "genCall "););
1979
1980     /* if caller saves & we have not saved then */
1981     if (!ic->regsSaved)
1982         saveRegisters(ic);
1983
1984     /* if we are calling a function that is not using
1985     the same register bank then we need to save the
1986     destination registers on the stack */
1987     detype = getSpec(operandType(IC_LEFT(ic)));
1988     if (detype        && 
1989         (SPEC_BANK(currFunc->etype) != SPEC_BANK(detype)) &&
1990         IS_ISR(currFunc->etype) &&
1991         !ic->bankSaved) 
1992
1993         saverbank(SPEC_BANK(detype),ic,TRUE);
1994
1995     /* if send set is not empty the assign */
1996     if (_G.sendSet) {
1997         iCode *sic ;
1998
1999         for (sic = setFirstItem(_G.sendSet) ; sic ; 
2000              sic = setNextItem(_G.sendSet)) 
2001         {
2002             int size, offset = 0;
2003         
2004             aopOp(IC_LEFT(sic),sic,FALSE, TRUE);
2005             size = AOP_SIZE(IC_LEFT(sic));
2006             
2007             _startLazyDPSEvaluation();
2008             while (size--) {
2009                 char *l = aopGet(AOP(IC_LEFT(sic)),offset,
2010                                 FALSE, FALSE, TRUE);
2011                 if (strcmp(l,fReturn[offset]))
2012                     emitcode("mov","%s,%s",
2013                              fReturn[offset],
2014                              l);
2015                 offset++;
2016             }
2017             _endLazyDPSEvaluation();
2018             freeAsmop (IC_LEFT(sic),NULL,sic,TRUE);
2019         }
2020         _G.sendSet = NULL;
2021     }
2022     /* make the call */
2023     emitcode("lcall","%s",(OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
2024                            OP_SYMBOL(IC_LEFT(ic))->rname :
2025                            OP_SYMBOL(IC_LEFT(ic))->name));
2026
2027     /* if we need assign a result value */
2028     if ((IS_ITEMP(IC_RESULT(ic)) && 
2029          (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
2030           OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
2031         IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
2032
2033 #ifdef LAZY_DPS_OPT
2034         /* Not really related to LAZY_DPS_OPT, but don't want
2035          * another testing flag right now...
2036          */
2037         _G.accInUse++;
2038         aopOp(IC_RESULT(ic),ic,FALSE, TRUE);
2039         _G.accInUse--;
2040                                      
2041         assignResultValue(IC_RESULT(ic));
2042                                                   
2043         freeAsmop(IC_RESULT(ic),NULL, ic,TRUE);
2044                                                                       
2045 #else
2046         if (!isOperandInFarSpace(IC_RESULT(ic)))
2047         {
2048             _G.accInUse++;
2049             aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
2050             _G.accInUse--;
2051
2052             assignResultValue(IC_RESULT(ic));
2053                 
2054             freeAsmop(IC_RESULT(ic),NULL, ic,TRUE);
2055         }
2056         else
2057         {
2058             /* Result is in far space, and requires DPTR to access
2059              * it. Push the result onto the stack and restore from
2060              * there.
2061              */
2062             int size = getSize(operandType(IC_RESULT(ic)));
2063             int offset = size - 1;
2064             char *l;
2065             
2066             emitcode(";", "Kevin function call abuse #1");
2067
2068             /* first push the right side on to the stack */
2069             /* NB: this relies on the fact that "a" is the last
2070              * register in fReturn. If it were not, the MOVA
2071              * would potentially clobber a returned byte in A.
2072              */
2073             while (size--) {
2074                 l = fReturn[offset--];
2075                 MOVA(l);
2076                 emitcode ("push","acc");
2077             }
2078     
2079             /* now assign DPTR to result */
2080             aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
2081             size = AOP_SIZE(IC_RESULT(ic));
2082             aopOp(IC_RESULT(ic),ic,FALSE, FALSE); /* bug? */
2083             while (size--) {
2084                 emitcode ("pop","acc");
2085                 aopPut(AOP(IC_RESULT(ic)),"a",++offset);
2086             }
2087             freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
2088         }
2089 #endif  
2090     }
2091
2092     /* adjust the stack for parameters if 
2093     required */
2094     if (IC_LEFT(ic)->parmBytes) {
2095         int i;
2096         if (IC_LEFT(ic)->parmBytes > 3) {
2097             emitcode("mov","a,%s",spname);
2098             emitcode("add","a,#0x%02x", (- IC_LEFT(ic)->parmBytes) & 0xff);
2099             emitcode("mov","%s,a",spname);
2100         } else 
2101             for ( i = 0 ; i <  IC_LEFT(ic)->parmBytes ;i++)
2102                 emitcode("dec","%s",spname);
2103
2104     }
2105
2106     /* if register bank was saved then pop them */
2107     if (ic->bankSaved)
2108         unsaverbank(SPEC_BANK(detype),ic,TRUE);
2109
2110     /* if we hade saved some registers then unsave them */
2111     if (ic->regsSaved && !(OP_SYMBOL(IC_LEFT(ic))->calleeSave))
2112         unsaveRegisters (ic);
2113
2114
2115 }
2116
2117 /*-----------------------------------------------------------------*/
2118 /* genPcall - generates a call by pointer statement                */
2119 /*-----------------------------------------------------------------*/
2120 static void genPcall (iCode *ic)
2121 {
2122     link *detype;
2123     symbol *rlbl = newiTempLabel(NULL);
2124
2125     D(emitcode(";", "genPcall "););
2126
2127
2128     /* if caller saves & we have not saved then */
2129     if (!ic->regsSaved)
2130         saveRegisters(ic);
2131
2132     /* if we are calling a function that is not using
2133     the same register bank then we need to save the
2134     destination registers on the stack */
2135     detype = getSpec(operandType(IC_LEFT(ic)));
2136     if (detype        && 
2137         IS_ISR(currFunc->etype) &&
2138         (SPEC_BANK(currFunc->etype) != SPEC_BANK(detype)))
2139         saverbank(SPEC_BANK(detype),ic,TRUE);
2140
2141
2142     /* push the return address on to the stack */
2143     emitcode("mov","a,#%05d$",(rlbl->key+100));
2144     emitcode("push","acc");    
2145     emitcode("mov","a,#(%05d$ >> 8)",(rlbl->key+100));
2146     emitcode("push","acc");
2147     
2148     if (options.model == MODEL_FLAT24)
2149     {
2150         emitcode("mov","a,#(%05d$ >> 16)",(rlbl->key+100));
2151         emitcode("push","acc");    
2152     }
2153
2154     /* now push the calling address */
2155     aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
2156
2157     pushSide(IC_LEFT(ic), FPTRSIZE);
2158
2159     freeAsmop(IC_LEFT(ic),NULL,ic,TRUE); 
2160
2161     /* if send set is not empty the assign */
2162     if (_G.sendSet) {
2163         iCode *sic ;
2164
2165         for (sic = setFirstItem(_G.sendSet) ; sic ; 
2166              sic = setNextItem(_G.sendSet)) 
2167              {
2168                 int size, offset = 0;
2169             
2170                 aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
2171                 size = AOP_SIZE(IC_LEFT(sic));
2172                 _startLazyDPSEvaluation();
2173                 while (size--) 
2174                 {
2175                         char *l = aopGet(AOP(IC_LEFT(sic)),offset,
2176                                          FALSE,FALSE,TRUE);
2177                         if (strcmp(l,fReturn[offset]))
2178                         {
2179                                 emitcode("mov","%s,%s",
2180                                          fReturn[offset],
2181                                          l);
2182                         }
2183                         offset++;
2184                 }
2185                 _endLazyDPSEvaluation();
2186                 freeAsmop (IC_LEFT(sic),NULL,sic,TRUE);
2187             }
2188             _G.sendSet = NULL;
2189     }
2190
2191     emitcode("ret","");
2192     emitcode("","%05d$:",(rlbl->key+100));
2193
2194
2195     /* if we need assign a result value */
2196     if ((IS_ITEMP(IC_RESULT(ic)) &&
2197          (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
2198           OP_SYMBOL(IC_RESULT(ic))->spildir)) ||
2199         IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
2200
2201         _G.accInUse++;
2202         aopOp(IC_RESULT(ic),ic,FALSE, TRUE);
2203         _G.accInUse--;
2204         
2205         assignResultValue(IC_RESULT(ic));
2206
2207         freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
2208     }
2209
2210     /* adjust the stack for parameters if 
2211     required */
2212     if (IC_LEFT(ic)->parmBytes) {
2213         int i;
2214         if (IC_LEFT(ic)->parmBytes > 3) {
2215             emitcode("mov","a,%s",spname);
2216             emitcode("add","a,#0x%02x", (- IC_LEFT(ic)->parmBytes) & 0xff);
2217             emitcode("mov","%s,a",spname);
2218         } else 
2219             for ( i = 0 ; i <  IC_LEFT(ic)->parmBytes ;i++)
2220                 emitcode("dec","%s",spname);
2221
2222     }
2223
2224     /* if register bank was saved then unsave them */
2225     if (detype        && 
2226         (SPEC_BANK(currFunc->etype) != 
2227          SPEC_BANK(detype)))
2228         unsaverbank(SPEC_BANK(detype),ic,TRUE);
2229
2230     /* if we hade saved some registers then
2231     unsave them */
2232     if (ic->regsSaved)
2233         unsaveRegisters (ic);
2234
2235 }
2236
2237 /*-----------------------------------------------------------------*/
2238 /* resultRemat - result  is rematerializable                       */
2239 /*-----------------------------------------------------------------*/
2240 static int resultRemat (iCode *ic)
2241 {
2242     if (SKIP_IC(ic) || ic->op == IFX)
2243         return 0;
2244
2245     if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
2246         symbol *sym = OP_SYMBOL(IC_RESULT(ic));
2247         if (sym->remat && !POINTER_SET(ic)) 
2248             return 1;
2249     }
2250
2251     return 0;
2252 }
2253
2254 #ifdef __BORLANDC__
2255 #define STRCASECMP stricmp
2256 #else
2257 #define STRCASECMP strcasecmp
2258 #endif
2259
2260 /*-----------------------------------------------------------------*/
2261 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2262 /*-----------------------------------------------------------------*/
2263 static bool inExcludeList(char *s)
2264 {
2265     int i =0;
2266     
2267     if (options.excludeRegs[i] &&
2268     STRCASECMP(options.excludeRegs[i],"none") == 0)
2269         return FALSE ;
2270
2271     for ( i = 0 ; options.excludeRegs[i]; i++) {
2272         if (options.excludeRegs[i] &&
2273         STRCASECMP(s,options.excludeRegs[i]) == 0)
2274             return TRUE;
2275     }
2276     return FALSE ;
2277 }
2278
2279 /*-----------------------------------------------------------------*/
2280 /* genFunction - generated code for function entry                 */
2281 /*-----------------------------------------------------------------*/
2282 static void genFunction (iCode *ic)
2283 {
2284     symbol *sym;
2285     link *fetype;
2286
2287     D(emitcode(";", "genFunction "););
2288
2289     _G.nRegsSaved = 0;
2290     /* create the function header */
2291     emitcode(";","-----------------------------------------");
2292     emitcode(";"," function %s",(sym = OP_SYMBOL(IC_LEFT(ic)))->name);
2293     emitcode(";","-----------------------------------------");
2294
2295     emitcode("","%s:",sym->rname);
2296     fetype = getSpec(operandType(IC_LEFT(ic)));
2297
2298     /* if critical function then turn interrupts off */
2299     if (SPEC_CRTCL(fetype))
2300         emitcode("clr","ea");
2301
2302     /* here we need to generate the equates for the
2303        register bank if required */
2304     if (SPEC_BANK(fetype) != rbank) {
2305         int i ;
2306
2307         rbank = SPEC_BANK(fetype);
2308         for ( i = 0 ; i < ds390_nRegs ; i++ ) {
2309             if (strcmp(regs390[i].base,"0") == 0)
2310                 emitcode("","%s = 0x%02x",
2311                          regs390[i].dname,
2312                          8*rbank+regs390[i].offset);
2313             else
2314                 emitcode ("","%s = %s + 0x%02x",
2315                           regs390[i].dname,
2316                           regs390[i].base,
2317                           8*rbank+regs390[i].offset);
2318         }
2319     }
2320
2321     /* if this is an interrupt service routine then
2322     save acc, b, dpl, dph  */
2323     if (IS_ISR(sym->etype)) {
2324         
2325         if (!inExcludeList("acc"))          
2326             emitcode ("push","acc");    
2327         if (!inExcludeList("b"))
2328             emitcode ("push","b");
2329         if (!inExcludeList("dpl"))
2330             emitcode ("push","dpl");
2331         if (!inExcludeList("dph"))
2332             emitcode ("push","dph");
2333         if (options.model == MODEL_FLAT24 && !inExcludeList("dpx"))
2334         {
2335             emitcode ("push", "dpx");
2336             /* Make sure we're using standard DPTR */
2337             emitcode ("push", "dps");
2338             emitcode ("mov", "dps, #0x00");
2339             if (options.stack10bit)
2340             {   
2341                 /* This ISR could conceivably use DPTR2. Better save it. */
2342                 emitcode ("push", "dpl1");
2343                 emitcode ("push", "dph1");
2344                 emitcode ("push", "dpx1");
2345             emitcode ("push", "ap");
2346             }
2347         }
2348         /* if this isr has no bank i.e. is going to
2349            run with bank 0 , then we need to save more
2350            registers :-) */
2351         if (!SPEC_BANK(sym->etype)) {
2352
2353             /* if this function does not call any other
2354                function then we can be economical and
2355                save only those registers that are used */
2356             if (! sym->hasFcall) {
2357                 int i;
2358
2359                 /* if any registers used */
2360                 if (sym->regsUsed) {
2361                     /* save the registers used */
2362                     for ( i = 0 ; i < sym->regsUsed->size ; i++) {
2363                         if (bitVectBitValue(sym->regsUsed,i) ||
2364                           (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)) )
2365                             emitcode("push","%s",ds390_regWithIdx(i)->dname);                       
2366                     }
2367                 }
2368                 
2369             } else {
2370                 /* this function has  a function call cannot
2371                    determines register usage so we will have the
2372                    entire bank */
2373                 saverbank(0,ic,FALSE);
2374             }       
2375         }
2376     } else {
2377         /* if callee-save to be used for this function
2378            then save the registers being used in this function */
2379         if (sym->calleeSave) {
2380             int i;
2381             
2382             /* if any registers used */
2383             if (sym->regsUsed) {
2384                 /* save the registers used */
2385                 for ( i = 0 ; i < sym->regsUsed->size ; i++) {
2386                     if (bitVectBitValue(sym->regsUsed,i) ||
2387                       (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) {
2388                         emitcode("push","%s",ds390_regWithIdx(i)->dname);
2389                         _G.nRegsSaved++;
2390                     }
2391                 }
2392             }
2393         }
2394     }
2395
2396     /* set the register bank to the desired value */
2397     if (SPEC_BANK(sym->etype) || IS_ISR(sym->etype)) {
2398         emitcode("push","psw");
2399         emitcode("mov","psw,#0x%02x",(SPEC_BANK(sym->etype) << 3)&0x00ff);   
2400     }
2401
2402     if (IS_RENT(sym->etype) || options.stackAuto) {
2403
2404         if (options.useXstack) {
2405             emitcode("mov","r0,%s",spname);
2406             emitcode("mov","a,_bp");
2407             emitcode("movx","@r0,a");
2408             emitcode("inc","%s",spname);
2409         }
2410         else
2411         {
2412             /* set up the stack */
2413             emitcode ("push","_bp");     /* save the callers stack  */
2414         }
2415         emitcode ("mov","_bp,%s",spname);
2416     }
2417
2418     /* adjust the stack for the function */
2419     if (sym->stack) {
2420
2421         int i = sym->stack;
2422         if (i > 256 ) 
2423             werror(W_STACK_OVERFLOW,sym->name);
2424
2425         if (i > 3 && sym->recvSize < 4) {              
2426
2427             emitcode ("mov","a,sp");
2428             emitcode ("add","a,#0x%02x",((char)sym->stack & 0xff));
2429             emitcode ("mov","sp,a");
2430            
2431         }
2432         else
2433             while(i--)
2434                 emitcode("inc","sp");
2435     }
2436
2437      if (sym->xstack) {
2438
2439         emitcode ("mov","a,_spx");
2440         emitcode ("add","a,#0x%02x",((char)sym->xstack & 0xff));
2441         emitcode ("mov","_spx,a");
2442     }    
2443
2444 }
2445
2446 /*-----------------------------------------------------------------*/
2447 /* genEndFunction - generates epilogue for functions               */
2448 /*-----------------------------------------------------------------*/
2449 static void genEndFunction (iCode *ic)
2450 {
2451     symbol *sym = OP_SYMBOL(IC_LEFT(ic));
2452
2453     D(emitcode(";", "genEndFunction "););
2454
2455     if (IS_RENT(sym->etype) || options.stackAuto)
2456     {
2457         emitcode ("mov","%s,_bp",spname);
2458     }
2459
2460     /* if use external stack but some variables were
2461     added to the local stack then decrement the
2462     local stack */
2463     if (options.useXstack && sym->stack) {      
2464         emitcode("mov","a,sp");
2465         emitcode("add","a,#0x%02x",((char)-sym->stack) & 0xff);
2466         emitcode("mov","sp,a");
2467     }
2468
2469
2470     if ((IS_RENT(sym->etype) || options.stackAuto)) {
2471         if (options.useXstack) {
2472             emitcode("mov","r0,%s",spname);
2473             emitcode("movx","a,@r0");
2474             emitcode("mov","_bp,a");
2475             emitcode("dec","%s",spname);
2476         }
2477         else
2478         {
2479             emitcode ("pop","_bp");
2480         }
2481     }
2482
2483     /* restore the register bank  */    
2484     if (SPEC_BANK(sym->etype) || IS_ISR(sym->etype))
2485         emitcode ("pop","psw");
2486
2487     if (IS_ISR(sym->etype)) {
2488
2489         /* now we need to restore the registers */
2490         /* if this isr has no bank i.e. is going to
2491            run with bank 0 , then we need to save more
2492            registers :-) */
2493         if (!SPEC_BANK(sym->etype)) {
2494             
2495             /* if this function does not call any other
2496                function then we can be economical and
2497                save only those registers that are used */
2498             if (! sym->hasFcall) {
2499                 int i;
2500                 
2501                 /* if any registers used */
2502                 if (sym->regsUsed) {
2503                     /* save the registers used */
2504                     for ( i = sym->regsUsed->size ; i >= 0 ; i--) {
2505                         if (bitVectBitValue(sym->regsUsed,i) ||
2506                           (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)) )
2507                             emitcode("pop","%s",ds390_regWithIdx(i)->dname);
2508                     }
2509                 }
2510                 
2511             } else {
2512                 /* this function has  a function call cannot
2513                    determines register usage so we will have the
2514                    entire bank */
2515                 unsaverbank(0,ic,FALSE);
2516             }       
2517         }
2518
2519         if (options.model == MODEL_FLAT24 && !inExcludeList("dpx"))
2520         {
2521             if (options.stack10bit)
2522             {
2523             emitcode ("pop", "ap");
2524                 emitcode ("pop", "dpx1");
2525                 emitcode ("pop", "dph1");
2526                 emitcode ("pop", "dpl1");
2527             }   
2528             emitcode ("pop", "dps");
2529             emitcode ("pop", "dpx");
2530         }
2531         if (!inExcludeList("dph"))
2532             emitcode ("pop","dph");
2533         if (!inExcludeList("dpl"))
2534             emitcode ("pop","dpl");
2535         if (!inExcludeList("b"))
2536             emitcode ("pop","b");
2537         if (!inExcludeList("acc"))
2538             emitcode ("pop","acc");
2539
2540         if (SPEC_CRTCL(sym->etype))
2541             emitcode("setb","ea");
2542
2543         /* if debug then send end of function */
2544 /*      if (options.debug && currFunc) { */
2545         if (currFunc) {
2546             _G.debugLine = 1;
2547             emitcode("","C$%s$%d$%d$%d ==.",
2548                      ic->filename,currFunc->lastLine,
2549                      ic->level,ic->block); 
2550             if (IS_STATIC(currFunc->etype))         
2551                 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name); 
2552             else
2553                 emitcode("","XG$%s$0$0 ==.",currFunc->name);
2554             _G.debugLine = 0;
2555         }
2556         
2557         emitcode ("reti","");
2558     }
2559     else {
2560         if (SPEC_CRTCL(sym->etype))
2561             emitcode("setb","ea");
2562         
2563         if (sym->calleeSave) {
2564             int i;
2565             
2566             /* if any registers used */
2567             if (sym->regsUsed) {
2568                 /* save the registers used */
2569                 for ( i = sym->regsUsed->size ; i >= 0 ; i--) {
2570                     if (bitVectBitValue(sym->regsUsed,i) ||
2571                       (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)) )
2572                         emitcode("pop","%s",ds390_regWithIdx(i)->dname);
2573                 }
2574             }
2575             
2576         }
2577
2578         /* if debug then send end of function */
2579         if (currFunc) {
2580             _G.debugLine = 1;
2581             emitcode("","C$%s$%d$%d$%d ==.",
2582                      ic->filename,currFunc->lastLine,
2583                      ic->level,ic->block); 
2584             if (IS_STATIC(currFunc->etype))         
2585                 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name); 
2586             else
2587                 emitcode("","XG$%s$0$0 ==.",currFunc->name);
2588             _G.debugLine = 0;
2589         }
2590
2591         emitcode ("ret","");
2592     }
2593
2594 }
2595
2596 /*-----------------------------------------------------------------*/
2597 /* genRet - generate code for return statement                     */
2598 /*-----------------------------------------------------------------*/
2599 static void genRet (iCode *ic)
2600 {
2601     int size,offset = 0 , pushed = 0;
2602     
2603     D(emitcode(";", "genRet "););
2604
2605     /* if we have no return value then
2606        just generate the "ret" */
2607     if (!IC_LEFT(ic)) 
2608         goto jumpret;       
2609     
2610     /* we have something to return then
2611        move the return value into place */
2612     aopOp(IC_LEFT(ic),ic,FALSE, TRUE);
2613     size = AOP_SIZE(IC_LEFT(ic));
2614     
2615     _startLazyDPSEvaluation();
2616     while (size--) {
2617             char *l ;
2618             if (AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR) {
2619                     l = aopGet(AOP(IC_LEFT(ic)),offset++,
2620                            FALSE,TRUE,FALSE);
2621                     emitcode("push","%s",l);
2622                     pushed++;
2623             } else {
2624                     l = aopGet(AOP(IC_LEFT(ic)),offset,
2625                                FALSE,FALSE,FALSE);
2626                     if (strcmp(fReturn[offset],l))
2627                             emitcode("mov","%s,%s",fReturn[offset++],l);
2628             }
2629     }
2630     _endLazyDPSEvaluation();    
2631
2632     if (pushed) {
2633         while(pushed) {
2634             pushed--;
2635             if (strcmp(fReturn[pushed],"a"))
2636                 emitcode("pop",fReturn[pushed]);
2637             else
2638                 emitcode("pop","acc");
2639         }
2640     }
2641     freeAsmop (IC_LEFT(ic),NULL,ic,TRUE);
2642     
2643  jumpret:
2644         /* generate a jump to the return label
2645            if the next is not the return statement */
2646     if (!(ic->next && ic->next->op == LABEL &&
2647           IC_LABEL(ic->next) == returnLabel))
2648         
2649         emitcode("ljmp","%05d$",(returnLabel->key+100));
2650     
2651 }
2652
2653 /*-----------------------------------------------------------------*/
2654 /* genLabel - generates a label                                    */
2655 /*-----------------------------------------------------------------*/
2656 static void genLabel (iCode *ic)
2657 {
2658     /* special case never generate */
2659     if (IC_LABEL(ic) == entryLabel)
2660         return ;
2661
2662     D(emitcode(";", "genLabel "););
2663
2664     emitcode("","%05d$:",(IC_LABEL(ic)->key+100));
2665 }
2666
2667 /*-----------------------------------------------------------------*/
2668 /* genGoto - generates a ljmp                                      */
2669 /*-----------------------------------------------------------------*/
2670 static void genGoto (iCode *ic)
2671 {
2672     D(emitcode(";", "genGoto "););
2673     emitcode ("ljmp","%05d$",(IC_LABEL(ic)->key+100));
2674 }
2675
2676 /*-----------------------------------------------------------------*/
2677 /* findLabelBackwards: walks back through the iCode chain looking  */
2678 /* for the given label. Returns number of iCode instructions       */
2679 /* between that label and given ic.                                */
2680 /* Returns zero if label not found.                                */
2681 /*-----------------------------------------------------------------*/
2682 static int findLabelBackwards(iCode *ic, int key)
2683 {
2684     int count = 0;
2685     
2686     while (ic->prev)
2687     {
2688         ic = ic->prev;
2689         count++;
2690         
2691         if (ic->op == LABEL && IC_LABEL(ic)->key == key)
2692         {
2693             /* printf("findLabelBackwards = %d\n", count); */
2694             return count;
2695         }
2696     }
2697     
2698     return 0;
2699 }
2700
2701 /*-----------------------------------------------------------------*/
2702 /* genPlusIncr :- does addition with increment if possible         */
2703 /*-----------------------------------------------------------------*/
2704 static bool genPlusIncr (iCode *ic)
2705 {
2706     unsigned int icount ;
2707     unsigned int size = getDataSize(IC_RESULT(ic));
2708     
2709     /* will try to generate an increment */
2710     /* if the right side is not a literal 
2711        we cannot */
2712     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
2713         return FALSE ;
2714     
2715     /* if the literal value of the right hand side
2716        is greater than 4 then it is not worth it */
2717     if ((icount =  floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 4)
2718         return FALSE ;
2719     
2720     /* if increment 16 bits in register */
2721     if (
2722         AOP_TYPE(IC_LEFT(ic)) == AOP_REG &&
2723         AOP_TYPE(IC_RESULT(ic)) == AOP_REG &&
2724         sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
2725         (size > 1) &&
2726         (icount == 1)) {
2727         symbol *tlbl;
2728         int emitTlbl;
2729         int labelRange;
2730
2731         /* If the next instruction is a goto and the goto target
2732          * is <= 5 instructions previous to this, we can generate
2733          * jumps straight to that target.
2734          */
2735         if (ic->next && ic->next->op == GOTO
2736             && (labelRange = findLabelBackwards(ic, IC_LABEL(ic->next)->key)) != 0
2737             && labelRange <= 5 )
2738         {
2739            emitcode(";", "tail increment optimized (range %d)", labelRange);
2740            tlbl = IC_LABEL(ic->next);
2741            emitTlbl = 0;
2742         }
2743         else
2744         {
2745             tlbl = newiTempLabel(NULL);
2746             emitTlbl = 1;
2747         }
2748         emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE,FALSE));
2749         if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
2750            IS_AOP_PREG(IC_RESULT(ic)))
2751             emitcode("cjne","%s,#0x00,%05d$"
2752                      ,aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE,FALSE)
2753                      ,tlbl->key+100);
2754         else {
2755             emitcode("clr","a");
2756             emitcode("cjne","a,%s,%05d$"
2757                      ,aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE,FALSE)
2758                      ,tlbl->key+100);
2759         }
2760     
2761         emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE,FALSE));
2762         if (size > 2)
2763         {
2764             if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
2765                IS_AOP_PREG(IC_RESULT(ic)))
2766                 emitcode("cjne","%s,#0x00,%05d$"
2767                          ,aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE,FALSE)
2768                          ,tlbl->key+100);
2769             else
2770                 emitcode("cjne","a,%s,%05d$"
2771                          ,aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE,FALSE)
2772                          ,tlbl->key+100);
2773             
2774             emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE,FALSE));
2775        }
2776        if (size > 3)
2777        {
2778             if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
2779                IS_AOP_PREG(IC_RESULT(ic)))
2780                 emitcode("cjne","%s,#0x00,%05d$"
2781                          ,aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE,FALSE)
2782                          ,tlbl->key+100);
2783             else{
2784                 emitcode("cjne","a,%s,%05d$"
2785                          ,aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE,FALSE)
2786                          ,tlbl->key+100);
2787             }
2788             emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB32,FALSE,FALSE,FALSE));
2789         }
2790         
2791         if (emitTlbl)
2792         {
2793             emitcode("","%05d$:",tlbl->key+100);
2794         }
2795         return TRUE;
2796     }
2797     
2798     /* if the sizes are greater than 1 then we cannot */
2799     if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
2800         AOP_SIZE(IC_LEFT(ic)) > 1   )
2801         return FALSE ;
2802     
2803     /* we can if the aops of the left & result match or
2804        if they are in registers and the registers are the
2805        same */
2806     if (
2807         AOP_TYPE(IC_LEFT(ic)) == AOP_REG &&
2808         AOP_TYPE(IC_RESULT(ic)) == AOP_REG &&
2809         sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
2810         
2811         if (icount > 3) {
2812             MOVA(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE,TRUE));
2813             emitcode("add","a,#0x%02x",((char) icount) & 0xff);
2814             aopPut(AOP(IC_RESULT(ic)),"a",0);
2815         } else {
2816             
2817             _startLazyDPSEvaluation();
2818             while (icount--) 
2819             {
2820                 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE,FALSE));
2821             }
2822             _endLazyDPSEvaluation();
2823         }
2824         
2825         return TRUE ;
2826     }
2827     
2828     return FALSE ;
2829 }
2830
2831 /*-----------------------------------------------------------------*/
2832 /* outBitAcc - output a bit in acc                                 */
2833 /*-----------------------------------------------------------------*/
2834 static void outBitAcc(operand *result)
2835 {
2836     symbol *tlbl = newiTempLabel(NULL);
2837     /* if the result is a bit */
2838     if (AOP_TYPE(result) == AOP_CRY){
2839         aopPut(AOP(result),"a",0);
2840     }
2841     else {
2842         emitcode("jz","%05d$",tlbl->key+100);
2843         emitcode("mov","a,%s",one);
2844         emitcode("","%05d$:",tlbl->key+100);
2845         outAcc(result);
2846     }
2847 }
2848
2849 /*-----------------------------------------------------------------*/
2850 /* genPlusBits - generates code for addition of two bits           */
2851 /*-----------------------------------------------------------------*/
2852 static void genPlusBits (iCode *ic)
2853 {
2854     D(emitcode(";", "genPlusBits "););
2855     if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){
2856         symbol *lbl = newiTempLabel(NULL);
2857         emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir);
2858         emitcode("jnb","%s,%05d$",AOP(IC_RIGHT(ic))->aopu.aop_dir,(lbl->key+100));
2859         emitcode("cpl","c");
2860         emitcode("","%05d$:",(lbl->key+100));
2861         outBitC(IC_RESULT(ic));
2862     }
2863     else{
2864         emitcode("clr","a");
2865         emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir);
2866         emitcode("rlc","a");
2867         emitcode("mov","c,%s",AOP(IC_RIGHT(ic))->aopu.aop_dir);
2868         emitcode("addc","a,#0x00");
2869         outAcc(IC_RESULT(ic));
2870     }
2871 }
2872
2873 static void adjustArithmeticResult(iCode *ic)
2874 {
2875     if (opIsGptr(IC_RESULT(ic)) &&
2876         opIsGptr(IC_LEFT(ic))   &&
2877         !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
2878     {
2879         aopPut(AOP(IC_RESULT(ic)),
2880                aopGet(AOP(IC_LEFT(ic)), GPTRSIZE - 1,FALSE,FALSE,FALSE),
2881                GPTRSIZE - 1);
2882     }
2883
2884     if (opIsGptr(IC_RESULT(ic)) &&
2885         opIsGptr(IC_RIGHT(ic))   &&
2886         !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
2887     {
2888         aopPut(AOP(IC_RESULT(ic)),
2889                aopGet(AOP(IC_RIGHT(ic)),GPTRSIZE - 1,FALSE,FALSE,FALSE),
2890                GPTRSIZE - 1);
2891     }
2892
2893     if (opIsGptr(IC_RESULT(ic))            &&
2894         AOP_SIZE(IC_LEFT(ic)) < GPTRSIZE   &&
2895         AOP_SIZE(IC_RIGHT(ic)) < GPTRSIZE  &&
2896          !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) &&
2897          !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) {
2898          char buffer[5];
2899          sprintf(buffer,"#%d",pointerCode(getSpec(operandType(IC_LEFT(ic)))));
2900          aopPut(AOP(IC_RESULT(ic)),buffer,GPTRSIZE - 1);
2901      }
2902 }
2903
2904 #define AOP_OP_3(ic) \
2905     aopOp (IC_LEFT(ic),ic,FALSE, FALSE); \
2906     aopOp (IC_RIGHT(ic),ic,FALSE, TRUE); \
2907     aopOp (IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR); \
2908     if (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR2 && \
2909         AOP_TYPE(IC_RESULT(ic)) == AOP_DPTR2) \
2910     { \
2911         /* werror(E_INTERNAL_ERROR,__FILE__,__LINE__, */ \
2912         fprintf(stderr,                                  \
2913                "Ack: three operands in far space! (%s:%d %s:%d)\n", __FILE__, __LINE__, ic->filename, ic->lineno);   \
2914     }
2915
2916 #define AOP_SET_LOCALS(ic) \
2917     left = IC_LEFT(ic); \
2918     right = IC_RIGHT(ic); \
2919     result = IC_RESULT(ic);
2920
2921 /*-----------------------------------------------------------------*/
2922 /* genPlus - generates code for addition                           */
2923 /*-----------------------------------------------------------------*/
2924 static void genPlus (iCode *ic)
2925 {
2926     int size, offset = 0;
2927     bool pushResult = FALSE;
2928     int  rSize;
2929
2930     D(emitcode(";", "genPlus "););
2931
2932     /* special cases :- */
2933
2934     aopOp (IC_LEFT(ic),ic,FALSE, TRUE);
2935     aopOp (IC_RIGHT(ic),ic,FALSE, FALSE);
2936     if ((AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR2) &&
2937         (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR))
2938     {
2939         pushResult = TRUE;
2940     }
2941     else
2942     {
2943         aopOp (IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR);
2944
2945     /* if literal, literal on the right or
2946        if left requires ACC or right is already
2947        in ACC */
2948     if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
2949         (AOP_NEEDSACC(IC_LEFT(ic))) ||
2950         AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
2951         operand *t = IC_RIGHT(ic);
2952         IC_RIGHT(ic) = IC_LEFT(ic);
2953         IC_LEFT(ic) = t;
2954     }
2955
2956     /* if both left & right are in bit
2957     space */
2958     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2959         AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
2960         genPlusBits (ic);
2961         goto release ;
2962     }
2963
2964     /* if left in bit space & right literal */
2965     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
2966         AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
2967         emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir);
2968         /* if result in bit space */
2969         if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){
2970             if((unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit) != 0L)
2971                 emitcode("cpl","c");
2972             outBitC(IC_RESULT(ic));
2973         } else {
2974             size = getDataSize(IC_RESULT(ic));
2975             _startLazyDPSEvaluation();
2976             while (size--) {
2977                 MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE,TRUE));
2978                 emitcode("addc","a,#00");
2979                 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
2980             }
2981             _endLazyDPSEvaluation();
2982         }
2983         goto release ;
2984     }
2985
2986     /* if I can do an increment instead
2987     of add then GOOD for ME */
2988     if (genPlusIncr (ic) == TRUE)
2989         goto release;   
2990
2991     }
2992     size = getDataSize(pushResult ? IC_LEFT(ic) : IC_RESULT(ic));
2993
2994     _startLazyDPSEvaluation();
2995     while(size--)
2996     {
2997         if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) 
2998         {
2999             MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE,TRUE));
3000             if(offset == 0)
3001                 emitcode("add","a,%s",
3002                          aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE,FALSE));
3003             else
3004                 emitcode("addc","a,%s",
3005                          aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE,FALSE));
3006         } else {
3007             MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE,TRUE));
3008             if(offset == 0)
3009                 emitcode("add","a,%s",
3010                          aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE,FALSE));
3011             else
3012                 emitcode("addc","a,%s",
3013                          aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE,FALSE));
3014         }
3015         if (!pushResult)
3016         {
3017             aopPut(AOP(IC_RESULT(ic)),"a",offset);
3018         }
3019         else
3020         {
3021             emitcode("push", "acc");
3022         }
3023         offset++;
3024     }
3025     _endLazyDPSEvaluation();
3026    
3027     if (pushResult)
3028     {
3029         aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
3030
3031         size = getDataSize(IC_LEFT(ic));
3032         rSize = getDataSize(IC_RESULT(ic));
3033         
3034         /* If the pushed data is bigger than the result,
3035          * simply discard unused bytes. Icky, but works.
3036          *
3037          * Should we throw a warning here? We're losing data...
3038          */
3039         while (size > rSize)
3040         {
3041            D(emitcode(";", "discarding unused result byte."););
3042            emitcode("pop", "acc");
3043            size--;
3044            offset--; 
3045         }
3046         if (size < rSize)
3047         {
3048             emitcode("clr", "a");
3049             /* Conversly, we haven't pushed enough here.
3050              * just zero-pad, and all is well. 
3051              */
3052             while (size < rSize)
3053             {
3054                 emitcode("push", "acc");
3055                 size++;
3056                 offset++;
3057             }
3058         }
3059
3060         _startLazyDPSEvaluation();
3061         while(size--)
3062         {
3063             emitcode("pop", "acc");
3064             aopPut(AOP(IC_RESULT(ic)), "a", --offset);
3065         }
3066         _endLazyDPSEvaluation();
3067     }
3068
3069     adjustArithmeticResult(ic);
3070
3071 release:
3072     freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
3073     freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
3074     freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
3075 }
3076
3077 /*-----------------------------------------------------------------*/
3078 /* genMinusDec :- does subtraction with deccrement if possible     */
3079 /*-----------------------------------------------------------------*/
3080 static bool genMinusDec (iCode *ic)
3081 {
3082     unsigned int icount ;
3083     unsigned int size = getDataSize(IC_RESULT(ic));
3084
3085     /* will try to generate an increment */
3086     /* if the right side is not a literal 
3087     we cannot */
3088     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
3089         return FALSE ;
3090
3091     /* if the literal value of the right hand side
3092     is greater than 4 then it is not worth it */
3093     if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 4)
3094         return FALSE ;
3095
3096     /* if decrement 16 bits in register */
3097     if (AOP_TYPE(IC_LEFT(ic)) == AOP_REG &&
3098         AOP_TYPE(IC_RESULT(ic)) == AOP_REG &&
3099         sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
3100         (size > 1) &&
3101         (icount == 1)) {
3102             symbol *tlbl;
3103             int emitTlbl;
3104             int labelRange;
3105
3106             /* If the next instruction is a goto and the goto target
3107          * is <= 5 instructions previous to this, we can generate
3108              * jumps straight to that target.
3109              */
3110             if (ic->next && ic->next->op == GOTO
3111                 && (labelRange = findLabelBackwards(ic, IC_LABEL(ic->next)->key)) != 0
3112                 && labelRange <= 5 )
3113             {        
3114                emitcode(";", "tail decrement optimized (range %d)", labelRange);
3115                tlbl = IC_LABEL(ic->next);
3116                emitTlbl = 0;
3117             }
3118             else
3119             {
3120                 tlbl = newiTempLabel(NULL);
3121                 emitTlbl = 1;
3122             }
3123         
3124                 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE,FALSE));
3125                 if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
3126                    AOP_TYPE(IC_RESULT(ic)) == AOP_DPTR ||
3127                    IS_AOP_PREG(IC_RESULT(ic)))
3128                         emitcode("cjne","%s,#0xff,%05d$"
3129                                          ,aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE,FALSE)
3130                                          ,tlbl->key+100);
3131                 else{
3132                         emitcode("mov","a,#0xff");
3133                         emitcode("cjne","a,%s,%05d$"
3134                                          ,aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE,FALSE)
3135                                          ,tlbl->key+100);
3136                 }
3137                 emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE,FALSE));
3138                 if (size > 2)
3139                 {
3140                         if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
3141                            AOP_TYPE(IC_RESULT(ic)) == AOP_DPTR ||
3142                            IS_AOP_PREG(IC_RESULT(ic)))
3143                                 emitcode("cjne","%s,#0xff,%05d$"
3144                                                  ,aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE,FALSE)
3145                                                  ,tlbl->key+100);
3146                         else{
3147                                 emitcode("cjne","a,%s,%05d$"
3148                                                  ,aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE,FALSE)
3149                                                  ,tlbl->key+100);
3150                         }
3151                         emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE,FALSE));
3152                 }
3153                 if (size > 3)
3154                 {
3155                         if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG ||
3156                            AOP_TYPE(IC_RESULT(ic)) == AOP_DPTR ||
3157                            IS_AOP_PREG(IC_RESULT(ic)))
3158                                 emitcode("cjne","%s,#0xff,%05d$"
3159                                                  ,aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE,FALSE)
3160                                                  ,tlbl->key+100);
3161                         else{
3162                                 emitcode("cjne","a,%s,%05d$"
3163                                                  ,aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE,FALSE)
3164                                                  ,tlbl->key+100);
3165                         }
3166                         emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB32,FALSE,FALSE,FALSE));
3167                 }
3168                 if (emitTlbl)
3169                 {
3170                     emitcode("","%05d$:",tlbl->key+100);
3171                 }
3172         return TRUE;
3173     }
3174
3175     /* if the sizes are greater than 1 then we cannot */
3176     if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
3177         AOP_SIZE(IC_LEFT(ic)) > 1   )
3178         return FALSE ;
3179
3180     /* we can if the aops of the left & result match or
3181     if they are in registers and the registers are the
3182     same */
3183     if (
3184         AOP_TYPE(IC_LEFT(ic)) == AOP_REG &&
3185         AOP_TYPE(IC_RESULT(ic)) == AOP_REG &&
3186         sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
3187
3188         _startLazyDPSEvaluation();
3189         while (icount--) 
3190         {
3191             emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE,FALSE));
3192         }
3193         _endLazyDPSEvaluation();
3194
3195         return TRUE ;
3196     }
3197
3198     return FALSE ;
3199 }
3200
3201 /*-----------------------------------------------------------------*/
3202 /* addSign - complete with sign                                    */
3203 /*-----------------------------------------------------------------*/
3204 static void addSign(operand *result, int offset, int sign)
3205 {
3206     int size = (getDataSize(result) - offset);
3207     if(size > 0){
3208         if(sign){
3209             emitcode("rlc","a");
3210             emitcode("subb","a,acc");
3211             while(size--)
3212                 aopPut(AOP(result),"a",offset++); 
3213         } else
3214             while(size--)
3215                 aopPut(AOP(result),zero,offset++);
3216     }
3217 }
3218
3219 /*-----------------------------------------------------------------*/
3220 /* genMinusBits - generates code for subtraction  of two bits      */
3221 /*-----------------------------------------------------------------*/
3222 static void genMinusBits (iCode *ic)
3223 {
3224     symbol *lbl = newiTempLabel(NULL);
3225     
3226     D(emitcode(";", "genMinusBits "););    
3227
3228     if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){
3229         emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir);
3230         emitcode("jnb","%s,%05d$",AOP(IC_RIGHT(ic))->aopu.aop_dir,(lbl->key+100));
3231         emitcode("cpl","c");
3232         emitcode("","%05d$:",(lbl->key+100));
3233         outBitC(IC_RESULT(ic));
3234     }
3235     else{
3236         emitcode("mov","c,%s",AOP(IC_RIGHT(ic))->aopu.aop_dir);
3237         emitcode("subb","a,acc");
3238         emitcode("jnb","%s,%05d$",AOP(IC_LEFT(ic))->aopu.aop_dir,(lbl->key+100));
3239         emitcode("inc","a");
3240         emitcode("","%05d$:",(lbl->key+100));
3241         aopPut(AOP(IC_RESULT(ic)),"a",0);
3242         addSign(IC_RESULT(ic), MSB16, SPEC_USIGN(getSpec(operandType(IC_RESULT(ic)))));
3243     }
3244 }
3245
3246 /*-----------------------------------------------------------------*/
3247 /* genMinus - generates code for subtraction                       */
3248 /*-----------------------------------------------------------------*/
3249 static void genMinus (iCode *ic)
3250 {
3251     int size, offset = 0;
3252     int rSize;
3253     unsigned long lit = 0L;
3254     bool pushResult = FALSE;
3255
3256     D(emitcode(";", "genMinus "););
3257
3258     aopOp (IC_LEFT(ic),ic,FALSE, FALSE);
3259     aopOp (IC_RIGHT(ic),ic,FALSE, TRUE);
3260     if ((AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR) &&
3261         (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR2))
3262     {
3263         pushResult = TRUE;
3264     }
3265     else
3266     {
3267         aopOp (IC_RESULT(ic),ic,TRUE, AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR);
3268
3269     /* special cases :- */
3270     /* if both left & right are in bit space */
3271     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
3272         AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
3273         genMinusBits (ic);
3274         goto release ;
3275     }
3276
3277     /* if I can do an decrement instead
3278     of subtract then GOOD for ME */
3279     if (genMinusDec (ic) == TRUE)
3280         goto release;
3281
3282     }
3283
3284     size = getDataSize(pushResult ? IC_LEFT(ic) : IC_RESULT(ic));
3285
3286     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
3287         CLRC;
3288     }
3289     else{
3290         lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
3291         lit = - (long)lit;
3292     }
3293
3294
3295     /* if literal, add a,#-lit, else normal subb */
3296     _startLazyDPSEvaluation();
3297     while (size--) {
3298         MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE,TRUE));
3299         if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)  
3300             emitcode("subb","a,%s",
3301                      aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE,FALSE));
3302         else{
3303             /* first add without previous c */
3304             if(!offset)
3305                 emitcode("add","a,#0x%02x",
3306                          (unsigned int)(lit & 0x0FFL));
3307             else
3308                 emitcode("addc","a,#0x%02x",
3309                          (unsigned int)((lit >> (offset*8)) & 0x0FFL));
3310         }
3311
3312         if (pushResult)
3313         {
3314             emitcode("push", "acc");
3315         }
3316         else
3317         {
3318             aopPut(AOP(IC_RESULT(ic)),"a",offset);
3319         }
3320         offset++;
3321     }
3322     _endLazyDPSEvaluation();
3323
3324     if (pushResult)
3325     {
3326         aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
3327
3328         size = getDataSize(IC_LEFT(ic));
3329         rSize = getDataSize(IC_RESULT(ic));
3330
3331         /* If the pushed data is bigger than the result,
3332          * simply discard unused bytes. Icky, but works.
3333          *
3334          * Should we throw a warning here? We're losing data...
3335          */
3336         while (size > getDataSize(IC_RESULT(ic)))
3337         {
3338            emitcode(";", "discarding unused result byte.");
3339            emitcode("pop", "acc");
3340            size--;
3341            offset--; 
3342         }
3343         if (size < rSize)
3344         {
3345             emitcode("clr", "a");
3346             /* Conversly, we haven't pushed enough here.
3347              * just zero-pad, and all is well. 
3348              */
3349             while (size < rSize)
3350             {
3351                 emitcode("push", "acc");
3352                 size++;
3353                 offset++;
3354             }
3355         }
3356
3357         while(size--)
3358         {
3359             emitcode("pop", "acc");
3360             aopPut(AOP(IC_RESULT(ic)), "a", --offset);
3361         }
3362     }
3363
3364     adjustArithmeticResult(ic);
3365         
3366 release:
3367     freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
3368     freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
3369     freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
3370 }
3371
3372
3373 /*-----------------------------------------------------------------*/
3374 /* genMultbits :- multiplication of bits                           */
3375 /*-----------------------------------------------------------------*/
3376 static void genMultbits (operand *left, 
3377                          operand *right, 
3378                          operand *result)
3379 {
3380     emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
3381     emitcode("anl","c,%s",AOP(right)->aopu.aop_dir);
3382     outBitC(result);
3383 }
3384
3385
3386 /*-----------------------------------------------------------------*/
3387 /* genMultOneByte : 8 bit multiplication & division                */
3388 /*-----------------------------------------------------------------*/
3389 static void genMultOneByte (operand *left,
3390                             operand *right,
3391                             operand *result)
3392 {
3393     link *opetype = operandType(result);
3394     char *l ;
3395     symbol *lbl ;
3396     int size,offset;
3397
3398     /* (if two literals, the value is computed before) */
3399     /* if one literal, literal on the right */
3400     if (AOP_TYPE(left) == AOP_LIT){
3401         operand *t = right;
3402         right = left;
3403         left = t;
3404     }
3405
3406     size = AOP_SIZE(result);
3407     /* signed or unsigned */
3408     emitcode("mov","b,%s", aopGet(AOP(right),0,FALSE,FALSE,FALSE));
3409     l = aopGet(AOP(left),0,FALSE,FALSE,TRUE);
3410     MOVA(l);       
3411     emitcode("mul","ab");
3412     /* if result size = 1, mul signed = mul unsigned */
3413     aopPut(AOP(result),"a",0);
3414     if (size > 1){
3415         if (SPEC_USIGN(opetype)){
3416             aopPut(AOP(result),"b",1);
3417             if (size > 2)
3418                 /* for filling the MSBs */
3419                 emitcode("clr","a");
3420         }
3421         else{
3422             emitcode("mov","a,b");
3423
3424             /* adjust the MSB if left or right neg */
3425
3426             /* if one literal */
3427             if (AOP_TYPE(right) == AOP_LIT){
3428                 /* AND literal negative */
3429                 if((int) floatFromVal (AOP(right)->aopu.aop_lit) < 0){
3430                     /* adjust MSB (c==0 after mul) */
3431                     emitcode("subb","a,%s", aopGet(AOP(left),0,FALSE,FALSE,FALSE));
3432                 }
3433             }
3434             else{
3435                 lbl = newiTempLabel(NULL);
3436                 emitcode("xch","a,%s",aopGet(AOP(right),0,FALSE,FALSE,FALSE));
3437                 emitcode("cjne","a,#0x80,%05d$", (lbl->key+100));
3438                 emitcode("","%05d$:",(lbl->key+100));
3439                 emitcode("xch","a,%s",aopGet(AOP(right),0,FALSE,FALSE,FALSE));
3440                 lbl = newiTempLabel(NULL);      
3441                 emitcode("jc","%05d$",(lbl->key+100));          
3442                 emitcode("subb","a,%s", aopGet(AOP(left),0,FALSE,FALSE,FALSE));
3443                 emitcode("","%05d$:",(lbl->key+100));
3444             }
3445
3446             lbl = newiTempLabel(NULL);
3447             emitcode("xch","a,%s",aopGet(AOP(left),0,FALSE,FALSE,FALSE));
3448             emitcode("cjne","a,#0x80,%05d$", (lbl->key+100));
3449             emitcode("","%05d$:",(lbl->key+100));
3450             emitcode("xch","a,%s",aopGet(AOP(left),0,FALSE,FALSE,FALSE));
3451             lbl = newiTempLabel(NULL);      
3452             emitcode("jc","%05d$",(lbl->key+100));          
3453             emitcode("subb","a,%s", aopGet(AOP(right),0,FALSE,FALSE,FALSE));
3454             emitcode("","%05d$:",(lbl->key+100));
3455
3456             aopPut(AOP(result),"a",1);
3457             if(size > 2){
3458                 /* get the sign */
3459                 emitcode("rlc","a");
3460                 emitcode("subb","a,acc");
3461             }
3462         }
3463         size -= 2;   
3464         offset = 2;
3465         if (size > 0)
3466             while (size--)
3467                 aopPut(AOP(result),"a",offset++);
3468     }
3469 }
3470
3471 /*-----------------------------------------------------------------*/
3472 /* genMult - generates code for multiplication                     */
3473 /*-----------------------------------------------------------------*/
3474 static void genMult (iCode *ic)
3475 {
3476     operand *left = IC_LEFT(ic);
3477     operand *right = IC_RIGHT(ic);
3478     operand *result= IC_RESULT(ic);   
3479
3480     D(emitcode(";", "genMult "););
3481
3482     /* assign the amsops */
3483     AOP_OP_3(ic);
3484 #if 0
3485     aopOp (left,ic,FALSE, FALSE);
3486     aopOp (right,ic,FALSE, TRUE);
3487     aopOp (result,ic,TRUE, FALSE);
3488 #endif
3489
3490     /* special cases first */
3491     /* both are bits */
3492     if (AOP_TYPE(left) == AOP_CRY &&
3493         AOP_TYPE(right)== AOP_CRY) {
3494         genMultbits(left,right,result);
3495         goto release ;
3496     }
3497
3498     /* if both are of size == 1 */
3499     if (AOP_SIZE(left) == 1 &&
3500         AOP_SIZE(right) == 1 ) {
3501         genMultOneByte(left,right,result);
3502         goto release ;
3503     }
3504
3505     /* should have been converted to function call */       
3506     assert(1) ;
3507
3508 release :
3509     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
3510     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
3511     freeAsmop(result,NULL,ic,TRUE); 
3512 }
3513
3514 /*-----------------------------------------------------------------*/
3515 /* genDivbits :- division of bits                                  */
3516 /*-----------------------------------------------------------------*/
3517 static void genDivbits (operand *left, 
3518                         operand *right, 
3519                         operand *result)
3520 {
3521
3522     char *l;
3523
3524     /* the result must be bit */
3525     LOAD_AB_FOR_DIV(left, right, l);
3526     emitcode("div","ab");
3527     emitcode("rrc","a");
3528     aopPut(AOP(result),"c",0);
3529 }
3530
3531 /*-----------------------------------------------------------------*/
3532 /* genDivOneByte : 8 bit division                                  */
3533 /*-----------------------------------------------------------------*/
3534 static void genDivOneByte (operand *left,
3535                            operand *right,
3536                            operand *result)
3537 {
3538     link *opetype = operandType(result);
3539     char *l ;
3540     symbol *lbl ;
3541     int size,offset;
3542
3543     size = AOP_SIZE(result) - 1;
3544     offset = 1;
3545     /* signed or unsigned */
3546     if (SPEC_USIGN(opetype)) {
3547         /* unsigned is easy */
3548         LOAD_AB_FOR_DIV(left, right, l);
3549         emitcode("div","ab");
3550         aopPut(AOP(result),"a",0);
3551         while (size--)
3552             aopPut(AOP(result),zero,offset++);
3553         return ;
3554     }
3555
3556     /* signed is a little bit more difficult */
3557
3558     /* save the signs of the operands */
3559     l = aopGet(AOP(left),0,FALSE,FALSE,TRUE);    
3560     MOVA(l);    
3561     emitcode("xrl","a,%s",aopGet(AOP(right),0,FALSE,TRUE,FALSE));
3562     emitcode("push","acc"); /* save it on the stack */
3563
3564     /* now sign adjust for both left & right */
3565     l =  aopGet(AOP(right),0,FALSE,FALSE,TRUE);
3566     MOVA(l);       
3567     lbl = newiTempLabel(NULL);
3568     emitcode("jnb","acc.7,%05d$",(lbl->key+100));   
3569     emitcode("cpl","a");   
3570     emitcode("inc","a");
3571     emitcode("","%05d$:",(lbl->key+100));
3572     emitcode("mov","b,a");
3573
3574     /* sign adjust left side */
3575     l =  aopGet(AOP(left),0,FALSE,FALSE,TRUE);
3576     MOVA(l);
3577
3578     lbl = newiTempLabel(NULL);
3579     emitcode("jnb","acc.7,%05d$",(lbl->key+100));
3580     emitcode("cpl","a");
3581     emitcode("inc","a");
3582     emitcode("","%05d$:",(lbl->key+100));
3583
3584     /* now the division */
3585     emitcode("nop", "; workaround for DS80C390 div bug.");
3586     emitcode("div","ab");
3587     /* we are interested in the lower order
3588     only */
3589     emitcode("mov","b,a");
3590     lbl = newiTempLabel(NULL);
3591     emitcode("pop","acc");   
3592     /* if there was an over flow we don't 
3593     adjust the sign of the result */
3594     emitcode("jb","ov,%05d$",(lbl->key+100));
3595     emitcode("jnb","acc.7,%05d$",(lbl->key+100));
3596     CLRC;
3597     emitcode("clr","a");
3598     emitcode("subb","a,b");
3599     emitcode("mov","b,a");
3600     emitcode("","%05d$:",(lbl->key+100));
3601
3602     /* now we are done */
3603     aopPut(AOP(result),"b",0);
3604     if(size > 0){
3605         emitcode("mov","c,b.7");
3606         emitcode("subb","a,acc");   
3607     }
3608     while (size--)
3609         aopPut(AOP(result),"a",offset++);
3610
3611 }
3612
3613 /*-----------------------------------------------------------------*/
3614 /* genDiv - generates code for division                            */
3615 /*-----------------------------------------------------------------*/
3616 static void genDiv (iCode *ic)
3617 {
3618     operand *left = IC_LEFT(ic);
3619     operand *right = IC_RIGHT(ic);
3620     operand *result= IC_RESULT(ic);   
3621
3622     D(emitcode(";", "genDiv "););
3623
3624     /* assign the amsops */
3625     AOP_OP_3(ic);
3626 #if 0
3627     aopOp (left,ic,FALSE, FALSE);
3628     aopOp (right,ic,FALSE, TRUE);
3629     aopOp (result,ic,TRUE, FALSE);
3630 #endif
3631
3632     /* special cases first */
3633     /* both are bits */
3634     if (AOP_TYPE(left) == AOP_CRY &&
3635         AOP_TYPE(right)== AOP_CRY) {
3636         genDivbits(left,right,result);
3637         goto release ;
3638     }
3639
3640     /* if both are of size == 1 */
3641     if (AOP_SIZE(left) == 1 &&
3642         AOP_SIZE(right) == 1 ) {
3643         genDivOneByte(left,right,result);
3644         goto release ;
3645     }
3646
3647     /* should have been converted to function call */
3648     assert(1);
3649 release :
3650     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
3651     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
3652     freeAsmop(result,NULL,ic,TRUE); 
3653 }
3654
3655 /*-----------------------------------------------------------------*/
3656 /* genModbits :- modulus of bits                                   */
3657 /*-----------------------------------------------------------------*/
3658 static void genModbits (operand *left, 
3659                         operand *right, 
3660                         operand *result)
3661 {
3662
3663     char *l;
3664
3665     /* the result must be bit */    
3666     LOAD_AB_FOR_DIV(left, right, l);
3667     emitcode("div","ab");
3668     emitcode("mov","a,b");
3669     emitcode("rrc","a");
3670     aopPut(AOP(result),"c",0);
3671 }
3672
3673 /*-----------------------------------------------------------------*/
3674 /* genModOneByte : 8 bit modulus                                   */
3675 /*-----------------------------------------------------------------*/
3676 static void genModOneByte (operand *left,
3677                            operand *right,
3678                            operand *result)
3679 {
3680     link *opetype = operandType(result);
3681     char *l ;
3682     symbol *lbl ;
3683
3684     /* signed or unsigned */
3685     if (SPEC_USIGN(opetype)) {
3686         /* unsigned is easy */
3687         LOAD_AB_FOR_DIV(left, right, l);
3688         emitcode("div","ab");
3689         aopPut(AOP(result),"b",0);
3690         return ;
3691     }
3692
3693     /* signed is a little bit more difficult */
3694
3695     /* save the signs of the operands */
3696     l = aopGet(AOP(left),0,FALSE,FALSE,TRUE);
3697     MOVA(l);
3698
3699     emitcode("xrl","a,%s",aopGet(AOP(right),0,FALSE,FALSE,FALSE));
3700     emitcode("push","acc"); /* save it on the stack */
3701
3702     /* now sign adjust for both left & right */
3703     l =  aopGet(AOP(right),0,FALSE,FALSE,TRUE);
3704     MOVA(l);
3705
3706     lbl = newiTempLabel(NULL);
3707     emitcode("jnb","acc.7,%05d$",(lbl->key+100));  
3708     emitcode("cpl","a");   
3709     emitcode("inc","a");
3710     emitcode("","%05d$:",(lbl->key+100));
3711     emitcode("mov","b,a"); 
3712
3713     /* sign adjust left side */
3714     l =  aopGet(AOP(left),0,FALSE,FALSE,TRUE);
3715     MOVA(l);
3716
3717     lbl = newiTempLabel(NULL);
3718     emitcode("jnb","acc.7,%05d$",(lbl->key+100));
3719     emitcode("cpl","a");   
3720     emitcode("inc","a");
3721     emitcode("","%05d$:",(lbl->key+100));
3722
3723     /* now the multiplication */
3724     emitcode("nop", "; workaround for DS80C390 div bug.");
3725     emitcode("div","ab");
3726     /* we are interested in the lower order
3727     only */
3728     lbl = newiTempLabel(NULL);
3729     emitcode("pop","acc");   
3730     /* if there was an over flow we don't 
3731     adjust the sign of the result */
3732     emitcode("jb","ov,%05d$",(lbl->key+100));
3733     emitcode("jnb","acc.7,%05d$",(lbl->key+100));
3734     CLRC ;
3735     emitcode("clr","a");
3736     emitcode("subb","a,b");
3737     emitcode("mov","b,a");
3738     emitcode("","%05d$:",(lbl->key+100));
3739
3740     /* now we are done */
3741     aopPut(AOP(result),"b",0);
3742
3743 }
3744
3745 /*-----------------------------------------------------------------*/
3746 /* genMod - generates code for division                            */
3747 /*-----------------------------------------------------------------*/
3748 static void genMod (iCode *ic)
3749 {
3750     operand *left = IC_LEFT(ic);
3751     operand *right = IC_RIGHT(ic);
3752     operand *result= IC_RESULT(ic);  
3753
3754     D(emitcode(";", "genMod "););
3755
3756     /* assign the amsops */
3757     AOP_OP_3(ic);
3758 #if 0
3759     aopOp (left,ic,FALSE, FALSE);
3760     aopOp (right,ic,FALSE, TRUE);
3761     aopOp (result,ic,TRUE, FALSE);
3762 #endif
3763
3764     /* special cases first */
3765     /* both are bits */
3766     if (AOP_TYPE(left) == AOP_CRY &&
3767         AOP_TYPE(right)== AOP_CRY) {
3768         genModbits(left,right,result);
3769         goto release ;
3770     }
3771
3772     /* if both are of size == 1 */
3773     if (AOP_SIZE(left) == 1 &&
3774         AOP_SIZE(right) == 1 ) {
3775         genModOneByte(left,right,result);
3776         goto release ;
3777     }
3778
3779     /* should have been converted to function call */
3780     assert(1);
3781
3782 release :
3783     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
3784     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
3785     freeAsmop(result,NULL,ic,TRUE); 
3786 }
3787
3788 /*-----------------------------------------------------------------*/
3789 /* genIfxJump :- will create a jump depending on the ifx           */
3790 /*-----------------------------------------------------------------*/
3791 static void genIfxJump (iCode *ic, char *jval)
3792 {
3793     symbol *jlbl ;
3794     symbol *tlbl = newiTempLabel(NULL);
3795     char *inst;
3796
3797     D(emitcode(";", "genIfxJump "););
3798
3799     /* if true label then we jump if condition
3800     supplied is true */
3801     if ( IC_TRUE(ic) ) {
3802         jlbl = IC_TRUE(ic);
3803         inst = ((strcmp(jval,"a") == 0 ? "jz" :
3804                  (strcmp(jval,"c") == 0 ? "jnc" : "jnb" )));
3805     }
3806     else {
3807         /* false label is present */
3808         jlbl = IC_FALSE(ic) ;
3809         inst = ((strcmp(jval,"a") == 0 ? "jnz" :
3810                  (strcmp(jval,"c") == 0 ? "jc" : "jb" )));              
3811     }
3812     if (strcmp(inst,"jb") == 0 || strcmp(inst,"jnb") == 0) 
3813         emitcode(inst,"%s,%05d$",jval,(tlbl->key+100));
3814     else
3815         emitcode(inst,"%05d$",tlbl->key+100);
3816     emitcode("ljmp","%05d$",jlbl->key+100);
3817     emitcode("","%05d$:",tlbl->key+100);                
3818
3819     /* mark the icode as generated */
3820     ic->generated = 1;
3821 }
3822
3823 /*-----------------------------------------------------------------*/
3824 /* genCmp :- greater or less than comparison                       */
3825 /*-----------------------------------------------------------------*/
3826 static void genCmp (operand *left,operand *right,
3827                     operand *result, iCode *ifx, int sign)
3828 {
3829     int size, offset = 0 ;
3830     unsigned long lit = 0L;
3831     bool swappedOps = FALSE;
3832
3833     D(emitcode(";", "genCmp"););
3834
3835 #if 0
3836     /* If left if lit and right isn't, swap 'em. */
3837     if (AOP_TYPE(left) == AOP_LIT &&
3838         AOP_TYPE(right) != AOP_LIT)
3839     {
3840         operand *tmp = left;
3841         left = right;
3842         right = tmp;
3843         D(emitcode(";", "kevin literal hack"););
3844         swappedOps = !swappedOps;
3845     }
3846
3847     if (AOP_NEEDSACC(right))
3848     {
3849         if (AOP_NEEDSACC(left))
3850         {
3851             werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
3852                    "both CMP operands need ACC!");
3853             exit(1);
3854         }
3855         else
3856         {
3857             operand *tmp = left;
3858             left = right;
3859             right = tmp;
3860             D(emitcode(";", "kevin ACC hack"););
3861             swappedOps = !swappedOps;
3862         }
3863     }
3864 #endif
3865
3866     /* if left & right are bit variables */
3867     if (AOP_TYPE(left) == AOP_CRY &&
3868         AOP_TYPE(right) == AOP_CRY ) {
3869         emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
3870         emitcode("anl","c,/%s",AOP(left)->aopu.aop_dir);
3871     } else {
3872         /* subtract right from left if at the
3873         end the carry flag is set then we know that
3874         left is greater than right */
3875         size = max(AOP_SIZE(left),AOP_SIZE(right));
3876
3877         /* if unsigned char cmp with lit, do cjne left,#right,zz */
3878         if((size == 1) && !sign &&
3879            (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
3880             symbol *lbl  = newiTempLabel(NULL);
3881             emitcode("cjne","%s,%s,%05d$",
3882                      aopGet(AOP(left),offset,FALSE,FALSE,FALSE),
3883                      aopGet(AOP(right),offset,FALSE,FALSE,FALSE),
3884                      lbl->key+100);
3885             emitcode("","%05d$:",lbl->key+100);
3886         } else {
3887             if(AOP_TYPE(right) == AOP_LIT){
3888                 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
3889                 /* optimize if(x < 0) or if(x >= 0) */
3890                 if(lit == 0L){
3891                     if(!sign){
3892                         CLRC;
3893                     }
3894                     else{
3895                         MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE,FALSE,TRUE));
3896                         if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx){
3897                             genIfxJump (ifx,"acc.7");
3898                             return;
3899                         }
3900                         else    
3901                             emitcode("rlc","a");
3902                     }
3903                     goto release;
3904                 }
3905             }
3906             CLRC;
3907             while (size--)
3908             {
3909                 emitcode(";", "genCmp #1: %d/%d/%d", size, sign, offset);
3910                 MOVA(aopGet(AOP(left),offset,FALSE,FALSE,TRUE));
3911                 emitcode(";", "genCmp #2");
3912                 if (sign && (size == 0))
3913                 {
3914                     emitcode(";", "genCmp #3");
3915                     emitcode("xrl","a,#0x80");
3916                     if (AOP_TYPE(right) == AOP_LIT)
3917                     {
3918                         unsigned long lit = (unsigned long)
3919                             floatFromVal(AOP(right)->aopu.aop_lit);
3920                         emitcode(";", "genCmp #3.1");
3921                         emitcode("subb","a,#0x%02x",
3922                             0x80 ^ (unsigned int)((lit >> (offset*8)) & 0x0FFL));
3923                     }
3924                     else
3925                     {
3926                         emitcode(";", "genCmp #3.2");
3927                         if (AOP_NEEDSACC(right))
3928                         {
3929                             emitcode("push", "acc");
3930                         }
3931                         emitcode("mov","b,%s",aopGet(AOP(right),offset++,
3932                                   FALSE,FALSE,FALSE));
3933                         emitcode("xrl","b,#0x80");
3934                         if (AOP_NEEDSACC(right))
3935                         {
3936                             emitcode("pop", "acc");
3937                         }
3938                         emitcode("subb","a,b");
3939                     }
3940                 }
3941                 else
3942                 {
3943                     const char *s;
3944
3945                     emitcode(";", "genCmp #4");
3946                     if (AOP_NEEDSACC(right))
3947                     {
3948                         /* Yuck!! */
3949                         emitcode(";", "genCmp #4.1");
3950                         emitcode("xch", "a, b");
3951                         MOVA(aopGet(AOP(right),offset++,FALSE,FALSE,TRUE));
3952                         emitcode("xch", "a, b");
3953                         s = "b";
3954                     }
3955                     else
3956                     {
3957                         emitcode(";", "genCmp #4.2");
3958                         s = aopGet(AOP(right),offset++,FALSE,FALSE,FALSE);
3959                     }
3960
3961                     emitcode("subb","a,%s",s);
3962                 }
3963             }
3964         }
3965     }
3966
3967 release:
3968     if (swappedOps)
3969     {
3970         D(emitcode(";","kevHack: flip carry."););
3971         emitcode("cpl", "c");
3972     }
3973
3974     if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
3975         outBitC(result);
3976     } else {
3977         /* if the result is used in the next
3978         ifx conditional branch then generate
3979         code a little differently */
3980         if (ifx )
3981             genIfxJump (ifx,"c");
3982         else
3983             outBitC(result);
3984         /* leave the result in acc */
3985     }
3986 }
3987
3988 /*-----------------------------------------------------------------*/
3989 /* genCmpGt :- greater than comparison                             */
3990 /*-----------------------------------------------------------------*/
3991 static void genCmpGt (iCode *ic, iCode *ifx)
3992 {
3993     operand *left, *right, *result;
3994     link *letype , *retype;
3995     int sign ;
3996
3997     D(emitcode(";", "genCmpGt "););
3998
3999     left = IC_LEFT(ic);
4000     right= IC_RIGHT(ic);
4001     result = IC_RESULT(ic);
4002
4003     letype = getSpec(operandType(left));
4004     retype =getSpec(operandType(right));
4005     sign =  !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
4006     /* assign the amsops */
4007     AOP_OP_3(ic);
4008 #if 0
4009     aopOp (left,ic,FALSE, TRUE);
4010     aopOp (right,ic,FALSE, FALSE);
4011     aopOp (result,ic,TRUE, FALSE);
4012 #endif
4013
4014     genCmp(right, left, result, ifx, sign);
4015
4016     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4017     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4018     freeAsmop(result,NULL,ic,TRUE); 
4019 }
4020
4021 /*-----------------------------------------------------------------*/
4022 /* genCmpLt - less than comparisons                                */
4023 /*-----------------------------------------------------------------*/
4024 static void genCmpLt (iCode *ic, iCode *ifx)
4025 {
4026     operand *left, *right, *result;
4027     link *letype , *retype;
4028     int sign ;
4029
4030     D(emitcode(";", "genCmpLt "););
4031
4032     left = IC_LEFT(ic);
4033     right= IC_RIGHT(ic);
4034     result = IC_RESULT(ic);
4035
4036     letype = getSpec(operandType(left));
4037     retype =getSpec(operandType(right));
4038     sign =  !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
4039
4040     /* assign the amsops */
4041     AOP_OP_3(ic);
4042 #if 0
4043     aopOp (left,ic,FALSE, FALSE);
4044     aopOp (right,ic,FALSE, TRUE);
4045     aopOp (result,ic,TRUE, FALSE);
4046 #endif
4047
4048     genCmp(left, right, result, ifx, sign);
4049
4050     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4051     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4052     freeAsmop(result,NULL,ic,TRUE); 
4053 }
4054
4055 /*-----------------------------------------------------------------*/
4056 /* gencjneshort - compare and jump if not equal                    */
4057 /*-----------------------------------------------------------------*/
4058 static void gencjneshort(operand *left, operand *right, symbol *lbl)
4059 {
4060     int size = max(AOP_SIZE(left),AOP_SIZE(right));
4061     int offset = 0;
4062     unsigned long lit = 0L;
4063
4064     D(emitcode(";", "gencjneshort"););
4065
4066     /* if the left side is a literal or 
4067     if the right is in a pointer register and left 
4068     is not */
4069     if ((AOP_TYPE(left) == AOP_LIT) || 
4070         (IS_AOP_PREG(right) && !IS_AOP_PREG(left))) {
4071         operand *t = right;
4072         right = left;
4073         left = t;
4074     }
4075     
4076     if(AOP_TYPE(right) == AOP_LIT)
4077         lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
4078         
4079     if (opIsGptr(left) || opIsGptr(right))
4080     {
4081         /* We are comparing a generic pointer to something.
4082          * Exclude the generic type byte from the comparison.
4083          */
4084         size--;
4085         D(emitcode(";", "cjneshort: generic ptr special case.");) 
4086     }
4087          
4088
4089     /* if the right side is a literal then anything goes */
4090     if (AOP_TYPE(right) == AOP_LIT &&
4091         AOP_TYPE(left) != AOP_DIR ) {
4092         while (size--) {
4093             char *l = aopGet(AOP(left), offset, FALSE, FALSE,TRUE);
4094             MOVA(l);
4095             emitcode("cjne","a,%s,%05d$",
4096                      aopGet(AOP(right),offset,FALSE,FALSE,FALSE),
4097                      lbl->key+100);
4098             offset++;
4099         }
4100     }
4101
4102     /* if the right side is in a register or in direct space or
4103     if the left is a pointer register & right is not */    
4104     else if (AOP_TYPE(right) == AOP_REG ||
4105              AOP_TYPE(right) == AOP_DIR || 
4106              (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) ||
4107              (IS_AOP_PREG(left) && !IS_AOP_PREG(right))) 
4108     {
4109         while (size--) 
4110         {
4111             MOVA(aopGet(AOP(left),offset,FALSE,FALSE,TRUE));
4112             if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
4113                ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
4114                 emitcode("jnz","%05d$",lbl->key+100);
4115             else
4116                 emitcode("cjne","a,%s,%05d$",
4117                          aopGet(AOP(right),offset,FALSE,TRUE,FALSE),
4118                          lbl->key+100);
4119             offset++;
4120         }
4121     } else {
4122         /* right is a pointer reg need both a & b */
4123         while(size--) {
4124             char *l = aopGet(AOP(left),offset,FALSE,FALSE,TRUE);
4125             if(strcmp(l,"b"))
4126                 emitcode("mov","b,%s",l);
4127             MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
4128             emitcode("cjne","a,b,%05d$",lbl->key+100);    
4129             offset++;
4130         }
4131     }
4132 }
4133
4134 /*-----------------------------------------------------------------*/
4135 /* gencjne - compare and jump if not equal                         */
4136 /*-----------------------------------------------------------------*/
4137 static void gencjne(operand *left, operand *right, symbol *lbl)
4138 {
4139     symbol *tlbl  = newiTempLabel(NULL);
4140
4141     D(emitcode(";", "gencjne"););
4142
4143     gencjneshort(left, right, lbl);
4144
4145     emitcode("mov","a,%s",one);
4146     emitcode("sjmp","%05d$",tlbl->key+100);
4147     emitcode("","%05d$:",lbl->key+100);
4148     emitcode("clr","a");
4149     emitcode("","%05d$:",tlbl->key+100);
4150 }
4151
4152 /*-----------------------------------------------------------------*/
4153 /* genCmpEq - generates code for equal to                          */
4154 /*-----------------------------------------------------------------*/
4155 static void genCmpEq (iCode *ic, iCode *ifx)
4156 {
4157     operand *left, *right, *result;
4158
4159     D(emitcode(";", "genCmpEq "););
4160
4161     AOP_OP_3(ic);
4162     AOP_SET_LOCALS(ic);
4163 #if 0
4164     aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
4165     aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
4166     aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
4167 #endif
4168
4169     /* if literal, literal on the right or 
4170     if the right is in a pointer register and left 
4171     is not */
4172     if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) || 
4173         (IS_AOP_PREG(right) && !IS_AOP_PREG(left))) {
4174         operand *t = IC_RIGHT(ic);
4175         IC_RIGHT(ic) = IC_LEFT(ic);
4176         IC_LEFT(ic) = t;
4177     }
4178
4179     if(ifx && !AOP_SIZE(result)){
4180         symbol *tlbl;
4181         /* if they are both bit variables */
4182         if (AOP_TYPE(left) == AOP_CRY &&
4183             ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
4184             if(AOP_TYPE(right) == AOP_LIT){
4185                 unsigned long lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
4186                 if(lit == 0L){
4187                     emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
4188                     emitcode("cpl","c");
4189                 } else if(lit == 1L) {
4190                     emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
4191                 } else {
4192                     emitcode("clr","c");
4193                 }
4194                 /* AOP_TYPE(right) == AOP_CRY */
4195             } else {
4196                 symbol *lbl = newiTempLabel(NULL);
4197                 emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
4198                 emitcode("jb","%s,%05d$",AOP(right)->aopu.aop_dir,(lbl->key+100));
4199                 emitcode("cpl","c");
4200                 emitcode("","%05d$:",(lbl->key+100));
4201             }
4202             /* if true label then we jump if condition
4203             supplied is true */
4204             tlbl = newiTempLabel(NULL);
4205             if ( IC_TRUE(ifx) ) {
4206                 emitcode("jnc","%05d$",tlbl->key+100);
4207                 emitcode("ljmp","%05d$",IC_TRUE(ifx)->key+100);
4208             } else {
4209                 emitcode("jc","%05d$",tlbl->key+100);
4210                 emitcode("ljmp","%05d$",IC_FALSE(ifx)->key+100);
4211             }
4212             emitcode("","%05d$:",tlbl->key+100);                
4213         } else {
4214             tlbl = newiTempLabel(NULL);
4215             gencjneshort(left, right, tlbl);
4216             if ( IC_TRUE(ifx) ) {
4217                 emitcode("ljmp","%05d$",IC_TRUE(ifx)->key+100);
4218                 emitcode("","%05d$:",tlbl->key+100);                
4219             } else {
4220                 symbol *lbl = newiTempLabel(NULL);
4221                 emitcode("sjmp","%05d$",lbl->key+100);
4222                 emitcode("","%05d$:",tlbl->key+100);                
4223                 emitcode("ljmp","%05d$",IC_FALSE(ifx)->key+100);
4224                 emitcode("","%05d$:",lbl->key+100);             
4225             }
4226         }
4227         /* mark the icode as generated */
4228         ifx->generated = 1;
4229         goto release ;
4230     }
4231
4232     /* if they are both bit variables */
4233     if (AOP_TYPE(left) == AOP_CRY &&
4234         ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
4235         if(AOP_TYPE(right) == AOP_LIT){
4236             unsigned long lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
4237             if(lit == 0L){
4238                 emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
4239                 emitcode("cpl","c");
4240             } else if(lit == 1L) {
4241                 emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
4242             } else {
4243                 emitcode("clr","c");
4244             }
4245             /* AOP_TYPE(right) == AOP_CRY */
4246         } else {
4247             symbol *lbl = newiTempLabel(NULL);
4248             emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
4249             emitcode("jb","%s,%05d$",AOP(right)->aopu.aop_dir,(lbl->key+100));
4250             emitcode("cpl","c");
4251             emitcode("","%05d$:",(lbl->key+100));
4252         }
4253         /* c = 1 if egal */
4254         if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)){
4255             outBitC(result);
4256             goto release ;
4257         }
4258         if (ifx) {
4259             genIfxJump (ifx,"c");
4260             goto release ;
4261         }
4262         /* if the result is used in an arithmetic operation
4263         then put the result in place */
4264         outBitC(result);
4265     } else {
4266         gencjne(left,right,newiTempLabel(NULL));    
4267         if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
4268             aopPut(AOP(result),"a",0);
4269             goto release ;
4270         }
4271         if (ifx) {
4272             genIfxJump (ifx,"a");
4273             goto release ;
4274         }
4275         /* if the result is used in an arithmetic operation
4276         then put the result in place */
4277         if (AOP_TYPE(result) != AOP_CRY) 
4278             outAcc(result);
4279         /* leave the result in acc */
4280     }
4281
4282 release:
4283     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4284     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4285     freeAsmop(result,NULL,ic,TRUE);
4286 }
4287
4288 /*-----------------------------------------------------------------*/
4289 /* ifxForOp - returns the icode containing the ifx for operand     */
4290 /*-----------------------------------------------------------------*/
4291 static iCode *ifxForOp ( operand *op, iCode *ic )
4292 {
4293     /* if true symbol then needs to be assigned */
4294     if (IS_TRUE_SYMOP(op))
4295         return NULL ;
4296
4297     /* if this has register type condition and
4298     the next instruction is ifx with the same operand
4299     and live to of the operand is upto the ifx only then */
4300     if (ic->next &&
4301         ic->next->op == IFX &&
4302         IC_COND(ic->next)->key == op->key &&
4303         OP_SYMBOL(op)->liveTo <= ic->next->seq )
4304         return ic->next;
4305
4306     return NULL;
4307 }
4308 /*-----------------------------------------------------------------*/
4309 /* genAndOp - for && operation                                     */
4310 /*-----------------------------------------------------------------*/
4311 static void genAndOp (iCode *ic)
4312 {
4313     operand *left,*right, *result;
4314     symbol *tlbl;
4315
4316     D(emitcode(";", "genAndOp "););
4317
4318     /* note here that && operations that are in an
4319     if statement are taken away by backPatchLabels
4320     only those used in arthmetic operations remain */
4321     AOP_OP_3(ic);
4322     AOP_SET_LOCALS(ic);
4323 #if 0
4324     aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
4325     aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
4326     aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
4327 #endif
4328
4329     /* if both are bit variables */
4330     if (AOP_TYPE(left) == AOP_CRY &&
4331         AOP_TYPE(right) == AOP_CRY ) {
4332         emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
4333         emitcode("anl","c,%s",AOP(right)->aopu.aop_dir);
4334         outBitC(result);
4335     } else {
4336         tlbl = newiTempLabel(NULL);
4337         toBoolean(left);    
4338         emitcode("jz","%05d$",tlbl->key+100);
4339         toBoolean(right);
4340         emitcode("","%05d$:",tlbl->key+100);
4341         outBitAcc(result);
4342     }
4343
4344     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4345     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4346     freeAsmop(result,NULL,ic,TRUE);
4347 }
4348
4349
4350 /*-----------------------------------------------------------------*/
4351 /* genOrOp - for || operation                                      */
4352 /*-----------------------------------------------------------------*/
4353 static void genOrOp (iCode *ic)
4354 {
4355     operand *left,*right, *result;
4356     symbol *tlbl;
4357
4358     D(emitcode(";", "genOrOp "););
4359
4360     /* note here that || operations that are in an
4361     if statement are taken away by backPatchLabels
4362     only those used in arthmetic operations remain */
4363     AOP_OP_3(ic);
4364     AOP_SET_LOCALS(ic);
4365 #if 0
4366     aopOp((left=IC_LEFT(ic)),ic,FALSE, FALSE);
4367     aopOp((right=IC_RIGHT(ic)),ic,FALSE, TRUE);
4368     aopOp((result=IC_RESULT(ic)),ic,FALSE, FALSE);
4369 #endif
4370
4371     /* if both are bit variables */
4372     if (AOP_TYPE(left) == AOP_CRY &&
4373         AOP_TYPE(right) == AOP_CRY ) {
4374         emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
4375         emitcode("orl","c,%s",AOP(right)->aopu.aop_dir);
4376         outBitC(result);
4377     } else {
4378         tlbl = newiTempLabel(NULL);
4379         toBoolean(left);
4380         emitcode("jnz","%05d$",tlbl->key+100);
4381         toBoolean(right);
4382         emitcode("","%05d$:",tlbl->key+100);
4383         outBitAcc(result);
4384     }
4385
4386     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4387     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4388     freeAsmop(result,NULL,ic,TRUE);            
4389 }
4390
4391 /*-----------------------------------------------------------------*/
4392 /* isLiteralBit - test if lit == 2^n                               */
4393 /*-----------------------------------------------------------------*/
4394 static int isLiteralBit(unsigned long lit)
4395 {
4396     unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
4397     0x100L,0x200L,0x400L,0x800L,
4398     0x1000L,0x2000L,0x4000L,0x8000L,
4399     0x10000L,0x20000L,0x40000L,0x80000L,
4400     0x100000L,0x200000L,0x400000L,0x800000L,
4401     0x1000000L,0x2000000L,0x4000000L,0x8000000L,
4402     0x10000000L,0x20000000L,0x40000000L,0x80000000L};
4403     int idx;
4404     
4405     for(idx = 0; idx < 32; idx++)
4406         if(lit == pw[idx])
4407             return idx+1;
4408     return 0;
4409 }
4410
4411 /*-----------------------------------------------------------------*/
4412 /* continueIfTrue -                                                */
4413 /*-----------------------------------------------------------------*/
4414 static void continueIfTrue (iCode *ic)
4415 {
4416     if(IC_TRUE(ic))
4417         emitcode("ljmp","%05d$",IC_TRUE(ic)->key+100);
4418     ic->generated = 1;
4419 }
4420
4421 /*-----------------------------------------------------------------*/
4422 /* jmpIfTrue -                                                     */
4423 /*-----------------------------------------------------------------*/
4424 static void jumpIfTrue (iCode *ic)
4425 {
4426     if(!IC_TRUE(ic))
4427         emitcode("ljmp","%05d$",IC_FALSE(ic)->key+100);
4428     ic->generated = 1;
4429 }
4430
4431 /*-----------------------------------------------------------------*/
4432 /* jmpTrueOrFalse -                                                */
4433 /*-----------------------------------------------------------------*/
4434 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
4435 {
4436     // ugly but optimized by peephole
4437     if(IC_TRUE(ic)){
4438         symbol *nlbl = newiTempLabel(NULL);
4439         emitcode("sjmp","%05d$",nlbl->key+100);                 
4440         emitcode("","%05d$:",tlbl->key+100);
4441         emitcode("ljmp","%05d$",IC_TRUE(ic)->key+100);
4442         emitcode("","%05d$:",nlbl->key+100);
4443     }
4444     else{
4445         emitcode("ljmp","%05d$",IC_FALSE(ic)->key+100);
4446         emitcode("","%05d$:",tlbl->key+100);
4447     }
4448     ic->generated = 1;
4449 }
4450
4451 /*-----------------------------------------------------------------*/
4452 /* genAnd  - code for and                                          */
4453 /*-----------------------------------------------------------------*/
4454 static void genAnd (iCode *ic, iCode *ifx)
4455 {
4456     operand *left, *right, *result;
4457     int size, offset=0;  
4458     unsigned long lit = 0L;
4459     int bytelit = 0;
4460     char buffer[10];
4461
4462     D(emitcode(";", "genAnd "););
4463
4464     AOP_OP_3(ic);
4465     AOP_SET_LOCALS(ic);
4466 #if 0
4467     aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
4468     aopOp((right= IC_RIGHT(ic)),ic,FALSE, TRUE);
4469     aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
4470 #endif
4471
4472 #ifdef DEBUG_TYPE
4473     emitcode("","; Type res[%d] = l[%d]&r[%d]",
4474              AOP_TYPE(result),
4475              AOP_TYPE(left), AOP_TYPE(right));
4476     emitcode("","; Size res[%d] = l[%d]&r[%d]",
4477              AOP_SIZE(result),
4478              AOP_SIZE(left), AOP_SIZE(right));
4479 #endif
4480
4481     /* if left is a literal & right is not then exchange them */
4482     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
4483         AOP_NEEDSACC(left)) {
4484         operand *tmp = right ;
4485         right = left;
4486         left = tmp;
4487     }
4488
4489     /* if result = right then exchange them */
4490     if(sameRegs(AOP(result),AOP(right))){
4491         operand *tmp = right ;
4492         right = left;
4493         left = tmp;
4494     }
4495
4496     /* if right is bit then exchange them */
4497     if (AOP_TYPE(right) == AOP_CRY &&
4498         AOP_TYPE(left) != AOP_CRY){
4499         operand *tmp = right ;
4500         right = left;
4501         left = tmp;
4502     }
4503     if(AOP_TYPE(right) == AOP_LIT)
4504         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
4505
4506     size = AOP_SIZE(result);
4507
4508     // if(bit & yy)
4509     // result = bit & yy;
4510     if (AOP_TYPE(left) == AOP_CRY){
4511         // c = bit & literal;
4512         if(AOP_TYPE(right) == AOP_LIT){
4513             if(lit & 1) {
4514                 if(size && sameRegs(AOP(result),AOP(left)))
4515                     // no change
4516                     goto release;
4517                 emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
4518             } else {
4519                 // bit(result) = 0;
4520                 if(size && (AOP_TYPE(result) == AOP_CRY)){
4521                     emitcode("clr","%s",AOP(result)->aopu.aop_dir);
4522                     goto release;
4523                 }
4524                 if((AOP_TYPE(result) == AOP_CRY) && ifx){
4525                     jumpIfTrue(ifx);
4526                     goto release;
4527                 }
4528                 emitcode("clr","c");
4529             }
4530         } else {
4531             if (AOP_TYPE(right) == AOP_CRY){
4532                 // c = bit & bit;
4533                 emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
4534                 emitcode("anl","c,%s",AOP(left)->aopu.aop_dir);
4535             } else {
4536                 // c = bit & val;
4537                 MOVA(aopGet(AOP(right),0,FALSE,FALSE,TRUE));
4538                 // c = lsb
4539                 emitcode("rrc","a");
4540                 emitcode("anl","c,%s",AOP(left)->aopu.aop_dir);
4541             }
4542         }
4543         // bit = c
4544         // val = c
4545         if(size)
4546             outBitC(result);
4547         // if(bit & ...)
4548         else if((AOP_TYPE(result) == AOP_CRY) && ifx)
4549             genIfxJump(ifx, "c");           
4550         goto release ;
4551     }
4552
4553     // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
4554     // bit = val & 0xZZ     - size = 1, ifx = FALSE -
4555     if((AOP_TYPE(right) == AOP_LIT) &&
4556        (AOP_TYPE(result) == AOP_CRY) &&
4557        (AOP_TYPE(left) != AOP_CRY)){
4558         int posbit = isLiteralBit(lit);
4559         /* left &  2^n */
4560         if(posbit){
4561             posbit--;
4562             MOVA(aopGet(AOP(left),posbit>>3,FALSE,FALSE,TRUE));
4563             // bit = left & 2^n
4564             if(size)
4565                 emitcode("mov","c,acc.%d",posbit&0x07);
4566             // if(left &  2^n)
4567             else{
4568                 if(ifx){
4569                     sprintf(buffer,"acc.%d",posbit&0x07);
4570                     genIfxJump(ifx, buffer);
4571                 }
4572                 goto release;
4573             }
4574         } else {
4575             symbol *tlbl = newiTempLabel(NULL);
4576             int sizel = AOP_SIZE(left);
4577             if(size)
4578                 emitcode("setb","c");
4579             while(sizel--){
4580                 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
4581                     MOVA( aopGet(AOP(left),offset,FALSE,FALSE,TRUE));
4582                     // byte ==  2^n ?
4583                     if((posbit = isLiteralBit(bytelit)) != 0)
4584                         emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
4585                     else{
4586                         if(bytelit != 0x0FFL)
4587                             emitcode("anl","a,%s",
4588                                      aopGet(AOP(right),offset,FALSE,TRUE,FALSE));
4589                         emitcode("jnz","%05d$",tlbl->key+100);
4590                     }
4591                 }
4592                 offset++;
4593             }
4594             // bit = left & literal
4595             if(size){
4596                 emitcode("clr","c");
4597                 emitcode("","%05d$:",tlbl->key+100);
4598             }
4599             // if(left & literal)
4600             else{
4601                 if(ifx)
4602                     jmpTrueOrFalse(ifx, tlbl);
4603                 goto release ;
4604             }
4605         }
4606         outBitC(result);
4607         goto release ;
4608     }
4609
4610     /* if left is same as result */
4611     if(sameRegs(AOP(result),AOP(left))){
4612         for(;size--; offset++) {
4613             if(AOP_TYPE(right) == AOP_LIT){
4614                 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
4615                     continue;
4616                 else 
4617                     if (bytelit == 0)
4618                         aopPut(AOP(result),zero,offset);
4619                     else 
4620                         if (IS_AOP_PREG(result)) {
4621                             MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
4622                             emitcode("anl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE,FALSE));
4623                             aopPut(AOP(result),"a",offset);
4624                         } else
4625                             emitcode("anl","%s,%s",
4626                                      aopGet(AOP(left),offset,FALSE,TRUE,FALSE),
4627                                      aopGet(AOP(right),offset,FALSE,FALSE,FALSE));
4628             } else {
4629                 if (AOP_TYPE(left) == AOP_ACC)
4630                     emitcode("anl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE,FALSE));
4631                 else {
4632                     MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
4633                     if (IS_AOP_PREG(result)) {
4634                         emitcode("anl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE,FALSE));
4635                         aopPut(AOP(result),"a",offset);
4636
4637                     } else
4638                         emitcode("anl","%s,a",
4639                                  aopGet(AOP(left),offset,FALSE,TRUE,FALSE));
4640                 }
4641             }
4642         }
4643     } else {
4644         // left & result in different registers
4645         if(AOP_TYPE(result) == AOP_CRY){
4646             // result = bit
4647             // if(size), result in bit
4648             // if(!size && ifx), conditional oper: if(left & right)
4649             symbol *tlbl = newiTempLabel(NULL);
4650             int sizer = min(AOP_SIZE(left),AOP_SIZE(right));
4651             if(size)
4652                 emitcode("setb","c");
4653             while(sizer--){
4654                 MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
4655                 emitcode("anl","a,%s",
4656                          aopGet(AOP(left),offset,FALSE,FALSE,FALSE));
4657                 emitcode("jnz","%05d$",tlbl->key+100);
4658                 offset++;
4659             }
4660             if(size){
4661                 CLRC;
4662                 emitcode("","%05d$:",tlbl->key+100);
4663                 outBitC(result);
4664             } else if(ifx)
4665                 jmpTrueOrFalse(ifx, tlbl);
4666         } else {
4667             for(;(size--);offset++) {
4668                 // normal case
4669                 // result = left & right
4670                 if(AOP_TYPE(right) == AOP_LIT){
4671                     if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
4672                         aopPut(AOP(result),
4673                                aopGet(AOP(left),offset,FALSE,FALSE,FALSE),
4674                                offset);
4675                         continue;
4676                     } else if(bytelit == 0){
4677                         aopPut(AOP(result),zero,offset);
4678                         continue;
4679                     }
4680                 }
4681                 // faster than result <- left, anl result,right
4682                 // and better if result is SFR
4683                 if (AOP_TYPE(left) == AOP_ACC) 
4684                     emitcode("anl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE,FALSE));
4685                 else {
4686                     MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
4687                     emitcode("anl","a,%s",
4688                              aopGet(AOP(left),offset,FALSE,FALSE,FALSE));
4689                 }
4690                 aopPut(AOP(result),"a",offset);
4691             }
4692         }
4693     }
4694
4695 release :
4696     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4697     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4698     freeAsmop(result,NULL,ic,TRUE);     
4699 }
4700
4701 /*-----------------------------------------------------------------*/
4702 /* genOr  - code for or                                            */
4703 /*-----------------------------------------------------------------*/
4704 static void genOr (iCode *ic, iCode *ifx)
4705 {
4706     operand *left, *right, *result;
4707     int size, offset=0;
4708     unsigned long lit = 0L;
4709
4710     D(emitcode(";", "genOr "););
4711
4712     AOP_OP_3(ic);
4713     AOP_SET_LOCALS(ic);
4714     #if 0
4715     aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
4716     aopOp((right= IC_RIGHT(ic)),ic,FALSE, TRUE);
4717     aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
4718     #endif
4719
4720 #ifdef DEBUG_TYPE
4721     emitcode("","; Type res[%d] = l[%d]&r[%d]",
4722              AOP_TYPE(result),
4723              AOP_TYPE(left), AOP_TYPE(right));
4724     emitcode("","; Size res[%d] = l[%d]&r[%d]",
4725              AOP_SIZE(result),
4726              AOP_SIZE(left), AOP_SIZE(right));
4727 #endif
4728
4729     /* if left is a literal & right is not then exchange them */
4730     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
4731         AOP_NEEDSACC(left)) {
4732         operand *tmp = right ;
4733         right = left;
4734         left = tmp;
4735     }
4736
4737     /* if result = right then exchange them */
4738     if(sameRegs(AOP(result),AOP(right))){
4739         operand *tmp = right ;
4740         right = left;
4741         left = tmp;
4742     }
4743
4744     /* if right is bit then exchange them */
4745     if (AOP_TYPE(right) == AOP_CRY &&
4746         AOP_TYPE(left) != AOP_CRY){
4747         operand *tmp = right ;
4748         right = left;
4749         left = tmp;
4750     }
4751     if(AOP_TYPE(right) == AOP_LIT)
4752         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
4753
4754     size = AOP_SIZE(result);
4755
4756     // if(bit | yy)
4757     // xx = bit | yy;
4758     if (AOP_TYPE(left) == AOP_CRY){
4759         if(AOP_TYPE(right) == AOP_LIT){
4760             // c = bit & literal;
4761             if(lit){
4762                 // lit != 0 => result = 1
4763                 if(AOP_TYPE(result) == AOP_CRY){
4764                     if(size)
4765                         emitcode("setb","%s",AOP(result)->aopu.aop_dir);
4766                     else if(ifx)
4767                         continueIfTrue(ifx);
4768                     goto release;
4769                 }
4770                 emitcode("setb","c");
4771             } else {
4772                 // lit == 0 => result = left
4773                 if(size && sameRegs(AOP(result),AOP(left)))
4774                     goto release;
4775                 emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
4776             }
4777         } else {
4778             if (AOP_TYPE(right) == AOP_CRY){
4779                 // c = bit | bit;
4780                 emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
4781                 emitcode("orl","c,%s",AOP(left)->aopu.aop_dir);
4782             }
4783             else{
4784                 // c = bit | val;
4785                 symbol *tlbl = newiTempLabel(NULL);
4786                 if(!((AOP_TYPE(result) == AOP_CRY) && ifx))
4787                     emitcode("setb","c");
4788                 emitcode("jb","%s,%05d$",
4789                          AOP(left)->aopu.aop_dir,tlbl->key+100);
4790                 toBoolean(right);
4791                 emitcode("jnz","%05d$",tlbl->key+100);
4792                 if((AOP_TYPE(result) == AOP_CRY) && ifx){
4793                     jmpTrueOrFalse(ifx, tlbl);
4794                     goto release;
4795                 } else {
4796                     CLRC;
4797                     emitcode("","%05d$:",tlbl->key+100);
4798                 }
4799             }
4800         }
4801         // bit = c
4802         // val = c
4803         if(size)
4804             outBitC(result);
4805         // if(bit | ...)
4806         else if((AOP_TYPE(result) == AOP_CRY) && ifx)
4807             genIfxJump(ifx, "c");           
4808         goto release ;
4809     }
4810
4811     // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
4812     // bit = val | 0xZZ     - size = 1, ifx = FALSE -
4813     if((AOP_TYPE(right) == AOP_LIT) &&
4814        (AOP_TYPE(result) == AOP_CRY) &&
4815        (AOP_TYPE(left) != AOP_CRY)){
4816         if(lit){
4817             // result = 1
4818             if(size)
4819                 emitcode("setb","%s",AOP(result)->aopu.aop_dir);
4820             else 
4821                 continueIfTrue(ifx);
4822             goto release;
4823         } else {
4824             // lit = 0, result = boolean(left)
4825             if(size)
4826                 emitcode("setb","c");
4827             toBoolean(right);
4828             if(size){
4829                 symbol *tlbl = newiTempLabel(NULL);
4830                 emitcode("jnz","%05d$",tlbl->key+100);
4831                 CLRC;
4832                 emitcode("","%05d$:",tlbl->key+100);
4833             } else {
4834                 genIfxJump (ifx,"a");
4835                 goto release;
4836             }
4837         }
4838         outBitC(result);
4839         goto release ;
4840     }
4841
4842     /* if left is same as result */
4843     if(sameRegs(AOP(result),AOP(left))){
4844         for(;size--; offset++) {
4845             if(AOP_TYPE(right) == AOP_LIT){
4846                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
4847                     continue;
4848                 else 
4849                     if (IS_AOP_PREG(left)) {
4850                         MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
4851                         emitcode("orl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE,FALSE));
4852                         aopPut(AOP(result),"a",offset);
4853                     } else
4854                         emitcode("orl","%s,%s",
4855                                  aopGet(AOP(left),offset,FALSE,TRUE,FALSE),
4856                                  aopGet(AOP(right),offset,FALSE,FALSE,FALSE));
4857             } else {
4858                 if (AOP_TYPE(left) == AOP_ACC) 
4859                     emitcode("orl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE,FALSE));
4860                 else {              
4861                     MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
4862                     if (IS_AOP_PREG(left)) {
4863                         emitcode("orl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE,FALSE));
4864                         aopPut(AOP(result),"a",offset);
4865                     } else
4866                         emitcode("orl","%s,a",
4867                                  aopGet(AOP(left),offset,FALSE,TRUE,FALSE));
4868                 }
4869             }
4870         }
4871     } else {
4872         // left & result in different registers
4873         if(AOP_TYPE(result) == AOP_CRY){
4874             // result = bit
4875             // if(size), result in bit
4876             // if(!size && ifx), conditional oper: if(left | right)
4877             symbol *tlbl = newiTempLabel(NULL);
4878             int sizer = max(AOP_SIZE(left),AOP_SIZE(right));
4879             if(size)
4880                 emitcode("setb","c");
4881             while(sizer--){
4882                 MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
4883                 emitcode("orl","a,%s",
4884                          aopGet(AOP(left),offset,FALSE,FALSE,FALSE));
4885                 emitcode("jnz","%05d$",tlbl->key+100);
4886                 offset++;
4887             }
4888             if(size){
4889                 CLRC;
4890                 emitcode("","%05d$:",tlbl->key+100);
4891                 outBitC(result);
4892             } else if(ifx)
4893                 jmpTrueOrFalse(ifx, tlbl);
4894         } else for(;(size--);offset++){
4895             // normal case
4896             // result = left & right
4897             if(AOP_TYPE(right) == AOP_LIT){
4898                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
4899                     aopPut(AOP(result),
4900                            aopGet(AOP(left),offset,FALSE,FALSE,FALSE),
4901                            offset);
4902                     continue;
4903                 }
4904             }
4905             // faster than result <- left, anl result,right
4906             // and better if result is SFR
4907             if (AOP_TYPE(left) == AOP_ACC) 
4908                 emitcode("orl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE,FALSE));
4909             else {
4910                 MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
4911                 emitcode("orl","a,%s",
4912                          aopGet(AOP(left),offset,FALSE,FALSE,FALSE));
4913             }
4914             aopPut(AOP(result),"a",offset);                     
4915         }
4916     }
4917
4918 release :
4919     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4920     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
4921     freeAsmop(result,NULL,ic,TRUE);     
4922 }
4923
4924 /*-----------------------------------------------------------------*/
4925 /* genXor - code for xclusive or                                   */
4926 /*-----------------------------------------------------------------*/
4927 static void genXor (iCode *ic, iCode *ifx)
4928 {
4929     operand *left, *right, *result;
4930     int size, offset=0;
4931     unsigned long lit = 0L;
4932
4933     D(emitcode(";", "genXor "););
4934
4935     AOP_OP_3(ic);
4936     AOP_SET_LOCALS(ic);
4937 #if 0
4938     aopOp((left = IC_LEFT(ic)),ic,FALSE, FALSE);
4939     aopOp((right= IC_RIGHT(ic)),ic,FALSE, TRUE);
4940     aopOp((result=IC_RESULT(ic)),ic,TRUE, FALSE);
4941 #endif
4942
4943 #ifdef DEBUG_TYPE
4944     emitcode("","; Type res[%d] = l[%d]&r[%d]",
4945              AOP_TYPE(result),
4946              AOP_TYPE(left), AOP_TYPE(right));
4947     emitcode("","; Size res[%d] = l[%d]&r[%d]",
4948              AOP_SIZE(result),
4949              AOP_SIZE(left), AOP_SIZE(right));
4950 #endif
4951
4952     /* if left is a literal & right is not ||
4953        if left needs acc & right does not */
4954     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
4955         (AOP_NEEDSACC(left) && !AOP_NEEDSACC(right))) {
4956         operand *tmp = right ;
4957         right = left;
4958         left = tmp;
4959     }
4960
4961     /* if result = right then exchange them */
4962     if(sameRegs(AOP(result),AOP(right))){
4963         operand *tmp = right ;
4964         right = left;
4965         left = tmp;
4966     }
4967
4968     /* if right is bit then exchange them */
4969     if (AOP_TYPE(right) == AOP_CRY &&
4970         AOP_TYPE(left) != AOP_CRY){
4971         operand *tmp = right ;
4972         right = left;
4973         left = tmp;
4974     }
4975     if(AOP_TYPE(right) == AOP_LIT)
4976         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
4977
4978     size = AOP_SIZE(result);
4979
4980     // if(bit ^ yy)
4981     // xx = bit ^ yy;
4982     if (AOP_TYPE(left) == AOP_CRY){
4983         if(AOP_TYPE(right) == AOP_LIT){
4984             // c = bit & literal;
4985             if(lit>>1){
4986                 // lit>>1  != 0 => result = 1
4987                 if(AOP_TYPE(result) == AOP_CRY){
4988                     if(size)
4989                         emitcode("setb","%s",AOP(result)->aopu.aop_dir);
4990                     else if(ifx)
4991                         continueIfTrue(ifx);
4992                     goto release;
4993                 }
4994                 emitcode("setb","c");
4995             } else{
4996                 // lit == (0 or 1)
4997                 if(lit == 0){
4998                     // lit == 0, result = left
4999                     if(size && sameRegs(AOP(result),AOP(left)))
5000                         goto release;
5001                     emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
5002                 } else{
5003                     // lit == 1, result = not(left)
5004                     if(size && sameRegs(AOP(result),AOP(left))){
5005                         emitcode("cpl","%s",AOP(result)->aopu.aop_dir);
5006                         goto release;
5007                     } else {
5008                         emitcode("mov","c,%s",AOP(left)->aopu.aop_dir);
5009                         emitcode("cpl","c");
5010                     }
5011                 }
5012             }
5013
5014         } else {
5015             // right != literal
5016             symbol *tlbl = newiTempLabel(NULL);
5017             if (AOP_TYPE(right) == AOP_CRY){
5018                 // c = bit ^ bit;
5019                 emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
5020             }
5021             else{
5022                 int sizer = AOP_SIZE(right);
5023                 // c = bit ^ val
5024                 // if val>>1 != 0, result = 1
5025                 emitcode("setb","c");
5026                 while(sizer){
5027                     MOVA(aopGet(AOP(right),sizer-1,FALSE,FALSE,TRUE));
5028                     if(sizer == 1)
5029                         // test the msb of the lsb
5030                         emitcode("anl","a,#0xfe");
5031                     emitcode("jnz","%05d$",tlbl->key+100);
5032                     sizer--;
5033                 }
5034                 // val = (0,1)
5035                 emitcode("rrc","a");
5036             }
5037             emitcode("jnb","%s,%05d$",AOP(left)->aopu.aop_dir,(tlbl->key+100));
5038             emitcode("cpl","c");
5039             emitcode("","%05d$:",(tlbl->key+100));
5040         }
5041         // bit = c
5042         // val = c
5043         if(size)
5044             outBitC(result);
5045         // if(bit | ...)
5046         else if((AOP_TYPE(result) == AOP_CRY) && ifx)
5047             genIfxJump(ifx, "c");           
5048         goto release ;
5049     }
5050
5051     if(sameRegs(AOP(result),AOP(left))){
5052         /* if left is same as result */
5053         for(;size--; offset++) {
5054             if(AOP_TYPE(right) == AOP_LIT){
5055                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
5056                     continue;
5057                 else
5058                     if (IS_AOP_PREG(left)) {
5059                         MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
5060                         emitcode("xrl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE,FALSE));
5061                         aopPut(AOP(result),"a",offset);
5062                     } else 
5063                         emitcode("xrl","%s,%s",
5064                                  aopGet(AOP(left),offset,FALSE,TRUE,FALSE),
5065                                  aopGet(AOP(right),offset,FALSE,FALSE,FALSE));
5066             } else {
5067                 if (AOP_TYPE(left) == AOP_ACC)
5068                     emitcode("xrl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE,FALSE));
5069                 else {
5070                     MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
5071                     if (IS_AOP_PREG(left)) {
5072                         emitcode("xrl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE,FALSE));
5073                         aopPut(AOP(result),"a",offset);
5074                     } else
5075                         emitcode("xrl","%s,a",
5076                                  aopGet(AOP(left),offset,FALSE,TRUE,FALSE));
5077                 }
5078             }
5079         }
5080     } else {
5081         // left & result in different registers
5082         if(AOP_TYPE(result) == AOP_CRY){
5083             // result = bit
5084             // if(size), result in bit
5085             // if(!size && ifx), conditional oper: if(left ^ right)
5086             symbol *tlbl = newiTempLabel(NULL);
5087             int sizer = max(AOP_SIZE(left),AOP_SIZE(right));
5088             if(size)
5089                 emitcode("setb","c");
5090             while(sizer--){
5091                 if((AOP_TYPE(right) == AOP_LIT) &&
5092                    (((lit >> (offset*8)) & 0x0FFL) == 0x00L)){
5093                     MOVA(aopGet(AOP(left),offset,FALSE,FALSE,TRUE));
5094                 } else {
5095                     MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
5096                     emitcode("xrl","a,%s",
5097                              aopGet(AOP(left),offset,FALSE,FALSE,FALSE));
5098                 }
5099                 emitcode("jnz","%05d$",tlbl->key+100);
5100                 offset++;
5101             }
5102             if(size){
5103                 CLRC;
5104                 emitcode("","%05d$:",tlbl->key+100);
5105                 outBitC(result);
5106             } else if(ifx)
5107                 jmpTrueOrFalse(ifx, tlbl);
5108         } else for(;(size--);offset++){
5109             // normal case
5110             // result = left & right
5111             if(AOP_TYPE(right) == AOP_LIT){
5112                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
5113                     aopPut(AOP(result),
5114                            aopGet(AOP(left),offset,FALSE,FALSE,FALSE),
5115                            offset);
5116                     continue;
5117                 }
5118             }
5119             // faster than result <- left, anl result,right
5120             // and better if result is SFR
5121             if (AOP_TYPE(left) == AOP_ACC)
5122                 emitcode("xrl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE,FALSE));
5123             else {
5124                 MOVA(aopGet(AOP(right),offset,FALSE,FALSE,TRUE));
5125                 emitcode("xrl","a,%s",
5126                          aopGet(AOP(left),offset,FALSE,TRUE,FALSE));
5127             }
5128             aopPut(AOP(result),"a",offset);
5129         }
5130     }
5131
5132 release :
5133     freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
5134     freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
5135     freeAsmop(result,NULL,ic,TRUE);     
5136 }
5137
5138 /*-----------------------------------------------------------------*/
5139 /* genInline - write the inline code out                           */
5140 /*-----------------------------------------------------------------*/
5141 static void genInline (iCode *ic)
5142 {
5143     char buffer[MAX_INLINEASM];
5144     char *bp = buffer;
5145     char *bp1= buffer;
5146     
5147     D(emitcode(";", "genInline "););
5148
5149     _G.inLine += (!options.asmpeep);
5150     strcpy(buffer,IC_INLINE(ic));
5151
5152     /* emit each line as a code */
5153     while (*bp) {
5154         if (*bp == '\n') {
5155             *bp++ = '\0';
5156             emitcode(bp1,"");
5157             bp1 = bp;
5158         } else {
5159             if (*bp == ':') {
5160                 bp++;
5161                 *bp = '\0';
5162                 bp++;
5163                 emitcode(bp1,"");
5164                 bp1 = bp;
5165             } else
5166                 bp++;
5167         }
5168     }
5169     if (bp1 != bp)
5170         emitcode(bp1,"");
5171     /*     emitcode("",buffer); */
5172     _G.inLine -= (!options.asmpeep);
5173 }
5174
5175 /*-----------------------------------------------------------------*/
5176 /* genRRC - rotate right with carry                                */
5177 /*-----------------------------------------------------------------*/
5178 static void genRRC (iCode *ic)
5179 {
5180     operand *left , *result ;
5181     int size, offset = 0;
5182     char *l;    
5183
5184     D(emitcode(";", "genRRC "););
5185
5186     /* rotate right with carry */
5187     left = IC_LEFT(ic);
5188     result=IC_RESULT(ic);
5189     aopOp (left,ic,FALSE, FALSE);
5190     aopOp (result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
5191
5192     /* move it to the result */
5193     size = AOP_SIZE(result);    
5194     offset = size - 1 ;
5195     CLRC;
5196     
5197     _startLazyDPSEvaluation();
5198     while (size--) {
5199         l = aopGet(AOP(left),offset,FALSE,FALSE,TRUE);
5200         MOVA(l);
5201         emitcode("rrc","a");
5202         if (AOP_SIZE(result) > 1)
5203             aopPut(AOP(result),"a",offset--);
5204     }
5205     _endLazyDPSEvaluation();
5206     
5207     /* now we need to put the carry into the
5208     highest order byte of the result */
5209     if (AOP_SIZE(result) > 1) {
5210         l = aopGet(AOP(result),AOP_SIZE(result)-1,FALSE,FALSE,TRUE);
5211         MOVA(l);
5212     }
5213     emitcode("mov","acc.7,c");
5214     aopPut(AOP(result),"a",AOP_SIZE(result)-1);
5215     freeAsmop(left,NULL,ic,TRUE);
5216     freeAsmop(result,NULL,ic,TRUE);
5217 }
5218
5219 /*-----------------------------------------------------------------*/
5220 /* genRLC - generate code for rotate left with carry               */
5221 /*-----------------------------------------------------------------*/
5222 static void genRLC (iCode *ic)
5223 {    
5224     operand *left , *result ;
5225     int size, offset = 0;
5226     char *l;    
5227
5228     D(emitcode(";", "genRLC "););
5229
5230     /* rotate right with carry */
5231     left = IC_LEFT(ic);
5232     result=IC_RESULT(ic);
5233     aopOp (left,ic,FALSE, FALSE);
5234     aopOp (result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
5235
5236     /* move it to the result */
5237     size = AOP_SIZE(result);    
5238     offset = 0 ;
5239     if (size--) {
5240         l = aopGet(AOP(left),offset,FALSE,FALSE,TRUE);
5241         MOVA(l);
5242         emitcode("add","a,acc");
5243         if (AOP_SIZE(result) > 1)
5244         {
5245             aopPut(AOP(result),"a",offset++);
5246         }
5247             
5248         _startLazyDPSEvaluation();
5249         while (size--) {
5250             l = aopGet(AOP(left),offset,FALSE,FALSE,TRUE);
5251             MOVA(l);
5252             emitcode("rlc","a");
5253             if (AOP_SIZE(result) > 1)
5254                 aopPut(AOP(result),"a",offset++);
5255         }
5256         _endLazyDPSEvaluation();
5257     }
5258     /* now we need to put the carry into the
5259     highest order byte of the result */
5260     if (AOP_SIZE(result) > 1) {
5261         l = aopGet(AOP(result),0,FALSE,FALSE,TRUE);
5262         MOVA(l);
5263     }
5264     emitcode("mov","acc.0,c");
5265     aopPut(AOP(result),"a",0);
5266     freeAsmop(left,NULL,ic,TRUE);
5267     freeAsmop(result,NULL,ic,TRUE);
5268 }
5269
5270 /*-----------------------------------------------------------------*/
5271 /* genGetHbit - generates code get highest order bit               */
5272 /*-----------------------------------------------------------------*/
5273 static void genGetHbit (iCode *ic)
5274 {
5275     operand *left, *result;
5276     left = IC_LEFT(ic);
5277     result=IC_RESULT(ic);
5278     aopOp (left,ic,FALSE, FALSE);
5279     aopOp (result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
5280
5281     D(emitcode(";", "genGetHbit "););
5282
5283     /* get the highest order byte into a */
5284     MOVA(aopGet(AOP(left),AOP_SIZE(left) - 1,FALSE,FALSE,TRUE));
5285     if(AOP_TYPE(result) == AOP_CRY){
5286         emitcode("rlc","a");
5287         outBitC(result);
5288     }
5289     else{
5290         emitcode("rl","a");
5291         emitcode("anl","a,#0x01");
5292         outAcc(result);
5293     }
5294
5295
5296     freeAsmop(left,NULL,ic,TRUE);
5297     freeAsmop(result,NULL,ic,TRUE);
5298 }
5299
5300 /*-----------------------------------------------------------------*/
5301 /* AccRol - rotate left accumulator by known count                 */
5302 /*-----------------------------------------------------------------*/
5303 static void AccRol (int shCount)
5304 {
5305     shCount &= 0x0007;              // shCount : 0..7
5306     switch(shCount){
5307         case 0 :
5308             break;
5309         case 1 :
5310             emitcode("rl","a");
5311             break;
5312         case 2 :
5313             emitcode("rl","a");
5314             emitcode("rl","a");
5315             break;
5316         case 3 :
5317             emitcode("swap","a");
5318             emitcode("rr","a");
5319             break;
5320         case 4 :
5321             emitcode("swap","a");
5322             break;
5323         case 5 :
5324             emitcode("swap","a");
5325             emitcode("rl","a");
5326             break;
5327         case 6 :
5328             emitcode("rr","a");
5329             emitcode("rr","a");
5330             break;
5331         case 7 :
5332             emitcode("rr","a");
5333             break;
5334     }
5335 }
5336
5337 /*-----------------------------------------------------------------*/
5338 /* AccLsh - left shift accumulator by known count                  */
5339 /*-----------------------------------------------------------------*/
5340 static void AccLsh (int shCount)
5341 {
5342     if(shCount != 0){
5343         if(shCount == 1)
5344             emitcode("add","a,acc");
5345         else 
5346             if(shCount == 2) {
5347             emitcode("add","a,acc");
5348             emitcode("add","a,acc");
5349         } else {
5350             /* rotate left accumulator */
5351             AccRol(shCount);
5352             /* and kill the lower order bits */
5353             emitcode("anl","a,#0x%02x", SLMask[shCount]);
5354         }
5355     }
5356 }
5357
5358 /*-----------------------------------------------------------------*/
5359 /* AccRsh - right shift accumulator by known count                 */
5360 /*-----------------------------------------------------------------*/
5361 static void AccRsh (int shCount)
5362 {
5363     if(shCount != 0){
5364         if(shCount == 1){
5365             CLRC;
5366             emitcode("rrc","a");
5367         } else {
5368             /* rotate right accumulator */
5369             AccRol(8 - shCount);
5370             /* and kill the higher order bits */
5371             emitcode("anl","a,#0x%02x", SRMask[shCount]);
5372         }
5373     }
5374 }
5375
5376 /*-----------------------------------------------------------------*/
5377 /* AccSRsh - signed right shift accumulator by known count                 */
5378 /*-----------------------------------------------------------------*/
5379 static void AccSRsh (int shCount)
5380 {
5381     symbol *tlbl ;
5382     if(shCount != 0){
5383         if(shCount == 1){
5384             emitcode("mov","c,acc.7");
5385             emitcode("rrc","a");
5386         } else if(shCount == 2){
5387             emitcode("mov","c,acc.7");
5388             emitcode("rrc","a");
5389             emitcode("mov","c,acc.7");
5390             emitcode("rrc","a");
5391         } else {
5392             tlbl = newiTempLabel(NULL);
5393             /* rotate right accumulator */
5394             AccRol(8 - shCount);
5395             /* and kill the higher order bits */
5396             emitcode("anl","a,#0x%02x", SRMask[shCount]);
5397             emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100);
5398             emitcode("orl","a,#0x%02x",
5399                      (unsigned char)~SRMask[shCount]);
5400             emitcode("","%05d$:",tlbl->key+100);
5401         }
5402     }
5403 }
5404
5405 /*-----------------------------------------------------------------*/
5406 /* shiftR1Left2Result - shift right one byte from left to result   */
5407 /*-----------------------------------------------------------------*/
5408 static void shiftR1Left2Result (operand *left, int offl,
5409                                 operand *result, int offr,
5410                                 int shCount, int sign)
5411 {
5412     MOVA(aopGet(AOP(left),offl,FALSE,FALSE,TRUE));
5413     /* shift right accumulator */
5414     if(sign)
5415         AccSRsh(shCount);
5416     else
5417         AccRsh(shCount);
5418     aopPut(AOP(result),"a",offr);
5419 }
5420
5421 /*-----------------------------------------------------------------*/
5422 /* shiftL1Left2Result - shift left one byte from left to result    */
5423 /*-----------------------------------------------------------------*/
5424 static void shiftL1Left2Result (operand *left, int offl,
5425                                 operand *result, int offr, int shCount)
5426 {
5427     char *l;
5428     l = aopGet(AOP(left),offl,FALSE,FALSE,TRUE);
5429     MOVA(l);
5430     /* shift left accumulator */
5431     AccLsh(shCount);
5432     aopPut(AOP(result),"a",offr);
5433 }
5434
5435 /*-----------------------------------------------------------------*/
5436 /* movLeft2Result - move byte from left to result                  */
5437 /*-----------------------------------------------------------------*/
5438 static void movLeft2Result (operand *left, int offl,
5439                             operand *result, int offr, int sign)
5440 {
5441     char *l;
5442     if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
5443         l = aopGet(AOP(left),offl,FALSE,FALSE,FALSE);
5444
5445         if (*l == '@' && (IS_AOP_PREG(result))) {
5446             emitcode("mov","a,%s",l);
5447             aopPut(AOP(result),"a",offr);
5448         } else {
5449             if(!sign)
5450                 aopPut(AOP(result),l,offr);
5451             else{
5452                 /* MSB sign in acc.7 ! */
5453                 if(getDataSize(left) == offl+1){
5454                     emitcode("mov","a,%s",l);
5455                     aopPut(AOP(result),"a",offr);
5456                 }
5457             }
5458         }
5459     }
5460 }
5461
5462 /*-----------------------------------------------------------------*/
5463 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
5464 /*-----------------------------------------------------------------*/
5465 static void AccAXRrl1 (char *x)
5466 {
5467     emitcode("rrc","a");
5468     emitcode("xch","a,%s", x);
5469     emitcode("rrc","a");
5470     emitcode("xch","a,%s", x);
5471 }
5472
5473 /*-----------------------------------------------------------------*/
5474 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
5475 /*-----------------------------------------------------------------*/
5476 static void AccAXLrl1 (char *x)
5477 {
5478     emitcode("xch","a,%s",x);
5479     emitcode("rlc","a");
5480     emitcode("xch","a,%s",x);
5481     emitcode("rlc","a");
5482 }
5483
5484 /*-----------------------------------------------------------------*/
5485 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
5486 /*-----------------------------------------------------------------*/
5487 static void AccAXLsh1 (char *x)
5488 {
5489     emitcode("xch","a,%s",x);
5490     emitcode("add","a,acc");
5491     emitcode("xch","a,%s",x);
5492     emitcode("rlc","a");
5493 }
5494
5495 /*-----------------------------------------------------------------*/
5496 /* AccAXLsh - left shift a:x by known count (0..7)                 */
5497 /*-----------------------------------------------------------------*/
5498 static void AccAXLsh (char *x, int shCount)
5499 {
5500     switch(shCount){
5501         case 0 :
5502             break;
5503         case 1 :
5504             AccAXLsh1(x);
5505             break;
5506         case 2 :
5507             AccAXLsh1(x);
5508             AccAXLsh1(x);
5509             break;
5510         case 3 :
5511         case 4 :
5512         case 5 :                        // AAAAABBB:CCCCCDDD
5513             AccRol(shCount);            // BBBAAAAA:CCCCCDDD
5514             emitcode("anl","a,#0x%02x",
5515                      SLMask[shCount]);  // BBB00000:CCCCCDDD
5516             emitcode("xch","a,%s",x);   // CCCCCDDD:BBB00000
5517             AccRol(shCount);            // DDDCCCCC:BBB00000
5518             emitcode("xch","a,%s",x);   // BBB00000:DDDCCCCC
5519             emitcode("xrl","a,%s",x);   // (BBB^DDD)CCCCC:DDDCCCCC
5520             emitcode("xch","a,%s",x);   // DDDCCCCC:(BBB^DDD)CCCCC
5521             emitcode("anl","a,#0x%02x",
5522                      SLMask[shCount]);  // DDD00000:(BBB^DDD)CCCCC
5523             emitcode("xch","a,%s",x);   // (BBB^DDD)CCCCC:DDD00000
5524             emitcode("xrl","a,%s",x);   // BBBCCCCC:DDD00000            
5525             break;
5526         case 6 :                        // AAAAAABB:CCCCCCDD
5527             emitcode("anl","a,#0x%02x",
5528                      SRMask[shCount]);  // 000000BB:CCCCCCDD
5529             emitcode("mov","c,acc.0");  // c = B
5530             emitcode("xch","a,%s",x);   // CCCCCCDD:000000BB
5531             AccAXRrl1(x);               // BCCCCCCD:D000000B
5532             AccAXRrl1(x);               // BBCCCCCC:DD000000
5533             break;
5534         case 7 :                        // a:x <<= 7
5535             emitcode("anl","a,#0x%02x",
5536                      SRMask[shCount]);  // 0000000B:CCCCCCCD
5537             emitcode("mov","c,acc.0");  // c = B
5538             emitcode("xch","a,%s",x);   // CCCCCCCD:0000000B
5539             AccAXRrl1(x);               // BCCCCCCC:D0000000
5540             break;
5541         default :
5542             break;
5543     }
5544 }
5545
5546 /*-----------------------------------------------------------------*/
5547 /* AccAXRsh - right shift a:x known count (0..7)                   */
5548 /*-----------------------------------------------------------------*/
5549 static void AccAXRsh (char *x, int shCount)
5550 {   
5551     switch(shCount){
5552         case 0 :
5553             break;
5554         case 1 :
5555             CLRC;
5556             AccAXRrl1(x);               // 0->a:x
5557             break;
5558         case 2 :
5559             CLRC;
5560             AccAXRrl1(x);               // 0->a:x
5561             CLRC;
5562             AccAXRrl1(x);               // 0->a:x
5563             break;
5564         case 3 :
5565         case 4 :
5566         case 5 :                        // AAAAABBB:CCCCCDDD = a:x
5567             AccRol(8 - shCount);        // BBBAAAAA:DDDCCCCC
5568             emitcode("xch","a,%s",x);   // CCCCCDDD:BBBAAAAA
5569             AccRol(8 - shCount);        // DDDCCCCC:BBBAAAAA
5570             emitcode("anl","a,#0x%02x",
5571                      SRMask[shCount]);  // 000CCCCC:BBBAAAAA
5572             emitcode("xrl","a,%s",x);   // BBB(CCCCC^AAAAA):BBBAAAAA
5573             emitcode("xch","a,%s",x);   // BBBAAAAA:BBB(CCCCC^AAAAA)
5574             emitcode("anl","a,#0x%02x",
5575                      SRMask[shCount]);  // 000AAAAA:BBB(CCCCC^AAAAA)
5576             emitcode("xch","a,%s",x);   // BBB(CCCCC^AAAAA):000AAAAA
5577             emitcode("xrl","a,%s",x);   // BBBCCCCC:000AAAAA
5578             emitcode("xch","a,%s",x);   // 000AAAAA:BBBCCCCC
5579             break;
5580         case 6 :                        // AABBBBBB:CCDDDDDD
5581             emitcode("mov","c,acc.7");
5582             AccAXLrl1(x);               // ABBBBBBC:CDDDDDDA
5583             AccAXLrl1(x);               // BBBBBBCC:DDDDDDAA
5584             emitcode("xch","a,%s",x);   // DDDDDDAA:BBBBBBCC
5585             emitcode("anl","a,#0x%02x",
5586                      SRMask[shCount]);  // 000000AA:BBBBBBCC
5587             break;
5588         case 7 :                        // ABBBBBBB:CDDDDDDD
5589             emitcode("mov","c,acc.7");  // c = A
5590             AccAXLrl1(x);               // BBBBBBBC:DDDDDDDA
5591             emitcode("xch","a,%s",x);   // DDDDDDDA:BBBBBBCC
5592             emitcode("anl","a,#0x%02x",
5593                      SRMask[shCount]);  // 0000000A:BBBBBBBC
5594             break;
5595         default :
5596             break;
5597     }
5598 }
5599
5600 /*-----------------------------------------------------------------*/
5601 /* AccAXRshS - right shift signed a:x known count (0..7)           */
5602 /*-----------------------------------------------------------------*/
5603 static void AccAXRshS (char *x, int shCount)
5604 {   
5605     symbol *tlbl ;
5606     switch(shCount){
5607         case 0 :
5608             break;
5609         case 1 :
5610             emitcode("mov","c,acc.7");
5611             AccAXRrl1(x);               // s->a:x
5612             break;
5613         case 2 :
5614             emitcode("mov","c,acc.7");
5615             AccAXRrl1(x);               // s->a:x
5616             emitcode("mov","c,acc.7");
5617             AccAXRrl1(x);               // s->a:x
5618             break;
5619         case 3 :
5620         case 4 :
5621         case 5 :                        // AAAAABBB:CCCCCDDD = a:x
5622             tlbl = newiTempLabel(NULL);
5623             AccRol(8 - shCount);        // BBBAAAAA:CCCCCDDD
5624             emitcode("xch","a,%s",x);   // CCCCCDDD:BBBAAAAA
5625             AccRol(8 - shCount);        // DDDCCCCC:BBBAAAAA
5626             emitcode("anl","a,#0x%02x",
5627                      SRMask[shCount]);  // 000CCCCC:BBBAAAAA
5628             emitcode("xrl","a,%s",x);   // BBB(CCCCC^AAAAA):BBBAAAAA
5629             emitcode("xch","a,%s",x);   // BBBAAAAA:BBB(CCCCC^AAAAA)
5630             emitcode("anl","a,#0x%02x",
5631                      SRMask[shCount]);  // 000AAAAA:BBB(CCCCC^AAAAA)
5632             emitcode("xch","a,%s",x);   // BBB(CCCCC^AAAAA):000AAAAA
5633             emitcode("xrl","a,%s",x);   // BBBCCCCC:000AAAAA
5634             emitcode("xch","a,%s",x);   // 000SAAAA:BBBCCCCC
5635             emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100); 
5636             emitcode("orl","a,#0x%02x",
5637                      (unsigned char)~SRMask[shCount]);  // 111AAAAA:BBBCCCCC
5638             emitcode("","%05d$:",tlbl->key+100);
5639             break;                      // SSSSAAAA:BBBCCCCC
5640         case 6 :                        // AABBBBBB:CCDDDDDD
5641             tlbl = newiTempLabel(NULL);
5642             emitcode("mov","c,acc.7");
5643             AccAXLrl1(x);               // ABBBBBBC:CDDDDDDA
5644             AccAXLrl1(x);               // BBBBBBCC:DDDDDDAA
5645             emitcode("xch","a,%s",x);   // DDDDDDAA:BBBBBBCC
5646             emitcode("anl","a,#0x%02x",
5647                      SRMask[shCount]);  // 000000AA:BBBBBBCC
5648             emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100); 
5649             emitcode("orl","a,#0x%02x",
5650                      (unsigned char)~SRMask[shCount]);  // 111111AA:BBBBBBCC
5651             emitcode("","%05d$:",tlbl->key+100);
5652             break;
5653         case 7 :                        // ABBBBBBB:CDDDDDDD
5654             tlbl = newiTempLabel(NULL);
5655             emitcode("mov","c,acc.7");  // c = A
5656             AccAXLrl1(x);               // BBBBBBBC:DDDDDDDA
5657             emitcode("xch","a,%s",x);   // DDDDDDDA:BBBBBBCC
5658             emitcode("anl","a,#0x%02x",
5659                      SRMask[shCount]);  // 0000000A:BBBBBBBC
5660             emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100); 
5661             emitcode("orl","a,#0x%02x",
5662                      (unsigned char)~SRMask[shCount]);  // 1111111A:BBBBBBBC
5663             emitcode("","%05d$:",tlbl->key+100);
5664             break;
5665         default :
5666             break;
5667     }
5668 }
5669
5670 /*-----------------------------------------------------------------*/
5671 /* shiftL2Left2Result - shift left two bytes from left to result   */
5672 /*-----------------------------------------------------------------*/
5673 static void shiftL2Left2Result (operand *left, int offl,
5674                                 operand *result, int offr, int shCount)
5675 {
5676     if(sameRegs(AOP(result), AOP(left)) &&
5677        ((offl + MSB16) == offr)){
5678         /* don't crash result[offr] */
5679         MOVA(aopGet(AOP(left),offl,FALSE,FALSE,TRUE));
5680         emitcode("xch","a,%s", aopGet(AOP(left),offl+MSB16,FALSE,FALSE,FALSE));
5681     } else {
5682         movLeft2Result(left,offl, result, offr, 0);
5683         MOVA(aopGet(AOP(left),offl+MSB16,FALSE,FALSE,TRUE));
5684     }
5685     /* ax << shCount (x = lsb(result))*/
5686     AccAXLsh( aopGet(AOP(result),offr,FALSE,FALSE,FALSE), shCount);
5687     aopPut(AOP(result),"a",offr+MSB16);
5688 }
5689
5690
5691 /*-----------------------------------------------------------------*/
5692 /* shiftR2Left2Result - shift right two bytes from left to result  */
5693 /*-----------------------------------------------------------------*/
5694 static void shiftR2Left2Result (operand *left, int offl,
5695                                 operand *result, int offr,
5696                                 int shCount, int sign)
5697 {
5698     if(sameRegs(AOP(result), AOP(left)) &&
5699        ((offl + MSB16) == offr)){
5700         /* don't crash result[offr] */
5701         MOVA(aopGet(AOP(left),offl,FALSE,FALSE,TRUE));
5702         emitcode("xch","a,%s", aopGet(AOP(left),offl+MSB16,FALSE,FALSE,FALSE));
5703     } else {
5704         movLeft2Result(left,offl, result, offr, 0);
5705         MOVA(aopGet(AOP(left),offl+MSB16,FALSE,FALSE,TRUE));
5706     }
5707     /* a:x >> shCount (x = lsb(result))*/
5708     if(sign)
5709         AccAXRshS( aopGet(AOP(result),offr,FALSE,FALSE,FALSE) , shCount);
5710     else
5711         AccAXRsh( aopGet(AOP(result),offr,FALSE,FALSE,FALSE) , shCount);
5712     if(getDataSize(result) > 1)
5713         aopPut(AOP(result),"a",offr+MSB16);
5714 }
5715
5716 /*-----------------------------------------------------------------*/
5717 /* shiftLLeftOrResult - shift left one byte from left, or to result*/
5718 /*-----------------------------------------------------------------*/
5719 static void shiftLLeftOrResult (operand *left, int offl,
5720                                 operand *result, int offr, int shCount)
5721 {
5722     MOVA(aopGet(AOP(left),offl,FALSE,FALSE,TRUE));
5723     /* shift left accumulator */
5724     AccLsh(shCount);
5725     /* or with result */
5726     emitcode("orl","a,%s", aopGet(AOP(result),offr,FALSE,FALSE,FALSE));
5727     /* back to result */
5728     aopPut(AOP(result),"a",offr);
5729 }
5730
5731 /*-----------------------------------------------------------------*/
5732 /* shiftRLeftOrResult - shift right one byte from left,or to result*/
5733 /*-----------------------------------------------------------------*/
5734 static void shiftRLeftOrResult (operand *left, int offl,
5735                                 operand *result, int offr, int shCount)
5736 {
5737     MOVA(aopGet(AOP(left),offl,FALSE,FALSE,TRUE));
5738     /* shift right accumulator */
5739     AccRsh(shCount);
5740     /* or with result */
5741     emitcode("orl","a,%s", aopGet(AOP(result),offr,FALSE,FALSE,FALSE));
5742     /* back to result */
5743     aopPut(AOP(result),"a",offr);
5744 }
5745
5746 /*-----------------------------------------------------------------*/
5747 /* genlshOne - left shift a one byte quantity by known count       */
5748 /*-----------------------------------------------------------------*/
5749 static void genlshOne (operand *result, operand *left, int shCount)
5750 {       
5751     D(emitcode(";", "genlshOne "););
5752     shiftL1Left2Result(left, LSB, result, LSB, shCount);
5753 }
5754
5755 /*-----------------------------------------------------------------*/
5756 /* genlshTwo - left shift two bytes by known amount != 0           */
5757 /*-----------------------------------------------------------------*/
5758 static void genlshTwo (operand *result,operand *left, int shCount)
5759 {
5760     int size;
5761     
5762     D(emitcode(";", "genlshTwo "););
5763
5764     size = getDataSize(result);
5765
5766     /* if shCount >= 8 */
5767     if (shCount >= 8) {
5768         shCount -= 8 ;
5769
5770         if (size > 1){
5771             if (shCount)
5772                 shiftL1Left2Result(left, LSB, result, MSB16, shCount);
5773             else 
5774                 movLeft2Result(left, LSB, result, MSB16, 0);
5775         }
5776         aopPut(AOP(result),zero,LSB);   
5777     }
5778
5779     /*  1 <= shCount <= 7 */
5780     else {  
5781         if(size == 1)
5782             shiftL1Left2Result(left, LSB, result, LSB, shCount); 
5783         else 
5784             shiftL2Left2Result(left, LSB, result, LSB, shCount);
5785     }
5786 }
5787
5788 /*-----------------------------------------------------------------*/
5789 /* shiftLLong - shift left one long from left to result            */
5790 /* offl = LSB or MSB16                                             */
5791 /*-----------------------------------------------------------------*/
5792 static void shiftLLong (operand *left, operand *result, int offr )
5793 {
5794     char *l;
5795     int size = AOP_SIZE(result);
5796
5797     if(size >= LSB+offr){
5798         l = aopGet(AOP(left),LSB,FALSE,FALSE,TRUE);
5799         MOVA(l);
5800         emitcode("add","a,acc");
5801         if (sameRegs(AOP(left),AOP(result)) && 
5802             size >= MSB16+offr && offr != LSB )
5803             emitcode("xch","a,%s",
5804                      aopGet(AOP(left),LSB+offr,FALSE,FALSE,FALSE));
5805         else        
5806             aopPut(AOP(result),"a",LSB+offr);
5807     }
5808
5809     if(size >= MSB16+offr){
5810         if (!(sameRegs(AOP(result),AOP(left)) && size >= MSB16+offr && offr != LSB) ) {
5811             l = aopGet(AOP(left),MSB16,FALSE,FALSE,TRUE);
5812             MOVA(l);
5813         }
5814         emitcode("rlc","a");
5815         if (sameRegs(AOP(left),AOP(result)) && 
5816             size >= MSB24+offr && offr != LSB)
5817             emitcode("xch","a,%s",
5818                      aopGet(AOP(left),MSB16+offr,FALSE,FALSE,FALSE));
5819         else        
5820             aopPut(AOP(result),"a",MSB16+offr);
5821     }
5822
5823     if(size >= MSB24+offr){
5824         if (!(sameRegs(AOP(left),AOP(left)) && size >= MSB24+offr && offr != LSB)) {
5825             l = aopGet(AOP(left),MSB24,FALSE,FALSE,TRUE);
5826             MOVA(l);
5827         }
5828         emitcode("rlc","a");
5829         if (sameRegs(AOP(left),AOP(result)) && 
5830             size >= MSB32+offr && offr != LSB )
5831             emitcode("xch","a,%s",
5832                      aopGet(AOP(left),MSB24+offr,FALSE,FALSE,FALSE));
5833         else        
5834             aopPut(AOP(result),"a",MSB24+offr);
5835     }
5836
5837     if(size > MSB32+offr){
5838         if (!(sameRegs(AOP(result),AOP(left)) && size >= MSB32+offr && offr != LSB)) {
5839             l = aopGet(AOP(left),MSB32,FALSE,FALSE,TRUE);
5840             MOVA(l);    
5841         }
5842         emitcode("rlc","a");
5843         aopPut(AOP(result),"a",MSB32+offr);
5844     }
5845     if(offr != LSB)
5846         aopPut(AOP(result),zero,LSB);       
5847 }
5848
5849 /*-----------------------------------------------------------------*/
5850 /* genlshFour - shift four byte by a known amount != 0             */
5851 /*-----------------------------------------------------------------*/
5852 static void genlshFour (operand *result, operand *left, int shCount)
5853 {
5854     int size;
5855
5856     D(emitcode(";", "genlshFour "););
5857
5858     size = AOP_SIZE(result);
5859
5860     /* if shifting more that 3 bytes */
5861     if (shCount >= 24 ) {
5862         shCount -= 24;
5863         if (shCount)
5864             /* lowest order of left goes to the highest
5865             order of the destination */
5866             shiftL1Left2Result(left, LSB, result, MSB32, shCount);
5867         else
5868             movLeft2Result(left, LSB, result, MSB32, 0);
5869         aopPut(AOP(result),zero,LSB);
5870         aopPut(AOP(result),zero,MSB16);
5871         aopPut(AOP(result),zero,MSB32);
5872         return;
5873     }
5874
5875     /* more than two bytes */
5876     else if ( shCount >= 16 ) {
5877         /* lower order two bytes goes to higher order two bytes */
5878         shCount -= 16;
5879         /* if some more remaining */
5880         if (shCount)
5881             shiftL2Left2Result(left, LSB, result, MSB24, shCount);
5882         else {
5883             movLeft2Result(left, MSB16, result, MSB32, 0);
5884             movLeft2Result(left, LSB, result, MSB24, 0);
5885         }
5886         aopPut(AOP(result),zero,MSB16);
5887         aopPut(AOP(result),zero,LSB);
5888         return;
5889     }    
5890
5891     /* if more than 1 byte */
5892     else if ( shCount >= 8 ) {
5893         /* lower order three bytes goes to higher order  three bytes */
5894         shCount -= 8;
5895         if(size == 2){
5896             if(shCount)
5897                 shiftL1Left2Result(left, LSB, result, MSB16, shCount);
5898             else
5899                 movLeft2Result(left, LSB, result, MSB16, 0);
5900         }
5901         else{   /* size = 4 */
5902             if(shCount == 0){
5903                 movLeft2Result(left, MSB24, result, MSB32, 0);
5904                 movLeft2Result(left, MSB16, result, MSB24, 0);
5905                 movLeft2Result(left, LSB, result, MSB16, 0);
5906                 aopPut(AOP(result),zero,LSB);
5907             }
5908             else if(shCount == 1)
5909                 shiftLLong(left, result, MSB16);
5910             else{
5911                 shiftL2Left2Result(left, MSB16, result, MSB24, shCount);
5912                 shiftL1Left2Result(left, LSB, result, MSB16, shCount);
5913                 shiftRLeftOrResult(left, LSB, result, MSB24, 8 - shCount);
5914                 aopPut(AOP(result),zero,LSB);
5915             }
5916         }
5917     }
5918
5919     /* 1 <= shCount <= 7 */
5920     else if(shCount <= 2){
5921         shiftLLong(left, result, LSB);
5922         if(shCount == 2)
5923             shiftLLong(result, result, LSB);
5924     }
5925     /* 3 <= shCount <= 7, optimize */
5926     else{
5927         shiftL2Left2Result(left, MSB24, result, MSB24, shCount);
5928         shiftRLeftOrResult(left, MSB16, result, MSB24, 8 - shCount);
5929         shiftL2Left2Result(left, LSB, result, LSB, shCount);
5930     }
5931 }
5932
5933 /*-----------------------------------------------------------------*/
5934 /* genLeftShiftLiteral - left shifting by known count              */
5935 /*-----------------------------------------------------------------*/
5936 static void genLeftShiftLiteral (operand *left,
5937                                  operand *right,
5938                                  operand *result,
5939                                  iCode *ic)
5940 {    
5941     int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
5942     int size;
5943
5944     D(emitcode(";","genLeftShiftLiteral (%d)", shCount););
5945
5946     freeAsmop(right,NULL,ic,TRUE);
5947
5948     aopOp(left,ic,FALSE, FALSE);
5949     aopOp(result,ic,FALSE, TRUE);
5950
5951     size = getSize(operandType(result));
5952
5953 #if VIEW_SIZE
5954     emitcode("; shift left ","result %d, left %d",size,
5955              AOP_SIZE(left));
5956 #endif
5957
5958     /* I suppose that the left size >= result size */
5959     if(shCount == 0){
5960         while(size--){
5961             movLeft2Result(left, size, result, size, 0);
5962         }
5963     }
5964
5965     else if(shCount >= (size * 8))
5966         while(size--)
5967             aopPut(AOP(result),zero,size);
5968     else{
5969         switch (size) {
5970             case 1:
5971                 genlshOne (result,left,shCount);
5972                 break;
5973
5974             case 2:
5975             case 3: /* bug: this is for generic pointers, I bet. */
5976                 genlshTwo (result,left,shCount);
5977                 break;
5978
5979             case 4:
5980                 genlshFour (result,left,shCount);
5981                 break;
5982         }
5983     }
5984     freeAsmop(left,NULL,ic,TRUE);
5985     freeAsmop(result,NULL,ic,TRUE);
5986 }
5987
5988 /*-----------------------------------------------------------------*/
5989 /* genLeftShift - generates code for left shifting                 */
5990 /*-----------------------------------------------------------------*/
5991 static void genLeftShift (iCode *ic)
5992 {
5993     operand *left,*right, *result;
5994     int size, offset;
5995     char *l;
5996     symbol *tlbl , *tlbl1;
5997
5998     D(emitcode(";", "genLeftShift "););
5999
6000     right = IC_RIGHT(ic);
6001     left  = IC_LEFT(ic);
6002     result = IC_RESULT(ic);
6003
6004     aopOp(right,ic,FALSE, FALSE);
6005
6006     #if 0
6007     /* if the shift count is known then do it 
6008     as efficiently as possible */
6009     if (AOP_TYPE(right) == AOP_LIT) {
6010         genLeftShiftLiteral (left,right,result,ic);
6011         return ;
6012     }
6013     #endif
6014
6015     /* shift count is unknown then we have to form 
6016     a loop get the loop count in B : Note: we take
6017     only the lower order byte since shifting
6018     more that 32 bits make no sense anyway, ( the
6019     largest size of an object can be only 32 bits ) */  
6020
6021     emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,FALSE));
6022     emitcode("inc","b");
6023     freeAsmop (right,NULL,ic,TRUE);
6024     aopOp(left,ic,FALSE, FALSE);
6025     aopOp(result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
6026
6027     /* now move the left to the result if they are not the
6028     same */
6029     if (!sameRegs(AOP(left),AOP(result)) && 
6030         AOP_SIZE(result) > 1) {
6031
6032         size = AOP_SIZE(result);
6033         offset=0;
6034         _startLazyDPSEvaluation();
6035         while (size--) {
6036             l = aopGet(AOP(left),offset,FALSE,TRUE,FALSE);
6037             if (*l == '@' && (IS_AOP_PREG(result))) {
6038
6039                 emitcode("mov","a,%s",l);
6040                 aopPut(AOP(result),"a",offset);
6041             } else
6042                 aopPut(AOP(result),l,offset);
6043             offset++;
6044         }
6045         _endLazyDPSEvaluation();
6046     }
6047
6048     tlbl = newiTempLabel(NULL);
6049     size = AOP_SIZE(result);
6050     offset = 0 ;   
6051     tlbl1 = newiTempLabel(NULL);
6052
6053     /* if it is only one byte then */
6054     if (size == 1) {
6055         symbol *tlbl1 = newiTempLabel(NULL);
6056
6057         l = aopGet(AOP(left),0,FALSE,FALSE,TRUE);
6058         MOVA(l);
6059         emitcode("sjmp","%05d$",tlbl1->key+100); 
6060         emitcode("","%05d$:",tlbl->key+100);
6061         emitcode("add","a,acc");
6062         emitcode("","%05d$:",tlbl1->key+100);
6063         emitcode("djnz","b,%05d$",tlbl->key+100);      
6064         aopPut(AOP(result),"a",0);
6065         goto release ;
6066     }
6067     
6068     reAdjustPreg(AOP(result));    
6069     
6070     emitcode("sjmp","%05d$",tlbl1->key+100); 
6071     emitcode("","%05d$:",tlbl->key+100);    
6072     l = aopGet(AOP(result),offset,FALSE,FALSE,TRUE);
6073     MOVA(l);
6074     emitcode("add","a,acc");         
6075     aopPut(AOP(result),"a",offset++);
6076     _startLazyDPSEvaluation();
6077     while (--size) {
6078         l = aopGet(AOP(result),offset,FALSE,FALSE,TRUE);
6079         MOVA(l);
6080         emitcode("rlc","a");         
6081         aopPut(AOP(result),"a",offset++);
6082     }
6083     _endLazyDPSEvaluation();
6084     reAdjustPreg(AOP(result));
6085
6086     emitcode("","%05d$:",tlbl1->key+100);
6087     emitcode("djnz","b,%05d$",tlbl->key+100);
6088 release:
6089     freeAsmop(left,NULL,ic,TRUE);
6090     freeAsmop(result,NULL,ic,TRUE);
6091 }
6092
6093 /*-----------------------------------------------------------------*/
6094 /* genrshOne - right shift a one byte quantity by known count      */
6095 /*-----------------------------------------------------------------*/
6096 static void genrshOne (operand *result, operand *left,
6097                        int shCount, int sign)
6098 {
6099     D(emitcode(";", "genrshOne"););
6100     shiftR1Left2Result(left, LSB, result, LSB, shCount, sign);
6101 }
6102
6103 /*-----------------------------------------------------------------*/
6104 /* genrshTwo - right shift two bytes by known amount != 0          */
6105 /*-----------------------------------------------------------------*/
6106 static void genrshTwo (operand *result,operand *left,
6107                        int shCount, int sign)
6108 {
6109     D(emitcode(";", "genrshTwo"););
6110
6111     /* if shCount >= 8 */
6112     if (shCount >= 8) {
6113         shCount -= 8 ;
6114         if (shCount)
6115             shiftR1Left2Result(left, MSB16, result, LSB,
6116                                shCount, sign);
6117         else 
6118             movLeft2Result(left, MSB16, result, LSB, sign);
6119         addSign(result, MSB16, sign);
6120     }
6121
6122     /*  1 <= shCount <= 7 */
6123     else
6124         shiftR2Left2Result(left, LSB, result, LSB, shCount, sign); 
6125 }
6126
6127 /*-----------------------------------------------------------------*/
6128 /* shiftRLong - shift right one long from left to result           */
6129 /* offl = LSB or MSB16                                             */
6130 /*-----------------------------------------------------------------*/
6131 static void shiftRLong (operand *left, int offl,
6132                         operand *result, int sign)
6133 {
6134     if(!sign)
6135         emitcode("clr","c");
6136     MOVA(aopGet(AOP(left),MSB32,FALSE,FALSE,TRUE));
6137     if(sign)
6138         emitcode("mov","c,acc.7");
6139     emitcode("rrc","a");
6140     aopPut(AOP(result),"a",MSB32-offl);
6141     if(offl == MSB16)
6142         /* add sign of "a" */
6143         addSign(result, MSB32, sign);
6144
6145     MOVA(aopGet(AOP(left),MSB24,FALSE,FALSE,TRUE));
6146     emitcode("rrc","a");
6147     aopPut(AOP(result),"a",MSB24-offl);
6148
6149     MOVA(aopGet(AOP(left),MSB16,FALSE,FALSE,TRUE));
6150     emitcode("rrc","a");
6151     aopPut(AOP(result),"a",MSB16-offl);
6152
6153     if(offl == LSB){
6154         MOVA(aopGet(AOP(left),LSB,FALSE,FALSE,TRUE));
6155         emitcode("rrc","a");
6156         aopPut(AOP(result),"a",LSB);
6157     }
6158 }
6159
6160 /*-----------------------------------------------------------------*/
6161 /* genrshFour - shift four byte by a known amount != 0             */
6162 /*-----------------------------------------------------------------*/
6163 static void genrshFour (operand *result, operand *left,
6164                         int shCount, int sign)
6165 {
6166     D(emitcode(";", "genrshFour"););
6167     
6168     /* if shifting more that 3 bytes */
6169     if(shCount >= 24 ) {
6170         shCount -= 24;
6171         if(shCount)
6172             shiftR1Left2Result(left, MSB32, result, LSB, shCount, sign);
6173         else
6174             movLeft2Result(left, MSB32, result, LSB, sign);
6175         addSign(result, MSB16, sign);
6176     }
6177     else if(shCount >= 16){
6178         shCount -= 16;
6179         if(shCount)
6180             shiftR2Left2Result(left, MSB24, result, LSB, shCount, sign);
6181         else{
6182             movLeft2Result(left, MSB24, result, LSB, 0);
6183             movLeft2Result(left, MSB32, result, MSB16, sign);
6184         }
6185         addSign(result, MSB24, sign);
6186     }
6187     else if(shCount >= 8){
6188         shCount -= 8;
6189         if(shCount == 1)
6190             shiftRLong(left, MSB16, result, sign);
6191         else if(shCount == 0){
6192             movLeft2Result(left, MSB16, result, LSB, 0);
6193             movLeft2Result(left, MSB24, result, MSB16, 0);
6194             movLeft2Result(left, MSB32, result, MSB24, sign);
6195             addSign(result, MSB32, sign);
6196         }
6197         else{
6198             shiftR2Left2Result(left, MSB16, result, LSB, shCount, 0);
6199             shiftLLeftOrResult(left, MSB32, result, MSB16, 8 - shCount);
6200             /* the last shift is signed */
6201             shiftR1Left2Result(left, MSB32, result, MSB24, shCount, sign);
6202             addSign(result, MSB32, sign);
6203         }
6204     }
6205     else{   /* 1 <= shCount <= 7 */
6206         if(shCount <= 2){
6207             shiftRLong(left, LSB, result, sign);
6208             if(shCount == 2)
6209                 shiftRLong(result, LSB, result, sign);
6210         }
6211         else{
6212             shiftR2Left2Result(left, LSB, result, LSB, shCount, 0);
6213             shiftLLeftOrResult(left, MSB24, result, MSB16, 8 - shCount);
6214             shiftR2Left2Result(left, MSB24, result, MSB24, shCount, sign);
6215         }
6216     }
6217 }
6218
6219 /*-----------------------------------------------------------------*/
6220 /* genRightShiftLiteral - right shifting by known count            */
6221 /*-----------------------------------------------------------------*/
6222 static void genRightShiftLiteral (operand *left,
6223                                   operand *right,
6224                                   operand *result,
6225                                   iCode *ic,
6226                                   int sign)
6227 {    
6228     int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
6229     int size;
6230
6231     D(emitcode(";", "genRightShiftLiteral"););
6232
6233     freeAsmop(right,NULL,ic,TRUE);
6234
6235     aopOp(left,ic,FALSE, FALSE);
6236     aopOp(result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
6237
6238 #if VIEW_SIZE
6239     emitcode("; shift right ","result %d, left %d",AOP_SIZE(result),
6240              AOP_SIZE(left));
6241 #endif
6242
6243     size = getDataSize(left);
6244     /* test the LEFT size !!! */
6245
6246     /* I suppose that the left size >= result size */
6247     if(shCount == 0){
6248         size = getDataSize(result);
6249         while(size--)
6250             movLeft2Result(left, size, result, size, 0);
6251     }
6252
6253     else if(shCount >= (size * 8)){
6254         if(sign)
6255             /* get sign in acc.7 */
6256             MOVA(aopGet(AOP(left),size-1,FALSE,FALSE,TRUE));
6257         addSign(result, LSB, sign);
6258     } else{
6259         switch (size) {
6260             case 1:
6261                 genrshOne (result,left,shCount,sign);
6262                 break;
6263
6264             case 2:
6265                 genrshTwo (result,left,shCount,sign);
6266                 break;
6267
6268             case 4:
6269                 genrshFour (result,left,shCount,sign);
6270                 break;
6271             default :
6272                 break;
6273         }
6274
6275         freeAsmop(left,NULL,ic,TRUE);
6276         freeAsmop(result,NULL,ic,TRUE);
6277     }
6278 }
6279
6280 /*-----------------------------------------------------------------*/
6281 /* genSignedRightShift - right shift of signed number              */
6282 /*-----------------------------------------------------------------*/
6283 static void genSignedRightShift (iCode *ic)
6284 {
6285     operand *right, *left, *result;
6286     int size, offset;
6287     char *l;
6288     symbol *tlbl, *tlbl1 ;
6289
6290     D(emitcode(";", "genSignedRightShift "););
6291
6292     /* we do it the hard way put the shift count in b
6293     and loop thru preserving the sign */
6294
6295     right = IC_RIGHT(ic);
6296     left  = IC_LEFT(ic);
6297     result = IC_RESULT(ic);
6298
6299     aopOp(right,ic,FALSE, FALSE);
6300
6301     #if 0
6302     if ( AOP_TYPE(right) == AOP_LIT) {
6303         genRightShiftLiteral (left,right,result,ic,1);
6304         return ;
6305     }
6306     #endif
6307         /* shift count is unknown then we have to form 
6308        a loop get the loop count in B : Note: we take
6309        only the lower order byte since shifting
6310        more that 32 bits make no sense anyway, ( the
6311        largest size of an object can be only 32 bits ) */  
6312
6313     emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,FALSE));
6314     emitcode("inc","b");
6315     freeAsmop (right,NULL,ic,TRUE);
6316     aopOp(left,ic,FALSE, FALSE);
6317     aopOp(result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
6318
6319     /* now move the left to the result if they are not the
6320     same */
6321     if (!sameRegs(AOP(left),AOP(result)) && 
6322         AOP_SIZE(result) > 1) {
6323
6324         size = AOP_SIZE(result);
6325         offset=0;
6326         _startLazyDPSEvaluation();
6327         while (size--) {
6328             l = aopGet(AOP(left),offset,FALSE,TRUE,FALSE);
6329             if (*l == '@' && IS_AOP_PREG(result)) {
6330
6331                 emitcode("mov","a,%s",l);
6332                 aopPut(AOP(result),"a",offset);
6333             } else
6334                 aopPut(AOP(result),l,offset);
6335             offset++;
6336         }
6337         _endLazyDPSEvaluation();
6338     }
6339
6340     /* mov the highest order bit to OVR */    
6341     tlbl = newiTempLabel(NULL);
6342     tlbl1= newiTempLabel(NULL);
6343
6344     size = AOP_SIZE(result);
6345     offset = size - 1;
6346     emitcode("mov","a,%s",aopGet(AOP(left),offset,FALSE,FALSE,FALSE));
6347     emitcode("rlc","a");
6348     emitcode("mov","ov,c");
6349     /* if it is only one byte then */
6350     if (size == 1) {
6351         l = aopGet(AOP(left),0,FALSE,FALSE,TRUE);
6352         MOVA(l);
6353         emitcode("sjmp","%05d$",tlbl1->key+100);
6354         emitcode("","%05d$:",tlbl->key+100);
6355         emitcode("mov","c,ov");
6356         emitcode("rrc","a");
6357         emitcode("","%05d$:",tlbl1->key+100);
6358         emitcode("djnz","b,%05d$",tlbl->key+100);
6359         aopPut(AOP(result),"a",0);
6360         goto release ;
6361     }
6362
6363     reAdjustPreg(AOP(result));
6364     emitcode("sjmp","%05d$",tlbl1->key+100);
6365     emitcode("","%05d$:",tlbl->key+100);    
6366     emitcode("mov","c,ov");
6367     _startLazyDPSEvaluation();
6368     while (size--) {
6369         l = aopGet(AOP(result),offset,FALSE,FALSE,TRUE);
6370         MOVA(l);
6371         emitcode("rrc","a");         
6372         aopPut(AOP(result),"a",offset--);
6373     }
6374     _endLazyDPSEvaluation();
6375     reAdjustPreg(AOP(result));
6376     emitcode("","%05d$:",tlbl1->key+100);
6377     emitcode("djnz","b,%05d$",tlbl->key+100);
6378
6379 release:
6380     freeAsmop(left,NULL,ic,TRUE);
6381     freeAsmop(result,NULL,ic,TRUE);
6382 }
6383
6384 /*-----------------------------------------------------------------*/
6385 /* genRightShift - generate code for right shifting                */
6386 /*-----------------------------------------------------------------*/
6387 static void genRightShift (iCode *ic)
6388 {
6389     operand *right, *left, *result;
6390     link *retype ;
6391     int size, offset;
6392     char *l;
6393     symbol *tlbl, *tlbl1 ;
6394
6395     D(emitcode(";", "genRightShift "););
6396
6397     /* if signed then we do it the hard way preserve the
6398     sign bit moving it inwards */
6399     retype = getSpec(operandType(IC_RESULT(ic)));
6400
6401     if (!SPEC_USIGN(retype)) {
6402         genSignedRightShift (ic);
6403         return ;
6404     }
6405
6406     /* signed & unsigned types are treated the same : i.e. the
6407     signed is NOT propagated inwards : quoting from the
6408     ANSI - standard : "for E1 >> E2, is equivalent to division
6409     by 2**E2 if unsigned or if it has a non-negative value,
6410     otherwise the result is implementation defined ", MY definition
6411     is that the sign does not get propagated */
6412
6413     right = IC_RIGHT(ic);
6414     left  = IC_LEFT(ic);
6415     result = IC_RESULT(ic);
6416
6417     aopOp(right,ic,FALSE, FALSE);
6418
6419     #if 0
6420     /* if the shift count is known then do it 
6421     as efficiently as possible */
6422     if (AOP_TYPE(right) == AOP_LIT) {
6423         genRightShiftLiteral (left,right,result,ic, 0);
6424         return ;
6425     }
6426     #endif
6427
6428     /* shift count is unknown then we have to form 
6429     a loop get the loop count in B : Note: we take
6430     only the lower order byte since shifting
6431     more that 32 bits make no sense anyway, ( the
6432     largest size of an object can be only 32 bits ) */  
6433
6434     emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,FALSE));
6435     emitcode("inc","b");
6436     freeAsmop (right,NULL,ic,TRUE);
6437     aopOp(left,ic,FALSE, FALSE);
6438     aopOp(result,ic,FALSE, AOP_TYPE(left) == AOP_DPTR);
6439
6440     /* now move the left to the result if they are not the
6441     same */
6442     if (!sameRegs(AOP(left),AOP(result)) && 
6443         AOP_SIZE(result) > 1) {
6444
6445         size = AOP_SIZE(result);
6446         offset=0;
6447         _startLazyDPSEvaluation();
6448         while (size--) {
6449             l = aopGet(AOP(left),offset,FALSE,TRUE,FALSE);
6450             if (*l == '@' && IS_AOP_PREG(result)) {
6451
6452                 emitcode("mov","a,%s",l);
6453                 aopPut(AOP(result),"a",offset);
6454             } else
6455                 aopPut(AOP(result),l,offset);
6456             offset++;
6457         }
6458         _endLazyDPSEvaluation();
6459     }
6460
6461     tlbl = newiTempLabel(NULL);
6462     tlbl1= newiTempLabel(NULL);
6463     size = AOP_SIZE(result);
6464     offset = size - 1;
6465
6466     /* if it is only one byte then */
6467     if (size == 1) {
6468         l = aopGet(AOP(left),0,FALSE,FALSE,TRUE);
6469         MOVA(l);
6470         emitcode("sjmp","%05d$",tlbl1->key+100);
6471         emitcode("","%05d$:",tlbl->key+100);
6472         CLRC;
6473         emitcode("rrc","a");
6474         emitcode("","%05d$:",tlbl1->key+100);
6475         emitcode("djnz","b,%05d$",tlbl->key+100);
6476         aopPut(AOP(result),"a",0);
6477         goto release ;
6478     }
6479
6480     reAdjustPreg(AOP(result));
6481     emitcode("sjmp","%05d$",tlbl1->key+100);
6482     emitcode("","%05d$:",tlbl->key+100);    
6483     CLRC;
6484     _startLazyDPSEvaluation();
6485     while (size--) {
6486         l = aopGet(AOP(result),offset,FALSE,FALSE,TRUE);
6487         MOVA(l);
6488         emitcode("rrc","a");         
6489         aopPut(AOP(result),"a",offset--);
6490     }
6491     _endLazyDPSEvaluation();
6492     reAdjustPreg(AOP(result));
6493
6494     emitcode("","%05d$:",tlbl1->key+100);
6495     emitcode("djnz","b,%05d$",tlbl->key+100);
6496
6497 release:
6498     freeAsmop(left,NULL,ic,TRUE);
6499     freeAsmop(result,NULL,ic,TRUE);
6500 }
6501
6502 /*-----------------------------------------------------------------*/
6503 /* genUnpackBits - generates code for unpacking bits               */
6504 /*-----------------------------------------------------------------*/
6505 static void genUnpackBits (operand *result, char *rname, int ptype)
6506 {    
6507     int shCnt ;
6508     int rlen = 0 ;
6509     link *etype;
6510     int offset = 0 ;
6511
6512     D(emitcode(";", "genUnpackBits "););
6513
6514     etype = getSpec(operandType(result));
6515
6516     /* read the first byte  */
6517     switch (ptype) {
6518
6519     case POINTER:
6520     case IPOINTER:
6521         emitcode("mov","a,@%s",rname);
6522         break;
6523         
6524     case PPOINTER:
6525         emitcode("movx","a,@%s",rname);
6526         break;
6527         
6528     case FPOINTER:
6529         emitcode("movx","a,@dptr");
6530         break;
6531
6532     case CPOINTER:
6533         emitcode("clr","a");
6534         emitcode("movc","a","@a+dptr");
6535         break;
6536
6537     case GPOINTER:
6538         emitcode("lcall","__gptrget");
6539         break;
6540     }
6541
6542     /* if we have bitdisplacement then it fits   */
6543     /* into this byte completely or if length is */
6544     /* less than a byte                          */
6545     if ((shCnt = SPEC_BSTR(etype)) || 
6546         (SPEC_BLEN(etype) <= 8))  {
6547
6548         /* shift right acc */
6549         AccRsh(shCnt);
6550
6551         emitcode("anl","a,#0x%02x",
6552                  ((unsigned char) -1)>>(8 - SPEC_BLEN(etype)));
6553         aopPut(AOP(result),"a",offset);
6554         return ;
6555     }
6556
6557     /* bit field did not fit in a byte  */
6558     rlen = SPEC_BLEN(etype) - 8;
6559     aopPut(AOP(result),"a",offset++);
6560
6561     while (1)  {
6562
6563         switch (ptype) {
6564         case POINTER:
6565         case IPOINTER:
6566             emitcode("inc","%s",rname);
6567             emitcode("mov","a,@%s",rname);
6568             break;
6569             
6570         case PPOINTER:
6571             emitcode("inc","%s",rname);
6572             emitcode("movx","a,@%s",rname);
6573             break;
6574
6575         case FPOINTER:
6576             emitcode("inc","dptr");
6577             emitcode("movx","a,@dptr");
6578             break;
6579             
6580         case CPOINTER:
6581             emitcode("clr","a");
6582             emitcode("inc","dptr");
6583             emitcode("movc","a","@a+dptr");
6584             break;
6585             
6586         case GPOINTER:
6587             emitcode("inc","dptr");
6588             emitcode("lcall","__gptrget");
6589             break;
6590         }
6591
6592         rlen -= 8;            
6593         /* if we are done */
6594         if ( rlen <= 0 )
6595             break ;
6596         
6597         aopPut(AOP(result),"a",offset++);
6598                               
6599     }
6600     
6601     if (rlen) {
6602         emitcode("anl","a,#0x%02x",((unsigned char)-1)>>(-rlen));
6603         aopPut(AOP(result),"a",offset);        
6604     }
6605     
6606     return ;
6607 }
6608
6609
6610 /*-----------------------------------------------------------------*/
6611 /* genDataPointerGet - generates code when ptr offset is known     */
6612 /*-----------------------------------------------------------------*/
6613 static void genDataPointerGet (operand *left, 
6614                                operand *result, 
6615                                iCode *ic)
6616 {
6617     char *l;
6618     char buffer[256];
6619     int size , offset = 0;
6620     aopOp(result,ic,TRUE, FALSE);
6621
6622     /* get the string representation of the name */
6623     l = aopGet(AOP(left),0,FALSE,TRUE,FALSE);
6624     size = AOP_SIZE(result);
6625     _startLazyDPSEvaluation();
6626     while (size--) {
6627         if (offset)
6628             sprintf(buffer,"(%s + %d)",l+1,offset);
6629         else
6630             sprintf(buffer,"%s",l+1);
6631         aopPut(AOP(result),buffer,offset++);
6632     }
6633     _endLazyDPSEvaluation();
6634
6635     freeAsmop(left,NULL,ic,TRUE);
6636     freeAsmop(result,NULL,ic,TRUE);
6637 }
6638
6639 /*-----------------------------------------------------------------*/
6640 /* genNearPointerGet - emitcode for near pointer fetch             */
6641 /*-----------------------------------------------------------------*/
6642 static void genNearPointerGet (operand *left, 
6643                                operand *result, 
6644                                iCode *ic)
6645 {
6646     asmop *aop = NULL;
6647     regs *preg = NULL ;
6648     char *rname ;
6649     link *rtype, *retype;
6650     link *ltype = operandType(left);    
6651     char buffer[80];
6652
6653     rtype = operandType(result);
6654     retype= getSpec(rtype);
6655     
6656     aopOp(left,ic,FALSE, FALSE);
6657     
6658     /* if left is rematerialisable and
6659        result is not bit variable type and
6660        the left is pointer to data space i.e
6661        lower 128 bytes of space */
6662     if (AOP_TYPE(left) == AOP_IMMD &&
6663         !IS_BITVAR(retype)         &&
6664         DCL_TYPE(ltype) == POINTER) {
6665         genDataPointerGet (left,result,ic);
6666         return ;
6667     }
6668     
6669         /* if the value is already in a pointer register
6670        then don't need anything more */
6671     if (!AOP_INPREG(AOP(left))) {
6672         /* otherwise get a free pointer register */
6673         aop = newAsmop(0);
6674         preg = getFreePtr(ic,&aop,FALSE);
6675         emitcode("mov","%s,%s",
6676                 preg->name,
6677                 aopGet(AOP(left),0,FALSE,TRUE,FALSE));
6678         rname = preg->name ;
6679     } else
6680         rname = aopGet(AOP(left),0,FALSE,FALSE,FALSE);
6681     
6682     freeAsmop(left,NULL,ic,TRUE);
6683     aopOp (result,ic,FALSE, FALSE);
6684     
6685       /* if bitfield then unpack the bits */
6686     if (IS_BITVAR(retype)) 
6687         genUnpackBits (result,rname,POINTER);
6688     else {
6689         /* we have can just get the values */
6690         int size = AOP_SIZE(result);
6691         int offset = 0 ;        
6692         
6693         while (size--) {
6694             if (IS_AOP_PREG(result) || AOP_TYPE(result) == AOP_STK ) {
6695
6696                 emitcode("mov","a,@%s",rname);
6697                 aopPut(AOP(result),"a",offset);
6698             } else {
6699                 sprintf(buffer,"@%s",rname);
6700                 aopPut(AOP(result),buffer,offset);
6701             }
6702             offset++ ;
6703             if (size)
6704                 emitcode("inc","%s",rname);
6705         }
6706     }
6707
6708     /* now some housekeeping stuff */
6709     if (aop) {
6710         /* we had to allocate for this iCode */
6711         freeAsmop(NULL,aop,ic,TRUE);
6712     } else { 
6713         /* we did not allocate which means left
6714            already in a pointer register, then
6715            if size > 0 && this could be used again
6716            we have to point it back to where it 
6717            belongs */
6718         if (AOP_SIZE(result) > 1 &&
6719             !OP_SYMBOL(left)->remat &&
6720             ( OP_SYMBOL(left)->liveTo > ic->seq ||
6721               ic->depth )) {
6722             int size = AOP_SIZE(result) - 1;
6723             while (size--)
6724                 emitcode("dec","%s",rname);
6725         }
6726     }
6727
6728     /* done */
6729     freeAsmop(result,NULL,ic,TRUE);
6730      
6731 }
6732
6733 /*-----------------------------------------------------------------*/
6734 /* genPagedPointerGet - emitcode for paged pointer fetch           */
6735 /*-----------------------------------------------------------------*/
6736 static void genPagedPointerGet (operand *left, 
6737                                operand *result, 
6738                                iCode *ic)
6739 {
6740     asmop *aop = NULL;
6741     regs *preg = NULL ;
6742     char *rname ;
6743     link *rtype, *retype;    
6744
6745     rtype = operandType(result);
6746     retype= getSpec(rtype);
6747     
6748     aopOp(left,ic,FALSE, FALSE);
6749
6750   /* if the value is already in a pointer register
6751        then don't need anything more */
6752     if (!AOP_INPREG(AOP(left))) {
6753         /* otherwise get a free pointer register */
6754         aop = newAsmop(0);
6755         preg = getFreePtr(ic,&aop,FALSE);
6756         emitcode("mov","%s,%s",
6757                 preg->name,
6758                 aopGet(AOP(left),0,FALSE,TRUE,FALSE));
6759         rname = preg->name ;
6760     } else
6761         rname = aopGet(AOP(left),0,FALSE,FALSE,FALSE);
6762     
6763     freeAsmop(left,NULL,ic,TRUE);
6764     aopOp (result,ic,FALSE, FALSE);
6765
6766     /* if bitfield then unpack the bits */
6767     if (IS_BITVAR(retype)) 
6768         genUnpackBits (result,rname,PPOINTER);
6769     else {
6770         /* we have can just get the values */
6771         int size = AOP_SIZE(result);
6772         int offset = 0 ;        
6773         
6774         while (size--) {
6775             
6776             emitcode("movx","a,@%s",rname);
6777             aopPut(AOP(result),"a",offset);
6778             
6779             offset++ ;
6780             
6781             if (size)
6782                 emitcode("inc","%s",rname);
6783         }
6784     }
6785
6786     /* now some housekeeping stuff */
6787     if (aop) {
6788         /* we had to allocate for this iCode */
6789         freeAsmop(NULL,aop,ic,TRUE);
6790     } else { 
6791         /* we did not allocate which means left
6792            already in a pointer register, then
6793            if size > 0 && this could be used again
6794            we have to point it back to where it 
6795            belongs */
6796         if (AOP_SIZE(result) > 1 &&
6797             !OP_SYMBOL(left)->remat &&
6798             ( OP_SYMBOL(left)->liveTo > ic->seq ||
6799               ic->depth )) {
6800             int size = AOP_SIZE(result) - 1;
6801             while (size--)
6802                 emitcode("dec","%s",rname);
6803         }
6804     }
6805
6806     /* done */
6807     freeAsmop(result,NULL,ic,TRUE);
6808     
6809         
6810 }
6811
6812 /*-----------------------------------------------------------------*/
6813 /* genFarPointerGet - gget value from far space                    */
6814 /*-----------------------------------------------------------------*/
6815 static void genFarPointerGet (operand *left,
6816                               operand *result, iCode *ic)
6817 {
6818     int size, offset ;
6819     link *retype = getSpec(operandType(result));
6820
6821     D(emitcode(";", "genFarPointerGet"););
6822
6823     aopOp(left,ic,FALSE, FALSE);
6824
6825     /* if the operand is already in dptr 
6826     then we do nothing else we move the value to dptr */
6827     if (AOP_TYPE(left) != AOP_STR) {
6828         /* if this is remateriazable */
6829         if (AOP_TYPE(left) == AOP_IMMD)
6830         {
6831             emitcode("mov","dptr,%s",aopGet(AOP(left),0,TRUE,FALSE,FALSE));
6832         }
6833         else 
6834         { 
6835             /* we need to get it byte by byte */
6836             _startLazyDPSEvaluation();
6837             if (AOP_TYPE(left) != AOP_DPTR)
6838             {
6839                 emitcode("mov","dpl,%s",aopGet(AOP(left),0,FALSE,FALSE,TRUE));
6840                 emitcode("mov","dph,%s",aopGet(AOP(left),1,FALSE,FALSE,TRUE));
6841                 emitcode("mov","dpx,%s",aopGet(AOP(left),2,FALSE,FALSE,TRUE));
6842             }
6843             else
6844             {
6845                  /* We need to generate a load to DPTR indirect through DPTR. */
6846                  D(emitcode(";", "genFarPointerGet -- indirection special case."););
6847                  emitcode("push", "%s", aopGet(AOP(left),0,FALSE,TRUE,TRUE));
6848                  emitcode("push", "%s", aopGet(AOP(left),1,FALSE,TRUE,TRUE));
6849                  emitcode("mov", "dpx,%s",aopGet(AOP(left),2,FALSE,FALSE,TRUE));
6850                  emitcode("pop", "dph");
6851                  emitcode("pop", "dpl");
6852             }
6853             _endLazyDPSEvaluation();
6854         }
6855     }
6856     /* so dptr know contains the address */
6857     freeAsmop(left,NULL,ic,TRUE);
6858     aopOp(result,ic,FALSE, TRUE);
6859
6860     /* if bit then unpack */
6861     if (IS_BITVAR(retype)) 
6862         genUnpackBits(result,"dptr",FPOINTER);
6863     else {
6864         size = AOP_SIZE(result);
6865         offset = 0 ;
6866
6867         _startLazyDPSEvaluation();
6868         while (size--) {
6869             
6870             genSetDPTR(0);
6871             _flushLazyDPS();
6872             
6873             emitcode("movx","a,@dptr");
6874             aopPut(AOP(result),"a",offset++);
6875             if (size)
6876                 emitcode("inc","dptr");
6877         }
6878         _endLazyDPSEvaluation();
6879     }
6880
6881     freeAsmop(result,NULL,ic,TRUE);
6882 }
6883
6884 /*-----------------------------------------------------------------*/
6885 /* emitcodePointerGet - gget value from code space                  */
6886 /*-----------------------------------------------------------------*/
6887 static void emitcodePointerGet (operand *left,
6888                                 operand *result, iCode *ic)
6889 {
6890     int size, offset ;
6891     link *retype = getSpec(operandType(result));
6892
6893     aopOp(left,ic,FALSE, FALSE);
6894
6895     /* if the operand is already in dptr 
6896     then we do nothing else we move the value to dptr */
6897     if (AOP_TYPE(left) != AOP_STR) {
6898         /* if this is remateriazable */
6899         if (AOP_TYPE(left) == AOP_IMMD)
6900             emitcode("mov","dptr,%s",aopGet(AOP(left),0,TRUE,FALSE,FALSE));
6901         else { /* we need to get it byte by byte */
6902             _startLazyDPSEvaluation();
6903             emitcode("mov","dpl,%s",aopGet(AOP(left),0,FALSE,FALSE,TRUE));
6904             emitcode("mov","dph,%s",aopGet(AOP(left),1,FALSE,FALSE,TRUE));
6905             emitcode("mov","dpx,%s",aopGet(AOP(left),2,FALSE,FALSE,TRUE));
6906             _endLazyDPSEvaluation();
6907         }
6908     }
6909     /* so dptr know contains the address */
6910     freeAsmop(left,NULL,ic,TRUE);
6911     aopOp(result,ic,FALSE, FALSE);
6912
6913     /* if bit then unpack */
6914     if (IS_BITVAR(retype)) 
6915         genUnpackBits(result,"dptr",CPOINTER);
6916     else {
6917         size = AOP_SIZE(result);
6918         offset = 0 ;
6919
6920         while (size--) {
6921             emitcode("clr","a");
6922             emitcode("movc","a,@a+dptr");
6923             aopPut(AOP(result),"a",offset++);
6924             if (size)
6925                 emitcode("inc","dptr");
6926         }
6927     }
6928
6929     freeAsmop(result,NULL,ic,TRUE);
6930 }
6931
6932 /*-----------------------------------------------------------------*/
6933 /* genGenPointerGet - gget value from generic pointer space        */
6934 /*-----------------------------------------------------------------*/
6935 static void genGenPointerGet (operand *left,
6936                               operand *result, iCode *ic)
6937 {
6938     int size, offset ;
6939     link *retype = getSpec(operandType(result));
6940
6941     aopOp(left,ic,FALSE, TRUE);
6942
6943     /* if the operand is already in dptr 
6944     then we do nothing else we move the value to dptr */
6945     if (AOP_TYPE(left) != AOP_STR) {
6946         /* if this is remateriazable */
6947         if (AOP_TYPE(left) == AOP_IMMD) {
6948             emitcode("mov","dptr,%s",aopGet(AOP(left),0,TRUE,FALSE,FALSE));
6949             emitcode("mov","b,#%d",pointerCode(retype));
6950         }
6951         else { /* we need to get it byte by byte */
6952             _startLazyDPSEvaluation();
6953             emitcode("mov","dpl,%s",aopGet(AOP(left),0,FALSE,FALSE,TRUE));
6954             emitcode("mov","dph,%s",aopGet(AOP(left),1,FALSE,FALSE,TRUE));
6955             if (options.model == MODEL_FLAT24)
6956             {
6957                emitcode("mov", "dpx,%s",aopGet(AOP(left),2,FALSE,FALSE,TRUE));
6958                emitcode("mov","b,%s",aopGet(AOP(left),3,FALSE,FALSE,TRUE));
6959             }
6960             else
6961             {
6962                 emitcode("mov","b,%s",aopGet(AOP(left),2,FALSE,FALSE,TRUE));
6963             }
6964             _endLazyDPSEvaluation();
6965         }
6966     }
6967     /* so dptr know contains the address */
6968     freeAsmop(left,NULL,ic,TRUE);
6969     aopOp(result,ic,FALSE, TRUE);
6970
6971     /* if bit then unpack */
6972     if (IS_BITVAR(retype)) 
6973         genUnpackBits(result,"dptr",GPOINTER);
6974     else {
6975         size = AOP_SIZE(result);
6976         offset = 0 ;
6977
6978         while (size--) {
6979             emitcode("lcall","__gptrget");
6980             aopPut(AOP(result),"a",offset++);
6981             if (size)
6982                 emitcode("inc","dptr");
6983         }
6984     }
6985
6986     freeAsmop(result,NULL,ic,TRUE);
6987 }
6988
6989 /*-----------------------------------------------------------------*/
6990 /* genPointerGet - generate code for pointer get                   */
6991 /*-----------------------------------------------------------------*/
6992 static void genPointerGet (iCode *ic)
6993 {
6994     operand *left, *result ;
6995     link *type, *etype;
6996     int p_type;
6997
6998     D(emitcode(";", "genPointerGet "););
6999
7000     left = IC_LEFT(ic);
7001     result = IC_RESULT(ic) ;
7002
7003     /* depending on the type of pointer we need to
7004     move it to the correct pointer register */
7005     type = operandType(left);
7006     etype = getSpec(type);
7007     /* if left is of type of pointer then it is simple */
7008     if (IS_PTR(type) && !IS_FUNC(type->next)) 
7009         p_type = DCL_TYPE(type);
7010     else {
7011         /* we have to go by the storage class */
7012         p_type = PTR_TYPE(SPEC_OCLS(etype));
7013
7014 /*      if (SPEC_OCLS(etype)->codesp ) { */
7015 /*          p_type = CPOINTER ;  */
7016 /*      } */
7017 /*      else */
7018 /*          if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */
7019 /*              p_type = FPOINTER ; */
7020 /*          else */
7021 /*              if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */
7022 /*                  p_type = PPOINTER; */
7023 /*              else */
7024 /*                  if (SPEC_OCLS(etype) == idata ) */
7025 /*                      p_type = IPOINTER; */
7026 /*                  else */
7027 /*                      p_type = POINTER ; */
7028     }
7029
7030     /* now that we have the pointer type we assign
7031     the pointer values */
7032     switch (p_type) {
7033
7034     case POINTER:       
7035     case IPOINTER:
7036         genNearPointerGet (left,result,ic);
7037         break;
7038
7039     case PPOINTER:
7040         genPagedPointerGet(left,result,ic);
7041         break;
7042
7043     case FPOINTER:
7044         genFarPointerGet (left,result,ic);
7045         break;
7046
7047     case CPOINTER:
7048         emitcodePointerGet (left,result,ic);
7049         break;
7050
7051     case GPOINTER:
7052         genGenPointerGet (left,result,ic);
7053         break;
7054     }
7055
7056 }
7057
7058 /*-----------------------------------------------------------------*/
7059 /* genPackBits - generates code for packed bit storage             */
7060 /*-----------------------------------------------------------------*/
7061 static void genPackBits (link    *etype ,
7062                          operand *right ,
7063                          char *rname, int p_type)
7064 {
7065     int shCount = 0 ;
7066     int offset = 0  ;
7067     int rLen = 0 ;
7068     int blen, bstr ;   
7069     char *l ;
7070
7071     blen = SPEC_BLEN(etype);
7072     bstr = SPEC_BSTR(etype);
7073
7074     l = aopGet(AOP(right),offset++,FALSE,FALSE,TRUE);
7075     MOVA(l);   
7076
7077     /* if the bit lenth is less than or    */
7078     /* it exactly fits a byte then         */
7079     if (SPEC_BLEN(etype) <= 8 )  {
7080         shCount = SPEC_BSTR(etype) ;
7081
7082         /* shift left acc */
7083         AccLsh(shCount);
7084
7085         if (SPEC_BLEN(etype) < 8 ) { /* if smaller than a byte */
7086
7087
7088             switch (p_type) {
7089                 case POINTER:
7090                     emitcode ("mov","b,a");
7091                     emitcode("mov","a,@%s",rname);
7092                     break;
7093
7094                 case FPOINTER:
7095                     emitcode ("mov","b,a");
7096                     emitcode("movx","a,@dptr");
7097                     break;
7098
7099                 case GPOINTER:
7100                     emitcode ("push","b");
7101                     emitcode ("push","acc");
7102                     emitcode ("lcall","__gptrget");
7103                     emitcode ("pop","b");
7104                     break;
7105             }
7106
7107             emitcode ("anl","a,#0x%02x",(unsigned char)
7108                       ((unsigned char)(0xFF << (blen+bstr)) | 
7109                        (unsigned char)(0xFF >> (8-bstr)) ) );
7110             emitcode ("orl","a,b");
7111             if (p_type == GPOINTER)
7112                 emitcode("pop","b");
7113         }
7114     }
7115
7116     switch (p_type) {
7117         case POINTER:
7118             emitcode("mov","@%s,a",rname);
7119             break;
7120
7121         case FPOINTER:
7122             emitcode("movx","@dptr,a");
7123             break;
7124
7125         case GPOINTER:
7126             emitcode("lcall","__gptrput");
7127             break;
7128     }
7129
7130     /* if we r done */
7131     if ( SPEC_BLEN(etype) <= 8 )
7132         return ;
7133
7134     emitcode("inc","%s",rname);
7135     rLen = SPEC_BLEN(etype) ;     
7136
7137     /* now generate for lengths greater than one byte */
7138     while (1) {
7139
7140         l = aopGet(AOP(right),offset++,FALSE,TRUE,FALSE);
7141
7142         rLen -= 8 ;
7143         if (rLen <= 0 )
7144             break ;
7145
7146         switch (p_type) {
7147             case POINTER:
7148                 if (*l == '@') {
7149                     MOVA(l);
7150                     emitcode("mov","@%s,a",rname);
7151                 } else
7152                     emitcode("mov","@%s,%s",rname,l);
7153                 break;
7154
7155             case FPOINTER:
7156                 MOVA(l);
7157                 emitcode("movx","@dptr,a");
7158                 break;
7159
7160             case GPOINTER:
7161                 MOVA(l);
7162                 emitcode("lcall","__gptrput");
7163                 break;  
7164         }   
7165         emitcode ("inc","%s",rname);
7166     }
7167
7168     MOVA(l);
7169
7170     /* last last was not complete */
7171     if (rLen)   {
7172         /* save the byte & read byte */
7173         switch (p_type) {
7174             case POINTER:
7175                 emitcode ("mov","b,a");
7176                 emitcode("mov","a,@%s",rname);
7177                 break;
7178
7179             case FPOINTER:
7180                 emitcode ("mov","b,a");
7181                 emitcode("movx","a,@dptr");
7182                 break;
7183
7184             case GPOINTER:
7185                 emitcode ("push","b");
7186                 emitcode ("push","acc");
7187                 emitcode ("lcall","__gptrget");
7188                 emitcode ("pop","b");
7189                 break;
7190         }
7191
7192         emitcode ("anl","a,#0x%02x",((unsigned char)-1 << -rLen) );
7193         emitcode ("orl","a,b");
7194     }
7195
7196     if (p_type == GPOINTER)
7197         emitcode("pop","b");
7198
7199     switch (p_type) {
7200
7201     case POINTER:
7202         emitcode("mov","@%s,a",rname);
7203         break;
7204         
7205     case FPOINTER:
7206         emitcode("movx","@dptr,a");
7207         break;
7208         
7209     case GPOINTER:
7210         emitcode("lcall","__gptrput");
7211         break;                  
7212     }
7213 }
7214 /*-----------------------------------------------------------------*/
7215 /* genDataPointerSet - remat pointer to data space                 */
7216 /*-----------------------------------------------------------------*/
7217 static void genDataPointerSet(operand *right,
7218                               operand *result,
7219                               iCode *ic)
7220 {
7221     int size, offset = 0 ;
7222     char *l, buffer[256];
7223
7224     aopOp(right,ic,FALSE, FALSE);
7225     
7226     l = aopGet(AOP(result),0,FALSE,TRUE,FALSE);
7227     size = AOP_SIZE(right);
7228     while (size--) {
7229         if (offset)
7230             sprintf(buffer,"(%s + %d)",l+1,offset);
7231         else
7232             sprintf(buffer,"%s",l+1);
7233         emitcode("mov","%s,%s",buffer,
7234                  aopGet(AOP(right),offset++,FALSE,FALSE,FALSE));
7235     }
7236
7237     freeAsmop(right,NULL,ic,TRUE);
7238     freeAsmop(result,NULL,ic,TRUE);
7239 }
7240
7241 /*-----------------------------------------------------------------*/
7242 /* genNearPointerSet - emitcode for near pointer put                */
7243 /*-----------------------------------------------------------------*/
7244 static void genNearPointerSet (operand *right,
7245                                operand *result, 
7246                                iCode *ic)
7247 {
7248     asmop *aop = NULL;
7249     regs *preg = NULL ;
7250     char *rname , *l;
7251     link *retype;
7252     link *ptype = operandType(result);
7253     
7254     retype= getSpec(operandType(right));
7255
7256     aopOp(result,ic,FALSE, FALSE);
7257     
7258     /* if the result is rematerializable &
7259        in data space & not a bit variable */
7260     if (AOP_TYPE(result) == AOP_IMMD &&
7261         DCL_TYPE(ptype) == POINTER   &&
7262         !IS_BITVAR(retype)) {
7263         genDataPointerSet (right,result,ic);
7264         return;
7265     }
7266
7267     /* if the value is already in a pointer register
7268     then don't need anything more */
7269     if (!AOP_INPREG(AOP(result))) {
7270         /* otherwise get a free pointer register */
7271         aop = newAsmop(0);
7272         preg = getFreePtr(ic,&aop,FALSE);
7273         emitcode("mov","%s,%s",
7274                  preg->name,
7275                  aopGet(AOP(result),0,FALSE,TRUE,FALSE));
7276         rname = preg->name ;
7277     } else
7278         rname = aopGet(AOP(result),0,FALSE,FALSE,FALSE);
7279
7280     freeAsmop(result,NULL,ic,TRUE);
7281     aopOp (right,ic,FALSE, FALSE);
7282
7283     /* if bitfield then unpack the bits */
7284     if (IS_BITVAR(retype)) 
7285         genPackBits (retype,right,rname,POINTER);
7286     else {
7287         /* we have can just get the values */
7288         int size = AOP_SIZE(right);
7289         int offset = 0 ;    
7290
7291         while (size--) {
7292             l = aopGet(AOP(right),offset,FALSE,TRUE,FALSE);
7293             if (*l == '@' ) {
7294                 MOVA(l);
7295                 emitcode("mov","@%s,a",rname);
7296             } else
7297                 emitcode("mov","@%s,%s",rname,l);
7298             if (size)
7299                 emitcode("inc","%s",rname);
7300             offset++;
7301         }
7302     }
7303
7304     /* now some housekeeping stuff */
7305     if (aop) {
7306         /* we had to allocate for this iCode */
7307         freeAsmop(NULL,aop,ic,TRUE);
7308     } else { 
7309         /* we did not allocate which means left
7310         already in a pointer register, then
7311         if size > 0 && this could be used again
7312         we have to point it back to where it 
7313         belongs */
7314         if (AOP_SIZE(right) > 1 &&
7315             !OP_SYMBOL(result)->remat &&
7316             ( OP_SYMBOL(result)->liveTo > ic->seq ||
7317               ic->depth )) {
7318             int size = AOP_SIZE(right) - 1;
7319             while (size--)
7320                 emitcode("dec","%s",rname);
7321         }
7322     }
7323
7324     /* done */
7325     freeAsmop(right,NULL,ic,TRUE);
7326
7327
7328 }
7329
7330 /*-----------------------------------------------------------------*/
7331 /* genPagedPointerSet - emitcode for Paged pointer put             */
7332 /*-----------------------------------------------------------------*/
7333 static void genPagedPointerSet (operand *right,
7334                                operand *result, 
7335                                iCode *ic)
7336 {
7337     asmop *aop = NULL;
7338     regs *preg = NULL ;
7339     char *rname , *l;
7340     link *retype;
7341        
7342     retype= getSpec(operandType(right));
7343     
7344     aopOp(result,ic,FALSE, FALSE);
7345     
7346     /* if the value is already in a pointer register
7347        then don't need anything more */
7348     if (!AOP_INPREG(AOP(result))) {
7349         /* otherwise get a free pointer register */
7350         aop = newAsmop(0);
7351         preg = getFreePtr(ic,&aop,FALSE);
7352         emitcode("mov","%s,%s",
7353                 preg->name,
7354                 aopGet(AOP(result),0,FALSE,TRUE,FALSE));
7355         rname = preg->name ;
7356     } else
7357         rname = aopGet(AOP(result),0,FALSE,FALSE,FALSE);
7358     
7359     freeAsmop(result,NULL,ic,TRUE);
7360     aopOp (right,ic,FALSE, FALSE);
7361
7362     /* if bitfield then unpack the bits */
7363     if (IS_BITVAR(retype)) 
7364         genPackBits (retype,right,rname,PPOINTER);
7365     else {
7366         /* we have can just get the values */
7367         int size = AOP_SIZE(right);
7368         int offset = 0 ;        
7369         
7370         while (size--) {
7371             l = aopGet(AOP(right),offset,FALSE,TRUE,TRUE);
7372             
7373             MOVA(l);
7374             emitcode("movx","@%s,a",rname);
7375
7376             if (size)
7377                 emitcode("inc","%s",rname);
7378
7379             offset++;
7380         }
7381     }
7382     
7383     /* now some housekeeping stuff */
7384     if (aop) {
7385         /* we had to allocate for this iCode */
7386         freeAsmop(NULL,aop,ic,TRUE);
7387     } else { 
7388         /* we did not allocate which means left
7389            already in a pointer register, then
7390            if size > 0 && this could be used again
7391            we have to point it back to where it 
7392            belongs */
7393         if (AOP_SIZE(right) > 1 &&
7394             !OP_SYMBOL(result)->remat &&
7395             ( OP_SYMBOL(result)->liveTo > ic->seq ||
7396               ic->depth )) {
7397             int size = AOP_SIZE(right) - 1;
7398             while (size--)
7399                 emitcode("dec","%s",rname);
7400         }
7401     }
7402
7403     /* done */
7404     freeAsmop(right,NULL,ic,TRUE);
7405     
7406         
7407 }
7408
7409 /*-----------------------------------------------------------------*/
7410 /* genFarPointerSet - set value from far space                     */
7411 /*-----------------------------------------------------------------*/
7412 static void genFarPointerSet (operand *right,
7413                               operand *result, iCode *ic)
7414 {
7415     int size, offset ;
7416     link *retype = getSpec(operandType(right));
7417
7418     aopOp(result,ic,FALSE, FALSE);
7419
7420     /* if the operand is already in dptr 
7421     then we do nothing else we move the value to dptr */
7422     if (AOP_TYPE(result) != AOP_STR) {
7423         /* if this is remateriazable */
7424         if (AOP_TYPE(result) == AOP_IMMD)
7425             emitcode("mov","dptr,%s",aopGet(AOP(result),0,TRUE,FALSE,FALSE));
7426         else 
7427         {
7428             /* we need to get it byte by byte */
7429             _startLazyDPSEvaluation();
7430             if (AOP_TYPE(result) != AOP_DPTR)
7431             {
7432                 emitcode("mov","dpl,%s",aopGet(AOP(result),0,FALSE,FALSE,TRUE));
7433                 emitcode("mov","dph,%s",aopGet(AOP(result),1,FALSE,FALSE,TRUE));
7434                 emitcode("mov", "dpx,%s",aopGet(AOP(result),2,FALSE,FALSE,TRUE));
7435             }
7436             else
7437             {
7438                  /* We need to generate a load to DPTR indirect through DPTR. */
7439                  D(emitcode(";", "genFarPointerSet -- indirection special case."););
7440                  emitcode("push", "%s", aopGet(AOP(result),0,FALSE,TRUE,TRUE));
7441                  emitcode("push", "%s", aopGet(AOP(result),1,FALSE,TRUE,TRUE));
7442                  emitcode("mov", "dpx,%s",aopGet(AOP(result),2,FALSE,FALSE,TRUE));
7443                  emitcode("pop", "dph");
7444                  emitcode("pop", "dpl");
7445             }
7446             _endLazyDPSEvaluation();
7447         }
7448     }
7449     /* so dptr know contains the address */
7450     freeAsmop(result,NULL,ic,TRUE);
7451     aopOp(right,ic,FALSE, TRUE);
7452
7453     /* if bit then unpack */
7454     if (IS_BITVAR(retype)) 
7455         genPackBits(retype,right,"dptr",FPOINTER);
7456     else {
7457         size = AOP_SIZE(right);
7458         offset = 0 ;
7459
7460         _startLazyDPSEvaluation();
7461         while (size--) {
7462             char *l = aopGet(AOP(right),offset++,FALSE,FALSE,TRUE);
7463             MOVA(l);
7464             
7465             genSetDPTR(0);
7466             _flushLazyDPS();
7467             
7468             emitcode("movx","@dptr,a");
7469             if (size)
7470                 emitcode("inc","dptr");
7471         }
7472         _endLazyDPSEvaluation();
7473     }
7474
7475     freeAsmop(right,NULL,ic,TRUE);
7476 }
7477
7478 /*-----------------------------------------------------------------*/
7479 /* genGenPointerSet - set value from generic pointer space         */
7480 /*-----------------------------------------------------------------*/
7481 static void genGenPointerSet (operand *right,
7482                               operand *result, iCode *ic)
7483 {
7484     int size, offset ;
7485     link *retype = getSpec(operandType(right));
7486
7487     aopOp(result,ic,FALSE, TRUE);
7488
7489     /* if the operand is already in dptr 
7490     then we do nothing else we move the value to dptr */
7491     if (AOP_TYPE(result) != AOP_STR) {
7492         _startLazyDPSEvaluation();
7493         /* if this is remateriazable */
7494         if (AOP_TYPE(result) == AOP_IMMD) {
7495             emitcode("mov","dptr,%s",aopGet(AOP(result),0,TRUE,FALSE,FALSE));
7496             emitcode("mov","b,%s + 1",aopGet(AOP(result),0,TRUE,FALSE,FALSE));
7497         }
7498         else { /* we need to get it byte by byte */
7499             emitcode("mov","dpl,%s",aopGet(AOP(result),0,FALSE,FALSE,TRUE));
7500             emitcode("mov","dph,%s",aopGet(AOP(result),1,FALSE,FALSE,TRUE));
7501             emitcode("mov","dpx,%s",aopGet(AOP(result),2,FALSE,FALSE,TRUE));
7502             emitcode("mov","b,%s",aopGet(AOP(result),3,FALSE,FALSE,TRUE));
7503         }
7504         _endLazyDPSEvaluation();
7505     }
7506     /* so dptr know contains the address */
7507     freeAsmop(result,NULL,ic,TRUE);
7508     aopOp(right,ic,FALSE, TRUE);
7509
7510     /* if bit then unpack */
7511     if (IS_BITVAR(retype)) 
7512         genPackBits(retype,right,"dptr",GPOINTER);
7513     else {
7514         size = AOP_SIZE(right);
7515         offset = 0 ;
7516
7517         _startLazyDPSEvaluation();
7518         while (size--) {
7519             char *l = aopGet(AOP(right),offset++,FALSE,FALSE,TRUE);
7520             MOVA(l);
7521             
7522             genSetDPTR(0);
7523             _flushLazyDPS();
7524             
7525             emitcode("lcall","__gptrput");
7526             if (size)
7527                 emitcode("inc","dptr");
7528         }
7529         _endLazyDPSEvaluation();
7530     }
7531
7532     freeAsmop(right,NULL,ic,TRUE);
7533 }
7534
7535 /*-----------------------------------------------------------------*/
7536 /* genPointerSet - stores the value into a pointer location        */
7537 /*-----------------------------------------------------------------*/
7538 static void genPointerSet (iCode *ic)
7539 {    
7540     operand *right, *result ;
7541     link *type, *etype;
7542     int p_type;
7543
7544     D(emitcode(";", "genPointerSet "););
7545
7546     right = IC_RIGHT(ic);
7547     result = IC_RESULT(ic) ;
7548
7549     /* depending on the type of pointer we need to
7550     move it to the correct pointer register */
7551     type = operandType(result);
7552     etype = getSpec(type);
7553     /* if left is of type of pointer then it is simple */
7554     if (IS_PTR(type) && !IS_FUNC(type->next)) {
7555         p_type = DCL_TYPE(type);
7556     }
7557     else {
7558         /* we have to go by the storage class */
7559         p_type = PTR_TYPE(SPEC_OCLS(etype));
7560
7561 /*      if (SPEC_OCLS(etype)->codesp ) { */
7562 /*          p_type = CPOINTER ;  */
7563 /*      } */
7564 /*      else */
7565 /*          if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */
7566 /*              p_type = FPOINTER ; */
7567 /*          else */
7568 /*              if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */
7569 /*                  p_type = PPOINTER ; */
7570 /*              else */
7571 /*                  if (SPEC_OCLS(etype) == idata ) */
7572 /*                      p_type = IPOINTER ; */
7573 /*                  else */
7574 /*                      p_type = POINTER ; */
7575     }
7576
7577     /* now that we have the pointer type we assign
7578     the pointer values */
7579     switch (p_type) {
7580
7581     case POINTER:
7582     case IPOINTER:
7583         genNearPointerSet (right,result,ic);
7584         break;
7585
7586     case PPOINTER:
7587         genPagedPointerSet (right,result,ic);
7588         break;
7589
7590     case FPOINTER:
7591         genFarPointerSet (right,result,ic);
7592         break;
7593
7594     case GPOINTER:
7595         genGenPointerSet (right,result,ic);
7596         break;
7597     }
7598
7599 }
7600
7601 /*-----------------------------------------------------------------*/
7602 /* genIfx - generate code for Ifx statement                        */
7603 /*-----------------------------------------------------------------*/
7604 static void genIfx (iCode *ic, iCode *popIc)
7605 {
7606     operand *cond = IC_COND(ic);
7607     int isbit =0;
7608
7609     D(emitcode(";", "genIfx "););
7610
7611     aopOp(cond,ic,FALSE, FALSE);
7612
7613     /* get the value into acc */
7614     if (AOP_TYPE(cond) != AOP_CRY)
7615         toBoolean(cond);
7616     else
7617         isbit = 1;
7618     /* the result is now in the accumulator */
7619     freeAsmop(cond,NULL,ic,TRUE);
7620
7621     /* if there was something to be popped then do it */
7622     if (popIc)
7623         genIpop(popIc);
7624
7625     /* if the condition is  a bit variable */
7626     if (isbit && IS_ITEMP(cond) && 
7627         SPIL_LOC(cond))
7628         genIfxJump(ic,SPIL_LOC(cond)->rname);
7629     else
7630         if (isbit && !IS_ITEMP(cond))
7631             genIfxJump(ic,OP_SYMBOL(cond)->rname);
7632         else
7633             genIfxJump(ic,"a");
7634
7635     ic->generated = 1;
7636 }
7637
7638 /*-----------------------------------------------------------------*/
7639 /* genAddrOf - generates code for address of                       */
7640 /*-----------------------------------------------------------------*/
7641 static void genAddrOf (iCode *ic)
7642 {
7643     symbol *sym = OP_SYMBOL(IC_LEFT(ic));
7644     int size, offset ;
7645
7646     D(emitcode(";", "genAddrOf "););
7647
7648     aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
7649
7650     /* if the operand is on the stack then we 
7651     need to get the stack offset of this
7652     variable */
7653     if (sym->onStack) {
7654         /* if it has an offset then we need to compute
7655         it */
7656         if (sym->stack) {
7657             emitcode("mov","a,_bp");
7658             emitcode("add","a,#0x%02x",((char) sym->stack & 0xff));
7659             aopPut(AOP(IC_RESULT(ic)),"a",0);       
7660         } else {
7661             /* we can just move _bp */
7662             aopPut(AOP(IC_RESULT(ic)),"_bp",0);
7663         }
7664         /* fill the result with zero */
7665         size = AOP_SIZE(IC_RESULT(ic)) - 1;
7666         
7667         
7668         if (options.stack10bit && size < (FPTRSIZE - 1))
7669         {
7670             fprintf(stderr, 
7671                     "*** warning: pointer to stack var truncated.\n");
7672         }
7673         
7674         offset = 1;
7675         while (size--)
7676         {
7677             /* Yuck! */
7678             if (options.stack10bit && offset == 2)
7679             {
7680                 aopPut(AOP(IC_RESULT(ic)),"#0x40", offset++);
7681             }
7682             else
7683             {
7684                 aopPut(AOP(IC_RESULT(ic)),zero,offset++);
7685             }
7686         }
7687
7688         goto release;
7689     }
7690
7691     /* object not on stack then we need the name */
7692     size = AOP_SIZE(IC_RESULT(ic));
7693     offset = 0;
7694
7695     while (size--) {
7696         char s[SDCC_NAME_MAX];
7697         if (offset) 
7698             sprintf(s,"#(%s >> %d)",
7699                     sym->rname,
7700                     offset*8);
7701         else
7702             sprintf(s,"#%s",sym->rname);
7703         aopPut(AOP(IC_RESULT(ic)),s,offset++);
7704     }
7705
7706 release:
7707     freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
7708
7709 }
7710
7711 /*-----------------------------------------------------------------*/
7712 /* genFarFarAssign - assignment when both are in far space         */
7713 /*-----------------------------------------------------------------*/
7714 static void genFarFarAssign (operand *result, operand *right, iCode *ic)
7715 {
7716     int size = AOP_SIZE(right);
7717     int offset = 0;
7718     char *l;
7719
7720 #ifdef LAZY_DPS_OPT
7721     if (size > 1)
7722     {
7723         /* This is a net loss for size == 1, but a big gain
7724          * otherwise.
7725          */
7726         D(emitcode(";", "genFarFarAssign (improved)"););
7727
7728         aopOp(result,ic,TRUE, TRUE);
7729
7730         _startLazyDPSEvaluation();
7731         while (size--) 
7732         {
7733             aopPut(AOP(result),
7734                    aopGet(AOP(right),offset,FALSE,FALSE,FALSE),
7735                    offset);
7736             offset++;
7737         }
7738         _endLazyDPSEvaluation();    
7739         freeAsmop(result,NULL,ic,FALSE);
7740         freeAsmop(right,NULL,ic,FALSE);
7741     }
7742     else
7743 #endif
7744     {
7745     D(emitcode(";", "genFarFarAssign "););
7746
7747     /* first push the right side on to the stack */
7748     _startLazyDPSEvaluation();
7749     while (size--) {
7750         l = aopGet(AOP(right),offset++,FALSE,FALSE,TRUE);
7751         MOVA(l);
7752         emitcode ("push","acc");
7753     }
7754
7755     freeAsmop(right,NULL,ic,FALSE);
7756     /* now assign DPTR to result */
7757     aopOp(result,ic,FALSE, FALSE);
7758     size = AOP_SIZE(result);
7759     while (size--) {
7760         emitcode ("pop","acc");
7761         aopPut(AOP(result),"a",--offset);
7762     }
7763     freeAsmop(result,NULL,ic,FALSE);
7764     _endLazyDPSEvaluation();
7765     }
7766 }
7767
7768 /*-----------------------------------------------------------------*/
7769 /* genAssign - generate code for assignment                        */
7770 /*-----------------------------------------------------------------*/
7771 static void genAssign (iCode *ic)
7772 {
7773     operand *result, *right;
7774     int size, offset ;
7775         unsigned long lit = 0L;
7776
7777     D(emitcode(";", "genAssign "););
7778
7779     result = IC_RESULT(ic);
7780     right  = IC_RIGHT(ic) ;
7781
7782     /* if they are the same */
7783     if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic)))
7784         return ;
7785
7786     aopOp(right,ic,FALSE, FALSE);
7787     
7788     emitcode(";", "genAssign: resultIsFar = %s",
7789              isOperandInFarSpace(result) ?
7790              "TRUE" : "FALSE");
7791
7792     /* special case both in far space */
7793     if ((AOP_TYPE(right) == AOP_DPTR ||
7794          AOP_TYPE(right) == AOP_DPTR2) &&
7795     /* IS_TRUE_SYMOP(result)       && */
7796     isOperandInFarSpace(result)) {
7797         
7798         genFarFarAssign (result,right,ic);
7799         return ;
7800     }
7801
7802     aopOp(result,ic,TRUE, FALSE);
7803
7804     /* if they are the same registers */
7805     if (sameRegs(AOP(right),AOP(result)))
7806         goto release;
7807
7808     /* if the result is a bit */
7809     if (AOP_TYPE(result) == AOP_CRY) {
7810
7811         /* if the right size is a literal then
7812         we know what the value is */
7813         if (AOP_TYPE(right) == AOP_LIT) {
7814             if (((int) operandLitValue(right))) 
7815                 aopPut(AOP(result),one,0);
7816             else
7817                 aopPut(AOP(result),zero,0);
7818             goto release;
7819         }
7820
7821         /* the right is also a bit variable */
7822         if (AOP_TYPE(right) == AOP_CRY) {
7823             emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
7824             aopPut(AOP(result),"c",0);
7825             goto release ;
7826         }
7827
7828         /* we need to or */
7829         toBoolean(right);
7830         aopPut(AOP(result),"a",0);
7831         goto release ;
7832     }
7833
7834     /* bit variables done */
7835     /* general case */
7836     size = AOP_SIZE(result);
7837     offset = 0 ;
7838     if(AOP_TYPE(right) == AOP_LIT)
7839         lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
7840     
7841     if((size > 1) &&
7842        (AOP_TYPE(result) != AOP_REG) &&
7843        (AOP_TYPE(right) == AOP_LIT) &&
7844        !IS_FLOAT(operandType(right)) 
7845 #ifndef LAZY_DPS_OPT
7846        && (lit < 256L)
7847 #endif       
7848        )
7849     {
7850 #ifdef LAZY_DPS_OPT
7851         D(emitcode(";", "Kevin's better literal load code"););
7852         _startLazyDPSEvaluation();
7853         while (size && ((unsigned int)((lit >> (offset*8)) & 0xff) != 0))
7854         {
7855             aopPut(AOP(result),
7856                    aopGet(AOP(right),offset,FALSE,FALSE,TRUE),
7857                    offset);
7858             offset++;
7859             size--;
7860         }
7861         /* And now fill the rest with zeros. */
7862         if (size)
7863         {
7864             emitcode("clr","a");
7865         }
7866         while (size--)
7867         {
7868             aopPut(AOP(result), "a", offset++);
7869         }
7870         _endLazyDPSEvaluation();
7871 #else
7872         emitcode("clr","a");
7873         
7874         _startLazyDPSEvaluation();
7875         while (size--) 
7876         {
7877             if((unsigned int)((lit >> (size*8)) & 0x0FFL)== 0)
7878                 aopPut(AOP(result),"a",size);
7879             else
7880                 aopPut(AOP(result),
7881                        aopGet(AOP(right),size,FALSE,FALSE,FALSE),
7882                        size);
7883         }
7884         _endLazyDPSEvaluation();
7885 #endif  
7886     } 
7887     else 
7888     {
7889         _startLazyDPSEvaluation();
7890         while (size--) 
7891         {
7892             aopPut(AOP(result),
7893                    aopGet(AOP(right),offset,FALSE,FALSE,FALSE),
7894                    offset);
7895             offset++;
7896         }
7897         _endLazyDPSEvaluation();
7898     }
7899     
7900 release:
7901     freeAsmop (right,NULL,ic,FALSE);
7902     freeAsmop (result,NULL,ic,TRUE);
7903 }   
7904
7905 /*-----------------------------------------------------------------*/
7906 /* genJumpTab - generates code for jump table                      */
7907 /*-----------------------------------------------------------------*/
7908 static void genJumpTab (iCode *ic)
7909 {
7910     symbol *jtab;
7911     char *l;
7912
7913     D(emitcode(";", "genJumpTab "););
7914
7915     aopOp(IC_JTCOND(ic),ic,FALSE, FALSE);
7916     /* get the condition into accumulator */
7917     l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE,FALSE,TRUE);
7918     MOVA(l);
7919     /* multiply by four! */
7920     emitcode("add","a,acc");
7921     emitcode("add","a,acc");
7922     freeAsmop(IC_JTCOND(ic),NULL,ic,TRUE);
7923
7924     jtab = newiTempLabel(NULL);
7925     emitcode("mov","dptr,#%05d$",jtab->key+100);
7926     emitcode("jmp","@a+dptr");
7927     emitcode("","%05d$:",jtab->key+100);
7928     /* now generate the jump labels */
7929     for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
7930          jtab = setNextItem(IC_JTLABELS(ic)))
7931         emitcode("ljmp","%05d$",jtab->key+100);
7932
7933 }
7934
7935 /*-----------------------------------------------------------------*/
7936 /* genCast - gen code for casting                                  */
7937 /*-----------------------------------------------------------------*/
7938 static void genCast (iCode *ic)
7939 {
7940     operand *result = IC_RESULT(ic);
7941     link *ctype = operandType(IC_LEFT(ic));
7942     link *rtype = operandType(IC_RIGHT(ic));
7943     operand *right = IC_RIGHT(ic);
7944     int size, offset ;
7945
7946     D(emitcode(";", "genCast "););
7947
7948     /* if they are equivalent then do nothing */
7949     if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
7950         return ;
7951
7952     aopOp(right,ic,FALSE, FALSE) ;
7953     aopOp(result,ic,FALSE, AOP_TYPE(right) == AOP_DPTR);
7954
7955     /* if the result is a bit */
7956     if (AOP_TYPE(result) == AOP_CRY) {
7957         /* if the right size is a literal then
7958         we know what the value is */
7959         if (AOP_TYPE(right) == AOP_LIT) {
7960             if (((int) operandLitValue(right))) 
7961                 aopPut(AOP(result),one,0);
7962             else
7963                 aopPut(AOP(result),zero,0);
7964
7965             goto release;
7966         }
7967
7968         /* the right is also a bit variable */
7969         if (AOP_TYPE(right) == AOP_CRY) {
7970             emitcode("mov","c,%s",AOP(right)->aopu.aop_dir);
7971             aopPut(AOP(result),"c",0);
7972             goto release ;
7973         }
7974
7975         /* we need to or */
7976         toBoolean(right);
7977         aopPut(AOP(result),"a",0);
7978         goto release ;
7979     }
7980
7981     /* if they are the same size : or less */
7982     if (AOP_SIZE(result) <= AOP_SIZE(right)) {
7983
7984         /* if they are in the same place */
7985         if (sameRegs(AOP(right),AOP(result)))
7986             goto release;
7987
7988         /* if they in different places then copy */
7989         size = AOP_SIZE(result);
7990         offset = 0 ;
7991         _startLazyDPSEvaluation();
7992         while (size--) {
7993             aopPut(AOP(result),
7994                    aopGet(AOP(right),offset,FALSE,FALSE,FALSE),
7995                    offset);
7996             offset++;
7997         }
7998         _endLazyDPSEvaluation();
7999         goto release;
8000     }
8001
8002
8003     /* if the result is of type pointer */
8004     if (IS_PTR(ctype)) {
8005
8006         int p_type;
8007         link *type = operandType(right);
8008
8009         /* pointer to generic pointer */
8010         if (IS_GENPTR(ctype)) {
8011             char *l = zero;
8012             
8013             if (IS_PTR(type)) 
8014             {
8015                 p_type = DCL_TYPE(type);
8016             }
8017             else 
8018             {
8019 #if OLD_CAST_BEHAVIOR
8020                 /* KV: we are converting a non-pointer type to
8021                  * a generic pointer. This (ifdef'd out) code
8022                  * says that the resulting generic pointer 
8023                  * should have the same class as the storage
8024                  * location of the non-pointer variable.
8025                  * 
8026                  * For example, converting an int (which happens
8027                  * to be stored in DATA space) to a pointer results
8028                  * in a DATA generic pointer; if the original int
8029                  * in XDATA space, so will be the resulting pointer.
8030                  *
8031                  * I don't like that behavior, and thus this change:
8032                  * all such conversions will be forced to XDATA and
8033                  * throw a warning. If you want some non-XDATA
8034                  * type, or you want to suppress the warning, you
8035                  * must go through an intermediate cast, like so:
8036                  *
8037                  * char _generic *gp = (char _xdata *)(intVar);
8038                  */
8039                 link *etype = getSpec(type);             
8040
8041                 /* we have to go by the storage class */
8042                 if (SPEC_OCLS(etype) != generic)
8043                 {
8044                     p_type = PTR_TYPE(SPEC_OCLS(etype));
8045                 }
8046                 else
8047 #endif          
8048                 {
8049                     /* Converting unknown class (i.e. register variable)
8050                      * to generic pointer. This is not good, but
8051                      * we'll make a guess (and throw a warning).
8052                      */
8053                     p_type = FPOINTER;
8054                     werror(W_INT_TO_GEN_PTR_CAST);           
8055                 }
8056             }
8057                 
8058             /* the first two bytes are known */
8059             size = GPTRSIZE - 1; 
8060             offset = 0 ;
8061             _startLazyDPSEvaluation();
8062             while (size--) {
8063                 aopPut(AOP(result),
8064                        aopGet(AOP(right),offset,FALSE,FALSE,FALSE),
8065                        offset);
8066                 offset++;
8067             }
8068             _endLazyDPSEvaluation();
8069             
8070             /* the last byte depending on type */
8071             switch (p_type) {
8072             case IPOINTER:
8073             case POINTER:
8074                 l = zero;
8075                 break;
8076             case FPOINTER:
8077                 l = one;
8078                 break;
8079             case CPOINTER:
8080                 l = "#0x02";
8081                 break;                          
8082             case PPOINTER:
8083                 l = "#0x03";
8084                 break;
8085                 
8086             default:
8087                 /* this should never happen */
8088                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
8089                        "got unknown pointer type");
8090                 exit(1);
8091             }
8092             aopPut(AOP(result),l, GPTRSIZE - 1);            
8093             goto release ;
8094         }
8095         
8096         /* just copy the pointers */
8097         size = AOP_SIZE(result);
8098         offset = 0 ;
8099         _startLazyDPSEvaluation();
8100         while (size--) {
8101             aopPut(AOP(result),
8102                    aopGet(AOP(right),offset,FALSE,FALSE,FALSE),
8103                    offset);
8104             offset++;
8105         }
8106         _endLazyDPSEvaluation();
8107         goto release ;
8108     }
8109     
8110     /* so we now know that the size of destination is greater
8111     than the size of the source */
8112     /* we move to result for the size of source */
8113     size = AOP_SIZE(right);
8114     offset = 0 ;
8115     _startLazyDPSEvaluation();
8116     while (size--) {
8117         aopPut(AOP(result),
8118                aopGet(AOP(right),offset,FALSE,FALSE,FALSE),
8119                offset);
8120         offset++;
8121     }
8122     _endLazyDPSEvaluation();
8123
8124     /* now depending on the sign of the source && destination */
8125     size = AOP_SIZE(result) - AOP_SIZE(right);
8126     /* if unsigned or not an integral type */
8127     if (SPEC_USIGN(rtype) || !IS_SPEC(rtype)) {
8128         while (size--)
8129             aopPut(AOP(result),zero,offset++);
8130     } else {
8131         /* we need to extend the sign :{ */
8132         char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
8133                          FALSE,FALSE,TRUE);
8134         MOVA(l);
8135         emitcode("rlc","a");
8136         emitcode("subb","a,acc");
8137         while (size--)
8138             aopPut(AOP(result),"a",offset++);   
8139     }
8140
8141     /* we are done hurray !!!! */
8142
8143 release:
8144     freeAsmop(right,NULL,ic,TRUE);
8145     freeAsmop(result,NULL,ic,TRUE);
8146
8147 }
8148
8149 /*-----------------------------------------------------------------*/
8150 /* genDjnz - generate decrement & jump if not zero instrucion      */
8151 /*-----------------------------------------------------------------*/
8152 static int genDjnz (iCode *ic, iCode *ifx)
8153 {
8154     symbol *lbl, *lbl1;
8155     if (!ifx)
8156         return 0;
8157     
8158     /* if the if condition has a false label
8159        then we cannot save */
8160     if (IC_FALSE(ifx))
8161         return 0;
8162
8163     /* if the minus is not of the form 
8164        a = a - 1 */
8165     if (!isOperandEqual(IC_RESULT(ic),IC_LEFT(ic)) ||
8166         !IS_OP_LITERAL(IC_RIGHT(ic)))
8167         return 0;
8168
8169     if (operandLitValue(IC_RIGHT(ic)) != 1)
8170         return 0;
8171
8172     /* if the size of this greater than one then no
8173        saving */
8174     if (getSize(operandType(IC_RESULT(ic))) > 1)
8175         return 0;
8176
8177     /* otherwise we can save BIG */
8178     lbl = newiTempLabel(NULL);
8179     lbl1= newiTempLabel(NULL);
8180
8181     aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
8182     
8183     if (IS_AOP_PREG(IC_RESULT(ic))) {
8184         emitcode("dec","%s",
8185                  aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE,FALSE));
8186         emitcode("mov","a,%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE,FALSE));
8187         emitcode("jnz","%05d$",lbl->key+100);
8188     } else {    
8189         emitcode ("djnz","%s,%05d$",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE,FALSE),
8190                   lbl->key+100);
8191     }
8192     emitcode ("sjmp","%05d$",lbl1->key+100);
8193     emitcode ("","%05d$:",lbl->key+100);
8194     emitcode ("ljmp","%05d$",IC_TRUE(ifx)->key+100);
8195     emitcode ("","%05d$:",lbl1->key+100);
8196     
8197     freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
8198     ifx->generated = 1;
8199     return 1;
8200 }
8201
8202 /*-----------------------------------------------------------------*/
8203 /* genReceive - generate code for a receive iCode                  */
8204 /*-----------------------------------------------------------------*/
8205 static void genReceive (iCode *ic)
8206 {    
8207
8208     D(emitcode(";", "genReceive "););
8209
8210     if (isOperandInFarSpace(IC_RESULT(ic)) && 
8211         ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
8212           IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
8213         int size = getSize(operandType(IC_RESULT(ic)));
8214         int offset =  fReturnSize_390 - size;
8215         while (size--) {
8216             emitcode ("push","%s", (strcmp(fReturn[fReturnSize_390 - offset - 1],"a") ?
8217                                     fReturn[fReturnSize_390 - offset - 1] : "acc"));
8218             offset++;
8219         }
8220         aopOp(IC_RESULT(ic),ic,FALSE, FALSE);
8221         size = AOP_SIZE(IC_RESULT(ic));
8222         offset = 0;
8223         while (size--) {
8224             emitcode ("pop","acc");
8225             aopPut (AOP(IC_RESULT(ic)),"a",offset++);
8226         }
8227         
8228     } else {
8229         _G.accInUse++;
8230         aopOp(IC_RESULT(ic),ic,FALSE, FALSE);  
8231         _G.accInUse--;
8232         assignResultValue(IC_RESULT(ic));       
8233     }
8234
8235     freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
8236 }
8237
8238 /*-----------------------------------------------------------------*/
8239 /* gen390Code - generate code for 8051 based controllers            */
8240 /*-----------------------------------------------------------------*/
8241 void gen390Code (iCode *lic)
8242 {
8243     iCode *ic;
8244     int cln = 0;
8245
8246     lineHead = lineCurr = NULL;
8247
8248     /* print the allocation information */
8249     if (allocInfo)
8250         printAllocInfo( currFunc, codeOutFile);
8251     /* if debug information required */
8252 /*     if (options.debug && currFunc) { */
8253     if (currFunc) {
8254         cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
8255         _G.debugLine = 1;
8256         if (IS_STATIC(currFunc->etype))
8257             emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name); 
8258         else
8259             emitcode("","G$%s$0$0 ==.",currFunc->name);
8260         _G.debugLine = 0;
8261     }
8262     /* stack pointer name */
8263     if (options.useXstack)
8264         spname = "_spx";
8265     else
8266         spname = "sp";
8267     
8268  
8269     for (ic = lic ; ic ; ic = ic->next ) {
8270         
8271         if ( cln != ic->lineno ) {
8272             if ( options.debug ) {
8273                 _G.debugLine = 1;
8274                 emitcode("","C$%s$%d$%d$%d ==.",
8275                          ic->filename,ic->lineno,
8276                          ic->level,ic->block);
8277                 _G.debugLine = 0;
8278             }
8279             emitcode(";","%s %d",ic->filename,ic->lineno);
8280             cln = ic->lineno ;
8281         }
8282         /* if the result is marked as
8283            spilt and rematerializable or code for
8284            this has already been generated then
8285            do nothing */
8286         if (resultRemat(ic) || ic->generated ) 
8287             continue ;
8288         
8289         /* depending on the operation */
8290         switch (ic->op) {
8291         case '!' :
8292             genNot(ic);
8293             break;
8294             
8295         case '~' :
8296             genCpl(ic);
8297             break;
8298             
8299         case UNARYMINUS:
8300             genUminus (ic);
8301             break;
8302             
8303         case IPUSH:
8304             genIpush (ic);
8305             break;
8306             
8307         case IPOP:
8308             /* IPOP happens only when trying to restore a 
8309                spilt live range, if there is an ifx statement
8310                following this pop then the if statement might
8311                be using some of the registers being popped which
8312                would destory the contents of the register so
8313                we need to check for this condition and handle it */
8314             if (ic->next            && 
8315                 ic->next->op == IFX &&
8316                 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) 
8317                 genIfx (ic->next,ic);
8318             else
8319                 genIpop (ic);
8320             break; 
8321             
8322         case CALL:
8323             genCall (ic);
8324             break;
8325             
8326         case PCALL:
8327             genPcall (ic);
8328             break;
8329             
8330         case FUNCTION:
8331             genFunction (ic);
8332             break;
8333             
8334         case ENDFUNCTION:
8335             genEndFunction (ic);
8336             break;
8337             
8338         case RETURN:
8339             genRet (ic);
8340             break;
8341             
8342         case LABEL:
8343             genLabel (ic);
8344             break;
8345             
8346         case GOTO:
8347             genGoto (ic);
8348             break;
8349             
8350         case '+' :
8351             genPlus (ic) ;
8352             break;
8353             
8354         case '-' :
8355             if ( ! genDjnz (ic,ifxForOp(IC_RESULT(ic),ic)))
8356                 genMinus (ic);
8357             break;
8358             
8359         case '*' :
8360             genMult (ic);
8361             break;
8362             
8363         case '/' :
8364             genDiv (ic) ;
8365             break;
8366             
8367         case '%' :
8368             genMod (ic);
8369             break;
8370             
8371         case '>' :
8372             genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));                 
8373             break;
8374             
8375         case '<' :
8376             genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
8377             break;
8378             
8379         case LE_OP:
8380         case GE_OP:
8381         case NE_OP:
8382             
8383             /* note these two are xlated by algebraic equivalence
8384                during parsing SDCC.y */
8385             werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
8386                    "got '>=' or '<=' shouldn't have come here");
8387             break;      
8388             
8389         case EQ_OP:
8390             genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
8391             break;          
8392             
8393         case AND_OP:
8394             genAndOp (ic);
8395             break;
8396             
8397         case OR_OP:
8398             genOrOp (ic);
8399             break;
8400             
8401         case '^' :
8402             genXor (ic,ifxForOp(IC_RESULT(ic),ic));
8403             break;
8404             
8405         case '|' :
8406                 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
8407             break;
8408             
8409         case BITWISEAND:
8410             genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
8411             break;
8412             
8413         case INLINEASM:
8414             genInline (ic);
8415             break;
8416             
8417         case RRC:
8418             genRRC (ic);
8419             break;
8420             
8421         case RLC:
8422             genRLC (ic);
8423             break;
8424             
8425         case GETHBIT:
8426             genGetHbit (ic);
8427             break;
8428             
8429         case LEFT_OP:
8430             genLeftShift (ic);
8431             break;
8432             
8433         case RIGHT_OP:
8434             genRightShift (ic);
8435             break;
8436             
8437         case GET_VALUE_AT_ADDRESS:
8438             genPointerGet(ic);
8439             break;
8440             
8441         case '=' :
8442             if (POINTER_SET(ic))
8443                 genPointerSet(ic);
8444             else
8445                 genAssign(ic);
8446             break;
8447             
8448         case IFX:
8449             genIfx (ic,NULL);
8450             break;
8451             
8452         case ADDRESS_OF:
8453             genAddrOf (ic);
8454             break;
8455             
8456         case JUMPTABLE:
8457             genJumpTab (ic);
8458             break;
8459             
8460         case CAST:
8461             genCast (ic);
8462             break;
8463             
8464         case RECEIVE:
8465             genReceive(ic);
8466             break;
8467             
8468         case SEND:
8469             addSet(&_G.sendSet,ic);
8470             break;
8471
8472         default :
8473             ic = ic;
8474             /*      piCode(ic,stdout); */
8475             
8476         }
8477     }
8478     
8479
8480     /* now we are ready to call the 
8481        peep hole optimizer */
8482     if (!options.nopeep)
8483         peepHole (&lineHead);
8484
8485     /* now do the actual printing */
8486     printLine (lineHead,codeOutFile);    
8487     return;
8488 }