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