cleaned up the mess I left behind
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for DS80C390
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   DS390 adaptation by Kevin Vigor <kevin@vigor.nu>
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23   In other words, you are welcome to use, share and improve this program.
24   You are forbidden to forbid anyone else to use, share and improve
25   what you give them.   Help stamp out software-hoarding!
26 -------------------------------------------------------------------------*/
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32
33 #include "common.h"
34 #include "ralloc.h"
35 #include "gen.h"
36 #include "SDCCglobl.h"
37 #include "newalloc.h"
38
39 #define BETTER_LITERAL_SHIFT
40
41 char *aopLiteral (value * val, int offset);
42 extern int allocInfo;
43
44 /* this is the down and dirty file with all kinds of
45    kludgy & hacky stuff. This is what it is all about
46    CODE GENERATION for a specific MCU . some of the
47    routines may be reusable, will have to see */
48
49 static char *zero = "#0";
50 static char *one = "#1";
51 static char *spname;
52
53 #define D(x) x
54
55 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
56 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
57
58 unsigned fReturnSizeDS390 = 5;  /* shared with ralloc.c */
59 static char *fReturn24[] =
60 {"dpl", "dph", "dpx", "b", "a"};
61 static char *fReturn16[] =
62 {"dpl", "dph", "b", "a"};
63 static char **fReturn = fReturn24;
64 static char *accUse[] =
65 {"a", "b"};
66 static char *dptrn[2][3];
67 static char *javaRet[] = { "r0","r1","r2","r3"};
68 static short rbank = -1;
69
70 static struct
71   {
72     short r0Pushed;
73     short r1Pushed;
74     short accInUse;
75     short bInUse;
76     short inLine;
77     short debugLine;
78     short nRegsSaved;
79     short dptrInUse;
80     short dptr1InUse;
81     set *sendSet;
82   }
83 _G;
84
85 static char *rb1regs[] = {
86     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
87 };
88
89 static void saveRBank (int, iCode *, bool);
90
91 #define RESULTONSTACK(x) \
92                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
93                          IC_RESULT(x)->aop->type == AOP_STK )
94
95 #define MOVA(x) _movA(x)
96 #define MOVB(x) _movB(x)
97                 
98 #define CLRC    emitcode("clr","c")
99 #define SETC    emitcode("setb","c")
100
101 // A scratch register which will be used to hold
102 // result bytes from operands in far space via DPTR2.
103 #define DP2_RESULT_REG  "_ap"
104
105 static lineNode *lineHead = NULL;
106 static lineNode *lineCurr = NULL;
107
108 static unsigned char SLMask[] =
109 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
110  0xE0, 0xC0, 0x80, 0x00};
111 static unsigned char SRMask[] =
112 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
113  0x07, 0x03, 0x01, 0x00};
114
115 #define LSB     0
116 #define MSB16   1
117 #define MSB24   2
118 #define MSB32   3
119 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
120                                 symbol *lbl = newiTempLabel(NULL);              \
121                                 emitcode ("setb","F1");                         \
122                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
123                                 emitcode ("clr","F1");                          \
124                                 emitcode ("","!tlabeldef",lbl->key+100);        \
125                         }}
126 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
127                                 symbol *lbl = newiTempLabel(NULL);              \
128                                 emitcode ("jnb","F1,!tlabel",lbl->key+100);     \
129                                 emitcode ("setb","EA");                         \
130                                 emitcode ("","!tlabeldef",lbl->key+100);        \
131                         }}
132
133
134 /*-----------------------------------------------------------------*/
135 /* emitcode - writes the code into a file : for now it is simple    */
136 /*-----------------------------------------------------------------*/
137 static void
138 emitcode (char *inst, char *fmt,...)
139 {
140     va_list ap;
141     char lb[INITIAL_INLINEASM];
142     char *lbp = lb;
143     
144     va_start (ap, fmt);
145     
146     if (inst && *inst)
147     {
148         if (fmt && *fmt)
149         {
150             SNPRINTF (lb, sizeof(lb), "%s\t", inst);
151         }
152         else
153         {
154             SNPRINTF (lb, sizeof(lb), "%s", inst);
155         }
156         
157         tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), 
158                    fmt, ap);
159     }
160     else
161     {
162         tvsprintf (lb, sizeof(lb), fmt, ap);
163     }
164     
165
166     while (isspace (*lbp))
167     {
168         lbp++;
169     }
170
171     if (lbp && *lbp)
172     {
173         lineCurr = (lineCurr ?
174                     connectLine (lineCurr, newLineNode (lb)) :
175                     (lineHead = newLineNode (lb)));
176     }
177     
178     lineCurr->isInline = _G.inLine;
179     lineCurr->isDebug = _G.debugLine;
180     va_end (ap);
181 }
182
183 //
184 // Move the passed value into A unless it is already there.
185 // 
186 static void
187 _movA(const char *s)
188 {
189     if (strcmp(s,"a") && strcmp(s,"acc"))
190     { 
191         emitcode("mov","a,%s",s);
192     } 
193 }
194
195 //
196 // Move the passed value into B unless it is already there.
197 // 
198 static void
199 _movB(const char *s)
200 {
201     if (strcmp(s,"b"))
202     { 
203         emitcode("mov","b,%s",s);
204     } 
205 }
206
207 /*-----------------------------------------------------------------*/
208 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
209 /*-----------------------------------------------------------------*/
210 static regs *
211 getFreePtr (iCode * ic, asmop ** aopp, bool result)
212 {
213   bool r0iu, r1iu;
214   bool r0ou, r1ou;
215
216   /* the logic: if r0 & r1 used in the instruction
217      then we are in trouble otherwise */
218
219   /* first check if r0 & r1 are used by this
220      instruction, in which case we are in trouble */
221   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
222   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
223   if (r0iu && r1iu) {
224       goto endOfWorld;
225     }
226
227   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
228   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
229
230   /* if no usage of r0 then return it */
231   if (!r0iu && !r0ou)
232     {
233       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
234       (*aopp)->type = AOP_R0;
235
236       return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R0_IDX);
237     }
238
239   /* if no usage of r1 then return it */
240   if (!r1iu && !r1ou)
241     {
242       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
243       (*aopp)->type = AOP_R1;
244
245       return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R1_IDX);
246     }
247
248   /* now we know they both have usage */
249   /* if r0 not used in this instruction */
250   if (!r0iu)
251     {
252       /* push it if not already pushed */
253       if (!_G.r0Pushed)
254         {
255           emitcode ("push", "%s",
256                     ds390_regWithIdx (R0_IDX)->dname);
257           _G.r0Pushed++;
258         }
259
260       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
261       (*aopp)->type = AOP_R0;
262
263       return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R0_IDX);
264     }
265
266   /* if r1 not used then */
267
268   if (!r1iu)
269     {
270       /* push it if not already pushed */
271       if (!_G.r1Pushed)
272         {
273           emitcode ("push", "%s",
274                     ds390_regWithIdx (R1_IDX)->dname);
275           _G.r1Pushed++;
276         }
277
278       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
279       (*aopp)->type = AOP_R1;
280       return ds390_regWithIdx (R1_IDX);
281     }
282
283 endOfWorld:
284   /* I said end of world but not quite end of world yet */
285   /* if this is a result then we can push it on the stack */
286   if (result)
287     {
288       (*aopp)->type = AOP_STK;
289       return NULL;
290     }
291
292   /* other wise this is true end of the world */
293   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
294           "getFreePtr should never reach here");
295   exit (1);
296     
297   return NULL; // notreached, but makes compiler happy.
298 }
299
300 /*-----------------------------------------------------------------*/
301 /* newAsmop - creates a new asmOp                                  */
302 /*-----------------------------------------------------------------*/
303 static asmop *
304 newAsmop (short type)
305 {
306   asmop *aop;
307
308   aop = Safe_calloc (1, sizeof (asmop));
309   aop->type = type;
310   return aop;
311 }
312
313 static int _currentDPS;         /* Current processor DPS. */
314 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
315 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
316
317 /*-----------------------------------------------------------------*/
318 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
319 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
320 /* alternate DPTR (DPL1/DPH1/DPX1).          */
321 /*-----------------------------------------------------------------*/
322 static void
323 genSetDPTR (int n)
324 {
325
326   /* If we are doing lazy evaluation, simply note the desired
327    * change, but don't emit any code yet.
328    */
329   if (_lazyDPS)
330     {
331       _desiredDPS = n;
332       return;
333     }
334
335   if (!n)
336     {
337       emitcode ("mov", "dps,#0");
338     }
339   else
340     {
341       TR_DPTR("#1");
342       emitcode ("mov", "dps,#1");
343     }
344 }
345
346 /*-----------------------------------------------------------------*/
347 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
348 /*                   */
349 /* Any code that operates on DPTR (NB: not on the individual     */
350 /* components, like DPH) *must* call _flushLazyDPS() before using  */
351 /* DPTR within a lazy DPS evaluation block.        */
352 /*                   */
353 /* Note that aopPut and aopGet already contain the proper calls to */
354 /* _flushLazyDPS, so it is safe to use these calls within a lazy   */
355 /* DPS evaluation block.             */
356 /*                   */
357 /* Also, _flushLazyDPS must be called before any flow control      */
358 /* operations that could potentially branch out of the block.    */
359 /*                         */
360 /* Lazy DPS evaluation is simply an optimization (though an      */
361 /* important one), so if in doubt, leave it out.       */
362 /*-----------------------------------------------------------------*/
363 static void
364 _startLazyDPSEvaluation (void)
365 {
366   _currentDPS = 0;
367   _desiredDPS = 0;
368 #ifdef BETTER_LITERAL_SHIFT  
369   _lazyDPS++;
370 #else
371   _lazyDPS = 1;
372 #endif  
373 }
374
375 /*-----------------------------------------------------------------*/
376 /* _flushLazyDPS: emit code to force the actual DPS setting to the */
377 /* desired one. Call before using DPTR within a lazy DPS evaluation */
378 /* block.                */
379 /*-----------------------------------------------------------------*/
380 static void
381 _flushLazyDPS (void)
382 {
383   if (!_lazyDPS)
384     {
385       /* nothing to do. */
386       return;
387     }
388
389   if (_desiredDPS != _currentDPS)
390     {
391       if (_desiredDPS)
392         {
393           emitcode ("inc", "dps");
394         }
395       else
396         {
397           emitcode ("dec", "dps");
398         }
399       _currentDPS = _desiredDPS;
400     }
401 }
402
403 /*-----------------------------------------------------------------*/
404 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.     */
405 /*                   */
406 /* Forces us back to the safe state (standard DPTR selected).    */
407 /*-----------------------------------------------------------------*/
408 static void
409 _endLazyDPSEvaluation (void)
410 {
411 #ifdef BETTER_LITERAL_SHIFT  
412   _lazyDPS--;
413 #else
414   _lazyDPS = 0;
415 #endif    
416   if (!_lazyDPS)
417   {
418     if (_currentDPS)
419     {
420       genSetDPTR (0);
421       _flushLazyDPS ();
422     }
423     _currentDPS = 0;
424     _desiredDPS = 0;
425   }
426 }
427
428
429
430 /*-----------------------------------------------------------------*/
431 /* pointerCode - returns the code for a pointer type               */
432 /*-----------------------------------------------------------------*/
433 static int
434 pointerCode (sym_link * etype)
435 {
436
437   return PTR_TYPE (SPEC_OCLS (etype));
438
439 }
440
441 /*-----------------------------------------------------------------*/
442 /* aopForSym - for a true symbol                                   */
443 /*-----------------------------------------------------------------*/
444 static asmop *
445 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
446 {
447   asmop *aop;
448   memmap *space = SPEC_OCLS (sym->etype);
449
450   /* if already has one */
451   if (sym->aop)
452     return sym->aop;
453
454   /* assign depending on the storage class */
455   /* if it is on the stack or indirectly addressable */
456   /* space we need to assign either r0 or r1 to it   */
457   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
458     {
459       sym->aop = aop = newAsmop (0);
460       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
461       aop->size = getSize (sym->type);
462
463       /* now assign the address of the variable to
464          the pointer register */
465       if (aop->type != AOP_STK)
466         {
467
468           if (sym->onStack)
469             {
470               if (_G.accInUse)
471                 emitcode ("push", "acc");
472
473               if (_G.bInUse)
474                 emitcode ("push", "b");
475
476               emitcode ("mov", "a,_bp");
477               emitcode ("add", "a,#!constbyte",
478                         ((sym->stack < 0) ?
479                          ((char) (sym->stack - _G.nRegsSaved)) :
480                          ((char) sym->stack)) & 0xff);
481               emitcode ("mov", "%s,a",
482                         aop->aopu.aop_ptr->name);
483
484               if (_G.bInUse)
485                 emitcode ("pop", "b");
486
487               if (_G.accInUse)
488                 emitcode ("pop", "acc");
489             }
490           else
491             emitcode ("mov", "%s,#%s",
492                       aop->aopu.aop_ptr->name,
493                       sym->rname);
494           aop->paged = space->paged;
495         }
496       else
497         aop->aopu.aop_stk = sym->stack;
498       return aop;
499     }
500
501   if (sym->onStack && options.stack10bit)
502     {
503         short stack_val = -((sym->stack < 0) ?
504                             ((short) (sym->stack - _G.nRegsSaved)) :
505                             ((short) sym->stack)) ;
506         if (useDP2 && _G.dptr1InUse) {
507             emitcode ("push","dpl1");
508             emitcode ("push","dph1");
509             emitcode ("push","dpx1");
510         } else if (_G.dptrInUse ) {
511             emitcode ("push","dpl");
512             emitcode ("push","dph");
513             emitcode ("push","dpx");
514         }
515       /* It's on the 10 bit stack, which is located in
516        * far data space.
517        */           
518         if (stack_val < 0 && stack_val > -5) { /* between -5 & -1 */
519             if (useDP2) {
520                 if (options.model == MODEL_FLAT24)
521                     emitcode ("mov", "dpx1,#!constbyte", (options.stack_loc >> 16) & 0xff);
522                 TR_DPTR("#2");
523                 emitcode ("mov", "dph1,_bpx+1");
524                 emitcode ("mov", "dpl1,_bpx");
525                 emitcode ("mov","dps,#1");
526             } else {
527                 if (options.model == MODEL_FLAT24)
528                     emitcode ("mov", "dpx,#!constbyte", (options.stack_loc >> 16) & 0xff);
529                 emitcode ("mov", "dph,_bpx+1");
530                 emitcode ("mov", "dpl,_bpx");
531             }
532             stack_val = -stack_val;
533             while (stack_val--) {
534                 emitcode ("inc","dptr");
535             }
536             if (useDP2) {
537                 emitcode("mov","dps,#0");
538             }
539         }  else {
540             if (_G.accInUse)
541                 emitcode ("push", "acc");
542             
543             if (_G.bInUse)
544                 emitcode ("push", "b");
545         
546             emitcode ("mov", "a,_bpx");
547             emitcode ("clr","c");
548             emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
549             emitcode ("mov","b,a");
550             emitcode ("mov","a,_bpx+1");
551             emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
552             if (useDP2) {
553                 if (options.model == MODEL_FLAT24)
554                     emitcode ("mov", "dpx1,#!constbyte", (options.stack_loc >> 16) & 0xff);
555                 TR_DPTR("#2");
556                 emitcode ("mov", "dph1,a");
557                 emitcode ("mov", "dpl1,b");
558             } else {
559                 if (options.model == MODEL_FLAT24)
560                     emitcode ("mov", "dpx,#!constbyte", (options.stack_loc >> 16) & 0xff);
561                 emitcode ("mov", "dph,a");
562                 emitcode ("mov", "dpl,b");
563             }
564             
565             if (_G.bInUse)
566                 emitcode ("pop", "b");
567             
568             if (_G.accInUse)
569                 emitcode ("pop", "acc");
570         }
571         sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
572         aop->size = getSize (sym->type);
573         return aop;
574     }
575
576   /* if in bit space */
577   if (IN_BITSPACE (space))
578     {
579       sym->aop = aop = newAsmop (AOP_CRY);
580       aop->aopu.aop_dir = sym->rname;
581       aop->size = getSize (sym->type);
582       return aop;
583     }
584   /* if it is in direct space */
585   if (IN_DIRSPACE (space))
586     {
587       sym->aop = aop = newAsmop (AOP_DIR);
588       aop->aopu.aop_dir = sym->rname;
589       aop->size = getSize (sym->type);
590       return aop;
591     }
592
593   /* special case for a function */
594   if (IS_FUNC (sym->type))
595     {
596       sym->aop = aop = newAsmop (AOP_IMMD);
597       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);   
598       aop->size = FPTRSIZE;
599       return aop;
600     }
601   
602   /* only remaining is far space */
603   /* in which case DPTR gets the address */
604   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
605   if (useDP2)
606     {
607       genSetDPTR (1);
608       _flushLazyDPS ();
609       emitcode ("mov", "dptr,#%s", sym->rname);
610       genSetDPTR (0);
611     }
612   else
613     {
614       emitcode ("mov", "dptr,#%s", sym->rname);
615     }
616   aop->size = getSize (sym->type);
617
618   /* if it is in code space */
619   if (IN_CODESPACE (space))
620     aop->code = 1;
621
622   return aop;
623 }
624
625 /*-----------------------------------------------------------------*/
626 /* aopForRemat - rematerialzes an object                           */
627 /*-----------------------------------------------------------------*/
628 static asmop *
629 aopForRemat (symbol * sym)
630 {
631   iCode *ic = sym->rematiCode;
632   asmop *aop = newAsmop (AOP_IMMD);
633   int ptr_type =0;
634   int val = 0;
635
636   for (;;)
637     {
638       if (ic->op == '+')
639         val += (int) operandLitValue (IC_RIGHT (ic));
640       else if (ic->op == '-')
641         val -= (int) operandLitValue (IC_RIGHT (ic));
642       else if (IS_CAST_ICODE(ic)) {
643               sym_link *from_type = operandType(IC_RIGHT(ic));
644               aop->aopu.aop_immd.from_cast_remat = 1;
645               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
646               ptr_type = DCL_TYPE(from_type);
647               if (ptr_type == IPOINTER) {
648                 // bug #481053
649                 ptr_type = POINTER;
650               }
651               continue ;
652       } else break;
653       
654       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
655     }
656
657   if (val)
658   {
659       SNPRINTF (buffer, sizeof(buffer),
660                 "(%s %c 0x%04x)",
661                 OP_SYMBOL (IC_LEFT (ic))->rname,
662                 val >= 0 ? '+' : '-',
663                 abs (val) & 0xffffff);
664   }
665   else 
666   {
667       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
668       {
669           SNPRINTF(buffer, sizeof(buffer), 
670                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
671       }
672       else
673       {
674           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
675       }
676   }
677
678   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);  
679   /* set immd2 field if required */
680   if (aop->aopu.aop_immd.from_cast_remat) 
681   {
682       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
683       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
684   }
685
686   return aop;
687 }
688
689 /*-----------------------------------------------------------------*/
690 /* aopHasRegs - returns true if aop has regs between from-to       */
691 /*-----------------------------------------------------------------*/
692 static int aopHasRegs(asmop *aop, int from, int to)
693 {
694     int size =0;
695
696     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
697
698     for (; size < aop->size ; size++) {
699         int reg;
700         for (reg = from ; reg <= to ; reg++)
701             if (aop->aopu.aop_reg[size] == ds390_regWithIdx(reg)) return 1;
702     }
703     return 0;
704 }
705
706 /*-----------------------------------------------------------------*/
707 /* regsInCommon - two operands have some registers in common       */
708 /*-----------------------------------------------------------------*/
709 static bool
710 regsInCommon (operand * op1, operand * op2)
711 {
712   symbol *sym1, *sym2;
713   int i;
714
715   /* if they have registers in common */
716   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
717     return FALSE;
718
719   sym1 = OP_SYMBOL (op1);
720   sym2 = OP_SYMBOL (op2);
721
722   if (sym1->nRegs == 0 || sym2->nRegs == 0)
723     return FALSE;
724
725   for (i = 0; i < sym1->nRegs; i++)
726     {
727       int j;
728       if (!sym1->regs[i])
729         continue;
730
731       for (j = 0; j < sym2->nRegs; j++)
732         {
733           if (!sym2->regs[j])
734             continue;
735
736           if (sym2->regs[j] == sym1->regs[i])
737             return TRUE;
738         }
739     }
740
741   return FALSE;
742 }
743
744 /*-----------------------------------------------------------------*/
745 /* operandsEqu - equivalent                                        */
746 /*-----------------------------------------------------------------*/
747 static bool
748 operandsEqu (operand * op1, operand * op2)
749 {
750   symbol *sym1, *sym2;
751
752   /* if they not symbols */
753   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
754     return FALSE;
755
756   sym1 = OP_SYMBOL (op1);
757   sym2 = OP_SYMBOL (op2);
758
759   /* if both are itemps & one is spilt
760      and the other is not then false */
761   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
762       sym1->isspilt != sym2->isspilt)
763     return FALSE;
764
765   /* if they are the same */
766   if (sym1 == sym2)
767     return TRUE;
768
769   if (strcmp (sym1->rname, sym2->rname) == 0)
770     return TRUE;
771
772
773   /* if left is a tmp & right is not */
774   if (IS_ITEMP (op1) &&
775       !IS_ITEMP (op2) &&
776       sym1->isspilt &&
777       (sym1->usl.spillLoc == sym2))
778     return TRUE;
779
780   if (IS_ITEMP (op2) &&
781       !IS_ITEMP (op1) &&
782       sym2->isspilt &&
783       sym1->level > 0 &&
784       (sym2->usl.spillLoc == sym1))
785     return TRUE;
786
787   return FALSE;
788 }
789
790 /*-----------------------------------------------------------------*/
791 /* sameRegs - two asmops have the same registers                   */
792 /*-----------------------------------------------------------------*/
793 static bool
794 sameRegs (asmop * aop1, asmop * aop2)
795 {
796   int i;
797
798   if (aop1 == aop2)
799     {
800       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
801         {
802           return FALSE;
803         }
804       return TRUE;
805     }
806
807   if (aop1->type != AOP_REG ||
808       aop2->type != AOP_REG)
809     return FALSE;
810
811   if (aop1->size != aop2->size)
812     return FALSE;
813
814   for (i = 0; i < aop1->size; i++)
815     if (aop1->aopu.aop_reg[i] !=
816         aop2->aopu.aop_reg[i])
817       return FALSE;
818
819   return TRUE;
820 }
821
822 /*-----------------------------------------------------------------*/
823 /* aopOp - allocates an asmop for an operand  :                    */
824 /*-----------------------------------------------------------------*/
825 static void
826 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
827 {
828   asmop *aop;
829   symbol *sym;
830   int i;
831
832   if (!op)
833     return;
834
835   /* if this a literal */
836   if (IS_OP_LITERAL (op))
837     {
838       op->aop = aop = newAsmop (AOP_LIT);
839       aop->aopu.aop_lit = op->operand.valOperand;
840       aop->size = getSize (operandType (op));
841       return;
842     }
843
844   /* if already has a asmop then continue */
845   if (op->aop)
846     return;
847
848   /* if the underlying symbol has a aop */
849   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
850     {
851       op->aop = OP_SYMBOL (op)->aop;
852       return;
853     }
854
855   /* if this is a true symbol */
856   if (IS_TRUE_SYMOP (op))
857     {
858       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
859       return;
860     }
861
862   /* this is a temporary : this has
863      only four choices :
864      a) register
865      b) spillocation
866      c) rematerialize
867      d) conditional
868      e) can be a return use only */
869
870   sym = OP_SYMBOL (op);
871
872
873   /* if the type is a conditional */
874   if (sym->regType == REG_CND)
875     {
876       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
877       aop->size = 0;
878       return;
879     }
880
881   /* if it is spilt then two situations
882      a) is rematerialize
883      b) has a spill location */
884   if (sym->isspilt || sym->nRegs == 0)
885     {
886
887       /* rematerialize it NOW */
888       if (sym->remat)
889         {
890           sym->aop = op->aop = aop =
891             aopForRemat (sym);
892           aop->size = getSize (sym->type);
893           return;
894         }
895
896       if (sym->accuse)
897         {
898           int i;
899           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
900           aop->size = getSize (sym->type);
901           for (i = 0; i < 2; i++)
902             aop->aopu.aop_str[i] = accUse[i];
903           return;
904         }
905
906       if (sym->ruonly)
907         {
908           int i;
909
910           if (useDP2)
911             {
912               /* a AOP_STR uses DPTR, but DPTR is already in use;
913                * we're just hosed.
914                */
915                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
916             }
917
918           aop = op->aop = sym->aop = newAsmop (AOP_STR);
919           aop->size = getSize (sym->type);
920           for (i = 0; i < (int) fReturnSizeDS390; i++)
921             aop->aopu.aop_str[i] = fReturn[i];
922           return;
923         }
924       
925       if (sym->dptr) { /* has been allocated to a DPTRn */
926           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
927           aop->size = getSize (sym->type);
928           aop->aopu.dptr = sym->dptr;
929           return ;
930       }
931       /* else spill location  */
932       if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
933           /* force a new aop if sizes differ */
934           sym->usl.spillLoc->aop = NULL;
935       }
936       sym->aop = op->aop = aop =
937         aopForSym (ic, sym->usl.spillLoc, result, useDP2);
938       aop->size = getSize (sym->type);
939       return;
940     }
941
942   /* must be in a register */
943   sym->aop = op->aop = aop = newAsmop (AOP_REG);
944   aop->size = sym->nRegs;
945   for (i = 0; i < sym->nRegs; i++)
946     aop->aopu.aop_reg[i] = sym->regs[i];
947 }
948
949 /*-----------------------------------------------------------------*/
950 /* freeAsmop - free up the asmop given to an operand               */
951 /*----------------------------------------------------------------*/
952 static void
953 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
954 {
955   asmop *aop;
956
957   if (!op)
958     aop = aaop;
959   else
960     aop = op->aop;
961
962   if (!aop)
963     return;
964
965   if (aop->freed)
966     goto dealloc;
967
968   aop->freed = 1;
969
970   /* depending on the asmop type only three cases need work AOP_RO
971      , AOP_R1 && AOP_STK */
972   switch (aop->type)
973     {
974     case AOP_R0:
975       if (_G.r0Pushed)
976         {
977           if (pop)
978             {
979               emitcode ("pop", "ar0");
980               _G.r0Pushed--;
981             }
982         }
983       bitVectUnSetBit (ic->rUsed, R0_IDX);
984       break;
985
986     case AOP_R1:
987       if (_G.r1Pushed)
988         {
989           if (pop)
990             {
991               emitcode ("pop", "ar1");
992               _G.r1Pushed--;
993             }
994         }
995       bitVectUnSetBit (ic->rUsed, R1_IDX);
996       break;
997
998     case AOP_STK:
999       {
1000         int sz = aop->size;
1001         int stk = aop->aopu.aop_stk + aop->size;
1002         bitVectUnSetBit (ic->rUsed, R0_IDX);
1003         bitVectUnSetBit (ic->rUsed, R1_IDX);
1004
1005         getFreePtr (ic, &aop, FALSE);
1006
1007         if (options.stack10bit)
1008           {
1009             /* I'm not sure what to do here yet... */
1010             /* #STUB */
1011             fprintf (stderr,
1012                      "*** Warning: probably generating bad code for "
1013                      "10 bit stack mode.\n");
1014           }
1015
1016         if (stk)
1017           {
1018             emitcode ("mov", "a,_bp");
1019             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1020             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1021           }
1022         else
1023           {
1024             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1025           }
1026
1027         while (sz--)
1028           {
1029             emitcode ("pop", "acc");
1030             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1031             if (!sz)
1032               break;
1033             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1034           }
1035         op->aop = aop;
1036         freeAsmop (op, NULL, ic, TRUE);
1037         if (_G.r0Pushed)
1038           {
1039             emitcode ("pop", "ar0");
1040             _G.r0Pushed--;
1041           }
1042
1043         if (_G.r1Pushed)
1044           {
1045             emitcode ("pop", "ar1");
1046             _G.r1Pushed--;
1047           }
1048       }
1049     case AOP_DPTR2:
1050         if (_G.dptr1InUse) {
1051             emitcode ("pop","dpx1");
1052             emitcode ("pop","dph1");
1053             emitcode ("pop","dpl1");
1054         }
1055         break;
1056     case AOP_DPTR:
1057         if (_G.dptrInUse) {
1058             emitcode ("pop","dpx");
1059             emitcode ("pop","dph");
1060             emitcode ("pop","dpl");
1061         }
1062         break;
1063     }
1064 dealloc:
1065   /* all other cases just dealloc */
1066   if (op)
1067     {
1068       op->aop = NULL;
1069       if (IS_SYMOP (op))
1070         {
1071           OP_SYMBOL (op)->aop = NULL;
1072           /* if the symbol has a spill */
1073           if (SPIL_LOC (op))
1074             SPIL_LOC (op)->aop = NULL;
1075         }
1076     }
1077 }
1078
1079 #define DEFAULT_ACC_WARNING 0
1080 static int saveAccWarn = DEFAULT_ACC_WARNING;
1081
1082 /*-------------------------------------------------------------------*/
1083 /* aopGet - for fetching value of the aop                            */
1084 /*                                                                   */
1085 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1086 /* in the accumulator. Set it to the name of a free register         */
1087 /* if acc must be preserved; the register will be used to preserve   */
1088 /* acc temporarily and to return the result byte.                    */
1089 /*-------------------------------------------------------------------*/
1090
1091 static char *
1092 aopGet (asmop *aop,
1093         int   offset,
1094         bool  bit16,
1095         bool  dname,
1096         char  *saveAcc)
1097 {
1098   /* offset is greater than
1099      size then zero */
1100   if (offset > (aop->size - 1) &&
1101       aop->type != AOP_LIT)
1102     return zero;
1103
1104   /* depending on type */
1105   switch (aop->type)
1106     {
1107
1108     case AOP_R0:
1109     case AOP_R1:
1110       /* if we need to increment it */
1111       while (offset > aop->coff)
1112         {
1113           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1114           aop->coff++;
1115         }
1116
1117       while (offset < aop->coff)
1118         {
1119           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1120           aop->coff--;
1121         }
1122
1123       aop->coff = offset;
1124       if (aop->paged)
1125         {
1126           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1127           return (dname ? "acc" : "a");
1128         }
1129       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1130       return Safe_strdup(buffer);       
1131
1132     case AOP_DPTRn:
1133         assert(offset <= 3);
1134         return dptrn[aop->aopu.dptr][offset];
1135
1136     case AOP_DPTR:
1137     case AOP_DPTR2:
1138
1139       if (aop->type == AOP_DPTR2)
1140         {
1141           genSetDPTR (1);
1142         }
1143         
1144       if (saveAcc)
1145         {
1146             TR_AP("#1");
1147 //          if (aop->type != AOP_DPTR2)
1148 //          {
1149 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1150 //              emitcode(";", "spanky: saveAcc for DPTR");
1151 //          }
1152             
1153             emitcode ("xch", "a, %s", saveAcc);
1154         }
1155
1156       _flushLazyDPS ();
1157
1158       while (offset > aop->coff)
1159         {
1160           emitcode ("inc", "dptr");
1161           aop->coff++;
1162         }
1163
1164       while (offset < aop->coff)
1165         {
1166           emitcode ("lcall", "__decdptr");
1167           aop->coff--;
1168         }
1169
1170       aop->coff = offset;
1171       if (aop->code)
1172         {
1173           emitcode ("clr", "a");
1174           emitcode ("movc", "a,@a+dptr");
1175         }
1176       else
1177         {
1178           emitcode ("movx", "a,@dptr");
1179         }
1180
1181       if (aop->type == AOP_DPTR2)
1182         {
1183           genSetDPTR (0);
1184         }
1185         
1186         if (saveAcc)
1187         {
1188        TR_AP("#2");
1189               emitcode ("xch", "a, %s", saveAcc);
1190 //            if (strcmp(saveAcc, "_ap"))
1191 //            {
1192 //                emitcode(";", "spiffy: non _ap return from aopGet.");
1193 //            }
1194                   
1195               return saveAcc;
1196         }
1197       return (dname ? "acc" : "a");
1198
1199     case AOP_IMMD:
1200       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) 
1201       {
1202           SNPRINTF(buffer, sizeof(buffer), 
1203                    "%s",aop->aopu.aop_immd.aop_immd2);
1204       } 
1205       else if (bit16)
1206       {
1207          SNPRINTF(buffer, sizeof(buffer), 
1208                   "#%s", aop->aopu.aop_immd.aop_immd1);
1209       }
1210       else if (offset) 
1211       {
1212           switch (offset) {
1213           case 1:
1214               tsprintf(buffer, sizeof(buffer),
1215                        "#!his",aop->aopu.aop_immd.aop_immd1);
1216               break;
1217           case 2:
1218               tsprintf(buffer, sizeof(buffer), 
1219                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1220               break;
1221           case 3:
1222               tsprintf(buffer, sizeof(buffer),
1223                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1224               break;
1225           default: /* should not need this (just in case) */
1226               SNPRINTF (buffer, sizeof(buffer), 
1227                         "#(%s >> %d)",
1228                        aop->aopu.aop_immd.aop_immd1,
1229                        offset * 8);
1230           }
1231       }
1232       else
1233       {
1234         SNPRINTF (buffer, sizeof(buffer), 
1235                   "#%s", aop->aopu.aop_immd.aop_immd1);
1236       }
1237       return Safe_strdup(buffer);       
1238
1239     case AOP_DIR:
1240       if (offset)
1241       {
1242         SNPRINTF (buffer, sizeof(buffer),
1243                   "(%s + %d)",
1244                  aop->aopu.aop_dir,
1245                  offset);
1246       }
1247       else
1248       {
1249         SNPRINTF(buffer, sizeof(buffer), 
1250                  "%s", aop->aopu.aop_dir);
1251       }
1252
1253       return Safe_strdup(buffer);
1254
1255     case AOP_REG:
1256       if (dname)
1257         return aop->aopu.aop_reg[offset]->dname;
1258       else
1259         return aop->aopu.aop_reg[offset]->name;
1260
1261     case AOP_CRY:
1262       emitcode ("clr", "a");
1263       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1264       emitcode ("rlc", "a");
1265       return (dname ? "acc" : "a");
1266
1267     case AOP_ACC:
1268       if (!offset && dname)
1269         return "acc";
1270       return aop->aopu.aop_str[offset];
1271
1272     case AOP_LIT:
1273       return aopLiteral (aop->aopu.aop_lit, offset);
1274
1275     case AOP_STR:
1276       aop->coff = offset;
1277       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1278           dname)
1279         return "acc";
1280
1281       return aop->aopu.aop_str[offset];
1282
1283     }
1284
1285   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1286           "aopget got unsupported aop->type");
1287   exit (1);
1288     
1289   return NULL;  // not reached, but makes compiler happy.
1290 }
1291 /*-----------------------------------------------------------------*/
1292 /* aopPut - puts a string for a aop                                */
1293 /*-----------------------------------------------------------------*/
1294 static void
1295 aopPut (asmop * aop, char *s, int offset)
1296 {
1297   if (aop->size && offset > (aop->size - 1))
1298     {
1299       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1300               "aopPut got offset > aop->size");
1301       exit (1);
1302     }
1303
1304   /* will assign value to value */
1305   /* depending on where it is ofcourse */
1306   switch (aop->type)
1307     {
1308     case AOP_DIR:
1309         if (offset)
1310         {
1311             SNPRINTF (buffer, sizeof(buffer),
1312                       "(%s + %d)",
1313                       aop->aopu.aop_dir, offset);
1314         }
1315         else
1316         {
1317             SNPRINTF (buffer, sizeof(buffer), 
1318                      "%s", aop->aopu.aop_dir);
1319         }
1320         
1321
1322         if (strcmp (buffer, s))
1323         {
1324             emitcode ("mov", "%s,%s", buffer, s);
1325         }
1326       break;
1327
1328     case AOP_REG:
1329       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1330           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1331         {
1332           if (*s == '@' ||
1333               strcmp (s, "r0") == 0 ||
1334               strcmp (s, "r1") == 0 ||
1335               strcmp (s, "r2") == 0 ||
1336               strcmp (s, "r3") == 0 ||
1337               strcmp (s, "r4") == 0 ||
1338               strcmp (s, "r5") == 0 ||
1339               strcmp (s, "r6") == 0 ||
1340               strcmp (s, "r7") == 0)
1341             {
1342                 emitcode ("mov", "%s,%s",
1343                           aop->aopu.aop_reg[offset]->dname, s);
1344             }
1345             else
1346             {
1347                 emitcode ("mov", "%s,%s",
1348                           aop->aopu.aop_reg[offset]->name, s);
1349             }
1350         }
1351       break;
1352
1353     case AOP_DPTRn:
1354         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1355         break;
1356
1357     case AOP_DPTR:
1358     case AOP_DPTR2:
1359
1360       if (aop->type == AOP_DPTR2)
1361         {
1362           genSetDPTR (1);
1363         }
1364       _flushLazyDPS ();
1365
1366       if (aop->code)
1367         {
1368           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1369                   "aopPut writting to code space");
1370           exit (1);
1371         }
1372
1373       while (offset > aop->coff)
1374         {
1375           aop->coff++;
1376           emitcode ("inc", "dptr");
1377         }
1378
1379       while (offset < aop->coff)
1380         {
1381           aop->coff--;
1382           emitcode ("lcall", "__decdptr");
1383         }
1384
1385       aop->coff = offset;
1386
1387       /* if not in accumulater */
1388       MOVA (s);
1389
1390       emitcode ("movx", "@dptr,a");
1391
1392       if (aop->type == AOP_DPTR2)
1393         {
1394           genSetDPTR (0);
1395         }
1396       break;
1397
1398     case AOP_R0:
1399     case AOP_R1:
1400       while (offset > aop->coff)
1401         {
1402           aop->coff++;
1403           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1404         }
1405       while (offset < aop->coff)
1406         {
1407           aop->coff--;
1408           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1409         }
1410       aop->coff = offset;
1411
1412       if (aop->paged)
1413         {
1414           MOVA (s);
1415           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1416
1417         }
1418       else if (*s == '@')
1419         {
1420           MOVA (s);
1421           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1422         }
1423       else if (strcmp (s, "r0") == 0 ||
1424                strcmp (s, "r1") == 0 ||
1425                strcmp (s, "r2") == 0 ||
1426                strcmp (s, "r3") == 0 ||
1427                strcmp (s, "r4") == 0 ||
1428                strcmp (s, "r5") == 0 ||
1429                strcmp (s, "r6") == 0 ||
1430                strcmp (s, "r7") == 0)
1431         {
1432           char buff[10];
1433           SNPRINTF(buff, sizeof(buff), 
1434                    "a%s", s);
1435           emitcode ("mov", "@%s,%s",
1436                     aop->aopu.aop_ptr->name, buff);
1437         }
1438         else
1439         {
1440             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1441         }
1442       break;
1443
1444     case AOP_STK:
1445       if (strcmp (s, "a") == 0)
1446         emitcode ("push", "acc");
1447       else
1448         if (*s=='@') {
1449           MOVA(s);
1450           emitcode ("push", "acc");
1451         } else {
1452           emitcode ("push", s);
1453         }
1454
1455       break;
1456
1457     case AOP_CRY:
1458       /* if bit variable */
1459       if (!aop->aopu.aop_dir)
1460         {
1461           emitcode ("clr", "a");
1462           emitcode ("rlc", "a");
1463         }
1464       else
1465         {
1466           if (s == zero)
1467             emitcode ("clr", "%s", aop->aopu.aop_dir);
1468           else if (s == one)
1469             emitcode ("setb", "%s", aop->aopu.aop_dir);
1470           else if (!strcmp (s, "c"))
1471             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1472           else
1473             {
1474               if (strcmp (s, "a"))
1475                 {
1476                   MOVA (s);
1477                 }
1478               {
1479                 /* set C, if a >= 1 */
1480                 emitcode ("add", "a,#!constbyte",0xff);
1481                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1482               }
1483             }
1484         }
1485       break;
1486
1487     case AOP_STR:
1488       aop->coff = offset;
1489       if (strcmp (aop->aopu.aop_str[offset], s))
1490         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1491       break;
1492
1493     case AOP_ACC:
1494       aop->coff = offset;
1495       if (!offset && (strcmp (s, "acc") == 0))
1496         break;
1497
1498       if (strcmp (aop->aopu.aop_str[offset], s))
1499         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1500       break;
1501
1502     default:
1503       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1504               "aopPut got unsupported aop->type");
1505       exit (1);
1506     }
1507
1508 }
1509
1510
1511 /*--------------------------------------------------------------------*/
1512 /* reAdjustPreg - points a register back to where it should (coff==0) */
1513 /*--------------------------------------------------------------------*/
1514 static void
1515 reAdjustPreg (asmop * aop)
1516 {
1517   if ((aop->coff==0) || (aop->size <= 1)) {
1518     return;
1519   }
1520
1521   switch (aop->type)
1522     {
1523     case AOP_R0:
1524     case AOP_R1:
1525       while (aop->coff--)
1526         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1527       break;
1528     case AOP_DPTR:
1529     case AOP_DPTR2:
1530       if (aop->type == AOP_DPTR2)
1531         {
1532           genSetDPTR (1);
1533           _flushLazyDPS ();
1534         }
1535       while (aop->coff--)
1536         {
1537           emitcode ("lcall", "__decdptr");
1538         }
1539
1540       if (aop->type == AOP_DPTR2)
1541         {
1542           genSetDPTR (0);
1543         }
1544       break;
1545
1546     }
1547   aop->coff=0;
1548 }
1549
1550 #define AOP(op) op->aop
1551 #define AOP_TYPE(op) AOP(op)->type
1552 #define AOP_SIZE(op) AOP(op)->size
1553 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1554                        AOP_TYPE(x) == AOP_R0))
1555
1556 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1557                         AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
1558                          AOP(x)->paged))
1559
1560 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1561                       (x->aopu.aop_reg[0] == ds390_regWithIdx(R0_IDX) || \
1562                       x->aopu.aop_reg[0] == ds390_regWithIdx(R1_IDX) )))
1563 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
1564 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
1565 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
1566
1567 // The following two macros can be used even if the aop has not yet been aopOp'd.
1568 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
1569 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
1570
1571 /* Workaround for DS80C390 bug: div ab may return bogus results
1572  * if A is accessed in instruction immediately before the div.
1573  *
1574  * Will be fixed in B4 rev of processor, Dallas claims.
1575  */
1576
1577 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
1578     if (!AOP_NEEDSACC(RIGHT))         \
1579     {               \
1580       /* We can load A first, then B, since     \
1581        * B (the RIGHT operand) won't clobber A,   \
1582        * thus avoiding touching A right before the div. \
1583        */             \
1584       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
1585       L = aopGet(AOP(LEFT),0,FALSE,FALSE,NULL);     \
1586       MOVA(L);            \
1587       L = aopGet(AOP(RIGHT),0,FALSE,FALSE,"b"); \
1588       MOVB(L); \
1589     }               \
1590     else              \
1591     {               \
1592       /* Just stuff in a nop after loading A. */    \
1593       emitcode("mov","b,%s",aopGet(AOP(RIGHT),0,FALSE,FALSE,NULL));\
1594       L = aopGet(AOP(LEFT),0,FALSE,FALSE,NULL);   \
1595       MOVA(L);            \
1596       emitcode("nop", "; workaround for DS80C390 div bug.");  \
1597     }
1598
1599 /*-----------------------------------------------------------------*/
1600 /* genNotFloat - generates not for float operations              */
1601 /*-----------------------------------------------------------------*/
1602 static void
1603 genNotFloat (operand * op, operand * res)
1604 {
1605   int size, offset;
1606   symbol *tlbl;
1607
1608   D (emitcode (";", "genNotFloat "););
1609
1610   /* we will put 127 in the first byte of
1611      the result */
1612   aopPut (AOP (res), "#127", 0);
1613   size = AOP_SIZE (op) - 1;
1614   offset = 1;
1615
1616   _startLazyDPSEvaluation ();
1617   MOVA(aopGet(op->aop, offset++, FALSE, FALSE, NULL));
1618
1619   while (size--)
1620     {
1621       emitcode ("orl", "a,%s",
1622                 aopGet (op->aop,
1623                         offset++, FALSE, FALSE,
1624                         DP2_RESULT_REG));
1625     }
1626   _endLazyDPSEvaluation ();
1627
1628   tlbl = newiTempLabel (NULL);
1629   aopPut (res->aop, one, 1);
1630   emitcode ("jz", "!tlabel", (tlbl->key + 100));
1631   aopPut (res->aop, zero, 1);
1632   emitcode ("", "!tlabeldef", (tlbl->key + 100));
1633
1634   size = res->aop->size - 2;
1635   offset = 2;
1636   /* put zeros in the rest */
1637   while (size--)
1638     aopPut (res->aop, zero, offset++);
1639 }
1640
1641 /*-----------------------------------------------------------------*/
1642 /* opIsGptr: returns non-zero if the passed operand is       */
1643 /* a generic pointer type.             */
1644 /*-----------------------------------------------------------------*/
1645 static int
1646 opIsGptr (operand * op)
1647 {
1648   sym_link *type = operandType (op);
1649
1650   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1651     {
1652       return 1;
1653     }
1654   return 0;
1655 }
1656
1657 /*-----------------------------------------------------------------*/
1658 /* getDataSize - get the operand data size                         */
1659 /*-----------------------------------------------------------------*/
1660 static int
1661 getDataSize (operand * op)
1662 {
1663   int size;
1664   size = AOP_SIZE (op);
1665   if (size == GPTRSIZE)
1666     {
1667       sym_link *type = operandType (op);
1668       if (IS_GENPTR (type))
1669         {
1670           /* generic pointer; arithmetic operations
1671            * should ignore the high byte (pointer type).
1672            */
1673           size--;
1674         }
1675     }
1676   return size;
1677 }
1678
1679 /*-----------------------------------------------------------------*/
1680 /* outAcc - output Acc                                             */
1681 /*-----------------------------------------------------------------*/
1682 static void
1683 outAcc (operand * result)
1684 {
1685   int size, offset;
1686   size = getDataSize (result);
1687   if (size)
1688     {
1689       aopPut (AOP (result), "a", 0);
1690       size--;
1691       offset = 1;
1692       /* unsigned or positive */
1693       while (size--)
1694         {
1695           aopPut (AOP (result), zero, offset++);
1696         }
1697     }
1698 }
1699
1700 /*-----------------------------------------------------------------*/
1701 /* outBitC - output a bit C                                        */
1702 /*-----------------------------------------------------------------*/
1703 static void
1704 outBitC (operand * result)
1705 {
1706   /* if the result is bit */
1707   if (AOP_TYPE (result) == AOP_CRY)
1708     {
1709       aopPut (AOP (result), "c", 0);
1710     }
1711   else
1712     {
1713       emitcode ("clr", "a");
1714       emitcode ("rlc", "a");
1715       outAcc (result);
1716     }
1717 }
1718
1719 /*-----------------------------------------------------------------*/
1720 /* toBoolean - emit code for orl a,operator(sizeop)                */
1721 /*-----------------------------------------------------------------*/
1722 static void
1723 toBoolean (operand * oper)
1724 {
1725   int   size = AOP_SIZE (oper) - 1;
1726   int   offset = 1;
1727   bool usedB = FALSE;
1728
1729   /* The generic part of a generic pointer should
1730    * not participate in it's truth value.
1731    *
1732    * i.e. 0x10000000 is zero.
1733    */
1734   if (opIsGptr (oper))
1735     {
1736       D (emitcode (";", "toBoolean: generic ptr special case."););
1737       size--;
1738     }
1739
1740   _startLazyDPSEvaluation ();
1741   if (AOP_NEEDSACC (oper) && size)
1742     {
1743       usedB = TRUE;
1744       if (_G.bInUse)
1745       {
1746           emitcode ("push", "b");
1747       }
1748       MOVB (aopGet (AOP (oper), 0, FALSE, FALSE, NULL));
1749     }
1750   else
1751     {
1752       MOVA (aopGet (AOP (oper), 0, FALSE, FALSE, NULL));
1753     }
1754     
1755   while (size--)
1756     {
1757       if (usedB)
1758         {
1759           emitcode ("orl", "b,%s",
1760                     aopGet (AOP (oper), offset++, FALSE, FALSE, NULL));
1761         }
1762       else
1763         {
1764           emitcode ("orl", "a,%s",
1765                     aopGet (AOP (oper), offset++, FALSE, FALSE, NULL));
1766         }
1767     }
1768   _endLazyDPSEvaluation ();
1769
1770   if (usedB)
1771     {
1772       emitcode ("mov", "a,b");
1773       if (_G.bInUse)
1774       {
1775           emitcode ("pop", "b");
1776       }
1777         
1778     }
1779 }
1780
1781
1782 /*-----------------------------------------------------------------*/
1783 /* genNot - generate code for ! operation                          */
1784 /*-----------------------------------------------------------------*/
1785 static void
1786 genNot (iCode * ic)
1787 {
1788   symbol *tlbl;
1789   sym_link *optype = operandType (IC_LEFT (ic));
1790
1791   D (emitcode (";", "genNot "););
1792
1793   /* assign asmOps to operand & result */
1794   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1795   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
1796
1797   /* if in bit space then a special case */
1798   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1799     {
1800       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1801       emitcode ("cpl", "c");
1802       outBitC (IC_RESULT (ic));
1803       goto release;
1804     }
1805
1806   /* if type float then do float */
1807   if (IS_FLOAT (optype))
1808     {
1809       genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
1810       goto release;
1811     }
1812
1813   toBoolean (IC_LEFT (ic));
1814
1815   tlbl = newiTempLabel (NULL);
1816   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
1817   emitcode ("", "!tlabeldef", tlbl->key + 100);
1818   outBitC (IC_RESULT (ic));
1819
1820 release:
1821   /* release the aops */
1822   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1823   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1824 }
1825
1826
1827 /*-----------------------------------------------------------------*/
1828 /* genCpl - generate code for complement                           */
1829 /*-----------------------------------------------------------------*/
1830 static void
1831 genCpl (iCode * ic)
1832 {
1833   int offset = 0;
1834   int size;
1835   symbol *tlbl;
1836
1837   D (emitcode (";", "genCpl "););
1838
1839
1840   /* assign asmOps to operand & result */
1841   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1842   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
1843
1844   /* special case if in bit space */
1845   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY) {
1846     if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) {
1847       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1848       emitcode ("cpl", "c");
1849       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1850       goto release;
1851     }
1852     tlbl=newiTempLabel(NULL);
1853     emitcode ("cjne", "%s,#0x01,%05d$", 
1854               aopGet(AOP(IC_LEFT(ic)), 0, FALSE,FALSE,NULL), tlbl->key+100);
1855     emitcode ("", "%05d$:", tlbl->key+100);
1856     outBitC (IC_RESULT(ic));
1857     goto release;
1858   }
1859
1860   size = AOP_SIZE (IC_RESULT (ic));
1861   _startLazyDPSEvaluation ();
1862   while (size--)
1863     {
1864       MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
1865       emitcode ("cpl", "a");
1866       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1867     }
1868   _endLazyDPSEvaluation ();
1869
1870
1871 release:
1872   /* release the aops */
1873   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1874   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1875 }
1876
1877 /*-----------------------------------------------------------------*/
1878 /* genUminusFloat - unary minus for floating points                */
1879 /*-----------------------------------------------------------------*/
1880 static void
1881 genUminusFloat (operand * op, operand * result)
1882 {
1883   int size, offset = 0;
1884     
1885   D(emitcode (";", "genUminusFloat"););
1886   
1887   /* for this we just copy and then flip the bit */
1888     
1889   _startLazyDPSEvaluation ();
1890   size = AOP_SIZE (op) - 1;
1891
1892   while (size--)
1893   {
1894       aopPut (AOP (result),
1895               aopGet (AOP (op), offset, FALSE, FALSE, NULL),
1896               offset);
1897       offset++;
1898     }
1899   
1900   MOVA(aopGet (AOP (op), offset, FALSE, FALSE, NULL));
1901
1902   emitcode ("cpl", "acc.7");
1903   aopPut (AOP (result), "a", offset);    
1904   _endLazyDPSEvaluation ();
1905 }
1906
1907 /*-----------------------------------------------------------------*/
1908 /* genUminus - unary minus code generation                         */
1909 /*-----------------------------------------------------------------*/
1910 static void
1911 genUminus (iCode * ic)
1912 {
1913   int offset, size;
1914   sym_link *optype;
1915
1916   D (emitcode (";", "genUminus "););
1917
1918   /* assign asmops */
1919   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1920   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
1921
1922   /* if both in bit space then special
1923      case */
1924   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1925       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1926     {
1927
1928       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1929       emitcode ("cpl", "c");
1930       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1931       goto release;
1932     }
1933
1934   optype = operandType (IC_LEFT (ic));
1935
1936   /* if float then do float stuff */
1937   if (IS_FLOAT (optype))
1938     {
1939       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1940       goto release;
1941     }
1942
1943   /* otherwise subtract from zero */
1944   size = AOP_SIZE (IC_LEFT (ic));
1945   offset = 0;
1946   _startLazyDPSEvaluation ();
1947   while (size--)
1948     {
1949       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL);
1950       if (!strcmp (l, "a"))
1951         {
1952           if (offset == 0)
1953             SETC;
1954           emitcode ("cpl", "a");
1955           emitcode ("addc", "a,#0");
1956         }
1957       else
1958         {
1959           if (offset == 0)
1960             CLRC;
1961           emitcode ("clr", "a");
1962           emitcode ("subb", "a,%s", l);
1963         }
1964       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1965     }
1966   _endLazyDPSEvaluation ();
1967
1968   /* if any remaining bytes in the result */
1969   /* we just need to propagate the sign   */
1970   if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic)))) != 0)
1971     {
1972       emitcode ("rlc", "a");
1973       emitcode ("subb", "a,acc");
1974       while (size--)
1975         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1976     }
1977
1978 release:
1979   /* release the aops */
1980   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1981   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1982 }
1983
1984 /*-----------------------------------------------------------------*/
1985 /* savermask - saves registers in the mask                         */
1986 /*-----------------------------------------------------------------*/
1987 static void savermask(bitVect *rs_mask)
1988 {
1989     int i;
1990     if (options.useXstack) {
1991         if (bitVectBitValue (rs_mask, R0_IDX))
1992             emitcode ("mov", "b,r0");
1993         emitcode ("mov", "r0,%s", spname);
1994         for (i = 0; i < ds390_nRegs; i++) {
1995             if (bitVectBitValue (rs_mask, i)) {
1996                 if (i == R0_IDX)
1997                     emitcode ("mov", "a,b");
1998                 else
1999                     emitcode ("mov", "a,%s", ds390_regWithIdx (i)->name);
2000                 emitcode ("movx", "@r0,a");
2001                 emitcode ("inc", "r0");
2002             }
2003         }
2004         emitcode ("mov", "%s,r0", spname);
2005         if (bitVectBitValue (rs_mask, R0_IDX))
2006             emitcode ("mov", "r0,b");
2007     } else {
2008         for (i = 0; i < ds390_nRegs; i++) {
2009             if (bitVectBitValue (rs_mask, i))
2010                 emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
2011         }
2012     }
2013 }
2014
2015 /*-----------------------------------------------------------------*/
2016 /* saveRegisters - will look for a call and save the registers     */
2017 /*-----------------------------------------------------------------*/
2018 static void
2019 saveRegisters (iCode * lic)
2020 {
2021   iCode *ic;
2022   bitVect *rsave;
2023
2024   /* look for call */
2025   for (ic = lic; ic; ic = ic->next)
2026     if (ic->op == CALL || ic->op == PCALL)
2027       break;
2028
2029   if (!ic)
2030     {
2031       fprintf (stderr, "found parameter push with no function call\n");
2032       return;
2033     }
2034
2035   /* if the registers have been saved already then
2036      do nothing */
2037   if (ic->regsSaved || IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic)))) return ;
2038
2039   /* special case if DPTR alive across a function call then must save it 
2040      even though callee saves */
2041   if (IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2042       int i;
2043       rsave = newBitVect(ic->rMask->size);
2044       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2045           if (bitVectBitValue(ic->rMask,i))
2046               rsave = bitVectSetBit(rsave,i);
2047       }
2048       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2049   } else {
2050     /* safe the registers in use at this time but skip the
2051        ones for the result */
2052     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2053                            ds390_rUmaskForOp (IC_RESULT(ic)));
2054   }
2055   ic->regsSaved = 1;
2056   savermask(rsave);
2057 }
2058
2059 /*-----------------------------------------------------------------*/
2060 /* usavermask - restore registers with mask                        */
2061 /*-----------------------------------------------------------------*/
2062 static void unsavermask(bitVect *rs_mask)
2063 {
2064     int i;
2065     if (options.useXstack) {
2066         emitcode ("mov", "r0,%s", spname);
2067         for (i = ds390_nRegs; i >= 0; i--) {
2068             if (bitVectBitValue (rs_mask, i)) {
2069                 emitcode ("dec", "r0");
2070                 emitcode ("movx", "a,@r0");
2071                 if (i == R0_IDX)
2072                     emitcode ("mov", "b,a");
2073                 else
2074                     emitcode ("mov", "%s,a", ds390_regWithIdx (i)->name);
2075             }       
2076         }
2077         emitcode ("mov", "%s,r0", spname);
2078         if (bitVectBitValue (rs_mask, R0_IDX))
2079             emitcode ("mov", "r0,b");
2080     } else {
2081         for (i = ds390_nRegs; i >= 0; i--) {
2082             if (bitVectBitValue (rs_mask, i))
2083                 emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
2084         }
2085     }
2086 }
2087
2088 /*-----------------------------------------------------------------*/
2089 /* unsaveRegisters - pop the pushed registers                      */
2090 /*-----------------------------------------------------------------*/
2091 static void
2092 unsaveRegisters (iCode * ic)
2093 {
2094   bitVect *rsave;
2095
2096   if (IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2097       int i;
2098       rsave = newBitVect(ic->rMask->size);
2099       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2100           if (bitVectBitValue(ic->rMask,i))
2101               rsave = bitVectSetBit(rsave,i);
2102       }
2103       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2104   } else {
2105     /* restore the registers in use at this time but skip the
2106        ones for the result */
2107     rsave = bitVectCplAnd (bitVectCopy (ic->rMask), 
2108                            ds390_rUmaskForOp (IC_RESULT(ic)));
2109   }
2110   unsavermask(rsave);
2111 }
2112
2113
2114 /*-----------------------------------------------------------------*/
2115 /* pushSide -                */
2116 /*-----------------------------------------------------------------*/
2117 static void
2118 pushSide (operand * oper, int size)
2119 {
2120   int offset = 0;
2121   _startLazyDPSEvaluation ();
2122   while (size--)
2123     {
2124       char *l = aopGet (AOP (oper), offset++, FALSE, TRUE, NULL);
2125       if (AOP_TYPE (oper) != AOP_REG &&
2126           AOP_TYPE (oper) != AOP_DIR &&
2127           strcmp (l, "a"))
2128         {
2129           emitcode ("mov", "a,%s", l);
2130           emitcode ("push", "acc");
2131         }
2132       else
2133         emitcode ("push", "%s", l);
2134     }
2135   _endLazyDPSEvaluation ();
2136 }
2137
2138 /*-----------------------------------------------------------------*/
2139 /* assignResultValue -               */
2140 /*-----------------------------------------------------------------*/
2141 static void
2142 assignResultValue (operand * oper)
2143 {
2144   int offset = 0;
2145   int size = AOP_SIZE (oper);
2146   bool pushedAcc = FALSE;
2147
2148   if (size == fReturnSizeDS390)
2149   {
2150       /* I don't think this case can ever happen... */
2151       /* ACC is the last part of this. If writing the result
2152        * uses AC, we must preserve it.
2153        */
2154       if (AOP_NEEDSACC(oper))
2155       {
2156           emitcode(";", "assignResultValue special case for ACC.");
2157           emitcode("push", "acc");
2158           pushedAcc = TRUE;
2159           size--;
2160       }
2161   }
2162     
2163     
2164   _startLazyDPSEvaluation ();
2165   while (size--)
2166     {
2167       aopPut (AOP (oper), fReturn[offset], offset);
2168       offset++;
2169     }
2170   _endLazyDPSEvaluation ();
2171     
2172   if (pushedAcc)
2173     {
2174         emitcode("pop", "acc");
2175         aopPut(AOP(oper), "a", offset);
2176     }
2177 }
2178
2179
2180 /*-----------------------------------------------------------------*/
2181 /* genXpush - pushes onto the external stack                       */
2182 /*-----------------------------------------------------------------*/
2183 static void
2184 genXpush (iCode * ic)
2185 {
2186   asmop *aop = newAsmop (0);
2187   regs *r;
2188   int size, offset = 0;
2189
2190   D (emitcode (";", "genXpush ");
2191     );
2192
2193   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2194   r = getFreePtr (ic, &aop, FALSE);
2195
2196
2197   emitcode ("mov", "%s,_spx", r->name);
2198
2199   size = AOP_SIZE (IC_LEFT (ic));
2200   _startLazyDPSEvaluation ();
2201   while (size--)
2202     {
2203
2204       MOVA (aopGet (AOP (IC_LEFT (ic)),
2205                         offset++, FALSE, FALSE, NULL));
2206       emitcode ("movx", "@%s,a", r->name);
2207       emitcode ("inc", "%s", r->name);
2208
2209     }
2210   _endLazyDPSEvaluation ();
2211
2212
2213   emitcode ("mov", "_spx,%s", r->name);
2214
2215   freeAsmop (NULL, aop, ic, TRUE);
2216   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2217 }
2218
2219 /*-----------------------------------------------------------------*/
2220 /* genIpush - generate code for pushing this gets a little complex  */
2221 /*-----------------------------------------------------------------*/
2222 static void
2223 genIpush (iCode * ic)
2224 {
2225   int size, offset = 0;
2226   char *l;
2227
2228   D (emitcode (";", "genIpush ");
2229     );
2230
2231   /* if this is not a parm push : ie. it is spill push
2232      and spill push is always done on the local stack */
2233   if (!ic->parmPush)
2234     {
2235
2236       /* and the item is spilt then do nothing */
2237       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2238         return;
2239
2240       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2241       size = AOP_SIZE (IC_LEFT (ic));
2242       /* push it on the stack */
2243       _startLazyDPSEvaluation ();
2244       while (size--)
2245         {
2246           l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE, NULL);
2247           if (*l == '#')
2248             {
2249               MOVA (l);
2250               l = "acc";
2251             }
2252           emitcode ("push", "%s", l);
2253         }
2254       _endLazyDPSEvaluation ();
2255       return;
2256     }
2257
2258   /* this is a paramter push: in this case we call
2259      the routine to find the call and save those
2260      registers that need to be saved */
2261   saveRegisters (ic);
2262
2263   /* if use external stack then call the external
2264      stack pushing routine */
2265   if (options.useXstack)
2266     {
2267       genXpush (ic);
2268       return;
2269     }
2270
2271   /* then do the push */
2272   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2273
2274   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2275   size = AOP_SIZE (IC_LEFT (ic));
2276
2277   _startLazyDPSEvaluation ();
2278   while (size--)
2279     {
2280       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE, NULL);
2281       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2282           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2283           strcmp (l, "acc"))
2284         {
2285           emitcode ("mov", "a,%s", l);
2286           emitcode ("push", "acc");
2287         }
2288       else
2289         {
2290             emitcode ("push", "%s", l);
2291         }
2292     }
2293   _endLazyDPSEvaluation ();
2294
2295   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2296 }
2297
2298 /*-----------------------------------------------------------------*/
2299 /* genIpop - recover the registers: can happen only for spilling   */
2300 /*-----------------------------------------------------------------*/
2301 static void
2302 genIpop (iCode * ic)
2303 {
2304   int size, offset;
2305
2306   D (emitcode (";", "genIpop ");
2307     );
2308
2309
2310   /* if the temp was not pushed then */
2311   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2312     return;
2313
2314   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2315   size = AOP_SIZE (IC_LEFT (ic));
2316   offset = (size - 1);
2317   _startLazyDPSEvaluation ();
2318   while (size--)
2319     {
2320       emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
2321                                      FALSE, TRUE, NULL));
2322     }
2323   _endLazyDPSEvaluation ();
2324
2325   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2326 }
2327
2328 /*-----------------------------------------------------------------*/
2329 /* unsaveRBank - restores the resgister bank from stack            */
2330 /*-----------------------------------------------------------------*/
2331 static void
2332 unsaveRBank (int bank, iCode * ic, bool popPsw)
2333 {
2334   int i;
2335   asmop *aop = NULL;
2336   regs *r = NULL;
2337
2338   if (options.useXstack)
2339   {
2340       if (!ic)
2341       {
2342           /* Assume r0 is available for use. */
2343           r = ds390_regWithIdx (R0_IDX);;          
2344       } 
2345       else
2346       {
2347           aop = newAsmop (0);
2348           r = getFreePtr (ic, &aop, FALSE);
2349       }
2350       emitcode ("mov", "%s,_spx", r->name);      
2351   }
2352   
2353   if (popPsw)
2354     {
2355       if (options.useXstack)
2356       {
2357           emitcode ("movx", "a,@%s", r->name);
2358           emitcode ("mov", "psw,a");
2359           emitcode ("dec", "%s", r->name);
2360         }
2361       else
2362       {
2363         emitcode ("pop", "psw");
2364       }
2365     }
2366
2367   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2368     {
2369       if (options.useXstack)
2370         {
2371           emitcode ("movx", "a,@%s", r->name);
2372           emitcode ("mov", "(%s+%d),a",
2373                     regs390[i].base, 8 * bank + regs390[i].offset);
2374           emitcode ("dec", "%s", r->name);
2375
2376         }
2377       else
2378         emitcode ("pop", "(%s+%d)",
2379                   regs390[i].base, 8 * bank + regs390[i].offset);
2380     }
2381
2382   if (options.useXstack)
2383     {
2384       emitcode ("mov", "_spx,%s", r->name);
2385     }
2386     
2387   if (aop)
2388   {
2389       freeAsmop (NULL, aop, ic, TRUE);  
2390   }    
2391 }
2392
2393 /*-----------------------------------------------------------------*/
2394 /* saveRBank - saves an entire register bank on the stack          */
2395 /*-----------------------------------------------------------------*/
2396 static void
2397 saveRBank (int bank, iCode * ic, bool pushPsw)
2398 {
2399   int i;
2400   asmop *aop = NULL;
2401   regs *r = NULL;
2402
2403   if (options.useXstack)
2404     {
2405         if (!ic)
2406         {
2407           /* Assume r0 is available for use. */
2408                   r = ds390_regWithIdx (R0_IDX);;
2409         }
2410         else
2411         {
2412           aop = newAsmop (0);
2413           r = getFreePtr (ic, &aop, FALSE);
2414         }
2415         emitcode ("mov", "%s,_spx", r->name);    
2416     }
2417
2418   for (i = 0; i < 8 ; i++) /* only R0-R7 needs saving */
2419     {
2420       if (options.useXstack)
2421         {
2422           emitcode ("inc", "%s", r->name);
2423           emitcode ("mov", "a,(%s+%d)",
2424                     regs390[i].base, 8 * bank + regs390[i].offset);
2425           emitcode ("movx", "@%s,a", r->name);
2426         }
2427       else
2428         emitcode ("push", "(%s+%d)",
2429                   regs390[i].base, 8 * bank + regs390[i].offset);
2430     }
2431
2432   if (pushPsw)
2433     {
2434       if (options.useXstack)
2435         {
2436           emitcode ("mov", "a,psw");
2437           emitcode ("movx", "@%s,a", r->name);
2438           emitcode ("inc", "%s", r->name);
2439           emitcode ("mov", "_spx,%s", r->name);
2440         }
2441       else
2442       {
2443         emitcode ("push", "psw");
2444       }
2445
2446       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2447     }
2448   
2449   if (aop)
2450   {
2451        freeAsmop (NULL, aop, ic, TRUE);
2452   }    
2453     
2454   if (ic)
2455   {  
2456       ic->bankSaved = 1;
2457   }
2458 }
2459
2460 /*-----------------------------------------------------------------*/
2461 /* genSend - gen code for SEND                                     */
2462 /*-----------------------------------------------------------------*/
2463 static void genSend(set *sendSet)
2464 {
2465     iCode *sic;
2466     int sendCount = 0 ;
2467     static int rb1_count = 0;
2468
2469     for (sic = setFirstItem (sendSet); sic;
2470          sic = setNextItem (sendSet)) {     
2471         int size, offset = 0;
2472         
2473         size=getSize(operandType(IC_LEFT(sic)));
2474         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2475         if (sendCount == 0) { /* first parameter */
2476             // we know that dpl(hxb) is the result, so
2477             rb1_count = 0 ;
2478             _startLazyDPSEvaluation ();
2479             if (size>1) {
2480                 aopOp (IC_LEFT (sic), sic, FALSE, 
2481                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2482             } else {
2483                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2484             }
2485             while (size--) {
2486                 char *l = aopGet (AOP (IC_LEFT (sic)), offset,
2487                                   FALSE, FALSE, NULL);
2488                 if (strcmp (l, fReturn[offset])) {
2489                     emitcode ("mov", "%s,%s",
2490                               fReturn[offset],
2491                               l);
2492                 }
2493                 offset++;
2494             }
2495             _endLazyDPSEvaluation ();
2496             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2497             rb1_count =0;
2498         } else { /* if more parameter in registers */
2499             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2500             while (size--) {
2501                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (AOP (IC_LEFT (sic)), offset++,
2502                                                                 FALSE, FALSE, NULL));
2503             }
2504             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2505         }
2506         sendCount++;
2507     }
2508 }
2509
2510 /*-----------------------------------------------------------------*/
2511 /* genCall - generates a call statement                            */
2512 /*-----------------------------------------------------------------*/
2513 static void
2514 genCall (iCode * ic)
2515 {
2516   sym_link *dtype;
2517   bool restoreBank = FALSE;
2518   bool swapBanks = FALSE;
2519
2520   D (emitcode (";", "genCall "););
2521
2522   /* if we are calling a not _naked function that is not using
2523      the same register bank then we need to save the
2524      destination registers on the stack */
2525   dtype = operandType (IC_LEFT (ic));
2526   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2527       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2528       IFFUNC_ISISR (currFunc->type))
2529   {
2530       if (!ic->bankSaved) 
2531       {
2532            /* This is unexpected; the bank should have been saved in
2533             * genFunction.
2534             */
2535            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2536            restoreBank = TRUE;
2537       }
2538       swapBanks = TRUE;
2539   }
2540   
2541     /* if caller saves & we have not saved then */
2542     if (!ic->regsSaved)
2543       saveRegisters (ic);
2544   
2545   /* if send set is not empty the assign */
2546   /* We've saved all the registers we care about;
2547   * therefore, we may clobber any register not used
2548   * in the calling convention (i.e. anything not in
2549   * fReturn.
2550   */
2551   if (_G.sendSet)
2552     {
2553         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2554             genSend(reverseSet(_G.sendSet));
2555         } else {
2556             genSend(_G.sendSet);
2557         }
2558       _G.sendSet = NULL;
2559     }  
2560     
2561   if (swapBanks)
2562   {
2563         emitcode ("mov", "psw,#!constbyte", 
2564            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2565   }
2566
2567   /* make the call */
2568   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2569                             OP_SYMBOL (IC_LEFT (ic))->rname :
2570                             OP_SYMBOL (IC_LEFT (ic))->name));
2571
2572   if (swapBanks)
2573   {
2574        emitcode ("mov", "psw,#!constbyte", 
2575           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2576   }
2577
2578   /* if we need assign a result value */
2579   if ((IS_ITEMP (IC_RESULT (ic)) &&
2580        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2581         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2582         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2583       IS_TRUE_SYMOP (IC_RESULT (ic)))
2584     {
2585       if (isOperandInFarSpace (IC_RESULT (ic))
2586           && getSize (operandType (IC_RESULT (ic))) <= 2)
2587         {
2588           int size = getSize (operandType (IC_RESULT (ic)));
2589
2590           /* Special case for 1 or 2 byte return in far space. */
2591           MOVA (fReturn[0]);
2592           if (size > 1)
2593             {
2594               emitcode ("mov", "b,%s", fReturn[1]);
2595             }
2596
2597           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2598           aopPut (AOP (IC_RESULT (ic)), "a", 0);
2599
2600           if (size > 1)
2601             {
2602               aopPut (AOP (IC_RESULT (ic)), "b", 1);
2603             }
2604           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2605         }
2606       else
2607         {
2608           _G.accInUse++;
2609           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
2610           _G.accInUse--;
2611
2612           assignResultValue (IC_RESULT (ic));
2613
2614           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2615         }
2616     }
2617
2618   /* adjust the stack for parameters if
2619      required */
2620   if (ic->parmBytes) {
2621       int i;
2622       if (options.stack10bit) {
2623           if (ic->parmBytes <= 10) {
2624               emitcode(";","stack adjustment for parms");
2625               for (i=0; i < ic->parmBytes ; i++) {
2626                   emitcode("pop","acc");
2627               }
2628           } else {            
2629               PROTECT_SP;
2630               emitcode ("clr","c");
2631               emitcode ("mov","a,sp");
2632               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
2633               emitcode ("mov","sp,a");
2634               emitcode ("mov","a,esp");
2635               emitcode ("anl","a,#3");
2636               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
2637               emitcode ("mov","esp,a");   
2638               UNPROTECT_SP;
2639           }
2640       } else {
2641           if (ic->parmBytes > 3) {
2642               emitcode ("mov", "a,%s", spname);
2643               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
2644               emitcode ("mov", "%s,a", spname);
2645           } else
2646               for (i = 0; i < ic->parmBytes; i++)
2647                   emitcode ("dec", "%s", spname);
2648       }
2649   }
2650
2651   /* if we hade saved some registers then unsave them */
2652   if (ic->regsSaved)
2653     unsaveRegisters (ic);
2654
2655   /* if register bank was saved then pop them */
2656   if (restoreBank)
2657     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2658 }
2659
2660 /*-----------------------------------------------------------------*/
2661 /* genPcall - generates a call by pointer statement                */
2662 /*-----------------------------------------------------------------*/
2663 static void
2664 genPcall (iCode * ic)
2665 {
2666   sym_link *dtype;
2667   symbol *rlbl = newiTempLabel (NULL);
2668   bool restoreBank=FALSE;
2669
2670   D (emitcode (";", "genPcall ");
2671     );
2672
2673
2674   /* if caller saves & we have not saved then */
2675   if (!ic->regsSaved)
2676     saveRegisters (ic);
2677
2678   /* if we are calling a function that is not using
2679      the same register bank then we need to save the
2680      destination registers on the stack */
2681   dtype = operandType (IC_LEFT (ic));
2682   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2683       IFFUNC_ISISR (currFunc->type) &&
2684       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
2685     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2686     restoreBank=TRUE;
2687   }
2688
2689   /* push the return address on to the stack */
2690   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
2691   emitcode ("push", "acc");
2692   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
2693   emitcode ("push", "acc");
2694
2695   if (options.model == MODEL_FLAT24)
2696     {
2697       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
2698       emitcode ("push", "acc");
2699     }
2700
2701   /* now push the calling address */
2702   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2703
2704   pushSide (IC_LEFT (ic), FPTRSIZE);
2705
2706   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2707
2708   /* if send set is not empty the assign */
2709   if (_G.sendSet)
2710     {
2711         genSend(reverseSet(_G.sendSet));
2712         _G.sendSet = NULL;
2713     }
2714
2715   emitcode ("ret", "");
2716   emitcode ("", "!tlabeldef", (rlbl->key + 100));
2717
2718
2719   /* if we need assign a result value */
2720   if ((IS_ITEMP (IC_RESULT (ic)) &&
2721        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2722         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2723       IS_TRUE_SYMOP (IC_RESULT (ic)))
2724     {
2725
2726       _G.accInUse++;
2727       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
2728       _G.accInUse--;
2729
2730       assignResultValue (IC_RESULT (ic));
2731
2732       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2733     }
2734
2735   /* adjust the stack for parameters if
2736      required */
2737   if (ic->parmBytes)
2738     {
2739       int i;
2740       if (options.stack10bit) {
2741           if (ic->parmBytes <= 10) {
2742               emitcode(";","stack adjustment for parms");
2743               for (i=0; i < ic->parmBytes ; i++) {
2744                   emitcode("pop","acc");
2745               }
2746           } else {            
2747               PROTECT_SP;
2748               emitcode ("clr","c");
2749               emitcode ("mov","a,sp");
2750               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
2751               emitcode ("mov","sp,a");
2752               emitcode ("mov","a,esp");
2753               emitcode ("anl","a,#3");
2754               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
2755               emitcode ("mov","esp,a");   
2756               UNPROTECT_SP;
2757           }
2758       } else {
2759           if (ic->parmBytes > 3) {
2760               emitcode ("mov", "a,%s", spname);
2761               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
2762               emitcode ("mov", "%s,a", spname);
2763           }
2764           else
2765               for (i = 0; i < ic->parmBytes; i++)
2766                   emitcode ("dec", "%s", spname);
2767           
2768       }
2769     }
2770   /* if register bank was saved then unsave them */
2771   if (restoreBank)
2772     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2773   
2774   /* if we hade saved some registers then
2775      unsave them */
2776   if (ic->regsSaved)
2777     unsaveRegisters (ic);
2778
2779 }
2780
2781 /*-----------------------------------------------------------------*/
2782 /* resultRemat - result  is rematerializable                       */
2783 /*-----------------------------------------------------------------*/
2784 static int
2785 resultRemat (iCode * ic)
2786 {
2787   if (SKIP_IC (ic) || ic->op == IFX)
2788     return 0;
2789
2790   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2791     {
2792       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2793       if (sym->remat && !POINTER_SET (ic))
2794         return 1;
2795     }
2796
2797   return 0;
2798 }
2799
2800 #if defined(__BORLANDC__) || defined(_MSC_VER)
2801 #define STRCASECMP stricmp
2802 #else
2803 #define STRCASECMP strcasecmp
2804 #endif
2805
2806 /*-----------------------------------------------------------------*/
2807 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2808 /*-----------------------------------------------------------------*/
2809 static bool
2810 inExcludeList (char *s)
2811 {
2812   int i = 0;
2813
2814   if (options.excludeRegs[i] &&
2815       STRCASECMP (options.excludeRegs[i], "none") == 0)
2816     return FALSE;
2817
2818   for (i = 0; options.excludeRegs[i]; i++)
2819     {
2820       if (options.excludeRegs[i] &&
2821           STRCASECMP (s, options.excludeRegs[i]) == 0)
2822         return TRUE;
2823     }
2824   return FALSE;
2825 }
2826
2827 /*-----------------------------------------------------------------*/
2828 /* genFunction - generated code for function entry                 */
2829 /*-----------------------------------------------------------------*/
2830 static void
2831 genFunction (iCode * ic)
2832 {
2833   symbol *sym;
2834   sym_link *ftype;
2835   bool   switchedPSW = FALSE;
2836
2837   D (emitcode (";", "genFunction "););
2838
2839   _G.nRegsSaved = 0;
2840   /* create the function header */
2841   emitcode (";", "-----------------------------------------");
2842   emitcode (";", " function %s", (sym = OP_SYMBOL (IC_LEFT (ic)))->name);
2843   emitcode (";", "-----------------------------------------");
2844
2845   emitcode ("", "%s:", sym->rname);
2846   ftype = operandType (IC_LEFT (ic));
2847
2848   if (IFFUNC_ISNAKED(ftype))
2849   {
2850       emitcode(";", "naked function: no prologue.");
2851       return;
2852   }
2853   
2854   if (options.stack_probe) 
2855       emitcode ("lcall","__stack_probe");
2856   /* if critical function then turn interrupts off */
2857   if (IFFUNC_ISCRITICAL (ftype))
2858     emitcode ("clr", "ea");
2859
2860   /* here we need to generate the equates for the
2861      register bank if required */
2862   if (FUNC_REGBANK (ftype) != rbank)
2863     {
2864       int i;
2865
2866       rbank = FUNC_REGBANK (ftype);
2867       for (i = 0; i < ds390_nRegs; i++)
2868         {
2869           if (regs390[i].print) {
2870               if (strcmp (regs390[i].base, "0") == 0)
2871                   emitcode ("", "%s !equ !constbyte",
2872                             regs390[i].dname,
2873                             8 * rbank + regs390[i].offset);
2874               else
2875                   emitcode ("", "%s !equ %s + !constbyte",
2876                             regs390[i].dname,
2877                             regs390[i].base,
2878                             8 * rbank + regs390[i].offset);
2879           }
2880         }
2881     }
2882
2883   /* if this is an interrupt service routine then
2884      save acc, b, dpl, dph  */
2885   if (IFFUNC_ISISR (sym->type))
2886       { /* is ISR */
2887       if (!inExcludeList ("acc"))
2888         emitcode ("push", "acc");
2889       if (!inExcludeList ("b"))
2890         emitcode ("push", "b");
2891       if (!inExcludeList ("dpl"))
2892         emitcode ("push", "dpl");
2893       if (!inExcludeList ("dph"))
2894         emitcode ("push", "dph");
2895       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
2896         {
2897           emitcode ("push", "dpx");
2898           /* Make sure we're using standard DPTR */
2899           emitcode ("push", "dps");
2900           emitcode ("mov", "dps,#0");
2901           if (options.stack10bit)
2902             {
2903               /* This ISR could conceivably use DPTR2. Better save it. */
2904               emitcode ("push", "dpl1");
2905               emitcode ("push", "dph1");
2906               emitcode ("push", "dpx1");
2907               emitcode ("push",  DP2_RESULT_REG);
2908             }
2909         }
2910       /* if this isr has no bank i.e. is going to
2911          run with bank 0 , then we need to save more
2912          registers :-) */
2913       if (!FUNC_REGBANK (sym->type))
2914         {
2915             int i;
2916
2917           /* if this function does not call any other
2918              function then we can be economical and
2919              save only those registers that are used */
2920           if (!IFFUNC_HASFCALL(sym->type))
2921             {
2922
2923               /* if any registers used */
2924               if (sym->regsUsed)
2925                 {
2926                   /* save the registers used */
2927                   for (i = 0; i < sym->regsUsed->size; i++)
2928                     {
2929                       if (bitVectBitValue (sym->regsUsed, i) ||
2930                           (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
2931                         emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
2932                     }
2933                 }
2934
2935             }
2936           else
2937             {
2938               /* this function has  a function call cannot
2939                  determines register usage so we will have to push the
2940                  entire bank */
2941               saveRBank (0, ic, FALSE);
2942               if (options.parms_in_bank1) {
2943                   for (i=0; i < 8 ; i++ ) {
2944                       emitcode ("push","%s",rb1regs[i]);
2945                   }
2946               }
2947             }
2948         }
2949         else
2950         {
2951             /* This ISR uses a non-zero bank.
2952              *
2953              * We assume that the bank is available for our
2954              * exclusive use.
2955              *
2956              * However, if this ISR calls a function which uses some
2957              * other bank, we must save that bank entirely.
2958              */
2959             unsigned long banksToSave = 0;
2960             
2961             if (IFFUNC_HASFCALL(sym->type))
2962             {
2963
2964 #define MAX_REGISTER_BANKS 4
2965
2966                 iCode *i;
2967                 int ix;
2968
2969                 for (i = ic; i; i = i->next)
2970                 {
2971                     if (i->op == ENDFUNCTION)
2972                     {
2973                         /* we got to the end OK. */
2974                         break;
2975                     }
2976                     
2977                     if (i->op == CALL)
2978                     {
2979                         sym_link *dtype;
2980                         
2981                         dtype = operandType (IC_LEFT(i));
2982                         if (dtype 
2983                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2984                         {
2985                              /* Mark this bank for saving. */
2986                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2987                              {
2988                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2989                              }
2990                              else
2991                              {
2992                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2993                              }
2994                              
2995                              /* And note that we don't need to do it in 
2996                               * genCall.
2997                               */
2998                              i->bankSaved = 1;
2999                         }
3000                     }
3001                     if (i->op == PCALL)
3002                     {
3003                         /* This is a mess; we have no idea what
3004                          * register bank the called function might
3005                          * use.
3006                          *
3007                          * The only thing I can think of to do is
3008                          * throw a warning and hope.
3009                          */
3010                         werror(W_FUNCPTR_IN_USING_ISR);   
3011                     }
3012                 }
3013
3014                 if (banksToSave && options.useXstack)
3015                 {
3016                     /* Since we aren't passing it an ic, 
3017                      * saveRBank will assume r0 is available to abuse.
3018                      *
3019                      * So switch to our (trashable) bank now, so
3020                      * the caller's R0 isn't trashed.
3021                      */
3022                     emitcode ("push", "psw");
3023                     emitcode ("mov", "psw,#!constbyte", 
3024                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3025                     switchedPSW = TRUE;
3026                 }
3027                 
3028                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3029                 {
3030                      if (banksToSave & (1 << ix))
3031                      {
3032                          saveRBank(ix, NULL, FALSE);
3033                      }
3034                 }
3035             }
3036             // TODO: this needs a closer look
3037             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3038         }
3039     }
3040   else
3041     {
3042       /* if callee-save to be used for this function
3043          then save the registers being used in this function */
3044       if (IFFUNC_CALLEESAVES(sym->type))
3045         {
3046           int i;
3047
3048           /* if any registers used */
3049           if (sym->regsUsed)
3050             {
3051               /* save the registers used */
3052               for (i = 0; i < sym->regsUsed->size; i++)
3053                 {
3054                   if (bitVectBitValue (sym->regsUsed, i) ||
3055                       (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3056                     {
3057                       emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
3058                       _G.nRegsSaved++;
3059                     }
3060                 }
3061             }
3062         }
3063     }
3064
3065   /* set the register bank to the desired value */
3066   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3067    && !switchedPSW)
3068     {
3069       emitcode ("push", "psw");
3070       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3071     }
3072
3073   if ( (IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3074        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3075       if (options.stack10bit) {
3076           emitcode ("push","_bpx");
3077           emitcode ("push","_bpx+1");
3078           emitcode ("mov","_bpx,%s",spname);
3079           emitcode ("mov","_bpx+1,esp");
3080           emitcode ("anl","_bpx+1,#3");
3081       } else {
3082           if (options.useXstack) {
3083               emitcode ("mov", "r0,%s", spname);
3084               emitcode ("mov", "a,_bp");
3085               emitcode ("movx", "@r0,a");
3086               emitcode ("inc", "%s", spname);
3087           } else {
3088               /* set up the stack */
3089               emitcode ("push", "_bp"); /* save the callers stack  */
3090           }
3091           emitcode ("mov", "_bp,%s", spname);
3092       }
3093   }
3094
3095   /* adjust the stack for the function */
3096   if (sym->stack) {
3097       int i = sym->stack;
3098       if (options.stack10bit) {
3099           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);    
3100           assert (sym->recvSize <= 4);
3101           if (sym->stack <= 8) {
3102               while (i--) emitcode ("push","acc");
3103           } else {
3104               PROTECT_SP;
3105               emitcode ("mov","a,sp");
3106               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3107               emitcode ("mov","sp,a");
3108               emitcode ("mov","a,esp");
3109               emitcode ("anl","a,#3");
3110               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3111               emitcode ("mov","esp,a");
3112               UNPROTECT_SP;
3113           }
3114       } else {
3115           if (i > 256)
3116               werror (W_STACK_OVERFLOW, sym->name);
3117           
3118           if (i > 3 && sym->recvSize < 4) {
3119               
3120               emitcode ("mov", "a,sp");
3121               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3122               emitcode ("mov", "sp,a");
3123               
3124           } else
3125               while (i--)
3126                   emitcode ("inc", "sp");
3127       }
3128   }
3129
3130   if (sym->xstack)
3131     {
3132
3133       emitcode ("mov", "a,_spx");
3134       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3135       emitcode ("mov", "_spx,a");
3136     }
3137
3138 }
3139
3140 /*-----------------------------------------------------------------*/
3141 /* genEndFunction - generates epilogue for functions               */
3142 /*-----------------------------------------------------------------*/
3143 static void
3144 genEndFunction (iCode * ic)
3145 {
3146   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3147
3148   D (emitcode (";", "genEndFunction "););
3149
3150   if (IFFUNC_ISNAKED(sym->type))
3151   {
3152       emitcode(";", "naked function: no epilogue.");
3153       return;
3154   }
3155
3156   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3157        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3158
3159       if (options.stack10bit) {
3160           PROTECT_SP;     
3161           emitcode ("mov", "sp,_bpx", spname);
3162           emitcode ("mov", "esp,_bpx+1", spname);
3163           UNPROTECT_SP;
3164       } else {
3165           emitcode ("mov", "%s,_bp", spname);
3166       }
3167   }
3168
3169   /* if use external stack but some variables were
3170      added to the local stack then decrement the
3171      local stack */
3172   if (options.useXstack && sym->stack) {
3173       emitcode ("mov", "a,sp");
3174       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3175       emitcode ("mov", "sp,a");
3176   }
3177
3178
3179   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3180        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3181
3182       if (options.useXstack) {
3183           emitcode ("mov", "r0,%s", spname);
3184           emitcode ("movx", "a,@r0");
3185           emitcode ("mov", "_bp,a");
3186           emitcode ("dec", "%s", spname);
3187       } else {
3188           if (options.stack10bit) {
3189               emitcode ("pop", "_bpx+1");
3190               emitcode ("pop", "_bpx");
3191           } else {
3192               emitcode ("pop", "_bp");
3193           }
3194       }
3195   }
3196
3197   /* restore the register bank  */
3198   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3199   {
3200     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3201      || !options.useXstack)
3202     {
3203         /* Special case of ISR using non-zero bank with useXstack
3204          * is handled below.
3205          */
3206         emitcode ("pop", "psw");
3207     }
3208   } 
3209
3210   if (IFFUNC_ISISR (sym->type))
3211       { /* is ISR */  
3212
3213       /* now we need to restore the registers */
3214       /* if this isr has no bank i.e. is going to
3215          run with bank 0 , then we need to save more
3216          registers :-) */
3217       if (!FUNC_REGBANK (sym->type))
3218         {
3219             int i;
3220           /* if this function does not call any other
3221              function then we can be economical and
3222              save only those registers that are used */
3223           if (!IFFUNC_HASFCALL(sym->type))
3224             {
3225
3226               /* if any registers used */
3227               if (sym->regsUsed)
3228                 {
3229                   /* save the registers used */
3230                   for (i = sym->regsUsed->size; i >= 0; i--)
3231                     {
3232                       if (bitVectBitValue (sym->regsUsed, i) ||
3233                           (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3234                         emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
3235                     }
3236                 }
3237
3238             }
3239           else
3240             {
3241               /* this function has  a function call cannot
3242                  determines register usage so we will have to pop the
3243                  entire bank */
3244               if (options.parms_in_bank1) {
3245                   for (i = 7 ; i >= 0 ; i-- ) {
3246                       emitcode ("pop","%s",rb1regs[i]);
3247                   }
3248               }
3249               unsaveRBank (0, ic, FALSE);
3250             }
3251         }
3252         else
3253         {
3254             /* This ISR uses a non-zero bank.
3255              *
3256              * Restore any register banks saved by genFunction
3257              * in reverse order.
3258              */
3259             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3260             int ix;
3261           
3262             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3263             {
3264                 if (savedBanks & (1 << ix))
3265                 {
3266                     unsaveRBank(ix, NULL, FALSE);
3267                 }
3268             }
3269             
3270             if (options.useXstack)
3271             {
3272                 /* Restore bank AFTER calling unsaveRBank,
3273                  * since it can trash r0.
3274                  */
3275                 emitcode ("pop", "psw");
3276             }
3277         }
3278
3279       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3280         {
3281           if (options.stack10bit)
3282             {
3283               emitcode ("pop", DP2_RESULT_REG);
3284               emitcode ("pop", "dpx1");
3285               emitcode ("pop", "dph1");
3286               emitcode ("pop", "dpl1");
3287             }
3288           emitcode ("pop", "dps");
3289           emitcode ("pop", "dpx");
3290         }
3291       if (!inExcludeList ("dph"))
3292         emitcode ("pop", "dph");
3293       if (!inExcludeList ("dpl"))
3294         emitcode ("pop", "dpl");
3295       if (!inExcludeList ("b"))
3296         emitcode ("pop", "b");
3297       if (!inExcludeList ("acc"))
3298         emitcode ("pop", "acc");
3299
3300       if (IFFUNC_ISCRITICAL (sym->type))
3301         emitcode ("setb", "ea");
3302
3303       /* if debug then send end of function */
3304       if (options.debug && currFunc) {
3305           _G.debugLine = 1;
3306           emitcode ("", "C$%s$%d$%d$%d ==.",
3307                     FileBaseName (ic->filename), currFunc->lastLine,
3308                     ic->level, ic->block);
3309           if (IS_STATIC (currFunc->etype))
3310             emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
3311           else
3312             emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
3313           _G.debugLine = 0;
3314         }
3315
3316       emitcode ("reti", "");
3317     }
3318   else
3319     {
3320       if (IFFUNC_ISCRITICAL (sym->type))
3321         emitcode ("setb", "ea");
3322
3323       if (IFFUNC_CALLEESAVES(sym->type))
3324         {
3325           int i;
3326
3327           /* if any registers used */
3328           if (sym->regsUsed)
3329             {
3330               /* save the registers used */
3331               for (i = sym->regsUsed->size; i >= 0; i--)
3332                 {
3333                   if (bitVectBitValue (sym->regsUsed, i) ||
3334                       (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3335                     emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
3336                 }
3337             }
3338
3339         }
3340
3341       /* if debug then send end of function */
3342       if (options.debug && currFunc)
3343         {
3344           _G.debugLine = 1;
3345           emitcode ("", "C$%s$%d$%d$%d ==.",
3346                     FileBaseName (ic->filename), currFunc->lastLine,
3347                     ic->level, ic->block);
3348           if (IS_STATIC (currFunc->etype))
3349             emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
3350           else
3351             emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
3352           _G.debugLine = 0;
3353         }
3354
3355       emitcode ("ret", "");
3356     }
3357
3358 }
3359
3360 /*-----------------------------------------------------------------*/
3361 /* genJavaNativeRet - generate code for return JavaNative          */
3362 /*-----------------------------------------------------------------*/
3363 static void genJavaNativeRet(iCode *ic)
3364 {
3365     int i, size;
3366
3367     aopOp (IC_LEFT (ic), ic, FALSE, 
3368            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
3369     size = AOP_SIZE (IC_LEFT (ic));
3370
3371     assert (size <= 4);
3372
3373     /* it is assigned to GPR0-R3 then push them */
3374     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
3375         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
3376         for (i = 0 ; i < size ; i++ ) {
3377             emitcode ("push","%s",
3378                       aopGet(AOP(IC_LEFT(ic)),i,FALSE,TRUE,DP2_RESULT_REG));
3379         }
3380         for (i = (size-1) ; i >= 0 ; i--) {
3381             emitcode ("pop","a%s",javaRet[i]);
3382         }
3383     } else {
3384         for (i = 0 ; i < size ; i++) 
3385             emitcode ("mov","%s,%s",javaRet[i],
3386                       aopGet(AOP(IC_LEFT(ic)),i,FALSE,TRUE,DP2_RESULT_REG));
3387     }
3388     for (i = size ; i < 4 ; i++ )
3389             emitcode ("mov","%s,#0",javaRet[i]);
3390     return;
3391 }
3392
3393 /*-----------------------------------------------------------------*/
3394 /* genRet - generate code for return statement                     */
3395 /*-----------------------------------------------------------------*/
3396 static void
3397 genRet (iCode * ic)
3398 {
3399   int size, offset = 0, pushed = 0;
3400
3401   D (emitcode (";", "genRet "););
3402
3403   /* if we have no return value then
3404      just generate the "ret" */
3405   if (!IC_LEFT (ic))
3406     goto jumpret;
3407
3408   /* if this is a JavaNative function then return 
3409      value in different register */
3410   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
3411       genJavaNativeRet(ic);
3412       goto jumpret;
3413   }
3414   /* we have something to return then
3415      move the return value into place */
3416   aopOp (IC_LEFT (ic), ic, FALSE, 
3417          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
3418   size = AOP_SIZE (IC_LEFT (ic));
3419
3420   _startLazyDPSEvaluation ();
3421   while (size--)
3422     {
3423       char *l;
3424       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3425         {
3426           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3427                       FALSE, TRUE, NULL);
3428           emitcode ("push", "%s", l);
3429           pushed++;
3430         }
3431       else
3432         {
3433           /* Since A is the last element of fReturn,
3434            * is is OK to clobber it in the aopGet.
3435            */
3436           l = aopGet (AOP (IC_LEFT (ic)), offset,
3437                       FALSE, FALSE, NULL);
3438           if (strcmp (fReturn[offset], l))
3439             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3440         }
3441     }
3442   _endLazyDPSEvaluation ();
3443
3444   if (pushed)
3445     {
3446       while (pushed)
3447         {
3448           pushed--;
3449           if (strcmp (fReturn[pushed], "a"))
3450             emitcode ("pop", fReturn[pushed]);
3451           else
3452             emitcode ("pop", "acc");
3453         }
3454     }
3455   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3456
3457 jumpret:
3458   /* generate a jump to the return label
3459      if the next is not the return statement */
3460   if (!(ic->next && ic->next->op == LABEL &&
3461         IC_LABEL (ic->next) == returnLabel))
3462
3463     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
3464
3465 }
3466
3467 /*-----------------------------------------------------------------*/
3468 /* genLabel - generates a label                                    */
3469 /*-----------------------------------------------------------------*/
3470 static void
3471 genLabel (iCode * ic)
3472 {
3473   /* special case never generate */
3474   if (IC_LABEL (ic) == entryLabel)
3475     return;
3476
3477   D (emitcode (";", "genLabel ");
3478     );
3479
3480   emitcode ("", "!tlabeldef", (IC_LABEL (ic)->key + 100));
3481 }
3482
3483 /*-----------------------------------------------------------------*/
3484 /* genGoto - generates a ljmp                                      */
3485 /*-----------------------------------------------------------------*/
3486 static void
3487 genGoto (iCode * ic)
3488 {
3489   D (emitcode (";", "genGoto ");
3490     );
3491   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
3492 }
3493
3494 /*-----------------------------------------------------------------*/
3495 /* findLabelBackwards: walks back through the iCode chain looking  */
3496 /* for the given label. Returns number of iCode instructions     */
3497 /* between that label and given ic.          */
3498 /* Returns zero if label not found.          */
3499 /*-----------------------------------------------------------------*/
3500 static int
3501 findLabelBackwards (iCode * ic, int key)
3502 {
3503   int count = 0;
3504
3505   while (ic->prev)
3506     {
3507       ic = ic->prev;
3508       count++;
3509
3510       /* If we have any pushes or pops, we cannot predict the distance.
3511          I don't like this at all, this should be dealt with in the 
3512          back-end */
3513       if (ic->op == IPUSH || ic->op == IPOP) {
3514         return 0;
3515       }
3516
3517       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3518         {
3519           /* printf("findLabelBackwards = %d\n", count); */
3520           return count;
3521         }
3522     }
3523
3524   return 0;
3525 }
3526
3527 /*-----------------------------------------------------------------*/
3528 /* genPlusIncr :- does addition with increment if possible         */
3529 /*-----------------------------------------------------------------*/
3530 static bool
3531 genPlusIncr (iCode * ic)
3532 {
3533   unsigned int icount;
3534   unsigned int size = getDataSize (IC_RESULT (ic));
3535
3536   /* will try to generate an increment */
3537   /* if the right side is not a literal
3538      we cannot */
3539   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3540     return FALSE;
3541
3542   /* if the literal value of the right hand side
3543      is greater than 4 then it is not worth it */
3544   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3545     return FALSE;
3546
3547   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
3548       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
3549       while (icount--) {
3550           emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE,NULL));
3551       }
3552       return TRUE;
3553   }
3554   /* if increment 16 bits in register */
3555   if (
3556        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
3557        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
3558        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3559        (size > 1) &&
3560        (icount == 1))
3561     {
3562       symbol  *tlbl;
3563       int     emitTlbl;
3564       int     labelRange;
3565       char    *l;
3566
3567       /* If the next instruction is a goto and the goto target
3568        * is <= 5 instructions previous to this, we can generate
3569        * jumps straight to that target.
3570        */
3571       if (ic->next && ic->next->op == GOTO
3572           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3573           && labelRange <= 5)
3574         {
3575           D(emitcode (";", "tail increment optimized (range %d)", labelRange););
3576           tlbl = IC_LABEL (ic->next);
3577           emitTlbl = 0;
3578         }
3579       else
3580         {
3581           tlbl = newiTempLabel (NULL);
3582           emitTlbl = 1;
3583         }
3584         
3585       l = aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, NULL);
3586       emitcode ("inc", "%s", l);
3587       
3588       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3589           IS_AOP_PREG (IC_RESULT (ic)))
3590       {   
3591         emitcode ("cjne", "%s,#0,!tlabel", l, tlbl->key + 100);
3592       }
3593       else
3594       {
3595           emitcode ("clr", "a");
3596           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
3597       }
3598
3599       l = aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, NULL); 
3600       emitcode ("inc", "%s", l);
3601       if (size > 2)
3602         {
3603             if (!strcmp(l, "acc"))
3604             {
3605                 emitcode("jnz", "!tlabel", tlbl->key + 100);
3606             }
3607             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3608                      IS_AOP_PREG (IC_RESULT (ic)))
3609             {
3610                 emitcode ("cjne", "%s,#0,!tlabel", l, tlbl->key + 100);
3611             }
3612             else
3613             {
3614                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
3615             }
3616
3617             l = aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, NULL);
3618             emitcode ("inc", "%s", l);
3619         }
3620       if (size > 3)
3621         {
3622             if (!strcmp(l, "acc"))
3623             {
3624                 emitcode("jnz", "!tlabel", tlbl->key + 100);
3625             }
3626             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3627                      IS_AOP_PREG (IC_RESULT (ic)))
3628             {
3629                 emitcode ("cjne", "%s,#0,!tlabel", l, tlbl->key + 100);
3630             }
3631             else
3632             {
3633                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
3634             }
3635
3636             l = aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE, NULL);
3637             emitcode ("inc", "%s", l);  }
3638
3639       if (emitTlbl)
3640         {
3641           emitcode ("", "!tlabeldef", tlbl->key + 100);
3642         }
3643       return TRUE;
3644     }
3645
3646   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
3647       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 && 
3648       options.model == MODEL_FLAT24 ) {
3649
3650       switch (size) {
3651       case 3:
3652           emitcode ("mov","dpx,%s",aopGet(AOP (IC_LEFT (ic)), 2, FALSE, FALSE, NULL));
3653       case 2:
3654           emitcode ("mov","dph,%s",aopGet(AOP (IC_LEFT (ic)), 1, FALSE, FALSE, NULL));
3655       case 1:
3656           emitcode ("mov","dpl,%s",aopGet(AOP (IC_LEFT (ic)), 0, FALSE, FALSE, NULL));
3657           break;
3658       }
3659       while (icount--) emitcode ("inc","dptr");      
3660       return TRUE;
3661   }
3662
3663   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
3664       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
3665       icount <= 5 ) {
3666       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
3667       while (icount--) emitcode ("inc","dptr");
3668       emitcode ("mov","dps,#0");
3669       return TRUE;
3670   }
3671
3672   /* if the sizes are greater than 1 then we cannot */
3673   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3674       AOP_SIZE (IC_LEFT (ic)) > 1)
3675     return FALSE;
3676
3677   /* we can if the aops of the left & result match or
3678      if they are in registers and the registers are the
3679      same */
3680   if (
3681        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
3682        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
3683        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3684     {
3685
3686       if (icount > 3)
3687         {
3688           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE, NULL));
3689           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
3690           aopPut (AOP (IC_RESULT (ic)), "a", 0);
3691         }
3692       else
3693         {
3694
3695           _startLazyDPSEvaluation ();
3696           while (icount--)
3697             {
3698               emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE, NULL));
3699             }
3700           _endLazyDPSEvaluation ();
3701         }
3702
3703       return TRUE;
3704     }
3705
3706   return FALSE;
3707 }
3708
3709 /*-----------------------------------------------------------------*/
3710 /* outBitAcc - output a bit in acc                                 */
3711 /*-----------------------------------------------------------------*/
3712 static void
3713 outBitAcc (operand * result)
3714 {
3715   symbol *tlbl = newiTempLabel (NULL);
3716   /* if the result is a bit */
3717   if (AOP_TYPE (result) == AOP_CRY)
3718     {
3719       aopPut (AOP (result), "a", 0);
3720     }
3721   else
3722     {
3723       emitcode ("jz", "!tlabel", tlbl->key + 100);
3724       emitcode ("mov", "a,%s", one);
3725       emitcode ("", "!tlabeldef", tlbl->key + 100);
3726       outAcc (result);
3727     }
3728 }
3729
3730 /*-----------------------------------------------------------------*/
3731 /* genPlusBits - generates code for addition of two bits           */
3732 /*-----------------------------------------------------------------*/
3733 static void
3734 genPlusBits (iCode * ic)
3735 {
3736   D (emitcode (";", "genPlusBits "););
3737     
3738   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3739     {
3740       symbol *lbl = newiTempLabel (NULL);
3741       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3742       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3743       emitcode ("cpl", "c");
3744       emitcode ("", "!tlabeldef", (lbl->key + 100));
3745       outBitC (IC_RESULT (ic));
3746     }
3747   else
3748     {
3749       emitcode ("clr", "a");
3750       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3751       emitcode ("rlc", "a");
3752       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3753       emitcode ("addc", "a,#0");
3754       outAcc (IC_RESULT (ic));
3755     }
3756 }
3757
3758 static void
3759 adjustArithmeticResult (iCode * ic)
3760 {
3761   if (opIsGptr (IC_RESULT (ic)) &&
3762       opIsGptr (IC_LEFT (ic)) &&
3763       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3764     {
3765       aopPut (AOP (IC_RESULT (ic)),
3766               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE, NULL),
3767               GPTRSIZE - 1);
3768     }
3769
3770   if (opIsGptr (IC_RESULT (ic)) &&
3771       opIsGptr (IC_RIGHT (ic)) &&
3772       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3773     {
3774       aopPut (AOP (IC_RESULT (ic)),
3775             aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE, NULL),
3776               GPTRSIZE - 1);
3777     }
3778
3779   if (opIsGptr (IC_RESULT (ic)) &&
3780       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3781       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3782       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3783       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3784     {
3785       char buff[5];
3786       SNPRINTF (buff, sizeof(buff), 
3787                 "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3788       aopPut (AOP (IC_RESULT (ic)), buff, GPTRSIZE - 1);
3789     }
3790 }
3791
3792 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
3793 // generates the result if possible. If result is generated, returns TRUE; otherwise
3794 // returns false and caller must deal with fact that result isn't aopOp'd.
3795 bool aopOp3(iCode * ic)
3796 {
3797     bool dp1InUse, dp2InUse;
3798     bool useDp2;
3799     
3800     // First, generate the right opcode. DPTR may be used if neither left nor result are
3801     // of type AOP_STR.
3802     
3803 //    D(emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
3804 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
3805 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
3806 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
3807 //      );
3808 //    D(emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
3809 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
3810 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
3811 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
3812 //      );      
3813
3814     
3815     // Right uses DPTR unless left or result is an AOP_STR.
3816     aopOp (IC_RIGHT(ic),ic,FALSE, AOP_IS_STR(IC_LEFT(ic)) || AOP_IS_STR(IC_RESULT(ic)));
3817     
3818     // if the right used DPTR, left MUST use DPTR2.
3819     // if the right used DPTR2, left MUST use DPTR.
3820     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
3821     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
3822     // enabling us to assign DPTR to result.
3823      
3824     if (AOP_USESDPTR(IC_RIGHT(ic)))
3825     {
3826         useDp2 = TRUE;
3827     }
3828     else if (AOP_USESDPTR2(IC_RIGHT(ic)))
3829     {
3830         useDp2 = FALSE;
3831     }
3832     else
3833     {
3834         if (AOP_IS_STR(IC_RESULT(ic)) && !AOP_IS_STR(IC_LEFT(ic)))
3835         {
3836             useDp2 = TRUE;
3837         }
3838         else
3839         {
3840             useDp2 = FALSE;
3841         }
3842     }
3843
3844     aopOp(IC_LEFT(ic), ic, FALSE, useDp2);
3845     
3846     // We've op'd the left & right. So, if left or right are the same operand as result, 
3847     // we know aopOp will succeed, and we can just do it & bail.
3848     if (isOperandEqual(IC_LEFT(ic),IC_RESULT(ic)) ||
3849         isOperandEqual(IC_RIGHT(ic),IC_RESULT(ic)))
3850     {
3851 //      D(emitcode(";", "aopOp3: (left | right) & result equal"););
3852         aopOp(IC_RESULT(ic),ic,TRUE, FALSE);
3853         return TRUE;
3854     }
3855     
3856     // Note which dptrs are currently in use.
3857     dp1InUse = AOP_USESDPTR(IC_LEFT(ic)) || AOP_USESDPTR(IC_RIGHT(ic));
3858     dp2InUse = AOP_USESDPTR2(IC_LEFT(ic)) || AOP_USESDPTR2(IC_RIGHT(ic));
3859     
3860     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot 
3861     // generate it.
3862     if (dp1InUse && AOP_IS_STR(IC_RESULT(ic)))
3863     {
3864         return FALSE;
3865     }
3866     
3867     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
3868     if (dp2InUse && AOP_IS_DPTRn(IC_RESULT(ic)))
3869     {
3870         return FALSE;
3871     }
3872     
3873     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck    
3874     if (dp1InUse && dp2InUse && isOperandInFarSpace(IC_RESULT(ic)))
3875     {
3876         return FALSE;
3877     }
3878
3879     aopOp (IC_RESULT(ic),ic,TRUE, dp1InUse);
3880
3881     // Some sanity checking...
3882     if (dp1InUse && AOP_USESDPTR(IC_RESULT(ic)))
3883     {
3884         fprintf(stderr,
3885                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
3886                 __FILE__, __LINE__, ic->filename, ic->lineno);  
3887         emitcode(";", ">>> unexpected DPTR here.");
3888     }
3889     
3890     if (dp2InUse && AOP_USESDPTR2(IC_RESULT(ic)))
3891     {
3892         fprintf(stderr,
3893                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
3894                 __FILE__, __LINE__, ic->filename, ic->lineno);  
3895         emitcode(";", ">>> unexpected DPTR2 here.");
3896     }    
3897     
3898     return TRUE;
3899 }
3900
3901 // Macro to aopOp all three operands of an ic. If this cannot be done, 
3902 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
3903 // will be set TRUE. The caller must then handle the case specially, noting
3904 // that the IC_RESULT operand is not aopOp'd.
3905 // 
3906 #define AOP_OP_3_NOFATAL(ic, rc) \
3907             do { rc = !aopOp3(ic); } while (0)
3908
3909 // aopOp the left & right operands of an ic.
3910 #define AOP_OP_2(ic) \
3911     aopOp (IC_RIGHT(ic),ic,FALSE, AOP_IS_STR(IC_LEFT(ic))); \
3912     aopOp (IC_LEFT(ic),ic,FALSE, AOP_USESDPTR(IC_RIGHT(ic)));
3913
3914 // convienience macro.
3915 #define AOP_SET_LOCALS(ic) \
3916     left = IC_LEFT(ic); \
3917     right = IC_RIGHT(ic); \
3918     result = IC_RESULT(ic);
3919
3920
3921 // Given an integer value of pushedSize bytes on the stack,
3922 // adjust it to be resultSize bytes, either by discarding
3923 // the most significant bytes or by zero-padding.
3924 //
3925 // On exit from this macro, pushedSize will have been adjusted to
3926 // equal resultSize, and ACC may be trashed.
3927 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
3928       /* If the pushed data is bigger than the result,          \
3929        * simply discard unused bytes. Icky, but works.          \
3930        */                                                       \
3931       while (pushedSize > resultSize)                           \
3932       {                                                         \
3933           D (emitcode (";", "discarding unused result byte."););\
3934           emitcode ("pop", "acc");                              \
3935           pushedSize--;                                         \
3936       }                                                         \
3937       if (pushedSize < resultSize)                              \
3938       {                                                         \
3939           emitcode ("clr", "a");                                \
3940           /* Conversly, we haven't pushed enough here.          \
3941            * just zero-pad, and all is well.                    \
3942            */                                                   \
3943           while (pushedSize < resultSize)                       \
3944           {                                                     \
3945               emitcode("push", "acc");                          \
3946               pushedSize++;                                     \
3947           }                                                     \
3948       }                                                         \
3949       assert(pushedSize == resultSize);
3950
3951 /*-----------------------------------------------------------------*/
3952 /* genPlus - generates code for addition                           */
3953 /*-----------------------------------------------------------------*/
3954 static void
3955 genPlus (iCode * ic)
3956 {
3957   int size, offset = 0;
3958   bool pushResult;
3959   int rSize;
3960
3961   D (emitcode (";", "genPlus "););
3962
3963   /* special cases :- */
3964   if ( AOP_IS_STR(IC_LEFT(ic)) &&
3965       isOperandLiteral(IC_RIGHT(ic)) && OP_SYMBOL(IC_RESULT(ic))->ruonly) {
3966       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
3967       size = floatFromVal (AOP (IC_RIGHT(ic))->aopu.aop_lit);
3968       if (size <= 9) {
3969           while (size--) emitcode ("inc","dptr");
3970       } else {
3971           emitcode ("mov","a,dpl");
3972           emitcode ("add","a,#!constbyte",size & 0xff);
3973           emitcode ("mov","dpl,a");
3974           emitcode ("mov","a,dph");
3975           emitcode ("addc","a,#!constbyte",(size >> 8) & 0xff);
3976           emitcode ("mov","dph,a");
3977           emitcode ("mov","a,dpx");
3978           emitcode ("addc","a,#!constbyte",(size >> 16) & 0xff);
3979           emitcode ("mov","dpx,a");
3980       }
3981       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
3982       return ;
3983   }
3984   if ( IS_SYMOP(IC_LEFT(ic)) && 
3985        OP_SYMBOL(IC_LEFT(ic))->remat &&
3986        isOperandInFarSpace(IC_RIGHT(ic))) {
3987       operand *op = IC_RIGHT(ic);
3988       IC_RIGHT(ic) = IC_LEFT(ic);
3989       IC_LEFT(ic) = op;
3990   }
3991                 
3992   AOP_OP_3_NOFATAL (ic, pushResult);
3993     
3994   if (pushResult)
3995     {
3996       D (emitcode (";", "genPlus: must push result: 3 ops in far space"););
3997     }
3998
3999   if (!pushResult)
4000     {
4001       /* if literal, literal on the right or
4002          if left requires ACC or right is already
4003          in ACC */
4004       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4005        || ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic))))
4006           || AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4007         {
4008           operand *t = IC_RIGHT (ic);
4009           IC_RIGHT (ic) = IC_LEFT (ic);
4010           IC_LEFT (ic) = t;
4011           emitcode (";", "Swapped plus args.");
4012         }
4013
4014       /* if both left & right are in bit
4015          space */
4016       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4017           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4018         {
4019           genPlusBits (ic);
4020           goto release;
4021         }
4022
4023       /* if left in bit space & right literal */
4024       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4025           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4026         {
4027           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4028           /* if result in bit space */
4029           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4030             {
4031               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4032                 emitcode ("cpl", "c");
4033               outBitC (IC_RESULT (ic));
4034             }
4035           else
4036             {
4037               size = getDataSize (IC_RESULT (ic));
4038               _startLazyDPSEvaluation ();
4039               while (size--)
4040                 {
4041                   MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4042                   emitcode ("addc", "a,#0");
4043                   aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4044                 }
4045               _endLazyDPSEvaluation ();
4046             }
4047           goto release;
4048         }
4049
4050       /* if I can do an increment instead
4051          of add then GOOD for ME */
4052       if (genPlusIncr (ic) == TRUE)
4053         {
4054           emitcode (";", "did genPlusIncr");
4055           goto release;
4056         }
4057
4058     }
4059   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4060
4061   _startLazyDPSEvaluation ();
4062   while (size--)
4063     {
4064       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4065         {
4066           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4067           if (offset == 0)
4068             emitcode ("add", "a,%s",
4069                  aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4070           else
4071             emitcode ("addc", "a,%s",
4072                  aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4073         }
4074       else
4075         {
4076           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4077           {
4078               /* right is going to use ACC or we would have taken the
4079                * above branch.
4080                */
4081               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4082        TR_AP("#3");
4083               D(emitcode(";", "+ AOP_ACC special case."););
4084               emitcode("xch", "a, %s", DP2_RESULT_REG);
4085           }
4086           MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4087           if (offset == 0)
4088           {
4089             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4090             {
4091          TR_AP("#4");
4092                 emitcode("add", "a, %s", DP2_RESULT_REG); 
4093             }
4094             else
4095             {
4096                 emitcode ("add", "a,%s",
4097                           aopGet (AOP(IC_LEFT(ic)), offset, FALSE, FALSE,
4098                                   DP2_RESULT_REG));
4099             }
4100           }
4101           else
4102           {
4103             emitcode ("addc", "a,%s",
4104                   aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE,
4105                           DP2_RESULT_REG));
4106           }
4107         }
4108       if (!pushResult)
4109         {
4110           aopPut (AOP (IC_RESULT (ic)), "a", offset);
4111         }
4112       else
4113         {
4114           emitcode ("push", "acc");
4115         }
4116       offset++;
4117     }
4118   _endLazyDPSEvaluation ();
4119
4120   if (pushResult)
4121     {
4122       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4123
4124       size = getDataSize (IC_LEFT (ic));
4125       rSize = getDataSize (IC_RESULT (ic));
4126
4127       ADJUST_PUSHED_RESULT(size, rSize);
4128
4129       _startLazyDPSEvaluation ();
4130       while (size--)
4131         {
4132           emitcode ("pop", "acc");
4133           aopPut (AOP (IC_RESULT (ic)), "a", size);
4134         }
4135       _endLazyDPSEvaluation ();
4136     }
4137
4138   adjustArithmeticResult (ic);
4139
4140 release:
4141   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4142   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4143   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4144 }
4145
4146 /*-----------------------------------------------------------------*/
4147 /* genMinusDec :- does subtraction with deccrement if possible     */
4148 /*-----------------------------------------------------------------*/
4149 static bool
4150 genMinusDec (iCode * ic)
4151 {
4152   unsigned int icount;
4153   unsigned int size = getDataSize (IC_RESULT (ic));
4154
4155   /* will try to generate an increment */
4156   /* if the right side is not a literal
4157      we cannot */
4158   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4159     return FALSE;
4160
4161   /* if the literal value of the right hand side
4162      is greater than 4 then it is not worth it */
4163   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4164     return FALSE;
4165
4166   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4167       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4168       while (icount--) {
4169           emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE,NULL));
4170       }
4171       return TRUE;
4172   }
4173   /* if decrement 16 bits in register */
4174   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4175       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4176       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4177       (size > 1) &&
4178       (icount == 1))
4179     {
4180       symbol *tlbl;
4181       int    emitTlbl;
4182       int    labelRange;
4183       char   *l;
4184
4185       /* If the next instruction is a goto and the goto target
4186          * is <= 5 instructions previous to this, we can generate
4187          * jumps straight to that target.
4188        */
4189       if (ic->next && ic->next->op == GOTO
4190           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4191           && labelRange <= 5)
4192         {
4193           emitcode (";", "tail decrement optimized (range %d)", labelRange);
4194           tlbl = IC_LABEL (ic->next);
4195           emitTlbl = 0;
4196         }
4197       else
4198         {
4199           tlbl = newiTempLabel (NULL);
4200           emitTlbl = 1;
4201         }
4202
4203       l = aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, NULL);
4204       emitcode ("dec", "%s", l);
4205  
4206       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4207           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4208           IS_AOP_PREG (IC_RESULT (ic)))
4209       {     
4210           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4211       }
4212       else
4213       {
4214           emitcode ("mov", "a,#!constbyte",0xff);
4215           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4216       }
4217       l = aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, NULL);
4218       emitcode ("dec", "%s", l);
4219       if (size > 2)
4220         {
4221             if (!strcmp(l, "acc"))
4222             {
4223                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4224             }
4225             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4226                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4227                      IS_AOP_PREG (IC_RESULT (ic)))
4228             {       
4229                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4230             }
4231             else
4232             {
4233                 emitcode ("mov", "a,#!constbyte",0xff);
4234                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4235             }
4236             l = aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, NULL);
4237             emitcode ("dec", "%s", l);
4238         }
4239       if (size > 3)
4240         {
4241             if (!strcmp(l, "acc"))
4242             {
4243                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4244             }
4245             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4246                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4247                      IS_AOP_PREG (IC_RESULT (ic)))
4248             {       
4249                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4250             }
4251             else
4252             {
4253                 emitcode ("mov", "a,#!constbyte",0xff);
4254                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4255             }       
4256             l = aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE, NULL);
4257             emitcode ("dec", "%s", l);
4258         }
4259       if (emitTlbl)
4260         {
4261           emitcode ("", "!tlabeldef", tlbl->key + 100);
4262         }
4263       return TRUE;
4264     }
4265
4266   /* if the sizes are greater than 1 then we cannot */
4267   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4268       AOP_SIZE (IC_LEFT (ic)) > 1)
4269     return FALSE;
4270
4271   /* we can if the aops of the left & result match or
4272      if they are in registers and the registers are the
4273      same */
4274   if (
4275        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4276        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4277        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4278     {
4279
4280       _startLazyDPSEvaluation ();
4281       while (icount--)
4282         {
4283           emitcode ("dec", "%s",
4284                     aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, NULL));
4285         }
4286       _endLazyDPSEvaluation ();
4287
4288       return TRUE;
4289     }
4290
4291   return FALSE;
4292 }
4293
4294 /*-----------------------------------------------------------------*/
4295 /* addSign - complete with sign                                    */
4296 /*-----------------------------------------------------------------*/
4297 static void
4298 addSign (operand * result, int offset, int sign)
4299 {
4300   int size = (getDataSize (result) - offset);
4301   if (size > 0)
4302     {
4303       _startLazyDPSEvaluation();
4304       if (sign)
4305         {
4306           emitcode ("rlc", "a");
4307           emitcode ("subb", "a,acc");
4308           while (size--)
4309           {
4310             aopPut (AOP (result), "a", offset++);
4311           }
4312         }
4313       else
4314       {
4315         while (size--)
4316         {
4317           aopPut (AOP (result), zero, offset++);
4318         }
4319       }
4320       _endLazyDPSEvaluation();
4321     }
4322 }
4323
4324 /*-----------------------------------------------------------------*/
4325 /* genMinusBits - generates code for subtraction  of two bits      */
4326 /*-----------------------------------------------------------------*/
4327 static void
4328 genMinusBits (iCode * ic)
4329 {
4330   symbol *lbl = newiTempLabel (NULL);
4331
4332   D (emitcode (";", "genMinusBits "););
4333
4334   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4335     {
4336       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4337       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4338       emitcode ("cpl", "c");
4339       emitcode ("", "!tlabeldef", (lbl->key + 100));
4340       outBitC (IC_RESULT (ic));
4341     }
4342   else
4343     {
4344       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4345       emitcode ("subb", "a,acc");
4346       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4347       emitcode ("inc", "a");
4348       emitcode ("", "!tlabeldef", (lbl->key + 100));
4349       aopPut (AOP (IC_RESULT (ic)), "a", 0);
4350       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4351     }
4352 }
4353
4354 /*-----------------------------------------------------------------*/
4355 /* genMinus - generates code for subtraction                       */
4356 /*-----------------------------------------------------------------*/
4357 static void
4358 genMinus (iCode * ic)
4359 {
4360     int size, offset = 0;
4361     int rSize;
4362     long lit = 0L;
4363     bool pushResult;
4364
4365     D (emitcode (";", "genMinus "););
4366
4367     AOP_OP_3_NOFATAL(ic, pushResult);   
4368
4369     if (!pushResult)
4370     {
4371       /* special cases :- */
4372       /* if both left & right are in bit space */
4373       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4374           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4375         {
4376           genMinusBits (ic);
4377           goto release;
4378         }
4379
4380       /* if I can do an decrement instead
4381          of subtract then GOOD for ME */
4382       if (genMinusDec (ic) == TRUE)
4383         goto release;
4384
4385     }
4386
4387   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4388
4389   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4390     {
4391       CLRC;
4392     }
4393   else
4394     {
4395       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4396       lit = -lit;
4397     }
4398
4399
4400   /* if literal, add a,#-lit, else normal subb */
4401   _startLazyDPSEvaluation ();
4402   while (size--) {
4403       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
4404           if (AOP_USESDPTR(IC_RIGHT(ic))) {
4405               emitcode ("mov","b,%s",
4406                         aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4407               MOVA(aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4408               emitcode ("subb","a,b");
4409           } else {
4410               MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4411               emitcode ("subb", "a,%s",
4412                         aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, 
4413                                 DP2_RESULT_REG));
4414           }
4415       } else {
4416           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4417           /* first add without previous c */
4418           if (!offset) {
4419               if (!size && lit==-1) {
4420                   emitcode ("dec", "a");
4421               } else {
4422                   emitcode ("add", "a,#!constbyte",
4423                             (unsigned int) (lit & 0x0FFL));
4424               }
4425           } else {
4426               emitcode ("addc", "a,#!constbyte",
4427                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4428           }
4429       }
4430       
4431       if (pushResult) {
4432           emitcode ("push", "acc");
4433       } else {
4434           aopPut (AOP (IC_RESULT (ic)), "a", offset);
4435       }
4436       offset++;
4437   }
4438   _endLazyDPSEvaluation ();
4439   
4440   if (pushResult)
4441     {
4442       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4443
4444       size = getDataSize (IC_LEFT (ic));
4445       rSize = getDataSize (IC_RESULT (ic));
4446
4447       ADJUST_PUSHED_RESULT(size, rSize);
4448
4449       _startLazyDPSEvaluation ();
4450       while (size--)
4451         {
4452           emitcode ("pop", "acc");
4453           aopPut (AOP (IC_RESULT (ic)), "a", size);
4454         }
4455       _endLazyDPSEvaluation ();
4456     }
4457
4458   adjustArithmeticResult (ic);
4459
4460 release:
4461   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4462   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4463   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4464 }
4465
4466
4467 /*-----------------------------------------------------------------*/
4468 /* genMultbits :- multiplication of bits                           */
4469 /*-----------------------------------------------------------------*/
4470 static void
4471 genMultbits (operand * left,
4472              operand * right,
4473              operand * result,
4474              iCode   * ic)
4475 {
4476   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4477   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4478   aopOp(result, ic, TRUE, FALSE);
4479   outBitC (result);
4480 }
4481
4482
4483 /*-----------------------------------------------------------------*/
4484 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4485 /*-----------------------------------------------------------------*/
4486 static void
4487 genMultOneByte (operand * left,
4488                 operand * right,
4489                 operand * result,
4490                 iCode   * ic)
4491 {
4492   sym_link *opetype = operandType (result);
4493   symbol *lbl;
4494
4495
4496   /* (if two literals: the value is computed before) */
4497   /* if one literal, literal on the right */
4498   if (AOP_TYPE (left) == AOP_LIT)
4499     {
4500       operand *t = right;
4501       right = left;
4502       left = t;
4503       emitcode (";", "swapped left and right");
4504     }
4505
4506   if (SPEC_USIGN(opetype)
4507       // ignore the sign of left and right, what else can we do?
4508       || (SPEC_USIGN(operandType(left)) && 
4509           SPEC_USIGN(operandType(right)))) {
4510     // just an unsigned 8*8=8/16 multiply
4511     //emitcode (";","unsigned");
4512     emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
4513     MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
4514     emitcode ("mul", "ab");
4515    
4516     _G.accInUse++; _G.bInUse++;
4517     aopOp(result, ic, TRUE, FALSE);
4518       
4519       if (AOP_SIZE(result)<1 || AOP_SIZE(result)>2) 
4520       {
4521           // this should never happen
4522           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n", 
4523                    AOP_SIZE(result), __FILE__, lineno);
4524           exit (1);
4525       }      
4526       
4527     aopPut (AOP (result), "a", 0);
4528     _G.accInUse--; _G.bInUse--;
4529     if (AOP_SIZE(result)==2) 
4530     {
4531       aopPut (AOP (result), "b", 1);
4532     }
4533     return;
4534   }
4535
4536   // we have to do a signed multiply
4537
4538   emitcode (";", "signed");
4539   emitcode ("clr", "F0"); // reset sign flag
4540   MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
4541
4542   lbl=newiTempLabel(NULL);
4543   emitcode ("jnb", "acc.7,!tlabel",  lbl->key+100);
4544   // left side is negative, 8-bit two's complement, this fails for -128
4545   emitcode ("setb", "F0"); // set sign flag
4546   emitcode ("cpl", "a");
4547   emitcode ("inc", "a");
4548
4549   emitcode ("", "!tlabeldef", lbl->key+100);
4550
4551   /* if literal */
4552   if (AOP_TYPE(right)==AOP_LIT) {
4553     signed char val=floatFromVal (AOP (right)->aopu.aop_lit);
4554     /* AND literal negative */
4555     if ((int) val < 0) {
4556       emitcode ("cpl", "F0"); // complement sign flag
4557       emitcode ("mov", "b,#!constbyte", -val);
4558     } else {
4559       emitcode ("mov", "b,#!constbyte", val);
4560     }
4561   } else {
4562     lbl=newiTempLabel(NULL);
4563     emitcode ("mov", "b,a");
4564     emitcode ("mov", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
4565     emitcode ("jnb", "acc.7,!tlabel", lbl->key+100);
4566     // right side is negative, 8-bit two's complement
4567     emitcode ("cpl", "F0"); // complement sign flag
4568     emitcode ("cpl", "a");
4569     emitcode ("inc", "a");
4570     emitcode ("", "!tlabeldef", lbl->key+100);
4571   }
4572   emitcode ("mul", "ab");
4573     
4574   _G.accInUse++;_G.bInUse++;
4575   aopOp(result, ic, TRUE, FALSE);
4576     
4577   if (AOP_SIZE(result)<1 || AOP_SIZE(result)>2) 
4578   {
4579     // this should never happen
4580       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n", 
4581                AOP_SIZE(result), __FILE__, lineno);
4582       exit (1);
4583   }    
4584     
4585   lbl=newiTempLabel(NULL);
4586   emitcode ("jnb", "F0,!tlabel", lbl->key+100);
4587   // only ONE op was negative, we have to do a 8/16-bit two's complement
4588   emitcode ("cpl", "a"); // lsb
4589   if (AOP_SIZE(result)==1) {
4590     emitcode ("inc", "a");
4591   } else {
4592     emitcode ("add", "a,#1");
4593     emitcode ("xch", "a,b");
4594     emitcode ("cpl", "a"); // msb
4595     emitcode ("addc", "a,#0");
4596     emitcode ("xch", "a,b");
4597   }
4598
4599   emitcode ("", "!tlabeldef", lbl->key+100);
4600   aopPut (AOP (result), "a", 0);
4601   _G.accInUse--;_G.bInUse--;
4602   if (AOP_SIZE(result)==2) {
4603     aopPut (AOP (result), "b", 1);
4604   }
4605 }
4606
4607 /*-----------------------------------------------------------------*/
4608 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
4609 /*-----------------------------------------------------------------*/
4610 static void genMultTwoByte (operand *left, operand *right, 
4611                             operand *result, iCode *ic)
4612 {
4613         sym_link *retype = getSpec(operandType(right));
4614         sym_link *letype = getSpec(operandType(left));
4615         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
4616         symbol *lbl;
4617
4618         if (AOP_TYPE (left) == AOP_LIT) {
4619                 operand *t = right;
4620                 right = left;
4621                 left = t;
4622         }
4623         /* save EA bit in F1 */
4624         lbl = newiTempLabel(NULL);
4625         emitcode ("setb","F1");
4626         emitcode ("jbc","EA,!tlabel",lbl->key+100);
4627         emitcode ("clr","F1");
4628         emitcode("","!tlabeldef",lbl->key+100);
4629
4630         /* load up MB with right */
4631         if (!umult) {
4632                 emitcode("clr","F0");
4633                 if (AOP_TYPE(right) == AOP_LIT) {
4634                         int val=floatFromVal (AOP (right)->aopu.aop_lit);
4635                         if (val < 0) {
4636                                 emitcode("setb","F0");
4637                                 val = -val;
4638                         }
4639                         emitcode ("mov","mb,#!constbyte",val & 0xff);
4640                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);                
4641                 } else {
4642                         lbl = newiTempLabel(NULL);
4643                         emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
4644                         emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
4645                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);          
4646                         emitcode ("xch", "a,b");
4647                         emitcode ("cpl","a");
4648                         emitcode ("add", "a,#1");
4649                         emitcode ("xch", "a,b");
4650                         emitcode ("cpl", "a"); // msb
4651                         emitcode ("addc", "a,#0");
4652                         emitcode ("setb","F0");
4653                         emitcode ("","!tlabeldef",lbl->key+100);
4654                         emitcode ("mov","mb,b");
4655                         emitcode ("mov","mb,a");
4656                 }
4657         } else {
4658                 emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
4659                 emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
4660         }
4661         /* load up MA with left */
4662         if (!umult) {
4663                 lbl = newiTempLabel(NULL);
4664                 emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
4665                 emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
4666                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
4667                 emitcode ("xch", "a,b");
4668                 emitcode ("cpl","a");
4669                 emitcode ("add", "a,#1");
4670                 emitcode ("xch", "a,b");
4671                 emitcode ("cpl", "a"); // msb
4672                 emitcode ("addc","a,#0");
4673                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
4674                 emitcode ("setb","F0");
4675                 emitcode ("","!tlabeldef",lbl->key+100);
4676                 emitcode ("mov","ma,b");
4677                 emitcode ("mov","ma,a");
4678         } else {
4679                 emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
4680                 emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
4681         }
4682         /* wait for multiplication to finish */
4683         lbl = newiTempLabel(NULL);
4684         emitcode("","!tlabeldef", lbl->key+100);
4685         emitcode("mov","a,mcnt1");
4686         emitcode("anl","a,#!constbyte",0x80);
4687         emitcode("jnz","!tlabel",lbl->key+100);
4688         
4689         freeAsmop (left, NULL, ic, TRUE);
4690         freeAsmop (right, NULL, ic,TRUE);
4691         aopOp(result, ic, TRUE, FALSE);
4692
4693         /* if unsigned then simple */   
4694         if (umult) {
4695                 emitcode ("mov","a,ma");
4696                 if (AOP_SIZE(result) >= 4) aopPut(AOP(result),"a",3);
4697                 emitcode ("mov","a,ma");
4698                 if (AOP_SIZE(result) >= 3) aopPut(AOP(result),"a",2);
4699                 aopPut(AOP(result),"ma",1);
4700                 aopPut(AOP(result),"ma",0);
4701         } else {
4702                 emitcode("push","ma");
4703                 emitcode("push","ma");
4704                 emitcode("push","ma");
4705                 MOVA("ma");
4706                 /* negate result if needed */
4707                 lbl = newiTempLabel(NULL);      
4708                 emitcode("jnb","F0,!tlabel",lbl->key+100);
4709                 emitcode("cpl","a");
4710                 emitcode("add","a,#1");
4711                 emitcode("","!tlabeldef", lbl->key+100);
4712                 if (AOP_TYPE(result) == AOP_ACC)
4713                 {
4714                     D(emitcode(";", "ACC special case."););
4715                     /* We know result is the only live aop, and 
4716                      * it's obviously not a DPTR2, so AP is available.
4717                      */
4718                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
4719                 }
4720                 else
4721                 {
4722                     aopPut(AOP(result),"a",0);
4723                 }
4724             
4725                 emitcode("pop","acc");
4726                 lbl = newiTempLabel(NULL);      
4727                 emitcode("jnb","F0,!tlabel",lbl->key+100);
4728                 emitcode("cpl","a");
4729                 emitcode("addc","a,#0");
4730                 emitcode("","!tlabeldef", lbl->key+100);
4731                 aopPut(AOP(result),"a",1);
4732                 emitcode("pop","acc");
4733                 if (AOP_SIZE(result) >= 3) {
4734                         lbl = newiTempLabel(NULL);      
4735                         emitcode("jnb","F0,!tlabel",lbl->key+100);
4736                         emitcode("cpl","a");
4737                         emitcode("addc","a,#0");                        
4738                         emitcode("","!tlabeldef", lbl->key+100);
4739                         aopPut(AOP(result),"a",2);
4740                 }
4741                 emitcode("pop","acc");
4742                 if (AOP_SIZE(result) >= 4) {
4743                         lbl = newiTempLabel(NULL);      
4744                         emitcode("jnb","F0,!tlabel",lbl->key+100);
4745                         emitcode("cpl","a");
4746                         emitcode("addc","a,#0");                        
4747                         emitcode("","!tlabeldef", lbl->key+100);
4748                         aopPut(AOP(result),"a",3);
4749                 }
4750                 if (AOP_TYPE(result) == AOP_ACC)
4751                 {
4752                     /* We stashed the result away above. */
4753                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
4754                 }           
4755                 
4756         }
4757         freeAsmop (result, NULL, ic, TRUE);
4758
4759         /* restore EA bit in F1 */
4760         lbl = newiTempLabel(NULL);
4761         emitcode ("jnb","F1,!tlabel",lbl->key+100);
4762         emitcode ("setb","EA");
4763         emitcode("","!tlabeldef",lbl->key+100);
4764         return ;
4765 }
4766
4767 /*-----------------------------------------------------------------*/
4768 /* genMult - generates code for multiplication                     */
4769 /*-----------------------------------------------------------------*/
4770 static void
4771 genMult (iCode * ic)
4772 {
4773   operand *left = IC_LEFT (ic);
4774   operand *right = IC_RIGHT (ic);
4775   operand *result = IC_RESULT (ic);
4776
4777   D (emitcode (";", "genMult "););
4778
4779   /* assign the amsops */
4780   AOP_OP_2 (ic);
4781
4782   /* special cases first */
4783   /* both are bits */
4784   if (AOP_TYPE (left) == AOP_CRY &&
4785       AOP_TYPE (right) == AOP_CRY)
4786     {
4787       genMultbits (left, right, result, ic);
4788       goto release;
4789     }
4790
4791   /* if both are of size == 1 */
4792   if (AOP_SIZE (left) == 1 &&
4793       AOP_SIZE (right) == 1)
4794     {
4795       genMultOneByte (left, right, result, ic);
4796       goto release;
4797     }
4798
4799   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
4800           /* use the ds390 ARITHMETIC accel UNIT */
4801           genMultTwoByte (left, right, result, ic);
4802           return ;
4803   }
4804   /* should have been converted to function call */
4805   assert (0);
4806
4807 release:
4808   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4809   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4810   freeAsmop (result, NULL, ic, TRUE);
4811 }
4812
4813 /*-----------------------------------------------------------------*/
4814 /* genDivbits :- division of bits                                  */
4815 /*-----------------------------------------------------------------*/
4816 static void
4817 genDivbits (operand * left,
4818             operand * right,
4819             operand * result,
4820             iCode   * ic)
4821 {
4822
4823   char *l;
4824
4825   /* the result must be bit */
4826   LOAD_AB_FOR_DIV (left, right, l);
4827   emitcode ("div", "ab");
4828   emitcode ("rrc", "a");
4829   aopOp(result, ic, TRUE, FALSE);
4830     
4831   aopPut (AOP (result), "c", 0);
4832 }
4833
4834 /*-----------------------------------------------------------------*/
4835 /* genDivOneByte : 8 bit division                                  */
4836 /*-----------------------------------------------------------------*/
4837 static void
4838 genDivOneByte (operand * left,
4839                operand * right,
4840                operand * result,
4841                iCode   * ic)
4842 {
4843   sym_link *opetype = operandType (result);
4844   char *l;
4845   symbol *lbl;
4846   int size, offset;
4847
4848   offset = 1;
4849   /* signed or unsigned */
4850   if (SPEC_USIGN (opetype))
4851     {
4852         /* unsigned is easy */
4853         LOAD_AB_FOR_DIV (left, right, l);
4854         emitcode ("div", "ab");
4855
4856         _G.accInUse++;
4857         aopOp(result, ic, TRUE, FALSE);
4858         aopPut (AOP (result), "a", 0);
4859         _G.accInUse--;
4860
4861         size = AOP_SIZE (result) - 1;
4862         
4863         while (size--)
4864         {
4865             aopPut (AOP (result), zero, offset++);
4866         }
4867       return;
4868     }
4869
4870   /* signed is a little bit more difficult */
4871
4872   /* save the signs of the operands */
4873   MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
4874   emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, TRUE, FALSE));
4875   emitcode ("push", "acc");     /* save it on the stack */
4876
4877   /* now sign adjust for both left & right */
4878   MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
4879   lbl = newiTempLabel (NULL);
4880   emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
4881   emitcode ("cpl", "a");
4882   emitcode ("inc", "a");
4883   emitcode ("", "!tlabeldef", (lbl->key + 100));
4884   emitcode ("mov", "b,a");
4885
4886   /* sign adjust left side */
4887   MOVA( aopGet (AOP (left), 0, FALSE, FALSE, NULL));
4888
4889   lbl = newiTempLabel (NULL);
4890   emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
4891   emitcode ("cpl", "a");
4892   emitcode ("inc", "a");
4893   emitcode ("", "!tlabeldef", (lbl->key + 100));
4894
4895   /* now the division */
4896   emitcode ("nop", "; workaround for DS80C390 div bug.");
4897   emitcode ("div", "ab");
4898   /* we are interested in the lower order
4899      only */
4900   emitcode ("mov", "b,a");
4901   lbl = newiTempLabel (NULL);
4902   emitcode ("pop", "acc");
4903   /* if there was an over flow we don't
4904      adjust the sign of the result */
4905   emitcode ("jb", "ov,!tlabel", (lbl->key + 100));
4906   emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
4907   CLRC;
4908   emitcode ("clr", "a");
4909   emitcode ("subb", "a,b");
4910   emitcode ("mov", "b,a");
4911   emitcode ("", "!tlabeldef", (lbl->key + 100));
4912
4913   /* now we are done */
4914   _G.accInUse++;     _G.bInUse++;
4915     aopOp(result, ic, TRUE, FALSE);
4916     
4917     aopPut (AOP (result), "b", 0);
4918     
4919     size = AOP_SIZE (result) - 1;
4920     
4921     if (size > 0)
4922     {
4923       emitcode ("mov", "c,b.7");
4924       emitcode ("subb", "a,acc");
4925     }
4926     while (size--)
4927     {
4928         aopPut (AOP (result), "a", offset++);
4929     }
4930     _G.accInUse--;     _G.bInUse--;
4931
4932 }
4933
4934 /*-----------------------------------------------------------------*/
4935 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
4936 /*-----------------------------------------------------------------*/
4937 static void genDivTwoByte (operand *left, operand *right, 
4938                             operand *result, iCode *ic)
4939 {
4940         sym_link *retype = getSpec(operandType(right));
4941         sym_link *letype = getSpec(operandType(left));
4942         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
4943         symbol *lbl;
4944
4945         /* save EA bit in F1 */
4946         lbl = newiTempLabel(NULL);
4947         emitcode ("setb","F1");
4948         emitcode ("jbc","EA,!tlabel",lbl->key+100);
4949         emitcode ("clr","F1");
4950         emitcode("","!tlabeldef",lbl->key+100);
4951
4952         /* load up MA with left */
4953         if (!umult) {
4954                 emitcode("clr","F0");
4955                 lbl = newiTempLabel(NULL);
4956                 emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
4957                 emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
4958                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
4959                 emitcode ("xch", "a,b");
4960                 emitcode ("cpl","a");
4961                 emitcode ("add", "a,#1");
4962                 emitcode ("xch", "a,b");
4963                 emitcode ("cpl", "a"); // msb
4964                 emitcode ("addc","a,#0");
4965                 emitcode ("setb","F0");
4966                 emitcode ("","!tlabeldef",lbl->key+100);
4967                 emitcode ("mov","ma,b");
4968                 emitcode ("mov","ma,a");
4969         } else {
4970                 emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
4971                 emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
4972         }
4973
4974         /* load up MB with right */
4975         if (!umult) {
4976                 if (AOP_TYPE(right) == AOP_LIT) {
4977                         int val=floatFromVal (AOP (right)->aopu.aop_lit);
4978                         if (val < 0) {
4979                                 lbl = newiTempLabel(NULL);
4980                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
4981                                 emitcode("setb","F0");
4982                                 emitcode ("","!tlabeldef",lbl->key+100);
4983                                 val = -val;
4984                         } 
4985                         emitcode ("mov","mb,#!constbyte",val & 0xff);               
4986                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
4987                 } else {
4988                         lbl = newiTempLabel(NULL);
4989                         emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
4990                         emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
4991                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);          
4992                         emitcode ("xch", "a,b");
4993                         emitcode ("cpl","a");
4994                         emitcode ("add", "a,#1");
4995                         emitcode ("xch", "a,b");
4996                         emitcode ("cpl", "a"); // msb
4997                         emitcode ("addc", "a,#0");
4998                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
4999                         emitcode ("setb","F0");
5000                         emitcode ("","!tlabeldef",lbl->key+100);
5001                         emitcode ("mov","mb,b");
5002                         emitcode ("mov","mb,a");
5003                 }
5004         } else {
5005                 emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5006                 emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5007         }
5008
5009         /* wait for multiplication to finish */
5010         lbl = newiTempLabel(NULL);
5011         emitcode("","!tlabeldef", lbl->key+100);
5012         emitcode("mov","a,mcnt1");
5013         emitcode("anl","a,#!constbyte",0x80);
5014         emitcode("jnz","!tlabel",lbl->key+100);
5015         
5016         freeAsmop (left, NULL, ic, TRUE);
5017         freeAsmop (right, NULL, ic,TRUE);
5018         aopOp(result, ic, TRUE, FALSE);
5019
5020         /* if unsigned then simple */   
5021         if (umult) {
5022                 aopPut(AOP(result),"ma",1);
5023                 aopPut(AOP(result),"ma",0);
5024         } else {
5025                 emitcode("push","ma");
5026                 MOVA("ma");
5027                 /* negate result if needed */
5028                 lbl = newiTempLabel(NULL);      
5029                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5030                 emitcode("cpl","a");
5031                 emitcode("add","a,#1");
5032                 emitcode("","!tlabeldef", lbl->key+100);
5033                 aopPut(AOP(result),"a",0);
5034                 emitcode("pop","acc");
5035                 lbl = newiTempLabel(NULL);      
5036                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5037                 emitcode("cpl","a");
5038                 emitcode("addc","a,#0");
5039                 emitcode("","!tlabeldef", lbl->key+100);
5040                 aopPut(AOP(result),"a",1);
5041         }
5042         freeAsmop (result, NULL, ic, TRUE);
5043         /* restore EA bit in F1 */
5044         lbl = newiTempLabel(NULL);
5045         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5046         emitcode ("setb","EA");
5047         emitcode("","!tlabeldef",lbl->key+100);
5048         return ;
5049 }
5050
5051 /*-----------------------------------------------------------------*/
5052 /* genDiv - generates code for division                            */
5053 /*-----------------------------------------------------------------*/
5054 static void
5055 genDiv (iCode * ic)
5056 {
5057   operand *left = IC_LEFT (ic);
5058   operand *right = IC_RIGHT (ic);
5059   operand *result = IC_RESULT (ic);
5060
5061   D (emitcode (";", "genDiv "););
5062
5063   /* assign the amsops */
5064   AOP_OP_2 (ic);
5065
5066   /* special cases first */
5067   /* both are bits */
5068   if (AOP_TYPE (left) == AOP_CRY &&
5069       AOP_TYPE (right) == AOP_CRY)
5070     {
5071       genDivbits (left, right, result, ic);
5072       goto release;
5073     }
5074
5075   /* if both are of size == 1 */
5076   if (AOP_SIZE (left) == 1 &&
5077       AOP_SIZE (right) == 1)
5078     {
5079       genDivOneByte (left, right, result, ic);
5080       goto release;
5081     }
5082
5083   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5084           /* use the ds390 ARITHMETIC accel UNIT */
5085           genDivTwoByte (left, right, result, ic);
5086           return ;
5087   }
5088   /* should have been converted to function call */
5089   assert (0);
5090 release:
5091   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5092   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5093   freeAsmop (result, NULL, ic, TRUE);
5094 }
5095
5096 /*-----------------------------------------------------------------*/
5097 /* genModbits :- modulus of bits                                   */
5098 /*-----------------------------------------------------------------*/
5099 static void
5100 genModbits (operand * left,
5101             operand * right,
5102             operand * result,
5103             iCode   * ic)
5104 {
5105
5106   char *l;
5107
5108   /* the result must be bit */
5109   LOAD_AB_FOR_DIV (left, right, l);
5110   emitcode ("div", "ab");
5111   emitcode ("mov", "a,b");
5112   emitcode ("rrc", "a");
5113   aopOp(result, ic, TRUE, FALSE);
5114   aopPut (AOP (result), "c", 0);
5115 }
5116
5117 /*-----------------------------------------------------------------*/
5118 /* genModOneByte : 8 bit modulus                                   */
5119 /*-----------------------------------------------------------------*/
5120 static void
5121 genModOneByte (operand * left,
5122                operand * right,
5123                operand * result,
5124                iCode   * ic)
5125 {
5126   sym_link *opetype = operandType (result);
5127   char *l;
5128   symbol *lbl;
5129
5130   /* signed or unsigned */
5131   if (SPEC_USIGN (opetype))
5132     {
5133       /* unsigned is easy */
5134       LOAD_AB_FOR_DIV (left, right, l);
5135       emitcode ("div", "ab");
5136       aopOp(result, ic, TRUE, FALSE);   
5137       aopPut (AOP (result), "b", 0);
5138       return;
5139     }
5140
5141   /* signed is a little bit more difficult */
5142
5143   /* save the signs of the operands */
5144   MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
5145
5146   emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
5147   emitcode ("push", "acc");     /* save it on the stack */
5148
5149   /* now sign adjust for both left & right */
5150   MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
5151
5152   lbl = newiTempLabel (NULL);
5153   emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
5154   emitcode ("cpl", "a");
5155   emitcode ("inc", "a");
5156   emitcode ("", "!tlabeldef", (lbl->key + 100));
5157   emitcode ("mov", "b,a");
5158
5159   /* sign adjust left side */
5160   MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
5161
5162   lbl = newiTempLabel (NULL);
5163   emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
5164   emitcode ("cpl", "a");
5165   emitcode ("inc", "a");
5166   emitcode ("", "!tlabeldef", (lbl->key + 100));
5167
5168   /* now the multiplication */
5169   emitcode ("nop", "; workaround for DS80C390 div bug.");
5170   emitcode ("div", "ab");
5171   /* we are interested in the lower order
5172      only */
5173   lbl = newiTempLabel (NULL);
5174   emitcode ("pop", "acc");
5175   /* if there was an over flow we don't
5176      adjust the sign of the result */
5177   emitcode ("jb", "ov,!tlabel", (lbl->key + 100));
5178   emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
5179   CLRC;
5180   emitcode ("clr", "a");
5181   emitcode ("subb", "a,b");
5182   emitcode ("mov", "b,a");
5183   emitcode ("", "!tlabeldef", (lbl->key + 100));
5184   
5185   _G.bInUse++;
5186   /* now we are done */
5187   aopOp(result, ic, TRUE, FALSE);    
5188   aopPut (AOP (result), "b", 0);
5189   _G.bInUse--;
5190
5191 }
5192
5193 /*-----------------------------------------------------------------*/
5194 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
5195 /*-----------------------------------------------------------------*/
5196 static void genModTwoByte (operand *left, operand *right, 
5197                             operand *result, iCode *ic)
5198 {
5199         sym_link *retype = getSpec(operandType(right));
5200         sym_link *letype = getSpec(operandType(left));
5201         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5202         symbol *lbl;
5203
5204         /* load up MA with left */
5205         /* save EA bit in F1 */
5206         lbl = newiTempLabel(NULL);
5207         emitcode ("setb","F1");
5208         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5209         emitcode ("clr","F1");
5210         emitcode("","!tlabeldef",lbl->key+100);
5211
5212         if (!umult) {
5213                 lbl = newiTempLabel(NULL);
5214                 emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5215                 emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5216                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5217                 emitcode ("xch", "a,b");
5218                 emitcode ("cpl","a");
5219                 emitcode ("add", "a,#1");
5220                 emitcode ("xch", "a,b");
5221                 emitcode ("cpl", "a"); // msb
5222                 emitcode ("addc","a,#0");
5223                 emitcode ("","!tlabeldef",lbl->key+100);
5224                 emitcode ("mov","ma,b");
5225                 emitcode ("mov","ma,a");
5226         } else {
5227                 emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5228                 emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5229         }
5230
5231         /* load up MB with right */
5232         if (!umult) {
5233                 if (AOP_TYPE(right) == AOP_LIT) {
5234                         int val=floatFromVal (AOP (right)->aopu.aop_lit);
5235                         if (val < 0) {
5236                                 val = -val;
5237                         } 
5238                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5239                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);                
5240                 } else {
5241                         lbl = newiTempLabel(NULL);
5242                         emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5243                         emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5244                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);          
5245                         emitcode ("xch", "a,b");
5246                         emitcode ("cpl","a");
5247                         emitcode ("add", "a,#1");
5248                         emitcode ("xch", "a,b");
5249                         emitcode ("cpl", "a"); // msb
5250                         emitcode ("addc", "a,#0");
5251                         emitcode ("","!tlabeldef",lbl->key+100);
5252                         emitcode ("mov","mb,b");
5253                         emitcode ("mov","mb,a");
5254                 }
5255         } else {
5256                 emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5257                 emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5258         }
5259
5260         /* wait for multiplication to finish */
5261         lbl = newiTempLabel(NULL);
5262         emitcode("","!tlabeldef", lbl->key+100);
5263         emitcode("mov","a,mcnt1");
5264         emitcode("anl","a,#!constbyte",0x80);
5265         emitcode("jnz","!tlabel",lbl->key+100);
5266         
5267         freeAsmop (left, NULL, ic, TRUE);
5268         freeAsmop (right, NULL, ic,TRUE);
5269         aopOp(result, ic, TRUE, FALSE);
5270
5271         aopPut(AOP(result),"mb",1);
5272         aopPut(AOP(result),"mb",0);
5273         freeAsmop (result, NULL, ic, TRUE);
5274
5275         /* restore EA bit in F1 */
5276         lbl = newiTempLabel(NULL);
5277         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5278         emitcode ("setb","EA");
5279         emitcode("","!tlabeldef",lbl->key+100);
5280         return ;
5281 }
5282
5283 /*-----------------------------------------------------------------*/
5284 /* genMod - generates code for division                            */
5285 /*-----------------------------------------------------------------*/
5286 static void
5287 genMod (iCode * ic)
5288 {
5289   operand *left = IC_LEFT (ic);
5290   operand *right = IC_RIGHT (ic);
5291   operand *result = IC_RESULT (ic);
5292
5293   D (emitcode (";", "genMod "); );
5294
5295   /* assign the amsops */
5296   AOP_OP_2 (ic);
5297
5298   /* special cases first */
5299   /* both are bits */
5300   if (AOP_TYPE (left) == AOP_CRY &&
5301       AOP_TYPE (right) == AOP_CRY)
5302     {
5303       genModbits (left, right, result, ic);
5304       goto release;
5305     }
5306
5307   /* if both are of size == 1 */
5308   if (AOP_SIZE (left) == 1 &&
5309       AOP_SIZE (right) == 1)
5310     {
5311       genModOneByte (left, right, result, ic);
5312       goto release;
5313     }
5314
5315   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5316           /* use the ds390 ARITHMETIC accel UNIT */
5317           genModTwoByte (left, right, result, ic);
5318           return ;
5319   }
5320
5321   /* should have been converted to function call */
5322   assert (0);
5323
5324 release:
5325   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5326   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5327   freeAsmop (result, NULL, ic, TRUE);
5328 }
5329
5330 /*-----------------------------------------------------------------*/
5331 /* genIfxJump :- will create a jump depending on the ifx           */
5332 /*-----------------------------------------------------------------*/
5333 static void
5334 genIfxJump (iCode * ic, char *jval)
5335 {
5336   symbol *jlbl;
5337   symbol *tlbl = newiTempLabel (NULL);
5338   char *inst;
5339
5340   D (emitcode (";", "genIfxJump"););
5341
5342   /* if true label then we jump if condition
5343      supplied is true */
5344   if (IC_TRUE (ic))
5345     {
5346       jlbl = IC_TRUE (ic);
5347       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5348                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5349     }
5350   else
5351     {
5352       /* false label is present */
5353       jlbl = IC_FALSE (ic);
5354       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5355                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5356     }
5357   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5358     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
5359   else
5360     emitcode (inst, "!tlabel", tlbl->key + 100);
5361   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
5362   emitcode ("", "!tlabeldef", tlbl->key + 100);
5363
5364   /* mark the icode as generated */
5365   ic->generated = 1;
5366 }
5367
5368 /*-----------------------------------------------------------------*/
5369 /* genCmp :- greater or less than comparison                       */
5370 /*-----------------------------------------------------------------*/
5371 static void
5372 genCmp (operand * left, operand * right,
5373         iCode * ic, iCode * ifx, int sign)
5374 {
5375   int size, offset = 0;
5376   unsigned long lit = 0L;
5377   operand *result;
5378
5379   D (emitcode (";", "genCmp"););
5380
5381   result = IC_RESULT (ic);
5382
5383   /* if left & right are bit variables */
5384   if (AOP_TYPE (left) == AOP_CRY &&
5385       AOP_TYPE (right) == AOP_CRY)
5386     {
5387       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5388       emitcode ("anl", "c,/%s", AOP (left)->aopu.aop_dir);
5389     }
5390   else
5391     {
5392       /* subtract right from left if at the
5393          end the carry flag is set then we know that
5394          left is greater than right */
5395       size = max (AOP_SIZE (left), AOP_SIZE (right));
5396
5397       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5398       if ((size == 1) && !sign 
5399           && (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
5400         {
5401           symbol *lbl = newiTempLabel (NULL);
5402           emitcode ("cjne", "%s,%s,!tlabel",
5403                     aopGet (AOP (left), offset, FALSE, FALSE, NULL),
5404                     aopGet (AOP (right), offset, FALSE, FALSE, NULL),
5405                     lbl->key + 100);
5406           emitcode ("", "!tlabeldef", lbl->key + 100);
5407         }
5408       else
5409         {
5410           if (AOP_TYPE (right) == AOP_LIT)
5411             {
5412               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5413               /* optimize if(x < 0) or if(x >= 0) */
5414               if (lit == 0L)
5415                 {
5416                   if (!sign)
5417                     {
5418                       CLRC;
5419                     }
5420                   else
5421                     {
5422                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
5423
5424                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5425                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5426
5427                       aopOp (result, ic, FALSE, FALSE);
5428
5429                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5430                         {
5431                           freeAsmop (result, NULL, ic, TRUE);
5432                           genIfxJump (ifx, "acc.7");
5433                           return;
5434                         }
5435                       else
5436                         {
5437                           emitcode ("rlc", "a");
5438                         }
5439                       goto release_freedLR;
5440                     }
5441                   goto release;
5442                 }
5443             }
5444           CLRC;
5445           while (size--)
5446             {
5447               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
5448               MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
5449               // emitcode (";", "genCmp #2");
5450               if (sign && (size == 0))
5451                 {
5452                   // emitcode (";", "genCmp #3");
5453                   emitcode ("xrl", "a,#!constbyte",0x80);
5454                   if (AOP_TYPE (right) == AOP_LIT)
5455                     {
5456                       unsigned long lit = (unsigned long)
5457                       floatFromVal (AOP (right)->aopu.aop_lit);
5458                       // emitcode (";", "genCmp #3.1");
5459                       emitcode ("subb", "a,#!constbyte",
5460                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5461                     }
5462                   else
5463                     {
5464                       // emitcode (";", "genCmp #3.2");
5465                       saveAccWarn = 0;  
5466                       MOVB(aopGet (AOP (right), offset++, FALSE, FALSE, "b"));
5467                       saveAccWarn = DEFAULT_ACC_WARNING;
5468                       emitcode ("xrl", "b,#!constbyte",0x80);
5469                       emitcode ("subb", "a,b");
5470                     }
5471                 }
5472               else
5473                 {
5474                   const char *s;
5475
5476                   // emitcode (";", "genCmp #4");
5477                   saveAccWarn = 0;
5478                   s = aopGet (AOP (right), offset++, FALSE, FALSE, "b");
5479                   saveAccWarn = DEFAULT_ACC_WARNING;
5480
5481                   emitcode ("subb", "a,%s", s);
5482                 }
5483             }
5484         }
5485     }
5486
5487 release:
5488 /* Don't need the left & right operands any more; do need the result. */
5489   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5490   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5491
5492   aopOp (result, ic, FALSE, FALSE);
5493
5494 release_freedLR:
5495
5496   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5497     {
5498       outBitC (result);
5499     }
5500   else
5501     {
5502       /* if the result is used in the next
5503          ifx conditional branch then generate
5504          code a little differently */
5505       if (ifx)
5506         {
5507           genIfxJump (ifx, "c");
5508         }
5509       else
5510         {
5511           outBitC (result);
5512         }
5513       /* leave the result in acc */
5514     }
5515   freeAsmop (result, NULL, ic, TRUE);
5516 }
5517
5518 /*-----------------------------------------------------------------*/
5519 /* genCmpGt :- greater than comparison                             */
5520 /*-----------------------------------------------------------------*/
5521 static void
5522 genCmpGt (iCode * ic, iCode * ifx)
5523 {
5524   operand *left, *right;
5525   sym_link *letype, *retype;
5526   int sign;
5527
5528   D (emitcode (";", "genCmpGt ");
5529     );
5530
5531   left = IC_LEFT (ic);
5532   right = IC_RIGHT (ic);
5533
5534   letype = getSpec (operandType (left));
5535   retype = getSpec (operandType (right));
5536   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
5537
5538   /* assign the left & right amsops */
5539   AOP_OP_2 (ic);
5540
5541   genCmp (right, left, ic, ifx, sign);
5542 }
5543
5544 /*-----------------------------------------------------------------*/
5545 /* genCmpLt - less than comparisons                                */
5546 /*-----------------------------------------------------------------*/
5547 static void
5548 genCmpLt (iCode * ic, iCode * ifx)
5549 {
5550   operand *left, *right;
5551   sym_link *letype, *retype;
5552   int sign;
5553
5554   D (emitcode (";", "genCmpLt "););
5555
5556   left = IC_LEFT (ic);
5557   right = IC_RIGHT (ic);
5558
5559   letype = getSpec (operandType (left));
5560   retype = getSpec (operandType (right));
5561   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
5562
5563   /* assign the left & right amsops */
5564   AOP_OP_2 (ic);
5565
5566   genCmp (left, right, ic, ifx, sign);
5567 }
5568
5569 /*-----------------------------------------------------------------*/
5570 /* gencjneshort - compare and jump if not equal                    */
5571 /*-----------------------------------------------------------------*/
5572 static void
5573 gencjneshort (operand * left, operand * right, symbol * lbl)
5574 {
5575   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5576   int offset = 0;
5577   unsigned long lit = 0L;
5578
5579   D (emitcode (";", "gencjneshort");
5580     );
5581
5582   /* if the left side is a literal or
5583      if the right is in a pointer register and left
5584      is not */
5585   if ((AOP_TYPE (left) == AOP_LIT) ||
5586       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5587     {
5588       operand *t = right;
5589       right = left;
5590       left = t;
5591     }
5592
5593   if (AOP_TYPE (right) == AOP_LIT)
5594     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5595
5596   if (opIsGptr (left) || opIsGptr (right))
5597     {
5598       /* We are comparing a generic pointer to something.
5599        * Exclude the generic type byte from the comparison.
5600        */
5601       size--;
5602       D (emitcode (";", "cjneshort: generic ptr special case."););
5603     }
5604
5605
5606   /* if the right side is a literal then anything goes */
5607   if (AOP_TYPE (right) == AOP_LIT &&
5608       AOP_TYPE (left) != AOP_DIR)
5609     {
5610       while (size--)
5611         {
5612           MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
5613           emitcode ("cjne", "a,%s,!tlabel",
5614                     aopGet (AOP (right), offset, FALSE, FALSE, NULL),
5615                     lbl->key + 100);
5616           offset++;
5617         }
5618     }
5619
5620   /* if the right side is in a register or in direct space or
5621      if the left is a pointer register & right is not */
5622   else if (AOP_TYPE (right) == AOP_REG ||
5623            AOP_TYPE (right) == AOP_DIR ||
5624            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5625            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5626     {
5627       while (size--)
5628         {
5629           MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
5630           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5631               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5632             emitcode ("jnz", "!tlabel", lbl->key + 100);
5633           else
5634             emitcode ("cjne", "a,%s,!tlabel",
5635                       aopGet (AOP (right), offset, FALSE, TRUE, DP2_RESULT_REG),
5636                       lbl->key + 100);
5637           offset++;
5638         }
5639     }
5640   else
5641     {
5642       /* right is a pointer reg need both a & b */
5643       while (size--)
5644         {
5645           MOVB (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
5646           MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
5647           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
5648           offset++;
5649         }
5650     }
5651 }
5652
5653 /*-----------------------------------------------------------------*/
5654 /* gencjne - compare and jump if not equal                         */
5655 /*-----------------------------------------------------------------*/
5656 static void
5657 gencjne (operand * left, operand * right, symbol * lbl)
5658 {
5659   symbol *tlbl = newiTempLabel (NULL);
5660
5661   D (emitcode (";", "gencjne");
5662     );
5663
5664   gencjneshort (left, right, lbl);
5665
5666   emitcode ("mov", "a,%s", one);
5667   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
5668   emitcode ("", "!tlabeldef", lbl->key + 100);
5669   emitcode ("clr", "a");
5670   emitcode ("", "!tlabeldef", tlbl->key + 100);
5671 }
5672
5673 /*-----------------------------------------------------------------*/
5674 /* genCmpEq - generates code for equal to                          */
5675 /*-----------------------------------------------------------------*/
5676 static void
5677 genCmpEq (iCode * ic, iCode * ifx)
5678 {
5679   operand *left, *right, *result;
5680
5681   D (emitcode (";", "genCmpEq ");
5682     );
5683
5684   AOP_OP_2 (ic);
5685   AOP_SET_LOCALS (ic);
5686
5687   /* if literal, literal on the right or
5688      if the right is in a pointer register and left
5689      is not */
5690   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5691       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5692     {
5693       operand *t = IC_RIGHT (ic);
5694       IC_RIGHT (ic) = IC_LEFT (ic);
5695       IC_LEFT (ic) = t;
5696     }
5697
5698   if (ifx &&                    /* !AOP_SIZE(result) */
5699       OP_SYMBOL (result) &&
5700       OP_SYMBOL (result)->regType == REG_CND)
5701     {
5702       symbol *tlbl;
5703       /* if they are both bit variables */
5704       if (AOP_TYPE (left) == AOP_CRY &&
5705           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5706         {
5707           if (AOP_TYPE (right) == AOP_LIT)
5708             {
5709               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5710               if (lit == 0L)
5711                 {
5712                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5713                   emitcode ("cpl", "c");
5714                 }
5715               else if (lit == 1L)
5716                 {
5717                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5718                 }
5719               else
5720                 {
5721                   emitcode ("clr", "c");
5722                 }
5723               /* AOP_TYPE(right) == AOP_CRY */
5724             }
5725           else
5726             {
5727               symbol *lbl = newiTempLabel (NULL);
5728               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5729               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5730               emitcode ("cpl", "c");
5731               emitcode ("", "!tlabeldef", (lbl->key + 100));
5732             }
5733           /* if true label then we jump if condition
5734              supplied is true */
5735           tlbl = newiTempLabel (NULL);
5736           if (IC_TRUE (ifx))
5737             {
5738               emitcode ("jnc", "!tlabel", tlbl->key + 100);
5739               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
5740             }
5741           else
5742             {
5743               emitcode ("jc", "!tlabel", tlbl->key + 100);
5744               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
5745             }
5746           emitcode ("", "!tlabeldef", tlbl->key + 100);
5747         }
5748       else
5749         {
5750           tlbl = newiTempLabel (NULL);
5751           gencjneshort (left, right, tlbl);
5752           if (IC_TRUE (ifx))
5753             {
5754               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
5755               emitcode ("", "!tlabeldef", tlbl->key + 100);
5756             }
5757           else
5758             {
5759               symbol *lbl = newiTempLabel (NULL);
5760               emitcode ("sjmp", "!tlabel", lbl->key + 100);
5761               emitcode ("", "!tlabeldef", tlbl->key + 100);
5762               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
5763               emitcode ("", "!tlabeldef", lbl->key + 100);
5764             }
5765         }
5766       /* mark the icode as generated */
5767       ifx->generated = 1;
5768
5769       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5770       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5771       return;
5772     }
5773
5774   /* if they are both bit variables */
5775   if (AOP_TYPE (left) == AOP_CRY &&
5776       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5777     {
5778       if (AOP_TYPE (right) == AOP_LIT)
5779         {
5780           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5781           if (lit == 0L)
5782             {
5783               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5784               emitcode ("cpl", "c");
5785             }
5786           else if (lit == 1L)
5787             {
5788               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5789             }
5790           else
5791             {
5792               emitcode ("clr", "c");
5793             }
5794           /* AOP_TYPE(right) == AOP_CRY */
5795         }
5796       else
5797         {
5798           symbol *lbl = newiTempLabel (NULL);
5799           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5800           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5801           emitcode ("cpl", "c");
5802           emitcode ("", "!tlabeldef", (lbl->key + 100));
5803         }
5804
5805       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5806       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5807
5808       aopOp (result, ic, TRUE, FALSE);
5809
5810       /* c = 1 if egal */
5811       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5812         {
5813           outBitC (result);
5814           goto release;
5815         }
5816       if (ifx)
5817         {
5818           genIfxJump (ifx, "c");
5819           goto release;
5820         }
5821       /* if the result is used in an arithmetic operation
5822          then put the result in place */
5823       outBitC (result);
5824     }
5825   else
5826     {
5827       gencjne (left, right, newiTempLabel (NULL));
5828
5829       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5830       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5831
5832       aopOp (result, ic, TRUE, FALSE);
5833
5834       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5835         {
5836           aopPut (AOP (result), "a", 0);
5837           goto release;
5838         }
5839       if (ifx)
5840         {
5841           genIfxJump (ifx, "a");
5842           goto release;
5843         }
5844       /* if the result is used in an arithmetic operation
5845          then put the result in place */
5846       if (AOP_TYPE (result) != AOP_CRY)
5847         outAcc (result);
5848       /* leave the result in acc */
5849     }
5850
5851 release:
5852   freeAsmop (result, NULL, ic, TRUE);
5853 }
5854
5855 /*-----------------------------------------------------------------*/
5856 /* ifxForOp - returns the icode containing the ifx for operand     */
5857 /*-----------------------------------------------------------------*/
5858 static iCode *
5859 ifxForOp (operand * op, iCode * ic)
5860 {
5861   /* if true symbol then needs to be assigned */
5862   if (IS_TRUE_SYMOP (op))
5863     return NULL;
5864
5865   /* if this has register type condition and
5866      the next instruction is ifx with the same operand
5867      and live to of the operand is upto the ifx only then */
5868   if (ic->next &&
5869       ic->next->op == IFX &&
5870       IC_COND (ic->next)->key == op->key &&
5871       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5872     return ic->next;
5873
5874   return NULL;
5875 }
5876 /*-----------------------------------------------------------------*/
5877 /* hasInc - operand is incremented before any other use            */
5878 /*-----------------------------------------------------------------*/
5879 static iCode *
5880 hasInc (operand *op, iCode *ic, int osize)
5881 {
5882   sym_link *type = operandType(op);
5883   sym_link *retype = getSpec (type);
5884   iCode *lic = ic->next;
5885   int isize ;
5886   
5887   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5888   if (!IS_SYMOP(op)) return NULL;
5889
5890   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5891   if (IS_AGGREGATE(type->next)) return NULL;
5892   if (osize != (isize = getSize(type->next))) return NULL;
5893
5894   while (lic) {
5895       /* if operand of the form op = op + <sizeof *op> */
5896       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5897           isOperandEqual(IC_RESULT(lic),op) && 
5898           isOperandLiteral(IC_RIGHT(lic)) &&
5899           operandLitValue(IC_RIGHT(lic)) == isize) {
5900           return lic;
5901       }
5902       /* if the operand used or deffed */
5903       if (bitVectBitValue(OP_USES(op),lic->key) || (unsigned) lic->defKey == op->key) {
5904           return NULL;
5905       }
5906       /* if GOTO or IFX */
5907       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5908       lic = lic->next;
5909   }
5910   return NULL;
5911 }
5912
5913 /*-----------------------------------------------------------------*/
5914 /* genAndOp - for && operation                                     */
5915 /*-----------------------------------------------------------------*/
5916 static void
5917 genAndOp (iCode * ic)
5918 {
5919   operand *left, *right, *result;
5920   symbol *tlbl;
5921
5922   D (emitcode (";", "genAndOp "););
5923
5924   /* note here that && operations that are in an
5925      if statement are taken away by backPatchLabels
5926      only those used in arthmetic operations remain */
5927   AOP_OP_2 (ic);
5928   AOP_SET_LOCALS (ic);
5929
5930   /* if both are bit variables */
5931   if (AOP_TYPE (left) == AOP_CRY &&
5932       AOP_TYPE (right) == AOP_CRY)
5933     {
5934       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5935       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5936       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5937       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5938   
5939       aopOp (result,ic,FALSE, FALSE);
5940       outBitC (result);
5941     }
5942   else
5943     {
5944       tlbl = newiTempLabel (NULL);
5945       toBoolean (left);
5946       emitcode ("jz", "!tlabel", tlbl->key + 100);
5947       toBoolean (right);
5948       emitcode ("", "!tlabeldef", tlbl->key + 100);
5949       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5950       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5951   
5952       aopOp (result,ic,FALSE, FALSE);
5953       outBitAcc (result);
5954     }
5955     freeAsmop (result, NULL, ic, TRUE);
5956 }
5957
5958
5959 /*-----------------------------------------------------------------*/
5960 /* genOrOp - for || operation                                      */
5961 /*-----------------------------------------------------------------*/
5962 static void
5963 genOrOp (iCode * ic)
5964 {
5965   operand *left, *right, *result;
5966   symbol *tlbl;
5967
5968   D (emitcode (";", "genOrOp "););
5969
5970   /* note here that || operations that are in an
5971      if statement are taken away by backPatchLabels
5972      only those used in arthmetic operations remain */
5973   AOP_OP_2 (ic);
5974   AOP_SET_LOCALS (ic);
5975
5976   /* if both are bit variables */
5977   if (AOP_TYPE (left) == AOP_CRY &&
5978       AOP_TYPE (right) == AOP_CRY)
5979     {
5980       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5981       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5982       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5983       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5984   
5985       aopOp (result,ic,FALSE, FALSE);
5986       
5987       outBitC (result);
5988     }
5989   else
5990     {
5991       tlbl = newiTempLabel (NULL);
5992       toBoolean (left);
5993       emitcode ("jnz", "!tlabel", tlbl->key + 100);
5994       toBoolean (right);
5995       emitcode ("", "!tlabeldef", tlbl->key + 100);
5996       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5997       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5998   
5999       aopOp (result,ic,FALSE, FALSE);
6000       
6001       outBitAcc (result);
6002     }
6003
6004   freeAsmop (result, NULL, ic, TRUE);
6005 }
6006
6007 /*-----------------------------------------------------------------*/
6008 /* isLiteralBit - test if lit == 2^n                               */
6009 /*-----------------------------------------------------------------*/
6010 static int
6011 isLiteralBit (unsigned long lit)
6012 {
6013   unsigned long pw[32] =
6014   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6015    0x100L, 0x200L, 0x400L, 0x800L,
6016    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6017    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6018    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6019    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6020    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6021   int idx;
6022
6023   for (idx = 0; idx < 32; idx++)
6024     if (lit == pw[idx])
6025       return idx + 1;
6026   return 0;
6027 }
6028
6029 /*-----------------------------------------------------------------*/
6030 /* continueIfTrue -                                                */
6031 /*-----------------------------------------------------------------*/
6032 static void
6033 continueIfTrue (iCode * ic)
6034 {
6035   if (IC_TRUE (ic))
6036     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
6037   ic->generated = 1;
6038 }
6039
6040 /*-----------------------------------------------------------------*/
6041 /* jmpIfTrue -                                                     */
6042 /*-----------------------------------------------------------------*/
6043 static void
6044 jumpIfTrue (iCode * ic)
6045 {
6046   if (!IC_TRUE (ic))
6047     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
6048   ic->generated = 1;
6049 }
6050
6051 /*-----------------------------------------------------------------*/
6052 /* jmpTrueOrFalse -                                                */
6053 /*-----------------------------------------------------------------*/
6054 static void
6055 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
6056 {
6057   // ugly but optimized by peephole
6058   if (IC_TRUE (ic))
6059     {
6060       symbol *nlbl = newiTempLabel (NULL);
6061       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
6062       emitcode ("", "!tlabeldef", tlbl->key + 100);
6063       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
6064       emitcode ("", "!tlabeldef", nlbl->key + 100);
6065     }
6066   else
6067     {
6068       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
6069       emitcode ("", "!tlabeldef", tlbl->key + 100);
6070     }
6071   ic->generated = 1;
6072 }
6073
6074 // Generate code to perform a bit-wise logic operation
6075 // on two operands in far space (assumed to already have been 
6076 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
6077 // in far space. This requires pushing the result on the stack
6078 // then popping it into the result.
6079 static void
6080 genFarFarLogicOp(iCode *ic, char *logicOp)
6081 {
6082       int size, resultSize, compSize;
6083       int offset = 0;
6084       
6085       TR_AP("#5");
6086       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
6087       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ? 
6088                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
6089       
6090       _startLazyDPSEvaluation();
6091       for (size = compSize; (size--); offset++)
6092       {
6093           MOVA (aopGet (AOP (IC_LEFT(ic)), offset, FALSE, FALSE, NULL));
6094           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
6095           MOVA (aopGet (AOP (IC_RIGHT(ic)), offset, FALSE, FALSE, NULL));
6096           
6097           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
6098           emitcode ("push", "acc");
6099       }
6100       _endLazyDPSEvaluation();
6101      
6102       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
6103       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
6104       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
6105      
6106       resultSize = AOP_SIZE(IC_RESULT(ic));
6107
6108       ADJUST_PUSHED_RESULT(compSize, resultSize);
6109
6110       _startLazyDPSEvaluation();
6111       while (compSize--)
6112       {
6113           emitcode ("pop", "acc");
6114           aopPut (AOP (IC_RESULT (ic)), "a", compSize);
6115       }
6116       _endLazyDPSEvaluation();
6117       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
6118 }
6119
6120
6121 /*-----------------------------------------------------------------*/
6122 /* genAnd  - code for and                                          */
6123 /*-----------------------------------------------------------------*/
6124 static void
6125 genAnd (iCode * ic, iCode * ifx)
6126 {
6127   operand *left, *right, *result;
6128   int size, offset = 0;
6129   unsigned long lit = 0L;
6130   int bytelit;
6131   char buff[10];
6132   bool pushResult;
6133
6134   D (emitcode (";", "genAnd "););
6135
6136   AOP_OP_3_NOFATAL (ic, pushResult);
6137   AOP_SET_LOCALS (ic);
6138
6139   if (pushResult)
6140   {
6141       genFarFarLogicOp(ic, "anl");
6142       return;
6143   }  
6144
6145 #ifdef DEBUG_TYPE
6146   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6147             AOP_TYPE (result),
6148             AOP_TYPE (left), AOP_TYPE (right));
6149   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6150             AOP_SIZE (result),
6151             AOP_SIZE (left), AOP_SIZE (right));
6152 #endif
6153
6154   /* if left is a literal & right is not then exchange them */
6155   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
6156 #ifdef LOGIC_OPS_BROKEN      
6157     ||  AOP_NEEDSACC (left)
6158 #endif
6159     )
6160     {
6161       operand *tmp = right;
6162       right = left;
6163       left = tmp;
6164     }
6165
6166   /* if result = right then exchange them */
6167   if (sameRegs (AOP (result), AOP (right)))
6168     {
6169       operand *tmp = right;
6170       right = left;
6171       left = tmp;
6172     }
6173
6174   /* if right is bit then exchange them */
6175   if (AOP_TYPE (right) == AOP_CRY &&
6176       AOP_TYPE (left) != AOP_CRY)
6177     {
6178       operand *tmp = right;
6179       right = left;
6180       left = tmp;
6181     }
6182   if (AOP_TYPE (right) == AOP_LIT)
6183     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6184
6185   size = AOP_SIZE (result);
6186
6187   // if(bit & yy)
6188   // result = bit & yy;
6189   if (AOP_TYPE (left) == AOP_CRY)
6190     {
6191       // c = bit & literal;
6192       if (AOP_TYPE (right) == AOP_LIT)
6193         {
6194           if (lit & 1)
6195             {
6196               if (size && sameRegs (AOP (result), AOP (left)))
6197                 // no change
6198                 goto release;
6199               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6200             }
6201           else
6202             {
6203               // bit(result) = 0;
6204               if (size && (AOP_TYPE (result) == AOP_CRY))
6205                 {
6206                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6207                   goto release;
6208                 }
6209               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6210                 {
6211                   jumpIfTrue (ifx);
6212                   goto release;
6213                 }
6214               emitcode ("clr", "c");
6215             }
6216         }
6217       else
6218         {
6219           if (AOP_TYPE (right) == AOP_CRY)
6220             {
6221               // c = bit & bit;
6222               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6223               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6224             }
6225           else
6226             {
6227               // c = bit & val;
6228               MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
6229               // c = lsb
6230               emitcode ("rrc", "a");
6231               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6232             }
6233         }
6234       // bit = c
6235       // val = c
6236       if (size)
6237         outBitC (result);
6238       // if(bit & ...)
6239       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6240         genIfxJump (ifx, "c");
6241       goto release;
6242     }
6243
6244   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6245   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6246   if ((AOP_TYPE (right) == AOP_LIT) &&
6247       (AOP_TYPE (result) == AOP_CRY) &&
6248       (AOP_TYPE (left) != AOP_CRY))
6249     {
6250       int posbit = isLiteralBit (lit);
6251       /* left &  2^n */
6252       if (posbit)
6253         {
6254           posbit--;
6255           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE, NULL));
6256           // bit = left & 2^n
6257           if (size)
6258             emitcode ("mov", "c,acc.%d", posbit & 0x07);
6259           // if(left &  2^n)
6260           else
6261             {
6262               if (ifx)
6263                 {
6264                   SNPRINTF (buff, sizeof(buff), 
6265                             "acc.%d", posbit & 0x07);
6266                   genIfxJump (ifx, buff);
6267                 }
6268               else 
6269                   {
6270                       emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6271                   }
6272               goto release;
6273             }
6274         }
6275       else
6276         {
6277           symbol *tlbl = newiTempLabel (NULL);
6278           int sizel = AOP_SIZE (left);
6279           if (size)
6280             emitcode ("setb", "c");
6281           while (sizel--)
6282             {
6283               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6284                 {
6285                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6286                   // byte ==  2^n ?
6287                   if ((posbit = isLiteralBit (bytelit)) != 0)
6288                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
6289                   else
6290                     {
6291                       if (bytelit != 0x0FFL)
6292                         emitcode ("anl", "a,%s",
6293                           aopGet (AOP (right), offset, FALSE, TRUE, DP2_RESULT_REG));
6294                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6295                     }
6296                 }
6297               offset++;
6298             }
6299           // bit = left & literal
6300           if (size)
6301             {
6302               emitcode ("clr", "c");
6303               emitcode ("", "!tlabeldef", tlbl->key + 100);
6304             }
6305           // if(left & literal)
6306           else
6307             {
6308               if (ifx)
6309                 jmpTrueOrFalse (ifx, tlbl);
6310               goto release;
6311             }
6312         }
6313       outBitC (result);
6314       goto release;
6315     }
6316
6317   /* if left is same as result */
6318   if (sameRegs (AOP (result), AOP (left)))
6319     {
6320       for (; size--; offset++)
6321         {
6322           if (AOP_TYPE (right) == AOP_LIT)
6323             {
6324               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
6325                 continue;
6326               else if (bytelit == 0)
6327                 aopPut (AOP (result), zero, offset);
6328               else if (IS_AOP_PREG (result))
6329                 {
6330                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6331                   emitcode ("anl", "a,%s",
6332                             aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6333                   aopPut (AOP (result), "a", offset);
6334                 }
6335               else
6336                 emitcode ("anl", "%s,%s",
6337                           aopGet (AOP (left), offset, FALSE, TRUE, NULL),
6338                           aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6339             }
6340           else
6341             {
6342               if (AOP_TYPE (left) == AOP_ACC)
6343                 emitcode ("anl", "a,%s",
6344                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6345               else
6346                 {
6347                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6348                   if (IS_AOP_PREG (result))
6349                     {
6350                       emitcode ("anl", "a,%s",
6351                                 aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6352                       aopPut (AOP (result), "a", offset);
6353                     }
6354                   else
6355                     emitcode ("anl", "%s,a",
6356                            aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6357                 }
6358             }
6359         }
6360     }
6361   else
6362     {
6363       // left & result in different registers
6364       if (AOP_TYPE (result) == AOP_CRY)
6365         {
6366           // result = bit
6367           // if(size), result in bit
6368           // if(!size && ifx), conditional oper: if(left & right)
6369           symbol *tlbl = newiTempLabel (NULL);
6370           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6371           if (size)
6372             emitcode ("setb", "c");
6373           while (sizer--)
6374             {
6375               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6376                 emitcode ("anl", "a,%s",
6377                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6378               } else {
6379                 if (AOP_TYPE(left)==AOP_ACC) {
6380                   emitcode("mov", "b,a");
6381                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6382                   emitcode("anl", "a,b");
6383                 }else {
6384                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6385                   emitcode ("anl", "a,%s",
6386                             aopGet (AOP (left), offset, FALSE, FALSE, DP2_RESULT_REG));
6387                 }
6388               }
6389               emitcode ("jnz", "!tlabel", tlbl->key + 100);
6390               offset++;
6391             }
6392           if (size)
6393             {
6394               CLRC;
6395               emitcode ("", "!tlabeldef", tlbl->key + 100);
6396               outBitC (result);
6397             }
6398           else if (ifx)
6399             jmpTrueOrFalse (ifx, tlbl);
6400         }
6401       else
6402         {
6403           for (; (size--); offset++)
6404             {
6405               // normal case
6406               // result = left & right
6407               if (AOP_TYPE (right) == AOP_LIT)
6408                 {
6409                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
6410                     {
6411                       aopPut (AOP (result),
6412                            aopGet (AOP (left), offset, FALSE, FALSE, NULL),
6413                               offset);
6414                       continue;
6415                     }
6416                   else if (bytelit == 0)
6417                     {
6418                       aopPut (AOP (result), zero, offset);
6419                       continue;
6420                     }
6421                   D (emitcode (";", "better literal AND."););
6422                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6423                   emitcode ("anl", "a, %s", aopGet (AOP (right), offset,
6424                                                     FALSE, FALSE, DP2_RESULT_REG));
6425
6426                 }
6427               else
6428                 {
6429                   // faster than result <- left, anl result,right
6430                   // and better if result is SFR
6431                   if (AOP_TYPE (left) == AOP_ACC)
6432                     {
6433                       emitcode ("anl", "a,%s", 
6434                                 aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6435                     }
6436                   else
6437                     {
6438                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
6439                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
6440                       {
6441                           emitcode("mov", "b,a");
6442                           rOp = "b";
6443                       }
6444                         
6445                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6446                       emitcode ("anl", "a,%s", rOp);
6447                     }                   
6448                 }
6449               aopPut (AOP (result), "a", offset);
6450             }
6451         }
6452     }
6453
6454 release:
6455   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6456   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6457   freeAsmop (result, NULL, ic, TRUE);
6458 }
6459
6460
6461 /*-----------------------------------------------------------------*/
6462 /* genOr  - code for or                                            */
6463 /*-----------------------------------------------------------------*/
6464 static void
6465 genOr (iCode * ic, iCode * ifx)
6466 {
6467   operand *left, *right, *result;
6468   int size, offset = 0;
6469   unsigned long lit = 0L;
6470   bool     pushResult;
6471
6472   D (emitcode (";", "genOr "););
6473
6474   AOP_OP_3_NOFATAL (ic, pushResult);
6475   AOP_SET_LOCALS (ic);
6476
6477   if (pushResult)
6478   {
6479       genFarFarLogicOp(ic, "orl");
6480       return;
6481   }
6482
6483
6484 #ifdef DEBUG_TYPE
6485   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6486             AOP_TYPE (result),
6487             AOP_TYPE (left), AOP_TYPE (right));
6488   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6489             AOP_SIZE (result),
6490             AOP_SIZE (left), AOP_SIZE (right));
6491 #endif
6492
6493   /* if left is a literal & right is not then exchange them */
6494   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
6495 #ifdef LOGIC_OPS_BROKEN
6496    || AOP_NEEDSACC (left) // I think this is a net loss now.
6497 #endif      
6498       )
6499     {
6500       operand *tmp = right;
6501       right = left;
6502       left = tmp;
6503     }
6504
6505   /* if result = right then exchange them */
6506   if (sameRegs (AOP (result), AOP (right)))
6507     {
6508       operand *tmp = right;
6509       right = left;
6510       left = tmp;
6511     }
6512
6513   /* if right is bit then exchange them */
6514   if (AOP_TYPE (right) == AOP_CRY &&
6515       AOP_TYPE (left) != AOP_CRY)
6516     {
6517       operand *tmp = right;
6518       right = left;
6519       left = tmp;
6520     }
6521   if (AOP_TYPE (right) == AOP_LIT)
6522     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6523
6524   size = AOP_SIZE (result);
6525
6526   // if(bit | yy)
6527   // xx = bit | yy;
6528   if (AOP_TYPE (left) == AOP_CRY)
6529     {
6530       if (AOP_TYPE (right) == AOP_LIT)
6531         {
6532           // c = bit & literal;
6533           if (lit)
6534             {
6535               // lit != 0 => result = 1
6536               if (AOP_TYPE (result) == AOP_CRY)
6537                 {
6538                   if (size)
6539                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6540                   else if (ifx)
6541                     continueIfTrue (ifx);
6542                   goto release;
6543                 }
6544               emitcode ("setb", "c");
6545             }
6546           else
6547             {
6548               // lit == 0 => result = left
6549               if (size && sameRegs (AOP (result), AOP (left)))
6550                 goto release;
6551               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6552             }
6553         }
6554       else
6555         {
6556           if (AOP_TYPE (right) == AOP_CRY)
6557             {
6558               // c = bit | bit;
6559               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6560               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6561             }
6562           else
6563             {
6564               // c = bit | val;
6565               symbol *tlbl = newiTempLabel (NULL);
6566               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6567                 emitcode ("setb", "c");
6568               emitcode ("jb", "%s,!tlabel",
6569                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6570               toBoolean (right);
6571               emitcode ("jnz", "!tlabel", tlbl->key + 100);
6572               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6573                 {
6574                   jmpTrueOrFalse (ifx, tlbl);
6575                   goto release;
6576                 }
6577               else
6578                 {
6579                   CLRC;
6580                   emitcode ("", "!tlabeldef", tlbl->key + 100);
6581                 }
6582             }
6583         }
6584       // bit = c
6585       // val = c
6586       if (size)
6587         outBitC (result);
6588       // if(bit | ...)
6589       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6590            genIfxJump (ifx, "c");
6591       goto release;
6592     }
6593
6594   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6595   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6596   if ((AOP_TYPE (right) == AOP_LIT) &&
6597       (AOP_TYPE (result) == AOP_CRY) &&
6598       (AOP_TYPE (left) != AOP_CRY))
6599     {
6600       if (lit)
6601         {
6602           // result = 1
6603           if (size)
6604             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6605           else
6606             continueIfTrue (ifx);
6607           goto release;
6608         }
6609       else
6610         {
6611           // lit = 0, result = boolean(left)
6612           if (size)
6613             emitcode ("setb", "c");
6614           toBoolean (right);
6615           if (size)
6616             {
6617               symbol *tlbl = newiTempLabel (NULL);
6618               emitcode ("jnz", "!tlabel", tlbl->key + 100);
6619               CLRC;
6620               emitcode ("", "!tlabeldef", tlbl->key + 100);
6621             }
6622           else
6623             {
6624               genIfxJump (ifx, "a");
6625               goto release;
6626             }
6627         }
6628       outBitC (result);
6629       goto release;
6630     }
6631
6632   /* if left is same as result */
6633   if (sameRegs (AOP (result), AOP (left)))
6634     {
6635       for (; size--; offset++)
6636         {
6637           if (AOP_TYPE (right) == AOP_LIT)
6638             {
6639               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6640                 {
6641                   continue;
6642                 }
6643               else
6644                 {
6645                   if (IS_AOP_PREG (left))
6646                     {
6647                       MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6648                       emitcode ("orl", "a,%s",
6649                                 aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6650                       aopPut (AOP (result), "a", offset);
6651                     }
6652                   else
6653                     {
6654                       emitcode ("orl", "%s,%s",
6655                                 aopGet (AOP (left), offset, FALSE, TRUE, NULL),
6656                                 aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6657                     }
6658                 }
6659             }
6660           else
6661             {
6662               if (AOP_TYPE (left) == AOP_ACC)
6663                 {
6664                   emitcode ("orl", "a,%s",
6665                             aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6666                 }
6667               else
6668                 {
6669                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6670                   if (IS_AOP_PREG (left))
6671                     {
6672                       emitcode ("orl", "a,%s", 
6673                                 aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6674                       aopPut (AOP (result), "a", offset);
6675                     }
6676                   else
6677                     {
6678                       emitcode ("orl", "%s,a",
6679                            aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6680                     }
6681                 }
6682             }
6683         }
6684     }
6685   else
6686     {
6687       // left & result in different registers
6688       if (AOP_TYPE (result) == AOP_CRY)
6689         {
6690           // result = bit
6691           // if(size), result in bit
6692           // if(!size && ifx), conditional oper: if(left | right)
6693           symbol *tlbl = newiTempLabel (NULL);
6694           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6695           if (size)
6696             emitcode ("setb", "c");
6697           while (sizer--)
6698             {
6699               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6700                 emitcode ("orl", "a,%s",
6701                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6702               } else {
6703                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6704                 emitcode ("orl", "a,%s",
6705                           aopGet (AOP (left), offset, FALSE, FALSE, DP2_RESULT_REG));
6706               }
6707               emitcode ("jnz", "!tlabel", tlbl->key + 100);
6708               offset++;
6709             }
6710           if (size)
6711             {
6712               CLRC;
6713               emitcode ("", "!tlabeldef", tlbl->key + 100);
6714               outBitC (result);
6715             }
6716           else if (ifx)
6717             jmpTrueOrFalse (ifx, tlbl);
6718         }
6719       else
6720         {
6721             _startLazyDPSEvaluation();
6722           for (; (size--); offset++)
6723             {
6724               // normal case
6725               // result = left & right
6726               if (AOP_TYPE (right) == AOP_LIT)
6727                 {
6728                   if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6729                     {
6730                       aopPut (AOP (result),
6731                            aopGet (AOP (left), offset, FALSE, FALSE, NULL),
6732                               offset);
6733                       continue;
6734                     }
6735                   D (emitcode (";", "better literal OR."););
6736                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6737                   emitcode ("orl", "a, %s",
6738                             aopGet (AOP (right), offset,
6739                                     FALSE, FALSE, DP2_RESULT_REG));
6740
6741                 }
6742               else
6743                 {
6744                   // faster than result <- left, anl result,right
6745                   // and better if result is SFR
6746                   if (AOP_TYPE (left) == AOP_ACC)
6747                     {
6748                       emitcode ("orl", "a,%s",
6749                                 aopGet (AOP (right), offset,
6750                                         FALSE, FALSE, DP2_RESULT_REG));
6751                     }
6752                   else
6753                     {
6754                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
6755                         
6756                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
6757                       {
6758                           emitcode("mov", "b,a");
6759                           rOp = "b";
6760                       }
6761                         
6762                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6763                       emitcode ("orl", "a,%s", rOp);
6764                     }
6765                 }
6766               aopPut (AOP (result), "a", offset);
6767             }
6768             _endLazyDPSEvaluation();
6769         }
6770     }
6771
6772 release:
6773   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6774   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6775   freeAsmop (result, NULL, ic, TRUE);
6776 }
6777
6778 /*-----------------------------------------------------------------*/
6779 /* genXor - code for xclusive or                                   */
6780 /*-----------------------------------------------------------------*/
6781 static void
6782 genXor (iCode * ic, iCode * ifx)
6783 {
6784   operand *left, *right, *result;
6785   int size, offset = 0;
6786   unsigned long lit = 0L;
6787   bool pushResult;
6788
6789   D (emitcode (";", "genXor "););
6790
6791   AOP_OP_3_NOFATAL (ic, pushResult);
6792   AOP_SET_LOCALS (ic);
6793
6794   if (pushResult)
6795   {
6796       genFarFarLogicOp(ic, "xrl");
6797       return;
6798   }  
6799
6800 #ifdef DEBUG_TYPE
6801   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6802             AOP_TYPE (result),
6803             AOP_TYPE (left), AOP_TYPE (right));
6804   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6805             AOP_SIZE (result),
6806             AOP_SIZE (left), AOP_SIZE (right));
6807 #endif
6808
6809   /* if left is a literal & right is not ||
6810      if left needs acc & right does not */
6811   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) 
6812 #ifdef LOGIC_OPS_BROKEN      
6813       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
6814 #endif
6815      )
6816     {
6817       operand *tmp = right;
6818       right = left;
6819       left = tmp;
6820     }
6821
6822   /* if result = right then exchange them */
6823   if (sameRegs (AOP (result), AOP (right)))
6824     {
6825       operand *tmp = right;
6826       right = left;
6827       left = tmp;
6828     }
6829
6830   /* if right is bit then exchange them */
6831   if (AOP_TYPE (right) == AOP_CRY &&
6832       AOP_TYPE (left) != AOP_CRY)
6833     {
6834       operand *tmp = right;
6835       right = left;
6836       left = tmp;
6837     }
6838   if (AOP_TYPE (right) == AOP_LIT)
6839     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6840
6841   size = AOP_SIZE (result);
6842
6843   // if(bit ^ yy)
6844   // xx = bit ^ yy;
6845   if (AOP_TYPE (left) == AOP_CRY)
6846     {
6847       if (AOP_TYPE (right) == AOP_LIT)
6848         {
6849           // c = bit & literal;
6850           if (lit >> 1)
6851             {
6852               // lit>>1  != 0 => result = 1
6853               if (AOP_TYPE (result) == AOP_CRY)
6854                 {
6855                   if (size)
6856                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6857                   else if (ifx)
6858                     continueIfTrue (ifx);
6859                   goto release;
6860                 }
6861               emitcode ("setb", "c");
6862             }
6863           else
6864             {
6865               // lit == (0 or 1)
6866               if (lit == 0)
6867                 {
6868                   // lit == 0, result = left
6869                   if (size && sameRegs (AOP (result), AOP (left)))
6870                     goto release;
6871                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6872                 }
6873               else
6874                 {
6875                   // lit == 1, result = not(left)
6876                   if (size && sameRegs (AOP (result), AOP (left)))
6877                     {
6878                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6879                       goto release;
6880                     }
6881                   else
6882                     {
6883                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6884                       emitcode ("cpl", "c");
6885                     }
6886                 }
6887             }
6888
6889         }
6890       else
6891         {
6892           // right != literal
6893           symbol *tlbl = newiTempLabel (NULL);
6894           if (AOP_TYPE (right) == AOP_CRY)
6895             {
6896               // c = bit ^ bit;
6897               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6898             }
6899           else
6900             {
6901               int sizer = AOP_SIZE (right);
6902               // c = bit ^ val
6903               // if val>>1 != 0, result = 1
6904               emitcode ("setb", "c");
6905               while (sizer)
6906                 {
6907                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE, NULL));
6908                   if (sizer == 1)
6909                     // test the msb of the lsb
6910                     emitcode ("anl", "a,#!constbyte",0xfe);
6911                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
6912                   sizer--;
6913                 }
6914               // val = (0,1)
6915               emitcode ("rrc", "a");
6916             }
6917           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6918           emitcode ("cpl", "c");
6919           emitcode ("", "!tlabeldef", (tlbl->key + 100));
6920         }
6921       // bit = c
6922       // val = c
6923       if (size)
6924         outBitC (result);
6925       // if(bit | ...)
6926       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6927         genIfxJump (ifx, "c");
6928       goto release;
6929     }
6930
6931   if (sameRegs (AOP (result), AOP (left)))
6932     {
6933       /* if left is same as result */
6934       for (; size--; offset++)
6935         {
6936           if (AOP_TYPE (right) == AOP_LIT)
6937             {
6938               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6939                 continue;
6940               else if (IS_AOP_PREG (left))
6941                 {
6942                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6943                   emitcode ("xrl", "a,%s",
6944                             aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6945                   aopPut (AOP (result), "a", offset);
6946                 }
6947               else
6948                 emitcode ("xrl", "%s,%s",
6949                           aopGet (AOP (left), offset, FALSE, TRUE, NULL),
6950                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6951             }
6952           else
6953             {
6954               if (AOP_TYPE (left) == AOP_ACC)
6955                 emitcode ("xrl", "a,%s",
6956                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6957               else
6958                 {
6959                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6960                   if (IS_AOP_PREG (left))
6961                     {
6962                       emitcode ("xrl", "a,%s",
6963                                 aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6964                       aopPut (AOP (result), "a", offset);
6965                     }
6966                   else
6967                     emitcode ("xrl", "%s,a",
6968                            aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6969                 }
6970             }
6971         }
6972     }
6973   else
6974     {
6975       // left & result in different registers
6976       if (AOP_TYPE (result) == AOP_CRY)
6977         {
6978           // result = bit
6979           // if(size), result in bit
6980           // if(!size && ifx), conditional oper: if(left ^ right)
6981           symbol *tlbl = newiTempLabel (NULL);
6982           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6983                   
6984           if (size)
6985             emitcode ("setb", "c");
6986           while (sizer--)
6987             {
6988               if ((AOP_TYPE (right) == AOP_LIT) &&
6989                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6990                 {
6991                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6992                 }
6993               else
6994                 {
6995                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6996                     emitcode ("xrl", "a,%s",
6997                               aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6998                   } else {
6999                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
7000                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7001                       {
7002                           emitcode("mov", "b,a");
7003                           rOp = "b";
7004                       }
7005                         
7006                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7007                       emitcode ("xrl", "a,%s", rOp);                  
7008                   }
7009                 }
7010               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7011               offset++;
7012             }
7013           if (size)
7014             {
7015               CLRC;
7016               emitcode ("", "!tlabeldef", tlbl->key + 100);
7017               outBitC (result);
7018             }
7019           else if (ifx)
7020             jmpTrueOrFalse (ifx, tlbl);
7021         }
7022       else
7023         {
7024         for (; (size--); offset++)
7025           {
7026             // normal case
7027             // result = left & right
7028             if (AOP_TYPE (right) == AOP_LIT)
7029               {
7030                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
7031                   {
7032                     aopPut (AOP (result),
7033                             aopGet (AOP (left), offset, FALSE, FALSE, NULL),
7034                             offset);
7035                     continue;
7036                   }
7037                 D (emitcode (";", "better literal XOR."););
7038                 MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7039                 emitcode ("xrl", "a, %s",
7040                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7041               }
7042             else
7043               {
7044                 // faster than result <- left, anl result,right
7045                 // and better if result is SFR
7046                 if (AOP_TYPE (left) == AOP_ACC)
7047                   {
7048                     emitcode ("xrl", "a,%s",
7049                               aopGet (AOP (right), offset,
7050                                       FALSE, FALSE, DP2_RESULT_REG));
7051                   }
7052                 else
7053                   {
7054                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
7055                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7056                       {
7057                           emitcode("mov", "b,a");
7058                           rOp = "b";
7059                       }
7060                         
7061                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7062                       emitcode ("xrl", "a,%s", rOp);
7063                   }
7064               }
7065             aopPut (AOP (result), "a", offset);
7066           }
7067         }
7068         
7069     }
7070
7071 release:
7072   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7073   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7074   freeAsmop (result, NULL, ic, TRUE);
7075 }
7076
7077 /*-----------------------------------------------------------------*/
7078 /* genInline - write the inline code out                           */
7079 /*-----------------------------------------------------------------*/
7080 static void
7081 genInline (iCode * ic)
7082 {
7083   char *buffer, *bp, *bp1;
7084
7085   D (emitcode (";", "genInline "); );
7086
7087   _G.inLine += (!options.asmpeep);
7088
7089   buffer = Safe_strdup(IC_INLINE(ic));
7090   bp = buffer;
7091   bp1 = buffer;
7092
7093   /* emit each line as a code */
7094   while (*bp)
7095     {
7096       if (*bp == '\n')
7097         {
7098           *bp++ = '\0';
7099           emitcode (bp1, "");
7100           bp1 = bp;
7101         }
7102       else
7103         {
7104           if (*bp == ':')
7105             {
7106               bp++;
7107               *bp = '\0';
7108               bp++;
7109               emitcode (bp1, "");
7110               bp1 = bp;
7111             }
7112           else
7113             bp++;
7114         }
7115     }
7116   if (bp1 != bp)
7117     emitcode (bp1, "");
7118   /*     emitcode("",buffer); */
7119   _G.inLine -= (!options.asmpeep);
7120 }
7121
7122 /*-----------------------------------------------------------------*/
7123 /* genRRC - rotate right with carry                                */
7124 /*-----------------------------------------------------------------*/
7125 static void
7126 genRRC (iCode * ic)
7127 {
7128   operand *left, *result;
7129   int     size, offset;
7130
7131   D (emitcode (";", "genRRC "););
7132
7133   /* rotate right with carry */
7134   left = IC_LEFT (ic);
7135   result = IC_RESULT (ic);
7136   aopOp (left, ic, FALSE, FALSE);
7137   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7138
7139   /* move it to the result */
7140   size = AOP_SIZE (result);
7141   offset = size - 1;
7142   CLRC;
7143
7144   _startLazyDPSEvaluation ();
7145   while (size--)
7146     {
7147       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7148       emitcode ("rrc", "a");
7149       if (AOP_SIZE (result) > 1)
7150         aopPut (AOP (result), "a", offset--);
7151     }
7152   _endLazyDPSEvaluation ();
7153
7154   /* now we need to put the carry into the
7155      highest order byte of the result */
7156   if (AOP_SIZE (result) > 1)
7157     {
7158       MOVA (aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE, NULL));
7159     }
7160   emitcode ("mov", "acc.7,c");
7161   aopPut (AOP (result), "a", AOP_SIZE (result) - 1);
7162   freeAsmop (left, NULL, ic, TRUE);
7163   freeAsmop (result, NULL, ic, TRUE);
7164 }
7165
7166 /*-----------------------------------------------------------------*/
7167 /* genRLC - generate code for rotate left with carry               */
7168 /*-----------------------------------------------------------------*/
7169 static void
7170 genRLC (iCode * ic)
7171 {
7172   operand *left, *result;
7173   int size, offset;
7174   char *l;
7175
7176   D (emitcode (";", "genRLC "););
7177
7178   /* rotate right with carry */
7179   left = IC_LEFT (ic);
7180   result = IC_RESULT (ic);
7181   aopOp (left, ic, FALSE, FALSE);
7182   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7183
7184   /* move it to the result */
7185   size = AOP_SIZE (result);
7186   offset = 0;
7187   if (size--)
7188     {
7189       l = aopGet (AOP (left), offset, FALSE, FALSE, NULL);
7190       MOVA (l);
7191       emitcode ("add", "a,acc");
7192       if (AOP_SIZE (result) > 1)
7193         {
7194           aopPut (AOP (result), "a", offset++);
7195         }
7196
7197       _startLazyDPSEvaluation ();
7198       while (size--)
7199         {
7200           l = aopGet (AOP (left), offset, FALSE, FALSE, NULL);
7201           MOVA (l);
7202           emitcode ("rlc", "a");
7203           if (AOP_SIZE (result) > 1)
7204             aopPut (AOP (result), "a", offset++);
7205         }
7206       _endLazyDPSEvaluation ();
7207     }
7208   /* now we need to put the carry into the
7209      highest order byte of the result */
7210   if (AOP_SIZE (result) > 1)
7211     {
7212       l = aopGet (AOP (result), 0, FALSE, FALSE, NULL);
7213       MOVA (l);
7214     }
7215   emitcode ("mov", "acc.0,c");
7216   aopPut (AOP (result), "a", 0);
7217   freeAsmop (left, NULL, ic, TRUE);
7218   freeAsmop (result, NULL, ic, TRUE);
7219 }
7220
7221 /*-----------------------------------------------------------------*/
7222 /* genGetHbit - generates code get highest order bit               */
7223 /*-----------------------------------------------------------------*/
7224 static void
7225 genGetHbit (iCode * ic)
7226 {
7227   operand *left, *result;
7228   left = IC_LEFT (ic);
7229   result = IC_RESULT (ic);
7230   aopOp (left, ic, FALSE, FALSE);
7231   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7232
7233   D (emitcode (";", "genGetHbit "););
7234
7235   /* get the highest order byte into a */
7236   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
7237   if (AOP_TYPE (result) == AOP_CRY)
7238     {
7239       emitcode ("rlc", "a");
7240       outBitC (result);
7241     }
7242   else
7243     {
7244       emitcode ("rl", "a");
7245       emitcode ("anl", "a,#1");
7246       outAcc (result);
7247     }
7248
7249
7250   freeAsmop (left, NULL, ic, TRUE);
7251   freeAsmop (result, NULL, ic, TRUE);
7252 }
7253
7254 /*-----------------------------------------------------------------*/
7255 /* AccRol - rotate left accumulator by known count                 */
7256 /*-----------------------------------------------------------------*/
7257 static void
7258 AccRol (int shCount)
7259 {
7260   shCount &= 0x0007;            // shCount : 0..7
7261
7262   switch (shCount)
7263     {
7264     case 0:
7265       break;
7266     case 1:
7267       emitcode ("rl", "a");
7268       break;
7269     case 2:
7270       emitcode ("rl", "a");
7271       emitcode ("rl", "a");
7272       break;
7273     case 3:
7274       emitcode ("swap", "a");
7275       emitcode ("rr", "a");
7276       break;
7277     case 4:
7278       emitcode ("swap", "a");
7279       break;
7280     case 5:
7281       emitcode ("swap", "a");
7282       emitcode ("rl", "a");
7283       break;
7284     case 6:
7285       emitcode ("rr", "a");
7286       emitcode ("rr", "a");
7287       break;
7288     case 7:
7289       emitcode ("rr", "a");
7290       break;
7291     }
7292 }
7293
7294 /*-----------------------------------------------------------------*/
7295 /* AccLsh - left shift accumulator by known count                  */
7296 /*-----------------------------------------------------------------*/
7297 static void
7298 AccLsh (int shCount)
7299 {
7300   if (shCount != 0)
7301     {
7302       if (shCount == 1)
7303         emitcode ("add", "a,acc");
7304       else if (shCount == 2)
7305         {
7306           emitcode ("add", "a,acc");
7307           emitcode ("add", "a,acc");
7308         }
7309       else
7310         {
7311           /* rotate left accumulator */
7312           AccRol (shCount);
7313           /* and kill the lower order bits */
7314           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
7315         }
7316     }
7317 }
7318
7319 /*-----------------------------------------------------------------*/
7320 /* AccRsh - right shift accumulator by known count                 */
7321 /*-----------------------------------------------------------------*/
7322 static void
7323 AccRsh (int shCount)
7324 {
7325   if (shCount != 0)
7326     {
7327       if (shCount == 1)
7328         {
7329           CLRC;
7330           emitcode ("rrc", "a");
7331         }
7332       else
7333         {
7334           /* rotate right accumulator */
7335           AccRol (8 - shCount);
7336           /* and kill the higher order bits */
7337           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
7338         }
7339     }
7340 }
7341
7342 #ifdef BETTER_LITERAL_SHIFT
7343 /*-----------------------------------------------------------------*/
7344 /* AccSRsh - signed right shift accumulator by known count                 */
7345 /*-----------------------------------------------------------------*/
7346 static void
7347 AccSRsh (int shCount)
7348 {
7349   symbol *tlbl;
7350   if (shCount != 0)
7351     {
7352       if (shCount == 1)
7353         {
7354           emitcode ("mov", "c,acc.7");
7355           emitcode ("rrc", "a");
7356         }
7357       else if (shCount == 2)
7358         {
7359           emitcode ("mov", "c,acc.7");
7360           emitcode ("rrc", "a");
7361           emitcode ("mov", "c,acc.7");
7362           emitcode ("rrc", "a");
7363         }
7364       else
7365         {
7366           tlbl = newiTempLabel (NULL);
7367           /* rotate right accumulator */
7368           AccRol (8 - shCount);
7369           /* and kill the higher order bits */
7370           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
7371           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
7372           emitcode ("orl", "a,#!constbyte",
7373                     (unsigned char) ~SRMask[shCount]);
7374           emitcode ("", "!tlabeldef", tlbl->key + 100);
7375         }
7376     }
7377 }
7378 #endif
7379
7380 #ifdef BETTER_LITERAL_SHIFT
7381 /*-----------------------------------------------------------------*/
7382 /* shiftR1Left2Result - shift right one byte from left to result   */
7383 /*-----------------------------------------------------------------*/
7384 static void
7385 shiftR1Left2Result (operand * left, int offl,
7386                     operand * result, int offr,
7387                     int shCount, int sign)
7388 {
7389   MOVA (aopGet (AOP (left), offl, FALSE, FALSE, NULL));
7390   /* shift right accumulator */
7391   if (sign)
7392     AccSRsh (shCount);
7393   else
7394     AccRsh (shCount);
7395   aopPut (AOP (result), "a", offr);
7396 }
7397 #endif
7398
7399 #ifdef BETTER_LITERAL_SHIFT
7400 /*-----------------------------------------------------------------*/
7401 /* shiftL1Left2Result - shift left one byte from left to result    */
7402 /*-----------------------------------------------------------------*/
7403 static void
7404 shiftL1Left2Result (operand * left, int offl,
7405                     operand * result, int offr, int shCount)
7406 {
7407   MOVA(aopGet (AOP (left), offl, FALSE, FALSE, NULL));
7408   /* shift left accumulator */
7409   AccLsh (shCount);
7410   aopPut (AOP (result), "a", offr);
7411 }
7412 #endif
7413
7414 #ifdef BETTER_LITERAL_SHIFT
7415 /*-----------------------------------------------------------------*/
7416 /* movLeft2Result - move byte from left to result                  */
7417 /*-----------------------------------------------------------------*/
7418 static void
7419 movLeft2Result (operand * left, int offl,
7420                 operand * result, int offr, int sign)
7421 {
7422   char *l;
7423   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7424   {
7425       l = aopGet (AOP (left), offl, FALSE, FALSE, NULL);
7426
7427       if (*l == '@' && (IS_AOP_PREG (result)))
7428       {
7429           emitcode ("mov", "a,%s", l);
7430           aopPut (AOP (result), "a", offr);
7431       }
7432       else
7433       {
7434           if (!sign)
7435           {
7436             aopPut (AOP (result), l, offr);
7437           }
7438           else
7439             {
7440               /* MSB sign in acc.7 ! */
7441               if (getDataSize (left) == offl + 1)
7442                 {
7443                   emitcode ("mov", "a,%s", l);
7444                   aopPut (AOP (result), "a", offr);
7445                 }
7446             }
7447       }
7448   }
7449 }
7450 #endif
7451
7452 #ifdef BETTER_LITERAL_SHIFT
7453 /*-----------------------------------------------------------------*/
7454 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7455 /*-----------------------------------------------------------------*/
7456 static void
7457 AccAXRrl1 (char *x)
7458 {
7459   emitcode ("rrc", "a");
7460   emitcode ("xch", "a,%s", x);
7461   emitcode ("rrc", "a");
7462   emitcode ("xch", "a,%s", x);
7463 }
7464 #endif
7465
7466 #ifdef BETTER_LITERAL_SHIFT
7467 //REMOVE ME!!!
7468 /*-----------------------------------------------------------------*/
7469 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7470 /*-----------------------------------------------------------------*/
7471 static void
7472 AccAXLrl1 (char *x)
7473 {
7474   emitcode ("xch", "a,%s", x);
7475   emitcode ("rlc", "a");
7476   emitcode ("xch", "a,%s", x);
7477   emitcode ("rlc", "a");
7478 }
7479 #endif
7480
7481 #ifdef BETTER_LITERAL_SHIFT
7482 /*-----------------------------------------------------------------*/
7483 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7484 /*-----------------------------------------------------------------*/
7485 static void
7486 AccAXLsh1 (char *x)
7487 {
7488   emitcode ("xch", "a,%s", x);
7489   emitcode ("add", "a,acc");
7490   emitcode ("xch", "a,%s", x);
7491   emitcode ("rlc", "a");
7492 }
7493 #endif
7494
7495 #ifdef BETTER_LITERAL_SHIFT
7496 /*-----------------------------------------------------------------*/
7497 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7498 /*-----------------------------------------------------------------*/
7499 static void
7500 AccAXLsh (char *x, int shCount)
7501 {
7502   switch (shCount)
7503     {
7504     case 0:
7505       break;
7506     case 1:
7507       AccAXLsh1 (x);
7508       break;
7509     case 2:
7510       AccAXLsh1 (x);
7511       AccAXLsh1 (x);
7512       break;
7513     case 3:
7514     case 4:
7515     case 5:                     // AAAAABBB:CCCCCDDD
7516
7517       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7518
7519       emitcode ("anl", "a,#!constbyte",
7520                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7521
7522       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7523
7524       AccRol (shCount);         // DDDCCCCC:BBB00000
7525
7526       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7527
7528       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7529
7530       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7531
7532       emitcode ("anl", "a,#!constbyte",
7533                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7534
7535       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7536
7537       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7538
7539       break;
7540     case 6:                     // AAAAAABB:CCCCCCDD
7541       emitcode ("anl", "a,#!constbyte",
7542                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7543       emitcode ("mov", "c,acc.0");      // c = B
7544       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7545 #if 0
7546       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7547       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7548 #else
7549       emitcode("rrc","a"); 
7550       emitcode("xch","a,%s", x); 
7551       emitcode("rrc","a"); 
7552       emitcode("mov","c,acc.0"); //<< get correct bit 
7553       emitcode("xch","a,%s", x); 
7554
7555       emitcode("rrc","a"); 
7556       emitcode("xch","a,%s", x); 
7557       emitcode("rrc","a"); 
7558       emitcode("xch","a,%s", x); 
7559 #endif
7560       break;
7561     case 7:                     // a:x <<= 7
7562
7563       emitcode ("anl", "a,#!constbyte",
7564                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7565
7566       emitcode ("mov", "c,acc.0");      // c = B
7567
7568       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7569
7570       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7571
7572       break;
7573     default:
7574       break;
7575     }
7576 }
7577 #endif
7578
7579 #ifdef BETTER_LITERAL_SHIFT
7580 //REMOVE ME!!!
7581 /*-----------------------------------------------------------------*/
7582 /* AccAXRsh - right shift a:x known count (0..7)                   */
7583 /*-----------------------------------------------------------------*/
7584 static void
7585 AccAXRsh (char *x, int shCount)
7586 {
7587   switch (shCount)
7588     {
7589     case 0:
7590       break;
7591     case 1:
7592       CLRC;
7593       AccAXRrl1 (x);            // 0->a:x
7594
7595       break;
7596     case 2:
7597       CLRC;
7598       AccAXRrl1 (x);            // 0->a:x
7599
7600       CLRC;
7601       AccAXRrl1 (x);            // 0->a:x
7602
7603       break;
7604     case 3:
7605     case 4:
7606     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7607
7608       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7609
7610       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7611
7612       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7613
7614       emitcode ("anl", "a,#!constbyte",
7615                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7616
7617       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7618
7619       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7620
7621       emitcode ("anl", "a,#!constbyte",
7622                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7623
7624       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7625
7626       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7627
7628       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7629
7630       break;
7631     case 6:                     // AABBBBBB:CCDDDDDD
7632
7633       emitcode ("mov", "c,acc.7");
7634       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7635
7636       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7637
7638       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7639
7640       emitcode ("anl", "a,#!constbyte",
7641                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7642
7643       break;
7644     case 7:                     // ABBBBBBB:CDDDDDDD
7645
7646       emitcode ("mov", "c,acc.7");      // c = A
7647
7648       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7649
7650       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7651
7652       emitcode ("anl", "a,#!constbyte",
7653                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7654
7655       break;
7656     default:
7657       break;
7658     }
7659 }
7660 #endif
7661
7662 #ifdef BETTER_LITERAL_SHIFT
7663 /*-----------------------------------------------------------------*/
7664 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7665 /*-----------------------------------------------------------------*/
7666 static void
7667 AccAXRshS (char *x, int shCount)
7668 {
7669   symbol *tlbl;
7670   switch (shCount)
7671     {
7672     case 0:
7673       break;
7674     case 1:
7675       emitcode ("mov", "c,acc.7");
7676       AccAXRrl1 (x);            // s->a:x
7677
7678       break;
7679     case 2:
7680       emitcode ("mov", "c,acc.7");
7681       AccAXRrl1 (x);            // s->a:x
7682
7683       emitcode ("mov", "c,acc.7");
7684       AccAXRrl1 (x);            // s->a:x
7685
7686       break;
7687     case 3:
7688     case 4:
7689     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7690
7691       tlbl = newiTempLabel (NULL);
7692       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7693
7694       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7695
7696       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7697
7698       emitcode ("anl", "a,#!constbyte",
7699                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7700
7701       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7702
7703       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7704
7705       emitcode ("anl", "a,#!constbyte",
7706                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7707
7708       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7709
7710       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7711
7712       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7713
7714       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
7715       emitcode ("orl", "a,#!constbyte",
7716                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7717
7718       emitcode ("", "!tlabeldef", tlbl->key + 100);
7719       break;                    // SSSSAAAA:BBBCCCCC
7720
7721     case 6:                     // AABBBBBB:CCDDDDDD
7722
7723       tlbl = newiTempLabel (NULL);
7724       emitcode ("mov", "c,acc.7");
7725       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7726
7727       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7728
7729       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7730
7731       emitcode ("anl", "a,#!constbyte",
7732                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7733
7734       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
7735       emitcode ("orl", "a,#!constbyte",
7736                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7737
7738       emitcode ("", "!tlabeldef", tlbl->key + 100);
7739       break;
7740     case 7:                     // ABBBBBBB:CDDDDDDD
7741
7742       tlbl = newiTempLabel (NULL);
7743       emitcode ("mov", "c,acc.7");      // c = A
7744
7745       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7746
7747       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7748
7749       emitcode ("anl", "a,#!constbyte",
7750                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7751
7752       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
7753       emitcode ("orl", "a,#!constbyte",
7754                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7755
7756       emitcode ("", "!tlabeldef", tlbl->key + 100);
7757       break;
7758     default:
7759       break;
7760     }
7761 }
7762 #endif
7763
7764 #ifdef BETTER_LITERAL_SHIFT
7765 static void
7766 _loadLeftIntoAx(char    **lsb, 
7767                 operand *left, 
7768                 operand *result,
7769                 int     offl,
7770                 int     offr)
7771 {
7772   // Get the initial value from left into a pair of registers.
7773   // MSB must be in A, LSB can be any register.
7774   //
7775   // If the result is held in registers, it is an optimization
7776   // if the LSB can be held in the register which will hold the,
7777   // result LSB since this saves us from having to copy it into
7778   // the result following AccAXLsh.
7779   //
7780   // If the result is addressed indirectly, this is not a gain.
7781   if (AOP_NEEDSACC(result))
7782   {
7783        char *leftByte;
7784        
7785        _startLazyDPSEvaluation();
7786       if (AOP_TYPE(left) == AOP_DPTR2)
7787        {
7788            // Get MSB in A.
7789            MOVA(aopGet(AOP(left), offl + MSB16, FALSE, FALSE, NULL));
7790            // get LSB in DP2_RESULT_REG.
7791            leftByte = aopGet(AOP(left), offl, FALSE, FALSE, DP2_RESULT_REG);
7792            assert(!strcmp(leftByte, DP2_RESULT_REG));
7793        }
7794        else
7795        {
7796            // get LSB into DP2_RESULT_REG
7797            leftByte = aopGet (AOP(left), offl, FALSE, FALSE, NULL);
7798            if (strcmp(leftByte, DP2_RESULT_REG))
7799            {
7800                TR_AP("#7");
7801                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
7802            }
7803            // And MSB in A.
7804            leftByte = aopGet(AOP(left), offl + MSB16, FALSE, FALSE, NULL);
7805            assert(strcmp(leftByte, DP2_RESULT_REG));
7806            MOVA(leftByte);
7807        }
7808        _endLazyDPSEvaluation();
7809        *lsb = DP2_RESULT_REG;
7810   }
7811   else
7812   {
7813       if (sameRegs (AOP (result), AOP (left)) &&
7814         ((offl + MSB16) == offr))
7815       {
7816           /* don't crash result[offr] */
7817           MOVA(aopGet(AOP(left), offl, FALSE, FALSE, NULL));
7818           emitcode ("xch", "a,%s", 
7819                     aopGet(AOP(left), offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
7820       }
7821       else
7822       {
7823           movLeft2Result (left, offl, result, offr, 0);
7824           MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE, NULL));
7825       }
7826       *lsb = aopGet(AOP (result), offr, FALSE, FALSE, DP2_RESULT_REG);
7827       assert(strcmp(*lsb,"a"));      
7828   }
7829 }
7830
7831 static void
7832 _storeAxResults(char    *lsb,
7833                 operand *result,
7834                 int     offr)
7835 {
7836   _startLazyDPSEvaluation();
7837   if (AOP_NEEDSACC(result))
7838   {
7839       /* We have to explicitly update the result LSB.
7840        */
7841       emitcode("xch","a,%s", lsb);
7842       aopPut(AOP(result), "a", offr);
7843       emitcode("mov","a,%s", lsb);
7844   }
7845   if (getDataSize (result) > 1)
7846   {
7847       aopPut (AOP (result), "a", offr + MSB16);
7848   }
7849   _endLazyDPSEvaluation();
7850 }
7851
7852 /*-----------------------------------------------------------------*/
7853 /* shiftL2Left2Result - shift left two bytes from left to result   */
7854 /*-----------------------------------------------------------------*/
7855 static void
7856 shiftL2Left2Result (operand * left, int offl,
7857                     operand * result, int offr, int shCount)
7858 {
7859   char *lsb;
7860
7861   _loadLeftIntoAx(&lsb, left, result, offl, offr);
7862   
7863   AccAXLsh (lsb, shCount);
7864   
7865   _storeAxResults(lsb, result, offr);
7866 }
7867 #endif
7868
7869 #ifdef BETTER_LITERAL_SHIFT
7870 /*-----------------------------------------------------------------*/
7871 /* shiftR2Left2Result - shift right two bytes from left to result  */
7872 /*-----------------------------------------------------------------*/
7873 static void
7874 shiftR2Left2Result (operand * left, int offl,
7875                     operand * result, int offr,
7876                     int shCount, int sign)
7877 {
7878   char *lsb;
7879   
7880   _loadLeftIntoAx(&lsb, left, result, offl, offr);
7881   
7882   /* a:x >> shCount (x = lsb(result)) */
7883   if (sign)
7884   {
7885      AccAXRshS(lsb, shCount);
7886   }
7887   else
7888   {
7889     AccAXRsh(lsb, shCount);
7890   }
7891   
7892   _storeAxResults(lsb, result, offr);
7893 }
7894 #endif
7895
7896 #if 0
7897 //REMOVE ME!!!
7898 /*-----------------------------------------------------------------*/
7899 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7900 /*-----------------------------------------------------------------*/
7901 static void
7902 shiftLLeftOrResult (operand * left, int offl,
7903                     operand * result, int offr, int shCount)
7904 {
7905   MOVA (aopGet (AOP (left), offl, FALSE, FALSE, NULL));
7906   /* shift left accumulator */
7907   AccLsh (shCount);
7908   /* or with result */
7909   emitcode ("orl", "a,%s",
7910             aopGet (AOP (result), offr, FALSE, FALSE, DP2_RESULT_REG));
7911   /* back to result */
7912   aopPut (AOP (result), "a", offr);
7913 }
7914 #endif
7915
7916 #if 0
7917 //REMOVE ME!!!
7918 /*-----------------------------------------------------------------*/
7919 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7920 /*-----------------------------------------------------------------*/
7921 static void
7922 shiftRLeftOrResult (operand * left, int offl,
7923                     operand * result, int offr, int shCount)
7924 {
7925   MOVA (aopGet (AOP (left), offl, FALSE, FALSE, NULL));
7926   /* shift right accumulator */
7927   AccRsh (shCount);
7928   /* or with result */
7929   emitcode ("orl", "a,%s",
7930             aopGet (AOP (result), offr, FALSE, FALSE, DP2_RESULT_REG));
7931   /* back to result */
7932   aopPut (AOP (result), "a", offr);
7933 }
7934 #endif
7935
7936 #ifdef BETTER_LITERAL_SHIFT
7937 /*-----------------------------------------------------------------*/
7938 /* genlshOne - left shift a one byte quantity by known count       */
7939 /*-----------------------------------------------------------------*/
7940 static void
7941 genlshOne (operand * result, operand * left, int shCount)
7942 {
7943   D (emitcode (";", "genlshOne "););
7944   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7945 }
7946 #endif
7947
7948 #ifdef BETTER_LITERAL_SHIFT
7949 /*-----------------------------------------------------------------*/
7950 /* genlshTwo - left shift two bytes by known amount != 0           */
7951 /*-----------------------------------------------------------------*/
7952 static void
7953 genlshTwo (operand * result, operand * left, int shCount)
7954 {
7955   int size;
7956
7957   D (emitcode (";", "genlshTwo "););
7958
7959   size = getDataSize (result);
7960
7961   /* if shCount >= 8 */
7962   if (shCount >= 8)
7963   {
7964       shCount -= 8;
7965
7966       _startLazyDPSEvaluation();
7967
7968       if (size > 1)
7969         {
7970           if (shCount)
7971           {
7972             _endLazyDPSEvaluation();
7973             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7974             aopPut (AOP (result), zero, LSB);       
7975           }
7976           else
7977           {
7978             movLeft2Result (left, LSB, result, MSB16, 0);
7979             aopPut (AOP (result), zero, LSB);
7980             _endLazyDPSEvaluation();
7981           }
7982         }
7983         else
7984         {
7985           aopPut (AOP (result), zero, LSB);
7986           _endLazyDPSEvaluation();
7987         }
7988   }
7989
7990   /*  1 <= shCount <= 7 */
7991   else
7992     {
7993       if (size == 1)
7994       {
7995         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7996       }
7997       else
7998       {
7999         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8000       }
8001     }
8002 }
8003 #endif
8004
8005 #if 0
8006 //REMOVE ME!!!
8007 /*-----------------------------------------------------------------*/
8008 /* shiftLLong - shift left one long from left to result            */
8009 /* offl = LSB or MSB16                                             */
8010 /*-----------------------------------------------------------------*/
8011 static void
8012 shiftLLong (operand * left, operand * result, int offr)
8013 {
8014   char *l;
8015   int size = AOP_SIZE (result);
8016
8017   if (size >= LSB + offr)
8018     {
8019       l = aopGet (AOP (left), LSB, FALSE, FALSE, NULL);
8020       MOVA (l);
8021       emitcode ("add", "a,acc");
8022       if (sameRegs (AOP (left), AOP (result)) &&
8023           size >= MSB16 + offr && offr != LSB)
8024         emitcode ("xch", "a,%s",
8025                   aopGet (AOP (left), LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
8026       else
8027         aopPut (AOP (result), "a", LSB + offr);
8028     }
8029
8030   if (size >= MSB16 + offr)
8031     {
8032       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8033         {
8034           MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE, TRUE));
8035         }
8036       emitcode ("rlc", "a");
8037       if (sameRegs (AOP (left), AOP (result)) &&
8038           size >= MSB24 + offr && offr != LSB)
8039         emitcode ("xch", "a,%s",
8040                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
8041       else
8042         aopPut (AOP (result), "a", MSB16 + offr);
8043     }
8044
8045   if (size >= MSB24 + offr)
8046     {
8047       if (!(sameRegs (AOP (left), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8048         {
8049           MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE, NULL));
8050         }
8051       emitcode ("rlc", "a");
8052       if (sameRegs (AOP (left), AOP (result)) &&
8053           size >= MSB32 + offr && offr != LSB)
8054         emitcode ("xch", "a,%s",
8055                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
8056       else
8057         aopPut (AOP (result), "a", MSB24 + offr);
8058     }
8059
8060   if (size > MSB32 + offr)
8061     {
8062       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8063         {
8064           MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE, NULL));
8065         }
8066       emitcode ("rlc", "a");
8067       aopPut (AOP (result), "a", MSB32 + offr);
8068     }
8069   if (offr != LSB)
8070     aopPut (AOP (result), zero, LSB);
8071 }
8072 #endif
8073
8074 #if 0
8075 //REMOVE ME!!!
8076 /*-----------------------------------------------------------------*/
8077 /* genlshFour - shift four byte by a known amount != 0             */
8078 /*-----------------------------------------------------------------*/
8079 static void
8080 genlshFour (operand * result, operand * left, int shCount)
8081 {
8082   int size;
8083
8084   D (emitcode (";", "genlshFour ");
8085     );
8086
8087   size = AOP_SIZE (result);
8088
8089   /* if shifting more that 3 bytes */
8090   if (shCount >= 24)
8091     {
8092       shCount -= 24;
8093       if (shCount)
8094         /* lowest order of left goes to the highest
8095            order of the destination */
8096         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8097       else
8098         movLeft2Result (left, LSB, result, MSB32, 0);
8099       aopPut (AOP (result), zero, LSB);
8100       aopPut (AOP (result), zero, MSB16);
8101       aopPut (AOP (result), zero, MSB24);
8102       return;
8103     }
8104
8105   /* more than two bytes */
8106   else if (shCount >= 16)
8107     {
8108       /* lower order two bytes goes to higher order two bytes */
8109       shCount -= 16;
8110       /* if some more remaining */
8111       if (shCount)
8112         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8113       else
8114         {
8115           movLeft2Result (left, MSB16, result, MSB32, 0);
8116           movLeft2Result (left, LSB, result, MSB24, 0);
8117         }
8118       aopPut (AOP (result), zero, MSB16);
8119       aopPut (AOP (result), zero, LSB);
8120       return;
8121     }
8122
8123   /* if more than 1 byte */
8124   else if (shCount >= 8)
8125     {
8126       /* lower order three bytes goes to higher order  three bytes */
8127       shCount -= 8;
8128       if (size == 2)
8129         {
8130           if (shCount)
8131             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8132           else
8133             movLeft2Result (left, LSB, result, MSB16, 0);
8134         }
8135       else
8136         {                       /* size = 4 */
8137           if (shCount == 0)
8138             {
8139               movLeft2Result (left, MSB24, result, MSB32, 0);
8140               movLeft2Result (left, MSB16, result, MSB24, 0);
8141               movLeft2Result (left, LSB, result, MSB16, 0);
8142               aopPut (AOP (result), zero, LSB);
8143             }
8144           else if (shCount == 1)
8145             shiftLLong (left, result, MSB16);
8146           else
8147             {
8148               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8149               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8150               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8151               aopPut (AOP (result), zero, LSB);
8152             }
8153         }
8154     }
8155
8156   /* 1 <= shCount <= 7 */
8157   else if (shCount <= 2)
8158     {
8159       shiftLLong (left, result, LSB);
8160       if (shCount == 2)
8161         shiftLLong (result, result, LSB);
8162     }
8163   /* 3 <= shCount <= 7, optimize */
8164   else
8165     {
8166       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8167       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8168       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8169     }
8170 }
8171 #endif
8172
8173 #ifdef BETTER_LITERAL_SHIFT
8174 /*-----------------------------------------------------------------*/
8175 /* genLeftShiftLiteral - left shifting by known count              */
8176 /*-----------------------------------------------------------------*/
8177 static bool
8178 genLeftShiftLiteral (operand * left,
8179                      operand * right,
8180                      operand * result,
8181                      iCode * ic)
8182 {
8183   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8184   int size;
8185
8186   size = getSize (operandType (result));
8187
8188   D(emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
8189
8190   /* We only handle certain easy cases so far. */
8191   if ((shCount != 0)
8192    && (shCount < (size * 8))
8193    && (size != 1)
8194    && (size != 2))
8195   {
8196       D(emitcode (";", "genLeftShiftLiteral wimping out"););    
8197       return FALSE;
8198   }
8199
8200   freeAsmop (right, NULL, ic, TRUE);
8201
8202   aopOp(left, ic, FALSE, FALSE);
8203   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
8204
8205 #if 0 // debug spew
8206   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
8207   {
8208         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
8209         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
8210         {
8211            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
8212         }
8213   }
8214   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
8215   {
8216         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
8217         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
8218         {
8219            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
8220         }       
8221   }  
8222 #endif
8223   
8224 #if VIEW_SIZE
8225   emitcode ("; shift left ", "result %d, left %d", size,
8226             AOP_SIZE (left));
8227 #endif
8228
8229   /* I suppose that the left size >= result size */
8230   if (shCount == 0)
8231   {
8232         _startLazyDPSEvaluation();
8233         while (size--)
8234         {
8235           movLeft2Result (left, size, result, size, 0);
8236         }
8237         _endLazyDPSEvaluation();
8238   }
8239   else if (shCount >= (size * 8))
8240   {
8241     _startLazyDPSEvaluation();
8242     while (size--)
8243     {
8244       aopPut (AOP (result), zero, size);
8245     }
8246     _endLazyDPSEvaluation();
8247   }
8248   else
8249   {
8250       switch (size)
8251         {
8252         case 1:
8253           genlshOne (result, left, shCount);
8254           break;
8255
8256         case 2:
8257           genlshTwo (result, left, shCount);
8258           break;
8259 #if 0
8260         case 4:
8261           genlshFour (result, left, shCount);
8262           break;
8263 #endif
8264         default:
8265           fprintf(stderr, "*** ack! mystery literal shift!\n");   
8266           break;
8267         }
8268     }
8269   freeAsmop (left, NULL, ic, TRUE);
8270   freeAsmop (result, NULL, ic, TRUE);
8271   return TRUE;
8272 }
8273 #endif
8274
8275 /*-----------------------------------------------------------------*/
8276 /* genLeftShift - generates code for left shifting                 */
8277 /*-----------------------------------------------------------------*/
8278 static void
8279 genLeftShift (iCode * ic)
8280 {
8281   operand *left, *right, *result;
8282   int size, offset;
8283   char *l;
8284   symbol *tlbl, *tlbl1;
8285
8286   D (emitcode (";", "genLeftShift "););
8287
8288   right = IC_RIGHT (ic);
8289   left = IC_LEFT (ic);
8290   result = IC_RESULT (ic);
8291
8292   aopOp (right, ic, FALSE, FALSE);
8293
8294
8295 #ifdef BETTER_LITERAL_SHIFT
8296   /* if the shift count is known then do it
8297      as efficiently as possible */
8298   if (AOP_TYPE (right) == AOP_LIT)
8299     {
8300       if (genLeftShiftLiteral (left, right, result, ic))
8301       {
8302         return;
8303       }
8304     }
8305 #endif
8306
8307   /* shift count is unknown then we have to form
8308      a loop get the loop count in B : Note: we take
8309      only the lower order byte since shifting
8310      more that 32 bits make no sense anyway, ( the
8311      largest size of an object can be only 32 bits ) */
8312
8313   if (AOP_TYPE (right) == AOP_LIT)
8314   {
8315       /* Really should be handled by genLeftShiftLiteral,
8316        * but since I'm too lazy to fix that today, at least we can make
8317        * some small improvement.
8318        */
8319        emitcode("mov", "b,#!constbyte",
8320                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
8321   }
8322   else
8323   {
8324       MOVB(aopGet (AOP (right), 0, FALSE, FALSE, "b"));
8325       emitcode ("inc", "b");
8326   }
8327   freeAsmop (right, NULL, ic, TRUE);
8328   aopOp (left, ic, FALSE, FALSE);
8329   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8330
8331   /* now move the left to the result if they are not the
8332      same */
8333   if (!sameRegs (AOP (left), AOP (result)) &&
8334       AOP_SIZE (result) > 1)
8335     {
8336
8337       size = AOP_SIZE (result);
8338       offset = 0;
8339       _startLazyDPSEvaluation ();
8340       while (size--)
8341         {
8342           l = aopGet (AOP (left), offset, FALSE, TRUE, NULL);
8343           if (*l == '@' && (IS_AOP_PREG (result)))
8344             {
8345
8346               emitcode ("mov", "a,%s", l);
8347               aopPut (AOP (result), "a", offset);
8348             }
8349           else
8350             aopPut (AOP (result), l, offset);
8351           offset++;
8352         }
8353       _endLazyDPSEvaluation ();
8354     }
8355
8356   tlbl = newiTempLabel (NULL);
8357   size = AOP_SIZE (result);
8358   offset = 0;
8359   tlbl1 = newiTempLabel (NULL);
8360
8361   /* if it is only one byte then */
8362   if (size == 1)
8363     {
8364       symbol *tlbl1 = newiTempLabel (NULL);
8365
8366       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
8367       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
8368       emitcode ("", "!tlabeldef", tlbl->key + 100);
8369       emitcode ("add", "a,acc");
8370       emitcode ("", "!tlabeldef", tlbl1->key + 100);
8371       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
8372       aopPut (AOP (result), "a", 0);
8373       goto release;
8374     }
8375
8376   reAdjustPreg (AOP (result));
8377
8378   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
8379   emitcode ("", "!tlabeldef", tlbl->key + 100);
8380   MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
8381   emitcode ("add", "a,acc");
8382   aopPut (AOP (result), "a", offset++);
8383   _startLazyDPSEvaluation ();
8384   while (--size)
8385     {
8386       MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
8387       emitcode ("rlc", "a");
8388       aopPut (AOP (result), "a", offset++);
8389     }
8390   _endLazyDPSEvaluation ();
8391   reAdjustPreg (AOP (result));
8392
8393   emitcode ("", "!tlabeldef", tlbl1->key + 100);
8394   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
8395 release:
8396   freeAsmop (left, NULL, ic, TRUE);
8397   freeAsmop (result, NULL, ic, TRUE);
8398 }
8399
8400 #ifdef BETTER_LITERAL_SHIFT
8401 /*-----------------------------------------------------------------*/
8402 /* genrshOne - right shift a one byte quantity by known count      */
8403 /*-----------------------------------------------------------------*/
8404 static void
8405 genrshOne (operand * result, operand * left,
8406            int shCount, int sign)
8407 {
8408   D (emitcode (";", "genrshOne"););
8409   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
8410 }
8411 #endif
8412
8413 #ifdef BETTER_LITERAL_SHIFT
8414 /*-----------------------------------------------------------------*/
8415 /* genrshTwo - right shift two bytes by known amount != 0          */
8416 /*-----------------------------------------------------------------*/
8417 static void
8418 genrshTwo (operand * result, operand * left,
8419            int shCount, int sign)
8420 {
8421   D (emitcode (";", "genrshTwo"););
8422
8423   /* if shCount >= 8 */
8424   if (shCount >= 8)
8425     {
8426       shCount -= 8;
8427       _startLazyDPSEvaluation();
8428       if (shCount)
8429       {
8430         shiftR1Left2Result (left, MSB16, result, LSB,
8431                             shCount, sign);
8432       }                     
8433       else
8434       {
8435         movLeft2Result (left, MSB16, result, LSB, sign);
8436       }
8437       addSign (result, MSB16, sign);
8438       _endLazyDPSEvaluation();
8439     }
8440
8441   /*  1 <= shCount <= 7 */
8442   else
8443   {
8444     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
8445   }
8446 }
8447 #endif
8448
8449 #if 0
8450 //REMOVE ME!!!
8451 /*-----------------------------------------------------------------*/
8452 /* shiftRLong - shift right one long from left to result           */
8453 /* offl = LSB or MSB16                                             */
8454 /*-----------------------------------------------------------------*/
8455 static void
8456 shiftRLong (operand * left, int offl,
8457             operand * result, int sign)
8458 {
8459   int isSameRegs=sameRegs(AOP(left),AOP(result));
8460
8461   if (isSameRegs && offl>1) {
8462     // we are in big trouble, but this shouldn't happen
8463     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
8464   }
8465
8466   MOVA (aopGet (AOP (left), MSB32, FALSE, NULL));
8467   
8468   if (offl==MSB16) {
8469     // shift is > 8
8470     if (sign) {
8471       emitcode ("rlc", "a");
8472       emitcode ("subb", "a,acc");
8473       emitcode ("xch", "a,%s",
8474                 aopGet(AOP(left), MSB32, FALSE, DP2_RESULT_REG));
8475     } else {
8476       aopPut (AOP(result), zero, MSB32);
8477     }
8478   }
8479
8480   if (!sign) {
8481     emitcode ("clr", "c");
8482   } else {
8483     emitcode ("mov", "c,acc.7");
8484   }
8485
8486   emitcode ("rrc", "a");
8487
8488   if (isSameRegs && offl==MSB16) {
8489     emitcode ("xch",
8490               "a,%s",aopGet (AOP (left), MSB24, FALSE, DP2_RESULT_REG));
8491   } else {
8492     aopPut (AOP (result), "a", MSB32);
8493     MOVA (aopGet (AOP (left), MSB24, FALSE, NULL));
8494   }
8495
8496   emitcode ("rrc", "a");
8497   if (isSameRegs && offl==1) {
8498     emitcode ("xch", "a,%s",
8499               aopGet (AOP (left), MSB16, FALSE, DP2_RESULT_REG));
8500   } else {
8501     aopPut (AOP (result), "a", MSB24);
8502     MOVA (aopGet (AOP (left), MSB16, FALSE, NULL));
8503   }
8504   emitcode ("rrc", "a");
8505   aopPut (AOP (result), "a", MSB16 - offl);
8506
8507   if (offl == LSB)
8508     {
8509       MOVA (aopGet (AOP (left), LSB, FALSE, NULL));
8510       emitcode ("rrc", "a");
8511       aopPut (AOP (result), "a", LSB);
8512     }
8513 }
8514 #endif
8515
8516 #if 0
8517 //REMOVE ME!!!
8518 /*-----------------------------------------------------------------*/
8519 /* genrshFour - shift four byte by a known amount != 0             */
8520 /*-----------------------------------------------------------------*/
8521 static void
8522 genrshFour (operand * result, operand * left,
8523             int shCount, int sign)
8524 {
8525   D (emitcode (";", "genrshFour");
8526     );
8527
8528   /* if shifting more that 3 bytes */
8529   if (shCount >= 24)
8530     {
8531       shCount -= 24;
8532       if (shCount)
8533         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8534       else
8535         movLeft2Result (left, MSB32, result, LSB, sign);
8536       addSign (result, MSB16, sign);
8537     }
8538   else if (shCount >= 16)
8539     {
8540       shCount -= 16;
8541       if (shCount)
8542         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8543       else
8544         {
8545           movLeft2Result (left, MSB24, result, LSB, 0);
8546           movLeft2Result (left, MSB32, result, MSB16, sign);
8547         }
8548       addSign (result, MSB24, sign);
8549     }
8550   else if (shCount >= 8)
8551     {
8552       shCount -= 8;
8553       if (shCount == 1)
8554         shiftRLong (left, MSB16, result, sign);
8555       else if (shCount == 0)
8556         {
8557           movLeft2Result (left, MSB16, result, LSB, 0);
8558           movLeft2Result (left, MSB24, result, MSB16, 0);
8559           movLeft2Result (left, MSB32, result, MSB24, sign);
8560           addSign (result, MSB32, sign);
8561         }
8562       else
8563         {
8564           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8565           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8566           /* the last shift is signed */
8567           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8568           addSign (result, MSB32, sign);
8569         }
8570     }
8571   else
8572     {                           /* 1 <= shCount <= 7 */
8573       if (shCount <= 2)
8574         {
8575           shiftRLong (left, LSB, result, sign);
8576           if (shCount == 2)
8577             shiftRLong (result, LSB, result, sign);
8578         }
8579       else
8580         {
8581           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8582           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8583           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8584         }
8585     }
8586 }
8587 #endif
8588
8589 #ifdef BETTER_LITERAL_SHIFT
8590 /*-----------------------------------------------------------------*/
8591 /* genRightShiftLiteral - right shifting by known count            */
8592 /*-----------------------------------------------------------------*/
8593 static bool
8594 genRightShiftLiteral (operand * left,
8595                       operand * right,
8596                       operand * result,
8597                       iCode * ic,
8598                       int sign)
8599 {
8600   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8601   int size;
8602
8603   size = getSize (operandType (result));
8604
8605   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
8606
8607   /* We only handle certain easy cases so far. */
8608   if ((shCount != 0)
8609    && (shCount < (size * 8))
8610    && (size != 1)
8611    && (size != 2))
8612   {
8613       D(emitcode (";", "genRightShiftLiteral wimping out"););   
8614       return FALSE;
8615   }
8616
8617   freeAsmop (right, NULL, ic, TRUE);
8618
8619   aopOp (left, ic, FALSE, FALSE);
8620   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8621
8622 #if VIEW_SIZE
8623   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8624             AOP_SIZE (left));
8625 #endif
8626
8627   /* test the LEFT size !!! */
8628
8629   /* I suppose that the left size >= result size */
8630   if (shCount == 0)
8631   {
8632       size = getDataSize (result);
8633       _startLazyDPSEvaluation();
8634       while (size--)
8635       {
8636         movLeft2Result (left, size, result, size, 0);
8637       }
8638       _endLazyDPSEvaluation();
8639   }
8640   else if (shCount >= (size * 8))
8641     {
8642       if (sign)
8643       {
8644         /* get sign in acc.7 */
8645         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE, NULL));
8646       }
8647       addSign (result, LSB, sign);
8648     }
8649   else
8650     {
8651       switch (size)
8652         {
8653         case 1:
8654           genrshOne (result, left, shCount, sign);
8655           break;
8656
8657         case 2:
8658           genrshTwo (result, left, shCount, sign);
8659           break;
8660 #if 0
8661         case 4:
8662           genrshFour (result, left, shCount, sign);
8663           break;
8664 #endif    
8665         default:
8666           break;
8667         }
8668     }
8669   freeAsmop (left, NULL, ic, TRUE);
8670   freeAsmop (result, NULL, ic, TRUE);
8671   
8672   return TRUE;
8673 }
8674 #endif
8675
8676 /*-----------------------------------------------------------------*/
8677 /* genSignedRightShift - right shift of signed number              */
8678 /*-----------------------------------------------------------------*/
8679 static void
8680 genSignedRightShift (iCode * ic)
8681 {
8682   operand *right, *left, *result;
8683   int size, offset;
8684   char *l;
8685   symbol *tlbl, *tlbl1;
8686
8687   D (emitcode (";", "genSignedRightShift "););
8688
8689   /* we do it the hard way put the shift count in b
8690      and loop thru preserving the sign */
8691
8692   right = IC_RIGHT (ic);
8693   left = IC_LEFT (ic);
8694   result = IC_RESULT (ic);
8695
8696   aopOp (right, ic, FALSE, FALSE);
8697
8698 #ifdef BETTER_LITERAL_SHIFT
8699   if (AOP_TYPE (right) == AOP_LIT)
8700     {
8701       if (genRightShiftLiteral (left, right, result, ic, 1))
8702       {
8703         return;
8704       }
8705     }
8706 #endif
8707   /* shift count is unknown then we have to form
8708      a loop get the loop count in B : Note: we take
8709      only the lower order byte since shifting
8710      more that 32 bits make no sense anyway, ( the
8711      largest size of an object can be only 32 bits ) */
8712
8713   if (AOP_TYPE (right) == AOP_LIT)
8714   {
8715       /* Really should be handled by genRightShiftLiteral,
8716        * but since I'm too lazy to fix that today, at least we can make
8717        * some small improvement.
8718        */
8719        emitcode("mov", "b,#!constbyte",
8720                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
8721   }
8722   else
8723   {
8724         MOVB(aopGet (AOP (right), 0, FALSE, FALSE, "b"));
8725         emitcode ("inc", "b");
8726   }
8727   freeAsmop (right, NULL, ic, TRUE);
8728   aopOp (left, ic, FALSE, FALSE);
8729   aopOp (result, ic, FALSE, AOP_USESDPTR(left)); 
8730
8731   /* now move the left to the result if they are not the
8732      same */
8733   if (!sameRegs (AOP (left), AOP (result)) &&
8734       AOP_SIZE (result) > 1)
8735     {
8736
8737       size = AOP_SIZE (result);
8738       offset = 0;
8739       _startLazyDPSEvaluation ();
8740       while (size--)
8741         {
8742           l = aopGet (AOP (left), offset, FALSE, TRUE, NULL);
8743           if (*l == '@' && IS_AOP_PREG (result))
8744             {
8745
8746               emitcode ("mov", "a,%s", l);
8747               aopPut (AOP (result), "a", offset);
8748             }
8749           else
8750             aopPut (AOP (result), l, offset);
8751           offset++;
8752         }
8753       _endLazyDPSEvaluation ();
8754     }
8755
8756   /* mov the highest order bit to OVR */
8757   tlbl = newiTempLabel (NULL);
8758   tlbl1 = newiTempLabel (NULL);
8759
8760   size = AOP_SIZE (result);
8761   offset = size - 1;
8762   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
8763   emitcode ("rlc", "a");
8764   emitcode ("mov", "ov,c");
8765   /* if it is only one byte then */
8766   if (size == 1)
8767     {
8768       MOVA( aopGet (AOP (left), 0, FALSE, FALSE, NULL));
8769       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
8770       emitcode ("", "!tlabeldef", tlbl->key + 100);
8771       emitcode ("mov", "c,ov");
8772       emitcode ("rrc", "a");
8773       emitcode ("", "!tlabeldef", tlbl1->key + 100);
8774       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
8775       aopPut (AOP (result), "a", 0);
8776       goto release;
8777     }
8778
8779   reAdjustPreg (AOP (result));
8780   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
8781   emitcode ("", "!tlabeldef", tlbl->key + 100);
8782   emitcode ("mov", "c,ov");
8783   _startLazyDPSEvaluation ();
8784   while (size--)
8785     {
8786       MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
8787       emitcode ("rrc", "a");
8788       aopPut (AOP (result), "a", offset--);
8789     }
8790   _endLazyDPSEvaluation ();
8791   reAdjustPreg (AOP (result));
8792   emitcode ("", "!tlabeldef", tlbl1->key + 100);
8793   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
8794
8795 release:
8796   freeAsmop (left, NULL, ic, TRUE);
8797   freeAsmop (result, NULL, ic, TRUE);
8798 }
8799
8800 /*-----------------------------------------------------------------*/
8801 /* genRightShift - generate code for right shifting                */
8802 /*-----------------------------------------------------------------*/
8803 static void
8804 genRightShift (iCode * ic)
8805 {
8806   operand *right, *left, *result;
8807   sym_link *retype;
8808   int size, offset;
8809   char *l;
8810   symbol *tlbl, *tlbl1;
8811
8812   D (emitcode (";", "genRightShift "););
8813
8814   /* if signed then we do it the hard way preserve the
8815      sign bit moving it inwards */
8816   retype = getSpec (operandType (IC_RESULT (ic)));
8817
8818   if (!SPEC_USIGN (retype))
8819     {
8820       genSignedRightShift (ic);
8821       return;
8822     }
8823
8824   /* signed & unsigned types are treated the same : i.e. the
8825      signed is NOT propagated inwards : quoting from the
8826      ANSI - standard : "for E1 >> E2, is equivalent to division
8827      by 2**E2 if unsigned or if it has a non-negative value,
8828      otherwise the result is implementation defined ", MY definition
8829      is that the sign does not get propagated */
8830
8831   right = IC_RIGHT (ic);
8832   left = IC_LEFT (ic);
8833   result = IC_RESULT (ic);
8834
8835   aopOp (right, ic, FALSE, FALSE);
8836
8837 #ifdef BETTER_LITERAL_SHIFT
8838   /* if the shift count is known then do it
8839      as efficiently as possible */
8840   if (AOP_TYPE (right) == AOP_LIT)
8841     {
8842       if (genRightShiftLiteral (left, right, result, ic, 0))
8843       {
8844         return;
8845       }
8846     }
8847 #endif
8848
8849   /* shift count is unknown then we have to form
8850      a loop get the loop count in B : Note: we take
8851      only the lower order byte since shifting
8852      more that 32 bits make no sense anyway, ( the
8853      largest size of an object can be only 32 bits ) */
8854   
8855   if (AOP_TYPE (right) == AOP_LIT)
8856   {
8857       /* Really should be handled by genRightShiftLiteral,
8858        * but since I'm too lazy to fix that today, at least we can make
8859        * some small improvement.
8860        */
8861        emitcode("mov", "b,#!constbyte",
8862                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
8863   }
8864   else
8865   {
8866       MOVB(aopGet (AOP (right), 0, FALSE, FALSE, "b"));
8867       emitcode ("inc", "b");
8868   }
8869   freeAsmop (right, NULL, ic, TRUE);
8870   aopOp (left, ic, FALSE, FALSE);
8871   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8872
8873   /* now move the left to the result if they are not the
8874      same */
8875   if (!sameRegs (AOP (left), AOP (result)) &&
8876       AOP_SIZE (result) > 1)
8877     {
8878
8879       size = AOP_SIZE (result);
8880       offset = 0;
8881       _startLazyDPSEvaluation ();
8882       while (size--)
8883         {
8884           l = aopGet (AOP (left), offset, FALSE, TRUE, NULL);
8885           if (*l == '@' && IS_AOP_PREG (result))
8886             {
8887
8888               emitcode ("mov", "a,%s", l);
8889               aopPut (AOP (result), "a", offset);
8890             }
8891           else
8892             aopPut (AOP (result), l, offset);
8893           offset++;
8894         }
8895       _endLazyDPSEvaluation ();
8896     }
8897
8898   tlbl = newiTempLabel (NULL);
8899   tlbl1 = newiTempLabel (NULL);
8900   size = AOP_SIZE (result);
8901   offset = size - 1;
8902
8903   /* if it is only one byte then */
8904   if (size == 1)
8905     {
8906       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
8907       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
8908       emitcode ("", "!tlabeldef", tlbl->key + 100);
8909       CLRC;
8910       emitcode ("rrc", "a");
8911       emitcode ("", "!tlabeldef", tlbl1->key + 100);
8912       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
8913       aopPut (AOP (result), "a", 0);
8914       goto release;
8915     }
8916
8917   reAdjustPreg (AOP (result));
8918   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
8919   emitcode ("", "!tlabeldef", tlbl->key + 100);
8920   CLRC;
8921   _startLazyDPSEvaluation ();
8922   while (size--)
8923     {
8924       MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
8925       emitcode ("rrc", "a");
8926       aopPut (AOP (result), "a", offset--);
8927     }
8928   _endLazyDPSEvaluation ();
8929   reAdjustPreg (AOP (result));
8930
8931   emitcode ("", "!tlabeldef", tlbl1->key + 100);
8932   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
8933
8934 release:
8935   freeAsmop (left, NULL, ic, TRUE);
8936   freeAsmop (result, NULL, ic, TRUE);
8937 }
8938
8939 /*-----------------------------------------------------------------*/
8940 /* genUnpackBits - generates code for unpacking bits               */
8941 /*-----------------------------------------------------------------*/
8942 static void
8943 genUnpackBits (operand * result, char *rname, int ptype)
8944 {
8945   int shCnt;
8946   int rlen;
8947   sym_link *etype;
8948   int offset = 0;
8949
8950   D (emitcode (";", "genUnpackBits "););
8951
8952   etype = getSpec (operandType (result));
8953
8954   /* read the first byte  */
8955   switch (ptype)
8956     {
8957
8958     case POINTER:
8959     case IPOINTER:
8960       emitcode ("mov", "a,@%s", rname);
8961       break;
8962
8963     case PPOINTER:
8964       emitcode ("movx", "a,@%s", rname);
8965       break;
8966
8967     case FPOINTER:
8968       emitcode ("movx", "a,@dptr");
8969       break;
8970
8971     case CPOINTER:
8972       emitcode ("clr", "a");
8973       emitcode ("movc", "a,@a+dptr");
8974       break;
8975
8976     case GPOINTER:
8977       emitcode ("lcall", "__gptrget");
8978       break;
8979     }
8980
8981   /* if we have bitdisplacement then it fits   */
8982   /* into this byte completely or if length is */
8983   /* less than a byte                          */
8984   if (((shCnt = SPEC_BSTR (etype)) != 0) || (SPEC_BLEN (etype) <= 8))
8985     {
8986
8987       /* shift right acc */
8988       AccRsh (shCnt);
8989
8990       emitcode ("anl", "a,#!constbyte",
8991                 ((unsigned char) -1) >> (8 - SPEC_BLEN (etype)));
8992       aopPut (AOP (result), "a", offset);
8993       return;
8994     }
8995
8996   /* bit field did not fit in a byte  */
8997   rlen = SPEC_BLEN (etype) - 8;
8998   aopPut (AOP (result), "a", offset++);
8999
9000   while (1)
9001     {
9002
9003       switch (ptype)
9004         {
9005         case POINTER:
9006         case IPOINTER:
9007           emitcode ("inc", "%s", rname);
9008           emitcode ("mov", "a,@%s", rname);
9009           break;
9010
9011         case PPOINTER:
9012           emitcode ("inc", "%s", rname);
9013           emitcode ("movx", "a,@%s", rname);
9014           break;
9015
9016         case FPOINTER:
9017           emitcode ("inc", "dptr");
9018           emitcode ("movx", "a,@dptr");
9019           break;
9020
9021         case CPOINTER:
9022           emitcode ("clr", "a");
9023           emitcode ("inc", "dptr");
9024           emitcode ("movc", "a,@a+dptr");
9025           break;
9026
9027         case GPOINTER:
9028           emitcode ("inc", "dptr");
9029           emitcode ("lcall", "__gptrget");
9030           break;
9031         }
9032
9033       rlen -= 8;
9034       /* if we are done */
9035       if (rlen < 8)
9036         break;
9037
9038       aopPut (AOP (result), "a", offset++);
9039
9040     }
9041
9042   if (rlen)
9043     {
9044       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (rlen));
9045       aopPut (AOP (result), "a", offset);
9046     }
9047
9048   return;
9049 }
9050
9051
9052 /*-----------------------------------------------------------------*/
9053 /* genDataPointerGet - generates code when ptr offset is known     */
9054 /*-----------------------------------------------------------------*/
9055 static void
9056 genDataPointerGet (operand * left,
9057                    operand * result,
9058                    iCode * ic)
9059 {
9060   char *l;
9061   char buff[256];
9062   int size, offset = 0;
9063   aopOp (result, ic, TRUE, FALSE);
9064
9065   /* get the string representation of the name */
9066   l = aopGet (AOP (left), 0, FALSE, TRUE, NULL);
9067   size = AOP_SIZE (result);
9068   _startLazyDPSEvaluation ();
9069   while (size--)
9070     {
9071         if (offset)
9072         {
9073             SNPRINTF (buff, sizeof(buff), 
9074                       "(%s + %d)", l + 1, offset);
9075         }
9076         else
9077         {
9078             SNPRINTF (buff, sizeof(buff), 
9079                       "%s", l + 1);
9080         }
9081       aopPut (AOP (result), buff, offset++);
9082     }
9083   _endLazyDPSEvaluation ();
9084
9085   freeAsmop (left, NULL, ic, TRUE);
9086   freeAsmop (result, NULL, ic, TRUE);
9087 }
9088
9089 /*-----------------------------------------------------------------*/
9090 /* genNearPointerGet - emitcode for near pointer fetch             */
9091 /*-----------------------------------------------------------------*/
9092 static void
9093 genNearPointerGet (operand * left,
9094                    operand * result,
9095                    iCode * ic,
9096                    iCode *pi)
9097 {
9098   asmop *aop = NULL;
9099   regs *preg;
9100   char *rname;
9101   sym_link *rtype, *retype, *letype;
9102   sym_link *ltype = operandType (left);
9103   char buff[80];
9104
9105   rtype = operandType (result);
9106   retype = getSpec (rtype);
9107   letype = getSpec (ltype);
9108
9109   aopOp (left, ic, FALSE, FALSE);
9110
9111   /* if left is rematerialisable and
9112      result is not bit variable type and
9113      the left is pointer to data space i.e
9114      lower 128 bytes of space */
9115   if (AOP_TYPE (left) == AOP_IMMD &&
9116       !IS_BITVAR (retype) &&
9117       !IS_BITVAR (letype) &&
9118       DCL_TYPE (ltype) == POINTER)
9119     {
9120       genDataPointerGet (left, result, ic);
9121       return;
9122     }
9123
9124   /* if the value is already in a pointer register
9125      then don't need anything more */
9126   if (!AOP_INPREG (AOP (left)))
9127     {
9128       /* otherwise get a free pointer register */
9129       aop = newAsmop (0);
9130       preg = getFreePtr (ic, &aop, FALSE);
9131       emitcode ("mov", "%s,%s",
9132                 preg->name,
9133                 aopGet (AOP (left), 0, FALSE, TRUE, DP2_RESULT_REG));
9134       rname = preg->name;
9135     }
9136   else
9137     rname = aopGet (AOP (left), 0, FALSE, FALSE, DP2_RESULT_REG);
9138
9139   freeAsmop (left, NULL, ic, TRUE);
9140   aopOp (result, ic, FALSE, FALSE);
9141
9142   /* if bitfield then unpack the bits */
9143   if (IS_BITVAR (retype) || IS_BITVAR (letype))
9144     genUnpackBits (result, rname, POINTER);
9145   else
9146     {
9147       /* we have can just get the values */
9148       int size = AOP_SIZE (result);
9149       int offset = 0;
9150
9151       while (size--)
9152         {
9153           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9154             {
9155
9156               emitcode ("mov", "a,@%s", rname);
9157               aopPut (AOP (result), "a", offset);
9158             }
9159           else
9160             {
9161               SNPRINTF (buff, sizeof(buff), "@%s", rname);
9162               aopPut (AOP (result), buff, offset);
9163             }
9164           offset++;
9165           if (size || pi)
9166             {
9167                 emitcode ("inc", "%s", rname);
9168             }
9169         }
9170     }
9171
9172   /* now some housekeeping stuff */
9173   if (aop)
9174     {
9175       /* we had to allocate for this iCode */
9176       if (pi) { /* post increment present */
9177         aopPut(AOP ( left ),rname,0);
9178       }
9179       freeAsmop (NULL, aop, ic, TRUE);
9180     }
9181   else
9182     {
9183       /* we did not allocate which means left
9184          already in a pointer register, then
9185          if size > 0 && this could be used again
9186          we have to point it back to where it
9187          belongs */
9188       if (AOP_SIZE (result) > 1 &&
9189           !OP_SYMBOL (left)->remat &&
9190           (OP_SYMBOL (left)->liveTo > ic->seq ||
9191            ic->depth) &&
9192           !pi)
9193         {
9194           int size = AOP_SIZE (result) - 1;
9195           while (size--)
9196             emitcode ("dec", "%s", rname);
9197         }
9198     }
9199
9200   /* done */
9201   freeAsmop (result, NULL, ic, TRUE);
9202   if (pi) pi->generated = 1;
9203 }
9204
9205 /*-----------------------------------------------------------------*/
9206 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9207 /*-----------------------------------------------------------------*/
9208 static void
9209 genPagedPointerGet (operand * left,
9210                     operand * result,
9211                     iCode * ic,
9212                     iCode * pi)
9213 {
9214   asmop *aop = NULL;
9215   regs *preg;
9216   char *rname;
9217   sym_link *rtype, *retype, *letype;
9218
9219   rtype = operandType (result);
9220   retype = getSpec (rtype);
9221   letype = getSpec (operandType (left));
9222   aopOp (left, ic, FALSE, FALSE);
9223
9224   /* if the value is already in a pointer register
9225      then don't need anything more */
9226   if (!AOP_INPREG (AOP (left)))
9227     {
9228       /* otherwise get a free pointer register */
9229       aop = newAsmop (0);
9230       preg = getFreePtr (ic, &aop, FALSE);
9231       emitcode ("mov", "%s,%s",
9232                 preg->name,
9233                 aopGet (AOP (left), 0, FALSE, TRUE, NULL));
9234       rname = preg->name;
9235     }
9236   else
9237     rname = aopGet (AOP (left), 0, FALSE, FALSE, NULL);
9238
9239   freeAsmop (left, NULL, ic, TRUE);
9240   aopOp (result, ic, FALSE, FALSE);
9241
9242   /* if bitfield then unpack the bits */
9243   if (IS_BITVAR (retype) || IS_BITVAR (letype))
9244     genUnpackBits (result, rname, PPOINTER);
9245   else
9246     {
9247       /* we have can just get the values */
9248       int size = AOP_SIZE (result);
9249       int offset = 0;
9250
9251       while (size--)
9252         {
9253
9254           emitcode ("movx", "a,@%s", rname);
9255           aopPut (AOP (result), "a", offset);
9256
9257           offset++;
9258
9259           if (size || pi)
9260             emitcode ("inc", "%s", rname);
9261         }
9262     }
9263
9264   /* now some housekeeping stuff */
9265   if (aop)
9266     {
9267       /* we had to allocate for this iCode */
9268       if (pi) aopPut ( AOP (left), rname, 0);
9269       freeAsmop (NULL, aop, ic, TRUE);
9270     }
9271   else
9272     {
9273       /* we did not allocate which means left
9274          already in a pointer register, then
9275          if size > 0 && this could be used again
9276          we have to point it back to where it
9277          belongs */
9278       if (AOP_SIZE (result) > 1 &&
9279           !OP_SYMBOL (left)->remat &&
9280           (OP_SYMBOL (left)->liveTo > ic->seq ||
9281            ic->depth) &&
9282           !pi)
9283         {
9284           int size = AOP_SIZE (result) - 1;
9285           while (size--)
9286             emitcode ("dec", "%s", rname);
9287         }
9288     }
9289
9290   /* done */
9291   freeAsmop (result, NULL, ic, TRUE);
9292   if (pi) pi->generated = 1;
9293 }
9294
9295 /*-----------------------------------------------------------------*/
9296 /* genFarPointerGet - gget value from far space                    */
9297 /*-----------------------------------------------------------------*/
9298 static void
9299 genFarPointerGet (operand * left,
9300                   operand * result, iCode * ic, iCode *pi)
9301 {
9302     int size, offset, dopi=1;
9303   sym_link *retype = getSpec (operandType (result));
9304   sym_link *letype = getSpec (operandType (left));
9305   D (emitcode (";", "genFarPointerGet"););
9306
9307   aopOp (left, ic, FALSE, FALSE);
9308
9309   /* if the operand is already in dptr
9310      then we do nothing else we move the value to dptr */
9311   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
9312     {
9313       /* if this is remateriazable */
9314       if (AOP_TYPE (left) == AOP_IMMD)
9315         {
9316           emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, NULL));
9317         }
9318       else
9319         {
9320           /* we need to get it byte by byte */
9321           _startLazyDPSEvaluation ();
9322           if (AOP_TYPE (left) != AOP_DPTR)
9323             {
9324               emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
9325               emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, NULL));
9326               if (options.model == MODEL_FLAT24)
9327                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
9328             }
9329           else
9330             {
9331               /* We need to generate a load to DPTR indirect through DPTR. */
9332               D (emitcode (";", "genFarPointerGet -- indirection special case."););
9333               emitcode ("push", "%s", aopGet (AOP (left), 0, FALSE, TRUE, NULL));
9334               emitcode ("push", "%s", aopGet (AOP (left), 1, FALSE, TRUE, NULL));
9335               if (options.model == MODEL_FLAT24)
9336                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
9337               emitcode ("pop", "dph");
9338               emitcode ("pop", "dpl");
9339               dopi =0;
9340             }
9341           _endLazyDPSEvaluation ();
9342         }
9343     }
9344   /* so dptr know contains the address */
9345   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
9346
9347   /* if bit then unpack */
9348   if (IS_BITVAR (retype) || IS_BITVAR (letype)) {
9349       if (AOP_INDPTRn(left)) {
9350           genSetDPTR(AOP(left)->aopu.dptr);
9351       }
9352       genUnpackBits (result, "dptr", FPOINTER);
9353       if (AOP_INDPTRn(left)) {
9354           genSetDPTR(0);
9355       }
9356   } else
9357     {
9358       size = AOP_SIZE (result);
9359       offset = 0;
9360
9361       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
9362           while (size--) {
9363               genSetDPTR(AOP(left)->aopu.dptr);
9364               emitcode ("movx", "a,@dptr");
9365               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
9366                   emitcode ("inc", "dptr");
9367               genSetDPTR (0);
9368               aopPut (AOP (result), "a", offset++);
9369           }
9370       } else {
9371           _startLazyDPSEvaluation ();
9372           while (size--) {
9373               if (AOP_INDPTRn(left)) {
9374                   genSetDPTR(AOP(left)->aopu.dptr);
9375               } else {
9376                   genSetDPTR (0);
9377               }
9378               _flushLazyDPS ();
9379               
9380               emitcode ("movx", "a,@dptr");
9381               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
9382                   emitcode ("inc", "dptr");
9383               
9384               aopPut (AOP (result), "a", offset++);
9385           }
9386           _endLazyDPSEvaluation ();
9387       }
9388     }
9389   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
9390       if (!AOP_INDPTRn(left)) {
9391           _startLazyDPSEvaluation ();
9392           aopPut ( AOP (left), "dpl", 0);
9393           aopPut ( AOP (left), "dph", 1);
9394           if (options.model == MODEL_FLAT24)
9395               aopPut ( AOP (left), "dpx", 2);
9396           _endLazyDPSEvaluation ();
9397       }
9398     pi->generated = 1;
9399   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) && 
9400              AOP_SIZE(result) > 1 &&
9401              IS_SYMOP(left) &&
9402              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
9403       
9404       size = AOP_SIZE (result) - 1;
9405       if (AOP_INDPTRn(left)) {
9406           genSetDPTR(AOP(left)->aopu.dptr);
9407       }
9408       while (size--) emitcode ("lcall","__decdptr");
9409       if (AOP_INDPTRn(left)) {
9410           genSetDPTR(0);
9411       }
9412   }
9413
9414   freeAsmop (left, NULL, ic, TRUE);
9415   freeAsmop (result, NULL, ic, TRUE);
9416 }
9417
9418 /*-----------------------------------------------------------------*/
9419 /* genCodePointerGet - get value from code space                  */
9420 /*-----------------------------------------------------------------*/
9421 static void
9422 genCodePointerGet (operand * left,
9423                     operand * result, iCode * ic, iCode *pi)
9424 {
9425   int size, offset, dopi=1;
9426   sym_link *retype = getSpec (operandType (result));
9427
9428   aopOp (left, ic, FALSE, FALSE);
9429
9430   /* if the operand is already in dptr
9431      then we do nothing else we move the value to dptr */
9432   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
9433     {
9434       /* if this is remateriazable */
9435       if (AOP_TYPE (left) == AOP_IMMD)
9436         {
9437           emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, NULL));
9438         }
9439       else
9440         {                       /* we need to get it byte by byte */
9441           _startLazyDPSEvaluation ();
9442           if (AOP_TYPE (left) != AOP_DPTR)
9443             {
9444               emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
9445               emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, NULL));
9446               if (options.model == MODEL_FLAT24)
9447                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
9448             }
9449           else
9450             {
9451               /* We need to generate a load to DPTR indirect through DPTR. */
9452               D (emitcode (";", "gencodePointerGet -- indirection special case."););
9453               emitcode ("push", "%s", aopGet (AOP (left), 0, FALSE, TRUE, NULL));
9454               emitcode ("push", "%s", aopGet (AOP (left), 1, FALSE, TRUE, NULL));
9455               if (options.model == MODEL_FLAT24)
9456                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
9457               emitcode ("pop", "dph");
9458               emitcode ("pop", "dpl");
9459               dopi=0;
9460             }
9461           _endLazyDPSEvaluation ();
9462         }
9463     }
9464   /* so dptr know contains the address */
9465   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
9466
9467   /* if bit then unpack */
9468   if (IS_BITVAR (retype)) {
9469       if (AOP_INDPTRn(left)) {
9470           genSetDPTR(AOP(left)->aopu.dptr);
9471       }
9472       genUnpackBits (result, "dptr", CPOINTER);
9473       if (AOP_INDPTRn(left)) {
9474           genSetDPTR(0);
9475       }
9476   } else
9477     {
9478       size = AOP_SIZE (result);
9479       offset = 0;
9480       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
9481           while (size--) {
9482               genSetDPTR(AOP(left)->aopu.dptr);
9483               emitcode ("clr", "a");
9484               emitcode ("movc", "a,@a+dptr");
9485               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
9486                   emitcode ("inc", "dptr");
9487               genSetDPTR (0);
9488               aopPut (AOP (result), "a", offset++);
9489           }
9490       } else {
9491           _startLazyDPSEvaluation ();
9492           while (size--)
9493               {
9494                   if (AOP_INDPTRn(left)) {
9495                       genSetDPTR(AOP(left)->aopu.dptr);
9496                   } else {
9497                       genSetDPTR (0);
9498                   }
9499                   _flushLazyDPS ();
9500                   
9501                   emitcode ("clr", "a");
9502                   emitcode ("movc", "a,@a+dptr");
9503                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
9504                       emitcode ("inc", "dptr");
9505                   aopPut (AOP (result), "a", offset++);
9506               }
9507           _endLazyDPSEvaluation ();
9508       }
9509     }
9510   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
9511       if (!AOP_INDPTRn(left)) {
9512           _startLazyDPSEvaluation ();
9513           
9514           aopPut ( AOP (left), "dpl", 0);
9515           aopPut ( AOP (left), "dph", 1);
9516           if (options.model == MODEL_FLAT24)
9517               aopPut ( AOP (left), "dpx", 2);
9518
9519           _endLazyDPSEvaluation ();
9520       }
9521       pi->generated = 1;
9522   } else if ((OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) && 
9523              AOP_SIZE(result) > 1 &&
9524              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
9525       
9526       size = AOP_SIZE (result) - 1;
9527       if (AOP_INDPTRn(left)) {
9528           genSetDPTR(AOP(left)->aopu.dptr);
9529       }
9530       while (size--) emitcode ("lcall","__decdptr");
9531       if (AOP_INDPTRn(left)) {
9532           genSetDPTR(0);
9533       }
9534   }
9535   
9536   freeAsmop (left, NULL, ic, TRUE);
9537   freeAsmop (result, NULL, ic, TRUE);
9538 }
9539
9540 /*-----------------------------------------------------------------*/
9541 /* genGenPointerGet - gget value from generic pointer space        */
9542 /*-----------------------------------------------------------------*/
9543 static void
9544 genGenPointerGet (operand * left,
9545                   operand * result, iCode * ic, iCode * pi)
9546 {
9547   int size, offset;
9548   sym_link *retype = getSpec (operandType (result));
9549   sym_link *letype = getSpec (operandType (left));
9550
9551   D (emitcode (";", "genGenPointerGet "); );
9552
9553   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
9554
9555   /* if the operand is already in dptr
9556      then we do nothing else we move the value to dptr */
9557   if (AOP_TYPE (left) != AOP_STR)
9558     {
9559       /* if this is remateriazable */
9560       if (AOP_TYPE (left) == AOP_IMMD)
9561         {
9562           emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, NULL));
9563           if (AOP(left)->aopu.aop_immd.from_cast_remat) 
9564             {
9565                 MOVB(aopGet(AOP (left), AOP_SIZE(left)-1, FALSE, FALSE, NULL));
9566             }
9567             else
9568             {
9569                 emitcode ("mov", "b,#%d", pointerCode (retype));
9570             }
9571         }
9572       else
9573         {                       /* we need to get it byte by byte */
9574             _startLazyDPSEvaluation ();
9575             emitcode ("mov", "dpl,%s", aopGet (AOP(left),0,FALSE,FALSE,NULL));
9576             emitcode ("mov", "dph,%s", aopGet (AOP(left),1,FALSE,FALSE,NULL));
9577             if (options.model == MODEL_FLAT24) {
9578                 emitcode ("mov", "dpx,%s", aopGet (AOP(left),2,FALSE,FALSE,NULL));
9579                 emitcode ("mov", "b,%s", aopGet (AOP(left),3,FALSE,FALSE,NULL));
9580             } else {
9581                 emitcode ("mov", "b,%s", aopGet (AOP(left),2,FALSE,FALSE,NULL));
9582             }
9583             _endLazyDPSEvaluation ();
9584         }
9585     }
9586
9587   /* so dptr-b now contains the address */
9588   _G.bInUse++;
9589   aopOp (result, ic, FALSE, TRUE);
9590   _G.bInUse--;
9591
9592   /* if bit then unpack */
9593   if (IS_BITVAR (retype) || IS_BITVAR (letype))
9594   {
9595     genUnpackBits (result, "dptr", GPOINTER);
9596   }
9597   else
9598     {
9599         size = AOP_SIZE (result);
9600         offset = 0;
9601
9602         while (size--)
9603         {
9604             if (size)
9605             {
9606                 // Get two bytes at a time, results in _AP & A.
9607                 // dptr will be incremented ONCE by __gptrgetWord.
9608                 //
9609                 // Note: any change here must be coordinated
9610                 // with the implementation of __gptrgetWord
9611                 // in device/lib/_gptrget.c
9612                 emitcode ("lcall", "__gptrgetWord");
9613                 aopPut (AOP (result), DP2_RESULT_REG, offset++);
9614                 aopPut (AOP (result), "a", offset++);
9615                 size--;
9616             }
9617             else
9618             {
9619                 // Only one byte to get.
9620                 emitcode ("lcall", "__gptrget");
9621                 aopPut (AOP (result), "a", offset++);
9622             }
9623             
9624             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
9625             {
9626                 emitcode ("inc", "dptr");
9627             }
9628         }
9629     }
9630
9631   if (pi && AOP_TYPE (left) != AOP_IMMD) {
9632     _startLazyDPSEvaluation ();
9633       
9634     aopPut ( AOP (left), "dpl", 0);
9635     aopPut ( AOP (left), "dph", 1);
9636     if (options.model == MODEL_FLAT24) {
9637         aopPut ( AOP (left), "dpx", 2);
9638         aopPut ( AOP (left), "b", 3);   
9639     } else  aopPut ( AOP (left), "b", 2);       
9640     
9641     _endLazyDPSEvaluation ();
9642       
9643     pi->generated = 1;
9644   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
9645              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
9646       
9647       size = AOP_SIZE (result) - 1;
9648       while (size--) emitcode ("lcall","__decdptr");
9649   }
9650
9651   freeAsmop (left, NULL, ic, TRUE);
9652   freeAsmop (result, NULL, ic, TRUE);
9653 }
9654
9655 /*-----------------------------------------------------------------*/
9656 /* genPointerGet - generate code for pointer get                   */
9657 /*-----------------------------------------------------------------*/
9658 static void
9659 genPointerGet (iCode * ic, iCode *pi)
9660 {
9661   operand *left, *result;
9662   sym_link *type, *etype;
9663   int p_type;
9664
9665   D (emitcode (";", "genPointerGet ");
9666     );
9667
9668   left = IC_LEFT (ic);
9669   result = IC_RESULT (ic);
9670
9671   /* depending on the type of pointer we need to
9672      move it to the correct pointer register */
9673   type = operandType (left);
9674   etype = getSpec (type);
9675   /* if left is of type of pointer then it is simple */
9676   if (IS_PTR (type) && !IS_FUNC (type->next))
9677     p_type = DCL_TYPE (type);
9678   else
9679     {
9680       /* we have to go by the storage class */
9681       p_type = PTR_TYPE (SPEC_OCLS (etype));
9682     }
9683   /* special case when cast remat */
9684   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9685       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9686           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9687           type = operandType (left);
9688           p_type = DCL_TYPE (type);
9689   }
9690   /* now that we have the pointer type we assign
9691      the pointer values */
9692   switch (p_type)
9693     {
9694
9695     case POINTER:
9696     case IPOINTER:
9697       genNearPointerGet (left, result, ic, pi);
9698       break;
9699
9700     case PPOINTER:
9701       genPagedPointerGet (left, result, ic, pi);
9702       break;
9703
9704     case FPOINTER:
9705       genFarPointerGet (left, result, ic, pi);
9706       break;
9707
9708     case CPOINTER:
9709       genCodePointerGet (left, result, ic, pi);
9710       break;
9711
9712     case GPOINTER:
9713       genGenPointerGet (left, result, ic, pi);
9714       break;
9715     }
9716
9717 }
9718
9719 /*-----------------------------------------------------------------*/
9720 /* genPackBits - generates code for packed bit storage             */
9721 /*-----------------------------------------------------------------*/
9722 static void
9723 genPackBits (sym_link * etype,
9724              operand * right,
9725              char *rname, int p_type)
9726 {
9727   int offset = 0;
9728   int rLen;
9729   int blen, bstr;
9730   char *l;
9731
9732   blen = SPEC_BLEN (etype);
9733   bstr = SPEC_BSTR (etype);
9734
9735   MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
9736
9737   /* if the bit lenth is less than or    */
9738   /* it exactly fits a byte then         */
9739   if (SPEC_BLEN (etype) <= 8)
9740     {
9741       /* shift left acc */
9742       AccLsh (SPEC_BSTR (etype));
9743
9744       if (SPEC_BLEN (etype) < 8)
9745         {                       /* if smaller than a byte */
9746
9747
9748           switch (p_type)
9749             {
9750             case POINTER:
9751               emitcode ("mov", "b,a");
9752               emitcode ("mov", "a,@%s", rname);
9753               break;
9754
9755             case FPOINTER:
9756               emitcode ("mov", "b,a");
9757               emitcode ("movx", "a,@dptr");
9758               break;
9759
9760             case GPOINTER:
9761               emitcode ("push", "b");
9762               emitcode ("push", "acc");
9763               emitcode ("lcall", "__gptrget");
9764               emitcode ("pop", "b");
9765               break;
9766             }
9767
9768           emitcode ("anl", "a,#!constbyte", (unsigned char)
9769                     ((unsigned char) (0xFF << (blen + bstr)) |
9770                      (unsigned char) (0xFF >> (8 - bstr))));
9771           emitcode ("orl", "a,b");
9772           if (p_type == GPOINTER)
9773             emitcode ("pop", "b");
9774         }
9775     }
9776
9777   switch (p_type)
9778     {
9779     case POINTER:
9780       emitcode ("mov", "@%s,a", rname);
9781       break;
9782
9783     case FPOINTER:
9784       emitcode ("movx", "@dptr,a");
9785       break;
9786
9787     case GPOINTER:
9788       emitcode ("lcall", "__gptrput");
9789       break;
9790     }
9791
9792   /* if we r done */
9793   if (SPEC_BLEN (etype) <= 8)
9794     return;
9795
9796   emitcode ("inc", "%s", rname);
9797   rLen = SPEC_BLEN (etype);
9798
9799   /* now generate for lengths greater than one byte */
9800   while (1)
9801     {
9802
9803       l = aopGet (AOP (right), offset++, FALSE, TRUE, NULL);
9804
9805       rLen -= 8;
9806       if (rLen < 8)
9807         break;
9808
9809       switch (p_type)
9810         {
9811         case POINTER:
9812           if (*l == '@')
9813             {
9814               MOVA (l);
9815               emitcode ("mov", "@%s,a", rname);
9816             }
9817           else
9818             emitcode ("mov", "@%s,%s", rname, l);
9819           break;
9820
9821         case FPOINTER:
9822           MOVA (l);
9823           emitcode ("movx", "@dptr,a");
9824           break;
9825
9826         case GPOINTER:
9827           MOVA (l);
9828           emitcode ("lcall", "__gptrput");
9829           break;
9830         }
9831       emitcode ("inc", "%s", rname);
9832     }
9833
9834   MOVA (l);
9835
9836   /* last last was not complete */
9837   if (rLen)
9838     {
9839       /* save the byte & read byte */
9840       switch (p_type)
9841         {
9842         case POINTER:
9843           emitcode ("mov", "b,a");
9844           emitcode ("mov", "a,@%s", rname);
9845           break;
9846
9847         case FPOINTER:
9848           emitcode ("mov", "b,a");
9849           emitcode ("movx", "a,@dptr");
9850           break;
9851
9852         case GPOINTER:
9853           emitcode ("push", "b");
9854           emitcode ("push", "acc");
9855           emitcode ("lcall", "__gptrget");
9856           emitcode ("pop", "b");
9857           break;
9858         }
9859
9860       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1 << rLen));
9861       emitcode ("orl", "a,b");
9862     }
9863
9864   if (p_type == GPOINTER)
9865     emitcode ("pop", "b");
9866
9867   switch (p_type)
9868     {
9869
9870     case POINTER:
9871       emitcode ("mov", "@%s,a", rname);
9872       break;
9873
9874     case FPOINTER:
9875       emitcode ("movx", "@dptr,a");
9876       break;
9877
9878     case GPOINTER:
9879       emitcode ("lcall", "__gptrput");
9880       break;
9881     }
9882 }
9883 /*-----------------------------------------------------------------*/
9884 /* genDataPointerSet - remat pointer to data space                 */
9885 /*-----------------------------------------------------------------*/
9886 static void
9887 genDataPointerSet (operand * right,
9888                    operand * result,
9889                    iCode * ic)
9890 {
9891   int size, offset = 0;
9892   char *l, buff[256];
9893
9894   aopOp (right, ic, FALSE, FALSE);
9895
9896   l = aopGet (AOP (result), 0, FALSE, TRUE, NULL);
9897   size = AOP_SIZE (right);
9898   while (size--)
9899     {
9900       if (offset)
9901         {
9902             SNPRINTF (buff, sizeof(buff), "(%s + %d)", l + 1, offset);
9903         }
9904       else
9905         {
9906             SNPRINTF (buff, sizeof(buff), "%s", l + 1);
9907         }
9908         
9909       emitcode ("mov", "%s,%s", buff,
9910                 aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
9911     }
9912
9913   freeAsmop (right, NULL, ic, TRUE);
9914   freeAsmop (result, NULL, ic, TRUE);
9915 }
9916
9917 /*-----------------------------------------------------------------*/
9918 /* genNearPointerSet - emitcode for near pointer put                */
9919 /*-----------------------------------------------------------------*/
9920 static void
9921 genNearPointerSet (operand * right,
9922                    operand * result,
9923                    iCode * ic,
9924                    iCode * pi)
9925 {
9926   asmop *aop = NULL;
9927   char *rname, *l;
9928   sym_link *retype, *letype;
9929   sym_link *ptype = operandType (result);
9930
9931   retype = getSpec (operandType (right));
9932   letype = getSpec (ptype);
9933
9934   aopOp (result, ic, FALSE, FALSE);
9935
9936   /* if the result is rematerializable &
9937      in data space & not a bit variable */
9938   if (AOP_TYPE (result) == AOP_IMMD &&
9939       DCL_TYPE (ptype) == POINTER &&
9940       !IS_BITVAR (retype) &&
9941       !IS_BITVAR (letype))
9942     {
9943       genDataPointerSet (right, result, ic);
9944       return;
9945     }
9946
9947   /* if the value is already in a pointer register
9948      then don't need anything more */
9949   if (!AOP_INPREG (AOP (result)))
9950     {
9951       /* otherwise get a free pointer register */
9952       regs *preg;
9953         
9954       aop = newAsmop (0);
9955       preg = getFreePtr (ic, &aop, FALSE);
9956       emitcode ("mov", "%s,%s",
9957                 preg->name,
9958                 aopGet (AOP (result), 0, FALSE, TRUE, NULL));
9959       rname = preg->name;
9960     }
9961   else
9962     rname = aopGet (AOP (result), 0, FALSE, FALSE, NULL);
9963
9964   aopOp (right, ic, FALSE, FALSE);
9965
9966   /* if bitfield then unpack the bits */
9967   if (IS_BITVAR (retype) || IS_BITVAR (letype))
9968     genPackBits ((IS_BITVAR (retype) ? retype : letype), right, rname, POINTER);
9969   else
9970     {
9971       /* we have can just get the values */
9972       int size = AOP_SIZE (right);
9973       int offset = 0;
9974
9975       while (size--)
9976         {
9977           l = aopGet (AOP (right), offset, FALSE, TRUE, NULL);
9978           if (*l == '@')
9979             {
9980               MOVA (l);
9981               emitcode ("mov", "@%s,a", rname);
9982             }
9983           else
9984             emitcode ("mov", "@%s,%s", rname, l);
9985           if (size || pi)
9986             emitcode ("inc", "%s", rname);
9987           offset++;
9988         }
9989     }
9990
9991   /* now some housekeeping stuff */
9992   if (aop)
9993     {
9994       /* we had to allocate for this iCode */
9995       if (pi) aopPut (AOP (result),rname,0);
9996       freeAsmop (NULL, aop, ic, TRUE);
9997     }
9998   else
9999     {
10000       /* we did not allocate which means left
10001          already in a pointer register, then
10002          if size > 0 && this could be used again
10003          we have to point it back to where it
10004          belongs */
10005       if (AOP_SIZE (right) > 1 &&
10006           !OP_SYMBOL (result)->remat &&
10007           (OP_SYMBOL (result)->liveTo > ic->seq ||
10008            ic->depth) &&
10009           !pi)
10010         {
10011           int size = AOP_SIZE (right) - 1;
10012           while (size--)
10013             emitcode ("dec", "%s", rname);
10014         }
10015     }
10016
10017   /* done */
10018   if (pi) pi->generated = 1;
10019   freeAsmop (result, NULL, ic, TRUE);
10020   freeAsmop (right, NULL, ic, TRUE);
10021
10022
10023 }
10024
10025 /*-----------------------------------------------------------------*/
10026 /* genPagedPointerSet - emitcode for Paged pointer put             */
10027 /*-----------------------------------------------------------------*/
10028 static void
10029 genPagedPointerSet (operand * right,
10030                     operand * result,
10031                     iCode * ic,
10032                     iCode *pi)
10033 {
10034   asmop *aop = NULL;
10035   char *rname;
10036   sym_link *retype, *letype;
10037
10038   retype = getSpec (operandType (right));
10039   letype = getSpec (operandType (result));
10040
10041   aopOp (result, ic, FALSE, FALSE);
10042
10043   /* if the value is already in a pointer register
10044      then don't need anything more */
10045   if (!AOP_INPREG (AOP (result)))
10046     {
10047       /* otherwise get a free pointer register */
10048       regs *preg;
10049         
10050       aop = newAsmop (0);
10051       preg = getFreePtr (ic, &aop, FALSE);
10052       emitcode ("mov", "%s,%s",
10053                 preg->name,
10054                 aopGet (AOP (result), 0, FALSE, TRUE, NULL));
10055       rname = preg->name;
10056     }
10057   else
10058     rname = aopGet (AOP (result), 0, FALSE, FALSE, NULL);
10059
10060   aopOp (right, ic, FALSE, FALSE);
10061
10062   /* if bitfield then unpack the bits */
10063   if (IS_BITVAR (retype) || IS_BITVAR (letype))
10064     genPackBits ((IS_BITVAR (retype) ? retype : letype), right, rname, PPOINTER);
10065   else
10066     {
10067       /* we have can just get the values */
10068       int size = AOP_SIZE (right);
10069       int offset = 0;
10070
10071       while (size--)
10072         {
10073           MOVA (aopGet (AOP (right), offset, FALSE, TRUE, NULL));
10074
10075           emitcode ("movx", "@%s,a", rname);
10076
10077           if (size || pi)
10078             emitcode ("inc", "%s", rname);
10079
10080           offset++;
10081         }
10082     }
10083
10084   /* now some housekeeping stuff */
10085   if (aop)
10086     {
10087       if (pi) aopPut (AOP (result),rname,0);
10088       /* we had to allocate for this iCode */
10089       freeAsmop (NULL, aop, ic, TRUE);
10090     }
10091   else
10092     {
10093       /* we did not allocate which means left
10094          already in a pointer register, then
10095          if size > 0 && this could be used again
10096          we have to point it back to where it
10097          belongs */
10098       if (AOP_SIZE (right) > 1 &&
10099           !OP_SYMBOL (result)->remat &&
10100           (OP_SYMBOL (result)->liveTo > ic->seq ||
10101            ic->depth) &&
10102           !pi)
10103         {
10104           int size = AOP_SIZE (right) - 1;
10105           while (size--)
10106             emitcode ("dec", "%s", rname);
10107         }
10108     }
10109
10110   /* done */
10111   if (pi) pi->generated = 1;
10112   freeAsmop (result, NULL, ic, TRUE);
10113   freeAsmop (right, NULL, ic, TRUE);
10114
10115
10116 }
10117
10118 /*-----------------------------------------------------------------*/
10119 /* genFarPointerSet - set value from far space                     */
10120 /*-----------------------------------------------------------------*/
10121 static void
10122 genFarPointerSet (operand * right,
10123                   operand * result, iCode * ic, iCode *pi)
10124 {
10125   int size, offset, dopi=1;
10126   sym_link *retype = getSpec (operandType (right));
10127   sym_link *letype = getSpec (operandType (result));
10128
10129   aopOp (result, ic, FALSE, FALSE);
10130
10131   /* if the operand is already in dptr
10132      then we do nothing else we move the value to dptr */
10133   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
10134     {
10135       /* if this is remateriazable */
10136       if (AOP_TYPE (result) == AOP_IMMD)
10137         emitcode ("mov", "dptr,%s", 
10138                   aopGet (AOP (result), 0, TRUE, FALSE, NULL));
10139       else
10140         {
10141           /* we need to get it byte by byte */
10142           _startLazyDPSEvaluation ();
10143           if (AOP_TYPE (result) != AOP_DPTR)
10144             {
10145               emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE, NULL));
10146               emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE, NULL));
10147               if (options.model == MODEL_FLAT24)
10148                 emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10149             }
10150           else
10151             {
10152               /* We need to generate a load to DPTR indirect through DPTR. */
10153               D (emitcode (";", "genFarPointerSet -- indirection special case."););
10154                 
10155               emitcode ("push", "%s", aopGet (AOP (result), 0, FALSE, TRUE, NULL));
10156               emitcode ("push", "%s", aopGet (AOP (result), 1, FALSE, TRUE, NULL));
10157               if (options.model == MODEL_FLAT24)
10158                 emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10159               emitcode ("pop", "dph");
10160               emitcode ("pop", "dpl");
10161               dopi=0;
10162             }
10163           _endLazyDPSEvaluation ();
10164         }
10165     }
10166   /* so dptr know contains the address */
10167   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
10168
10169   /* if bit then unpack */
10170   if (IS_BITVAR (retype) || IS_BITVAR (letype)) {
10171       if (AOP_INDPTRn(result)) {
10172           genSetDPTR(AOP(result)->aopu.dptr);
10173       }
10174       genPackBits ((IS_BITVAR (retype) ? retype : letype), right, "dptr", FPOINTER);
10175       if (AOP_INDPTRn(result)) {
10176           genSetDPTR(0);
10177       }
10178   } else {
10179       size = AOP_SIZE (right);
10180       offset = 0;
10181       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
10182           while (size--) {
10183               MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10184               
10185               genSetDPTR(AOP(result)->aopu.dptr);
10186               emitcode ("movx", "@dptr,a");
10187               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
10188                   emitcode ("inc", "dptr");
10189               genSetDPTR (0);
10190           }
10191       } else {
10192           _startLazyDPSEvaluation ();
10193           while (size--) {
10194               MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10195               
10196               if (AOP_INDPTRn(result)) {
10197                   genSetDPTR(AOP(result)->aopu.dptr);
10198               } else {
10199                   genSetDPTR (0);
10200               }
10201               _flushLazyDPS ();
10202               
10203               emitcode ("movx", "@dptr,a");
10204               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
10205                   emitcode ("inc", "dptr");
10206           }
10207           _endLazyDPSEvaluation ();
10208       }
10209   }
10210   
10211   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
10212       if (!AOP_INDPTRn(result)) {
10213           _startLazyDPSEvaluation ();
10214           
10215           aopPut (AOP(result),"dpl",0);
10216           aopPut (AOP(result),"dph",1);
10217           if (options.model == MODEL_FLAT24)
10218               aopPut (AOP(result),"dpx",2);
10219
10220           _endLazyDPSEvaluation ();
10221       }
10222       pi->generated=1;
10223   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) && 
10224              AOP_SIZE(right) > 1 &&
10225              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
10226       
10227       size = AOP_SIZE (right) - 1;
10228       if (AOP_INDPTRn(result)) {
10229           genSetDPTR(AOP(result)->aopu.dptr);
10230       } 
10231       while (size--) emitcode ("lcall","__decdptr");
10232       if (AOP_INDPTRn(result)) {
10233           genSetDPTR(0);
10234       }
10235   }
10236   freeAsmop (result, NULL, ic, TRUE);
10237   freeAsmop (right, NULL, ic, TRUE);
10238 }
10239
10240 /*-----------------------------------------------------------------*/
10241 /* genGenPointerSet - set value from generic pointer space         */
10242 /*-----------------------------------------------------------------*/
10243 static void
10244 genGenPointerSet (operand * right,
10245                   operand * result, iCode * ic, iCode *pi)
10246 {
10247   int size, offset;
10248   sym_link *retype = getSpec (operandType (right));
10249   sym_link *letype = getSpec (operandType (result));
10250
10251   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
10252
10253   /* if the operand is already in dptr
10254      then we do nothing else we move the value to dptr */
10255   if (AOP_TYPE (result) != AOP_STR)
10256     {
10257       _startLazyDPSEvaluation ();
10258       /* if this is remateriazable */
10259       if (AOP_TYPE (result) == AOP_IMMD)
10260         {
10261           emitcode ("mov", "dptr,%s", aopGet (AOP (result), 0, TRUE, FALSE, NULL));
10262           if (AOP(result)->aopu.aop_immd.from_cast_remat) 
10263           {
10264               MOVB(aopGet(AOP (result), AOP_SIZE(result)-1, FALSE, FALSE, NULL));
10265           }
10266           else
10267           {
10268               emitcode ("mov", 
10269                         "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE, NULL));
10270           }
10271         }
10272       else
10273         {                       /* we need to get it byte by byte */
10274           emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE, NULL));
10275           emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE, NULL));
10276           if (options.model == MODEL_FLAT24) {
10277             emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10278             emitcode ("mov", "b,%s", aopGet (AOP (result), 3, FALSE, FALSE, NULL));
10279           } else {
10280             emitcode ("mov", "b,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10281           }
10282         }
10283       _endLazyDPSEvaluation ();
10284     }
10285   /* so dptr + b now contains the address */
10286   _G.bInUse++;
10287   aopOp (right, ic, FALSE, TRUE);
10288   _G.bInUse--;
10289     
10290
10291   /* if bit then unpack */
10292   if (IS_BITVAR (retype) || IS_BITVAR (letype))
10293     {
10294         genPackBits ((IS_BITVAR (retype) ? retype : letype), right, "dptr", GPOINTER);
10295     }
10296   else
10297     {
10298         size = AOP_SIZE (right);
10299         offset = 0;
10300
10301         _startLazyDPSEvaluation ();
10302         while (size--)
10303         {
10304             if (size)
10305             {
10306                 // Set two bytes at a time, passed in _AP & A.
10307                 // dptr will be incremented ONCE by __gptrputWord.
10308                 //
10309                 // Note: any change here must be coordinated
10310                 // with the implementation of __gptrputWord
10311                 // in device/lib/_gptrput.c
10312                 emitcode("mov", "_ap, %s", 
10313                          aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10314                 MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10315                 
10316                 genSetDPTR (0);
10317                 _flushLazyDPS ();
10318                 emitcode ("lcall", "__gptrputWord");
10319                 size--;
10320             }
10321             else
10322             {
10323                 // Only one byte to put.
10324                 MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10325
10326                 genSetDPTR (0);
10327                 _flushLazyDPS ();               
10328                 emitcode ("lcall", "__gptrput");
10329             }
10330             
10331             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
10332             {
10333                 emitcode ("inc", "dptr");
10334             }
10335         }
10336         _endLazyDPSEvaluation ();
10337     }
10338
10339   if (pi && AOP_TYPE (result) != AOP_IMMD) {
10340       _startLazyDPSEvaluation ();
10341       
10342       aopPut (AOP(result),"dpl",0);
10343       aopPut (AOP(result),"dph",1);
10344       if (options.model == MODEL_FLAT24) {
10345           aopPut (AOP(result),"dpx",2);
10346           aopPut (AOP(result),"b",3);
10347       } else {
10348           aopPut (AOP(result),"b",2);
10349       }
10350       _endLazyDPSEvaluation ();
10351       
10352       pi->generated=1;
10353   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
10354              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
10355       
10356       size = AOP_SIZE (right) - 1;
10357       while (size--) emitcode ("lcall","__decdptr");
10358   }
10359   freeAsmop (result, NULL, ic, TRUE);
10360   freeAsmop (right, NULL, ic, TRUE);
10361 }
10362
10363 /*-----------------------------------------------------------------*/
10364 /* genPointerSet - stores the value into a pointer location        */
10365 /*-----------------------------------------------------------------*/
10366 static void
10367 genPointerSet (iCode * ic, iCode *pi)
10368 {
10369   operand *right, *result;
10370   sym_link *type, *etype;
10371   int p_type;
10372
10373   D (emitcode (";", "genPointerSet "););
10374
10375   right = IC_RIGHT (ic);
10376   result = IC_RESULT (ic);
10377
10378   /* depending on the type of pointer we need to
10379      move it to the correct pointer register */
10380   type = operandType (result);
10381   etype = getSpec (type);
10382   /* if left is of type of pointer then it is simple */
10383   if (IS_PTR (type) && !IS_FUNC (type->next))
10384     {
10385       p_type = DCL_TYPE (type);
10386     }
10387   else
10388     {
10389       /* we have to go by the storage class */
10390       p_type = PTR_TYPE (SPEC_OCLS (etype));
10391     }
10392   /* special case when cast remat */
10393   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10394       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10395           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10396           type = operandType (result);
10397           p_type = DCL_TYPE (type);
10398   }
10399
10400   /* now that we have the pointer type we assign
10401      the pointer values */
10402   switch (p_type)
10403     {
10404
10405     case POINTER:
10406     case IPOINTER:
10407       genNearPointerSet (right, result, ic, pi);
10408       break;
10409
10410     case PPOINTER:
10411       genPagedPointerSet (right, result, ic, pi);
10412       break;
10413
10414     case FPOINTER:
10415       genFarPointerSet (right, result, ic, pi);
10416       break;
10417
10418     case GPOINTER:
10419       genGenPointerSet (right, result, ic, pi);
10420       break;
10421
10422     default:
10423       werror (E_INTERNAL_ERROR, __FILE__, __LINE__, 
10424               "genPointerSet: illegal pointer type");
10425     }
10426
10427 }
10428
10429 /*-----------------------------------------------------------------*/
10430 /* genIfx - generate code for Ifx statement                        */
10431 /*-----------------------------------------------------------------*/
10432 static void
10433 genIfx (iCode * ic, iCode * popIc)
10434 {
10435   operand *cond = IC_COND (ic);
10436   int isbit = 0;
10437
10438   D (emitcode (";", "genIfx "););
10439
10440   aopOp (cond, ic, FALSE, FALSE);
10441
10442   /* get the value into acc */
10443   if (AOP_TYPE (cond) != AOP_CRY)
10444     {
10445         toBoolean (cond);
10446     }
10447   else
10448     {
10449         isbit = 1;
10450     }
10451     
10452   /* the result is now in the accumulator */
10453   freeAsmop (cond, NULL, ic, TRUE);
10454
10455   /* if there was something to be popped then do it */
10456   if (popIc)
10457     genIpop (popIc);
10458
10459   /* if the condition is  a bit variable */
10460   if (isbit && IS_ITEMP (cond) &&
10461       SPIL_LOC (cond))
10462     {
10463         genIfxJump (ic, SPIL_LOC (cond)->rname);
10464     }
10465   else if (isbit && !IS_ITEMP (cond))
10466     {
10467         genIfxJump (ic, OP_SYMBOL (cond)->rname);
10468     }
10469   else
10470     {
10471         genIfxJump (ic, "a");
10472     }
10473
10474   ic->generated = 1;
10475 }
10476
10477 /*-----------------------------------------------------------------*/
10478 /* genAddrOf - generates code for address of                       */
10479 /*-----------------------------------------------------------------*/
10480 static void
10481 genAddrOf (iCode * ic)
10482 {
10483   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10484   int size, offset;
10485
10486   D (emitcode (";", "genAddrOf ");
10487     );
10488
10489   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
10490
10491   /* if the operand is on the stack then we
10492      need to get the stack offset of this
10493      variable */
10494   if (sym->onStack) {
10495       
10496       /* if 10 bit stack */
10497       if (options.stack10bit) {
10498           char buff[10];
10499           tsprintf(buff, sizeof(buff), 
10500                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
10501           /* if it has an offset then we need to compute it */
10502 /*        emitcode ("subb", "a,#!constbyte", */
10503 /*                  -((sym->stack < 0) ? */
10504 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
10505 /*                    ((short) sym->stack)) & 0xff); */
10506 /*        emitcode ("mov","b,a"); */
10507 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
10508 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
10509 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
10510           if (sym->stack) {
10511               emitcode ("mov", "a,_bpx");
10512               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ? 
10513                                              ((char) (sym->stack - _G.nRegsSaved)) :
10514                                              ((char) sym->stack )) & 0xff);
10515               emitcode ("mov", "b,a");
10516               emitcode ("mov", "a,_bpx+1");
10517               emitcode ("addc","a,#!constbyte", (((sym->stack < 0) ? 
10518                                               ((short) (sym->stack - _G.nRegsSaved)) :
10519                                               ((short) sym->stack )) >> 8) & 0xff);
10520               aopPut (AOP (IC_RESULT (ic)), "b", 0);
10521               aopPut (AOP (IC_RESULT (ic)), "a", 1);
10522               aopPut (AOP (IC_RESULT (ic)), buff, 2);
10523           } else {
10524               /* we can just move _bp */
10525               aopPut (AOP (IC_RESULT (ic)), "_bpx", 0);
10526               aopPut (AOP (IC_RESULT (ic)), "_bpx+1", 1);
10527               aopPut (AOP (IC_RESULT (ic)), buff, 2);
10528           }       
10529       } else {
10530           /* if it has an offset then we need to compute it */
10531           if (sym->stack) {
10532               emitcode ("mov", "a,_bp");
10533               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
10534               aopPut (AOP (IC_RESULT (ic)), "a", 0);
10535           } else {
10536               /* we can just move _bp */
10537               aopPut (AOP (IC_RESULT (ic)), "_bp", 0);
10538           }
10539           /* fill the result with zero */
10540           size = AOP_SIZE (IC_RESULT (ic)) - 1;
10541           
10542           
10543           if (options.stack10bit && size < (FPTRSIZE - 1)) {
10544               fprintf (stderr,
10545                        "*** warning: pointer to stack var truncated.\n");
10546           }
10547
10548           offset = 1;
10549           while (size--) {
10550               aopPut (AOP (IC_RESULT (ic)), zero, offset++);
10551           }      
10552       }
10553       goto release;
10554   }
10555
10556   /* object not on stack then we need the name */
10557   size = AOP_SIZE (IC_RESULT (ic));
10558   offset = 0;
10559
10560   while (size--)
10561     {
10562       char s[SDCC_NAME_MAX];
10563       if (offset) {
10564           switch (offset) {
10565           case 1:
10566               tsprintf(s, sizeof(s), "#!his",sym->rname);
10567               break;
10568           case 2:
10569               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
10570               break;
10571           case 3:
10572               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
10573               break;
10574           default: /* should not need this (just in case) */
10575               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
10576                        sym->rname,
10577                        offset * 8);
10578           }
10579       } 
10580       else
10581       {
10582           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
10583       }
10584         
10585       aopPut (AOP (IC_RESULT (ic)), s, offset++);
10586     }
10587
10588 release:
10589   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10590
10591 }
10592
10593 /*-----------------------------------------------------------------*/
10594 /* genArrayInit - generates code for address of                       */
10595 /*-----------------------------------------------------------------*/
10596 static void
10597 genArrayInit (iCode * ic)
10598 {
10599     literalList *iLoop;
10600     int         ix, count;
10601     int         elementSize = 0, eIndex;
10602     unsigned    val, lastVal;
10603     sym_link    *type;
10604     operand     *left=IC_LEFT(ic);
10605     
10606     D (emitcode (";", "genArrayInit "););
10607
10608     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
10609     
10610     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
10611     {
10612         // Load immediate value into DPTR.
10613         emitcode("mov", "dptr, %s",
10614              aopGet(AOP(IC_LEFT(ic)), 0, TRUE, FALSE, NULL));
10615     }
10616     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
10617     {
10618 #if 0
10619       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10620               "Unexpected operand to genArrayInit.\n");
10621       exit(1);
10622 #else
10623       // a regression because of SDCCcse.c:1.52
10624       emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
10625       emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, NULL));
10626       if (options.model == MODEL_FLAT24)
10627         emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
10628 #endif
10629     }
10630     
10631     type = operandType(IC_LEFT(ic));
10632     
10633     if (type && type->next)
10634     {
10635         elementSize = getSize(type->next);
10636     }
10637     else
10638     {
10639         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10640                                 "can't determine element size in genArrayInit.\n");
10641         exit(1);
10642     }
10643     
10644     iLoop = IC_ARRAYILIST(ic);
10645     lastVal = 0xffff;
10646     
10647     while (iLoop)
10648     {
10649         bool firstpass = TRUE;
10650         
10651         emitcode(";", "store %d x 0x%x to DPTR (element size %d)", 
10652                  iLoop->count, (int)iLoop->literalValue, elementSize);
10653         
10654         ix = iLoop->count;
10655         
10656         while (ix)
10657         {
10658             symbol *tlbl = NULL;
10659             
10660             count = ix > 256 ? 256 : ix;
10661             
10662             if (count > 1)
10663             {
10664                 tlbl = newiTempLabel (NULL);
10665                 if (firstpass || (count & 0xff))
10666                 {
10667                     emitcode("mov", "b, #!constbyte", count & 0xff);
10668                 }
10669                 
10670                 emitcode ("", "!tlabeldef", tlbl->key + 100);
10671             }
10672             
10673             firstpass = FALSE;
10674                 
10675             for (eIndex = 0; eIndex < elementSize; eIndex++)
10676             {
10677                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
10678                 if (val != lastVal)
10679                 {
10680                     emitcode("mov", "a, #!constbyte", val);
10681                     lastVal = val;
10682                 }
10683                 
10684                 emitcode("movx", "@dptr, a");
10685                 emitcode("inc", "dptr");
10686             }
10687             
10688             if (count > 1)
10689             {
10690                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
10691             }
10692             
10693             ix -= count;
10694         }
10695         
10696         iLoop = iLoop->next;
10697     }
10698     
10699     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
10700 }
10701
10702 /*-----------------------------------------------------------------*/
10703 /* genFarFarAssign - assignment when both are in far space         */
10704 /*-----------------------------------------------------------------*/
10705 static void
10706 genFarFarAssign (operand * result, operand * right, iCode * ic)
10707 {
10708   int size = AOP_SIZE (right);
10709   int offset = 0;
10710   symbol *rSym = NULL;
10711
10712   if (size == 1)
10713   {
10714       /* quick & easy case. */
10715       D(emitcode(";","genFarFarAssign (1 byte case)"););      
10716       MOVA(aopGet(AOP(right), 0, FALSE, FALSE, NULL));
10717       freeAsmop (right, NULL, ic, FALSE);
10718       /* now assign DPTR to result */
10719       _G.accInUse++;
10720       aopOp(result, ic, FALSE, FALSE);
10721       _G.accInUse--;
10722       aopPut(AOP(result), "a", 0);
10723       freeAsmop(result, NULL, ic, FALSE);
10724       return;
10725   }
10726   
10727   /* See if we've got an underlying symbol to abuse. */
10728   if (IS_SYMOP(result) && OP_SYMBOL(result))
10729   {
10730       if (IS_TRUE_SYMOP(result))
10731       {
10732           rSym = OP_SYMBOL(result);
10733       }
10734       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
10735       {
10736           rSym = OP_SYMBOL(result)->usl.spillLoc;
10737       }
10738   }
10739              
10740   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
10741   {
10742       /* We can use the '390 auto-toggle feature to good effect here. */
10743       
10744       D(emitcode(";","genFarFarAssign (390 auto-toggle fun)"););
10745       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
10746       emitcode ("mov", "dptr,#%s", rSym->rname); 
10747       /* DP2 = result, DP1 = right, DP1 is current. */
10748       while (size)
10749       {
10750           emitcode("movx", "a,@dptr");
10751           emitcode("movx", "@dptr,a");
10752           if (--size)
10753           {
10754                emitcode("inc", "dptr");
10755                emitcode("inc", "dptr");
10756           }
10757       }
10758       emitcode("mov", "dps,#0");
10759       freeAsmop (right, NULL, ic, FALSE);
10760 #if 0
10761 some alternative code for processors without auto-toggle
10762 no time to test now, so later well put in...kpb
10763         D(emitcode(";","genFarFarAssign (dual-dptr fun)"););
10764         emitcode("mov", "dps,#1");      /* Select DPTR2. */
10765         emitcode ("mov", "dptr,#%s", rSym->rname); 
10766         /* DP2 = result, DP1 = right, DP1 is current. */
10767         while (size)
10768         {
10769           --size;
10770           emitcode("movx", "a,@dptr");
10771           if (size)
10772             emitcode("inc", "dptr");
10773           emitcode("inc", "dps");
10774           emitcode("movx", "@dptr,a");
10775           if (size)
10776             emitcode("inc", "dptr");
10777           emitcode("inc", "dps");
10778         }
10779         emitcode("mov", "dps,#0");
10780         freeAsmop (right, NULL, ic, FALSE);
10781 #endif
10782   }
10783   else
10784   {
10785       D (emitcode (";", "genFarFarAssign"););
10786       aopOp (result, ic, TRUE, TRUE);
10787
10788       _startLazyDPSEvaluation ();
10789       
10790       while (size--)
10791         {
10792           aopPut (AOP (result),
10793                   aopGet (AOP (right), offset, FALSE, FALSE, NULL), offset);
10794           offset++;
10795         }
10796       _endLazyDPSEvaluation ();
10797       freeAsmop (result, NULL, ic, FALSE);
10798       freeAsmop (right, NULL, ic, FALSE);
10799   }
10800 }
10801
10802 /*-----------------------------------------------------------------*/
10803 /* genAssign - generate code for assignment                        */
10804 /*-----------------------------------------------------------------*/
10805 static void
10806 genAssign (iCode * ic)
10807 {
10808   operand *result, *right;
10809   int size, offset;
10810   unsigned long lit = 0L;
10811
10812   D (emitcode (";", "genAssign ");
10813     );
10814
10815   result = IC_RESULT (ic);
10816   right = IC_RIGHT (ic);
10817
10818   /* if they are the same */
10819   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10820     return;
10821
10822   aopOp (right, ic, FALSE, FALSE);
10823
10824   emitcode (";", "genAssign: resultIsFar = %s",
10825             isOperandInFarSpace (result) ?
10826             "TRUE" : "FALSE");
10827
10828   /* special case both in far space */
10829   if ((AOP_TYPE (right) == AOP_DPTR ||
10830        AOP_TYPE (right) == AOP_DPTR2) &&
10831   /* IS_TRUE_SYMOP(result)       && */
10832       isOperandInFarSpace (result))
10833     {
10834       genFarFarAssign (result, right, ic);
10835       return;
10836     }
10837
10838   aopOp (result, ic, TRUE, FALSE);
10839
10840   /* if they are the same registers */
10841   if (sameRegs (AOP (right), AOP (result)))
10842     goto release;
10843
10844   /* if the result is a bit */
10845   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
10846     {
10847       /* if the right size is a literal then
10848          we know what the value is */
10849       if (AOP_TYPE (right) == AOP_LIT)
10850         {
10851           if (((int) operandLitValue (right)))
10852             aopPut (AOP (result), one, 0);
10853           else
10854             aopPut (AOP (result), zero, 0);
10855           goto release;
10856         }
10857
10858       /* the right is also a bit variable */
10859       if (AOP_TYPE (right) == AOP_CRY)
10860         {
10861           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10862           aopPut (AOP (result), "c", 0);
10863           goto release;
10864         }
10865
10866       /* we need to or */
10867       toBoolean (right);
10868       aopPut (AOP (result), "a", 0);
10869       goto release;
10870     }
10871
10872   /* bit variables done */
10873   /* general case */
10874   size = AOP_SIZE (result);
10875   offset = 0;
10876   if (AOP_TYPE (right) == AOP_LIT)
10877     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
10878
10879   if ((size > 1) &&
10880       (AOP_TYPE (result) != AOP_REG) &&
10881       (AOP_TYPE (right) == AOP_LIT) &&
10882       !IS_FLOAT (operandType (right)))
10883     {
10884       _startLazyDPSEvaluation ();
10885       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
10886         {
10887           aopPut (AOP (result),
10888                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
10889                   offset);
10890           offset++;
10891           size--;
10892         }
10893       /* And now fill the rest with zeros. */
10894       if (size)
10895         {
10896           emitcode ("clr", "a");
10897         }
10898       while (size--)
10899         {
10900           aopPut (AOP (result), "a", offset++);
10901         }
10902       _endLazyDPSEvaluation ();
10903     }
10904   else
10905     {
10906       _startLazyDPSEvaluation ();
10907       while (size--)
10908         {
10909           aopPut (AOP (result),
10910                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
10911                   offset);
10912           offset++;
10913         }
10914       _endLazyDPSEvaluation ();
10915     }
10916
10917 release:
10918   freeAsmop (right, NULL, ic, FALSE);
10919   freeAsmop (result, NULL, ic, TRUE);
10920 }
10921
10922 /*-----------------------------------------------------------------*/
10923 /* genJumpTab - generates code for jump table                      */
10924 /*-----------------------------------------------------------------*/
10925 static void
10926 genJumpTab (iCode * ic)
10927 {
10928   symbol *jtab;
10929   char *l;
10930
10931   D (emitcode (";", "genJumpTab ");
10932     );
10933
10934   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
10935   /* get the condition into accumulator */
10936   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE, NULL);
10937   MOVA (l);
10938   /* multiply by four! */
10939   emitcode ("add", "a,acc");
10940   emitcode ("add", "a,acc");
10941   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10942
10943   jtab = newiTempLabel (NULL);
10944   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
10945   emitcode ("jmp", "@a+dptr");
10946   emitcode ("", "!tlabeldef", jtab->key + 100);
10947   /* now generate the jump labels */
10948   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10949        jtab = setNextItem (IC_JTLABELS (ic)))
10950     emitcode ("ljmp", "!tlabel", jtab->key + 100);
10951
10952 }
10953
10954 /*-----------------------------------------------------------------*/
10955 /* genCast - gen code for casting                                  */
10956 /*-----------------------------------------------------------------*/
10957 static void
10958 genCast (iCode * ic)
10959 {
10960   operand *result = IC_RESULT (ic);
10961   sym_link *ctype = operandType (IC_LEFT (ic));
10962   sym_link *rtype = operandType (IC_RIGHT (ic));
10963   operand *right = IC_RIGHT (ic);
10964   int size, offset;
10965
10966   D (emitcode (";", "genCast "););
10967
10968   /* if they are equivalent then do nothing */
10969   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10970     return;
10971
10972   aopOp (right, ic, FALSE, FALSE);
10973   aopOp (result, ic, FALSE, AOP_USESDPTR(right));
10974
10975   /* if the result is a bit */
10976   // if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
10977   if (IS_BITVAR(OP_SYMBOL(result)->type))
10978     {
10979       /* if the right size is a literal then
10980          we know what the value is */
10981       if (AOP_TYPE (right) == AOP_LIT)
10982         {
10983           if (((int) operandLitValue (right)))
10984             aopPut (AOP (result), one, 0);
10985           else
10986             aopPut (AOP (result), zero, 0);
10987
10988           goto release;
10989         }
10990
10991       /* the right is also a bit variable */
10992       if (AOP_TYPE (right) == AOP_CRY)
10993         {
10994           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10995           aopPut (AOP (result), "c", 0);
10996           goto release;
10997         }
10998
10999       /* we need to or */
11000       toBoolean (right);
11001       aopPut (AOP (result), "a", 0);
11002       goto release;
11003     }
11004
11005   /* if they are the same size : or less */
11006   if (AOP_SIZE (result) <= AOP_SIZE (right))
11007     {
11008
11009       /* if they are in the same place */
11010       if (sameRegs (AOP (right), AOP (result)))
11011         goto release;
11012
11013       /* if they in different places then copy */
11014       size = AOP_SIZE (result);
11015       offset = 0;
11016       _startLazyDPSEvaluation ();
11017       while (size--)
11018         {
11019           aopPut (AOP (result),
11020                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11021                   offset);
11022           offset++;
11023         }
11024       _endLazyDPSEvaluation ();
11025       goto release;
11026     }
11027
11028
11029   /* if the result is of type pointer */
11030   if (IS_PTR (ctype))
11031     {
11032
11033       int p_type;
11034       sym_link *type = operandType (right);
11035
11036       /* pointer to generic pointer */
11037       if (IS_GENPTR (ctype))
11038         {
11039           if (IS_PTR (type))
11040             {
11041               p_type = DCL_TYPE (type);
11042             }
11043           else
11044             {
11045 #if OLD_CAST_BEHAVIOR
11046               /* KV: we are converting a non-pointer type to
11047                * a generic pointer. This (ifdef'd out) code
11048                * says that the resulting generic pointer
11049                * should have the same class as the storage
11050                * location of the non-pointer variable.
11051                *
11052                * For example, converting an int (which happens
11053                * to be stored in DATA space) to a pointer results
11054                * in a DATA generic pointer; if the original int
11055                * in XDATA space, so will be the resulting pointer.
11056                *
11057                * I don't like that behavior, and thus this change:
11058                * all such conversions will be forced to XDATA and
11059                * throw a warning. If you want some non-XDATA
11060                * type, or you want to suppress the warning, you
11061                * must go through an intermediate cast, like so:
11062                *
11063                * char _generic *gp = (char _xdata *)(intVar);
11064                */
11065               sym_link *etype = getSpec (type);
11066
11067               /* we have to go by the storage class */
11068               if (SPEC_OCLS (etype) != generic)
11069                 {
11070                   p_type = PTR_TYPE (SPEC_OCLS (etype));
11071                 }
11072               else
11073 #endif
11074                 {
11075                   /* Converting unknown class (i.e. register variable)
11076                    * to generic pointer. This is not good, but
11077                    * we'll make a guess (and throw a warning).
11078                    */
11079                   p_type = FPOINTER;
11080                   werror (W_INT_TO_GEN_PTR_CAST);
11081                 }
11082             }
11083
11084           /* the first two bytes are known */
11085           size = GPTRSIZE - 1;
11086           offset = 0;
11087           _startLazyDPSEvaluation ();
11088           while (size--)
11089             {
11090               aopPut (AOP (result),
11091                       aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11092                       offset);
11093               offset++;
11094             }
11095           _endLazyDPSEvaluation ();
11096
11097           /* the last byte depending on type */
11098             {
11099                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11100                 char gpValStr[10];
11101             
11102                 if (gpVal == -1)
11103                 {
11104                     // pointerTypeToGPByte will have bitched.
11105                     exit(1);
11106                 }
11107             
11108                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%d", gpVal);
11109                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1);
11110             }
11111           goto release;
11112         }
11113
11114       /* just copy the pointers */
11115       size = AOP_SIZE (result);
11116       offset = 0;
11117       _startLazyDPSEvaluation ();
11118       while (size--)
11119         {
11120           aopPut (AOP (result),
11121                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11122                   offset);
11123           offset++;
11124         }
11125       _endLazyDPSEvaluation ();
11126       goto release;
11127     }
11128
11129   /* so we now know that the size of destination is greater
11130      than the size of the source */
11131   /* we move to result for the size of source */
11132   size = AOP_SIZE (right);
11133   offset = 0;
11134   _startLazyDPSEvaluation ();
11135   while (size--)
11136     {
11137       aopPut (AOP (result),
11138               aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11139               offset);
11140       offset++;
11141     }
11142   _endLazyDPSEvaluation ();
11143
11144   /* now depending on the sign of the source && destination */
11145   size = AOP_SIZE (result) - AOP_SIZE (right);
11146   /* if unsigned or not an integral type */
11147   /* also, if the source is a bit, we don't need to sign extend, because
11148    * it can't possibly have set the sign bit.
11149    */
11150   if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE (right) == AOP_CRY)
11151     {
11152       while (size--)
11153         {
11154           aopPut (AOP (result), zero, offset++);
11155         }
11156     }
11157   else
11158     {
11159       /* we need to extend the sign :{ */
11160       MOVA (aopGet (AOP (right), AOP_SIZE (right) - 1,
11161                         FALSE, FALSE, NULL));
11162       emitcode ("rlc", "a");
11163       emitcode ("subb", "a,acc");
11164       while (size--)
11165         aopPut (AOP (result), "a", offset++);
11166     }
11167
11168   /* we are done hurray !!!! */
11169
11170 release:
11171   freeAsmop (right, NULL, ic, TRUE);
11172   freeAsmop (result, NULL, ic, TRUE);
11173
11174 }
11175
11176 /*-----------------------------------------------------------------*/
11177 /* genDjnz - generate decrement & jump if not zero instrucion      */
11178 /*-----------------------------------------------------------------*/
11179 static int
11180 genDjnz (iCode * ic, iCode * ifx)
11181 {
11182   symbol *lbl, *lbl1;
11183   if (!ifx)
11184     return 0;
11185
11186   /* if the if condition has a false label
11187      then we cannot save */
11188   if (IC_FALSE (ifx))
11189     return 0;
11190
11191   /* if the minus is not of the form
11192      a = a - 1 */
11193   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11194       !IS_OP_LITERAL (IC_RIGHT (ic)))
11195     return 0;
11196
11197   if (operandLitValue (IC_RIGHT (ic)) != 1)
11198     return 0;
11199
11200   /* if the size of this greater than one then no
11201      saving */
11202   if (getSize (operandType (IC_RESULT (ic))) > 1)
11203     return 0;
11204
11205   /* otherwise we can save BIG */
11206   D(emitcode(";", "genDjnz"););
11207
11208   lbl = newiTempLabel (NULL);
11209   lbl1 = newiTempLabel (NULL);
11210
11211   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11212
11213   if (AOP_NEEDSACC(IC_RESULT(ic)))
11214   {
11215       /* If the result is accessed indirectly via
11216        * the accumulator, we must explicitly write
11217        * it back after the decrement.
11218        */
11219       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE, NULL);
11220       
11221       if (strcmp(rByte, "a"))
11222       {
11223            /* Something is hopelessly wrong */
11224            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11225                    __FILE__, __LINE__);
11226            /* We can just give up; the generated code will be inefficient,
11227             * but what the hey.
11228             */
11229            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11230            return 0;
11231       }
11232       emitcode ("dec", "%s", rByte);
11233       aopPut(AOP(IC_RESULT(ic)), rByte, 0);
11234       emitcode ("jnz", "!tlabel", lbl->key + 100);
11235   }
11236   else if (IS_AOP_PREG (IC_RESULT (ic)))
11237     {
11238       emitcode ("dec", "%s",
11239                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, NULL));
11240       emitcode ("mov", "a,%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, NULL));
11241       emitcode ("jnz", "!tlabel", lbl->key + 100);
11242     }
11243   else
11244     {
11245       emitcode ("djnz", "%s,!tlabel", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, TRUE, NULL),
11246                 lbl->key + 100);
11247     }
11248   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
11249   emitcode ("", "!tlabeldef", lbl->key + 100);
11250   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
11251   emitcode ("", "!tlabeldef", lbl1->key + 100);
11252
11253   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11254   ifx->generated = 1;
11255   return 1;
11256 }
11257
11258 /*-----------------------------------------------------------------*/
11259 /* genReceive - generate code for a receive iCode                  */
11260 /*-----------------------------------------------------------------*/
11261 static void
11262 genReceive (iCode * ic)
11263 {
11264     int size = getSize (operandType (IC_RESULT (ic)));
11265     int offset = 0;
11266     int rb1off ;
11267     
11268     D (emitcode (";", "genReceive "););
11269
11270     if (ic->argreg == 1) 
11271     {
11272         /* first parameter */
11273         if (AOP_IS_STR(IC_RESULT(ic)))
11274         {
11275             /* Nothing to do: it's already in the proper place. */
11276             return;
11277         }
11278         else
11279         {
11280             bool useDp2;
11281             
11282             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
11283                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11284                  IS_TRUE_SYMOP (IC_RESULT (ic)));
11285             
11286             _G.accInUse++;
11287             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
11288             _G.accInUse--; 
11289             
11290             /* Sanity checking... */
11291             if (AOP_USESDPTR(IC_RESULT(ic)))
11292             {
11293                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11294                         "genReceive got unexpected DPTR.");
11295             }
11296             assignResultValue (IC_RESULT (ic));
11297         }
11298     } 
11299     else 
11300     { 
11301         /* second receive onwards */
11302         /* this gets a little tricky since unused recevies will be
11303          eliminated, we have saved the reg in the type field . and
11304          we use that to figure out which register to use */
11305         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11306         rb1off = ic->argreg;
11307         while (size--) 
11308         {
11309             aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++);
11310         }
11311     }
11312     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11313 }
11314
11315 /*-----------------------------------------------------------------*/
11316 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
11317 /*-----------------------------------------------------------------*/
11318 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
11319 {
11320     operand *from , *to , *count;
11321     symbol *lbl;
11322     bitVect *rsave;
11323     int i;
11324
11325     /* we know it has to be 3 parameters */
11326     assert (nparms == 3);
11327     
11328     rsave = newBitVect(16);
11329     /* save DPTR if it needs to be saved */
11330     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
11331             if (bitVectBitValue(ic->rMask,i))
11332                     rsave = bitVectSetBit(rsave,i);
11333     }
11334     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
11335                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
11336     savermask(rsave);
11337     
11338     to = parms[0];
11339     from = parms[1];
11340     count = parms[2];
11341
11342     aopOp (from, ic->next, FALSE, FALSE);
11343
11344     /* get from into DPTR1 */
11345     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
11346     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
11347     if (options.model == MODEL_FLAT24) {
11348         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
11349     }
11350
11351     freeAsmop (from, NULL, ic, FALSE);
11352     aopOp (to, ic, FALSE, FALSE);
11353     /* get "to" into DPTR */
11354     /* if the operand is already in dptr
11355        then we do nothing else we move the value to dptr */
11356     if (AOP_TYPE (to) != AOP_STR) {
11357         /* if already in DPTR then we need to push */
11358         if (AOP_TYPE(to) == AOP_DPTR) {
11359             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
11360             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
11361             if (options.model == MODEL_FLAT24)
11362                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11363             emitcode ("pop", "dph");
11364             emitcode ("pop", "dpl");        
11365         } else {
11366             _startLazyDPSEvaluation ();
11367             /* if this is remateriazable */
11368             if (AOP_TYPE (to) == AOP_IMMD) {
11369                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
11370             } else {                    /* we need to get it byte by byte */
11371                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
11372                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
11373                 if (options.model == MODEL_FLAT24) {
11374                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11375                 }
11376             }
11377             _endLazyDPSEvaluation ();
11378         }
11379     }
11380     freeAsmop (to, NULL, ic, FALSE);
11381     _G.dptrInUse = _G.dptr1InUse = 1;
11382     aopOp (count, ic->next->next, FALSE,FALSE);
11383     lbl =newiTempLabel(NULL);
11384
11385     /* now for the actual copy */
11386     if (AOP_TYPE(count) == AOP_LIT && 
11387         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
11388         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
11389         if (fromc) {
11390             emitcode ("lcall","__bi_memcpyc2x_s");
11391         } else {
11392             emitcode ("lcall","__bi_memcpyx2x_s");
11393         }
11394         freeAsmop (count, NULL, ic, FALSE);
11395     } else {
11396         symbol *lbl1 = newiTempLabel(NULL);
11397         
11398         emitcode (";"," Auto increment but no djnz");
11399         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
11400         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
11401         freeAsmop (count, NULL, ic, FALSE);
11402         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
11403         emitcode ("","!tlabeldef",lbl->key+100);
11404         if (fromc) {
11405             emitcode ("clr","a");
11406             emitcode ("movc", "a,@a+dptr");
11407         } else 
11408             emitcode ("movx", "a,@dptr");
11409         emitcode ("movx", "@dptr,a");
11410         emitcode ("inc", "dptr");
11411         emitcode ("inc", "dptr");
11412         emitcode ("mov","a,b");
11413         emitcode ("orl","a,_ap");
11414         emitcode ("jz","!tlabel",lbl1->key+100);
11415         emitcode ("mov","a,_ap");
11416         emitcode ("add","a,#!constbyte",0xFF);
11417         emitcode ("mov","_ap,a");
11418         emitcode ("mov","a,b");
11419         emitcode ("addc","a,#!constbyte",0xFF);
11420         emitcode ("mov","b,a");
11421         emitcode ("sjmp","!tlabel",lbl->key+100);
11422         emitcode ("","!tlabeldef",lbl1->key+100);
11423     }
11424     emitcode ("mov", "dps,#0"); 
11425     _G.dptrInUse = _G.dptr1InUse = 0;
11426     unsavermask(rsave);
11427
11428 }
11429
11430 /*-----------------------------------------------------------------*/
11431 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
11432 /*-----------------------------------------------------------------*/
11433 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
11434 {
11435     operand *from , *to , *count;
11436     symbol *lbl,*lbl2;
11437     bitVect *rsave;
11438     int i;
11439
11440     /* we know it has to be 3 parameters */
11441     assert (nparms == 3);
11442     
11443     rsave = newBitVect(16);
11444     /* save DPTR if it needs to be saved */
11445     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
11446             if (bitVectBitValue(ic->rMask,i))
11447                     rsave = bitVectSetBit(rsave,i);
11448     }
11449     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
11450                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
11451     savermask(rsave);
11452     
11453     to = parms[0];
11454     from = parms[1];
11455     count = parms[2];
11456
11457     aopOp (from, ic->next, FALSE, FALSE);
11458
11459     /* get from into DPTR1 */
11460     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
11461     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
11462     if (options.model == MODEL_FLAT24) {
11463         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
11464     }
11465
11466     freeAsmop (from, NULL, ic, FALSE);
11467     aopOp (to, ic, FALSE, FALSE);
11468     /* get "to" into DPTR */
11469     /* if the operand is already in dptr
11470        then we do nothing else we move the value to dptr */
11471     if (AOP_TYPE (to) != AOP_STR) {
11472         /* if already in DPTR then we need to push */
11473         if (AOP_TYPE(to) == AOP_DPTR) {
11474             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
11475             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
11476             if (options.model == MODEL_FLAT24)
11477                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11478             emitcode ("pop", "dph");
11479             emitcode ("pop", "dpl");        
11480         } else {
11481             _startLazyDPSEvaluation ();
11482             /* if this is remateriazable */
11483             if (AOP_TYPE (to) == AOP_IMMD) {
11484                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
11485             } else {                    /* we need to get it byte by byte */
11486                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
11487                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
11488                 if (options.model == MODEL_FLAT24) {
11489                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11490                 }
11491             }
11492             _endLazyDPSEvaluation ();
11493         }
11494     }
11495     freeAsmop (to, NULL, ic, FALSE);
11496     _G.dptrInUse = _G.dptr1InUse = 1;
11497     aopOp (count, ic->next->next, FALSE,FALSE);
11498     lbl =newiTempLabel(NULL);
11499     lbl2 =newiTempLabel(NULL);
11500
11501     /* now for the actual compare */
11502     if (AOP_TYPE(count) == AOP_LIT && 
11503         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
11504         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
11505         if (fromc)
11506             emitcode("lcall","__bi_memcmpc2x_s");
11507         else
11508             emitcode("lcall","__bi_memcmpx2x_s");
11509         freeAsmop (count, NULL, ic, FALSE);
11510         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
11511         aopPut(AOP(IC_RESULT(ic)),"a",0);
11512         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
11513     } else {
11514         symbol *lbl1 = newiTempLabel(NULL);
11515
11516         emitcode("push","ar0");         
11517         emitcode (";"," Auto increment but no djnz");
11518         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
11519         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
11520         freeAsmop (count, NULL, ic, FALSE);
11521         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
11522         emitcode ("","!tlabeldef",lbl->key+100);
11523         if (fromc) {
11524             emitcode ("clr","a");
11525             emitcode ("movc", "a,@a+dptr");
11526         } else 
11527             emitcode ("movx", "a,@dptr");
11528         emitcode ("mov","r0,a");
11529         emitcode ("movx", "a,@dptr");
11530         emitcode ("clr","c");
11531         emitcode ("subb","a,r0");
11532         emitcode ("jnz","!tlabel",lbl2->key+100);
11533         emitcode ("inc", "dptr");
11534         emitcode ("inc", "dptr");
11535         emitcode ("mov","a,b");
11536         emitcode ("orl","a,_ap");
11537         emitcode ("jz","!tlabel",lbl1->key+100);
11538         emitcode ("mov","a,_ap");
11539         emitcode ("add","a,#!constbyte",0xFF);
11540         emitcode ("mov","_ap,a");
11541         emitcode ("mov","a,b");
11542         emitcode ("addc","a,#!constbyte",0xFF);
11543         emitcode ("mov","b,a");
11544         emitcode ("sjmp","!tlabel",lbl->key+100);
11545         emitcode ("","!tlabeldef",lbl1->key+100);
11546         emitcode ("clr","a");
11547         emitcode ("","!tlabeldef",lbl2->key+100);
11548         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
11549         aopPut(AOP(IC_RESULT(ic)),"a",0);
11550         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
11551         emitcode("pop","ar0");
11552         emitcode ("mov", "dps,#0");      
11553     }
11554     _G.dptrInUse = _G.dptr1InUse = 0;
11555     unsavermask(rsave);
11556
11557 }
11558
11559 /*-----------------------------------------------------------------*/
11560 /* genInp - gen code for __builtin_inp read data from a mem mapped */
11561 /* port, first parameter output area second parameter pointer to   */
11562 /* port third parameter count                                      */
11563 /*-----------------------------------------------------------------*/
11564 static void genInp( iCode *ic, int nparms, operand **parms)
11565 {
11566     operand *from , *to , *count;
11567     symbol *lbl;
11568     bitVect *rsave;
11569     int i;
11570
11571     /* we know it has to be 3 parameters */
11572     assert (nparms == 3);
11573     
11574     rsave = newBitVect(16);
11575     /* save DPTR if it needs to be saved */
11576     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
11577             if (bitVectBitValue(ic->rMask,i))
11578                     rsave = bitVectSetBit(rsave,i);
11579     }
11580     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
11581                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
11582     savermask(rsave);
11583     
11584     to = parms[0];
11585     from = parms[1];
11586     count = parms[2];
11587
11588     aopOp (from, ic->next, FALSE, FALSE);
11589
11590     /* get from into DPTR1 */
11591     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
11592     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
11593     if (options.model == MODEL_FLAT24) {
11594         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
11595     }
11596
11597     freeAsmop (from, NULL, ic, FALSE);
11598     aopOp (to, ic, FALSE, FALSE);
11599     /* get "to" into DPTR */
11600     /* if the operand is already in dptr
11601        then we do nothing else we move the value to dptr */
11602     if (AOP_TYPE (to) != AOP_STR) {
11603         /* if already in DPTR then we need to push */
11604         if (AOP_TYPE(to) == AOP_DPTR) {
11605             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
11606             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
11607             if (options.model == MODEL_FLAT24)
11608                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11609             emitcode ("pop", "dph");
11610             emitcode ("pop", "dpl");        
11611         } else {
11612             _startLazyDPSEvaluation ();
11613             /* if this is remateriazable */
11614             if (AOP_TYPE (to) == AOP_IMMD) {
11615                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
11616             } else {                    /* we need to get it byte by byte */
11617                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
11618                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
11619                 if (options.model == MODEL_FLAT24) {
11620                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11621                 }
11622             }
11623             _endLazyDPSEvaluation ();
11624         }
11625     }
11626     freeAsmop (to, NULL, ic, FALSE);
11627
11628     _G.dptrInUse = _G.dptr1InUse = 1;
11629     aopOp (count, ic->next->next, FALSE,FALSE);
11630     lbl =newiTempLabel(NULL);
11631
11632     /* now for the actual copy */
11633     if (AOP_TYPE(count) == AOP_LIT && 
11634         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
11635         emitcode (";","OH  JOY auto increment with djnz (very fast)");
11636         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
11637         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
11638         freeAsmop (count, NULL, ic, FALSE);
11639         emitcode ("","!tlabeldef",lbl->key+100);
11640         emitcode ("movx", "a,@dptr");   /* read data from port */
11641         emitcode ("dec","dps");         /* switch to DPTR */
11642         emitcode ("movx", "@dptr,a");   /* save into location */
11643         emitcode ("inc", "dptr");       /* point to next area */
11644         emitcode ("inc","dps");         /* switch to DPTR2 */
11645         emitcode ("djnz","b,!tlabel",lbl->key+100);
11646     } else {
11647         symbol *lbl1 = newiTempLabel(NULL);
11648         
11649         emitcode (";"," Auto increment but no djnz");
11650         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
11651         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
11652         freeAsmop (count, NULL, ic, FALSE);
11653         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
11654         emitcode ("","!tlabeldef",lbl->key+100);
11655         emitcode ("movx", "a,@dptr");
11656         emitcode ("dec","dps");         /* switch to DPTR */
11657         emitcode ("movx", "@dptr,a");
11658         emitcode ("inc", "dptr");
11659         emitcode ("inc","dps");         /* switch to DPTR2 */
11660 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
11661 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
11662         emitcode ("mov","a,b");
11663         emitcode ("orl","a,_ap");
11664         emitcode ("jz","!tlabel",lbl1->key+100);
11665         emitcode ("mov","a,_ap");
11666         emitcode ("add","a,#!constbyte",0xFF);
11667         emitcode ("mov","_ap,a");
11668         emitcode ("mov","a,b");
11669         emitcode ("addc","a,#!constbyte",0xFF);
11670         emitcode ("mov","b,a");
11671         emitcode ("sjmp","!tlabel",lbl->key+100);
11672         emitcode ("","!tlabeldef",lbl1->key+100);
11673     }
11674     emitcode ("mov", "dps,#0"); 
11675     _G.dptrInUse = _G.dptr1InUse = 0;
11676     unsavermask(rsave);
11677
11678 }
11679
11680 /*-----------------------------------------------------------------*/
11681 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
11682 /* port, first parameter output area second parameter pointer to   */
11683 /* port third parameter count                                      */
11684 /*-----------------------------------------------------------------*/
11685 static void genOutp( iCode *ic, int nparms, operand **parms)
11686 {
11687     operand *from , *to , *count;
11688     symbol *lbl;
11689     bitVect *rsave;
11690     int i;
11691
11692     /* we know it has to be 3 parameters */
11693     assert (nparms == 3);
11694     
11695     rsave = newBitVect(16);
11696     /* save DPTR if it needs to be saved */
11697     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
11698             if (bitVectBitValue(ic->rMask,i))
11699                     rsave = bitVectSetBit(rsave,i);
11700     }
11701     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
11702                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
11703     savermask(rsave);
11704     
11705     to = parms[0];
11706     from = parms[1];
11707     count = parms[2];
11708
11709     aopOp (from, ic->next, FALSE, FALSE);
11710
11711     /* get from into DPTR1 */
11712     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
11713     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
11714     if (options.model == MODEL_FLAT24) {
11715         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
11716     }
11717
11718     freeAsmop (from, NULL, ic, FALSE);
11719     aopOp (to, ic, FALSE, FALSE);
11720     /* get "to" into DPTR */
11721     /* if the operand is already in dptr
11722        then we do nothing else we move the value to dptr */
11723     if (AOP_TYPE (to) != AOP_STR) {
11724         /* if already in DPTR then we need to push */
11725         if (AOP_TYPE(to) == AOP_DPTR) {
11726             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
11727             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
11728             if (options.model == MODEL_FLAT24)
11729                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11730             emitcode ("pop", "dph");
11731             emitcode ("pop", "dpl");        
11732         } else {
11733             _startLazyDPSEvaluation ();
11734             /* if this is remateriazable */
11735             if (AOP_TYPE (to) == AOP_IMMD) {
11736                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
11737             } else {                    /* we need to get it byte by byte */
11738                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
11739                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
11740                 if (options.model == MODEL_FLAT24) {
11741                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11742                 }
11743             }
11744             _endLazyDPSEvaluation ();
11745         }
11746     }
11747     freeAsmop (to, NULL, ic, FALSE);
11748
11749     _G.dptrInUse = _G.dptr1InUse = 1;
11750     aopOp (count, ic->next->next, FALSE,FALSE);
11751     lbl =newiTempLabel(NULL);
11752
11753     /* now for the actual copy */
11754     if (AOP_TYPE(count) == AOP_LIT && 
11755         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
11756         emitcode (";","OH  JOY auto increment with djnz (very fast)");
11757         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
11758         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
11759         emitcode ("","!tlabeldef",lbl->key+100);
11760         emitcode ("movx", "a,@dptr");   /* read data from port */
11761         emitcode ("inc","dps");         /* switch to DPTR2 */
11762         emitcode ("movx", "@dptr,a");   /* save into location */
11763         emitcode ("inc", "dptr");       /* point to next area */
11764         emitcode ("dec","dps");         /* switch to DPTR */
11765         emitcode ("djnz","b,!tlabel",lbl->key+100);
11766         freeAsmop (count, NULL, ic, FALSE);
11767     } else {
11768         symbol *lbl1 = newiTempLabel(NULL);
11769         
11770         emitcode (";"," Auto increment but no djnz");
11771         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
11772         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
11773         freeAsmop (count, NULL, ic, FALSE);
11774         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
11775         emitcode ("","!tlabeldef",lbl->key+100);
11776         emitcode ("movx", "a,@dptr");
11777         emitcode ("inc", "dptr");
11778         emitcode ("inc","dps");         /* switch to DPTR2 */
11779         emitcode ("movx", "@dptr,a");
11780         emitcode ("dec","dps");         /* switch to DPTR */
11781         emitcode ("mov","a,b");
11782         emitcode ("orl","a,_ap");
11783         emitcode ("jz","!tlabel",lbl1->key+100);
11784         emitcode ("mov","a,_ap");
11785         emitcode ("add","a,#!constbyte",0xFF);
11786         emitcode ("mov","_ap,a");
11787         emitcode ("mov","a,b");
11788         emitcode ("addc","a,#!constbyte",0xFF);
11789         emitcode ("mov","b,a");
11790         emitcode ("sjmp","!tlabel",lbl->key+100);
11791         emitcode ("","!tlabeldef",lbl1->key+100);
11792     }
11793     emitcode ("mov", "dps,#0"); 
11794     _G.dptrInUse = _G.dptr1InUse = 0;
11795     unsavermask(rsave);
11796
11797 }
11798
11799 /*-----------------------------------------------------------------*/
11800 /* genSwapW - swap lower & high order bytes                        */
11801 /*-----------------------------------------------------------------*/
11802 static void genSwapW(iCode *ic, int nparms, operand **parms)
11803 {
11804     operand *dest;
11805     operand *src;
11806     assert (nparms==1);
11807
11808     src = parms[0];
11809     dest=IC_RESULT(ic);
11810
11811     assert(getSize(operandType(src))==2);
11812
11813     aopOp (src, ic, FALSE, FALSE);
11814     emitcode ("mov","a,%s",aopGet(AOP(src),0,FALSE,FALSE,NULL));
11815     _G.accInUse++;
11816     MOVB(aopGet(AOP(src),1,FALSE,FALSE,"b"));
11817     _G.accInUse--;
11818     freeAsmop (src, NULL, ic, FALSE);
11819     
11820     aopOp (dest,ic, FALSE, FALSE);
11821     aopPut(AOP(dest),"b",0);
11822     aopPut(AOP(dest),"a",1);
11823     freeAsmop (dest, NULL, ic, FALSE);    
11824 }
11825
11826 /*-----------------------------------------------------------------*/
11827 /* genMemsetX - gencode for memSetX data                           */
11828 /*-----------------------------------------------------------------*/
11829 static void genMemsetX(iCode *ic, int nparms, operand **parms)
11830 {
11831     operand *to , *val , *count;
11832     symbol *lbl;
11833     char *l;
11834     int i;
11835     bitVect *rsave;
11836
11837     /* we know it has to be 3 parameters */
11838     assert (nparms == 3);
11839     
11840     to = parms[0];
11841     val = parms[1];
11842     count = parms[2];
11843         
11844     /* save DPTR if it needs to be saved */
11845     rsave = newBitVect(16);
11846     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
11847             if (bitVectBitValue(ic->rMask,i))
11848                     rsave = bitVectSetBit(rsave,i);
11849     }
11850     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
11851                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
11852     savermask(rsave);
11853
11854     aopOp (to, ic, FALSE, FALSE);
11855     /* get "to" into DPTR */
11856     /* if the operand is already in dptr
11857        then we do nothing else we move the value to dptr */
11858     if (AOP_TYPE (to) != AOP_STR) {
11859         /* if already in DPTR then we need to push */
11860         if (AOP_TYPE(to) == AOP_DPTR) {
11861             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
11862             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
11863             if (options.model == MODEL_FLAT24)
11864                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11865             emitcode ("pop", "dph");
11866             emitcode ("pop", "dpl");        
11867         } else {
11868             _startLazyDPSEvaluation ();
11869             /* if this is remateriazable */
11870             if (AOP_TYPE (to) == AOP_IMMD) {
11871                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
11872             } else {                    /* we need to get it byte by byte */
11873                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
11874                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
11875                 if (options.model == MODEL_FLAT24) {
11876                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11877                 }
11878             }
11879             _endLazyDPSEvaluation ();
11880         }
11881     }
11882     freeAsmop (to, NULL, ic, FALSE);
11883
11884     aopOp (val, ic->next->next, FALSE,FALSE);
11885     aopOp (count, ic->next->next, FALSE,FALSE);    
11886     lbl =newiTempLabel(NULL);
11887     /* now for the actual copy */
11888     if (AOP_TYPE(count) == AOP_LIT && 
11889         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
11890         l = aopGet(AOP (val), 0, FALSE, FALSE, NULL);
11891         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
11892         MOVA(l);
11893         emitcode ("","!tlabeldef",lbl->key+100);
11894         emitcode ("movx", "@dptr,a");
11895         emitcode ("inc", "dptr");
11896         emitcode ("djnz","b,!tlabel",lbl->key+100);
11897     } else {
11898         symbol *lbl1 = newiTempLabel(NULL);
11899         
11900         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
11901         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
11902         emitcode ("","!tlabeldef",lbl->key+100);
11903         MOVA (aopGet(AOP (val), 0, FALSE, FALSE, NULL));
11904         emitcode ("movx", "@dptr,a");
11905         emitcode ("inc", "dptr");
11906         emitcode ("mov","a,b");
11907         emitcode ("orl","a,_ap");
11908         emitcode ("jz","!tlabel",lbl1->key+100);
11909         emitcode ("mov","a,_ap");
11910         emitcode ("add","a,#!constbyte",0xFF);
11911         emitcode ("mov","_ap,a");
11912         emitcode ("mov","a,b");
11913         emitcode ("addc","a,#!constbyte",0xFF);
11914         emitcode ("mov","b,a");
11915         emitcode ("sjmp","!tlabel",lbl->key+100);
11916         emitcode ("","!tlabeldef",lbl1->key+100);
11917     }
11918     freeAsmop (count, NULL, ic, FALSE);
11919     unsavermask(rsave);
11920 }
11921
11922 /*-----------------------------------------------------------------*/
11923 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
11924 /*-----------------------------------------------------------------*/
11925 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
11926 {
11927         bitVect *rsave ;
11928         operand *pnum, *result;
11929         int i;
11930     
11931         assert (nparms==1);
11932         /* save registers that need to be saved */
11933         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
11934                                          ds390_rUmaskForOp (IC_RESULT(ic))));
11935     
11936         pnum = parms[0]; 
11937         aopOp (pnum, ic, FALSE, FALSE);
11938         emitcode ("mov","a,%s",aopGet(AOP(pnum),0,FALSE,FALSE,DP2_RESULT_REG));
11939         freeAsmop (pnum, NULL, ic, FALSE);
11940         emitcode ("lcall","NatLib_LoadPrimitive");
11941         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
11942         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) || 
11943             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
11944                 for (i = (size-1) ; i >= 0 ; i-- ) {
11945                         emitcode ("push","a%s",javaRet[i]);
11946                 }
11947                 for (i=0; i < size ; i++ ) {
11948                         emitcode ("pop","a%s",
11949                                   aopGet(AOP(result),i,FALSE,FALSE,DP2_RESULT_REG));
11950                 }
11951         } else {
11952                 for (i = 0 ; i < size ; i++ ) {
11953                         aopPut(AOP(result),javaRet[i],i);
11954                 }
11955         }    
11956         freeAsmop (result, NULL, ic, FALSE);
11957         unsavermask(rsave);
11958 }
11959
11960 /*-----------------------------------------------------------------*/
11961 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
11962 /*-----------------------------------------------------------------*/
11963 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
11964 {
11965         bitVect *rsave ;
11966         operand *pnum, *result;
11967         int size = 3;
11968         int i;
11969     
11970         assert (nparms==1);
11971         /* save registers that need to be saved */
11972         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
11973                                          ds390_rUmaskForOp (IC_RESULT(ic))));
11974     
11975         pnum = parms[0]; 
11976         aopOp (pnum, ic, FALSE, FALSE);
11977         emitcode ("mov","a,%s",aopGet(AOP(pnum),0,FALSE,FALSE,DP2_RESULT_REG));
11978         freeAsmop (pnum, NULL, ic, FALSE);
11979         emitcode ("lcall","NatLib_LoadPointer");
11980         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
11981         if (AOP_TYPE(result)!=AOP_STR) {
11982                 for (i = 0 ; i < size ; i++ ) {
11983                         aopPut(AOP(result),fReturn[i],i);
11984                 }
11985         }    
11986         freeAsmop (result, NULL, ic, FALSE);
11987         unsavermask(rsave);
11988 }
11989
11990 /*-----------------------------------------------------------------*/
11991 /* genNatLibInstallStateBlock -                                    */
11992 /*-----------------------------------------------------------------*/
11993 static void genNatLibInstallStateBlock(iCode *ic, int nparms, 
11994                                        operand **parms, const char *name)
11995 {
11996         bitVect *rsave ;
11997         operand *psb, *handle;
11998         assert (nparms==2);
11999
12000         /* save registers that need to be saved */
12001         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12002                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12003         psb = parms[0];
12004         handle = parms[1];
12005
12006         /* put pointer to state block into DPTR1 */
12007         aopOp (psb, ic, FALSE, FALSE);
12008         if (AOP_TYPE (psb) == AOP_IMMD) {
12009                 emitcode ("mov","dps,#1");
12010                 emitcode ("mov", "dptr,%s",
12011                           aopGet (AOP (psb), 0, TRUE, FALSE, DP2_RESULT_REG));
12012                 emitcode ("mov","dps,#0");
12013         } else {
12014                 emitcode ("mov","dpl1,%s",aopGet(AOP(psb),0,FALSE,FALSE,DP2_RESULT_REG));
12015                 emitcode ("mov","dph1,%s",aopGet(AOP(psb),1,FALSE,FALSE,DP2_RESULT_REG));
12016                 emitcode ("mov","dpx1,%s",aopGet(AOP(psb),2,FALSE,FALSE,DP2_RESULT_REG));
12017         }
12018         freeAsmop (psb, NULL, ic, FALSE);
12019
12020         /* put libraryID into DPTR */
12021         emitcode ("mov","dptr,#LibraryID");
12022
12023         /* put handle into r3:r2 */
12024         aopOp (handle, ic, FALSE, FALSE);
12025         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12026                 emitcode ("push","%s",aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12027                 emitcode ("push","%s",aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12028                 emitcode ("pop","ar3");
12029                 emitcode ("pop","ar2");
12030         } else {        
12031                 emitcode ("mov","r2,%s",aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));       
12032                 emitcode ("mov","r3,%s",aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12033         }
12034         freeAsmop (psb, NULL, ic, FALSE);
12035
12036         /* make the call */
12037         emitcode ("lcall","NatLib_Install%sStateBlock",name);
12038
12039         /* put return value into place*/
12040         _G.accInUse++;
12041         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
12042         _G.accInUse--;
12043         aopPut(AOP(IC_RESULT(ic)),"a",0);
12044         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12045         unsavermask(rsave);
12046 }
12047
12048 /*-----------------------------------------------------------------*/
12049 /* genNatLibRemoveStateBlock -                                     */
12050 /*-----------------------------------------------------------------*/
12051 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
12052 {
12053         bitVect *rsave ;
12054
12055         assert(nparms==0);
12056
12057         /* save registers that need to be saved */
12058         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12059                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12060
12061         /* put libraryID into DPTR */
12062         emitcode ("mov","dptr,#LibraryID");
12063         /* make the call */
12064         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
12065         unsavermask(rsave);
12066 }
12067
12068 /*-----------------------------------------------------------------*/
12069 /* genNatLibGetStateBlock -                                        */
12070 /*-----------------------------------------------------------------*/
12071 static void genNatLibGetStateBlock(iCode *ic,int nparms,
12072                                    operand **parms,const char *name)
12073 {
12074         bitVect *rsave ;
12075         symbol *lbl = newiTempLabel(NULL);
12076         
12077         assert(nparms==0);
12078         /* save registers that need to be saved */
12079         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12080                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12081
12082         /* put libraryID into DPTR */
12083         emitcode ("mov","dptr,#LibraryID");
12084         /* make the call */
12085         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
12086         emitcode ("jnz","!tlabel",lbl->key+100);
12087
12088         /* put return value into place */
12089         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
12090         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
12091                 emitcode ("push","ar3");
12092                 emitcode ("push","ar2");
12093                 emitcode ("pop","%s",
12094                           aopGet(AOP(IC_RESULT(ic)),0,FALSE,TRUE,DP2_RESULT_REG));
12095                 emitcode ("pop","%s",
12096                           aopGet(AOP(IC_RESULT(ic)),1,FALSE,TRUE,DP2_RESULT_REG));
12097         } else {
12098                 aopPut(AOP(IC_RESULT(ic)),"r2",0);
12099                 aopPut(AOP(IC_RESULT(ic)),"r3",1);
12100         }
12101         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12102         emitcode ("","!tlabeldef",lbl->key+100);
12103         unsavermask(rsave);
12104 }
12105
12106 /*-----------------------------------------------------------------*/
12107 /* genMMMalloc -                                                   */
12108 /*-----------------------------------------------------------------*/
12109 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
12110                          int size, const char *name)
12111 {
12112         bitVect *rsave ;
12113         operand *bsize;
12114         symbol *rsym;
12115         symbol *lbl = newiTempLabel(NULL);
12116
12117         assert (nparms == 1);
12118         /* save registers that need to be saved */
12119         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12120                                          ds390_rUmaskForOp (IC_RESULT(ic))));   
12121         
12122         bsize=parms[0];
12123         aopOp (bsize,ic,FALSE,FALSE);
12124
12125         /* put the size in R4-R2 */
12126         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
12127                 emitcode("push","%s",aopGet(AOP(bsize),0,FALSE,TRUE,DP2_RESULT_REG));
12128                 emitcode("push","%s",aopGet(AOP(bsize),1,FALSE,TRUE,DP2_RESULT_REG));
12129                 if (size==3) {
12130                         emitcode("push","%s",aopGet(AOP(bsize),2,FALSE,TRUE,DP2_RESULT_REG));
12131                         emitcode("pop","ar4");
12132                 }
12133                 emitcode("pop","ar3");
12134                 emitcode("pop","ar2");          
12135         } else {
12136                 emitcode ("mov","r2,%s",aopGet(AOP(bsize),0,FALSE,TRUE,DP2_RESULT_REG));
12137                 emitcode ("mov","r3,%s",aopGet(AOP(bsize),1,FALSE,TRUE,DP2_RESULT_REG));
12138                 if (size==3) {
12139                         emitcode("mov","r4,%s",aopGet(AOP(bsize),2,FALSE,TRUE,DP2_RESULT_REG));
12140                 }
12141         }
12142         freeAsmop (bsize, NULL, ic, FALSE);
12143
12144         /* make the call */
12145         emitcode ("lcall","MM_%s",name);
12146         emitcode ("jz","!tlabel",lbl->key+100);
12147         emitcode ("mov","r2,#!constbyte",0xff);
12148         emitcode ("mov","r3,#!constbyte",0xff);
12149         emitcode ("","!tlabeldef",lbl->key+100);
12150         /* we don't care about the pointer : we just save the handle */
12151         rsym = OP_SYMBOL(IC_RESULT(ic));
12152         if (rsym->liveFrom != rsym->liveTo) {
12153                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
12154                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
12155                         emitcode ("push","ar3");
12156                         emitcode ("push","ar2");
12157                         emitcode ("pop","%s",
12158                                   aopGet(AOP(IC_RESULT(ic)),0,FALSE,TRUE,DP2_RESULT_REG));
12159                         emitcode ("pop","%s",
12160                                   aopGet(AOP(IC_RESULT(ic)),1,FALSE,TRUE,DP2_RESULT_REG));
12161                 } else {
12162                         aopPut(AOP(IC_RESULT(ic)),"r2",0);
12163                         aopPut(AOP(IC_RESULT(ic)),"r3",1);
12164                 }
12165                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12166         }
12167         unsavermask(rsave);
12168 }
12169
12170 /*-----------------------------------------------------------------*/
12171 /* genMMDeref -                                                    */
12172 /*-----------------------------------------------------------------*/
12173 static void genMMDeref (iCode *ic,int nparms, operand **parms)
12174 {
12175         bitVect *rsave ;
12176         operand *handle;
12177
12178         assert (nparms == 1);
12179         /* save registers that need to be saved */
12180         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12181                                          ds390_rUmaskForOp (IC_RESULT(ic))));   
12182         
12183         handle=parms[0];
12184         aopOp (handle,ic,FALSE,FALSE);
12185
12186         /* put the size in R4-R2 */
12187         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12188                 emitcode("push","%s",
12189                          aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12190                 emitcode("push","%s",
12191                          aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12192                 emitcode("pop","ar3");
12193                 emitcode("pop","ar2");          
12194         } else {
12195                 emitcode ("mov","r2,%s",
12196                           aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12197                 emitcode ("mov","r3,%s",
12198                           aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12199         }
12200         freeAsmop (handle, NULL, ic, FALSE);
12201
12202         /* make the call */
12203         emitcode ("lcall","MM_Deref");
12204         
12205         {
12206                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12207                 if (rsym->liveFrom != rsym->liveTo) {                   
12208                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12209                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
12210                             _startLazyDPSEvaluation ();
12211                             
12212                                 aopPut(AOP(IC_RESULT(ic)),"dpl",0);
12213                                 aopPut(AOP(IC_RESULT(ic)),"dph",1);
12214                                 aopPut(AOP(IC_RESULT(ic)),"dpx",2);
12215
12216                             _endLazyDPSEvaluation ();
12217                             
12218                         }
12219                 }
12220         }
12221         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12222         unsavermask(rsave);
12223 }
12224
12225 /*-----------------------------------------------------------------*/
12226 /* genMMUnrestrictedPersist -                                      */
12227 /*-----------------------------------------------------------------*/
12228 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
12229 {
12230         bitVect *rsave ;
12231         operand *handle;
12232
12233         assert (nparms == 1);
12234         /* save registers that need to be saved */
12235         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12236                                          ds390_rUmaskForOp (IC_RESULT(ic))));   
12237         
12238         handle=parms[0];
12239         aopOp (handle,ic,FALSE,FALSE);
12240
12241         /* put the size in R3-R2 */
12242         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12243                 emitcode("push","%s",
12244                          aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12245                 emitcode("push","%s",
12246                          aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12247                 emitcode("pop","ar3");
12248                 emitcode("pop","ar2");          
12249         } else {
12250                 emitcode ("mov","r2,%s",
12251                           aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12252                 emitcode ("mov","r3,%s",
12253                           aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12254         }
12255         freeAsmop (handle, NULL, ic, FALSE);
12256
12257         /* make the call */
12258         emitcode ("lcall","MM_UnrestrictedPersist");
12259
12260         {
12261                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12262                 if (rsym->liveFrom != rsym->liveTo) {   
12263                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12264                         aopPut(AOP(IC_RESULT(ic)),"a",0);
12265                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12266                 }
12267         }
12268         unsavermask(rsave);
12269 }
12270
12271 /*-----------------------------------------------------------------*/
12272 /* genSystemExecJavaProcess -                                      */
12273 /*-----------------------------------------------------------------*/
12274 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
12275 {
12276         bitVect *rsave ;
12277         operand *handle, *pp;
12278
12279         assert (nparms==2);
12280         /* save registers that need to be saved */
12281         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12282                                          ds390_rUmaskForOp (IC_RESULT(ic))));   
12283         
12284         pp = parms[0];
12285         handle = parms[1];
12286         
12287         /* put the handle in R3-R2 */
12288         aopOp (handle,ic,FALSE,FALSE);
12289         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12290                 emitcode("push","%s",
12291                          aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12292                 emitcode("push","%s",
12293                          aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12294                 emitcode("pop","ar3");
12295                 emitcode("pop","ar2");          
12296         } else {
12297                 emitcode ("mov","r2,%s",
12298                           aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12299                 emitcode ("mov","r3,%s",
12300                           aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12301         }
12302         freeAsmop (handle, NULL, ic, FALSE);
12303         
12304         /* put pointer in DPTR */
12305         aopOp (pp,ic,FALSE,FALSE);
12306         if (AOP_TYPE(pp) == AOP_IMMD) {
12307                 emitcode ("mov", "dptr,%s",
12308                           aopGet (AOP (pp), 0, TRUE, FALSE, NULL));
12309         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
12310                 emitcode ("mov","dpl,%s",aopGet(AOP(pp),0,FALSE,FALSE,NULL));
12311                 emitcode ("mov","dph,%s",aopGet(AOP(pp),1,FALSE,FALSE,NULL));
12312                 emitcode ("mov","dpx,%s",aopGet(AOP(pp),2,FALSE,FALSE,NULL));
12313         }
12314         freeAsmop (handle, NULL, ic, FALSE);
12315
12316         /* make the call */
12317         emitcode ("lcall","System_ExecJavaProcess");
12318         
12319         /* put result in place */
12320         {
12321                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12322                 if (rsym->liveFrom != rsym->liveTo) {   
12323                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12324                         aopPut(AOP(IC_RESULT(ic)),"a",0);
12325                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12326                 }
12327         }
12328         
12329         unsavermask(rsave);
12330 }
12331
12332 /*-----------------------------------------------------------------*/
12333 /* genSystemRTCRegisters -                                         */
12334 /*-----------------------------------------------------------------*/
12335 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
12336                                   char *name)
12337 {
12338         bitVect *rsave ;
12339         operand *pp;
12340
12341         assert (nparms==1);
12342         /* save registers that need to be saved */
12343         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12344                                          ds390_rUmaskForOp (IC_RESULT(ic))));   
12345         
12346         pp=parms[0];
12347         /* put pointer in DPTR */
12348         aopOp (pp,ic,FALSE,FALSE);
12349         if (AOP_TYPE (pp) == AOP_IMMD) {
12350                 emitcode ("mov","dps,#1");
12351                 emitcode ("mov", "dptr,%s", 
12352                           aopGet (AOP (pp), 0, TRUE, FALSE, NULL));
12353                 emitcode ("mov","dps,#0");
12354         } else {
12355                 emitcode ("mov","dpl1,%s",
12356                           aopGet(AOP(pp),0,FALSE,FALSE,DP2_RESULT_REG));
12357                 emitcode ("mov","dph1,%s",
12358                           aopGet(AOP(pp),1,FALSE,FALSE,DP2_RESULT_REG));
12359                 emitcode ("mov","dpx1,%s",
12360                           aopGet(AOP(pp),2,FALSE,FALSE,DP2_RESULT_REG));
12361         }
12362         freeAsmop (pp, NULL, ic, FALSE);
12363
12364         /* make the call */
12365         emitcode ("lcall","System_%sRTCRegisters",name);
12366
12367         unsavermask(rsave);
12368 }
12369
12370 /*-----------------------------------------------------------------*/
12371 /* genSystemThreadSleep -                                          */
12372 /*-----------------------------------------------------------------*/
12373 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
12374 {
12375         bitVect *rsave ;
12376         operand *to, *s;
12377
12378         assert (nparms==1);
12379         /* save registers that need to be saved */
12380         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12381                                          ds390_rUmaskForOp (IC_RESULT(ic))));   
12382
12383         to = parms[0];
12384         aopOp(to,ic,FALSE,FALSE);
12385         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
12386             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
12387                 emitcode ("push","%s",
12388                           aopGet(AOP(to),0,FALSE,TRUE,DP2_RESULT_REG));
12389                 emitcode ("push","%s",
12390                           aopGet(AOP(to),1,FALSE,TRUE,DP2_RESULT_REG));
12391                 emitcode ("push","%s",
12392                           aopGet(AOP(to),2,FALSE,TRUE,DP2_RESULT_REG));
12393                 emitcode ("push","%s",
12394                           aopGet(AOP(to),3,FALSE,TRUE,DP2_RESULT_REG));
12395                 emitcode ("pop","ar3");
12396                 emitcode ("pop","ar2");
12397                 emitcode ("pop","ar1");
12398                 emitcode ("pop","ar0");
12399         } else {
12400                 emitcode ("mov","r0,%s",
12401                           aopGet(AOP(to),0,FALSE,TRUE,DP2_RESULT_REG));
12402                 emitcode ("mov","r1,%s",
12403                           aopGet(AOP(to),1,FALSE,TRUE,DP2_RESULT_REG));
12404                 emitcode ("mov","r2,%s",
12405                           aopGet(AOP(to),2,FALSE,TRUE,DP2_RESULT_REG));
12406                 emitcode ("mov","r3,%s",
12407                           aopGet(AOP(to),3,FALSE,TRUE,DP2_RESULT_REG));
12408         }
12409         freeAsmop (to, NULL, ic, FALSE);
12410
12411         /* suspend in acc */
12412         s = parms[1];
12413         aopOp(s,ic,FALSE,FALSE);
12414         emitcode ("mov","a,%s",
12415                   aopGet(AOP(s),0,FALSE,TRUE,NULL));
12416         freeAsmop (s, NULL, ic, FALSE);
12417
12418         /* make the call */
12419         emitcode ("lcall","System_%s",name);
12420
12421         unsavermask(rsave);
12422 }
12423
12424 /*-----------------------------------------------------------------*/
12425 /* genSystemThreadResume -                                         */
12426 /*-----------------------------------------------------------------*/
12427 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
12428 {
12429         bitVect *rsave ;
12430         operand *tid,*pid;
12431
12432         assert (nparms==2);
12433         /* save registers that need to be saved */
12434         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12435                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12436         
12437         tid = parms[0];
12438         pid = parms[1];
12439         
12440         /* PID in R0 */
12441         aopOp(pid,ic,FALSE,FALSE);
12442         emitcode ("mov","r0,%s",
12443                   aopGet(AOP(pid),0,FALSE,TRUE,DP2_RESULT_REG));
12444         freeAsmop (pid, NULL, ic, FALSE);
12445         
12446         /* tid into ACC */
12447         aopOp(tid,ic,FALSE,FALSE);
12448         emitcode ("mov","a,%s",
12449                   aopGet(AOP(tid),0,FALSE,TRUE,DP2_RESULT_REG));
12450         freeAsmop (tid, NULL, ic, FALSE);
12451         
12452         emitcode ("lcall","System_ThreadResume");
12453
12454         /* put result into place */
12455         {
12456                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12457                 if (rsym->liveFrom != rsym->liveTo) {   
12458                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12459                         aopPut(AOP(IC_RESULT(ic)),"a",0);
12460                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12461                 }
12462         }
12463         unsavermask(rsave);
12464 }
12465
12466 /*-----------------------------------------------------------------*/
12467 /* genSystemProcessResume -                                        */
12468 /*-----------------------------------------------------------------*/
12469 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
12470 {
12471         bitVect *rsave ;
12472         operand *pid;
12473
12474         assert (nparms==1);
12475         /* save registers that need to be saved */
12476         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12477                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12478         
12479         pid = parms[0];
12480         
12481         /* pid into ACC */
12482         aopOp(pid,ic,FALSE,FALSE);
12483         emitcode ("mov","a,%s",
12484                   aopGet(AOP(pid),0,FALSE,TRUE,DP2_RESULT_REG));
12485         freeAsmop (pid, NULL, ic, FALSE);
12486         
12487         emitcode ("lcall","System_ProcessResume");
12488
12489         unsavermask(rsave);
12490 }
12491
12492 /*-----------------------------------------------------------------*/
12493 /* genSystem -                                                     */
12494 /*-----------------------------------------------------------------*/
12495 static void genSystem (iCode *ic,int nparms,char *name)
12496 {
12497         assert(nparms == 0);
12498
12499         emitcode ("lcall","System_%s",name);
12500 }
12501
12502 /*-----------------------------------------------------------------*/
12503 /* genSystemPoll -                                                  */
12504 /*-----------------------------------------------------------------*/
12505 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
12506 {
12507         bitVect *rsave ;
12508         operand *fp;
12509
12510         assert (nparms==1);
12511         /* save registers that need to be saved */
12512         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12513                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12514
12515         fp = parms[0];
12516         aopOp (fp,ic,FALSE,FALSE);
12517         if (AOP_TYPE (fp) == AOP_IMMD) {
12518                 emitcode ("mov", "dptr,%s", 
12519                           aopGet (AOP (fp), 0, TRUE, FALSE, DP2_RESULT_REG));
12520         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
12521                 emitcode ("mov","dpl,%s",
12522                           aopGet(AOP(fp),0,FALSE,FALSE,DP2_RESULT_REG));
12523                 emitcode ("mov","dph,%s",
12524                           aopGet(AOP(fp),1,FALSE,FALSE,DP2_RESULT_REG));
12525                 emitcode ("mov","dpx,%s",
12526                           aopGet(AOP(fp),2,FALSE,FALSE,DP2_RESULT_REG));
12527         }
12528         freeAsmop (fp, NULL, ic, FALSE);
12529
12530         emitcode ("lcall","System_%sPoll",name);
12531
12532         /* put result into place */
12533         {
12534                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12535                 if (rsym->liveFrom != rsym->liveTo) {   
12536                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12537                         aopPut(AOP(IC_RESULT(ic)),"a",0);
12538                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12539                 }
12540         }
12541         unsavermask(rsave);
12542 }
12543
12544 /*-----------------------------------------------------------------*/
12545 /* genSystemGetCurrentID -                                         */
12546 /*-----------------------------------------------------------------*/
12547 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
12548 {
12549         assert (nparms==0);
12550
12551         emitcode ("lcall","System_GetCurrent%sId",name);
12552         /* put result into place */
12553         {
12554                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12555                 if (rsym->liveFrom != rsym->liveTo) {   
12556                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12557                         aopPut(AOP(IC_RESULT(ic)),"a",0);
12558                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12559                 }
12560         }
12561 }
12562
12563 /*-----------------------------------------------------------------*/
12564 /* genBuiltIn - calls the appropriate function to  generating code */
12565 /* for a built in function                                         */
12566 /*-----------------------------------------------------------------*/
12567 static void genBuiltIn (iCode *ic)
12568 {
12569         operand *bi_parms[MAX_BUILTIN_ARGS];
12570         int nbi_parms;
12571         iCode *bi_iCode;
12572         symbol *bif;
12573
12574         /* get all the arguments for a built in function */
12575         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
12576
12577         /* which function is it */
12578         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
12579         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
12580                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
12581         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
12582                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
12583         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
12584                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
12585         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
12586                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
12587         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
12588                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
12589         } else if (strcmp(bif->name,"__builtin_inp")==0) {
12590                 genInp(bi_iCode,nbi_parms,bi_parms);
12591         } else if (strcmp(bif->name,"__builtin_outp")==0) {
12592                 genOutp(bi_iCode,nbi_parms,bi_parms);
12593         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
12594                 genSwapW(bi_iCode,nbi_parms,bi_parms);
12595                 /* JavaNative builtIns */               
12596         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
12597                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
12598         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
12599                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
12600         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
12601                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
12602         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
12603                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
12604         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
12605                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
12606         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
12607                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
12608         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
12609                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
12610         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
12611                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
12612         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
12613                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
12614         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
12615                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
12616         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
12617                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
12618         } else if (strcmp(bif->name,"MM_Malloc")==0) {
12619                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
12620         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
12621                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
12622         } else if (strcmp(bif->name,"MM_Free")==0) {
12623                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
12624         } else if (strcmp(bif->name,"MM_Deref")==0) {
12625                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
12626         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
12627                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
12628         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
12629                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
12630         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
12631                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
12632         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
12633                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
12634         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
12635                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
12636         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
12637                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
12638         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
12639                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
12640         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
12641                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
12642         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
12643                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
12644         } else if (strcmp(bif->name,"System_SaveThread")==0) {
12645                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
12646         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
12647                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
12648         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
12649                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
12650         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
12651                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
12652         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
12653                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
12654         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
12655                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
12656         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
12657                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
12658         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
12659                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
12660         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
12661                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
12662         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
12663                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
12664         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
12665                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
12666         } else {
12667                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
12668                 return ;
12669         }
12670         return ;    
12671 }
12672
12673 /*-----------------------------------------------------------------*/
12674 /* gen390Code - generate code for Dallas 390 based controllers     */
12675 /*-----------------------------------------------------------------*/
12676 void
12677 gen390Code (iCode * lic)
12678 {
12679   iCode *ic;
12680   int cln = 0;
12681
12682   lineHead = lineCurr = NULL;
12683   dptrn[1][0] = "dpl1";
12684   dptrn[1][1] = "dph1";
12685   dptrn[1][2] = "dpx1";
12686   
12687   if (options.model == MODEL_FLAT24) {
12688     fReturnSizeDS390 = 5;
12689     fReturn = fReturn24;
12690   } else {
12691     fReturnSizeDS390 = 4;
12692     fReturn = fReturn16;
12693     options.stack10bit=0;
12694   }
12695 #if 1
12696   /* print the allocation information */
12697   if (allocInfo)
12698     printAllocInfo (currFunc, codeOutFile);
12699 #endif
12700   /* if debug information required */
12701   if (options.debug && currFunc)
12702     {
12703       cdbSymbol (currFunc, cdbFile, FALSE, TRUE);
12704       _G.debugLine = 1;
12705       if (IS_STATIC (currFunc->etype))
12706         emitcode ("", "F%s$%s$0$0 ==.", moduleName, currFunc->name);
12707       else
12708         emitcode ("", "G$%s$0$0 ==.", currFunc->name);
12709       _G.debugLine = 0;
12710     }
12711   /* stack pointer name */
12712   if (options.useXstack)
12713     spname = "_spx";
12714   else
12715     spname = "sp";
12716
12717
12718   for (ic = lic; ic; ic = ic->next)
12719     {
12720
12721       if (ic->lineno && cln != ic->lineno)
12722         {
12723           if (options.debug)
12724             {
12725               _G.debugLine = 1;
12726               emitcode ("", "C$%s$%d$%d$%d ==.",
12727                         FileBaseName (ic->filename), ic->lineno,
12728                         ic->level, ic->block);
12729               _G.debugLine = 0;
12730             }
12731           if (!options.noCcodeInAsm) {
12732             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno, 
12733                       printCLine(ic->filename, ic->lineno));
12734           }
12735           cln = ic->lineno;
12736         }
12737       if (options.iCodeInAsm) {
12738         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
12739       }
12740       /* if the result is marked as
12741          spilt and rematerializable or code for
12742          this has already been generated then
12743          do nothing */
12744       if (resultRemat (ic) || ic->generated)
12745         continue;
12746
12747       /* depending on the operation */
12748       switch (ic->op)
12749         {
12750         case '!':
12751           genNot (ic);
12752           break;
12753
12754         case '~':
12755           genCpl (ic);
12756           break;
12757
12758         case UNARYMINUS:
12759           genUminus (ic);
12760           break;
12761
12762         case IPUSH:
12763           genIpush (ic);
12764           break;
12765
12766         case IPOP:
12767           /* IPOP happens only when trying to restore a
12768              spilt live range, if there is an ifx statement
12769              following this pop then the if statement might
12770              be using some of the registers being popped which
12771              would destory the contents of the register so
12772              we need to check for this condition and handle it */
12773           if (ic->next &&
12774               ic->next->op == IFX &&
12775               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
12776             genIfx (ic->next, ic);
12777           else
12778             genIpop (ic);
12779           break;
12780
12781         case CALL:
12782           genCall (ic);
12783           break;
12784
12785         case PCALL:
12786           genPcall (ic);
12787           break;
12788
12789         case FUNCTION:
12790           genFunction (ic);
12791           break;
12792
12793         case ENDFUNCTION:
12794           genEndFunction (ic);
12795           break;
12796
12797         case RETURN:
12798           genRet (ic);
12799           break;
12800
12801         case LABEL:
12802           genLabel (ic);
12803           break;
12804
12805         case GOTO:
12806           genGoto (ic);
12807           break;
12808
12809         case '+':
12810           genPlus (ic);
12811           break;
12812
12813         case '-':
12814           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
12815             genMinus (ic);
12816           break;
12817
12818         case '*':
12819           genMult (ic);
12820           break;
12821
12822         case '/':
12823           genDiv (ic);
12824           break;
12825
12826         case '%':
12827           genMod (ic);
12828           break;
12829
12830         case '>':
12831           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
12832           break;
12833
12834         case '<':
12835           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
12836           break;
12837
12838         case LE_OP:
12839         case GE_OP:
12840         case NE_OP:
12841
12842           /* note these two are xlated by algebraic equivalence
12843              during parsing SDCC.y */
12844           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12845                   "got '>=' or '<=' shouldn't have come here");
12846           break;
12847
12848         case EQ_OP:
12849           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
12850           break;
12851
12852         case AND_OP:
12853           genAndOp (ic);
12854           break;
12855
12856         case OR_OP:
12857           genOrOp (ic);
12858           break;
12859
12860         case '^':
12861           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
12862           break;
12863
12864         case '|':
12865           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
12866           break;
12867
12868         case BITWISEAND:
12869           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
12870           break;
12871
12872         case INLINEASM:
12873           genInline (ic);
12874           break;
12875
12876         case RRC:
12877           genRRC (ic);
12878           break;
12879
12880         case RLC:
12881           genRLC (ic);
12882           break;
12883
12884         case GETHBIT:
12885           genGetHbit (ic);
12886           break;
12887
12888         case LEFT_OP:
12889           genLeftShift (ic);
12890           break;
12891
12892         case RIGHT_OP:
12893           genRightShift (ic);
12894           break;
12895
12896         case GET_VALUE_AT_ADDRESS:
12897           genPointerGet (ic,hasInc(IC_LEFT(ic),ic, getSize(operandType(IC_RESULT(ic)))));
12898           break;
12899
12900         case '=':
12901           if (POINTER_SET (ic))
12902             genPointerSet (ic,hasInc(IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
12903           else
12904             genAssign (ic);
12905           break;
12906
12907         case IFX:
12908           genIfx (ic, NULL);
12909           break;
12910
12911         case ADDRESS_OF:
12912           genAddrOf (ic);
12913           break;
12914
12915         case JUMPTABLE:
12916           genJumpTab (ic);
12917           break;
12918
12919         case CAST:
12920           genCast (ic);
12921           break;
12922
12923         case RECEIVE:
12924           genReceive (ic);
12925           break;
12926
12927         case SEND:
12928           if (ic->builtinSEND) genBuiltIn(ic);
12929           else addSet (&_G.sendSet, ic);
12930           break;
12931
12932         case ARRAYINIT:
12933             genArrayInit(ic);
12934             break;
12935             
12936         default:
12937           ic = ic;
12938         }
12939     }
12940
12941
12942   /* now we are ready to call the
12943      peep hole optimizer */
12944   if (!options.nopeep)
12945     peepHole (&lineHead);
12946
12947   /* now do the actual printing */
12948   printLine (lineHead, codeOutFile);
12949   return;
12950 }