ae25d32950f3694444beb4802b53a59722dfbf11
[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               char offset = ((sym->stack < 0) ?
732                          ((char) (sym->stack - _G.nRegsSaved)) :
733                          ((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 static bool
1666 aopPutUsesAcc (operand * oper, const char *s, int offset)
1667 {
1668   asmop * aop = AOP (oper);
1669
1670   if (offset > (aop->size - 1))
1671     return FALSE;
1672
1673   switch (aop->type)
1674     {
1675     case AOP_DUMMY:
1676       return TRUE;
1677     case AOP_DIR:
1678       return FALSE;
1679     case AOP_REG:
1680       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1681       return FALSE;
1682     case AOP_DPTR:
1683       return TRUE;
1684     case AOP_R0:
1685     case AOP_R1:
1686       return ((aop->paged) || (*s == '@'));
1687     case AOP_STK:
1688       return (*s == '@');
1689     case AOP_CRY:
1690       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1691     case AOP_STR:
1692       return FALSE;
1693     case AOP_IMMD:
1694       return FALSE;
1695     case AOP_ACC:
1696       return FALSE;
1697     default:
1698       /* Error case --- will have been caught already */
1699       wassert(0);
1700       return FALSE;
1701     }
1702 }
1703
1704 /*-----------------------------------------------------------------*/
1705 /* aopPut - puts a string for a aop and indicates if acc is in use */
1706 /*-----------------------------------------------------------------*/
1707 static bool
1708 aopPut (operand * result, const char *s, int offset)
1709 {
1710   bool bvolatile = isOperandVolatile (result, FALSE);
1711   bool accuse = FALSE;
1712   asmop * aop = AOP (result);
1713
1714   if (aop->size && offset > (aop->size - 1))
1715     {
1716       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1717               "aopPut got offset > aop->size");
1718       exit (1);
1719     }
1720
1721   /* will assign value to value */
1722   /* depending on where it is ofcourse */
1723   switch (aop->type)
1724     {
1725     case AOP_DUMMY:
1726       MOVA (s);         /* read s in case it was volatile */
1727       accuse = TRUE;
1728       break;
1729
1730     case AOP_DIR:
1731       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1732         {
1733           SNPRINTF (buffer, sizeof(buffer),
1734                     "(%s >> %d)",
1735                     aop->aopu.aop_dir, offset * 8);
1736         }
1737       else if (offset)
1738         {
1739           SNPRINTF (buffer, sizeof(buffer),
1740                     "(%s + %d)",
1741                     aop->aopu.aop_dir, offset);
1742         }
1743       else
1744         {
1745           SNPRINTF (buffer, sizeof(buffer),
1746                     "%s",
1747                     aop->aopu.aop_dir);
1748         }
1749
1750       if (strcmp (buffer, s) || bvolatile)
1751         {
1752           emitcode ("mov", "%s,%s", buffer, s);
1753         }
1754       if (!strcmp (buffer, "acc"))
1755         {
1756           accuse = TRUE;
1757         }
1758       break;
1759
1760     case AOP_REG:
1761       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1762           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1763         {
1764           if (*s == '@' ||
1765               strcmp (s, "r0") == 0 ||
1766               strcmp (s, "r1") == 0 ||
1767               strcmp (s, "r2") == 0 ||
1768               strcmp (s, "r3") == 0 ||
1769               strcmp (s, "r4") == 0 ||
1770               strcmp (s, "r5") == 0 ||
1771               strcmp (s, "r6") == 0 ||
1772               strcmp (s, "r7") == 0)
1773             {
1774               emitcode ("mov", "%s,%s",
1775                         aop->aopu.aop_reg[offset]->dname, s);
1776             }
1777             else
1778             {
1779               emitcode ("mov", "%s,%s",
1780                         aop->aopu.aop_reg[offset]->name, s);
1781             }
1782         }
1783       break;
1784
1785     case AOP_DPTRn:
1786         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1787         break;
1788
1789     case AOP_DPTR:
1790     case AOP_DPTR2:
1791
1792       if (aop->type == AOP_DPTR2)
1793         {
1794           genSetDPTR (1);
1795         }
1796       _flushLazyDPS ();
1797
1798       if (aop->code)
1799         {
1800           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1801                   "aopPut writing to code space");
1802           exit (1);
1803         }
1804
1805       while (offset > aop->coff)
1806         {
1807           aop->coff++;
1808           emitcode ("inc", "dptr");
1809         }
1810
1811       while (offset < aop->coff)
1812         {
1813           aop->coff--;
1814           emitcode ("lcall", "__decdptr");
1815         }
1816
1817       aop->coff = offset;
1818
1819       /* if not in accumulator */
1820       MOVA (s);
1821
1822       emitcode ("movx", "@dptr,a");
1823
1824       if (aop->type == AOP_DPTR2)
1825         {
1826           genSetDPTR (0);
1827         }
1828       break;
1829
1830     case AOP_R0:
1831     case AOP_R1:
1832       while (offset > aop->coff)
1833         {
1834           aop->coff++;
1835           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1836         }
1837       while (offset < aop->coff)
1838         {
1839           aop->coff--;
1840           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1841         }
1842       aop->coff = offset;
1843
1844       if (aop->paged)
1845         {
1846           MOVA (s);
1847           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1848         }
1849       else if (*s == '@')
1850         {
1851           MOVA (s);
1852           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1853         }
1854       else if (strcmp (s, "r0") == 0 ||
1855                strcmp (s, "r1") == 0 ||
1856                strcmp (s, "r2") == 0 ||
1857                strcmp (s, "r3") == 0 ||
1858                strcmp (s, "r4") == 0 ||
1859                strcmp (s, "r5") == 0 ||
1860                strcmp (s, "r6") == 0 ||
1861                strcmp (s, "r7") == 0)
1862         {
1863           char buffer[10];
1864           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1865           emitcode ("mov", "@%s,%s",
1866                     aop->aopu.aop_ptr->name, buffer);
1867         }
1868         else
1869         {
1870             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1871         }
1872       break;
1873
1874     case AOP_STK:
1875       if (strcmp (s, "a") == 0)
1876         emitcode ("push", "acc");
1877       else
1878         if (*s=='@') {
1879           MOVA(s);
1880           emitcode ("push", "acc");
1881         } else {
1882           emitcode ("push", s);
1883         }
1884
1885       break;
1886
1887     case AOP_CRY:
1888       /* if not bit variable */
1889       if (!aop->aopu.aop_dir)
1890         {
1891           /* inefficient: move carry into A and use jz/jnz */
1892           emitcode ("clr", "a");
1893           emitcode ("rlc", "a");
1894           accuse = TRUE;
1895         }
1896       else
1897         {
1898           if (s == zero)
1899             emitcode ("clr", "%s", aop->aopu.aop_dir);
1900           else if (s == one)
1901             emitcode ("setb", "%s", aop->aopu.aop_dir);
1902           else if (!strcmp (s, "c"))
1903             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1904           else if (strcmp (s, aop->aopu.aop_dir))
1905             {
1906                   MOVA (s);
1907                 /* set C, if a >= 1 */
1908                 emitcode ("add", "a,#!constbyte",0xff);
1909                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1910               }
1911             }
1912       break;
1913
1914     case AOP_STR:
1915       aop->coff = offset;
1916       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1917         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1918       break;
1919
1920     case AOP_ACC:
1921       accuse = TRUE;
1922       aop->coff = offset;
1923       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1924         break;
1925
1926       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1927         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1928       break;
1929
1930     default:
1931       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1932               "aopPut got unsupported aop->type");
1933       exit (1);
1934     }
1935
1936     return accuse;
1937 }
1938
1939
1940 /*--------------------------------------------------------------------*/
1941 /* reAdjustPreg - points a register back to where it should (coff==0) */
1942 /*--------------------------------------------------------------------*/
1943 static void
1944 reAdjustPreg (asmop * aop)
1945 {
1946   if ((aop->coff==0) || (aop->size <= 1))
1947     return;
1948
1949   switch (aop->type)
1950     {
1951     case AOP_R0:
1952     case AOP_R1:
1953       while (aop->coff--)
1954         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1955       break;
1956     case AOP_DPTR:
1957     case AOP_DPTR2:
1958       if (aop->type == AOP_DPTR2)
1959         {
1960           genSetDPTR (1);
1961           _flushLazyDPS ();
1962         }
1963       while (aop->coff--)
1964         {
1965           emitcode ("lcall", "__decdptr");
1966         }
1967
1968       if (aop->type == AOP_DPTR2)
1969         {
1970           genSetDPTR (0);
1971         }
1972       break;
1973     }
1974   aop->coff = 0;
1975 }
1976
1977 /*-----------------------------------------------------------------*/
1978 /* opIsGptr: returns non-zero if the passed operand is       */
1979 /* a generic pointer type.             */
1980 /*-----------------------------------------------------------------*/
1981 static int
1982 opIsGptr (operand * op)
1983 {
1984   sym_link *type = operandType (op);
1985
1986   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1987     {
1988       return 1;
1989     }
1990   return 0;
1991 }
1992
1993 /*-----------------------------------------------------------------*/
1994 /* getDataSize - get the operand data size                         */
1995 /*-----------------------------------------------------------------*/
1996 static int
1997 getDataSize (operand * op)
1998 {
1999   int size;
2000   size = AOP_SIZE (op);
2001   if (size == GPTRSIZE)
2002     {
2003       sym_link *type = operandType (op);
2004       if (IS_GENPTR (type))
2005         {
2006           /* generic pointer; arithmetic operations
2007            * should ignore the high byte (pointer type).
2008            */
2009           size--;
2010         }
2011     }
2012   return size;
2013 }
2014
2015 /*-----------------------------------------------------------------*/
2016 /* outAcc - output Acc                                             */
2017 /*-----------------------------------------------------------------*/
2018 static void
2019 outAcc (operand * result)
2020 {
2021   int size, offset;
2022   size = getDataSize (result);
2023   if (size)
2024     {
2025       aopPut (result, "a", 0);
2026       size--;
2027       offset = 1;
2028       /* unsigned or positive */
2029       while (size--)
2030         {
2031           aopPut (result, zero, offset++);
2032         }
2033     }
2034 }
2035
2036 /*-----------------------------------------------------------------*/
2037 /* outBitC - output a bit C                                        */
2038 /*-----------------------------------------------------------------*/
2039 static void
2040 outBitC (operand * result)
2041 {
2042   /* if the result is bit */
2043   if (AOP_TYPE (result) == AOP_CRY)
2044     {
2045       aopPut (result, "c", 0);
2046     }
2047   else
2048     {
2049       emitcode ("clr", "a");
2050       emitcode ("rlc", "a");
2051       outAcc (result);
2052     }
2053 }
2054
2055 /*-----------------------------------------------------------------*/
2056 /* toBoolean - emit code for orl a,operator(sizeop)                */
2057 /*-----------------------------------------------------------------*/
2058 static void
2059 toBoolean (operand * oper)
2060 {
2061   int  size = AOP_SIZE (oper) - 1;
2062   int  offset = 1;
2063   bool pushedB;
2064
2065   /* The generic part of a generic pointer should
2066    * not participate in it's truth value.
2067    *
2068    * i.e. 0x10000000 is zero.
2069    */
2070   if (opIsGptr (oper))
2071     {
2072       D (emitcode (";", "toBoolean: generic ptr special case."));
2073       size--;
2074     }
2075
2076   _startLazyDPSEvaluation ();
2077   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2078   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2079     {
2080       pushedB = pushB ();
2081       emitcode("mov", "b,a");
2082       while (--size)
2083         {
2084         MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2085           emitcode ("orl", "b,a");
2086         }
2087       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2088       emitcode ("orl", "a,b");
2089       popB (pushedB);
2090     }
2091   else
2092     {
2093       while (size--)
2094         {
2095           emitcode ("orl", "a,%s",
2096                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2097         }
2098     }
2099   _endLazyDPSEvaluation ();
2100 }
2101
2102
2103 /*-----------------------------------------------------------------*/
2104 /* genNot - generate code for ! operation                          */
2105 /*-----------------------------------------------------------------*/
2106 static void
2107 genNot (iCode * ic)
2108 {
2109   symbol *tlbl;
2110
2111   D (emitcode (";", "genNot"));
2112
2113   /* assign asmOps to operand & result */
2114   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2115   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2116
2117   /* if in bit space then a special case */
2118   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2119     {
2120       /* if left==result then cpl bit */
2121       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2122         {
2123           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2124         }
2125       else
2126         {
2127           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2128           emitcode ("cpl", "c");
2129           outBitC (IC_RESULT (ic));
2130         }
2131       goto release;
2132     }
2133
2134   toBoolean (IC_LEFT (ic));
2135
2136   /* set C, if a == 0 */
2137   tlbl = newiTempLabel (NULL);
2138   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2139   emitLabel (tlbl);
2140   outBitC (IC_RESULT (ic));
2141
2142 release:
2143   /* release the aops */
2144   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2145   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2146 }
2147
2148
2149 /*-----------------------------------------------------------------*/
2150 /* genCpl - generate code for complement                           */
2151 /*-----------------------------------------------------------------*/
2152 static void
2153 genCpl (iCode * ic)
2154 {
2155   int offset = 0;
2156   int size;
2157   symbol *tlbl;
2158   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2159
2160   D(emitcode (";", "genCpl"));
2161
2162   /* assign asmOps to operand & result */
2163   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2164   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2165
2166   /* special case if in bit space */
2167   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2168     {
2169       char *l;
2170
2171       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2172           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2173         {
2174           /* promotion rules are responsible for this strange result:
2175              bit -> int -> ~int -> bit
2176              uchar -> int -> ~int -> bit
2177           */
2178           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2179           goto release;
2180         }
2181
2182       tlbl=newiTempLabel(NULL);
2183       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2184       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2185           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2186           IS_AOP_PREG (IC_LEFT (ic)))
2187         {
2188           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2189         }
2190       else
2191         {
2192           MOVA (l);
2193           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2194         }
2195       emitLabel (tlbl);
2196       outBitC (IC_RESULT(ic));
2197       goto release;
2198     }
2199
2200   size = AOP_SIZE (IC_RESULT (ic));
2201   _startLazyDPSEvaluation ();
2202   while (size--)
2203     {
2204       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2205       MOVA (l);
2206       emitcode ("cpl", "a");
2207       aopPut (IC_RESULT (ic), "a", offset++);
2208     }
2209   _endLazyDPSEvaluation ();
2210
2211
2212 release:
2213   /* release the aops */
2214   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2215   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2216 }
2217
2218 /*-----------------------------------------------------------------*/
2219 /* genUminusFloat - unary minus for floating points                */
2220 /*-----------------------------------------------------------------*/
2221 static void
2222 genUminusFloat (operand * op, operand * result)
2223 {
2224   int size, offset = 0;
2225   char *l;
2226
2227   D (emitcode (";", "genUminusFloat"));
2228
2229   /* for this we just copy and then flip the bit */
2230
2231   _startLazyDPSEvaluation ();
2232   size = AOP_SIZE (op) - 1;
2233
2234   while (size--)
2235     {
2236       aopPut (result,
2237               aopGet (op, offset, FALSE, FALSE, NULL),
2238               offset);
2239       offset++;
2240     }
2241
2242   l = aopGet (op, offset, FALSE, FALSE, NULL);
2243   MOVA (l);
2244
2245   emitcode ("cpl", "acc.7");
2246   aopPut (result, "a", offset);
2247   _endLazyDPSEvaluation ();
2248 }
2249
2250 /*-----------------------------------------------------------------*/
2251 /* genUminus - unary minus code generation                         */
2252 /*-----------------------------------------------------------------*/
2253 static void
2254 genUminus (iCode * ic)
2255 {
2256   int offset, size;
2257   sym_link *optype;
2258
2259   D (emitcode (";", "genUminus"));
2260
2261   /* assign asmops */
2262   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2263   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2264
2265   /* if both in bit space then special
2266      case */
2267   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2268       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2269     {
2270
2271       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2272       emitcode ("cpl", "c");
2273       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2274       goto release;
2275     }
2276
2277   optype = operandType (IC_LEFT (ic));
2278
2279   /* if float then do float stuff */
2280   if (IS_FLOAT (optype))
2281     {
2282       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2283       goto release;
2284     }
2285
2286   /* otherwise subtract from zero */
2287   size = AOP_SIZE (IC_LEFT (ic));
2288   offset = 0;
2289   _startLazyDPSEvaluation ();
2290   while (size--)
2291     {
2292       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2293       if (!strcmp (l, "a"))
2294         {
2295           if (offset == 0)
2296             SETC;
2297           emitcode ("cpl", "a");
2298           emitcode ("addc", "a,#0");
2299         }
2300       else
2301         {
2302           if (offset == 0)
2303             CLRC;
2304           emitcode ("clr", "a");
2305           emitcode ("subb", "a,%s", l);
2306         }
2307       aopPut (IC_RESULT (ic), "a", offset++);
2308     }
2309   _endLazyDPSEvaluation ();
2310
2311   /* if any remaining bytes in the result */
2312   /* we just need to propagate the sign   */
2313   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2314     {
2315       emitcode ("rlc", "a");
2316       emitcode ("subb", "a,acc");
2317       while (size--)
2318         aopPut (IC_RESULT (ic), "a", offset++);
2319     }
2320
2321 release:
2322   /* release the aops */
2323   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2324   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2325 }
2326
2327 /*-----------------------------------------------------------------*/
2328 /* savermask - saves registers in the mask                         */
2329 /*-----------------------------------------------------------------*/
2330 static void savermask(bitVect *rs_mask)
2331 {
2332   int i;
2333   if (options.useXstack)
2334     {
2335       if (bitVectBitValue (rs_mask, R0_IDX))
2336           emitcode ("mov", "b,r0");
2337       emitcode ("mov", "r0,%s", spname);
2338       for (i = 0; i < ds390_nRegs; i++)
2339         {
2340           if (bitVectBitValue (rs_mask, i))
2341             {
2342               if (i == R0_IDX)
2343                   emitcode ("mov", "a,b");
2344               else
2345                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2346               emitcode ("movx", "@r0,a");
2347               emitcode ("inc", "r0");
2348             }
2349         }
2350       emitcode ("mov", "%s,r0", spname);
2351       if (bitVectBitValue (rs_mask, R0_IDX))
2352           emitcode ("mov", "r0,b");
2353     }
2354   else
2355     {
2356       bool bits_pushed = FALSE;
2357       for (i = 0; i < ds390_nRegs; i++)
2358         {
2359           if (bitVectBitValue (rs_mask, i))
2360             {
2361               bits_pushed = pushReg (i, bits_pushed);
2362             }
2363         }
2364     }
2365 }
2366
2367 /*-----------------------------------------------------------------*/
2368 /* saveRegisters - will look for a call and save the registers     */
2369 /*-----------------------------------------------------------------*/
2370 static void
2371 saveRegisters (iCode * lic)
2372 {
2373   iCode *ic;
2374   bitVect *rsave;
2375
2376   /* look for call */
2377   for (ic = lic; ic; ic = ic->next)
2378     if (ic->op == CALL || ic->op == PCALL)
2379       break;
2380
2381   if (!ic)
2382     {
2383       fprintf (stderr, "found parameter push with no function call\n");
2384       return;
2385     }
2386
2387   /* if the registers have been saved already or don't need to be then
2388      do nothing */
2389   if (ic->regsSaved
2390       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2391     return ;
2392
2393   /* special case if DPTR alive across a function call then must save it
2394      even though callee saves */
2395   if (IS_SYMOP(IC_LEFT(ic)) &&
2396       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2397     {
2398       int i;
2399       rsave = newBitVect(ic->rMask->size);
2400       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2401           if (bitVectBitValue(ic->rMask,i))
2402               rsave = bitVectSetBit(rsave,i);
2403       }
2404       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2405     }
2406   else
2407     {
2408       /* save the registers in use at this time but skip the
2409          ones for the result */
2410       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2411                              ds390_rUmaskForOp (IC_RESULT(ic)));
2412     }
2413   ic->regsSaved = 1;
2414   savermask(rsave);
2415 }
2416
2417 /*-----------------------------------------------------------------*/
2418 /* usavermask - restore registers with mask                        */
2419 /*-----------------------------------------------------------------*/
2420 static void unsavermask(bitVect *rs_mask)
2421 {
2422     int i;
2423     if (options.useXstack) {
2424         emitcode ("mov", "r0,%s", spname);
2425       for (i = ds390_nRegs; i >= 0; i--)
2426         {
2427           if (bitVectBitValue (rs_mask, i))
2428             {
2429               regs * reg = REG_WITH_INDEX (i);
2430               emitcode ("dec", "r0");
2431               emitcode ("movx", "a,@r0");
2432               if (i == R0_IDX)
2433                 {
2434                   emitcode ("push", "acc");
2435                 }
2436               else
2437                 {
2438                   emitcode ("mov", "%s,a", reg->name);
2439                 }
2440             }
2441         }
2442       emitcode ("mov", "%s,r0", spname);
2443       if (bitVectBitValue (rs_mask, R0_IDX))
2444         {
2445           emitcode ("pop", "ar0");
2446         }
2447     }
2448   else
2449     {
2450       bool bits_popped = FALSE;
2451       for (i = ds390_nRegs; i >= 0; i--)
2452         {
2453             if (bitVectBitValue (rs_mask, i))
2454             {
2455               bits_popped = popReg (i, bits_popped);
2456             }
2457         }
2458     }
2459 }
2460
2461 /*-----------------------------------------------------------------*/
2462 /* unsaveRegisters - pop the pushed registers                      */
2463 /*-----------------------------------------------------------------*/
2464 static void
2465 unsaveRegisters (iCode * ic)
2466 {
2467   bitVect *rsave;
2468
2469   if (IS_SYMOP(IC_LEFT (ic)) &&
2470       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2471       int i;
2472       rsave = newBitVect(ic->rMask->size);
2473       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2474           if (bitVectBitValue(ic->rMask,i))
2475               rsave = bitVectSetBit(rsave,i);
2476       }
2477       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2478   } else {
2479     /* restore the registers in use at this time but skip the
2480        ones for the result */
2481     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2482                            ds390_rUmaskForOp (IC_RESULT(ic)));
2483   }
2484   unsavermask(rsave);
2485 }
2486
2487
2488 /*-----------------------------------------------------------------*/
2489 /* pushSide -                */
2490 /*-----------------------------------------------------------------*/
2491 static void
2492 pushSide (operand * oper, int size)
2493 {
2494   int offset = 0;
2495   _startLazyDPSEvaluation ();
2496   while (size--)
2497     {
2498       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2499       if (AOP_TYPE (oper) != AOP_REG &&
2500           AOP_TYPE (oper) != AOP_DIR &&
2501           strcmp (l, "a"))
2502         {
2503           MOVA (l);
2504           emitcode ("push", "acc");
2505         }
2506       else
2507         {
2508         emitcode ("push", "%s", l);
2509     }
2510     }
2511   _endLazyDPSEvaluation ();
2512 }
2513
2514 /*-----------------------------------------------------------------*/
2515 /* assignResultValue - also indicates if acc is in use afterwards  */
2516 /*-----------------------------------------------------------------*/
2517 static bool
2518 assignResultValue (operand * oper, operand * func)
2519 {
2520   int offset = 0;
2521   unsigned size = AOP_SIZE (oper);
2522   bool accuse = FALSE;
2523   bool pushedA = FALSE;
2524
2525   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2526     {
2527       outBitC (oper);
2528       return FALSE;
2529     }
2530
2531   if (size == fReturnSizeDS390)
2532   {
2533       /* I don't think this case can ever happen... */
2534       /* ACC is the last part of this. If writing the result
2535        * uses ACC, we must preserve it.
2536        */
2537       if (AOP_NEEDSACC(oper))
2538       {
2539           emitcode(";", "assignResultValue special case for ACC.");
2540           emitcode("push", "acc");
2541           pushedA = TRUE;
2542           size--;
2543       }
2544   }
2545
2546   _startLazyDPSEvaluation ();
2547   while (size--)
2548     {
2549       accuse |= aopPut (oper, fReturn[offset], offset);
2550       offset++;
2551     }
2552   _endLazyDPSEvaluation ();
2553
2554   if (pushedA)
2555     {
2556         emitcode ("pop", "acc");
2557         accuse |= aopPut (oper, "a", offset);
2558     }
2559   return accuse;
2560 }
2561
2562
2563 /*-----------------------------------------------------------------*/
2564 /* genXpush - pushes onto the external stack                       */
2565 /*-----------------------------------------------------------------*/
2566 static void
2567 genXpush (iCode * ic)
2568 {
2569   asmop *aop = newAsmop (0);
2570   regs *r;
2571   int size, offset = 0;
2572
2573   D (emitcode (";", "genXpush"));
2574
2575   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2576   r = getFreePtr (ic, &aop, FALSE);
2577
2578   size = AOP_SIZE (IC_LEFT (ic));
2579
2580   if (size == 1)
2581     {
2582       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2583       emitcode ("mov", "%s,_spx", r->name);
2584       emitcode ("inc", "_spx"); // allocate space first
2585       emitcode ("movx", "@%s,a", r->name);
2586     }
2587   else
2588     {
2589       // allocate space first
2590       emitcode ("mov", "%s,_spx", r->name);
2591       MOVA (r->name);
2592       emitcode ("add", "a,#%d", size);
2593       emitcode ("mov", "_spx,a");
2594
2595       _startLazyDPSEvaluation ();
2596       while (size--)
2597         {
2598           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2599           emitcode ("movx", "@%s,a", r->name);
2600           emitcode ("inc", "%s", r->name);
2601         }
2602       _endLazyDPSEvaluation ();
2603     }
2604
2605   freeAsmop (NULL, aop, ic, TRUE);
2606   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2607 }
2608
2609 /*-----------------------------------------------------------------*/
2610 /* genIpush - generate code for pushing this gets a little complex  */
2611 /*-----------------------------------------------------------------*/
2612 static void
2613 genIpush (iCode * ic)
2614 {
2615   int size, offset = 0;
2616   char *l;
2617   char *prev = "";
2618
2619   D (emitcode (";", "genIpush"));
2620
2621   /* if this is not a parm push : ie. it is spill push
2622      and spill push is always done on the local stack */
2623   if (!ic->parmPush)
2624     {
2625
2626       /* and the item is spilt then do nothing */
2627       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2628         return;
2629
2630       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2631       size = AOP_SIZE (IC_LEFT (ic));
2632       /* push it on the stack */
2633       _startLazyDPSEvaluation ();
2634       while (size--)
2635         {
2636           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2637           if (*l == '#')
2638             {
2639               MOVA (l);
2640               l = "acc";
2641             }
2642           emitcode ("push", "%s", l);
2643         }
2644       _endLazyDPSEvaluation ();
2645       return;
2646     }
2647
2648   /* this is a parameter push: in this case we call
2649      the routine to find the call and save those
2650      registers that need to be saved */
2651   saveRegisters (ic);
2652
2653   /* if use external stack then call the external
2654      stack pushing routine */
2655   if (options.useXstack)
2656     {
2657       genXpush (ic);
2658       return;
2659     }
2660
2661   /* then do the push */
2662   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2663
2664   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2665   size = AOP_SIZE (IC_LEFT (ic));
2666
2667   _startLazyDPSEvaluation ();
2668   while (size--)
2669     {
2670       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2671       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2672           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2673           strcmp (l, "acc"))
2674         {
2675           if (strcmp (l, prev) || *l == '@')
2676             MOVA (l);
2677           emitcode ("push", "acc");
2678         }
2679       else
2680         {
2681             emitcode ("push", "%s", l);
2682         }
2683       prev = l;
2684     }
2685   _endLazyDPSEvaluation ();
2686
2687   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2688 }
2689
2690 /*-----------------------------------------------------------------*/
2691 /* genIpop - recover the registers: can happen only for spilling   */
2692 /*-----------------------------------------------------------------*/
2693 static void
2694 genIpop (iCode * ic)
2695 {
2696   int size, offset;
2697
2698   D (emitcode (";", "genIpop"));
2699
2700   /* if the temp was not pushed then */
2701   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2702     return;
2703
2704   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2705   size = AOP_SIZE (IC_LEFT (ic));
2706   offset = (size - 1);
2707   _startLazyDPSEvaluation ();
2708   while (size--)
2709     {
2710       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2711                                      FALSE, TRUE, NULL));
2712     }
2713   _endLazyDPSEvaluation ();
2714
2715   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2716 }
2717
2718 /*-----------------------------------------------------------------*/
2719 /* saveRBank - saves an entire register bank on the stack          */
2720 /*-----------------------------------------------------------------*/
2721 static void
2722 saveRBank (int bank, iCode * ic, bool pushPsw)
2723 {
2724   int i;
2725   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2726   asmop *aop = NULL;
2727   regs *r = NULL;
2728
2729   if (options.useXstack)
2730   {
2731       if (!ic)
2732       {
2733           /* Assume r0 is available for use. */
2734           r = REG_WITH_INDEX (R0_IDX);;
2735       }
2736       else
2737       {
2738           aop = newAsmop (0);
2739           r = getFreePtr (ic, &aop, FALSE);
2740       }
2741       // allocate space first
2742       emitcode ("mov", "%s,_spx", r->name);
2743       MOVA (r->name);
2744       emitcode ("add", "a,#%d", count);
2745       emitcode ("mov", "_spx,a");
2746   }
2747
2748   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2749     {
2750       if (options.useXstack)
2751       {
2752           emitcode ("mov", "a,(%s+%d)",
2753                     regs390[i].base, 8 * bank + regs390[i].offset);
2754           emitcode ("movx", "@%s,a", r->name);
2755           if (--count)
2756             emitcode ("inc", "%s", r->name);
2757         }
2758       else
2759         emitcode ("push", "(%s+%d)",
2760                   regs390[i].base, 8 * bank + regs390[i].offset);
2761     }
2762
2763   if (ds390_nBitRegs > 0)
2764     {
2765       if (options.useXstack)
2766         {
2767           emitcode ("mov", "a,bits");
2768           emitcode ("movx", "@%s,a", r->name);
2769           if (--count)
2770             emitcode ("inc", "%s", r->name);
2771         }
2772       else
2773         {
2774           emitcode ("push", "bits");
2775         }
2776       BitBankUsed = 1;
2777     }
2778
2779   if (pushPsw)
2780     {
2781       if (options.useXstack)
2782         {
2783           emitcode ("mov", "a,psw");
2784           emitcode ("movx", "@%s,a", r->name);
2785         }
2786       else
2787       {
2788         emitcode ("push", "psw");
2789     }
2790
2791       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2792     }
2793
2794   if (aop)
2795   {
2796       freeAsmop (NULL, aop, ic, TRUE);
2797   }
2798
2799   if (ic)
2800   {
2801     ic->bankSaved = 1;
2802   }
2803 }
2804
2805 /*-----------------------------------------------------------------*/
2806 /* unsaveRBank - restores the register bank from stack             */
2807 /*-----------------------------------------------------------------*/
2808 static void
2809 unsaveRBank (int bank, iCode * ic, bool popPsw)
2810 {
2811   int i;
2812   asmop *aop = NULL;
2813   regs *r = NULL;
2814
2815   if (options.useXstack)
2816     {
2817         if (!ic)
2818         {
2819           /* Assume r0 is available for use. */
2820           r = REG_WITH_INDEX (R0_IDX);;
2821         }
2822         else
2823         {
2824           aop = newAsmop (0);
2825           r = getFreePtr (ic, &aop, FALSE);
2826         }
2827         emitcode ("mov", "%s,_spx", r->name);
2828     }
2829
2830   if (popPsw)
2831     {
2832       if (options.useXstack)
2833         {
2834           emitcode ("dec", "%s", r->name);
2835           emitcode ("movx", "a,@%s", r->name);
2836           emitcode ("mov", "psw,a");
2837         }
2838       else
2839       {
2840         emitcode ("pop", "psw");
2841       }
2842     }
2843
2844   if (ds390_nBitRegs > 0)
2845     {
2846       if (options.useXstack)
2847         {
2848           emitcode ("dec", "%s", r->name);
2849           emitcode ("movx", "a,@%s", r->name);
2850           emitcode ("mov", "bits,a");
2851         }
2852       else
2853         {
2854           emitcode ("pop", "bits");
2855         }
2856     }
2857
2858   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2859     {
2860       if (options.useXstack)
2861         {
2862           emitcode ("dec", "%s", r->name);
2863           emitcode ("movx", "a,@%s", r->name);
2864           emitcode ("mov", "(%s+%d),a",
2865                     regs390[i].base, 8 * bank + regs390[i].offset);
2866         }
2867       else
2868         {
2869           emitcode ("pop", "(%s+%d)",
2870                   regs390[i].base, 8 * bank + regs390[i].offset);
2871         }
2872     }
2873
2874   if (options.useXstack)
2875     {
2876       emitcode ("mov", "_spx,%s", r->name);
2877     }
2878
2879   if (aop)
2880   {
2881     freeAsmop (NULL, aop, ic, TRUE);
2882   }
2883 }
2884
2885 /*-----------------------------------------------------------------*/
2886 /* genSend - gen code for SEND                                     */
2887 /*-----------------------------------------------------------------*/
2888 static void genSend(set *sendSet)
2889 {
2890     iCode *sic;
2891   int bit_count = 0;
2892     int sendCount = 0 ;
2893     static int rb1_count = 0;
2894
2895   /* first we do all bit parameters */
2896     for (sic = setFirstItem (sendSet); sic;
2897        sic = setNextItem (sendSet))
2898     {
2899       if (sic->argreg > 12)
2900         {
2901           int bit = sic->argreg-13;
2902
2903           aopOp (IC_LEFT (sic), sic, FALSE,
2904                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2905
2906           /* if left is a literal then
2907              we know what the value is */
2908           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2909             {
2910               if (((int) operandLitValue (IC_LEFT (sic))))
2911                   emitcode ("setb", "b[%d]", bit);
2912               else
2913                   emitcode ("clr", "b[%d]", bit);
2914             }
2915           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2916             {
2917               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2918                 if (strcmp (l, "c"))
2919                     emitcode ("mov", "c,%s", l);
2920                 emitcode ("mov", "b[%d],c", bit);
2921             }
2922           else
2923             {
2924               /* we need to or */
2925               toBoolean (IC_LEFT (sic));
2926               /* set C, if a >= 1 */
2927               emitcode ("add", "a,#0xff");
2928               emitcode ("mov", "b[%d],c", bit);
2929             }
2930           bit_count++;
2931           BitBankUsed = 1;
2932
2933           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2934         }
2935     }
2936
2937   if (bit_count)
2938     {
2939       saveRegisters (setFirstItem (sendSet));
2940       emitcode ("mov", "bits,b");
2941     }
2942
2943   /* then we do all other parameters */
2944   for (sic = setFirstItem (sendSet); sic;
2945        sic = setNextItem (sendSet))
2946     {
2947       if (sic->argreg <= 12)
2948       {
2949         int size, offset = 0;
2950
2951         size = getSize (operandType (IC_LEFT (sic)));
2952         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2953         if (sendCount == 0) { /* first parameter */
2954             // we know that dpl(hxb) is the result, so
2955             rb1_count = 0 ;
2956             _startLazyDPSEvaluation ();
2957             if (size>1) {
2958                 aopOp (IC_LEFT (sic), sic, FALSE,
2959                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2960             } else {
2961                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2962             }
2963             while (size--)
2964               {
2965                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2966                 if (strcmp (l, fReturn[offset]))
2967                   {
2968                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2969                 }
2970                 offset++;
2971             }
2972             _endLazyDPSEvaluation ();
2973             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2974             rb1_count =0;
2975         } else { /* if more parameter in registers */
2976             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2977             while (size--) {
2978                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2979                                                                 FALSE, FALSE, NULL));
2980             }
2981             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2982         }
2983         sendCount++;
2984       }
2985     }
2986 }
2987
2988 static void
2989 adjustEsp(const char *reg)
2990 {
2991     emitcode ("anl","%s,#3", reg);
2992     if (TARGET_IS_DS400)
2993     {
2994         emitcode ("orl","%s,#!constbyte",
2995                   reg,
2996                   (options.stack_loc >> 8) & 0xff);
2997     }
2998 }
2999
3000 /*-----------------------------------------------------------------*/
3001 /* selectRegBank - emit code to select the register bank           */
3002 /*-----------------------------------------------------------------*/
3003 static void
3004 selectRegBank (short bank, bool keepFlags)
3005 {
3006   /* if f.e. result is in carry */
3007   if (keepFlags)
3008     {
3009       emitcode ("anl", "psw,#0xE7");
3010       if (bank)
3011         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
3012     }
3013   else
3014     {
3015       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
3016     }
3017 }
3018
3019 /*-----------------------------------------------------------------*/
3020 /* genCall - generates a call statement                            */
3021 /*-----------------------------------------------------------------*/
3022 static void
3023 genCall (iCode * ic)
3024 {
3025   sym_link *dtype;
3026   sym_link *etype;
3027   bool restoreBank = FALSE;
3028   bool swapBanks = FALSE;
3029   bool accuse = FALSE;
3030   bool accPushed = FALSE;
3031   bool resultInF0 = FALSE;
3032   bool assignResultGenerated = FALSE;
3033
3034   D (emitcode (";", "genCall"));
3035
3036   /* if we are calling a not _naked function that is not using
3037      the same register bank then we need to save the
3038      destination registers on the stack */
3039   dtype = operandType (IC_LEFT (ic));
3040   etype = getSpec(dtype);
3041   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3042       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3043       IFFUNC_ISISR (currFunc->type))
3044   {
3045       if (!ic->bankSaved)
3046       {
3047            /* This is unexpected; the bank should have been saved in
3048             * genFunction.
3049             */
3050            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3051            restoreBank = TRUE;
3052       }
3053       swapBanks = TRUE;
3054   }
3055
3056     /* if caller saves & we have not saved then */
3057     if (!ic->regsSaved)
3058       saveRegisters (ic);
3059
3060   /* if send set is not empty then assign */
3061   /* We've saved all the registers we care about;
3062   * therefore, we may clobber any register not used
3063   * in the calling convention (i.e. anything not in
3064   * fReturn.
3065   */
3066   if (_G.sendSet)
3067     {
3068         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3069             genSend(reverseSet(_G.sendSet));
3070         } else {
3071             genSend(_G.sendSet);
3072         }
3073       _G.sendSet = NULL;
3074     }
3075
3076   if (swapBanks)
3077   {
3078         emitcode ("mov", "psw,#!constbyte",
3079            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3080   }
3081
3082   /* make the call */
3083   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3084                             OP_SYMBOL (IC_LEFT (ic))->rname :
3085                             OP_SYMBOL (IC_LEFT (ic))->name));
3086
3087   if (swapBanks)
3088     {
3089       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3090     }
3091
3092   /* if we need assign a result value */
3093   if ((IS_ITEMP (IC_RESULT (ic)) &&
3094        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3095        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3096         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3097         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3098       IS_TRUE_SYMOP (IC_RESULT (ic)))
3099     {
3100       if (isOperandInFarSpace (IC_RESULT (ic))
3101           && getSize (operandType (IC_RESULT (ic))) <= 2)
3102         {
3103           int size = getSize (operandType (IC_RESULT (ic)));
3104           bool pushedB = FALSE;
3105
3106           /* Special case for 1 or 2 byte return in far space. */
3107           MOVA (fReturn[0]);
3108           if (size > 1)
3109             {
3110               pushedB = pushB ();
3111               emitcode ("mov", "b,%s", fReturn[1]);
3112             }
3113
3114           _G.accInUse++;
3115           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3116           _G.accInUse--;
3117
3118           popB (pushedB);
3119
3120           aopPut (IC_RESULT (ic), "a", 0);
3121
3122           if (size > 1)
3123             {
3124               aopPut (IC_RESULT (ic), "b", 1);
3125             }
3126           assignResultGenerated = TRUE;
3127           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3128         }
3129       else
3130         {
3131           bool pushedB = pushB ();
3132           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3133           popB (pushedB);
3134
3135           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3136           assignResultGenerated = TRUE;
3137           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3138         }
3139     }
3140
3141   /* adjust the stack for parameters if required */
3142   if (ic->parmBytes)
3143     {
3144       int i;
3145       if (options.stack10bit) {
3146           if (ic->parmBytes <= 10) {
3147               emitcode(";","stack adjustment for parms");
3148               for (i=0; i < ic->parmBytes ; i++) {
3149                   emitcode("pop","acc");
3150               }
3151           } else {
3152               PROTECT_SP;
3153               emitcode ("clr","c");
3154               emitcode ("mov","a,sp");
3155               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3156               emitcode ("mov","sp,a");
3157               emitcode ("mov","a,esp");
3158               adjustEsp("a");
3159               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3160               emitcode ("mov","esp,a");
3161               UNPROTECT_SP;
3162           }
3163       } else {
3164           if (ic->parmBytes > 3)
3165             {
3166               if (accuse)
3167                 {
3168                   emitcode ("push", "acc");
3169                   accPushed = TRUE;
3170                 }
3171             if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3172                 IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3173                 !assignResultGenerated)
3174               {
3175                 emitcode ("mov", "F0,c");
3176                 resultInF0 = TRUE;
3177               }
3178
3179               emitcode ("mov", "a,%s", spname);
3180               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3181               emitcode ("mov", "%s,a", spname);
3182
3183               /* unsaveRegisters from xstack needs acc, but */
3184               /* unsaveRegisters from stack needs this popped */
3185               if (accPushed && !options.useXstack)
3186                 {
3187                   emitcode ("pop", "acc");
3188                   accPushed = FALSE;
3189                 }
3190             }
3191           else
3192               for (i = 0; i < ic->parmBytes; i++)
3193                   emitcode ("dec", "%s", spname);
3194       }
3195   }
3196
3197   /* if we had saved some registers then unsave them */
3198   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3199     {
3200       if (accuse && !accPushed && options.useXstack)
3201         {
3202           /* xstack needs acc, but doesn't touch normal stack */
3203           emitcode ("push", "acc");
3204           accPushed = TRUE;
3205         }
3206       unsaveRegisters (ic);
3207     }
3208
3209   /* if register bank was saved then pop them */
3210   if (restoreBank)
3211     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3212
3213   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3214     {
3215       if (resultInF0)
3216           emitcode ("mov", "c,F0");
3217
3218       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3219       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3220       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3221     }
3222
3223   if (accPushed)
3224     emitcode ("pop", "acc");
3225 }
3226
3227 /*-----------------------------------------------------------------*/
3228 /* genPcall - generates a call by pointer statement                */
3229 /*-----------------------------------------------------------------*/
3230 static void
3231 genPcall (iCode * ic)
3232 {
3233   sym_link *dtype;
3234   sym_link *etype;
3235   symbol *rlbl = newiTempLabel (NULL);
3236   bool restoreBank=FALSE;
3237   bool resultInF0 = FALSE;
3238
3239   D (emitcode (";", "genPcall"));
3240
3241   dtype = operandType (IC_LEFT (ic))->next;
3242   etype = getSpec(dtype);
3243   /* if caller saves & we have not saved then */
3244   if (!ic->regsSaved)
3245     saveRegisters (ic);
3246
3247   /* if we are calling a not _naked function that is not using
3248      the same register bank then we need to save the
3249      destination registers on the stack */
3250   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3251       IFFUNC_ISISR (currFunc->type) &&
3252       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3253     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3254     restoreBank=TRUE;
3255   }
3256
3257   /* push the return address on to the stack */
3258   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3259   emitcode ("push", "acc");
3260   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3261   emitcode ("push", "acc");
3262
3263   if (options.model == MODEL_FLAT24)
3264     {
3265       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3266       emitcode ("push", "acc");
3267     }
3268
3269   /* now push the calling address */
3270   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3271
3272   pushSide (IC_LEFT (ic), FPTRSIZE);
3273
3274   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3275
3276   /* if send set is not empty the assign */
3277   if (_G.sendSet)
3278     {
3279         genSend(reverseSet(_G.sendSet));
3280         _G.sendSet = NULL;
3281     }
3282
3283   /* make the call */
3284   emitcode ("ret", "");
3285   emitLabel (rlbl);
3286
3287
3288   /* if we need assign a result value */
3289   if ((IS_ITEMP (IC_RESULT (ic)) &&
3290        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3291        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3292         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3293       IS_TRUE_SYMOP (IC_RESULT (ic)))
3294     {
3295
3296       _G.accInUse++;
3297       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3298       _G.accInUse--;
3299
3300       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3301
3302       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3303     }
3304
3305   /* adjust the stack for parameters if required */
3306   if (ic->parmBytes)
3307     {
3308       int i;
3309       if (options.stack10bit) {
3310           if (ic->parmBytes <= 10) {
3311               emitcode(";","stack adjustment for parms");
3312               for (i=0; i < ic->parmBytes ; i++) {
3313                   emitcode("pop","acc");
3314               }
3315           } else {
3316               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3317                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3318                 {
3319                   emitcode ("mov", "F0,c");
3320                   resultInF0 = TRUE;
3321                 }
3322
3323               PROTECT_SP;
3324               emitcode ("clr","c");
3325               emitcode ("mov","a,sp");
3326               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3327               emitcode ("mov","sp,a");
3328               emitcode ("mov","a,esp");
3329               adjustEsp("a");
3330               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3331               emitcode ("mov","esp,a");
3332               UNPROTECT_SP;
3333           }
3334       } else {
3335           if (ic->parmBytes > 3) {
3336               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3337                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3338                 {
3339                   emitcode ("mov", "F0,c");
3340                   resultInF0 = TRUE;
3341                 }
3342
3343               emitcode ("mov", "a,%s", spname);
3344               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3345               emitcode ("mov", "%s,a", spname);
3346             }
3347           else
3348               for (i = 0; i < ic->parmBytes; i++)
3349                   emitcode ("dec", "%s", spname);
3350       }
3351     }
3352   /* if register bank was saved then unsave them */
3353   if (restoreBank)
3354     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3355
3356   /* if we had saved some registers then unsave them */
3357   if (ic->regsSaved)
3358     unsaveRegisters (ic);
3359
3360   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3361     {
3362       if (resultInF0)
3363           emitcode ("mov", "c,F0");
3364
3365       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3366       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3367       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3368     }
3369 }
3370
3371 /*-----------------------------------------------------------------*/
3372 /* resultRemat - result  is rematerializable                       */
3373 /*-----------------------------------------------------------------*/
3374 static int
3375 resultRemat (iCode * ic)
3376 {
3377   if (SKIP_IC (ic) || ic->op == IFX)
3378     return 0;
3379
3380   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3381     {
3382       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3383       if (sym->remat && !POINTER_SET (ic))
3384         return 1;
3385     }
3386
3387   return 0;
3388 }
3389
3390 #if defined(__BORLANDC__) || defined(_MSC_VER)
3391 #define STRCASECMP stricmp
3392 #else
3393 #define STRCASECMP strcasecmp
3394 #endif
3395
3396 /*-----------------------------------------------------------------*/
3397 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3398 /*-----------------------------------------------------------------*/
3399 static int
3400 regsCmp(void *p1, void *p2)
3401 {
3402   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3403 }
3404
3405 static bool
3406 inExcludeList (char *s)
3407 {
3408   const char *p = setFirstItem(options.excludeRegsSet);
3409
3410   if (p == NULL || STRCASECMP(p, "none") == 0)
3411     return FALSE;
3412
3413
3414   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3415 }
3416
3417 /*-----------------------------------------------------------------*/
3418 /* genFunction - generated code for function entry                 */
3419 /*-----------------------------------------------------------------*/
3420 static void
3421 genFunction (iCode * ic)
3422 {
3423   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3424   sym_link *ftype;
3425   bool   switchedPSW = FALSE;
3426   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3427
3428   D (emitcode (";", "genFunction"));
3429
3430   _G.nRegsSaved = 0;
3431   /* create the function header */
3432   emitcode (";", "-----------------------------------------");
3433   emitcode (";", " function %s", sym->name);
3434   emitcode (";", "-----------------------------------------");
3435
3436   emitcode ("", "%s:", sym->rname);
3437   ftype = operandType (IC_LEFT (ic));
3438   _G.currentFunc = sym;
3439
3440   if (IFFUNC_ISNAKED(ftype))
3441   {
3442       emitcode(";", "naked function: no prologue.");
3443       return;
3444   }
3445
3446   if (options.stack_probe)
3447       emitcode ("lcall","__stack_probe");
3448
3449   /* here we need to generate the equates for the
3450      register bank if required */
3451   if (FUNC_REGBANK (ftype) != rbank)
3452     {
3453       int i;
3454
3455       rbank = FUNC_REGBANK (ftype);
3456       for (i = 0; i < ds390_nRegs; i++)
3457         {
3458           if (regs390[i].print) {
3459               if (strcmp (regs390[i].base, "0") == 0)
3460                   emitcode ("", "%s !equ !constbyte",
3461                             regs390[i].dname,
3462                             8 * rbank + regs390[i].offset);
3463               else
3464                   emitcode ("", "%s !equ %s + !constbyte",
3465                             regs390[i].dname,
3466                             regs390[i].base,
3467                             8 * rbank + regs390[i].offset);
3468           }
3469         }
3470     }
3471
3472   /* if this is an interrupt service routine then
3473      save acc, b, dpl, dph  */
3474   if (IFFUNC_ISISR (sym->type))
3475       { /* is ISR */
3476       if (!inExcludeList ("acc"))
3477         emitcode ("push", "acc");
3478       if (!inExcludeList ("b"))
3479         emitcode ("push", "b");
3480       if (!inExcludeList ("dpl"))
3481         emitcode ("push", "dpl");
3482       if (!inExcludeList ("dph"))
3483         emitcode ("push", "dph");
3484       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3485         {
3486           emitcode ("push", "dpx");
3487           /* Make sure we're using standard DPTR */
3488           emitcode ("push", "dps");
3489           emitcode ("mov", "dps,#0");
3490           if (options.stack10bit)
3491             {
3492               /* This ISR could conceivably use DPTR2. Better save it. */
3493               emitcode ("push", "dpl1");
3494               emitcode ("push", "dph1");
3495               emitcode ("push", "dpx1");
3496               emitcode ("push",  DP2_RESULT_REG);
3497             }
3498         }
3499       /* if this isr has no bank i.e. is going to
3500          run with bank 0 , then we need to save more
3501          registers :-) */
3502       if (!FUNC_REGBANK (sym->type))
3503         {
3504             int i;
3505
3506           /* if this function does not call any other
3507              function then we can be economical and
3508              save only those registers that are used */
3509           if (!IFFUNC_HASFCALL(sym->type))
3510             {
3511               /* if any registers used */
3512               if (sym->regsUsed)
3513                 {
3514                   bool bits_pushed = FALSE;
3515                   /* save the registers used */
3516                   for (i = 0; i < sym->regsUsed->size; i++)
3517                     {
3518                       if (bitVectBitValue (sym->regsUsed, i))
3519                         bits_pushed = pushReg (i, bits_pushed);
3520                     }
3521                 }
3522             }
3523           else
3524             {
3525               /* this function has a function call. We cannot
3526                  determine register usage so we will have to push the
3527                  entire bank */
3528               saveRBank (0, ic, FALSE);
3529               if (options.parms_in_bank1) {
3530                   for (i=0; i < 8 ; i++ ) {
3531                       emitcode ("push","%s",rb1regs[i]);
3532                   }
3533               }
3534             }
3535         }
3536         else
3537         {
3538             /* This ISR uses a non-zero bank.
3539              *
3540              * We assume that the bank is available for our
3541              * exclusive use.
3542              *
3543              * However, if this ISR calls a function which uses some
3544              * other bank, we must save that bank entirely.
3545              */
3546             unsigned long banksToSave = 0;
3547
3548             if (IFFUNC_HASFCALL(sym->type))
3549             {
3550
3551 #define MAX_REGISTER_BANKS 4
3552
3553                 iCode *i;
3554                 int ix;
3555
3556                 for (i = ic; i; i = i->next)
3557                 {
3558                     if (i->op == ENDFUNCTION)
3559                     {
3560                         /* we got to the end OK. */
3561                         break;
3562                     }
3563
3564                     if (i->op == CALL)
3565                     {
3566                         sym_link *dtype;
3567
3568                         dtype = operandType (IC_LEFT(i));
3569                         if (dtype
3570                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3571                         {
3572                              /* Mark this bank for saving. */
3573                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3574                              {
3575                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3576                              }
3577                              else
3578                              {
3579                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3580                              }
3581
3582                              /* And note that we don't need to do it in
3583                               * genCall.
3584                               */
3585                              i->bankSaved = 1;
3586                         }
3587                     }
3588                     if (i->op == PCALL)
3589                     {
3590                         /* This is a mess; we have no idea what
3591                          * register bank the called function might
3592                          * use.
3593                          *
3594                          * The only thing I can think of to do is
3595                          * throw a warning and hope.
3596                          */
3597                         werror(W_FUNCPTR_IN_USING_ISR);
3598                     }
3599                 }
3600
3601                 if (banksToSave && options.useXstack)
3602                 {
3603                     /* Since we aren't passing it an ic,
3604                      * saveRBank will assume r0 is available to abuse.
3605                      *
3606                      * So switch to our (trashable) bank now, so
3607                      * the caller's R0 isn't trashed.
3608                      */
3609                     emitcode ("push", "psw");
3610                     emitcode ("mov", "psw,#!constbyte",
3611                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3612                     switchedPSW = TRUE;
3613                 }
3614
3615                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3616                 {
3617                      if (banksToSave & (1 << ix))
3618                      {
3619                          saveRBank(ix, NULL, FALSE);
3620                      }
3621                 }
3622             }
3623             // TODO: this needs a closer look
3624             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3625         }
3626     }
3627   else
3628     {
3629       /* if callee-save to be used for this function
3630          then save the registers being used in this function */
3631       if (IFFUNC_CALLEESAVES(sym->type))
3632         {
3633           int i;
3634
3635           /* if any registers used */
3636           if (sym->regsUsed)
3637             {
3638               bool bits_pushed = FALSE;
3639               /* save the registers used */
3640               for (i = 0; i < sym->regsUsed->size; i++)
3641                 {
3642                   if (bitVectBitValue (sym->regsUsed, i))
3643                     {
3644                       bits_pushed = pushReg (i, bits_pushed);
3645                       _G.nRegsSaved++;
3646                     }
3647                 }
3648             }
3649         }
3650     }
3651
3652   /* set the register bank to the desired value */
3653   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3654    && !switchedPSW)
3655     {
3656       emitcode ("push", "psw");
3657       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3658     }
3659
3660   if (fReentrant &&
3661        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3662       if (options.stack10bit) {
3663           emitcode ("push","_bpx");
3664           emitcode ("push","_bpx+1");
3665           emitcode ("mov","_bpx,%s",spname);
3666           emitcode ("mov","_bpx+1,esp");
3667           adjustEsp("_bpx+1");
3668       } else {
3669           if (options.useXstack)
3670           {
3671               emitcode ("mov", "r0,%s", spname);
3672               emitcode ("mov", "a,_bp");
3673               emitcode ("movx", "@r0,a");
3674               emitcode ("inc", "%s", spname);
3675           } else {
3676               /* set up the stack */
3677               emitcode ("push", "_bp"); /* save the callers stack  */
3678           }
3679           emitcode ("mov", "_bp,%s", spname);
3680       }
3681   }
3682
3683   /* adjust the stack for the function */
3684   if (sym->stack) {
3685       int i = sym->stack;
3686       if (options.stack10bit) {
3687           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3688           assert (sym->recvSize <= 4);
3689           if (sym->stack <= 8) {
3690               while (i--) emitcode ("push","acc");
3691           } else {
3692               PROTECT_SP;
3693               emitcode ("mov","a,sp");
3694               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3695               emitcode ("mov","sp,a");
3696               emitcode ("mov","a,esp");
3697               adjustEsp("a");
3698               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3699               emitcode ("mov","esp,a");
3700               UNPROTECT_SP;
3701           }
3702       } else {
3703           if (i > 256)
3704               werror (W_STACK_OVERFLOW, sym->name);
3705
3706           if (i > 3 && sym->recvSize < 4) {
3707
3708               emitcode ("mov", "a,sp");
3709               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3710               emitcode ("mov", "sp,a");
3711
3712           } else
3713               while (i--)
3714                   emitcode ("inc", "sp");
3715       }
3716   }
3717
3718   if (sym->xstack)
3719     {
3720
3721       emitcode ("mov", "a,_spx");
3722       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3723       emitcode ("mov", "_spx,a");
3724     }
3725
3726   /* if critical function then turn interrupts off */
3727   if (IFFUNC_ISCRITICAL (ftype))
3728     {
3729       symbol *tlbl = newiTempLabel (NULL);
3730       emitcode ("setb", "c");
3731       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3732       emitcode ("clr", "c");
3733       emitLabel (tlbl);
3734       emitcode ("push", "psw"); /* save old ea via c in psw */
3735     }
3736 }
3737
3738 /*-----------------------------------------------------------------*/
3739 /* genEndFunction - generates epilogue for functions               */
3740 /*-----------------------------------------------------------------*/
3741 static void
3742 genEndFunction (iCode * ic)
3743 {
3744   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3745   lineNode *lnp = lineCurr;
3746   bitVect *regsUsed;
3747   bitVect *regsUsedPrologue;
3748   bitVect *regsUnneeded;
3749   int idx;
3750
3751   D (emitcode (";", "genEndFunction"));
3752
3753   _G.currentFunc = NULL;
3754   if (IFFUNC_ISNAKED(sym->type))
3755   {
3756       emitcode(";", "naked function: no epilogue.");
3757       if (options.debug && currFunc)
3758         debugFile->writeEndFunction (currFunc, ic, 0);
3759       return;
3760   }
3761
3762   if (IFFUNC_ISCRITICAL (sym->type))
3763     {
3764       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3765         {
3766           emitcode ("rlc", "a");   /* save c in a */
3767           emitcode ("pop", "psw"); /* restore ea via c in psw */
3768           emitcode ("mov", "ea,c");
3769           emitcode ("rrc", "a");   /* restore c from a */
3770         }
3771       else
3772         {
3773           emitcode ("pop", "psw"); /* restore ea via c in psw */
3774           emitcode ("mov", "ea,c");
3775         }
3776     }
3777
3778   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3779        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3780
3781       if (options.stack10bit) {
3782           PROTECT_SP;
3783           emitcode ("mov", "sp,_bpx", spname);
3784           emitcode ("mov", "esp,_bpx+1", spname);
3785           UNPROTECT_SP;
3786       } else {
3787           emitcode ("mov", "%s,_bp", spname);
3788       }
3789   }
3790
3791   /* if use external stack but some variables were
3792      added to the local stack then decrement the
3793      local stack */
3794   if (options.useXstack && sym->stack) {
3795       emitcode ("mov", "a,sp");
3796       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3797       emitcode ("mov", "sp,a");
3798   }
3799
3800
3801   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3802        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3803
3804       if (options.useXstack) {
3805           emitcode ("mov", "r0,%s", spname);
3806           emitcode ("movx", "a,@r0");
3807           emitcode ("mov", "_bp,a");
3808           emitcode ("dec", "%s", spname);
3809       } else {
3810           if (options.stack10bit) {
3811               emitcode ("pop", "_bpx+1");
3812               emitcode ("pop", "_bpx");
3813           } else {
3814               emitcode ("pop", "_bp");
3815           }
3816       }
3817   }
3818
3819   /* restore the register bank  */
3820   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3821   {
3822     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3823      || !options.useXstack)
3824     {
3825         /* Special case of ISR using non-zero bank with useXstack
3826          * is handled below.
3827          */
3828         emitcode ("pop", "psw");
3829     }
3830   }
3831
3832   if (IFFUNC_ISISR (sym->type))
3833       { /* is ISR */
3834
3835       /* now we need to restore the registers */
3836       /* if this isr has no bank i.e. is going to
3837          run with bank 0 , then we need to save more
3838          registers :-) */
3839       if (!FUNC_REGBANK (sym->type))
3840         {
3841             int i;
3842           /* if this function does not call any other
3843              function then we can be economical and
3844              save only those registers that are used */
3845           if (!IFFUNC_HASFCALL(sym->type))
3846             {
3847               /* if any registers used */
3848               if (sym->regsUsed)
3849                 {
3850                   bool bits_popped = FALSE;
3851                   /* save the registers used */
3852                   for (i = sym->regsUsed->size; i >= 0; i--)
3853                     {
3854                       if (bitVectBitValue (sym->regsUsed, i))
3855                         bits_popped = popReg (i, bits_popped);
3856                     }
3857                 }
3858             }
3859           else
3860             {
3861               /* this function has a function call. We cannot
3862                  determine register usage so we will have to pop the
3863                  entire bank */
3864               if (options.parms_in_bank1) {
3865                   for (i = 7 ; i >= 0 ; i-- ) {
3866                       emitcode ("pop","%s",rb1regs[i]);
3867                   }
3868               }
3869               unsaveRBank (0, ic, FALSE);
3870             }
3871         }
3872         else
3873         {
3874             /* This ISR uses a non-zero bank.
3875              *
3876              * Restore any register banks saved by genFunction
3877              * in reverse order.
3878              */
3879             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3880             int ix;
3881
3882             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3883             {
3884                 if (savedBanks & (1 << ix))
3885                 {
3886                     unsaveRBank(ix, NULL, FALSE);
3887                 }
3888             }
3889
3890             if (options.useXstack)
3891             {
3892                 /* Restore bank AFTER calling unsaveRBank,
3893                  * since it can trash r0.
3894                  */
3895                 emitcode ("pop", "psw");
3896             }
3897         }
3898
3899       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3900         {
3901           if (options.stack10bit)
3902             {
3903               emitcode ("pop", DP2_RESULT_REG);
3904               emitcode ("pop", "dpx1");
3905               emitcode ("pop", "dph1");
3906               emitcode ("pop", "dpl1");
3907             }
3908           emitcode ("pop", "dps");
3909           emitcode ("pop", "dpx");
3910         }
3911       if (!inExcludeList ("dph"))
3912         emitcode ("pop", "dph");
3913       if (!inExcludeList ("dpl"))
3914         emitcode ("pop", "dpl");
3915       if (!inExcludeList ("b"))
3916         emitcode ("pop", "b");
3917       if (!inExcludeList ("acc"))
3918         emitcode ("pop", "acc");
3919
3920       /* if debug then send end of function */
3921       if (options.debug && currFunc)
3922         {
3923           debugFile->writeEndFunction (currFunc, ic, 1);
3924         }
3925
3926       emitcode ("reti", "");
3927     }
3928   else
3929     {
3930       if (IFFUNC_CALLEESAVES(sym->type))
3931         {
3932           int i;
3933
3934           /* if any registers used */
3935           if (sym->regsUsed)
3936             {
3937               /* save the registers used */
3938               for (i = sym->regsUsed->size; i >= 0; i--)
3939                 {
3940                   if (bitVectBitValue (sym->regsUsed, i))
3941                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3942                 }
3943             }
3944         }
3945
3946       /* if debug then send end of function */
3947       if (options.debug && currFunc)
3948         {
3949           debugFile->writeEndFunction (currFunc, ic, 1);
3950         }
3951
3952       emitcode ("ret", "");
3953     }
3954
3955   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3956     return;
3957
3958   /* If this was an interrupt handler using bank 0 that called another */
3959   /* function, then all registers must be saved; nothing to optimized. */
3960   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3961       && !FUNC_REGBANK(sym->type))
3962     return;
3963
3964   /* There are no push/pops to optimize if not callee-saves or ISR */
3965   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3966     return;
3967
3968   /* If there were stack parameters, we cannot optimize without also    */
3969   /* fixing all of the stack offsets; this is too dificult to consider. */
3970   if (FUNC_HASSTACKPARM(sym->type))
3971     return;
3972
3973   /* Compute the registers actually used */
3974   regsUsed = newBitVect (ds390_nRegs);
3975   regsUsedPrologue = newBitVect (ds390_nRegs);
3976   while (lnp)
3977     {
3978       if (lnp->ic && lnp->ic->op == FUNCTION)
3979         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3980       else
3981         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3982
3983       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3984           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3985         break;
3986       if (!lnp->prev)
3987         break;
3988       lnp = lnp->prev;
3989     }
3990
3991   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3992       && !bitVectBitValue (regsUsed, DPS_IDX))
3993     {
3994       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3995     }
3996
3997   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3998       && !bitVectBitValue (regsUsed, CND_IDX))
3999     {
4000       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4001       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
4002           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
4003         bitVectUnSetBit (regsUsed, CND_IDX);
4004     }
4005   else
4006     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4007
4008   /* If this was an interrupt handler that called another function */
4009   /* function, then assume working registers may be modified by it. */
4010   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
4011     {
4012       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
4013       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
4014       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
4015       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
4016       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
4017       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
4018       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4019       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
4020       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4021       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4022       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4023     }
4024
4025   /* Remove the unneeded push/pops */
4026   regsUnneeded = newBitVect (ds390_nRegs);
4027   while (lnp)
4028     {
4029       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4030         {
4031           if (!strncmp(lnp->line, "push", 4))
4032             {
4033               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4034               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4035                 {
4036                   connectLine (lnp->prev, lnp->next);
4037                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4038                 }
4039             }
4040           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4041             {
4042               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4043               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4044                 {
4045                   connectLine (lnp->prev, lnp->next);
4046                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4047                 }
4048             }
4049         }
4050       lnp = lnp->next;
4051     }
4052
4053   for (idx = 0; idx < regsUnneeded->size; idx++)
4054     if (bitVectBitValue (regsUnneeded, idx))
4055       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4056
4057   freeBitVect (regsUnneeded);
4058   freeBitVect (regsUsed);
4059   freeBitVect (regsUsedPrologue);
4060 }
4061
4062 /*-----------------------------------------------------------------*/
4063 /* genJavaNativeRet - generate code for return JavaNative          */
4064 /*-----------------------------------------------------------------*/
4065 static void genJavaNativeRet(iCode *ic)
4066 {
4067     int i, size;
4068
4069     aopOp (IC_LEFT (ic), ic, FALSE,
4070            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4071     size = AOP_SIZE (IC_LEFT (ic));
4072
4073     assert (size <= 4);
4074
4075     /* it is assigned to GPR0-R3 then push them */
4076     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4077         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4078         for (i = 0 ; i < size ; i++ ) {
4079             emitcode ("push","%s",
4080                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4081         }
4082         for (i = (size-1) ; i >= 0 ; i--) {
4083             emitcode ("pop","a%s",javaRet[i]);
4084         }
4085     } else {
4086         for (i = 0 ; i < size ; i++)
4087             emitcode ("mov","%s,%s",javaRet[i],
4088                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4089     }
4090     for (i = size ; i < 4 ; i++ )
4091             emitcode ("mov","%s,#0",javaRet[i]);
4092     return;
4093 }
4094
4095 /*-----------------------------------------------------------------*/
4096 /* genRet - generate code for return statement                     */
4097 /*-----------------------------------------------------------------*/
4098 static void
4099 genRet (iCode * ic)
4100 {
4101   int size, offset = 0, pushed = 0;
4102
4103   D (emitcode (";", "genRet"));
4104
4105   /* if we have no return value then
4106      just generate the "ret" */
4107   if (!IC_LEFT (ic))
4108     goto jumpret;
4109
4110   /* if this is a JavaNative function then return
4111      value in different register */
4112   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4113       genJavaNativeRet(ic);
4114       goto jumpret;
4115   }
4116   /* we have something to return then
4117      move the return value into place */
4118   aopOp (IC_LEFT (ic), ic, FALSE,
4119          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4120   size = AOP_SIZE (IC_LEFT (ic));
4121
4122   _startLazyDPSEvaluation ();
4123
4124   if (IS_BIT(_G.currentFunc->etype))
4125     {
4126       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4127       size = 0;
4128     }
4129
4130   while (size--)
4131     {
4132       char *l;
4133       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4134         {
4135           l = aopGet (IC_LEFT (ic), offset++,
4136                       FALSE, TRUE, NULL);
4137           emitcode ("push", "%s", l);
4138           pushed++;
4139         }
4140       else
4141         {
4142           /* Since A is the last element of fReturn,
4143            * it is OK to clobber it in the aopGet.
4144            */
4145           l = aopGet (IC_LEFT (ic), offset,
4146                       FALSE, FALSE, NULL);
4147           if (strcmp (fReturn[offset], l))
4148             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4149         }
4150     }
4151   _endLazyDPSEvaluation ();
4152
4153   while (pushed)
4154     {
4155       pushed--;
4156       if (strcmp (fReturn[pushed], "a"))
4157         emitcode ("pop", fReturn[pushed]);
4158       else
4159         emitcode ("pop", "acc");
4160     }
4161   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4162
4163 jumpret:
4164   /* generate a jump to the return label
4165      if the next is not the return statement */
4166   if (!(ic->next && ic->next->op == LABEL &&
4167         IC_LABEL (ic->next) == returnLabel))
4168
4169     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4170
4171 }
4172
4173 /*-----------------------------------------------------------------*/
4174 /* genLabel - generates a label                                    */
4175 /*-----------------------------------------------------------------*/
4176 static void
4177 genLabel (iCode * ic)
4178 {
4179   /* special case never generate */
4180   if (IC_LABEL (ic) == entryLabel)
4181     return;
4182
4183   D (emitcode (";", "genLabel"));
4184
4185   emitcode ("", "!tlabeldef", (IC_LABEL (ic)->key + 100));
4186 }
4187
4188 /*-----------------------------------------------------------------*/
4189 /* genGoto - generates a ljmp                                      */
4190 /*-----------------------------------------------------------------*/
4191 static void
4192 genGoto (iCode * ic)
4193 {
4194   D (emitcode (";", "genGoto"));
4195
4196   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4197 }
4198
4199 /*-----------------------------------------------------------------*/
4200 /* findLabelBackwards: walks back through the iCode chain looking  */
4201 /* for the given label. Returns number of iCode instructions     */
4202 /* between that label and given ic.          */
4203 /* Returns zero if label not found.          */
4204 /*-----------------------------------------------------------------*/
4205 static int
4206 findLabelBackwards (iCode * ic, int key)
4207 {
4208   int count = 0;
4209
4210   while (ic->prev)
4211     {
4212       ic = ic->prev;
4213       count++;
4214
4215       /* If we have any pushes or pops, we cannot predict the distance.
4216          I don't like this at all, this should be dealt with in the
4217          back-end */
4218       if (ic->op == IPUSH || ic->op == IPOP) {
4219         return 0;
4220       }
4221
4222       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4223         {
4224           /* printf("findLabelBackwards = %d\n", count); */
4225           return count;
4226         }
4227     }
4228
4229   return 0;
4230 }
4231
4232 /*-----------------------------------------------------------------*/
4233 /* genPlusIncr :- does addition with increment if possible         */
4234 /*-----------------------------------------------------------------*/
4235 static bool
4236 genPlusIncr (iCode * ic)
4237 {
4238   unsigned int icount;
4239   unsigned int size = getDataSize (IC_RESULT (ic));
4240
4241   /* will try to generate an increment */
4242   /* if the right side is not a literal
4243      we cannot */
4244   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4245     return FALSE;
4246
4247   /* if the literal value of the right hand side
4248      is greater than 4 then it is not worth it */
4249   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4250     return FALSE;
4251
4252   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4253       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4254       while (icount--) {
4255           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4256       }
4257       return TRUE;
4258   }
4259   /* if increment 16 bits in register */
4260   if (
4261        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4262        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4263        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4264        (size > 1) &&
4265        (icount == 1))
4266     {
4267       symbol  *tlbl;
4268       int     emitTlbl;
4269       int     labelRange;
4270       char    *l;
4271
4272       /* If the next instruction is a goto and the goto target
4273        * is <= 5 instructions previous to this, we can generate
4274        * jumps straight to that target.
4275        */
4276       if (ic->next && ic->next->op == GOTO
4277           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4278           && labelRange <= 5)
4279         {
4280           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4281           tlbl = IC_LABEL (ic->next);
4282           emitTlbl = 0;
4283         }
4284       else
4285         {
4286           tlbl = newiTempLabel (NULL);
4287           emitTlbl = 1;
4288         }
4289       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4290       emitcode ("inc", "%s", l);
4291
4292       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4293           IS_AOP_PREG (IC_RESULT (ic)))
4294         {
4295           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4296         }
4297       else
4298         {
4299           emitcode ("clr", "a");
4300           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4301         }
4302
4303       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4304       emitcode ("inc", "%s", l);
4305       if (size > 2)
4306         {
4307           if (!strcmp(l, "acc"))
4308             {
4309                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4310             }
4311           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4312                    IS_AOP_PREG (IC_RESULT (ic)))
4313             {
4314                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4315             }
4316           else
4317             {
4318                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4319             }
4320
4321           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4322           emitcode ("inc", "%s", l);
4323         }
4324       if (size > 3)
4325         {
4326           if (!strcmp(l, "acc"))
4327             {
4328                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4329             }
4330           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4331                    IS_AOP_PREG (IC_RESULT (ic)))
4332             {
4333                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4334             }
4335           else
4336             {
4337                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4338             }
4339
4340           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4341           emitcode ("inc", "%s", l);
4342         }
4343
4344       if (emitTlbl)
4345         {
4346           emitLabel (tlbl);
4347         }
4348       return TRUE;
4349     }
4350
4351   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4352       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4353       options.model == MODEL_FLAT24 )
4354     {
4355       if (IC_RESULT(ic)->isGptr)
4356         {
4357           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4358         }
4359       switch (size) {
4360       case 3:
4361           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4362       case 2:
4363           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4364       case 1:
4365           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4366           break;
4367       }
4368       while (icount--)
4369         emitcode ("inc", "dptr");
4370       return TRUE;
4371   }
4372
4373   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4374       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4375       icount <= 5 ) {
4376       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4377       while (icount--)
4378         emitcode ("inc", "dptr");
4379       emitcode ("mov", "dps,#0");
4380       return TRUE;
4381   }
4382
4383   /* if the sizes are greater than 1 then we cannot */
4384   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4385       AOP_SIZE (IC_LEFT (ic)) > 1)
4386     return FALSE;
4387
4388   /* we can if the aops of the left & result match or
4389      if they are in registers and the registers are the
4390      same */
4391   if (
4392        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4393        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4394        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4395     {
4396       if (icount > 3)
4397         {
4398           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4399           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4400           aopPut (IC_RESULT (ic), "a", 0);
4401         }
4402       else
4403         {
4404           _startLazyDPSEvaluation ();
4405           while (icount--)
4406             {
4407               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4408             }
4409           _endLazyDPSEvaluation ();
4410         }
4411
4412       return TRUE;
4413     }
4414
4415   return FALSE;
4416 }
4417
4418 /*-----------------------------------------------------------------*/
4419 /* outBitAcc - output a bit in acc                                 */
4420 /*-----------------------------------------------------------------*/
4421 static void
4422 outBitAcc (operand * result)
4423 {
4424   symbol *tlbl = newiTempLabel (NULL);
4425   /* if the result is a bit */
4426   if (AOP_TYPE (result) == AOP_CRY)
4427     {
4428       aopPut (result, "a", 0);
4429     }
4430   else
4431     {
4432       emitcode ("jz", "!tlabel", tlbl->key + 100);
4433       emitcode ("mov", "a,%s", one);
4434       emitLabel (tlbl);
4435       outAcc (result);
4436     }
4437 }
4438
4439 /*-----------------------------------------------------------------*/
4440 /* genPlusBits - generates code for addition of two bits           */
4441 /*-----------------------------------------------------------------*/
4442 static void
4443 genPlusBits (iCode * ic)
4444 {
4445   D (emitcode (";", "genPlusBits"));
4446
4447   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4448     {
4449       symbol *lbl = newiTempLabel (NULL);
4450       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4451       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4452       emitcode ("cpl", "c");
4453       emitLabel (lbl);
4454       outBitC (IC_RESULT (ic));
4455     }
4456   else
4457     {
4458       emitcode ("clr", "a");
4459       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4460       emitcode ("rlc", "a");
4461       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4462       emitcode ("addc", "a,%s", zero);
4463       outAcc (IC_RESULT (ic));
4464     }
4465 }
4466
4467 static void
4468 adjustArithmeticResult (iCode * ic)
4469 {
4470   if (opIsGptr (IC_RESULT (ic)) &&
4471       opIsGptr (IC_LEFT (ic)) &&
4472       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4473     {
4474       aopPut (IC_RESULT (ic),
4475               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4476               GPTRSIZE - 1);
4477     }
4478
4479   if (opIsGptr (IC_RESULT (ic)) &&
4480       opIsGptr (IC_RIGHT (ic)) &&
4481       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4482     {
4483       aopPut (IC_RESULT (ic),
4484               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4485               GPTRSIZE - 1);
4486     }
4487
4488   if (opIsGptr (IC_RESULT (ic)) &&
4489       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4490       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4491       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4492       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4493     {
4494       char buffer[5];
4495       SNPRINTF (buffer, sizeof(buffer),
4496                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4497       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4498     }
4499 }
4500
4501 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4502 // generates the result if possible. If result is generated, returns TRUE; otherwise
4503 // returns false and caller must deal with fact that result isn't aopOp'd.
4504 bool aopOp3(iCode * ic)
4505 {
4506     bool dp1InUse, dp2InUse;
4507     bool useDp2;
4508
4509     // First, generate the right opcode. DPTR may be used if neither left nor result are
4510     // of type AOP_STR.
4511
4512 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4513 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4514 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4515 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4516 //      );
4517 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4518 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4519 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4520 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4521 //      );
4522
4523     // Right uses DPTR unless left or result is an AOP_STR; however,
4524     // if right is an AOP_STR, it must use DPTR regardless.
4525     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4526      && !AOP_IS_STR (IC_RIGHT (ic)))
4527     {
4528         useDp2 = TRUE;
4529     }
4530     else
4531     {
4532         useDp2 = FALSE;
4533     }
4534
4535     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4536
4537     // if the right used DPTR, left MUST use DPTR2.
4538     // if the right used DPTR2, left MUST use DPTR.
4539     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4540     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4541     // enabling us to assign DPTR to result.
4542
4543     if (AOP_USESDPTR (IC_RIGHT (ic)))
4544     {
4545         useDp2 = TRUE;
4546     }
4547     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4548     {
4549         useDp2 = FALSE;
4550     }
4551     else
4552     {
4553         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4554         {
4555             useDp2 = TRUE;
4556         }
4557         else
4558         {
4559             useDp2 = FALSE;
4560         }
4561     }
4562
4563     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4564
4565
4566     // We've op'd the left & right. So, if left or right are the same operand as result,
4567     // we know aopOp will succeed, and we can just do it & bail.
4568     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4569       {
4570         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4571         return TRUE;
4572       }
4573     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4574       {
4575 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4576         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4577         return TRUE;
4578       }
4579
4580     // Operands may be equivalent (but not equal) if they share a spill location. If
4581     // so, use the same DPTR or DPTR2.
4582     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4583       {
4584         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4585         return TRUE;
4586       }
4587     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4588       {
4589         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4590         return TRUE;
4591       }
4592
4593     // Note which dptrs are currently in use.
4594     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4595     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4596
4597     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4598     // generate it.
4599     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4600     {
4601         return FALSE;
4602     }
4603
4604     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4605     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4606     {
4607         return FALSE;
4608     }
4609
4610     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4611     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4612     {
4613         return FALSE;
4614     }
4615
4616     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4617
4618     // Some sanity checking...
4619     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4620     {
4621         fprintf(stderr,
4622                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4623                 __FILE__, __LINE__, ic->filename, ic->lineno);
4624         emitcode(";", ">>> unexpected DPTR here.");
4625     }
4626
4627     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4628     {
4629         fprintf(stderr,
4630                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4631                 __FILE__, __LINE__, ic->filename, ic->lineno);
4632         emitcode(";", ">>> unexpected DPTR2 here.");
4633     }
4634
4635     return TRUE;
4636 }
4637
4638 // Macro to aopOp all three operands of an ic. If this cannot be done,
4639 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4640 // will be set TRUE. The caller must then handle the case specially, noting
4641 // that the IC_RESULT operand is not aopOp'd.
4642 //
4643 #define AOP_OP_3_NOFATAL(ic, rc) \
4644             do { rc = !aopOp3(ic); } while (0)
4645
4646 // aopOp the left & right operands of an ic.
4647 #define AOP_OP_2(ic) \
4648     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4649     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4650
4651 // convienience macro.
4652 #define AOP_SET_LOCALS(ic) \
4653     left = IC_LEFT(ic); \
4654     right = IC_RIGHT(ic); \
4655     result = IC_RESULT(ic);
4656
4657
4658 // Given an integer value of pushedSize bytes on the stack,
4659 // adjust it to be resultSize bytes, either by discarding
4660 // the most significant bytes or by zero-padding.
4661 //
4662 // On exit from this macro, pushedSize will have been adjusted to
4663 // equal resultSize, and ACC may be trashed.
4664 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4665       /* If the pushed data is bigger than the result,          \
4666        * simply discard unused bytes. Icky, but works.          \
4667        */                                                       \
4668       while (pushedSize > resultSize)                           \
4669       {                                                         \
4670           D (emitcode (";", "discarding unused result byte.")); \
4671           emitcode ("pop", "acc");                              \
4672           pushedSize--;                                         \
4673       }                                                         \
4674       if (pushedSize < resultSize)                              \
4675       {                                                         \
4676           emitcode ("clr", "a");                                \
4677           /* Conversly, we haven't pushed enough here.          \
4678            * just zero-pad, and all is well.                    \
4679            */                                                   \
4680           while (pushedSize < resultSize)                       \
4681           {                                                     \
4682               emitcode("push", "acc");                          \
4683               pushedSize++;                                     \
4684           }                                                     \
4685       }                                                         \
4686       assert(pushedSize == resultSize);
4687
4688 /*-----------------------------------------------------------------*/
4689 /* genPlus - generates code for addition                           */
4690 /*-----------------------------------------------------------------*/
4691 static void
4692 genPlus (iCode * ic)
4693 {
4694   int size, offset = 0;
4695   bool pushResult;
4696   int rSize;
4697   bool swappedLR = FALSE;
4698
4699   D (emitcode (";", "genPlus"));
4700
4701   /* special cases :- */
4702   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4703       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4704       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4705       size = (int)floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4706       if (size <= 9) {
4707           while (size--) emitcode ("inc","dptr");
4708       } else {
4709           emitcode ("mov", "a,dpl");
4710           emitcode ("add", "a,#!constbyte", size & 0xff);
4711           emitcode ("mov", "dpl,a");
4712           emitcode ("mov", "a,dph");
4713           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4714           emitcode ("mov", "dph,a");
4715           emitcode ("mov", "a,dpx");
4716           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4717           emitcode ("mov", "dpx,a");
4718       }
4719       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4720       return ;
4721   }
4722   if ( IS_SYMOP (IC_LEFT (ic)) &&
4723        OP_SYMBOL (IC_LEFT (ic))->remat &&
4724        isOperandInFarSpace (IC_RIGHT (ic))) {
4725       operand *op = IC_RIGHT(ic);
4726       IC_RIGHT(ic) = IC_LEFT(ic);
4727       IC_LEFT(ic) = op;
4728   }
4729
4730   AOP_OP_3_NOFATAL (ic, pushResult);
4731
4732   if (pushResult)
4733     {
4734       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4735     }
4736
4737   if (!pushResult)
4738     {
4739       /* if literal, literal on the right or
4740          if left requires ACC or right is already
4741          in ACC */
4742       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4743           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4744           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4745         {
4746           operand *t = IC_RIGHT (ic);
4747           IC_RIGHT (ic) = IC_LEFT (ic);
4748           IC_LEFT (ic) = t;
4749           swappedLR = TRUE;
4750           D (emitcode (";", "Swapped plus args."));
4751         }
4752
4753       /* if both left & right are in bit
4754          space */
4755       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4756           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4757         {
4758           genPlusBits (ic);
4759           goto release;
4760         }
4761
4762       /* if left in bit space & right literal */
4763       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4764           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4765         {
4766           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4767           /* if result in bit space */
4768           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4769             {
4770               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4771                 emitcode ("cpl", "c");
4772               outBitC (IC_RESULT (ic));
4773             }
4774           else
4775             {
4776               size = getDataSize (IC_RESULT (ic));
4777               _startLazyDPSEvaluation ();
4778               while (size--)
4779                 {
4780                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4781                   emitcode ("addc", "a,%s", zero);
4782                   aopPut (IC_RESULT (ic), "a", offset++);
4783                 }
4784               _endLazyDPSEvaluation ();
4785             }
4786           goto release;
4787         }
4788
4789       /* if I can do an increment instead
4790          of add then GOOD for ME */
4791       if (genPlusIncr (ic) == TRUE)
4792         {
4793           D (emitcode (";", "did genPlusIncr"));
4794           goto release;
4795         }
4796
4797     }
4798   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4799
4800   _startLazyDPSEvaluation ();
4801   while (size--)
4802     {
4803       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4804         {
4805           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4806           if (offset == 0)
4807             emitcode ("add", "a,%s",
4808                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4809           else
4810             emitcode ("addc", "a,%s",
4811                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4812         }
4813       else
4814         {
4815           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4816           {
4817               /* right is going to use ACC or we would have taken the
4818                * above branch.
4819                */
4820               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4821               TR_AP("#3");
4822               D(emitcode(";", "+ AOP_ACC special case."););
4823               emitcode("xch", "a, %s", DP2_RESULT_REG);
4824           }
4825           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4826           if (offset == 0)
4827           {
4828             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4829             {
4830                 TR_AP("#4");
4831                 emitcode("add", "a, %s", DP2_RESULT_REG);
4832             }
4833             else
4834             {
4835                 emitcode ("add", "a,%s",
4836                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4837                                   DP2_RESULT_REG));
4838             }
4839           }
4840           else
4841           {
4842             emitcode ("addc", "a,%s",
4843                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4844                           DP2_RESULT_REG));
4845           }
4846         }
4847       if (!pushResult)
4848         {
4849           aopPut (IC_RESULT (ic), "a", offset);
4850         }
4851       else
4852         {
4853           emitcode ("push", "acc");
4854         }
4855       offset++;
4856     }
4857   _endLazyDPSEvaluation ();
4858
4859   if (pushResult)
4860     {
4861       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4862
4863       size = getDataSize (IC_LEFT (ic));
4864       rSize = getDataSize (IC_RESULT (ic));
4865
4866       ADJUST_PUSHED_RESULT(size, rSize);
4867
4868       _startLazyDPSEvaluation ();
4869       while (size--)
4870         {
4871           emitcode ("pop", "acc");
4872           aopPut (IC_RESULT (ic), "a", size);
4873         }
4874       _endLazyDPSEvaluation ();
4875     }
4876
4877   adjustArithmeticResult (ic);
4878
4879 release:
4880   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4881   if (!swappedLR)
4882     {
4883       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4884       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4885     }
4886   else
4887     {
4888       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4889       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4890     }
4891 }
4892
4893 /*-----------------------------------------------------------------*/
4894 /* genMinusDec :- does subtraction with decrement if possible      */
4895 /*-----------------------------------------------------------------*/
4896 static bool
4897 genMinusDec (iCode * ic)
4898 {
4899   unsigned int icount;
4900   unsigned int size = getDataSize (IC_RESULT (ic));
4901
4902   /* will try to generate an increment */
4903   /* if the right side is not a literal
4904      we cannot */
4905   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4906     return FALSE;
4907
4908   /* if the literal value of the right hand side
4909      is greater than 4 then it is not worth it */
4910   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4911     return FALSE;
4912
4913   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4914       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4915       while (icount--) {
4916           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4917       }
4918       return TRUE;
4919   }
4920   /* if decrement 16 bits in register */
4921   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4922       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4923       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4924       (size > 1) &&
4925       (icount == 1))
4926     {
4927       symbol *tlbl;
4928       int    emitTlbl;
4929       int    labelRange;
4930       char   *l;
4931
4932       /* If the next instruction is a goto and the goto target
4933          * is <= 5 instructions previous to this, we can generate
4934          * jumps straight to that target.
4935        */
4936       if (ic->next && ic->next->op == GOTO
4937           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4938           && labelRange <= 5)
4939         {
4940           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4941           tlbl = IC_LABEL (ic->next);
4942           emitTlbl = 0;
4943         }
4944       else
4945         {
4946           tlbl = newiTempLabel (NULL);
4947           emitTlbl = 1;
4948         }
4949
4950       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4951       emitcode ("dec", "%s", l);
4952
4953       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4954           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4955           IS_AOP_PREG (IC_RESULT (ic)))
4956       {
4957           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4958       }
4959       else
4960       {
4961           emitcode ("mov", "a,#!constbyte",0xff);
4962           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4963       }
4964       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4965       emitcode ("dec", "%s", l);
4966       if (size > 2)
4967         {
4968             if (!strcmp(l, "acc"))
4969             {
4970                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4971             }
4972             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4973                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4974                      IS_AOP_PREG (IC_RESULT (ic)))
4975             {
4976                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4977             }
4978             else
4979             {
4980                 emitcode ("mov", "a,#!constbyte",0xff);
4981                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4982             }
4983             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4984             emitcode ("dec", "%s", l);
4985         }
4986       if (size > 3)
4987         {
4988             if (!strcmp(l, "acc"))
4989             {
4990                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4991             }
4992             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4993                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4994                      IS_AOP_PREG (IC_RESULT (ic)))
4995             {
4996                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4997             }
4998             else
4999             {
5000                 emitcode ("mov", "a,#!constbyte",0xff);
5001                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
5002             }
5003             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
5004             emitcode ("dec", "%s", l);
5005         }
5006       if (emitTlbl)
5007         {
5008           emitLabel (tlbl);
5009         }
5010       return TRUE;
5011     }
5012
5013   /* if the sizes are greater than 1 then we cannot */
5014   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
5015       AOP_SIZE (IC_LEFT (ic)) > 1)
5016     return FALSE;
5017
5018   /* we can if the aops of the left & result match or
5019      if they are in registers and the registers are the
5020      same */
5021   if (
5022        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
5023        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
5024        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
5025     {
5026       char *l;
5027
5028       if (aopGetUsesAcc (IC_LEFT (ic), 0))
5029         {
5030           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
5031           l = "a";
5032         }
5033       else
5034         {
5035           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5036         }
5037
5038       _startLazyDPSEvaluation ();
5039       while (icount--)
5040         {
5041           emitcode ("dec", "%s", l);
5042         }
5043       _endLazyDPSEvaluation ();
5044
5045       if (AOP_NEEDSACC (IC_RESULT (ic)))
5046         aopPut (IC_RESULT (ic), "a", 0);
5047
5048       return TRUE;
5049     }
5050
5051   return FALSE;
5052 }
5053
5054 /*-----------------------------------------------------------------*/
5055 /* addSign - complete with sign                                    */
5056 /*-----------------------------------------------------------------*/
5057 static void
5058 addSign (operand * result, int offset, int sign)
5059 {
5060   int size = (getDataSize (result) - offset);
5061   if (size > 0)
5062     {
5063       _startLazyDPSEvaluation();
5064       if (sign)
5065         {
5066           emitcode ("rlc", "a");
5067           emitcode ("subb", "a,acc");
5068           while (size--)
5069           {
5070             aopPut (result, "a", offset++);
5071           }
5072         }
5073       else
5074       {
5075         while (size--)
5076         {
5077           aopPut (result, zero, offset++);
5078         }
5079       }
5080       _endLazyDPSEvaluation();
5081     }
5082 }
5083
5084 /*-----------------------------------------------------------------*/
5085 /* genMinusBits - generates code for subtraction  of two bits      */
5086 /*-----------------------------------------------------------------*/
5087 static void
5088 genMinusBits (iCode * ic)
5089 {
5090   symbol *lbl = newiTempLabel (NULL);
5091
5092   D (emitcode (";", "genMinusBits"));
5093
5094   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5095     {
5096       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5097       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5098       emitcode ("cpl", "c");
5099       emitLabel (lbl);
5100       outBitC (IC_RESULT (ic));
5101     }
5102   else
5103     {
5104       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5105       emitcode ("subb", "a,acc");
5106       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5107       emitcode ("inc", "a");
5108       emitLabel (lbl);
5109       aopPut (IC_RESULT (ic), "a", 0);
5110       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5111     }
5112 }
5113
5114 /*-----------------------------------------------------------------*/
5115 /* genMinus - generates code for subtraction                       */
5116 /*-----------------------------------------------------------------*/
5117 static void
5118 genMinus (iCode * ic)
5119 {
5120     int size, offset = 0;
5121     int rSize;
5122     long lit = 0L;
5123     bool pushResult;
5124
5125     D (emitcode (";", "genMinus"));
5126
5127     AOP_OP_3_NOFATAL(ic, pushResult);
5128
5129     if (!pushResult)
5130     {
5131       /* special cases :- */
5132       /* if both left & right are in bit space */
5133       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5134           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5135         {
5136           genMinusBits (ic);
5137           goto release;
5138         }
5139
5140       /* if I can do an decrement instead
5141          of subtract then GOOD for ME */
5142       if (genMinusDec (ic) == TRUE)
5143         goto release;
5144
5145     }
5146
5147   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5148
5149   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5150     {
5151       CLRC;
5152     }
5153   else
5154     {
5155       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5156       lit = -lit;
5157     }
5158
5159
5160   /* if literal, add a,#-lit, else normal subb */
5161   _startLazyDPSEvaluation ();
5162   while (size--) {
5163       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5164           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5165               emitcode ("mov","b,%s",
5166                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5167               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5168               emitcode ("subb","a,b");
5169           } else {
5170               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5171               emitcode ("subb", "a,%s",
5172                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5173                                 DP2_RESULT_REG));
5174           }
5175       } else {
5176           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5177           /* first add without previous c */
5178           if (!offset) {
5179               if (!size && lit==-1) {
5180                   emitcode ("dec", "a");
5181               } else {
5182                   emitcode ("add", "a,#!constbyte",
5183                             (unsigned int) (lit & 0x0FFL));
5184               }
5185           } else {
5186               emitcode ("addc", "a,#!constbyte",
5187                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5188           }
5189       }
5190
5191       if (pushResult) {
5192           emitcode ("push", "acc");
5193       } else {
5194           aopPut (IC_RESULT (ic), "a", offset);
5195       }
5196       offset++;
5197   }
5198   _endLazyDPSEvaluation ();
5199
5200   if (pushResult)
5201     {
5202       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5203
5204       size = getDataSize (IC_LEFT (ic));
5205       rSize = getDataSize (IC_RESULT (ic));
5206
5207       ADJUST_PUSHED_RESULT(size, rSize);
5208
5209       _startLazyDPSEvaluation ();
5210       while (size--)
5211         {
5212           emitcode ("pop", "acc");
5213           aopPut (IC_RESULT (ic), "a", size);
5214         }
5215       _endLazyDPSEvaluation ();
5216     }
5217
5218   adjustArithmeticResult (ic);
5219
5220 release:
5221   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5222   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5223   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5224 }
5225
5226
5227 /*-----------------------------------------------------------------*/
5228 /* genMultbits :- multiplication of bits                           */
5229 /*-----------------------------------------------------------------*/
5230 static void
5231 genMultbits (operand * left,
5232              operand * right,
5233              operand * result,
5234              iCode   * ic)
5235 {
5236   D (emitcode (";", "genMultbits"));
5237
5238   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5239   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5240   aopOp(result, ic, TRUE, FALSE);
5241   outBitC (result);
5242 }
5243
5244 /*-----------------------------------------------------------------*/
5245 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5246 /*-----------------------------------------------------------------*/
5247 static void
5248 genMultOneByte (operand * left,
5249                 operand * right,
5250                 operand * result,
5251                 iCode   * ic)
5252 {
5253   symbol *lbl;
5254   int size;
5255   bool runtimeSign, compiletimeSign;
5256   bool lUnsigned, rUnsigned, pushedB;
5257
5258   /* (if two literals: the value is computed before) */
5259   /* if one literal, literal on the right */
5260   if (AOP_TYPE (left) == AOP_LIT)
5261     {
5262       operand *t = right;
5263       right = left;
5264       left = t;
5265       /* emitcode (";", "swapped left and right"); */
5266     }
5267   /* if no literal, unsigned on the right: shorter code */
5268   if (   AOP_TYPE (right) != AOP_LIT
5269       && SPEC_USIGN (getSpec (operandType (left))))
5270     {
5271       operand *t = right;
5272       right = left;
5273       left = t;
5274     }
5275
5276   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5277   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5278
5279   pushedB = pushB ();
5280
5281   if ((lUnsigned && rUnsigned)
5282 /* sorry, I don't know how to get size
5283    without calling aopOp (result,...);
5284    see Feature Request  */
5285       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5286                    no need to take care about the signedness! */
5287     {
5288       /* just an unsigned 8 * 8 = 8 multiply
5289          or 8u * 8u = 16u */
5290       /* emitcode (";","unsigned"); */
5291       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5292       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5293       emitcode ("mul", "ab");
5294
5295       _G.accInUse++;
5296       aopOp (result, ic, TRUE, FALSE);
5297       size = AOP_SIZE (result);
5298
5299       if (size < 1 || size > 2)
5300         {
5301           /* this should never happen */
5302           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5303                    size, __FILE__, lineno);
5304           exit (1);
5305         }
5306
5307       aopPut (result, "a", 0);
5308       _G.accInUse--;
5309       if (size == 2)
5310         aopPut (result, "b", 1);
5311
5312       popB (pushedB);
5313       return;
5314     }
5315
5316   /* we have to do a signed multiply */
5317   /* emitcode (";", "signed"); */
5318
5319   /* now sign adjust for both left & right */
5320
5321   /* let's see what's needed: */
5322   /* apply negative sign during runtime */
5323   runtimeSign = FALSE;
5324   /* negative sign from literals */
5325   compiletimeSign = FALSE;
5326
5327   if (!lUnsigned)
5328     {
5329       if (AOP_TYPE(left) == AOP_LIT)
5330         {
5331           /* signed literal */
5332           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5333           if (val < 0)
5334             compiletimeSign = TRUE;
5335         }
5336       else
5337         /* signed but not literal */
5338         runtimeSign = TRUE;
5339     }
5340
5341   if (!rUnsigned)
5342     {
5343       if (AOP_TYPE(right) == AOP_LIT)
5344         {
5345           /* signed literal */
5346           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5347           if (val < 0)
5348             compiletimeSign ^= TRUE;
5349         }
5350       else
5351         /* signed but not literal */
5352         runtimeSign = TRUE;
5353     }
5354
5355   /* initialize F0, which stores the runtime sign */
5356   if (runtimeSign)
5357     {
5358       if (compiletimeSign)
5359         emitcode ("setb", "F0"); /* set sign flag */
5360       else
5361         emitcode ("clr", "F0"); /* reset sign flag */
5362     }
5363
5364   /* save the signs of the operands */
5365   if (AOP_TYPE(right) == AOP_LIT)
5366     {
5367       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5368
5369       if (!rUnsigned && val < 0)
5370         emitcode ("mov", "b,#!constbyte", -val);
5371       else
5372         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5373     }
5374   else /* ! literal */
5375     {
5376       if (rUnsigned)  /* emitcode (";", "signed"); */
5377         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5378       else
5379         {
5380           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5381           lbl = newiTempLabel (NULL);
5382           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5383           emitcode ("cpl", "F0"); /* complement sign flag */
5384           emitcode ("cpl", "a");  /* 2's complement */
5385           emitcode ("inc", "a");
5386           emitLabel (lbl);
5387           emitcode ("mov", "b,a");
5388         }
5389     }
5390
5391   if (AOP_TYPE(left) == AOP_LIT)
5392     {
5393       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5394
5395       if (!lUnsigned && val < 0)
5396         emitcode ("mov", "a,#!constbyte", -val);
5397       else
5398         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5399     }
5400   else /* ! literal */
5401     {
5402       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5403
5404       if (!lUnsigned)  /* emitcode (";", "signed"); */
5405         {
5406           lbl = newiTempLabel (NULL);
5407           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5408           emitcode ("cpl", "F0"); /* complement sign flag */
5409           emitcode ("cpl", "a");  /* 2's complement */
5410           emitcode ("inc", "a");
5411           emitLabel (lbl);
5412         }
5413     }
5414
5415   /* now the multiplication */
5416   emitcode ("mul", "ab");
5417   _G.accInUse++;
5418   aopOp(result, ic, TRUE, FALSE);
5419   size = AOP_SIZE (result);
5420
5421   if (size < 1 || size > 2)
5422     {
5423       /* this should never happen */
5424       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5425                size, __FILE__, lineno);
5426       exit (1);
5427     }
5428
5429   if (runtimeSign || compiletimeSign)
5430     {
5431       lbl = newiTempLabel (NULL);
5432       if (runtimeSign)
5433         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5434       emitcode ("cpl", "a"); /* lsb 2's complement */
5435       if (size != 2)
5436         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5437       else
5438         {
5439           emitcode ("add", "a,#1"); /* this sets carry flag */
5440           emitcode ("xch", "a,b");
5441           emitcode ("cpl", "a"); /* msb 2's complement */
5442           emitcode ("addc", "a,#0");
5443           emitcode ("xch", "a,b");
5444         }
5445       emitLabel (lbl);
5446     }
5447   aopPut (result, "a", 0);
5448   _G.accInUse--;
5449   if (size == 2)
5450     aopPut (result, "b", 1);
5451
5452   popB (pushedB);
5453 }
5454
5455 /*-----------------------------------------------------------------*/
5456 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5457 /*-----------------------------------------------------------------*/
5458 static void genMultTwoByte (operand *left, operand *right,
5459                             operand *result, iCode *ic)
5460 {
5461         sym_link *retype = getSpec(operandType(right));
5462         sym_link *letype = getSpec(operandType(left));
5463         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5464         symbol *lbl;
5465
5466         if (AOP_TYPE (left) == AOP_LIT) {
5467                 operand *t = right;
5468                 right = left;
5469                 left = t;
5470         }
5471         /* save EA bit in F1 */
5472         lbl = newiTempLabel(NULL);
5473         emitcode ("setb","F1");
5474         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5475         emitcode ("clr","F1");
5476         emitLabel (lbl);
5477
5478         /* load up MB with right */
5479         if (!umult) {
5480                 emitcode("clr","F0");
5481                 if (AOP_TYPE(right) == AOP_LIT) {
5482                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5483                         if (val < 0) {
5484                                 emitcode("setb","F0");
5485                                 val = -val;
5486                         }
5487                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5488                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5489                 } else {
5490                         lbl = newiTempLabel(NULL);
5491                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5492                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5493                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5494                         emitcode ("xch", "a,b");
5495                         emitcode ("cpl","a");
5496                         emitcode ("add", "a,#1");
5497                         emitcode ("xch", "a,b");
5498                         emitcode ("cpl", "a"); // msb
5499                         emitcode ("addc", "a,#0");
5500                         emitcode ("setb","F0");
5501                         emitLabel (lbl);
5502                         emitcode ("mov","mb,b");
5503                         emitcode ("mov","mb,a");
5504                 }
5505         } else {
5506                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5507                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5508         }
5509         /* load up MA with left */
5510         if (!umult) {
5511                 lbl = newiTempLabel(NULL);
5512                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5513                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5514                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5515                 emitcode ("xch", "a,b");
5516                 emitcode ("cpl","a");
5517                 emitcode ("add", "a,#1");
5518                 emitcode ("xch", "a,b");
5519                 emitcode ("cpl", "a"); // msb
5520                 emitcode ("addc","a,#0");
5521                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5522                 emitcode ("setb","F0");
5523                 emitLabel (lbl);
5524                 emitcode ("mov","ma,b");
5525                 emitcode ("mov","ma,a");
5526         } else {
5527                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5528                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5529         }
5530         /* wait for multiplication to finish */
5531         lbl = newiTempLabel(NULL);
5532         emitLabel (lbl);
5533         emitcode("mov","a,mcnt1");
5534         emitcode("anl","a,#!constbyte",0x80);
5535         emitcode("jnz","!tlabel",lbl->key+100);
5536
5537         freeAsmop (left, NULL, ic, TRUE);
5538         freeAsmop (right, NULL, ic,TRUE);
5539         aopOp(result, ic, TRUE, FALSE);
5540
5541         /* if unsigned then simple */
5542         if (umult) {
5543                 emitcode ("mov","a,ma");
5544                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5545                 emitcode ("mov","a,ma");
5546                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5547                 aopPut(result,"ma",1);
5548                 aopPut(result,"ma",0);
5549         } else {
5550                 emitcode("push","ma");
5551                 emitcode("push","ma");
5552                 emitcode("push","ma");
5553                 MOVA("ma");
5554                 /* negate result if needed */
5555                 lbl = newiTempLabel(NULL);
5556                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5557                 emitcode("cpl","a");
5558                 emitcode("add","a,#1");
5559                 emitLabel (lbl);
5560                 if (AOP_TYPE(result) == AOP_ACC)
5561                 {
5562                     D (emitcode(";", "ACC special case."));
5563                     /* We know result is the only live aop, and
5564                      * it's obviously not a DPTR2, so AP is available.
5565                      */
5566                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5567                 }
5568                 else
5569                 {
5570                     aopPut(result,"a",0);
5571                 }
5572
5573                 emitcode("pop","acc");
5574                 lbl = newiTempLabel(NULL);
5575                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5576                 emitcode("cpl","a");
5577                 emitcode("addc","a,#0");
5578                 emitLabel (lbl);
5579                 aopPut(result,"a",1);
5580                 emitcode("pop","acc");
5581                 if (AOP_SIZE(result) >= 3) {
5582                         lbl = newiTempLabel(NULL);
5583                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5584                         emitcode("cpl","a");
5585                         emitcode("addc","a,#0");
5586                         emitLabel (lbl);
5587                         aopPut(result,"a",2);
5588                 }
5589                 emitcode("pop","acc");
5590                 if (AOP_SIZE(result) >= 4) {
5591                         lbl = newiTempLabel(NULL);
5592                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5593                         emitcode("cpl","a");
5594                         emitcode("addc","a,#0");
5595                         emitLabel (lbl);
5596                         aopPut(result,"a",3);
5597                 }
5598                 if (AOP_TYPE(result) == AOP_ACC)
5599                 {
5600                     /* We stashed the result away above. */
5601                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5602                 }
5603
5604         }
5605         freeAsmop (result, NULL, ic, TRUE);
5606
5607         /* restore EA bit in F1 */
5608         lbl = newiTempLabel(NULL);
5609         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5610         emitcode ("setb","EA");
5611         emitLabel (lbl);
5612         return ;
5613 }
5614
5615 /*-----------------------------------------------------------------*/
5616 /* genMult - generates code for multiplication                     */
5617 /*-----------------------------------------------------------------*/
5618 static void
5619 genMult (iCode * ic)
5620 {
5621   operand *left = IC_LEFT (ic);
5622   operand *right = IC_RIGHT (ic);
5623   operand *result = IC_RESULT (ic);
5624
5625   D (emitcode (";", "genMult"));
5626
5627   /* assign the asmops */
5628   AOP_OP_2 (ic);
5629
5630   /* special cases first */
5631   /* both are bits */
5632   if (AOP_TYPE (left) == AOP_CRY &&
5633       AOP_TYPE (right) == AOP_CRY)
5634     {
5635       genMultbits (left, right, result, ic);
5636       goto release;
5637     }
5638
5639   /* if both are of size == 1 */
5640   if (AOP_SIZE (left) == 1 &&
5641       AOP_SIZE (right) == 1)
5642     {
5643       genMultOneByte (left, right, result, ic);
5644       goto release;
5645     }
5646
5647   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5648           /* use the ds390 ARITHMETIC accel UNIT */
5649           genMultTwoByte (left, right, result, ic);
5650           return ;
5651   }
5652   /* should have been converted to function call */
5653   assert (0);
5654
5655 release:
5656   freeAsmop (result, NULL, ic, TRUE);
5657   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5658   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5659 }
5660
5661 /*-----------------------------------------------------------------*/
5662 /* genDivbits :- division of bits                                  */
5663 /*-----------------------------------------------------------------*/
5664 static void
5665 genDivbits (operand * left,
5666             operand * right,
5667             operand * result,
5668             iCode   * ic)
5669 {
5670   char *l;
5671   bool pushedB;
5672
5673   D(emitcode (";     genDivbits",""));
5674
5675   pushedB = pushB ();
5676
5677   /* the result must be bit */
5678   LOAD_AB_FOR_DIV (left, right, l);
5679   emitcode ("div", "ab");
5680   emitcode ("rrc", "a");
5681   aopOp(result, ic, TRUE, FALSE);
5682
5683   popB (pushedB);
5684
5685   aopPut (result, "c", 0);
5686 }
5687
5688 /*-----------------------------------------------------------------*/
5689 /* genDivOneByte : 8 bit division                                  */
5690 /*-----------------------------------------------------------------*/
5691 static void
5692 genDivOneByte (operand * left,
5693                operand * right,
5694                operand * result,
5695                iCode   * ic)
5696 {
5697   bool lUnsigned, rUnsigned, pushedB;
5698   bool runtimeSign, compiletimeSign;
5699   char *l;
5700   symbol *lbl;
5701   int size, offset;
5702
5703   D(emitcode (";     genDivOneByte",""));
5704
5705   offset = 1;
5706   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5707   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5708
5709   pushedB = pushB ();
5710
5711   /* signed or unsigned */
5712   if (lUnsigned && rUnsigned)
5713     {
5714       /* unsigned is easy */
5715       LOAD_AB_FOR_DIV (left, right, l);
5716       emitcode ("div", "ab");
5717
5718       _G.accInUse++;
5719       aopOp (result, ic, TRUE, FALSE);
5720       aopPut (result, "a", 0);
5721       _G.accInUse--;
5722
5723       size = AOP_SIZE (result) - 1;
5724
5725       while (size--)
5726         aopPut (result, zero, offset++);
5727
5728       popB (pushedB);
5729       return;
5730     }
5731
5732   /* signed is a little bit more difficult */
5733
5734   /* now sign adjust for both left & right */
5735
5736   /* let's see what's needed: */
5737   /* apply negative sign during runtime */
5738   runtimeSign = FALSE;
5739   /* negative sign from literals */
5740   compiletimeSign = FALSE;
5741
5742   if (!lUnsigned)
5743     {
5744       if (AOP_TYPE(left) == AOP_LIT)
5745         {
5746           /* signed literal */
5747           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5748           if (val < 0)
5749             compiletimeSign = TRUE;
5750         }
5751       else
5752         /* signed but not literal */
5753         runtimeSign = TRUE;
5754     }
5755
5756   if (!rUnsigned)
5757     {
5758       if (AOP_TYPE(right) == AOP_LIT)
5759         {
5760           /* signed literal */
5761           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5762           if (val < 0)
5763             compiletimeSign ^= TRUE;
5764         }
5765       else
5766         /* signed but not literal */
5767         runtimeSign = TRUE;
5768     }
5769
5770   /* initialize F0, which stores the runtime sign */
5771   if (runtimeSign)
5772     {
5773       if (compiletimeSign)
5774         emitcode ("setb", "F0"); /* set sign flag */
5775       else
5776         emitcode ("clr", "F0"); /* reset sign flag */
5777     }
5778
5779   /* save the signs of the operands */
5780   if (AOP_TYPE(right) == AOP_LIT)
5781     {
5782       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5783
5784       if (!rUnsigned && val < 0)
5785         emitcode ("mov", "b,#0x%02x", -val);
5786       else
5787         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5788     }
5789   else /* ! literal */
5790     {
5791       if (rUnsigned)
5792         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5793       else
5794         {
5795           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5796           lbl = newiTempLabel (NULL);
5797           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5798           emitcode ("cpl", "F0"); /* complement sign flag */
5799           emitcode ("cpl", "a");  /* 2's complement */
5800           emitcode ("inc", "a");
5801           emitLabel (lbl);
5802           emitcode ("mov", "b,a");
5803         }
5804     }
5805
5806   if (AOP_TYPE(left) == AOP_LIT)
5807     {
5808       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5809
5810       if (!lUnsigned && val < 0)
5811         emitcode ("mov", "a,#0x%02x", -val);
5812       else
5813         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5814     }
5815   else /* ! literal */
5816     {
5817       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5818
5819       if (!lUnsigned)
5820         {
5821           lbl = newiTempLabel (NULL);
5822           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5823           emitcode ("cpl", "F0"); /* complement sign flag */
5824           emitcode ("cpl", "a");  /* 2's complement */
5825           emitcode ("inc", "a");
5826           emitLabel (lbl);
5827         }
5828     }
5829
5830   /* now the division */
5831   emitcode ("nop", "; workaround for DS80C390 div bug.");
5832   emitcode ("div", "ab");
5833
5834   if (runtimeSign || compiletimeSign)
5835     {
5836       lbl = newiTempLabel (NULL);
5837       if (runtimeSign)
5838         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5839       emitcode ("cpl", "a"); /* lsb 2's complement */
5840       emitcode ("inc", "a");
5841       emitLabel (lbl);
5842
5843       _G.accInUse++;
5844       aopOp (result, ic, TRUE, FALSE);
5845       size = AOP_SIZE (result) - 1;
5846
5847       if (size > 0)
5848         {
5849           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5850              then the result will be in b, a */
5851           emitcode ("mov", "b,a"); /* 1 */
5852           /* msb is 0x00 or 0xff depending on the sign */
5853           if (runtimeSign)
5854             {
5855               emitcode ("mov",  "c,F0");
5856               emitcode ("subb", "a,acc");
5857               emitcode ("xch",  "a,b"); /* 2 */
5858               while (size--)
5859                 aopPut (result, "b", offset++); /* write msb's */
5860             }
5861           else /* compiletimeSign */
5862             while (size--)
5863               aopPut (result, "#0xff", offset++); /* write msb's */
5864         }
5865       aopPut (result, "a", 0); /* 3: write lsb */
5866     }
5867   else
5868     {
5869       _G.accInUse++;
5870       aopOp(result, ic, TRUE, FALSE);
5871       size = AOP_SIZE (result) - 1;
5872
5873       aopPut (result, "a", 0);
5874       while (size--)
5875         aopPut (result, zero, offset++);
5876     }
5877   _G.accInUse--;
5878   popB (pushedB);
5879 }
5880
5881 /*-----------------------------------------------------------------*/
5882 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5883 /*-----------------------------------------------------------------*/
5884 static void genDivTwoByte (operand *left, operand *right,
5885                             operand *result, iCode *ic)
5886 {
5887         sym_link *retype = getSpec(operandType(right));
5888         sym_link *letype = getSpec(operandType(left));
5889         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5890         symbol *lbl;
5891
5892         /* save EA bit in F1 */
5893         lbl = newiTempLabel(NULL);
5894         emitcode ("setb","F1");
5895         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5896         emitcode ("clr","F1");
5897         emitLabel (lbl);
5898
5899         /* load up MA with left */
5900         if (!umult) {
5901                 emitcode("clr","F0");
5902                 lbl = newiTempLabel(NULL);
5903                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5904                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5905                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5906                 emitcode ("xch", "a,b");
5907                 emitcode ("cpl","a");
5908                 emitcode ("add", "a,#1");
5909                 emitcode ("xch", "a,b");
5910                 emitcode ("cpl", "a"); // msb
5911                 emitcode ("addc","a,#0");
5912                 emitcode ("setb","F0");
5913                 emitLabel (lbl);
5914                 emitcode ("mov","ma,b");
5915                 emitcode ("mov","ma,a");
5916         } else {
5917                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5918                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5919         }
5920
5921         /* load up MB with right */
5922         if (!umult) {
5923                 if (AOP_TYPE(right) == AOP_LIT) {
5924                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5925                         if (val < 0) {
5926                                 lbl = newiTempLabel(NULL);
5927                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5928                                 emitcode("setb","F0");
5929                                 emitLabel (lbl);
5930                                 val = -val;
5931                         }
5932                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5933                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5934                 } else {
5935                         lbl = newiTempLabel(NULL);
5936                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5937                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5938                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5939                         emitcode ("xch", "a,b");
5940                         emitcode ("cpl","a");
5941                         emitcode ("add", "a,#1");
5942                         emitcode ("xch", "a,b");
5943                         emitcode ("cpl", "a"); // msb
5944                         emitcode ("addc", "a,#0");
5945                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5946                         emitcode ("setb","F0");
5947                         emitLabel (lbl);
5948                         emitcode ("mov","mb,b");
5949                         emitcode ("mov","mb,a");
5950                 }
5951         } else {
5952                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5953                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5954         }
5955
5956         /* wait for multiplication to finish */
5957         lbl = newiTempLabel(NULL);
5958         emitLabel (lbl);
5959         emitcode("mov","a,mcnt1");
5960         emitcode("anl","a,#!constbyte",0x80);
5961         emitcode("jnz","!tlabel",lbl->key+100);
5962
5963         freeAsmop (left, NULL, ic, TRUE);
5964         freeAsmop (right, NULL, ic,TRUE);
5965         aopOp(result, ic, TRUE, FALSE);
5966
5967         /* if unsigned then simple */
5968         if (umult) {
5969                 aopPut(result,"ma",1);
5970                 aopPut(result,"ma",0);
5971         } else {
5972                 emitcode("push","ma");
5973                 MOVA("ma");
5974                 /* negate result if needed */
5975                 lbl = newiTempLabel(NULL);
5976                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5977                 emitcode("cpl","a");
5978                 emitcode("add","a,#1");
5979                 emitLabel (lbl);
5980                 aopPut(result,"a",0);
5981                 emitcode("pop","acc");
5982                 lbl = newiTempLabel(NULL);
5983                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5984                 emitcode("cpl","a");
5985                 emitcode("addc","a,#0");
5986                 emitLabel (lbl);
5987                 aopPut(result,"a",1);
5988         }
5989         freeAsmop (result, NULL, ic, TRUE);
5990         /* restore EA bit in F1 */
5991         lbl = newiTempLabel(NULL);
5992         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5993         emitcode ("setb","EA");
5994         emitLabel (lbl);
5995         return ;
5996 }
5997
5998 /*-----------------------------------------------------------------*/
5999 /* genDiv - generates code for division                            */
6000 /*-----------------------------------------------------------------*/
6001 static void
6002 genDiv (iCode * ic)
6003 {
6004   operand *left = IC_LEFT (ic);
6005   operand *right = IC_RIGHT (ic);
6006   operand *result = IC_RESULT (ic);
6007
6008   D (emitcode (";", "genDiv"));
6009
6010   /* assign the amsops */
6011   AOP_OP_2 (ic);
6012
6013   /* special cases first */
6014   /* both are bits */
6015   if (AOP_TYPE (left) == AOP_CRY &&
6016       AOP_TYPE (right) == AOP_CRY)
6017     {
6018       genDivbits (left, right, result, ic);
6019       goto release;
6020     }
6021
6022   /* if both are of size == 1 */
6023   if (AOP_SIZE (left) == 1 &&
6024       AOP_SIZE (right) == 1)
6025     {
6026       genDivOneByte (left, right, result, ic);
6027       goto release;
6028     }
6029
6030   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6031           /* use the ds390 ARITHMETIC accel UNIT */
6032           genDivTwoByte (left, right, result, ic);
6033           return ;
6034   }
6035   /* should have been converted to function call */
6036   assert (0);
6037 release:
6038   freeAsmop (result, NULL, ic, TRUE);
6039   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6040   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6041 }
6042
6043 /*-----------------------------------------------------------------*/
6044 /* genModbits :- modulus of bits                                   */
6045 /*-----------------------------------------------------------------*/
6046 static void
6047 genModbits (operand * left,
6048             operand * right,
6049             operand * result,
6050             iCode   * ic)
6051 {
6052   char *l;
6053   bool pushedB;
6054
6055   D (emitcode (";", "genModbits"));
6056
6057   pushedB = pushB ();
6058
6059   /* the result must be bit */
6060   LOAD_AB_FOR_DIV (left, right, l);
6061   emitcode ("div", "ab");
6062   emitcode ("mov", "a,b");
6063   emitcode ("rrc", "a");
6064   aopOp(result, ic, TRUE, FALSE);
6065
6066   popB (pushedB);
6067
6068   aopPut (result, "c", 0);
6069 }
6070
6071 /*-----------------------------------------------------------------*/
6072 /* genModOneByte : 8 bit modulus                                   */
6073 /*-----------------------------------------------------------------*/
6074 static void
6075 genModOneByte (operand * left,
6076                operand * right,
6077                operand * result,
6078                iCode   * ic)
6079 {
6080   bool lUnsigned, rUnsigned, pushedB;
6081   bool runtimeSign, compiletimeSign;
6082   char *l;
6083   symbol *lbl;
6084   int size, offset;
6085
6086   D (emitcode (";", "genModOneByte"));
6087
6088   offset = 1;
6089   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6090   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6091
6092   pushedB = pushB ();
6093
6094   /* signed or unsigned */
6095   if (lUnsigned && rUnsigned)
6096     {
6097       /* unsigned is easy */
6098       LOAD_AB_FOR_DIV (left, right, l);
6099       emitcode ("div", "ab");
6100       aopOp (result, ic, TRUE, FALSE);
6101       aopPut (result, "b", 0);
6102
6103       for (size = AOP_SIZE (result) - 1; size--;)
6104         aopPut (result, zero, offset++);
6105
6106       popB (pushedB);
6107       return;
6108     }
6109
6110   /* signed is a little bit more difficult */
6111
6112   /* now sign adjust for both left & right */
6113
6114   /* modulus: sign of the right operand has no influence on the result! */
6115   if (AOP_TYPE(right) == AOP_LIT)
6116     {
6117       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6118
6119       if (!rUnsigned && val < 0)
6120         emitcode ("mov", "b,#0x%02x", -val);
6121       else
6122         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6123     }
6124   else /* not literal */
6125     {
6126       if (rUnsigned)
6127         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6128       else
6129         {
6130           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6131           lbl = newiTempLabel (NULL);
6132           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6133           emitcode ("cpl", "a");  /* 2's complement */
6134           emitcode ("inc", "a");
6135           emitLabel (lbl);
6136           emitcode ("mov", "b,a");
6137         }
6138     }
6139
6140   /* let's see what's needed: */
6141   /* apply negative sign during runtime */
6142   runtimeSign = FALSE;
6143   /* negative sign from literals */
6144   compiletimeSign = FALSE;
6145
6146   /* sign adjust left side */
6147   if (AOP_TYPE(left) == AOP_LIT)
6148     {
6149       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6150
6151       if (!lUnsigned && val < 0)
6152         {
6153           compiletimeSign = TRUE; /* set sign flag */
6154           emitcode ("mov", "a,#0x%02x", -val);
6155         }
6156       else
6157         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6158     }
6159   else /* ! literal */
6160     {
6161       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6162
6163       if (!lUnsigned)
6164         {
6165           runtimeSign = TRUE;
6166           emitcode ("clr", "F0"); /* clear sign flag */
6167
6168           lbl = newiTempLabel (NULL);
6169           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6170           emitcode ("setb", "F0"); /* set sign flag */
6171           emitcode ("cpl", "a");   /* 2's complement */
6172           emitcode ("inc", "a");
6173           emitLabel (lbl);
6174         }
6175     }
6176
6177   /* now the modulus */
6178   emitcode ("nop", "; workaround for DS80C390 div bug.");
6179   emitcode ("div", "ab");
6180
6181   if (runtimeSign || compiletimeSign)
6182     {
6183       emitcode ("mov", "a,b");
6184       lbl = newiTempLabel (NULL);
6185       if (runtimeSign)
6186         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6187       emitcode ("cpl", "a"); /* lsb 2's complement */
6188       emitcode ("inc", "a");
6189       emitLabel (lbl);
6190
6191       _G.accInUse++;
6192       aopOp (result, ic, TRUE, FALSE);
6193       size = AOP_SIZE (result) - 1;
6194
6195       if (size > 0)
6196         {
6197           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6198              then the result will be in b, a */
6199           emitcode ("mov", "b,a"); /* 1 */
6200           /* msb is 0x00 or 0xff depending on the sign */
6201           if (runtimeSign)
6202             {
6203               emitcode ("mov",  "c,F0");
6204               emitcode ("subb", "a,acc");
6205               emitcode ("xch",  "a,b"); /* 2 */
6206               while (size--)
6207                 aopPut (result, "b", offset++); /* write msb's */
6208             }
6209           else /* compiletimeSign */
6210             while (size--)
6211               aopPut (result, "#0xff", offset++); /* write msb's */
6212         }
6213       aopPut (result, "a", 0); /* 3: write lsb */
6214     }
6215   else
6216     {
6217       _G.accInUse++;
6218       aopOp(result, ic, TRUE, FALSE);
6219       size = AOP_SIZE (result) - 1;
6220
6221       aopPut (result, "b", 0);
6222       while (size--)
6223         aopPut (result, zero, offset++);
6224     }
6225   _G.accInUse--;
6226   popB (pushedB);
6227 }
6228
6229 /*-----------------------------------------------------------------*/
6230 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6231 /*-----------------------------------------------------------------*/
6232 static void genModTwoByte (operand *left, operand *right,
6233                             operand *result, iCode *ic)
6234 {
6235         sym_link *retype = getSpec(operandType(right));
6236         sym_link *letype = getSpec(operandType(left));
6237         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6238         symbol *lbl;
6239
6240         /* load up MA with left */
6241         /* save EA bit in F1 */
6242         lbl = newiTempLabel(NULL);
6243         emitcode ("setb","F1");
6244         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6245         emitcode ("clr","F1");
6246         emitLabel (lbl);
6247
6248         if (!umult) {
6249                 lbl = newiTempLabel(NULL);
6250                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6251                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6252                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6253                 emitcode ("xch", "a,b");
6254                 emitcode ("cpl","a");
6255                 emitcode ("add", "a,#1");
6256                 emitcode ("xch", "a,b");
6257                 emitcode ("cpl", "a"); // msb
6258                 emitcode ("addc","a,#0");
6259                 emitLabel (lbl);
6260                 emitcode ("mov","ma,b");
6261                 emitcode ("mov","ma,a");
6262         } else {
6263                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6264                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6265         }
6266
6267         /* load up MB with right */
6268         if (!umult) {
6269                 if (AOP_TYPE(right) == AOP_LIT) {
6270                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6271                         if (val < 0) {
6272                                 val = -val;
6273                         }
6274                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6275                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6276                 } else {
6277                         lbl = newiTempLabel(NULL);
6278                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6279                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6280                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6281                         emitcode ("xch", "a,b");
6282                         emitcode ("cpl","a");
6283                         emitcode ("add", "a,#1");
6284                         emitcode ("xch", "a,b");
6285                         emitcode ("cpl", "a"); // msb
6286                         emitcode ("addc", "a,#0");
6287                         emitLabel (lbl);
6288                         emitcode ("mov","mb,b");
6289                         emitcode ("mov","mb,a");
6290                 }
6291         } else {
6292                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6293                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6294         }
6295
6296         /* wait for multiplication to finish */
6297         lbl = newiTempLabel(NULL);
6298         emitLabel (lbl);
6299         emitcode("mov","a,mcnt1");
6300         emitcode("anl","a,#!constbyte",0x80);
6301         emitcode("jnz","!tlabel",lbl->key+100);
6302
6303         freeAsmop (left, NULL, ic, TRUE);
6304         freeAsmop (right, NULL, ic,TRUE);
6305         aopOp(result, ic, TRUE, FALSE);
6306
6307         aopPut(result,"mb",1);
6308         aopPut(result,"mb",0);
6309         freeAsmop (result, NULL, ic, TRUE);
6310
6311         /* restore EA bit in F1 */
6312         lbl = newiTempLabel(NULL);
6313         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6314         emitcode ("setb","EA");
6315         emitLabel (lbl);
6316 }
6317
6318 /*-----------------------------------------------------------------*/
6319 /* genMod - generates code for division                            */
6320 /*-----------------------------------------------------------------*/
6321 static void
6322 genMod (iCode * ic)
6323 {
6324   operand *left = IC_LEFT (ic);
6325   operand *right = IC_RIGHT (ic);
6326   operand *result = IC_RESULT (ic);
6327
6328   D (emitcode (";", "genMod"));
6329
6330   /* assign the asmops */
6331   AOP_OP_2 (ic);
6332
6333   /* special cases first */
6334   /* both are bits */
6335   if (AOP_TYPE (left) == AOP_CRY &&
6336       AOP_TYPE (right) == AOP_CRY)
6337     {
6338       genModbits (left, right, result, ic);
6339       goto release;
6340     }
6341
6342   /* if both are of size == 1 */
6343   if (AOP_SIZE (left) == 1 &&
6344       AOP_SIZE (right) == 1)
6345     {
6346       genModOneByte (left, right, result, ic);
6347       goto release;
6348     }
6349
6350   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6351           /* use the ds390 ARITHMETIC accel UNIT */
6352           genModTwoByte (left, right, result, ic);
6353           return ;
6354   }
6355
6356   /* should have been converted to function call */
6357   assert (0);
6358
6359 release:
6360   freeAsmop (result, NULL, ic, TRUE);
6361   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6362   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6363 }
6364
6365 /*-----------------------------------------------------------------*/
6366 /* genIfxJump :- will create a jump depending on the ifx           */
6367 /*-----------------------------------------------------------------*/
6368 static void
6369 genIfxJump (iCode * ic, char *jval)
6370 {
6371   symbol *jlbl;
6372   symbol *tlbl = newiTempLabel (NULL);
6373   char *inst;
6374
6375   D (emitcode (";", "genIfxJump"));
6376
6377   /* if true label then we jump if condition
6378      supplied is true */
6379   if (IC_TRUE (ic))
6380     {
6381       jlbl = IC_TRUE (ic);
6382       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6383                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6384     }
6385   else
6386     {
6387       /* false label is present */
6388       jlbl = IC_FALSE (ic);
6389       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6390                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6391     }
6392   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6393     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6394   else
6395     emitcode (inst, "!tlabel", tlbl->key + 100);
6396   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6397   emitLabel (tlbl);
6398
6399   /* mark the icode as generated */
6400   ic->generated = 1;
6401 }
6402
6403 /*-----------------------------------------------------------------*/
6404 /* genCmp :- greater or less than comparison                       */
6405 /*-----------------------------------------------------------------*/
6406 static void
6407 genCmp (operand * left, operand * right,
6408         iCode * ic, iCode * ifx, int sign)
6409 {
6410   int size, offset = 0;
6411   unsigned long lit = 0L;
6412   operand *result;
6413
6414   D (emitcode (";", "genCmp"));
6415
6416   result = IC_RESULT (ic);
6417
6418   /* if left & right are bit variables */
6419   if (AOP_TYPE (left) == AOP_CRY &&
6420       AOP_TYPE (right) == AOP_CRY)
6421     {
6422       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6423       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6424     }
6425   else
6426     {
6427       /* subtract right from left if at the
6428          end the carry flag is set then we know that
6429          left is greater than right */
6430       size = max (AOP_SIZE (left), AOP_SIZE (right));
6431
6432       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6433       if ((size == 1) && !sign &&
6434           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6435         {
6436           symbol *lbl = newiTempLabel (NULL);
6437           emitcode ("cjne", "%s,%s,!tlabel",
6438                     aopGet (left, offset, FALSE, FALSE, NULL),
6439                     aopGet (right, offset, FALSE, FALSE, NULL),
6440                     lbl->key + 100);
6441           emitLabel (lbl);
6442         }
6443       else
6444         {
6445           if (AOP_TYPE (right) == AOP_LIT)
6446             {
6447               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6448               /* optimize if(x < 0) or if(x >= 0) */
6449               if (lit == 0L)
6450                 {
6451                   if (!sign)
6452                     {
6453                       CLRC;
6454                     }
6455                   else
6456                     {
6457                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6458
6459                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6460                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6461
6462                       aopOp (result, ic, FALSE, FALSE);
6463
6464                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6465                         {
6466                           freeAsmop (result, NULL, ic, TRUE);
6467                           genIfxJump (ifx, "acc.7");
6468                           return;
6469                         }
6470                       else
6471                         {
6472                           emitcode ("rlc", "a");
6473                         }
6474                       goto release_freedLR;
6475                     }
6476                   goto release;
6477                 }
6478             }
6479           CLRC;
6480           while (size--)
6481             {
6482               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6483               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6484               // emitcode (";", "genCmp #2");
6485               if (sign && (size == 0))
6486                 {
6487                   // emitcode (";", "genCmp #3");
6488                   emitcode ("xrl", "a,#!constbyte",0x80);
6489                   if (AOP_TYPE (right) == AOP_LIT)
6490                     {
6491                       unsigned long lit = (unsigned long)
6492                       floatFromVal (AOP (right)->aopu.aop_lit);
6493                       // emitcode (";", "genCmp #3.1");
6494                       emitcode ("subb", "a,#!constbyte",
6495                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6496                     }
6497                   else
6498                     {
6499                       // emitcode (";", "genCmp #3.2");
6500                       saveAccWarn = 0;
6501                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6502                       saveAccWarn = DEFAULT_ACC_WARNING;
6503                       emitcode ("xrl", "b,#!constbyte",0x80);
6504                       emitcode ("subb", "a,b");
6505                     }
6506                 }
6507               else
6508                 {
6509                   const char *s;
6510
6511                   // emitcode (";", "genCmp #4");
6512                   saveAccWarn = 0;
6513                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6514                   saveAccWarn = DEFAULT_ACC_WARNING;
6515
6516                   emitcode ("subb", "a,%s", s);
6517                 }
6518             }
6519         }
6520     }
6521
6522 release:
6523 /* Don't need the left & right operands any more; do need the result. */
6524   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6525   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6526
6527   aopOp (result, ic, FALSE, FALSE);
6528
6529 release_freedLR:
6530
6531   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6532     {
6533       outBitC (result);
6534     }
6535   else
6536     {
6537       /* if the result is used in the next
6538          ifx conditional branch then generate
6539          code a little differently */
6540       if (ifx)
6541         {
6542           genIfxJump (ifx, "c");
6543         }
6544       else
6545         {
6546           outBitC (result);
6547         }
6548       /* leave the result in acc */
6549     }
6550   freeAsmop (result, NULL, ic, TRUE);
6551 }
6552
6553 /*-----------------------------------------------------------------*/
6554 /* genCmpGt :- greater than comparison                             */
6555 /*-----------------------------------------------------------------*/
6556 static void
6557 genCmpGt (iCode * ic, iCode * ifx)
6558 {
6559   operand *left, *right;
6560   sym_link *letype, *retype;
6561   int sign;
6562
6563   D (emitcode (";", "genCmpGt"));
6564
6565   left = IC_LEFT (ic);
6566   right = IC_RIGHT (ic);
6567
6568   letype = getSpec (operandType (left));
6569   retype = getSpec (operandType (right));
6570   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6571
6572   /* assign the left & right amsops */
6573   AOP_OP_2 (ic);
6574
6575   genCmp (right, left, ic, ifx, sign);
6576 }
6577
6578 /*-----------------------------------------------------------------*/
6579 /* genCmpLt - less than comparisons                                */
6580 /*-----------------------------------------------------------------*/
6581 static void
6582 genCmpLt (iCode * ic, iCode * ifx)
6583 {
6584   operand *left, *right;
6585   sym_link *letype, *retype;
6586   int sign;
6587
6588   D (emitcode (";", "genCmpLt"));
6589
6590   left = IC_LEFT (ic);
6591   right = IC_RIGHT (ic);
6592
6593   letype = getSpec (operandType (left));
6594   retype = getSpec (operandType (right));
6595   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6596
6597   /* assign the left & right amsops */
6598   AOP_OP_2 (ic);
6599
6600   genCmp (left, right, ic, ifx, sign);
6601 }
6602
6603 /*-----------------------------------------------------------------*/
6604 /* gencjneshort - compare and jump if not equal                    */
6605 /*-----------------------------------------------------------------*/
6606 static void
6607 gencjneshort (operand * left, operand * right, symbol * lbl)
6608 {
6609   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6610   int offset = 0;
6611   unsigned long lit = 0L;
6612
6613   D (emitcode (";", "gencjneshort"));
6614
6615   /* if the left side is a literal or
6616      if the right is in a pointer register and left
6617      is not */
6618   if ((AOP_TYPE (left) == AOP_LIT) ||
6619       (AOP_TYPE (left) == AOP_IMMD) ||
6620       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6621     {
6622       operand *t = right;
6623       right = left;
6624       left = t;
6625     }
6626
6627   if (AOP_TYPE (right) == AOP_LIT)
6628     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6629
6630   if (opIsGptr (left) || opIsGptr (right))
6631     {
6632       /* We are comparing a generic pointer to something.
6633        * Exclude the generic type byte from the comparison.
6634        */
6635       size--;
6636       D (emitcode (";", "cjneshort: generic ptr special case."););
6637     }
6638
6639
6640   /* if the right side is a literal then anything goes */
6641   if (AOP_TYPE (right) == AOP_LIT &&
6642       AOP_TYPE (left) != AOP_DIR)
6643     {
6644       while (size--)
6645         {
6646           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6647           emitcode ("cjne", "a,%s,!tlabel",
6648                     aopGet (right, offset, FALSE, FALSE, NULL),
6649                     lbl->key + 100);
6650           offset++;
6651         }
6652     }
6653
6654   /* if the right side is in a register or in direct space or
6655      if the left is a pointer register & right is not */
6656   else if (AOP_TYPE (right) == AOP_REG ||
6657            AOP_TYPE (right) == AOP_DIR ||
6658            AOP_TYPE (right) == AOP_LIT ||
6659            AOP_TYPE (right) == AOP_IMMD ||
6660            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6661            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6662     {
6663       while (size--)
6664         {
6665           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6666           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6667               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6668             emitcode ("jnz", "!tlabel", lbl->key + 100);
6669           else
6670             emitcode ("cjne", "a,%s,!tlabel",
6671                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6672                       lbl->key + 100);
6673           offset++;
6674         }
6675     }
6676   else
6677     {
6678       /* right is a pointer reg need both a & b */
6679       while (size--)
6680         {
6681           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6682           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6683           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6684           offset++;
6685         }
6686     }
6687 }
6688
6689 /*-----------------------------------------------------------------*/
6690 /* gencjne - compare and jump if not equal                         */
6691 /*-----------------------------------------------------------------*/
6692 static void
6693 gencjne (operand * left, operand * right, symbol * lbl)
6694 {
6695   symbol *tlbl = newiTempLabel (NULL);
6696
6697   D (emitcode (";", "gencjne"));
6698
6699   gencjneshort (left, right, lbl);
6700
6701   emitcode ("mov", "a,%s", one);
6702   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6703   emitLabel (lbl);
6704   emitcode ("clr", "a");
6705   emitLabel (tlbl);
6706 }
6707
6708 /*-----------------------------------------------------------------*/
6709 /* genCmpEq - generates code for equal to                          */
6710 /*-----------------------------------------------------------------*/
6711 static void
6712 genCmpEq (iCode * ic, iCode * ifx)
6713 {
6714   operand *left, *right, *result;
6715
6716   D (emitcode (";", "genCmpEq"));
6717
6718   AOP_OP_2 (ic);
6719   AOP_SET_LOCALS (ic);
6720
6721   /* if literal, literal on the right or
6722      if the right is in a pointer register and left
6723      is not */
6724   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6725       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6726     {
6727       operand *t = IC_RIGHT (ic);
6728       IC_RIGHT (ic) = IC_LEFT (ic);
6729       IC_LEFT (ic) = t;
6730     }
6731
6732   if (ifx &&                    /* !AOP_SIZE(result) */
6733       OP_SYMBOL (result) &&
6734       OP_SYMBOL (result)->regType == REG_CND)
6735     {
6736       symbol *tlbl;
6737       /* if they are both bit variables */
6738       if (AOP_TYPE (left) == AOP_CRY &&
6739           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6740         {
6741           if (AOP_TYPE (right) == AOP_LIT)
6742             {
6743               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6744               if (lit == 0L)
6745                 {
6746                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6747                   emitcode ("cpl", "c");
6748                 }
6749               else if (lit == 1L)
6750                 {
6751                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6752                 }
6753               else
6754                 {
6755                   emitcode ("clr", "c");
6756                 }
6757               /* AOP_TYPE(right) == AOP_CRY */
6758             }
6759           else
6760             {
6761               symbol *lbl = newiTempLabel (NULL);
6762               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6763               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6764               emitcode ("cpl", "c");
6765               emitLabel (lbl);
6766             }
6767           /* if true label then we jump if condition
6768              supplied is true */
6769           tlbl = newiTempLabel (NULL);
6770           if (IC_TRUE (ifx))
6771             {
6772               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6773               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6774             }
6775           else
6776             {
6777               emitcode ("jc", "!tlabel", tlbl->key + 100);
6778               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6779             }
6780           emitLabel (tlbl);
6781         }
6782       else
6783         {
6784           tlbl = newiTempLabel (NULL);
6785           gencjneshort (left, right, tlbl);
6786           if (IC_TRUE (ifx))
6787             {
6788               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6789               emitLabel (tlbl);
6790             }
6791           else
6792             {
6793               symbol *lbl = newiTempLabel (NULL);
6794               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6795               emitLabel (tlbl);
6796               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6797               emitLabel (lbl);
6798             }
6799         }
6800       /* mark the icode as generated */
6801       ifx->generated = 1;
6802
6803       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6804       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6805       return;
6806     }
6807
6808   /* if they are both bit variables */
6809   if (AOP_TYPE (left) == AOP_CRY &&
6810       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6811     {
6812       if (AOP_TYPE (right) == AOP_LIT)
6813         {
6814           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6815           if (lit == 0L)
6816             {
6817               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6818               emitcode ("cpl", "c");
6819             }
6820           else if (lit == 1L)
6821             {
6822               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6823             }
6824           else
6825             {
6826               emitcode ("clr", "c");
6827             }
6828           /* AOP_TYPE(right) == AOP_CRY */
6829         }
6830       else
6831         {
6832           symbol *lbl = newiTempLabel (NULL);
6833           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6834           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6835           emitcode ("cpl", "c");
6836           emitLabel (lbl);
6837         }
6838
6839       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6840       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6841
6842       aopOp (result, ic, TRUE, FALSE);
6843
6844       /* c = 1 if egal */
6845       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6846         {
6847           outBitC (result);
6848           goto release;
6849         }
6850       if (ifx)
6851         {
6852           genIfxJump (ifx, "c");
6853           goto release;
6854         }
6855       /* if the result is used in an arithmetic operation
6856          then put the result in place */
6857       outBitC (result);
6858     }
6859   else
6860     {
6861       gencjne (left, right, newiTempLabel (NULL));
6862
6863       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6864       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6865
6866       aopOp (result, ic, TRUE, FALSE);
6867
6868       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6869         {
6870           aopPut (result, "a", 0);
6871           goto release;
6872         }
6873       if (ifx)
6874         {
6875           genIfxJump (ifx, "a");
6876           goto release;
6877         }
6878       /* if the result is used in an arithmetic operation
6879          then put the result in place */
6880       if (AOP_TYPE (result) != AOP_CRY)
6881         outAcc (result);
6882       /* leave the result in acc */
6883     }
6884
6885 release:
6886   freeAsmop (result, NULL, ic, TRUE);
6887 }
6888
6889 /*-----------------------------------------------------------------*/
6890 /* ifxForOp - returns the icode containing the ifx for operand     */
6891 /*-----------------------------------------------------------------*/
6892 static iCode *
6893 ifxForOp (operand * op, iCode * ic)
6894 {
6895   /* if true symbol then needs to be assigned */
6896   if (IS_TRUE_SYMOP (op))
6897     return NULL;
6898
6899   /* if this has register type condition and
6900      the next instruction is ifx with the same operand
6901      and live to of the operand is upto the ifx only then */
6902   if (ic->next &&
6903       ic->next->op == IFX &&
6904       IC_COND (ic->next)->key == op->key &&
6905       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6906     return ic->next;
6907
6908   return NULL;
6909 }
6910
6911 /*-----------------------------------------------------------------*/
6912 /* hasInc - operand is incremented before any other use            */
6913 /*-----------------------------------------------------------------*/
6914 static iCode *
6915 hasInc (operand *op, iCode *ic, int osize)
6916 {
6917   sym_link *type = operandType(op);
6918   sym_link *retype = getSpec (type);
6919   iCode *lic = ic->next;
6920   int isize ;
6921
6922   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6923   if (!IS_SYMOP(op)) return NULL;
6924
6925   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6926   if (IS_AGGREGATE(type->next)) return NULL;
6927   if (osize != (isize = getSize(type->next))) return NULL;
6928
6929   while (lic) {
6930       /* if operand of the form op = op + <sizeof *op> */
6931       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6932           isOperandEqual(IC_RESULT(lic),op) &&
6933           isOperandLiteral(IC_RIGHT(lic)) &&
6934           operandLitValue(IC_RIGHT(lic)) == isize) {
6935           return lic;
6936       }
6937       /* if the operand used or deffed */
6938       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6939           return NULL;
6940       }
6941       /* if GOTO or IFX */
6942       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6943       lic = lic->next;
6944   }
6945   return NULL;
6946 }
6947
6948 /*-----------------------------------------------------------------*/
6949 /* genAndOp - for && operation                                     */
6950 /*-----------------------------------------------------------------*/
6951 static void
6952 genAndOp (iCode * ic)
6953 {
6954   operand *left, *right, *result;
6955   symbol *tlbl;
6956
6957   D (emitcode (";", "genAndOp"));
6958
6959   /* note here that && operations that are in an
6960      if statement are taken away by backPatchLabels
6961      only those used in arthmetic operations remain */
6962   AOP_OP_2 (ic);
6963   AOP_SET_LOCALS (ic);
6964
6965   /* if both are bit variables */
6966   if (AOP_TYPE (left) == AOP_CRY &&
6967       AOP_TYPE (right) == AOP_CRY)
6968     {
6969       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6970       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6971       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6972       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6973
6974       aopOp (result,ic,FALSE, FALSE);
6975       outBitC (result);
6976     }
6977   else
6978     {
6979       tlbl = newiTempLabel (NULL);
6980       toBoolean (left);
6981       emitcode ("jz", "!tlabel", tlbl->key + 100);
6982       toBoolean (right);
6983       emitLabel (tlbl);
6984       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6985       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6986
6987       aopOp (result,ic,FALSE, FALSE);
6988       outBitAcc (result);
6989     }
6990
6991     freeAsmop (result, NULL, ic, TRUE);
6992 }
6993
6994
6995 /*-----------------------------------------------------------------*/
6996 /* genOrOp - for || operation                                      */
6997 /*-----------------------------------------------------------------*/
6998 static void
6999 genOrOp (iCode * ic)
7000 {
7001   operand *left, *right, *result;
7002   symbol *tlbl;
7003
7004   D (emitcode (";", "genOrOp"));
7005
7006   /* note here that || operations that are in an
7007      if statement are taken away by backPatchLabels
7008      only those used in arthmetic operations remain */
7009   AOP_OP_2 (ic);
7010   AOP_SET_LOCALS (ic);
7011
7012   /* if both are bit variables */
7013   if (AOP_TYPE (left) == AOP_CRY &&
7014       AOP_TYPE (right) == AOP_CRY)
7015     {
7016       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7017       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7018       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7019       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7020
7021       aopOp (result,ic,FALSE, FALSE);
7022
7023       outBitC (result);
7024     }
7025   else
7026     {
7027       tlbl = newiTempLabel (NULL);
7028       toBoolean (left);
7029       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7030       toBoolean (right);
7031       emitLabel (tlbl);
7032       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7033       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7034
7035       aopOp (result,ic,FALSE, FALSE);
7036
7037       outBitAcc (result);
7038     }
7039
7040   freeAsmop (result, NULL, ic, TRUE);
7041 }
7042
7043 /*-----------------------------------------------------------------*/
7044 /* isLiteralBit - test if lit == 2^n                               */
7045 /*-----------------------------------------------------------------*/
7046 static int
7047 isLiteralBit (unsigned long lit)
7048 {
7049   unsigned long pw[32] =
7050   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7051    0x100L, 0x200L, 0x400L, 0x800L,
7052    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7053    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7054    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7055    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7056    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7057   int idx;
7058
7059   for (idx = 0; idx < 32; idx++)
7060     if (lit == pw[idx])
7061       return idx + 1;
7062   return 0;
7063 }
7064
7065 /*-----------------------------------------------------------------*/
7066 /* continueIfTrue -                                                */
7067 /*-----------------------------------------------------------------*/
7068 static void
7069 continueIfTrue (iCode * ic)
7070 {
7071   if (IC_TRUE (ic))
7072     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7073   ic->generated = 1;
7074 }
7075
7076 /*-----------------------------------------------------------------*/
7077 /* jmpIfTrue -                                                     */
7078 /*-----------------------------------------------------------------*/
7079 static void
7080 jumpIfTrue (iCode * ic)
7081 {
7082   if (!IC_TRUE (ic))
7083     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7084   ic->generated = 1;
7085 }
7086
7087 /*-----------------------------------------------------------------*/
7088 /* jmpTrueOrFalse -                                                */
7089 /*-----------------------------------------------------------------*/
7090 static void
7091 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7092 {
7093   // ugly but optimized by peephole
7094   if (IC_TRUE (ic))
7095     {
7096       symbol *nlbl = newiTempLabel (NULL);
7097       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7098       emitLabel (tlbl);
7099       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7100       emitLabel (nlbl);
7101     }
7102   else
7103     {
7104       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7105       emitLabel (tlbl);
7106     }
7107   ic->generated = 1;
7108 }
7109
7110 // Generate code to perform a bit-wise logic operation
7111 // on two operands in far space (assumed to already have been
7112 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7113 // in far space. This requires pushing the result on the stack
7114 // then popping it into the result.
7115 static void
7116 genFarFarLogicOp(iCode *ic, char *logicOp)
7117 {
7118       int size, resultSize, compSize;
7119       int offset = 0;
7120
7121       TR_AP("#5");
7122       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7123       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7124                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7125
7126       _startLazyDPSEvaluation();
7127       for (size = compSize; (size--); offset++)
7128       {
7129           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7130           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7131           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7132
7133           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7134           emitcode ("push", "acc");
7135       }
7136       _endLazyDPSEvaluation();
7137
7138       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7139       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7140       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7141
7142       resultSize = AOP_SIZE(IC_RESULT(ic));
7143
7144       ADJUST_PUSHED_RESULT(compSize, resultSize);
7145
7146       _startLazyDPSEvaluation();
7147       while (compSize--)
7148       {
7149           emitcode ("pop", "acc");
7150           aopPut (IC_RESULT (ic), "a", compSize);
7151       }
7152       _endLazyDPSEvaluation();
7153       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7154 }
7155
7156
7157 /*-----------------------------------------------------------------*/
7158 /* genAnd  - code for and                                          */
7159 /*-----------------------------------------------------------------*/
7160 static void
7161 genAnd (iCode * ic, iCode * ifx)
7162 {
7163   operand *left, *right, *result;
7164   int size, offset = 0;
7165   unsigned long lit = 0L;
7166   int bytelit = 0;
7167   char buffer[10];
7168   bool pushResult;
7169
7170   D (emitcode (";", "genAnd"));
7171
7172   AOP_OP_3_NOFATAL (ic, pushResult);
7173   AOP_SET_LOCALS (ic);
7174
7175   if (pushResult)
7176   {
7177       genFarFarLogicOp(ic, "anl");
7178       return;
7179   }
7180
7181 #ifdef DEBUG_TYPE
7182   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7183             AOP_TYPE (result),
7184             AOP_TYPE (left), AOP_TYPE (right));
7185   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7186             AOP_SIZE (result),
7187             AOP_SIZE (left), AOP_SIZE (right));
7188 #endif
7189
7190   /* if left is a literal & right is not then exchange them */
7191   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7192 #ifdef LOGIC_OPS_BROKEN
7193     ||  AOP_NEEDSACC (left)
7194 #endif
7195     )
7196     {
7197       operand *tmp = right;
7198       right = left;
7199       left = tmp;
7200     }
7201
7202   /* if result = right then exchange left and right */
7203   if (sameRegs (AOP (result), AOP (right)))
7204     {
7205       operand *tmp = right;
7206       right = left;
7207       left = tmp;
7208     }
7209
7210   /* if right is bit then exchange them */
7211   if (AOP_TYPE (right) == AOP_CRY &&
7212       AOP_TYPE (left) != AOP_CRY)
7213     {
7214       operand *tmp = right;
7215       right = left;
7216       left = tmp;
7217     }
7218   if (AOP_TYPE (right) == AOP_LIT)
7219     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7220
7221   size = AOP_SIZE (result);
7222
7223   // if(bit & yy)
7224   // result = bit & yy;
7225   if (AOP_TYPE (left) == AOP_CRY)
7226     {
7227       // c = bit & literal;
7228       if (AOP_TYPE (right) == AOP_LIT)
7229         {
7230           if (lit & 1)
7231             {
7232               if (size && sameRegs (AOP (result), AOP (left)))
7233                 // no change
7234                 goto release;
7235               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7236             }
7237           else
7238             {
7239               // bit(result) = 0;
7240               if (size && (AOP_TYPE (result) == AOP_CRY))
7241                 {
7242                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7243                   goto release;
7244                 }
7245               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7246                 {
7247                   jumpIfTrue (ifx);
7248                   goto release;
7249                 }
7250               emitcode ("clr", "c");
7251             }
7252         }
7253       else
7254         {
7255           if (AOP_TYPE (right) == AOP_CRY)
7256             {
7257               // c = bit & bit;
7258               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7259               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7260             }
7261           else
7262             {
7263               // c = bit & val;
7264               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7265               // c = lsb
7266               emitcode ("rrc", "a");
7267               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7268             }
7269         }
7270       // bit = c
7271       // val = c
7272       if (size)
7273         outBitC (result);
7274       // if(bit & ...)
7275       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7276         genIfxJump (ifx, "c");
7277       goto release;
7278     }
7279
7280   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7281   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7282   if ((AOP_TYPE (right) == AOP_LIT) &&
7283       (AOP_TYPE (result) == AOP_CRY) &&
7284       (AOP_TYPE (left) != AOP_CRY))
7285     {
7286       int posbit = isLiteralBit (lit);
7287       /* left &  2^n */
7288       if (posbit)
7289         {
7290           posbit--;
7291           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7292           // bit = left & 2^n
7293           if (size)
7294             {
7295               switch (posbit & 0x07)
7296                 {
7297                   case 0: emitcode ("rrc", "a");
7298                           break;
7299                   case 7: emitcode ("rlc", "a");
7300                           break;
7301                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7302                           break;
7303                 }
7304             }
7305           // if(left &  2^n)
7306           else
7307             {
7308               if (ifx)
7309                 {
7310                   SNPRINTF (buffer, sizeof(buffer),
7311                             "acc.%d", posbit & 0x07);
7312                   genIfxJump (ifx, buffer);
7313                 }
7314               else
7315                   {
7316                       emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7317                   }
7318               goto release;
7319             }
7320         }
7321       else
7322         {
7323           symbol *tlbl = newiTempLabel (NULL);
7324           int sizel = AOP_SIZE (left);
7325           if (size)
7326             emitcode ("setb", "c");
7327           while (sizel--)
7328             {
7329               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7330                 {
7331                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7332                   // byte ==  2^n ?
7333                   if ((posbit = isLiteralBit (bytelit)) != 0)
7334                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7335                   else
7336                     {
7337                       if (bytelit != 0x0FFL)
7338                         emitcode ("anl", "a,%s",
7339                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7340                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7341                     }
7342                 }
7343               offset++;
7344             }
7345           // bit = left & literal
7346           if (size)
7347             {
7348               emitcode ("clr", "c");
7349               emitLabel (tlbl);
7350             }
7351           // if(left & literal)
7352           else
7353             {
7354               if (ifx)
7355                 jmpTrueOrFalse (ifx, tlbl);
7356               else
7357                 emitLabel (tlbl);
7358               goto release;
7359             }
7360         }
7361       outBitC (result);
7362       goto release;
7363     }
7364
7365   /* if left is same as result */
7366   if (sameRegs (AOP (result), AOP (left)))
7367     {
7368       for (; size--; offset++)
7369         {
7370           if (AOP_TYPE (right) == AOP_LIT)
7371             {
7372               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7373               if (bytelit == 0x0FF)
7374                 {
7375                   /* dummy read of volatile operand */
7376                   if (isOperandVolatile (left, FALSE))
7377                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7378                   else
7379                     continue;
7380                 }
7381               else if (bytelit == 0)
7382                 {
7383                   aopPut (result, zero, offset);
7384                 }
7385               else if (IS_AOP_PREG (result))
7386                 {
7387                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7388                   emitcode ("anl", "a,%s",
7389                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7390                   aopPut (result, "a", offset);
7391                 }
7392               else
7393                 emitcode ("anl", "%s,%s",
7394                           aopGet (left, offset, FALSE, TRUE, NULL),
7395                           aopGet (right, offset, FALSE, FALSE, NULL));
7396             }
7397           else
7398             {
7399               if (AOP_TYPE (left) == AOP_ACC)
7400                 emitcode ("anl", "a,%s",
7401                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7402               else
7403                 {
7404                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7405                   if (IS_AOP_PREG (result))
7406                     {
7407                       emitcode ("anl", "a,%s",
7408                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7409                       aopPut (result, "a", offset);
7410                     }
7411                   else
7412                     emitcode ("anl", "%s,a",
7413                               aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7414                 }
7415             }
7416         }
7417     }
7418   else
7419     {
7420       // left & result in different registers
7421       if (AOP_TYPE (result) == AOP_CRY)
7422         {
7423           // result = bit
7424           // if(size), result in bit
7425           // if(!size && ifx), conditional oper: if(left & right)
7426           symbol *tlbl = newiTempLabel (NULL);
7427           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7428           if (size)
7429             emitcode ("setb", "c");
7430           while (sizer--)
7431             {
7432               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7433                 emitcode ("anl", "a,%s",
7434                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7435               } else {
7436                 if (AOP_TYPE(left)==AOP_ACC)
7437                 {
7438                   bool pushedB = pushB ();
7439                   emitcode("mov", "b,a");
7440                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7441                   emitcode("anl", "a,b");
7442                   popB (pushedB);
7443                 }
7444                 else
7445                 {
7446                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7447                   emitcode ("anl", "a,%s",
7448                             aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7449                 }
7450               }
7451               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7452               offset++;
7453             }
7454           if (size)
7455             {
7456               CLRC;
7457               emitLabel (tlbl);
7458               outBitC (result);
7459             }
7460           else if (ifx)
7461             jmpTrueOrFalse (ifx, tlbl);
7462           else
7463             emitLabel (tlbl);
7464         }
7465       else
7466         {
7467           for (; (size--); offset++)
7468             {
7469               // normal case
7470               // result = left & right
7471               if (AOP_TYPE (right) == AOP_LIT)
7472                 {
7473                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7474                   if (bytelit == 0x0FF)
7475                     {
7476                       aopPut (result,
7477                               aopGet (left, offset, FALSE, FALSE, NULL),
7478                               offset);
7479                       continue;
7480                     }
7481                   else if (bytelit == 0)
7482                     {
7483                       /* dummy read of volatile operand */
7484                       if (isOperandVolatile (left, FALSE))
7485                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7486                       aopPut (result, zero, offset);
7487                       continue;
7488                     }
7489                   D (emitcode (";", "better literal AND."));
7490                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7491                   emitcode ("anl", "a, %s", aopGet (right, offset,
7492                                                     FALSE, FALSE, DP2_RESULT_REG));
7493
7494                 }
7495               else
7496                 {
7497                   // faster than result <- left, anl result,right
7498                   // and better if result is SFR
7499                   if (AOP_TYPE (left) == AOP_ACC)
7500                     {
7501                       emitcode ("anl", "a,%s",
7502                                 aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7503                     }
7504                   else
7505                     {
7506                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
7507                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7508                       {
7509                           emitcode("mov", "b,a");
7510                           rOp = "b";
7511                       }
7512
7513                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7514                       emitcode ("anl", "a,%s", rOp);
7515                     }
7516                 }
7517               aopPut (result, "a", offset);
7518             }
7519         }
7520     }
7521
7522 release:
7523   freeAsmop (result, NULL, ic, TRUE);
7524   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7525   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7526 }
7527
7528 /*-----------------------------------------------------------------*/
7529 /* genOr  - code for or                                            */
7530 /*-----------------------------------------------------------------*/
7531 static void
7532 genOr (iCode * ic, iCode * ifx)
7533 {
7534   operand *left, *right, *result;
7535   int size, offset = 0;
7536   unsigned long lit = 0L;
7537   int bytelit = 0;
7538   bool     pushResult;
7539
7540   D (emitcode (";", "genOr"));
7541
7542   AOP_OP_3_NOFATAL (ic, pushResult);
7543   AOP_SET_LOCALS (ic);
7544
7545   if (pushResult)
7546   {
7547       genFarFarLogicOp(ic, "orl");
7548       return;
7549   }
7550
7551
7552 #ifdef DEBUG_TYPE
7553   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7554             AOP_TYPE (result),
7555             AOP_TYPE (left), AOP_TYPE (right));
7556   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7557             AOP_SIZE (result),
7558             AOP_SIZE (left), AOP_SIZE (right));
7559 #endif
7560
7561   /* if left is a literal & right is not then exchange them */
7562   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7563 #ifdef LOGIC_OPS_BROKEN
7564    || AOP_NEEDSACC (left) // I think this is a net loss now.
7565 #endif
7566       )
7567     {
7568       operand *tmp = right;
7569       right = left;
7570       left = tmp;
7571     }
7572
7573   /* if result = right then exchange them */
7574   if (sameRegs (AOP (result), AOP (right)))
7575     {
7576       operand *tmp = right;
7577       right = left;
7578       left = tmp;
7579     }
7580
7581   /* if right is bit then exchange them */
7582   if (AOP_TYPE (right) == AOP_CRY &&
7583       AOP_TYPE (left) != AOP_CRY)
7584     {
7585       operand *tmp = right;
7586       right = left;
7587       left = tmp;
7588     }
7589   if (AOP_TYPE (right) == AOP_LIT)
7590     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7591
7592   size = AOP_SIZE (result);
7593
7594   // if(bit | yy)
7595   // xx = bit | yy;
7596   if (AOP_TYPE (left) == AOP_CRY)
7597     {
7598       if (AOP_TYPE (right) == AOP_LIT)
7599         {
7600           // c = bit | literal;
7601           if (lit)
7602             {
7603               // lit != 0 => result = 1
7604               if (AOP_TYPE (result) == AOP_CRY)
7605                 {
7606                   if (size)
7607                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7608                   else if (ifx)
7609                     continueIfTrue (ifx);
7610                   goto release;
7611                 }
7612               emitcode ("setb", "c");
7613             }
7614           else
7615             {
7616               // lit == 0 => result = left
7617               if (size && sameRegs (AOP (result), AOP (left)))
7618                 goto release;
7619               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7620             }
7621         }
7622       else
7623         {
7624           if (AOP_TYPE (right) == AOP_CRY)
7625             {
7626               // c = bit | bit;
7627               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7628               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7629             }
7630           else
7631             {
7632               // c = bit | val;
7633               symbol *tlbl = newiTempLabel (NULL);
7634               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7635                 emitcode ("setb", "c");
7636               emitcode ("jb", "%s,!tlabel",
7637                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7638               toBoolean (right);
7639               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7640               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7641                 {
7642                   jmpTrueOrFalse (ifx, tlbl);
7643                   goto release;
7644                 }
7645               else
7646                 {
7647                   CLRC;
7648                   emitLabel (tlbl);
7649                 }
7650             }
7651         }
7652       // bit = c
7653       // val = c
7654       if (size)
7655         outBitC (result);
7656       // if(bit | ...)
7657       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7658            genIfxJump (ifx, "c");
7659       goto release;
7660     }
7661
7662   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7663   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7664   if ((AOP_TYPE (right) == AOP_LIT) &&
7665       (AOP_TYPE (result) == AOP_CRY) &&
7666       (AOP_TYPE (left) != AOP_CRY))
7667     {
7668       if (lit)
7669         {
7670           // result = 1
7671           if (size)
7672             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7673           else
7674             continueIfTrue (ifx);
7675           goto release;
7676         }
7677       else
7678         {
7679           // lit = 0, result = boolean(left)
7680           if (size)
7681             emitcode ("setb", "c");
7682           toBoolean (right);
7683           if (size)
7684             {
7685               symbol *tlbl = newiTempLabel (NULL);
7686               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7687               CLRC;
7688               emitLabel (tlbl);
7689             }
7690           else
7691             {
7692               genIfxJump (ifx, "a");
7693               goto release;
7694             }
7695         }
7696       outBitC (result);
7697       goto release;
7698     }
7699
7700   /* if left is same as result */
7701   if (sameRegs (AOP (result), AOP (left)))
7702     {
7703       for (; size--; offset++)
7704         {
7705           if (AOP_TYPE (right) == AOP_LIT)
7706             {
7707               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7708               if (bytelit == 0)
7709                 {
7710                   /* dummy read of volatile operand */
7711                   if (isOperandVolatile (left, FALSE))
7712                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7713                   else
7714                     continue;
7715                 }
7716               else if (bytelit == 0x0FF)
7717                 {
7718                   aopPut (result, "#0xFF", offset);
7719                 }
7720               else if (IS_AOP_PREG (left))
7721                 {
7722                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7723                   emitcode ("orl", "a,%s",
7724                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7725                   aopPut (result, "a", offset);
7726                 }
7727               else
7728                 {
7729                   emitcode ("orl", "%s,%s",
7730                             aopGet (left, offset, FALSE, TRUE, NULL),
7731                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7732                 }
7733             }
7734           else
7735             {
7736               if (AOP_TYPE (left) == AOP_ACC)
7737                 {
7738                   emitcode ("orl", "a,%s",
7739                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7740                 }
7741               else
7742                 {
7743                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7744                   if (IS_AOP_PREG (left))
7745                     {
7746                       emitcode ("orl", "a,%s",
7747                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7748                       aopPut (result, "a", offset);
7749                     }
7750                   else
7751                     {
7752                       emitcode ("orl", "%s,a",
7753                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7754                     }
7755                 }
7756             }
7757         }
7758     }
7759   else
7760     {
7761       // left & result in different registers
7762       if (AOP_TYPE (result) == AOP_CRY)
7763         {
7764           // result = bit
7765           // if(size), result in bit
7766           // if(!size && ifx), conditional oper: if(left | right)
7767           symbol *tlbl = newiTempLabel (NULL);
7768           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7769           if (size)
7770             emitcode ("setb", "c");
7771           while (sizer--)
7772             {
7773               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7774                 emitcode ("orl", "a,%s",
7775                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7776               } else {
7777                 MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7778                 emitcode ("orl", "a,%s",
7779                           aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7780               }
7781               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7782               offset++;
7783             }
7784           if (size)
7785             {
7786               CLRC;
7787               emitLabel (tlbl);
7788               outBitC (result);
7789             }
7790           else if (ifx)
7791             jmpTrueOrFalse (ifx, tlbl);
7792           else
7793             emitLabel (tlbl);
7794         }
7795       else
7796         {
7797             _startLazyDPSEvaluation();
7798           for (; (size--); offset++)
7799             {
7800               // normal case
7801               // result = left | right
7802               if (AOP_TYPE (right) == AOP_LIT)
7803                 {
7804                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7805                   if (bytelit == 0)
7806                     {
7807                       aopPut (result,
7808                               aopGet (left, offset, FALSE, FALSE, NULL),
7809                               offset);
7810                       continue;
7811                     }
7812                   else if (bytelit == 0x0FF)
7813                     {
7814                       /* dummy read of volatile operand */
7815                       if (isOperandVolatile (left, FALSE))
7816                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7817                       aopPut (result, "#0xFF", offset);
7818                       continue;
7819                     }
7820                   D (emitcode (";", "better literal OR."));
7821                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7822                   emitcode ("orl", "a, %s",
7823                             aopGet (right, offset,
7824                                     FALSE, FALSE, DP2_RESULT_REG));
7825
7826                 }
7827               else
7828                 {
7829                   // faster than result <- left, anl result,right
7830                   // and better if result is SFR
7831                   if (AOP_TYPE (left) == AOP_ACC)
7832                     {
7833                       emitcode ("orl", "a,%s",
7834                                 aopGet (right, offset,
7835                                         FALSE, FALSE, DP2_RESULT_REG));
7836                     }
7837                   else
7838                     {
7839                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
7840
7841                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7842                       {
7843                           emitcode("mov", "b,a");
7844                           rOp = "b";
7845                       }
7846
7847                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7848                       emitcode ("orl", "a,%s", rOp);
7849                     }
7850                 }
7851               aopPut (result, "a", offset);
7852             }
7853             _endLazyDPSEvaluation();
7854         }
7855     }
7856
7857 release:
7858   freeAsmop (result, NULL, ic, TRUE);
7859   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7860   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7861 }
7862
7863 /*-----------------------------------------------------------------*/
7864 /* genXor - code for xclusive or                                   */
7865 /*-----------------------------------------------------------------*/
7866 static void
7867 genXor (iCode * ic, iCode * ifx)
7868 {
7869   operand *left, *right, *result;
7870   int size, offset = 0;
7871   unsigned long lit = 0L;
7872   int bytelit = 0;
7873   bool pushResult;
7874
7875   D (emitcode (";", "genXor"));
7876
7877   AOP_OP_3_NOFATAL (ic, pushResult);
7878   AOP_SET_LOCALS (ic);
7879
7880   if (pushResult)
7881   {
7882       genFarFarLogicOp(ic, "xrl");
7883       return;
7884   }
7885
7886 #ifdef DEBUG_TYPE
7887   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7888             AOP_TYPE (result),
7889             AOP_TYPE (left), AOP_TYPE (right));
7890   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7891             AOP_SIZE (result),
7892             AOP_SIZE (left), AOP_SIZE (right));
7893 #endif
7894
7895   /* if left is a literal & right is not ||
7896      if left needs acc & right does not */
7897   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7898 #ifdef LOGIC_OPS_BROKEN
7899       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7900 #endif
7901      )
7902     {
7903       operand *tmp = right;
7904       right = left;
7905       left = tmp;
7906     }
7907
7908   /* if result = right then exchange them */
7909   if (sameRegs (AOP (result), AOP (right)))
7910     {
7911       operand *tmp = right;
7912       right = left;
7913       left = tmp;
7914     }
7915
7916   /* if right is bit then exchange them */
7917   if (AOP_TYPE (right) == AOP_CRY &&
7918       AOP_TYPE (left) != AOP_CRY)
7919     {
7920       operand *tmp = right;
7921       right = left;
7922       left = tmp;
7923     }
7924   if (AOP_TYPE (right) == AOP_LIT)
7925     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7926
7927   size = AOP_SIZE (result);
7928
7929   // if(bit ^ yy)
7930   // xx = bit ^ yy;
7931   if (AOP_TYPE (left) == AOP_CRY)
7932     {
7933       if (AOP_TYPE (right) == AOP_LIT)
7934         {
7935           // c = bit & literal;
7936           if (lit >> 1)
7937             {
7938               // lit>>1  != 0 => result = 1
7939               if (AOP_TYPE (result) == AOP_CRY)
7940                 {
7941                   if (size)
7942                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7943                   else if (ifx)
7944                     continueIfTrue (ifx);
7945                   goto release;
7946                 }
7947               emitcode ("setb", "c");
7948             }
7949           else
7950             {
7951               // lit == (0 or 1)
7952               if (lit == 0)
7953                 {
7954                   // lit == 0, result = left
7955                   if (size && sameRegs (AOP (result), AOP (left)))
7956                     goto release;
7957                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7958                 }
7959               else
7960                 {
7961                   // lit == 1, result = not(left)
7962                   if (size && sameRegs (AOP (result), AOP (left)))
7963                     {
7964                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7965                       goto release;
7966                     }
7967                   else
7968                     {
7969                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7970                       emitcode ("cpl", "c");
7971                     }
7972                 }
7973             }
7974
7975         }
7976       else
7977         {
7978           // right != literal
7979           symbol *tlbl = newiTempLabel (NULL);
7980           if (AOP_TYPE (right) == AOP_CRY)
7981             {
7982               // c = bit ^ bit;
7983               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7984             }
7985           else
7986             {
7987               int sizer = AOP_SIZE (right);
7988               // c = bit ^ val
7989               // if val>>1 != 0, result = 1
7990               emitcode ("setb", "c");
7991               while (sizer)
7992                 {
7993                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
7994                   if (sizer == 1)
7995                     // test the msb of the lsb
7996                     emitcode ("anl", "a,#!constbyte",0xfe);
7997                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
7998                   sizer--;
7999                 }
8000               // val = (0,1)
8001               emitcode ("rrc", "a");
8002             }
8003           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8004           emitcode ("cpl", "c");
8005           emitLabel (tlbl);
8006         }
8007       // bit = c
8008       // val = c
8009       if (size)
8010         outBitC (result);
8011       // if(bit | ...)
8012       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8013         genIfxJump (ifx, "c");
8014       goto release;
8015     }
8016
8017   /* if left is same as result */
8018   if (sameRegs (AOP (result), AOP (left)))
8019     {
8020       for (; size--; offset++)
8021         {
8022           if (AOP_TYPE (right) == AOP_LIT)
8023             {
8024               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8025               if (bytelit == 0)
8026                 {
8027                   /* dummy read of volatile operand */
8028                   if (isOperandVolatile (left, FALSE))
8029                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8030                   else
8031                     continue;
8032                 }
8033               else if (IS_AOP_PREG (left))
8034                 {
8035                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8036                   emitcode ("xrl", "a,%s",
8037                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8038                   aopPut (result, "a", offset);
8039                 }
8040               else
8041                 {
8042                   emitcode ("xrl", "%s,%s",
8043                             aopGet (left, offset, FALSE, TRUE, NULL),
8044                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8045                 }
8046             }
8047           else
8048             {
8049               if (AOP_TYPE (left) == AOP_ACC)
8050                 emitcode ("xrl", "a,%s",
8051                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8052               else
8053                 {
8054                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8055                   if (IS_AOP_PREG (left))
8056                     {
8057                       emitcode ("xrl", "a,%s",
8058                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8059                       aopPut (result, "a", offset);
8060                     }
8061                   else
8062                     emitcode ("xrl", "%s,a",
8063                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8064                 }
8065             }
8066         }
8067     }
8068   else
8069     {
8070       // left & result in different registers
8071       if (AOP_TYPE (result) == AOP_CRY)
8072         {
8073           // result = bit
8074           // if(size), result in bit
8075           // if(!size && ifx), conditional oper: if(left ^ right)
8076           symbol *tlbl = newiTempLabel (NULL);
8077           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8078
8079           if (size)
8080             emitcode ("setb", "c");
8081           while (sizer--)
8082             {
8083               if ((AOP_TYPE (right) == AOP_LIT) &&
8084                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8085                 {
8086                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8087                 }
8088               else
8089                 {
8090                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
8091                     emitcode ("xrl", "a,%s",
8092                               aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8093                   } else {
8094                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8095                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8096                       {
8097                           emitcode("mov", "b,a");
8098                           rOp = "b";
8099                       }
8100
8101                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8102                       emitcode ("xrl", "a,%s", rOp);
8103                   }
8104                 }
8105               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8106               offset++;
8107             }
8108           if (size)
8109             {
8110               CLRC;
8111               emitLabel (tlbl);
8112               outBitC (result);
8113             }
8114           else if (ifx)
8115             jmpTrueOrFalse (ifx, tlbl);
8116         }
8117       else
8118         {
8119         for (; (size--); offset++)
8120           {
8121             // normal case
8122             // result = left ^ right
8123             if (AOP_TYPE (right) == AOP_LIT)
8124               {
8125                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8126                 if (bytelit == 0)
8127                   {
8128                     aopPut (result,
8129                             aopGet (left, offset, FALSE, FALSE, NULL),
8130                             offset);
8131                     continue;
8132                   }
8133                 D (emitcode (";", "better literal XOR."));
8134                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8135                 emitcode ("xrl", "a, %s",
8136                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8137               }
8138             else
8139               {
8140                 // faster than result <- left, anl result,right
8141                 // and better if result is SFR
8142                 if (AOP_TYPE (left) == AOP_ACC)
8143                   {
8144                     emitcode ("xrl", "a,%s",
8145                               aopGet (right, offset,
8146                                       FALSE, FALSE, DP2_RESULT_REG));
8147                   }
8148                 else
8149                   {
8150                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8151                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8152                       {
8153                           emitcode("mov", "b,a");
8154                           rOp = "b";
8155                       }
8156
8157                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8158                       emitcode ("xrl", "a,%s", rOp);
8159                   }
8160               }
8161             aopPut (result, "a", offset);
8162           }
8163         }
8164     }
8165
8166 release:
8167   freeAsmop (result, NULL, ic, TRUE);
8168   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8169   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8170 }
8171
8172 /*-----------------------------------------------------------------*/
8173 /* genInline - write the inline code out                           */
8174 /*-----------------------------------------------------------------*/
8175 static void
8176 genInline (iCode * ic)
8177 {
8178   char *buffer, *bp, *bp1;
8179
8180   D (emitcode (";", "genInline"));
8181
8182   _G.inLine += (!options.asmpeep);
8183
8184   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
8185
8186   /* emit each line as a code */
8187   while (*bp)
8188     {
8189       if (*bp == '\n')
8190         {
8191           *bp++ = '\0';
8192           emitcode (bp1, "");
8193           bp1 = bp;
8194         }
8195       else
8196         {
8197           /* Add \n for labels, not dirs such as c:\mydir */
8198           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
8199             {
8200               bp++;
8201               *bp = '\0';
8202               bp++;
8203               emitcode (bp1, "");
8204               bp1 = bp;
8205             }
8206           else
8207             bp++;
8208         }
8209     }
8210   if (bp1 != bp)
8211     emitcode (bp1, "");
8212   /*     emitcode("",buffer); */
8213   _G.inLine -= (!options.asmpeep);
8214 }
8215
8216 /*-----------------------------------------------------------------*/
8217 /* genRRC - rotate right with carry                                */
8218 /*-----------------------------------------------------------------*/
8219 static void
8220 genRRC (iCode * ic)
8221 {
8222   operand *left, *result;
8223   int     size, offset;
8224   char *l;
8225
8226   D (emitcode (";", "genRRC"));
8227
8228   /* rotate right with carry */
8229   left = IC_LEFT (ic);
8230   result = IC_RESULT (ic);
8231   aopOp (left, ic, FALSE, FALSE);
8232   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8233
8234   /* move it to the result */
8235   size = AOP_SIZE (result);
8236   offset = size - 1;
8237   CLRC;
8238
8239   _startLazyDPSEvaluation ();
8240   while (size--)
8241     {
8242       l = aopGet (left, offset, FALSE, FALSE, NULL);
8243       MOVA (l);
8244       emitcode ("rrc", "a");
8245       if (AOP_SIZE (result) > 1)
8246         aopPut (result, "a", offset--);
8247     }
8248   _endLazyDPSEvaluation ();
8249
8250   /* now we need to put the carry into the
8251      highest order byte of the result */
8252   if (AOP_SIZE (result) > 1)
8253     {
8254       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8255       MOVA (l);
8256     }
8257   emitcode ("mov", "acc.7,c");
8258   aopPut (result, "a", AOP_SIZE (result) - 1);
8259   freeAsmop (result, NULL, ic, TRUE);
8260   freeAsmop (left, NULL, ic, TRUE);
8261 }
8262
8263 /*-----------------------------------------------------------------*/
8264 /* genRLC - generate code for rotate left with carry               */
8265 /*-----------------------------------------------------------------*/
8266 static void
8267 genRLC (iCode * ic)
8268 {
8269   operand *left, *result;
8270   int size, offset;
8271   char *l;
8272
8273   D (emitcode (";", "genRLC"));
8274
8275   /* rotate right with carry */
8276   left = IC_LEFT (ic);
8277   result = IC_RESULT (ic);
8278   aopOp (left, ic, FALSE, FALSE);
8279   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8280
8281   /* move it to the result */
8282   size = AOP_SIZE (result);
8283   offset = 0;
8284   if (size--)
8285     {
8286       l = aopGet (left, offset, FALSE, FALSE, NULL);
8287       MOVA (l);
8288       emitcode ("add", "a,acc");
8289       if (AOP_SIZE (result) > 1)
8290         {
8291           aopPut (result, "a", offset++);
8292         }
8293
8294       _startLazyDPSEvaluation ();
8295       while (size--)
8296         {
8297           l = aopGet (left, offset, FALSE, FALSE, NULL);
8298           MOVA (l);
8299           emitcode ("rlc", "a");
8300           if (AOP_SIZE (result) > 1)
8301             aopPut (result, "a", offset++);
8302         }
8303       _endLazyDPSEvaluation ();
8304     }
8305   /* now we need to put the carry into the
8306      highest order byte of the result */
8307   if (AOP_SIZE (result) > 1)
8308     {
8309       l = aopGet (result, 0, FALSE, FALSE, NULL);
8310       MOVA (l);
8311     }
8312   emitcode ("mov", "acc.0,c");
8313   aopPut (result, "a", 0);
8314   freeAsmop (result, NULL, ic, TRUE);
8315   freeAsmop (left, NULL, ic, TRUE);
8316 }
8317
8318 /*-----------------------------------------------------------------*/
8319 /* genGetHbit - generates code get highest order bit               */
8320 /*-----------------------------------------------------------------*/
8321 static void
8322 genGetHbit (iCode * ic)
8323 {
8324   operand *left, *result;
8325
8326   D (emitcode (";", "genGetHbit"));
8327
8328   left = IC_LEFT (ic);
8329   result = IC_RESULT (ic);
8330   aopOp (left, ic, FALSE, FALSE);
8331   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8332
8333   /* get the highest order byte into a */
8334   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8335   if (AOP_TYPE (result) == AOP_CRY)
8336     {
8337       emitcode ("rlc", "a");
8338       outBitC (result);
8339     }
8340   else
8341     {
8342       emitcode ("rl", "a");
8343       emitcode ("anl", "a,#1");
8344       outAcc (result);
8345     }
8346
8347
8348   freeAsmop (result, NULL, ic, TRUE);
8349   freeAsmop (left, NULL, ic, TRUE);
8350 }
8351
8352 /*-----------------------------------------------------------------*/
8353 /* genSwap - generates code to swap nibbles or bytes               */
8354 /*-----------------------------------------------------------------*/
8355 static void
8356 genSwap (iCode * ic)
8357 {
8358   operand *left, *result;
8359
8360   D(emitcode (";     genSwap",""));
8361
8362   left = IC_LEFT (ic);
8363   result = IC_RESULT (ic);
8364   aopOp (left, ic, FALSE, FALSE);
8365   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8366
8367   _startLazyDPSEvaluation ();
8368   switch (AOP_SIZE (left))
8369     {
8370     case 1: /* swap nibbles in byte */
8371       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8372       emitcode ("swap", "a");
8373       aopPut (result, "a", 0);
8374       break;
8375     case 2: /* swap bytes in word */
8376       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8377         {
8378           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8379           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8380           aopPut (result, "a", 1);
8381         }
8382       else if (operandsEqu (left, result))
8383         {
8384           char * reg = "a";
8385           bool pushedB = FALSE, leftInB = FALSE;
8386
8387           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8388           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8389             {
8390               pushedB = pushB ();
8391               emitcode ("mov", "b,a");
8392               reg = "b";
8393               leftInB = TRUE;
8394             }
8395           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8396           aopPut (result, reg, 1);
8397
8398           if (leftInB)
8399             popB (pushedB);
8400         }
8401       else
8402         {
8403           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8404           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8405         }
8406       break;
8407     default:
8408       wassertl(FALSE, "unsupported SWAP operand size");
8409     }
8410   _endLazyDPSEvaluation ();
8411
8412   freeAsmop (result, NULL, ic, TRUE);
8413   freeAsmop (left, NULL, ic, TRUE);
8414 }
8415
8416 /*-----------------------------------------------------------------*/
8417 /* AccRol - rotate left accumulator by known count                 */
8418 /*-----------------------------------------------------------------*/
8419 static void
8420 AccRol (int shCount)
8421 {
8422   shCount &= 0x0007;            // shCount : 0..7
8423
8424   switch (shCount)
8425     {
8426     case 0:
8427       break;
8428     case 1:
8429       emitcode ("rl", "a");
8430       break;
8431     case 2:
8432       emitcode ("rl", "a");
8433       emitcode ("rl", "a");
8434       break;
8435     case 3:
8436       emitcode ("swap", "a");
8437       emitcode ("rr", "a");
8438       break;
8439     case 4:
8440       emitcode ("swap", "a");
8441       break;
8442     case 5:
8443       emitcode ("swap", "a");
8444       emitcode ("rl", "a");
8445       break;
8446     case 6:
8447       emitcode ("rr", "a");
8448       emitcode ("rr", "a");
8449       break;
8450     case 7:
8451       emitcode ("rr", "a");
8452       break;
8453     }
8454 }
8455
8456 /*-----------------------------------------------------------------*/
8457 /* AccLsh - left shift accumulator by known count                  */
8458 /*-----------------------------------------------------------------*/
8459 static void
8460 AccLsh (int shCount)
8461 {
8462   if (shCount != 0)
8463     {
8464       if (shCount == 1)
8465         emitcode ("add", "a,acc");
8466       else if (shCount == 2)
8467         {
8468           emitcode ("add", "a,acc");
8469           emitcode ("add", "a,acc");
8470         }
8471       else
8472         {
8473           /* rotate left accumulator */
8474           AccRol (shCount);
8475           /* and kill the lower order bits */
8476           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8477         }
8478     }
8479 }
8480
8481 /*-----------------------------------------------------------------*/
8482 /* AccRsh - right shift accumulator by known count                 */
8483 /*-----------------------------------------------------------------*/
8484 static void
8485 AccRsh (int shCount)
8486 {
8487   if (shCount != 0)
8488     {
8489       if (shCount == 1)
8490         {
8491           CLRC;
8492           emitcode ("rrc", "a");
8493         }
8494       else
8495         {
8496           /* rotate right accumulator */
8497           AccRol (8 - shCount);
8498           /* and kill the higher order bits */
8499           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8500         }
8501     }
8502 }
8503
8504 #ifdef BETTER_LITERAL_SHIFT
8505 /*-----------------------------------------------------------------*/
8506 /* AccSRsh - signed right shift accumulator by known count                 */
8507 /*-----------------------------------------------------------------*/
8508 static void
8509 AccSRsh (int shCount)
8510 {
8511   symbol *tlbl;
8512   if (shCount != 0)
8513     {
8514       if (shCount == 1)
8515         {
8516           emitcode ("mov", "c,acc.7");
8517           emitcode ("rrc", "a");
8518         }
8519       else if (shCount == 2)
8520         {
8521           emitcode ("mov", "c,acc.7");
8522           emitcode ("rrc", "a");
8523           emitcode ("mov", "c,acc.7");
8524           emitcode ("rrc", "a");
8525         }
8526       else
8527         {
8528           tlbl = newiTempLabel (NULL);
8529           /* rotate right accumulator */
8530           AccRol (8 - shCount);
8531           /* and kill the higher order bits */
8532           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8533           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8534           emitcode ("orl", "a,#!constbyte",
8535                     (unsigned char) ~SRMask[shCount]);
8536           emitLabel (tlbl);
8537         }
8538     }
8539 }
8540 #endif
8541
8542 #ifdef BETTER_LITERAL_SHIFT
8543 /*-----------------------------------------------------------------*/
8544 /* shiftR1Left2Result - shift right one byte from left to result   */
8545 /*-----------------------------------------------------------------*/
8546 static void
8547 shiftR1Left2Result (operand * left, int offl,
8548                     operand * result, int offr,
8549                     int shCount, int sign)
8550 {
8551   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8552   /* shift right accumulator */
8553   if (sign)
8554     AccSRsh (shCount);
8555   else
8556     AccRsh (shCount);
8557   aopPut (result, "a", offr);
8558 }
8559 #endif
8560
8561 #ifdef BETTER_LITERAL_SHIFT
8562 /*-----------------------------------------------------------------*/
8563 /* shiftL1Left2Result - shift left one byte from left to result    */
8564 /*-----------------------------------------------------------------*/
8565 static void
8566 shiftL1Left2Result (operand * left, int offl,
8567                     operand * result, int offr, int shCount)
8568 {
8569   char *l;
8570   l = aopGet (left, offl, FALSE, FALSE, NULL);
8571   MOVA (l);
8572   /* shift left accumulator */
8573   AccLsh (shCount);
8574   aopPut (result, "a", offr);
8575 }
8576 #endif
8577
8578 #ifdef BETTER_LITERAL_SHIFT
8579 /*-----------------------------------------------------------------*/
8580 /* movLeft2Result - move byte from left to result                  */
8581 /*-----------------------------------------------------------------*/
8582 static void
8583 movLeft2Result (operand * left, int offl,
8584                 operand * result, int offr, int sign)
8585 {
8586   char *l;
8587   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8588   {
8589       l = aopGet (left, offl, FALSE, FALSE, NULL);
8590
8591       if (*l == '@' && (IS_AOP_PREG (result)))
8592       {
8593           emitcode ("mov", "a,%s", l);
8594           aopPut (result, "a", offr);
8595       }
8596       else
8597       {
8598           if (!sign)
8599           {
8600             aopPut (result, l, offr);
8601           }
8602           else
8603             {
8604               /* MSB sign in acc.7 ! */
8605               if (getDataSize (left) == offl + 1)
8606                 {
8607                   MOVA (l);
8608                   aopPut (result, "a", offr);
8609                 }
8610             }
8611       }
8612   }
8613 }
8614 #endif
8615
8616 #ifdef BETTER_LITERAL_SHIFT
8617 /*-----------------------------------------------------------------*/
8618 /* AccAXRrl1 - right rotate a:x by 1                               */
8619 /*-----------------------------------------------------------------*/
8620 static void
8621 AccAXRrl1 (char *x)
8622 {
8623   emitcode ("mov", "c,acc.0");
8624   emitcode ("xch", "a,%s", x);
8625   emitcode ("rrc", "a");
8626   emitcode ("xch", "a,%s", x);
8627   emitcode ("rrc", "a");
8628 }
8629 #endif
8630
8631 #ifdef BETTER_LITERAL_SHIFT
8632 //REMOVE ME!!!
8633 /*-----------------------------------------------------------------*/
8634 /* AccAXLrl1 - left rotate a:x by 1                                */
8635 /*-----------------------------------------------------------------*/
8636 static void
8637 AccAXLrl1 (char *x)
8638 {
8639   emitcode ("mov", "c,acc.7");
8640   emitcode ("xch", "a,%s", x);
8641   emitcode ("rlc", "a");
8642   emitcode ("xch", "a,%s", x);
8643   emitcode ("rlc", "a");
8644 }
8645 #endif
8646
8647 #ifdef BETTER_LITERAL_SHIFT
8648 /*-----------------------------------------------------------------*/
8649 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8650 /*-----------------------------------------------------------------*/
8651 static void
8652 AccAXRsh1 (char *x)
8653 {
8654   emitcode ("rrc", "a");
8655   emitcode ("xch", "a,%s", x);
8656   emitcode ("rrc", "a");
8657   emitcode ("xch", "a,%s", x);
8658 }
8659 #endif
8660
8661 #ifdef BETTER_LITERAL_SHIFT
8662 /*-----------------------------------------------------------------*/
8663 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8664 /*-----------------------------------------------------------------*/
8665 static void
8666 AccAXLsh1 (char *x)
8667 {
8668   emitcode ("xch", "a,%s", x);
8669   emitcode ("add", "a,acc");
8670   emitcode ("xch", "a,%s", x);
8671   emitcode ("rlc", "a");
8672 }
8673 #endif
8674
8675 #ifdef BETTER_LITERAL_SHIFT
8676 /*-----------------------------------------------------------------*/
8677 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8678 /*-----------------------------------------------------------------*/
8679 static void
8680 AccAXLsh (char *x, int shCount)
8681 {
8682   switch (shCount)
8683     {
8684     case 0:
8685       break;
8686     case 1:
8687       AccAXLsh1 (x);
8688       break;
8689     case 2:
8690       AccAXLsh1 (x);
8691       AccAXLsh1 (x);
8692       break;
8693     case 3:
8694     case 4:
8695     case 5:                             // AAAAABBB:CCCCCDDD
8696
8697       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8698
8699       emitcode ("anl", "a,#!constbyte",
8700                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8701
8702       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8703
8704       AccRol (shCount);                 // DDDCCCCC:BBB00000
8705
8706       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8707
8708       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8709
8710       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8711
8712       emitcode ("anl", "a,#!constbyte",
8713                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8714
8715       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8716
8717       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8718
8719       break;
8720     case 6:                             // AAAAAABB:CCCCCCDD
8721       emitcode ("anl", "a,#!constbyte",
8722                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8723 #if 1
8724       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8725       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8726       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8727 #else
8728       emitcode ("mov", "c,acc.0");      // c = B
8729       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8730       emitcode("rrc","a");
8731       emitcode("xch","a,%s", x);
8732       emitcode("rrc","a");
8733       emitcode("mov","c,acc.0"); //<< get correct bit
8734       emitcode("xch","a,%s", x);
8735
8736       emitcode("rrc","a");
8737       emitcode("xch","a,%s", x);
8738       emitcode("rrc","a");
8739       emitcode("xch","a,%s", x);
8740 #endif
8741       break;
8742     case 7:                             // a:x <<= 7
8743
8744       emitcode ("anl", "a,#!constbyte",
8745                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8746
8747       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8748
8749       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8750
8751       break;
8752     default:
8753       break;
8754     }
8755 }
8756 #endif
8757
8758 #ifdef BETTER_LITERAL_SHIFT
8759 //REMOVE ME!!!
8760 /*-----------------------------------------------------------------*/
8761 /* AccAXRsh - right shift a:x known count (0..7)                   */
8762 /*-----------------------------------------------------------------*/
8763 static void
8764 AccAXRsh (char *x, int shCount)
8765 {
8766   switch (shCount)
8767     {
8768     case 0:
8769       break;
8770     case 1:
8771       CLRC;
8772       AccAXRsh1 (x);                    // 0->a:x
8773
8774       break;
8775     case 2:
8776       CLRC;
8777       AccAXRsh1 (x);                    // 0->a:x
8778
8779       CLRC;
8780       AccAXRsh1 (x);                    // 0->a:x
8781
8782       break;
8783     case 3:
8784     case 4:
8785     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8786
8787       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8788
8789       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8790
8791       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8792
8793       emitcode ("anl", "a,#!constbyte",
8794                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8795
8796       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8797
8798       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8799
8800       emitcode ("anl", "a,#!constbyte",
8801                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8802
8803       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8804
8805       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8806
8807       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8808
8809       break;
8810     case 6:                             // AABBBBBB:CCDDDDDD
8811
8812       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8813       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8814
8815       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8816
8817       emitcode ("anl", "a,#!constbyte",
8818                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8819
8820       break;
8821     case 7:                             // ABBBBBBB:CDDDDDDD
8822
8823       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8824
8825       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8826
8827       emitcode ("anl", "a,#!constbyte",
8828                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8829
8830       break;
8831     default:
8832       break;
8833     }
8834 }
8835 #endif
8836
8837 #ifdef BETTER_LITERAL_SHIFT
8838 /*-----------------------------------------------------------------*/
8839 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8840 /*-----------------------------------------------------------------*/
8841 static void
8842 AccAXRshS (char *x, int shCount)
8843 {
8844   symbol *tlbl;
8845   switch (shCount)
8846     {
8847     case 0:
8848       break;
8849     case 1:
8850       emitcode ("mov", "c,acc.7");
8851       AccAXRsh1 (x);                    // s->a:x
8852
8853       break;
8854     case 2:
8855       emitcode ("mov", "c,acc.7");
8856       AccAXRsh1 (x);                    // s->a:x
8857
8858       emitcode ("mov", "c,acc.7");
8859       AccAXRsh1 (x);                    // s->a:x
8860
8861       break;
8862     case 3:
8863     case 4:
8864     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8865
8866       tlbl = newiTempLabel (NULL);
8867       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8868
8869       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8870
8871       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8872
8873       emitcode ("anl", "a,#!constbyte",
8874                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8875
8876       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8877
8878       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8879
8880       emitcode ("anl", "a,#!constbyte",
8881                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8882
8883       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8884
8885       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8886
8887       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8888
8889       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8890       emitcode ("orl", "a,#!constbyte",
8891                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8892
8893       emitLabel (tlbl);
8894       break;                            // SSSSAAAA:BBBCCCCC
8895
8896     case 6:                             // AABBBBBB:CCDDDDDD
8897
8898       tlbl = newiTempLabel (NULL);
8899
8900       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
8901       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8902
8903       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8904
8905       emitcode ("anl", "a,#!constbyte",
8906                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8907
8908       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8909       emitcode ("orl", "a,#!constbyte",
8910                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8911
8912       emitLabel (tlbl);
8913       break;
8914     case 7:                             // ABBBBBBB:CDDDDDDD
8915
8916       tlbl = newiTempLabel (NULL);
8917
8918       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8919
8920       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8921
8922       emitcode ("anl", "a,#!constbyte",
8923                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8924
8925       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8926       emitcode ("orl", "a,#!constbyte",
8927                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8928
8929       emitLabel (tlbl);
8930       break;
8931     default:
8932       break;
8933     }
8934 }
8935 #endif
8936
8937 #ifdef BETTER_LITERAL_SHIFT
8938 static void
8939 _loadLeftIntoAx(char    **lsb,
8940                 operand *left,
8941                 operand *result,
8942                 int     offl,
8943                 int     offr)
8944 {
8945   // Get the initial value from left into a pair of registers.
8946   // MSB must be in A, LSB can be any register.
8947   //
8948   // If the result is held in registers, it is an optimization
8949   // if the LSB can be held in the register which will hold the,
8950   // result LSB since this saves us from having to copy it into
8951   // the result following AccAXLsh.
8952   //
8953   // If the result is addressed indirectly, this is not a gain.
8954   if (AOP_NEEDSACC(result))
8955   {
8956        char *leftByte;
8957
8958        _startLazyDPSEvaluation();
8959       if (AOP_TYPE(left) == AOP_DPTR2)
8960        {
8961            // Get MSB in A.
8962            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
8963            // get LSB in DP2_RESULT_REG.
8964            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
8965            assert(!strcmp(leftByte, DP2_RESULT_REG));
8966        }
8967        else
8968        {
8969            // get LSB into DP2_RESULT_REG
8970            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
8971            if (strcmp(leftByte, DP2_RESULT_REG))
8972            {
8973                TR_AP("#7");
8974                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
8975            }
8976            // And MSB in A.
8977            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
8978            assert(strcmp(leftByte, DP2_RESULT_REG));
8979            MOVA (leftByte);
8980        }
8981        _endLazyDPSEvaluation();
8982        *lsb = DP2_RESULT_REG;
8983   }
8984   else
8985   {
8986       if (sameRegs (AOP (result), AOP (left)) &&
8987         ((offl + MSB16) == offr))
8988       {
8989           /* don't crash result[offr] */
8990           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8991           emitcode ("xch", "a,%s",
8992                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
8993       }
8994       else
8995       {
8996           movLeft2Result (left, offl, result, offr, 0);
8997           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
8998       }
8999       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9000       assert(strcmp(*lsb,"a"));
9001   }
9002 }
9003
9004 static void
9005 _storeAxResults(char    *lsb,
9006                 operand *result,
9007                 int     offr)
9008 {
9009   _startLazyDPSEvaluation();
9010   if (AOP_NEEDSACC(result))
9011   {
9012       /* We have to explicitly update the result LSB.
9013        */
9014       emitcode ("xch","a,%s", lsb);
9015       aopPut (result, "a", offr);
9016       emitcode ("mov","a,%s", lsb);
9017   }
9018   if (getDataSize (result) > 1)
9019   {
9020       aopPut (result, "a", offr + MSB16);
9021   }
9022   _endLazyDPSEvaluation();
9023 }
9024
9025 /*-----------------------------------------------------------------*/
9026 /* shiftL2Left2Result - shift left two bytes from left to result   */
9027 /*-----------------------------------------------------------------*/
9028 static void
9029 shiftL2Left2Result (operand * left, int offl,
9030                     operand * result, int offr, int shCount)
9031 {
9032   char *lsb;
9033
9034   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9035
9036   AccAXLsh (lsb, shCount);
9037
9038   _storeAxResults(lsb, result, offr);
9039 }
9040 #endif
9041
9042 #ifdef BETTER_LITERAL_SHIFT
9043 /*-----------------------------------------------------------------*/
9044 /* shiftR2Left2Result - shift right two bytes from left to result  */
9045 /*-----------------------------------------------------------------*/
9046 static void
9047 shiftR2Left2Result (operand * left, int offl,
9048                     operand * result, int offr,
9049                     int shCount, int sign)
9050 {
9051   char *lsb;
9052
9053   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9054
9055   /* a:x >> shCount (x = lsb(result)) */
9056   if (sign)
9057   {
9058      AccAXRshS(lsb, shCount);
9059   }
9060   else
9061   {
9062     AccAXRsh(lsb, shCount);
9063   }
9064
9065   _storeAxResults(lsb, result, offr);
9066 }
9067 #endif
9068
9069 /*-----------------------------------------------------------------*/
9070 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9071 /*-----------------------------------------------------------------*/
9072 static void
9073 shiftLLeftOrResult (operand * left, int offl,
9074                     operand * result, int offr, int shCount)
9075 {
9076   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9077   /* shift left accumulator */
9078   AccLsh (shCount);
9079   /* or with result */
9080   emitcode ("orl", "a,%s",
9081             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9082   /* back to result */
9083   aopPut (result, "a", offr);
9084 }
9085
9086 #if 0
9087 //REMOVE ME!!!
9088 /*-----------------------------------------------------------------*/
9089 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9090 /*-----------------------------------------------------------------*/
9091 static void
9092 shiftRLeftOrResult (operand * left, int offl,
9093                     operand * result, int offr, int shCount)
9094 {
9095   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9096   /* shift right accumulator */
9097   AccRsh (shCount);
9098   /* or with result */
9099   emitcode ("orl", "a,%s",
9100             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9101   /* back to result */
9102   aopPut (result, "a", offr);
9103 }
9104 #endif
9105
9106 #ifdef BETTER_LITERAL_SHIFT
9107 /*-----------------------------------------------------------------*/
9108 /* genlshOne - left shift a one byte quantity by known count       */
9109 /*-----------------------------------------------------------------*/
9110 static void
9111 genlshOne (operand * result, operand * left, int shCount)
9112 {
9113   D (emitcode (";", "genlshOne"));
9114
9115   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9116 }
9117 #endif
9118
9119 #ifdef BETTER_LITERAL_SHIFT
9120 /*-----------------------------------------------------------------*/
9121 /* genlshTwo - left shift two bytes by known amount != 0           */
9122 /*-----------------------------------------------------------------*/
9123 static void
9124 genlshTwo (operand * result, operand * left, int shCount)
9125 {
9126   int size;
9127
9128   D (emitcode (";", "genlshTwo"));
9129
9130   size = getDataSize (result);
9131
9132   /* if shCount >= 8 */
9133   if (shCount >= 8)
9134   {
9135       shCount -= 8;
9136
9137       _startLazyDPSEvaluation();
9138
9139       if (size > 1)
9140         {
9141           if (shCount)
9142           {
9143             _endLazyDPSEvaluation();
9144             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9145             aopPut (result, zero, LSB);
9146           }
9147           else
9148           {
9149             movLeft2Result (left, LSB, result, MSB16, 0);
9150             aopPut (result, zero, LSB);
9151             _endLazyDPSEvaluation();
9152           }
9153         }
9154         else
9155         {
9156           aopPut (result, zero, LSB);
9157           _endLazyDPSEvaluation();
9158         }
9159   }
9160
9161   /*  1 <= shCount <= 7 */
9162   else
9163     {
9164       if (size == 1)
9165         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9166       else
9167         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9168       }
9169 }
9170 #endif
9171
9172 #if 0
9173 //REMOVE ME!!!
9174 /*-----------------------------------------------------------------*/
9175 /* shiftLLong - shift left one long from left to result            */
9176 /* offl = LSB or MSB16                                             */
9177 /*-----------------------------------------------------------------*/
9178 static void
9179 shiftLLong (operand * left, operand * result, int offr)
9180 {
9181   char *l;
9182   int size = AOP_SIZE (result);
9183
9184   if (size >= LSB + offr)
9185     {
9186       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9187       MOVA (l);
9188       emitcode ("add", "a,acc");
9189       if (sameRegs (AOP (left), AOP (result)) &&
9190           size >= MSB16 + offr && offr != LSB)
9191         emitcode ("xch", "a,%s",
9192                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9193       else
9194         aopPut (result, "a", LSB + offr);
9195     }
9196
9197   if (size >= MSB16 + offr)
9198     {
9199       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9200         {
9201           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9202           MOVA (l);
9203         }
9204       emitcode ("rlc", "a");
9205       if (sameRegs (AOP (left), AOP (result)) &&
9206           size >= MSB24 + offr && offr != LSB)
9207         emitcode ("xch", "a,%s",
9208                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9209       else
9210         aopPut (result, "a", MSB16 + offr);
9211     }
9212
9213   if (size >= MSB24 + offr)
9214     {
9215       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9216         {
9217           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9218           MOVA (l);
9219         }
9220       emitcode ("rlc", "a");
9221       if (sameRegs (AOP (left), AOP (result)) &&
9222           size >= MSB32 + offr && offr != LSB)
9223         emitcode ("xch", "a,%s",
9224                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9225       else
9226         aopPut (result, "a", MSB24 + offr);
9227     }
9228
9229   if (size > MSB32 + offr)
9230     {
9231       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9232         {
9233           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9234           MOVA (l);
9235         }
9236       emitcode ("rlc", "a");
9237       aopPut (result, "a", MSB32 + offr);
9238     }
9239   if (offr != LSB)
9240     aopPut (result, zero, LSB);
9241 }
9242 #endif
9243
9244 #if 0
9245 //REMOVE ME!!!
9246 /*-----------------------------------------------------------------*/
9247 /* genlshFour - shift four byte by a known amount != 0             */
9248 /*-----------------------------------------------------------------*/
9249 static void
9250 genlshFour (operand * result, operand * left, int shCount)
9251 {
9252   int size;
9253
9254   D (emitcode (";", "genlshFour"));
9255
9256   size = AOP_SIZE (result);
9257
9258   /* if shifting more that 3 bytes */
9259   if (shCount >= 24)
9260     {
9261       shCount -= 24;
9262       if (shCount)
9263         /* lowest order of left goes to the highest
9264            order of the destination */
9265         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9266       else
9267         movLeft2Result (left, LSB, result, MSB32, 0);
9268       aopPut (result, zero, LSB);
9269       aopPut (result, zero, MSB16);
9270       aopPut (result, zero, MSB24);
9271       return;
9272     }
9273
9274   /* more than two bytes */
9275   else if (shCount >= 16)
9276     {
9277       /* lower order two bytes goes to higher order two bytes */
9278       shCount -= 16;
9279       /* if some more remaining */
9280       if (shCount)
9281         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9282       else
9283         {
9284           movLeft2Result (left, MSB16, result, MSB32, 0);
9285           movLeft2Result (left, LSB, result, MSB24, 0);
9286         }
9287       aopPut (result, zero, MSB16);
9288       aopPut (result, zero, LSB);
9289       return;
9290     }
9291
9292   /* if more than 1 byte */
9293   else if (shCount >= 8)
9294     {
9295       /* lower order three bytes goes to higher order  three bytes */
9296       shCount -= 8;
9297       if (size == 2)
9298         {
9299           if (shCount)
9300             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9301           else
9302             movLeft2Result (left, LSB, result, MSB16, 0);
9303         }
9304       else
9305         {                       /* size = 4 */
9306           if (shCount == 0)
9307             {
9308               movLeft2Result (left, MSB24, result, MSB32, 0);
9309               movLeft2Result (left, MSB16, result, MSB24, 0);
9310               movLeft2Result (left, LSB, result, MSB16, 0);
9311               aopPut (result, zero, LSB);
9312             }
9313           else if (shCount == 1)
9314             shiftLLong (left, result, MSB16);
9315           else
9316             {
9317               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9318               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9319               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9320               aopPut (result, zero, LSB);
9321             }
9322         }
9323     }
9324
9325   /* 1 <= shCount <= 7 */
9326   else if (shCount <= 2)
9327     {
9328       shiftLLong (left, result, LSB);
9329       if (shCount == 2)
9330         shiftLLong (result, result, LSB);
9331     }
9332   /* 3 <= shCount <= 7, optimize */
9333   else
9334     {
9335       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9336       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9337       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9338     }
9339 }
9340 #endif
9341
9342 #ifdef BETTER_LITERAL_SHIFT
9343 /*-----------------------------------------------------------------*/
9344 /* genLeftShiftLiteral - left shifting by known count              */
9345 /*-----------------------------------------------------------------*/
9346 static bool
9347 genLeftShiftLiteral (operand * left,
9348                      operand * right,
9349                      operand * result,
9350                      iCode * ic)
9351 {
9352   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9353   int size;
9354
9355   size = getSize (operandType (result));
9356
9357   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9358
9359   /* We only handle certain easy cases so far. */
9360   if ((shCount != 0)
9361    && (shCount < (size * 8))
9362    && (size != 1)
9363    && (size != 2))
9364   {
9365       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9366       return FALSE;
9367   }
9368
9369   freeAsmop (right, NULL, ic, TRUE);
9370
9371   aopOp(left, ic, FALSE, FALSE);
9372   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9373
9374 #if 0 // debug spew
9375   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9376   {
9377         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9378         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9379         {
9380            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9381         }
9382   }
9383   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9384   {
9385         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9386         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9387         {
9388            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9389         }
9390   }
9391 #endif
9392
9393 #if VIEW_SIZE
9394   emitcode ("; shift left ", "result %d, left %d", size,
9395             AOP_SIZE (left));
9396 #endif
9397
9398   /* I suppose that the left size >= result size */
9399   if (shCount == 0)
9400   {
9401         _startLazyDPSEvaluation();
9402         while (size--)
9403         {
9404           movLeft2Result (left, size, result, size, 0);
9405         }
9406         _endLazyDPSEvaluation();
9407   }
9408   else if (shCount >= (size * 8))
9409   {
9410     _startLazyDPSEvaluation();
9411     while (size--)
9412     {
9413       aopPut (result, zero, size);
9414     }
9415     _endLazyDPSEvaluation();
9416   }
9417   else
9418   {
9419       switch (size)
9420         {
9421         case 1:
9422           genlshOne (result, left, shCount);
9423           break;
9424
9425         case 2:
9426           genlshTwo (result, left, shCount);
9427           break;
9428 #if 0
9429         case 4:
9430           genlshFour (result, left, shCount);
9431           break;
9432 #endif
9433         default:
9434           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9435                   "*** ack! mystery literal shift!\n");
9436           break;
9437         }
9438     }
9439   freeAsmop (result, NULL, ic, TRUE);
9440   freeAsmop (left, NULL, ic, TRUE);
9441   return TRUE;
9442 }
9443 #endif
9444
9445 /*-----------------------------------------------------------------*/
9446 /* genLeftShift - generates code for left shifting                 */
9447 /*-----------------------------------------------------------------*/
9448 static void
9449 genLeftShift (iCode * ic)
9450 {
9451   operand *left, *right, *result;
9452   int size, offset;
9453   char *l;
9454   symbol *tlbl, *tlbl1;
9455   bool pushedB;
9456
9457   D (emitcode (";", "genLeftShift"));
9458
9459   right = IC_RIGHT (ic);
9460   left = IC_LEFT (ic);
9461   result = IC_RESULT (ic);
9462
9463   aopOp (right, ic, FALSE, FALSE);
9464
9465
9466 #ifdef BETTER_LITERAL_SHIFT
9467   /* if the shift count is known then do it
9468      as efficiently as possible */
9469   if (AOP_TYPE (right) == AOP_LIT)
9470     {
9471       if (genLeftShiftLiteral (left, right, result, ic))
9472       {
9473         return;
9474       }
9475     }
9476 #endif
9477
9478   /* shift count is unknown then we have to form
9479      a loop get the loop count in B : Note: we take
9480      only the lower order byte since shifting
9481      more that 32 bits make no sense anyway, ( the
9482      largest size of an object can be only 32 bits ) */
9483
9484   pushedB = pushB ();
9485   if (AOP_TYPE (right) == AOP_LIT)
9486   {
9487       /* Really should be handled by genLeftShiftLiteral,
9488        * but since I'm too lazy to fix that today, at least we can make
9489        * some small improvement.
9490        */
9491        emitcode("mov", "b,#!constbyte",
9492                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9493   }
9494   else
9495   {
9496       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9497       emitcode ("inc", "b");
9498   }
9499   freeAsmop (right, NULL, ic, TRUE);
9500   aopOp (left, ic, FALSE, FALSE);
9501   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9502
9503   /* now move the left to the result if they are not the same */
9504   if (!sameRegs (AOP (left), AOP (result)) &&
9505       AOP_SIZE (result) > 1)
9506     {
9507
9508       size = AOP_SIZE (result);
9509       offset = 0;
9510       _startLazyDPSEvaluation ();
9511       while (size--)
9512         {
9513           l = aopGet (left, offset, FALSE, TRUE, NULL);
9514           if (*l == '@' && (IS_AOP_PREG (result)))
9515             {
9516
9517               emitcode ("mov", "a,%s", l);
9518               aopPut (result, "a", offset);
9519             }
9520           else
9521             aopPut (result, l, offset);
9522           offset++;
9523         }
9524       _endLazyDPSEvaluation ();
9525     }
9526
9527   tlbl = newiTempLabel (NULL);
9528   size = AOP_SIZE (result);
9529   offset = 0;
9530   tlbl1 = newiTempLabel (NULL);
9531
9532   /* if it is only one byte then */
9533   if (size == 1)
9534     {
9535       symbol *tlbl1 = newiTempLabel (NULL);
9536
9537       l = aopGet (left, 0, FALSE, FALSE, NULL);
9538       MOVA (l);
9539       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9540       emitLabel (tlbl);
9541       emitcode ("add", "a,acc");
9542       emitLabel (tlbl1);
9543       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9544       popB (pushedB);
9545       aopPut (result, "a", 0);
9546       goto release;
9547     }
9548
9549   reAdjustPreg (AOP (result));
9550
9551   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9552   emitLabel (tlbl);
9553   l = aopGet (result, offset, FALSE, FALSE, NULL);
9554   MOVA (l);
9555   emitcode ("add", "a,acc");
9556   aopPut (result, "a", offset++);
9557   _startLazyDPSEvaluation ();
9558   while (--size)
9559     {
9560       l = aopGet (result, offset, FALSE, FALSE, NULL);
9561       MOVA (l);
9562       emitcode ("rlc", "a");
9563       aopPut (result, "a", offset++);
9564     }
9565   _endLazyDPSEvaluation ();
9566   reAdjustPreg (AOP (result));
9567
9568   emitLabel (tlbl1);
9569   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9570   popB (pushedB);
9571 release:
9572   freeAsmop (result, NULL, ic, TRUE);
9573   freeAsmop (left, NULL, ic, TRUE);
9574 }
9575
9576 #ifdef BETTER_LITERAL_SHIFT
9577 /*-----------------------------------------------------------------*/
9578 /* genrshOne - right shift a one byte quantity by known count      */
9579 /*-----------------------------------------------------------------*/
9580 static void
9581 genrshOne (operand * result, operand * left,
9582            int shCount, int sign)
9583 {
9584   D (emitcode (";", "genrshOne"));
9585
9586   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9587 }
9588 #endif
9589
9590 #ifdef BETTER_LITERAL_SHIFT
9591 /*-----------------------------------------------------------------*/
9592 /* genrshTwo - right shift two bytes by known amount != 0          */
9593 /*-----------------------------------------------------------------*/
9594 static void
9595 genrshTwo (operand * result, operand * left,
9596            int shCount, int sign)
9597 {
9598   D (emitcode (";", "genrshTwo"));
9599
9600   /* if shCount >= 8 */
9601   if (shCount >= 8)
9602     {
9603       shCount -= 8;
9604       _startLazyDPSEvaluation();
9605       if (shCount)
9606         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9607       else
9608         movLeft2Result (left, MSB16, result, LSB, sign);
9609       addSign (result, MSB16, sign);
9610       _endLazyDPSEvaluation();
9611     }
9612
9613   /*  1 <= shCount <= 7 */
9614   else
9615     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9616 }
9617 #endif
9618
9619 /*-----------------------------------------------------------------*/
9620 /* shiftRLong - shift right one long from left to result           */
9621 /* offl = LSB or MSB16                                             */
9622 /*-----------------------------------------------------------------*/
9623 static void
9624 shiftRLong (operand * left, int offl,
9625             operand * result, int sign)
9626 {
9627   int isSameRegs=sameRegs(AOP(left),AOP(result));
9628
9629   if (isSameRegs && offl>1) {
9630     // we are in big trouble, but this shouldn't happen
9631     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9632   }
9633
9634   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9635
9636   if (offl==MSB16)
9637     {
9638       // shift is > 8
9639       if (sign)
9640         {
9641           emitcode ("rlc", "a");
9642           emitcode ("subb", "a,acc");
9643           emitcode ("xch", "a,%s",
9644                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9645         }
9646       else
9647         {
9648           aopPut (result, zero, MSB32);
9649         }
9650     }
9651
9652   if (!sign)
9653     {
9654       emitcode ("clr", "c");
9655     }
9656   else
9657     {
9658       emitcode ("mov", "c,acc.7");
9659     }
9660
9661   emitcode ("rrc", "a");
9662
9663   if (isSameRegs && offl==MSB16) {
9664     emitcode ("xch",
9665               "a,%s",aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9666   } else {
9667     aopPut (result, "a", MSB32);
9668     MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9669   }
9670
9671   emitcode ("rrc", "a");
9672   if (isSameRegs && offl==1) {
9673     emitcode ("xch", "a,%s",
9674               aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9675   } else {
9676     aopPut (result, "a", MSB24);
9677     MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9678   }
9679   emitcode ("rrc", "a");
9680   aopPut (result, "a", MSB16 - offl);
9681
9682   if (offl == LSB)
9683     {
9684       MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9685       emitcode ("rrc", "a");
9686       aopPut (result, "a", LSB);
9687     }
9688 }
9689
9690 /*-----------------------------------------------------------------*/
9691 /* genrshFour - shift four byte by a known amount != 0             */
9692 /*-----------------------------------------------------------------*/
9693 static void
9694 genrshFour (operand * result, operand * left,
9695             int shCount, int sign)
9696 {
9697   D (emitcode (";", "genrshFour"));
9698
9699   /* if shifting more that 3 bytes */
9700   if (shCount >= 24)
9701     {
9702       shCount -= 24;
9703       _startLazyDPSEvaluation();
9704       if (shCount)
9705         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9706       else
9707         movLeft2Result (left, MSB32, result, LSB, sign);
9708       addSign (result, MSB16, sign);
9709       _endLazyDPSEvaluation();
9710     }
9711   else if (shCount >= 16)
9712     {
9713       shCount -= 16;
9714       _startLazyDPSEvaluation();
9715       if (shCount)
9716         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9717       else
9718         {
9719           movLeft2Result (left, MSB24, result, LSB, 0);
9720           movLeft2Result (left, MSB32, result, MSB16, sign);
9721         }
9722       addSign (result, MSB24, sign);
9723       _endLazyDPSEvaluation();
9724     }
9725   else if (shCount >= 8)
9726     {
9727       shCount -= 8;
9728       _startLazyDPSEvaluation();
9729       if (shCount == 1)
9730         {
9731             shiftRLong (left, MSB16, result, sign);
9732         }
9733       else if (shCount == 0)
9734         {
9735           movLeft2Result (left, MSB16, result, LSB, 0);
9736           movLeft2Result (left, MSB24, result, MSB16, 0);
9737           movLeft2Result (left, MSB32, result, MSB24, sign);
9738           addSign (result, MSB32, sign);
9739         }
9740       else
9741         {
9742           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9743           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9744           /* the last shift is signed */
9745           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9746           addSign (result, MSB32, sign);
9747         }
9748         _endLazyDPSEvaluation();
9749     }
9750   else
9751     {
9752       /* 1 <= shCount <= 7 */
9753       if (shCount <= 2)
9754         {
9755           shiftRLong (left, LSB, result, sign);
9756           if (shCount == 2)
9757             shiftRLong (result, LSB, result, sign);
9758         }
9759       else
9760         {
9761           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9762           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9763           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9764         }
9765     }
9766 }
9767
9768 #ifdef BETTER_LITERAL_SHIFT
9769 /*-----------------------------------------------------------------*/
9770 /* genRightShiftLiteral - right shifting by known count            */
9771 /*-----------------------------------------------------------------*/
9772 static bool
9773 genRightShiftLiteral (operand * left,
9774                       operand * right,
9775                       operand * result,
9776                       iCode * ic,
9777                       int sign)
9778 {
9779   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9780   int size;
9781
9782   size = getSize (operandType (result));
9783
9784   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9785
9786   /* We only handle certain easy cases so far. */
9787   if ((shCount != 0)
9788    && (shCount < (size * 8))
9789    && (size != 1)
9790    && (size != 2)
9791    && (size != 4))
9792   {
9793       D(emitcode (";", "genRightShiftLiteral wimping out"););
9794       return FALSE;
9795   }
9796
9797   freeAsmop (right, NULL, ic, TRUE);
9798
9799   aopOp (left, ic, FALSE, FALSE);
9800   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9801
9802 #if VIEW_SIZE
9803   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9804             AOP_SIZE (left));
9805 #endif
9806
9807   /* test the LEFT size !!! */
9808
9809   /* I suppose that the left size >= result size */
9810   if (shCount == 0)
9811   {
9812       size = getDataSize (result);
9813       _startLazyDPSEvaluation();
9814       while (size--)
9815         movLeft2Result (left, size, result, size, 0);
9816       _endLazyDPSEvaluation();
9817   }
9818   else if (shCount >= (size * 8))
9819     {
9820       if (sign)
9821         {
9822           /* get sign in acc.7 */
9823           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9824         }
9825       addSign (result, LSB, sign);
9826     }
9827   else
9828     {
9829       switch (size)
9830         {
9831         case 1:
9832           genrshOne (result, left, shCount, sign);
9833           break;
9834
9835         case 2:
9836           genrshTwo (result, left, shCount, sign);
9837           break;
9838 #if 1
9839         case 4:
9840           genrshFour (result, left, shCount, sign);
9841           break;
9842 #endif
9843         default:
9844           break;
9845         }
9846     }
9847   freeAsmop (result, NULL, ic, TRUE);
9848   freeAsmop (left, NULL, ic, TRUE);
9849
9850   return TRUE;
9851 }
9852 #endif
9853
9854 /*-----------------------------------------------------------------*/
9855 /* genSignedRightShift - right shift of signed number              */
9856 /*-----------------------------------------------------------------*/
9857 static void
9858 genSignedRightShift (iCode * ic)
9859 {
9860   operand *right, *left, *result;
9861   int size, offset;
9862   char *l;
9863   symbol *tlbl, *tlbl1;
9864   bool pushedB;
9865
9866   D (emitcode (";", "genSignedRightShift"));
9867
9868   /* we do it the hard way put the shift count in b
9869      and loop thru preserving the sign */
9870
9871   right = IC_RIGHT (ic);
9872   left = IC_LEFT (ic);
9873   result = IC_RESULT (ic);
9874
9875   aopOp (right, ic, FALSE, FALSE);
9876
9877 #ifdef BETTER_LITERAL_SHIFT
9878   if (AOP_TYPE (right) == AOP_LIT)
9879     {
9880       if (genRightShiftLiteral (left, right, result, ic, 1))
9881       {
9882         return;
9883       }
9884     }
9885 #endif
9886   /* shift count is unknown then we have to form
9887      a loop get the loop count in B : Note: we take
9888      only the lower order byte since shifting
9889      more that 32 bits make no sense anyway, ( the
9890      largest size of an object can be only 32 bits ) */
9891
9892   pushedB = pushB ();
9893   if (AOP_TYPE (right) == AOP_LIT)
9894   {
9895       /* Really should be handled by genRightShiftLiteral,
9896        * but since I'm too lazy to fix that today, at least we can make
9897        * some small improvement.
9898        */
9899        emitcode("mov", "b,#!constbyte",
9900                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9901   }
9902   else
9903   {
9904         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9905         emitcode ("inc", "b");
9906   }
9907   freeAsmop (right, NULL, ic, TRUE);
9908   aopOp (left, ic, FALSE, FALSE);
9909   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9910
9911   /* now move the left to the result if they are not the
9912      same */
9913   if (!sameRegs (AOP (left), AOP (result)) &&
9914       AOP_SIZE (result) > 1)
9915     {
9916
9917       size = AOP_SIZE (result);
9918       offset = 0;
9919       _startLazyDPSEvaluation ();
9920       while (size--)
9921         {
9922           l = aopGet (left, offset, FALSE, TRUE, NULL);
9923           if (*l == '@' && IS_AOP_PREG (result))
9924             {
9925
9926               emitcode ("mov", "a,%s", l);
9927               aopPut (result, "a", offset);
9928             }
9929           else
9930             aopPut (result, l, offset);
9931           offset++;
9932         }
9933       _endLazyDPSEvaluation ();
9934     }
9935
9936   /* mov the highest order bit to OVR */
9937   tlbl = newiTempLabel (NULL);
9938   tlbl1 = newiTempLabel (NULL);
9939
9940   size = AOP_SIZE (result);
9941   offset = size - 1;
9942   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
9943   emitcode ("rlc", "a");
9944   emitcode ("mov", "ov,c");
9945   /* if it is only one byte then */
9946   if (size == 1)
9947     {
9948       l = aopGet (left, 0, FALSE, FALSE, NULL);
9949       MOVA (l);
9950       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9951       emitLabel (tlbl);
9952       emitcode ("mov", "c,ov");
9953       emitcode ("rrc", "a");
9954       emitLabel (tlbl1);
9955       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9956       popB (pushedB);
9957       aopPut (result, "a", 0);
9958       goto release;
9959     }
9960
9961   reAdjustPreg (AOP (result));
9962   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9963   emitLabel (tlbl);
9964   emitcode ("mov", "c,ov");
9965   _startLazyDPSEvaluation ();
9966   while (size--)
9967     {
9968       l = aopGet (result, offset, FALSE, FALSE, NULL);
9969       MOVA (l);
9970       emitcode ("rrc", "a");
9971       aopPut (result, "a", offset--);
9972     }
9973   _endLazyDPSEvaluation ();
9974   reAdjustPreg (AOP (result));
9975   emitLabel (tlbl1);
9976   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9977   popB (pushedB);
9978
9979 release:
9980   freeAsmop (result, NULL, ic, TRUE);
9981   freeAsmop (left, NULL, ic, TRUE);
9982 }
9983
9984 /*-----------------------------------------------------------------*/
9985 /* genRightShift - generate code for right shifting                */
9986 /*-----------------------------------------------------------------*/
9987 static void
9988 genRightShift (iCode * ic)
9989 {
9990   operand *right, *left, *result;
9991   sym_link *letype;
9992   int size, offset;
9993   char *l;
9994   symbol *tlbl, *tlbl1;
9995   bool pushedB;
9996
9997   D (emitcode (";", "genRightShift"));
9998
9999   /* if signed then we do it the hard way preserve the
10000      sign bit moving it inwards */
10001   letype = getSpec (operandType (IC_LEFT (ic)));
10002
10003   if (!SPEC_USIGN (letype))
10004     {
10005       genSignedRightShift (ic);
10006       return;
10007     }
10008
10009   /* signed & unsigned types are treated the same : i.e. the
10010      signed is NOT propagated inwards : quoting from the
10011      ANSI - standard : "for E1 >> E2, is equivalent to division
10012      by 2**E2 if unsigned or if it has a non-negative value,
10013      otherwise the result is implementation defined ", MY definition
10014      is that the sign does not get propagated */
10015
10016   right = IC_RIGHT (ic);
10017   left = IC_LEFT (ic);
10018   result = IC_RESULT (ic);
10019
10020   aopOp (right, ic, FALSE, FALSE);
10021
10022 #ifdef BETTER_LITERAL_SHIFT
10023   /* if the shift count is known then do it
10024      as efficiently as possible */
10025   if (AOP_TYPE (right) == AOP_LIT)
10026     {
10027       if (genRightShiftLiteral (left, right, result, ic, 0))
10028       {
10029         return;
10030       }
10031     }
10032 #endif
10033
10034   /* shift count is unknown then we have to form
10035      a loop get the loop count in B : Note: we take
10036      only the lower order byte since shifting
10037      more that 32 bits make no sense anyway, ( the
10038      largest size of an object can be only 32 bits ) */
10039
10040   pushedB = pushB ();
10041   if (AOP_TYPE (right) == AOP_LIT)
10042   {
10043       /* Really should be handled by genRightShiftLiteral,
10044        * but since I'm too lazy to fix that today, at least we can make
10045        * some small improvement.
10046        */
10047        emitcode("mov", "b,#!constbyte",
10048                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10049   }
10050   else
10051   {
10052       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10053       emitcode ("inc", "b");
10054   }
10055   freeAsmop (right, NULL, ic, TRUE);
10056   aopOp (left, ic, FALSE, FALSE);
10057   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10058
10059   /* now move the left to the result if they are not the
10060      same */
10061   if (!sameRegs (AOP (left), AOP (result)) &&
10062       AOP_SIZE (result) > 1)
10063     {
10064       size = AOP_SIZE (result);
10065       offset = 0;
10066       _startLazyDPSEvaluation ();
10067       while (size--)
10068         {
10069           l = aopGet (left, offset, FALSE, TRUE, NULL);
10070           if (*l == '@' && IS_AOP_PREG (result))
10071             {
10072
10073               emitcode ("mov", "a,%s", l);
10074               aopPut (result, "a", offset);
10075             }
10076           else
10077             aopPut (result, l, offset);
10078           offset++;
10079         }
10080       _endLazyDPSEvaluation ();
10081     }
10082
10083   tlbl = newiTempLabel (NULL);
10084   tlbl1 = newiTempLabel (NULL);
10085   size = AOP_SIZE (result);
10086   offset = size - 1;
10087
10088   /* if it is only one byte then */
10089   if (size == 1)
10090     {
10091       l = aopGet (left, 0, FALSE, FALSE, NULL);
10092       MOVA (l);
10093       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10094       emitLabel (tlbl);
10095       CLRC;
10096       emitcode ("rrc", "a");
10097       emitLabel (tlbl1);
10098       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10099       popB (pushedB);
10100       aopPut (result, "a", 0);
10101       goto release;
10102     }
10103
10104   reAdjustPreg (AOP (result));
10105   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10106   emitLabel (tlbl);
10107   CLRC;
10108   _startLazyDPSEvaluation ();
10109   while (size--)
10110     {
10111       l = aopGet (result, offset, FALSE, FALSE, NULL);
10112       MOVA (l);
10113       emitcode ("rrc", "a");
10114       aopPut (result, "a", offset--);
10115     }
10116   _endLazyDPSEvaluation ();
10117   reAdjustPreg (AOP (result));
10118
10119   emitLabel (tlbl1);
10120   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10121   popB (pushedB);
10122
10123 release:
10124   freeAsmop (result, NULL, ic, TRUE);
10125   freeAsmop (left, NULL, ic, TRUE);
10126 }
10127
10128 /*-----------------------------------------------------------------*/
10129 /* emitPtrByteGet - emits code to get a byte into A through a      */
10130 /*                  pointer register (R0, R1, or DPTR). The        */
10131 /*                  original value of A can be preserved in B.     */
10132 /*-----------------------------------------------------------------*/
10133 static void
10134 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10135 {
10136   switch (p_type)
10137     {
10138     case IPOINTER:
10139     case POINTER:
10140       if (preserveAinB)
10141         emitcode ("mov", "b,a");
10142       emitcode ("mov", "a,@%s", rname);
10143       break;
10144
10145     case PPOINTER:
10146       if (preserveAinB)
10147         emitcode ("mov", "b,a");
10148       emitcode ("movx", "a,@%s", rname);
10149       break;
10150
10151     case FPOINTER:
10152       if (preserveAinB)
10153         emitcode ("mov", "b,a");
10154       emitcode ("movx", "a,@dptr");
10155       break;
10156
10157     case CPOINTER:
10158       if (preserveAinB)
10159         emitcode ("mov", "b,a");
10160       emitcode ("clr", "a");
10161       emitcode ("movc", "a,@a+dptr");
10162       break;
10163
10164     case GPOINTER:
10165       if (preserveAinB)
10166         {
10167           emitcode ("push", "b");
10168           emitcode ("push", "acc");
10169         }
10170       emitcode ("lcall", "__gptrget");
10171       if (preserveAinB)
10172         emitcode ("pop", "b");
10173       break;
10174     }
10175 }
10176
10177 /*-----------------------------------------------------------------*/
10178 /* emitPtrByteSet - emits code to set a byte from src through a    */
10179 /*                  pointer register (R0, R1, or DPTR).            */
10180 /*-----------------------------------------------------------------*/
10181 static void
10182 emitPtrByteSet (char *rname, int p_type, char *src)
10183 {
10184   switch (p_type)
10185     {
10186     case IPOINTER:
10187     case POINTER:
10188       if (*src=='@')
10189         {
10190           MOVA (src);
10191           emitcode ("mov", "@%s,a", rname);
10192         }
10193       else
10194         emitcode ("mov", "@%s,%s", rname, src);
10195       break;
10196
10197     case PPOINTER:
10198       MOVA (src);
10199       emitcode ("movx", "@%s,a", rname);
10200       break;
10201
10202     case FPOINTER:
10203       MOVA (src);
10204       emitcode ("movx", "@dptr,a");
10205       break;
10206
10207     case GPOINTER:
10208       MOVA (src);
10209       emitcode ("lcall", "__gptrput");
10210       break;
10211     }
10212 }
10213
10214 /*-----------------------------------------------------------------*/
10215 /* genUnpackBits - generates code for unpacking bits               */
10216 /*-----------------------------------------------------------------*/
10217 static void
10218 genUnpackBits (operand * result, char *rname, int ptype)
10219 {
10220   int offset = 0;       /* result byte offset */
10221   int rsize;            /* result size */
10222   int rlen = 0;         /* remaining bitfield length */
10223   sym_link *etype;      /* bitfield type information */
10224   int blen;             /* bitfield length */
10225   int bstr;             /* bitfield starting bit within byte */
10226
10227   D(emitcode (";     genUnpackBits",""));
10228
10229   etype = getSpec (operandType (result));
10230   rsize = getSize (operandType (result));
10231   blen = SPEC_BLEN (etype);
10232   bstr = SPEC_BSTR (etype);
10233
10234   /* If the bitfield length is less than a byte */
10235   if (blen < 8)
10236     {
10237       emitPtrByteGet (rname, ptype, FALSE);
10238       AccRol (8 - bstr);
10239       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10240       if (!SPEC_USIGN (etype))
10241         {
10242           /* signed bitfield */
10243           symbol *tlbl = newiTempLabel (NULL);
10244
10245           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10246           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10247           emitLabel (tlbl);
10248         }
10249       aopPut (result, "a", offset++);
10250       goto finish;
10251     }
10252
10253   /* Bit field did not fit in a byte. Copy all
10254      but the partial byte at the end.  */
10255   for (rlen=blen;rlen>=8;rlen-=8)
10256     {
10257       emitPtrByteGet (rname, ptype, FALSE);
10258       aopPut (result, "a", offset++);
10259       if (rlen>8)
10260         emitcode ("inc", "%s", rname);
10261     }
10262
10263   /* Handle the partial byte at the end */
10264   if (rlen)
10265     {
10266       emitPtrByteGet (rname, ptype, FALSE);
10267       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10268       if (!SPEC_USIGN (etype))
10269         {
10270           /* signed bitfield */
10271           symbol *tlbl = newiTempLabel (NULL);
10272
10273           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10274           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10275           emitLabel (tlbl);
10276         }
10277       aopPut (result, "a", offset++);
10278     }
10279
10280 finish:
10281   if (offset < rsize)
10282     {
10283       char *source;
10284
10285       if (SPEC_USIGN (etype))
10286         source = zero;
10287       else
10288         {
10289           /* signed bitfield: sign extension with 0x00 or 0xff */
10290           emitcode ("rlc", "a");
10291           emitcode ("subb", "a,acc");
10292
10293           source = "a";
10294         }
10295       rsize -= offset;
10296       while (rsize--)
10297         aopPut (result, source, offset++);
10298     }
10299 }
10300
10301
10302 /*-----------------------------------------------------------------*/
10303 /* genDataPointerGet - generates code when ptr offset is known     */
10304 /*-----------------------------------------------------------------*/
10305 static void
10306 genDataPointerGet (operand * left,
10307                    operand * result,
10308                    iCode * ic)
10309 {
10310   char *l;
10311   char buffer[256];
10312   int size, offset = 0;
10313   aopOp (result, ic, TRUE, FALSE);
10314
10315   /* get the string representation of the name */
10316   l = aopGet (left, 0, FALSE, TRUE, NULL);
10317   size = AOP_SIZE (result);
10318   _startLazyDPSEvaluation ();
10319   while (size--)
10320     {
10321         if (offset)
10322         {
10323             SNPRINTF (buffer, sizeof(buffer),
10324                       "(%s + %d)", l + 1, offset);
10325         }
10326         else
10327         {
10328             SNPRINTF (buffer, sizeof(buffer),
10329                       "%s", l + 1);
10330         }
10331       aopPut (result, buffer, offset++);
10332     }
10333   _endLazyDPSEvaluation ();
10334
10335   freeAsmop (result, NULL, ic, TRUE);
10336   freeAsmop (left, NULL, ic, TRUE);
10337 }
10338
10339 /*-----------------------------------------------------------------*/
10340 /* genNearPointerGet - emitcode for near pointer fetch             */
10341 /*-----------------------------------------------------------------*/
10342 static void
10343 genNearPointerGet (operand * left,
10344                    operand * result,
10345                    iCode * ic,
10346                    iCode *pi)
10347 {
10348   asmop *aop = NULL;
10349   regs *preg;
10350   char *rname;
10351   sym_link *rtype, *retype, *letype;
10352   sym_link *ltype = operandType (left);
10353   char buffer[80];
10354
10355   rtype = operandType (result);
10356   retype = getSpec (rtype);
10357   letype = getSpec (ltype);
10358
10359   aopOp (left, ic, FALSE, FALSE);
10360
10361   /* if left is rematerialisable and
10362      result is not bitfield variable type and
10363      the left is pointer to data space i.e
10364      lower 128 bytes of space */
10365   if (AOP_TYPE (left) == AOP_IMMD &&
10366       !IS_BITFIELD (retype) &&
10367       !IS_BITFIELD (letype) &&
10368       DCL_TYPE (ltype) == POINTER)
10369     {
10370       genDataPointerGet (left, result, ic);
10371       return;
10372     }
10373
10374   /* if the value is already in a pointer register
10375      then don't need anything more */
10376   if (!AOP_INPREG (AOP (left)))
10377     {
10378       /* otherwise get a free pointer register */
10379       aop = newAsmop (0);
10380       preg = getFreePtr (ic, &aop, FALSE);
10381       emitcode ("mov", "%s,%s",
10382                 preg->name,
10383                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10384       rname = preg->name;
10385     }
10386   else
10387     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10388
10389   freeAsmop (left, NULL, ic, TRUE);
10390   aopOp (result, ic, FALSE, FALSE);
10391
10392   /* if bitfield then unpack the bits */
10393   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10394     genUnpackBits (result, rname, POINTER);
10395   else
10396     {
10397       /* we have can just get the values */
10398       int size = AOP_SIZE (result);
10399       int offset = 0;
10400
10401       while (size--)
10402         {
10403           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10404             {
10405
10406               emitcode ("mov", "a,@%s", rname);
10407               aopPut (result, "a", offset);
10408             }
10409           else
10410             {
10411               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10412               aopPut (result, buffer, offset);
10413             }
10414           offset++;
10415           if (size || pi)
10416                 emitcode ("inc", "%s", rname);
10417             }
10418         }
10419
10420   /* now some housekeeping stuff */
10421   if (aop)      /* we had to allocate for this iCode */
10422     {
10423       if (pi) { /* post increment present */
10424         aopPut (left, rname, 0);
10425       }
10426       freeAsmop (NULL, aop, ic, TRUE);
10427     }
10428   else
10429     {
10430       /* we did not allocate which means left
10431          already in a pointer register, then
10432          if size > 0 && this could be used again
10433          we have to point it back to where it
10434          belongs */
10435       if (AOP_SIZE (result) > 1 &&
10436           !OP_SYMBOL (left)->remat &&
10437           (OP_SYMBOL (left)->liveTo > ic->seq ||
10438            ic->depth) &&
10439           !pi)
10440         {
10441           int size = AOP_SIZE (result) - 1;
10442           while (size--)
10443             emitcode ("dec", "%s", rname);
10444         }
10445     }
10446
10447   /* done */
10448   freeAsmop (result, NULL, ic, TRUE);
10449   if (pi) pi->generated = 1;
10450 }
10451
10452 /*-----------------------------------------------------------------*/
10453 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10454 /*-----------------------------------------------------------------*/
10455 static void
10456 genPagedPointerGet (operand * left,
10457                     operand * result,
10458                     iCode * ic,
10459                     iCode * pi)
10460 {
10461   asmop *aop = NULL;
10462   regs *preg;
10463   char *rname;
10464   sym_link *rtype, *retype, *letype;
10465
10466   rtype = operandType (result);
10467   retype = getSpec (rtype);
10468   letype = getSpec (operandType (left));
10469   aopOp (left, ic, FALSE, FALSE);
10470
10471   /* if the value is already in a pointer register
10472      then don't need anything more */
10473   if (!AOP_INPREG (AOP (left)))
10474     {
10475       /* otherwise get a free pointer register */
10476       aop = newAsmop (0);
10477       preg = getFreePtr (ic, &aop, FALSE);
10478       emitcode ("mov", "%s,%s",
10479                 preg->name,
10480                 aopGet (left, 0, FALSE, TRUE, NULL));
10481       rname = preg->name;
10482     }
10483   else
10484     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10485
10486   freeAsmop (left, NULL, ic, TRUE);
10487   aopOp (result, ic, FALSE, FALSE);
10488
10489   /* if bitfield then unpack the bits */
10490   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10491     genUnpackBits (result, rname, PPOINTER);
10492   else
10493     {
10494       /* we have can just get the values */
10495       int size = AOP_SIZE (result);
10496       int offset = 0;
10497
10498       while (size--)
10499         {
10500
10501           emitcode ("movx", "a,@%s", rname);
10502           aopPut (result, "a", offset);
10503
10504           offset++;
10505
10506           if (size || pi)
10507             emitcode ("inc", "%s", rname);
10508         }
10509     }
10510
10511   /* now some housekeeping stuff */
10512   if (aop)      /* we had to allocate for this iCode */
10513     {
10514       if (pi)
10515         aopPut (left, rname, 0);
10516       freeAsmop (NULL, aop, ic, TRUE);
10517     }
10518   else
10519     {
10520       /* we did not allocate which means left
10521          already in a pointer register, then
10522          if size > 0 && this could be used again
10523          we have to point it back to where it
10524          belongs */
10525       if (AOP_SIZE (result) > 1 &&
10526           !OP_SYMBOL (left)->remat &&
10527           (OP_SYMBOL (left)->liveTo > ic->seq ||
10528            ic->depth) &&
10529           !pi)
10530         {
10531           int size = AOP_SIZE (result) - 1;
10532           while (size--)
10533             emitcode ("dec", "%s", rname);
10534         }
10535     }
10536
10537   /* done */
10538   freeAsmop (result, NULL, ic, TRUE);
10539   if (pi) pi->generated = 1;
10540 }
10541
10542 /*-----------------------------------------------------------------*/
10543 /* genFarPointerGet - get value from far space                     */
10544 /*-----------------------------------------------------------------*/
10545 static void
10546 genFarPointerGet (operand * left,
10547                   operand * result, iCode * ic, iCode *pi)
10548 {
10549     int size, offset, dopi=1;
10550   sym_link *retype = getSpec (operandType (result));
10551   sym_link *letype = getSpec (operandType (left));
10552   D (emitcode (";", "genFarPointerGet"););
10553
10554   aopOp (left, ic, FALSE, FALSE);
10555
10556   /* if the operand is already in dptr
10557      then we do nothing else we move the value to dptr */
10558   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10559     {
10560       /* if this is rematerializable */
10561       if (AOP_TYPE (left) == AOP_IMMD)
10562         {
10563           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10564         }
10565       else
10566         {
10567           /* we need to get it byte by byte */
10568           _startLazyDPSEvaluation ();
10569           if (AOP_TYPE (left) != AOP_DPTR)
10570             {
10571               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10572               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10573               if (options.model == MODEL_FLAT24)
10574                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10575             }
10576           else
10577             {
10578               /* We need to generate a load to DPTR indirect through DPTR. */
10579               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10580               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10581               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10582               if (options.model == MODEL_FLAT24)
10583                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10584               emitcode ("pop", "dph");
10585               emitcode ("pop", "dpl");
10586               dopi =0;
10587             }
10588           _endLazyDPSEvaluation ();
10589         }
10590     }
10591   /* so dptr now contains the address */
10592   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10593
10594   /* if bit then unpack */
10595   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10596       if (AOP_INDPTRn(left)) {
10597           genSetDPTR(AOP(left)->aopu.dptr);
10598       }
10599       genUnpackBits (result, "dptr", FPOINTER);
10600       if (AOP_INDPTRn(left)) {
10601           genSetDPTR(0);
10602       }
10603   } else
10604     {
10605       size = AOP_SIZE (result);
10606       offset = 0;
10607
10608       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10609           while (size--) {
10610               genSetDPTR(AOP(left)->aopu.dptr);
10611               emitcode ("movx", "a,@dptr");
10612               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10613                   emitcode ("inc", "dptr");
10614               genSetDPTR (0);
10615               aopPut (result, "a", offset++);
10616           }
10617       } else {
10618           _startLazyDPSEvaluation ();
10619           while (size--) {
10620               if (AOP_INDPTRn(left)) {
10621                   genSetDPTR(AOP(left)->aopu.dptr);
10622               } else {
10623                   genSetDPTR (0);
10624               }
10625               _flushLazyDPS ();
10626
10627               emitcode ("movx", "a,@dptr");
10628               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10629                   emitcode ("inc", "dptr");
10630
10631               aopPut (result, "a", offset++);
10632           }
10633           _endLazyDPSEvaluation ();
10634       }
10635     }
10636   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10637       if (!AOP_INDPTRn(left)) {
10638           _startLazyDPSEvaluation ();
10639           aopPut (left, "dpl", 0);
10640           aopPut (left, "dph", 1);
10641           if (options.model == MODEL_FLAT24)
10642               aopPut (left, "dpx", 2);
10643           _endLazyDPSEvaluation ();
10644       }
10645     pi->generated = 1;
10646   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10647              AOP_SIZE(result) > 1 &&
10648              IS_SYMOP(left) &&
10649              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10650
10651       size = AOP_SIZE (result) - 1;
10652       if (AOP_INDPTRn(left)) {
10653           genSetDPTR(AOP(left)->aopu.dptr);
10654       }
10655       while (size--) emitcode ("lcall","__decdptr");
10656       if (AOP_INDPTRn(left)) {
10657           genSetDPTR(0);
10658       }
10659   }
10660
10661   freeAsmop (result, NULL, ic, TRUE);
10662   freeAsmop (left, NULL, ic, TRUE);
10663 }
10664
10665 /*-----------------------------------------------------------------*/
10666 /* genCodePointerGet - get value from code space                  */
10667 /*-----------------------------------------------------------------*/
10668 static void
10669 genCodePointerGet (operand * left,
10670                     operand * result, iCode * ic, iCode *pi)
10671 {
10672   int size, offset, dopi=1;
10673   sym_link *retype = getSpec (operandType (result));
10674
10675   aopOp (left, ic, FALSE, FALSE);
10676
10677   /* if the operand is already in dptr
10678      then we do nothing else we move the value to dptr */
10679   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10680     {
10681       /* if this is rematerializable */
10682       if (AOP_TYPE (left) == AOP_IMMD)
10683         {
10684           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10685         }
10686       else
10687         {                       /* we need to get it byte by byte */
10688           _startLazyDPSEvaluation ();
10689           if (AOP_TYPE (left) != AOP_DPTR)
10690             {
10691               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10692               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10693               if (options.model == MODEL_FLAT24)
10694                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10695             }
10696           else
10697             {
10698               /* We need to generate a load to DPTR indirect through DPTR. */
10699               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10700               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10701               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10702               if (options.model == MODEL_FLAT24)
10703                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10704               emitcode ("pop", "dph");
10705               emitcode ("pop", "dpl");
10706               dopi=0;
10707             }
10708           _endLazyDPSEvaluation ();
10709         }
10710     }
10711   /* so dptr now contains the address */
10712   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10713
10714   /* if bit then unpack */
10715   if (IS_BITFIELD (retype)) {
10716       if (AOP_INDPTRn(left)) {
10717           genSetDPTR(AOP(left)->aopu.dptr);
10718       }
10719       genUnpackBits (result, "dptr", CPOINTER);
10720       if (AOP_INDPTRn(left)) {
10721           genSetDPTR(0);
10722       }
10723   } else
10724     {
10725       size = AOP_SIZE (result);
10726       offset = 0;
10727       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10728           while (size--) {
10729               genSetDPTR(AOP(left)->aopu.dptr);
10730               emitcode ("clr", "a");
10731               emitcode ("movc", "a,@a+dptr");
10732               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10733                   emitcode ("inc", "dptr");
10734               genSetDPTR (0);
10735               aopPut (result, "a", offset++);
10736           }
10737       } else {
10738           _startLazyDPSEvaluation ();
10739           while (size--)
10740               {
10741                   if (AOP_INDPTRn(left)) {
10742                       genSetDPTR(AOP(left)->aopu.dptr);
10743                   } else {
10744                       genSetDPTR (0);
10745                   }
10746                   _flushLazyDPS ();
10747
10748                   emitcode ("clr", "a");
10749                   emitcode ("movc", "a,@a+dptr");
10750                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10751                       emitcode ("inc", "dptr");
10752                   aopPut (result, "a", offset++);
10753               }
10754           _endLazyDPSEvaluation ();
10755       }
10756     }
10757   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10758       if (!AOP_INDPTRn(left)) {
10759           _startLazyDPSEvaluation ();
10760
10761           aopPut (left, "dpl", 0);
10762           aopPut (left, "dph", 1);
10763           if (options.model == MODEL_FLAT24)
10764               aopPut (left, "dpx", 2);
10765
10766           _endLazyDPSEvaluation ();
10767       }
10768       pi->generated = 1;
10769   } else if ((OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10770              AOP_SIZE(result) > 1 &&
10771              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10772
10773       size = AOP_SIZE (result) - 1;
10774       if (AOP_INDPTRn(left)) {
10775           genSetDPTR(AOP(left)->aopu.dptr);
10776       }
10777       while (size--) emitcode ("lcall","__decdptr");
10778       if (AOP_INDPTRn(left)) {
10779           genSetDPTR(0);
10780       }
10781   }
10782
10783   freeAsmop (result, NULL, ic, TRUE);
10784   freeAsmop (left, NULL, ic, TRUE);
10785 }
10786
10787 /*-----------------------------------------------------------------*/
10788 /* genGenPointerGet - get value from generic pointer space         */
10789 /*-----------------------------------------------------------------*/
10790 static void
10791 genGenPointerGet (operand * left,
10792                   operand * result, iCode * ic, iCode * pi)
10793 {
10794   int size, offset;
10795   bool pushedB;
10796   sym_link *retype = getSpec (operandType (result));
10797   sym_link *letype = getSpec (operandType (left));
10798
10799   D (emitcode (";", "genGenPointerGet"));
10800
10801   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10802
10803   pushedB = pushB ();
10804   /* if the operand is already in dptr
10805      then we do nothing else we move the value to dptr */
10806   if (AOP_TYPE (left) != AOP_STR)
10807     {
10808       /* if this is rematerializable */
10809       if (AOP_TYPE (left) == AOP_IMMD)
10810         {
10811           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10812           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10813             {
10814               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10815             }
10816           else
10817             {
10818               emitcode ("mov", "b,#%d", pointerCode (retype));
10819             }
10820         }
10821       else
10822         {                       /* we need to get it byte by byte */
10823           _startLazyDPSEvaluation ();
10824           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10825           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10826           if (options.model == MODEL_FLAT24) {
10827               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10828               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10829           } else {
10830               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10831           }
10832           _endLazyDPSEvaluation ();
10833         }
10834     }
10835
10836   /* so dptr-b now contains the address */
10837   aopOp (result, ic, FALSE, TRUE);
10838
10839   /* if bit then unpack */
10840   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10841   {
10842     genUnpackBits (result, "dptr", GPOINTER);
10843   }
10844   else
10845     {
10846         size = AOP_SIZE (result);
10847         offset = 0;
10848
10849         while (size--)
10850         {
10851             if (size)
10852             {
10853                 // Get two bytes at a time, results in _AP & A.
10854                 // dptr will be incremented ONCE by __gptrgetWord.
10855                 //
10856                 // Note: any change here must be coordinated
10857                 // with the implementation of __gptrgetWord
10858                 // in device/lib/_gptrget.c
10859                 emitcode ("lcall", "__gptrgetWord");
10860                 aopPut (result, DP2_RESULT_REG, offset++);
10861                 aopPut (result, "a", offset++);
10862                 size--;
10863             }
10864             else
10865             {
10866                 // Only one byte to get.
10867                 emitcode ("lcall", "__gptrget");
10868                 aopPut (result, "a", offset++);
10869             }
10870
10871             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
10872             {
10873                 emitcode ("inc", "dptr");
10874             }
10875         }
10876     }
10877
10878   if (pi && AOP_TYPE (left) != AOP_IMMD) {
10879     _startLazyDPSEvaluation ();
10880
10881     aopPut (left, "dpl", 0);
10882     aopPut (left, "dph", 1);
10883     if (options.model == MODEL_FLAT24) {
10884         aopPut (left, "dpx", 2);
10885         aopPut (left, "b", 3);
10886     } else  aopPut (left, "b", 2);
10887
10888     _endLazyDPSEvaluation ();
10889
10890     pi->generated = 1;
10891   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
10892              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10893
10894       size = AOP_SIZE (result) - 1;
10895       while (size--) emitcode ("lcall","__decdptr");
10896   }
10897   popB (pushedB);
10898
10899   freeAsmop (result, NULL, ic, TRUE);
10900   freeAsmop (left, NULL, ic, TRUE);
10901 }
10902
10903 /*-----------------------------------------------------------------*/
10904 /* genPointerGet - generate code for pointer get                   */
10905 /*-----------------------------------------------------------------*/
10906 static void
10907 genPointerGet (iCode * ic, iCode *pi)
10908 {
10909   operand *left, *result;
10910   sym_link *type, *etype;
10911   int p_type;
10912
10913   D (emitcode (";", "genPointerGet"));
10914
10915   left = IC_LEFT (ic);
10916   result = IC_RESULT (ic);
10917
10918   /* depending on the type of pointer we need to
10919      move it to the correct pointer register */
10920   type = operandType (left);
10921   etype = getSpec (type);
10922   /* if left is of type of pointer then it is simple */
10923   if (IS_PTR (type) && !IS_FUNC (type->next))
10924     p_type = DCL_TYPE (type);
10925   else
10926     {
10927       /* we have to go by the storage class */
10928       p_type = PTR_TYPE (SPEC_OCLS (etype));
10929     }
10930
10931   /* special case when cast remat */
10932   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10933       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10934     {
10935       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10936       type = operandType (left);
10937       p_type = DCL_TYPE (type);
10938     }
10939   /* now that we have the pointer type we assign
10940      the pointer values */
10941   switch (p_type)
10942     {
10943
10944     case POINTER:
10945     case IPOINTER:
10946       genNearPointerGet (left, result, ic, pi);
10947       break;
10948
10949     case PPOINTER:
10950       genPagedPointerGet (left, result, ic, pi);
10951       break;
10952
10953     case FPOINTER:
10954       genFarPointerGet (left, result, ic, pi);
10955       break;
10956
10957     case CPOINTER:
10958       genCodePointerGet (left, result, ic, pi);
10959       break;
10960
10961     case GPOINTER:
10962       genGenPointerGet (left, result, ic, pi);
10963       break;
10964     }
10965 }
10966
10967
10968 /*-----------------------------------------------------------------*/
10969 /* genPackBits - generates code for packed bit storage             */
10970 /*-----------------------------------------------------------------*/
10971 static void
10972 genPackBits (sym_link * etype,
10973              operand * right,
10974              char *rname, int p_type)
10975 {
10976   int offset = 0;       /* source byte offset */
10977   int rlen = 0;         /* remaining bitfield length */
10978   int blen;             /* bitfield length */
10979   int bstr;             /* bitfield starting bit within byte */
10980   int litval;           /* source literal value (if AOP_LIT) */
10981   unsigned char mask;   /* bitmask within current byte */
10982
10983   D(emitcode (";     genPackBits",""));
10984
10985   blen = SPEC_BLEN (etype);
10986   bstr = SPEC_BSTR (etype);
10987
10988   /* If the bitfield length is less than a byte */
10989   if (blen < 8)
10990     {
10991       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10992               (unsigned char) (0xFF >> (8 - bstr)));
10993
10994       if (AOP_TYPE (right) == AOP_LIT)
10995         {
10996           /* Case with a bitfield length <8 and literal source
10997           */
10998           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10999           litval <<= bstr;
11000           litval &= (~mask) & 0xff;
11001           emitPtrByteGet (rname, p_type, FALSE);
11002           if ((mask|litval)!=0xff)
11003             emitcode ("anl","a,#!constbyte", mask);
11004           if (litval)
11005             emitcode ("orl","a,#!constbyte", litval);
11006         }
11007       else
11008         {
11009           if ((blen==1) && (p_type!=GPOINTER))
11010             {
11011               /* Case with a bitfield length == 1 and no generic pointer
11012               */
11013               if (AOP_TYPE (right) == AOP_CRY)
11014                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11015               else
11016                 {
11017                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11018                   emitcode ("rrc","a");
11019                 }
11020               emitPtrByteGet (rname, p_type, FALSE);
11021               emitcode ("mov","acc.%d,c",bstr);
11022             }
11023           else
11024             {
11025               bool pushedB;
11026               /* Case with a bitfield length < 8 and arbitrary source
11027               */
11028               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11029               /* shift and mask source value */
11030               AccLsh (bstr);
11031               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11032
11033               pushedB = pushB ();
11034               /* transfer A to B and get next byte */
11035               emitPtrByteGet (rname, p_type, TRUE);
11036
11037               emitcode ("anl", "a,#!constbyte", mask);
11038               emitcode ("orl", "a,b");
11039               if (p_type == GPOINTER)
11040                 emitcode ("pop", "b");
11041
11042               popB (pushedB);
11043            }
11044         }
11045
11046       emitPtrByteSet (rname, p_type, "a");
11047       return;
11048     }
11049
11050   /* Bit length is greater than 7 bits. In this case, copy  */
11051   /* all except the partial byte at the end                 */
11052   for (rlen=blen;rlen>=8;rlen-=8)
11053     {
11054       emitPtrByteSet (rname, p_type,
11055                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11056       if (rlen>8)
11057         emitcode ("inc", "%s", rname);
11058     }
11059
11060   /* If there was a partial byte at the end */
11061   if (rlen)
11062     {
11063       mask = (((unsigned char) -1 << rlen) & 0xff);
11064
11065       if (AOP_TYPE (right) == AOP_LIT)
11066         {
11067           /* Case with partial byte and literal source
11068           */
11069           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11070           litval >>= (blen-rlen);
11071           litval &= (~mask) & 0xff;
11072           emitPtrByteGet (rname, p_type, FALSE);
11073           if ((mask|litval)!=0xff)
11074             emitcode ("anl","a,#!constbyte", mask);
11075           if (litval)
11076             emitcode ("orl","a,#!constbyte", litval);
11077         }
11078       else
11079         {
11080           bool pushedB;
11081           /* Case with partial byte and arbitrary source
11082           */
11083           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11084           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11085
11086           pushedB = pushB ();
11087           /* transfer A to B and get next byte */
11088           emitPtrByteGet (rname, p_type, TRUE);
11089
11090           emitcode ("anl", "a,#!constbyte", mask);
11091           emitcode ("orl", "a,b");
11092           if (p_type == GPOINTER)
11093             emitcode ("pop", "b");
11094
11095           popB (pushedB);
11096         }
11097       emitPtrByteSet (rname, p_type, "a");
11098     }
11099 }
11100
11101
11102 /*-----------------------------------------------------------------*/
11103 /* genDataPointerSet - remat pointer to data space                 */
11104 /*-----------------------------------------------------------------*/
11105 static void
11106 genDataPointerSet (operand * right,
11107                    operand * result,
11108                    iCode * ic)
11109 {
11110   int size, offset = 0;
11111   char *l, buffer[256];
11112
11113   D (emitcode (";", "genDataPointerSet"));
11114
11115   aopOp (right, ic, FALSE, FALSE);
11116
11117   l = aopGet (result, 0, FALSE, TRUE, NULL);
11118   size = AOP_SIZE (right);
11119   while (size--)
11120     {
11121       if (offset)
11122           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11123       else
11124           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11125       emitcode ("mov", "%s,%s", buffer,
11126                 aopGet (right, offset++, FALSE, FALSE, NULL));
11127     }
11128
11129   freeAsmop (result, NULL, ic, TRUE);
11130   freeAsmop (right, NULL, ic, TRUE);
11131 }
11132
11133 /*-----------------------------------------------------------------*/
11134 /* genNearPointerSet - emitcode for near pointer put                */
11135 /*-----------------------------------------------------------------*/
11136 static void
11137 genNearPointerSet (operand * right,
11138                    operand * result,
11139                    iCode * ic,
11140                    iCode * pi)
11141 {
11142   asmop *aop = NULL;
11143   char *rname, *l;
11144   sym_link *retype, *letype;
11145   sym_link *ptype = operandType (result);
11146
11147   D (emitcode (";", "genNearPointerSet"));
11148
11149   retype = getSpec (operandType (right));
11150   letype = getSpec (ptype);
11151
11152   aopOp (result, ic, FALSE, FALSE);
11153
11154   /* if the result is rematerializable &
11155      in data space & not a bit variable */
11156   if (AOP_TYPE (result) == AOP_IMMD &&
11157       DCL_TYPE (ptype) == POINTER &&
11158       !IS_BITVAR (retype) &&
11159       !IS_BITVAR (letype))
11160     {
11161       genDataPointerSet (right, result, ic);
11162       return;
11163     }
11164
11165   /* if the value is already in a pointer register
11166      then don't need anything more */
11167   if (!AOP_INPREG (AOP (result)))
11168     {
11169       /* otherwise get a free pointer register */
11170       regs *preg;
11171
11172       aop = newAsmop (0);
11173       preg = getFreePtr (ic, &aop, FALSE);
11174       emitcode ("mov", "%s,%s",
11175                 preg->name,
11176                 aopGet (result, 0, FALSE, TRUE, NULL));
11177       rname = preg->name;
11178     }
11179   else
11180     {
11181       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11182     }
11183
11184   aopOp (right, ic, FALSE, FALSE);
11185
11186   /* if bitfield then unpack the bits */
11187   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11188     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11189   else
11190     {
11191       /* we can just get the values */
11192       int size = AOP_SIZE (right);
11193       int offset = 0;
11194
11195       while (size--)
11196         {
11197           l = aopGet (right, offset, FALSE, TRUE, NULL);
11198           if ((*l == '@') || (strcmp (l, "acc") == 0))
11199             {
11200               MOVA (l);
11201               emitcode ("mov", "@%s,a", rname);
11202             }
11203           else
11204             emitcode ("mov", "@%s,%s", rname, l);
11205           if (size || pi)
11206             emitcode ("inc", "%s", rname);
11207           offset++;
11208         }
11209     }
11210
11211   /* now some housekeeping stuff */
11212   if (aop)      /* we had to allocate for this iCode */
11213     {
11214       if (pi)
11215         aopPut (result, rname, 0);
11216       freeAsmop (NULL, aop, ic, TRUE);
11217     }
11218   else
11219     {
11220       /* we did not allocate which means left
11221          already in a pointer register, then
11222          if size > 0 && this could be used again
11223          we have to point it back to where it
11224          belongs */
11225       if (AOP_SIZE (right) > 1 &&
11226           !OP_SYMBOL (result)->remat &&
11227           (OP_SYMBOL (result)->liveTo > ic->seq ||
11228            ic->depth) &&
11229           !pi)
11230         {
11231           int size = AOP_SIZE (right) - 1;
11232           while (size--)
11233             emitcode ("dec", "%s", rname);
11234         }
11235     }
11236
11237   /* done */
11238   if (pi) pi->generated = 1;
11239   freeAsmop (result, NULL, ic, TRUE);
11240   freeAsmop (right, NULL, ic, TRUE);
11241 }
11242
11243 /*-----------------------------------------------------------------*/
11244 /* genPagedPointerSet - emitcode for Paged pointer put             */
11245 /*-----------------------------------------------------------------*/
11246 static void
11247 genPagedPointerSet (operand * right,
11248                     operand * result,
11249                     iCode * ic,
11250                     iCode *pi)
11251 {
11252   asmop *aop = NULL;
11253   char *rname, *l;
11254   sym_link *retype, *letype;
11255
11256   D (emitcode (";", "genPagedPointerSet"));
11257
11258   retype = getSpec (operandType (right));
11259   letype = getSpec (operandType (result));
11260
11261   aopOp (result, ic, FALSE, FALSE);
11262
11263   /* if the value is already in a pointer register
11264      then don't need anything more */
11265   if (!AOP_INPREG (AOP (result)))
11266     {
11267       /* otherwise get a free pointer register */
11268       regs *preg;
11269
11270       aop = newAsmop (0);
11271       preg = getFreePtr (ic, &aop, FALSE);
11272       emitcode ("mov", "%s,%s",
11273                 preg->name,
11274                 aopGet (result, 0, FALSE, TRUE, NULL));
11275       rname = preg->name;
11276     }
11277   else
11278     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11279
11280   aopOp (right, ic, FALSE, FALSE);
11281
11282   /* if bitfield then unpack the bits */
11283   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11284     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11285   else
11286     {
11287       /* we have can just get the values */
11288       int size = AOP_SIZE (right);
11289       int offset = 0;
11290
11291       while (size--)
11292         {
11293           l = aopGet (right, offset, FALSE, TRUE, NULL);
11294           MOVA (l);
11295           emitcode ("movx", "@%s,a", rname);
11296
11297           if (size || pi)
11298             emitcode ("inc", "%s", rname);
11299
11300           offset++;
11301         }
11302     }
11303
11304   /* now some housekeeping stuff */
11305   if (aop)
11306     {
11307       if (pi)
11308         aopPut (result, rname, 0);
11309       /* we had to allocate for this iCode */
11310       freeAsmop (NULL, aop, ic, TRUE);
11311     }
11312   else
11313     {
11314       /* we did not allocate which means left
11315          already in a pointer register, then
11316          if size > 0 && this could be used again
11317          we have to point it back to where it
11318          belongs */
11319       if (AOP_SIZE (right) > 1 &&
11320           !OP_SYMBOL (result)->remat &&
11321           (OP_SYMBOL (result)->liveTo > ic->seq ||
11322            ic->depth) &&
11323           !pi)
11324         {
11325           int size = AOP_SIZE (right) - 1;
11326           while (size--)
11327             emitcode ("dec", "%s", rname);
11328         }
11329     }
11330
11331   /* done */
11332   if (pi) pi->generated = 1;
11333   freeAsmop (result, NULL, ic, TRUE);
11334   freeAsmop (right, NULL, ic, TRUE);
11335 }
11336
11337 /*-----------------------------------------------------------------*/
11338 /* genFarPointerSet - set value from far space                     */
11339 /*-----------------------------------------------------------------*/
11340 static void
11341 genFarPointerSet (operand * right,
11342                   operand * result, iCode * ic, iCode *pi)
11343 {
11344   int size, offset, dopi=1;
11345   sym_link *retype = getSpec (operandType (right));
11346   sym_link *letype = getSpec (operandType (result));
11347
11348   aopOp (result, ic, FALSE, FALSE);
11349
11350   /* if the operand is already in dptr
11351      then we do nothing else we move the value to dptr */
11352   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11353     {
11354       /* if this is remateriazable */
11355       if (AOP_TYPE (result) == AOP_IMMD)
11356         emitcode ("mov", "dptr,%s",
11357                   aopGet (result, 0, TRUE, FALSE, NULL));
11358       else
11359         {
11360           /* we need to get it byte by byte */
11361           _startLazyDPSEvaluation ();
11362           if (AOP_TYPE (result) != AOP_DPTR)
11363             {
11364               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11365               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11366               if (options.model == MODEL_FLAT24)
11367                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11368             }
11369           else
11370             {
11371               /* We need to generate a load to DPTR indirect through DPTR. */
11372               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11373
11374               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11375               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11376               if (options.model == MODEL_FLAT24)
11377                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11378               emitcode ("pop", "dph");
11379               emitcode ("pop", "dpl");
11380               dopi=0;
11381             }
11382           _endLazyDPSEvaluation ();
11383         }
11384     }
11385   /* so dptr now contains the address */
11386   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11387
11388   /* if bit then unpack */
11389   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11390   {
11391       if (AOP_INDPTRn(result)) {
11392           genSetDPTR(AOP(result)->aopu.dptr);
11393       }
11394       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11395       if (AOP_INDPTRn(result)) {
11396           genSetDPTR(0);
11397       }
11398   } else {
11399       size = AOP_SIZE (right);
11400       offset = 0;
11401       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11402           while (size--) {
11403               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11404
11405               genSetDPTR(AOP(result)->aopu.dptr);
11406               emitcode ("movx", "@dptr,a");
11407               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11408                   emitcode ("inc", "dptr");
11409               genSetDPTR (0);
11410           }
11411       } else {
11412           _startLazyDPSEvaluation ();
11413           while (size--) {
11414               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11415
11416               if (AOP_INDPTRn(result)) {
11417                   genSetDPTR(AOP(result)->aopu.dptr);
11418               } else {
11419                   genSetDPTR (0);
11420               }
11421               _flushLazyDPS ();
11422
11423               emitcode ("movx", "@dptr,a");
11424               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11425                   emitcode ("inc", "dptr");
11426           }
11427           _endLazyDPSEvaluation ();
11428       }
11429   }
11430
11431   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11432       if (!AOP_INDPTRn(result)) {
11433           _startLazyDPSEvaluation ();
11434
11435           aopPut (result,"dpl",0);
11436           aopPut (result,"dph",1);
11437           if (options.model == MODEL_FLAT24)
11438               aopPut (result,"dpx",2);
11439
11440           _endLazyDPSEvaluation ();
11441       }
11442       pi->generated=1;
11443   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11444              AOP_SIZE(right) > 1 &&
11445              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11446
11447       size = AOP_SIZE (right) - 1;
11448       if (AOP_INDPTRn(result)) {
11449           genSetDPTR(AOP(result)->aopu.dptr);
11450       }
11451       while (size--) emitcode ("lcall","__decdptr");
11452       if (AOP_INDPTRn(result)) {
11453           genSetDPTR(0);
11454       }
11455   }
11456   freeAsmop (result, NULL, ic, TRUE);
11457   freeAsmop (right, NULL, ic, TRUE);
11458 }
11459
11460 /*-----------------------------------------------------------------*/
11461 /* genGenPointerSet - set value from generic pointer space         */
11462 /*-----------------------------------------------------------------*/
11463 static void
11464 genGenPointerSet (operand * right,
11465                   operand * result, iCode * ic, iCode *pi)
11466 {
11467   int size, offset;
11468   bool pushedB;
11469   sym_link *retype = getSpec (operandType (right));
11470   sym_link *letype = getSpec (operandType (result));
11471
11472   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11473
11474   pushedB = pushB ();
11475   /* if the operand is already in dptr
11476      then we do nothing else we move the value to dptr */
11477   if (AOP_TYPE (result) != AOP_STR)
11478     {
11479       _startLazyDPSEvaluation ();
11480       /* if this is remateriazable */
11481       if (AOP_TYPE (result) == AOP_IMMD)
11482         {
11483           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11484           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11485           {
11486               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11487           }
11488           else
11489           {
11490               emitcode ("mov",
11491                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11492           }
11493         }
11494       else
11495         {                       /* we need to get it byte by byte */
11496           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11497           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11498           if (options.model == MODEL_FLAT24) {
11499             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11500             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11501           } else {
11502             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11503           }
11504         }
11505       _endLazyDPSEvaluation ();
11506     }
11507   /* so dptr + b now contains the address */
11508   aopOp (right, ic, FALSE, TRUE);
11509
11510   /* if bit then unpack */
11511   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11512     {
11513         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11514     }
11515   else
11516     {
11517         size = AOP_SIZE (right);
11518         offset = 0;
11519
11520         _startLazyDPSEvaluation ();
11521         while (size--)
11522         {
11523             if (size)
11524             {
11525                 // Set two bytes at a time, passed in _AP & A.
11526                 // dptr will be incremented ONCE by __gptrputWord.
11527                 //
11528                 // Note: any change here must be coordinated
11529                 // with the implementation of __gptrputWord
11530                 // in device/lib/_gptrput.c
11531                 emitcode("mov", "_ap, %s",
11532                          aopGet (right, offset++, FALSE, FALSE, NULL));
11533                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11534
11535                 genSetDPTR (0);
11536                 _flushLazyDPS ();
11537                 emitcode ("lcall", "__gptrputWord");
11538                 size--;
11539             }
11540             else
11541             {
11542                 // Only one byte to put.
11543                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11544
11545                 genSetDPTR (0);
11546                 _flushLazyDPS ();
11547                 emitcode ("lcall", "__gptrput");
11548             }
11549
11550             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11551             {
11552                 emitcode ("inc", "dptr");
11553             }
11554         }
11555         _endLazyDPSEvaluation ();
11556     }
11557
11558   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11559       _startLazyDPSEvaluation ();
11560
11561       aopPut (result, "dpl",0);
11562       aopPut (result, "dph",1);
11563       if (options.model == MODEL_FLAT24) {
11564           aopPut (result, "dpx",2);
11565           aopPut (result, "b",3);
11566       } else {
11567           aopPut (result, "b",2);
11568       }
11569       _endLazyDPSEvaluation ();
11570
11571       pi->generated=1;
11572   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11573              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11574
11575       size = AOP_SIZE (right) - 1;
11576       while (size--) emitcode ("lcall","__decdptr");
11577   }
11578   popB (pushedB);
11579
11580   freeAsmop (result, NULL, ic, TRUE);
11581   freeAsmop (right, NULL, ic, TRUE);
11582 }
11583
11584 /*-----------------------------------------------------------------*/
11585 /* genPointerSet - stores the value into a pointer location        */
11586 /*-----------------------------------------------------------------*/
11587 static void
11588 genPointerSet (iCode * ic, iCode *pi)
11589 {
11590   operand *right, *result;
11591   sym_link *type, *etype;
11592   int p_type;
11593
11594   D (emitcode (";", "genPointerSet"));
11595
11596   right = IC_RIGHT (ic);
11597   result = IC_RESULT (ic);
11598
11599   /* depending on the type of pointer we need to
11600      move it to the correct pointer register */
11601   type = operandType (result);
11602   etype = getSpec (type);
11603   /* if left is of type of pointer then it is simple */
11604   if (IS_PTR (type) && !IS_FUNC (type->next))
11605     {
11606       p_type = DCL_TYPE (type);
11607     }
11608   else
11609     {
11610       /* we have to go by the storage class */
11611       p_type = PTR_TYPE (SPEC_OCLS (etype));
11612     }
11613
11614   /* special case when cast remat */
11615   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11616       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11617           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11618           type = operandType (result);
11619           p_type = DCL_TYPE (type);
11620   }
11621
11622   /* now that we have the pointer type we assign
11623      the pointer values */
11624   switch (p_type)
11625     {
11626
11627     case POINTER:
11628     case IPOINTER:
11629       genNearPointerSet (right, result, ic, pi);
11630       break;
11631
11632     case PPOINTER:
11633       genPagedPointerSet (right, result, ic, pi);
11634       break;
11635
11636     case FPOINTER:
11637       genFarPointerSet (right, result, ic, pi);
11638       break;
11639
11640     case GPOINTER:
11641       genGenPointerSet (right, result, ic, pi);
11642       break;
11643
11644     default:
11645       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11646               "genPointerSet: illegal pointer type");
11647     }
11648 }
11649
11650 /*-----------------------------------------------------------------*/
11651 /* genIfx - generate code for Ifx statement                        */
11652 /*-----------------------------------------------------------------*/
11653 static void
11654 genIfx (iCode * ic, iCode * popIc)
11655 {
11656   operand *cond = IC_COND (ic);
11657   int isbit = 0;
11658   char *dup = NULL;
11659
11660   D (emitcode (";", "genIfx"));
11661
11662   aopOp (cond, ic, FALSE, FALSE);
11663
11664   /* get the value into acc */
11665   if (AOP_TYPE (cond) != AOP_CRY)
11666     {
11667         toBoolean (cond);
11668     }
11669   else
11670     {
11671         isbit = 1;
11672       if (AOP(cond)->aopu.aop_dir)
11673         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11674     }
11675
11676   /* the result is now in the accumulator or a directly addressable bit */
11677   freeAsmop (cond, NULL, ic, TRUE);
11678
11679   /* if there was something to be popped then do it */
11680   if (popIc)
11681     genIpop (popIc);
11682
11683   /* if the condition is  a bit variable */
11684   if (isbit && dup)
11685     genIfxJump (ic, dup);
11686   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11687     genIfxJump (ic, SPIL_LOC (cond)->rname);
11688   else if (isbit && !IS_ITEMP (cond))
11689     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11690   else
11691     genIfxJump (ic, "a");
11692
11693   ic->generated = 1;
11694 }
11695
11696 /*-----------------------------------------------------------------*/
11697 /* genAddrOf - generates code for address of                       */
11698 /*-----------------------------------------------------------------*/
11699 static void
11700 genAddrOf (iCode * ic)
11701 {
11702   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11703   int size, offset;
11704
11705   D (emitcode (";", "genAddrOf"));
11706
11707   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11708
11709   /* if the operand is on the stack then we
11710      need to get the stack offset of this
11711      variable */
11712   if (sym->onStack)
11713   {
11714
11715       /* if 10 bit stack */
11716       if (options.stack10bit) {
11717           char buff[10];
11718           int  offset;
11719
11720           tsprintf(buff, sizeof(buff),
11721                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11722           /* if it has an offset then we need to compute it */
11723 /*        emitcode ("subb", "a,#!constbyte", */
11724 /*                  -((sym->stack < 0) ? */
11725 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11726 /*                    ((short) sym->stack)) & 0xff); */
11727 /*        emitcode ("mov","b,a"); */
11728 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11729 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11730 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11731           if (sym->stack) {
11732               emitcode ("mov", "a,_bpx");
11733               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11734                                              ((char) (sym->stack - _G.nRegsSaved)) :
11735                                              ((char) sym->stack )) & 0xff);
11736               emitcode ("mov", "b,a");
11737               emitcode ("mov", "a,_bpx+1");
11738
11739               offset = (((sym->stack < 0) ?
11740                          ((short) (sym->stack - _G.nRegsSaved)) :
11741                          ((short) sym->stack )) >> 8) & 0xff;
11742
11743               emitcode ("addc","a,#!constbyte", offset);
11744
11745               aopPut (IC_RESULT (ic), "b", 0);
11746               aopPut (IC_RESULT (ic), "a", 1);
11747               aopPut (IC_RESULT (ic), buff, 2);
11748           } else {
11749               /* we can just move _bp */
11750               aopPut (IC_RESULT (ic), "_bpx", 0);
11751               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11752               aopPut (IC_RESULT (ic), buff, 2);
11753           }
11754       } else {
11755           /* if it has an offset then we need to compute it */
11756           if (sym->stack)
11757             {
11758               emitcode ("mov", "a,_bp");
11759               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11760               aopPut (IC_RESULT (ic), "a", 0);
11761             }
11762           else
11763             {
11764               /* we can just move _bp */
11765               aopPut (IC_RESULT (ic), "_bp", 0);
11766             }
11767           /* fill the result with zero */
11768           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11769
11770
11771           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11772               fprintf (stderr,
11773                        "*** warning: pointer to stack var truncated.\n");
11774           }
11775
11776           offset = 1;
11777           while (size--)
11778             {
11779               aopPut (IC_RESULT (ic), zero, offset++);
11780           }
11781       }
11782       goto release;
11783   }
11784
11785   /* object not on stack then we need the name */
11786   size = AOP_SIZE (IC_RESULT (ic));
11787   offset = 0;
11788
11789   while (size--)
11790     {
11791       char s[SDCC_NAME_MAX];
11792       if (offset) {
11793           switch (offset) {
11794           case 1:
11795               tsprintf(s, sizeof(s), "#!his",sym->rname);
11796               break;
11797           case 2:
11798               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11799               break;
11800           case 3:
11801               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11802               break;
11803           default: /* should not need this (just in case) */
11804               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11805                        sym->rname,
11806                        offset * 8);
11807           }
11808       }
11809       else
11810       {
11811           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11812       }
11813
11814       aopPut (IC_RESULT (ic), s, offset++);
11815     }
11816
11817 release:
11818   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11819
11820 }
11821
11822 #if 0 // obsolete, and buggy for != xdata
11823 /*-----------------------------------------------------------------*/
11824 /* genArrayInit - generates code for address of                       */
11825 /*-----------------------------------------------------------------*/
11826 static void
11827 genArrayInit (iCode * ic)
11828 {
11829     literalList *iLoop;
11830     int         ix, count;
11831     int         elementSize = 0, eIndex;
11832     unsigned    val, lastVal;
11833     sym_link    *type;
11834     operand     *left=IC_LEFT(ic);
11835
11836     D (emitcode (";", "genArrayInit"));
11837
11838     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11839
11840     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11841     {
11842         // Load immediate value into DPTR.
11843         emitcode("mov", "dptr, %s",
11844              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11845     }
11846     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11847     {
11848 #if 0
11849       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11850               "Unexpected operand to genArrayInit.\n");
11851       exit(1);
11852 #else
11853       // a regression because of SDCCcse.c:1.52
11854       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11855       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11856       if (options.model == MODEL_FLAT24)
11857         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
11858 #endif
11859     }
11860
11861     type = operandType(IC_LEFT(ic));
11862
11863     if (type && type->next)
11864     {
11865         elementSize = getSize(type->next);
11866     }
11867     else
11868     {
11869         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11870                                 "can't determine element size in genArrayInit.\n");
11871         exit(1);
11872     }
11873
11874     iLoop = IC_ARRAYILIST(ic);
11875     lastVal = 0xffff;
11876
11877     while (iLoop)
11878     {
11879         bool firstpass = TRUE;
11880
11881         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
11882                  iLoop->count, (int)iLoop->literalValue, elementSize);
11883
11884         ix = iLoop->count;
11885
11886         while (ix)
11887         {
11888             symbol *tlbl = NULL;
11889
11890             count = ix > 256 ? 256 : ix;
11891
11892             if (count > 1)
11893             {
11894                 tlbl = newiTempLabel (NULL);
11895                 if (firstpass || (count & 0xff))
11896                 {
11897                     emitcode("mov", "b, #!constbyte", count & 0xff);
11898                 }
11899
11900                 emitLabel (tlbl);
11901             }
11902
11903             firstpass = FALSE;
11904
11905             for (eIndex = 0; eIndex < elementSize; eIndex++)
11906             {
11907                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
11908                 if (val != lastVal)
11909                 {
11910                     emitcode("mov", "a, #!constbyte", val);
11911                     lastVal = val;
11912                 }
11913
11914                 emitcode("movx", "@dptr, a");
11915                 emitcode("inc", "dptr");
11916             }
11917
11918             if (count > 1)
11919             {
11920                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
11921             }
11922
11923             ix -= count;
11924         }
11925
11926         iLoop = iLoop->next;
11927     }
11928
11929     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
11930 }
11931 #endif
11932
11933 /*-----------------------------------------------------------------*/
11934 /* genFarFarAssign - assignment when both are in far space         */
11935 /*-----------------------------------------------------------------*/
11936 static void
11937 genFarFarAssign (operand * result, operand * right, iCode * ic)
11938 {
11939   int size = AOP_SIZE (right);
11940   int offset = 0;
11941   symbol *rSym = NULL;
11942
11943   if (size == 1)
11944   {
11945       /* quick & easy case. */
11946       D (emitcode(";","genFarFarAssign (1 byte case)"));
11947       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11948       freeAsmop (right, NULL, ic, FALSE);
11949       /* now assign DPTR to result */
11950       _G.accInUse++;
11951       aopOp(result, ic, FALSE, FALSE);
11952       _G.accInUse--;
11953       aopPut (result, "a", 0);
11954       freeAsmop(result, NULL, ic, FALSE);
11955       return;
11956   }
11957
11958   /* See if we've got an underlying symbol to abuse. */
11959   if (IS_SYMOP(result) && OP_SYMBOL(result))
11960   {
11961       if (IS_TRUE_SYMOP(result))
11962       {
11963           rSym = OP_SYMBOL(result);
11964       }
11965       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
11966       {
11967           rSym = OP_SYMBOL(result)->usl.spillLoc;
11968       }
11969   }
11970
11971   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
11972   {
11973       /* We can use the '390 auto-toggle feature to good effect here. */
11974
11975       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
11976       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
11977       emitcode ("mov", "dptr,#%s", rSym->rname);
11978       /* DP2 = result, DP1 = right, DP1 is current. */
11979       while (size)
11980       {
11981           emitcode("movx", "a,@dptr");
11982           emitcode("movx", "@dptr,a");
11983           if (--size)
11984           {
11985                emitcode("inc", "dptr");
11986                emitcode("inc", "dptr");
11987           }
11988       }
11989       emitcode("mov", "dps,#0");
11990       freeAsmop (right, NULL, ic, FALSE);
11991 #if 0
11992 some alternative code for processors without auto-toggle
11993 no time to test now, so later well put in...kpb
11994         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
11995         emitcode("mov", "dps,#1");      /* Select DPTR2. */
11996         emitcode ("mov", "dptr,#%s", rSym->rname);
11997         /* DP2 = result, DP1 = right, DP1 is current. */
11998         while (size)
11999         {
12000           --size;
12001           emitcode("movx", "a,@dptr");
12002           if (size)
12003             emitcode("inc", "dptr");
12004           emitcode("inc", "dps");
12005           emitcode("movx", "@dptr,a");
12006           if (size)
12007             emitcode("inc", "dptr");
12008           emitcode("inc", "dps");
12009         }
12010         emitcode("mov", "dps,#0");
12011         freeAsmop (right, NULL, ic, FALSE);
12012 #endif
12013   }
12014   else
12015   {
12016       D (emitcode (";", "genFarFarAssign"));
12017       aopOp (result, ic, TRUE, TRUE);
12018
12019       _startLazyDPSEvaluation ();
12020
12021       while (size--)
12022         {
12023           aopPut (result,
12024                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12025           offset++;
12026         }
12027       _endLazyDPSEvaluation ();
12028       freeAsmop (result, NULL, ic, FALSE);
12029       freeAsmop (right, NULL, ic, FALSE);
12030   }
12031 }
12032
12033 /*-----------------------------------------------------------------*/
12034 /* genAssign - generate code for assignment                        */
12035 /*-----------------------------------------------------------------*/
12036 static void
12037 genAssign (iCode * ic)
12038 {
12039   operand *result, *right;
12040   int size, offset;
12041   unsigned long lit = 0L;
12042
12043   D (emitcode (";", "genAssign"));
12044
12045   result = IC_RESULT (ic);
12046   right = IC_RIGHT (ic);
12047
12048   /* if they are the same */
12049   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12050     return;
12051
12052   aopOp (right, ic, FALSE, FALSE);
12053
12054   emitcode (";", "genAssign: resultIsFar = %s",
12055             isOperandInFarSpace (result) ?
12056             "TRUE" : "FALSE");
12057
12058   /* special case both in far space */
12059   if ((AOP_TYPE (right) == AOP_DPTR ||
12060        AOP_TYPE (right) == AOP_DPTR2) &&
12061   /* IS_TRUE_SYMOP(result)       && */
12062       isOperandInFarSpace (result))
12063     {
12064       genFarFarAssign (result, right, ic);
12065       return;
12066     }
12067
12068   aopOp (result, ic, TRUE, FALSE);
12069
12070   /* if they are the same registers */
12071   if (sameRegs (AOP (right), AOP (result)))
12072     goto release;
12073
12074   /* if the result is a bit */
12075   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12076     {
12077       /* if the right size is a literal then
12078          we know what the value is */
12079       if (AOP_TYPE (right) == AOP_LIT)
12080         {
12081           if (((int) operandLitValue (right)))
12082             aopPut (result, one, 0);
12083           else
12084             aopPut (result, zero, 0);
12085           goto release;
12086         }
12087
12088       /* the right is also a bit variable */
12089       if (AOP_TYPE (right) == AOP_CRY)
12090         {
12091           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12092           aopPut (result, "c", 0);
12093           goto release;
12094         }
12095
12096       /* we need to or */
12097       toBoolean (right);
12098       aopPut (result, "a", 0);
12099       goto release;
12100     }
12101
12102   /* bit variables done */
12103   /* general case */
12104   size = AOP_SIZE (result);
12105   offset = 0;
12106   if (AOP_TYPE (right) == AOP_LIT)
12107     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12108
12109   if ((size > 1) &&
12110       (AOP_TYPE (result) != AOP_REG) &&
12111       (AOP_TYPE (right) == AOP_LIT) &&
12112       !IS_FLOAT (operandType (right)))
12113     {
12114       _startLazyDPSEvaluation ();
12115       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12116         {
12117           aopPut (result,
12118                   aopGet (right, offset, FALSE, FALSE, NULL),
12119                   offset);
12120           offset++;
12121           size--;
12122         }
12123       /* And now fill the rest with zeros. */
12124       if (size)
12125         {
12126           emitcode ("clr", "a");
12127         }
12128       while (size--)
12129         {
12130           aopPut (result, "a", offset++);
12131         }
12132       _endLazyDPSEvaluation ();
12133     }
12134   else
12135     {
12136       _startLazyDPSEvaluation ();
12137       while (size--)
12138         {
12139           aopPut (result,
12140                   aopGet (right, offset, FALSE, FALSE, NULL),
12141                   offset);
12142           offset++;
12143         }
12144       _endLazyDPSEvaluation ();
12145     }
12146
12147 release:
12148   freeAsmop (result, NULL, ic, TRUE);
12149   freeAsmop (right, NULL, ic, TRUE);
12150 }
12151
12152 /*-----------------------------------------------------------------*/
12153 /* genJumpTab - generates code for jump table                      */
12154 /*-----------------------------------------------------------------*/
12155 static void
12156 genJumpTab (iCode * ic)
12157 {
12158   symbol *jtab;
12159   char *l;
12160
12161   D (emitcode (";", "genJumpTab"));
12162
12163   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12164   /* get the condition into accumulator */
12165   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12166   MOVA (l);
12167   /* multiply by four! */
12168   emitcode ("add", "a,acc");
12169   emitcode ("add", "a,acc");
12170   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12171
12172   jtab = newiTempLabel (NULL);
12173   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12174   emitcode ("jmp", "@a+dptr");
12175   emitLabel (jtab);
12176   /* now generate the jump labels */
12177   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12178        jtab = setNextItem (IC_JTLABELS (ic)))
12179     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12180
12181 }
12182
12183 /*-----------------------------------------------------------------*/
12184 /* genCast - gen code for casting                                  */
12185 /*-----------------------------------------------------------------*/
12186 static void
12187 genCast (iCode * ic)
12188 {
12189   operand *result = IC_RESULT (ic);
12190   sym_link *ctype = operandType (IC_LEFT (ic));
12191   sym_link *rtype = operandType (IC_RIGHT (ic));
12192   operand *right = IC_RIGHT (ic);
12193   int size, offset;
12194
12195   D (emitcode (";", "genCast"));
12196
12197   /* if they are equivalent then do nothing */
12198   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12199     return;
12200
12201   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12202   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12203
12204   /* if the result is a bit (and not a bitfield) */
12205   if (IS_BIT (OP_SYMBOL (result)->type))
12206     {
12207       /* if the right size is a literal then
12208          we know what the value is */
12209       if (AOP_TYPE (right) == AOP_LIT)
12210         {
12211           if (((int) operandLitValue (right)))
12212             aopPut (result, one, 0);
12213           else
12214             aopPut (result, zero, 0);
12215
12216           goto release;
12217         }
12218
12219       /* the right is also a bit variable */
12220       if (AOP_TYPE (right) == AOP_CRY)
12221         {
12222           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12223           aopPut (result, "c", 0);
12224           goto release;
12225         }
12226
12227       /* we need to or */
12228       toBoolean (right);
12229       aopPut (result, "a", 0);
12230       goto release;
12231     }
12232
12233   /* if they are the same size : or less */
12234   if (AOP_SIZE (result) <= AOP_SIZE (right))
12235     {
12236
12237       /* if they are in the same place */
12238       if (sameRegs (AOP (right), AOP (result)))
12239         goto release;
12240
12241       /* if they in different places then copy */
12242       size = AOP_SIZE (result);
12243       offset = 0;
12244       _startLazyDPSEvaluation ();
12245       while (size--)
12246         {
12247           aopPut (result,
12248                   aopGet (right, offset, FALSE, FALSE, NULL),
12249                   offset);
12250           offset++;
12251         }
12252       _endLazyDPSEvaluation ();
12253       goto release;
12254     }
12255
12256   /* if the result is of type pointer */
12257   if (IS_PTR (ctype))
12258     {
12259
12260       int p_type;
12261       sym_link *type = operandType (right);
12262
12263       /* pointer to generic pointer */
12264       if (IS_GENPTR (ctype))
12265         {
12266           if (IS_PTR (type))
12267             {
12268               p_type = DCL_TYPE (type);
12269             }
12270           else
12271             {
12272 #if OLD_CAST_BEHAVIOR
12273               /* KV: we are converting a non-pointer type to
12274                * a generic pointer. This (ifdef'd out) code
12275                * says that the resulting generic pointer
12276                * should have the same class as the storage
12277                * location of the non-pointer variable.
12278                *
12279                * For example, converting an int (which happens
12280                * to be stored in DATA space) to a pointer results
12281                * in a DATA generic pointer; if the original int
12282                * in XDATA space, so will be the resulting pointer.
12283                *
12284                * I don't like that behavior, and thus this change:
12285                * all such conversions will be forced to XDATA and
12286                * throw a warning. If you want some non-XDATA
12287                * type, or you want to suppress the warning, you
12288                * must go through an intermediate cast, like so:
12289                *
12290                * char _generic *gp = (char _xdata *)(intVar);
12291                */
12292               sym_link *etype = getSpec (type);
12293
12294               /* we have to go by the storage class */
12295               if (SPEC_OCLS (etype) != generic)
12296                 {
12297                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12298                 }
12299               else
12300 #endif
12301                 {
12302                   /* Converting unknown class (i.e. register variable)
12303                    * to generic pointer. This is not good, but
12304                    * we'll make a guess (and throw a warning).
12305                    */
12306                   p_type = FPOINTER;
12307                   werror (W_INT_TO_GEN_PTR_CAST);
12308                 }
12309             }
12310
12311           /* the first two bytes are known */
12312           size = GPTRSIZE - 1;
12313           offset = 0;
12314           _startLazyDPSEvaluation ();
12315           while (size--)
12316             {
12317               aopPut (result,
12318                       aopGet (right, offset, FALSE, FALSE, NULL),
12319                       offset);
12320               offset++;
12321             }
12322           _endLazyDPSEvaluation ();
12323
12324           /* the last byte depending on type */
12325             {
12326                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12327                 char gpValStr[10];
12328
12329                 if (gpVal == -1)
12330                 {
12331                     // pointerTypeToGPByte will have bitched.
12332                     exit(1);
12333                 }
12334
12335                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12336                 aopPut (result, gpValStr, GPTRSIZE - 1);
12337             }
12338           goto release;
12339         }
12340
12341       /* just copy the pointers */
12342       size = AOP_SIZE (result);
12343       offset = 0;
12344       _startLazyDPSEvaluation ();
12345       while (size--)
12346         {
12347           aopPut (result,
12348                   aopGet (right, offset, FALSE, FALSE, NULL),
12349                   offset);
12350           offset++;
12351         }
12352       _endLazyDPSEvaluation ();
12353       goto release;
12354     }
12355
12356   /* so we now know that the size of destination is greater
12357      than the size of the source */
12358   /* we move to result for the size of source */
12359   size = AOP_SIZE (right);
12360   offset = 0;
12361   _startLazyDPSEvaluation ();
12362   while (size--)
12363     {
12364       aopPut (result,
12365               aopGet (right, offset, FALSE, FALSE, NULL),
12366               offset);
12367       offset++;
12368     }
12369   _endLazyDPSEvaluation ();
12370
12371   /* now depending on the sign of the source && destination */
12372   size = AOP_SIZE (result) - AOP_SIZE (right);
12373   /* if unsigned or not an integral type */
12374   /* also, if the source is a bit, we don't need to sign extend, because
12375    * it can't possibly have set the sign bit.
12376    */
12377   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12378     {
12379       while (size--)
12380         {
12381           aopPut (result, zero, offset++);
12382         }
12383     }
12384   else
12385     {
12386       /* we need to extend the sign :{ */
12387       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12388                         FALSE, FALSE, NULL));
12389       emitcode ("rlc", "a");
12390       emitcode ("subb", "a,acc");
12391       while (size--)
12392         aopPut (result, "a", offset++);
12393     }
12394
12395   /* we are done hurray !!!! */
12396
12397 release:
12398   freeAsmop (right, NULL, ic, TRUE);
12399   freeAsmop (result, NULL, ic, TRUE);
12400
12401 }
12402
12403 /*-----------------------------------------------------------------*/
12404 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12405 /*-----------------------------------------------------------------*/
12406 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12407 {
12408     operand *from , *to , *count;
12409     symbol *lbl;
12410     bitVect *rsave;
12411     int i;
12412
12413     /* we know it has to be 3 parameters */
12414     assert (nparms == 3);
12415
12416     rsave = newBitVect(16);
12417     /* save DPTR if it needs to be saved */
12418     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12419             if (bitVectBitValue(ic->rMask,i))
12420                     rsave = bitVectSetBit(rsave,i);
12421     }
12422     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12423                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12424     savermask(rsave);
12425
12426     to = parms[0];
12427     from = parms[1];
12428     count = parms[2];
12429
12430     aopOp (from, ic->next, FALSE, FALSE);
12431
12432     /* get from into DPTR1 */
12433     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12434     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12435     if (options.model == MODEL_FLAT24) {
12436         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12437     }
12438
12439     freeAsmop (from, NULL, ic, FALSE);
12440     aopOp (to, ic, FALSE, FALSE);
12441     /* get "to" into DPTR */
12442     /* if the operand is already in dptr
12443        then we do nothing else we move the value to dptr */
12444     if (AOP_TYPE (to) != AOP_STR) {
12445         /* if already in DPTR then we need to push */
12446         if (AOP_TYPE(to) == AOP_DPTR) {
12447             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12448             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12449             if (options.model == MODEL_FLAT24)
12450                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12451             emitcode ("pop", "dph");
12452             emitcode ("pop", "dpl");
12453         } else {
12454             _startLazyDPSEvaluation ();
12455             /* if this is remateriazable */
12456             if (AOP_TYPE (to) == AOP_IMMD) {
12457                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12458             } else {                    /* we need to get it byte by byte */
12459                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12460                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12461                 if (options.model == MODEL_FLAT24) {
12462                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12463                 }
12464             }
12465             _endLazyDPSEvaluation ();
12466         }
12467     }
12468     freeAsmop (to, NULL, ic, FALSE);
12469     _G.dptrInUse = _G.dptr1InUse = 1;
12470     aopOp (count, ic->next->next, FALSE,FALSE);
12471     lbl =newiTempLabel(NULL);
12472
12473     /* now for the actual copy */
12474     if (AOP_TYPE(count) == AOP_LIT &&
12475         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12476         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12477         if (fromc) {
12478             emitcode ("lcall","__bi_memcpyc2x_s");
12479         } else {
12480             emitcode ("lcall","__bi_memcpyx2x_s");
12481         }
12482         freeAsmop (count, NULL, ic, FALSE);
12483     } else {
12484         symbol *lbl1 = newiTempLabel(NULL);
12485
12486         emitcode (";"," Auto increment but no djnz");
12487         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12488         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12489         freeAsmop (count, NULL, ic, FALSE);
12490         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12491         emitcode ("","!tlabeldef",lbl->key+100);
12492         if (fromc) {
12493             emitcode ("clr","a");
12494             emitcode ("movc", "a,@a+dptr");
12495         } else
12496             emitcode ("movx", "a,@dptr");
12497         emitcode ("movx", "@dptr,a");
12498         emitcode ("inc", "dptr");
12499         emitcode ("inc", "dptr");
12500         emitcode ("mov","a,b");
12501         emitcode ("orl","a,_ap");
12502         emitcode ("jz","!tlabel",lbl1->key+100);
12503         emitcode ("mov","a,_ap");
12504         emitcode ("add","a,#!constbyte",0xFF);
12505         emitcode ("mov","_ap,a");
12506         emitcode ("mov","a,b");
12507         emitcode ("addc","a,#!constbyte",0xFF);
12508         emitcode ("mov","b,a");
12509         emitcode ("sjmp","!tlabel",lbl->key+100);
12510         emitcode ("","!tlabeldef",lbl1->key+100);
12511     }
12512     emitcode ("mov", "dps,#0");
12513     _G.dptrInUse = _G.dptr1InUse = 0;
12514     unsavermask(rsave);
12515
12516 }
12517
12518 /*-----------------------------------------------------------------*/
12519 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12520 /*-----------------------------------------------------------------*/
12521 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12522 {
12523     operand *from , *to , *count;
12524     symbol *lbl,*lbl2;
12525     bitVect *rsave;
12526     int i;
12527
12528     /* we know it has to be 3 parameters */
12529     assert (nparms == 3);
12530
12531     rsave = newBitVect(16);
12532     /* save DPTR if it needs to be saved */
12533     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12534             if (bitVectBitValue(ic->rMask,i))
12535                     rsave = bitVectSetBit(rsave,i);
12536     }
12537     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12538                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12539     savermask(rsave);
12540
12541     to = parms[0];
12542     from = parms[1];
12543     count = parms[2];
12544
12545     aopOp (from, ic->next, FALSE, FALSE);
12546
12547     /* get from into DPTR1 */
12548     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12549     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12550     if (options.model == MODEL_FLAT24) {
12551         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12552     }
12553
12554     freeAsmop (from, NULL, ic, FALSE);
12555     aopOp (to, ic, FALSE, FALSE);
12556     /* get "to" into DPTR */
12557     /* if the operand is already in dptr
12558        then we do nothing else we move the value to dptr */
12559     if (AOP_TYPE (to) != AOP_STR) {
12560         /* if already in DPTR then we need to push */
12561         if (AOP_TYPE(to) == AOP_DPTR) {
12562             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12563             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12564             if (options.model == MODEL_FLAT24)
12565                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12566             emitcode ("pop", "dph");
12567             emitcode ("pop", "dpl");
12568         } else {
12569             _startLazyDPSEvaluation ();
12570             /* if this is remateriazable */
12571             if (AOP_TYPE (to) == AOP_IMMD) {
12572                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12573             } else {                    /* we need to get it byte by byte */
12574                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12575                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12576                 if (options.model == MODEL_FLAT24) {
12577                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12578                 }
12579             }
12580             _endLazyDPSEvaluation ();
12581         }
12582     }
12583     freeAsmop (to, NULL, ic, FALSE);
12584     _G.dptrInUse = _G.dptr1InUse = 1;
12585     aopOp (count, ic->next->next, FALSE,FALSE);
12586     lbl =newiTempLabel(NULL);
12587     lbl2 =newiTempLabel(NULL);
12588
12589     /* now for the actual compare */
12590     if (AOP_TYPE(count) == AOP_LIT &&
12591         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12592         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12593         if (fromc)
12594             emitcode("lcall","__bi_memcmpc2x_s");
12595         else
12596             emitcode("lcall","__bi_memcmpx2x_s");
12597         freeAsmop (count, NULL, ic, FALSE);
12598         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12599         aopPut(IC_RESULT(ic),"a",0);
12600         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12601     } else {
12602         symbol *lbl1 = newiTempLabel(NULL);
12603
12604         emitcode("push","ar0");
12605         emitcode (";"," Auto increment but no djnz");
12606         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12607         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12608         freeAsmop (count, NULL, ic, FALSE);
12609         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12610         emitcode ("","!tlabeldef",lbl->key+100);
12611         if (fromc) {
12612             emitcode ("clr","a");
12613             emitcode ("movc", "a,@a+dptr");
12614         } else
12615             emitcode ("movx", "a,@dptr");
12616         emitcode ("mov","r0,a");
12617         emitcode ("movx", "a,@dptr");
12618         emitcode ("clr","c");
12619         emitcode ("subb","a,r0");
12620         emitcode ("jnz","!tlabel",lbl2->key+100);
12621         emitcode ("inc", "dptr");
12622         emitcode ("inc", "dptr");
12623         emitcode ("mov","a,b");
12624         emitcode ("orl","a,_ap");
12625         emitcode ("jz","!tlabel",lbl1->key+100);
12626         emitcode ("mov","a,_ap");
12627         emitcode ("add","a,#!constbyte",0xFF);
12628         emitcode ("mov","_ap,a");
12629         emitcode ("mov","a,b");
12630         emitcode ("addc","a,#!constbyte",0xFF);
12631         emitcode ("mov","b,a");
12632         emitcode ("sjmp","!tlabel",lbl->key+100);
12633         emitcode ("","!tlabeldef",lbl1->key+100);
12634         emitcode ("clr","a");
12635         emitcode ("","!tlabeldef",lbl2->key+100);
12636         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12637         aopPut(IC_RESULT(ic),"a",0);
12638         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12639         emitcode("pop","ar0");
12640         emitcode ("mov", "dps,#0");
12641     }
12642     _G.dptrInUse = _G.dptr1InUse = 0;
12643     unsavermask(rsave);
12644
12645 }
12646
12647 /*-----------------------------------------------------------------*/
12648 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12649 /* port, first parameter output area second parameter pointer to   */
12650 /* port third parameter count                                      */
12651 /*-----------------------------------------------------------------*/
12652 static void genInp( iCode *ic, int nparms, operand **parms)
12653 {
12654     operand *from , *to , *count;
12655     symbol *lbl;
12656     bitVect *rsave;
12657     int i;
12658
12659     /* we know it has to be 3 parameters */
12660     assert (nparms == 3);
12661
12662     rsave = newBitVect(16);
12663     /* save DPTR if it needs to be saved */
12664     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12665             if (bitVectBitValue(ic->rMask,i))
12666                     rsave = bitVectSetBit(rsave,i);
12667     }
12668     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12669                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12670     savermask(rsave);
12671
12672     to = parms[0];
12673     from = parms[1];
12674     count = parms[2];
12675
12676     aopOp (from, ic->next, FALSE, FALSE);
12677
12678     /* get from into DPTR1 */
12679     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12680     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12681     if (options.model == MODEL_FLAT24) {
12682         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12683     }
12684
12685     freeAsmop (from, NULL, ic, FALSE);
12686     aopOp (to, ic, FALSE, FALSE);
12687     /* get "to" into DPTR */
12688     /* if the operand is already in dptr
12689        then we do nothing else we move the value to dptr */
12690     if (AOP_TYPE (to) != AOP_STR) {
12691         /* if already in DPTR then we need to push */
12692         if (AOP_TYPE(to) == AOP_DPTR) {
12693             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12694             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12695             if (options.model == MODEL_FLAT24)
12696                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12697             emitcode ("pop", "dph");
12698             emitcode ("pop", "dpl");
12699         } else {
12700             _startLazyDPSEvaluation ();
12701             /* if this is remateriazable */
12702             if (AOP_TYPE (to) == AOP_IMMD) {
12703                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12704             } else {                    /* we need to get it byte by byte */
12705                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12706                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12707                 if (options.model == MODEL_FLAT24) {
12708                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12709                 }
12710             }
12711             _endLazyDPSEvaluation ();
12712         }
12713     }
12714     freeAsmop (to, NULL, ic, FALSE);
12715
12716     _G.dptrInUse = _G.dptr1InUse = 1;
12717     aopOp (count, ic->next->next, FALSE,FALSE);
12718     lbl =newiTempLabel(NULL);
12719
12720     /* now for the actual copy */
12721     if (AOP_TYPE(count) == AOP_LIT &&
12722         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12723         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12724         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12725         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12726         freeAsmop (count, NULL, ic, FALSE);
12727         emitcode ("","!tlabeldef",lbl->key+100);
12728         emitcode ("movx", "a,@dptr");   /* read data from port */
12729         emitcode ("dec","dps");         /* switch to DPTR */
12730         emitcode ("movx", "@dptr,a");   /* save into location */
12731         emitcode ("inc", "dptr");       /* point to next area */
12732         emitcode ("inc","dps");         /* switch to DPTR2 */
12733         emitcode ("djnz","b,!tlabel",lbl->key+100);
12734     } else {
12735         symbol *lbl1 = newiTempLabel(NULL);
12736
12737         emitcode (";"," Auto increment but no djnz");
12738         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12739         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12740         freeAsmop (count, NULL, ic, FALSE);
12741         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12742         emitcode ("","!tlabeldef",lbl->key+100);
12743         emitcode ("movx", "a,@dptr");
12744         emitcode ("dec","dps");         /* switch to DPTR */
12745         emitcode ("movx", "@dptr,a");
12746         emitcode ("inc", "dptr");
12747         emitcode ("inc","dps");         /* switch to DPTR2 */
12748 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12749 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12750         emitcode ("mov","a,b");
12751         emitcode ("orl","a,_ap");
12752         emitcode ("jz","!tlabel",lbl1->key+100);
12753         emitcode ("mov","a,_ap");
12754         emitcode ("add","a,#!constbyte",0xFF);
12755         emitcode ("mov","_ap,a");
12756         emitcode ("mov","a,b");
12757         emitcode ("addc","a,#!constbyte",0xFF);
12758         emitcode ("mov","b,a");
12759         emitcode ("sjmp","!tlabel",lbl->key+100);
12760         emitcode ("","!tlabeldef",lbl1->key+100);
12761     }
12762     emitcode ("mov", "dps,#0");
12763     _G.dptrInUse = _G.dptr1InUse = 0;
12764     unsavermask(rsave);
12765
12766 }
12767
12768 /*-----------------------------------------------------------------*/
12769 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12770 /* port, first parameter output area second parameter pointer to   */
12771 /* port third parameter count                                      */
12772 /*-----------------------------------------------------------------*/
12773 static void genOutp( iCode *ic, int nparms, operand **parms)
12774 {
12775     operand *from , *to , *count;
12776     symbol *lbl;
12777     bitVect *rsave;
12778     int i;
12779
12780     /* we know it has to be 3 parameters */
12781     assert (nparms == 3);
12782
12783     rsave = newBitVect(16);
12784     /* save DPTR if it needs to be saved */
12785     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12786             if (bitVectBitValue(ic->rMask,i))
12787                     rsave = bitVectSetBit(rsave,i);
12788     }
12789     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12790                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12791     savermask(rsave);
12792
12793     to = parms[0];
12794     from = parms[1];
12795     count = parms[2];
12796
12797     aopOp (from, ic->next, FALSE, FALSE);
12798
12799     /* get from into DPTR1 */
12800     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12801     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12802     if (options.model == MODEL_FLAT24) {
12803         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12804     }
12805
12806     freeAsmop (from, NULL, ic, FALSE);
12807     aopOp (to, ic, FALSE, FALSE);
12808     /* get "to" into DPTR */
12809     /* if the operand is already in dptr
12810        then we do nothing else we move the value to dptr */
12811     if (AOP_TYPE (to) != AOP_STR) {
12812         /* if already in DPTR then we need to push */
12813         if (AOP_TYPE(to) == AOP_DPTR) {
12814             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12815             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12816             if (options.model == MODEL_FLAT24)
12817                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12818             emitcode ("pop", "dph");
12819             emitcode ("pop", "dpl");
12820         } else {
12821             _startLazyDPSEvaluation ();
12822             /* if this is remateriazable */
12823             if (AOP_TYPE (to) == AOP_IMMD) {
12824                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12825             } else {                    /* we need to get it byte by byte */
12826                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12827                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12828                 if (options.model == MODEL_FLAT24) {
12829                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12830                 }
12831             }
12832             _endLazyDPSEvaluation ();
12833         }
12834     }
12835     freeAsmop (to, NULL, ic, FALSE);
12836
12837     _G.dptrInUse = _G.dptr1InUse = 1;
12838     aopOp (count, ic->next->next, FALSE,FALSE);
12839     lbl =newiTempLabel(NULL);
12840
12841     /* now for the actual copy */
12842     if (AOP_TYPE(count) == AOP_LIT &&
12843         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12844         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12845         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12846         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12847         emitcode ("","!tlabeldef",lbl->key+100);
12848         emitcode ("movx", "a,@dptr");   /* read data from port */
12849         emitcode ("inc","dps");         /* switch to DPTR2 */
12850         emitcode ("movx", "@dptr,a");   /* save into location */
12851         emitcode ("inc", "dptr");       /* point to next area */
12852         emitcode ("dec","dps");         /* switch to DPTR */
12853         emitcode ("djnz","b,!tlabel",lbl->key+100);
12854         freeAsmop (count, NULL, ic, FALSE);
12855     } else {
12856         symbol *lbl1 = newiTempLabel(NULL);
12857
12858         emitcode (";"," Auto increment but no djnz");
12859         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12860         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12861         freeAsmop (count, NULL, ic, FALSE);
12862         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12863         emitcode ("","!tlabeldef",lbl->key+100);
12864         emitcode ("movx", "a,@dptr");
12865         emitcode ("inc", "dptr");
12866         emitcode ("inc","dps");         /* switch to DPTR2 */
12867         emitcode ("movx", "@dptr,a");
12868         emitcode ("dec","dps");         /* switch to DPTR */
12869         emitcode ("mov","a,b");
12870         emitcode ("orl","a,_ap");
12871         emitcode ("jz","!tlabel",lbl1->key+100);
12872         emitcode ("mov","a,_ap");
12873         emitcode ("add","a,#!constbyte",0xFF);
12874         emitcode ("mov","_ap,a");
12875         emitcode ("mov","a,b");
12876         emitcode ("addc","a,#!constbyte",0xFF);
12877         emitcode ("mov","b,a");
12878         emitcode ("sjmp","!tlabel",lbl->key+100);
12879         emitcode ("","!tlabeldef",lbl1->key+100);
12880     }
12881     emitcode ("mov", "dps,#0");
12882     _G.dptrInUse = _G.dptr1InUse = 0;
12883     unsavermask(rsave);
12884
12885 }
12886
12887 /*-----------------------------------------------------------------*/
12888 /* genSwapW - swap lower & high order bytes                        */
12889 /*-----------------------------------------------------------------*/
12890 static void genSwapW(iCode *ic, int nparms, operand **parms)
12891 {
12892     operand *dest;
12893     operand *src;
12894     assert (nparms==1);
12895
12896     src = parms[0];
12897     dest=IC_RESULT(ic);
12898
12899     assert(getSize(operandType(src))==2);
12900
12901     aopOp (src, ic, FALSE, FALSE);
12902     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
12903     _G.accInUse++;
12904     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
12905     _G.accInUse--;
12906     freeAsmop (src, NULL, ic, FALSE);
12907
12908     aopOp (dest,ic, FALSE, FALSE);
12909     aopPut(dest,"b",0);
12910     aopPut(dest,"a",1);
12911     freeAsmop (dest, NULL, ic, FALSE);
12912 }
12913
12914 /*-----------------------------------------------------------------*/
12915 /* genMemsetX - gencode for memSetX data                           */
12916 /*-----------------------------------------------------------------*/
12917 static void genMemsetX(iCode *ic, int nparms, operand **parms)
12918 {
12919     operand *to , *val , *count;
12920     symbol *lbl;
12921     char *l;
12922     int i;
12923     bitVect *rsave;
12924
12925     /* we know it has to be 3 parameters */
12926     assert (nparms == 3);
12927
12928     to = parms[0];
12929     val = parms[1];
12930     count = parms[2];
12931
12932     /* save DPTR if it needs to be saved */
12933     rsave = newBitVect(16);
12934     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12935             if (bitVectBitValue(ic->rMask,i))
12936                     rsave = bitVectSetBit(rsave,i);
12937     }
12938     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12939                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12940     savermask(rsave);
12941
12942     aopOp (to, ic, FALSE, FALSE);
12943     /* get "to" into DPTR */
12944     /* if the operand is already in dptr
12945        then we do nothing else we move the value to dptr */
12946     if (AOP_TYPE (to) != AOP_STR) {
12947         /* if already in DPTR then we need to push */
12948         if (AOP_TYPE(to) == AOP_DPTR) {
12949             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12950             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12951             if (options.model == MODEL_FLAT24)
12952                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12953             emitcode ("pop", "dph");
12954             emitcode ("pop", "dpl");
12955         } else {
12956             _startLazyDPSEvaluation ();
12957             /* if this is remateriazable */
12958             if (AOP_TYPE (to) == AOP_IMMD) {
12959                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12960             } else {                    /* we need to get it byte by byte */
12961                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12962                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12963                 if (options.model == MODEL_FLAT24) {
12964                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12965                 }
12966             }
12967             _endLazyDPSEvaluation ();
12968         }
12969     }
12970     freeAsmop (to, NULL, ic, FALSE);
12971
12972     aopOp (val, ic->next->next, FALSE,FALSE);
12973     aopOp (count, ic->next->next, FALSE,FALSE);
12974     lbl =newiTempLabel(NULL);
12975     /* now for the actual copy */
12976     if (AOP_TYPE(count) == AOP_LIT &&
12977         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12978         l = aopGet(val, 0, FALSE, FALSE, NULL);
12979         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12980         MOVA(l);
12981         emitcode ("","!tlabeldef",lbl->key+100);
12982         emitcode ("movx", "@dptr,a");
12983         emitcode ("inc", "dptr");
12984         emitcode ("djnz","b,!tlabel",lbl->key+100);
12985     } else {
12986         symbol *lbl1 = newiTempLabel(NULL);
12987
12988         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12989         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12990         emitcode ("","!tlabeldef",lbl->key+100);
12991         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
12992         emitcode ("movx", "@dptr,a");
12993         emitcode ("inc", "dptr");
12994         emitcode ("mov","a,b");
12995         emitcode ("orl","a,_ap");
12996         emitcode ("jz","!tlabel",lbl1->key+100);
12997         emitcode ("mov","a,_ap");
12998         emitcode ("add","a,#!constbyte",0xFF);
12999         emitcode ("mov","_ap,a");
13000         emitcode ("mov","a,b");
13001         emitcode ("addc","a,#!constbyte",0xFF);
13002         emitcode ("mov","b,a");
13003         emitcode ("sjmp","!tlabel",lbl->key+100);
13004         emitcode ("","!tlabeldef",lbl1->key+100);
13005     }
13006     freeAsmop (count, NULL, ic, FALSE);
13007     unsavermask(rsave);
13008 }
13009
13010 /*-----------------------------------------------------------------*/
13011 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13012 /*-----------------------------------------------------------------*/
13013 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13014 {
13015         bitVect *rsave ;
13016         operand *pnum, *result;
13017         int i;
13018
13019         assert (nparms==1);
13020         /* save registers that need to be saved */
13021         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13022                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13023
13024         pnum = parms[0];
13025         aopOp (pnum, ic, FALSE, FALSE);
13026         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13027         freeAsmop (pnum, NULL, ic, FALSE);
13028         emitcode ("lcall","NatLib_LoadPrimitive");
13029         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13030         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13031             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13032                 for (i = (size-1) ; i >= 0 ; i-- ) {
13033                         emitcode ("push","a%s",javaRet[i]);
13034                 }
13035                 for (i=0; i < size ; i++ ) {
13036                         emitcode ("pop","a%s",
13037                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13038                 }
13039         } else {
13040                 for (i = 0 ; i < size ; i++ ) {
13041                         aopPut(result,javaRet[i],i);
13042                 }
13043         }
13044         freeAsmop (result, NULL, ic, FALSE);
13045         unsavermask(rsave);
13046 }
13047
13048 /*-----------------------------------------------------------------*/
13049 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13050 /*-----------------------------------------------------------------*/
13051 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13052 {
13053         bitVect *rsave ;
13054         operand *pnum, *result;
13055         int size = 3;
13056         int i;
13057
13058         assert (nparms==1);
13059         /* save registers that need to be saved */
13060         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13061                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13062
13063         pnum = parms[0];
13064         aopOp (pnum, ic, FALSE, FALSE);
13065         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13066         freeAsmop (pnum, NULL, ic, FALSE);
13067         emitcode ("lcall","NatLib_LoadPointer");
13068         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13069         if (AOP_TYPE(result)!=AOP_STR) {
13070                 for (i = 0 ; i < size ; i++ ) {
13071                         aopPut(result,fReturn[i],i);
13072                 }
13073         }
13074         freeAsmop (result, NULL, ic, FALSE);
13075         unsavermask(rsave);
13076 }
13077
13078 /*-----------------------------------------------------------------*/
13079 /* genNatLibInstallStateBlock -                                    */
13080 /*-----------------------------------------------------------------*/
13081 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13082                                        operand **parms, const char *name)
13083 {
13084         bitVect *rsave ;
13085         operand *psb, *handle;
13086         assert (nparms==2);
13087
13088         /* save registers that need to be saved */
13089         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13090                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13091         psb = parms[0];
13092         handle = parms[1];
13093
13094         /* put pointer to state block into DPTR1 */
13095         aopOp (psb, ic, FALSE, FALSE);
13096         if (AOP_TYPE (psb) == AOP_IMMD) {
13097                 emitcode ("mov","dps,#1");
13098                 emitcode ("mov", "dptr,%s",
13099                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13100                 emitcode ("mov","dps,#0");
13101         } else {
13102                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13103                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13104                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13105         }
13106         freeAsmop (psb, NULL, ic, FALSE);
13107
13108         /* put libraryID into DPTR */
13109         emitcode ("mov","dptr,#LibraryID");
13110
13111         /* put handle into r3:r2 */
13112         aopOp (handle, ic, FALSE, FALSE);
13113         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13114                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13115                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13116                 emitcode ("pop","ar3");
13117                 emitcode ("pop","ar2");
13118         } else {
13119                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13120                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13121         }
13122         freeAsmop (psb, NULL, ic, FALSE);
13123
13124         /* make the call */
13125         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13126
13127         /* put return value into place*/
13128         _G.accInUse++;
13129         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13130         _G.accInUse--;
13131         aopPut(IC_RESULT(ic),"a",0);
13132         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13133         unsavermask(rsave);
13134 }
13135
13136 /*-----------------------------------------------------------------*/
13137 /* genNatLibRemoveStateBlock -                                     */
13138 /*-----------------------------------------------------------------*/
13139 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13140 {
13141         bitVect *rsave ;
13142
13143         assert(nparms==0);
13144
13145         /* save registers that need to be saved */
13146         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13147                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13148
13149         /* put libraryID into DPTR */
13150         emitcode ("mov","dptr,#LibraryID");
13151         /* make the call */
13152         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13153         unsavermask(rsave);
13154 }
13155
13156 /*-----------------------------------------------------------------*/
13157 /* genNatLibGetStateBlock -                                        */
13158 /*-----------------------------------------------------------------*/
13159 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13160                                    operand **parms,const char *name)
13161 {
13162         bitVect *rsave ;
13163         symbol *lbl = newiTempLabel(NULL);
13164
13165         assert(nparms==0);
13166         /* save registers that need to be saved */
13167         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13168                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13169
13170         /* put libraryID into DPTR */
13171         emitcode ("mov","dptr,#LibraryID");
13172         /* make the call */
13173         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13174         emitcode ("jnz","!tlabel",lbl->key+100);
13175
13176         /* put return value into place */
13177         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13178         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13179                 emitcode ("push","ar3");
13180                 emitcode ("push","ar2");
13181                 emitcode ("pop","%s",
13182                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13183                 emitcode ("pop","%s",
13184                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13185         } else {
13186                 aopPut(IC_RESULT(ic),"r2",0);
13187                 aopPut(IC_RESULT(ic),"r3",1);
13188         }
13189         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13190         emitcode ("","!tlabeldef",lbl->key+100);
13191         unsavermask(rsave);
13192 }
13193
13194 /*-----------------------------------------------------------------*/
13195 /* genMMMalloc -                                                   */
13196 /*-----------------------------------------------------------------*/
13197 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13198                          int size, const char *name)
13199 {
13200         bitVect *rsave ;
13201         operand *bsize;
13202         symbol *rsym;
13203         symbol *lbl = newiTempLabel(NULL);
13204
13205         assert (nparms == 1);
13206         /* save registers that need to be saved */
13207         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13208                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13209
13210         bsize=parms[0];
13211         aopOp (bsize,ic,FALSE,FALSE);
13212
13213         /* put the size in R4-R2 */
13214         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13215                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13216                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13217                 if (size==3) {
13218                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13219                         emitcode("pop","ar4");
13220                 }
13221                 emitcode("pop","ar3");
13222                 emitcode("pop","ar2");
13223         } else {
13224                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13225                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13226                 if (size==3) {
13227                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13228                 }
13229         }
13230         freeAsmop (bsize, NULL, ic, FALSE);
13231
13232         /* make the call */
13233         emitcode ("lcall","MM_%s",name);
13234         emitcode ("jz","!tlabel",lbl->key+100);
13235         emitcode ("mov","r2,#!constbyte",0xff);
13236         emitcode ("mov","r3,#!constbyte",0xff);
13237         emitcode ("","!tlabeldef",lbl->key+100);
13238         /* we don't care about the pointer : we just save the handle */
13239         rsym = OP_SYMBOL(IC_RESULT(ic));
13240         if (rsym->liveFrom != rsym->liveTo) {
13241                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13242                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13243                         emitcode ("push","ar3");
13244                         emitcode ("push","ar2");
13245                         emitcode ("pop","%s",
13246                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13247                         emitcode ("pop","%s",
13248                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13249                 } else {
13250                         aopPut(IC_RESULT(ic),"r2",0);
13251                         aopPut(IC_RESULT(ic),"r3",1);
13252                 }
13253                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13254         }
13255         unsavermask(rsave);
13256 }
13257
13258 /*-----------------------------------------------------------------*/
13259 /* genMMDeref -                                                    */
13260 /*-----------------------------------------------------------------*/
13261 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13262 {
13263         bitVect *rsave ;
13264         operand *handle;
13265
13266         assert (nparms == 1);
13267         /* save registers that need to be saved */
13268         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13269                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13270
13271         handle=parms[0];
13272         aopOp (handle,ic,FALSE,FALSE);
13273
13274         /* put the size in R4-R2 */
13275         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13276                 emitcode("push","%s",
13277                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13278                 emitcode("push","%s",
13279                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13280                 emitcode("pop","ar3");
13281                 emitcode("pop","ar2");
13282         } else {
13283                 emitcode ("mov","r2,%s",
13284                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13285                 emitcode ("mov","r3,%s",
13286                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13287         }
13288         freeAsmop (handle, NULL, ic, FALSE);
13289
13290         /* make the call */
13291         emitcode ("lcall","MM_Deref");
13292
13293         {
13294                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13295                 if (rsym->liveFrom != rsym->liveTo) {
13296                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13297                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13298                             _startLazyDPSEvaluation ();
13299
13300                                 aopPut(IC_RESULT(ic),"dpl",0);
13301                                 aopPut(IC_RESULT(ic),"dph",1);
13302                                 aopPut(IC_RESULT(ic),"dpx",2);
13303
13304                             _endLazyDPSEvaluation ();
13305
13306                         }
13307                 }
13308         }
13309         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13310         unsavermask(rsave);
13311 }
13312
13313 /*-----------------------------------------------------------------*/
13314 /* genMMUnrestrictedPersist -                                      */
13315 /*-----------------------------------------------------------------*/
13316 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13317 {
13318         bitVect *rsave ;
13319         operand *handle;
13320
13321         assert (nparms == 1);
13322         /* save registers that need to be saved */
13323         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13324                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13325
13326         handle=parms[0];
13327         aopOp (handle,ic,FALSE,FALSE);
13328
13329         /* put the size in R3-R2 */
13330         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13331                 emitcode("push","%s",
13332                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13333                 emitcode("push","%s",
13334                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13335                 emitcode("pop","ar3");
13336                 emitcode("pop","ar2");
13337         } else {
13338                 emitcode ("mov","r2,%s",
13339                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13340                 emitcode ("mov","r3,%s",
13341                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13342         }
13343         freeAsmop (handle, NULL, ic, FALSE);
13344
13345         /* make the call */
13346         emitcode ("lcall","MM_UnrestrictedPersist");
13347
13348         {
13349                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13350                 if (rsym->liveFrom != rsym->liveTo) {
13351                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13352                         aopPut(IC_RESULT(ic),"a",0);
13353                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13354                 }
13355         }
13356         unsavermask(rsave);
13357 }
13358
13359 /*-----------------------------------------------------------------*/
13360 /* genSystemExecJavaProcess -                                      */
13361 /*-----------------------------------------------------------------*/
13362 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13363 {
13364         bitVect *rsave ;
13365         operand *handle, *pp;
13366
13367         assert (nparms==2);
13368         /* save registers that need to be saved */
13369         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13370                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13371
13372         pp = parms[0];
13373         handle = parms[1];
13374
13375         /* put the handle in R3-R2 */
13376         aopOp (handle,ic,FALSE,FALSE);
13377         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13378                 emitcode("push","%s",
13379                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13380                 emitcode("push","%s",
13381                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13382                 emitcode("pop","ar3");
13383                 emitcode("pop","ar2");
13384         } else {
13385                 emitcode ("mov","r2,%s",
13386                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13387                 emitcode ("mov","r3,%s",
13388                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13389         }
13390         freeAsmop (handle, NULL, ic, FALSE);
13391
13392         /* put pointer in DPTR */
13393         aopOp (pp,ic,FALSE,FALSE);
13394         if (AOP_TYPE(pp) == AOP_IMMD) {
13395                 emitcode ("mov", "dptr,%s",
13396                           aopGet (pp, 0, TRUE, FALSE, NULL));
13397         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13398                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13399                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13400                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13401         }
13402         freeAsmop (handle, NULL, ic, FALSE);
13403
13404         /* make the call */
13405         emitcode ("lcall","System_ExecJavaProcess");
13406
13407         /* put result in place */
13408         {
13409                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13410                 if (rsym->liveFrom != rsym->liveTo) {
13411                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13412                         aopPut(IC_RESULT(ic),"a",0);
13413                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13414                 }
13415         }
13416
13417         unsavermask(rsave);
13418 }
13419
13420 /*-----------------------------------------------------------------*/
13421 /* genSystemRTCRegisters -                                         */
13422 /*-----------------------------------------------------------------*/
13423 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13424                                   char *name)
13425 {
13426         bitVect *rsave ;
13427         operand *pp;
13428
13429         assert (nparms==1);
13430         /* save registers that need to be saved */
13431         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13432                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13433
13434         pp=parms[0];
13435         /* put pointer in DPTR */
13436         aopOp (pp,ic,FALSE,FALSE);
13437         if (AOP_TYPE (pp) == AOP_IMMD) {
13438                 emitcode ("mov","dps,#1");
13439                 emitcode ("mov", "dptr,%s",
13440                           aopGet (pp, 0, TRUE, FALSE, NULL));
13441                 emitcode ("mov","dps,#0");
13442         } else {
13443                 emitcode ("mov","dpl1,%s",
13444                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13445                 emitcode ("mov","dph1,%s",
13446                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13447                 emitcode ("mov","dpx1,%s",
13448                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13449         }
13450         freeAsmop (pp, NULL, ic, FALSE);
13451
13452         /* make the call */
13453         emitcode ("lcall","System_%sRTCRegisters",name);
13454
13455         unsavermask(rsave);
13456 }
13457
13458 /*-----------------------------------------------------------------*/
13459 /* genSystemThreadSleep -                                          */
13460 /*-----------------------------------------------------------------*/
13461 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13462 {
13463         bitVect *rsave ;
13464         operand *to, *s;
13465
13466         assert (nparms==1);
13467         /* save registers that need to be saved */
13468         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13469                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13470
13471         to = parms[0];
13472         aopOp(to,ic,FALSE,FALSE);
13473         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13474             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13475                 emitcode ("push","%s",
13476                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13477                 emitcode ("push","%s",
13478                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13479                 emitcode ("push","%s",
13480                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13481                 emitcode ("push","%s",
13482                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13483                 emitcode ("pop","ar3");
13484                 emitcode ("pop","ar2");
13485                 emitcode ("pop","ar1");
13486                 emitcode ("pop","ar0");
13487         } else {
13488                 emitcode ("mov","r0,%s",
13489                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13490                 emitcode ("mov","r1,%s",
13491                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13492                 emitcode ("mov","r2,%s",
13493                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13494                 emitcode ("mov","r3,%s",
13495                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13496         }
13497         freeAsmop (to, NULL, ic, FALSE);
13498
13499         /* suspend in acc */
13500         s = parms[1];
13501         aopOp(s,ic,FALSE,FALSE);
13502         emitcode ("mov","a,%s",
13503                   aopGet(s,0,FALSE,TRUE,NULL));
13504         freeAsmop (s, NULL, ic, FALSE);
13505
13506         /* make the call */
13507         emitcode ("lcall","System_%s",name);
13508
13509         unsavermask(rsave);
13510 }
13511
13512 /*-----------------------------------------------------------------*/
13513 /* genSystemThreadResume -                                         */
13514 /*-----------------------------------------------------------------*/
13515 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13516 {
13517         bitVect *rsave ;
13518         operand *tid,*pid;
13519
13520         assert (nparms==2);
13521         /* save registers that need to be saved */
13522         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13523                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13524
13525         tid = parms[0];
13526         pid = parms[1];
13527
13528         /* PID in R0 */
13529         aopOp(pid,ic,FALSE,FALSE);
13530         emitcode ("mov","r0,%s",
13531                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13532         freeAsmop (pid, NULL, ic, FALSE);
13533
13534         /* tid into ACC */
13535         aopOp(tid,ic,FALSE,FALSE);
13536         emitcode ("mov","a,%s",
13537                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13538         freeAsmop (tid, NULL, ic, FALSE);
13539
13540         emitcode ("lcall","System_ThreadResume");
13541
13542         /* put result into place */
13543         {
13544                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13545                 if (rsym->liveFrom != rsym->liveTo) {
13546                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13547                         aopPut(IC_RESULT(ic),"a",0);
13548                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13549                 }
13550         }
13551         unsavermask(rsave);
13552 }
13553
13554 /*-----------------------------------------------------------------*/
13555 /* genSystemProcessResume -                                        */
13556 /*-----------------------------------------------------------------*/
13557 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13558 {
13559         bitVect *rsave ;
13560         operand *pid;
13561
13562         assert (nparms==1);
13563         /* save registers that need to be saved */
13564         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13565                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13566
13567         pid = parms[0];
13568
13569         /* pid into ACC */
13570         aopOp(pid,ic,FALSE,FALSE);
13571         emitcode ("mov","a,%s",
13572                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13573         freeAsmop (pid, NULL, ic, FALSE);
13574
13575         emitcode ("lcall","System_ProcessResume");
13576
13577         unsavermask(rsave);
13578 }
13579
13580 /*-----------------------------------------------------------------*/
13581 /* genSystem -                                                     */
13582 /*-----------------------------------------------------------------*/
13583 static void genSystem (iCode *ic,int nparms,char *name)
13584 {
13585         assert(nparms == 0);
13586
13587         emitcode ("lcall","System_%s",name);
13588 }
13589
13590 /*-----------------------------------------------------------------*/
13591 /* genSystemPoll -                                                  */
13592 /*-----------------------------------------------------------------*/
13593 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13594 {
13595         bitVect *rsave ;
13596         operand *fp;
13597
13598         assert (nparms==1);
13599         /* save registers that need to be saved */
13600         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13601                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13602
13603         fp = parms[0];
13604         aopOp (fp,ic,FALSE,FALSE);
13605         if (AOP_TYPE (fp) == AOP_IMMD) {
13606                 emitcode ("mov", "dptr,%s",
13607                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13608         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13609                 emitcode ("mov","dpl,%s",
13610                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13611                 emitcode ("mov","dph,%s",
13612                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13613                 emitcode ("mov","dpx,%s",
13614                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13615         }
13616         freeAsmop (fp, NULL, ic, FALSE);
13617
13618         emitcode ("lcall","System_%sPoll",name);
13619
13620         /* put result into place */
13621         {
13622                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13623                 if (rsym->liveFrom != rsym->liveTo) {
13624                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13625                         aopPut(IC_RESULT(ic),"a",0);
13626                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13627                 }
13628         }
13629         unsavermask(rsave);
13630 }
13631
13632 /*-----------------------------------------------------------------*/
13633 /* genSystemGetCurrentID -                                         */
13634 /*-----------------------------------------------------------------*/
13635 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13636 {
13637         assert (nparms==0);
13638
13639         emitcode ("lcall","System_GetCurrent%sId",name);
13640         /* put result into place */
13641         {
13642                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13643                 if (rsym->liveFrom != rsym->liveTo) {
13644                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13645                         aopPut(IC_RESULT(ic),"a",0);
13646                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13647                 }
13648         }
13649 }
13650
13651 /*-----------------------------------------------------------------*/
13652 /* genDjnz - generate decrement & jump if not zero instrucion      */
13653 /*-----------------------------------------------------------------*/
13654 static int
13655 genDjnz (iCode * ic, iCode * ifx)
13656 {
13657   symbol *lbl, *lbl1;
13658   if (!ifx)
13659     return 0;
13660
13661   /* if the if condition has a false label
13662      then we cannot save */
13663   if (IC_FALSE (ifx))
13664     return 0;
13665
13666   /* if the minus is not of the form a = a - 1 */
13667   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13668       !IS_OP_LITERAL (IC_RIGHT (ic)))
13669     return 0;
13670
13671   if (operandLitValue (IC_RIGHT (ic)) != 1)
13672     return 0;
13673
13674   /* if the size of this greater than one then no
13675      saving */
13676   if (getSize (operandType (IC_RESULT (ic))) > 1)
13677     return 0;
13678
13679   /* otherwise we can save BIG */
13680
13681   D (emitcode (";", "genDjnz"));
13682
13683   lbl = newiTempLabel (NULL);
13684   lbl1 = newiTempLabel (NULL);
13685
13686   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13687
13688   if (AOP_NEEDSACC(IC_RESULT(ic)))
13689   {
13690       /* If the result is accessed indirectly via
13691        * the accumulator, we must explicitly write
13692        * it back after the decrement.
13693        */
13694       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13695
13696       if (strcmp(rByte, "a"))
13697       {
13698            /* Something is hopelessly wrong */
13699            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13700                    __FILE__, __LINE__);
13701            /* We can just give up; the generated code will be inefficient,
13702             * but what the hey.
13703             */
13704            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13705            return 0;
13706       }
13707       emitcode ("dec", "%s", rByte);
13708       aopPut (IC_RESULT (ic), rByte, 0);
13709       emitcode ("jnz", "!tlabel", lbl->key + 100);
13710   }
13711   else if (IS_AOP_PREG (IC_RESULT (ic)))
13712     {
13713       emitcode ("dec", "%s",
13714                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13715       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13716       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13717       ifx->generated = 1;
13718       emitcode ("jnz", "!tlabel", lbl->key + 100);
13719     }
13720   else
13721     {
13722       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13723                 lbl->key + 100);
13724     }
13725   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13726   emitLabel (lbl);
13727   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13728   emitLabel (lbl1);
13729
13730   if (!ifx->generated)
13731       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13732   ifx->generated = 1;
13733   return 1;
13734 }
13735
13736 /*-----------------------------------------------------------------*/
13737 /* genReceive - generate code for a receive iCode                  */
13738 /*-----------------------------------------------------------------*/
13739 static void
13740 genReceive (iCode * ic)
13741 {
13742     int size = getSize (operandType (IC_RESULT (ic)));
13743     int offset = 0;
13744     int rb1off ;
13745
13746     D (emitcode (";", "genReceive"));
13747
13748     if (ic->argreg == 1)
13749     {
13750         /* first parameter */
13751         if (AOP_IS_STR(IC_RESULT(ic)))
13752         {
13753             /* Nothing to do: it's already in the proper place. */
13754             return;
13755         }
13756         else
13757         {
13758             bool useDp2;
13759
13760             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13761                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13762                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13763
13764             _G.accInUse++;
13765             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13766             _G.accInUse--;
13767
13768             /* Sanity checking... */
13769             if (AOP_USESDPTR(IC_RESULT(ic)))
13770             {
13771                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13772                         "genReceive got unexpected DPTR.");
13773             }
13774             assignResultValue (IC_RESULT (ic), NULL);
13775         }
13776     }
13777     else if (ic->argreg > 12)
13778     { /* bit parameters */
13779       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13780         {
13781           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13782           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13783           outBitC(IC_RESULT (ic));
13784         }
13785     }
13786     else
13787     {
13788         /* second receive onwards */
13789         /* this gets a little tricky since unused receives will be
13790          eliminated, we have saved the reg in the type field . and
13791          we use that to figure out which register to use */
13792         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13793         rb1off = ic->argreg;
13794         while (size--)
13795         {
13796             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13797         }
13798     }
13799     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13800 }
13801
13802 /*-----------------------------------------------------------------*/
13803 /* genDummyRead - generate code for dummy read of volatiles        */
13804 /*-----------------------------------------------------------------*/
13805 static void
13806 genDummyRead (iCode * ic)
13807 {
13808   operand *op;
13809   int size, offset;
13810
13811   D (emitcode(";", "genDummyRead"));
13812
13813   op = IC_RIGHT (ic);
13814   if (op && IS_SYMOP (op))
13815     {
13816       aopOp (op, ic, FALSE, FALSE);
13817
13818       /* if the result is a bit */
13819       if (AOP_TYPE (op) == AOP_CRY)
13820         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13821       else
13822         {
13823           /* bit variables done */
13824           /* general case */
13825           size = AOP_SIZE (op);
13826           offset = 0;
13827           while (size--)
13828           {
13829             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13830             offset++;
13831           }
13832         }
13833
13834       freeAsmop (op, NULL, ic, TRUE);
13835     }
13836
13837   op = IC_LEFT (ic);
13838   if (op && IS_SYMOP (op))
13839     {
13840       aopOp (op, ic, FALSE, FALSE);
13841
13842       /* if the result is a bit */
13843       if (AOP_TYPE (op) == AOP_CRY)
13844         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13845       else
13846         {
13847           /* bit variables done */
13848           /* general case */
13849           size = AOP_SIZE (op);
13850           offset = 0;
13851           while (size--)
13852           {
13853             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13854             offset++;
13855           }
13856         }
13857
13858       freeAsmop (op, NULL, ic, TRUE);
13859     }
13860 }
13861
13862 /*-----------------------------------------------------------------*/
13863 /* genCritical - generate code for start of a critical sequence    */
13864 /*-----------------------------------------------------------------*/
13865 static void
13866 genCritical (iCode *ic)
13867 {
13868   symbol *tlbl = newiTempLabel (NULL);
13869
13870   D (emitcode(";", "genCritical"));
13871
13872   if (IC_RESULT (ic))
13873     {
13874       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
13875       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
13876       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
13877       aopPut (IC_RESULT (ic), zero, 0);
13878       emitLabel (tlbl);
13879       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13880     }
13881   else
13882     {
13883       emitcode ("setb", "c");
13884       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
13885       emitcode ("clr", "c");
13886       emitLabel (tlbl);
13887       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
13888     }
13889 }
13890
13891 /*-----------------------------------------------------------------*/
13892 /* genEndCritical - generate code for end of a critical sequence   */
13893 /*-----------------------------------------------------------------*/
13894 static void
13895 genEndCritical (iCode *ic)
13896 {
13897   D(emitcode(";     genEndCritical",""));
13898
13899   if (IC_RIGHT (ic))
13900     {
13901       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
13902       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
13903         {
13904           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
13905           emitcode ("mov", "ea,c");
13906         }
13907       else
13908         {
13909           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
13910           emitcode ("rrc", "a");
13911           emitcode ("mov", "ea,c");
13912         }
13913       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
13914     }
13915   else
13916     {
13917       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
13918       emitcode ("mov", "ea,c");
13919     }
13920 }
13921
13922
13923
13924 /*-----------------------------------------------------------------*/
13925 /* genBuiltIn - calls the appropriate function to  generating code */
13926 /* for a built in function                                         */
13927 /*-----------------------------------------------------------------*/
13928 static void genBuiltIn (iCode *ic)
13929 {
13930         operand *bi_parms[MAX_BUILTIN_ARGS];
13931         int nbi_parms;
13932         iCode *bi_iCode;
13933         symbol *bif;
13934
13935         /* get all the arguments for a built in function */
13936         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
13937
13938         /* which function is it */
13939         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
13940         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
13941                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
13942         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
13943                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
13944         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
13945                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
13946         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
13947                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
13948         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
13949                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
13950         } else if (strcmp(bif->name,"__builtin_inp")==0) {
13951                 genInp(bi_iCode,nbi_parms,bi_parms);
13952         } else if (strcmp(bif->name,"__builtin_outp")==0) {
13953                 genOutp(bi_iCode,nbi_parms,bi_parms);
13954         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
13955                 genSwapW(bi_iCode,nbi_parms,bi_parms);
13956                 /* JavaNative builtIns */
13957         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
13958                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
13959         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
13960                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
13961         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
13962                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
13963         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
13964                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
13965         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
13966                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13967         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
13968                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13969         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
13970                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
13971         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
13972                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
13973         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
13974                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13975         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
13976                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13977         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
13978                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
13979         } else if (strcmp(bif->name,"MM_Malloc")==0) {
13980                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
13981         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
13982                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
13983         } else if (strcmp(bif->name,"MM_Free")==0) {
13984                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
13985         } else if (strcmp(bif->name,"MM_Deref")==0) {
13986                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
13987         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
13988                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
13989         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
13990                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
13991         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
13992                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
13993         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
13994                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
13995         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
13996                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
13997         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
13998                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
13999         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14000                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14001         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14002                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14003         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14004                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14005         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14006                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14007         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14008                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14009         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14010                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14011         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14012                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14013         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14014                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14015         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14016                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14017         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14018                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14019         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14020                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14021         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14022                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14023         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14024                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14025         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14026                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14027         } else {
14028                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14029                 return ;
14030         }
14031         return ;
14032 }
14033
14034 /*-----------------------------------------------------------------*/
14035 /* gen390Code - generate code for Dallas 390 based controllers     */
14036 /*-----------------------------------------------------------------*/
14037 void
14038 gen390Code (iCode * lic)
14039 {
14040   iCode *ic;
14041   int cln = 0;
14042
14043   _G.currentFunc = NULL;
14044   lineHead = lineCurr = NULL;
14045   dptrn[1][0] = "dpl1";
14046   dptrn[1][1] = "dph1";
14047   dptrn[1][2] = "dpx1";
14048
14049   if (options.model == MODEL_FLAT24) {
14050     fReturnSizeDS390 = 5;
14051     fReturn = fReturn24;
14052   } else {
14053     fReturnSizeDS390 = 4;
14054     fReturn = fReturn16;
14055     options.stack10bit=0;
14056   }
14057 #if 1
14058   /* print the allocation information */
14059   if (allocInfo && currFunc)
14060     printAllocInfo (currFunc, codeOutFile);
14061 #endif
14062   /* if debug information required */
14063   if (options.debug && currFunc)
14064     {
14065       debugFile->writeFunction (currFunc, lic);
14066     }
14067   /* stack pointer name */
14068   if (options.useXstack)
14069     spname = "_spx";
14070   else
14071     spname = "sp";
14072
14073
14074   for (ic = lic; ic; ic = ic->next)
14075     {
14076       _G.current_iCode = ic;
14077
14078       if (ic->lineno && cln != ic->lineno)
14079         {
14080           if (options.debug)
14081             {
14082               debugFile->writeCLine (ic);
14083             }
14084           if (!options.noCcodeInAsm) {
14085             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14086                       printCLine(ic->filename, ic->lineno));
14087           }
14088           cln = ic->lineno;
14089         }
14090       if (options.iCodeInAsm) {
14091         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
14092       }
14093       /* if the result is marked as
14094          spilt and rematerializable or code for
14095          this has already been generated then
14096          do nothing */
14097       if (resultRemat (ic) || ic->generated)
14098         continue;
14099
14100       /* depending on the operation */
14101       switch (ic->op)
14102         {
14103         case '!':
14104           genNot (ic);
14105           break;
14106
14107         case '~':
14108           genCpl (ic);
14109           break;
14110
14111         case UNARYMINUS:
14112           genUminus (ic);
14113           break;
14114
14115         case IPUSH:
14116           genIpush (ic);
14117           break;
14118
14119         case IPOP:
14120           /* IPOP happens only when trying to restore a
14121              spilt live range, if there is an ifx statement
14122              following this pop then the if statement might
14123              be using some of the registers being popped which
14124              would destory the contents of the register so
14125              we need to check for this condition and handle it */
14126           if (ic->next &&
14127               ic->next->op == IFX &&
14128               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14129             genIfx (ic->next, ic);
14130           else
14131             genIpop (ic);
14132           break;
14133
14134         case CALL:
14135           genCall (ic);
14136           break;
14137
14138         case PCALL:
14139           genPcall (ic);
14140           break;
14141
14142         case FUNCTION:
14143           genFunction (ic);
14144           break;
14145
14146         case ENDFUNCTION:
14147           genEndFunction (ic);
14148           break;
14149
14150         case RETURN:
14151           genRet (ic);
14152           break;
14153
14154         case LABEL:
14155           genLabel (ic);
14156           break;
14157
14158         case GOTO:
14159           genGoto (ic);
14160           break;
14161
14162         case '+':
14163           genPlus (ic);
14164           break;
14165
14166         case '-':
14167           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14168             genMinus (ic);
14169           break;
14170
14171         case '*':
14172           genMult (ic);
14173           break;
14174
14175         case '/':
14176           genDiv (ic);
14177           break;
14178
14179         case '%':
14180           genMod (ic);
14181           break;
14182
14183         case '>':
14184           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14185           break;
14186
14187         case '<':
14188           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14189           break;
14190
14191         case LE_OP:
14192         case GE_OP:
14193         case NE_OP:
14194
14195           /* note these two are xlated by algebraic equivalence
14196              during parsing SDCC.y */
14197           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14198                   "got '>=' or '<=' shouldn't have come here");
14199           break;
14200
14201         case EQ_OP:
14202           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14203           break;
14204
14205         case AND_OP:
14206           genAndOp (ic);
14207           break;
14208
14209         case OR_OP:
14210           genOrOp (ic);
14211           break;
14212
14213         case '^':
14214           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14215           break;
14216
14217         case '|':
14218           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14219           break;
14220
14221         case BITWISEAND:
14222           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14223           break;
14224
14225         case INLINEASM:
14226           genInline (ic);
14227           break;
14228
14229         case RRC:
14230           genRRC (ic);
14231           break;
14232
14233         case RLC:
14234           genRLC (ic);
14235           break;
14236
14237         case GETHBIT:
14238           genGetHbit (ic);
14239           break;
14240
14241         case LEFT_OP:
14242           genLeftShift (ic);
14243           break;
14244
14245         case RIGHT_OP:
14246           genRightShift (ic);
14247           break;
14248
14249         case GET_VALUE_AT_ADDRESS:
14250           genPointerGet (ic,
14251                          hasInc (IC_LEFT (ic), ic,
14252                                  getSize (operandType (IC_RESULT (ic)))));
14253           break;
14254
14255         case '=':
14256           if (POINTER_SET (ic))
14257             genPointerSet (ic,
14258                            hasInc (IC_RESULT (ic), ic,
14259                                    getSize (operandType (IC_RIGHT (ic)))));
14260           else
14261             genAssign (ic);
14262           break;
14263
14264         case IFX:
14265           genIfx (ic, NULL);
14266           break;
14267
14268         case ADDRESS_OF:
14269           genAddrOf (ic);
14270           break;
14271
14272         case JUMPTABLE:
14273           genJumpTab (ic);
14274           break;
14275
14276         case CAST:
14277           genCast (ic);
14278           break;
14279
14280         case RECEIVE:
14281           genReceive (ic);
14282           break;
14283
14284         case SEND:
14285           if (ic->builtinSEND)
14286             genBuiltIn(ic);
14287           else
14288             addSet (&_G.sendSet, ic);
14289           break;
14290
14291         case DUMMY_READ_VOLATILE:
14292           genDummyRead (ic);
14293           break;
14294
14295         case CRITICAL:
14296           genCritical (ic);
14297           break;
14298
14299         case ENDCRITICAL:
14300           genEndCritical (ic);
14301           break;
14302
14303         case SWAP:
14304           genSwap (ic);
14305           break;
14306
14307 #if 0 // obsolete, and buggy for != xdata
14308         case ARRAYINIT:
14309             genArrayInit(ic);
14310             break;
14311 #endif
14312
14313         default:
14314           ic = ic;
14315         }
14316     }
14317
14318
14319   /* now we are ready to call the
14320      peep hole optimizer */
14321   if (!options.nopeep)
14322     peepHole (&lineHead);
14323
14324   /* now do the actual printing */
14325   printLine (lineHead, codeOutFile);
14326   return;
14327 }