* device/lib/Makefile.in (Z80SOURCES): enabled float support
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for DS80C390
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7   DS390 adaptation by Kevin Vigor <kevin@vigor.nu>
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23   In other words, you are welcome to use, share and improve this program.
24   You are forbidden to forbid anyone else to use, share and improve
25   what you give them.   Help stamp out software-hoarding!
26 -------------------------------------------------------------------------*/
27
28 //#define D(x)
29 #define D(x) x
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "SDCCglobl.h"
36 #include "newalloc.h"
37
38 #include "common.h"
39 #include "main.h"
40 #include "ralloc.h"
41 #include "gen.h"
42
43 #define BETTER_LITERAL_SHIFT
44
45 char *aopLiteral (value * val, int offset);
46 extern int allocInfo;
47
48 /* this is the down and dirty file with all kinds of
49    kludgy & hacky stuff. This is what it is all about
50    CODE GENERATION for a specific MCU . some of the
51    routines may be reusable, will have to see */
52
53 static char *zero = "#0";
54 static char *one = "#1";
55 static char *spname;
56
57 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
58 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
59
60 unsigned fReturnSizeDS390 = 5;
61 static char *fReturn24[] =
62 {"dpl", "dph", "dpx", "b", "a"};
63 static char *fReturn16[] =
64 {"dpl", "dph", "b", "a"};
65 static char **fReturn = fReturn24;
66 static char *accUse[] =
67 {"a", "b"};
68 static char *dptrn[2][3];
69 static char *javaRet[] = { "r0","r1","r2","r3"};
70 static short rbank = -1;
71
72 #define REG_WITH_INDEX   ds390_regWithIdx
73
74 #define AOP(op) op->aop
75 #define AOP_TYPE(op) AOP(op)->type
76 #define AOP_SIZE(op) AOP(op)->size
77 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
78                        AOP_TYPE(x) == AOP_R0))
79
80 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
81                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
82                          AOP(x)->paged))
83
84 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
85                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
86                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
87 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
88 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
89 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
90
91 // The following two macros can be used even if the aop has not yet been aopOp'd.
92 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
93 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
94
95 /* Workaround for DS80C390 bug: div ab may return bogus results
96  * if A is accessed in instruction immediately before the div.
97  *
98  * Will be fixed in B4 rev of processor, Dallas claims.
99  */
100
101 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
102     if (!AOP_NEEDSACC(RIGHT))         \
103     {               \
104       /* We can load A first, then B, since     \
105        * B (the RIGHT operand) won't clobber A,   \
106        * thus avoiding touching A right before the div. \
107        */             \
108       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
109       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
110       MOVA(L);            \
111       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
112       MOVB(L); \
113     }               \
114     else              \
115     {               \
116       /* Just stuff in a nop after loading A. */    \
117       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
118       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
119       MOVA(L);            \
120       emitcode("nop", "; workaround for DS80C390 div bug.");  \
121     }
122
123 #define R0INB   _G.bu.bs.r0InB
124 #define R1INB   _G.bu.bs.r1InB
125 #define OPINB   _G.bu.bs.OpInB
126 #define BINUSE  _G.bu.BInUse
127
128 static struct
129   {
130     short r0Pushed;
131     short r1Pushed;
132     union
133       {
134         struct
135           {
136             short r0InB : 2;//2 so we can see it overflow
137             short r1InB : 2;//2 so we can see it overflow
138             short OpInB : 2;//2 so we can see it overflow
139           } bs;
140         short BInUse;
141       } bu;
142     short accInUse;
143     short inLine;
144     short debugLine;
145     short nRegsSaved;
146     short dptrInUse;
147     short dptr1InUse;
148     set *sendSet;
149     iCode *current_iCode;
150     symbol *currentFunc;
151   }
152 _G;
153
154 static char *rb1regs[] = {
155     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
156     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
157 };
158
159 static void saveRBank (int, iCode *, bool);
160
161 #define RESULTONSTACK(x) \
162                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
163                          IC_RESULT(x)->aop->type == AOP_STK )
164
165 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
166 #define MOVB(x)  movb(x)
167
168 #define CLRC    emitcode("clr","c")
169 #define SETC    emitcode("setb","c")
170
171 // A scratch register which will be used to hold
172 // result bytes from operands in far space via DPTR2.
173 #define DP2_RESULT_REG  "_ap"
174
175 static lineNode *lineHead = NULL;
176 static lineNode *lineCurr = NULL;
177
178 static unsigned char SLMask[] =
179 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
180  0xE0, 0xC0, 0x80, 0x00};
181 static unsigned char SRMask[] =
182 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
183  0x07, 0x03, 0x01, 0x00};
184
185 #define LSB     0
186 #define MSB16   1
187 #define MSB24   2
188 #define MSB32   3
189 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
190                                 symbol *lbl = newiTempLabel(NULL);              \
191                                 emitcode ("setb","F1");                         \
192                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
193                                 emitcode ("clr","F1");                          \
194                                 emitcode ("","!tlabeldef",lbl->key+100);        \
195                         }}
196 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
197                                 emitcode ("mov","EA,F1");                       \
198                         }}
199
200 static int _currentDPS;         /* Current processor DPS. */
201 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
202 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
203
204 /*-----------------------------------------------------------------*/
205 /* emitcode - writes the code into a file : for now it is simple    */
206 /*-----------------------------------------------------------------*/
207 static void
208 emitcode (char *inst, const char *fmt,...)
209 {
210   va_list ap;
211   char lb[INITIAL_INLINEASM];
212   char *lbp = lb;
213
214   va_start (ap, fmt);
215
216   if (inst && *inst)
217     {
218       if (fmt && *fmt)
219         {
220           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
221         }
222       else
223         {
224           SNPRINTF (lb, sizeof(lb), "%s", inst);
225         }
226
227       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
228     }
229   else
230     {
231       tvsprintf (lb, sizeof(lb), fmt, ap);
232     }
233
234   while (isspace ((unsigned char)*lbp))
235     {
236       lbp++;
237     }
238
239   if (lbp && *lbp)
240     {
241       lineCurr = (lineCurr ?
242                   connectLine (lineCurr, newLineNode (lb)) :
243                   (lineHead = newLineNode (lb)));
244     }
245
246   lineCurr->isInline = _G.inLine;
247   lineCurr->isDebug = _G.debugLine;
248   lineCurr->ic = _G.current_iCode;
249   lineCurr->aln = ds390newAsmLineNode(_currentDPS);
250   va_end (ap);
251 }
252
253 static void
254 emitLabel (symbol *tlbl)
255 {
256   emitcode ("", "!tlabeldef", tlbl->key + 100);
257 }
258
259 /*-----------------------------------------------------------------*/
260 /* ds390_emitDebuggerSymbol - associate the current code location  */
261 /*   with a debugger symbol                                        */
262 /*-----------------------------------------------------------------*/
263 void
264 ds390_emitDebuggerSymbol (char * debugSym)
265 {
266   _G.debugLine = 1;
267   emitcode ("", "%s ==.", debugSym);
268   _G.debugLine = 0;
269 }
270
271 /*-----------------------------------------------------------------*/
272 /* mova - moves specified value into accumulator                   */
273 /*-----------------------------------------------------------------*/
274 static void
275 mova (const char *x)
276 {
277   /* do some early peephole optimization */
278   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
279     return;
280
281   emitcode("mov", "a,%s", x);
282 }
283
284 /*-----------------------------------------------------------------*/
285 /* movb - moves specified value into register b                    */
286 /*-----------------------------------------------------------------*/
287 static void
288 movb (const char *x)
289 {
290   /* do some early peephole optimization */
291   if (!strncmp(x, "b", 2))
292     return;
293
294   emitcode("mov","b,%s", x);
295 }
296
297 /*-----------------------------------------------------------------*/
298 /* movc - moves specified value into the carry                     */
299 /*-----------------------------------------------------------------*/
300 static void
301 movc (const char *s)
302 {
303   if (s == zero)
304     CLRC;
305   else if (s == one)
306     SETC;
307   else if (strcmp (s, "c"))
308     {/* it's not in carry already */
309       MOVA (s);
310       /* set C, if a >= 1 */
311       emitcode ("add", "a,#0xff");
312     }
313 }
314
315 /*-----------------------------------------------------------------*/
316 /* pushB - saves register B if necessary                           */
317 /*-----------------------------------------------------------------*/
318 static bool
319 pushB (void)
320 {
321   bool pushedB = FALSE;
322
323   if (BINUSE)
324     {
325       emitcode ("push", "b");
326 //    printf("B was in use !\n");
327       pushedB = TRUE;
328     }
329   else
330     {
331       OPINB++;
332     }
333   return pushedB;
334 }
335
336 /*-----------------------------------------------------------------*/
337 /* popB - restores value of register B if necessary                */
338 /*-----------------------------------------------------------------*/
339 static void
340 popB (bool pushedB)
341 {
342   if (pushedB)
343     {
344       emitcode ("pop", "b");
345     }
346   else
347     {
348       OPINB--;
349     }
350 }
351
352 /*-----------------------------------------------------------------*/
353 /* pushReg - saves register                                        */
354 /*-----------------------------------------------------------------*/
355 static bool
356 pushReg (int index, bool bits_pushed)
357 {
358   regs * reg = REG_WITH_INDEX (index);
359   if (reg->type == REG_BIT)
360     {
361       if (!bits_pushed)
362         emitcode ("push", "%s", reg->base);
363       return TRUE;
364     }
365   else
366     emitcode ("push", "%s", reg->dname);
367   return bits_pushed;
368 }
369
370 /*-----------------------------------------------------------------*/
371 /* popReg - restores register                                      */
372 /*-----------------------------------------------------------------*/
373 static bool
374 popReg (int index, bool bits_popped)
375 {
376   regs * reg = REG_WITH_INDEX (index);
377   if (reg->type == REG_BIT)
378     {
379       if (!bits_popped)
380         emitcode ("pop", "%s", reg->base);
381       return TRUE;
382     }
383   else
384     emitcode ("pop", "%s", reg->dname);
385   return bits_popped;
386 }
387
388 /*-----------------------------------------------------------------*/
389 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
390 /*-----------------------------------------------------------------*/
391 static regs *
392 getFreePtr (iCode * ic, asmop ** aopp, bool result)
393 {
394   bool r0iu, r1iu;
395   bool r0ou, r1ou;
396
397   /* the logic: if r0 & r1 used in the instruction
398      then we are in trouble otherwise */
399
400   /* first check if r0 & r1 are used by this
401      instruction, in which case we are in trouble */
402   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
403   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
404   if (r0iu && r1iu) {
405       goto endOfWorld;
406     }
407
408   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
409   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
410
411   /* if no usage of r0 then return it */
412   if (!r0iu && !r0ou)
413     {
414       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
415       (*aopp)->type = AOP_R0;
416
417       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
418     }
419
420   /* if no usage of r1 then return it */
421   if (!r1iu && !r1ou)
422     {
423       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
424       (*aopp)->type = AOP_R1;
425
426       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
427     }
428
429   /* now we know they both have usage */
430   /* if r0 not used in this instruction */
431   if (!r0iu)
432     {
433       /* push it if not already pushed */
434       if (!_G.r0Pushed)
435         {
436           emitcode ("push", "%s",
437                     REG_WITH_INDEX (R0_IDX)->dname);
438           _G.r0Pushed++;
439         }
440
441       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
442       (*aopp)->type = AOP_R0;
443
444       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
445     }
446
447   /* if r1 not used then */
448
449   if (!r1iu)
450     {
451       /* push it if not already pushed */
452       if (!_G.r1Pushed)
453         {
454           emitcode ("push", "%s",
455                     REG_WITH_INDEX (R1_IDX)->dname);
456           _G.r1Pushed++;
457         }
458
459       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
460       (*aopp)->type = AOP_R1;
461       return REG_WITH_INDEX (R1_IDX);
462     }
463
464 endOfWorld:
465   /* I said end of world, but not quite end of world yet */
466   /* if this is a result then we can push it on the stack */
467   if (result)
468     {
469       (*aopp)->type = AOP_STK;
470       return NULL;
471     }
472
473   /* now this is REALLY the end of the world */
474   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
475           "getFreePtr should never reach here");
476   exit (1);
477
478   return NULL; // notreached, but makes compiler happy.
479 }
480
481
482 /*-----------------------------------------------------------------*/
483 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
484 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
485 /* alternate DPTR (DPL1/DPH1/DPX1).          */
486 /*-----------------------------------------------------------------*/
487 static void
488 genSetDPTR (int n)
489 {
490
491   /* If we are doing lazy evaluation, simply note the desired
492    * change, but don't emit any code yet.
493    */
494   if (_lazyDPS)
495     {
496       _desiredDPS = n;
497       return;
498     }
499
500   if (!n)
501     {
502       emitcode ("mov", "dps,#0");
503     }
504   else
505     {
506       TR_DPTR("#1");
507       emitcode ("mov", "dps,#1");
508     }
509 }
510
511 /*------------------------------------------------------------------*/
512 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
513 /*                                                                  */
514 /* Any code that operates on DPTR (NB: not on the individual        */
515 /* components, like DPH) *must* call _flushLazyDPS() before using   */
516 /* DPTR within a lazy DPS evaluation block.                         */
517 /*                                                                  */
518 /* Note that aopPut and aopGet already contain the proper calls to  */
519 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
520 /* DPS evaluation block.                                            */
521 /*                                                                  */
522 /* Also, _flushLazyDPS must be called before any flow control       */
523 /* operations that could potentially branch out of the block.       */
524 /*                                                                  */
525 /* Lazy DPS evaluation is simply an optimization (though an         */
526 /* important one), so if in doubt, leave it out.                    */
527 /*------------------------------------------------------------------*/
528 static void
529 _startLazyDPSEvaluation (void)
530 {
531   _currentDPS = 0;
532   _desiredDPS = 0;
533 #ifdef BETTER_LITERAL_SHIFT
534   _lazyDPS++;
535 #else
536   _lazyDPS = 1;
537 #endif
538 }
539
540 /*------------------------------------------------------------------*/
541 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
542 /* desired one. Call before using DPTR within a lazy DPS evaluation */
543 /* block.                                                           */
544 /*------------------------------------------------------------------*/
545 static void
546 _flushLazyDPS (void)
547 {
548   if (!_lazyDPS)
549     {
550       /* nothing to do. */
551       return;
552     }
553
554   if (_desiredDPS != _currentDPS)
555     {
556       if (_desiredDPS)
557         {
558           emitcode ("inc", "dps");
559         }
560       else
561         {
562           emitcode ("dec", "dps");
563         }
564       _currentDPS = _desiredDPS;
565     }
566 }
567
568 /*-----------------------------------------------------------------*/
569 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.     */
570 /*                   */
571 /* Forces us back to the safe state (standard DPTR selected).    */
572 /*-----------------------------------------------------------------*/
573 static void
574 _endLazyDPSEvaluation (void)
575 {
576 #ifdef BETTER_LITERAL_SHIFT
577   _lazyDPS--;
578 #else
579   _lazyDPS = 0;
580 #endif
581   if (!_lazyDPS)
582   {
583     if (_currentDPS)
584     {
585       genSetDPTR (0);
586       _flushLazyDPS ();
587     }
588     _currentDPS = 0;
589     _desiredDPS = 0;
590   }
591 }
592
593
594 /*-----------------------------------------------------------------*/
595 /* newAsmop - creates a new asmOp                                  */
596 /*-----------------------------------------------------------------*/
597 static asmop *
598 newAsmop (short type)
599 {
600   asmop *aop;
601
602   aop = Safe_calloc (1, sizeof (asmop));
603   aop->type = type;
604   aop->allocated = 1;
605   return aop;
606 }
607
608 /*-----------------------------------------------------------------*/
609 /* pointerCode - returns the code for a pointer type               */
610 /*-----------------------------------------------------------------*/
611 static int
612 pointerCode (sym_link * etype)
613 {
614
615   return PTR_TYPE (SPEC_OCLS (etype));
616
617 }
618
619 /*-----------------------------------------------------------------*/
620 /* leftRightUseAcc - returns size of accumulator use by operands   */
621 /*-----------------------------------------------------------------*/
622 static int
623 leftRightUseAcc(iCode *ic)
624 {
625   operand *op;
626   int size;
627   int accuseSize = 0;
628   int accuse = 0;
629
630   if (!ic)
631     {
632       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
633               "null iCode pointer");
634       return 0;
635     }
636
637   if (ic->op == IFX)
638     {
639       op = IC_COND (ic);
640       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
641         {
642           accuse = 1;
643           size = getSize (OP_SYMBOL (op)->type);
644           if (size>accuseSize)
645             accuseSize = size;
646         }
647     }
648   else if (ic->op == JUMPTABLE)
649     {
650       op = IC_JTCOND (ic);
651       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
652         {
653           accuse = 1;
654           size = getSize (OP_SYMBOL (op)->type);
655           if (size>accuseSize)
656             accuseSize = size;
657         }
658     }
659   else
660     {
661       op = IC_LEFT (ic);
662       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
663         {
664           accuse = 1;
665           size = getSize (OP_SYMBOL (op)->type);
666           if (size>accuseSize)
667             accuseSize = size;
668         }
669       op = IC_RIGHT (ic);
670       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
671         {
672           accuse = 1;
673           size = getSize (OP_SYMBOL (op)->type);
674           if (size>accuseSize)
675             accuseSize = size;
676         }
677     }
678
679   if (accuseSize)
680     return accuseSize;
681   else
682     return accuse;
683 }
684
685 /*-----------------------------------------------------------------*/
686 /* aopForSym - for a true symbol                                   */
687 /*-----------------------------------------------------------------*/
688 static asmop *
689 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
690 {
691   asmop *aop;
692   memmap *space;
693   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
694   char *dpl = useDP2 ? "dpl1" : "dpl";
695   char *dph = useDP2 ? "dph1" : "dph";
696   char *dpx = useDP2 ? "dpx1" : "dpx";
697
698   wassertl (ic != NULL, "Got a null iCode");
699   wassertl (sym != NULL, "Got a null symbol");
700
701   space = SPEC_OCLS (sym->etype);
702
703   /* if already has one */
704   if (sym->aop)
705     {
706       if ((sym->aop->type == AOP_DPTR && useDP2)
707           || (sym->aop->type == AOP_DPTR2 && !useDP2))
708         sym->aop = NULL;
709       else
710         {
711           sym->aop->allocated++;
712           return sym->aop;
713         }
714     }
715
716   /* assign depending on the storage class */
717   /* if it is on the stack or indirectly addressable */
718   /* space we need to assign either r0 or r1 to it   */
719   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
720     {
721       sym->aop = aop = newAsmop (0);
722       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
723       aop->size = getSize (sym->type);
724
725       /* now assign the address of the variable to
726          the pointer register */
727       if (aop->type != AOP_STK)
728         {
729           if (sym->onStack)
730             {
731               signed char offset = ((sym->stack < 0) ?
732                          ((signed char) (sym->stack - _G.nRegsSaved)) :
733                          ((signed char) sym->stack)) & 0xff;
734
735               if ((abs(offset) <= 3) ||
736                   (accuse && (abs(offset) <= 7)))
737                 {
738                   emitcode ("mov", "%s,_bp",
739                             aop->aopu.aop_ptr->name);
740                   while (offset < 0)
741                     {
742                       emitcode ("dec", aop->aopu.aop_ptr->name);
743                       offset++;
744                     }
745                   while (offset > 0)
746                     {
747                       emitcode ("inc", aop->aopu.aop_ptr->name);
748                       offset--;
749                     }
750                 }
751               else
752                 {
753                   if (accuse)
754                     emitcode ("push", "acc");
755                   emitcode ("mov", "a,_bp");
756                   emitcode ("add", "a,#!constbyte", offset);
757                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
758                   if (accuse)
759                     emitcode ("pop", "acc");
760                 }
761             }
762           else
763             {
764               emitcode ("mov", "%s,#%s",
765                         aop->aopu.aop_ptr->name,
766                         sym->rname);
767             }
768           aop->paged = space->paged;
769         }
770       else
771         aop->aopu.aop_stk = sym->stack;
772       return aop;
773     }
774
775   if (sym->onStack && options.stack10bit)
776     {
777         short stack_val = -((sym->stack < 0) ?
778                             ((short) (sym->stack - _G.nRegsSaved)) :
779                             ((short) sym->stack)) ;
780         if (_G.dptrInUse ) {
781             emitcode ("push",dpl);
782             emitcode ("push",dph);
783             emitcode ("push",dpx);
784         }
785       /* It's on the 10 bit stack, which is located in
786        * far data space.
787        */
788       if (stack_val < 0 && stack_val > -5)
789         { /* between -5 & -1 */
790           if (options.model == MODEL_FLAT24)
791             {
792                 emitcode ("mov", "%s,#!constbyte", dpx,
793                           (options.stack_loc >> 16) & 0xff);
794             }
795           emitcode ("mov", "%s,_bpx+1", dph);
796           emitcode ("mov", "%s,_bpx", dpl);
797           if (useDP2) {
798               emitcode ("mov","dps,#1");
799           }
800           stack_val = -stack_val;
801           while (stack_val--) {
802               emitcode ("inc","dptr");
803           }
804           if (useDP2) {
805               emitcode("mov","dps,#0");
806           }
807         }
808       else
809         {
810           if (accuse)
811               emitcode ("push", "acc");
812
813           emitcode ("mov", "a,_bpx");
814           emitcode ("clr","c");
815           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
816           emitcode ("mov","%s,a", dpl);
817           emitcode ("mov","a,_bpx+1");
818           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
819           emitcode ("mov", "%s,a", dph);
820           if (options.model == MODEL_FLAT24)
821             {
822               emitcode ("mov", "%s,#!constbyte", dpx,
823                         (options.stack_loc >> 16) & 0xff);
824             }
825
826           if (accuse)
827               emitcode ("pop", "acc");
828         }
829       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
830       aop->size = getSize (sym->type);
831       return aop;
832     }
833
834   /* if in bit space */
835   if (IN_BITSPACE (space))
836     {
837       sym->aop = aop = newAsmop (AOP_CRY);
838       aop->aopu.aop_dir = sym->rname;
839       aop->size = getSize (sym->type);
840       return aop;
841     }
842   /* if it is in direct space */
843   if (IN_DIRSPACE (space))
844     {
845       sym->aop = aop = newAsmop (AOP_DIR);
846       aop->aopu.aop_dir = sym->rname;
847       aop->size = getSize (sym->type);
848       return aop;
849     }
850
851   /* special case for a function */
852   if (IS_FUNC (sym->type) && !(sym->isitmp))
853     {
854       sym->aop = aop = newAsmop (AOP_IMMD);
855       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
856       aop->size = FPTRSIZE;
857       return aop;
858     }
859
860   /* only remaining is far space */
861   /* in which case DPTR gets the address */
862   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
863   if (useDP2)
864     {
865       genSetDPTR (1);
866       _flushLazyDPS ();
867       emitcode ("mov", "dptr,#%s", sym->rname);
868       genSetDPTR (0);
869     }
870   else
871     {
872       emitcode ("mov", "dptr,#%s", sym->rname);
873     }
874   aop->size = getSize (sym->type);
875
876   /* if it is in code space */
877   if (IN_CODESPACE (space))
878     aop->code = 1;
879
880   return aop;
881 }
882
883 /*-----------------------------------------------------------------*/
884 /* aopForRemat - rematerialzes an object                           */
885 /*-----------------------------------------------------------------*/
886 static asmop *
887 aopForRemat (symbol * sym)
888 {
889   iCode *ic = sym->rematiCode;
890   asmop *aop = newAsmop (AOP_IMMD);
891   int ptr_type = 0;
892   int val = 0;
893
894   for (;;)
895     {
896       if (ic->op == '+')
897         val += (int) operandLitValue (IC_RIGHT (ic));
898       else if (ic->op == '-')
899         val -= (int) operandLitValue (IC_RIGHT (ic));
900       else if (IS_CAST_ICODE(ic)) {
901               sym_link *from_type = operandType(IC_RIGHT(ic));
902               aop->aopu.aop_immd.from_cast_remat = 1;
903               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
904               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
905               continue;
906       } else break;
907
908       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
909     }
910
911   if (val)
912   {
913       SNPRINTF (buffer, sizeof(buffer),
914                 "(%s %c 0x%06x)",
915                 OP_SYMBOL (IC_LEFT (ic))->rname,
916                 val >= 0 ? '+' : '-',
917                 abs (val) & 0xffffff);
918   }
919   else
920   {
921       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
922       {
923           SNPRINTF(buffer, sizeof(buffer),
924                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
925       }
926       else
927       {
928           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
929       }
930   }
931
932   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
933   /* set immd2 field if required */
934   if (aop->aopu.aop_immd.from_cast_remat)
935   {
936       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
937       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
938   }
939
940   return aop;
941 }
942
943 /*-----------------------------------------------------------------*/
944 /* aopHasRegs - returns true if aop has regs between from-to       */
945 /*-----------------------------------------------------------------*/
946 static int aopHasRegs(asmop *aop, int from, int to)
947 {
948     int size =0;
949
950     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
951
952     for (; size < aop->size ; size++) {
953         int reg;
954         for (reg = from ; reg <= to ; reg++)
955             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
956     }
957     return 0;
958 }
959
960 /*-----------------------------------------------------------------*/
961 /* regsInCommon - two operands have some registers in common       */
962 /*-----------------------------------------------------------------*/
963 static bool
964 regsInCommon (operand * op1, operand * op2)
965 {
966   symbol *sym1, *sym2;
967   int i;
968
969   /* if they have registers in common */
970   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
971     return FALSE;
972
973   sym1 = OP_SYMBOL (op1);
974   sym2 = OP_SYMBOL (op2);
975
976   if (sym1->nRegs == 0 || sym2->nRegs == 0)
977     return FALSE;
978
979   for (i = 0; i < sym1->nRegs; i++)
980     {
981       int j;
982       if (!sym1->regs[i])
983         continue;
984
985       for (j = 0; j < sym2->nRegs; j++)
986         {
987           if (!sym2->regs[j])
988             continue;
989
990           if (sym2->regs[j] == sym1->regs[i])
991             return TRUE;
992         }
993     }
994
995   return FALSE;
996 }
997
998 /*-----------------------------------------------------------------*/
999 /* operandsEqu - equivalent                                        */
1000 /*-----------------------------------------------------------------*/
1001 static bool
1002 operandsEqu (operand * op1, operand * op2)
1003 {
1004   symbol *sym1, *sym2;
1005
1006   /* if they're not symbols */
1007   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1008     return FALSE;
1009
1010   sym1 = OP_SYMBOL (op1);
1011   sym2 = OP_SYMBOL (op2);
1012
1013   /* if both are itemps & one is spilt
1014      and the other is not then false */
1015   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1016       sym1->isspilt != sym2->isspilt)
1017     return FALSE;
1018
1019   /* if they are the same */
1020   if (sym1 == sym2)
1021     return TRUE;
1022
1023   /* if they have the same rname */
1024   if (sym1->rname[0] && sym2->rname[0] &&
1025       strcmp (sym1->rname, sym2->rname) == 0 &&
1026       !(IS_PARM (op2) && IS_ITEMP (op1)))
1027     return TRUE;
1028
1029   /* if left is a tmp & right is not */
1030   if (IS_ITEMP (op1) &&
1031       !IS_ITEMP (op2) &&
1032       sym1->isspilt &&
1033       (sym1->usl.spillLoc == sym2))
1034     return TRUE;
1035
1036   if (IS_ITEMP (op2) &&
1037       !IS_ITEMP (op1) &&
1038       sym2->isspilt &&
1039       sym1->level > 0 &&
1040       (sym2->usl.spillLoc == sym1))
1041     return TRUE;
1042
1043   /* are they spilt to the same location */
1044   if (IS_ITEMP (op2) &&
1045       IS_ITEMP (op1) &&
1046       sym2->isspilt &&
1047       sym1->isspilt &&
1048       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1049     return TRUE;
1050
1051   return FALSE;
1052 }
1053
1054 /*-----------------------------------------------------------------*/
1055 /* sameRegs - two asmops have the same registers                   */
1056 /*-----------------------------------------------------------------*/
1057 static bool
1058 sameRegs (asmop * aop1, asmop * aop2)
1059 {
1060   int i;
1061
1062   if (aop1 == aop2)
1063     {
1064       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1065         {
1066           return FALSE;
1067         }
1068       return TRUE;
1069     }
1070
1071   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1072     return FALSE;
1073
1074   if (aop1->type != aop2->type)
1075     return FALSE;
1076
1077   if (aop1->size != aop2->size)
1078     return FALSE;
1079
1080   for (i = 0; i < aop1->size; i++)
1081     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1082       return FALSE;
1083
1084   return TRUE;
1085 }
1086
1087 /*-----------------------------------------------------------------*/
1088 /* aopOp - allocates an asmop for an operand  :                    */
1089 /*-----------------------------------------------------------------*/
1090 static void
1091 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1092 {
1093   asmop *aop;
1094   symbol *sym;
1095   int i;
1096
1097   if (!op)
1098     return;
1099
1100   /* if this a literal */
1101   if (IS_OP_LITERAL (op))
1102     {
1103       op->aop = aop = newAsmop (AOP_LIT);
1104       aop->aopu.aop_lit = op->operand.valOperand;
1105       aop->size = getSize (operandType (op));
1106       return;
1107     }
1108
1109   /* if already has a asmop then continue */
1110   if (op->aop)
1111     {
1112       if ((op->aop->type == AOP_DPTR && useDP2)
1113           || (op->aop->type == AOP_DPTR2 && !useDP2))
1114         op->aop = NULL;
1115       else
1116         {
1117           op->aop->allocated++;
1118           return;
1119         }
1120     }
1121
1122   /* if the underlying symbol has a aop */
1123   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1124     {
1125       op->aop = OP_SYMBOL (op)->aop;
1126       if ((op->aop->type == AOP_DPTR && useDP2)
1127           || (op->aop->type == AOP_DPTR2 && !useDP2))
1128         op->aop = NULL;
1129       else
1130         {
1131           op->aop->allocated++;
1132           return;
1133         }
1134     }
1135
1136   /* if this is a true symbol */
1137   if (IS_TRUE_SYMOP (op))
1138     {
1139       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1140       return;
1141     }
1142
1143   /* this is a temporary : this has
1144      only five choices :
1145      a) register
1146      b) spillocation
1147      c) rematerialize
1148      d) conditional
1149      e) can be a return use only */
1150
1151   sym = OP_SYMBOL (op);
1152
1153   /* if the type is a conditional */
1154   if (sym->regType == REG_CND)
1155     {
1156       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1157       aop->size = 0;
1158       return;
1159     }
1160
1161   /* if it is spilt then two situations
1162      a) is rematerialize
1163      b) has a spill location */
1164   if (sym->isspilt || sym->nRegs == 0)
1165     {
1166
1167       /* rematerialize it NOW */
1168       if (sym->remat)
1169         {
1170           sym->aop = op->aop = aop =
1171             aopForRemat (sym);
1172           aop->size = getSize (sym->type);
1173           return;
1174         }
1175
1176       if (sym->accuse)
1177         {
1178           int i;
1179           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1180           aop->size = getSize (sym->type);
1181           for (i = 0; i < 2; i++)
1182             aop->aopu.aop_str[i] = accUse[i];
1183           return;
1184         }
1185
1186       if (sym->ruonly)
1187         {
1188           unsigned i;
1189
1190           if (useDP2)
1191             {
1192               /* a AOP_STR uses DPTR, but DPTR is already in use;
1193                * we're just hosed.
1194                */
1195                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1196             }
1197
1198           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1199           aop->size = getSize (sym->type);
1200           for (i = 0; i < fReturnSizeDS390; i++)
1201             aop->aopu.aop_str[i] = fReturn[i];
1202           return;
1203         }
1204
1205       if (sym->dptr) { /* has been allocated to a DPTRn */
1206           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1207           aop->size = getSize (sym->type);
1208           aop->aopu.dptr = sym->dptr;
1209           return ;
1210       }
1211
1212       if (sym->usl.spillLoc)
1213         {
1214           asmop *oldAsmOp = NULL;
1215
1216           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1217             {
1218               /* force a new aop if sizes differ */
1219               oldAsmOp = sym->usl.spillLoc->aop;
1220               sym->usl.spillLoc->aop = NULL;
1221             }
1222           sym->aop = op->aop = aop =
1223                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1224           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1225             {
1226               /* Don't reuse the new aop, go with the last one */
1227               sym->usl.spillLoc->aop = oldAsmOp;
1228             }
1229           aop->size = getSize (sym->type);
1230           return;
1231         }
1232
1233       /* else must be a dummy iTemp */
1234       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1235       aop->size = getSize (sym->type);
1236       return;
1237     }
1238
1239   /* if the type is a bit register */
1240   if (sym->regType == REG_BIT)
1241     {
1242       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1243       aop->size = sym->nRegs;//1???
1244       aop->aopu.aop_reg[0] = sym->regs[0];
1245       aop->aopu.aop_dir = sym->regs[0]->name;
1246       return;
1247     }
1248
1249   /* must be in a register */
1250   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1251   aop->size = sym->nRegs;
1252   for (i = 0; i < sym->nRegs; i++)
1253     aop->aopu.aop_reg[i] = sym->regs[i];
1254 }
1255
1256 /*-----------------------------------------------------------------*/
1257 /* freeAsmop - free up the asmop given to an operand               */
1258 /*----------------------------------------------------------------*/
1259 static void
1260 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1261 {
1262   asmop *aop;
1263
1264   if (!op)
1265     aop = aaop;
1266   else
1267     aop = op->aop;
1268
1269   if (!aop)
1270     return;
1271
1272   aop->allocated--;
1273
1274   if (aop->allocated)
1275     goto dealloc;
1276
1277   /* depending on the asmop type only three cases need work
1278      AOP_R0, AOP_R1 & AOP_STK */
1279   switch (aop->type)
1280     {
1281     case AOP_R0:
1282       if (_G.r0Pushed)
1283         {
1284           if (pop)
1285             {
1286               emitcode ("pop", "ar0");
1287               _G.r0Pushed--;
1288             }
1289         }
1290       bitVectUnSetBit (ic->rUsed, R0_IDX);
1291       break;
1292
1293     case AOP_R1:
1294       if (_G.r1Pushed)
1295         {
1296           if (pop)
1297             {
1298               emitcode ("pop", "ar1");
1299               _G.r1Pushed--;
1300             }
1301         }
1302       bitVectUnSetBit (ic->rUsed, R1_IDX);
1303       break;
1304
1305     case AOP_STK:
1306       {
1307         int sz = aop->size;
1308         int stk = aop->aopu.aop_stk + aop->size;
1309         bitVectUnSetBit (ic->rUsed, R0_IDX);
1310         bitVectUnSetBit (ic->rUsed, R1_IDX);
1311
1312         getFreePtr (ic, &aop, FALSE);
1313
1314         if (options.stack10bit)
1315           {
1316             /* I'm not sure what to do here yet... */
1317             /* #STUB */
1318             fprintf (stderr,
1319                      "*** Warning: probably generating bad code for "
1320                      "10 bit stack mode.\n");
1321           }
1322
1323         if (stk)
1324           {
1325             emitcode ("mov", "a,_bp");
1326             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1327             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1328           }
1329         else
1330           {
1331             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1332           }
1333
1334         while (sz--)
1335           {
1336             emitcode ("pop", "acc");
1337             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1338             if (!sz)
1339               break;
1340             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1341           }
1342         op->aop = aop;
1343         freeAsmop (op, NULL, ic, TRUE);
1344         if (_G.r1Pushed)
1345           {
1346             emitcode ("pop", "ar1");
1347             _G.r1Pushed--;
1348           }
1349         if (_G.r0Pushed)
1350           {
1351             emitcode ("pop", "ar0");
1352             _G.r0Pushed--;
1353           }
1354       }
1355     case AOP_DPTR2:
1356         if (_G.dptr1InUse) {
1357             emitcode ("pop","dpx1");
1358             emitcode ("pop","dph1");
1359             emitcode ("pop","dpl1");
1360         }
1361         break;
1362     case AOP_DPTR:
1363         if (_G.dptrInUse) {
1364             emitcode ("pop","dpx");
1365             emitcode ("pop","dph");
1366             emitcode ("pop","dpl");
1367         }
1368         break;
1369     }
1370
1371 dealloc:
1372   /* all other cases just dealloc */
1373   if (op)
1374     {
1375       op->aop = NULL;
1376       if (IS_SYMOP (op))
1377         {
1378           OP_SYMBOL (op)->aop = NULL;
1379           /* if the symbol has a spill */
1380           if (SPIL_LOC (op))
1381             SPIL_LOC (op)->aop = NULL;
1382         }
1383     }
1384 }
1385
1386 #define DEFAULT_ACC_WARNING 0
1387 static int saveAccWarn = DEFAULT_ACC_WARNING;
1388
1389
1390 /*-----------------------------------------------------------------*/
1391 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1392 /*                 clobber the accumulator                         */
1393 /*-----------------------------------------------------------------*/
1394 static bool
1395 aopGetUsesAcc (operand * oper, int offset)
1396 {
1397   asmop * aop = AOP (oper);
1398
1399   if (offset > (aop->size - 1))
1400     return FALSE;
1401
1402   switch (aop->type)
1403     {
1404
1405     case AOP_R0:
1406     case AOP_R1:
1407       if (aop->paged)
1408         return TRUE;
1409       return FALSE;
1410     case AOP_DPTR:
1411       return TRUE;
1412     case AOP_IMMD:
1413       return FALSE;
1414     case AOP_DIR:
1415       return FALSE;
1416     case AOP_REG:
1417       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1418       return FALSE;
1419     case AOP_CRY:
1420       return TRUE;
1421     case AOP_ACC:
1422       if (offset)
1423         return FALSE;
1424       return TRUE;
1425     case AOP_LIT:
1426       return FALSE;
1427     case AOP_STR:
1428       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1429         return TRUE;
1430       return FALSE;
1431     case AOP_DUMMY:
1432       return FALSE;
1433     default:
1434       /* Error case --- will have been caught already */
1435       wassert(0);
1436       return FALSE;
1437     }
1438 }
1439
1440 /*-------------------------------------------------------------------*/
1441 /* aopGet - for fetching value of the aop                            */
1442 /*                                                                   */
1443 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1444 /* in the accumulator. Set it to the name of a free register         */
1445 /* if acc must be preserved; the register will be used to preserve   */
1446 /* acc temporarily and to return the result byte.                    */
1447 /*-------------------------------------------------------------------*/
1448 static char *
1449 aopGet (operand * oper,
1450         int   offset,
1451         bool  bit16,
1452         bool  dname,
1453         char  *saveAcc)
1454 {
1455   asmop * aop = AOP (oper);
1456
1457   /* offset is greater than
1458      size then zero */
1459   if (offset > (aop->size - 1) &&
1460       aop->type != AOP_LIT)
1461     return zero;
1462
1463   /* depending on type */
1464   switch (aop->type)
1465     {
1466     case AOP_DUMMY:
1467       return zero;
1468
1469     case AOP_R0:
1470     case AOP_R1:
1471       /* if we need to increment it */
1472       while (offset > aop->coff)
1473         {
1474           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1475           aop->coff++;
1476         }
1477
1478       while (offset < aop->coff)
1479         {
1480           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1481           aop->coff--;
1482         }
1483
1484       aop->coff = offset;
1485       if (aop->paged)
1486         {
1487           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1488           return (dname ? "acc" : "a");
1489         }
1490       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1491       return Safe_strdup(buffer);
1492
1493     case AOP_DPTRn:
1494         assert(offset <= 3);
1495         return dptrn[aop->aopu.dptr][offset];
1496
1497     case AOP_DPTR:
1498     case AOP_DPTR2:
1499
1500       if (aop->type == AOP_DPTR2)
1501         {
1502           genSetDPTR (1);
1503         }
1504
1505       if (saveAcc)
1506         {
1507             TR_AP("#1");
1508 //          if (aop->type != AOP_DPTR2)
1509 //          {
1510 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1511 //              emitcode(";", "spanky: saveAcc for DPTR");
1512 //          }
1513
1514             emitcode ("xch", "a, %s", saveAcc);
1515         }
1516
1517       _flushLazyDPS ();
1518
1519       while (offset > aop->coff)
1520         {
1521           emitcode ("inc", "dptr");
1522           aop->coff++;
1523         }
1524
1525       while (offset < aop->coff)
1526         {
1527           emitcode ("lcall", "__decdptr");
1528           aop->coff--;
1529         }
1530
1531       aop->coff = offset;
1532       if (aop->code)
1533         {
1534           emitcode ("clr", "a");
1535           emitcode ("movc", "a,@a+dptr");
1536         }
1537       else
1538         {
1539           emitcode ("movx", "a,@dptr");
1540         }
1541
1542       if (aop->type == AOP_DPTR2)
1543         {
1544           genSetDPTR (0);
1545         }
1546
1547         if (saveAcc)
1548         {
1549        TR_AP("#2");
1550               emitcode ("xch", "a, %s", saveAcc);
1551 //            if (strcmp(saveAcc, "_ap"))
1552 //            {
1553 //                emitcode(";", "spiffy: non _ap return from aopGet.");
1554 //            }
1555
1556               return saveAcc;
1557         }
1558       return (dname ? "acc" : "a");
1559
1560     case AOP_IMMD:
1561       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1562       {
1563           SNPRINTF(buffer, sizeof(buffer),
1564                    "%s",aop->aopu.aop_immd.aop_immd2);
1565       }
1566       else if (bit16)
1567       {
1568          SNPRINTF(buffer, sizeof(buffer),
1569                   "#%s", aop->aopu.aop_immd.aop_immd1);
1570       }
1571       else if (offset)
1572       {
1573           switch (offset) {
1574           case 1:
1575               tsprintf(buffer, sizeof(buffer),
1576                        "#!his",aop->aopu.aop_immd.aop_immd1);
1577               break;
1578           case 2:
1579               tsprintf(buffer, sizeof(buffer),
1580                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1581               break;
1582           case 3:
1583               tsprintf(buffer, sizeof(buffer),
1584                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1585               break;
1586           default: /* should not need this (just in case) */
1587               SNPRINTF (buffer, sizeof(buffer),
1588                         "#(%s >> %d)",
1589                        aop->aopu.aop_immd.aop_immd1,
1590                        offset * 8);
1591           }
1592       }
1593       else
1594       {
1595         SNPRINTF (buffer, sizeof(buffer),
1596                   "#%s",
1597                   aop->aopu.aop_immd.aop_immd1);
1598       }
1599       return Safe_strdup(buffer);
1600
1601     case AOP_DIR:
1602       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1603         {
1604           SNPRINTF (buffer, sizeof(buffer),
1605                     "(%s >> %d)",
1606                     aop->aopu.aop_dir, offset * 8);
1607         }
1608       else if (offset)
1609         {
1610           SNPRINTF (buffer, sizeof(buffer),
1611                     "(%s + %d)",
1612                    aop->aopu.aop_dir,
1613                    offset);
1614         }
1615       else
1616         {
1617           SNPRINTF (buffer, sizeof(buffer),
1618                     "%s",
1619                     aop->aopu.aop_dir);
1620         }
1621
1622       return Safe_strdup(buffer);
1623
1624     case AOP_REG:
1625       if (dname)
1626         return aop->aopu.aop_reg[offset]->dname;
1627       else
1628         return aop->aopu.aop_reg[offset]->name;
1629
1630     case AOP_CRY:
1631       emitcode ("clr", "a");
1632       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1633       emitcode ("rlc", "a");
1634       return (dname ? "acc" : "a");
1635
1636     case AOP_ACC:
1637       if (!offset && dname)
1638         return "acc";
1639       return aop->aopu.aop_str[offset];
1640
1641     case AOP_LIT:
1642       return aopLiteral (aop->aopu.aop_lit, offset);
1643
1644     case AOP_STR:
1645       aop->coff = offset;
1646       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1647           dname)
1648         return "acc";
1649
1650       return aop->aopu.aop_str[offset];
1651
1652     }
1653
1654   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1655           "aopget got unsupported aop->type");
1656   exit (1);
1657
1658   return NULL;  // not reached, but makes compiler happy.
1659 }
1660
1661 /*-----------------------------------------------------------------*/
1662 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1663 /*                 clobber the accumulator                         */
1664 /*-----------------------------------------------------------------*/
1665 #if 0
1666 static bool
1667 aopPutUsesAcc (operand * oper, const char *s, int offset)
1668 {
1669   asmop * aop = AOP (oper);
1670
1671   if (offset > (aop->size - 1))
1672     return FALSE;
1673
1674   switch (aop->type)
1675     {
1676     case AOP_DUMMY:
1677       return TRUE;
1678     case AOP_DIR:
1679       return FALSE;
1680     case AOP_REG:
1681       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1682       return FALSE;
1683     case AOP_DPTR:
1684       return TRUE;
1685     case AOP_R0:
1686     case AOP_R1:
1687       return ((aop->paged) || (*s == '@'));
1688     case AOP_STK:
1689       return (*s == '@');
1690     case AOP_CRY:
1691       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1692     case AOP_STR:
1693       return FALSE;
1694     case AOP_IMMD:
1695       return FALSE;
1696     case AOP_ACC:
1697       return FALSE;
1698     default:
1699       /* Error case --- will have been caught already */
1700       wassert(0);
1701       return FALSE;
1702     }
1703 }
1704 #endif
1705
1706 /*-----------------------------------------------------------------*/
1707 /* aopPut - puts a string for a aop and indicates if acc is in use */
1708 /*-----------------------------------------------------------------*/
1709 static bool
1710 aopPut (operand * result, const char *s, int offset)
1711 {
1712   bool bvolatile = isOperandVolatile (result, FALSE);
1713   bool accuse = FALSE;
1714   asmop * aop = AOP (result);
1715
1716   if (aop->size && offset > (aop->size - 1))
1717     {
1718       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1719               "aopPut got offset > aop->size");
1720       exit (1);
1721     }
1722
1723   /* will assign value to value */
1724   /* depending on where it is ofcourse */
1725   switch (aop->type)
1726     {
1727     case AOP_DUMMY:
1728       MOVA (s);         /* read s in case it was volatile */
1729       accuse = TRUE;
1730       break;
1731
1732     case AOP_DIR:
1733       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1734         {
1735           SNPRINTF (buffer, sizeof(buffer),
1736                     "(%s >> %d)",
1737                     aop->aopu.aop_dir, offset * 8);
1738         }
1739       else if (offset)
1740         {
1741           SNPRINTF (buffer, sizeof(buffer),
1742                     "(%s + %d)",
1743                     aop->aopu.aop_dir, offset);
1744         }
1745       else
1746         {
1747           SNPRINTF (buffer, sizeof(buffer),
1748                     "%s",
1749                     aop->aopu.aop_dir);
1750         }
1751
1752       if (strcmp (buffer, s) || bvolatile)
1753         {
1754           emitcode ("mov", "%s,%s", buffer, s);
1755         }
1756       if (!strcmp (buffer, "acc"))
1757         {
1758           accuse = TRUE;
1759         }
1760       break;
1761
1762     case AOP_REG:
1763       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1764           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1765         {
1766           if (*s == '@' ||
1767               strcmp (s, "r0") == 0 ||
1768               strcmp (s, "r1") == 0 ||
1769               strcmp (s, "r2") == 0 ||
1770               strcmp (s, "r3") == 0 ||
1771               strcmp (s, "r4") == 0 ||
1772               strcmp (s, "r5") == 0 ||
1773               strcmp (s, "r6") == 0 ||
1774               strcmp (s, "r7") == 0)
1775             {
1776               emitcode ("mov", "%s,%s",
1777                         aop->aopu.aop_reg[offset]->dname, s);
1778             }
1779             else
1780             {
1781               emitcode ("mov", "%s,%s",
1782                         aop->aopu.aop_reg[offset]->name, s);
1783             }
1784         }
1785       break;
1786
1787     case AOP_DPTRn:
1788         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1789         break;
1790
1791     case AOP_DPTR:
1792     case AOP_DPTR2:
1793
1794       if (aop->type == AOP_DPTR2)
1795         {
1796           genSetDPTR (1);
1797         }
1798       _flushLazyDPS ();
1799
1800       if (aop->code)
1801         {
1802           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1803                   "aopPut writing to code space");
1804           exit (1);
1805         }
1806
1807       while (offset > aop->coff)
1808         {
1809           aop->coff++;
1810           emitcode ("inc", "dptr");
1811         }
1812
1813       while (offset < aop->coff)
1814         {
1815           aop->coff--;
1816           emitcode ("lcall", "__decdptr");
1817         }
1818
1819       aop->coff = offset;
1820
1821       /* if not in accumulator */
1822       MOVA (s);
1823
1824       emitcode ("movx", "@dptr,a");
1825
1826       if (aop->type == AOP_DPTR2)
1827         {
1828           genSetDPTR (0);
1829         }
1830       break;
1831
1832     case AOP_R0:
1833     case AOP_R1:
1834       while (offset > aop->coff)
1835         {
1836           aop->coff++;
1837           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1838         }
1839       while (offset < aop->coff)
1840         {
1841           aop->coff--;
1842           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1843         }
1844       aop->coff = offset;
1845
1846       if (aop->paged)
1847         {
1848           MOVA (s);
1849           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1850         }
1851       else if (*s == '@')
1852         {
1853           MOVA (s);
1854           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1855         }
1856       else if (strcmp (s, "r0") == 0 ||
1857                strcmp (s, "r1") == 0 ||
1858                strcmp (s, "r2") == 0 ||
1859                strcmp (s, "r3") == 0 ||
1860                strcmp (s, "r4") == 0 ||
1861                strcmp (s, "r5") == 0 ||
1862                strcmp (s, "r6") == 0 ||
1863                strcmp (s, "r7") == 0)
1864         {
1865           char buffer[10];
1866           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1867           emitcode ("mov", "@%s,%s",
1868                     aop->aopu.aop_ptr->name, buffer);
1869         }
1870         else
1871         {
1872             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1873         }
1874       break;
1875
1876     case AOP_STK:
1877       if (strcmp (s, "a") == 0)
1878         emitcode ("push", "acc");
1879       else
1880         if (*s=='@') {
1881           MOVA(s);
1882           emitcode ("push", "acc");
1883         } else {
1884           emitcode ("push", s);
1885         }
1886
1887       break;
1888
1889     case AOP_CRY:
1890       /* if not bit variable */
1891       if (!aop->aopu.aop_dir)
1892         {
1893           /* inefficient: move carry into A and use jz/jnz */
1894           emitcode ("clr", "a");
1895           emitcode ("rlc", "a");
1896           accuse = TRUE;
1897         }
1898       else
1899         {
1900           if (s == zero)
1901             emitcode ("clr", "%s", aop->aopu.aop_dir);
1902           else if (s == one)
1903             emitcode ("setb", "%s", aop->aopu.aop_dir);
1904           else if (!strcmp (s, "c"))
1905             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1906           else if (strcmp (s, aop->aopu.aop_dir))
1907             {
1908                   MOVA (s);
1909                 /* set C, if a >= 1 */
1910                 emitcode ("add", "a,#!constbyte",0xff);
1911                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1912               }
1913             }
1914       break;
1915
1916     case AOP_STR:
1917       aop->coff = offset;
1918       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1919         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1920       break;
1921
1922     case AOP_ACC:
1923       accuse = TRUE;
1924       aop->coff = offset;
1925       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1926         break;
1927
1928       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1929         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1930       break;
1931
1932     default:
1933       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1934               "aopPut got unsupported aop->type");
1935       exit (1);
1936     }
1937
1938     return accuse;
1939 }
1940
1941
1942 /*--------------------------------------------------------------------*/
1943 /* reAdjustPreg - points a register back to where it should (coff==0) */
1944 /*--------------------------------------------------------------------*/
1945 static void
1946 reAdjustPreg (asmop * aop)
1947 {
1948   if ((aop->coff==0) || (aop->size <= 1))
1949     return;
1950
1951   switch (aop->type)
1952     {
1953     case AOP_R0:
1954     case AOP_R1:
1955       while (aop->coff--)
1956         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1957       break;
1958     case AOP_DPTR:
1959     case AOP_DPTR2:
1960       if (aop->type == AOP_DPTR2)
1961         {
1962           genSetDPTR (1);
1963           _flushLazyDPS ();
1964         }
1965       while (aop->coff--)
1966         {
1967           emitcode ("lcall", "__decdptr");
1968         }
1969
1970       if (aop->type == AOP_DPTR2)
1971         {
1972           genSetDPTR (0);
1973         }
1974       break;
1975     }
1976   aop->coff = 0;
1977 }
1978
1979 /*-----------------------------------------------------------------*/
1980 /* opIsGptr: returns non-zero if the passed operand is       */
1981 /* a generic pointer type.             */
1982 /*-----------------------------------------------------------------*/
1983 static int
1984 opIsGptr (operand * op)
1985 {
1986   sym_link *type = operandType (op);
1987
1988   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1989     {
1990       return 1;
1991     }
1992   return 0;
1993 }
1994
1995 /*-----------------------------------------------------------------*/
1996 /* getDataSize - get the operand data size                         */
1997 /*-----------------------------------------------------------------*/
1998 static int
1999 getDataSize (operand * op)
2000 {
2001   int size;
2002   size = AOP_SIZE (op);
2003   if (size == GPTRSIZE)
2004     {
2005       sym_link *type = operandType (op);
2006       if (IS_GENPTR (type))
2007         {
2008           /* generic pointer; arithmetic operations
2009            * should ignore the high byte (pointer type).
2010            */
2011           size--;
2012         }
2013     }
2014   return size;
2015 }
2016
2017 /*-----------------------------------------------------------------*/
2018 /* outAcc - output Acc                                             */
2019 /*-----------------------------------------------------------------*/
2020 static void
2021 outAcc (operand * result)
2022 {
2023   int size, offset;
2024   size = getDataSize (result);
2025   if (size)
2026     {
2027       aopPut (result, "a", 0);
2028       size--;
2029       offset = 1;
2030       /* unsigned or positive */
2031       while (size--)
2032         {
2033           aopPut (result, zero, offset++);
2034         }
2035     }
2036 }
2037
2038 /*-----------------------------------------------------------------*/
2039 /* outBitC - output a bit C                                        */
2040 /*-----------------------------------------------------------------*/
2041 static void
2042 outBitC (operand * result)
2043 {
2044   /* if the result is bit */
2045   if (AOP_TYPE (result) == AOP_CRY)
2046     {
2047       aopPut (result, "c", 0);
2048     }
2049   else
2050     {
2051       emitcode ("clr", "a");
2052       emitcode ("rlc", "a");
2053       outAcc (result);
2054     }
2055 }
2056
2057 /*-----------------------------------------------------------------*/
2058 /* toBoolean - emit code for orl a,operator(sizeop)                */
2059 /*-----------------------------------------------------------------*/
2060 static void
2061 toBoolean (operand * oper)
2062 {
2063   int  size = AOP_SIZE (oper) - 1;
2064   int  offset = 1;
2065   bool pushedB;
2066
2067   /* The generic part of a generic pointer should
2068    * not participate in it's truth value.
2069    *
2070    * i.e. 0x10000000 is zero.
2071    */
2072   if (opIsGptr (oper))
2073     {
2074       D (emitcode (";", "toBoolean: generic ptr special case."));
2075       size--;
2076     }
2077
2078   _startLazyDPSEvaluation ();
2079   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2080   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2081     {
2082       pushedB = pushB ();
2083       emitcode("mov", "b,a");
2084       while (--size)
2085         {
2086         MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2087           emitcode ("orl", "b,a");
2088         }
2089       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2090       emitcode ("orl", "a,b");
2091       popB (pushedB);
2092     }
2093   else
2094     {
2095       while (size--)
2096         {
2097           emitcode ("orl", "a,%s",
2098                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2099         }
2100     }
2101   _endLazyDPSEvaluation ();
2102 }
2103
2104
2105 /*-----------------------------------------------------------------*/
2106 /* genNot - generate code for ! operation                          */
2107 /*-----------------------------------------------------------------*/
2108 static void
2109 genNot (iCode * ic)
2110 {
2111   symbol *tlbl;
2112
2113   D (emitcode (";", "genNot"));
2114
2115   /* assign asmOps to operand & result */
2116   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2117   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2118
2119   /* if in bit space then a special case */
2120   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2121     {
2122       /* if left==result then cpl bit */
2123       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2124         {
2125           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2126         }
2127       else
2128         {
2129           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2130           emitcode ("cpl", "c");
2131           outBitC (IC_RESULT (ic));
2132         }
2133       goto release;
2134     }
2135
2136   toBoolean (IC_LEFT (ic));
2137
2138   /* set C, if a == 0 */
2139   tlbl = newiTempLabel (NULL);
2140   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2141   emitLabel (tlbl);
2142   outBitC (IC_RESULT (ic));
2143
2144 release:
2145   /* release the aops */
2146   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2147   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2148 }
2149
2150
2151 /*-----------------------------------------------------------------*/
2152 /* genCpl - generate code for complement                           */
2153 /*-----------------------------------------------------------------*/
2154 static void
2155 genCpl (iCode * ic)
2156 {
2157   int offset = 0;
2158   int size;
2159   symbol *tlbl;
2160   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2161
2162   D(emitcode (";", "genCpl"));
2163
2164   /* assign asmOps to operand & result */
2165   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2166   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2167
2168   /* special case if in bit space */
2169   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2170     {
2171       char *l;
2172
2173       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2174           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2175         {
2176           /* promotion rules are responsible for this strange result:
2177              bit -> int -> ~int -> bit
2178              uchar -> int -> ~int -> bit
2179           */
2180           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2181           goto release;
2182         }
2183
2184       tlbl=newiTempLabel(NULL);
2185       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2186       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2187           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2188           IS_AOP_PREG (IC_LEFT (ic)))
2189         {
2190           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2191         }
2192       else
2193         {
2194           MOVA (l);
2195           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2196         }
2197       emitLabel (tlbl);
2198       outBitC (IC_RESULT(ic));
2199       goto release;
2200     }
2201
2202   size = AOP_SIZE (IC_RESULT (ic));
2203   _startLazyDPSEvaluation ();
2204   while (size--)
2205     {
2206       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2207       MOVA (l);
2208       emitcode ("cpl", "a");
2209       aopPut (IC_RESULT (ic), "a", offset++);
2210     }
2211   _endLazyDPSEvaluation ();
2212
2213
2214 release:
2215   /* release the aops */
2216   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2217   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2218 }
2219
2220 /*-----------------------------------------------------------------*/
2221 /* genUminusFloat - unary minus for floating points                */
2222 /*-----------------------------------------------------------------*/
2223 static void
2224 genUminusFloat (operand * op, operand * result)
2225 {
2226   int size, offset = 0;
2227   char *l;
2228
2229   D (emitcode (";", "genUminusFloat"));
2230
2231   /* for this we just copy and then flip the bit */
2232
2233   _startLazyDPSEvaluation ();
2234   size = AOP_SIZE (op) - 1;
2235
2236   while (size--)
2237     {
2238       aopPut (result,
2239               aopGet (op, offset, FALSE, FALSE, NULL),
2240               offset);
2241       offset++;
2242     }
2243
2244   l = aopGet (op, offset, FALSE, FALSE, NULL);
2245   MOVA (l);
2246
2247   emitcode ("cpl", "acc.7");
2248   aopPut (result, "a", offset);
2249   _endLazyDPSEvaluation ();
2250 }
2251
2252 /*-----------------------------------------------------------------*/
2253 /* genUminus - unary minus code generation                         */
2254 /*-----------------------------------------------------------------*/
2255 static void
2256 genUminus (iCode * ic)
2257 {
2258   int offset, size;
2259   sym_link *optype;
2260
2261   D (emitcode (";", "genUminus"));
2262
2263   /* assign asmops */
2264   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2265   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2266
2267   /* if both in bit space then special
2268      case */
2269   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2270       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2271     {
2272
2273       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2274       emitcode ("cpl", "c");
2275       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2276       goto release;
2277     }
2278
2279   optype = operandType (IC_LEFT (ic));
2280
2281   /* if float then do float stuff */
2282   if (IS_FLOAT (optype))
2283     {
2284       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2285       goto release;
2286     }
2287
2288   /* otherwise subtract from zero */
2289   size = AOP_SIZE (IC_LEFT (ic));
2290   offset = 0;
2291   _startLazyDPSEvaluation ();
2292   while (size--)
2293     {
2294       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2295       if (!strcmp (l, "a"))
2296         {
2297           if (offset == 0)
2298             SETC;
2299           emitcode ("cpl", "a");
2300           emitcode ("addc", "a,#0");
2301         }
2302       else
2303         {
2304           if (offset == 0)
2305             CLRC;
2306           emitcode ("clr", "a");
2307           emitcode ("subb", "a,%s", l);
2308         }
2309       aopPut (IC_RESULT (ic), "a", offset++);
2310     }
2311   _endLazyDPSEvaluation ();
2312
2313   /* if any remaining bytes in the result */
2314   /* we just need to propagate the sign   */
2315   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2316     {
2317       emitcode ("rlc", "a");
2318       emitcode ("subb", "a,acc");
2319       while (size--)
2320         aopPut (IC_RESULT (ic), "a", offset++);
2321     }
2322
2323 release:
2324   /* release the aops */
2325   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2326   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2327 }
2328
2329 /*-----------------------------------------------------------------*/
2330 /* savermask - saves registers in the mask                         */
2331 /*-----------------------------------------------------------------*/
2332 static void savermask(bitVect *rs_mask)
2333 {
2334   int i;
2335   if (options.useXstack)
2336     {
2337       if (bitVectBitValue (rs_mask, R0_IDX))
2338           emitcode ("mov", "b,r0");
2339       emitcode ("mov", "r0,%s", spname);
2340       for (i = 0; i < ds390_nRegs; i++)
2341         {
2342           if (bitVectBitValue (rs_mask, i))
2343             {
2344               if (i == R0_IDX)
2345                   emitcode ("mov", "a,b");
2346               else
2347                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2348               emitcode ("movx", "@r0,a");
2349               emitcode ("inc", "r0");
2350             }
2351         }
2352       emitcode ("mov", "%s,r0", spname);
2353       if (bitVectBitValue (rs_mask, R0_IDX))
2354           emitcode ("mov", "r0,b");
2355     }
2356   else
2357     {
2358       bool bits_pushed = FALSE;
2359       for (i = 0; i < ds390_nRegs; i++)
2360         {
2361           if (bitVectBitValue (rs_mask, i))
2362             {
2363               bits_pushed = pushReg (i, bits_pushed);
2364             }
2365         }
2366     }
2367 }
2368
2369 /*-----------------------------------------------------------------*/
2370 /* saveRegisters - will look for a call and save the registers     */
2371 /*-----------------------------------------------------------------*/
2372 static void
2373 saveRegisters (iCode * lic)
2374 {
2375   iCode *ic;
2376   bitVect *rsave;
2377
2378   /* look for call */
2379   for (ic = lic; ic; ic = ic->next)
2380     if (ic->op == CALL || ic->op == PCALL)
2381       break;
2382
2383   if (!ic)
2384     {
2385       fprintf (stderr, "found parameter push with no function call\n");
2386       return;
2387     }
2388
2389   /* if the registers have been saved already or don't need to be then
2390      do nothing */
2391   if (ic->regsSaved
2392       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2393     return ;
2394
2395   /* special case if DPTR alive across a function call then must save it
2396      even though callee saves */
2397   if (IS_SYMOP(IC_LEFT(ic)) &&
2398       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2399     {
2400       int i;
2401       rsave = newBitVect(ic->rMask->size);
2402       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2403           if (bitVectBitValue(ic->rMask,i))
2404               rsave = bitVectSetBit(rsave,i);
2405       }
2406       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2407     }
2408   else
2409     {
2410       /* save the registers in use at this time but skip the
2411          ones for the result */
2412       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2413                              ds390_rUmaskForOp (IC_RESULT(ic)));
2414     }
2415   ic->regsSaved = 1;
2416   savermask(rsave);
2417 }
2418
2419 /*-----------------------------------------------------------------*/
2420 /* usavermask - restore registers with mask                        */
2421 /*-----------------------------------------------------------------*/
2422 static void unsavermask(bitVect *rs_mask)
2423 {
2424     int i;
2425     if (options.useXstack) {
2426         emitcode ("mov", "r0,%s", spname);
2427       for (i = ds390_nRegs; i >= 0; i--)
2428         {
2429           if (bitVectBitValue (rs_mask, i))
2430             {
2431               regs * reg = REG_WITH_INDEX (i);
2432               emitcode ("dec", "r0");
2433               emitcode ("movx", "a,@r0");
2434               if (i == R0_IDX)
2435                 {
2436                   emitcode ("push", "acc");
2437                 }
2438               else
2439                 {
2440                   emitcode ("mov", "%s,a", reg->name);
2441                 }
2442             }
2443         }
2444       emitcode ("mov", "%s,r0", spname);
2445       if (bitVectBitValue (rs_mask, R0_IDX))
2446         {
2447           emitcode ("pop", "ar0");
2448         }
2449     }
2450   else
2451     {
2452       bool bits_popped = FALSE;
2453       for (i = ds390_nRegs; i >= 0; i--)
2454         {
2455             if (bitVectBitValue (rs_mask, i))
2456             {
2457               bits_popped = popReg (i, bits_popped);
2458             }
2459         }
2460     }
2461 }
2462
2463 /*-----------------------------------------------------------------*/
2464 /* unsaveRegisters - pop the pushed registers                      */
2465 /*-----------------------------------------------------------------*/
2466 static void
2467 unsaveRegisters (iCode * ic)
2468 {
2469   bitVect *rsave;
2470
2471   if (IS_SYMOP(IC_LEFT (ic)) &&
2472       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2473       int i;
2474       rsave = newBitVect(ic->rMask->size);
2475       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2476           if (bitVectBitValue(ic->rMask,i))
2477               rsave = bitVectSetBit(rsave,i);
2478       }
2479       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2480   } else {
2481     /* restore the registers in use at this time but skip the
2482        ones for the result */
2483     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2484                            ds390_rUmaskForOp (IC_RESULT(ic)));
2485   }
2486   unsavermask(rsave);
2487 }
2488
2489
2490 /*-----------------------------------------------------------------*/
2491 /* pushSide -                */
2492 /*-----------------------------------------------------------------*/
2493 static void
2494 pushSide (operand * oper, int size)
2495 {
2496   int offset = 0;
2497   _startLazyDPSEvaluation ();
2498   while (size--)
2499     {
2500       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2501       if (AOP_TYPE (oper) != AOP_REG &&
2502           AOP_TYPE (oper) != AOP_DIR &&
2503           strcmp (l, "a"))
2504         {
2505           MOVA (l);
2506           emitcode ("push", "acc");
2507         }
2508       else
2509         {
2510         emitcode ("push", "%s", l);
2511     }
2512     }
2513   _endLazyDPSEvaluation ();
2514 }
2515
2516 /*-----------------------------------------------------------------*/
2517 /* assignResultValue - also indicates if acc is in use afterwards  */
2518 /*-----------------------------------------------------------------*/
2519 static bool
2520 assignResultValue (operand * oper, operand * func)
2521 {
2522   int offset = 0;
2523   unsigned size = AOP_SIZE (oper);
2524   bool accuse = FALSE;
2525   bool pushedA = FALSE;
2526
2527   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2528     {
2529       outBitC (oper);
2530       return FALSE;
2531     }
2532
2533   if (size == fReturnSizeDS390)
2534   {
2535       /* I don't think this case can ever happen... */
2536       /* ACC is the last part of this. If writing the result
2537        * uses ACC, we must preserve it.
2538        */
2539       if (AOP_NEEDSACC(oper))
2540       {
2541           emitcode(";", "assignResultValue special case for ACC.");
2542           emitcode("push", "acc");
2543           pushedA = TRUE;
2544           size--;
2545       }
2546   }
2547
2548   _startLazyDPSEvaluation ();
2549   while (size--)
2550     {
2551       accuse |= aopPut (oper, fReturn[offset], offset);
2552       offset++;
2553     }
2554   _endLazyDPSEvaluation ();
2555
2556   if (pushedA)
2557     {
2558         emitcode ("pop", "acc");
2559         accuse |= aopPut (oper, "a", offset);
2560     }
2561   return accuse;
2562 }
2563
2564
2565 /*-----------------------------------------------------------------*/
2566 /* genXpush - pushes onto the external stack                       */
2567 /*-----------------------------------------------------------------*/
2568 static void
2569 genXpush (iCode * ic)
2570 {
2571   asmop *aop = newAsmop (0);
2572   regs *r;
2573   int size, offset = 0;
2574
2575   D (emitcode (";", "genXpush"));
2576
2577   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2578   r = getFreePtr (ic, &aop, FALSE);
2579
2580   size = AOP_SIZE (IC_LEFT (ic));
2581
2582   if (size == 1)
2583     {
2584       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2585       emitcode ("mov", "%s,_spx", r->name);
2586       emitcode ("inc", "_spx"); // allocate space first
2587       emitcode ("movx", "@%s,a", r->name);
2588     }
2589   else
2590     {
2591       // allocate space first
2592       emitcode ("mov", "%s,_spx", r->name);
2593       MOVA (r->name);
2594       emitcode ("add", "a,#%d", size);
2595       emitcode ("mov", "_spx,a");
2596
2597       _startLazyDPSEvaluation ();
2598       while (size--)
2599         {
2600           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2601           emitcode ("movx", "@%s,a", r->name);
2602           emitcode ("inc", "%s", r->name);
2603         }
2604       _endLazyDPSEvaluation ();
2605     }
2606
2607   freeAsmop (NULL, aop, ic, TRUE);
2608   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2609 }
2610
2611 /*-----------------------------------------------------------------*/
2612 /* genIpush - generate code for pushing this gets a little complex  */
2613 /*-----------------------------------------------------------------*/
2614 static void
2615 genIpush (iCode * ic)
2616 {
2617   int size, offset = 0;
2618   char *l;
2619   char *prev = "";
2620
2621   D (emitcode (";", "genIpush"));
2622
2623   /* if this is not a parm push : ie. it is spill push
2624      and spill push is always done on the local stack */
2625   if (!ic->parmPush)
2626     {
2627
2628       /* and the item is spilt then do nothing */
2629       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2630         return;
2631
2632       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2633       size = AOP_SIZE (IC_LEFT (ic));
2634       /* push it on the stack */
2635       _startLazyDPSEvaluation ();
2636       while (size--)
2637         {
2638           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2639           if (*l == '#')
2640             {
2641               MOVA (l);
2642               l = "acc";
2643             }
2644           emitcode ("push", "%s", l);
2645         }
2646       _endLazyDPSEvaluation ();
2647       return;
2648     }
2649
2650   /* this is a parameter push: in this case we call
2651      the routine to find the call and save those
2652      registers that need to be saved */
2653   saveRegisters (ic);
2654
2655   /* if use external stack then call the external
2656      stack pushing routine */
2657   if (options.useXstack)
2658     {
2659       genXpush (ic);
2660       return;
2661     }
2662
2663   /* then do the push */
2664   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2665
2666   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2667   size = AOP_SIZE (IC_LEFT (ic));
2668
2669   _startLazyDPSEvaluation ();
2670   while (size--)
2671     {
2672       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2673       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2674           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2675           strcmp (l, "acc"))
2676         {
2677           if (strcmp (l, prev) || *l == '@')
2678             MOVA (l);
2679           emitcode ("push", "acc");
2680         }
2681       else
2682         {
2683             emitcode ("push", "%s", l);
2684         }
2685       prev = l;
2686     }
2687   _endLazyDPSEvaluation ();
2688
2689   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2690 }
2691
2692 /*-----------------------------------------------------------------*/
2693 /* genIpop - recover the registers: can happen only for spilling   */
2694 /*-----------------------------------------------------------------*/
2695 static void
2696 genIpop (iCode * ic)
2697 {
2698   int size, offset;
2699
2700   D (emitcode (";", "genIpop"));
2701
2702   /* if the temp was not pushed then */
2703   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2704     return;
2705
2706   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2707   size = AOP_SIZE (IC_LEFT (ic));
2708   offset = (size - 1);
2709   _startLazyDPSEvaluation ();
2710   while (size--)
2711     {
2712       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2713                                      FALSE, TRUE, NULL));
2714     }
2715   _endLazyDPSEvaluation ();
2716
2717   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2718 }
2719
2720 /*-----------------------------------------------------------------*/
2721 /* saveRBank - saves an entire register bank on the stack          */
2722 /*-----------------------------------------------------------------*/
2723 static void
2724 saveRBank (int bank, iCode * ic, bool pushPsw)
2725 {
2726   int i;
2727   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2728   asmop *aop = NULL;
2729   regs *r = NULL;
2730
2731   if (options.useXstack)
2732   {
2733       if (!ic)
2734       {
2735           /* Assume r0 is available for use. */
2736           r = REG_WITH_INDEX (R0_IDX);;
2737       }
2738       else
2739       {
2740           aop = newAsmop (0);
2741           r = getFreePtr (ic, &aop, FALSE);
2742       }
2743       // allocate space first
2744       emitcode ("mov", "%s,_spx", r->name);
2745       MOVA (r->name);
2746       emitcode ("add", "a,#%d", count);
2747       emitcode ("mov", "_spx,a");
2748   }
2749
2750   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2751     {
2752       if (options.useXstack)
2753       {
2754           emitcode ("mov", "a,(%s+%d)",
2755                     regs390[i].base, 8 * bank + regs390[i].offset);
2756           emitcode ("movx", "@%s,a", r->name);
2757           if (--count)
2758             emitcode ("inc", "%s", r->name);
2759         }
2760       else
2761         emitcode ("push", "(%s+%d)",
2762                   regs390[i].base, 8 * bank + regs390[i].offset);
2763     }
2764
2765   if (ds390_nBitRegs > 0)
2766     {
2767       if (options.useXstack)
2768         {
2769           emitcode ("mov", "a,bits");
2770           emitcode ("movx", "@%s,a", r->name);
2771           if (--count)
2772             emitcode ("inc", "%s", r->name);
2773         }
2774       else
2775         {
2776           emitcode ("push", "bits");
2777         }
2778       BitBankUsed = 1;
2779     }
2780
2781   if (pushPsw)
2782     {
2783       if (options.useXstack)
2784         {
2785           emitcode ("mov", "a,psw");
2786           emitcode ("movx", "@%s,a", r->name);
2787         }
2788       else
2789       {
2790         emitcode ("push", "psw");
2791     }
2792
2793       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2794     }
2795
2796   if (aop)
2797   {
2798       freeAsmop (NULL, aop, ic, TRUE);
2799   }
2800
2801   if (ic)
2802   {
2803     ic->bankSaved = 1;
2804   }
2805 }
2806
2807 /*-----------------------------------------------------------------*/
2808 /* unsaveRBank - restores the register bank from stack             */
2809 /*-----------------------------------------------------------------*/
2810 static void
2811 unsaveRBank (int bank, iCode * ic, bool popPsw)
2812 {
2813   int i;
2814   asmop *aop = NULL;
2815   regs *r = NULL;
2816
2817   if (options.useXstack)
2818     {
2819         if (!ic)
2820         {
2821           /* Assume r0 is available for use. */
2822           r = REG_WITH_INDEX (R0_IDX);;
2823         }
2824         else
2825         {
2826           aop = newAsmop (0);
2827           r = getFreePtr (ic, &aop, FALSE);
2828         }
2829         emitcode ("mov", "%s,_spx", r->name);
2830     }
2831
2832   if (popPsw)
2833     {
2834       if (options.useXstack)
2835         {
2836           emitcode ("dec", "%s", r->name);
2837           emitcode ("movx", "a,@%s", r->name);
2838           emitcode ("mov", "psw,a");
2839         }
2840       else
2841       {
2842         emitcode ("pop", "psw");
2843       }
2844     }
2845
2846   if (ds390_nBitRegs > 0)
2847     {
2848       if (options.useXstack)
2849         {
2850           emitcode ("dec", "%s", r->name);
2851           emitcode ("movx", "a,@%s", r->name);
2852           emitcode ("mov", "bits,a");
2853         }
2854       else
2855         {
2856           emitcode ("pop", "bits");
2857         }
2858     }
2859
2860   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2861     {
2862       if (options.useXstack)
2863         {
2864           emitcode ("dec", "%s", r->name);
2865           emitcode ("movx", "a,@%s", r->name);
2866           emitcode ("mov", "(%s+%d),a",
2867                     regs390[i].base, 8 * bank + regs390[i].offset);
2868         }
2869       else
2870         {
2871           emitcode ("pop", "(%s+%d)",
2872                   regs390[i].base, 8 * bank + regs390[i].offset);
2873         }
2874     }
2875
2876   if (options.useXstack)
2877     {
2878       emitcode ("mov", "_spx,%s", r->name);
2879     }
2880
2881   if (aop)
2882   {
2883     freeAsmop (NULL, aop, ic, TRUE);
2884   }
2885 }
2886
2887 /*-----------------------------------------------------------------*/
2888 /* genSend - gen code for SEND                                     */
2889 /*-----------------------------------------------------------------*/
2890 static void genSend(set *sendSet)
2891 {
2892     iCode *sic;
2893   int bit_count = 0;
2894     int sendCount = 0 ;
2895     static int rb1_count = 0;
2896
2897   /* first we do all bit parameters */
2898     for (sic = setFirstItem (sendSet); sic;
2899        sic = setNextItem (sendSet))
2900     {
2901       if (sic->argreg > 12)
2902         {
2903           int bit = sic->argreg-13;
2904
2905           aopOp (IC_LEFT (sic), sic, FALSE,
2906                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2907
2908           /* if left is a literal then
2909              we know what the value is */
2910           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2911             {
2912               if (((int) operandLitValue (IC_LEFT (sic))))
2913                   emitcode ("setb", "b[%d]", bit);
2914               else
2915                   emitcode ("clr", "b[%d]", bit);
2916             }
2917           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2918             {
2919               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2920                 if (strcmp (l, "c"))
2921                     emitcode ("mov", "c,%s", l);
2922                 emitcode ("mov", "b[%d],c", bit);
2923             }
2924           else
2925             {
2926               /* we need to or */
2927               toBoolean (IC_LEFT (sic));
2928               /* set C, if a >= 1 */
2929               emitcode ("add", "a,#0xff");
2930               emitcode ("mov", "b[%d],c", bit);
2931             }
2932           bit_count++;
2933           BitBankUsed = 1;
2934
2935           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2936         }
2937     }
2938
2939   if (bit_count)
2940     {
2941       saveRegisters (setFirstItem (sendSet));
2942       emitcode ("mov", "bits,b");
2943     }
2944
2945   /* then we do all other parameters */
2946   for (sic = setFirstItem (sendSet); sic;
2947        sic = setNextItem (sendSet))
2948     {
2949       if (sic->argreg <= 12)
2950       {
2951         int size, offset = 0;
2952
2953         size = getSize (operandType (IC_LEFT (sic)));
2954         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2955         if (sendCount == 0) { /* first parameter */
2956             // we know that dpl(hxb) is the result, so
2957             rb1_count = 0 ;
2958             _startLazyDPSEvaluation ();
2959             if (size>1) {
2960                 aopOp (IC_LEFT (sic), sic, FALSE,
2961                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2962             } else {
2963                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2964             }
2965             while (size--)
2966               {
2967                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2968                 if (strcmp (l, fReturn[offset]))
2969                   {
2970                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2971                 }
2972                 offset++;
2973             }
2974             _endLazyDPSEvaluation ();
2975             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2976             rb1_count =0;
2977         } else { /* if more parameter in registers */
2978             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2979             while (size--) {
2980                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2981                                                                 FALSE, FALSE, NULL));
2982             }
2983             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2984         }
2985         sendCount++;
2986       }
2987     }
2988 }
2989
2990 static void
2991 adjustEsp(const char *reg)
2992 {
2993     emitcode ("anl","%s,#3", reg);
2994     if (TARGET_IS_DS400)
2995     {
2996         emitcode ("orl","%s,#!constbyte",
2997                   reg,
2998                   (options.stack_loc >> 8) & 0xff);
2999     }
3000 }
3001
3002 /*-----------------------------------------------------------------*/
3003 /* selectRegBank - emit code to select the register bank           */
3004 /*-----------------------------------------------------------------*/
3005 static void
3006 selectRegBank (short bank, bool keepFlags)
3007 {
3008   /* if f.e. result is in carry */
3009   if (keepFlags)
3010     {
3011       emitcode ("anl", "psw,#0xE7");
3012       if (bank)
3013         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
3014     }
3015   else
3016     {
3017       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
3018     }
3019 }
3020
3021 /*-----------------------------------------------------------------*/
3022 /* genCall - generates a call statement                            */
3023 /*-----------------------------------------------------------------*/
3024 static void
3025 genCall (iCode * ic)
3026 {
3027   sym_link *dtype;
3028   sym_link *etype;
3029   bool restoreBank = FALSE;
3030   bool swapBanks = FALSE;
3031   bool accuse = FALSE;
3032   bool accPushed = FALSE;
3033   bool resultInF0 = FALSE;
3034   bool assignResultGenerated = FALSE;
3035
3036   D (emitcode (";", "genCall"));
3037
3038   /* if we are calling a not _naked function that is not using
3039      the same register bank then we need to save the
3040      destination registers on the stack */
3041   dtype = operandType (IC_LEFT (ic));
3042   etype = getSpec(dtype);
3043   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3044       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3045       IFFUNC_ISISR (currFunc->type))
3046   {
3047       if (!ic->bankSaved)
3048       {
3049            /* This is unexpected; the bank should have been saved in
3050             * genFunction.
3051             */
3052            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3053            restoreBank = TRUE;
3054       }
3055       swapBanks = TRUE;
3056   }
3057
3058     /* if caller saves & we have not saved then */
3059     if (!ic->regsSaved)
3060       saveRegisters (ic);
3061
3062   /* if send set is not empty then assign */
3063   /* We've saved all the registers we care about;
3064   * therefore, we may clobber any register not used
3065   * in the calling convention (i.e. anything not in
3066   * fReturn.
3067   */
3068   if (_G.sendSet)
3069     {
3070         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3071             genSend(reverseSet(_G.sendSet));
3072         } else {
3073             genSend(_G.sendSet);
3074         }
3075       _G.sendSet = NULL;
3076     }
3077
3078   if (swapBanks)
3079   {
3080         emitcode ("mov", "psw,#!constbyte",
3081            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3082   }
3083
3084   /* make the call */
3085   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3086                             OP_SYMBOL (IC_LEFT (ic))->rname :
3087                             OP_SYMBOL (IC_LEFT (ic))->name));
3088
3089   if (swapBanks)
3090     {
3091       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3092     }
3093
3094   /* if we need assign a result value */
3095   if ((IS_ITEMP (IC_RESULT (ic)) &&
3096        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3097        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3098         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3099         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3100       IS_TRUE_SYMOP (IC_RESULT (ic)))
3101     {
3102       if (isOperandInFarSpace (IC_RESULT (ic))
3103           && getSize (operandType (IC_RESULT (ic))) <= 2)
3104         {
3105           int size = getSize (operandType (IC_RESULT (ic)));
3106           bool pushedB = FALSE;
3107
3108           /* Special case for 1 or 2 byte return in far space. */
3109           MOVA (fReturn[0]);
3110           if (size > 1)
3111             {
3112               pushedB = pushB ();
3113               emitcode ("mov", "b,%s", fReturn[1]);
3114             }
3115
3116           _G.accInUse++;
3117           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3118           _G.accInUse--;
3119
3120           popB (pushedB);
3121
3122           aopPut (IC_RESULT (ic), "a", 0);
3123
3124           if (size > 1)
3125             {
3126               aopPut (IC_RESULT (ic), "b", 1);
3127             }
3128           assignResultGenerated = TRUE;
3129           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3130         }
3131       else
3132         {
3133           bool pushedB = pushB ();
3134           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3135           popB (pushedB);
3136
3137           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3138           assignResultGenerated = TRUE;
3139           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3140         }
3141     }
3142
3143   /* adjust the stack for parameters if required */
3144   if (ic->parmBytes)
3145     {
3146       int i;
3147       if (options.stack10bit) {
3148           if (ic->parmBytes <= 10) {
3149               emitcode(";","stack adjustment for parms");
3150               for (i=0; i < ic->parmBytes ; i++) {
3151                   emitcode("pop","acc");
3152               }
3153           } else {
3154               PROTECT_SP;
3155               emitcode ("clr","c");
3156               emitcode ("mov","a,sp");
3157               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3158               emitcode ("mov","sp,a");
3159               emitcode ("mov","a,esp");
3160               adjustEsp("a");
3161               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3162               emitcode ("mov","esp,a");
3163               UNPROTECT_SP;
3164           }
3165       } else {
3166           if (ic->parmBytes > 3)
3167             {
3168               if (accuse)
3169                 {
3170                   emitcode ("push", "acc");
3171                   accPushed = TRUE;
3172                 }
3173             if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3174                 IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3175                 !assignResultGenerated)
3176               {
3177                 emitcode ("mov", "F0,c");
3178                 resultInF0 = TRUE;
3179               }
3180
3181               emitcode ("mov", "a,%s", spname);
3182               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3183               emitcode ("mov", "%s,a", spname);
3184
3185               /* unsaveRegisters from xstack needs acc, but */
3186               /* unsaveRegisters from stack needs this popped */
3187               if (accPushed && !options.useXstack)
3188                 {
3189                   emitcode ("pop", "acc");
3190                   accPushed = FALSE;
3191                 }
3192             }
3193           else
3194               for (i = 0; i < ic->parmBytes; i++)
3195                   emitcode ("dec", "%s", spname);
3196       }
3197   }
3198
3199   /* if we had saved some registers then unsave them */
3200   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3201     {
3202       if (accuse && !accPushed && options.useXstack)
3203         {
3204           /* xstack needs acc, but doesn't touch normal stack */
3205           emitcode ("push", "acc");
3206           accPushed = TRUE;
3207         }
3208       unsaveRegisters (ic);
3209     }
3210
3211   /* if register bank was saved then pop them */
3212   if (restoreBank)
3213     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3214
3215   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3216     {
3217       if (resultInF0)
3218           emitcode ("mov", "c,F0");
3219
3220       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3221       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3222       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3223     }
3224
3225   if (accPushed)
3226     emitcode ("pop", "acc");
3227 }
3228
3229 /*-----------------------------------------------------------------*/
3230 /* genPcall - generates a call by pointer statement                */
3231 /*-----------------------------------------------------------------*/
3232 static void
3233 genPcall (iCode * ic)
3234 {
3235   sym_link *dtype;
3236   sym_link *etype;
3237   symbol *rlbl = newiTempLabel (NULL);
3238   bool restoreBank=FALSE;
3239   bool resultInF0 = FALSE;
3240
3241   D (emitcode (";", "genPcall"));
3242
3243   dtype = operandType (IC_LEFT (ic))->next;
3244   etype = getSpec(dtype);
3245   /* if caller saves & we have not saved then */
3246   if (!ic->regsSaved)
3247     saveRegisters (ic);
3248
3249   /* if we are calling a not _naked function that is not using
3250      the same register bank then we need to save the
3251      destination registers on the stack */
3252   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3253       IFFUNC_ISISR (currFunc->type) &&
3254       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3255     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3256     restoreBank=TRUE;
3257   }
3258
3259   /* push the return address on to the stack */
3260   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3261   emitcode ("push", "acc");
3262   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3263   emitcode ("push", "acc");
3264
3265   if (options.model == MODEL_FLAT24)
3266     {
3267       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3268       emitcode ("push", "acc");
3269     }
3270
3271   /* now push the calling address */
3272   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3273
3274   pushSide (IC_LEFT (ic), FPTRSIZE);
3275
3276   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3277
3278   /* if send set is not empty the assign */
3279   if (_G.sendSet)
3280     {
3281         genSend(reverseSet(_G.sendSet));
3282         _G.sendSet = NULL;
3283     }
3284
3285   /* make the call */
3286   emitcode ("ret", "");
3287   emitLabel (rlbl);
3288
3289
3290   /* if we need assign a result value */
3291   if ((IS_ITEMP (IC_RESULT (ic)) &&
3292        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3293        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3294         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3295       IS_TRUE_SYMOP (IC_RESULT (ic)))
3296     {
3297
3298       _G.accInUse++;
3299       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3300       _G.accInUse--;
3301
3302       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3303
3304       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3305     }
3306
3307   /* adjust the stack for parameters if required */
3308   if (ic->parmBytes)
3309     {
3310       int i;
3311       if (options.stack10bit) {
3312           if (ic->parmBytes <= 10) {
3313               emitcode(";","stack adjustment for parms");
3314               for (i=0; i < ic->parmBytes ; i++) {
3315                   emitcode("pop","acc");
3316               }
3317           } else {
3318               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3319                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3320                 {
3321                   emitcode ("mov", "F0,c");
3322                   resultInF0 = TRUE;
3323                 }
3324
3325               PROTECT_SP;
3326               emitcode ("clr","c");
3327               emitcode ("mov","a,sp");
3328               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3329               emitcode ("mov","sp,a");
3330               emitcode ("mov","a,esp");
3331               adjustEsp("a");
3332               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3333               emitcode ("mov","esp,a");
3334               UNPROTECT_SP;
3335           }
3336       } else {
3337           if (ic->parmBytes > 3) {
3338               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3339                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3340                 {
3341                   emitcode ("mov", "F0,c");
3342                   resultInF0 = TRUE;
3343                 }
3344
3345               emitcode ("mov", "a,%s", spname);
3346               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3347               emitcode ("mov", "%s,a", spname);
3348             }
3349           else
3350               for (i = 0; i < ic->parmBytes; i++)
3351                   emitcode ("dec", "%s", spname);
3352       }
3353     }
3354   /* if register bank was saved then unsave them */
3355   if (restoreBank)
3356     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3357
3358   /* if we had saved some registers then unsave them */
3359   if (ic->regsSaved)
3360     unsaveRegisters (ic);
3361
3362   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3363     {
3364       if (resultInF0)
3365           emitcode ("mov", "c,F0");
3366
3367       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3368       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3369       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3370     }
3371 }
3372
3373 /*-----------------------------------------------------------------*/
3374 /* resultRemat - result  is rematerializable                       */
3375 /*-----------------------------------------------------------------*/
3376 static int
3377 resultRemat (iCode * ic)
3378 {
3379   if (SKIP_IC (ic) || ic->op == IFX)
3380     return 0;
3381
3382   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3383     {
3384       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3385       if (sym->remat && !POINTER_SET (ic))
3386         return 1;
3387     }
3388
3389   return 0;
3390 }
3391
3392 #if defined(__BORLANDC__) || defined(_MSC_VER)
3393 #define STRCASECMP stricmp
3394 #else
3395 #define STRCASECMP strcasecmp
3396 #endif
3397
3398 /*-----------------------------------------------------------------*/
3399 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3400 /*-----------------------------------------------------------------*/
3401 static int
3402 regsCmp(void *p1, void *p2)
3403 {
3404   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3405 }
3406
3407 static bool
3408 inExcludeList (char *s)
3409 {
3410   const char *p = setFirstItem(options.excludeRegsSet);
3411
3412   if (p == NULL || STRCASECMP(p, "none") == 0)
3413     return FALSE;
3414
3415
3416   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3417 }
3418
3419 /*-----------------------------------------------------------------*/
3420 /* genFunction - generated code for function entry                 */
3421 /*-----------------------------------------------------------------*/
3422 static void
3423 genFunction (iCode * ic)
3424 {
3425   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3426   sym_link *ftype;
3427   bool   switchedPSW = FALSE;
3428   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3429
3430   D (emitcode (";", "genFunction"));
3431
3432   _G.nRegsSaved = 0;
3433   /* create the function header */
3434   emitcode (";", "-----------------------------------------");
3435   emitcode (";", " function %s", sym->name);
3436   emitcode (";", "-----------------------------------------");
3437
3438   emitcode ("", "%s:", sym->rname);
3439   ftype = operandType (IC_LEFT (ic));
3440   _G.currentFunc = sym;
3441
3442   if (IFFUNC_ISNAKED(ftype))
3443   {
3444       emitcode(";", "naked function: no prologue.");
3445       return;
3446   }
3447
3448   if (options.stack_probe)
3449       emitcode ("lcall","__stack_probe");
3450
3451   /* here we need to generate the equates for the
3452      register bank if required */
3453   if (FUNC_REGBANK (ftype) != rbank)
3454     {
3455       int i;
3456
3457       rbank = FUNC_REGBANK (ftype);
3458       for (i = 0; i < ds390_nRegs; i++)
3459         {
3460           if (regs390[i].print) {
3461               if (strcmp (regs390[i].base, "0") == 0)
3462                   emitcode ("", "%s !equ !constbyte",
3463                             regs390[i].dname,
3464                             8 * rbank + regs390[i].offset);
3465               else
3466                   emitcode ("", "%s !equ %s + !constbyte",
3467                             regs390[i].dname,
3468                             regs390[i].base,
3469                             8 * rbank + regs390[i].offset);
3470           }
3471         }
3472     }
3473
3474   /* if this is an interrupt service routine then
3475      save acc, b, dpl, dph  */
3476   if (IFFUNC_ISISR (sym->type))
3477       { /* is ISR */
3478       if (!inExcludeList ("acc"))
3479         emitcode ("push", "acc");
3480       if (!inExcludeList ("b"))
3481         emitcode ("push", "b");
3482       if (!inExcludeList ("dpl"))
3483         emitcode ("push", "dpl");
3484       if (!inExcludeList ("dph"))
3485         emitcode ("push", "dph");
3486       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3487         {
3488           emitcode ("push", "dpx");
3489           /* Make sure we're using standard DPTR */
3490           emitcode ("push", "dps");
3491           emitcode ("mov", "dps,#0");
3492           if (options.stack10bit)
3493             {
3494               /* This ISR could conceivably use DPTR2. Better save it. */
3495               emitcode ("push", "dpl1");
3496               emitcode ("push", "dph1");
3497               emitcode ("push", "dpx1");
3498               emitcode ("push",  DP2_RESULT_REG);
3499             }
3500         }
3501       /* if this isr has no bank i.e. is going to
3502          run with bank 0 , then we need to save more
3503          registers :-) */
3504       if (!FUNC_REGBANK (sym->type))
3505         {
3506             int i;
3507
3508           /* if this function does not call any other
3509              function then we can be economical and
3510              save only those registers that are used */
3511           if (!IFFUNC_HASFCALL(sym->type))
3512             {
3513               /* if any registers used */
3514               if (sym->regsUsed)
3515                 {
3516                   bool bits_pushed = FALSE;
3517                   /* save the registers used */
3518                   for (i = 0; i < sym->regsUsed->size; i++)
3519                     {
3520                       if (bitVectBitValue (sym->regsUsed, i))
3521                         bits_pushed = pushReg (i, bits_pushed);
3522                     }
3523                 }
3524             }
3525           else
3526             {
3527               /* this function has a function call. We cannot
3528                  determine register usage so we will have to push the
3529                  entire bank */
3530               saveRBank (0, ic, FALSE);
3531               if (options.parms_in_bank1) {
3532                   for (i=0; i < 8 ; i++ ) {
3533                       emitcode ("push","%s",rb1regs[i]);
3534                   }
3535               }
3536             }
3537         }
3538         else
3539         {
3540             /* This ISR uses a non-zero bank.
3541              *
3542              * We assume that the bank is available for our
3543              * exclusive use.
3544              *
3545              * However, if this ISR calls a function which uses some
3546              * other bank, we must save that bank entirely.
3547              */
3548             unsigned long banksToSave = 0;
3549
3550             if (IFFUNC_HASFCALL(sym->type))
3551             {
3552
3553 #define MAX_REGISTER_BANKS 4
3554
3555                 iCode *i;
3556                 int ix;
3557
3558                 for (i = ic; i; i = i->next)
3559                 {
3560                     if (i->op == ENDFUNCTION)
3561                     {
3562                         /* we got to the end OK. */
3563                         break;
3564                     }
3565
3566                     if (i->op == CALL)
3567                     {
3568                         sym_link *dtype;
3569
3570                         dtype = operandType (IC_LEFT(i));
3571                         if (dtype
3572                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3573                         {
3574                              /* Mark this bank for saving. */
3575                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3576                              {
3577                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3578                              }
3579                              else
3580                              {
3581                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3582                              }
3583
3584                              /* And note that we don't need to do it in
3585                               * genCall.
3586                               */
3587                              i->bankSaved = 1;
3588                         }
3589                     }
3590                     if (i->op == PCALL)
3591                     {
3592                         /* This is a mess; we have no idea what
3593                          * register bank the called function might
3594                          * use.
3595                          *
3596                          * The only thing I can think of to do is
3597                          * throw a warning and hope.
3598                          */
3599                         werror(W_FUNCPTR_IN_USING_ISR);
3600                     }
3601                 }
3602
3603                 if (banksToSave && options.useXstack)
3604                 {
3605                     /* Since we aren't passing it an ic,
3606                      * saveRBank will assume r0 is available to abuse.
3607                      *
3608                      * So switch to our (trashable) bank now, so
3609                      * the caller's R0 isn't trashed.
3610                      */
3611                     emitcode ("push", "psw");
3612                     emitcode ("mov", "psw,#!constbyte",
3613                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3614                     switchedPSW = TRUE;
3615                 }
3616
3617                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3618                 {
3619                      if (banksToSave & (1 << ix))
3620                      {
3621                          saveRBank(ix, NULL, FALSE);
3622                      }
3623                 }
3624             }
3625             // TODO: this needs a closer look
3626             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3627         }
3628     }
3629   else
3630     {
3631       /* if callee-save to be used for this function
3632          then save the registers being used in this function */
3633       if (IFFUNC_CALLEESAVES(sym->type))
3634         {
3635           int i;
3636
3637           /* if any registers used */
3638           if (sym->regsUsed)
3639             {
3640               bool bits_pushed = FALSE;
3641               /* save the registers used */
3642               for (i = 0; i < sym->regsUsed->size; i++)
3643                 {
3644                   if (bitVectBitValue (sym->regsUsed, i))
3645                     {
3646                       bits_pushed = pushReg (i, bits_pushed);
3647                       _G.nRegsSaved++;
3648                     }
3649                 }
3650             }
3651         }
3652     }
3653
3654   /* set the register bank to the desired value */
3655   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3656    && !switchedPSW)
3657     {
3658       emitcode ("push", "psw");
3659       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3660     }
3661
3662   if (fReentrant &&
3663        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3664       if (options.stack10bit) {
3665           emitcode ("push","_bpx");
3666           emitcode ("push","_bpx+1");
3667           emitcode ("mov","_bpx,%s",spname);
3668           emitcode ("mov","_bpx+1,esp");
3669           adjustEsp("_bpx+1");
3670       } else {
3671           if (options.useXstack)
3672           {
3673               emitcode ("mov", "r0,%s", spname);
3674               emitcode ("mov", "a,_bp");
3675               emitcode ("movx", "@r0,a");
3676               emitcode ("inc", "%s", spname);
3677           } else {
3678               /* set up the stack */
3679               emitcode ("push", "_bp"); /* save the callers stack  */
3680           }
3681           emitcode ("mov", "_bp,%s", spname);
3682       }
3683   }
3684
3685   /* adjust the stack for the function */
3686   if (sym->stack) {
3687       int i = sym->stack;
3688       if (options.stack10bit) {
3689           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3690           assert (sym->recvSize <= 4);
3691           if (sym->stack <= 8) {
3692               while (i--) emitcode ("push","acc");
3693           } else {
3694               PROTECT_SP;
3695               emitcode ("mov","a,sp");
3696               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3697               emitcode ("mov","sp,a");
3698               emitcode ("mov","a,esp");
3699               adjustEsp("a");
3700               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3701               emitcode ("mov","esp,a");
3702               UNPROTECT_SP;
3703           }
3704       } else {
3705           if (i > 256)
3706               werror (W_STACK_OVERFLOW, sym->name);
3707
3708           if (i > 3 && sym->recvSize < 4) {
3709
3710               emitcode ("mov", "a,sp");
3711               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3712               emitcode ("mov", "sp,a");
3713
3714           } else
3715               while (i--)
3716                   emitcode ("inc", "sp");
3717       }
3718   }
3719
3720   if (sym->xstack)
3721     {
3722
3723       emitcode ("mov", "a,_spx");
3724       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3725       emitcode ("mov", "_spx,a");
3726     }
3727
3728   /* if critical function then turn interrupts off */
3729   if (IFFUNC_ISCRITICAL (ftype))
3730     {
3731       symbol *tlbl = newiTempLabel (NULL);
3732       emitcode ("setb", "c");
3733       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3734       emitcode ("clr", "c");
3735       emitLabel (tlbl);
3736       emitcode ("push", "psw"); /* save old ea via c in psw */
3737     }
3738 }
3739
3740 /*-----------------------------------------------------------------*/
3741 /* genEndFunction - generates epilogue for functions               */
3742 /*-----------------------------------------------------------------*/
3743 static void
3744 genEndFunction (iCode * ic)
3745 {
3746   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3747   lineNode *lnp = lineCurr;
3748   bitVect *regsUsed;
3749   bitVect *regsUsedPrologue;
3750   bitVect *regsUnneeded;
3751   int idx;
3752
3753   D (emitcode (";", "genEndFunction"));
3754
3755   _G.currentFunc = NULL;
3756   if (IFFUNC_ISNAKED(sym->type))
3757   {
3758       emitcode(";", "naked function: no epilogue.");
3759       if (options.debug && currFunc)
3760         debugFile->writeEndFunction (currFunc, ic, 0);
3761       return;
3762   }
3763
3764   if (IFFUNC_ISCRITICAL (sym->type))
3765     {
3766       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3767         {
3768           emitcode ("rlc", "a");   /* save c in a */
3769           emitcode ("pop", "psw"); /* restore ea via c in psw */
3770           emitcode ("mov", "ea,c");
3771           emitcode ("rrc", "a");   /* restore c from a */
3772         }
3773       else
3774         {
3775           emitcode ("pop", "psw"); /* restore ea via c in psw */
3776           emitcode ("mov", "ea,c");
3777         }
3778     }
3779
3780   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3781        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3782
3783       if (options.stack10bit) {
3784           PROTECT_SP;
3785           emitcode ("mov", "sp,_bpx", spname);
3786           emitcode ("mov", "esp,_bpx+1", spname);
3787           UNPROTECT_SP;
3788       } else {
3789           emitcode ("mov", "%s,_bp", spname);
3790       }
3791   }
3792
3793   /* if use external stack but some variables were
3794      added to the local stack then decrement the
3795      local stack */
3796   if (options.useXstack && sym->stack) {
3797       emitcode ("mov", "a,sp");
3798       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3799       emitcode ("mov", "sp,a");
3800   }
3801
3802
3803   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3804        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3805
3806       if (options.useXstack) {
3807           emitcode ("mov", "r0,%s", spname);
3808           emitcode ("movx", "a,@r0");
3809           emitcode ("mov", "_bp,a");
3810           emitcode ("dec", "%s", spname);
3811       } else {
3812           if (options.stack10bit) {
3813               emitcode ("pop", "_bpx+1");
3814               emitcode ("pop", "_bpx");
3815           } else {
3816               emitcode ("pop", "_bp");
3817           }
3818       }
3819   }
3820
3821   /* restore the register bank  */
3822   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3823   {
3824     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3825      || !options.useXstack)
3826     {
3827         /* Special case of ISR using non-zero bank with useXstack
3828          * is handled below.
3829          */
3830         emitcode ("pop", "psw");
3831     }
3832   }
3833
3834   if (IFFUNC_ISISR (sym->type))
3835       { /* is ISR */
3836
3837       /* now we need to restore the registers */
3838       /* if this isr has no bank i.e. is going to
3839          run with bank 0 , then we need to save more
3840          registers :-) */
3841       if (!FUNC_REGBANK (sym->type))
3842         {
3843             int i;
3844           /* if this function does not call any other
3845              function then we can be economical and
3846              save only those registers that are used */
3847           if (!IFFUNC_HASFCALL(sym->type))
3848             {
3849               /* if any registers used */
3850               if (sym->regsUsed)
3851                 {
3852                   bool bits_popped = FALSE;
3853                   /* save the registers used */
3854                   for (i = sym->regsUsed->size; i >= 0; i--)
3855                     {
3856                       if (bitVectBitValue (sym->regsUsed, i))
3857                         bits_popped = popReg (i, bits_popped);
3858                     }
3859                 }
3860             }
3861           else
3862             {
3863               /* this function has a function call. We cannot
3864                  determine register usage so we will have to pop the
3865                  entire bank */
3866               if (options.parms_in_bank1) {
3867                   for (i = 7 ; i >= 0 ; i-- ) {
3868                       emitcode ("pop","%s",rb1regs[i]);
3869                   }
3870               }
3871               unsaveRBank (0, ic, FALSE);
3872             }
3873         }
3874         else
3875         {
3876             /* This ISR uses a non-zero bank.
3877              *
3878              * Restore any register banks saved by genFunction
3879              * in reverse order.
3880              */
3881             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3882             int ix;
3883
3884             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3885             {
3886                 if (savedBanks & (1 << ix))
3887                 {
3888                     unsaveRBank(ix, NULL, FALSE);
3889                 }
3890             }
3891
3892             if (options.useXstack)
3893             {
3894                 /* Restore bank AFTER calling unsaveRBank,
3895                  * since it can trash r0.
3896                  */
3897                 emitcode ("pop", "psw");
3898             }
3899         }
3900
3901       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3902         {
3903           if (options.stack10bit)
3904             {
3905               emitcode ("pop", DP2_RESULT_REG);
3906               emitcode ("pop", "dpx1");
3907               emitcode ("pop", "dph1");
3908               emitcode ("pop", "dpl1");
3909             }
3910           emitcode ("pop", "dps");
3911           emitcode ("pop", "dpx");
3912         }
3913       if (!inExcludeList ("dph"))
3914         emitcode ("pop", "dph");
3915       if (!inExcludeList ("dpl"))
3916         emitcode ("pop", "dpl");
3917       if (!inExcludeList ("b"))
3918         emitcode ("pop", "b");
3919       if (!inExcludeList ("acc"))
3920         emitcode ("pop", "acc");
3921
3922       /* if debug then send end of function */
3923       if (options.debug && currFunc)
3924         {
3925           debugFile->writeEndFunction (currFunc, ic, 1);
3926         }
3927
3928       emitcode ("reti", "");
3929     }
3930   else
3931     {
3932       if (IFFUNC_CALLEESAVES(sym->type))
3933         {
3934           int i;
3935
3936           /* if any registers used */
3937           if (sym->regsUsed)
3938             {
3939               /* save the registers used */
3940               for (i = sym->regsUsed->size; i >= 0; i--)
3941                 {
3942                   if (bitVectBitValue (sym->regsUsed, i))
3943                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3944                 }
3945             }
3946         }
3947
3948       /* if debug then send end of function */
3949       if (options.debug && currFunc)
3950         {
3951           debugFile->writeEndFunction (currFunc, ic, 1);
3952         }
3953
3954       emitcode ("ret", "");
3955     }
3956
3957   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3958     return;
3959
3960   /* If this was an interrupt handler using bank 0 that called another */
3961   /* function, then all registers must be saved; nothing to optimized. */
3962   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3963       && !FUNC_REGBANK(sym->type))
3964     return;
3965
3966   /* There are no push/pops to optimize if not callee-saves or ISR */
3967   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3968     return;
3969
3970   /* If there were stack parameters, we cannot optimize without also    */
3971   /* fixing all of the stack offsets; this is too dificult to consider. */
3972   if (FUNC_HASSTACKPARM(sym->type))
3973     return;
3974
3975   /* Compute the registers actually used */
3976   regsUsed = newBitVect (ds390_nRegs);
3977   regsUsedPrologue = newBitVect (ds390_nRegs);
3978   while (lnp)
3979     {
3980       if (lnp->ic && lnp->ic->op == FUNCTION)
3981         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3982       else
3983         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3984
3985       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3986           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3987         break;
3988       if (!lnp->prev)
3989         break;
3990       lnp = lnp->prev;
3991     }
3992
3993   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3994       && !bitVectBitValue (regsUsed, DPS_IDX))
3995     {
3996       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3997     }
3998
3999   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
4000       && !bitVectBitValue (regsUsed, CND_IDX))
4001     {
4002       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4003       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
4004           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
4005         bitVectUnSetBit (regsUsed, CND_IDX);
4006     }
4007   else
4008     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4009
4010   /* If this was an interrupt handler that called another function */
4011   /* function, then assume working registers may be modified by it. */
4012   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
4013     {
4014       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
4015       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
4016       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
4017       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
4018       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
4019       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
4020       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4021       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
4022       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4023       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4024       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4025     }
4026
4027   /* Remove the unneeded push/pops */
4028   regsUnneeded = newBitVect (ds390_nRegs);
4029   while (lnp)
4030     {
4031       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4032         {
4033           if (!strncmp(lnp->line, "push", 4))
4034             {
4035               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4036               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4037                 {
4038                   connectLine (lnp->prev, lnp->next);
4039                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4040                 }
4041             }
4042           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4043             {
4044               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4045               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4046                 {
4047                   connectLine (lnp->prev, lnp->next);
4048                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4049                 }
4050             }
4051         }
4052       lnp = lnp->next;
4053     }
4054
4055   for (idx = 0; idx < regsUnneeded->size; idx++)
4056     if (bitVectBitValue (regsUnneeded, idx))
4057       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4058
4059   freeBitVect (regsUnneeded);
4060   freeBitVect (regsUsed);
4061   freeBitVect (regsUsedPrologue);
4062 }
4063
4064 /*-----------------------------------------------------------------*/
4065 /* genJavaNativeRet - generate code for return JavaNative          */
4066 /*-----------------------------------------------------------------*/
4067 static void genJavaNativeRet(iCode *ic)
4068 {
4069     int i, size;
4070
4071     aopOp (IC_LEFT (ic), ic, FALSE,
4072            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4073     size = AOP_SIZE (IC_LEFT (ic));
4074
4075     assert (size <= 4);
4076
4077     /* it is assigned to GPR0-R3 then push them */
4078     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4079         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4080         for (i = 0 ; i < size ; i++ ) {
4081             emitcode ("push","%s",
4082                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4083         }
4084         for (i = (size-1) ; i >= 0 ; i--) {
4085             emitcode ("pop","a%s",javaRet[i]);
4086         }
4087     } else {
4088         for (i = 0 ; i < size ; i++)
4089             emitcode ("mov","%s,%s",javaRet[i],
4090                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4091     }
4092     for (i = size ; i < 4 ; i++ )
4093             emitcode ("mov","%s,#0",javaRet[i]);
4094     return;
4095 }
4096
4097 /*-----------------------------------------------------------------*/
4098 /* genRet - generate code for return statement                     */
4099 /*-----------------------------------------------------------------*/
4100 static void
4101 genRet (iCode * ic)
4102 {
4103   int size, offset = 0, pushed = 0;
4104
4105   D (emitcode (";", "genRet"));
4106
4107   /* if we have no return value then
4108      just generate the "ret" */
4109   if (!IC_LEFT (ic))
4110     goto jumpret;
4111
4112   /* if this is a JavaNative function then return
4113      value in different register */
4114   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4115       genJavaNativeRet(ic);
4116       goto jumpret;
4117   }
4118   /* we have something to return then
4119      move the return value into place */
4120   aopOp (IC_LEFT (ic), ic, FALSE,
4121          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4122   size = AOP_SIZE (IC_LEFT (ic));
4123
4124   _startLazyDPSEvaluation ();
4125
4126   if (IS_BIT(_G.currentFunc->etype))
4127     {
4128       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4129       size = 0;
4130     }
4131
4132   while (size--)
4133     {
4134       char *l;
4135       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4136         {
4137           l = aopGet (IC_LEFT (ic), offset++,
4138                       FALSE, TRUE, NULL);
4139           emitcode ("push", "%s", l);
4140           pushed++;
4141         }
4142       else
4143         {
4144           /* Since A is the last element of fReturn,
4145            * it is OK to clobber it in the aopGet.
4146            */
4147           l = aopGet (IC_LEFT (ic), offset,
4148                       FALSE, FALSE, NULL);
4149           if (strcmp (fReturn[offset], l))
4150             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4151         }
4152     }
4153   _endLazyDPSEvaluation ();
4154
4155   while (pushed)
4156     {
4157       pushed--;
4158       if (strcmp (fReturn[pushed], "a"))
4159         emitcode ("pop", fReturn[pushed]);
4160       else
4161         emitcode ("pop", "acc");
4162     }
4163   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4164
4165 jumpret:
4166   /* generate a jump to the return label
4167      if the next is not the return statement */
4168   if (!(ic->next && ic->next->op == LABEL &&
4169         IC_LABEL (ic->next) == returnLabel))
4170
4171     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4172
4173 }
4174
4175 /*-----------------------------------------------------------------*/
4176 /* genLabel - generates a label                                    */
4177 /*-----------------------------------------------------------------*/
4178 static void
4179 genLabel (iCode * ic)
4180 {
4181   /* special case never generate */
4182   if (IC_LABEL (ic) == entryLabel)
4183     return;
4184
4185   D (emitcode (";", "genLabel"));
4186
4187   emitcode ("", "!tlabeldef", (IC_LABEL (ic)->key + 100));
4188 }
4189
4190 /*-----------------------------------------------------------------*/
4191 /* genGoto - generates a ljmp                                      */
4192 /*-----------------------------------------------------------------*/
4193 static void
4194 genGoto (iCode * ic)
4195 {
4196   D (emitcode (";", "genGoto"));
4197
4198   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4199 }
4200
4201 /*-----------------------------------------------------------------*/
4202 /* findLabelBackwards: walks back through the iCode chain looking  */
4203 /* for the given label. Returns number of iCode instructions     */
4204 /* between that label and given ic.          */
4205 /* Returns zero if label not found.          */
4206 /*-----------------------------------------------------------------*/
4207 static int
4208 findLabelBackwards (iCode * ic, int key)
4209 {
4210   int count = 0;
4211
4212   while (ic->prev)
4213     {
4214       ic = ic->prev;
4215       count++;
4216
4217       /* If we have any pushes or pops, we cannot predict the distance.
4218          I don't like this at all, this should be dealt with in the
4219          back-end */
4220       if (ic->op == IPUSH || ic->op == IPOP) {
4221         return 0;
4222       }
4223
4224       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4225         {
4226           /* printf("findLabelBackwards = %d\n", count); */
4227           return count;
4228         }
4229     }
4230
4231   return 0;
4232 }
4233
4234 /*-----------------------------------------------------------------*/
4235 /* genPlusIncr :- does addition with increment if possible         */
4236 /*-----------------------------------------------------------------*/
4237 static bool
4238 genPlusIncr (iCode * ic)
4239 {
4240   unsigned int icount;
4241   unsigned int size = getDataSize (IC_RESULT (ic));
4242
4243   /* will try to generate an increment */
4244   /* if the right side is not a literal
4245      we cannot */
4246   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4247     return FALSE;
4248
4249   /* if the literal value of the right hand side
4250      is greater than 4 then it is not worth it */
4251   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4252     return FALSE;
4253
4254   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4255       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4256       while (icount--) {
4257           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4258       }
4259       return TRUE;
4260   }
4261   /* if increment 16 bits in register */
4262   if (
4263        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4264        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4265        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4266        (size > 1) &&
4267        (icount == 1))
4268     {
4269       symbol  *tlbl;
4270       int     emitTlbl;
4271       int     labelRange;
4272       char    *l;
4273
4274       /* If the next instruction is a goto and the goto target
4275        * is <= 5 instructions previous to this, we can generate
4276        * jumps straight to that target.
4277        */
4278       if (ic->next && ic->next->op == GOTO
4279           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4280           && labelRange <= 5)
4281         {
4282           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4283           tlbl = IC_LABEL (ic->next);
4284           emitTlbl = 0;
4285         }
4286       else
4287         {
4288           tlbl = newiTempLabel (NULL);
4289           emitTlbl = 1;
4290         }
4291       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4292       emitcode ("inc", "%s", l);
4293
4294       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4295           IS_AOP_PREG (IC_RESULT (ic)))
4296         {
4297           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4298         }
4299       else
4300         {
4301           emitcode ("clr", "a");
4302           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4303         }
4304
4305       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4306       emitcode ("inc", "%s", l);
4307       if (size > 2)
4308         {
4309           if (!strcmp(l, "acc"))
4310             {
4311                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4312             }
4313           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4314                    IS_AOP_PREG (IC_RESULT (ic)))
4315             {
4316                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4317             }
4318           else
4319             {
4320                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4321             }
4322
4323           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4324           emitcode ("inc", "%s", l);
4325         }
4326       if (size > 3)
4327         {
4328           if (!strcmp(l, "acc"))
4329             {
4330                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4331             }
4332           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4333                    IS_AOP_PREG (IC_RESULT (ic)))
4334             {
4335                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4336             }
4337           else
4338             {
4339                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4340             }
4341
4342           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4343           emitcode ("inc", "%s", l);
4344         }
4345
4346       if (emitTlbl)
4347         {
4348           emitLabel (tlbl);
4349         }
4350       return TRUE;
4351     }
4352
4353   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4354       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4355       options.model == MODEL_FLAT24 )
4356     {
4357       if (IC_RESULT(ic)->isGptr)
4358         {
4359           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4360         }
4361       switch (size) {
4362       case 3:
4363           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4364       case 2:
4365           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4366       case 1:
4367           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4368           break;
4369       }
4370       while (icount--)
4371         emitcode ("inc", "dptr");
4372       return TRUE;
4373   }
4374
4375   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4376       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4377       icount <= 5 ) {
4378       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4379       while (icount--)
4380         emitcode ("inc", "dptr");
4381       emitcode ("mov", "dps,#0");
4382       return TRUE;
4383   }
4384
4385   /* if the sizes are greater than 1 then we cannot */
4386   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4387       AOP_SIZE (IC_LEFT (ic)) > 1)
4388     return FALSE;
4389
4390   /* we can if the aops of the left & result match or
4391      if they are in registers and the registers are the
4392      same */
4393   if (
4394        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4395        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4396        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4397     {
4398       if (icount > 3)
4399         {
4400           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4401           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4402           aopPut (IC_RESULT (ic), "a", 0);
4403         }
4404       else
4405         {
4406           _startLazyDPSEvaluation ();
4407           while (icount--)
4408             {
4409               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4410             }
4411           _endLazyDPSEvaluation ();
4412         }
4413
4414       return TRUE;
4415     }
4416
4417   return FALSE;
4418 }
4419
4420 /*-----------------------------------------------------------------*/
4421 /* outBitAcc - output a bit in acc                                 */
4422 /*-----------------------------------------------------------------*/
4423 static void
4424 outBitAcc (operand * result)
4425 {
4426   symbol *tlbl = newiTempLabel (NULL);
4427   /* if the result is a bit */
4428   if (AOP_TYPE (result) == AOP_CRY)
4429     {
4430       aopPut (result, "a", 0);
4431     }
4432   else
4433     {
4434       emitcode ("jz", "!tlabel", tlbl->key + 100);
4435       emitcode ("mov", "a,%s", one);
4436       emitLabel (tlbl);
4437       outAcc (result);
4438     }
4439 }
4440
4441 /*-----------------------------------------------------------------*/
4442 /* genPlusBits - generates code for addition of two bits           */
4443 /*-----------------------------------------------------------------*/
4444 static void
4445 genPlusBits (iCode * ic)
4446 {
4447   D (emitcode (";", "genPlusBits"));
4448
4449   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4450     {
4451       symbol *lbl = newiTempLabel (NULL);
4452       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4453       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4454       emitcode ("cpl", "c");
4455       emitLabel (lbl);
4456       outBitC (IC_RESULT (ic));
4457     }
4458   else
4459     {
4460       emitcode ("clr", "a");
4461       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4462       emitcode ("rlc", "a");
4463       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4464       emitcode ("addc", "a,%s", zero);
4465       outAcc (IC_RESULT (ic));
4466     }
4467 }
4468
4469 static void
4470 adjustArithmeticResult (iCode * ic)
4471 {
4472   if (opIsGptr (IC_RESULT (ic)) &&
4473       opIsGptr (IC_LEFT (ic)) &&
4474       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4475     {
4476       aopPut (IC_RESULT (ic),
4477               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4478               GPTRSIZE - 1);
4479     }
4480
4481   if (opIsGptr (IC_RESULT (ic)) &&
4482       opIsGptr (IC_RIGHT (ic)) &&
4483       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4484     {
4485       aopPut (IC_RESULT (ic),
4486               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4487               GPTRSIZE - 1);
4488     }
4489
4490   if (opIsGptr (IC_RESULT (ic)) &&
4491       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4492       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4493       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4494       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4495     {
4496       char buffer[5];
4497       SNPRINTF (buffer, sizeof(buffer),
4498                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4499       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4500     }
4501 }
4502
4503 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4504 // generates the result if possible. If result is generated, returns TRUE; otherwise
4505 // returns false and caller must deal with fact that result isn't aopOp'd.
4506 bool aopOp3(iCode * ic)
4507 {
4508     bool dp1InUse, dp2InUse;
4509     bool useDp2;
4510
4511     // First, generate the right opcode. DPTR may be used if neither left nor result are
4512     // of type AOP_STR.
4513
4514 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4515 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4516 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4517 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4518 //      );
4519 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4520 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4521 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4522 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4523 //      );
4524
4525     // Right uses DPTR unless left or result is an AOP_STR; however,
4526     // if right is an AOP_STR, it must use DPTR regardless.
4527     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4528      && !AOP_IS_STR (IC_RIGHT (ic)))
4529     {
4530         useDp2 = TRUE;
4531     }
4532     else
4533     {
4534         useDp2 = FALSE;
4535     }
4536
4537     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4538
4539     // if the right used DPTR, left MUST use DPTR2.
4540     // if the right used DPTR2, left MUST use DPTR.
4541     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4542     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4543     // enabling us to assign DPTR to result.
4544
4545     if (AOP_USESDPTR (IC_RIGHT (ic)))
4546     {
4547         useDp2 = TRUE;
4548     }
4549     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4550     {
4551         useDp2 = FALSE;
4552     }
4553     else
4554     {
4555         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4556         {
4557             useDp2 = TRUE;
4558         }
4559         else
4560         {
4561             useDp2 = FALSE;
4562         }
4563     }
4564
4565     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4566
4567
4568     // We've op'd the left & right. So, if left or right are the same operand as result,
4569     // we know aopOp will succeed, and we can just do it & bail.
4570     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4571       {
4572         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4573         return TRUE;
4574       }
4575     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4576       {
4577 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4578         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4579         return TRUE;
4580       }
4581
4582     // Operands may be equivalent (but not equal) if they share a spill location. If
4583     // so, use the same DPTR or DPTR2.
4584     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4585       {
4586         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4587         return TRUE;
4588       }
4589     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4590       {
4591         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4592         return TRUE;
4593       }
4594
4595     // Note which dptrs are currently in use.
4596     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4597     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4598
4599     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4600     // generate it.
4601     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4602     {
4603         return FALSE;
4604     }
4605
4606     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4607     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4608     {
4609         return FALSE;
4610     }
4611
4612     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4613     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4614     {
4615         return FALSE;
4616     }
4617
4618     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4619
4620     // Some sanity checking...
4621     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4622     {
4623         fprintf(stderr,
4624                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4625                 __FILE__, __LINE__, ic->filename, ic->lineno);
4626         emitcode(";", ">>> unexpected DPTR here.");
4627     }
4628
4629     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4630     {
4631         fprintf(stderr,
4632                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4633                 __FILE__, __LINE__, ic->filename, ic->lineno);
4634         emitcode(";", ">>> unexpected DPTR2 here.");
4635     }
4636
4637     return TRUE;
4638 }
4639
4640 // Macro to aopOp all three operands of an ic. If this cannot be done,
4641 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4642 // will be set TRUE. The caller must then handle the case specially, noting
4643 // that the IC_RESULT operand is not aopOp'd.
4644 //
4645 #define AOP_OP_3_NOFATAL(ic, rc) \
4646             do { rc = !aopOp3(ic); } while (0)
4647
4648 // aopOp the left & right operands of an ic.
4649 #define AOP_OP_2(ic) \
4650     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4651     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4652
4653 // convienience macro.
4654 #define AOP_SET_LOCALS(ic) \
4655     left = IC_LEFT(ic); \
4656     right = IC_RIGHT(ic); \
4657     result = IC_RESULT(ic);
4658
4659
4660 // Given an integer value of pushedSize bytes on the stack,
4661 // adjust it to be resultSize bytes, either by discarding
4662 // the most significant bytes or by zero-padding.
4663 //
4664 // On exit from this macro, pushedSize will have been adjusted to
4665 // equal resultSize, and ACC may be trashed.
4666 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4667       /* If the pushed data is bigger than the result,          \
4668        * simply discard unused bytes. Icky, but works.          \
4669        */                                                       \
4670       while (pushedSize > resultSize)                           \
4671       {                                                         \
4672           D (emitcode (";", "discarding unused result byte.")); \
4673           emitcode ("pop", "acc");                              \
4674           pushedSize--;                                         \
4675       }                                                         \
4676       if (pushedSize < resultSize)                              \
4677       {                                                         \
4678           emitcode ("clr", "a");                                \
4679           /* Conversly, we haven't pushed enough here.          \
4680            * just zero-pad, and all is well.                    \
4681            */                                                   \
4682           while (pushedSize < resultSize)                       \
4683           {                                                     \
4684               emitcode("push", "acc");                          \
4685               pushedSize++;                                     \
4686           }                                                     \
4687       }                                                         \
4688       assert(pushedSize == resultSize);
4689
4690 /*-----------------------------------------------------------------*/
4691 /* genPlus - generates code for addition                           */
4692 /*-----------------------------------------------------------------*/
4693 static void
4694 genPlus (iCode * ic)
4695 {
4696   int size, offset = 0;
4697   bool pushResult;
4698   int rSize;
4699   bool swappedLR = FALSE;
4700
4701   D (emitcode (";", "genPlus"));
4702
4703   /* special cases :- */
4704   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4705       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4706       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4707       size = (int)floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4708       if (size <= 9) {
4709           while (size--) emitcode ("inc","dptr");
4710       } else {
4711           emitcode ("mov", "a,dpl");
4712           emitcode ("add", "a,#!constbyte", size & 0xff);
4713           emitcode ("mov", "dpl,a");
4714           emitcode ("mov", "a,dph");
4715           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4716           emitcode ("mov", "dph,a");
4717           emitcode ("mov", "a,dpx");
4718           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4719           emitcode ("mov", "dpx,a");
4720       }
4721       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4722       return ;
4723   }
4724   if ( IS_SYMOP (IC_LEFT (ic)) &&
4725        OP_SYMBOL (IC_LEFT (ic))->remat &&
4726        isOperandInFarSpace (IC_RIGHT (ic))) {
4727       operand *op = IC_RIGHT(ic);
4728       IC_RIGHT(ic) = IC_LEFT(ic);
4729       IC_LEFT(ic) = op;
4730   }
4731
4732   AOP_OP_3_NOFATAL (ic, pushResult);
4733
4734   if (pushResult)
4735     {
4736       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4737     }
4738
4739   if (!pushResult)
4740     {
4741       /* if literal, literal on the right or
4742          if left requires ACC or right is already
4743          in ACC */
4744       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4745           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4746           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4747         {
4748           operand *t = IC_RIGHT (ic);
4749           IC_RIGHT (ic) = IC_LEFT (ic);
4750           IC_LEFT (ic) = t;
4751           swappedLR = TRUE;
4752           D (emitcode (";", "Swapped plus args."));
4753         }
4754
4755       /* if both left & right are in bit
4756          space */
4757       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4758           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4759         {
4760           genPlusBits (ic);
4761           goto release;
4762         }
4763
4764       /* if left in bit space & right literal */
4765       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4766           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4767         {
4768           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4769           /* if result in bit space */
4770           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4771             {
4772               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4773                 emitcode ("cpl", "c");
4774               outBitC (IC_RESULT (ic));
4775             }
4776           else
4777             {
4778               size = getDataSize (IC_RESULT (ic));
4779               _startLazyDPSEvaluation ();
4780               while (size--)
4781                 {
4782                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4783                   emitcode ("addc", "a,%s", zero);
4784                   aopPut (IC_RESULT (ic), "a", offset++);
4785                 }
4786               _endLazyDPSEvaluation ();
4787             }
4788           goto release;
4789         }
4790
4791       /* if I can do an increment instead
4792          of add then GOOD for ME */
4793       if (genPlusIncr (ic) == TRUE)
4794         {
4795           D (emitcode (";", "did genPlusIncr"));
4796           goto release;
4797         }
4798
4799     }
4800   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4801
4802   _startLazyDPSEvaluation ();
4803   while (size--)
4804     {
4805       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4806         {
4807           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4808           if (offset == 0)
4809             emitcode ("add", "a,%s",
4810                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4811           else
4812             emitcode ("addc", "a,%s",
4813                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4814         }
4815       else
4816         {
4817           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4818           {
4819               /* right is going to use ACC or we would have taken the
4820                * above branch.
4821                */
4822               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4823               TR_AP("#3");
4824               D(emitcode(";", "+ AOP_ACC special case."););
4825               emitcode("xch", "a, %s", DP2_RESULT_REG);
4826           }
4827           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4828           if (offset == 0)
4829           {
4830             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4831             {
4832                 TR_AP("#4");
4833                 emitcode("add", "a, %s", DP2_RESULT_REG);
4834             }
4835             else
4836             {
4837                 emitcode ("add", "a,%s",
4838                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4839                                   DP2_RESULT_REG));
4840             }
4841           }
4842           else
4843           {
4844             emitcode ("addc", "a,%s",
4845                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4846                           DP2_RESULT_REG));
4847           }
4848         }
4849       if (!pushResult)
4850         {
4851           aopPut (IC_RESULT (ic), "a", offset);
4852         }
4853       else
4854         {
4855           emitcode ("push", "acc");
4856         }
4857       offset++;
4858     }
4859   _endLazyDPSEvaluation ();
4860
4861   if (pushResult)
4862     {
4863       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4864
4865       size = getDataSize (IC_LEFT (ic));
4866       rSize = getDataSize (IC_RESULT (ic));
4867
4868       ADJUST_PUSHED_RESULT(size, rSize);
4869
4870       _startLazyDPSEvaluation ();
4871       while (size--)
4872         {
4873           emitcode ("pop", "acc");
4874           aopPut (IC_RESULT (ic), "a", size);
4875         }
4876       _endLazyDPSEvaluation ();
4877     }
4878
4879   adjustArithmeticResult (ic);
4880
4881 release:
4882   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4883   if (!swappedLR)
4884     {
4885       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4886       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4887     }
4888   else
4889     {
4890       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4891       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4892     }
4893 }
4894
4895 /*-----------------------------------------------------------------*/
4896 /* genMinusDec :- does subtraction with decrement if possible      */
4897 /*-----------------------------------------------------------------*/
4898 static bool
4899 genMinusDec (iCode * ic)
4900 {
4901   unsigned int icount;
4902   unsigned int size = getDataSize (IC_RESULT (ic));
4903
4904   /* will try to generate an increment */
4905   /* if the right side is not a literal
4906      we cannot */
4907   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4908     return FALSE;
4909
4910   /* if the literal value of the right hand side
4911      is greater than 4 then it is not worth it */
4912   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4913     return FALSE;
4914
4915   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4916       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4917       while (icount--) {
4918           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4919       }
4920       return TRUE;
4921   }
4922   /* if decrement 16 bits in register */
4923   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4924       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4925       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4926       (size > 1) &&
4927       (icount == 1))
4928     {
4929       symbol *tlbl;
4930       int    emitTlbl;
4931       int    labelRange;
4932       char   *l;
4933
4934       /* If the next instruction is a goto and the goto target
4935          * is <= 5 instructions previous to this, we can generate
4936          * jumps straight to that target.
4937        */
4938       if (ic->next && ic->next->op == GOTO
4939           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4940           && labelRange <= 5)
4941         {
4942           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4943           tlbl = IC_LABEL (ic->next);
4944           emitTlbl = 0;
4945         }
4946       else
4947         {
4948           tlbl = newiTempLabel (NULL);
4949           emitTlbl = 1;
4950         }
4951
4952       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4953       emitcode ("dec", "%s", l);
4954
4955       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4956           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4957           IS_AOP_PREG (IC_RESULT (ic)))
4958       {
4959           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4960       }
4961       else
4962       {
4963           emitcode ("mov", "a,#!constbyte",0xff);
4964           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4965       }
4966       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4967       emitcode ("dec", "%s", l);
4968       if (size > 2)
4969         {
4970             if (!strcmp(l, "acc"))
4971             {
4972                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4973             }
4974             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4975                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4976                      IS_AOP_PREG (IC_RESULT (ic)))
4977             {
4978                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4979             }
4980             else
4981             {
4982                 emitcode ("mov", "a,#!constbyte",0xff);
4983                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4984             }
4985             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4986             emitcode ("dec", "%s", l);
4987         }
4988       if (size > 3)
4989         {
4990             if (!strcmp(l, "acc"))
4991             {
4992                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4993             }
4994             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4995                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4996                      IS_AOP_PREG (IC_RESULT (ic)))
4997             {
4998                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4999             }
5000             else
5001             {
5002                 emitcode ("mov", "a,#!constbyte",0xff);
5003                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
5004             }
5005             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
5006             emitcode ("dec", "%s", l);
5007         }
5008       if (emitTlbl)
5009         {
5010           emitLabel (tlbl);
5011         }
5012       return TRUE;
5013     }
5014
5015   /* if the sizes are greater than 1 then we cannot */
5016   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
5017       AOP_SIZE (IC_LEFT (ic)) > 1)
5018     return FALSE;
5019
5020   /* we can if the aops of the left & result match or
5021      if they are in registers and the registers are the
5022      same */
5023   if (
5024        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
5025        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
5026        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
5027     {
5028       char *l;
5029
5030       if (aopGetUsesAcc (IC_LEFT (ic), 0))
5031         {
5032           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
5033           l = "a";
5034         }
5035       else
5036         {
5037           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5038         }
5039
5040       _startLazyDPSEvaluation ();
5041       while (icount--)
5042         {
5043           emitcode ("dec", "%s", l);
5044         }
5045       _endLazyDPSEvaluation ();
5046
5047       if (AOP_NEEDSACC (IC_RESULT (ic)))
5048         aopPut (IC_RESULT (ic), "a", 0);
5049
5050       return TRUE;
5051     }
5052
5053   return FALSE;
5054 }
5055
5056 /*-----------------------------------------------------------------*/
5057 /* addSign - complete with sign                                    */
5058 /*-----------------------------------------------------------------*/
5059 static void
5060 addSign (operand * result, int offset, int sign)
5061 {
5062   int size = (getDataSize (result) - offset);
5063   if (size > 0)
5064     {
5065       _startLazyDPSEvaluation();
5066       if (sign)
5067         {
5068           emitcode ("rlc", "a");
5069           emitcode ("subb", "a,acc");
5070           while (size--)
5071           {
5072             aopPut (result, "a", offset++);
5073           }
5074         }
5075       else
5076       {
5077         while (size--)
5078         {
5079           aopPut (result, zero, offset++);
5080         }
5081       }
5082       _endLazyDPSEvaluation();
5083     }
5084 }
5085
5086 /*-----------------------------------------------------------------*/
5087 /* genMinusBits - generates code for subtraction  of two bits      */
5088 /*-----------------------------------------------------------------*/
5089 static void
5090 genMinusBits (iCode * ic)
5091 {
5092   symbol *lbl = newiTempLabel (NULL);
5093
5094   D (emitcode (";", "genMinusBits"));
5095
5096   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5097     {
5098       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5099       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5100       emitcode ("cpl", "c");
5101       emitLabel (lbl);
5102       outBitC (IC_RESULT (ic));
5103     }
5104   else
5105     {
5106       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5107       emitcode ("subb", "a,acc");
5108       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5109       emitcode ("inc", "a");
5110       emitLabel (lbl);
5111       aopPut (IC_RESULT (ic), "a", 0);
5112       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5113     }
5114 }
5115
5116 /*-----------------------------------------------------------------*/
5117 /* genMinus - generates code for subtraction                       */
5118 /*-----------------------------------------------------------------*/
5119 static void
5120 genMinus (iCode * ic)
5121 {
5122     int size, offset = 0;
5123     int rSize;
5124     long lit = 0L;
5125     bool pushResult;
5126
5127     D (emitcode (";", "genMinus"));
5128
5129     AOP_OP_3_NOFATAL(ic, pushResult);
5130
5131     if (!pushResult)
5132     {
5133       /* special cases :- */
5134       /* if both left & right are in bit space */
5135       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5136           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5137         {
5138           genMinusBits (ic);
5139           goto release;
5140         }
5141
5142       /* if I can do an decrement instead
5143          of subtract then GOOD for ME */
5144       if (genMinusDec (ic) == TRUE)
5145         goto release;
5146
5147     }
5148
5149   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5150
5151   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5152     {
5153       CLRC;
5154     }
5155   else
5156     {
5157       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5158       lit = -lit;
5159     }
5160
5161
5162   /* if literal, add a,#-lit, else normal subb */
5163   _startLazyDPSEvaluation ();
5164   while (size--) {
5165       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5166           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5167               emitcode ("mov","b,%s",
5168                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5169               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5170               emitcode ("subb","a,b");
5171           } else {
5172               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5173               emitcode ("subb", "a,%s",
5174                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5175                                 DP2_RESULT_REG));
5176           }
5177       } else {
5178           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5179           /* first add without previous c */
5180           if (!offset) {
5181               if (!size && lit==-1) {
5182                   emitcode ("dec", "a");
5183               } else {
5184                   emitcode ("add", "a,#!constbyte",
5185                             (unsigned int) (lit & 0x0FFL));
5186               }
5187           } else {
5188               emitcode ("addc", "a,#!constbyte",
5189                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5190           }
5191       }
5192
5193       if (pushResult) {
5194           emitcode ("push", "acc");
5195       } else {
5196           aopPut (IC_RESULT (ic), "a", offset);
5197       }
5198       offset++;
5199   }
5200   _endLazyDPSEvaluation ();
5201
5202   if (pushResult)
5203     {
5204       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5205
5206       size = getDataSize (IC_LEFT (ic));
5207       rSize = getDataSize (IC_RESULT (ic));
5208
5209       ADJUST_PUSHED_RESULT(size, rSize);
5210
5211       _startLazyDPSEvaluation ();
5212       while (size--)
5213         {
5214           emitcode ("pop", "acc");
5215           aopPut (IC_RESULT (ic), "a", size);
5216         }
5217       _endLazyDPSEvaluation ();
5218     }
5219
5220   adjustArithmeticResult (ic);
5221
5222 release:
5223   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5224   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5225   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5226 }
5227
5228
5229 /*-----------------------------------------------------------------*/
5230 /* genMultbits :- multiplication of bits                           */
5231 /*-----------------------------------------------------------------*/
5232 static void
5233 genMultbits (operand * left,
5234              operand * right,
5235              operand * result,
5236              iCode   * ic)
5237 {
5238   D (emitcode (";", "genMultbits"));
5239
5240   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5241   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5242   aopOp(result, ic, TRUE, FALSE);
5243   outBitC (result);
5244 }
5245
5246 /*-----------------------------------------------------------------*/
5247 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5248 /*-----------------------------------------------------------------*/
5249 static void
5250 genMultOneByte (operand * left,
5251                 operand * right,
5252                 operand * result,
5253                 iCode   * ic)
5254 {
5255   symbol *lbl;
5256   int size;
5257   bool runtimeSign, compiletimeSign;
5258   bool lUnsigned, rUnsigned, pushedB;
5259
5260   /* (if two literals: the value is computed before) */
5261   /* if one literal, literal on the right */
5262   if (AOP_TYPE (left) == AOP_LIT)
5263     {
5264       operand *t = right;
5265       right = left;
5266       left = t;
5267       /* emitcode (";", "swapped left and right"); */
5268     }
5269   /* if no literal, unsigned on the right: shorter code */
5270   if (   AOP_TYPE (right) != AOP_LIT
5271       && SPEC_USIGN (getSpec (operandType (left))))
5272     {
5273       operand *t = right;
5274       right = left;
5275       left = t;
5276     }
5277
5278   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5279   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5280
5281   pushedB = pushB ();
5282
5283   if ((lUnsigned && rUnsigned)
5284 /* sorry, I don't know how to get size
5285    without calling aopOp (result,...);
5286    see Feature Request  */
5287       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5288                    no need to take care about the signedness! */
5289     {
5290       /* just an unsigned 8 * 8 = 8 multiply
5291          or 8u * 8u = 16u */
5292       /* emitcode (";","unsigned"); */
5293       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5294       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5295       emitcode ("mul", "ab");
5296
5297       _G.accInUse++;
5298       aopOp (result, ic, TRUE, FALSE);
5299       size = AOP_SIZE (result);
5300
5301       if (size < 1 || size > 2)
5302         {
5303           /* this should never happen */
5304           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5305                    size, __FILE__, lineno);
5306           exit (1);
5307         }
5308
5309       aopPut (result, "a", 0);
5310       _G.accInUse--;
5311       if (size == 2)
5312         aopPut (result, "b", 1);
5313
5314       popB (pushedB);
5315       return;
5316     }
5317
5318   /* we have to do a signed multiply */
5319   /* emitcode (";", "signed"); */
5320
5321   /* now sign adjust for both left & right */
5322
5323   /* let's see what's needed: */
5324   /* apply negative sign during runtime */
5325   runtimeSign = FALSE;
5326   /* negative sign from literals */
5327   compiletimeSign = FALSE;
5328
5329   if (!lUnsigned)
5330     {
5331       if (AOP_TYPE(left) == AOP_LIT)
5332         {
5333           /* signed literal */
5334           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5335           if (val < 0)
5336             compiletimeSign = TRUE;
5337         }
5338       else
5339         /* signed but not literal */
5340         runtimeSign = TRUE;
5341     }
5342
5343   if (!rUnsigned)
5344     {
5345       if (AOP_TYPE(right) == AOP_LIT)
5346         {
5347           /* signed literal */
5348           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5349           if (val < 0)
5350             compiletimeSign ^= TRUE;
5351         }
5352       else
5353         /* signed but not literal */
5354         runtimeSign = TRUE;
5355     }
5356
5357   /* initialize F0, which stores the runtime sign */
5358   if (runtimeSign)
5359     {
5360       if (compiletimeSign)
5361         emitcode ("setb", "F0"); /* set sign flag */
5362       else
5363         emitcode ("clr", "F0"); /* reset sign flag */
5364     }
5365
5366   /* save the signs of the operands */
5367   if (AOP_TYPE(right) == AOP_LIT)
5368     {
5369       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5370
5371       if (!rUnsigned && val < 0)
5372         emitcode ("mov", "b,#!constbyte", -val);
5373       else
5374         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5375     }
5376   else /* ! literal */
5377     {
5378       if (rUnsigned)  /* emitcode (";", "signed"); */
5379         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5380       else
5381         {
5382           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5383           lbl = newiTempLabel (NULL);
5384           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5385           emitcode ("cpl", "F0"); /* complement sign flag */
5386           emitcode ("cpl", "a");  /* 2's complement */
5387           emitcode ("inc", "a");
5388           emitLabel (lbl);
5389           emitcode ("mov", "b,a");
5390         }
5391     }
5392
5393   if (AOP_TYPE(left) == AOP_LIT)
5394     {
5395       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5396
5397       if (!lUnsigned && val < 0)
5398         emitcode ("mov", "a,#!constbyte", -val);
5399       else
5400         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5401     }
5402   else /* ! literal */
5403     {
5404       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5405
5406       if (!lUnsigned)  /* emitcode (";", "signed"); */
5407         {
5408           lbl = newiTempLabel (NULL);
5409           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5410           emitcode ("cpl", "F0"); /* complement sign flag */
5411           emitcode ("cpl", "a");  /* 2's complement */
5412           emitcode ("inc", "a");
5413           emitLabel (lbl);
5414         }
5415     }
5416
5417   /* now the multiplication */
5418   emitcode ("mul", "ab");
5419   _G.accInUse++;
5420   aopOp(result, ic, TRUE, FALSE);
5421   size = AOP_SIZE (result);
5422
5423   if (size < 1 || size > 2)
5424     {
5425       /* this should never happen */
5426       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5427                size, __FILE__, lineno);
5428       exit (1);
5429     }
5430
5431   if (runtimeSign || compiletimeSign)
5432     {
5433       lbl = newiTempLabel (NULL);
5434       if (runtimeSign)
5435         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5436       emitcode ("cpl", "a"); /* lsb 2's complement */
5437       if (size != 2)
5438         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5439       else
5440         {
5441           emitcode ("add", "a,#1"); /* this sets carry flag */
5442           emitcode ("xch", "a,b");
5443           emitcode ("cpl", "a"); /* msb 2's complement */
5444           emitcode ("addc", "a,#0");
5445           emitcode ("xch", "a,b");
5446         }
5447       emitLabel (lbl);
5448     }
5449   aopPut (result, "a", 0);
5450   _G.accInUse--;
5451   if (size == 2)
5452     aopPut (result, "b", 1);
5453
5454   popB (pushedB);
5455 }
5456
5457 /*-----------------------------------------------------------------*/
5458 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5459 /*-----------------------------------------------------------------*/
5460 static void genMultTwoByte (operand *left, operand *right,
5461                             operand *result, iCode *ic)
5462 {
5463         sym_link *retype = getSpec(operandType(right));
5464         sym_link *letype = getSpec(operandType(left));
5465         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5466         symbol *lbl;
5467
5468         if (AOP_TYPE (left) == AOP_LIT) {
5469                 operand *t = right;
5470                 right = left;
5471                 left = t;
5472         }
5473         /* save EA bit in F1 */
5474         lbl = newiTempLabel(NULL);
5475         emitcode ("setb","F1");
5476         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5477         emitcode ("clr","F1");
5478         emitLabel (lbl);
5479
5480         /* load up MB with right */
5481         if (!umult) {
5482                 emitcode("clr","F0");
5483                 if (AOP_TYPE(right) == AOP_LIT) {
5484                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5485                         if (val < 0) {
5486                                 emitcode("setb","F0");
5487                                 val = -val;
5488                         }
5489                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5490                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5491                 } else {
5492                         lbl = newiTempLabel(NULL);
5493                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5494                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5495                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5496                         emitcode ("xch", "a,b");
5497                         emitcode ("cpl","a");
5498                         emitcode ("add", "a,#1");
5499                         emitcode ("xch", "a,b");
5500                         emitcode ("cpl", "a"); // msb
5501                         emitcode ("addc", "a,#0");
5502                         emitcode ("setb","F0");
5503                         emitLabel (lbl);
5504                         emitcode ("mov","mb,b");
5505                         emitcode ("mov","mb,a");
5506                 }
5507         } else {
5508                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5509                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5510         }
5511         /* load up MA with left */
5512         if (!umult) {
5513                 lbl = newiTempLabel(NULL);
5514                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5515                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5516                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5517                 emitcode ("xch", "a,b");
5518                 emitcode ("cpl","a");
5519                 emitcode ("add", "a,#1");
5520                 emitcode ("xch", "a,b");
5521                 emitcode ("cpl", "a"); // msb
5522                 emitcode ("addc","a,#0");
5523                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5524                 emitcode ("setb","F0");
5525                 emitLabel (lbl);
5526                 emitcode ("mov","ma,b");
5527                 emitcode ("mov","ma,a");
5528         } else {
5529                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5530                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5531         }
5532         /* wait for multiplication to finish */
5533         lbl = newiTempLabel(NULL);
5534         emitLabel (lbl);
5535         emitcode("mov","a,mcnt1");
5536         emitcode("anl","a,#!constbyte",0x80);
5537         emitcode("jnz","!tlabel",lbl->key+100);
5538
5539         freeAsmop (left, NULL, ic, TRUE);
5540         freeAsmop (right, NULL, ic,TRUE);
5541         aopOp(result, ic, TRUE, FALSE);
5542
5543         /* if unsigned then simple */
5544         if (umult) {
5545                 emitcode ("mov","a,ma");
5546                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5547                 emitcode ("mov","a,ma");
5548                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5549                 aopPut(result,"ma",1);
5550                 aopPut(result,"ma",0);
5551         } else {
5552                 emitcode("push","ma");
5553                 emitcode("push","ma");
5554                 emitcode("push","ma");
5555                 MOVA("ma");
5556                 /* negate result if needed */
5557                 lbl = newiTempLabel(NULL);
5558                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5559                 emitcode("cpl","a");
5560                 emitcode("add","a,#1");
5561                 emitLabel (lbl);
5562                 if (AOP_TYPE(result) == AOP_ACC)
5563                 {
5564                     D (emitcode(";", "ACC special case."));
5565                     /* We know result is the only live aop, and
5566                      * it's obviously not a DPTR2, so AP is available.
5567                      */
5568                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5569                 }
5570                 else
5571                 {
5572                     aopPut(result,"a",0);
5573                 }
5574
5575                 emitcode("pop","acc");
5576                 lbl = newiTempLabel(NULL);
5577                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5578                 emitcode("cpl","a");
5579                 emitcode("addc","a,#0");
5580                 emitLabel (lbl);
5581                 aopPut(result,"a",1);
5582                 emitcode("pop","acc");
5583                 if (AOP_SIZE(result) >= 3) {
5584                         lbl = newiTempLabel(NULL);
5585                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5586                         emitcode("cpl","a");
5587                         emitcode("addc","a,#0");
5588                         emitLabel (lbl);
5589                         aopPut(result,"a",2);
5590                 }
5591                 emitcode("pop","acc");
5592                 if (AOP_SIZE(result) >= 4) {
5593                         lbl = newiTempLabel(NULL);
5594                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5595                         emitcode("cpl","a");
5596                         emitcode("addc","a,#0");
5597                         emitLabel (lbl);
5598                         aopPut(result,"a",3);
5599                 }
5600                 if (AOP_TYPE(result) == AOP_ACC)
5601                 {
5602                     /* We stashed the result away above. */
5603                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5604                 }
5605
5606         }
5607         freeAsmop (result, NULL, ic, TRUE);
5608
5609         /* restore EA bit in F1 */
5610         lbl = newiTempLabel(NULL);
5611         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5612         emitcode ("setb","EA");
5613         emitLabel (lbl);
5614         return ;
5615 }
5616
5617 /*-----------------------------------------------------------------*/
5618 /* genMult - generates code for multiplication                     */
5619 /*-----------------------------------------------------------------*/
5620 static void
5621 genMult (iCode * ic)
5622 {
5623   operand *left = IC_LEFT (ic);
5624   operand *right = IC_RIGHT (ic);
5625   operand *result = IC_RESULT (ic);
5626
5627   D (emitcode (";", "genMult"));
5628
5629   /* assign the asmops */
5630   AOP_OP_2 (ic);
5631
5632   /* special cases first */
5633   /* both are bits */
5634   if (AOP_TYPE (left) == AOP_CRY &&
5635       AOP_TYPE (right) == AOP_CRY)
5636     {
5637       genMultbits (left, right, result, ic);
5638       goto release;
5639     }
5640
5641   /* if both are of size == 1 */
5642   if (AOP_SIZE (left) == 1 &&
5643       AOP_SIZE (right) == 1)
5644     {
5645       genMultOneByte (left, right, result, ic);
5646       goto release;
5647     }
5648
5649   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5650           /* use the ds390 ARITHMETIC accel UNIT */
5651           genMultTwoByte (left, right, result, ic);
5652           return ;
5653   }
5654   /* should have been converted to function call */
5655   assert (0);
5656
5657 release:
5658   freeAsmop (result, NULL, ic, TRUE);
5659   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5660   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5661 }
5662
5663 /*-----------------------------------------------------------------*/
5664 /* genDivbits :- division of bits                                  */
5665 /*-----------------------------------------------------------------*/
5666 static void
5667 genDivbits (operand * left,
5668             operand * right,
5669             operand * result,
5670             iCode   * ic)
5671 {
5672   char *l;
5673   bool pushedB;
5674
5675   D(emitcode (";     genDivbits",""));
5676
5677   pushedB = pushB ();
5678
5679   /* the result must be bit */
5680   LOAD_AB_FOR_DIV (left, right, l);
5681   emitcode ("div", "ab");
5682   emitcode ("rrc", "a");
5683   aopOp(result, ic, TRUE, FALSE);
5684
5685   popB (pushedB);
5686
5687   aopPut (result, "c", 0);
5688 }
5689
5690 /*-----------------------------------------------------------------*/
5691 /* genDivOneByte : 8 bit division                                  */
5692 /*-----------------------------------------------------------------*/
5693 static void
5694 genDivOneByte (operand * left,
5695                operand * right,
5696                operand * result,
5697                iCode   * ic)
5698 {
5699   bool lUnsigned, rUnsigned, pushedB;
5700   bool runtimeSign, compiletimeSign;
5701   char *l;
5702   symbol *lbl;
5703   int size, offset;
5704
5705   D(emitcode (";     genDivOneByte",""));
5706
5707   offset = 1;
5708   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5709   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5710
5711   pushedB = pushB ();
5712
5713   /* signed or unsigned */
5714   if (lUnsigned && rUnsigned)
5715     {
5716       /* unsigned is easy */
5717       LOAD_AB_FOR_DIV (left, right, l);
5718       emitcode ("div", "ab");
5719
5720       _G.accInUse++;
5721       aopOp (result, ic, TRUE, FALSE);
5722       aopPut (result, "a", 0);
5723       _G.accInUse--;
5724
5725       size = AOP_SIZE (result) - 1;
5726
5727       while (size--)
5728         aopPut (result, zero, offset++);
5729
5730       popB (pushedB);
5731       return;
5732     }
5733
5734   /* signed is a little bit more difficult */
5735
5736   /* now sign adjust for both left & right */
5737
5738   /* let's see what's needed: */
5739   /* apply negative sign during runtime */
5740   runtimeSign = FALSE;
5741   /* negative sign from literals */
5742   compiletimeSign = FALSE;
5743
5744   if (!lUnsigned)
5745     {
5746       if (AOP_TYPE(left) == AOP_LIT)
5747         {
5748           /* signed literal */
5749           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5750           if (val < 0)
5751             compiletimeSign = TRUE;
5752         }
5753       else
5754         /* signed but not literal */
5755         runtimeSign = TRUE;
5756     }
5757
5758   if (!rUnsigned)
5759     {
5760       if (AOP_TYPE(right) == AOP_LIT)
5761         {
5762           /* signed literal */
5763           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5764           if (val < 0)
5765             compiletimeSign ^= TRUE;
5766         }
5767       else
5768         /* signed but not literal */
5769         runtimeSign = TRUE;
5770     }
5771
5772   /* initialize F0, which stores the runtime sign */
5773   if (runtimeSign)
5774     {
5775       if (compiletimeSign)
5776         emitcode ("setb", "F0"); /* set sign flag */
5777       else
5778         emitcode ("clr", "F0"); /* reset sign flag */
5779     }
5780
5781   /* save the signs of the operands */
5782   if (AOP_TYPE(right) == AOP_LIT)
5783     {
5784       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5785
5786       if (!rUnsigned && val < 0)
5787         emitcode ("mov", "b,#0x%02x", -val);
5788       else
5789         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5790     }
5791   else /* ! literal */
5792     {
5793       if (rUnsigned)
5794         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5795       else
5796         {
5797           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5798           lbl = newiTempLabel (NULL);
5799           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5800           emitcode ("cpl", "F0"); /* complement sign flag */
5801           emitcode ("cpl", "a");  /* 2's complement */
5802           emitcode ("inc", "a");
5803           emitLabel (lbl);
5804           emitcode ("mov", "b,a");
5805         }
5806     }
5807
5808   if (AOP_TYPE(left) == AOP_LIT)
5809     {
5810       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5811
5812       if (!lUnsigned && val < 0)
5813         emitcode ("mov", "a,#0x%02x", -val);
5814       else
5815         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5816     }
5817   else /* ! literal */
5818     {
5819       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5820
5821       if (!lUnsigned)
5822         {
5823           lbl = newiTempLabel (NULL);
5824           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5825           emitcode ("cpl", "F0"); /* complement sign flag */
5826           emitcode ("cpl", "a");  /* 2's complement */
5827           emitcode ("inc", "a");
5828           emitLabel (lbl);
5829         }
5830     }
5831
5832   /* now the division */
5833   emitcode ("nop", "; workaround for DS80C390 div bug.");
5834   emitcode ("div", "ab");
5835
5836   if (runtimeSign || compiletimeSign)
5837     {
5838       lbl = newiTempLabel (NULL);
5839       if (runtimeSign)
5840         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5841       emitcode ("cpl", "a"); /* lsb 2's complement */
5842       emitcode ("inc", "a");
5843       emitLabel (lbl);
5844
5845       _G.accInUse++;
5846       aopOp (result, ic, TRUE, FALSE);
5847       size = AOP_SIZE (result) - 1;
5848
5849       if (size > 0)
5850         {
5851           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5852              then the result will be in b, a */
5853           emitcode ("mov", "b,a"); /* 1 */
5854           /* msb is 0x00 or 0xff depending on the sign */
5855           if (runtimeSign)
5856             {
5857               emitcode ("mov",  "c,F0");
5858               emitcode ("subb", "a,acc");
5859               emitcode ("xch",  "a,b"); /* 2 */
5860               while (size--)
5861                 aopPut (result, "b", offset++); /* write msb's */
5862             }
5863           else /* compiletimeSign */
5864             while (size--)
5865               aopPut (result, "#0xff", offset++); /* write msb's */
5866         }
5867       aopPut (result, "a", 0); /* 3: write lsb */
5868     }
5869   else
5870     {
5871       _G.accInUse++;
5872       aopOp(result, ic, TRUE, FALSE);
5873       size = AOP_SIZE (result) - 1;
5874
5875       aopPut (result, "a", 0);
5876       while (size--)
5877         aopPut (result, zero, offset++);
5878     }
5879   _G.accInUse--;
5880   popB (pushedB);
5881 }
5882
5883 /*-----------------------------------------------------------------*/
5884 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5885 /*-----------------------------------------------------------------*/
5886 static void genDivTwoByte (operand *left, operand *right,
5887                             operand *result, iCode *ic)
5888 {
5889         sym_link *retype = getSpec(operandType(right));
5890         sym_link *letype = getSpec(operandType(left));
5891         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5892         symbol *lbl;
5893
5894         /* save EA bit in F1 */
5895         lbl = newiTempLabel(NULL);
5896         emitcode ("setb","F1");
5897         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5898         emitcode ("clr","F1");
5899         emitLabel (lbl);
5900
5901         /* load up MA with left */
5902         if (!umult) {
5903                 emitcode("clr","F0");
5904                 lbl = newiTempLabel(NULL);
5905                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5906                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5907                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5908                 emitcode ("xch", "a,b");
5909                 emitcode ("cpl","a");
5910                 emitcode ("add", "a,#1");
5911                 emitcode ("xch", "a,b");
5912                 emitcode ("cpl", "a"); // msb
5913                 emitcode ("addc","a,#0");
5914                 emitcode ("setb","F0");
5915                 emitLabel (lbl);
5916                 emitcode ("mov","ma,b");
5917                 emitcode ("mov","ma,a");
5918         } else {
5919                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5920                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5921         }
5922
5923         /* load up MB with right */
5924         if (!umult) {
5925                 if (AOP_TYPE(right) == AOP_LIT) {
5926                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5927                         if (val < 0) {
5928                                 lbl = newiTempLabel(NULL);
5929                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5930                                 emitcode("setb","F0");
5931                                 emitLabel (lbl);
5932                                 val = -val;
5933                         }
5934                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5935                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5936                 } else {
5937                         lbl = newiTempLabel(NULL);
5938                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5939                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5940                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5941                         emitcode ("xch", "a,b");
5942                         emitcode ("cpl","a");
5943                         emitcode ("add", "a,#1");
5944                         emitcode ("xch", "a,b");
5945                         emitcode ("cpl", "a"); // msb
5946                         emitcode ("addc", "a,#0");
5947                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5948                         emitcode ("setb","F0");
5949                         emitLabel (lbl);
5950                         emitcode ("mov","mb,b");
5951                         emitcode ("mov","mb,a");
5952                 }
5953         } else {
5954                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5955                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5956         }
5957
5958         /* wait for multiplication to finish */
5959         lbl = newiTempLabel(NULL);
5960         emitLabel (lbl);
5961         emitcode("mov","a,mcnt1");
5962         emitcode("anl","a,#!constbyte",0x80);
5963         emitcode("jnz","!tlabel",lbl->key+100);
5964
5965         freeAsmop (left, NULL, ic, TRUE);
5966         freeAsmop (right, NULL, ic,TRUE);
5967         aopOp(result, ic, TRUE, FALSE);
5968
5969         /* if unsigned then simple */
5970         if (umult) {
5971                 aopPut(result,"ma",1);
5972                 aopPut(result,"ma",0);
5973         } else {
5974                 emitcode("push","ma");
5975                 MOVA("ma");
5976                 /* negate result if needed */
5977                 lbl = newiTempLabel(NULL);
5978                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5979                 emitcode("cpl","a");
5980                 emitcode("add","a,#1");
5981                 emitLabel (lbl);
5982                 aopPut(result,"a",0);
5983                 emitcode("pop","acc");
5984                 lbl = newiTempLabel(NULL);
5985                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5986                 emitcode("cpl","a");
5987                 emitcode("addc","a,#0");
5988                 emitLabel (lbl);
5989                 aopPut(result,"a",1);
5990         }
5991         freeAsmop (result, NULL, ic, TRUE);
5992         /* restore EA bit in F1 */
5993         lbl = newiTempLabel(NULL);
5994         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5995         emitcode ("setb","EA");
5996         emitLabel (lbl);
5997         return ;
5998 }
5999
6000 /*-----------------------------------------------------------------*/
6001 /* genDiv - generates code for division                            */
6002 /*-----------------------------------------------------------------*/
6003 static void
6004 genDiv (iCode * ic)
6005 {
6006   operand *left = IC_LEFT (ic);
6007   operand *right = IC_RIGHT (ic);
6008   operand *result = IC_RESULT (ic);
6009
6010   D (emitcode (";", "genDiv"));
6011
6012   /* assign the amsops */
6013   AOP_OP_2 (ic);
6014
6015   /* special cases first */
6016   /* both are bits */
6017   if (AOP_TYPE (left) == AOP_CRY &&
6018       AOP_TYPE (right) == AOP_CRY)
6019     {
6020       genDivbits (left, right, result, ic);
6021       goto release;
6022     }
6023
6024   /* if both are of size == 1 */
6025   if (AOP_SIZE (left) == 1 &&
6026       AOP_SIZE (right) == 1)
6027     {
6028       genDivOneByte (left, right, result, ic);
6029       goto release;
6030     }
6031
6032   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6033           /* use the ds390 ARITHMETIC accel UNIT */
6034           genDivTwoByte (left, right, result, ic);
6035           return ;
6036   }
6037   /* should have been converted to function call */
6038   assert (0);
6039 release:
6040   freeAsmop (result, NULL, ic, TRUE);
6041   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6042   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6043 }
6044
6045 /*-----------------------------------------------------------------*/
6046 /* genModbits :- modulus of bits                                   */
6047 /*-----------------------------------------------------------------*/
6048 static void
6049 genModbits (operand * left,
6050             operand * right,
6051             operand * result,
6052             iCode   * ic)
6053 {
6054   char *l;
6055   bool pushedB;
6056
6057   D (emitcode (";", "genModbits"));
6058
6059   pushedB = pushB ();
6060
6061   /* the result must be bit */
6062   LOAD_AB_FOR_DIV (left, right, l);
6063   emitcode ("div", "ab");
6064   emitcode ("mov", "a,b");
6065   emitcode ("rrc", "a");
6066   aopOp(result, ic, TRUE, FALSE);
6067
6068   popB (pushedB);
6069
6070   aopPut (result, "c", 0);
6071 }
6072
6073 /*-----------------------------------------------------------------*/
6074 /* genModOneByte : 8 bit modulus                                   */
6075 /*-----------------------------------------------------------------*/
6076 static void
6077 genModOneByte (operand * left,
6078                operand * right,
6079                operand * result,
6080                iCode   * ic)
6081 {
6082   bool lUnsigned, rUnsigned, pushedB;
6083   bool runtimeSign, compiletimeSign;
6084   char *l;
6085   symbol *lbl;
6086   int size, offset;
6087
6088   D (emitcode (";", "genModOneByte"));
6089
6090   offset = 1;
6091   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6092   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6093
6094   pushedB = pushB ();
6095
6096   /* signed or unsigned */
6097   if (lUnsigned && rUnsigned)
6098     {
6099       /* unsigned is easy */
6100       LOAD_AB_FOR_DIV (left, right, l);
6101       emitcode ("div", "ab");
6102       aopOp (result, ic, TRUE, FALSE);
6103       aopPut (result, "b", 0);
6104
6105       for (size = AOP_SIZE (result) - 1; size--;)
6106         aopPut (result, zero, offset++);
6107
6108       popB (pushedB);
6109       return;
6110     }
6111
6112   /* signed is a little bit more difficult */
6113
6114   /* now sign adjust for both left & right */
6115
6116   /* modulus: sign of the right operand has no influence on the result! */
6117   if (AOP_TYPE(right) == AOP_LIT)
6118     {
6119       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6120
6121       if (!rUnsigned && val < 0)
6122         emitcode ("mov", "b,#0x%02x", -val);
6123       else
6124         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6125     }
6126   else /* not literal */
6127     {
6128       if (rUnsigned)
6129         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6130       else
6131         {
6132           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6133           lbl = newiTempLabel (NULL);
6134           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6135           emitcode ("cpl", "a");  /* 2's complement */
6136           emitcode ("inc", "a");
6137           emitLabel (lbl);
6138           emitcode ("mov", "b,a");
6139         }
6140     }
6141
6142   /* let's see what's needed: */
6143   /* apply negative sign during runtime */
6144   runtimeSign = FALSE;
6145   /* negative sign from literals */
6146   compiletimeSign = FALSE;
6147
6148   /* sign adjust left side */
6149   if (AOP_TYPE(left) == AOP_LIT)
6150     {
6151       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6152
6153       if (!lUnsigned && val < 0)
6154         {
6155           compiletimeSign = TRUE; /* set sign flag */
6156           emitcode ("mov", "a,#0x%02x", -val);
6157         }
6158       else
6159         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6160     }
6161   else /* ! literal */
6162     {
6163       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6164
6165       if (!lUnsigned)
6166         {
6167           runtimeSign = TRUE;
6168           emitcode ("clr", "F0"); /* clear sign flag */
6169
6170           lbl = newiTempLabel (NULL);
6171           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6172           emitcode ("setb", "F0"); /* set sign flag */
6173           emitcode ("cpl", "a");   /* 2's complement */
6174           emitcode ("inc", "a");
6175           emitLabel (lbl);
6176         }
6177     }
6178
6179   /* now the modulus */
6180   emitcode ("nop", "; workaround for DS80C390 div bug.");
6181   emitcode ("div", "ab");
6182
6183   if (runtimeSign || compiletimeSign)
6184     {
6185       emitcode ("mov", "a,b");
6186       lbl = newiTempLabel (NULL);
6187       if (runtimeSign)
6188         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6189       emitcode ("cpl", "a"); /* lsb 2's complement */
6190       emitcode ("inc", "a");
6191       emitLabel (lbl);
6192
6193       _G.accInUse++;
6194       aopOp (result, ic, TRUE, FALSE);
6195       size = AOP_SIZE (result) - 1;
6196
6197       if (size > 0)
6198         {
6199           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6200              then the result will be in b, a */
6201           emitcode ("mov", "b,a"); /* 1 */
6202           /* msb is 0x00 or 0xff depending on the sign */
6203           if (runtimeSign)
6204             {
6205               emitcode ("mov",  "c,F0");
6206               emitcode ("subb", "a,acc");
6207               emitcode ("xch",  "a,b"); /* 2 */
6208               while (size--)
6209                 aopPut (result, "b", offset++); /* write msb's */
6210             }
6211           else /* compiletimeSign */
6212             while (size--)
6213               aopPut (result, "#0xff", offset++); /* write msb's */
6214         }
6215       aopPut (result, "a", 0); /* 3: write lsb */
6216     }
6217   else
6218     {
6219       _G.accInUse++;
6220       aopOp(result, ic, TRUE, FALSE);
6221       size = AOP_SIZE (result) - 1;
6222
6223       aopPut (result, "b", 0);
6224       while (size--)
6225         aopPut (result, zero, offset++);
6226     }
6227   _G.accInUse--;
6228   popB (pushedB);
6229 }
6230
6231 /*-----------------------------------------------------------------*/
6232 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6233 /*-----------------------------------------------------------------*/
6234 static void genModTwoByte (operand *left, operand *right,
6235                             operand *result, iCode *ic)
6236 {
6237         sym_link *retype = getSpec(operandType(right));
6238         sym_link *letype = getSpec(operandType(left));
6239         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6240         symbol *lbl;
6241
6242         /* load up MA with left */
6243         /* save EA bit in F1 */
6244         lbl = newiTempLabel(NULL);
6245         emitcode ("setb","F1");
6246         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6247         emitcode ("clr","F1");
6248         emitLabel (lbl);
6249
6250         if (!umult) {
6251                 lbl = newiTempLabel(NULL);
6252                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6253                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6254                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6255                 emitcode ("xch", "a,b");
6256                 emitcode ("cpl","a");
6257                 emitcode ("add", "a,#1");
6258                 emitcode ("xch", "a,b");
6259                 emitcode ("cpl", "a"); // msb
6260                 emitcode ("addc","a,#0");
6261                 emitLabel (lbl);
6262                 emitcode ("mov","ma,b");
6263                 emitcode ("mov","ma,a");
6264         } else {
6265                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6266                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6267         }
6268
6269         /* load up MB with right */
6270         if (!umult) {
6271                 if (AOP_TYPE(right) == AOP_LIT) {
6272                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6273                         if (val < 0) {
6274                                 val = -val;
6275                         }
6276                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6277                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6278                 } else {
6279                         lbl = newiTempLabel(NULL);
6280                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6281                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6282                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6283                         emitcode ("xch", "a,b");
6284                         emitcode ("cpl","a");
6285                         emitcode ("add", "a,#1");
6286                         emitcode ("xch", "a,b");
6287                         emitcode ("cpl", "a"); // msb
6288                         emitcode ("addc", "a,#0");
6289                         emitLabel (lbl);
6290                         emitcode ("mov","mb,b");
6291                         emitcode ("mov","mb,a");
6292                 }
6293         } else {
6294                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6295                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6296         }
6297
6298         /* wait for multiplication to finish */
6299         lbl = newiTempLabel(NULL);
6300         emitLabel (lbl);
6301         emitcode("mov","a,mcnt1");
6302         emitcode("anl","a,#!constbyte",0x80);
6303         emitcode("jnz","!tlabel",lbl->key+100);
6304
6305         freeAsmop (left, NULL, ic, TRUE);
6306         freeAsmop (right, NULL, ic,TRUE);
6307         aopOp(result, ic, TRUE, FALSE);
6308
6309         aopPut(result,"mb",1);
6310         aopPut(result,"mb",0);
6311         freeAsmop (result, NULL, ic, TRUE);
6312
6313         /* restore EA bit in F1 */
6314         lbl = newiTempLabel(NULL);
6315         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6316         emitcode ("setb","EA");
6317         emitLabel (lbl);
6318 }
6319
6320 /*-----------------------------------------------------------------*/
6321 /* genMod - generates code for division                            */
6322 /*-----------------------------------------------------------------*/
6323 static void
6324 genMod (iCode * ic)
6325 {
6326   operand *left = IC_LEFT (ic);
6327   operand *right = IC_RIGHT (ic);
6328   operand *result = IC_RESULT (ic);
6329
6330   D (emitcode (";", "genMod"));
6331
6332   /* assign the asmops */
6333   AOP_OP_2 (ic);
6334
6335   /* special cases first */
6336   /* both are bits */
6337   if (AOP_TYPE (left) == AOP_CRY &&
6338       AOP_TYPE (right) == AOP_CRY)
6339     {
6340       genModbits (left, right, result, ic);
6341       goto release;
6342     }
6343
6344   /* if both are of size == 1 */
6345   if (AOP_SIZE (left) == 1 &&
6346       AOP_SIZE (right) == 1)
6347     {
6348       genModOneByte (left, right, result, ic);
6349       goto release;
6350     }
6351
6352   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6353           /* use the ds390 ARITHMETIC accel UNIT */
6354           genModTwoByte (left, right, result, ic);
6355           return ;
6356   }
6357
6358   /* should have been converted to function call */
6359   assert (0);
6360
6361 release:
6362   freeAsmop (result, NULL, ic, TRUE);
6363   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6364   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6365 }
6366
6367 /*-----------------------------------------------------------------*/
6368 /* genIfxJump :- will create a jump depending on the ifx           */
6369 /*-----------------------------------------------------------------*/
6370 static void
6371 genIfxJump (iCode * ic, char *jval)
6372 {
6373   symbol *jlbl;
6374   symbol *tlbl = newiTempLabel (NULL);
6375   char *inst;
6376
6377   D (emitcode (";", "genIfxJump"));
6378
6379   /* if true label then we jump if condition
6380      supplied is true */
6381   if (IC_TRUE (ic))
6382     {
6383       jlbl = IC_TRUE (ic);
6384       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6385                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6386     }
6387   else
6388     {
6389       /* false label is present */
6390       jlbl = IC_FALSE (ic);
6391       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6392                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6393     }
6394   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6395     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6396   else
6397     emitcode (inst, "!tlabel", tlbl->key + 100);
6398   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6399   emitLabel (tlbl);
6400
6401   /* mark the icode as generated */
6402   ic->generated = 1;
6403 }
6404
6405 /*-----------------------------------------------------------------*/
6406 /* genCmp :- greater or less than comparison                       */
6407 /*-----------------------------------------------------------------*/
6408 static void
6409 genCmp (operand * left, operand * right,
6410         iCode * ic, iCode * ifx, int sign)
6411 {
6412   int size, offset = 0;
6413   unsigned long lit = 0L;
6414   operand *result;
6415
6416   D (emitcode (";", "genCmp"));
6417
6418   result = IC_RESULT (ic);
6419
6420   /* if left & right are bit variables */
6421   if (AOP_TYPE (left) == AOP_CRY &&
6422       AOP_TYPE (right) == AOP_CRY)
6423     {
6424       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6425       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6426     }
6427   else
6428     {
6429       /* subtract right from left if at the
6430          end the carry flag is set then we know that
6431          left is greater than right */
6432       size = max (AOP_SIZE (left), AOP_SIZE (right));
6433
6434       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6435       if ((size == 1) && !sign &&
6436           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6437         {
6438           symbol *lbl = newiTempLabel (NULL);
6439           emitcode ("cjne", "%s,%s,!tlabel",
6440                     aopGet (left, offset, FALSE, FALSE, NULL),
6441                     aopGet (right, offset, FALSE, FALSE, NULL),
6442                     lbl->key + 100);
6443           emitLabel (lbl);
6444         }
6445       else
6446         {
6447           if (AOP_TYPE (right) == AOP_LIT)
6448             {
6449               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6450               /* optimize if(x < 0) or if(x >= 0) */
6451               if (lit == 0L)
6452                 {
6453                   if (!sign)
6454                     {
6455                       CLRC;
6456                     }
6457                   else
6458                     {
6459                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6460
6461                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6462                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6463
6464                       aopOp (result, ic, FALSE, FALSE);
6465
6466                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6467                         {
6468                           freeAsmop (result, NULL, ic, TRUE);
6469                           genIfxJump (ifx, "acc.7");
6470                           return;
6471                         }
6472                       else
6473                         {
6474                           emitcode ("rlc", "a");
6475                         }
6476                       goto release_freedLR;
6477                     }
6478                   goto release;
6479                 }
6480             }
6481           CLRC;
6482           while (size--)
6483             {
6484               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6485               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6486               // emitcode (";", "genCmp #2");
6487               if (sign && (size == 0))
6488                 {
6489                   // emitcode (";", "genCmp #3");
6490                   emitcode ("xrl", "a,#!constbyte",0x80);
6491                   if (AOP_TYPE (right) == AOP_LIT)
6492                     {
6493                       unsigned long lit = (unsigned long)
6494                       floatFromVal (AOP (right)->aopu.aop_lit);
6495                       // emitcode (";", "genCmp #3.1");
6496                       emitcode ("subb", "a,#!constbyte",
6497                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6498                     }
6499                   else
6500                     {
6501                       // emitcode (";", "genCmp #3.2");
6502                       saveAccWarn = 0;
6503                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6504                       saveAccWarn = DEFAULT_ACC_WARNING;
6505                       emitcode ("xrl", "b,#!constbyte",0x80);
6506                       emitcode ("subb", "a,b");
6507                     }
6508                 }
6509               else
6510                 {
6511                   const char *s;
6512
6513                   // emitcode (";", "genCmp #4");
6514                   saveAccWarn = 0;
6515                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6516                   saveAccWarn = DEFAULT_ACC_WARNING;
6517
6518                   emitcode ("subb", "a,%s", s);
6519                 }
6520             }
6521         }
6522     }
6523
6524 release:
6525 /* Don't need the left & right operands any more; do need the result. */
6526   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6527   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6528
6529   aopOp (result, ic, FALSE, FALSE);
6530
6531 release_freedLR:
6532
6533   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6534     {
6535       outBitC (result);
6536     }
6537   else
6538     {
6539       /* if the result is used in the next
6540          ifx conditional branch then generate
6541          code a little differently */
6542       if (ifx)
6543         {
6544           genIfxJump (ifx, "c");
6545         }
6546       else
6547         {
6548           outBitC (result);
6549         }
6550       /* leave the result in acc */
6551     }
6552   freeAsmop (result, NULL, ic, TRUE);
6553 }
6554
6555 /*-----------------------------------------------------------------*/
6556 /* genCmpGt :- greater than comparison                             */
6557 /*-----------------------------------------------------------------*/
6558 static void
6559 genCmpGt (iCode * ic, iCode * ifx)
6560 {
6561   operand *left, *right;
6562   sym_link *letype, *retype;
6563   int sign;
6564
6565   D (emitcode (";", "genCmpGt"));
6566
6567   left = IC_LEFT (ic);
6568   right = IC_RIGHT (ic);
6569
6570   letype = getSpec (operandType (left));
6571   retype = getSpec (operandType (right));
6572   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6573
6574   /* assign the left & right amsops */
6575   AOP_OP_2 (ic);
6576
6577   genCmp (right, left, ic, ifx, sign);
6578 }
6579
6580 /*-----------------------------------------------------------------*/
6581 /* genCmpLt - less than comparisons                                */
6582 /*-----------------------------------------------------------------*/
6583 static void
6584 genCmpLt (iCode * ic, iCode * ifx)
6585 {
6586   operand *left, *right;
6587   sym_link *letype, *retype;
6588   int sign;
6589
6590   D (emitcode (";", "genCmpLt"));
6591
6592   left = IC_LEFT (ic);
6593   right = IC_RIGHT (ic);
6594
6595   letype = getSpec (operandType (left));
6596   retype = getSpec (operandType (right));
6597   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6598
6599   /* assign the left & right amsops */
6600   AOP_OP_2 (ic);
6601
6602   genCmp (left, right, ic, ifx, sign);
6603 }
6604
6605 /*-----------------------------------------------------------------*/
6606 /* gencjneshort - compare and jump if not equal                    */
6607 /*-----------------------------------------------------------------*/
6608 static void
6609 gencjneshort (operand * left, operand * right, symbol * lbl)
6610 {
6611   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6612   int offset = 0;
6613   unsigned long lit = 0L;
6614
6615   D (emitcode (";", "gencjneshort"));
6616
6617   /* if the left side is a literal or
6618      if the right is in a pointer register and left
6619      is not */
6620   if ((AOP_TYPE (left) == AOP_LIT) ||
6621       (AOP_TYPE (left) == AOP_IMMD) ||
6622       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6623     {
6624       operand *t = right;
6625       right = left;
6626       left = t;
6627     }
6628
6629   if (AOP_TYPE (right) == AOP_LIT)
6630     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6631
6632   if (opIsGptr (left) || opIsGptr (right))
6633     {
6634       /* We are comparing a generic pointer to something.
6635        * Exclude the generic type byte from the comparison.
6636        */
6637       size--;
6638       D (emitcode (";", "cjneshort: generic ptr special case."););
6639     }
6640
6641
6642   /* if the right side is a literal then anything goes */
6643   if (AOP_TYPE (right) == AOP_LIT &&
6644       AOP_TYPE (left) != AOP_DIR)
6645     {
6646       while (size--)
6647         {
6648           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6649           emitcode ("cjne", "a,%s,!tlabel",
6650                     aopGet (right, offset, FALSE, FALSE, NULL),
6651                     lbl->key + 100);
6652           offset++;
6653         }
6654     }
6655
6656   /* if the right side is in a register or in direct space or
6657      if the left is a pointer register & right is not */
6658   else if (AOP_TYPE (right) == AOP_REG ||
6659            AOP_TYPE (right) == AOP_DIR ||
6660            AOP_TYPE (right) == AOP_LIT ||
6661            AOP_TYPE (right) == AOP_IMMD ||
6662            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6663            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6664     {
6665       while (size--)
6666         {
6667           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6668           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6669               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6670             emitcode ("jnz", "!tlabel", lbl->key + 100);
6671           else
6672             emitcode ("cjne", "a,%s,!tlabel",
6673                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6674                       lbl->key + 100);
6675           offset++;
6676         }
6677     }
6678   else
6679     {
6680       /* right is a pointer reg need both a & b */
6681       while (size--)
6682         {
6683           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6684           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6685           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6686           offset++;
6687         }
6688     }
6689 }
6690
6691 /*-----------------------------------------------------------------*/
6692 /* gencjne - compare and jump if not equal                         */
6693 /*-----------------------------------------------------------------*/
6694 static void
6695 gencjne (operand * left, operand * right, symbol * lbl)
6696 {
6697   symbol *tlbl = newiTempLabel (NULL);
6698
6699   D (emitcode (";", "gencjne"));
6700
6701   gencjneshort (left, right, lbl);
6702
6703   emitcode ("mov", "a,%s", one);
6704   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6705   emitLabel (lbl);
6706   emitcode ("clr", "a");
6707   emitLabel (tlbl);
6708 }
6709
6710 /*-----------------------------------------------------------------*/
6711 /* genCmpEq - generates code for equal to                          */
6712 /*-----------------------------------------------------------------*/
6713 static void
6714 genCmpEq (iCode * ic, iCode * ifx)
6715 {
6716   operand *left, *right, *result;
6717
6718   D (emitcode (";", "genCmpEq"));
6719
6720   AOP_OP_2 (ic);
6721   AOP_SET_LOCALS (ic);
6722
6723   /* if literal, literal on the right or
6724      if the right is in a pointer register and left
6725      is not */
6726   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6727       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6728     {
6729       operand *t = IC_RIGHT (ic);
6730       IC_RIGHT (ic) = IC_LEFT (ic);
6731       IC_LEFT (ic) = t;
6732     }
6733
6734   if (ifx &&                    /* !AOP_SIZE(result) */
6735       OP_SYMBOL (result) &&
6736       OP_SYMBOL (result)->regType == REG_CND)
6737     {
6738       symbol *tlbl;
6739       /* if they are both bit variables */
6740       if (AOP_TYPE (left) == AOP_CRY &&
6741           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6742         {
6743           if (AOP_TYPE (right) == AOP_LIT)
6744             {
6745               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6746               if (lit == 0L)
6747                 {
6748                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6749                   emitcode ("cpl", "c");
6750                 }
6751               else if (lit == 1L)
6752                 {
6753                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6754                 }
6755               else
6756                 {
6757                   emitcode ("clr", "c");
6758                 }
6759               /* AOP_TYPE(right) == AOP_CRY */
6760             }
6761           else
6762             {
6763               symbol *lbl = newiTempLabel (NULL);
6764               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6765               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6766               emitcode ("cpl", "c");
6767               emitLabel (lbl);
6768             }
6769           /* if true label then we jump if condition
6770              supplied is true */
6771           tlbl = newiTempLabel (NULL);
6772           if (IC_TRUE (ifx))
6773             {
6774               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6775               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6776             }
6777           else
6778             {
6779               emitcode ("jc", "!tlabel", tlbl->key + 100);
6780               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6781             }
6782           emitLabel (tlbl);
6783         }
6784       else
6785         {
6786           tlbl = newiTempLabel (NULL);
6787           gencjneshort (left, right, tlbl);
6788           if (IC_TRUE (ifx))
6789             {
6790               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6791               emitLabel (tlbl);
6792             }
6793           else
6794             {
6795               symbol *lbl = newiTempLabel (NULL);
6796               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6797               emitLabel (tlbl);
6798               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6799               emitLabel (lbl);
6800             }
6801         }
6802       /* mark the icode as generated */
6803       ifx->generated = 1;
6804
6805       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6806       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6807       return;
6808     }
6809
6810   /* if they are both bit variables */
6811   if (AOP_TYPE (left) == AOP_CRY &&
6812       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6813     {
6814       if (AOP_TYPE (right) == AOP_LIT)
6815         {
6816           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6817           if (lit == 0L)
6818             {
6819               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6820               emitcode ("cpl", "c");
6821             }
6822           else if (lit == 1L)
6823             {
6824               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6825             }
6826           else
6827             {
6828               emitcode ("clr", "c");
6829             }
6830           /* AOP_TYPE(right) == AOP_CRY */
6831         }
6832       else
6833         {
6834           symbol *lbl = newiTempLabel (NULL);
6835           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6836           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6837           emitcode ("cpl", "c");
6838           emitLabel (lbl);
6839         }
6840
6841       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6842       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6843
6844       aopOp (result, ic, TRUE, FALSE);
6845
6846       /* c = 1 if egal */
6847       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6848         {
6849           outBitC (result);
6850           goto release;
6851         }
6852       if (ifx)
6853         {
6854           genIfxJump (ifx, "c");
6855           goto release;
6856         }
6857       /* if the result is used in an arithmetic operation
6858          then put the result in place */
6859       outBitC (result);
6860     }
6861   else
6862     {
6863       gencjne (left, right, newiTempLabel (NULL));
6864
6865       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6866       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6867
6868       aopOp (result, ic, TRUE, FALSE);
6869
6870       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6871         {
6872           aopPut (result, "a", 0);
6873           goto release;
6874         }
6875       if (ifx)
6876         {
6877           genIfxJump (ifx, "a");
6878           goto release;
6879         }
6880       /* if the result is used in an arithmetic operation
6881          then put the result in place */
6882       if (AOP_TYPE (result) != AOP_CRY)
6883         outAcc (result);
6884       /* leave the result in acc */
6885     }
6886
6887 release:
6888   freeAsmop (result, NULL, ic, TRUE);
6889 }
6890
6891 /*-----------------------------------------------------------------*/
6892 /* ifxForOp - returns the icode containing the ifx for operand     */
6893 /*-----------------------------------------------------------------*/
6894 static iCode *
6895 ifxForOp (operand * op, iCode * ic)
6896 {
6897   /* if true symbol then needs to be assigned */
6898   if (IS_TRUE_SYMOP (op))
6899     return NULL;
6900
6901   /* if this has register type condition and
6902      the next instruction is ifx with the same operand
6903      and live to of the operand is upto the ifx only then */
6904   if (ic->next &&
6905       ic->next->op == IFX &&
6906       IC_COND (ic->next)->key == op->key &&
6907       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6908     return ic->next;
6909
6910   return NULL;
6911 }
6912
6913 /*-----------------------------------------------------------------*/
6914 /* hasInc - operand is incremented before any other use            */
6915 /*-----------------------------------------------------------------*/
6916 static iCode *
6917 hasInc (operand *op, iCode *ic, int osize)
6918 {
6919   sym_link *type = operandType(op);
6920   sym_link *retype = getSpec (type);
6921   iCode *lic = ic->next;
6922   int isize ;
6923
6924   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6925   if (!IS_SYMOP(op)) return NULL;
6926
6927   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6928   if (IS_AGGREGATE(type->next)) return NULL;
6929   if (osize != (isize = getSize(type->next))) return NULL;
6930
6931   while (lic) {
6932       /* if operand of the form op = op + <sizeof *op> */
6933       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6934           isOperandEqual(IC_RESULT(lic),op) &&
6935           isOperandLiteral(IC_RIGHT(lic)) &&
6936           operandLitValue(IC_RIGHT(lic)) == isize) {
6937           return lic;
6938       }
6939       /* if the operand used or deffed */
6940       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6941           return NULL;
6942       }
6943       /* if GOTO or IFX */
6944       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6945       lic = lic->next;
6946   }
6947   return NULL;
6948 }
6949
6950 /*-----------------------------------------------------------------*/
6951 /* genAndOp - for && operation                                     */
6952 /*-----------------------------------------------------------------*/
6953 static void
6954 genAndOp (iCode * ic)
6955 {
6956   operand *left, *right, *result;
6957   symbol *tlbl;
6958
6959   D (emitcode (";", "genAndOp"));
6960
6961   /* note here that && operations that are in an
6962      if statement are taken away by backPatchLabels
6963      only those used in arthmetic operations remain */
6964   AOP_OP_2 (ic);
6965   AOP_SET_LOCALS (ic);
6966
6967   /* if both are bit variables */
6968   if (AOP_TYPE (left) == AOP_CRY &&
6969       AOP_TYPE (right) == AOP_CRY)
6970     {
6971       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6972       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6973       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6974       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6975
6976       aopOp (result,ic,FALSE, FALSE);
6977       outBitC (result);
6978     }
6979   else
6980     {
6981       tlbl = newiTempLabel (NULL);
6982       toBoolean (left);
6983       emitcode ("jz", "!tlabel", tlbl->key + 100);
6984       toBoolean (right);
6985       emitLabel (tlbl);
6986       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6987       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6988
6989       aopOp (result,ic,FALSE, FALSE);
6990       outBitAcc (result);
6991     }
6992
6993     freeAsmop (result, NULL, ic, TRUE);
6994 }
6995
6996
6997 /*-----------------------------------------------------------------*/
6998 /* genOrOp - for || operation                                      */
6999 /*-----------------------------------------------------------------*/
7000 static void
7001 genOrOp (iCode * ic)
7002 {
7003   operand *left, *right, *result;
7004   symbol *tlbl;
7005
7006   D (emitcode (";", "genOrOp"));
7007
7008   /* note here that || operations that are in an
7009      if statement are taken away by backPatchLabels
7010      only those used in arthmetic operations remain */
7011   AOP_OP_2 (ic);
7012   AOP_SET_LOCALS (ic);
7013
7014   /* if both are bit variables */
7015   if (AOP_TYPE (left) == AOP_CRY &&
7016       AOP_TYPE (right) == AOP_CRY)
7017     {
7018       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7019       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7020       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7021       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7022
7023       aopOp (result,ic,FALSE, FALSE);
7024
7025       outBitC (result);
7026     }
7027   else
7028     {
7029       tlbl = newiTempLabel (NULL);
7030       toBoolean (left);
7031       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7032       toBoolean (right);
7033       emitLabel (tlbl);
7034       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7035       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7036
7037       aopOp (result,ic,FALSE, FALSE);
7038
7039       outBitAcc (result);
7040     }
7041
7042   freeAsmop (result, NULL, ic, TRUE);
7043 }
7044
7045 /*-----------------------------------------------------------------*/
7046 /* isLiteralBit - test if lit == 2^n                               */
7047 /*-----------------------------------------------------------------*/
7048 static int
7049 isLiteralBit (unsigned long lit)
7050 {
7051   unsigned long pw[32] =
7052   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7053    0x100L, 0x200L, 0x400L, 0x800L,
7054    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7055    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7056    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7057    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7058    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7059   int idx;
7060
7061   for (idx = 0; idx < 32; idx++)
7062     if (lit == pw[idx])
7063       return idx + 1;
7064   return 0;
7065 }
7066
7067 /*-----------------------------------------------------------------*/
7068 /* continueIfTrue -                                                */
7069 /*-----------------------------------------------------------------*/
7070 static void
7071 continueIfTrue (iCode * ic)
7072 {
7073   if (IC_TRUE (ic))
7074     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7075   ic->generated = 1;
7076 }
7077
7078 /*-----------------------------------------------------------------*/
7079 /* jmpIfTrue -                                                     */
7080 /*-----------------------------------------------------------------*/
7081 static void
7082 jumpIfTrue (iCode * ic)
7083 {
7084   if (!IC_TRUE (ic))
7085     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7086   ic->generated = 1;
7087 }
7088
7089 /*-----------------------------------------------------------------*/
7090 /* jmpTrueOrFalse -                                                */
7091 /*-----------------------------------------------------------------*/
7092 static void
7093 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7094 {
7095   // ugly but optimized by peephole
7096   if (IC_TRUE (ic))
7097     {
7098       symbol *nlbl = newiTempLabel (NULL);
7099       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7100       emitLabel (tlbl);
7101       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7102       emitLabel (nlbl);
7103     }
7104   else
7105     {
7106       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7107       emitLabel (tlbl);
7108     }
7109   ic->generated = 1;
7110 }
7111
7112 // Generate code to perform a bit-wise logic operation
7113 // on two operands in far space (assumed to already have been
7114 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7115 // in far space. This requires pushing the result on the stack
7116 // then popping it into the result.
7117 static void
7118 genFarFarLogicOp(iCode *ic, char *logicOp)
7119 {
7120       int size, resultSize, compSize;
7121       int offset = 0;
7122
7123       TR_AP("#5");
7124       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7125       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7126                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7127
7128       _startLazyDPSEvaluation();
7129       for (size = compSize; (size--); offset++)
7130       {
7131           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7132           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7133           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7134
7135           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7136           emitcode ("push", "acc");
7137       }
7138       _endLazyDPSEvaluation();
7139
7140       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7141       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7142       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7143
7144       resultSize = AOP_SIZE(IC_RESULT(ic));
7145
7146       ADJUST_PUSHED_RESULT(compSize, resultSize);
7147
7148       _startLazyDPSEvaluation();
7149       while (compSize--)
7150       {
7151           emitcode ("pop", "acc");
7152           aopPut (IC_RESULT (ic), "a", compSize);
7153       }
7154       _endLazyDPSEvaluation();
7155       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7156 }
7157
7158
7159 /*-----------------------------------------------------------------*/
7160 /* genAnd  - code for and                                          */
7161 /*-----------------------------------------------------------------*/
7162 static void
7163 genAnd (iCode * ic, iCode * ifx)
7164 {
7165   operand *left, *right, *result;
7166   int size, offset = 0;
7167   unsigned long lit = 0L;
7168   int bytelit = 0;
7169   char buffer[10];
7170   bool pushResult;
7171
7172   D (emitcode (";", "genAnd"));
7173
7174   AOP_OP_3_NOFATAL (ic, pushResult);
7175   AOP_SET_LOCALS (ic);
7176
7177   if (pushResult)
7178   {
7179       genFarFarLogicOp(ic, "anl");
7180       return;
7181   }
7182
7183 #ifdef DEBUG_TYPE
7184   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7185             AOP_TYPE (result),
7186             AOP_TYPE (left), AOP_TYPE (right));
7187   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7188             AOP_SIZE (result),
7189             AOP_SIZE (left), AOP_SIZE (right));
7190 #endif
7191
7192   /* if left is a literal & right is not then exchange them */
7193   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7194 #ifdef LOGIC_OPS_BROKEN
7195     ||  AOP_NEEDSACC (left)
7196 #endif
7197     )
7198     {
7199       operand *tmp = right;
7200       right = left;
7201       left = tmp;
7202     }
7203
7204   /* if result = right then exchange left and right */
7205   if (sameRegs (AOP (result), AOP (right)))
7206     {
7207       operand *tmp = right;
7208       right = left;
7209       left = tmp;
7210     }
7211
7212   /* if right is bit then exchange them */
7213   if (AOP_TYPE (right) == AOP_CRY &&
7214       AOP_TYPE (left) != AOP_CRY)
7215     {
7216       operand *tmp = right;
7217       right = left;
7218       left = tmp;
7219     }
7220   if (AOP_TYPE (right) == AOP_LIT)
7221     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7222
7223   size = AOP_SIZE (result);
7224
7225   // if(bit & yy)
7226   // result = bit & yy;
7227   if (AOP_TYPE (left) == AOP_CRY)
7228     {
7229       // c = bit & literal;
7230       if (AOP_TYPE (right) == AOP_LIT)
7231         {
7232           if (lit & 1)
7233             {
7234               if (size && sameRegs (AOP (result), AOP (left)))
7235                 // no change
7236                 goto release;
7237               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7238             }
7239           else
7240             {
7241               // bit(result) = 0;
7242               if (size && (AOP_TYPE (result) == AOP_CRY))
7243                 {
7244                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7245                   goto release;
7246                 }
7247               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7248                 {
7249                   jumpIfTrue (ifx);
7250                   goto release;
7251                 }
7252               emitcode ("clr", "c");
7253             }
7254         }
7255       else
7256         {
7257           if (AOP_TYPE (right) == AOP_CRY)
7258             {
7259               // c = bit & bit;
7260               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7261               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7262             }
7263           else
7264             {
7265               // c = bit & val;
7266               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7267               // c = lsb
7268               emitcode ("rrc", "a");
7269               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7270             }
7271         }
7272       // bit = c
7273       // val = c
7274       if (size)
7275         outBitC (result);
7276       // if(bit & ...)
7277       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7278         genIfxJump (ifx, "c");
7279       goto release;
7280     }
7281
7282   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7283   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7284   if ((AOP_TYPE (right) == AOP_LIT) &&
7285       (AOP_TYPE (result) == AOP_CRY) &&
7286       (AOP_TYPE (left) != AOP_CRY))
7287     {
7288       int posbit = isLiteralBit (lit);
7289       /* left &  2^n */
7290       if (posbit)
7291         {
7292           posbit--;
7293           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7294           // bit = left & 2^n
7295           if (size)
7296             {
7297               switch (posbit & 0x07)
7298                 {
7299                   case 0: emitcode ("rrc", "a");
7300                           break;
7301                   case 7: emitcode ("rlc", "a");
7302                           break;
7303                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7304                           break;
7305                 }
7306             }
7307           // if(left &  2^n)
7308           else
7309             {
7310               if (ifx)
7311                 {
7312                   SNPRINTF (buffer, sizeof(buffer),
7313                             "acc.%d", posbit & 0x07);
7314                   genIfxJump (ifx, buffer);
7315                 }
7316               else
7317                   {
7318                       emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7319                   }
7320               goto release;
7321             }
7322         }
7323       else
7324         {
7325           symbol *tlbl = newiTempLabel (NULL);
7326           int sizel = AOP_SIZE (left);
7327           if (size)
7328             emitcode ("setb", "c");
7329           while (sizel--)
7330             {
7331               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7332                 {
7333                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7334                   // byte ==  2^n ?
7335                   if ((posbit = isLiteralBit (bytelit)) != 0)
7336                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7337                   else
7338                     {
7339                       if (bytelit != 0x0FFL)
7340                         emitcode ("anl", "a,%s",
7341                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7342                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7343                     }
7344                 }
7345               offset++;
7346             }
7347           // bit = left & literal
7348           if (size)
7349             {
7350               emitcode ("clr", "c");
7351               emitLabel (tlbl);
7352             }
7353           // if(left & literal)
7354           else
7355             {
7356               if (ifx)
7357                 jmpTrueOrFalse (ifx, tlbl);
7358               else
7359                 emitLabel (tlbl);
7360               goto release;
7361             }
7362         }
7363       outBitC (result);
7364       goto release;
7365     }
7366
7367   /* if left is same as result */
7368   if (sameRegs (AOP (result), AOP (left)))
7369     {
7370       for (; size--; offset++)
7371         {
7372           if (AOP_TYPE (right) == AOP_LIT)
7373             {
7374               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7375               if (bytelit == 0x0FF)
7376                 {
7377                   /* dummy read of volatile operand */
7378                   if (isOperandVolatile (left, FALSE))
7379                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7380                   else
7381                     continue;
7382                 }
7383               else if (bytelit == 0)
7384                 {
7385                   aopPut (result, zero, offset);
7386                 }
7387               else if (IS_AOP_PREG (result))
7388                 {
7389                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7390                   emitcode ("anl", "a,%s",
7391                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7392                   aopPut (result, "a", offset);
7393                 }
7394               else
7395                 emitcode ("anl", "%s,%s",
7396                           aopGet (left, offset, FALSE, TRUE, NULL),
7397                           aopGet (right, offset, FALSE, FALSE, NULL));
7398             }
7399           else
7400             {
7401               if (AOP_TYPE (left) == AOP_ACC)
7402                 emitcode ("anl", "a,%s",
7403                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7404               else
7405                 {
7406                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7407                   if (IS_AOP_PREG (result))
7408                     {
7409                       emitcode ("anl", "a,%s",
7410                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7411                       aopPut (result, "a", offset);
7412                     }
7413                   else
7414                     emitcode ("anl", "%s,a",
7415                               aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7416                 }
7417             }
7418         }
7419     }
7420   else
7421     {
7422       // left & result in different registers
7423       if (AOP_TYPE (result) == AOP_CRY)
7424         {
7425           // result = bit
7426           // if(size), result in bit
7427           // if(!size && ifx), conditional oper: if(left & right)
7428           symbol *tlbl = newiTempLabel (NULL);
7429           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7430           if (size)
7431             emitcode ("setb", "c");
7432           while (sizer--)
7433             {
7434               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7435                 emitcode ("anl", "a,%s",
7436                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7437               } else {
7438                 if (AOP_TYPE(left)==AOP_ACC)
7439                 {
7440                   bool pushedB = pushB ();
7441                   emitcode("mov", "b,a");
7442                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7443                   emitcode("anl", "a,b");
7444                   popB (pushedB);
7445                 }
7446                 else
7447                 {
7448                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7449                   emitcode ("anl", "a,%s",
7450                             aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7451                 }
7452               }
7453               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7454               offset++;
7455             }
7456           if (size)
7457             {
7458               CLRC;
7459               emitLabel (tlbl);
7460               outBitC (result);
7461             }
7462           else if (ifx)
7463             jmpTrueOrFalse (ifx, tlbl);
7464           else
7465             emitLabel (tlbl);
7466         }
7467       else
7468         {
7469           for (; (size--); offset++)
7470             {
7471               // normal case
7472               // result = left & right
7473               if (AOP_TYPE (right) == AOP_LIT)
7474                 {
7475                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7476                   if (bytelit == 0x0FF)
7477                     {
7478                       aopPut (result,
7479                               aopGet (left, offset, FALSE, FALSE, NULL),
7480                               offset);
7481                       continue;
7482                     }
7483                   else if (bytelit == 0)
7484                     {
7485                       /* dummy read of volatile operand */
7486                       if (isOperandVolatile (left, FALSE))
7487                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7488                       aopPut (result, zero, offset);
7489                       continue;
7490                     }
7491                   D (emitcode (";", "better literal AND."));
7492                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7493                   emitcode ("anl", "a, %s", aopGet (right, offset,
7494                                                     FALSE, FALSE, DP2_RESULT_REG));
7495
7496                 }
7497               else
7498                 {
7499                   // faster than result <- left, anl result,right
7500                   // and better if result is SFR
7501                   if (AOP_TYPE (left) == AOP_ACC)
7502                     {
7503                       emitcode ("anl", "a,%s",
7504                                 aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7505                     }
7506                   else
7507                     {
7508                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
7509                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7510                       {
7511                           emitcode("mov", "b,a");
7512                           rOp = "b";
7513                       }
7514
7515                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7516                       emitcode ("anl", "a,%s", rOp);
7517                     }
7518                 }
7519               aopPut (result, "a", offset);
7520             }
7521         }
7522     }
7523
7524 release:
7525   freeAsmop (result, NULL, ic, TRUE);
7526   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7527   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7528 }
7529
7530 /*-----------------------------------------------------------------*/
7531 /* genOr  - code for or                                            */
7532 /*-----------------------------------------------------------------*/
7533 static void
7534 genOr (iCode * ic, iCode * ifx)
7535 {
7536   operand *left, *right, *result;
7537   int size, offset = 0;
7538   unsigned long lit = 0L;
7539   int bytelit = 0;
7540   bool     pushResult;
7541
7542   D (emitcode (";", "genOr"));
7543
7544   AOP_OP_3_NOFATAL (ic, pushResult);
7545   AOP_SET_LOCALS (ic);
7546
7547   if (pushResult)
7548   {
7549       genFarFarLogicOp(ic, "orl");
7550       return;
7551   }
7552
7553
7554 #ifdef DEBUG_TYPE
7555   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7556             AOP_TYPE (result),
7557             AOP_TYPE (left), AOP_TYPE (right));
7558   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7559             AOP_SIZE (result),
7560             AOP_SIZE (left), AOP_SIZE (right));
7561 #endif
7562
7563   /* if left is a literal & right is not then exchange them */
7564   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7565 #ifdef LOGIC_OPS_BROKEN
7566    || AOP_NEEDSACC (left) // I think this is a net loss now.
7567 #endif
7568       )
7569     {
7570       operand *tmp = right;
7571       right = left;
7572       left = tmp;
7573     }
7574
7575   /* if result = right then exchange them */
7576   if (sameRegs (AOP (result), AOP (right)))
7577     {
7578       operand *tmp = right;
7579       right = left;
7580       left = tmp;
7581     }
7582
7583   /* if right is bit then exchange them */
7584   if (AOP_TYPE (right) == AOP_CRY &&
7585       AOP_TYPE (left) != AOP_CRY)
7586     {
7587       operand *tmp = right;
7588       right = left;
7589       left = tmp;
7590     }
7591   if (AOP_TYPE (right) == AOP_LIT)
7592     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7593
7594   size = AOP_SIZE (result);
7595
7596   // if(bit | yy)
7597   // xx = bit | yy;
7598   if (AOP_TYPE (left) == AOP_CRY)
7599     {
7600       if (AOP_TYPE (right) == AOP_LIT)
7601         {
7602           // c = bit | literal;
7603           if (lit)
7604             {
7605               // lit != 0 => result = 1
7606               if (AOP_TYPE (result) == AOP_CRY)
7607                 {
7608                   if (size)
7609                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7610                   else if (ifx)
7611                     continueIfTrue (ifx);
7612                   goto release;
7613                 }
7614               emitcode ("setb", "c");
7615             }
7616           else
7617             {
7618               // lit == 0 => result = left
7619               if (size && sameRegs (AOP (result), AOP (left)))
7620                 goto release;
7621               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7622             }
7623         }
7624       else
7625         {
7626           if (AOP_TYPE (right) == AOP_CRY)
7627             {
7628               // c = bit | bit;
7629               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7630               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7631             }
7632           else
7633             {
7634               // c = bit | val;
7635               symbol *tlbl = newiTempLabel (NULL);
7636               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7637                 emitcode ("setb", "c");
7638               emitcode ("jb", "%s,!tlabel",
7639                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7640               toBoolean (right);
7641               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7642               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7643                 {
7644                   jmpTrueOrFalse (ifx, tlbl);
7645                   goto release;
7646                 }
7647               else
7648                 {
7649                   CLRC;
7650                   emitLabel (tlbl);
7651                 }
7652             }
7653         }
7654       // bit = c
7655       // val = c
7656       if (size)
7657         outBitC (result);
7658       // if(bit | ...)
7659       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7660            genIfxJump (ifx, "c");
7661       goto release;
7662     }
7663
7664   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7665   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7666   if ((AOP_TYPE (right) == AOP_LIT) &&
7667       (AOP_TYPE (result) == AOP_CRY) &&
7668       (AOP_TYPE (left) != AOP_CRY))
7669     {
7670       if (lit)
7671         {
7672           // result = 1
7673           if (size)
7674             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7675           else
7676             continueIfTrue (ifx);
7677           goto release;
7678         }
7679       else
7680         {
7681           // lit = 0, result = boolean(left)
7682           if (size)
7683             emitcode ("setb", "c");
7684           toBoolean (right);
7685           if (size)
7686             {
7687               symbol *tlbl = newiTempLabel (NULL);
7688               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7689               CLRC;
7690               emitLabel (tlbl);
7691             }
7692           else
7693             {
7694               genIfxJump (ifx, "a");
7695               goto release;
7696             }
7697         }
7698       outBitC (result);
7699       goto release;
7700     }
7701
7702   /* if left is same as result */
7703   if (sameRegs (AOP (result), AOP (left)))
7704     {
7705       for (; size--; offset++)
7706         {
7707           if (AOP_TYPE (right) == AOP_LIT)
7708             {
7709               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7710               if (bytelit == 0)
7711                 {
7712                   /* dummy read of volatile operand */
7713                   if (isOperandVolatile (left, FALSE))
7714                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7715                   else
7716                     continue;
7717                 }
7718               else if (bytelit == 0x0FF)
7719                 {
7720                   aopPut (result, "#0xFF", offset);
7721                 }
7722               else if (IS_AOP_PREG (left))
7723                 {
7724                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7725                   emitcode ("orl", "a,%s",
7726                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7727                   aopPut (result, "a", offset);
7728                 }
7729               else
7730                 {
7731                   emitcode ("orl", "%s,%s",
7732                             aopGet (left, offset, FALSE, TRUE, NULL),
7733                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7734                 }
7735             }
7736           else
7737             {
7738               if (AOP_TYPE (left) == AOP_ACC)
7739                 {
7740                   emitcode ("orl", "a,%s",
7741                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7742                 }
7743               else
7744                 {
7745                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7746                   if (IS_AOP_PREG (left))
7747                     {
7748                       emitcode ("orl", "a,%s",
7749                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7750                       aopPut (result, "a", offset);
7751                     }
7752                   else
7753                     {
7754                       emitcode ("orl", "%s,a",
7755                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7756                     }
7757                 }
7758             }
7759         }
7760     }
7761   else
7762     {
7763       // left & result in different registers
7764       if (AOP_TYPE (result) == AOP_CRY)
7765         {
7766           // result = bit
7767           // if(size), result in bit
7768           // if(!size && ifx), conditional oper: if(left | right)
7769           symbol *tlbl = newiTempLabel (NULL);
7770           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7771           if (size)
7772             emitcode ("setb", "c");
7773           while (sizer--)
7774             {
7775               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7776                 emitcode ("orl", "a,%s",
7777                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7778               } else {
7779                 MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7780                 emitcode ("orl", "a,%s",
7781                           aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7782               }
7783               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7784               offset++;
7785             }
7786           if (size)
7787             {
7788               CLRC;
7789               emitLabel (tlbl);
7790               outBitC (result);
7791             }
7792           else if (ifx)
7793             jmpTrueOrFalse (ifx, tlbl);
7794           else
7795             emitLabel (tlbl);
7796         }
7797       else
7798         {
7799             _startLazyDPSEvaluation();
7800           for (; (size--); offset++)
7801             {
7802               // normal case
7803               // result = left | right
7804               if (AOP_TYPE (right) == AOP_LIT)
7805                 {
7806                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7807                   if (bytelit == 0)
7808                     {
7809                       aopPut (result,
7810                               aopGet (left, offset, FALSE, FALSE, NULL),
7811                               offset);
7812                       continue;
7813                     }
7814                   else if (bytelit == 0x0FF)
7815                     {
7816                       /* dummy read of volatile operand */
7817                       if (isOperandVolatile (left, FALSE))
7818                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7819                       aopPut (result, "#0xFF", offset);
7820                       continue;
7821                     }
7822                   D (emitcode (";", "better literal OR."));
7823                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7824                   emitcode ("orl", "a, %s",
7825                             aopGet (right, offset,
7826                                     FALSE, FALSE, DP2_RESULT_REG));
7827
7828                 }
7829               else
7830                 {
7831                   // faster than result <- left, anl result,right
7832                   // and better if result is SFR
7833                   if (AOP_TYPE (left) == AOP_ACC)
7834                     {
7835                       emitcode ("orl", "a,%s",
7836                                 aopGet (right, offset,
7837                                         FALSE, FALSE, DP2_RESULT_REG));
7838                     }
7839                   else
7840                     {
7841                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
7842
7843                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7844                       {
7845                           emitcode("mov", "b,a");
7846                           rOp = "b";
7847                       }
7848
7849                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7850                       emitcode ("orl", "a,%s", rOp);
7851                     }
7852                 }
7853               aopPut (result, "a", offset);
7854             }
7855             _endLazyDPSEvaluation();
7856         }
7857     }
7858
7859 release:
7860   freeAsmop (result, NULL, ic, TRUE);
7861   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7862   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7863 }
7864
7865 /*-----------------------------------------------------------------*/
7866 /* genXor - code for xclusive or                                   */
7867 /*-----------------------------------------------------------------*/
7868 static void
7869 genXor (iCode * ic, iCode * ifx)
7870 {
7871   operand *left, *right, *result;
7872   int size, offset = 0;
7873   unsigned long lit = 0L;
7874   int bytelit = 0;
7875   bool pushResult;
7876
7877   D (emitcode (";", "genXor"));
7878
7879   AOP_OP_3_NOFATAL (ic, pushResult);
7880   AOP_SET_LOCALS (ic);
7881
7882   if (pushResult)
7883   {
7884       genFarFarLogicOp(ic, "xrl");
7885       return;
7886   }
7887
7888 #ifdef DEBUG_TYPE
7889   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7890             AOP_TYPE (result),
7891             AOP_TYPE (left), AOP_TYPE (right));
7892   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7893             AOP_SIZE (result),
7894             AOP_SIZE (left), AOP_SIZE (right));
7895 #endif
7896
7897   /* if left is a literal & right is not ||
7898      if left needs acc & right does not */
7899   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7900 #ifdef LOGIC_OPS_BROKEN
7901       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7902 #endif
7903      )
7904     {
7905       operand *tmp = right;
7906       right = left;
7907       left = tmp;
7908     }
7909
7910   /* if result = right then exchange them */
7911   if (sameRegs (AOP (result), AOP (right)))
7912     {
7913       operand *tmp = right;
7914       right = left;
7915       left = tmp;
7916     }
7917
7918   /* if right is bit then exchange them */
7919   if (AOP_TYPE (right) == AOP_CRY &&
7920       AOP_TYPE (left) != AOP_CRY)
7921     {
7922       operand *tmp = right;
7923       right = left;
7924       left = tmp;
7925     }
7926   if (AOP_TYPE (right) == AOP_LIT)
7927     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7928
7929   size = AOP_SIZE (result);
7930
7931   // if(bit ^ yy)
7932   // xx = bit ^ yy;
7933   if (AOP_TYPE (left) == AOP_CRY)
7934     {
7935       if (AOP_TYPE (right) == AOP_LIT)
7936         {
7937           // c = bit & literal;
7938           if (lit >> 1)
7939             {
7940               // lit>>1  != 0 => result = 1
7941               if (AOP_TYPE (result) == AOP_CRY)
7942                 {
7943                   if (size)
7944                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7945                   else if (ifx)
7946                     continueIfTrue (ifx);
7947                   goto release;
7948                 }
7949               emitcode ("setb", "c");
7950             }
7951           else
7952             {
7953               // lit == (0 or 1)
7954               if (lit == 0)
7955                 {
7956                   // lit == 0, result = left
7957                   if (size && sameRegs (AOP (result), AOP (left)))
7958                     goto release;
7959                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7960                 }
7961               else
7962                 {
7963                   // lit == 1, result = not(left)
7964                   if (size && sameRegs (AOP (result), AOP (left)))
7965                     {
7966                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7967                       goto release;
7968                     }
7969                   else
7970                     {
7971                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7972                       emitcode ("cpl", "c");
7973                     }
7974                 }
7975             }
7976
7977         }
7978       else
7979         {
7980           // right != literal
7981           symbol *tlbl = newiTempLabel (NULL);
7982           if (AOP_TYPE (right) == AOP_CRY)
7983             {
7984               // c = bit ^ bit;
7985               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7986             }
7987           else
7988             {
7989               int sizer = AOP_SIZE (right);
7990               // c = bit ^ val
7991               // if val>>1 != 0, result = 1
7992               emitcode ("setb", "c");
7993               while (sizer)
7994                 {
7995                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
7996                   if (sizer == 1)
7997                     // test the msb of the lsb
7998                     emitcode ("anl", "a,#!constbyte",0xfe);
7999                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8000                   sizer--;
8001                 }
8002               // val = (0,1)
8003               emitcode ("rrc", "a");
8004             }
8005           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8006           emitcode ("cpl", "c");
8007           emitLabel (tlbl);
8008         }
8009       // bit = c
8010       // val = c
8011       if (size)
8012         outBitC (result);
8013       // if(bit | ...)
8014       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8015         genIfxJump (ifx, "c");
8016       goto release;
8017     }
8018
8019   /* if left is same as result */
8020   if (sameRegs (AOP (result), AOP (left)))
8021     {
8022       for (; size--; offset++)
8023         {
8024           if (AOP_TYPE (right) == AOP_LIT)
8025             {
8026               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8027               if (bytelit == 0)
8028                 {
8029                   /* dummy read of volatile operand */
8030                   if (isOperandVolatile (left, FALSE))
8031                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8032                   else
8033                     continue;
8034                 }
8035               else if (IS_AOP_PREG (left))
8036                 {
8037                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8038                   emitcode ("xrl", "a,%s",
8039                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8040                   aopPut (result, "a", offset);
8041                 }
8042               else
8043                 {
8044                   emitcode ("xrl", "%s,%s",
8045                             aopGet (left, offset, FALSE, TRUE, NULL),
8046                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8047                 }
8048             }
8049           else
8050             {
8051               if (AOP_TYPE (left) == AOP_ACC)
8052                 emitcode ("xrl", "a,%s",
8053                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8054               else
8055                 {
8056                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8057                   if (IS_AOP_PREG (left))
8058                     {
8059                       emitcode ("xrl", "a,%s",
8060                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8061                       aopPut (result, "a", offset);
8062                     }
8063                   else
8064                     emitcode ("xrl", "%s,a",
8065                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8066                 }
8067             }
8068         }
8069     }
8070   else
8071     {
8072       // left & result in different registers
8073       if (AOP_TYPE (result) == AOP_CRY)
8074         {
8075           // result = bit
8076           // if(size), result in bit
8077           // if(!size && ifx), conditional oper: if(left ^ right)
8078           symbol *tlbl = newiTempLabel (NULL);
8079           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8080
8081           if (size)
8082             emitcode ("setb", "c");
8083           while (sizer--)
8084             {
8085               if ((AOP_TYPE (right) == AOP_LIT) &&
8086                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8087                 {
8088                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8089                 }
8090               else
8091                 {
8092                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
8093                     emitcode ("xrl", "a,%s",
8094                               aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8095                   } else {
8096                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8097                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8098                       {
8099                           emitcode("mov", "b,a");
8100                           rOp = "b";
8101                       }
8102
8103                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8104                       emitcode ("xrl", "a,%s", rOp);
8105                   }
8106                 }
8107               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8108               offset++;
8109             }
8110           if (size)
8111             {
8112               CLRC;
8113               emitLabel (tlbl);
8114               outBitC (result);
8115             }
8116           else if (ifx)
8117             jmpTrueOrFalse (ifx, tlbl);
8118         }
8119       else
8120         {
8121         for (; (size--); offset++)
8122           {
8123             // normal case
8124             // result = left ^ right
8125             if (AOP_TYPE (right) == AOP_LIT)
8126               {
8127                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8128                 if (bytelit == 0)
8129                   {
8130                     aopPut (result,
8131                             aopGet (left, offset, FALSE, FALSE, NULL),
8132                             offset);
8133                     continue;
8134                   }
8135                 D (emitcode (";", "better literal XOR."));
8136                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8137                 emitcode ("xrl", "a, %s",
8138                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8139               }
8140             else
8141               {
8142                 // faster than result <- left, anl result,right
8143                 // and better if result is SFR
8144                 if (AOP_TYPE (left) == AOP_ACC)
8145                   {
8146                     emitcode ("xrl", "a,%s",
8147                               aopGet (right, offset,
8148                                       FALSE, FALSE, DP2_RESULT_REG));
8149                   }
8150                 else
8151                   {
8152                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8153                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8154                       {
8155                           emitcode("mov", "b,a");
8156                           rOp = "b";
8157                       }
8158
8159                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8160                       emitcode ("xrl", "a,%s", rOp);
8161                   }
8162               }
8163             aopPut (result, "a", offset);
8164           }
8165         }
8166     }
8167
8168 release:
8169   freeAsmop (result, NULL, ic, TRUE);
8170   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8171   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8172 }
8173
8174 /*-----------------------------------------------------------------*/
8175 /* genInline - write the inline code out                           */
8176 /*-----------------------------------------------------------------*/
8177 static void
8178 genInline (iCode * ic)
8179 {
8180   char *buffer, *bp, *bp1;
8181
8182   D (emitcode (";", "genInline"));
8183
8184   _G.inLine += (!options.asmpeep);
8185
8186   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
8187
8188   /* emit each line as a code */
8189   while (*bp)
8190     {
8191       if (*bp == '\n')
8192         {
8193           *bp++ = '\0';
8194           emitcode (bp1, "");
8195           bp1 = bp;
8196         }
8197       else
8198         {
8199           /* Add \n for labels, not dirs such as c:\mydir */
8200           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
8201             {
8202               bp++;
8203               *bp = '\0';
8204               bp++;
8205               emitcode (bp1, "");
8206               bp1 = bp;
8207             }
8208           else
8209             bp++;
8210         }
8211     }
8212   if (bp1 != bp)
8213     emitcode (bp1, "");
8214   /*     emitcode("",buffer); */
8215   _G.inLine -= (!options.asmpeep);
8216 }
8217
8218 /*-----------------------------------------------------------------*/
8219 /* genRRC - rotate right with carry                                */
8220 /*-----------------------------------------------------------------*/
8221 static void
8222 genRRC (iCode * ic)
8223 {
8224   operand *left, *result;
8225   int     size, offset;
8226   char *l;
8227
8228   D (emitcode (";", "genRRC"));
8229
8230   /* rotate right with carry */
8231   left = IC_LEFT (ic);
8232   result = IC_RESULT (ic);
8233   aopOp (left, ic, FALSE, FALSE);
8234   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8235
8236   /* move it to the result */
8237   size = AOP_SIZE (result);
8238   offset = size - 1;
8239   CLRC;
8240
8241   _startLazyDPSEvaluation ();
8242   while (size--)
8243     {
8244       l = aopGet (left, offset, FALSE, FALSE, NULL);
8245       MOVA (l);
8246       emitcode ("rrc", "a");
8247       if (AOP_SIZE (result) > 1)
8248         aopPut (result, "a", offset--);
8249     }
8250   _endLazyDPSEvaluation ();
8251
8252   /* now we need to put the carry into the
8253      highest order byte of the result */
8254   if (AOP_SIZE (result) > 1)
8255     {
8256       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8257       MOVA (l);
8258     }
8259   emitcode ("mov", "acc.7,c");
8260   aopPut (result, "a", AOP_SIZE (result) - 1);
8261   freeAsmop (result, NULL, ic, TRUE);
8262   freeAsmop (left, NULL, ic, TRUE);
8263 }
8264
8265 /*-----------------------------------------------------------------*/
8266 /* genRLC - generate code for rotate left with carry               */
8267 /*-----------------------------------------------------------------*/
8268 static void
8269 genRLC (iCode * ic)
8270 {
8271   operand *left, *result;
8272   int size, offset;
8273   char *l;
8274
8275   D (emitcode (";", "genRLC"));
8276
8277   /* rotate right with carry */
8278   left = IC_LEFT (ic);
8279   result = IC_RESULT (ic);
8280   aopOp (left, ic, FALSE, FALSE);
8281   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8282
8283   /* move it to the result */
8284   size = AOP_SIZE (result);
8285   offset = 0;
8286   if (size--)
8287     {
8288       l = aopGet (left, offset, FALSE, FALSE, NULL);
8289       MOVA (l);
8290       emitcode ("add", "a,acc");
8291       if (AOP_SIZE (result) > 1)
8292         {
8293           aopPut (result, "a", offset++);
8294         }
8295
8296       _startLazyDPSEvaluation ();
8297       while (size--)
8298         {
8299           l = aopGet (left, offset, FALSE, FALSE, NULL);
8300           MOVA (l);
8301           emitcode ("rlc", "a");
8302           if (AOP_SIZE (result) > 1)
8303             aopPut (result, "a", offset++);
8304         }
8305       _endLazyDPSEvaluation ();
8306     }
8307   /* now we need to put the carry into the
8308      highest order byte of the result */
8309   if (AOP_SIZE (result) > 1)
8310     {
8311       l = aopGet (result, 0, FALSE, FALSE, NULL);
8312       MOVA (l);
8313     }
8314   emitcode ("mov", "acc.0,c");
8315   aopPut (result, "a", 0);
8316   freeAsmop (result, NULL, ic, TRUE);
8317   freeAsmop (left, NULL, ic, TRUE);
8318 }
8319
8320 /*-----------------------------------------------------------------*/
8321 /* genGetHbit - generates code get highest order bit               */
8322 /*-----------------------------------------------------------------*/
8323 static void
8324 genGetHbit (iCode * ic)
8325 {
8326   operand *left, *result;
8327
8328   D (emitcode (";", "genGetHbit"));
8329
8330   left = IC_LEFT (ic);
8331   result = IC_RESULT (ic);
8332   aopOp (left, ic, FALSE, FALSE);
8333   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8334
8335   /* get the highest order byte into a */
8336   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8337   if (AOP_TYPE (result) == AOP_CRY)
8338     {
8339       emitcode ("rlc", "a");
8340       outBitC (result);
8341     }
8342   else
8343     {
8344       emitcode ("rl", "a");
8345       emitcode ("anl", "a,#1");
8346       outAcc (result);
8347     }
8348
8349
8350   freeAsmop (result, NULL, ic, TRUE);
8351   freeAsmop (left, NULL, ic, TRUE);
8352 }
8353
8354 /*-----------------------------------------------------------------*/
8355 /* genSwap - generates code to swap nibbles or bytes               */
8356 /*-----------------------------------------------------------------*/
8357 static void
8358 genSwap (iCode * ic)
8359 {
8360   operand *left, *result;
8361
8362   D(emitcode (";     genSwap",""));
8363
8364   left = IC_LEFT (ic);
8365   result = IC_RESULT (ic);
8366   aopOp (left, ic, FALSE, FALSE);
8367   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8368
8369   _startLazyDPSEvaluation ();
8370   switch (AOP_SIZE (left))
8371     {
8372     case 1: /* swap nibbles in byte */
8373       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8374       emitcode ("swap", "a");
8375       aopPut (result, "a", 0);
8376       break;
8377     case 2: /* swap bytes in word */
8378       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8379         {
8380           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8381           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8382           aopPut (result, "a", 1);
8383         }
8384       else if (operandsEqu (left, result))
8385         {
8386           char * reg = "a";
8387           bool pushedB = FALSE, leftInB = FALSE;
8388
8389           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8390           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8391             {
8392               pushedB = pushB ();
8393               emitcode ("mov", "b,a");
8394               reg = "b";
8395               leftInB = TRUE;
8396             }
8397           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8398           aopPut (result, reg, 1);
8399
8400           if (leftInB)
8401             popB (pushedB);
8402         }
8403       else
8404         {
8405           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8406           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8407         }
8408       break;
8409     default:
8410       wassertl(FALSE, "unsupported SWAP operand size");
8411     }
8412   _endLazyDPSEvaluation ();
8413
8414   freeAsmop (result, NULL, ic, TRUE);
8415   freeAsmop (left, NULL, ic, TRUE);
8416 }
8417
8418 /*-----------------------------------------------------------------*/
8419 /* AccRol - rotate left accumulator by known count                 */
8420 /*-----------------------------------------------------------------*/
8421 static void
8422 AccRol (int shCount)
8423 {
8424   shCount &= 0x0007;            // shCount : 0..7
8425
8426   switch (shCount)
8427     {
8428     case 0:
8429       break;
8430     case 1:
8431       emitcode ("rl", "a");
8432       break;
8433     case 2:
8434       emitcode ("rl", "a");
8435       emitcode ("rl", "a");
8436       break;
8437     case 3:
8438       emitcode ("swap", "a");
8439       emitcode ("rr", "a");
8440       break;
8441     case 4:
8442       emitcode ("swap", "a");
8443       break;
8444     case 5:
8445       emitcode ("swap", "a");
8446       emitcode ("rl", "a");
8447       break;
8448     case 6:
8449       emitcode ("rr", "a");
8450       emitcode ("rr", "a");
8451       break;
8452     case 7:
8453       emitcode ("rr", "a");
8454       break;
8455     }
8456 }
8457
8458 /*-----------------------------------------------------------------*/
8459 /* AccLsh - left shift accumulator by known count                  */
8460 /*-----------------------------------------------------------------*/
8461 static void
8462 AccLsh (int shCount)
8463 {
8464   if (shCount != 0)
8465     {
8466       if (shCount == 1)
8467         emitcode ("add", "a,acc");
8468       else if (shCount == 2)
8469         {
8470           emitcode ("add", "a,acc");
8471           emitcode ("add", "a,acc");
8472         }
8473       else
8474         {
8475           /* rotate left accumulator */
8476           AccRol (shCount);
8477           /* and kill the lower order bits */
8478           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8479         }
8480     }
8481 }
8482
8483 /*-----------------------------------------------------------------*/
8484 /* AccRsh - right shift accumulator by known count                 */
8485 /*-----------------------------------------------------------------*/
8486 static void
8487 AccRsh (int shCount)
8488 {
8489   if (shCount != 0)
8490     {
8491       if (shCount == 1)
8492         {
8493           CLRC;
8494           emitcode ("rrc", "a");
8495         }
8496       else
8497         {
8498           /* rotate right accumulator */
8499           AccRol (8 - shCount);
8500           /* and kill the higher order bits */
8501           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8502         }
8503     }
8504 }
8505
8506 #ifdef BETTER_LITERAL_SHIFT
8507 /*-----------------------------------------------------------------*/
8508 /* AccSRsh - signed right shift accumulator by known count                 */
8509 /*-----------------------------------------------------------------*/
8510 static void
8511 AccSRsh (int shCount)
8512 {
8513   symbol *tlbl;
8514   if (shCount != 0)
8515     {
8516       if (shCount == 1)
8517         {
8518           emitcode ("mov", "c,acc.7");
8519           emitcode ("rrc", "a");
8520         }
8521       else if (shCount == 2)
8522         {
8523           emitcode ("mov", "c,acc.7");
8524           emitcode ("rrc", "a");
8525           emitcode ("mov", "c,acc.7");
8526           emitcode ("rrc", "a");
8527         }
8528       else
8529         {
8530           tlbl = newiTempLabel (NULL);
8531           /* rotate right accumulator */
8532           AccRol (8 - shCount);
8533           /* and kill the higher order bits */
8534           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8535           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8536           emitcode ("orl", "a,#!constbyte",
8537                     (unsigned char) ~SRMask[shCount]);
8538           emitLabel (tlbl);
8539         }
8540     }
8541 }
8542 #endif
8543
8544 #ifdef BETTER_LITERAL_SHIFT
8545 /*-----------------------------------------------------------------*/
8546 /* shiftR1Left2Result - shift right one byte from left to result   */
8547 /*-----------------------------------------------------------------*/
8548 static void
8549 shiftR1Left2Result (operand * left, int offl,
8550                     operand * result, int offr,
8551                     int shCount, int sign)
8552 {
8553   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8554   /* shift right accumulator */
8555   if (sign)
8556     AccSRsh (shCount);
8557   else
8558     AccRsh (shCount);
8559   aopPut (result, "a", offr);
8560 }
8561 #endif
8562
8563 #ifdef BETTER_LITERAL_SHIFT
8564 /*-----------------------------------------------------------------*/
8565 /* shiftL1Left2Result - shift left one byte from left to result    */
8566 /*-----------------------------------------------------------------*/
8567 static void
8568 shiftL1Left2Result (operand * left, int offl,
8569                     operand * result, int offr, int shCount)
8570 {
8571   char *l;
8572   l = aopGet (left, offl, FALSE, FALSE, NULL);
8573   MOVA (l);
8574   /* shift left accumulator */
8575   AccLsh (shCount);
8576   aopPut (result, "a", offr);
8577 }
8578 #endif
8579
8580 #ifdef BETTER_LITERAL_SHIFT
8581 /*-----------------------------------------------------------------*/
8582 /* movLeft2Result - move byte from left to result                  */
8583 /*-----------------------------------------------------------------*/
8584 static void
8585 movLeft2Result (operand * left, int offl,
8586                 operand * result, int offr, int sign)
8587 {
8588   char *l;
8589   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8590   {
8591       l = aopGet (left, offl, FALSE, FALSE, NULL);
8592
8593       if (*l == '@' && (IS_AOP_PREG (result)))
8594       {
8595           emitcode ("mov", "a,%s", l);
8596           aopPut (result, "a", offr);
8597       }
8598       else
8599       {
8600           if (!sign)
8601           {
8602             aopPut (result, l, offr);
8603           }
8604           else
8605             {
8606               /* MSB sign in acc.7 ! */
8607               if (getDataSize (left) == offl + 1)
8608                 {
8609                   MOVA (l);
8610                   aopPut (result, "a", offr);
8611                 }
8612             }
8613       }
8614   }
8615 }
8616 #endif
8617
8618 #ifdef BETTER_LITERAL_SHIFT
8619 /*-----------------------------------------------------------------*/
8620 /* AccAXRrl1 - right rotate a:x by 1                               */
8621 /*-----------------------------------------------------------------*/
8622 static void
8623 AccAXRrl1 (char *x)
8624 {
8625   emitcode ("mov", "c,acc.0");
8626   emitcode ("xch", "a,%s", x);
8627   emitcode ("rrc", "a");
8628   emitcode ("xch", "a,%s", x);
8629   emitcode ("rrc", "a");
8630 }
8631 #endif
8632
8633 #ifdef BETTER_LITERAL_SHIFT
8634 //REMOVE ME!!!
8635 /*-----------------------------------------------------------------*/
8636 /* AccAXLrl1 - left rotate a:x by 1                                */
8637 /*-----------------------------------------------------------------*/
8638 static void
8639 AccAXLrl1 (char *x)
8640 {
8641   emitcode ("mov", "c,acc.7");
8642   emitcode ("xch", "a,%s", x);
8643   emitcode ("rlc", "a");
8644   emitcode ("xch", "a,%s", x);
8645   emitcode ("rlc", "a");
8646 }
8647 #endif
8648
8649 #ifdef BETTER_LITERAL_SHIFT
8650 /*-----------------------------------------------------------------*/
8651 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8652 /*-----------------------------------------------------------------*/
8653 static void
8654 AccAXRsh1 (char *x)
8655 {
8656   emitcode ("rrc", "a");
8657   emitcode ("xch", "a,%s", x);
8658   emitcode ("rrc", "a");
8659   emitcode ("xch", "a,%s", x);
8660 }
8661 #endif
8662
8663 #ifdef BETTER_LITERAL_SHIFT
8664 /*-----------------------------------------------------------------*/
8665 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8666 /*-----------------------------------------------------------------*/
8667 static void
8668 AccAXLsh1 (char *x)
8669 {
8670   emitcode ("xch", "a,%s", x);
8671   emitcode ("add", "a,acc");
8672   emitcode ("xch", "a,%s", x);
8673   emitcode ("rlc", "a");
8674 }
8675 #endif
8676
8677 #ifdef BETTER_LITERAL_SHIFT
8678 /*-----------------------------------------------------------------*/
8679 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8680 /*-----------------------------------------------------------------*/
8681 static void
8682 AccAXLsh (char *x, int shCount)
8683 {
8684   switch (shCount)
8685     {
8686     case 0:
8687       break;
8688     case 1:
8689       AccAXLsh1 (x);
8690       break;
8691     case 2:
8692       AccAXLsh1 (x);
8693       AccAXLsh1 (x);
8694       break;
8695     case 3:
8696     case 4:
8697     case 5:                             // AAAAABBB:CCCCCDDD
8698
8699       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8700
8701       emitcode ("anl", "a,#!constbyte",
8702                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8703
8704       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8705
8706       AccRol (shCount);                 // DDDCCCCC:BBB00000
8707
8708       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8709
8710       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8711
8712       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8713
8714       emitcode ("anl", "a,#!constbyte",
8715                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8716
8717       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8718
8719       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8720
8721       break;
8722     case 6:                             // AAAAAABB:CCCCCCDD
8723       emitcode ("anl", "a,#!constbyte",
8724                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8725 #if 1
8726       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8727       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8728       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8729 #else
8730       emitcode ("mov", "c,acc.0");      // c = B
8731       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8732       emitcode("rrc","a");
8733       emitcode("xch","a,%s", x);
8734       emitcode("rrc","a");
8735       emitcode("mov","c,acc.0"); //<< get correct bit
8736       emitcode("xch","a,%s", x);
8737
8738       emitcode("rrc","a");
8739       emitcode("xch","a,%s", x);
8740       emitcode("rrc","a");
8741       emitcode("xch","a,%s", x);
8742 #endif
8743       break;
8744     case 7:                             // a:x <<= 7
8745
8746       emitcode ("anl", "a,#!constbyte",
8747                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8748
8749       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8750
8751       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8752
8753       break;
8754     default:
8755       break;
8756     }
8757 }
8758 #endif
8759
8760 #ifdef BETTER_LITERAL_SHIFT
8761 //REMOVE ME!!!
8762 /*-----------------------------------------------------------------*/
8763 /* AccAXRsh - right shift a:x known count (0..7)                   */
8764 /*-----------------------------------------------------------------*/
8765 static void
8766 AccAXRsh (char *x, int shCount)
8767 {
8768   switch (shCount)
8769     {
8770     case 0:
8771       break;
8772     case 1:
8773       CLRC;
8774       AccAXRsh1 (x);                    // 0->a:x
8775
8776       break;
8777     case 2:
8778       CLRC;
8779       AccAXRsh1 (x);                    // 0->a:x
8780
8781       CLRC;
8782       AccAXRsh1 (x);                    // 0->a:x
8783
8784       break;
8785     case 3:
8786     case 4:
8787     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8788
8789       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8790
8791       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8792
8793       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8794
8795       emitcode ("anl", "a,#!constbyte",
8796                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8797
8798       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8799
8800       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8801
8802       emitcode ("anl", "a,#!constbyte",
8803                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8804
8805       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8806
8807       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8808
8809       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8810
8811       break;
8812     case 6:                             // AABBBBBB:CCDDDDDD
8813
8814       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8815       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8816
8817       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8818
8819       emitcode ("anl", "a,#!constbyte",
8820                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8821
8822       break;
8823     case 7:                             // ABBBBBBB:CDDDDDDD
8824
8825       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8826
8827       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8828
8829       emitcode ("anl", "a,#!constbyte",
8830                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8831
8832       break;
8833     default:
8834       break;
8835     }
8836 }
8837 #endif
8838
8839 #ifdef BETTER_LITERAL_SHIFT
8840 /*-----------------------------------------------------------------*/
8841 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8842 /*-----------------------------------------------------------------*/
8843 static void
8844 AccAXRshS (char *x, int shCount)
8845 {
8846   symbol *tlbl;
8847   switch (shCount)
8848     {
8849     case 0:
8850       break;
8851     case 1:
8852       emitcode ("mov", "c,acc.7");
8853       AccAXRsh1 (x);                    // s->a:x
8854
8855       break;
8856     case 2:
8857       emitcode ("mov", "c,acc.7");
8858       AccAXRsh1 (x);                    // s->a:x
8859
8860       emitcode ("mov", "c,acc.7");
8861       AccAXRsh1 (x);                    // s->a:x
8862
8863       break;
8864     case 3:
8865     case 4:
8866     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8867
8868       tlbl = newiTempLabel (NULL);
8869       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8870
8871       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8872
8873       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8874
8875       emitcode ("anl", "a,#!constbyte",
8876                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8877
8878       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8879
8880       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8881
8882       emitcode ("anl", "a,#!constbyte",
8883                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8884
8885       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8886
8887       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8888
8889       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8890
8891       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8892       emitcode ("orl", "a,#!constbyte",
8893                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8894
8895       emitLabel (tlbl);
8896       break;                            // SSSSAAAA:BBBCCCCC
8897
8898     case 6:                             // AABBBBBB:CCDDDDDD
8899
8900       tlbl = newiTempLabel (NULL);
8901
8902       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
8903       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8904
8905       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8906
8907       emitcode ("anl", "a,#!constbyte",
8908                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8909
8910       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8911       emitcode ("orl", "a,#!constbyte",
8912                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8913
8914       emitLabel (tlbl);
8915       break;
8916     case 7:                             // ABBBBBBB:CDDDDDDD
8917
8918       tlbl = newiTempLabel (NULL);
8919
8920       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8921
8922       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8923
8924       emitcode ("anl", "a,#!constbyte",
8925                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8926
8927       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8928       emitcode ("orl", "a,#!constbyte",
8929                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8930
8931       emitLabel (tlbl);
8932       break;
8933     default:
8934       break;
8935     }
8936 }
8937 #endif
8938
8939 #ifdef BETTER_LITERAL_SHIFT
8940 static void
8941 _loadLeftIntoAx(char    **lsb,
8942                 operand *left,
8943                 operand *result,
8944                 int     offl,
8945                 int     offr)
8946 {
8947   // Get the initial value from left into a pair of registers.
8948   // MSB must be in A, LSB can be any register.
8949   //
8950   // If the result is held in registers, it is an optimization
8951   // if the LSB can be held in the register which will hold the,
8952   // result LSB since this saves us from having to copy it into
8953   // the result following AccAXLsh.
8954   //
8955   // If the result is addressed indirectly, this is not a gain.
8956   if (AOP_NEEDSACC(result))
8957   {
8958        char *leftByte;
8959
8960        _startLazyDPSEvaluation();
8961       if (AOP_TYPE(left) == AOP_DPTR2)
8962        {
8963            // Get MSB in A.
8964            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
8965            // get LSB in DP2_RESULT_REG.
8966            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
8967            assert(!strcmp(leftByte, DP2_RESULT_REG));
8968        }
8969        else
8970        {
8971            // get LSB into DP2_RESULT_REG
8972            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
8973            if (strcmp(leftByte, DP2_RESULT_REG))
8974            {
8975                TR_AP("#7");
8976                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
8977            }
8978            // And MSB in A.
8979            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
8980            assert(strcmp(leftByte, DP2_RESULT_REG));
8981            MOVA (leftByte);
8982        }
8983        _endLazyDPSEvaluation();
8984        *lsb = DP2_RESULT_REG;
8985   }
8986   else
8987   {
8988       if (sameRegs (AOP (result), AOP (left)) &&
8989         ((offl + MSB16) == offr))
8990       {
8991           /* don't crash result[offr] */
8992           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8993           emitcode ("xch", "a,%s",
8994                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
8995       }
8996       else
8997       {
8998           movLeft2Result (left, offl, result, offr, 0);
8999           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9000       }
9001       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9002       assert(strcmp(*lsb,"a"));
9003   }
9004 }
9005
9006 static void
9007 _storeAxResults(char    *lsb,
9008                 operand *result,
9009                 int     offr)
9010 {
9011   _startLazyDPSEvaluation();
9012   if (AOP_NEEDSACC(result))
9013   {
9014       /* We have to explicitly update the result LSB.
9015        */
9016       emitcode ("xch","a,%s", lsb);
9017       aopPut (result, "a", offr);
9018       emitcode ("mov","a,%s", lsb);
9019   }
9020   if (getDataSize (result) > 1)
9021   {
9022       aopPut (result, "a", offr + MSB16);
9023   }
9024   _endLazyDPSEvaluation();
9025 }
9026
9027 /*-----------------------------------------------------------------*/
9028 /* shiftL2Left2Result - shift left two bytes from left to result   */
9029 /*-----------------------------------------------------------------*/
9030 static void
9031 shiftL2Left2Result (operand * left, int offl,
9032                     operand * result, int offr, int shCount)
9033 {
9034   char *lsb;
9035
9036   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9037
9038   AccAXLsh (lsb, shCount);
9039
9040   _storeAxResults(lsb, result, offr);
9041 }
9042 #endif
9043
9044 #ifdef BETTER_LITERAL_SHIFT
9045 /*-----------------------------------------------------------------*/
9046 /* shiftR2Left2Result - shift right two bytes from left to result  */
9047 /*-----------------------------------------------------------------*/
9048 static void
9049 shiftR2Left2Result (operand * left, int offl,
9050                     operand * result, int offr,
9051                     int shCount, int sign)
9052 {
9053   char *lsb;
9054
9055   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9056
9057   /* a:x >> shCount (x = lsb(result)) */
9058   if (sign)
9059   {
9060      AccAXRshS(lsb, shCount);
9061   }
9062   else
9063   {
9064     AccAXRsh(lsb, shCount);
9065   }
9066
9067   _storeAxResults(lsb, result, offr);
9068 }
9069 #endif
9070
9071 /*-----------------------------------------------------------------*/
9072 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9073 /*-----------------------------------------------------------------*/
9074 static void
9075 shiftLLeftOrResult (operand * left, int offl,
9076                     operand * result, int offr, int shCount)
9077 {
9078   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9079   /* shift left accumulator */
9080   AccLsh (shCount);
9081   /* or with result */
9082   emitcode ("orl", "a,%s",
9083             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9084   /* back to result */
9085   aopPut (result, "a", offr);
9086 }
9087
9088 #if 0
9089 //REMOVE ME!!!
9090 /*-----------------------------------------------------------------*/
9091 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9092 /*-----------------------------------------------------------------*/
9093 static void
9094 shiftRLeftOrResult (operand * left, int offl,
9095                     operand * result, int offr, int shCount)
9096 {
9097   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9098   /* shift right accumulator */
9099   AccRsh (shCount);
9100   /* or with result */
9101   emitcode ("orl", "a,%s",
9102             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9103   /* back to result */
9104   aopPut (result, "a", offr);
9105 }
9106 #endif
9107
9108 #ifdef BETTER_LITERAL_SHIFT
9109 /*-----------------------------------------------------------------*/
9110 /* genlshOne - left shift a one byte quantity by known count       */
9111 /*-----------------------------------------------------------------*/
9112 static void
9113 genlshOne (operand * result, operand * left, int shCount)
9114 {
9115   D (emitcode (";", "genlshOne"));
9116
9117   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9118 }
9119 #endif
9120
9121 #ifdef BETTER_LITERAL_SHIFT
9122 /*-----------------------------------------------------------------*/
9123 /* genlshTwo - left shift two bytes by known amount != 0           */
9124 /*-----------------------------------------------------------------*/
9125 static void
9126 genlshTwo (operand * result, operand * left, int shCount)
9127 {
9128   int size;
9129
9130   D (emitcode (";", "genlshTwo"));
9131
9132   size = getDataSize (result);
9133
9134   /* if shCount >= 8 */
9135   if (shCount >= 8)
9136   {
9137       shCount -= 8;
9138
9139       _startLazyDPSEvaluation();
9140
9141       if (size > 1)
9142         {
9143           if (shCount)
9144           {
9145             _endLazyDPSEvaluation();
9146             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9147             aopPut (result, zero, LSB);
9148           }
9149           else
9150           {
9151             movLeft2Result (left, LSB, result, MSB16, 0);
9152             aopPut (result, zero, LSB);
9153             _endLazyDPSEvaluation();
9154           }
9155         }
9156         else
9157         {
9158           aopPut (result, zero, LSB);
9159           _endLazyDPSEvaluation();
9160         }
9161   }
9162
9163   /*  1 <= shCount <= 7 */
9164   else
9165     {
9166       if (size == 1)
9167         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9168       else
9169         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9170       }
9171 }
9172 #endif
9173
9174 #if 0
9175 //REMOVE ME!!!
9176 /*-----------------------------------------------------------------*/
9177 /* shiftLLong - shift left one long from left to result            */
9178 /* offl = LSB or MSB16                                             */
9179 /*-----------------------------------------------------------------*/
9180 static void
9181 shiftLLong (operand * left, operand * result, int offr)
9182 {
9183   char *l;
9184   int size = AOP_SIZE (result);
9185
9186   if (size >= LSB + offr)
9187     {
9188       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9189       MOVA (l);
9190       emitcode ("add", "a,acc");
9191       if (sameRegs (AOP (left), AOP (result)) &&
9192           size >= MSB16 + offr && offr != LSB)
9193         emitcode ("xch", "a,%s",
9194                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9195       else
9196         aopPut (result, "a", LSB + offr);
9197     }
9198
9199   if (size >= MSB16 + offr)
9200     {
9201       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9202         {
9203           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9204           MOVA (l);
9205         }
9206       emitcode ("rlc", "a");
9207       if (sameRegs (AOP (left), AOP (result)) &&
9208           size >= MSB24 + offr && offr != LSB)
9209         emitcode ("xch", "a,%s",
9210                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9211       else
9212         aopPut (result, "a", MSB16 + offr);
9213     }
9214
9215   if (size >= MSB24 + offr)
9216     {
9217       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9218         {
9219           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9220           MOVA (l);
9221         }
9222       emitcode ("rlc", "a");
9223       if (sameRegs (AOP (left), AOP (result)) &&
9224           size >= MSB32 + offr && offr != LSB)
9225         emitcode ("xch", "a,%s",
9226                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9227       else
9228         aopPut (result, "a", MSB24 + offr);
9229     }
9230
9231   if (size > MSB32 + offr)
9232     {
9233       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9234         {
9235           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9236           MOVA (l);
9237         }
9238       emitcode ("rlc", "a");
9239       aopPut (result, "a", MSB32 + offr);
9240     }
9241   if (offr != LSB)
9242     aopPut (result, zero, LSB);
9243 }
9244 #endif
9245
9246 #if 0
9247 //REMOVE ME!!!
9248 /*-----------------------------------------------------------------*/
9249 /* genlshFour - shift four byte by a known amount != 0             */
9250 /*-----------------------------------------------------------------*/
9251 static void
9252 genlshFour (operand * result, operand * left, int shCount)
9253 {
9254   int size;
9255
9256   D (emitcode (";", "genlshFour"));
9257
9258   size = AOP_SIZE (result);
9259
9260   /* if shifting more that 3 bytes */
9261   if (shCount >= 24)
9262     {
9263       shCount -= 24;
9264       if (shCount)
9265         /* lowest order of left goes to the highest
9266            order of the destination */
9267         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9268       else
9269         movLeft2Result (left, LSB, result, MSB32, 0);
9270       aopPut (result, zero, LSB);
9271       aopPut (result, zero, MSB16);
9272       aopPut (result, zero, MSB24);
9273       return;
9274     }
9275
9276   /* more than two bytes */
9277   else if (shCount >= 16)
9278     {
9279       /* lower order two bytes goes to higher order two bytes */
9280       shCount -= 16;
9281       /* if some more remaining */
9282       if (shCount)
9283         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9284       else
9285         {
9286           movLeft2Result (left, MSB16, result, MSB32, 0);
9287           movLeft2Result (left, LSB, result, MSB24, 0);
9288         }
9289       aopPut (result, zero, MSB16);
9290       aopPut (result, zero, LSB);
9291       return;
9292     }
9293
9294   /* if more than 1 byte */
9295   else if (shCount >= 8)
9296     {
9297       /* lower order three bytes goes to higher order  three bytes */
9298       shCount -= 8;
9299       if (size == 2)
9300         {
9301           if (shCount)
9302             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9303           else
9304             movLeft2Result (left, LSB, result, MSB16, 0);
9305         }
9306       else
9307         {                       /* size = 4 */
9308           if (shCount == 0)
9309             {
9310               movLeft2Result (left, MSB24, result, MSB32, 0);
9311               movLeft2Result (left, MSB16, result, MSB24, 0);
9312               movLeft2Result (left, LSB, result, MSB16, 0);
9313               aopPut (result, zero, LSB);
9314             }
9315           else if (shCount == 1)
9316             shiftLLong (left, result, MSB16);
9317           else
9318             {
9319               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9320               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9321               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9322               aopPut (result, zero, LSB);
9323             }
9324         }
9325     }
9326
9327   /* 1 <= shCount <= 7 */
9328   else if (shCount <= 2)
9329     {
9330       shiftLLong (left, result, LSB);
9331       if (shCount == 2)
9332         shiftLLong (result, result, LSB);
9333     }
9334   /* 3 <= shCount <= 7, optimize */
9335   else
9336     {
9337       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9338       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9339       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9340     }
9341 }
9342 #endif
9343
9344 #ifdef BETTER_LITERAL_SHIFT
9345 /*-----------------------------------------------------------------*/
9346 /* genLeftShiftLiteral - left shifting by known count              */
9347 /*-----------------------------------------------------------------*/
9348 static bool
9349 genLeftShiftLiteral (operand * left,
9350                      operand * right,
9351                      operand * result,
9352                      iCode * ic)
9353 {
9354   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9355   int size;
9356
9357   size = getSize (operandType (result));
9358
9359   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9360
9361   /* We only handle certain easy cases so far. */
9362   if ((shCount != 0)
9363    && (shCount < (size * 8))
9364    && (size != 1)
9365    && (size != 2))
9366   {
9367       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9368       return FALSE;
9369   }
9370
9371   freeAsmop (right, NULL, ic, TRUE);
9372
9373   aopOp(left, ic, FALSE, FALSE);
9374   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9375
9376 #if 0 // debug spew
9377   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9378   {
9379         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9380         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9381         {
9382            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9383         }
9384   }
9385   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9386   {
9387         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9388         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9389         {
9390            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9391         }
9392   }
9393 #endif
9394
9395 #if VIEW_SIZE
9396   emitcode ("; shift left ", "result %d, left %d", size,
9397             AOP_SIZE (left));
9398 #endif
9399
9400   /* I suppose that the left size >= result size */
9401   if (shCount == 0)
9402   {
9403         _startLazyDPSEvaluation();
9404         while (size--)
9405         {
9406           movLeft2Result (left, size, result, size, 0);
9407         }
9408         _endLazyDPSEvaluation();
9409   }
9410   else if (shCount >= (size * 8))
9411   {
9412     _startLazyDPSEvaluation();
9413     while (size--)
9414     {
9415       aopPut (result, zero, size);
9416     }
9417     _endLazyDPSEvaluation();
9418   }
9419   else
9420   {
9421       switch (size)
9422         {
9423         case 1:
9424           genlshOne (result, left, shCount);
9425           break;
9426
9427         case 2:
9428           genlshTwo (result, left, shCount);
9429           break;
9430 #if 0
9431         case 4:
9432           genlshFour (result, left, shCount);
9433           break;
9434 #endif
9435         default:
9436           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9437                   "*** ack! mystery literal shift!\n");
9438           break;
9439         }
9440     }
9441   freeAsmop (result, NULL, ic, TRUE);
9442   freeAsmop (left, NULL, ic, TRUE);
9443   return TRUE;
9444 }
9445 #endif
9446
9447 /*-----------------------------------------------------------------*/
9448 /* genLeftShift - generates code for left shifting                 */
9449 /*-----------------------------------------------------------------*/
9450 static void
9451 genLeftShift (iCode * ic)
9452 {
9453   operand *left, *right, *result;
9454   int size, offset;
9455   char *l;
9456   symbol *tlbl, *tlbl1;
9457   bool pushedB;
9458
9459   D (emitcode (";", "genLeftShift"));
9460
9461   right = IC_RIGHT (ic);
9462   left = IC_LEFT (ic);
9463   result = IC_RESULT (ic);
9464
9465   aopOp (right, ic, FALSE, FALSE);
9466
9467
9468 #ifdef BETTER_LITERAL_SHIFT
9469   /* if the shift count is known then do it
9470      as efficiently as possible */
9471   if (AOP_TYPE (right) == AOP_LIT)
9472     {
9473       if (genLeftShiftLiteral (left, right, result, ic))
9474       {
9475         return;
9476       }
9477     }
9478 #endif
9479
9480   /* shift count is unknown then we have to form
9481      a loop get the loop count in B : Note: we take
9482      only the lower order byte since shifting
9483      more that 32 bits make no sense anyway, ( the
9484      largest size of an object can be only 32 bits ) */
9485
9486   pushedB = pushB ();
9487   if (AOP_TYPE (right) == AOP_LIT)
9488   {
9489       /* Really should be handled by genLeftShiftLiteral,
9490        * but since I'm too lazy to fix that today, at least we can make
9491        * some small improvement.
9492        */
9493        emitcode("mov", "b,#!constbyte",
9494                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9495   }
9496   else
9497   {
9498       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9499       emitcode ("inc", "b");
9500   }
9501   freeAsmop (right, NULL, ic, TRUE);
9502   aopOp (left, ic, FALSE, FALSE);
9503   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9504
9505   /* now move the left to the result if they are not the same */
9506   if (!sameRegs (AOP (left), AOP (result)) &&
9507       AOP_SIZE (result) > 1)
9508     {
9509
9510       size = AOP_SIZE (result);
9511       offset = 0;
9512       _startLazyDPSEvaluation ();
9513       while (size--)
9514         {
9515           l = aopGet (left, offset, FALSE, TRUE, NULL);
9516           if (*l == '@' && (IS_AOP_PREG (result)))
9517             {
9518
9519               emitcode ("mov", "a,%s", l);
9520               aopPut (result, "a", offset);
9521             }
9522           else
9523             aopPut (result, l, offset);
9524           offset++;
9525         }
9526       _endLazyDPSEvaluation ();
9527     }
9528
9529   tlbl = newiTempLabel (NULL);
9530   size = AOP_SIZE (result);
9531   offset = 0;
9532   tlbl1 = newiTempLabel (NULL);
9533
9534   /* if it is only one byte then */
9535   if (size == 1)
9536     {
9537       symbol *tlbl1 = newiTempLabel (NULL);
9538
9539       l = aopGet (left, 0, FALSE, FALSE, NULL);
9540       MOVA (l);
9541       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9542       emitLabel (tlbl);
9543       emitcode ("add", "a,acc");
9544       emitLabel (tlbl1);
9545       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9546       popB (pushedB);
9547       aopPut (result, "a", 0);
9548       goto release;
9549     }
9550
9551   reAdjustPreg (AOP (result));
9552
9553   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9554   emitLabel (tlbl);
9555   l = aopGet (result, offset, FALSE, FALSE, NULL);
9556   MOVA (l);
9557   emitcode ("add", "a,acc");
9558   aopPut (result, "a", offset++);
9559   _startLazyDPSEvaluation ();
9560   while (--size)
9561     {
9562       l = aopGet (result, offset, FALSE, FALSE, NULL);
9563       MOVA (l);
9564       emitcode ("rlc", "a");
9565       aopPut (result, "a", offset++);
9566     }
9567   _endLazyDPSEvaluation ();
9568   reAdjustPreg (AOP (result));
9569
9570   emitLabel (tlbl1);
9571   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9572   popB (pushedB);
9573 release:
9574   freeAsmop (result, NULL, ic, TRUE);
9575   freeAsmop (left, NULL, ic, TRUE);
9576 }
9577
9578 #ifdef BETTER_LITERAL_SHIFT
9579 /*-----------------------------------------------------------------*/
9580 /* genrshOne - right shift a one byte quantity by known count      */
9581 /*-----------------------------------------------------------------*/
9582 static void
9583 genrshOne (operand * result, operand * left,
9584            int shCount, int sign)
9585 {
9586   D (emitcode (";", "genrshOne"));
9587
9588   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9589 }
9590 #endif
9591
9592 #ifdef BETTER_LITERAL_SHIFT
9593 /*-----------------------------------------------------------------*/
9594 /* genrshTwo - right shift two bytes by known amount != 0          */
9595 /*-----------------------------------------------------------------*/
9596 static void
9597 genrshTwo (operand * result, operand * left,
9598            int shCount, int sign)
9599 {
9600   D (emitcode (";", "genrshTwo"));
9601
9602   /* if shCount >= 8 */
9603   if (shCount >= 8)
9604     {
9605       shCount -= 8;
9606       _startLazyDPSEvaluation();
9607       if (shCount)
9608         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9609       else
9610         movLeft2Result (left, MSB16, result, LSB, sign);
9611       addSign (result, MSB16, sign);
9612       _endLazyDPSEvaluation();
9613     }
9614
9615   /*  1 <= shCount <= 7 */
9616   else
9617     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9618 }
9619 #endif
9620
9621 /*-----------------------------------------------------------------*/
9622 /* shiftRLong - shift right one long from left to result           */
9623 /* offl = LSB or MSB16                                             */
9624 /*-----------------------------------------------------------------*/
9625 static void
9626 shiftRLong (operand * left, int offl,
9627             operand * result, int sign)
9628 {
9629   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9630
9631   if (overlapping && offl>1)
9632     {
9633       // we are in big trouble, but this shouldn't happen
9634       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9635     }
9636
9637   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9638
9639   if (offl==MSB16)
9640     {
9641       // shift is > 8
9642       if (sign)
9643         {
9644           emitcode ("rlc", "a");
9645           emitcode ("subb", "a,acc");
9646           emitcode ("xch", "a,%s",
9647                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9648         }
9649       else
9650         {
9651           aopPut (result, zero, MSB32);
9652         }
9653     }
9654
9655   if (!sign)
9656     {
9657       emitcode ("clr", "c");
9658     }
9659   else
9660     {
9661       emitcode ("mov", "c,acc.7");
9662     }
9663
9664   emitcode ("rrc", "a");
9665
9666   if (overlapping && offl==MSB16)
9667     {
9668       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9669     }
9670   else
9671     {
9672       aopPut (result, "a", MSB32 - offl);
9673       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9674     }
9675
9676   emitcode ("rrc", "a");
9677
9678   if (overlapping && offl==MSB16)
9679     {
9680       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9681     }
9682   else
9683     {
9684       aopPut (result, "a", MSB24 - offl);
9685       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9686     }
9687
9688   emitcode ("rrc", "a");
9689   if (offl != LSB)
9690     {
9691       aopPut (result, "a", MSB16 - offl);
9692     }
9693   else
9694     {
9695       if (overlapping && offl==MSB16)
9696         {
9697           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9698         }
9699       else
9700         {
9701           aopPut (result, "a", MSB16 - offl);
9702           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9703         }
9704       emitcode ("rrc", "a");
9705       aopPut (result, "a", LSB);
9706     }
9707 }
9708
9709 /*-----------------------------------------------------------------*/
9710 /* genrshFour - shift four byte by a known amount != 0             */
9711 /*-----------------------------------------------------------------*/
9712 static void
9713 genrshFour (operand * result, operand * left,
9714             int shCount, int sign)
9715 {
9716   D (emitcode (";", "genrshFour"));
9717
9718   /* if shifting more that 3 bytes */
9719   if (shCount >= 24)
9720     {
9721       shCount -= 24;
9722       _startLazyDPSEvaluation();
9723       if (shCount)
9724         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9725       else
9726         movLeft2Result (left, MSB32, result, LSB, sign);
9727       addSign (result, MSB16, sign);
9728       _endLazyDPSEvaluation();
9729     }
9730   else if (shCount >= 16)
9731     {
9732       shCount -= 16;
9733       _startLazyDPSEvaluation();
9734       if (shCount)
9735         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9736       else
9737         {
9738           movLeft2Result (left, MSB24, result, LSB, 0);
9739           movLeft2Result (left, MSB32, result, MSB16, sign);
9740         }
9741       addSign (result, MSB24, sign);
9742       _endLazyDPSEvaluation();
9743     }
9744   else if (shCount >= 8)
9745     {
9746       shCount -= 8;
9747       _startLazyDPSEvaluation();
9748       if (shCount == 1)
9749         {
9750             shiftRLong (left, MSB16, result, sign);
9751         }
9752       else if (shCount == 0)
9753         {
9754           movLeft2Result (left, MSB16, result, LSB, 0);
9755           movLeft2Result (left, MSB24, result, MSB16, 0);
9756           movLeft2Result (left, MSB32, result, MSB24, sign);
9757           addSign (result, MSB32, sign);
9758         }
9759       else
9760         {
9761           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9762           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9763           /* the last shift is signed */
9764           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9765           addSign (result, MSB32, sign);
9766         }
9767         _endLazyDPSEvaluation();
9768     }
9769   else
9770     {
9771       /* 1 <= shCount <= 7 */
9772       if (shCount <= 2)
9773         {
9774           shiftRLong (left, LSB, result, sign);
9775           if (shCount == 2)
9776             shiftRLong (result, LSB, result, sign);
9777         }
9778       else
9779         {
9780           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9781           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9782           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9783         }
9784     }
9785 }
9786
9787 #ifdef BETTER_LITERAL_SHIFT
9788 /*-----------------------------------------------------------------*/
9789 /* genRightShiftLiteral - right shifting by known count            */
9790 /*-----------------------------------------------------------------*/
9791 static bool
9792 genRightShiftLiteral (operand * left,
9793                       operand * right,
9794                       operand * result,
9795                       iCode * ic,
9796                       int sign)
9797 {
9798   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9799   int size;
9800
9801   size = getSize (operandType (result));
9802
9803   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9804
9805   /* We only handle certain easy cases so far. */
9806   if ((shCount != 0)
9807    && (shCount < (size * 8))
9808    && (size != 1)
9809    && (size != 2)
9810    && (size != 4))
9811   {
9812       D(emitcode (";", "genRightShiftLiteral wimping out"););
9813       return FALSE;
9814   }
9815
9816   freeAsmop (right, NULL, ic, TRUE);
9817
9818   aopOp (left, ic, FALSE, FALSE);
9819   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9820
9821 #if VIEW_SIZE
9822   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9823             AOP_SIZE (left));
9824 #endif
9825
9826   /* test the LEFT size !!! */
9827
9828   /* I suppose that the left size >= result size */
9829   if (shCount == 0)
9830   {
9831       size = getDataSize (result);
9832       _startLazyDPSEvaluation();
9833       while (size--)
9834         movLeft2Result (left, size, result, size, 0);
9835       _endLazyDPSEvaluation();
9836   }
9837   else if (shCount >= (size * 8))
9838     {
9839       if (sign)
9840         {
9841           /* get sign in acc.7 */
9842           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9843         }
9844       addSign (result, LSB, sign);
9845     }
9846   else
9847     {
9848       switch (size)
9849         {
9850         case 1:
9851           genrshOne (result, left, shCount, sign);
9852           break;
9853
9854         case 2:
9855           genrshTwo (result, left, shCount, sign);
9856           break;
9857 #if 1
9858         case 4:
9859           genrshFour (result, left, shCount, sign);
9860           break;
9861 #endif
9862         default:
9863           break;
9864         }
9865     }
9866   freeAsmop (result, NULL, ic, TRUE);
9867   freeAsmop (left, NULL, ic, TRUE);
9868
9869   return TRUE;
9870 }
9871 #endif
9872
9873 /*-----------------------------------------------------------------*/
9874 /* genSignedRightShift - right shift of signed number              */
9875 /*-----------------------------------------------------------------*/
9876 static void
9877 genSignedRightShift (iCode * ic)
9878 {
9879   operand *right, *left, *result;
9880   int size, offset;
9881   char *l;
9882   symbol *tlbl, *tlbl1;
9883   bool pushedB;
9884
9885   D (emitcode (";", "genSignedRightShift"));
9886
9887   /* we do it the hard way put the shift count in b
9888      and loop thru preserving the sign */
9889
9890   right = IC_RIGHT (ic);
9891   left = IC_LEFT (ic);
9892   result = IC_RESULT (ic);
9893
9894   aopOp (right, ic, FALSE, FALSE);
9895
9896 #ifdef BETTER_LITERAL_SHIFT
9897   if (AOP_TYPE (right) == AOP_LIT)
9898     {
9899       if (genRightShiftLiteral (left, right, result, ic, 1))
9900       {
9901         return;
9902       }
9903     }
9904 #endif
9905   /* shift count is unknown then we have to form
9906      a loop get the loop count in B : Note: we take
9907      only the lower order byte since shifting
9908      more that 32 bits make no sense anyway, ( the
9909      largest size of an object can be only 32 bits ) */
9910
9911   pushedB = pushB ();
9912   if (AOP_TYPE (right) == AOP_LIT)
9913   {
9914       /* Really should be handled by genRightShiftLiteral,
9915        * but since I'm too lazy to fix that today, at least we can make
9916        * some small improvement.
9917        */
9918        emitcode("mov", "b,#!constbyte",
9919                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9920   }
9921   else
9922   {
9923         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9924         emitcode ("inc", "b");
9925   }
9926   freeAsmop (right, NULL, ic, TRUE);
9927   aopOp (left, ic, FALSE, FALSE);
9928   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9929
9930   /* now move the left to the result if they are not the
9931      same */
9932   if (!sameRegs (AOP (left), AOP (result)) &&
9933       AOP_SIZE (result) > 1)
9934     {
9935
9936       size = AOP_SIZE (result);
9937       offset = 0;
9938       _startLazyDPSEvaluation ();
9939       while (size--)
9940         {
9941           l = aopGet (left, offset, FALSE, TRUE, NULL);
9942           if (*l == '@' && IS_AOP_PREG (result))
9943             {
9944
9945               emitcode ("mov", "a,%s", l);
9946               aopPut (result, "a", offset);
9947             }
9948           else
9949             aopPut (result, l, offset);
9950           offset++;
9951         }
9952       _endLazyDPSEvaluation ();
9953     }
9954
9955   /* mov the highest order bit to OVR */
9956   tlbl = newiTempLabel (NULL);
9957   tlbl1 = newiTempLabel (NULL);
9958
9959   size = AOP_SIZE (result);
9960   offset = size - 1;
9961   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
9962   emitcode ("rlc", "a");
9963   emitcode ("mov", "ov,c");
9964   /* if it is only one byte then */
9965   if (size == 1)
9966     {
9967       l = aopGet (left, 0, FALSE, FALSE, NULL);
9968       MOVA (l);
9969       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9970       emitLabel (tlbl);
9971       emitcode ("mov", "c,ov");
9972       emitcode ("rrc", "a");
9973       emitLabel (tlbl1);
9974       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9975       popB (pushedB);
9976       aopPut (result, "a", 0);
9977       goto release;
9978     }
9979
9980   reAdjustPreg (AOP (result));
9981   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9982   emitLabel (tlbl);
9983   emitcode ("mov", "c,ov");
9984   _startLazyDPSEvaluation ();
9985   while (size--)
9986     {
9987       l = aopGet (result, offset, FALSE, FALSE, NULL);
9988       MOVA (l);
9989       emitcode ("rrc", "a");
9990       aopPut (result, "a", offset--);
9991     }
9992   _endLazyDPSEvaluation ();
9993   reAdjustPreg (AOP (result));
9994   emitLabel (tlbl1);
9995   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9996   popB (pushedB);
9997
9998 release:
9999   freeAsmop (result, NULL, ic, TRUE);
10000   freeAsmop (left, NULL, ic, TRUE);
10001 }
10002
10003 /*-----------------------------------------------------------------*/
10004 /* genRightShift - generate code for right shifting                */
10005 /*-----------------------------------------------------------------*/
10006 static void
10007 genRightShift (iCode * ic)
10008 {
10009   operand *right, *left, *result;
10010   sym_link *letype;
10011   int size, offset;
10012   char *l;
10013   symbol *tlbl, *tlbl1;
10014   bool pushedB;
10015
10016   D (emitcode (";", "genRightShift"));
10017
10018   /* if signed then we do it the hard way preserve the
10019      sign bit moving it inwards */
10020   letype = getSpec (operandType (IC_LEFT (ic)));
10021
10022   if (!SPEC_USIGN (letype))
10023     {
10024       genSignedRightShift (ic);
10025       return;
10026     }
10027
10028   /* signed & unsigned types are treated the same : i.e. the
10029      signed is NOT propagated inwards : quoting from the
10030      ANSI - standard : "for E1 >> E2, is equivalent to division
10031      by 2**E2 if unsigned or if it has a non-negative value,
10032      otherwise the result is implementation defined ", MY definition
10033      is that the sign does not get propagated */
10034
10035   right = IC_RIGHT (ic);
10036   left = IC_LEFT (ic);
10037   result = IC_RESULT (ic);
10038
10039   aopOp (right, ic, FALSE, FALSE);
10040
10041 #ifdef BETTER_LITERAL_SHIFT
10042   /* if the shift count is known then do it
10043      as efficiently as possible */
10044   if (AOP_TYPE (right) == AOP_LIT)
10045     {
10046       if (genRightShiftLiteral (left, right, result, ic, 0))
10047       {
10048         return;
10049       }
10050     }
10051 #endif
10052
10053   /* shift count is unknown then we have to form
10054      a loop get the loop count in B : Note: we take
10055      only the lower order byte since shifting
10056      more that 32 bits make no sense anyway, ( the
10057      largest size of an object can be only 32 bits ) */
10058
10059   pushedB = pushB ();
10060   if (AOP_TYPE (right) == AOP_LIT)
10061   {
10062       /* Really should be handled by genRightShiftLiteral,
10063        * but since I'm too lazy to fix that today, at least we can make
10064        * some small improvement.
10065        */
10066        emitcode("mov", "b,#!constbyte",
10067                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10068   }
10069   else
10070   {
10071       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10072       emitcode ("inc", "b");
10073   }
10074   freeAsmop (right, NULL, ic, TRUE);
10075   aopOp (left, ic, FALSE, FALSE);
10076   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10077
10078   /* now move the left to the result if they are not the
10079      same */
10080   if (!sameRegs (AOP (left), AOP (result)) &&
10081       AOP_SIZE (result) > 1)
10082     {
10083       size = AOP_SIZE (result);
10084       offset = 0;
10085       _startLazyDPSEvaluation ();
10086       while (size--)
10087         {
10088           l = aopGet (left, offset, FALSE, TRUE, NULL);
10089           if (*l == '@' && IS_AOP_PREG (result))
10090             {
10091
10092               emitcode ("mov", "a,%s", l);
10093               aopPut (result, "a", offset);
10094             }
10095           else
10096             aopPut (result, l, offset);
10097           offset++;
10098         }
10099       _endLazyDPSEvaluation ();
10100     }
10101
10102   tlbl = newiTempLabel (NULL);
10103   tlbl1 = newiTempLabel (NULL);
10104   size = AOP_SIZE (result);
10105   offset = size - 1;
10106
10107   /* if it is only one byte then */
10108   if (size == 1)
10109     {
10110       l = aopGet (left, 0, FALSE, FALSE, NULL);
10111       MOVA (l);
10112       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10113       emitLabel (tlbl);
10114       CLRC;
10115       emitcode ("rrc", "a");
10116       emitLabel (tlbl1);
10117       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10118       popB (pushedB);
10119       aopPut (result, "a", 0);
10120       goto release;
10121     }
10122
10123   reAdjustPreg (AOP (result));
10124   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10125   emitLabel (tlbl);
10126   CLRC;
10127   _startLazyDPSEvaluation ();
10128   while (size--)
10129     {
10130       l = aopGet (result, offset, FALSE, FALSE, NULL);
10131       MOVA (l);
10132       emitcode ("rrc", "a");
10133       aopPut (result, "a", offset--);
10134     }
10135   _endLazyDPSEvaluation ();
10136   reAdjustPreg (AOP (result));
10137
10138   emitLabel (tlbl1);
10139   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10140   popB (pushedB);
10141
10142 release:
10143   freeAsmop (result, NULL, ic, TRUE);
10144   freeAsmop (left, NULL, ic, TRUE);
10145 }
10146
10147 /*-----------------------------------------------------------------*/
10148 /* emitPtrByteGet - emits code to get a byte into A through a      */
10149 /*                  pointer register (R0, R1, or DPTR). The        */
10150 /*                  original value of A can be preserved in B.     */
10151 /*-----------------------------------------------------------------*/
10152 static void
10153 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10154 {
10155   switch (p_type)
10156     {
10157     case IPOINTER:
10158     case POINTER:
10159       if (preserveAinB)
10160         emitcode ("mov", "b,a");
10161       emitcode ("mov", "a,@%s", rname);
10162       break;
10163
10164     case PPOINTER:
10165       if (preserveAinB)
10166         emitcode ("mov", "b,a");
10167       emitcode ("movx", "a,@%s", rname);
10168       break;
10169
10170     case FPOINTER:
10171       if (preserveAinB)
10172         emitcode ("mov", "b,a");
10173       emitcode ("movx", "a,@dptr");
10174       break;
10175
10176     case CPOINTER:
10177       if (preserveAinB)
10178         emitcode ("mov", "b,a");
10179       emitcode ("clr", "a");
10180       emitcode ("movc", "a,@a+dptr");
10181       break;
10182
10183     case GPOINTER:
10184       if (preserveAinB)
10185         {
10186           emitcode ("push", "b");
10187           emitcode ("push", "acc");
10188         }
10189       emitcode ("lcall", "__gptrget");
10190       if (preserveAinB)
10191         emitcode ("pop", "b");
10192       break;
10193     }
10194 }
10195
10196 /*-----------------------------------------------------------------*/
10197 /* emitPtrByteSet - emits code to set a byte from src through a    */
10198 /*                  pointer register (R0, R1, or DPTR).            */
10199 /*-----------------------------------------------------------------*/
10200 static void
10201 emitPtrByteSet (char *rname, int p_type, char *src)
10202 {
10203   switch (p_type)
10204     {
10205     case IPOINTER:
10206     case POINTER:
10207       if (*src=='@')
10208         {
10209           MOVA (src);
10210           emitcode ("mov", "@%s,a", rname);
10211         }
10212       else
10213         emitcode ("mov", "@%s,%s", rname, src);
10214       break;
10215
10216     case PPOINTER:
10217       MOVA (src);
10218       emitcode ("movx", "@%s,a", rname);
10219       break;
10220
10221     case FPOINTER:
10222       MOVA (src);
10223       emitcode ("movx", "@dptr,a");
10224       break;
10225
10226     case GPOINTER:
10227       MOVA (src);
10228       emitcode ("lcall", "__gptrput");
10229       break;
10230     }
10231 }
10232
10233 /*-----------------------------------------------------------------*/
10234 /* genUnpackBits - generates code for unpacking bits               */
10235 /*-----------------------------------------------------------------*/
10236 static void
10237 genUnpackBits (operand * result, char *rname, int ptype)
10238 {
10239   int offset = 0;       /* result byte offset */
10240   int rsize;            /* result size */
10241   int rlen = 0;         /* remaining bitfield length */
10242   sym_link *etype;      /* bitfield type information */
10243   int blen;             /* bitfield length */
10244   int bstr;             /* bitfield starting bit within byte */
10245
10246   D(emitcode (";     genUnpackBits",""));
10247
10248   etype = getSpec (operandType (result));
10249   rsize = getSize (operandType (result));
10250   blen = SPEC_BLEN (etype);
10251   bstr = SPEC_BSTR (etype);
10252
10253   /* If the bitfield length is less than a byte */
10254   if (blen < 8)
10255     {
10256       emitPtrByteGet (rname, ptype, FALSE);
10257       AccRol (8 - bstr);
10258       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10259       if (!SPEC_USIGN (etype))
10260         {
10261           /* signed bitfield */
10262           symbol *tlbl = newiTempLabel (NULL);
10263
10264           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10265           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10266           emitLabel (tlbl);
10267         }
10268       aopPut (result, "a", offset++);
10269       goto finish;
10270     }
10271
10272   /* Bit field did not fit in a byte. Copy all
10273      but the partial byte at the end.  */
10274   for (rlen=blen;rlen>=8;rlen-=8)
10275     {
10276       emitPtrByteGet (rname, ptype, FALSE);
10277       aopPut (result, "a", offset++);
10278       if (rlen>8)
10279         emitcode ("inc", "%s", rname);
10280     }
10281
10282   /* Handle the partial byte at the end */
10283   if (rlen)
10284     {
10285       emitPtrByteGet (rname, ptype, FALSE);
10286       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10287       if (!SPEC_USIGN (etype))
10288         {
10289           /* signed bitfield */
10290           symbol *tlbl = newiTempLabel (NULL);
10291
10292           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10293           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10294           emitLabel (tlbl);
10295         }
10296       aopPut (result, "a", offset++);
10297     }
10298
10299 finish:
10300   if (offset < rsize)
10301     {
10302       char *source;
10303
10304       if (SPEC_USIGN (etype))
10305         source = zero;
10306       else
10307         {
10308           /* signed bitfield: sign extension with 0x00 or 0xff */
10309           emitcode ("rlc", "a");
10310           emitcode ("subb", "a,acc");
10311
10312           source = "a";
10313         }
10314       rsize -= offset;
10315       while (rsize--)
10316         aopPut (result, source, offset++);
10317     }
10318 }
10319
10320
10321 /*-----------------------------------------------------------------*/
10322 /* genDataPointerGet - generates code when ptr offset is known     */
10323 /*-----------------------------------------------------------------*/
10324 static void
10325 genDataPointerGet (operand * left,
10326                    operand * result,
10327                    iCode * ic)
10328 {
10329   char *l;
10330   char buffer[256];
10331   int size, offset = 0;
10332   aopOp (result, ic, TRUE, FALSE);
10333
10334   /* get the string representation of the name */
10335   l = aopGet (left, 0, FALSE, TRUE, NULL);
10336   size = AOP_SIZE (result);
10337   _startLazyDPSEvaluation ();
10338   while (size--)
10339     {
10340         if (offset)
10341         {
10342             SNPRINTF (buffer, sizeof(buffer),
10343                       "(%s + %d)", l + 1, offset);
10344         }
10345         else
10346         {
10347             SNPRINTF (buffer, sizeof(buffer),
10348                       "%s", l + 1);
10349         }
10350       aopPut (result, buffer, offset++);
10351     }
10352   _endLazyDPSEvaluation ();
10353
10354   freeAsmop (result, NULL, ic, TRUE);
10355   freeAsmop (left, NULL, ic, TRUE);
10356 }
10357
10358 /*-----------------------------------------------------------------*/
10359 /* genNearPointerGet - emitcode for near pointer fetch             */
10360 /*-----------------------------------------------------------------*/
10361 static void
10362 genNearPointerGet (operand * left,
10363                    operand * result,
10364                    iCode * ic,
10365                    iCode *pi)
10366 {
10367   asmop *aop = NULL;
10368   regs *preg;
10369   char *rname;
10370   sym_link *rtype, *retype, *letype;
10371   sym_link *ltype = operandType (left);
10372   char buffer[80];
10373
10374   rtype = operandType (result);
10375   retype = getSpec (rtype);
10376   letype = getSpec (ltype);
10377
10378   aopOp (left, ic, FALSE, FALSE);
10379
10380   /* if left is rematerialisable and
10381      result is not bitfield variable type and
10382      the left is pointer to data space i.e
10383      lower 128 bytes of space */
10384   if (AOP_TYPE (left) == AOP_IMMD &&
10385       !IS_BITFIELD (retype) &&
10386       !IS_BITFIELD (letype) &&
10387       DCL_TYPE (ltype) == POINTER)
10388     {
10389       genDataPointerGet (left, result, ic);
10390       return;
10391     }
10392
10393   /* if the value is already in a pointer register
10394      then don't need anything more */
10395   if (!AOP_INPREG (AOP (left)))
10396     {
10397       /* otherwise get a free pointer register */
10398       aop = newAsmop (0);
10399       preg = getFreePtr (ic, &aop, FALSE);
10400       emitcode ("mov", "%s,%s",
10401                 preg->name,
10402                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10403       rname = preg->name;
10404     }
10405   else
10406     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10407
10408   freeAsmop (left, NULL, ic, TRUE);
10409   aopOp (result, ic, FALSE, FALSE);
10410
10411   /* if bitfield then unpack the bits */
10412   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10413     genUnpackBits (result, rname, POINTER);
10414   else
10415     {
10416       /* we have can just get the values */
10417       int size = AOP_SIZE (result);
10418       int offset = 0;
10419
10420       while (size--)
10421         {
10422           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10423             {
10424
10425               emitcode ("mov", "a,@%s", rname);
10426               aopPut (result, "a", offset);
10427             }
10428           else
10429             {
10430               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10431               aopPut (result, buffer, offset);
10432             }
10433           offset++;
10434           if (size || pi)
10435                 emitcode ("inc", "%s", rname);
10436             }
10437         }
10438
10439   /* now some housekeeping stuff */
10440   if (aop)      /* we had to allocate for this iCode */
10441     {
10442       if (pi) { /* post increment present */
10443         aopPut (left, rname, 0);
10444       }
10445       freeAsmop (NULL, aop, ic, TRUE);
10446     }
10447   else
10448     {
10449       /* we did not allocate which means left
10450          already in a pointer register, then
10451          if size > 0 && this could be used again
10452          we have to point it back to where it
10453          belongs */
10454       if (AOP_SIZE (result) > 1 &&
10455           !OP_SYMBOL (left)->remat &&
10456           (OP_SYMBOL (left)->liveTo > ic->seq ||
10457            ic->depth) &&
10458           !pi)
10459         {
10460           int size = AOP_SIZE (result) - 1;
10461           while (size--)
10462             emitcode ("dec", "%s", rname);
10463         }
10464     }
10465
10466   /* done */
10467   freeAsmop (result, NULL, ic, TRUE);
10468   if (pi) pi->generated = 1;
10469 }
10470
10471 /*-----------------------------------------------------------------*/
10472 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10473 /*-----------------------------------------------------------------*/
10474 static void
10475 genPagedPointerGet (operand * left,
10476                     operand * result,
10477                     iCode * ic,
10478                     iCode * pi)
10479 {
10480   asmop *aop = NULL;
10481   regs *preg;
10482   char *rname;
10483   sym_link *rtype, *retype, *letype;
10484
10485   rtype = operandType (result);
10486   retype = getSpec (rtype);
10487   letype = getSpec (operandType (left));
10488   aopOp (left, ic, FALSE, FALSE);
10489
10490   /* if the value is already in a pointer register
10491      then don't need anything more */
10492   if (!AOP_INPREG (AOP (left)))
10493     {
10494       /* otherwise get a free pointer register */
10495       aop = newAsmop (0);
10496       preg = getFreePtr (ic, &aop, FALSE);
10497       emitcode ("mov", "%s,%s",
10498                 preg->name,
10499                 aopGet (left, 0, FALSE, TRUE, NULL));
10500       rname = preg->name;
10501     }
10502   else
10503     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10504
10505   freeAsmop (left, NULL, ic, TRUE);
10506   aopOp (result, ic, FALSE, FALSE);
10507
10508   /* if bitfield then unpack the bits */
10509   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10510     genUnpackBits (result, rname, PPOINTER);
10511   else
10512     {
10513       /* we have can just get the values */
10514       int size = AOP_SIZE (result);
10515       int offset = 0;
10516
10517       while (size--)
10518         {
10519
10520           emitcode ("movx", "a,@%s", rname);
10521           aopPut (result, "a", offset);
10522
10523           offset++;
10524
10525           if (size || pi)
10526             emitcode ("inc", "%s", rname);
10527         }
10528     }
10529
10530   /* now some housekeeping stuff */
10531   if (aop)      /* we had to allocate for this iCode */
10532     {
10533       if (pi)
10534         aopPut (left, rname, 0);
10535       freeAsmop (NULL, aop, ic, TRUE);
10536     }
10537   else
10538     {
10539       /* we did not allocate which means left
10540          already in a pointer register, then
10541          if size > 0 && this could be used again
10542          we have to point it back to where it
10543          belongs */
10544       if (AOP_SIZE (result) > 1 &&
10545           !OP_SYMBOL (left)->remat &&
10546           (OP_SYMBOL (left)->liveTo > ic->seq ||
10547            ic->depth) &&
10548           !pi)
10549         {
10550           int size = AOP_SIZE (result) - 1;
10551           while (size--)
10552             emitcode ("dec", "%s", rname);
10553         }
10554     }
10555
10556   /* done */
10557   freeAsmop (result, NULL, ic, TRUE);
10558   if (pi) pi->generated = 1;
10559 }
10560
10561 /*-----------------------------------------------------------------*/
10562 /* genFarPointerGet - get value from far space                     */
10563 /*-----------------------------------------------------------------*/
10564 static void
10565 genFarPointerGet (operand * left,
10566                   operand * result, iCode * ic, iCode *pi)
10567 {
10568     int size, offset, dopi=1;
10569   sym_link *retype = getSpec (operandType (result));
10570   sym_link *letype = getSpec (operandType (left));
10571   D (emitcode (";", "genFarPointerGet"););
10572
10573   aopOp (left, ic, FALSE, FALSE);
10574
10575   /* if the operand is already in dptr
10576      then we do nothing else we move the value to dptr */
10577   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10578     {
10579       /* if this is rematerializable */
10580       if (AOP_TYPE (left) == AOP_IMMD)
10581         {
10582           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10583         }
10584       else
10585         {
10586           /* we need to get it byte by byte */
10587           _startLazyDPSEvaluation ();
10588           if (AOP_TYPE (left) != AOP_DPTR)
10589             {
10590               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10591               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10592               if (options.model == MODEL_FLAT24)
10593                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10594             }
10595           else
10596             {
10597               /* We need to generate a load to DPTR indirect through DPTR. */
10598               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10599               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10600               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10601               if (options.model == MODEL_FLAT24)
10602                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10603               emitcode ("pop", "dph");
10604               emitcode ("pop", "dpl");
10605               dopi =0;
10606             }
10607           _endLazyDPSEvaluation ();
10608         }
10609     }
10610   /* so dptr now contains the address */
10611   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10612
10613   /* if bit then unpack */
10614   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10615       if (AOP_INDPTRn(left)) {
10616           genSetDPTR(AOP(left)->aopu.dptr);
10617       }
10618       genUnpackBits (result, "dptr", FPOINTER);
10619       if (AOP_INDPTRn(left)) {
10620           genSetDPTR(0);
10621       }
10622   } else
10623     {
10624       size = AOP_SIZE (result);
10625       offset = 0;
10626
10627       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10628           while (size--) {
10629               genSetDPTR(AOP(left)->aopu.dptr);
10630               emitcode ("movx", "a,@dptr");
10631               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10632                   emitcode ("inc", "dptr");
10633               genSetDPTR (0);
10634               aopPut (result, "a", offset++);
10635           }
10636       } else {
10637           _startLazyDPSEvaluation ();
10638           while (size--) {
10639               if (AOP_INDPTRn(left)) {
10640                   genSetDPTR(AOP(left)->aopu.dptr);
10641               } else {
10642                   genSetDPTR (0);
10643               }
10644               _flushLazyDPS ();
10645
10646               emitcode ("movx", "a,@dptr");
10647               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10648                   emitcode ("inc", "dptr");
10649
10650               aopPut (result, "a", offset++);
10651           }
10652           _endLazyDPSEvaluation ();
10653       }
10654     }
10655   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10656       if (!AOP_INDPTRn(left)) {
10657           _startLazyDPSEvaluation ();
10658           aopPut (left, "dpl", 0);
10659           aopPut (left, "dph", 1);
10660           if (options.model == MODEL_FLAT24)
10661               aopPut (left, "dpx", 2);
10662           _endLazyDPSEvaluation ();
10663       }
10664     pi->generated = 1;
10665   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10666              AOP_SIZE(result) > 1 &&
10667              IS_SYMOP(left) &&
10668              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10669
10670       size = AOP_SIZE (result) - 1;
10671       if (AOP_INDPTRn(left)) {
10672           genSetDPTR(AOP(left)->aopu.dptr);
10673       }
10674       while (size--) emitcode ("lcall","__decdptr");
10675       if (AOP_INDPTRn(left)) {
10676           genSetDPTR(0);
10677       }
10678   }
10679
10680   freeAsmop (result, NULL, ic, TRUE);
10681   freeAsmop (left, NULL, ic, TRUE);
10682 }
10683
10684 /*-----------------------------------------------------------------*/
10685 /* genCodePointerGet - get value from code space                  */
10686 /*-----------------------------------------------------------------*/
10687 static void
10688 genCodePointerGet (operand * left,
10689                     operand * result, iCode * ic, iCode *pi)
10690 {
10691   int size, offset, dopi=1;
10692   sym_link *retype = getSpec (operandType (result));
10693
10694   aopOp (left, ic, FALSE, FALSE);
10695
10696   /* if the operand is already in dptr
10697      then we do nothing else we move the value to dptr */
10698   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10699     {
10700       /* if this is rematerializable */
10701       if (AOP_TYPE (left) == AOP_IMMD)
10702         {
10703           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10704         }
10705       else
10706         {                       /* we need to get it byte by byte */
10707           _startLazyDPSEvaluation ();
10708           if (AOP_TYPE (left) != AOP_DPTR)
10709             {
10710               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10711               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10712               if (options.model == MODEL_FLAT24)
10713                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10714             }
10715           else
10716             {
10717               /* We need to generate a load to DPTR indirect through DPTR. */
10718               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10719               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10720               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10721               if (options.model == MODEL_FLAT24)
10722                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10723               emitcode ("pop", "dph");
10724               emitcode ("pop", "dpl");
10725               dopi=0;
10726             }
10727           _endLazyDPSEvaluation ();
10728         }
10729     }
10730   /* so dptr now contains the address */
10731   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10732
10733   /* if bit then unpack */
10734   if (IS_BITFIELD (retype)) {
10735       if (AOP_INDPTRn(left)) {
10736           genSetDPTR(AOP(left)->aopu.dptr);
10737       }
10738       genUnpackBits (result, "dptr", CPOINTER);
10739       if (AOP_INDPTRn(left)) {
10740           genSetDPTR(0);
10741       }
10742   } else
10743     {
10744       size = AOP_SIZE (result);
10745       offset = 0;
10746       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10747           while (size--) {
10748               genSetDPTR(AOP(left)->aopu.dptr);
10749               emitcode ("clr", "a");
10750               emitcode ("movc", "a,@a+dptr");
10751               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10752                   emitcode ("inc", "dptr");
10753               genSetDPTR (0);
10754               aopPut (result, "a", offset++);
10755           }
10756       } else {
10757           _startLazyDPSEvaluation ();
10758           while (size--)
10759               {
10760                   if (AOP_INDPTRn(left)) {
10761                       genSetDPTR(AOP(left)->aopu.dptr);
10762                   } else {
10763                       genSetDPTR (0);
10764                   }
10765                   _flushLazyDPS ();
10766
10767                   emitcode ("clr", "a");
10768                   emitcode ("movc", "a,@a+dptr");
10769                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10770                       emitcode ("inc", "dptr");
10771                   aopPut (result, "a", offset++);
10772               }
10773           _endLazyDPSEvaluation ();
10774       }
10775     }
10776   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10777       if (!AOP_INDPTRn(left)) {
10778           _startLazyDPSEvaluation ();
10779
10780           aopPut (left, "dpl", 0);
10781           aopPut (left, "dph", 1);
10782           if (options.model == MODEL_FLAT24)
10783               aopPut (left, "dpx", 2);
10784
10785           _endLazyDPSEvaluation ();
10786       }
10787       pi->generated = 1;
10788   } else if ((OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10789              AOP_SIZE(result) > 1 &&
10790              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10791
10792       size = AOP_SIZE (result) - 1;
10793       if (AOP_INDPTRn(left)) {
10794           genSetDPTR(AOP(left)->aopu.dptr);
10795       }
10796       while (size--) emitcode ("lcall","__decdptr");
10797       if (AOP_INDPTRn(left)) {
10798           genSetDPTR(0);
10799       }
10800   }
10801
10802   freeAsmop (result, NULL, ic, TRUE);
10803   freeAsmop (left, NULL, ic, TRUE);
10804 }
10805
10806 /*-----------------------------------------------------------------*/
10807 /* genGenPointerGet - get value from generic pointer space         */
10808 /*-----------------------------------------------------------------*/
10809 static void
10810 genGenPointerGet (operand * left,
10811                   operand * result, iCode * ic, iCode * pi)
10812 {
10813   int size, offset;
10814   bool pushedB;
10815   sym_link *retype = getSpec (operandType (result));
10816   sym_link *letype = getSpec (operandType (left));
10817
10818   D (emitcode (";", "genGenPointerGet"));
10819
10820   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10821
10822   pushedB = pushB ();
10823   /* if the operand is already in dptr
10824      then we do nothing else we move the value to dptr */
10825   if (AOP_TYPE (left) != AOP_STR)
10826     {
10827       /* if this is rematerializable */
10828       if (AOP_TYPE (left) == AOP_IMMD)
10829         {
10830           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10831           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10832             {
10833               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10834             }
10835           else
10836             {
10837               emitcode ("mov", "b,#%d", pointerCode (retype));
10838             }
10839         }
10840       else
10841         {                       /* we need to get it byte by byte */
10842           _startLazyDPSEvaluation ();
10843           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10844           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10845           if (options.model == MODEL_FLAT24) {
10846               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10847               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10848           } else {
10849               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10850           }
10851           _endLazyDPSEvaluation ();
10852         }
10853     }
10854
10855   /* so dptr-b now contains the address */
10856   aopOp (result, ic, FALSE, TRUE);
10857
10858   /* if bit then unpack */
10859   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10860   {
10861     genUnpackBits (result, "dptr", GPOINTER);
10862   }
10863   else
10864     {
10865         size = AOP_SIZE (result);
10866         offset = 0;
10867
10868         while (size--)
10869         {
10870             if (size)
10871             {
10872                 // Get two bytes at a time, results in _AP & A.
10873                 // dptr will be incremented ONCE by __gptrgetWord.
10874                 //
10875                 // Note: any change here must be coordinated
10876                 // with the implementation of __gptrgetWord
10877                 // in device/lib/_gptrget.c
10878                 emitcode ("lcall", "__gptrgetWord");
10879                 aopPut (result, DP2_RESULT_REG, offset++);
10880                 aopPut (result, "a", offset++);
10881                 size--;
10882             }
10883             else
10884             {
10885                 // Only one byte to get.
10886                 emitcode ("lcall", "__gptrget");
10887                 aopPut (result, "a", offset++);
10888             }
10889
10890             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
10891             {
10892                 emitcode ("inc", "dptr");
10893             }
10894         }
10895     }
10896
10897   if (pi && AOP_TYPE (left) != AOP_IMMD) {
10898     _startLazyDPSEvaluation ();
10899
10900     aopPut (left, "dpl", 0);
10901     aopPut (left, "dph", 1);
10902     if (options.model == MODEL_FLAT24) {
10903         aopPut (left, "dpx", 2);
10904         aopPut (left, "b", 3);
10905     } else  aopPut (left, "b", 2);
10906
10907     _endLazyDPSEvaluation ();
10908
10909     pi->generated = 1;
10910   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
10911              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10912
10913       size = AOP_SIZE (result) - 1;
10914       while (size--) emitcode ("lcall","__decdptr");
10915   }
10916   popB (pushedB);
10917
10918   freeAsmop (result, NULL, ic, TRUE);
10919   freeAsmop (left, NULL, ic, TRUE);
10920 }
10921
10922 /*-----------------------------------------------------------------*/
10923 /* genPointerGet - generate code for pointer get                   */
10924 /*-----------------------------------------------------------------*/
10925 static void
10926 genPointerGet (iCode * ic, iCode *pi)
10927 {
10928   operand *left, *result;
10929   sym_link *type, *etype;
10930   int p_type;
10931
10932   D (emitcode (";", "genPointerGet"));
10933
10934   left = IC_LEFT (ic);
10935   result = IC_RESULT (ic);
10936
10937   /* depending on the type of pointer we need to
10938      move it to the correct pointer register */
10939   type = operandType (left);
10940   etype = getSpec (type);
10941   /* if left is of type of pointer then it is simple */
10942   if (IS_PTR (type) && !IS_FUNC (type->next))
10943     p_type = DCL_TYPE (type);
10944   else
10945     {
10946       /* we have to go by the storage class */
10947       p_type = PTR_TYPE (SPEC_OCLS (etype));
10948     }
10949
10950   /* special case when cast remat */
10951   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10952       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10953     {
10954       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10955       type = operandType (left);
10956       p_type = DCL_TYPE (type);
10957     }
10958   /* now that we have the pointer type we assign
10959      the pointer values */
10960   switch (p_type)
10961     {
10962
10963     case POINTER:
10964     case IPOINTER:
10965       genNearPointerGet (left, result, ic, pi);
10966       break;
10967
10968     case PPOINTER:
10969       genPagedPointerGet (left, result, ic, pi);
10970       break;
10971
10972     case FPOINTER:
10973       genFarPointerGet (left, result, ic, pi);
10974       break;
10975
10976     case CPOINTER:
10977       genCodePointerGet (left, result, ic, pi);
10978       break;
10979
10980     case GPOINTER:
10981       genGenPointerGet (left, result, ic, pi);
10982       break;
10983     }
10984 }
10985
10986
10987 /*-----------------------------------------------------------------*/
10988 /* genPackBits - generates code for packed bit storage             */
10989 /*-----------------------------------------------------------------*/
10990 static void
10991 genPackBits (sym_link * etype,
10992              operand * right,
10993              char *rname, int p_type)
10994 {
10995   int offset = 0;       /* source byte offset */
10996   int rlen = 0;         /* remaining bitfield length */
10997   int blen;             /* bitfield length */
10998   int bstr;             /* bitfield starting bit within byte */
10999   int litval;           /* source literal value (if AOP_LIT) */
11000   unsigned char mask;   /* bitmask within current byte */
11001
11002   D(emitcode (";     genPackBits",""));
11003
11004   blen = SPEC_BLEN (etype);
11005   bstr = SPEC_BSTR (etype);
11006
11007   /* If the bitfield length is less than a byte */
11008   if (blen < 8)
11009     {
11010       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11011               (unsigned char) (0xFF >> (8 - bstr)));
11012
11013       if (AOP_TYPE (right) == AOP_LIT)
11014         {
11015           /* Case with a bitfield length <8 and literal source
11016           */
11017           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11018           litval <<= bstr;
11019           litval &= (~mask) & 0xff;
11020           emitPtrByteGet (rname, p_type, FALSE);
11021           if ((mask|litval)!=0xff)
11022             emitcode ("anl","a,#!constbyte", mask);
11023           if (litval)
11024             emitcode ("orl","a,#!constbyte", litval);
11025         }
11026       else
11027         {
11028           if ((blen==1) && (p_type!=GPOINTER))
11029             {
11030               /* Case with a bitfield length == 1 and no generic pointer
11031               */
11032               if (AOP_TYPE (right) == AOP_CRY)
11033                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11034               else
11035                 {
11036                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11037                   emitcode ("rrc","a");
11038                 }
11039               emitPtrByteGet (rname, p_type, FALSE);
11040               emitcode ("mov","acc.%d,c",bstr);
11041             }
11042           else
11043             {
11044               bool pushedB;
11045               /* Case with a bitfield length < 8 and arbitrary source
11046               */
11047               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11048               /* shift and mask source value */
11049               AccLsh (bstr);
11050               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11051
11052               pushedB = pushB ();
11053               /* transfer A to B and get next byte */
11054               emitPtrByteGet (rname, p_type, TRUE);
11055
11056               emitcode ("anl", "a,#!constbyte", mask);
11057               emitcode ("orl", "a,b");
11058               if (p_type == GPOINTER)
11059                 emitcode ("pop", "b");
11060
11061               popB (pushedB);
11062            }
11063         }
11064
11065       emitPtrByteSet (rname, p_type, "a");
11066       return;
11067     }
11068
11069   /* Bit length is greater than 7 bits. In this case, copy  */
11070   /* all except the partial byte at the end                 */
11071   for (rlen=blen;rlen>=8;rlen-=8)
11072     {
11073       emitPtrByteSet (rname, p_type,
11074                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11075       if (rlen>8)
11076         emitcode ("inc", "%s", rname);
11077     }
11078
11079   /* If there was a partial byte at the end */
11080   if (rlen)
11081     {
11082       mask = (((unsigned char) -1 << rlen) & 0xff);
11083
11084       if (AOP_TYPE (right) == AOP_LIT)
11085         {
11086           /* Case with partial byte and literal source
11087           */
11088           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11089           litval >>= (blen-rlen);
11090           litval &= (~mask) & 0xff;
11091           emitPtrByteGet (rname, p_type, FALSE);
11092           if ((mask|litval)!=0xff)
11093             emitcode ("anl","a,#!constbyte", mask);
11094           if (litval)
11095             emitcode ("orl","a,#!constbyte", litval);
11096         }
11097       else
11098         {
11099           bool pushedB;
11100           /* Case with partial byte and arbitrary source
11101           */
11102           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11103           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11104
11105           pushedB = pushB ();
11106           /* transfer A to B and get next byte */
11107           emitPtrByteGet (rname, p_type, TRUE);
11108
11109           emitcode ("anl", "a,#!constbyte", mask);
11110           emitcode ("orl", "a,b");
11111           if (p_type == GPOINTER)
11112             emitcode ("pop", "b");
11113
11114           popB (pushedB);
11115         }
11116       emitPtrByteSet (rname, p_type, "a");
11117     }
11118 }
11119
11120
11121 /*-----------------------------------------------------------------*/
11122 /* genDataPointerSet - remat pointer to data space                 */
11123 /*-----------------------------------------------------------------*/
11124 static void
11125 genDataPointerSet (operand * right,
11126                    operand * result,
11127                    iCode * ic)
11128 {
11129   int size, offset = 0;
11130   char *l, buffer[256];
11131
11132   D (emitcode (";", "genDataPointerSet"));
11133
11134   aopOp (right, ic, FALSE, FALSE);
11135
11136   l = aopGet (result, 0, FALSE, TRUE, NULL);
11137   size = AOP_SIZE (right);
11138   while (size--)
11139     {
11140       if (offset)
11141           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11142       else
11143           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11144       emitcode ("mov", "%s,%s", buffer,
11145                 aopGet (right, offset++, FALSE, FALSE, NULL));
11146     }
11147
11148   freeAsmop (result, NULL, ic, TRUE);
11149   freeAsmop (right, NULL, ic, TRUE);
11150 }
11151
11152 /*-----------------------------------------------------------------*/
11153 /* genNearPointerSet - emitcode for near pointer put                */
11154 /*-----------------------------------------------------------------*/
11155 static void
11156 genNearPointerSet (operand * right,
11157                    operand * result,
11158                    iCode * ic,
11159                    iCode * pi)
11160 {
11161   asmop *aop = NULL;
11162   char *rname, *l;
11163   sym_link *retype, *letype;
11164   sym_link *ptype = operandType (result);
11165
11166   D (emitcode (";", "genNearPointerSet"));
11167
11168   retype = getSpec (operandType (right));
11169   letype = getSpec (ptype);
11170
11171   aopOp (result, ic, FALSE, FALSE);
11172
11173   /* if the result is rematerializable &
11174      in data space & not a bit variable */
11175   if (AOP_TYPE (result) == AOP_IMMD &&
11176       DCL_TYPE (ptype) == POINTER &&
11177       !IS_BITVAR (retype) &&
11178       !IS_BITVAR (letype))
11179     {
11180       genDataPointerSet (right, result, ic);
11181       return;
11182     }
11183
11184   /* if the value is already in a pointer register
11185      then don't need anything more */
11186   if (!AOP_INPREG (AOP (result)))
11187     {
11188       /* otherwise get a free pointer register */
11189       regs *preg;
11190
11191       aop = newAsmop (0);
11192       preg = getFreePtr (ic, &aop, FALSE);
11193       emitcode ("mov", "%s,%s",
11194                 preg->name,
11195                 aopGet (result, 0, FALSE, TRUE, NULL));
11196       rname = preg->name;
11197     }
11198   else
11199     {
11200       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11201     }
11202
11203   aopOp (right, ic, FALSE, FALSE);
11204
11205   /* if bitfield then unpack the bits */
11206   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11207     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11208   else
11209     {
11210       /* we can just get the values */
11211       int size = AOP_SIZE (right);
11212       int offset = 0;
11213
11214       while (size--)
11215         {
11216           l = aopGet (right, offset, FALSE, TRUE, NULL);
11217           if ((*l == '@') || (strcmp (l, "acc") == 0))
11218             {
11219               MOVA (l);
11220               emitcode ("mov", "@%s,a", rname);
11221             }
11222           else
11223             emitcode ("mov", "@%s,%s", rname, l);
11224           if (size || pi)
11225             emitcode ("inc", "%s", rname);
11226           offset++;
11227         }
11228     }
11229
11230   /* now some housekeeping stuff */
11231   if (aop)      /* we had to allocate for this iCode */
11232     {
11233       if (pi)
11234         aopPut (result, rname, 0);
11235       freeAsmop (NULL, aop, ic, TRUE);
11236     }
11237   else
11238     {
11239       /* we did not allocate which means left
11240          already in a pointer register, then
11241          if size > 0 && this could be used again
11242          we have to point it back to where it
11243          belongs */
11244       if (AOP_SIZE (right) > 1 &&
11245           !OP_SYMBOL (result)->remat &&
11246           (OP_SYMBOL (result)->liveTo > ic->seq ||
11247            ic->depth) &&
11248           !pi)
11249         {
11250           int size = AOP_SIZE (right) - 1;
11251           while (size--)
11252             emitcode ("dec", "%s", rname);
11253         }
11254     }
11255
11256   /* done */
11257   if (pi) pi->generated = 1;
11258   freeAsmop (result, NULL, ic, TRUE);
11259   freeAsmop (right, NULL, ic, TRUE);
11260 }
11261
11262 /*-----------------------------------------------------------------*/
11263 /* genPagedPointerSet - emitcode for Paged pointer put             */
11264 /*-----------------------------------------------------------------*/
11265 static void
11266 genPagedPointerSet (operand * right,
11267                     operand * result,
11268                     iCode * ic,
11269                     iCode *pi)
11270 {
11271   asmop *aop = NULL;
11272   char *rname, *l;
11273   sym_link *retype, *letype;
11274
11275   D (emitcode (";", "genPagedPointerSet"));
11276
11277   retype = getSpec (operandType (right));
11278   letype = getSpec (operandType (result));
11279
11280   aopOp (result, ic, FALSE, FALSE);
11281
11282   /* if the value is already in a pointer register
11283      then don't need anything more */
11284   if (!AOP_INPREG (AOP (result)))
11285     {
11286       /* otherwise get a free pointer register */
11287       regs *preg;
11288
11289       aop = newAsmop (0);
11290       preg = getFreePtr (ic, &aop, FALSE);
11291       emitcode ("mov", "%s,%s",
11292                 preg->name,
11293                 aopGet (result, 0, FALSE, TRUE, NULL));
11294       rname = preg->name;
11295     }
11296   else
11297     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11298
11299   aopOp (right, ic, FALSE, FALSE);
11300
11301   /* if bitfield then unpack the bits */
11302   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11303     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11304   else
11305     {
11306       /* we have can just get the values */
11307       int size = AOP_SIZE (right);
11308       int offset = 0;
11309
11310       while (size--)
11311         {
11312           l = aopGet (right, offset, FALSE, TRUE, NULL);
11313           MOVA (l);
11314           emitcode ("movx", "@%s,a", rname);
11315
11316           if (size || pi)
11317             emitcode ("inc", "%s", rname);
11318
11319           offset++;
11320         }
11321     }
11322
11323   /* now some housekeeping stuff */
11324   if (aop)
11325     {
11326       if (pi)
11327         aopPut (result, rname, 0);
11328       /* we had to allocate for this iCode */
11329       freeAsmop (NULL, aop, ic, TRUE);
11330     }
11331   else
11332     {
11333       /* we did not allocate which means left
11334          already in a pointer register, then
11335          if size > 0 && this could be used again
11336          we have to point it back to where it
11337          belongs */
11338       if (AOP_SIZE (right) > 1 &&
11339           !OP_SYMBOL (result)->remat &&
11340           (OP_SYMBOL (result)->liveTo > ic->seq ||
11341            ic->depth) &&
11342           !pi)
11343         {
11344           int size = AOP_SIZE (right) - 1;
11345           while (size--)
11346             emitcode ("dec", "%s", rname);
11347         }
11348     }
11349
11350   /* done */
11351   if (pi) pi->generated = 1;
11352   freeAsmop (result, NULL, ic, TRUE);
11353   freeAsmop (right, NULL, ic, TRUE);
11354 }
11355
11356 /*-----------------------------------------------------------------*/
11357 /* genFarPointerSet - set value from far space                     */
11358 /*-----------------------------------------------------------------*/
11359 static void
11360 genFarPointerSet (operand * right,
11361                   operand * result, iCode * ic, iCode *pi)
11362 {
11363   int size, offset, dopi=1;
11364   sym_link *retype = getSpec (operandType (right));
11365   sym_link *letype = getSpec (operandType (result));
11366
11367   aopOp (result, ic, FALSE, FALSE);
11368
11369   /* if the operand is already in dptr
11370      then we do nothing else we move the value to dptr */
11371   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11372     {
11373       /* if this is remateriazable */
11374       if (AOP_TYPE (result) == AOP_IMMD)
11375         emitcode ("mov", "dptr,%s",
11376                   aopGet (result, 0, TRUE, FALSE, NULL));
11377       else
11378         {
11379           /* we need to get it byte by byte */
11380           _startLazyDPSEvaluation ();
11381           if (AOP_TYPE (result) != AOP_DPTR)
11382             {
11383               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11384               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11385               if (options.model == MODEL_FLAT24)
11386                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11387             }
11388           else
11389             {
11390               /* We need to generate a load to DPTR indirect through DPTR. */
11391               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11392
11393               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11394               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11395               if (options.model == MODEL_FLAT24)
11396                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11397               emitcode ("pop", "dph");
11398               emitcode ("pop", "dpl");
11399               dopi=0;
11400             }
11401           _endLazyDPSEvaluation ();
11402         }
11403     }
11404   /* so dptr now contains the address */
11405   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11406
11407   /* if bit then unpack */
11408   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11409   {
11410       if (AOP_INDPTRn(result)) {
11411           genSetDPTR(AOP(result)->aopu.dptr);
11412       }
11413       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11414       if (AOP_INDPTRn(result)) {
11415           genSetDPTR(0);
11416       }
11417   } else {
11418       size = AOP_SIZE (right);
11419       offset = 0;
11420       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11421           while (size--) {
11422               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11423
11424               genSetDPTR(AOP(result)->aopu.dptr);
11425               emitcode ("movx", "@dptr,a");
11426               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11427                   emitcode ("inc", "dptr");
11428               genSetDPTR (0);
11429           }
11430       } else {
11431           _startLazyDPSEvaluation ();
11432           while (size--) {
11433               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11434
11435               if (AOP_INDPTRn(result)) {
11436                   genSetDPTR(AOP(result)->aopu.dptr);
11437               } else {
11438                   genSetDPTR (0);
11439               }
11440               _flushLazyDPS ();
11441
11442               emitcode ("movx", "@dptr,a");
11443               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11444                   emitcode ("inc", "dptr");
11445           }
11446           _endLazyDPSEvaluation ();
11447       }
11448   }
11449
11450   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11451       if (!AOP_INDPTRn(result)) {
11452           _startLazyDPSEvaluation ();
11453
11454           aopPut (result,"dpl",0);
11455           aopPut (result,"dph",1);
11456           if (options.model == MODEL_FLAT24)
11457               aopPut (result,"dpx",2);
11458
11459           _endLazyDPSEvaluation ();
11460       }
11461       pi->generated=1;
11462   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11463              AOP_SIZE(right) > 1 &&
11464              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11465
11466       size = AOP_SIZE (right) - 1;
11467       if (AOP_INDPTRn(result)) {
11468           genSetDPTR(AOP(result)->aopu.dptr);
11469       }
11470       while (size--) emitcode ("lcall","__decdptr");
11471       if (AOP_INDPTRn(result)) {
11472           genSetDPTR(0);
11473       }
11474   }
11475   freeAsmop (result, NULL, ic, TRUE);
11476   freeAsmop (right, NULL, ic, TRUE);
11477 }
11478
11479 /*-----------------------------------------------------------------*/
11480 /* genGenPointerSet - set value from generic pointer space         */
11481 /*-----------------------------------------------------------------*/
11482 static void
11483 genGenPointerSet (operand * right,
11484                   operand * result, iCode * ic, iCode *pi)
11485 {
11486   int size, offset;
11487   bool pushedB;
11488   sym_link *retype = getSpec (operandType (right));
11489   sym_link *letype = getSpec (operandType (result));
11490
11491   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11492
11493   pushedB = pushB ();
11494   /* if the operand is already in dptr
11495      then we do nothing else we move the value to dptr */
11496   if (AOP_TYPE (result) != AOP_STR)
11497     {
11498       _startLazyDPSEvaluation ();
11499       /* if this is remateriazable */
11500       if (AOP_TYPE (result) == AOP_IMMD)
11501         {
11502           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11503           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11504           {
11505               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11506           }
11507           else
11508           {
11509               emitcode ("mov",
11510                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11511           }
11512         }
11513       else
11514         {                       /* we need to get it byte by byte */
11515           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11516           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11517           if (options.model == MODEL_FLAT24) {
11518             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11519             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11520           } else {
11521             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11522           }
11523         }
11524       _endLazyDPSEvaluation ();
11525     }
11526   /* so dptr + b now contains the address */
11527   aopOp (right, ic, FALSE, TRUE);
11528
11529   /* if bit then unpack */
11530   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11531     {
11532         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11533     }
11534   else
11535     {
11536         size = AOP_SIZE (right);
11537         offset = 0;
11538
11539         _startLazyDPSEvaluation ();
11540         while (size--)
11541         {
11542             if (size)
11543             {
11544                 // Set two bytes at a time, passed in _AP & A.
11545                 // dptr will be incremented ONCE by __gptrputWord.
11546                 //
11547                 // Note: any change here must be coordinated
11548                 // with the implementation of __gptrputWord
11549                 // in device/lib/_gptrput.c
11550                 emitcode("mov", "_ap, %s",
11551                          aopGet (right, offset++, FALSE, FALSE, NULL));
11552                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11553
11554                 genSetDPTR (0);
11555                 _flushLazyDPS ();
11556                 emitcode ("lcall", "__gptrputWord");
11557                 size--;
11558             }
11559             else
11560             {
11561                 // Only one byte to put.
11562                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11563
11564                 genSetDPTR (0);
11565                 _flushLazyDPS ();
11566                 emitcode ("lcall", "__gptrput");
11567             }
11568
11569             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11570             {
11571                 emitcode ("inc", "dptr");
11572             }
11573         }
11574         _endLazyDPSEvaluation ();
11575     }
11576
11577   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11578       _startLazyDPSEvaluation ();
11579
11580       aopPut (result, "dpl",0);
11581       aopPut (result, "dph",1);
11582       if (options.model == MODEL_FLAT24) {
11583           aopPut (result, "dpx",2);
11584           aopPut (result, "b",3);
11585       } else {
11586           aopPut (result, "b",2);
11587       }
11588       _endLazyDPSEvaluation ();
11589
11590       pi->generated=1;
11591   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11592              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11593
11594       size = AOP_SIZE (right) - 1;
11595       while (size--) emitcode ("lcall","__decdptr");
11596   }
11597   popB (pushedB);
11598
11599   freeAsmop (result, NULL, ic, TRUE);
11600   freeAsmop (right, NULL, ic, TRUE);
11601 }
11602
11603 /*-----------------------------------------------------------------*/
11604 /* genPointerSet - stores the value into a pointer location        */
11605 /*-----------------------------------------------------------------*/
11606 static void
11607 genPointerSet (iCode * ic, iCode *pi)
11608 {
11609   operand *right, *result;
11610   sym_link *type, *etype;
11611   int p_type;
11612
11613   D (emitcode (";", "genPointerSet"));
11614
11615   right = IC_RIGHT (ic);
11616   result = IC_RESULT (ic);
11617
11618   /* depending on the type of pointer we need to
11619      move it to the correct pointer register */
11620   type = operandType (result);
11621   etype = getSpec (type);
11622   /* if left is of type of pointer then it is simple */
11623   if (IS_PTR (type) && !IS_FUNC (type->next))
11624     {
11625       p_type = DCL_TYPE (type);
11626     }
11627   else
11628     {
11629       /* we have to go by the storage class */
11630       p_type = PTR_TYPE (SPEC_OCLS (etype));
11631     }
11632
11633   /* special case when cast remat */
11634   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11635       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11636           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11637           type = operandType (result);
11638           p_type = DCL_TYPE (type);
11639   }
11640
11641   /* now that we have the pointer type we assign
11642      the pointer values */
11643   switch (p_type)
11644     {
11645
11646     case POINTER:
11647     case IPOINTER:
11648       genNearPointerSet (right, result, ic, pi);
11649       break;
11650
11651     case PPOINTER:
11652       genPagedPointerSet (right, result, ic, pi);
11653       break;
11654
11655     case FPOINTER:
11656       genFarPointerSet (right, result, ic, pi);
11657       break;
11658
11659     case GPOINTER:
11660       genGenPointerSet (right, result, ic, pi);
11661       break;
11662
11663     default:
11664       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11665               "genPointerSet: illegal pointer type");
11666     }
11667 }
11668
11669 /*-----------------------------------------------------------------*/
11670 /* genIfx - generate code for Ifx statement                        */
11671 /*-----------------------------------------------------------------*/
11672 static void
11673 genIfx (iCode * ic, iCode * popIc)
11674 {
11675   operand *cond = IC_COND (ic);
11676   int isbit = 0;
11677   char *dup = NULL;
11678
11679   D (emitcode (";", "genIfx"));
11680
11681   aopOp (cond, ic, FALSE, FALSE);
11682
11683   /* get the value into acc */
11684   if (AOP_TYPE (cond) != AOP_CRY)
11685     {
11686         toBoolean (cond);
11687     }
11688   else
11689     {
11690         isbit = 1;
11691       if (AOP(cond)->aopu.aop_dir)
11692         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11693     }
11694
11695   /* the result is now in the accumulator or a directly addressable bit */
11696   freeAsmop (cond, NULL, ic, TRUE);
11697
11698   /* if there was something to be popped then do it */
11699   if (popIc)
11700     genIpop (popIc);
11701
11702   /* if the condition is  a bit variable */
11703   if (isbit && dup)
11704     genIfxJump (ic, dup);
11705   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11706     genIfxJump (ic, SPIL_LOC (cond)->rname);
11707   else if (isbit && !IS_ITEMP (cond))
11708     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11709   else
11710     genIfxJump (ic, "a");
11711
11712   ic->generated = 1;
11713 }
11714
11715 /*-----------------------------------------------------------------*/
11716 /* genAddrOf - generates code for address of                       */
11717 /*-----------------------------------------------------------------*/
11718 static void
11719 genAddrOf (iCode * ic)
11720 {
11721   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11722   int size, offset;
11723
11724   D (emitcode (";", "genAddrOf"));
11725
11726   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11727
11728   /* if the operand is on the stack then we
11729      need to get the stack offset of this
11730      variable */
11731   if (sym->onStack)
11732   {
11733
11734       /* if 10 bit stack */
11735       if (options.stack10bit) {
11736           char buff[10];
11737           int  offset;
11738
11739           tsprintf(buff, sizeof(buff),
11740                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11741           /* if it has an offset then we need to compute it */
11742 /*        emitcode ("subb", "a,#!constbyte", */
11743 /*                  -((sym->stack < 0) ? */
11744 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11745 /*                    ((short) sym->stack)) & 0xff); */
11746 /*        emitcode ("mov","b,a"); */
11747 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11748 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11749 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11750           if (sym->stack) {
11751               emitcode ("mov", "a,_bpx");
11752               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11753                                              ((char) (sym->stack - _G.nRegsSaved)) :
11754                                              ((char) sym->stack )) & 0xff);
11755               emitcode ("mov", "b,a");
11756               emitcode ("mov", "a,_bpx+1");
11757
11758               offset = (((sym->stack < 0) ?
11759                          ((short) (sym->stack - _G.nRegsSaved)) :
11760                          ((short) sym->stack )) >> 8) & 0xff;
11761
11762               emitcode ("addc","a,#!constbyte", offset);
11763
11764               aopPut (IC_RESULT (ic), "b", 0);
11765               aopPut (IC_RESULT (ic), "a", 1);
11766               aopPut (IC_RESULT (ic), buff, 2);
11767           } else {
11768               /* we can just move _bp */
11769               aopPut (IC_RESULT (ic), "_bpx", 0);
11770               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11771               aopPut (IC_RESULT (ic), buff, 2);
11772           }
11773       } else {
11774           /* if it has an offset then we need to compute it */
11775           if (sym->stack)
11776             {
11777               emitcode ("mov", "a,_bp");
11778               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11779               aopPut (IC_RESULT (ic), "a", 0);
11780             }
11781           else
11782             {
11783               /* we can just move _bp */
11784               aopPut (IC_RESULT (ic), "_bp", 0);
11785             }
11786           /* fill the result with zero */
11787           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11788
11789
11790           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11791               fprintf (stderr,
11792                        "*** warning: pointer to stack var truncated.\n");
11793           }
11794
11795           offset = 1;
11796           while (size--)
11797             {
11798               aopPut (IC_RESULT (ic), zero, offset++);
11799           }
11800       }
11801       goto release;
11802   }
11803
11804   /* object not on stack then we need the name */
11805   size = AOP_SIZE (IC_RESULT (ic));
11806   offset = 0;
11807
11808   while (size--)
11809     {
11810       char s[SDCC_NAME_MAX];
11811       if (offset) {
11812           switch (offset) {
11813           case 1:
11814               tsprintf(s, sizeof(s), "#!his",sym->rname);
11815               break;
11816           case 2:
11817               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11818               break;
11819           case 3:
11820               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11821               break;
11822           default: /* should not need this (just in case) */
11823               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11824                        sym->rname,
11825                        offset * 8);
11826           }
11827       }
11828       else
11829       {
11830           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11831       }
11832
11833       aopPut (IC_RESULT (ic), s, offset++);
11834     }
11835
11836 release:
11837   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11838
11839 }
11840
11841 #if 0 // obsolete, and buggy for != xdata
11842 /*-----------------------------------------------------------------*/
11843 /* genArrayInit - generates code for address of                       */
11844 /*-----------------------------------------------------------------*/
11845 static void
11846 genArrayInit (iCode * ic)
11847 {
11848     literalList *iLoop;
11849     int         ix, count;
11850     int         elementSize = 0, eIndex;
11851     unsigned    val, lastVal;
11852     sym_link    *type;
11853     operand     *left=IC_LEFT(ic);
11854
11855     D (emitcode (";", "genArrayInit"));
11856
11857     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11858
11859     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11860     {
11861         // Load immediate value into DPTR.
11862         emitcode("mov", "dptr, %s",
11863              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11864     }
11865     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11866     {
11867 #if 0
11868       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11869               "Unexpected operand to genArrayInit.\n");
11870       exit(1);
11871 #else
11872       // a regression because of SDCCcse.c:1.52
11873       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11874       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11875       if (options.model == MODEL_FLAT24)
11876         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
11877 #endif
11878     }
11879
11880     type = operandType(IC_LEFT(ic));
11881
11882     if (type && type->next)
11883     {
11884         elementSize = getSize(type->next);
11885     }
11886     else
11887     {
11888         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11889                                 "can't determine element size in genArrayInit.\n");
11890         exit(1);
11891     }
11892
11893     iLoop = IC_ARRAYILIST(ic);
11894     lastVal = 0xffff;
11895
11896     while (iLoop)
11897     {
11898         bool firstpass = TRUE;
11899
11900         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
11901                  iLoop->count, (int)iLoop->literalValue, elementSize);
11902
11903         ix = iLoop->count;
11904
11905         while (ix)
11906         {
11907             symbol *tlbl = NULL;
11908
11909             count = ix > 256 ? 256 : ix;
11910
11911             if (count > 1)
11912             {
11913                 tlbl = newiTempLabel (NULL);
11914                 if (firstpass || (count & 0xff))
11915                 {
11916                     emitcode("mov", "b, #!constbyte", count & 0xff);
11917                 }
11918
11919                 emitLabel (tlbl);
11920             }
11921
11922             firstpass = FALSE;
11923
11924             for (eIndex = 0; eIndex < elementSize; eIndex++)
11925             {
11926                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
11927                 if (val != lastVal)
11928                 {
11929                     emitcode("mov", "a, #!constbyte", val);
11930                     lastVal = val;
11931                 }
11932
11933                 emitcode("movx", "@dptr, a");
11934                 emitcode("inc", "dptr");
11935             }
11936
11937             if (count > 1)
11938             {
11939                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
11940             }
11941
11942             ix -= count;
11943         }
11944
11945         iLoop = iLoop->next;
11946     }
11947
11948     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
11949 }
11950 #endif
11951
11952 /*-----------------------------------------------------------------*/
11953 /* genFarFarAssign - assignment when both are in far space         */
11954 /*-----------------------------------------------------------------*/
11955 static void
11956 genFarFarAssign (operand * result, operand * right, iCode * ic)
11957 {
11958   int size = AOP_SIZE (right);
11959   int offset = 0;
11960   symbol *rSym = NULL;
11961
11962   if (size == 1)
11963   {
11964       /* quick & easy case. */
11965       D (emitcode(";","genFarFarAssign (1 byte case)"));
11966       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11967       freeAsmop (right, NULL, ic, FALSE);
11968       /* now assign DPTR to result */
11969       _G.accInUse++;
11970       aopOp(result, ic, FALSE, FALSE);
11971       _G.accInUse--;
11972       aopPut (result, "a", 0);
11973       freeAsmop(result, NULL, ic, FALSE);
11974       return;
11975   }
11976
11977   /* See if we've got an underlying symbol to abuse. */
11978   if (IS_SYMOP(result) && OP_SYMBOL(result))
11979   {
11980       if (IS_TRUE_SYMOP(result))
11981       {
11982           rSym = OP_SYMBOL(result);
11983       }
11984       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
11985       {
11986           rSym = OP_SYMBOL(result)->usl.spillLoc;
11987       }
11988   }
11989
11990   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
11991   {
11992       /* We can use the '390 auto-toggle feature to good effect here. */
11993
11994       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
11995       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
11996       emitcode ("mov", "dptr,#%s", rSym->rname);
11997       /* DP2 = result, DP1 = right, DP1 is current. */
11998       while (size)
11999       {
12000           emitcode("movx", "a,@dptr");
12001           emitcode("movx", "@dptr,a");
12002           if (--size)
12003           {
12004                emitcode("inc", "dptr");
12005                emitcode("inc", "dptr");
12006           }
12007       }
12008       emitcode("mov", "dps,#0");
12009       freeAsmop (right, NULL, ic, FALSE);
12010 #if 0
12011 some alternative code for processors without auto-toggle
12012 no time to test now, so later well put in...kpb
12013         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12014         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12015         emitcode ("mov", "dptr,#%s", rSym->rname);
12016         /* DP2 = result, DP1 = right, DP1 is current. */
12017         while (size)
12018         {
12019           --size;
12020           emitcode("movx", "a,@dptr");
12021           if (size)
12022             emitcode("inc", "dptr");
12023           emitcode("inc", "dps");
12024           emitcode("movx", "@dptr,a");
12025           if (size)
12026             emitcode("inc", "dptr");
12027           emitcode("inc", "dps");
12028         }
12029         emitcode("mov", "dps,#0");
12030         freeAsmop (right, NULL, ic, FALSE);
12031 #endif
12032   }
12033   else
12034   {
12035       D (emitcode (";", "genFarFarAssign"));
12036       aopOp (result, ic, TRUE, TRUE);
12037
12038       _startLazyDPSEvaluation ();
12039
12040       while (size--)
12041         {
12042           aopPut (result,
12043                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12044           offset++;
12045         }
12046       _endLazyDPSEvaluation ();
12047       freeAsmop (result, NULL, ic, FALSE);
12048       freeAsmop (right, NULL, ic, FALSE);
12049   }
12050 }
12051
12052 /*-----------------------------------------------------------------*/
12053 /* genAssign - generate code for assignment                        */
12054 /*-----------------------------------------------------------------*/
12055 static void
12056 genAssign (iCode * ic)
12057 {
12058   operand *result, *right;
12059   int size, offset;
12060   unsigned long lit = 0L;
12061
12062   D (emitcode (";", "genAssign"));
12063
12064   result = IC_RESULT (ic);
12065   right = IC_RIGHT (ic);
12066
12067   /* if they are the same */
12068   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12069     return;
12070
12071   aopOp (right, ic, FALSE, FALSE);
12072
12073   emitcode (";", "genAssign: resultIsFar = %s",
12074             isOperandInFarSpace (result) ?
12075             "TRUE" : "FALSE");
12076
12077   /* special case both in far space */
12078   if ((AOP_TYPE (right) == AOP_DPTR ||
12079        AOP_TYPE (right) == AOP_DPTR2) &&
12080   /* IS_TRUE_SYMOP(result)       && */
12081       isOperandInFarSpace (result))
12082     {
12083       genFarFarAssign (result, right, ic);
12084       return;
12085     }
12086
12087   aopOp (result, ic, TRUE, FALSE);
12088
12089   /* if they are the same registers */
12090   if (sameRegs (AOP (right), AOP (result)))
12091     goto release;
12092
12093   /* if the result is a bit */
12094   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12095     {
12096       /* if the right size is a literal then
12097          we know what the value is */
12098       if (AOP_TYPE (right) == AOP_LIT)
12099         {
12100           if (((int) operandLitValue (right)))
12101             aopPut (result, one, 0);
12102           else
12103             aopPut (result, zero, 0);
12104           goto release;
12105         }
12106
12107       /* the right is also a bit variable */
12108       if (AOP_TYPE (right) == AOP_CRY)
12109         {
12110           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12111           aopPut (result, "c", 0);
12112           goto release;
12113         }
12114
12115       /* we need to or */
12116       toBoolean (right);
12117       aopPut (result, "a", 0);
12118       goto release;
12119     }
12120
12121   /* bit variables done */
12122   /* general case */
12123   size = AOP_SIZE (result);
12124   offset = 0;
12125   if (AOP_TYPE (right) == AOP_LIT)
12126     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12127
12128   if ((size > 1) &&
12129       (AOP_TYPE (result) != AOP_REG) &&
12130       (AOP_TYPE (right) == AOP_LIT) &&
12131       !IS_FLOAT (operandType (right)))
12132     {
12133       _startLazyDPSEvaluation ();
12134       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12135         {
12136           aopPut (result,
12137                   aopGet (right, offset, FALSE, FALSE, NULL),
12138                   offset);
12139           offset++;
12140           size--;
12141         }
12142       /* And now fill the rest with zeros. */
12143       if (size)
12144         {
12145           emitcode ("clr", "a");
12146         }
12147       while (size--)
12148         {
12149           aopPut (result, "a", offset++);
12150         }
12151       _endLazyDPSEvaluation ();
12152     }
12153   else
12154     {
12155       _startLazyDPSEvaluation ();
12156       while (size--)
12157         {
12158           aopPut (result,
12159                   aopGet (right, offset, FALSE, FALSE, NULL),
12160                   offset);
12161           offset++;
12162         }
12163       _endLazyDPSEvaluation ();
12164     }
12165
12166 release:
12167   freeAsmop (result, NULL, ic, TRUE);
12168   freeAsmop (right, NULL, ic, TRUE);
12169 }
12170
12171 /*-----------------------------------------------------------------*/
12172 /* genJumpTab - generates code for jump table                      */
12173 /*-----------------------------------------------------------------*/
12174 static void
12175 genJumpTab (iCode * ic)
12176 {
12177   symbol *jtab;
12178   char *l;
12179
12180   D (emitcode (";", "genJumpTab"));
12181
12182   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12183   /* get the condition into accumulator */
12184   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12185   MOVA (l);
12186   /* multiply by four! */
12187   emitcode ("add", "a,acc");
12188   emitcode ("add", "a,acc");
12189   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12190
12191   jtab = newiTempLabel (NULL);
12192   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12193   emitcode ("jmp", "@a+dptr");
12194   emitLabel (jtab);
12195   /* now generate the jump labels */
12196   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12197        jtab = setNextItem (IC_JTLABELS (ic)))
12198     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12199
12200 }
12201
12202 /*-----------------------------------------------------------------*/
12203 /* genCast - gen code for casting                                  */
12204 /*-----------------------------------------------------------------*/
12205 static void
12206 genCast (iCode * ic)
12207 {
12208   operand *result = IC_RESULT (ic);
12209   sym_link *ctype = operandType (IC_LEFT (ic));
12210   sym_link *rtype = operandType (IC_RIGHT (ic));
12211   operand *right = IC_RIGHT (ic);
12212   int size, offset;
12213
12214   D (emitcode (";", "genCast"));
12215
12216   /* if they are equivalent then do nothing */
12217   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12218     return;
12219
12220   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12221   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12222
12223   /* if the result is a bit (and not a bitfield) */
12224   if (IS_BIT (OP_SYMBOL (result)->type))
12225     {
12226       /* if the right size is a literal then
12227          we know what the value is */
12228       if (AOP_TYPE (right) == AOP_LIT)
12229         {
12230           if (((int) operandLitValue (right)))
12231             aopPut (result, one, 0);
12232           else
12233             aopPut (result, zero, 0);
12234
12235           goto release;
12236         }
12237
12238       /* the right is also a bit variable */
12239       if (AOP_TYPE (right) == AOP_CRY)
12240         {
12241           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12242           aopPut (result, "c", 0);
12243           goto release;
12244         }
12245
12246       /* we need to or */
12247       toBoolean (right);
12248       aopPut (result, "a", 0);
12249       goto release;
12250     }
12251
12252   /* if they are the same size : or less */
12253   if (AOP_SIZE (result) <= AOP_SIZE (right))
12254     {
12255
12256       /* if they are in the same place */
12257       if (sameRegs (AOP (right), AOP (result)))
12258         goto release;
12259
12260       /* if they in different places then copy */
12261       size = AOP_SIZE (result);
12262       offset = 0;
12263       _startLazyDPSEvaluation ();
12264       while (size--)
12265         {
12266           aopPut (result,
12267                   aopGet (right, offset, FALSE, FALSE, NULL),
12268                   offset);
12269           offset++;
12270         }
12271       _endLazyDPSEvaluation ();
12272       goto release;
12273     }
12274
12275   /* if the result is of type pointer */
12276   if (IS_PTR (ctype))
12277     {
12278
12279       int p_type;
12280       sym_link *type = operandType (right);
12281
12282       /* pointer to generic pointer */
12283       if (IS_GENPTR (ctype))
12284         {
12285           if (IS_PTR (type))
12286             {
12287               p_type = DCL_TYPE (type);
12288             }
12289           else
12290             {
12291 #if OLD_CAST_BEHAVIOR
12292               /* KV: we are converting a non-pointer type to
12293                * a generic pointer. This (ifdef'd out) code
12294                * says that the resulting generic pointer
12295                * should have the same class as the storage
12296                * location of the non-pointer variable.
12297                *
12298                * For example, converting an int (which happens
12299                * to be stored in DATA space) to a pointer results
12300                * in a DATA generic pointer; if the original int
12301                * in XDATA space, so will be the resulting pointer.
12302                *
12303                * I don't like that behavior, and thus this change:
12304                * all such conversions will be forced to XDATA and
12305                * throw a warning. If you want some non-XDATA
12306                * type, or you want to suppress the warning, you
12307                * must go through an intermediate cast, like so:
12308                *
12309                * char _generic *gp = (char _xdata *)(intVar);
12310                */
12311               sym_link *etype = getSpec (type);
12312
12313               /* we have to go by the storage class */
12314               if (SPEC_OCLS (etype) != generic)
12315                 {
12316                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12317                 }
12318               else
12319 #endif
12320                 {
12321                   /* Converting unknown class (i.e. register variable)
12322                    * to generic pointer. This is not good, but
12323                    * we'll make a guess (and throw a warning).
12324                    */
12325                   p_type = FPOINTER;
12326                   werror (W_INT_TO_GEN_PTR_CAST);
12327                 }
12328             }
12329
12330           /* the first two bytes are known */
12331           size = GPTRSIZE - 1;
12332           offset = 0;
12333           _startLazyDPSEvaluation ();
12334           while (size--)
12335             {
12336               aopPut (result,
12337                       aopGet (right, offset, FALSE, FALSE, NULL),
12338                       offset);
12339               offset++;
12340             }
12341           _endLazyDPSEvaluation ();
12342
12343           /* the last byte depending on type */
12344             {
12345                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12346                 char gpValStr[10];
12347
12348                 if (gpVal == -1)
12349                 {
12350                     // pointerTypeToGPByte will have bitched.
12351                     exit(1);
12352                 }
12353
12354                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12355                 aopPut (result, gpValStr, GPTRSIZE - 1);
12356             }
12357           goto release;
12358         }
12359
12360       /* just copy the pointers */
12361       size = AOP_SIZE (result);
12362       offset = 0;
12363       _startLazyDPSEvaluation ();
12364       while (size--)
12365         {
12366           aopPut (result,
12367                   aopGet (right, offset, FALSE, FALSE, NULL),
12368                   offset);
12369           offset++;
12370         }
12371       _endLazyDPSEvaluation ();
12372       goto release;
12373     }
12374
12375   /* so we now know that the size of destination is greater
12376      than the size of the source */
12377   /* we move to result for the size of source */
12378   size = AOP_SIZE (right);
12379   offset = 0;
12380   _startLazyDPSEvaluation ();
12381   while (size--)
12382     {
12383       aopPut (result,
12384               aopGet (right, offset, FALSE, FALSE, NULL),
12385               offset);
12386       offset++;
12387     }
12388   _endLazyDPSEvaluation ();
12389
12390   /* now depending on the sign of the source && destination */
12391   size = AOP_SIZE (result) - AOP_SIZE (right);
12392   /* if unsigned or not an integral type */
12393   /* also, if the source is a bit, we don't need to sign extend, because
12394    * it can't possibly have set the sign bit.
12395    */
12396   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12397     {
12398       while (size--)
12399         {
12400           aopPut (result, zero, offset++);
12401         }
12402     }
12403   else
12404     {
12405       /* we need to extend the sign :{ */
12406       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12407                         FALSE, FALSE, NULL));
12408       emitcode ("rlc", "a");
12409       emitcode ("subb", "a,acc");
12410       while (size--)
12411         aopPut (result, "a", offset++);
12412     }
12413
12414   /* we are done hurray !!!! */
12415
12416 release:
12417   freeAsmop (right, NULL, ic, TRUE);
12418   freeAsmop (result, NULL, ic, TRUE);
12419
12420 }
12421
12422 /*-----------------------------------------------------------------*/
12423 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12424 /*-----------------------------------------------------------------*/
12425 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12426 {
12427     operand *from , *to , *count;
12428     symbol *lbl;
12429     bitVect *rsave;
12430     int i;
12431
12432     /* we know it has to be 3 parameters */
12433     assert (nparms == 3);
12434
12435     rsave = newBitVect(16);
12436     /* save DPTR if it needs to be saved */
12437     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12438             if (bitVectBitValue(ic->rMask,i))
12439                     rsave = bitVectSetBit(rsave,i);
12440     }
12441     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12442                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12443     savermask(rsave);
12444
12445     to = parms[0];
12446     from = parms[1];
12447     count = parms[2];
12448
12449     aopOp (from, ic->next, FALSE, FALSE);
12450
12451     /* get from into DPTR1 */
12452     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12453     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12454     if (options.model == MODEL_FLAT24) {
12455         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12456     }
12457
12458     freeAsmop (from, NULL, ic, FALSE);
12459     aopOp (to, ic, FALSE, FALSE);
12460     /* get "to" into DPTR */
12461     /* if the operand is already in dptr
12462        then we do nothing else we move the value to dptr */
12463     if (AOP_TYPE (to) != AOP_STR) {
12464         /* if already in DPTR then we need to push */
12465         if (AOP_TYPE(to) == AOP_DPTR) {
12466             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12467             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12468             if (options.model == MODEL_FLAT24)
12469                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12470             emitcode ("pop", "dph");
12471             emitcode ("pop", "dpl");
12472         } else {
12473             _startLazyDPSEvaluation ();
12474             /* if this is remateriazable */
12475             if (AOP_TYPE (to) == AOP_IMMD) {
12476                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12477             } else {                    /* we need to get it byte by byte */
12478                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12479                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12480                 if (options.model == MODEL_FLAT24) {
12481                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12482                 }
12483             }
12484             _endLazyDPSEvaluation ();
12485         }
12486     }
12487     freeAsmop (to, NULL, ic, FALSE);
12488     _G.dptrInUse = _G.dptr1InUse = 1;
12489     aopOp (count, ic->next->next, FALSE,FALSE);
12490     lbl =newiTempLabel(NULL);
12491
12492     /* now for the actual copy */
12493     if (AOP_TYPE(count) == AOP_LIT &&
12494         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12495         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12496         if (fromc) {
12497             emitcode ("lcall","__bi_memcpyc2x_s");
12498         } else {
12499             emitcode ("lcall","__bi_memcpyx2x_s");
12500         }
12501         freeAsmop (count, NULL, ic, FALSE);
12502     } else {
12503         symbol *lbl1 = newiTempLabel(NULL);
12504
12505         emitcode (";"," Auto increment but no djnz");
12506         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12507         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12508         freeAsmop (count, NULL, ic, FALSE);
12509         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12510         emitcode ("","!tlabeldef",lbl->key+100);
12511         if (fromc) {
12512             emitcode ("clr","a");
12513             emitcode ("movc", "a,@a+dptr");
12514         } else
12515             emitcode ("movx", "a,@dptr");
12516         emitcode ("movx", "@dptr,a");
12517         emitcode ("inc", "dptr");
12518         emitcode ("inc", "dptr");
12519         emitcode ("mov","a,b");
12520         emitcode ("orl","a,_ap");
12521         emitcode ("jz","!tlabel",lbl1->key+100);
12522         emitcode ("mov","a,_ap");
12523         emitcode ("add","a,#!constbyte",0xFF);
12524         emitcode ("mov","_ap,a");
12525         emitcode ("mov","a,b");
12526         emitcode ("addc","a,#!constbyte",0xFF);
12527         emitcode ("mov","b,a");
12528         emitcode ("sjmp","!tlabel",lbl->key+100);
12529         emitcode ("","!tlabeldef",lbl1->key+100);
12530     }
12531     emitcode ("mov", "dps,#0");
12532     _G.dptrInUse = _G.dptr1InUse = 0;
12533     unsavermask(rsave);
12534
12535 }
12536
12537 /*-----------------------------------------------------------------*/
12538 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12539 /*-----------------------------------------------------------------*/
12540 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12541 {
12542     operand *from , *to , *count;
12543     symbol *lbl,*lbl2;
12544     bitVect *rsave;
12545     int i;
12546
12547     /* we know it has to be 3 parameters */
12548     assert (nparms == 3);
12549
12550     rsave = newBitVect(16);
12551     /* save DPTR if it needs to be saved */
12552     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12553             if (bitVectBitValue(ic->rMask,i))
12554                     rsave = bitVectSetBit(rsave,i);
12555     }
12556     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12557                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12558     savermask(rsave);
12559
12560     to = parms[0];
12561     from = parms[1];
12562     count = parms[2];
12563
12564     aopOp (from, ic->next, FALSE, FALSE);
12565
12566     /* get from into DPTR1 */
12567     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12568     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12569     if (options.model == MODEL_FLAT24) {
12570         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12571     }
12572
12573     freeAsmop (from, NULL, ic, FALSE);
12574     aopOp (to, ic, FALSE, FALSE);
12575     /* get "to" into DPTR */
12576     /* if the operand is already in dptr
12577        then we do nothing else we move the value to dptr */
12578     if (AOP_TYPE (to) != AOP_STR) {
12579         /* if already in DPTR then we need to push */
12580         if (AOP_TYPE(to) == AOP_DPTR) {
12581             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12582             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12583             if (options.model == MODEL_FLAT24)
12584                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12585             emitcode ("pop", "dph");
12586             emitcode ("pop", "dpl");
12587         } else {
12588             _startLazyDPSEvaluation ();
12589             /* if this is remateriazable */
12590             if (AOP_TYPE (to) == AOP_IMMD) {
12591                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12592             } else {                    /* we need to get it byte by byte */
12593                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12594                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12595                 if (options.model == MODEL_FLAT24) {
12596                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12597                 }
12598             }
12599             _endLazyDPSEvaluation ();
12600         }
12601     }
12602     freeAsmop (to, NULL, ic, FALSE);
12603     _G.dptrInUse = _G.dptr1InUse = 1;
12604     aopOp (count, ic->next->next, FALSE,FALSE);
12605     lbl =newiTempLabel(NULL);
12606     lbl2 =newiTempLabel(NULL);
12607
12608     /* now for the actual compare */
12609     if (AOP_TYPE(count) == AOP_LIT &&
12610         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12611         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12612         if (fromc)
12613             emitcode("lcall","__bi_memcmpc2x_s");
12614         else
12615             emitcode("lcall","__bi_memcmpx2x_s");
12616         freeAsmop (count, NULL, ic, FALSE);
12617         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12618         aopPut(IC_RESULT(ic),"a",0);
12619         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12620     } else {
12621         symbol *lbl1 = newiTempLabel(NULL);
12622
12623         emitcode("push","ar0");
12624         emitcode (";"," Auto increment but no djnz");
12625         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12626         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12627         freeAsmop (count, NULL, ic, FALSE);
12628         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12629         emitcode ("","!tlabeldef",lbl->key+100);
12630         if (fromc) {
12631             emitcode ("clr","a");
12632             emitcode ("movc", "a,@a+dptr");
12633         } else
12634             emitcode ("movx", "a,@dptr");
12635         emitcode ("mov","r0,a");
12636         emitcode ("movx", "a,@dptr");
12637         emitcode ("clr","c");
12638         emitcode ("subb","a,r0");
12639         emitcode ("jnz","!tlabel",lbl2->key+100);
12640         emitcode ("inc", "dptr");
12641         emitcode ("inc", "dptr");
12642         emitcode ("mov","a,b");
12643         emitcode ("orl","a,_ap");
12644         emitcode ("jz","!tlabel",lbl1->key+100);
12645         emitcode ("mov","a,_ap");
12646         emitcode ("add","a,#!constbyte",0xFF);
12647         emitcode ("mov","_ap,a");
12648         emitcode ("mov","a,b");
12649         emitcode ("addc","a,#!constbyte",0xFF);
12650         emitcode ("mov","b,a");
12651         emitcode ("sjmp","!tlabel",lbl->key+100);
12652         emitcode ("","!tlabeldef",lbl1->key+100);
12653         emitcode ("clr","a");
12654         emitcode ("","!tlabeldef",lbl2->key+100);
12655         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12656         aopPut(IC_RESULT(ic),"a",0);
12657         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12658         emitcode("pop","ar0");
12659         emitcode ("mov", "dps,#0");
12660     }
12661     _G.dptrInUse = _G.dptr1InUse = 0;
12662     unsavermask(rsave);
12663
12664 }
12665
12666 /*-----------------------------------------------------------------*/
12667 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12668 /* port, first parameter output area second parameter pointer to   */
12669 /* port third parameter count                                      */
12670 /*-----------------------------------------------------------------*/
12671 static void genInp( iCode *ic, int nparms, operand **parms)
12672 {
12673     operand *from , *to , *count;
12674     symbol *lbl;
12675     bitVect *rsave;
12676     int i;
12677
12678     /* we know it has to be 3 parameters */
12679     assert (nparms == 3);
12680
12681     rsave = newBitVect(16);
12682     /* save DPTR if it needs to be saved */
12683     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12684             if (bitVectBitValue(ic->rMask,i))
12685                     rsave = bitVectSetBit(rsave,i);
12686     }
12687     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12688                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12689     savermask(rsave);
12690
12691     to = parms[0];
12692     from = parms[1];
12693     count = parms[2];
12694
12695     aopOp (from, ic->next, FALSE, FALSE);
12696
12697     /* get from into DPTR1 */
12698     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12699     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12700     if (options.model == MODEL_FLAT24) {
12701         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12702     }
12703
12704     freeAsmop (from, NULL, ic, FALSE);
12705     aopOp (to, ic, FALSE, FALSE);
12706     /* get "to" into DPTR */
12707     /* if the operand is already in dptr
12708        then we do nothing else we move the value to dptr */
12709     if (AOP_TYPE (to) != AOP_STR) {
12710         /* if already in DPTR then we need to push */
12711         if (AOP_TYPE(to) == AOP_DPTR) {
12712             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12713             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12714             if (options.model == MODEL_FLAT24)
12715                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12716             emitcode ("pop", "dph");
12717             emitcode ("pop", "dpl");
12718         } else {
12719             _startLazyDPSEvaluation ();
12720             /* if this is remateriazable */
12721             if (AOP_TYPE (to) == AOP_IMMD) {
12722                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12723             } else {                    /* we need to get it byte by byte */
12724                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12725                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12726                 if (options.model == MODEL_FLAT24) {
12727                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12728                 }
12729             }
12730             _endLazyDPSEvaluation ();
12731         }
12732     }
12733     freeAsmop (to, NULL, ic, FALSE);
12734
12735     _G.dptrInUse = _G.dptr1InUse = 1;
12736     aopOp (count, ic->next->next, FALSE,FALSE);
12737     lbl =newiTempLabel(NULL);
12738
12739     /* now for the actual copy */
12740     if (AOP_TYPE(count) == AOP_LIT &&
12741         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12742         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12743         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12744         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12745         freeAsmop (count, NULL, ic, FALSE);
12746         emitcode ("","!tlabeldef",lbl->key+100);
12747         emitcode ("movx", "a,@dptr");   /* read data from port */
12748         emitcode ("dec","dps");         /* switch to DPTR */
12749         emitcode ("movx", "@dptr,a");   /* save into location */
12750         emitcode ("inc", "dptr");       /* point to next area */
12751         emitcode ("inc","dps");         /* switch to DPTR2 */
12752         emitcode ("djnz","b,!tlabel",lbl->key+100);
12753     } else {
12754         symbol *lbl1 = newiTempLabel(NULL);
12755
12756         emitcode (";"," Auto increment but no djnz");
12757         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12758         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12759         freeAsmop (count, NULL, ic, FALSE);
12760         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12761         emitcode ("","!tlabeldef",lbl->key+100);
12762         emitcode ("movx", "a,@dptr");
12763         emitcode ("dec","dps");         /* switch to DPTR */
12764         emitcode ("movx", "@dptr,a");
12765         emitcode ("inc", "dptr");
12766         emitcode ("inc","dps");         /* switch to DPTR2 */
12767 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12768 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12769         emitcode ("mov","a,b");
12770         emitcode ("orl","a,_ap");
12771         emitcode ("jz","!tlabel",lbl1->key+100);
12772         emitcode ("mov","a,_ap");
12773         emitcode ("add","a,#!constbyte",0xFF);
12774         emitcode ("mov","_ap,a");
12775         emitcode ("mov","a,b");
12776         emitcode ("addc","a,#!constbyte",0xFF);
12777         emitcode ("mov","b,a");
12778         emitcode ("sjmp","!tlabel",lbl->key+100);
12779         emitcode ("","!tlabeldef",lbl1->key+100);
12780     }
12781     emitcode ("mov", "dps,#0");
12782     _G.dptrInUse = _G.dptr1InUse = 0;
12783     unsavermask(rsave);
12784
12785 }
12786
12787 /*-----------------------------------------------------------------*/
12788 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12789 /* port, first parameter output area second parameter pointer to   */
12790 /* port third parameter count                                      */
12791 /*-----------------------------------------------------------------*/
12792 static void genOutp( iCode *ic, int nparms, operand **parms)
12793 {
12794     operand *from , *to , *count;
12795     symbol *lbl;
12796     bitVect *rsave;
12797     int i;
12798
12799     /* we know it has to be 3 parameters */
12800     assert (nparms == 3);
12801
12802     rsave = newBitVect(16);
12803     /* save DPTR if it needs to be saved */
12804     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12805             if (bitVectBitValue(ic->rMask,i))
12806                     rsave = bitVectSetBit(rsave,i);
12807     }
12808     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12809                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12810     savermask(rsave);
12811
12812     to = parms[0];
12813     from = parms[1];
12814     count = parms[2];
12815
12816     aopOp (from, ic->next, FALSE, FALSE);
12817
12818     /* get from into DPTR1 */
12819     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12820     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12821     if (options.model == MODEL_FLAT24) {
12822         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12823     }
12824
12825     freeAsmop (from, NULL, ic, FALSE);
12826     aopOp (to, ic, FALSE, FALSE);
12827     /* get "to" into DPTR */
12828     /* if the operand is already in dptr
12829        then we do nothing else we move the value to dptr */
12830     if (AOP_TYPE (to) != AOP_STR) {
12831         /* if already in DPTR then we need to push */
12832         if (AOP_TYPE(to) == AOP_DPTR) {
12833             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12834             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12835             if (options.model == MODEL_FLAT24)
12836                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12837             emitcode ("pop", "dph");
12838             emitcode ("pop", "dpl");
12839         } else {
12840             _startLazyDPSEvaluation ();
12841             /* if this is remateriazable */
12842             if (AOP_TYPE (to) == AOP_IMMD) {
12843                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12844             } else {                    /* we need to get it byte by byte */
12845                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12846                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12847                 if (options.model == MODEL_FLAT24) {
12848                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12849                 }
12850             }
12851             _endLazyDPSEvaluation ();
12852         }
12853     }
12854     freeAsmop (to, NULL, ic, FALSE);
12855
12856     _G.dptrInUse = _G.dptr1InUse = 1;
12857     aopOp (count, ic->next->next, FALSE,FALSE);
12858     lbl =newiTempLabel(NULL);
12859
12860     /* now for the actual copy */
12861     if (AOP_TYPE(count) == AOP_LIT &&
12862         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12863         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12864         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12865         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12866         emitcode ("","!tlabeldef",lbl->key+100);
12867         emitcode ("movx", "a,@dptr");   /* read data from port */
12868         emitcode ("inc","dps");         /* switch to DPTR2 */
12869         emitcode ("movx", "@dptr,a");   /* save into location */
12870         emitcode ("inc", "dptr");       /* point to next area */
12871         emitcode ("dec","dps");         /* switch to DPTR */
12872         emitcode ("djnz","b,!tlabel",lbl->key+100);
12873         freeAsmop (count, NULL, ic, FALSE);
12874     } else {
12875         symbol *lbl1 = newiTempLabel(NULL);
12876
12877         emitcode (";"," Auto increment but no djnz");
12878         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12879         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12880         freeAsmop (count, NULL, ic, FALSE);
12881         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12882         emitcode ("","!tlabeldef",lbl->key+100);
12883         emitcode ("movx", "a,@dptr");
12884         emitcode ("inc", "dptr");
12885         emitcode ("inc","dps");         /* switch to DPTR2 */
12886         emitcode ("movx", "@dptr,a");
12887         emitcode ("dec","dps");         /* switch to DPTR */
12888         emitcode ("mov","a,b");
12889         emitcode ("orl","a,_ap");
12890         emitcode ("jz","!tlabel",lbl1->key+100);
12891         emitcode ("mov","a,_ap");
12892         emitcode ("add","a,#!constbyte",0xFF);
12893         emitcode ("mov","_ap,a");
12894         emitcode ("mov","a,b");
12895         emitcode ("addc","a,#!constbyte",0xFF);
12896         emitcode ("mov","b,a");
12897         emitcode ("sjmp","!tlabel",lbl->key+100);
12898         emitcode ("","!tlabeldef",lbl1->key+100);
12899     }
12900     emitcode ("mov", "dps,#0");
12901     _G.dptrInUse = _G.dptr1InUse = 0;
12902     unsavermask(rsave);
12903
12904 }
12905
12906 /*-----------------------------------------------------------------*/
12907 /* genSwapW - swap lower & high order bytes                        */
12908 /*-----------------------------------------------------------------*/
12909 static void genSwapW(iCode *ic, int nparms, operand **parms)
12910 {
12911     operand *dest;
12912     operand *src;
12913     assert (nparms==1);
12914
12915     src = parms[0];
12916     dest=IC_RESULT(ic);
12917
12918     assert(getSize(operandType(src))==2);
12919
12920     aopOp (src, ic, FALSE, FALSE);
12921     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
12922     _G.accInUse++;
12923     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
12924     _G.accInUse--;
12925     freeAsmop (src, NULL, ic, FALSE);
12926
12927     aopOp (dest,ic, FALSE, FALSE);
12928     aopPut(dest,"b",0);
12929     aopPut(dest,"a",1);
12930     freeAsmop (dest, NULL, ic, FALSE);
12931 }
12932
12933 /*-----------------------------------------------------------------*/
12934 /* genMemsetX - gencode for memSetX data                           */
12935 /*-----------------------------------------------------------------*/
12936 static void genMemsetX(iCode *ic, int nparms, operand **parms)
12937 {
12938     operand *to , *val , *count;
12939     symbol *lbl;
12940     char *l;
12941     int i;
12942     bitVect *rsave;
12943
12944     /* we know it has to be 3 parameters */
12945     assert (nparms == 3);
12946
12947     to = parms[0];
12948     val = parms[1];
12949     count = parms[2];
12950
12951     /* save DPTR if it needs to be saved */
12952     rsave = newBitVect(16);
12953     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12954             if (bitVectBitValue(ic->rMask,i))
12955                     rsave = bitVectSetBit(rsave,i);
12956     }
12957     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12958                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12959     savermask(rsave);
12960
12961     aopOp (to, ic, FALSE, FALSE);
12962     /* get "to" into DPTR */
12963     /* if the operand is already in dptr
12964        then we do nothing else we move the value to dptr */
12965     if (AOP_TYPE (to) != AOP_STR) {
12966         /* if already in DPTR then we need to push */
12967         if (AOP_TYPE(to) == AOP_DPTR) {
12968             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12969             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12970             if (options.model == MODEL_FLAT24)
12971                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12972             emitcode ("pop", "dph");
12973             emitcode ("pop", "dpl");
12974         } else {
12975             _startLazyDPSEvaluation ();
12976             /* if this is remateriazable */
12977             if (AOP_TYPE (to) == AOP_IMMD) {
12978                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12979             } else {                    /* we need to get it byte by byte */
12980                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12981                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12982                 if (options.model == MODEL_FLAT24) {
12983                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12984                 }
12985             }
12986             _endLazyDPSEvaluation ();
12987         }
12988     }
12989     freeAsmop (to, NULL, ic, FALSE);
12990
12991     aopOp (val, ic->next->next, FALSE,FALSE);
12992     aopOp (count, ic->next->next, FALSE,FALSE);
12993     lbl =newiTempLabel(NULL);
12994     /* now for the actual copy */
12995     if (AOP_TYPE(count) == AOP_LIT &&
12996         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12997         l = aopGet(val, 0, FALSE, FALSE, NULL);
12998         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12999         MOVA(l);
13000         emitcode ("","!tlabeldef",lbl->key+100);
13001         emitcode ("movx", "@dptr,a");
13002         emitcode ("inc", "dptr");
13003         emitcode ("djnz","b,!tlabel",lbl->key+100);
13004     } else {
13005         symbol *lbl1 = newiTempLabel(NULL);
13006
13007         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13008         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13009         emitcode ("","!tlabeldef",lbl->key+100);
13010         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13011         emitcode ("movx", "@dptr,a");
13012         emitcode ("inc", "dptr");
13013         emitcode ("mov","a,b");
13014         emitcode ("orl","a,_ap");
13015         emitcode ("jz","!tlabel",lbl1->key+100);
13016         emitcode ("mov","a,_ap");
13017         emitcode ("add","a,#!constbyte",0xFF);
13018         emitcode ("mov","_ap,a");
13019         emitcode ("mov","a,b");
13020         emitcode ("addc","a,#!constbyte",0xFF);
13021         emitcode ("mov","b,a");
13022         emitcode ("sjmp","!tlabel",lbl->key+100);
13023         emitcode ("","!tlabeldef",lbl1->key+100);
13024     }
13025     freeAsmop (count, NULL, ic, FALSE);
13026     unsavermask(rsave);
13027 }
13028
13029 /*-----------------------------------------------------------------*/
13030 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13031 /*-----------------------------------------------------------------*/
13032 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13033 {
13034         bitVect *rsave ;
13035         operand *pnum, *result;
13036         int i;
13037
13038         assert (nparms==1);
13039         /* save registers that need to be saved */
13040         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13041                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13042
13043         pnum = parms[0];
13044         aopOp (pnum, ic, FALSE, FALSE);
13045         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13046         freeAsmop (pnum, NULL, ic, FALSE);
13047         emitcode ("lcall","NatLib_LoadPrimitive");
13048         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13049         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13050             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13051                 for (i = (size-1) ; i >= 0 ; i-- ) {
13052                         emitcode ("push","a%s",javaRet[i]);
13053                 }
13054                 for (i=0; i < size ; i++ ) {
13055                         emitcode ("pop","a%s",
13056                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13057                 }
13058         } else {
13059                 for (i = 0 ; i < size ; i++ ) {
13060                         aopPut(result,javaRet[i],i);
13061                 }
13062         }
13063         freeAsmop (result, NULL, ic, FALSE);
13064         unsavermask(rsave);
13065 }
13066
13067 /*-----------------------------------------------------------------*/
13068 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13069 /*-----------------------------------------------------------------*/
13070 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13071 {
13072         bitVect *rsave ;
13073         operand *pnum, *result;
13074         int size = 3;
13075         int i;
13076
13077         assert (nparms==1);
13078         /* save registers that need to be saved */
13079         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13080                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13081
13082         pnum = parms[0];
13083         aopOp (pnum, ic, FALSE, FALSE);
13084         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13085         freeAsmop (pnum, NULL, ic, FALSE);
13086         emitcode ("lcall","NatLib_LoadPointer");
13087         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13088         if (AOP_TYPE(result)!=AOP_STR) {
13089                 for (i = 0 ; i < size ; i++ ) {
13090                         aopPut(result,fReturn[i],i);
13091                 }
13092         }
13093         freeAsmop (result, NULL, ic, FALSE);
13094         unsavermask(rsave);
13095 }
13096
13097 /*-----------------------------------------------------------------*/
13098 /* genNatLibInstallStateBlock -                                    */
13099 /*-----------------------------------------------------------------*/
13100 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13101                                        operand **parms, const char *name)
13102 {
13103         bitVect *rsave ;
13104         operand *psb, *handle;
13105         assert (nparms==2);
13106
13107         /* save registers that need to be saved */
13108         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13109                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13110         psb = parms[0];
13111         handle = parms[1];
13112
13113         /* put pointer to state block into DPTR1 */
13114         aopOp (psb, ic, FALSE, FALSE);
13115         if (AOP_TYPE (psb) == AOP_IMMD) {
13116                 emitcode ("mov","dps,#1");
13117                 emitcode ("mov", "dptr,%s",
13118                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13119                 emitcode ("mov","dps,#0");
13120         } else {
13121                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13122                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13123                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13124         }
13125         freeAsmop (psb, NULL, ic, FALSE);
13126
13127         /* put libraryID into DPTR */
13128         emitcode ("mov","dptr,#LibraryID");
13129
13130         /* put handle into r3:r2 */
13131         aopOp (handle, ic, FALSE, FALSE);
13132         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13133                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13134                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13135                 emitcode ("pop","ar3");
13136                 emitcode ("pop","ar2");
13137         } else {
13138                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13139                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13140         }
13141         freeAsmop (psb, NULL, ic, FALSE);
13142
13143         /* make the call */
13144         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13145
13146         /* put return value into place*/
13147         _G.accInUse++;
13148         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13149         _G.accInUse--;
13150         aopPut(IC_RESULT(ic),"a",0);
13151         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13152         unsavermask(rsave);
13153 }
13154
13155 /*-----------------------------------------------------------------*/
13156 /* genNatLibRemoveStateBlock -                                     */
13157 /*-----------------------------------------------------------------*/
13158 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13159 {
13160         bitVect *rsave ;
13161
13162         assert(nparms==0);
13163
13164         /* save registers that need to be saved */
13165         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13166                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13167
13168         /* put libraryID into DPTR */
13169         emitcode ("mov","dptr,#LibraryID");
13170         /* make the call */
13171         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13172         unsavermask(rsave);
13173 }
13174
13175 /*-----------------------------------------------------------------*/
13176 /* genNatLibGetStateBlock -                                        */
13177 /*-----------------------------------------------------------------*/
13178 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13179                                    operand **parms,const char *name)
13180 {
13181         bitVect *rsave ;
13182         symbol *lbl = newiTempLabel(NULL);
13183
13184         assert(nparms==0);
13185         /* save registers that need to be saved */
13186         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13187                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13188
13189         /* put libraryID into DPTR */
13190         emitcode ("mov","dptr,#LibraryID");
13191         /* make the call */
13192         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13193         emitcode ("jnz","!tlabel",lbl->key+100);
13194
13195         /* put return value into place */
13196         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13197         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13198                 emitcode ("push","ar3");
13199                 emitcode ("push","ar2");
13200                 emitcode ("pop","%s",
13201                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13202                 emitcode ("pop","%s",
13203                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13204         } else {
13205                 aopPut(IC_RESULT(ic),"r2",0);
13206                 aopPut(IC_RESULT(ic),"r3",1);
13207         }
13208         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13209         emitcode ("","!tlabeldef",lbl->key+100);
13210         unsavermask(rsave);
13211 }
13212
13213 /*-----------------------------------------------------------------*/
13214 /* genMMMalloc -                                                   */
13215 /*-----------------------------------------------------------------*/
13216 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13217                          int size, const char *name)
13218 {
13219         bitVect *rsave ;
13220         operand *bsize;
13221         symbol *rsym;
13222         symbol *lbl = newiTempLabel(NULL);
13223
13224         assert (nparms == 1);
13225         /* save registers that need to be saved */
13226         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13227                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13228
13229         bsize=parms[0];
13230         aopOp (bsize,ic,FALSE,FALSE);
13231
13232         /* put the size in R4-R2 */
13233         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13234                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13235                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13236                 if (size==3) {
13237                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13238                         emitcode("pop","ar4");
13239                 }
13240                 emitcode("pop","ar3");
13241                 emitcode("pop","ar2");
13242         } else {
13243                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13244                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13245                 if (size==3) {
13246                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13247                 }
13248         }
13249         freeAsmop (bsize, NULL, ic, FALSE);
13250
13251         /* make the call */
13252         emitcode ("lcall","MM_%s",name);
13253         emitcode ("jz","!tlabel",lbl->key+100);
13254         emitcode ("mov","r2,#!constbyte",0xff);
13255         emitcode ("mov","r3,#!constbyte",0xff);
13256         emitcode ("","!tlabeldef",lbl->key+100);
13257         /* we don't care about the pointer : we just save the handle */
13258         rsym = OP_SYMBOL(IC_RESULT(ic));
13259         if (rsym->liveFrom != rsym->liveTo) {
13260                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13261                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13262                         emitcode ("push","ar3");
13263                         emitcode ("push","ar2");
13264                         emitcode ("pop","%s",
13265                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13266                         emitcode ("pop","%s",
13267                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13268                 } else {
13269                         aopPut(IC_RESULT(ic),"r2",0);
13270                         aopPut(IC_RESULT(ic),"r3",1);
13271                 }
13272                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13273         }
13274         unsavermask(rsave);
13275 }
13276
13277 /*-----------------------------------------------------------------*/
13278 /* genMMDeref -                                                    */
13279 /*-----------------------------------------------------------------*/
13280 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13281 {
13282         bitVect *rsave ;
13283         operand *handle;
13284
13285         assert (nparms == 1);
13286         /* save registers that need to be saved */
13287         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13288                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13289
13290         handle=parms[0];
13291         aopOp (handle,ic,FALSE,FALSE);
13292
13293         /* put the size in R4-R2 */
13294         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13295                 emitcode("push","%s",
13296                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13297                 emitcode("push","%s",
13298                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13299                 emitcode("pop","ar3");
13300                 emitcode("pop","ar2");
13301         } else {
13302                 emitcode ("mov","r2,%s",
13303                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13304                 emitcode ("mov","r3,%s",
13305                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13306         }
13307         freeAsmop (handle, NULL, ic, FALSE);
13308
13309         /* make the call */
13310         emitcode ("lcall","MM_Deref");
13311
13312         {
13313                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13314                 if (rsym->liveFrom != rsym->liveTo) {
13315                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13316                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13317                             _startLazyDPSEvaluation ();
13318
13319                                 aopPut(IC_RESULT(ic),"dpl",0);
13320                                 aopPut(IC_RESULT(ic),"dph",1);
13321                                 aopPut(IC_RESULT(ic),"dpx",2);
13322
13323                             _endLazyDPSEvaluation ();
13324
13325                         }
13326                 }
13327         }
13328         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13329         unsavermask(rsave);
13330 }
13331
13332 /*-----------------------------------------------------------------*/
13333 /* genMMUnrestrictedPersist -                                      */
13334 /*-----------------------------------------------------------------*/
13335 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13336 {
13337         bitVect *rsave ;
13338         operand *handle;
13339
13340         assert (nparms == 1);
13341         /* save registers that need to be saved */
13342         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13343                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13344
13345         handle=parms[0];
13346         aopOp (handle,ic,FALSE,FALSE);
13347
13348         /* put the size in R3-R2 */
13349         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13350                 emitcode("push","%s",
13351                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13352                 emitcode("push","%s",
13353                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13354                 emitcode("pop","ar3");
13355                 emitcode("pop","ar2");
13356         } else {
13357                 emitcode ("mov","r2,%s",
13358                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13359                 emitcode ("mov","r3,%s",
13360                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13361         }
13362         freeAsmop (handle, NULL, ic, FALSE);
13363
13364         /* make the call */
13365         emitcode ("lcall","MM_UnrestrictedPersist");
13366
13367         {
13368                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13369                 if (rsym->liveFrom != rsym->liveTo) {
13370                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13371                         aopPut(IC_RESULT(ic),"a",0);
13372                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13373                 }
13374         }
13375         unsavermask(rsave);
13376 }
13377
13378 /*-----------------------------------------------------------------*/
13379 /* genSystemExecJavaProcess -                                      */
13380 /*-----------------------------------------------------------------*/
13381 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13382 {
13383         bitVect *rsave ;
13384         operand *handle, *pp;
13385
13386         assert (nparms==2);
13387         /* save registers that need to be saved */
13388         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13389                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13390
13391         pp = parms[0];
13392         handle = parms[1];
13393
13394         /* put the handle in R3-R2 */
13395         aopOp (handle,ic,FALSE,FALSE);
13396         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13397                 emitcode("push","%s",
13398                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13399                 emitcode("push","%s",
13400                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13401                 emitcode("pop","ar3");
13402                 emitcode("pop","ar2");
13403         } else {
13404                 emitcode ("mov","r2,%s",
13405                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13406                 emitcode ("mov","r3,%s",
13407                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13408         }
13409         freeAsmop (handle, NULL, ic, FALSE);
13410
13411         /* put pointer in DPTR */
13412         aopOp (pp,ic,FALSE,FALSE);
13413         if (AOP_TYPE(pp) == AOP_IMMD) {
13414                 emitcode ("mov", "dptr,%s",
13415                           aopGet (pp, 0, TRUE, FALSE, NULL));
13416         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13417                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13418                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13419                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13420         }
13421         freeAsmop (handle, NULL, ic, FALSE);
13422
13423         /* make the call */
13424         emitcode ("lcall","System_ExecJavaProcess");
13425
13426         /* put result in place */
13427         {
13428                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13429                 if (rsym->liveFrom != rsym->liveTo) {
13430                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13431                         aopPut(IC_RESULT(ic),"a",0);
13432                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13433                 }
13434         }
13435
13436         unsavermask(rsave);
13437 }
13438
13439 /*-----------------------------------------------------------------*/
13440 /* genSystemRTCRegisters -                                         */
13441 /*-----------------------------------------------------------------*/
13442 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13443                                   char *name)
13444 {
13445         bitVect *rsave ;
13446         operand *pp;
13447
13448         assert (nparms==1);
13449         /* save registers that need to be saved */
13450         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13451                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13452
13453         pp=parms[0];
13454         /* put pointer in DPTR */
13455         aopOp (pp,ic,FALSE,FALSE);
13456         if (AOP_TYPE (pp) == AOP_IMMD) {
13457                 emitcode ("mov","dps,#1");
13458                 emitcode ("mov", "dptr,%s",
13459                           aopGet (pp, 0, TRUE, FALSE, NULL));
13460                 emitcode ("mov","dps,#0");
13461         } else {
13462                 emitcode ("mov","dpl1,%s",
13463                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13464                 emitcode ("mov","dph1,%s",
13465                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13466                 emitcode ("mov","dpx1,%s",
13467                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13468         }
13469         freeAsmop (pp, NULL, ic, FALSE);
13470
13471         /* make the call */
13472         emitcode ("lcall","System_%sRTCRegisters",name);
13473
13474         unsavermask(rsave);
13475 }
13476
13477 /*-----------------------------------------------------------------*/
13478 /* genSystemThreadSleep -                                          */
13479 /*-----------------------------------------------------------------*/
13480 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13481 {
13482         bitVect *rsave ;
13483         operand *to, *s;
13484
13485         assert (nparms==1);
13486         /* save registers that need to be saved */
13487         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13488                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13489
13490         to = parms[0];
13491         aopOp(to,ic,FALSE,FALSE);
13492         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13493             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13494                 emitcode ("push","%s",
13495                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13496                 emitcode ("push","%s",
13497                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13498                 emitcode ("push","%s",
13499                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13500                 emitcode ("push","%s",
13501                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13502                 emitcode ("pop","ar3");
13503                 emitcode ("pop","ar2");
13504                 emitcode ("pop","ar1");
13505                 emitcode ("pop","ar0");
13506         } else {
13507                 emitcode ("mov","r0,%s",
13508                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13509                 emitcode ("mov","r1,%s",
13510                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13511                 emitcode ("mov","r2,%s",
13512                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13513                 emitcode ("mov","r3,%s",
13514                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13515         }
13516         freeAsmop (to, NULL, ic, FALSE);
13517
13518         /* suspend in acc */
13519         s = parms[1];
13520         aopOp(s,ic,FALSE,FALSE);
13521         emitcode ("mov","a,%s",
13522                   aopGet(s,0,FALSE,TRUE,NULL));
13523         freeAsmop (s, NULL, ic, FALSE);
13524
13525         /* make the call */
13526         emitcode ("lcall","System_%s",name);
13527
13528         unsavermask(rsave);
13529 }
13530
13531 /*-----------------------------------------------------------------*/
13532 /* genSystemThreadResume -                                         */
13533 /*-----------------------------------------------------------------*/
13534 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13535 {
13536         bitVect *rsave ;
13537         operand *tid,*pid;
13538
13539         assert (nparms==2);
13540         /* save registers that need to be saved */
13541         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13542                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13543
13544         tid = parms[0];
13545         pid = parms[1];
13546
13547         /* PID in R0 */
13548         aopOp(pid,ic,FALSE,FALSE);
13549         emitcode ("mov","r0,%s",
13550                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13551         freeAsmop (pid, NULL, ic, FALSE);
13552
13553         /* tid into ACC */
13554         aopOp(tid,ic,FALSE,FALSE);
13555         emitcode ("mov","a,%s",
13556                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13557         freeAsmop (tid, NULL, ic, FALSE);
13558
13559         emitcode ("lcall","System_ThreadResume");
13560
13561         /* put result into place */
13562         {
13563                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13564                 if (rsym->liveFrom != rsym->liveTo) {
13565                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13566                         aopPut(IC_RESULT(ic),"a",0);
13567                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13568                 }
13569         }
13570         unsavermask(rsave);
13571 }
13572
13573 /*-----------------------------------------------------------------*/
13574 /* genSystemProcessResume -                                        */
13575 /*-----------------------------------------------------------------*/
13576 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13577 {
13578         bitVect *rsave ;
13579         operand *pid;
13580
13581         assert (nparms==1);
13582         /* save registers that need to be saved */
13583         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13584                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13585
13586         pid = parms[0];
13587
13588         /* pid into ACC */
13589         aopOp(pid,ic,FALSE,FALSE);
13590         emitcode ("mov","a,%s",
13591                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13592         freeAsmop (pid, NULL, ic, FALSE);
13593
13594         emitcode ("lcall","System_ProcessResume");
13595
13596         unsavermask(rsave);
13597 }
13598
13599 /*-----------------------------------------------------------------*/
13600 /* genSystem -                                                     */
13601 /*-----------------------------------------------------------------*/
13602 static void genSystem (iCode *ic,int nparms,char *name)
13603 {
13604         assert(nparms == 0);
13605
13606         emitcode ("lcall","System_%s",name);
13607 }
13608
13609 /*-----------------------------------------------------------------*/
13610 /* genSystemPoll -                                                  */
13611 /*-----------------------------------------------------------------*/
13612 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13613 {
13614         bitVect *rsave ;
13615         operand *fp;
13616
13617         assert (nparms==1);
13618         /* save registers that need to be saved */
13619         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13620                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13621
13622         fp = parms[0];
13623         aopOp (fp,ic,FALSE,FALSE);
13624         if (AOP_TYPE (fp) == AOP_IMMD) {
13625                 emitcode ("mov", "dptr,%s",
13626                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13627         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13628                 emitcode ("mov","dpl,%s",
13629                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13630                 emitcode ("mov","dph,%s",
13631                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13632                 emitcode ("mov","dpx,%s",
13633                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13634         }
13635         freeAsmop (fp, NULL, ic, FALSE);
13636
13637         emitcode ("lcall","System_%sPoll",name);
13638
13639         /* put result into place */
13640         {
13641                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13642                 if (rsym->liveFrom != rsym->liveTo) {
13643                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13644                         aopPut(IC_RESULT(ic),"a",0);
13645                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13646                 }
13647         }
13648         unsavermask(rsave);
13649 }
13650
13651 /*-----------------------------------------------------------------*/
13652 /* genSystemGetCurrentID -                                         */
13653 /*-----------------------------------------------------------------*/
13654 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13655 {
13656         assert (nparms==0);
13657
13658         emitcode ("lcall","System_GetCurrent%sId",name);
13659         /* put result into place */
13660         {
13661                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13662                 if (rsym->liveFrom != rsym->liveTo) {
13663                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13664                         aopPut(IC_RESULT(ic),"a",0);
13665                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13666                 }
13667         }
13668 }
13669
13670 /*-----------------------------------------------------------------*/
13671 /* genDjnz - generate decrement & jump if not zero instrucion      */
13672 /*-----------------------------------------------------------------*/
13673 static int
13674 genDjnz (iCode * ic, iCode * ifx)
13675 {
13676   symbol *lbl, *lbl1;
13677   if (!ifx)
13678     return 0;
13679
13680   /* if the if condition has a false label
13681      then we cannot save */
13682   if (IC_FALSE (ifx))
13683     return 0;
13684
13685   /* if the minus is not of the form a = a - 1 */
13686   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13687       !IS_OP_LITERAL (IC_RIGHT (ic)))
13688     return 0;
13689
13690   if (operandLitValue (IC_RIGHT (ic)) != 1)
13691     return 0;
13692
13693   /* if the size of this greater than one then no
13694      saving */
13695   if (getSize (operandType (IC_RESULT (ic))) > 1)
13696     return 0;
13697
13698   /* otherwise we can save BIG */
13699
13700   D (emitcode (";", "genDjnz"));
13701
13702   lbl = newiTempLabel (NULL);
13703   lbl1 = newiTempLabel (NULL);
13704
13705   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13706
13707   if (AOP_NEEDSACC(IC_RESULT(ic)))
13708   {
13709       /* If the result is accessed indirectly via
13710        * the accumulator, we must explicitly write
13711        * it back after the decrement.
13712        */
13713       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13714
13715       if (strcmp(rByte, "a"))
13716       {
13717            /* Something is hopelessly wrong */
13718            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13719                    __FILE__, __LINE__);
13720            /* We can just give up; the generated code will be inefficient,
13721             * but what the hey.
13722             */
13723            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13724            return 0;
13725       }
13726       emitcode ("dec", "%s", rByte);
13727       aopPut (IC_RESULT (ic), rByte, 0);
13728       emitcode ("jnz", "!tlabel", lbl->key + 100);
13729   }
13730   else if (IS_AOP_PREG (IC_RESULT (ic)))
13731     {
13732       emitcode ("dec", "%s",
13733                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13734       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13735       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13736       ifx->generated = 1;
13737       emitcode ("jnz", "!tlabel", lbl->key + 100);
13738     }
13739   else
13740     {
13741       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13742                 lbl->key + 100);
13743     }
13744   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13745   emitLabel (lbl);
13746   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13747   emitLabel (lbl1);
13748
13749   if (!ifx->generated)
13750       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13751   ifx->generated = 1;
13752   return 1;
13753 }
13754
13755 /*-----------------------------------------------------------------*/
13756 /* genReceive - generate code for a receive iCode                  */
13757 /*-----------------------------------------------------------------*/
13758 static void
13759 genReceive (iCode * ic)
13760 {
13761     int size = getSize (operandType (IC_RESULT (ic)));
13762     int offset = 0;
13763     int rb1off ;
13764
13765     D (emitcode (";", "genReceive"));
13766
13767     if (ic->argreg == 1)
13768     {
13769         /* first parameter */
13770         if (AOP_IS_STR(IC_RESULT(ic)))
13771         {
13772             /* Nothing to do: it's already in the proper place. */
13773             return;
13774         }
13775         else
13776         {
13777             bool useDp2;
13778
13779             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13780                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13781                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13782
13783             _G.accInUse++;
13784             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13785             _G.accInUse--;
13786
13787             /* Sanity checking... */
13788             if (AOP_USESDPTR(IC_RESULT(ic)))
13789             {
13790                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13791                         "genReceive got unexpected DPTR.");
13792             }
13793             assignResultValue (IC_RESULT (ic), NULL);
13794         }
13795     }
13796     else if (ic->argreg > 12)
13797     { /* bit parameters */
13798       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13799         {
13800           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13801           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13802           outBitC(IC_RESULT (ic));
13803         }
13804     }
13805     else
13806     {
13807         /* second receive onwards */
13808         /* this gets a little tricky since unused receives will be
13809          eliminated, we have saved the reg in the type field . and
13810          we use that to figure out which register to use */
13811         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13812         rb1off = ic->argreg;
13813         while (size--)
13814         {
13815             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13816         }
13817     }
13818     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13819 }
13820
13821 /*-----------------------------------------------------------------*/
13822 /* genDummyRead - generate code for dummy read of volatiles        */
13823 /*-----------------------------------------------------------------*/
13824 static void
13825 genDummyRead (iCode * ic)
13826 {
13827   operand *op;
13828   int size, offset;
13829
13830   D (emitcode(";", "genDummyRead"));
13831
13832   op = IC_RIGHT (ic);
13833   if (op && IS_SYMOP (op))
13834     {
13835       aopOp (op, ic, FALSE, FALSE);
13836
13837       /* if the result is a bit */
13838       if (AOP_TYPE (op) == AOP_CRY)
13839         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13840       else
13841         {
13842           /* bit variables done */
13843           /* general case */
13844           size = AOP_SIZE (op);
13845           offset = 0;
13846           while (size--)
13847           {
13848             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13849             offset++;
13850           }
13851         }
13852
13853       freeAsmop (op, NULL, ic, TRUE);
13854     }
13855
13856   op = IC_LEFT (ic);
13857   if (op && IS_SYMOP (op))
13858     {
13859       aopOp (op, ic, FALSE, FALSE);
13860
13861       /* if the result is a bit */
13862       if (AOP_TYPE (op) == AOP_CRY)
13863         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13864       else
13865         {
13866           /* bit variables done */
13867           /* general case */
13868           size = AOP_SIZE (op);
13869           offset = 0;
13870           while (size--)
13871           {
13872             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13873             offset++;
13874           }
13875         }
13876
13877       freeAsmop (op, NULL, ic, TRUE);
13878     }
13879 }
13880
13881 /*-----------------------------------------------------------------*/
13882 /* genCritical - generate code for start of a critical sequence    */
13883 /*-----------------------------------------------------------------*/
13884 static void
13885 genCritical (iCode *ic)
13886 {
13887   symbol *tlbl = newiTempLabel (NULL);
13888
13889   D (emitcode(";", "genCritical"));
13890
13891   if (IC_RESULT (ic))
13892     {
13893       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
13894       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
13895       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
13896       aopPut (IC_RESULT (ic), zero, 0);
13897       emitLabel (tlbl);
13898       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13899     }
13900   else
13901     {
13902       emitcode ("setb", "c");
13903       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
13904       emitcode ("clr", "c");
13905       emitLabel (tlbl);
13906       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
13907     }
13908 }
13909
13910 /*-----------------------------------------------------------------*/
13911 /* genEndCritical - generate code for end of a critical sequence   */
13912 /*-----------------------------------------------------------------*/
13913 static void
13914 genEndCritical (iCode *ic)
13915 {
13916   D(emitcode(";     genEndCritical",""));
13917
13918   if (IC_RIGHT (ic))
13919     {
13920       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
13921       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
13922         {
13923           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
13924           emitcode ("mov", "ea,c");
13925         }
13926       else
13927         {
13928           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
13929           emitcode ("rrc", "a");
13930           emitcode ("mov", "ea,c");
13931         }
13932       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
13933     }
13934   else
13935     {
13936       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
13937       emitcode ("mov", "ea,c");
13938     }
13939 }
13940
13941
13942
13943 /*-----------------------------------------------------------------*/
13944 /* genBuiltIn - calls the appropriate function to  generating code */
13945 /* for a built in function                                         */
13946 /*-----------------------------------------------------------------*/
13947 static void genBuiltIn (iCode *ic)
13948 {
13949         operand *bi_parms[MAX_BUILTIN_ARGS];
13950         int nbi_parms;
13951         iCode *bi_iCode;
13952         symbol *bif;
13953
13954         /* get all the arguments for a built in function */
13955         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
13956
13957         /* which function is it */
13958         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
13959         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
13960                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
13961         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
13962                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
13963         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
13964                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
13965         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
13966                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
13967         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
13968                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
13969         } else if (strcmp(bif->name,"__builtin_inp")==0) {
13970                 genInp(bi_iCode,nbi_parms,bi_parms);
13971         } else if (strcmp(bif->name,"__builtin_outp")==0) {
13972                 genOutp(bi_iCode,nbi_parms,bi_parms);
13973         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
13974                 genSwapW(bi_iCode,nbi_parms,bi_parms);
13975                 /* JavaNative builtIns */
13976         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
13977                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
13978         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
13979                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
13980         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
13981                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
13982         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
13983                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
13984         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
13985                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13986         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
13987                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13988         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
13989                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
13990         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
13991                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
13992         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
13993                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13994         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
13995                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13996         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
13997                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
13998         } else if (strcmp(bif->name,"MM_Malloc")==0) {
13999                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14000         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14001                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14002         } else if (strcmp(bif->name,"MM_Free")==0) {
14003                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14004         } else if (strcmp(bif->name,"MM_Deref")==0) {
14005                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14006         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14007                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14008         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14009                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14010         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14011                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14012         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14013                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14014         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14015                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14016         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14017                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14018         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14019                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14020         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14021                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14022         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14023                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14024         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14025                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14026         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14027                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14028         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14029                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14030         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14031                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14032         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14033                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14034         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14035                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14036         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14037                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14038         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14039                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14040         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14041                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14042         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14043                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14044         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14045                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14046         } else {
14047                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14048                 return ;
14049         }
14050         return ;
14051 }
14052
14053 /*-----------------------------------------------------------------*/
14054 /* gen390Code - generate code for Dallas 390 based controllers     */
14055 /*-----------------------------------------------------------------*/
14056 void
14057 gen390Code (iCode * lic)
14058 {
14059   iCode *ic;
14060   int cln = 0;
14061
14062   _G.currentFunc = NULL;
14063   lineHead = lineCurr = NULL;
14064   dptrn[1][0] = "dpl1";
14065   dptrn[1][1] = "dph1";
14066   dptrn[1][2] = "dpx1";
14067
14068   if (options.model == MODEL_FLAT24) {
14069     fReturnSizeDS390 = 5;
14070     fReturn = fReturn24;
14071   } else {
14072     fReturnSizeDS390 = 4;
14073     fReturn = fReturn16;
14074     options.stack10bit=0;
14075   }
14076 #if 1
14077   /* print the allocation information */
14078   if (allocInfo && currFunc)
14079     printAllocInfo (currFunc, codeOutFile);
14080 #endif
14081   /* if debug information required */
14082   if (options.debug && currFunc)
14083     {
14084       debugFile->writeFunction (currFunc, lic);
14085     }
14086   /* stack pointer name */
14087   if (options.useXstack)
14088     spname = "_spx";
14089   else
14090     spname = "sp";
14091
14092
14093   for (ic = lic; ic; ic = ic->next)
14094     {
14095       _G.current_iCode = ic;
14096
14097       if (ic->lineno && cln != ic->lineno)
14098         {
14099           if (options.debug)
14100             {
14101               debugFile->writeCLine (ic);
14102             }
14103           if (!options.noCcodeInAsm) {
14104             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14105                       printCLine(ic->filename, ic->lineno));
14106           }
14107           cln = ic->lineno;
14108         }
14109       if (options.iCodeInAsm) {
14110         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
14111       }
14112       /* if the result is marked as
14113          spilt and rematerializable or code for
14114          this has already been generated then
14115          do nothing */
14116       if (resultRemat (ic) || ic->generated)
14117         continue;
14118
14119       /* depending on the operation */
14120       switch (ic->op)
14121         {
14122         case '!':
14123           genNot (ic);
14124           break;
14125
14126         case '~':
14127           genCpl (ic);
14128           break;
14129
14130         case UNARYMINUS:
14131           genUminus (ic);
14132           break;
14133
14134         case IPUSH:
14135           genIpush (ic);
14136           break;
14137
14138         case IPOP:
14139           /* IPOP happens only when trying to restore a
14140              spilt live range, if there is an ifx statement
14141              following this pop then the if statement might
14142              be using some of the registers being popped which
14143              would destory the contents of the register so
14144              we need to check for this condition and handle it */
14145           if (ic->next &&
14146               ic->next->op == IFX &&
14147               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14148             genIfx (ic->next, ic);
14149           else
14150             genIpop (ic);
14151           break;
14152
14153         case CALL:
14154           genCall (ic);
14155           break;
14156
14157         case PCALL:
14158           genPcall (ic);
14159           break;
14160
14161         case FUNCTION:
14162           genFunction (ic);
14163           break;
14164
14165         case ENDFUNCTION:
14166           genEndFunction (ic);
14167           break;
14168
14169         case RETURN:
14170           genRet (ic);
14171           break;
14172
14173         case LABEL:
14174           genLabel (ic);
14175           break;
14176
14177         case GOTO:
14178           genGoto (ic);
14179           break;
14180
14181         case '+':
14182           genPlus (ic);
14183           break;
14184
14185         case '-':
14186           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14187             genMinus (ic);
14188           break;
14189
14190         case '*':
14191           genMult (ic);
14192           break;
14193
14194         case '/':
14195           genDiv (ic);
14196           break;
14197
14198         case '%':
14199           genMod (ic);
14200           break;
14201
14202         case '>':
14203           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14204           break;
14205
14206         case '<':
14207           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14208           break;
14209
14210         case LE_OP:
14211         case GE_OP:
14212         case NE_OP:
14213
14214           /* note these two are xlated by algebraic equivalence
14215              during parsing SDCC.y */
14216           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14217                   "got '>=' or '<=' shouldn't have come here");
14218           break;
14219
14220         case EQ_OP:
14221           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14222           break;
14223
14224         case AND_OP:
14225           genAndOp (ic);
14226           break;
14227
14228         case OR_OP:
14229           genOrOp (ic);
14230           break;
14231
14232         case '^':
14233           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14234           break;
14235
14236         case '|':
14237           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14238           break;
14239
14240         case BITWISEAND:
14241           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14242           break;
14243
14244         case INLINEASM:
14245           genInline (ic);
14246           break;
14247
14248         case RRC:
14249           genRRC (ic);
14250           break;
14251
14252         case RLC:
14253           genRLC (ic);
14254           break;
14255
14256         case GETHBIT:
14257           genGetHbit (ic);
14258           break;
14259
14260         case LEFT_OP:
14261           genLeftShift (ic);
14262           break;
14263
14264         case RIGHT_OP:
14265           genRightShift (ic);
14266           break;
14267
14268         case GET_VALUE_AT_ADDRESS:
14269           genPointerGet (ic,
14270                          hasInc (IC_LEFT (ic), ic,
14271                                  getSize (operandType (IC_RESULT (ic)))));
14272           break;
14273
14274         case '=':
14275           if (POINTER_SET (ic))
14276             genPointerSet (ic,
14277                            hasInc (IC_RESULT (ic), ic,
14278                                    getSize (operandType (IC_RIGHT (ic)))));
14279           else
14280             genAssign (ic);
14281           break;
14282
14283         case IFX:
14284           genIfx (ic, NULL);
14285           break;
14286
14287         case ADDRESS_OF:
14288           genAddrOf (ic);
14289           break;
14290
14291         case JUMPTABLE:
14292           genJumpTab (ic);
14293           break;
14294
14295         case CAST:
14296           genCast (ic);
14297           break;
14298
14299         case RECEIVE:
14300           genReceive (ic);
14301           break;
14302
14303         case SEND:
14304           if (ic->builtinSEND)
14305             genBuiltIn(ic);
14306           else
14307             addSet (&_G.sendSet, ic);
14308           break;
14309
14310         case DUMMY_READ_VOLATILE:
14311           genDummyRead (ic);
14312           break;
14313
14314         case CRITICAL:
14315           genCritical (ic);
14316           break;
14317
14318         case ENDCRITICAL:
14319           genEndCritical (ic);
14320           break;
14321
14322         case SWAP:
14323           genSwap (ic);
14324           break;
14325
14326 #if 0 // obsolete, and buggy for != xdata
14327         case ARRAYINIT:
14328             genArrayInit(ic);
14329             break;
14330 #endif
14331
14332         default:
14333           ic = ic;
14334         }
14335     }
14336
14337
14338   /* now we are ready to call the
14339      peep hole optimizer */
14340   if (!options.nopeep)
14341     peepHole (&lineHead);
14342
14343   /* now do the actual printing */
14344   printLine (lineHead, codeOutFile);
14345   return;
14346 }