12fd021817d126fa3762c67664f822ae1c243fb4
[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   int isSameRegs=sameRegs(AOP(left),AOP(result));
9630
9631   if (isSameRegs && offl>1) {
9632     // we are in big trouble, but this shouldn't happen
9633     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9634   }
9635
9636   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9637
9638   if (offl==MSB16)
9639     {
9640       // shift is > 8
9641       if (sign)
9642         {
9643           emitcode ("rlc", "a");
9644           emitcode ("subb", "a,acc");
9645           emitcode ("xch", "a,%s",
9646                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9647         }
9648       else
9649         {
9650           aopPut (result, zero, MSB32);
9651         }
9652     }
9653
9654   if (!sign)
9655     {
9656       emitcode ("clr", "c");
9657     }
9658   else
9659     {
9660       emitcode ("mov", "c,acc.7");
9661     }
9662
9663   emitcode ("rrc", "a");
9664
9665   if (isSameRegs && offl==MSB16) {
9666     emitcode ("xch",
9667               "a,%s",aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9668   } else {
9669     aopPut (result, "a", MSB32);
9670     MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9671   }
9672
9673   emitcode ("rrc", "a");
9674   if (isSameRegs && offl==1) {
9675     emitcode ("xch", "a,%s",
9676               aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9677   } else {
9678     aopPut (result, "a", MSB24);
9679     MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9680   }
9681   emitcode ("rrc", "a");
9682   aopPut (result, "a", MSB16 - offl);
9683
9684   if (offl == LSB)
9685     {
9686       MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9687       emitcode ("rrc", "a");
9688       aopPut (result, "a", LSB);
9689     }
9690 }
9691
9692 /*-----------------------------------------------------------------*/
9693 /* genrshFour - shift four byte by a known amount != 0             */
9694 /*-----------------------------------------------------------------*/
9695 static void
9696 genrshFour (operand * result, operand * left,
9697             int shCount, int sign)
9698 {
9699   D (emitcode (";", "genrshFour"));
9700
9701   /* if shifting more that 3 bytes */
9702   if (shCount >= 24)
9703     {
9704       shCount -= 24;
9705       _startLazyDPSEvaluation();
9706       if (shCount)
9707         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9708       else
9709         movLeft2Result (left, MSB32, result, LSB, sign);
9710       addSign (result, MSB16, sign);
9711       _endLazyDPSEvaluation();
9712     }
9713   else if (shCount >= 16)
9714     {
9715       shCount -= 16;
9716       _startLazyDPSEvaluation();
9717       if (shCount)
9718         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9719       else
9720         {
9721           movLeft2Result (left, MSB24, result, LSB, 0);
9722           movLeft2Result (left, MSB32, result, MSB16, sign);
9723         }
9724       addSign (result, MSB24, sign);
9725       _endLazyDPSEvaluation();
9726     }
9727   else if (shCount >= 8)
9728     {
9729       shCount -= 8;
9730       _startLazyDPSEvaluation();
9731       if (shCount == 1)
9732         {
9733             shiftRLong (left, MSB16, result, sign);
9734         }
9735       else if (shCount == 0)
9736         {
9737           movLeft2Result (left, MSB16, result, LSB, 0);
9738           movLeft2Result (left, MSB24, result, MSB16, 0);
9739           movLeft2Result (left, MSB32, result, MSB24, sign);
9740           addSign (result, MSB32, sign);
9741         }
9742       else
9743         {
9744           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9745           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9746           /* the last shift is signed */
9747           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9748           addSign (result, MSB32, sign);
9749         }
9750         _endLazyDPSEvaluation();
9751     }
9752   else
9753     {
9754       /* 1 <= shCount <= 7 */
9755       if (shCount <= 2)
9756         {
9757           shiftRLong (left, LSB, result, sign);
9758           if (shCount == 2)
9759             shiftRLong (result, LSB, result, sign);
9760         }
9761       else
9762         {
9763           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9764           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9765           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9766         }
9767     }
9768 }
9769
9770 #ifdef BETTER_LITERAL_SHIFT
9771 /*-----------------------------------------------------------------*/
9772 /* genRightShiftLiteral - right shifting by known count            */
9773 /*-----------------------------------------------------------------*/
9774 static bool
9775 genRightShiftLiteral (operand * left,
9776                       operand * right,
9777                       operand * result,
9778                       iCode * ic,
9779                       int sign)
9780 {
9781   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9782   int size;
9783
9784   size = getSize (operandType (result));
9785
9786   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9787
9788   /* We only handle certain easy cases so far. */
9789   if ((shCount != 0)
9790    && (shCount < (size * 8))
9791    && (size != 1)
9792    && (size != 2)
9793    && (size != 4))
9794   {
9795       D(emitcode (";", "genRightShiftLiteral wimping out"););
9796       return FALSE;
9797   }
9798
9799   freeAsmop (right, NULL, ic, TRUE);
9800
9801   aopOp (left, ic, FALSE, FALSE);
9802   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9803
9804 #if VIEW_SIZE
9805   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9806             AOP_SIZE (left));
9807 #endif
9808
9809   /* test the LEFT size !!! */
9810
9811   /* I suppose that the left size >= result size */
9812   if (shCount == 0)
9813   {
9814       size = getDataSize (result);
9815       _startLazyDPSEvaluation();
9816       while (size--)
9817         movLeft2Result (left, size, result, size, 0);
9818       _endLazyDPSEvaluation();
9819   }
9820   else if (shCount >= (size * 8))
9821     {
9822       if (sign)
9823         {
9824           /* get sign in acc.7 */
9825           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9826         }
9827       addSign (result, LSB, sign);
9828     }
9829   else
9830     {
9831       switch (size)
9832         {
9833         case 1:
9834           genrshOne (result, left, shCount, sign);
9835           break;
9836
9837         case 2:
9838           genrshTwo (result, left, shCount, sign);
9839           break;
9840 #if 1
9841         case 4:
9842           genrshFour (result, left, shCount, sign);
9843           break;
9844 #endif
9845         default:
9846           break;
9847         }
9848     }
9849   freeAsmop (result, NULL, ic, TRUE);
9850   freeAsmop (left, NULL, ic, TRUE);
9851
9852   return TRUE;
9853 }
9854 #endif
9855
9856 /*-----------------------------------------------------------------*/
9857 /* genSignedRightShift - right shift of signed number              */
9858 /*-----------------------------------------------------------------*/
9859 static void
9860 genSignedRightShift (iCode * ic)
9861 {
9862   operand *right, *left, *result;
9863   int size, offset;
9864   char *l;
9865   symbol *tlbl, *tlbl1;
9866   bool pushedB;
9867
9868   D (emitcode (";", "genSignedRightShift"));
9869
9870   /* we do it the hard way put the shift count in b
9871      and loop thru preserving the sign */
9872
9873   right = IC_RIGHT (ic);
9874   left = IC_LEFT (ic);
9875   result = IC_RESULT (ic);
9876
9877   aopOp (right, ic, FALSE, FALSE);
9878
9879 #ifdef BETTER_LITERAL_SHIFT
9880   if (AOP_TYPE (right) == AOP_LIT)
9881     {
9882       if (genRightShiftLiteral (left, right, result, ic, 1))
9883       {
9884         return;
9885       }
9886     }
9887 #endif
9888   /* shift count is unknown then we have to form
9889      a loop get the loop count in B : Note: we take
9890      only the lower order byte since shifting
9891      more that 32 bits make no sense anyway, ( the
9892      largest size of an object can be only 32 bits ) */
9893
9894   pushedB = pushB ();
9895   if (AOP_TYPE (right) == AOP_LIT)
9896   {
9897       /* Really should be handled by genRightShiftLiteral,
9898        * but since I'm too lazy to fix that today, at least we can make
9899        * some small improvement.
9900        */
9901        emitcode("mov", "b,#!constbyte",
9902                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9903   }
9904   else
9905   {
9906         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9907         emitcode ("inc", "b");
9908   }
9909   freeAsmop (right, NULL, ic, TRUE);
9910   aopOp (left, ic, FALSE, FALSE);
9911   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9912
9913   /* now move the left to the result if they are not the
9914      same */
9915   if (!sameRegs (AOP (left), AOP (result)) &&
9916       AOP_SIZE (result) > 1)
9917     {
9918
9919       size = AOP_SIZE (result);
9920       offset = 0;
9921       _startLazyDPSEvaluation ();
9922       while (size--)
9923         {
9924           l = aopGet (left, offset, FALSE, TRUE, NULL);
9925           if (*l == '@' && IS_AOP_PREG (result))
9926             {
9927
9928               emitcode ("mov", "a,%s", l);
9929               aopPut (result, "a", offset);
9930             }
9931           else
9932             aopPut (result, l, offset);
9933           offset++;
9934         }
9935       _endLazyDPSEvaluation ();
9936     }
9937
9938   /* mov the highest order bit to OVR */
9939   tlbl = newiTempLabel (NULL);
9940   tlbl1 = newiTempLabel (NULL);
9941
9942   size = AOP_SIZE (result);
9943   offset = size - 1;
9944   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
9945   emitcode ("rlc", "a");
9946   emitcode ("mov", "ov,c");
9947   /* if it is only one byte then */
9948   if (size == 1)
9949     {
9950       l = aopGet (left, 0, FALSE, FALSE, NULL);
9951       MOVA (l);
9952       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9953       emitLabel (tlbl);
9954       emitcode ("mov", "c,ov");
9955       emitcode ("rrc", "a");
9956       emitLabel (tlbl1);
9957       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9958       popB (pushedB);
9959       aopPut (result, "a", 0);
9960       goto release;
9961     }
9962
9963   reAdjustPreg (AOP (result));
9964   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9965   emitLabel (tlbl);
9966   emitcode ("mov", "c,ov");
9967   _startLazyDPSEvaluation ();
9968   while (size--)
9969     {
9970       l = aopGet (result, offset, FALSE, FALSE, NULL);
9971       MOVA (l);
9972       emitcode ("rrc", "a");
9973       aopPut (result, "a", offset--);
9974     }
9975   _endLazyDPSEvaluation ();
9976   reAdjustPreg (AOP (result));
9977   emitLabel (tlbl1);
9978   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9979   popB (pushedB);
9980
9981 release:
9982   freeAsmop (result, NULL, ic, TRUE);
9983   freeAsmop (left, NULL, ic, TRUE);
9984 }
9985
9986 /*-----------------------------------------------------------------*/
9987 /* genRightShift - generate code for right shifting                */
9988 /*-----------------------------------------------------------------*/
9989 static void
9990 genRightShift (iCode * ic)
9991 {
9992   operand *right, *left, *result;
9993   sym_link *letype;
9994   int size, offset;
9995   char *l;
9996   symbol *tlbl, *tlbl1;
9997   bool pushedB;
9998
9999   D (emitcode (";", "genRightShift"));
10000
10001   /* if signed then we do it the hard way preserve the
10002      sign bit moving it inwards */
10003   letype = getSpec (operandType (IC_LEFT (ic)));
10004
10005   if (!SPEC_USIGN (letype))
10006     {
10007       genSignedRightShift (ic);
10008       return;
10009     }
10010
10011   /* signed & unsigned types are treated the same : i.e. the
10012      signed is NOT propagated inwards : quoting from the
10013      ANSI - standard : "for E1 >> E2, is equivalent to division
10014      by 2**E2 if unsigned or if it has a non-negative value,
10015      otherwise the result is implementation defined ", MY definition
10016      is that the sign does not get propagated */
10017
10018   right = IC_RIGHT (ic);
10019   left = IC_LEFT (ic);
10020   result = IC_RESULT (ic);
10021
10022   aopOp (right, ic, FALSE, FALSE);
10023
10024 #ifdef BETTER_LITERAL_SHIFT
10025   /* if the shift count is known then do it
10026      as efficiently as possible */
10027   if (AOP_TYPE (right) == AOP_LIT)
10028     {
10029       if (genRightShiftLiteral (left, right, result, ic, 0))
10030       {
10031         return;
10032       }
10033     }
10034 #endif
10035
10036   /* shift count is unknown then we have to form
10037      a loop get the loop count in B : Note: we take
10038      only the lower order byte since shifting
10039      more that 32 bits make no sense anyway, ( the
10040      largest size of an object can be only 32 bits ) */
10041
10042   pushedB = pushB ();
10043   if (AOP_TYPE (right) == AOP_LIT)
10044   {
10045       /* Really should be handled by genRightShiftLiteral,
10046        * but since I'm too lazy to fix that today, at least we can make
10047        * some small improvement.
10048        */
10049        emitcode("mov", "b,#!constbyte",
10050                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10051   }
10052   else
10053   {
10054       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10055       emitcode ("inc", "b");
10056   }
10057   freeAsmop (right, NULL, ic, TRUE);
10058   aopOp (left, ic, FALSE, FALSE);
10059   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10060
10061   /* now move the left to the result if they are not the
10062      same */
10063   if (!sameRegs (AOP (left), AOP (result)) &&
10064       AOP_SIZE (result) > 1)
10065     {
10066       size = AOP_SIZE (result);
10067       offset = 0;
10068       _startLazyDPSEvaluation ();
10069       while (size--)
10070         {
10071           l = aopGet (left, offset, FALSE, TRUE, NULL);
10072           if (*l == '@' && IS_AOP_PREG (result))
10073             {
10074
10075               emitcode ("mov", "a,%s", l);
10076               aopPut (result, "a", offset);
10077             }
10078           else
10079             aopPut (result, l, offset);
10080           offset++;
10081         }
10082       _endLazyDPSEvaluation ();
10083     }
10084
10085   tlbl = newiTempLabel (NULL);
10086   tlbl1 = newiTempLabel (NULL);
10087   size = AOP_SIZE (result);
10088   offset = size - 1;
10089
10090   /* if it is only one byte then */
10091   if (size == 1)
10092     {
10093       l = aopGet (left, 0, FALSE, FALSE, NULL);
10094       MOVA (l);
10095       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10096       emitLabel (tlbl);
10097       CLRC;
10098       emitcode ("rrc", "a");
10099       emitLabel (tlbl1);
10100       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10101       popB (pushedB);
10102       aopPut (result, "a", 0);
10103       goto release;
10104     }
10105
10106   reAdjustPreg (AOP (result));
10107   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10108   emitLabel (tlbl);
10109   CLRC;
10110   _startLazyDPSEvaluation ();
10111   while (size--)
10112     {
10113       l = aopGet (result, offset, FALSE, FALSE, NULL);
10114       MOVA (l);
10115       emitcode ("rrc", "a");
10116       aopPut (result, "a", offset--);
10117     }
10118   _endLazyDPSEvaluation ();
10119   reAdjustPreg (AOP (result));
10120
10121   emitLabel (tlbl1);
10122   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10123   popB (pushedB);
10124
10125 release:
10126   freeAsmop (result, NULL, ic, TRUE);
10127   freeAsmop (left, NULL, ic, TRUE);
10128 }
10129
10130 /*-----------------------------------------------------------------*/
10131 /* emitPtrByteGet - emits code to get a byte into A through a      */
10132 /*                  pointer register (R0, R1, or DPTR). The        */
10133 /*                  original value of A can be preserved in B.     */
10134 /*-----------------------------------------------------------------*/
10135 static void
10136 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10137 {
10138   switch (p_type)
10139     {
10140     case IPOINTER:
10141     case POINTER:
10142       if (preserveAinB)
10143         emitcode ("mov", "b,a");
10144       emitcode ("mov", "a,@%s", rname);
10145       break;
10146
10147     case PPOINTER:
10148       if (preserveAinB)
10149         emitcode ("mov", "b,a");
10150       emitcode ("movx", "a,@%s", rname);
10151       break;
10152
10153     case FPOINTER:
10154       if (preserveAinB)
10155         emitcode ("mov", "b,a");
10156       emitcode ("movx", "a,@dptr");
10157       break;
10158
10159     case CPOINTER:
10160       if (preserveAinB)
10161         emitcode ("mov", "b,a");
10162       emitcode ("clr", "a");
10163       emitcode ("movc", "a,@a+dptr");
10164       break;
10165
10166     case GPOINTER:
10167       if (preserveAinB)
10168         {
10169           emitcode ("push", "b");
10170           emitcode ("push", "acc");
10171         }
10172       emitcode ("lcall", "__gptrget");
10173       if (preserveAinB)
10174         emitcode ("pop", "b");
10175       break;
10176     }
10177 }
10178
10179 /*-----------------------------------------------------------------*/
10180 /* emitPtrByteSet - emits code to set a byte from src through a    */
10181 /*                  pointer register (R0, R1, or DPTR).            */
10182 /*-----------------------------------------------------------------*/
10183 static void
10184 emitPtrByteSet (char *rname, int p_type, char *src)
10185 {
10186   switch (p_type)
10187     {
10188     case IPOINTER:
10189     case POINTER:
10190       if (*src=='@')
10191         {
10192           MOVA (src);
10193           emitcode ("mov", "@%s,a", rname);
10194         }
10195       else
10196         emitcode ("mov", "@%s,%s", rname, src);
10197       break;
10198
10199     case PPOINTER:
10200       MOVA (src);
10201       emitcode ("movx", "@%s,a", rname);
10202       break;
10203
10204     case FPOINTER:
10205       MOVA (src);
10206       emitcode ("movx", "@dptr,a");
10207       break;
10208
10209     case GPOINTER:
10210       MOVA (src);
10211       emitcode ("lcall", "__gptrput");
10212       break;
10213     }
10214 }
10215
10216 /*-----------------------------------------------------------------*/
10217 /* genUnpackBits - generates code for unpacking bits               */
10218 /*-----------------------------------------------------------------*/
10219 static void
10220 genUnpackBits (operand * result, char *rname, int ptype)
10221 {
10222   int offset = 0;       /* result byte offset */
10223   int rsize;            /* result size */
10224   int rlen = 0;         /* remaining bitfield length */
10225   sym_link *etype;      /* bitfield type information */
10226   int blen;             /* bitfield length */
10227   int bstr;             /* bitfield starting bit within byte */
10228
10229   D(emitcode (";     genUnpackBits",""));
10230
10231   etype = getSpec (operandType (result));
10232   rsize = getSize (operandType (result));
10233   blen = SPEC_BLEN (etype);
10234   bstr = SPEC_BSTR (etype);
10235
10236   /* If the bitfield length is less than a byte */
10237   if (blen < 8)
10238     {
10239       emitPtrByteGet (rname, ptype, FALSE);
10240       AccRol (8 - bstr);
10241       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10242       if (!SPEC_USIGN (etype))
10243         {
10244           /* signed bitfield */
10245           symbol *tlbl = newiTempLabel (NULL);
10246
10247           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10248           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10249           emitLabel (tlbl);
10250         }
10251       aopPut (result, "a", offset++);
10252       goto finish;
10253     }
10254
10255   /* Bit field did not fit in a byte. Copy all
10256      but the partial byte at the end.  */
10257   for (rlen=blen;rlen>=8;rlen-=8)
10258     {
10259       emitPtrByteGet (rname, ptype, FALSE);
10260       aopPut (result, "a", offset++);
10261       if (rlen>8)
10262         emitcode ("inc", "%s", rname);
10263     }
10264
10265   /* Handle the partial byte at the end */
10266   if (rlen)
10267     {
10268       emitPtrByteGet (rname, ptype, FALSE);
10269       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10270       if (!SPEC_USIGN (etype))
10271         {
10272           /* signed bitfield */
10273           symbol *tlbl = newiTempLabel (NULL);
10274
10275           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10276           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10277           emitLabel (tlbl);
10278         }
10279       aopPut (result, "a", offset++);
10280     }
10281
10282 finish:
10283   if (offset < rsize)
10284     {
10285       char *source;
10286
10287       if (SPEC_USIGN (etype))
10288         source = zero;
10289       else
10290         {
10291           /* signed bitfield: sign extension with 0x00 or 0xff */
10292           emitcode ("rlc", "a");
10293           emitcode ("subb", "a,acc");
10294
10295           source = "a";
10296         }
10297       rsize -= offset;
10298       while (rsize--)
10299         aopPut (result, source, offset++);
10300     }
10301 }
10302
10303
10304 /*-----------------------------------------------------------------*/
10305 /* genDataPointerGet - generates code when ptr offset is known     */
10306 /*-----------------------------------------------------------------*/
10307 static void
10308 genDataPointerGet (operand * left,
10309                    operand * result,
10310                    iCode * ic)
10311 {
10312   char *l;
10313   char buffer[256];
10314   int size, offset = 0;
10315   aopOp (result, ic, TRUE, FALSE);
10316
10317   /* get the string representation of the name */
10318   l = aopGet (left, 0, FALSE, TRUE, NULL);
10319   size = AOP_SIZE (result);
10320   _startLazyDPSEvaluation ();
10321   while (size--)
10322     {
10323         if (offset)
10324         {
10325             SNPRINTF (buffer, sizeof(buffer),
10326                       "(%s + %d)", l + 1, offset);
10327         }
10328         else
10329         {
10330             SNPRINTF (buffer, sizeof(buffer),
10331                       "%s", l + 1);
10332         }
10333       aopPut (result, buffer, offset++);
10334     }
10335   _endLazyDPSEvaluation ();
10336
10337   freeAsmop (result, NULL, ic, TRUE);
10338   freeAsmop (left, NULL, ic, TRUE);
10339 }
10340
10341 /*-----------------------------------------------------------------*/
10342 /* genNearPointerGet - emitcode for near pointer fetch             */
10343 /*-----------------------------------------------------------------*/
10344 static void
10345 genNearPointerGet (operand * left,
10346                    operand * result,
10347                    iCode * ic,
10348                    iCode *pi)
10349 {
10350   asmop *aop = NULL;
10351   regs *preg;
10352   char *rname;
10353   sym_link *rtype, *retype, *letype;
10354   sym_link *ltype = operandType (left);
10355   char buffer[80];
10356
10357   rtype = operandType (result);
10358   retype = getSpec (rtype);
10359   letype = getSpec (ltype);
10360
10361   aopOp (left, ic, FALSE, FALSE);
10362
10363   /* if left is rematerialisable and
10364      result is not bitfield variable type and
10365      the left is pointer to data space i.e
10366      lower 128 bytes of space */
10367   if (AOP_TYPE (left) == AOP_IMMD &&
10368       !IS_BITFIELD (retype) &&
10369       !IS_BITFIELD (letype) &&
10370       DCL_TYPE (ltype) == POINTER)
10371     {
10372       genDataPointerGet (left, result, ic);
10373       return;
10374     }
10375
10376   /* if the value is already in a pointer register
10377      then don't need anything more */
10378   if (!AOP_INPREG (AOP (left)))
10379     {
10380       /* otherwise get a free pointer register */
10381       aop = newAsmop (0);
10382       preg = getFreePtr (ic, &aop, FALSE);
10383       emitcode ("mov", "%s,%s",
10384                 preg->name,
10385                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10386       rname = preg->name;
10387     }
10388   else
10389     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10390
10391   freeAsmop (left, NULL, ic, TRUE);
10392   aopOp (result, ic, FALSE, FALSE);
10393
10394   /* if bitfield then unpack the bits */
10395   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10396     genUnpackBits (result, rname, POINTER);
10397   else
10398     {
10399       /* we have can just get the values */
10400       int size = AOP_SIZE (result);
10401       int offset = 0;
10402
10403       while (size--)
10404         {
10405           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10406             {
10407
10408               emitcode ("mov", "a,@%s", rname);
10409               aopPut (result, "a", offset);
10410             }
10411           else
10412             {
10413               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10414               aopPut (result, buffer, offset);
10415             }
10416           offset++;
10417           if (size || pi)
10418                 emitcode ("inc", "%s", rname);
10419             }
10420         }
10421
10422   /* now some housekeeping stuff */
10423   if (aop)      /* we had to allocate for this iCode */
10424     {
10425       if (pi) { /* post increment present */
10426         aopPut (left, rname, 0);
10427       }
10428       freeAsmop (NULL, aop, ic, TRUE);
10429     }
10430   else
10431     {
10432       /* we did not allocate which means left
10433          already in a pointer register, then
10434          if size > 0 && this could be used again
10435          we have to point it back to where it
10436          belongs */
10437       if (AOP_SIZE (result) > 1 &&
10438           !OP_SYMBOL (left)->remat &&
10439           (OP_SYMBOL (left)->liveTo > ic->seq ||
10440            ic->depth) &&
10441           !pi)
10442         {
10443           int size = AOP_SIZE (result) - 1;
10444           while (size--)
10445             emitcode ("dec", "%s", rname);
10446         }
10447     }
10448
10449   /* done */
10450   freeAsmop (result, NULL, ic, TRUE);
10451   if (pi) pi->generated = 1;
10452 }
10453
10454 /*-----------------------------------------------------------------*/
10455 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10456 /*-----------------------------------------------------------------*/
10457 static void
10458 genPagedPointerGet (operand * left,
10459                     operand * result,
10460                     iCode * ic,
10461                     iCode * pi)
10462 {
10463   asmop *aop = NULL;
10464   regs *preg;
10465   char *rname;
10466   sym_link *rtype, *retype, *letype;
10467
10468   rtype = operandType (result);
10469   retype = getSpec (rtype);
10470   letype = getSpec (operandType (left));
10471   aopOp (left, ic, FALSE, FALSE);
10472
10473   /* if the value is already in a pointer register
10474      then don't need anything more */
10475   if (!AOP_INPREG (AOP (left)))
10476     {
10477       /* otherwise get a free pointer register */
10478       aop = newAsmop (0);
10479       preg = getFreePtr (ic, &aop, FALSE);
10480       emitcode ("mov", "%s,%s",
10481                 preg->name,
10482                 aopGet (left, 0, FALSE, TRUE, NULL));
10483       rname = preg->name;
10484     }
10485   else
10486     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10487
10488   freeAsmop (left, NULL, ic, TRUE);
10489   aopOp (result, ic, FALSE, FALSE);
10490
10491   /* if bitfield then unpack the bits */
10492   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10493     genUnpackBits (result, rname, PPOINTER);
10494   else
10495     {
10496       /* we have can just get the values */
10497       int size = AOP_SIZE (result);
10498       int offset = 0;
10499
10500       while (size--)
10501         {
10502
10503           emitcode ("movx", "a,@%s", rname);
10504           aopPut (result, "a", offset);
10505
10506           offset++;
10507
10508           if (size || pi)
10509             emitcode ("inc", "%s", rname);
10510         }
10511     }
10512
10513   /* now some housekeeping stuff */
10514   if (aop)      /* we had to allocate for this iCode */
10515     {
10516       if (pi)
10517         aopPut (left, rname, 0);
10518       freeAsmop (NULL, aop, ic, TRUE);
10519     }
10520   else
10521     {
10522       /* we did not allocate which means left
10523          already in a pointer register, then
10524          if size > 0 && this could be used again
10525          we have to point it back to where it
10526          belongs */
10527       if (AOP_SIZE (result) > 1 &&
10528           !OP_SYMBOL (left)->remat &&
10529           (OP_SYMBOL (left)->liveTo > ic->seq ||
10530            ic->depth) &&
10531           !pi)
10532         {
10533           int size = AOP_SIZE (result) - 1;
10534           while (size--)
10535             emitcode ("dec", "%s", rname);
10536         }
10537     }
10538
10539   /* done */
10540   freeAsmop (result, NULL, ic, TRUE);
10541   if (pi) pi->generated = 1;
10542 }
10543
10544 /*-----------------------------------------------------------------*/
10545 /* genFarPointerGet - get value from far space                     */
10546 /*-----------------------------------------------------------------*/
10547 static void
10548 genFarPointerGet (operand * left,
10549                   operand * result, iCode * ic, iCode *pi)
10550 {
10551     int size, offset, dopi=1;
10552   sym_link *retype = getSpec (operandType (result));
10553   sym_link *letype = getSpec (operandType (left));
10554   D (emitcode (";", "genFarPointerGet"););
10555
10556   aopOp (left, ic, FALSE, FALSE);
10557
10558   /* if the operand is already in dptr
10559      then we do nothing else we move the value to dptr */
10560   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10561     {
10562       /* if this is rematerializable */
10563       if (AOP_TYPE (left) == AOP_IMMD)
10564         {
10565           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10566         }
10567       else
10568         {
10569           /* we need to get it byte by byte */
10570           _startLazyDPSEvaluation ();
10571           if (AOP_TYPE (left) != AOP_DPTR)
10572             {
10573               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10574               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10575               if (options.model == MODEL_FLAT24)
10576                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10577             }
10578           else
10579             {
10580               /* We need to generate a load to DPTR indirect through DPTR. */
10581               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10582               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10583               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10584               if (options.model == MODEL_FLAT24)
10585                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10586               emitcode ("pop", "dph");
10587               emitcode ("pop", "dpl");
10588               dopi =0;
10589             }
10590           _endLazyDPSEvaluation ();
10591         }
10592     }
10593   /* so dptr now contains the address */
10594   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10595
10596   /* if bit then unpack */
10597   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10598       if (AOP_INDPTRn(left)) {
10599           genSetDPTR(AOP(left)->aopu.dptr);
10600       }
10601       genUnpackBits (result, "dptr", FPOINTER);
10602       if (AOP_INDPTRn(left)) {
10603           genSetDPTR(0);
10604       }
10605   } else
10606     {
10607       size = AOP_SIZE (result);
10608       offset = 0;
10609
10610       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10611           while (size--) {
10612               genSetDPTR(AOP(left)->aopu.dptr);
10613               emitcode ("movx", "a,@dptr");
10614               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10615                   emitcode ("inc", "dptr");
10616               genSetDPTR (0);
10617               aopPut (result, "a", offset++);
10618           }
10619       } else {
10620           _startLazyDPSEvaluation ();
10621           while (size--) {
10622               if (AOP_INDPTRn(left)) {
10623                   genSetDPTR(AOP(left)->aopu.dptr);
10624               } else {
10625                   genSetDPTR (0);
10626               }
10627               _flushLazyDPS ();
10628
10629               emitcode ("movx", "a,@dptr");
10630               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10631                   emitcode ("inc", "dptr");
10632
10633               aopPut (result, "a", offset++);
10634           }
10635           _endLazyDPSEvaluation ();
10636       }
10637     }
10638   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10639       if (!AOP_INDPTRn(left)) {
10640           _startLazyDPSEvaluation ();
10641           aopPut (left, "dpl", 0);
10642           aopPut (left, "dph", 1);
10643           if (options.model == MODEL_FLAT24)
10644               aopPut (left, "dpx", 2);
10645           _endLazyDPSEvaluation ();
10646       }
10647     pi->generated = 1;
10648   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10649              AOP_SIZE(result) > 1 &&
10650              IS_SYMOP(left) &&
10651              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10652
10653       size = AOP_SIZE (result) - 1;
10654       if (AOP_INDPTRn(left)) {
10655           genSetDPTR(AOP(left)->aopu.dptr);
10656       }
10657       while (size--) emitcode ("lcall","__decdptr");
10658       if (AOP_INDPTRn(left)) {
10659           genSetDPTR(0);
10660       }
10661   }
10662
10663   freeAsmop (result, NULL, ic, TRUE);
10664   freeAsmop (left, NULL, ic, TRUE);
10665 }
10666
10667 /*-----------------------------------------------------------------*/
10668 /* genCodePointerGet - get value from code space                  */
10669 /*-----------------------------------------------------------------*/
10670 static void
10671 genCodePointerGet (operand * left,
10672                     operand * result, iCode * ic, iCode *pi)
10673 {
10674   int size, offset, dopi=1;
10675   sym_link *retype = getSpec (operandType (result));
10676
10677   aopOp (left, ic, FALSE, FALSE);
10678
10679   /* if the operand is already in dptr
10680      then we do nothing else we move the value to dptr */
10681   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10682     {
10683       /* if this is rematerializable */
10684       if (AOP_TYPE (left) == AOP_IMMD)
10685         {
10686           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10687         }
10688       else
10689         {                       /* we need to get it byte by byte */
10690           _startLazyDPSEvaluation ();
10691           if (AOP_TYPE (left) != AOP_DPTR)
10692             {
10693               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10694               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10695               if (options.model == MODEL_FLAT24)
10696                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10697             }
10698           else
10699             {
10700               /* We need to generate a load to DPTR indirect through DPTR. */
10701               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10702               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10703               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10704               if (options.model == MODEL_FLAT24)
10705                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10706               emitcode ("pop", "dph");
10707               emitcode ("pop", "dpl");
10708               dopi=0;
10709             }
10710           _endLazyDPSEvaluation ();
10711         }
10712     }
10713   /* so dptr now contains the address */
10714   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10715
10716   /* if bit then unpack */
10717   if (IS_BITFIELD (retype)) {
10718       if (AOP_INDPTRn(left)) {
10719           genSetDPTR(AOP(left)->aopu.dptr);
10720       }
10721       genUnpackBits (result, "dptr", CPOINTER);
10722       if (AOP_INDPTRn(left)) {
10723           genSetDPTR(0);
10724       }
10725   } else
10726     {
10727       size = AOP_SIZE (result);
10728       offset = 0;
10729       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10730           while (size--) {
10731               genSetDPTR(AOP(left)->aopu.dptr);
10732               emitcode ("clr", "a");
10733               emitcode ("movc", "a,@a+dptr");
10734               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10735                   emitcode ("inc", "dptr");
10736               genSetDPTR (0);
10737               aopPut (result, "a", offset++);
10738           }
10739       } else {
10740           _startLazyDPSEvaluation ();
10741           while (size--)
10742               {
10743                   if (AOP_INDPTRn(left)) {
10744                       genSetDPTR(AOP(left)->aopu.dptr);
10745                   } else {
10746                       genSetDPTR (0);
10747                   }
10748                   _flushLazyDPS ();
10749
10750                   emitcode ("clr", "a");
10751                   emitcode ("movc", "a,@a+dptr");
10752                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10753                       emitcode ("inc", "dptr");
10754                   aopPut (result, "a", offset++);
10755               }
10756           _endLazyDPSEvaluation ();
10757       }
10758     }
10759   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10760       if (!AOP_INDPTRn(left)) {
10761           _startLazyDPSEvaluation ();
10762
10763           aopPut (left, "dpl", 0);
10764           aopPut (left, "dph", 1);
10765           if (options.model == MODEL_FLAT24)
10766               aopPut (left, "dpx", 2);
10767
10768           _endLazyDPSEvaluation ();
10769       }
10770       pi->generated = 1;
10771   } else if ((OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10772              AOP_SIZE(result) > 1 &&
10773              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10774
10775       size = AOP_SIZE (result) - 1;
10776       if (AOP_INDPTRn(left)) {
10777           genSetDPTR(AOP(left)->aopu.dptr);
10778       }
10779       while (size--) emitcode ("lcall","__decdptr");
10780       if (AOP_INDPTRn(left)) {
10781           genSetDPTR(0);
10782       }
10783   }
10784
10785   freeAsmop (result, NULL, ic, TRUE);
10786   freeAsmop (left, NULL, ic, TRUE);
10787 }
10788
10789 /*-----------------------------------------------------------------*/
10790 /* genGenPointerGet - get value from generic pointer space         */
10791 /*-----------------------------------------------------------------*/
10792 static void
10793 genGenPointerGet (operand * left,
10794                   operand * result, iCode * ic, iCode * pi)
10795 {
10796   int size, offset;
10797   bool pushedB;
10798   sym_link *retype = getSpec (operandType (result));
10799   sym_link *letype = getSpec (operandType (left));
10800
10801   D (emitcode (";", "genGenPointerGet"));
10802
10803   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10804
10805   pushedB = pushB ();
10806   /* if the operand is already in dptr
10807      then we do nothing else we move the value to dptr */
10808   if (AOP_TYPE (left) != AOP_STR)
10809     {
10810       /* if this is rematerializable */
10811       if (AOP_TYPE (left) == AOP_IMMD)
10812         {
10813           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10814           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10815             {
10816               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10817             }
10818           else
10819             {
10820               emitcode ("mov", "b,#%d", pointerCode (retype));
10821             }
10822         }
10823       else
10824         {                       /* we need to get it byte by byte */
10825           _startLazyDPSEvaluation ();
10826           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10827           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10828           if (options.model == MODEL_FLAT24) {
10829               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10830               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10831           } else {
10832               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10833           }
10834           _endLazyDPSEvaluation ();
10835         }
10836     }
10837
10838   /* so dptr-b now contains the address */
10839   aopOp (result, ic, FALSE, TRUE);
10840
10841   /* if bit then unpack */
10842   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10843   {
10844     genUnpackBits (result, "dptr", GPOINTER);
10845   }
10846   else
10847     {
10848         size = AOP_SIZE (result);
10849         offset = 0;
10850
10851         while (size--)
10852         {
10853             if (size)
10854             {
10855                 // Get two bytes at a time, results in _AP & A.
10856                 // dptr will be incremented ONCE by __gptrgetWord.
10857                 //
10858                 // Note: any change here must be coordinated
10859                 // with the implementation of __gptrgetWord
10860                 // in device/lib/_gptrget.c
10861                 emitcode ("lcall", "__gptrgetWord");
10862                 aopPut (result, DP2_RESULT_REG, offset++);
10863                 aopPut (result, "a", offset++);
10864                 size--;
10865             }
10866             else
10867             {
10868                 // Only one byte to get.
10869                 emitcode ("lcall", "__gptrget");
10870                 aopPut (result, "a", offset++);
10871             }
10872
10873             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
10874             {
10875                 emitcode ("inc", "dptr");
10876             }
10877         }
10878     }
10879
10880   if (pi && AOP_TYPE (left) != AOP_IMMD) {
10881     _startLazyDPSEvaluation ();
10882
10883     aopPut (left, "dpl", 0);
10884     aopPut (left, "dph", 1);
10885     if (options.model == MODEL_FLAT24) {
10886         aopPut (left, "dpx", 2);
10887         aopPut (left, "b", 3);
10888     } else  aopPut (left, "b", 2);
10889
10890     _endLazyDPSEvaluation ();
10891
10892     pi->generated = 1;
10893   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
10894              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10895
10896       size = AOP_SIZE (result) - 1;
10897       while (size--) emitcode ("lcall","__decdptr");
10898   }
10899   popB (pushedB);
10900
10901   freeAsmop (result, NULL, ic, TRUE);
10902   freeAsmop (left, NULL, ic, TRUE);
10903 }
10904
10905 /*-----------------------------------------------------------------*/
10906 /* genPointerGet - generate code for pointer get                   */
10907 /*-----------------------------------------------------------------*/
10908 static void
10909 genPointerGet (iCode * ic, iCode *pi)
10910 {
10911   operand *left, *result;
10912   sym_link *type, *etype;
10913   int p_type;
10914
10915   D (emitcode (";", "genPointerGet"));
10916
10917   left = IC_LEFT (ic);
10918   result = IC_RESULT (ic);
10919
10920   /* depending on the type of pointer we need to
10921      move it to the correct pointer register */
10922   type = operandType (left);
10923   etype = getSpec (type);
10924   /* if left is of type of pointer then it is simple */
10925   if (IS_PTR (type) && !IS_FUNC (type->next))
10926     p_type = DCL_TYPE (type);
10927   else
10928     {
10929       /* we have to go by the storage class */
10930       p_type = PTR_TYPE (SPEC_OCLS (etype));
10931     }
10932
10933   /* special case when cast remat */
10934   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10935       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10936     {
10937       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10938       type = operandType (left);
10939       p_type = DCL_TYPE (type);
10940     }
10941   /* now that we have the pointer type we assign
10942      the pointer values */
10943   switch (p_type)
10944     {
10945
10946     case POINTER:
10947     case IPOINTER:
10948       genNearPointerGet (left, result, ic, pi);
10949       break;
10950
10951     case PPOINTER:
10952       genPagedPointerGet (left, result, ic, pi);
10953       break;
10954
10955     case FPOINTER:
10956       genFarPointerGet (left, result, ic, pi);
10957       break;
10958
10959     case CPOINTER:
10960       genCodePointerGet (left, result, ic, pi);
10961       break;
10962
10963     case GPOINTER:
10964       genGenPointerGet (left, result, ic, pi);
10965       break;
10966     }
10967 }
10968
10969
10970 /*-----------------------------------------------------------------*/
10971 /* genPackBits - generates code for packed bit storage             */
10972 /*-----------------------------------------------------------------*/
10973 static void
10974 genPackBits (sym_link * etype,
10975              operand * right,
10976              char *rname, int p_type)
10977 {
10978   int offset = 0;       /* source byte offset */
10979   int rlen = 0;         /* remaining bitfield length */
10980   int blen;             /* bitfield length */
10981   int bstr;             /* bitfield starting bit within byte */
10982   int litval;           /* source literal value (if AOP_LIT) */
10983   unsigned char mask;   /* bitmask within current byte */
10984
10985   D(emitcode (";     genPackBits",""));
10986
10987   blen = SPEC_BLEN (etype);
10988   bstr = SPEC_BSTR (etype);
10989
10990   /* If the bitfield length is less than a byte */
10991   if (blen < 8)
10992     {
10993       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10994               (unsigned char) (0xFF >> (8 - bstr)));
10995
10996       if (AOP_TYPE (right) == AOP_LIT)
10997         {
10998           /* Case with a bitfield length <8 and literal source
10999           */
11000           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11001           litval <<= bstr;
11002           litval &= (~mask) & 0xff;
11003           emitPtrByteGet (rname, p_type, FALSE);
11004           if ((mask|litval)!=0xff)
11005             emitcode ("anl","a,#!constbyte", mask);
11006           if (litval)
11007             emitcode ("orl","a,#!constbyte", litval);
11008         }
11009       else
11010         {
11011           if ((blen==1) && (p_type!=GPOINTER))
11012             {
11013               /* Case with a bitfield length == 1 and no generic pointer
11014               */
11015               if (AOP_TYPE (right) == AOP_CRY)
11016                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11017               else
11018                 {
11019                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11020                   emitcode ("rrc","a");
11021                 }
11022               emitPtrByteGet (rname, p_type, FALSE);
11023               emitcode ("mov","acc.%d,c",bstr);
11024             }
11025           else
11026             {
11027               bool pushedB;
11028               /* Case with a bitfield length < 8 and arbitrary source
11029               */
11030               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11031               /* shift and mask source value */
11032               AccLsh (bstr);
11033               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11034
11035               pushedB = pushB ();
11036               /* transfer A to B and get next byte */
11037               emitPtrByteGet (rname, p_type, TRUE);
11038
11039               emitcode ("anl", "a,#!constbyte", mask);
11040               emitcode ("orl", "a,b");
11041               if (p_type == GPOINTER)
11042                 emitcode ("pop", "b");
11043
11044               popB (pushedB);
11045            }
11046         }
11047
11048       emitPtrByteSet (rname, p_type, "a");
11049       return;
11050     }
11051
11052   /* Bit length is greater than 7 bits. In this case, copy  */
11053   /* all except the partial byte at the end                 */
11054   for (rlen=blen;rlen>=8;rlen-=8)
11055     {
11056       emitPtrByteSet (rname, p_type,
11057                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11058       if (rlen>8)
11059         emitcode ("inc", "%s", rname);
11060     }
11061
11062   /* If there was a partial byte at the end */
11063   if (rlen)
11064     {
11065       mask = (((unsigned char) -1 << rlen) & 0xff);
11066
11067       if (AOP_TYPE (right) == AOP_LIT)
11068         {
11069           /* Case with partial byte and literal source
11070           */
11071           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11072           litval >>= (blen-rlen);
11073           litval &= (~mask) & 0xff;
11074           emitPtrByteGet (rname, p_type, FALSE);
11075           if ((mask|litval)!=0xff)
11076             emitcode ("anl","a,#!constbyte", mask);
11077           if (litval)
11078             emitcode ("orl","a,#!constbyte", litval);
11079         }
11080       else
11081         {
11082           bool pushedB;
11083           /* Case with partial byte and arbitrary source
11084           */
11085           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11086           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11087
11088           pushedB = pushB ();
11089           /* transfer A to B and get next byte */
11090           emitPtrByteGet (rname, p_type, TRUE);
11091
11092           emitcode ("anl", "a,#!constbyte", mask);
11093           emitcode ("orl", "a,b");
11094           if (p_type == GPOINTER)
11095             emitcode ("pop", "b");
11096
11097           popB (pushedB);
11098         }
11099       emitPtrByteSet (rname, p_type, "a");
11100     }
11101 }
11102
11103
11104 /*-----------------------------------------------------------------*/
11105 /* genDataPointerSet - remat pointer to data space                 */
11106 /*-----------------------------------------------------------------*/
11107 static void
11108 genDataPointerSet (operand * right,
11109                    operand * result,
11110                    iCode * ic)
11111 {
11112   int size, offset = 0;
11113   char *l, buffer[256];
11114
11115   D (emitcode (";", "genDataPointerSet"));
11116
11117   aopOp (right, ic, FALSE, FALSE);
11118
11119   l = aopGet (result, 0, FALSE, TRUE, NULL);
11120   size = AOP_SIZE (right);
11121   while (size--)
11122     {
11123       if (offset)
11124           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11125       else
11126           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11127       emitcode ("mov", "%s,%s", buffer,
11128                 aopGet (right, offset++, FALSE, FALSE, NULL));
11129     }
11130
11131   freeAsmop (result, NULL, ic, TRUE);
11132   freeAsmop (right, NULL, ic, TRUE);
11133 }
11134
11135 /*-----------------------------------------------------------------*/
11136 /* genNearPointerSet - emitcode for near pointer put                */
11137 /*-----------------------------------------------------------------*/
11138 static void
11139 genNearPointerSet (operand * right,
11140                    operand * result,
11141                    iCode * ic,
11142                    iCode * pi)
11143 {
11144   asmop *aop = NULL;
11145   char *rname, *l;
11146   sym_link *retype, *letype;
11147   sym_link *ptype = operandType (result);
11148
11149   D (emitcode (";", "genNearPointerSet"));
11150
11151   retype = getSpec (operandType (right));
11152   letype = getSpec (ptype);
11153
11154   aopOp (result, ic, FALSE, FALSE);
11155
11156   /* if the result is rematerializable &
11157      in data space & not a bit variable */
11158   if (AOP_TYPE (result) == AOP_IMMD &&
11159       DCL_TYPE (ptype) == POINTER &&
11160       !IS_BITVAR (retype) &&
11161       !IS_BITVAR (letype))
11162     {
11163       genDataPointerSet (right, result, ic);
11164       return;
11165     }
11166
11167   /* if the value is already in a pointer register
11168      then don't need anything more */
11169   if (!AOP_INPREG (AOP (result)))
11170     {
11171       /* otherwise get a free pointer register */
11172       regs *preg;
11173
11174       aop = newAsmop (0);
11175       preg = getFreePtr (ic, &aop, FALSE);
11176       emitcode ("mov", "%s,%s",
11177                 preg->name,
11178                 aopGet (result, 0, FALSE, TRUE, NULL));
11179       rname = preg->name;
11180     }
11181   else
11182     {
11183       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11184     }
11185
11186   aopOp (right, ic, FALSE, FALSE);
11187
11188   /* if bitfield then unpack the bits */
11189   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11190     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11191   else
11192     {
11193       /* we can just get the values */
11194       int size = AOP_SIZE (right);
11195       int offset = 0;
11196
11197       while (size--)
11198         {
11199           l = aopGet (right, offset, FALSE, TRUE, NULL);
11200           if ((*l == '@') || (strcmp (l, "acc") == 0))
11201             {
11202               MOVA (l);
11203               emitcode ("mov", "@%s,a", rname);
11204             }
11205           else
11206             emitcode ("mov", "@%s,%s", rname, l);
11207           if (size || pi)
11208             emitcode ("inc", "%s", rname);
11209           offset++;
11210         }
11211     }
11212
11213   /* now some housekeeping stuff */
11214   if (aop)      /* we had to allocate for this iCode */
11215     {
11216       if (pi)
11217         aopPut (result, rname, 0);
11218       freeAsmop (NULL, aop, ic, TRUE);
11219     }
11220   else
11221     {
11222       /* we did not allocate which means left
11223          already in a pointer register, then
11224          if size > 0 && this could be used again
11225          we have to point it back to where it
11226          belongs */
11227       if (AOP_SIZE (right) > 1 &&
11228           !OP_SYMBOL (result)->remat &&
11229           (OP_SYMBOL (result)->liveTo > ic->seq ||
11230            ic->depth) &&
11231           !pi)
11232         {
11233           int size = AOP_SIZE (right) - 1;
11234           while (size--)
11235             emitcode ("dec", "%s", rname);
11236         }
11237     }
11238
11239   /* done */
11240   if (pi) pi->generated = 1;
11241   freeAsmop (result, NULL, ic, TRUE);
11242   freeAsmop (right, NULL, ic, TRUE);
11243 }
11244
11245 /*-----------------------------------------------------------------*/
11246 /* genPagedPointerSet - emitcode for Paged pointer put             */
11247 /*-----------------------------------------------------------------*/
11248 static void
11249 genPagedPointerSet (operand * right,
11250                     operand * result,
11251                     iCode * ic,
11252                     iCode *pi)
11253 {
11254   asmop *aop = NULL;
11255   char *rname, *l;
11256   sym_link *retype, *letype;
11257
11258   D (emitcode (";", "genPagedPointerSet"));
11259
11260   retype = getSpec (operandType (right));
11261   letype = getSpec (operandType (result));
11262
11263   aopOp (result, ic, FALSE, FALSE);
11264
11265   /* if the value is already in a pointer register
11266      then don't need anything more */
11267   if (!AOP_INPREG (AOP (result)))
11268     {
11269       /* otherwise get a free pointer register */
11270       regs *preg;
11271
11272       aop = newAsmop (0);
11273       preg = getFreePtr (ic, &aop, FALSE);
11274       emitcode ("mov", "%s,%s",
11275                 preg->name,
11276                 aopGet (result, 0, FALSE, TRUE, NULL));
11277       rname = preg->name;
11278     }
11279   else
11280     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11281
11282   aopOp (right, ic, FALSE, FALSE);
11283
11284   /* if bitfield then unpack the bits */
11285   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11286     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11287   else
11288     {
11289       /* we have can just get the values */
11290       int size = AOP_SIZE (right);
11291       int offset = 0;
11292
11293       while (size--)
11294         {
11295           l = aopGet (right, offset, FALSE, TRUE, NULL);
11296           MOVA (l);
11297           emitcode ("movx", "@%s,a", rname);
11298
11299           if (size || pi)
11300             emitcode ("inc", "%s", rname);
11301
11302           offset++;
11303         }
11304     }
11305
11306   /* now some housekeeping stuff */
11307   if (aop)
11308     {
11309       if (pi)
11310         aopPut (result, rname, 0);
11311       /* we had to allocate for this iCode */
11312       freeAsmop (NULL, aop, ic, TRUE);
11313     }
11314   else
11315     {
11316       /* we did not allocate which means left
11317          already in a pointer register, then
11318          if size > 0 && this could be used again
11319          we have to point it back to where it
11320          belongs */
11321       if (AOP_SIZE (right) > 1 &&
11322           !OP_SYMBOL (result)->remat &&
11323           (OP_SYMBOL (result)->liveTo > ic->seq ||
11324            ic->depth) &&
11325           !pi)
11326         {
11327           int size = AOP_SIZE (right) - 1;
11328           while (size--)
11329             emitcode ("dec", "%s", rname);
11330         }
11331     }
11332
11333   /* done */
11334   if (pi) pi->generated = 1;
11335   freeAsmop (result, NULL, ic, TRUE);
11336   freeAsmop (right, NULL, ic, TRUE);
11337 }
11338
11339 /*-----------------------------------------------------------------*/
11340 /* genFarPointerSet - set value from far space                     */
11341 /*-----------------------------------------------------------------*/
11342 static void
11343 genFarPointerSet (operand * right,
11344                   operand * result, iCode * ic, iCode *pi)
11345 {
11346   int size, offset, dopi=1;
11347   sym_link *retype = getSpec (operandType (right));
11348   sym_link *letype = getSpec (operandType (result));
11349
11350   aopOp (result, ic, FALSE, FALSE);
11351
11352   /* if the operand is already in dptr
11353      then we do nothing else we move the value to dptr */
11354   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11355     {
11356       /* if this is remateriazable */
11357       if (AOP_TYPE (result) == AOP_IMMD)
11358         emitcode ("mov", "dptr,%s",
11359                   aopGet (result, 0, TRUE, FALSE, NULL));
11360       else
11361         {
11362           /* we need to get it byte by byte */
11363           _startLazyDPSEvaluation ();
11364           if (AOP_TYPE (result) != AOP_DPTR)
11365             {
11366               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11367               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11368               if (options.model == MODEL_FLAT24)
11369                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11370             }
11371           else
11372             {
11373               /* We need to generate a load to DPTR indirect through DPTR. */
11374               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11375
11376               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11377               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11378               if (options.model == MODEL_FLAT24)
11379                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11380               emitcode ("pop", "dph");
11381               emitcode ("pop", "dpl");
11382               dopi=0;
11383             }
11384           _endLazyDPSEvaluation ();
11385         }
11386     }
11387   /* so dptr now contains the address */
11388   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11389
11390   /* if bit then unpack */
11391   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11392   {
11393       if (AOP_INDPTRn(result)) {
11394           genSetDPTR(AOP(result)->aopu.dptr);
11395       }
11396       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11397       if (AOP_INDPTRn(result)) {
11398           genSetDPTR(0);
11399       }
11400   } else {
11401       size = AOP_SIZE (right);
11402       offset = 0;
11403       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11404           while (size--) {
11405               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11406
11407               genSetDPTR(AOP(result)->aopu.dptr);
11408               emitcode ("movx", "@dptr,a");
11409               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11410                   emitcode ("inc", "dptr");
11411               genSetDPTR (0);
11412           }
11413       } else {
11414           _startLazyDPSEvaluation ();
11415           while (size--) {
11416               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11417
11418               if (AOP_INDPTRn(result)) {
11419                   genSetDPTR(AOP(result)->aopu.dptr);
11420               } else {
11421                   genSetDPTR (0);
11422               }
11423               _flushLazyDPS ();
11424
11425               emitcode ("movx", "@dptr,a");
11426               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11427                   emitcode ("inc", "dptr");
11428           }
11429           _endLazyDPSEvaluation ();
11430       }
11431   }
11432
11433   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11434       if (!AOP_INDPTRn(result)) {
11435           _startLazyDPSEvaluation ();
11436
11437           aopPut (result,"dpl",0);
11438           aopPut (result,"dph",1);
11439           if (options.model == MODEL_FLAT24)
11440               aopPut (result,"dpx",2);
11441
11442           _endLazyDPSEvaluation ();
11443       }
11444       pi->generated=1;
11445   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11446              AOP_SIZE(right) > 1 &&
11447              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11448
11449       size = AOP_SIZE (right) - 1;
11450       if (AOP_INDPTRn(result)) {
11451           genSetDPTR(AOP(result)->aopu.dptr);
11452       }
11453       while (size--) emitcode ("lcall","__decdptr");
11454       if (AOP_INDPTRn(result)) {
11455           genSetDPTR(0);
11456       }
11457   }
11458   freeAsmop (result, NULL, ic, TRUE);
11459   freeAsmop (right, NULL, ic, TRUE);
11460 }
11461
11462 /*-----------------------------------------------------------------*/
11463 /* genGenPointerSet - set value from generic pointer space         */
11464 /*-----------------------------------------------------------------*/
11465 static void
11466 genGenPointerSet (operand * right,
11467                   operand * result, iCode * ic, iCode *pi)
11468 {
11469   int size, offset;
11470   bool pushedB;
11471   sym_link *retype = getSpec (operandType (right));
11472   sym_link *letype = getSpec (operandType (result));
11473
11474   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11475
11476   pushedB = pushB ();
11477   /* if the operand is already in dptr
11478      then we do nothing else we move the value to dptr */
11479   if (AOP_TYPE (result) != AOP_STR)
11480     {
11481       _startLazyDPSEvaluation ();
11482       /* if this is remateriazable */
11483       if (AOP_TYPE (result) == AOP_IMMD)
11484         {
11485           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11486           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11487           {
11488               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11489           }
11490           else
11491           {
11492               emitcode ("mov",
11493                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11494           }
11495         }
11496       else
11497         {                       /* we need to get it byte by byte */
11498           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11499           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11500           if (options.model == MODEL_FLAT24) {
11501             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11502             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11503           } else {
11504             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11505           }
11506         }
11507       _endLazyDPSEvaluation ();
11508     }
11509   /* so dptr + b now contains the address */
11510   aopOp (right, ic, FALSE, TRUE);
11511
11512   /* if bit then unpack */
11513   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11514     {
11515         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11516     }
11517   else
11518     {
11519         size = AOP_SIZE (right);
11520         offset = 0;
11521
11522         _startLazyDPSEvaluation ();
11523         while (size--)
11524         {
11525             if (size)
11526             {
11527                 // Set two bytes at a time, passed in _AP & A.
11528                 // dptr will be incremented ONCE by __gptrputWord.
11529                 //
11530                 // Note: any change here must be coordinated
11531                 // with the implementation of __gptrputWord
11532                 // in device/lib/_gptrput.c
11533                 emitcode("mov", "_ap, %s",
11534                          aopGet (right, offset++, FALSE, FALSE, NULL));
11535                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11536
11537                 genSetDPTR (0);
11538                 _flushLazyDPS ();
11539                 emitcode ("lcall", "__gptrputWord");
11540                 size--;
11541             }
11542             else
11543             {
11544                 // Only one byte to put.
11545                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11546
11547                 genSetDPTR (0);
11548                 _flushLazyDPS ();
11549                 emitcode ("lcall", "__gptrput");
11550             }
11551
11552             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11553             {
11554                 emitcode ("inc", "dptr");
11555             }
11556         }
11557         _endLazyDPSEvaluation ();
11558     }
11559
11560   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11561       _startLazyDPSEvaluation ();
11562
11563       aopPut (result, "dpl",0);
11564       aopPut (result, "dph",1);
11565       if (options.model == MODEL_FLAT24) {
11566           aopPut (result, "dpx",2);
11567           aopPut (result, "b",3);
11568       } else {
11569           aopPut (result, "b",2);
11570       }
11571       _endLazyDPSEvaluation ();
11572
11573       pi->generated=1;
11574   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11575              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11576
11577       size = AOP_SIZE (right) - 1;
11578       while (size--) emitcode ("lcall","__decdptr");
11579   }
11580   popB (pushedB);
11581
11582   freeAsmop (result, NULL, ic, TRUE);
11583   freeAsmop (right, NULL, ic, TRUE);
11584 }
11585
11586 /*-----------------------------------------------------------------*/
11587 /* genPointerSet - stores the value into a pointer location        */
11588 /*-----------------------------------------------------------------*/
11589 static void
11590 genPointerSet (iCode * ic, iCode *pi)
11591 {
11592   operand *right, *result;
11593   sym_link *type, *etype;
11594   int p_type;
11595
11596   D (emitcode (";", "genPointerSet"));
11597
11598   right = IC_RIGHT (ic);
11599   result = IC_RESULT (ic);
11600
11601   /* depending on the type of pointer we need to
11602      move it to the correct pointer register */
11603   type = operandType (result);
11604   etype = getSpec (type);
11605   /* if left is of type of pointer then it is simple */
11606   if (IS_PTR (type) && !IS_FUNC (type->next))
11607     {
11608       p_type = DCL_TYPE (type);
11609     }
11610   else
11611     {
11612       /* we have to go by the storage class */
11613       p_type = PTR_TYPE (SPEC_OCLS (etype));
11614     }
11615
11616   /* special case when cast remat */
11617   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11618       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11619           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11620           type = operandType (result);
11621           p_type = DCL_TYPE (type);
11622   }
11623
11624   /* now that we have the pointer type we assign
11625      the pointer values */
11626   switch (p_type)
11627     {
11628
11629     case POINTER:
11630     case IPOINTER:
11631       genNearPointerSet (right, result, ic, pi);
11632       break;
11633
11634     case PPOINTER:
11635       genPagedPointerSet (right, result, ic, pi);
11636       break;
11637
11638     case FPOINTER:
11639       genFarPointerSet (right, result, ic, pi);
11640       break;
11641
11642     case GPOINTER:
11643       genGenPointerSet (right, result, ic, pi);
11644       break;
11645
11646     default:
11647       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11648               "genPointerSet: illegal pointer type");
11649     }
11650 }
11651
11652 /*-----------------------------------------------------------------*/
11653 /* genIfx - generate code for Ifx statement                        */
11654 /*-----------------------------------------------------------------*/
11655 static void
11656 genIfx (iCode * ic, iCode * popIc)
11657 {
11658   operand *cond = IC_COND (ic);
11659   int isbit = 0;
11660   char *dup = NULL;
11661
11662   D (emitcode (";", "genIfx"));
11663
11664   aopOp (cond, ic, FALSE, FALSE);
11665
11666   /* get the value into acc */
11667   if (AOP_TYPE (cond) != AOP_CRY)
11668     {
11669         toBoolean (cond);
11670     }
11671   else
11672     {
11673         isbit = 1;
11674       if (AOP(cond)->aopu.aop_dir)
11675         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11676     }
11677
11678   /* the result is now in the accumulator or a directly addressable bit */
11679   freeAsmop (cond, NULL, ic, TRUE);
11680
11681   /* if there was something to be popped then do it */
11682   if (popIc)
11683     genIpop (popIc);
11684
11685   /* if the condition is  a bit variable */
11686   if (isbit && dup)
11687     genIfxJump (ic, dup);
11688   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11689     genIfxJump (ic, SPIL_LOC (cond)->rname);
11690   else if (isbit && !IS_ITEMP (cond))
11691     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11692   else
11693     genIfxJump (ic, "a");
11694
11695   ic->generated = 1;
11696 }
11697
11698 /*-----------------------------------------------------------------*/
11699 /* genAddrOf - generates code for address of                       */
11700 /*-----------------------------------------------------------------*/
11701 static void
11702 genAddrOf (iCode * ic)
11703 {
11704   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11705   int size, offset;
11706
11707   D (emitcode (";", "genAddrOf"));
11708
11709   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11710
11711   /* if the operand is on the stack then we
11712      need to get the stack offset of this
11713      variable */
11714   if (sym->onStack)
11715   {
11716
11717       /* if 10 bit stack */
11718       if (options.stack10bit) {
11719           char buff[10];
11720           int  offset;
11721
11722           tsprintf(buff, sizeof(buff),
11723                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11724           /* if it has an offset then we need to compute it */
11725 /*        emitcode ("subb", "a,#!constbyte", */
11726 /*                  -((sym->stack < 0) ? */
11727 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11728 /*                    ((short) sym->stack)) & 0xff); */
11729 /*        emitcode ("mov","b,a"); */
11730 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11731 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11732 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11733           if (sym->stack) {
11734               emitcode ("mov", "a,_bpx");
11735               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11736                                              ((char) (sym->stack - _G.nRegsSaved)) :
11737                                              ((char) sym->stack )) & 0xff);
11738               emitcode ("mov", "b,a");
11739               emitcode ("mov", "a,_bpx+1");
11740
11741               offset = (((sym->stack < 0) ?
11742                          ((short) (sym->stack - _G.nRegsSaved)) :
11743                          ((short) sym->stack )) >> 8) & 0xff;
11744
11745               emitcode ("addc","a,#!constbyte", offset);
11746
11747               aopPut (IC_RESULT (ic), "b", 0);
11748               aopPut (IC_RESULT (ic), "a", 1);
11749               aopPut (IC_RESULT (ic), buff, 2);
11750           } else {
11751               /* we can just move _bp */
11752               aopPut (IC_RESULT (ic), "_bpx", 0);
11753               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11754               aopPut (IC_RESULT (ic), buff, 2);
11755           }
11756       } else {
11757           /* if it has an offset then we need to compute it */
11758           if (sym->stack)
11759             {
11760               emitcode ("mov", "a,_bp");
11761               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11762               aopPut (IC_RESULT (ic), "a", 0);
11763             }
11764           else
11765             {
11766               /* we can just move _bp */
11767               aopPut (IC_RESULT (ic), "_bp", 0);
11768             }
11769           /* fill the result with zero */
11770           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11771
11772
11773           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11774               fprintf (stderr,
11775                        "*** warning: pointer to stack var truncated.\n");
11776           }
11777
11778           offset = 1;
11779           while (size--)
11780             {
11781               aopPut (IC_RESULT (ic), zero, offset++);
11782           }
11783       }
11784       goto release;
11785   }
11786
11787   /* object not on stack then we need the name */
11788   size = AOP_SIZE (IC_RESULT (ic));
11789   offset = 0;
11790
11791   while (size--)
11792     {
11793       char s[SDCC_NAME_MAX];
11794       if (offset) {
11795           switch (offset) {
11796           case 1:
11797               tsprintf(s, sizeof(s), "#!his",sym->rname);
11798               break;
11799           case 2:
11800               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11801               break;
11802           case 3:
11803               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11804               break;
11805           default: /* should not need this (just in case) */
11806               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11807                        sym->rname,
11808                        offset * 8);
11809           }
11810       }
11811       else
11812       {
11813           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11814       }
11815
11816       aopPut (IC_RESULT (ic), s, offset++);
11817     }
11818
11819 release:
11820   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11821
11822 }
11823
11824 #if 0 // obsolete, and buggy for != xdata
11825 /*-----------------------------------------------------------------*/
11826 /* genArrayInit - generates code for address of                       */
11827 /*-----------------------------------------------------------------*/
11828 static void
11829 genArrayInit (iCode * ic)
11830 {
11831     literalList *iLoop;
11832     int         ix, count;
11833     int         elementSize = 0, eIndex;
11834     unsigned    val, lastVal;
11835     sym_link    *type;
11836     operand     *left=IC_LEFT(ic);
11837
11838     D (emitcode (";", "genArrayInit"));
11839
11840     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11841
11842     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11843     {
11844         // Load immediate value into DPTR.
11845         emitcode("mov", "dptr, %s",
11846              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11847     }
11848     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11849     {
11850 #if 0
11851       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11852               "Unexpected operand to genArrayInit.\n");
11853       exit(1);
11854 #else
11855       // a regression because of SDCCcse.c:1.52
11856       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11857       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11858       if (options.model == MODEL_FLAT24)
11859         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
11860 #endif
11861     }
11862
11863     type = operandType(IC_LEFT(ic));
11864
11865     if (type && type->next)
11866     {
11867         elementSize = getSize(type->next);
11868     }
11869     else
11870     {
11871         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11872                                 "can't determine element size in genArrayInit.\n");
11873         exit(1);
11874     }
11875
11876     iLoop = IC_ARRAYILIST(ic);
11877     lastVal = 0xffff;
11878
11879     while (iLoop)
11880     {
11881         bool firstpass = TRUE;
11882
11883         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
11884                  iLoop->count, (int)iLoop->literalValue, elementSize);
11885
11886         ix = iLoop->count;
11887
11888         while (ix)
11889         {
11890             symbol *tlbl = NULL;
11891
11892             count = ix > 256 ? 256 : ix;
11893
11894             if (count > 1)
11895             {
11896                 tlbl = newiTempLabel (NULL);
11897                 if (firstpass || (count & 0xff))
11898                 {
11899                     emitcode("mov", "b, #!constbyte", count & 0xff);
11900                 }
11901
11902                 emitLabel (tlbl);
11903             }
11904
11905             firstpass = FALSE;
11906
11907             for (eIndex = 0; eIndex < elementSize; eIndex++)
11908             {
11909                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
11910                 if (val != lastVal)
11911                 {
11912                     emitcode("mov", "a, #!constbyte", val);
11913                     lastVal = val;
11914                 }
11915
11916                 emitcode("movx", "@dptr, a");
11917                 emitcode("inc", "dptr");
11918             }
11919
11920             if (count > 1)
11921             {
11922                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
11923             }
11924
11925             ix -= count;
11926         }
11927
11928         iLoop = iLoop->next;
11929     }
11930
11931     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
11932 }
11933 #endif
11934
11935 /*-----------------------------------------------------------------*/
11936 /* genFarFarAssign - assignment when both are in far space         */
11937 /*-----------------------------------------------------------------*/
11938 static void
11939 genFarFarAssign (operand * result, operand * right, iCode * ic)
11940 {
11941   int size = AOP_SIZE (right);
11942   int offset = 0;
11943   symbol *rSym = NULL;
11944
11945   if (size == 1)
11946   {
11947       /* quick & easy case. */
11948       D (emitcode(";","genFarFarAssign (1 byte case)"));
11949       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11950       freeAsmop (right, NULL, ic, FALSE);
11951       /* now assign DPTR to result */
11952       _G.accInUse++;
11953       aopOp(result, ic, FALSE, FALSE);
11954       _G.accInUse--;
11955       aopPut (result, "a", 0);
11956       freeAsmop(result, NULL, ic, FALSE);
11957       return;
11958   }
11959
11960   /* See if we've got an underlying symbol to abuse. */
11961   if (IS_SYMOP(result) && OP_SYMBOL(result))
11962   {
11963       if (IS_TRUE_SYMOP(result))
11964       {
11965           rSym = OP_SYMBOL(result);
11966       }
11967       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
11968       {
11969           rSym = OP_SYMBOL(result)->usl.spillLoc;
11970       }
11971   }
11972
11973   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
11974   {
11975       /* We can use the '390 auto-toggle feature to good effect here. */
11976
11977       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
11978       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
11979       emitcode ("mov", "dptr,#%s", rSym->rname);
11980       /* DP2 = result, DP1 = right, DP1 is current. */
11981       while (size)
11982       {
11983           emitcode("movx", "a,@dptr");
11984           emitcode("movx", "@dptr,a");
11985           if (--size)
11986           {
11987                emitcode("inc", "dptr");
11988                emitcode("inc", "dptr");
11989           }
11990       }
11991       emitcode("mov", "dps,#0");
11992       freeAsmop (right, NULL, ic, FALSE);
11993 #if 0
11994 some alternative code for processors without auto-toggle
11995 no time to test now, so later well put in...kpb
11996         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
11997         emitcode("mov", "dps,#1");      /* Select DPTR2. */
11998         emitcode ("mov", "dptr,#%s", rSym->rname);
11999         /* DP2 = result, DP1 = right, DP1 is current. */
12000         while (size)
12001         {
12002           --size;
12003           emitcode("movx", "a,@dptr");
12004           if (size)
12005             emitcode("inc", "dptr");
12006           emitcode("inc", "dps");
12007           emitcode("movx", "@dptr,a");
12008           if (size)
12009             emitcode("inc", "dptr");
12010           emitcode("inc", "dps");
12011         }
12012         emitcode("mov", "dps,#0");
12013         freeAsmop (right, NULL, ic, FALSE);
12014 #endif
12015   }
12016   else
12017   {
12018       D (emitcode (";", "genFarFarAssign"));
12019       aopOp (result, ic, TRUE, TRUE);
12020
12021       _startLazyDPSEvaluation ();
12022
12023       while (size--)
12024         {
12025           aopPut (result,
12026                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12027           offset++;
12028         }
12029       _endLazyDPSEvaluation ();
12030       freeAsmop (result, NULL, ic, FALSE);
12031       freeAsmop (right, NULL, ic, FALSE);
12032   }
12033 }
12034
12035 /*-----------------------------------------------------------------*/
12036 /* genAssign - generate code for assignment                        */
12037 /*-----------------------------------------------------------------*/
12038 static void
12039 genAssign (iCode * ic)
12040 {
12041   operand *result, *right;
12042   int size, offset;
12043   unsigned long lit = 0L;
12044
12045   D (emitcode (";", "genAssign"));
12046
12047   result = IC_RESULT (ic);
12048   right = IC_RIGHT (ic);
12049
12050   /* if they are the same */
12051   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12052     return;
12053
12054   aopOp (right, ic, FALSE, FALSE);
12055
12056   emitcode (";", "genAssign: resultIsFar = %s",
12057             isOperandInFarSpace (result) ?
12058             "TRUE" : "FALSE");
12059
12060   /* special case both in far space */
12061   if ((AOP_TYPE (right) == AOP_DPTR ||
12062        AOP_TYPE (right) == AOP_DPTR2) &&
12063   /* IS_TRUE_SYMOP(result)       && */
12064       isOperandInFarSpace (result))
12065     {
12066       genFarFarAssign (result, right, ic);
12067       return;
12068     }
12069
12070   aopOp (result, ic, TRUE, FALSE);
12071
12072   /* if they are the same registers */
12073   if (sameRegs (AOP (right), AOP (result)))
12074     goto release;
12075
12076   /* if the result is a bit */
12077   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12078     {
12079       /* if the right size is a literal then
12080          we know what the value is */
12081       if (AOP_TYPE (right) == AOP_LIT)
12082         {
12083           if (((int) operandLitValue (right)))
12084             aopPut (result, one, 0);
12085           else
12086             aopPut (result, zero, 0);
12087           goto release;
12088         }
12089
12090       /* the right is also a bit variable */
12091       if (AOP_TYPE (right) == AOP_CRY)
12092         {
12093           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12094           aopPut (result, "c", 0);
12095           goto release;
12096         }
12097
12098       /* we need to or */
12099       toBoolean (right);
12100       aopPut (result, "a", 0);
12101       goto release;
12102     }
12103
12104   /* bit variables done */
12105   /* general case */
12106   size = AOP_SIZE (result);
12107   offset = 0;
12108   if (AOP_TYPE (right) == AOP_LIT)
12109     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12110
12111   if ((size > 1) &&
12112       (AOP_TYPE (result) != AOP_REG) &&
12113       (AOP_TYPE (right) == AOP_LIT) &&
12114       !IS_FLOAT (operandType (right)))
12115     {
12116       _startLazyDPSEvaluation ();
12117       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12118         {
12119           aopPut (result,
12120                   aopGet (right, offset, FALSE, FALSE, NULL),
12121                   offset);
12122           offset++;
12123           size--;
12124         }
12125       /* And now fill the rest with zeros. */
12126       if (size)
12127         {
12128           emitcode ("clr", "a");
12129         }
12130       while (size--)
12131         {
12132           aopPut (result, "a", offset++);
12133         }
12134       _endLazyDPSEvaluation ();
12135     }
12136   else
12137     {
12138       _startLazyDPSEvaluation ();
12139       while (size--)
12140         {
12141           aopPut (result,
12142                   aopGet (right, offset, FALSE, FALSE, NULL),
12143                   offset);
12144           offset++;
12145         }
12146       _endLazyDPSEvaluation ();
12147     }
12148
12149 release:
12150   freeAsmop (result, NULL, ic, TRUE);
12151   freeAsmop (right, NULL, ic, TRUE);
12152 }
12153
12154 /*-----------------------------------------------------------------*/
12155 /* genJumpTab - generates code for jump table                      */
12156 /*-----------------------------------------------------------------*/
12157 static void
12158 genJumpTab (iCode * ic)
12159 {
12160   symbol *jtab;
12161   char *l;
12162
12163   D (emitcode (";", "genJumpTab"));
12164
12165   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12166   /* get the condition into accumulator */
12167   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12168   MOVA (l);
12169   /* multiply by four! */
12170   emitcode ("add", "a,acc");
12171   emitcode ("add", "a,acc");
12172   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12173
12174   jtab = newiTempLabel (NULL);
12175   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12176   emitcode ("jmp", "@a+dptr");
12177   emitLabel (jtab);
12178   /* now generate the jump labels */
12179   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12180        jtab = setNextItem (IC_JTLABELS (ic)))
12181     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12182
12183 }
12184
12185 /*-----------------------------------------------------------------*/
12186 /* genCast - gen code for casting                                  */
12187 /*-----------------------------------------------------------------*/
12188 static void
12189 genCast (iCode * ic)
12190 {
12191   operand *result = IC_RESULT (ic);
12192   sym_link *ctype = operandType (IC_LEFT (ic));
12193   sym_link *rtype = operandType (IC_RIGHT (ic));
12194   operand *right = IC_RIGHT (ic);
12195   int size, offset;
12196
12197   D (emitcode (";", "genCast"));
12198
12199   /* if they are equivalent then do nothing */
12200   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12201     return;
12202
12203   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12204   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12205
12206   /* if the result is a bit (and not a bitfield) */
12207   if (IS_BIT (OP_SYMBOL (result)->type))
12208     {
12209       /* if the right size is a literal then
12210          we know what the value is */
12211       if (AOP_TYPE (right) == AOP_LIT)
12212         {
12213           if (((int) operandLitValue (right)))
12214             aopPut (result, one, 0);
12215           else
12216             aopPut (result, zero, 0);
12217
12218           goto release;
12219         }
12220
12221       /* the right is also a bit variable */
12222       if (AOP_TYPE (right) == AOP_CRY)
12223         {
12224           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12225           aopPut (result, "c", 0);
12226           goto release;
12227         }
12228
12229       /* we need to or */
12230       toBoolean (right);
12231       aopPut (result, "a", 0);
12232       goto release;
12233     }
12234
12235   /* if they are the same size : or less */
12236   if (AOP_SIZE (result) <= AOP_SIZE (right))
12237     {
12238
12239       /* if they are in the same place */
12240       if (sameRegs (AOP (right), AOP (result)))
12241         goto release;
12242
12243       /* if they in different places then copy */
12244       size = AOP_SIZE (result);
12245       offset = 0;
12246       _startLazyDPSEvaluation ();
12247       while (size--)
12248         {
12249           aopPut (result,
12250                   aopGet (right, offset, FALSE, FALSE, NULL),
12251                   offset);
12252           offset++;
12253         }
12254       _endLazyDPSEvaluation ();
12255       goto release;
12256     }
12257
12258   /* if the result is of type pointer */
12259   if (IS_PTR (ctype))
12260     {
12261
12262       int p_type;
12263       sym_link *type = operandType (right);
12264
12265       /* pointer to generic pointer */
12266       if (IS_GENPTR (ctype))
12267         {
12268           if (IS_PTR (type))
12269             {
12270               p_type = DCL_TYPE (type);
12271             }
12272           else
12273             {
12274 #if OLD_CAST_BEHAVIOR
12275               /* KV: we are converting a non-pointer type to
12276                * a generic pointer. This (ifdef'd out) code
12277                * says that the resulting generic pointer
12278                * should have the same class as the storage
12279                * location of the non-pointer variable.
12280                *
12281                * For example, converting an int (which happens
12282                * to be stored in DATA space) to a pointer results
12283                * in a DATA generic pointer; if the original int
12284                * in XDATA space, so will be the resulting pointer.
12285                *
12286                * I don't like that behavior, and thus this change:
12287                * all such conversions will be forced to XDATA and
12288                * throw a warning. If you want some non-XDATA
12289                * type, or you want to suppress the warning, you
12290                * must go through an intermediate cast, like so:
12291                *
12292                * char _generic *gp = (char _xdata *)(intVar);
12293                */
12294               sym_link *etype = getSpec (type);
12295
12296               /* we have to go by the storage class */
12297               if (SPEC_OCLS (etype) != generic)
12298                 {
12299                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12300                 }
12301               else
12302 #endif
12303                 {
12304                   /* Converting unknown class (i.e. register variable)
12305                    * to generic pointer. This is not good, but
12306                    * we'll make a guess (and throw a warning).
12307                    */
12308                   p_type = FPOINTER;
12309                   werror (W_INT_TO_GEN_PTR_CAST);
12310                 }
12311             }
12312
12313           /* the first two bytes are known */
12314           size = GPTRSIZE - 1;
12315           offset = 0;
12316           _startLazyDPSEvaluation ();
12317           while (size--)
12318             {
12319               aopPut (result,
12320                       aopGet (right, offset, FALSE, FALSE, NULL),
12321                       offset);
12322               offset++;
12323             }
12324           _endLazyDPSEvaluation ();
12325
12326           /* the last byte depending on type */
12327             {
12328                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12329                 char gpValStr[10];
12330
12331                 if (gpVal == -1)
12332                 {
12333                     // pointerTypeToGPByte will have bitched.
12334                     exit(1);
12335                 }
12336
12337                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12338                 aopPut (result, gpValStr, GPTRSIZE - 1);
12339             }
12340           goto release;
12341         }
12342
12343       /* just copy the pointers */
12344       size = AOP_SIZE (result);
12345       offset = 0;
12346       _startLazyDPSEvaluation ();
12347       while (size--)
12348         {
12349           aopPut (result,
12350                   aopGet (right, offset, FALSE, FALSE, NULL),
12351                   offset);
12352           offset++;
12353         }
12354       _endLazyDPSEvaluation ();
12355       goto release;
12356     }
12357
12358   /* so we now know that the size of destination is greater
12359      than the size of the source */
12360   /* we move to result for the size of source */
12361   size = AOP_SIZE (right);
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
12373   /* now depending on the sign of the source && destination */
12374   size = AOP_SIZE (result) - AOP_SIZE (right);
12375   /* if unsigned or not an integral type */
12376   /* also, if the source is a bit, we don't need to sign extend, because
12377    * it can't possibly have set the sign bit.
12378    */
12379   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12380     {
12381       while (size--)
12382         {
12383           aopPut (result, zero, offset++);
12384         }
12385     }
12386   else
12387     {
12388       /* we need to extend the sign :{ */
12389       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12390                         FALSE, FALSE, NULL));
12391       emitcode ("rlc", "a");
12392       emitcode ("subb", "a,acc");
12393       while (size--)
12394         aopPut (result, "a", offset++);
12395     }
12396
12397   /* we are done hurray !!!! */
12398
12399 release:
12400   freeAsmop (right, NULL, ic, TRUE);
12401   freeAsmop (result, NULL, ic, TRUE);
12402
12403 }
12404
12405 /*-----------------------------------------------------------------*/
12406 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12407 /*-----------------------------------------------------------------*/
12408 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12409 {
12410     operand *from , *to , *count;
12411     symbol *lbl;
12412     bitVect *rsave;
12413     int i;
12414
12415     /* we know it has to be 3 parameters */
12416     assert (nparms == 3);
12417
12418     rsave = newBitVect(16);
12419     /* save DPTR if it needs to be saved */
12420     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12421             if (bitVectBitValue(ic->rMask,i))
12422                     rsave = bitVectSetBit(rsave,i);
12423     }
12424     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12425                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12426     savermask(rsave);
12427
12428     to = parms[0];
12429     from = parms[1];
12430     count = parms[2];
12431
12432     aopOp (from, ic->next, FALSE, FALSE);
12433
12434     /* get from into DPTR1 */
12435     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12436     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12437     if (options.model == MODEL_FLAT24) {
12438         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12439     }
12440
12441     freeAsmop (from, NULL, ic, FALSE);
12442     aopOp (to, ic, FALSE, FALSE);
12443     /* get "to" into DPTR */
12444     /* if the operand is already in dptr
12445        then we do nothing else we move the value to dptr */
12446     if (AOP_TYPE (to) != AOP_STR) {
12447         /* if already in DPTR then we need to push */
12448         if (AOP_TYPE(to) == AOP_DPTR) {
12449             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12450             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12451             if (options.model == MODEL_FLAT24)
12452                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12453             emitcode ("pop", "dph");
12454             emitcode ("pop", "dpl");
12455         } else {
12456             _startLazyDPSEvaluation ();
12457             /* if this is remateriazable */
12458             if (AOP_TYPE (to) == AOP_IMMD) {
12459                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12460             } else {                    /* we need to get it byte by byte */
12461                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12462                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12463                 if (options.model == MODEL_FLAT24) {
12464                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12465                 }
12466             }
12467             _endLazyDPSEvaluation ();
12468         }
12469     }
12470     freeAsmop (to, NULL, ic, FALSE);
12471     _G.dptrInUse = _G.dptr1InUse = 1;
12472     aopOp (count, ic->next->next, FALSE,FALSE);
12473     lbl =newiTempLabel(NULL);
12474
12475     /* now for the actual copy */
12476     if (AOP_TYPE(count) == AOP_LIT &&
12477         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12478         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12479         if (fromc) {
12480             emitcode ("lcall","__bi_memcpyc2x_s");
12481         } else {
12482             emitcode ("lcall","__bi_memcpyx2x_s");
12483         }
12484         freeAsmop (count, NULL, ic, FALSE);
12485     } else {
12486         symbol *lbl1 = newiTempLabel(NULL);
12487
12488         emitcode (";"," Auto increment but no djnz");
12489         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12490         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12491         freeAsmop (count, NULL, ic, FALSE);
12492         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12493         emitcode ("","!tlabeldef",lbl->key+100);
12494         if (fromc) {
12495             emitcode ("clr","a");
12496             emitcode ("movc", "a,@a+dptr");
12497         } else
12498             emitcode ("movx", "a,@dptr");
12499         emitcode ("movx", "@dptr,a");
12500         emitcode ("inc", "dptr");
12501         emitcode ("inc", "dptr");
12502         emitcode ("mov","a,b");
12503         emitcode ("orl","a,_ap");
12504         emitcode ("jz","!tlabel",lbl1->key+100);
12505         emitcode ("mov","a,_ap");
12506         emitcode ("add","a,#!constbyte",0xFF);
12507         emitcode ("mov","_ap,a");
12508         emitcode ("mov","a,b");
12509         emitcode ("addc","a,#!constbyte",0xFF);
12510         emitcode ("mov","b,a");
12511         emitcode ("sjmp","!tlabel",lbl->key+100);
12512         emitcode ("","!tlabeldef",lbl1->key+100);
12513     }
12514     emitcode ("mov", "dps,#0");
12515     _G.dptrInUse = _G.dptr1InUse = 0;
12516     unsavermask(rsave);
12517
12518 }
12519
12520 /*-----------------------------------------------------------------*/
12521 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12522 /*-----------------------------------------------------------------*/
12523 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12524 {
12525     operand *from , *to , *count;
12526     symbol *lbl,*lbl2;
12527     bitVect *rsave;
12528     int i;
12529
12530     /* we know it has to be 3 parameters */
12531     assert (nparms == 3);
12532
12533     rsave = newBitVect(16);
12534     /* save DPTR if it needs to be saved */
12535     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12536             if (bitVectBitValue(ic->rMask,i))
12537                     rsave = bitVectSetBit(rsave,i);
12538     }
12539     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12540                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12541     savermask(rsave);
12542
12543     to = parms[0];
12544     from = parms[1];
12545     count = parms[2];
12546
12547     aopOp (from, ic->next, FALSE, FALSE);
12548
12549     /* get from into DPTR1 */
12550     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12551     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12552     if (options.model == MODEL_FLAT24) {
12553         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12554     }
12555
12556     freeAsmop (from, NULL, ic, FALSE);
12557     aopOp (to, ic, FALSE, FALSE);
12558     /* get "to" into DPTR */
12559     /* if the operand is already in dptr
12560        then we do nothing else we move the value to dptr */
12561     if (AOP_TYPE (to) != AOP_STR) {
12562         /* if already in DPTR then we need to push */
12563         if (AOP_TYPE(to) == AOP_DPTR) {
12564             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12565             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12566             if (options.model == MODEL_FLAT24)
12567                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12568             emitcode ("pop", "dph");
12569             emitcode ("pop", "dpl");
12570         } else {
12571             _startLazyDPSEvaluation ();
12572             /* if this is remateriazable */
12573             if (AOP_TYPE (to) == AOP_IMMD) {
12574                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12575             } else {                    /* we need to get it byte by byte */
12576                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12577                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12578                 if (options.model == MODEL_FLAT24) {
12579                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12580                 }
12581             }
12582             _endLazyDPSEvaluation ();
12583         }
12584     }
12585     freeAsmop (to, NULL, ic, FALSE);
12586     _G.dptrInUse = _G.dptr1InUse = 1;
12587     aopOp (count, ic->next->next, FALSE,FALSE);
12588     lbl =newiTempLabel(NULL);
12589     lbl2 =newiTempLabel(NULL);
12590
12591     /* now for the actual compare */
12592     if (AOP_TYPE(count) == AOP_LIT &&
12593         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12594         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12595         if (fromc)
12596             emitcode("lcall","__bi_memcmpc2x_s");
12597         else
12598             emitcode("lcall","__bi_memcmpx2x_s");
12599         freeAsmop (count, NULL, ic, FALSE);
12600         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12601         aopPut(IC_RESULT(ic),"a",0);
12602         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12603     } else {
12604         symbol *lbl1 = newiTempLabel(NULL);
12605
12606         emitcode("push","ar0");
12607         emitcode (";"," Auto increment but no djnz");
12608         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12609         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12610         freeAsmop (count, NULL, ic, FALSE);
12611         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12612         emitcode ("","!tlabeldef",lbl->key+100);
12613         if (fromc) {
12614             emitcode ("clr","a");
12615             emitcode ("movc", "a,@a+dptr");
12616         } else
12617             emitcode ("movx", "a,@dptr");
12618         emitcode ("mov","r0,a");
12619         emitcode ("movx", "a,@dptr");
12620         emitcode ("clr","c");
12621         emitcode ("subb","a,r0");
12622         emitcode ("jnz","!tlabel",lbl2->key+100);
12623         emitcode ("inc", "dptr");
12624         emitcode ("inc", "dptr");
12625         emitcode ("mov","a,b");
12626         emitcode ("orl","a,_ap");
12627         emitcode ("jz","!tlabel",lbl1->key+100);
12628         emitcode ("mov","a,_ap");
12629         emitcode ("add","a,#!constbyte",0xFF);
12630         emitcode ("mov","_ap,a");
12631         emitcode ("mov","a,b");
12632         emitcode ("addc","a,#!constbyte",0xFF);
12633         emitcode ("mov","b,a");
12634         emitcode ("sjmp","!tlabel",lbl->key+100);
12635         emitcode ("","!tlabeldef",lbl1->key+100);
12636         emitcode ("clr","a");
12637         emitcode ("","!tlabeldef",lbl2->key+100);
12638         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12639         aopPut(IC_RESULT(ic),"a",0);
12640         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12641         emitcode("pop","ar0");
12642         emitcode ("mov", "dps,#0");
12643     }
12644     _G.dptrInUse = _G.dptr1InUse = 0;
12645     unsavermask(rsave);
12646
12647 }
12648
12649 /*-----------------------------------------------------------------*/
12650 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12651 /* port, first parameter output area second parameter pointer to   */
12652 /* port third parameter count                                      */
12653 /*-----------------------------------------------------------------*/
12654 static void genInp( iCode *ic, int nparms, operand **parms)
12655 {
12656     operand *from , *to , *count;
12657     symbol *lbl;
12658     bitVect *rsave;
12659     int i;
12660
12661     /* we know it has to be 3 parameters */
12662     assert (nparms == 3);
12663
12664     rsave = newBitVect(16);
12665     /* save DPTR if it needs to be saved */
12666     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12667             if (bitVectBitValue(ic->rMask,i))
12668                     rsave = bitVectSetBit(rsave,i);
12669     }
12670     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12671                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12672     savermask(rsave);
12673
12674     to = parms[0];
12675     from = parms[1];
12676     count = parms[2];
12677
12678     aopOp (from, ic->next, FALSE, FALSE);
12679
12680     /* get from into DPTR1 */
12681     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12682     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12683     if (options.model == MODEL_FLAT24) {
12684         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12685     }
12686
12687     freeAsmop (from, NULL, ic, FALSE);
12688     aopOp (to, ic, FALSE, FALSE);
12689     /* get "to" into DPTR */
12690     /* if the operand is already in dptr
12691        then we do nothing else we move the value to dptr */
12692     if (AOP_TYPE (to) != AOP_STR) {
12693         /* if already in DPTR then we need to push */
12694         if (AOP_TYPE(to) == AOP_DPTR) {
12695             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12696             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12697             if (options.model == MODEL_FLAT24)
12698                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12699             emitcode ("pop", "dph");
12700             emitcode ("pop", "dpl");
12701         } else {
12702             _startLazyDPSEvaluation ();
12703             /* if this is remateriazable */
12704             if (AOP_TYPE (to) == AOP_IMMD) {
12705                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12706             } else {                    /* we need to get it byte by byte */
12707                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12708                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12709                 if (options.model == MODEL_FLAT24) {
12710                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12711                 }
12712             }
12713             _endLazyDPSEvaluation ();
12714         }
12715     }
12716     freeAsmop (to, NULL, ic, FALSE);
12717
12718     _G.dptrInUse = _G.dptr1InUse = 1;
12719     aopOp (count, ic->next->next, FALSE,FALSE);
12720     lbl =newiTempLabel(NULL);
12721
12722     /* now for the actual copy */
12723     if (AOP_TYPE(count) == AOP_LIT &&
12724         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12725         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12726         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12727         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12728         freeAsmop (count, NULL, ic, FALSE);
12729         emitcode ("","!tlabeldef",lbl->key+100);
12730         emitcode ("movx", "a,@dptr");   /* read data from port */
12731         emitcode ("dec","dps");         /* switch to DPTR */
12732         emitcode ("movx", "@dptr,a");   /* save into location */
12733         emitcode ("inc", "dptr");       /* point to next area */
12734         emitcode ("inc","dps");         /* switch to DPTR2 */
12735         emitcode ("djnz","b,!tlabel",lbl->key+100);
12736     } else {
12737         symbol *lbl1 = newiTempLabel(NULL);
12738
12739         emitcode (";"," Auto increment but no djnz");
12740         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12741         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12742         freeAsmop (count, NULL, ic, FALSE);
12743         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12744         emitcode ("","!tlabeldef",lbl->key+100);
12745         emitcode ("movx", "a,@dptr");
12746         emitcode ("dec","dps");         /* switch to DPTR */
12747         emitcode ("movx", "@dptr,a");
12748         emitcode ("inc", "dptr");
12749         emitcode ("inc","dps");         /* switch to DPTR2 */
12750 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12751 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12752         emitcode ("mov","a,b");
12753         emitcode ("orl","a,_ap");
12754         emitcode ("jz","!tlabel",lbl1->key+100);
12755         emitcode ("mov","a,_ap");
12756         emitcode ("add","a,#!constbyte",0xFF);
12757         emitcode ("mov","_ap,a");
12758         emitcode ("mov","a,b");
12759         emitcode ("addc","a,#!constbyte",0xFF);
12760         emitcode ("mov","b,a");
12761         emitcode ("sjmp","!tlabel",lbl->key+100);
12762         emitcode ("","!tlabeldef",lbl1->key+100);
12763     }
12764     emitcode ("mov", "dps,#0");
12765     _G.dptrInUse = _G.dptr1InUse = 0;
12766     unsavermask(rsave);
12767
12768 }
12769
12770 /*-----------------------------------------------------------------*/
12771 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12772 /* port, first parameter output area second parameter pointer to   */
12773 /* port third parameter count                                      */
12774 /*-----------------------------------------------------------------*/
12775 static void genOutp( iCode *ic, int nparms, operand **parms)
12776 {
12777     operand *from , *to , *count;
12778     symbol *lbl;
12779     bitVect *rsave;
12780     int i;
12781
12782     /* we know it has to be 3 parameters */
12783     assert (nparms == 3);
12784
12785     rsave = newBitVect(16);
12786     /* save DPTR if it needs to be saved */
12787     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12788             if (bitVectBitValue(ic->rMask,i))
12789                     rsave = bitVectSetBit(rsave,i);
12790     }
12791     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12792                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12793     savermask(rsave);
12794
12795     to = parms[0];
12796     from = parms[1];
12797     count = parms[2];
12798
12799     aopOp (from, ic->next, FALSE, FALSE);
12800
12801     /* get from into DPTR1 */
12802     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12803     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12804     if (options.model == MODEL_FLAT24) {
12805         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12806     }
12807
12808     freeAsmop (from, NULL, ic, FALSE);
12809     aopOp (to, ic, FALSE, FALSE);
12810     /* get "to" into DPTR */
12811     /* if the operand is already in dptr
12812        then we do nothing else we move the value to dptr */
12813     if (AOP_TYPE (to) != AOP_STR) {
12814         /* if already in DPTR then we need to push */
12815         if (AOP_TYPE(to) == AOP_DPTR) {
12816             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12817             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12818             if (options.model == MODEL_FLAT24)
12819                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12820             emitcode ("pop", "dph");
12821             emitcode ("pop", "dpl");
12822         } else {
12823             _startLazyDPSEvaluation ();
12824             /* if this is remateriazable */
12825             if (AOP_TYPE (to) == AOP_IMMD) {
12826                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12827             } else {                    /* we need to get it byte by byte */
12828                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12829                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12830                 if (options.model == MODEL_FLAT24) {
12831                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12832                 }
12833             }
12834             _endLazyDPSEvaluation ();
12835         }
12836     }
12837     freeAsmop (to, NULL, ic, FALSE);
12838
12839     _G.dptrInUse = _G.dptr1InUse = 1;
12840     aopOp (count, ic->next->next, FALSE,FALSE);
12841     lbl =newiTempLabel(NULL);
12842
12843     /* now for the actual copy */
12844     if (AOP_TYPE(count) == AOP_LIT &&
12845         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12846         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12847         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12848         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12849         emitcode ("","!tlabeldef",lbl->key+100);
12850         emitcode ("movx", "a,@dptr");   /* read data from port */
12851         emitcode ("inc","dps");         /* switch to DPTR2 */
12852         emitcode ("movx", "@dptr,a");   /* save into location */
12853         emitcode ("inc", "dptr");       /* point to next area */
12854         emitcode ("dec","dps");         /* switch to DPTR */
12855         emitcode ("djnz","b,!tlabel",lbl->key+100);
12856         freeAsmop (count, NULL, ic, FALSE);
12857     } else {
12858         symbol *lbl1 = newiTempLabel(NULL);
12859
12860         emitcode (";"," Auto increment but no djnz");
12861         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12862         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12863         freeAsmop (count, NULL, ic, FALSE);
12864         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12865         emitcode ("","!tlabeldef",lbl->key+100);
12866         emitcode ("movx", "a,@dptr");
12867         emitcode ("inc", "dptr");
12868         emitcode ("inc","dps");         /* switch to DPTR2 */
12869         emitcode ("movx", "@dptr,a");
12870         emitcode ("dec","dps");         /* switch to DPTR */
12871         emitcode ("mov","a,b");
12872         emitcode ("orl","a,_ap");
12873         emitcode ("jz","!tlabel",lbl1->key+100);
12874         emitcode ("mov","a,_ap");
12875         emitcode ("add","a,#!constbyte",0xFF);
12876         emitcode ("mov","_ap,a");
12877         emitcode ("mov","a,b");
12878         emitcode ("addc","a,#!constbyte",0xFF);
12879         emitcode ("mov","b,a");
12880         emitcode ("sjmp","!tlabel",lbl->key+100);
12881         emitcode ("","!tlabeldef",lbl1->key+100);
12882     }
12883     emitcode ("mov", "dps,#0");
12884     _G.dptrInUse = _G.dptr1InUse = 0;
12885     unsavermask(rsave);
12886
12887 }
12888
12889 /*-----------------------------------------------------------------*/
12890 /* genSwapW - swap lower & high order bytes                        */
12891 /*-----------------------------------------------------------------*/
12892 static void genSwapW(iCode *ic, int nparms, operand **parms)
12893 {
12894     operand *dest;
12895     operand *src;
12896     assert (nparms==1);
12897
12898     src = parms[0];
12899     dest=IC_RESULT(ic);
12900
12901     assert(getSize(operandType(src))==2);
12902
12903     aopOp (src, ic, FALSE, FALSE);
12904     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
12905     _G.accInUse++;
12906     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
12907     _G.accInUse--;
12908     freeAsmop (src, NULL, ic, FALSE);
12909
12910     aopOp (dest,ic, FALSE, FALSE);
12911     aopPut(dest,"b",0);
12912     aopPut(dest,"a",1);
12913     freeAsmop (dest, NULL, ic, FALSE);
12914 }
12915
12916 /*-----------------------------------------------------------------*/
12917 /* genMemsetX - gencode for memSetX data                           */
12918 /*-----------------------------------------------------------------*/
12919 static void genMemsetX(iCode *ic, int nparms, operand **parms)
12920 {
12921     operand *to , *val , *count;
12922     symbol *lbl;
12923     char *l;
12924     int i;
12925     bitVect *rsave;
12926
12927     /* we know it has to be 3 parameters */
12928     assert (nparms == 3);
12929
12930     to = parms[0];
12931     val = parms[1];
12932     count = parms[2];
12933
12934     /* save DPTR if it needs to be saved */
12935     rsave = newBitVect(16);
12936     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12937             if (bitVectBitValue(ic->rMask,i))
12938                     rsave = bitVectSetBit(rsave,i);
12939     }
12940     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12941                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12942     savermask(rsave);
12943
12944     aopOp (to, ic, FALSE, FALSE);
12945     /* get "to" into DPTR */
12946     /* if the operand is already in dptr
12947        then we do nothing else we move the value to dptr */
12948     if (AOP_TYPE (to) != AOP_STR) {
12949         /* if already in DPTR then we need to push */
12950         if (AOP_TYPE(to) == AOP_DPTR) {
12951             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12952             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12953             if (options.model == MODEL_FLAT24)
12954                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12955             emitcode ("pop", "dph");
12956             emitcode ("pop", "dpl");
12957         } else {
12958             _startLazyDPSEvaluation ();
12959             /* if this is remateriazable */
12960             if (AOP_TYPE (to) == AOP_IMMD) {
12961                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12962             } else {                    /* we need to get it byte by byte */
12963                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12964                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12965                 if (options.model == MODEL_FLAT24) {
12966                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12967                 }
12968             }
12969             _endLazyDPSEvaluation ();
12970         }
12971     }
12972     freeAsmop (to, NULL, ic, FALSE);
12973
12974     aopOp (val, ic->next->next, FALSE,FALSE);
12975     aopOp (count, ic->next->next, FALSE,FALSE);
12976     lbl =newiTempLabel(NULL);
12977     /* now for the actual copy */
12978     if (AOP_TYPE(count) == AOP_LIT &&
12979         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12980         l = aopGet(val, 0, FALSE, FALSE, NULL);
12981         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12982         MOVA(l);
12983         emitcode ("","!tlabeldef",lbl->key+100);
12984         emitcode ("movx", "@dptr,a");
12985         emitcode ("inc", "dptr");
12986         emitcode ("djnz","b,!tlabel",lbl->key+100);
12987     } else {
12988         symbol *lbl1 = newiTempLabel(NULL);
12989
12990         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12991         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12992         emitcode ("","!tlabeldef",lbl->key+100);
12993         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
12994         emitcode ("movx", "@dptr,a");
12995         emitcode ("inc", "dptr");
12996         emitcode ("mov","a,b");
12997         emitcode ("orl","a,_ap");
12998         emitcode ("jz","!tlabel",lbl1->key+100);
12999         emitcode ("mov","a,_ap");
13000         emitcode ("add","a,#!constbyte",0xFF);
13001         emitcode ("mov","_ap,a");
13002         emitcode ("mov","a,b");
13003         emitcode ("addc","a,#!constbyte",0xFF);
13004         emitcode ("mov","b,a");
13005         emitcode ("sjmp","!tlabel",lbl->key+100);
13006         emitcode ("","!tlabeldef",lbl1->key+100);
13007     }
13008     freeAsmop (count, NULL, ic, FALSE);
13009     unsavermask(rsave);
13010 }
13011
13012 /*-----------------------------------------------------------------*/
13013 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13014 /*-----------------------------------------------------------------*/
13015 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13016 {
13017         bitVect *rsave ;
13018         operand *pnum, *result;
13019         int i;
13020
13021         assert (nparms==1);
13022         /* save registers that need to be saved */
13023         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13024                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13025
13026         pnum = parms[0];
13027         aopOp (pnum, ic, FALSE, FALSE);
13028         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13029         freeAsmop (pnum, NULL, ic, FALSE);
13030         emitcode ("lcall","NatLib_LoadPrimitive");
13031         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13032         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13033             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13034                 for (i = (size-1) ; i >= 0 ; i-- ) {
13035                         emitcode ("push","a%s",javaRet[i]);
13036                 }
13037                 for (i=0; i < size ; i++ ) {
13038                         emitcode ("pop","a%s",
13039                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13040                 }
13041         } else {
13042                 for (i = 0 ; i < size ; i++ ) {
13043                         aopPut(result,javaRet[i],i);
13044                 }
13045         }
13046         freeAsmop (result, NULL, ic, FALSE);
13047         unsavermask(rsave);
13048 }
13049
13050 /*-----------------------------------------------------------------*/
13051 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13052 /*-----------------------------------------------------------------*/
13053 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13054 {
13055         bitVect *rsave ;
13056         operand *pnum, *result;
13057         int size = 3;
13058         int i;
13059
13060         assert (nparms==1);
13061         /* save registers that need to be saved */
13062         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13063                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13064
13065         pnum = parms[0];
13066         aopOp (pnum, ic, FALSE, FALSE);
13067         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13068         freeAsmop (pnum, NULL, ic, FALSE);
13069         emitcode ("lcall","NatLib_LoadPointer");
13070         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13071         if (AOP_TYPE(result)!=AOP_STR) {
13072                 for (i = 0 ; i < size ; i++ ) {
13073                         aopPut(result,fReturn[i],i);
13074                 }
13075         }
13076         freeAsmop (result, NULL, ic, FALSE);
13077         unsavermask(rsave);
13078 }
13079
13080 /*-----------------------------------------------------------------*/
13081 /* genNatLibInstallStateBlock -                                    */
13082 /*-----------------------------------------------------------------*/
13083 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13084                                        operand **parms, const char *name)
13085 {
13086         bitVect *rsave ;
13087         operand *psb, *handle;
13088         assert (nparms==2);
13089
13090         /* save registers that need to be saved */
13091         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13092                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13093         psb = parms[0];
13094         handle = parms[1];
13095
13096         /* put pointer to state block into DPTR1 */
13097         aopOp (psb, ic, FALSE, FALSE);
13098         if (AOP_TYPE (psb) == AOP_IMMD) {
13099                 emitcode ("mov","dps,#1");
13100                 emitcode ("mov", "dptr,%s",
13101                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13102                 emitcode ("mov","dps,#0");
13103         } else {
13104                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13105                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13106                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13107         }
13108         freeAsmop (psb, NULL, ic, FALSE);
13109
13110         /* put libraryID into DPTR */
13111         emitcode ("mov","dptr,#LibraryID");
13112
13113         /* put handle into r3:r2 */
13114         aopOp (handle, ic, FALSE, FALSE);
13115         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13116                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13117                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13118                 emitcode ("pop","ar3");
13119                 emitcode ("pop","ar2");
13120         } else {
13121                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13122                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13123         }
13124         freeAsmop (psb, NULL, ic, FALSE);
13125
13126         /* make the call */
13127         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13128
13129         /* put return value into place*/
13130         _G.accInUse++;
13131         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13132         _G.accInUse--;
13133         aopPut(IC_RESULT(ic),"a",0);
13134         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13135         unsavermask(rsave);
13136 }
13137
13138 /*-----------------------------------------------------------------*/
13139 /* genNatLibRemoveStateBlock -                                     */
13140 /*-----------------------------------------------------------------*/
13141 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13142 {
13143         bitVect *rsave ;
13144
13145         assert(nparms==0);
13146
13147         /* save registers that need to be saved */
13148         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13149                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13150
13151         /* put libraryID into DPTR */
13152         emitcode ("mov","dptr,#LibraryID");
13153         /* make the call */
13154         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13155         unsavermask(rsave);
13156 }
13157
13158 /*-----------------------------------------------------------------*/
13159 /* genNatLibGetStateBlock -                                        */
13160 /*-----------------------------------------------------------------*/
13161 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13162                                    operand **parms,const char *name)
13163 {
13164         bitVect *rsave ;
13165         symbol *lbl = newiTempLabel(NULL);
13166
13167         assert(nparms==0);
13168         /* save registers that need to be saved */
13169         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13170                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13171
13172         /* put libraryID into DPTR */
13173         emitcode ("mov","dptr,#LibraryID");
13174         /* make the call */
13175         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13176         emitcode ("jnz","!tlabel",lbl->key+100);
13177
13178         /* put return value into place */
13179         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13180         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13181                 emitcode ("push","ar3");
13182                 emitcode ("push","ar2");
13183                 emitcode ("pop","%s",
13184                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13185                 emitcode ("pop","%s",
13186                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13187         } else {
13188                 aopPut(IC_RESULT(ic),"r2",0);
13189                 aopPut(IC_RESULT(ic),"r3",1);
13190         }
13191         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13192         emitcode ("","!tlabeldef",lbl->key+100);
13193         unsavermask(rsave);
13194 }
13195
13196 /*-----------------------------------------------------------------*/
13197 /* genMMMalloc -                                                   */
13198 /*-----------------------------------------------------------------*/
13199 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13200                          int size, const char *name)
13201 {
13202         bitVect *rsave ;
13203         operand *bsize;
13204         symbol *rsym;
13205         symbol *lbl = newiTempLabel(NULL);
13206
13207         assert (nparms == 1);
13208         /* save registers that need to be saved */
13209         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13210                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13211
13212         bsize=parms[0];
13213         aopOp (bsize,ic,FALSE,FALSE);
13214
13215         /* put the size in R4-R2 */
13216         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13217                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13218                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13219                 if (size==3) {
13220                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13221                         emitcode("pop","ar4");
13222                 }
13223                 emitcode("pop","ar3");
13224                 emitcode("pop","ar2");
13225         } else {
13226                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13227                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13228                 if (size==3) {
13229                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13230                 }
13231         }
13232         freeAsmop (bsize, NULL, ic, FALSE);
13233
13234         /* make the call */
13235         emitcode ("lcall","MM_%s",name);
13236         emitcode ("jz","!tlabel",lbl->key+100);
13237         emitcode ("mov","r2,#!constbyte",0xff);
13238         emitcode ("mov","r3,#!constbyte",0xff);
13239         emitcode ("","!tlabeldef",lbl->key+100);
13240         /* we don't care about the pointer : we just save the handle */
13241         rsym = OP_SYMBOL(IC_RESULT(ic));
13242         if (rsym->liveFrom != rsym->liveTo) {
13243                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13244                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13245                         emitcode ("push","ar3");
13246                         emitcode ("push","ar2");
13247                         emitcode ("pop","%s",
13248                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13249                         emitcode ("pop","%s",
13250                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13251                 } else {
13252                         aopPut(IC_RESULT(ic),"r2",0);
13253                         aopPut(IC_RESULT(ic),"r3",1);
13254                 }
13255                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13256         }
13257         unsavermask(rsave);
13258 }
13259
13260 /*-----------------------------------------------------------------*/
13261 /* genMMDeref -                                                    */
13262 /*-----------------------------------------------------------------*/
13263 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13264 {
13265         bitVect *rsave ;
13266         operand *handle;
13267
13268         assert (nparms == 1);
13269         /* save registers that need to be saved */
13270         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13271                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13272
13273         handle=parms[0];
13274         aopOp (handle,ic,FALSE,FALSE);
13275
13276         /* put the size in R4-R2 */
13277         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13278                 emitcode("push","%s",
13279                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13280                 emitcode("push","%s",
13281                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13282                 emitcode("pop","ar3");
13283                 emitcode("pop","ar2");
13284         } else {
13285                 emitcode ("mov","r2,%s",
13286                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13287                 emitcode ("mov","r3,%s",
13288                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13289         }
13290         freeAsmop (handle, NULL, ic, FALSE);
13291
13292         /* make the call */
13293         emitcode ("lcall","MM_Deref");
13294
13295         {
13296                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13297                 if (rsym->liveFrom != rsym->liveTo) {
13298                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13299                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13300                             _startLazyDPSEvaluation ();
13301
13302                                 aopPut(IC_RESULT(ic),"dpl",0);
13303                                 aopPut(IC_RESULT(ic),"dph",1);
13304                                 aopPut(IC_RESULT(ic),"dpx",2);
13305
13306                             _endLazyDPSEvaluation ();
13307
13308                         }
13309                 }
13310         }
13311         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13312         unsavermask(rsave);
13313 }
13314
13315 /*-----------------------------------------------------------------*/
13316 /* genMMUnrestrictedPersist -                                      */
13317 /*-----------------------------------------------------------------*/
13318 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13319 {
13320         bitVect *rsave ;
13321         operand *handle;
13322
13323         assert (nparms == 1);
13324         /* save registers that need to be saved */
13325         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13326                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13327
13328         handle=parms[0];
13329         aopOp (handle,ic,FALSE,FALSE);
13330
13331         /* put the size in R3-R2 */
13332         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13333                 emitcode("push","%s",
13334                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13335                 emitcode("push","%s",
13336                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13337                 emitcode("pop","ar3");
13338                 emitcode("pop","ar2");
13339         } else {
13340                 emitcode ("mov","r2,%s",
13341                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13342                 emitcode ("mov","r3,%s",
13343                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13344         }
13345         freeAsmop (handle, NULL, ic, FALSE);
13346
13347         /* make the call */
13348         emitcode ("lcall","MM_UnrestrictedPersist");
13349
13350         {
13351                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13352                 if (rsym->liveFrom != rsym->liveTo) {
13353                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13354                         aopPut(IC_RESULT(ic),"a",0);
13355                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13356                 }
13357         }
13358         unsavermask(rsave);
13359 }
13360
13361 /*-----------------------------------------------------------------*/
13362 /* genSystemExecJavaProcess -                                      */
13363 /*-----------------------------------------------------------------*/
13364 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13365 {
13366         bitVect *rsave ;
13367         operand *handle, *pp;
13368
13369         assert (nparms==2);
13370         /* save registers that need to be saved */
13371         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13372                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13373
13374         pp = parms[0];
13375         handle = parms[1];
13376
13377         /* put the handle in R3-R2 */
13378         aopOp (handle,ic,FALSE,FALSE);
13379         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13380                 emitcode("push","%s",
13381                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13382                 emitcode("push","%s",
13383                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13384                 emitcode("pop","ar3");
13385                 emitcode("pop","ar2");
13386         } else {
13387                 emitcode ("mov","r2,%s",
13388                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13389                 emitcode ("mov","r3,%s",
13390                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13391         }
13392         freeAsmop (handle, NULL, ic, FALSE);
13393
13394         /* put pointer in DPTR */
13395         aopOp (pp,ic,FALSE,FALSE);
13396         if (AOP_TYPE(pp) == AOP_IMMD) {
13397                 emitcode ("mov", "dptr,%s",
13398                           aopGet (pp, 0, TRUE, FALSE, NULL));
13399         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13400                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13401                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13402                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13403         }
13404         freeAsmop (handle, NULL, ic, FALSE);
13405
13406         /* make the call */
13407         emitcode ("lcall","System_ExecJavaProcess");
13408
13409         /* put result in place */
13410         {
13411                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13412                 if (rsym->liveFrom != rsym->liveTo) {
13413                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13414                         aopPut(IC_RESULT(ic),"a",0);
13415                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13416                 }
13417         }
13418
13419         unsavermask(rsave);
13420 }
13421
13422 /*-----------------------------------------------------------------*/
13423 /* genSystemRTCRegisters -                                         */
13424 /*-----------------------------------------------------------------*/
13425 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13426                                   char *name)
13427 {
13428         bitVect *rsave ;
13429         operand *pp;
13430
13431         assert (nparms==1);
13432         /* save registers that need to be saved */
13433         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13434                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13435
13436         pp=parms[0];
13437         /* put pointer in DPTR */
13438         aopOp (pp,ic,FALSE,FALSE);
13439         if (AOP_TYPE (pp) == AOP_IMMD) {
13440                 emitcode ("mov","dps,#1");
13441                 emitcode ("mov", "dptr,%s",
13442                           aopGet (pp, 0, TRUE, FALSE, NULL));
13443                 emitcode ("mov","dps,#0");
13444         } else {
13445                 emitcode ("mov","dpl1,%s",
13446                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13447                 emitcode ("mov","dph1,%s",
13448                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13449                 emitcode ("mov","dpx1,%s",
13450                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13451         }
13452         freeAsmop (pp, NULL, ic, FALSE);
13453
13454         /* make the call */
13455         emitcode ("lcall","System_%sRTCRegisters",name);
13456
13457         unsavermask(rsave);
13458 }
13459
13460 /*-----------------------------------------------------------------*/
13461 /* genSystemThreadSleep -                                          */
13462 /*-----------------------------------------------------------------*/
13463 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13464 {
13465         bitVect *rsave ;
13466         operand *to, *s;
13467
13468         assert (nparms==1);
13469         /* save registers that need to be saved */
13470         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13471                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13472
13473         to = parms[0];
13474         aopOp(to,ic,FALSE,FALSE);
13475         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13476             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13477                 emitcode ("push","%s",
13478                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13479                 emitcode ("push","%s",
13480                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13481                 emitcode ("push","%s",
13482                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13483                 emitcode ("push","%s",
13484                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13485                 emitcode ("pop","ar3");
13486                 emitcode ("pop","ar2");
13487                 emitcode ("pop","ar1");
13488                 emitcode ("pop","ar0");
13489         } else {
13490                 emitcode ("mov","r0,%s",
13491                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13492                 emitcode ("mov","r1,%s",
13493                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13494                 emitcode ("mov","r2,%s",
13495                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13496                 emitcode ("mov","r3,%s",
13497                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13498         }
13499         freeAsmop (to, NULL, ic, FALSE);
13500
13501         /* suspend in acc */
13502         s = parms[1];
13503         aopOp(s,ic,FALSE,FALSE);
13504         emitcode ("mov","a,%s",
13505                   aopGet(s,0,FALSE,TRUE,NULL));
13506         freeAsmop (s, NULL, ic, FALSE);
13507
13508         /* make the call */
13509         emitcode ("lcall","System_%s",name);
13510
13511         unsavermask(rsave);
13512 }
13513
13514 /*-----------------------------------------------------------------*/
13515 /* genSystemThreadResume -                                         */
13516 /*-----------------------------------------------------------------*/
13517 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13518 {
13519         bitVect *rsave ;
13520         operand *tid,*pid;
13521
13522         assert (nparms==2);
13523         /* save registers that need to be saved */
13524         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13525                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13526
13527         tid = parms[0];
13528         pid = parms[1];
13529
13530         /* PID in R0 */
13531         aopOp(pid,ic,FALSE,FALSE);
13532         emitcode ("mov","r0,%s",
13533                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13534         freeAsmop (pid, NULL, ic, FALSE);
13535
13536         /* tid into ACC */
13537         aopOp(tid,ic,FALSE,FALSE);
13538         emitcode ("mov","a,%s",
13539                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13540         freeAsmop (tid, NULL, ic, FALSE);
13541
13542         emitcode ("lcall","System_ThreadResume");
13543
13544         /* put result into place */
13545         {
13546                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13547                 if (rsym->liveFrom != rsym->liveTo) {
13548                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13549                         aopPut(IC_RESULT(ic),"a",0);
13550                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13551                 }
13552         }
13553         unsavermask(rsave);
13554 }
13555
13556 /*-----------------------------------------------------------------*/
13557 /* genSystemProcessResume -                                        */
13558 /*-----------------------------------------------------------------*/
13559 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13560 {
13561         bitVect *rsave ;
13562         operand *pid;
13563
13564         assert (nparms==1);
13565         /* save registers that need to be saved */
13566         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13567                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13568
13569         pid = parms[0];
13570
13571         /* pid into ACC */
13572         aopOp(pid,ic,FALSE,FALSE);
13573         emitcode ("mov","a,%s",
13574                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13575         freeAsmop (pid, NULL, ic, FALSE);
13576
13577         emitcode ("lcall","System_ProcessResume");
13578
13579         unsavermask(rsave);
13580 }
13581
13582 /*-----------------------------------------------------------------*/
13583 /* genSystem -                                                     */
13584 /*-----------------------------------------------------------------*/
13585 static void genSystem (iCode *ic,int nparms,char *name)
13586 {
13587         assert(nparms == 0);
13588
13589         emitcode ("lcall","System_%s",name);
13590 }
13591
13592 /*-----------------------------------------------------------------*/
13593 /* genSystemPoll -                                                  */
13594 /*-----------------------------------------------------------------*/
13595 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13596 {
13597         bitVect *rsave ;
13598         operand *fp;
13599
13600         assert (nparms==1);
13601         /* save registers that need to be saved */
13602         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13603                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13604
13605         fp = parms[0];
13606         aopOp (fp,ic,FALSE,FALSE);
13607         if (AOP_TYPE (fp) == AOP_IMMD) {
13608                 emitcode ("mov", "dptr,%s",
13609                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13610         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13611                 emitcode ("mov","dpl,%s",
13612                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13613                 emitcode ("mov","dph,%s",
13614                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13615                 emitcode ("mov","dpx,%s",
13616                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13617         }
13618         freeAsmop (fp, NULL, ic, FALSE);
13619
13620         emitcode ("lcall","System_%sPoll",name);
13621
13622         /* put result into place */
13623         {
13624                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13625                 if (rsym->liveFrom != rsym->liveTo) {
13626                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13627                         aopPut(IC_RESULT(ic),"a",0);
13628                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13629                 }
13630         }
13631         unsavermask(rsave);
13632 }
13633
13634 /*-----------------------------------------------------------------*/
13635 /* genSystemGetCurrentID -                                         */
13636 /*-----------------------------------------------------------------*/
13637 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13638 {
13639         assert (nparms==0);
13640
13641         emitcode ("lcall","System_GetCurrent%sId",name);
13642         /* put result into place */
13643         {
13644                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13645                 if (rsym->liveFrom != rsym->liveTo) {
13646                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13647                         aopPut(IC_RESULT(ic),"a",0);
13648                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13649                 }
13650         }
13651 }
13652
13653 /*-----------------------------------------------------------------*/
13654 /* genDjnz - generate decrement & jump if not zero instrucion      */
13655 /*-----------------------------------------------------------------*/
13656 static int
13657 genDjnz (iCode * ic, iCode * ifx)
13658 {
13659   symbol *lbl, *lbl1;
13660   if (!ifx)
13661     return 0;
13662
13663   /* if the if condition has a false label
13664      then we cannot save */
13665   if (IC_FALSE (ifx))
13666     return 0;
13667
13668   /* if the minus is not of the form a = a - 1 */
13669   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13670       !IS_OP_LITERAL (IC_RIGHT (ic)))
13671     return 0;
13672
13673   if (operandLitValue (IC_RIGHT (ic)) != 1)
13674     return 0;
13675
13676   /* if the size of this greater than one then no
13677      saving */
13678   if (getSize (operandType (IC_RESULT (ic))) > 1)
13679     return 0;
13680
13681   /* otherwise we can save BIG */
13682
13683   D (emitcode (";", "genDjnz"));
13684
13685   lbl = newiTempLabel (NULL);
13686   lbl1 = newiTempLabel (NULL);
13687
13688   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13689
13690   if (AOP_NEEDSACC(IC_RESULT(ic)))
13691   {
13692       /* If the result is accessed indirectly via
13693        * the accumulator, we must explicitly write
13694        * it back after the decrement.
13695        */
13696       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13697
13698       if (strcmp(rByte, "a"))
13699       {
13700            /* Something is hopelessly wrong */
13701            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13702                    __FILE__, __LINE__);
13703            /* We can just give up; the generated code will be inefficient,
13704             * but what the hey.
13705             */
13706            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13707            return 0;
13708       }
13709       emitcode ("dec", "%s", rByte);
13710       aopPut (IC_RESULT (ic), rByte, 0);
13711       emitcode ("jnz", "!tlabel", lbl->key + 100);
13712   }
13713   else if (IS_AOP_PREG (IC_RESULT (ic)))
13714     {
13715       emitcode ("dec", "%s",
13716                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13717       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13718       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13719       ifx->generated = 1;
13720       emitcode ("jnz", "!tlabel", lbl->key + 100);
13721     }
13722   else
13723     {
13724       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13725                 lbl->key + 100);
13726     }
13727   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13728   emitLabel (lbl);
13729   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13730   emitLabel (lbl1);
13731
13732   if (!ifx->generated)
13733       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13734   ifx->generated = 1;
13735   return 1;
13736 }
13737
13738 /*-----------------------------------------------------------------*/
13739 /* genReceive - generate code for a receive iCode                  */
13740 /*-----------------------------------------------------------------*/
13741 static void
13742 genReceive (iCode * ic)
13743 {
13744     int size = getSize (operandType (IC_RESULT (ic)));
13745     int offset = 0;
13746     int rb1off ;
13747
13748     D (emitcode (";", "genReceive"));
13749
13750     if (ic->argreg == 1)
13751     {
13752         /* first parameter */
13753         if (AOP_IS_STR(IC_RESULT(ic)))
13754         {
13755             /* Nothing to do: it's already in the proper place. */
13756             return;
13757         }
13758         else
13759         {
13760             bool useDp2;
13761
13762             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13763                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13764                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13765
13766             _G.accInUse++;
13767             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13768             _G.accInUse--;
13769
13770             /* Sanity checking... */
13771             if (AOP_USESDPTR(IC_RESULT(ic)))
13772             {
13773                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13774                         "genReceive got unexpected DPTR.");
13775             }
13776             assignResultValue (IC_RESULT (ic), NULL);
13777         }
13778     }
13779     else if (ic->argreg > 12)
13780     { /* bit parameters */
13781       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13782         {
13783           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13784           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13785           outBitC(IC_RESULT (ic));
13786         }
13787     }
13788     else
13789     {
13790         /* second receive onwards */
13791         /* this gets a little tricky since unused receives will be
13792          eliminated, we have saved the reg in the type field . and
13793          we use that to figure out which register to use */
13794         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13795         rb1off = ic->argreg;
13796         while (size--)
13797         {
13798             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13799         }
13800     }
13801     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13802 }
13803
13804 /*-----------------------------------------------------------------*/
13805 /* genDummyRead - generate code for dummy read of volatiles        */
13806 /*-----------------------------------------------------------------*/
13807 static void
13808 genDummyRead (iCode * ic)
13809 {
13810   operand *op;
13811   int size, offset;
13812
13813   D (emitcode(";", "genDummyRead"));
13814
13815   op = IC_RIGHT (ic);
13816   if (op && IS_SYMOP (op))
13817     {
13818       aopOp (op, ic, FALSE, FALSE);
13819
13820       /* if the result is a bit */
13821       if (AOP_TYPE (op) == AOP_CRY)
13822         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13823       else
13824         {
13825           /* bit variables done */
13826           /* general case */
13827           size = AOP_SIZE (op);
13828           offset = 0;
13829           while (size--)
13830           {
13831             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13832             offset++;
13833           }
13834         }
13835
13836       freeAsmop (op, NULL, ic, TRUE);
13837     }
13838
13839   op = IC_LEFT (ic);
13840   if (op && IS_SYMOP (op))
13841     {
13842       aopOp (op, ic, FALSE, FALSE);
13843
13844       /* if the result is a bit */
13845       if (AOP_TYPE (op) == AOP_CRY)
13846         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13847       else
13848         {
13849           /* bit variables done */
13850           /* general case */
13851           size = AOP_SIZE (op);
13852           offset = 0;
13853           while (size--)
13854           {
13855             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13856             offset++;
13857           }
13858         }
13859
13860       freeAsmop (op, NULL, ic, TRUE);
13861     }
13862 }
13863
13864 /*-----------------------------------------------------------------*/
13865 /* genCritical - generate code for start of a critical sequence    */
13866 /*-----------------------------------------------------------------*/
13867 static void
13868 genCritical (iCode *ic)
13869 {
13870   symbol *tlbl = newiTempLabel (NULL);
13871
13872   D (emitcode(";", "genCritical"));
13873
13874   if (IC_RESULT (ic))
13875     {
13876       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
13877       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
13878       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
13879       aopPut (IC_RESULT (ic), zero, 0);
13880       emitLabel (tlbl);
13881       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13882     }
13883   else
13884     {
13885       emitcode ("setb", "c");
13886       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
13887       emitcode ("clr", "c");
13888       emitLabel (tlbl);
13889       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
13890     }
13891 }
13892
13893 /*-----------------------------------------------------------------*/
13894 /* genEndCritical - generate code for end of a critical sequence   */
13895 /*-----------------------------------------------------------------*/
13896 static void
13897 genEndCritical (iCode *ic)
13898 {
13899   D(emitcode(";     genEndCritical",""));
13900
13901   if (IC_RIGHT (ic))
13902     {
13903       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
13904       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
13905         {
13906           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
13907           emitcode ("mov", "ea,c");
13908         }
13909       else
13910         {
13911           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
13912           emitcode ("rrc", "a");
13913           emitcode ("mov", "ea,c");
13914         }
13915       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
13916     }
13917   else
13918     {
13919       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
13920       emitcode ("mov", "ea,c");
13921     }
13922 }
13923
13924
13925
13926 /*-----------------------------------------------------------------*/
13927 /* genBuiltIn - calls the appropriate function to  generating code */
13928 /* for a built in function                                         */
13929 /*-----------------------------------------------------------------*/
13930 static void genBuiltIn (iCode *ic)
13931 {
13932         operand *bi_parms[MAX_BUILTIN_ARGS];
13933         int nbi_parms;
13934         iCode *bi_iCode;
13935         symbol *bif;
13936
13937         /* get all the arguments for a built in function */
13938         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
13939
13940         /* which function is it */
13941         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
13942         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
13943                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
13944         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
13945                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
13946         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
13947                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
13948         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
13949                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
13950         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
13951                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
13952         } else if (strcmp(bif->name,"__builtin_inp")==0) {
13953                 genInp(bi_iCode,nbi_parms,bi_parms);
13954         } else if (strcmp(bif->name,"__builtin_outp")==0) {
13955                 genOutp(bi_iCode,nbi_parms,bi_parms);
13956         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
13957                 genSwapW(bi_iCode,nbi_parms,bi_parms);
13958                 /* JavaNative builtIns */
13959         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
13960                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
13961         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
13962                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
13963         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
13964                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
13965         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
13966                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
13967         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
13968                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13969         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
13970                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13971         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
13972                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
13973         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
13974                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
13975         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
13976                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13977         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
13978                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13979         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
13980                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
13981         } else if (strcmp(bif->name,"MM_Malloc")==0) {
13982                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
13983         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
13984                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
13985         } else if (strcmp(bif->name,"MM_Free")==0) {
13986                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
13987         } else if (strcmp(bif->name,"MM_Deref")==0) {
13988                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
13989         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
13990                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
13991         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
13992                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
13993         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
13994                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
13995         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
13996                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
13997         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
13998                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
13999         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14000                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14001         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14002                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14003         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14004                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14005         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14006                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14007         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14008                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14009         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14010                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14011         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14012                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14013         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14014                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14015         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14016                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14017         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14018                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14019         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14020                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14021         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14022                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14023         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14024                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14025         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14026                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14027         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14028                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14029         } else {
14030                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14031                 return ;
14032         }
14033         return ;
14034 }
14035
14036 /*-----------------------------------------------------------------*/
14037 /* gen390Code - generate code for Dallas 390 based controllers     */
14038 /*-----------------------------------------------------------------*/
14039 void
14040 gen390Code (iCode * lic)
14041 {
14042   iCode *ic;
14043   int cln = 0;
14044
14045   _G.currentFunc = NULL;
14046   lineHead = lineCurr = NULL;
14047   dptrn[1][0] = "dpl1";
14048   dptrn[1][1] = "dph1";
14049   dptrn[1][2] = "dpx1";
14050
14051   if (options.model == MODEL_FLAT24) {
14052     fReturnSizeDS390 = 5;
14053     fReturn = fReturn24;
14054   } else {
14055     fReturnSizeDS390 = 4;
14056     fReturn = fReturn16;
14057     options.stack10bit=0;
14058   }
14059 #if 1
14060   /* print the allocation information */
14061   if (allocInfo && currFunc)
14062     printAllocInfo (currFunc, codeOutFile);
14063 #endif
14064   /* if debug information required */
14065   if (options.debug && currFunc)
14066     {
14067       debugFile->writeFunction (currFunc, lic);
14068     }
14069   /* stack pointer name */
14070   if (options.useXstack)
14071     spname = "_spx";
14072   else
14073     spname = "sp";
14074
14075
14076   for (ic = lic; ic; ic = ic->next)
14077     {
14078       _G.current_iCode = ic;
14079
14080       if (ic->lineno && cln != ic->lineno)
14081         {
14082           if (options.debug)
14083             {
14084               debugFile->writeCLine (ic);
14085             }
14086           if (!options.noCcodeInAsm) {
14087             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14088                       printCLine(ic->filename, ic->lineno));
14089           }
14090           cln = ic->lineno;
14091         }
14092       if (options.iCodeInAsm) {
14093         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
14094       }
14095       /* if the result is marked as
14096          spilt and rematerializable or code for
14097          this has already been generated then
14098          do nothing */
14099       if (resultRemat (ic) || ic->generated)
14100         continue;
14101
14102       /* depending on the operation */
14103       switch (ic->op)
14104         {
14105         case '!':
14106           genNot (ic);
14107           break;
14108
14109         case '~':
14110           genCpl (ic);
14111           break;
14112
14113         case UNARYMINUS:
14114           genUminus (ic);
14115           break;
14116
14117         case IPUSH:
14118           genIpush (ic);
14119           break;
14120
14121         case IPOP:
14122           /* IPOP happens only when trying to restore a
14123              spilt live range, if there is an ifx statement
14124              following this pop then the if statement might
14125              be using some of the registers being popped which
14126              would destory the contents of the register so
14127              we need to check for this condition and handle it */
14128           if (ic->next &&
14129               ic->next->op == IFX &&
14130               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14131             genIfx (ic->next, ic);
14132           else
14133             genIpop (ic);
14134           break;
14135
14136         case CALL:
14137           genCall (ic);
14138           break;
14139
14140         case PCALL:
14141           genPcall (ic);
14142           break;
14143
14144         case FUNCTION:
14145           genFunction (ic);
14146           break;
14147
14148         case ENDFUNCTION:
14149           genEndFunction (ic);
14150           break;
14151
14152         case RETURN:
14153           genRet (ic);
14154           break;
14155
14156         case LABEL:
14157           genLabel (ic);
14158           break;
14159
14160         case GOTO:
14161           genGoto (ic);
14162           break;
14163
14164         case '+':
14165           genPlus (ic);
14166           break;
14167
14168         case '-':
14169           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14170             genMinus (ic);
14171           break;
14172
14173         case '*':
14174           genMult (ic);
14175           break;
14176
14177         case '/':
14178           genDiv (ic);
14179           break;
14180
14181         case '%':
14182           genMod (ic);
14183           break;
14184
14185         case '>':
14186           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14187           break;
14188
14189         case '<':
14190           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14191           break;
14192
14193         case LE_OP:
14194         case GE_OP:
14195         case NE_OP:
14196
14197           /* note these two are xlated by algebraic equivalence
14198              during parsing SDCC.y */
14199           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14200                   "got '>=' or '<=' shouldn't have come here");
14201           break;
14202
14203         case EQ_OP:
14204           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14205           break;
14206
14207         case AND_OP:
14208           genAndOp (ic);
14209           break;
14210
14211         case OR_OP:
14212           genOrOp (ic);
14213           break;
14214
14215         case '^':
14216           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14217           break;
14218
14219         case '|':
14220           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14221           break;
14222
14223         case BITWISEAND:
14224           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14225           break;
14226
14227         case INLINEASM:
14228           genInline (ic);
14229           break;
14230
14231         case RRC:
14232           genRRC (ic);
14233           break;
14234
14235         case RLC:
14236           genRLC (ic);
14237           break;
14238
14239         case GETHBIT:
14240           genGetHbit (ic);
14241           break;
14242
14243         case LEFT_OP:
14244           genLeftShift (ic);
14245           break;
14246
14247         case RIGHT_OP:
14248           genRightShift (ic);
14249           break;
14250
14251         case GET_VALUE_AT_ADDRESS:
14252           genPointerGet (ic,
14253                          hasInc (IC_LEFT (ic), ic,
14254                                  getSize (operandType (IC_RESULT (ic)))));
14255           break;
14256
14257         case '=':
14258           if (POINTER_SET (ic))
14259             genPointerSet (ic,
14260                            hasInc (IC_RESULT (ic), ic,
14261                                    getSize (operandType (IC_RIGHT (ic)))));
14262           else
14263             genAssign (ic);
14264           break;
14265
14266         case IFX:
14267           genIfx (ic, NULL);
14268           break;
14269
14270         case ADDRESS_OF:
14271           genAddrOf (ic);
14272           break;
14273
14274         case JUMPTABLE:
14275           genJumpTab (ic);
14276           break;
14277
14278         case CAST:
14279           genCast (ic);
14280           break;
14281
14282         case RECEIVE:
14283           genReceive (ic);
14284           break;
14285
14286         case SEND:
14287           if (ic->builtinSEND)
14288             genBuiltIn(ic);
14289           else
14290             addSet (&_G.sendSet, ic);
14291           break;
14292
14293         case DUMMY_READ_VOLATILE:
14294           genDummyRead (ic);
14295           break;
14296
14297         case CRITICAL:
14298           genCritical (ic);
14299           break;
14300
14301         case ENDCRITICAL:
14302           genEndCritical (ic);
14303           break;
14304
14305         case SWAP:
14306           genSwap (ic);
14307           break;
14308
14309 #if 0 // obsolete, and buggy for != xdata
14310         case ARRAYINIT:
14311             genArrayInit(ic);
14312             break;
14313 #endif
14314
14315         default:
14316           ic = ic;
14317         }
14318     }
14319
14320
14321   /* now we are ready to call the
14322      peep hole optimizer */
14323   if (!options.nopeep)
14324     peepHole (&lineHead);
14325
14326   /* now do the actual printing */
14327   printLine (lineHead, codeOutFile);
14328   return;
14329 }