da277d24b43a9004356acdc23e97ed772eb39fad
[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) do if (options.verboseAsm) {x;} while(0)
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 #include "dbuf_string.h"
38
39 #include "common.h"
40 #include "main.h"
41 #include "ralloc.h"
42 #include "gen.h"
43
44 #define BETTER_LITERAL_SHIFT
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0";
55 static char *one = "#1";
56 static char *spname;
57
58 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
59 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
60
61 unsigned fReturnSizeDS390 = 5;
62 static char *fReturn24[] =
63 {"dpl", "dph", "dpx", "b", "a"};
64 static char *fReturn16[] =
65 {"dpl", "dph", "b", "a"};
66 static char **fReturn = fReturn24;
67 static char *accUse[] =
68 {"a", "b"};
69 static char *dptrn[2][3];
70 static char *javaRet[] = { "r0","r1","r2","r3"};
71 static short rbank = -1;
72
73 #define REG_WITH_INDEX   ds390_regWithIdx
74
75 #define AOP(op) op->aop
76 #define AOP_TYPE(op) AOP(op)->type
77 #define AOP_SIZE(op) AOP(op)->size
78 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
79                        AOP_TYPE(x) == AOP_R0))
80
81 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
82                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
83                          AOP(x)->paged))
84
85 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
86                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
87                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
88 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
89 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
90 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
91
92 // The following two macros can be used even if the aop has not yet been aopOp'd.
93 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
94 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
95
96 /* Workaround for DS80C390 bug: div ab may return bogus results
97  * if A is accessed in instruction immediately before the div.
98  *
99  * Will be fixed in B4 rev of processor, Dallas claims.
100  */
101
102 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
103     if (!AOP_NEEDSACC(RIGHT))         \
104     {               \
105       /* We can load A first, then B, since     \
106        * B (the RIGHT operand) won't clobber A,   \
107        * thus avoiding touching A right before the div. \
108        */             \
109       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
110       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
111       MOVA(L);            \
112       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
113       MOVB(L); \
114     }               \
115     else              \
116     {               \
117       /* Just stuff in a nop after loading A. */    \
118       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
119       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
120       MOVA(L);            \
121       emitcode("nop", "; workaround for DS80C390 div bug.");  \
122     }
123
124 #define R0INB   _G.bu.bs.r0InB
125 #define R1INB   _G.bu.bs.r1InB
126 #define OPINB   _G.bu.bs.OpInB
127 #define BINUSE  _G.bu.BInUse
128
129 static struct
130   {
131     short r0Pushed;
132     short r1Pushed;
133     union
134       {
135         struct
136           {
137             short r0InB : 2;//2 so we can see it overflow
138             short r1InB : 2;//2 so we can see it overflow
139             short OpInB : 2;//2 so we can see it overflow
140           } bs;
141         short BInUse;
142       } bu;
143     short accInUse;
144     short inLine;
145     short debugLine;
146     short nRegsSaved;
147     short dptrInUse;
148     short dptr1InUse;
149     set *sendSet;
150     iCode *current_iCode;
151     symbol *currentFunc;
152   }
153 _G;
154
155 static char *rb1regs[] = {
156     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
157     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
158 };
159
160 static void saveRBank (int, iCode *, bool);
161
162 #define RESULTONSTACK(x) \
163                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
164                          IC_RESULT(x)->aop->type == AOP_STK )
165
166 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
167 #define MOVB(x)  movb(x)
168
169 #define CLRC    emitcode("clr","c")
170 #define SETC    emitcode("setb","c")
171
172 // A scratch register which will be used to hold
173 // result bytes from operands in far space via DPTR2.
174 #define DP2_RESULT_REG  "_ap"
175
176 static lineNode *lineHead = NULL;
177 static lineNode *lineCurr = NULL;
178
179 static unsigned char SLMask[] =
180 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
181  0xE0, 0xC0, 0x80, 0x00};
182 static unsigned char SRMask[] =
183 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
184  0x07, 0x03, 0x01, 0x00};
185
186 #define LSB     0
187 #define MSB16   1
188 #define MSB24   2
189 #define MSB32   3
190 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
191                                 symbol *lbl = newiTempLabel(NULL);              \
192                                 emitcode ("setb","F1");                         \
193                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
194                                 emitcode ("clr","F1");                          \
195                                 emitLabel (lbl);                                \
196                         }}
197 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
198                                 emitcode ("mov","EA,F1");                       \
199                         }}
200
201 static int _currentDPS;         /* Current processor DPS. */
202 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
203 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
204
205 /*-----------------------------------------------------------------*/
206 /* emitcode - writes the code into a file : for now it is simple    */
207 /*-----------------------------------------------------------------*/
208 static void
209 emitcode (const char *inst, const char *fmt,...)
210 {
211   va_list ap;
212   struct dbuf_s dbuf;
213   const char *lbp, *lb;
214
215   dbuf_init (&dbuf, INITIAL_INLINEASM);
216
217   va_start (ap, fmt);
218
219   if (inst && *inst)
220     {
221       dbuf_append_str (&dbuf, inst);
222
223       if (fmt && *fmt)
224         {
225           dbuf_append_char (&dbuf, '\t');
226           dbuf_tvprintf (&dbuf, fmt, ap);
227       }
228     }
229   else
230     {
231       dbuf_tvprintf (&dbuf, fmt, ap);
232     }
233
234   lbp = lb = dbuf_c_str(&dbuf);
235
236   while (isspace ((unsigned char)*lbp))
237     {
238       lbp++;
239     }
240
241   if (lbp)
242     {
243       lineCurr = (lineCurr ?
244                   connectLine (lineCurr, newLineNode (lb)) :
245                   (lineHead = newLineNode (lb)));
246
247       lineCurr->isInline = _G.inLine;
248       lineCurr->isDebug = _G.debugLine;
249       lineCurr->ic = _G.current_iCode;
250       lineCurr->aln = ds390newAsmLineNode(_currentDPS);
251       lineCurr->isComment = (*lbp == ';');
252     }
253
254   va_end (ap);
255
256   dbuf_destroy(&dbuf);
257 }
258
259 static void
260 emitLabel (symbol *tlbl)
261 {
262   emitcode ("", "!tlabeldef", tlbl->key + 100);
263   lineCurr->isLabel = 1;
264 }
265
266 /*-----------------------------------------------------------------*/
267 /* ds390_emitDebuggerSymbol - associate the current code location  */
268 /*   with a debugger symbol                                        */
269 /*-----------------------------------------------------------------*/
270 void
271 ds390_emitDebuggerSymbol (char * debugSym)
272 {
273   _G.debugLine = 1;
274   emitcode ("", "%s ==.", debugSym);
275   _G.debugLine = 0;
276 }
277
278 /*-----------------------------------------------------------------*/
279 /* mova - moves specified value into accumulator                   */
280 /*-----------------------------------------------------------------*/
281 static void
282 mova (const char *x)
283 {
284   /* do some early peephole optimization */
285   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
286     return;
287
288   emitcode("mov", "a,%s", x);
289 }
290
291 /*-----------------------------------------------------------------*/
292 /* movb - moves specified value into register b                    */
293 /*-----------------------------------------------------------------*/
294 static void
295 movb (const char *x)
296 {
297   /* do some early peephole optimization */
298   if (!strncmp(x, "b", 2))
299     return;
300
301   emitcode("mov","b,%s", x);
302 }
303
304 /*-----------------------------------------------------------------*/
305 /* movc - moves specified value into the carry                     */
306 /*-----------------------------------------------------------------*/
307 static void
308 movc (const char *s)
309 {
310   if (s == zero)
311     CLRC;
312   else if (s == one)
313     SETC;
314   else if (strcmp (s, "c"))
315     {/* it's not in carry already */
316       MOVA (s);
317       /* set C, if a >= 1 */
318       emitcode ("add", "a,#0xff");
319     }
320 }
321
322 /*-----------------------------------------------------------------*/
323 /* pushB - saves register B if necessary                           */
324 /*-----------------------------------------------------------------*/
325 static bool
326 pushB (void)
327 {
328   bool pushedB = FALSE;
329
330   if (BINUSE)
331     {
332       emitcode ("push", "b");
333 //    printf("B was in use !\n");
334       pushedB = TRUE;
335     }
336   else
337     {
338       OPINB++;
339     }
340   return pushedB;
341 }
342
343 /*-----------------------------------------------------------------*/
344 /* popB - restores value of register B if necessary                */
345 /*-----------------------------------------------------------------*/
346 static void
347 popB (bool pushedB)
348 {
349   if (pushedB)
350     {
351       emitcode ("pop", "b");
352     }
353   else
354     {
355       OPINB--;
356     }
357 }
358
359 /*-----------------------------------------------------------------*/
360 /* pushReg - saves register                                        */
361 /*-----------------------------------------------------------------*/
362 static bool
363 pushReg (int index, bool bits_pushed)
364 {
365   regs * reg = REG_WITH_INDEX (index);
366   if (reg->type == REG_BIT)
367     {
368       if (!bits_pushed)
369         emitcode ("push", "%s", reg->base);
370       return TRUE;
371     }
372   else
373     emitcode ("push", "%s", reg->dname);
374   return bits_pushed;
375 }
376
377 /*-----------------------------------------------------------------*/
378 /* popReg - restores register                                      */
379 /*-----------------------------------------------------------------*/
380 static bool
381 popReg (int index, bool bits_popped)
382 {
383   regs * reg = REG_WITH_INDEX (index);
384   if (reg->type == REG_BIT)
385     {
386       if (!bits_popped)
387         emitcode ("pop", "%s", reg->base);
388       return TRUE;
389     }
390   else
391     emitcode ("pop", "%s", reg->dname);
392   return bits_popped;
393 }
394
395 /*-----------------------------------------------------------------*/
396 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
397 /*-----------------------------------------------------------------*/
398 static regs *
399 getFreePtr (iCode * ic, asmop ** aopp, bool result)
400 {
401   bool r0iu, r1iu;
402   bool r0ou, r1ou;
403
404   /* the logic: if r0 & r1 used in the instruction
405      then we are in trouble otherwise */
406
407   /* first check if r0 & r1 are used by this
408      instruction, in which case we are in trouble */
409   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
410   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
411   if (r0iu && r1iu) {
412       goto endOfWorld;
413     }
414
415   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
416   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
417
418   /* if no usage of r0 then return it */
419   if (!r0iu && !r0ou)
420     {
421       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
422       (*aopp)->type = AOP_R0;
423
424       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
425     }
426
427   /* if no usage of r1 then return it */
428   if (!r1iu && !r1ou)
429     {
430       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
431       (*aopp)->type = AOP_R1;
432
433       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
434     }
435
436   /* now we know they both have usage */
437   /* if r0 not used in this instruction */
438   if (!r0iu)
439     {
440       /* push it if not already pushed */
441       if (!_G.r0Pushed)
442         {
443           emitcode ("push", "%s",
444                     REG_WITH_INDEX (R0_IDX)->dname);
445           _G.r0Pushed++;
446         }
447
448       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
449       (*aopp)->type = AOP_R0;
450
451       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
452     }
453
454   /* if r1 not used then */
455
456   if (!r1iu)
457     {
458       /* push it if not already pushed */
459       if (!_G.r1Pushed)
460         {
461           emitcode ("push", "%s",
462                     REG_WITH_INDEX (R1_IDX)->dname);
463           _G.r1Pushed++;
464         }
465
466       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
467       (*aopp)->type = AOP_R1;
468       return REG_WITH_INDEX (R1_IDX);
469     }
470
471 endOfWorld:
472   /* I said end of world, but not quite end of world yet */
473   /* if this is a result then we can push it on the stack */
474   if (result)
475     {
476       (*aopp)->type = AOP_STK;
477       return NULL;
478     }
479
480   /* now this is REALLY the end of the world */
481   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
482           "getFreePtr should never reach here");
483   exit (1);
484
485   return NULL; // notreached, but makes compiler happy.
486 }
487
488
489 /*-----------------------------------------------------------------*/
490 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
491 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
492 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
493 /*-----------------------------------------------------------------*/
494 static void
495 genSetDPTR (int n)
496 {
497
498   /* If we are doing lazy evaluation, simply note the desired
499    * change, but don't emit any code yet.
500    */
501   if (_lazyDPS)
502     {
503       _desiredDPS = n;
504       return;
505     }
506
507   if (!n)
508     {
509       emitcode ("mov", "dps,#0");
510     }
511   else
512     {
513       TR_DPTR("#1");
514       emitcode ("mov", "dps,#1");
515     }
516 }
517
518 /*------------------------------------------------------------------*/
519 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
520 /*                                                                  */
521 /* Any code that operates on DPTR (NB: not on the individual        */
522 /* components, like DPH) *must* call _flushLazyDPS() before using   */
523 /* DPTR within a lazy DPS evaluation block.                         */
524 /*                                                                  */
525 /* Note that aopPut and aopGet already contain the proper calls to  */
526 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
527 /* DPS evaluation block.                                            */
528 /*                                                                  */
529 /* Also, _flushLazyDPS must be called before any flow control       */
530 /* operations that could potentially branch out of the block.       */
531 /*                                                                  */
532 /* Lazy DPS evaluation is simply an optimization (though an         */
533 /* important one), so if in doubt, leave it out.                    */
534 /*------------------------------------------------------------------*/
535 static void
536 _startLazyDPSEvaluation (void)
537 {
538   _currentDPS = 0;
539   _desiredDPS = 0;
540 #ifdef BETTER_LITERAL_SHIFT
541   _lazyDPS++;
542 #else
543   _lazyDPS = 1;
544 #endif
545 }
546
547 /*------------------------------------------------------------------*/
548 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
549 /* desired one. Call before using DPTR within a lazy DPS evaluation */
550 /* block.                                                           */
551 /*------------------------------------------------------------------*/
552 static void
553 _flushLazyDPS (void)
554 {
555   if (!_lazyDPS)
556     {
557       /* nothing to do. */
558       return;
559     }
560
561   if (_desiredDPS != _currentDPS)
562     {
563       if (_desiredDPS)
564         {
565           emitcode ("inc", "dps");
566         }
567       else
568         {
569           emitcode ("dec", "dps");
570         }
571       _currentDPS = _desiredDPS;
572     }
573 }
574
575 /*-----------------------------------------------------------------*/
576 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
577 /*                                                                 */
578 /* Forces us back to the safe state (standard DPTR selected).      */
579 /*-----------------------------------------------------------------*/
580 static void
581 _endLazyDPSEvaluation (void)
582 {
583 #ifdef BETTER_LITERAL_SHIFT
584   _lazyDPS--;
585 #else
586   _lazyDPS = 0;
587 #endif
588   if (!_lazyDPS)
589   {
590     if (_currentDPS)
591     {
592       genSetDPTR (0);
593       _flushLazyDPS ();
594     }
595     _currentDPS = 0;
596     _desiredDPS = 0;
597   }
598 }
599
600
601 /*-----------------------------------------------------------------*/
602 /* newAsmop - creates a new asmOp                                  */
603 /*-----------------------------------------------------------------*/
604 static asmop *
605 newAsmop (short type)
606 {
607   asmop *aop;
608
609   aop = Safe_calloc (1, sizeof (asmop));
610   aop->type = type;
611   aop->allocated = 1;
612   return aop;
613 }
614
615 /*-----------------------------------------------------------------*/
616 /* pointerCode - returns the code for a pointer type               */
617 /*-----------------------------------------------------------------*/
618 static int
619 pointerCode (sym_link * etype)
620 {
621
622   return PTR_TYPE (SPEC_OCLS (etype));
623
624 }
625
626 /*-----------------------------------------------------------------*/
627 /* leftRightUseAcc - returns size of accumulator use by operands   */
628 /*-----------------------------------------------------------------*/
629 static int
630 leftRightUseAcc(iCode *ic)
631 {
632   operand *op;
633   int size;
634   int accuseSize = 0;
635   int accuse = 0;
636
637   if (!ic)
638     {
639       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
640               "null iCode pointer");
641       return 0;
642     }
643
644   if (ic->op == IFX)
645     {
646       op = IC_COND (ic);
647       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
648         {
649           accuse = 1;
650           size = getSize (OP_SYMBOL (op)->type);
651           if (size>accuseSize)
652             accuseSize = size;
653         }
654     }
655   else if (ic->op == JUMPTABLE)
656     {
657       op = IC_JTCOND (ic);
658       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
659         {
660           accuse = 1;
661           size = getSize (OP_SYMBOL (op)->type);
662           if (size>accuseSize)
663             accuseSize = size;
664         }
665     }
666   else
667     {
668       op = IC_LEFT (ic);
669       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
670         {
671           accuse = 1;
672           size = getSize (OP_SYMBOL (op)->type);
673           if (size>accuseSize)
674             accuseSize = size;
675         }
676       op = IC_RIGHT (ic);
677       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
678         {
679           accuse = 1;
680           size = getSize (OP_SYMBOL (op)->type);
681           if (size>accuseSize)
682             accuseSize = size;
683         }
684     }
685
686   if (accuseSize)
687     return accuseSize;
688   else
689     return accuse;
690 }
691
692 /*-----------------------------------------------------------------*/
693 /* aopForSym - for a true symbol                                   */
694 /*-----------------------------------------------------------------*/
695 static asmop *
696 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
697 {
698   asmop *aop;
699   memmap *space;
700   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
701   char *dpl = useDP2 ? "dpl1" : "dpl";
702   char *dph = useDP2 ? "dph1" : "dph";
703   char *dpx = useDP2 ? "dpx1" : "dpx";
704
705   wassertl (ic != NULL, "Got a null iCode");
706   wassertl (sym != NULL, "Got a null symbol");
707
708   space = SPEC_OCLS (sym->etype);
709
710   /* if already has one */
711   if (sym->aop)
712     {
713       if ((sym->aop->type == AOP_DPTR && useDP2)
714           || (sym->aop->type == AOP_DPTR2 && !useDP2))
715         sym->aop = NULL;
716       else
717         {
718           sym->aop->allocated++;
719           return sym->aop;
720         }
721     }
722
723   /* assign depending on the storage class */
724   /* if it is on the stack or indirectly addressable */
725   /* space we need to assign either r0 or r1 to it   */
726   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
727     {
728       sym->aop = aop = newAsmop (0);
729       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
730       aop->size = getSize (sym->type);
731
732       /* now assign the address of the variable to
733          the pointer register */
734       if (aop->type != AOP_STK)
735         {
736           if (sym->onStack)
737             {
738               signed char offset = ((sym->stack < 0) ?
739                          ((signed char) (sym->stack - _G.nRegsSaved)) :
740                          ((signed char) sym->stack)) & 0xff;
741
742               if ((abs(offset) <= 3) ||
743                   (accuse && (abs(offset) <= 7)))
744                 {
745                   emitcode ("mov", "%s,_bp",
746                             aop->aopu.aop_ptr->name);
747                   while (offset < 0)
748                     {
749                       emitcode ("dec", aop->aopu.aop_ptr->name);
750                       offset++;
751                     }
752                   while (offset > 0)
753                     {
754                       emitcode ("inc", aop->aopu.aop_ptr->name);
755                       offset--;
756                     }
757                 }
758               else
759                 {
760                   if (accuse)
761                     emitcode ("push", "acc");
762                   emitcode ("mov", "a,_bp");
763                   emitcode ("add", "a,#!constbyte", offset);
764                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
765                   if (accuse)
766                     emitcode ("pop", "acc");
767                 }
768             }
769           else
770             {
771               emitcode ("mov", "%s,#%s",
772                         aop->aopu.aop_ptr->name,
773                         sym->rname);
774             }
775           aop->paged = space->paged;
776         }
777       else
778         aop->aopu.aop_stk = sym->stack;
779       return aop;
780     }
781
782   if (sym->onStack && options.stack10bit)
783     {
784       short stack_val = -((sym->stack < 0) ?
785                           ((short) (sym->stack - _G.nRegsSaved)) :
786                           ((short) sym->stack)) ;
787       if (_G.dptrInUse ) {
788           emitcode ("push",dpl);
789           emitcode ("push",dph);
790           emitcode ("push",dpx);
791       }
792       /* It's on the 10 bit stack, which is located in
793        * far data space.
794        */
795       if (stack_val < 0 && stack_val > -5)
796         { /* between -5 & -1 */
797           if (options.model == MODEL_FLAT24)
798             {
799               emitcode ("mov", "%s,#!constbyte", dpx,
800                         (options.stack_loc >> 16) & 0xff);
801             }
802           emitcode ("mov", "%s,_bpx+1", dph);
803           emitcode ("mov", "%s,_bpx", dpl);
804           if (useDP2) {
805               emitcode ("mov","dps,#1");
806           }
807           stack_val = -stack_val;
808           while (stack_val--) {
809               emitcode ("inc","dptr");
810           }
811           if (useDP2) {
812               emitcode("mov","dps,#0");
813           }
814         }
815       else
816         {
817           if (accuse)
818               emitcode ("push", "acc");
819
820           emitcode ("mov", "a,_bpx");
821           emitcode ("clr","c");
822           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
823           emitcode ("mov","%s,a", dpl);
824           emitcode ("mov","a,_bpx+1");
825           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
826           emitcode ("mov", "%s,a", dph);
827           if (options.model == MODEL_FLAT24)
828             {
829               emitcode ("mov", "%s,#!constbyte", dpx,
830                         (options.stack_loc >> 16) & 0xff);
831             }
832
833           if (accuse)
834               emitcode ("pop", "acc");
835         }
836       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
837       aop->size = getSize (sym->type);
838       return aop;
839     }
840
841   /* if in bit space */
842   if (IN_BITSPACE (space))
843     {
844       sym->aop = aop = newAsmop (AOP_CRY);
845       aop->aopu.aop_dir = sym->rname;
846       aop->size = getSize (sym->type);
847       return aop;
848     }
849   /* if it is in direct space */
850   if (IN_DIRSPACE (space))
851     {
852       sym->aop = aop = newAsmop (AOP_DIR);
853       aop->aopu.aop_dir = sym->rname;
854       aop->size = getSize (sym->type);
855       return aop;
856     }
857
858   /* special case for a function */
859   if (IS_FUNC (sym->type) && !(sym->isitmp))
860     {
861       sym->aop = aop = newAsmop (AOP_IMMD);
862       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
863       aop->size = FPTRSIZE;
864       return aop;
865     }
866
867   /* only remaining is far space */
868   /* in which case DPTR gets the address */
869   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
870   if (useDP2)
871     {
872       genSetDPTR (1);
873       _flushLazyDPS ();
874       emitcode ("mov", "dptr,#%s", sym->rname);
875       genSetDPTR (0);
876     }
877   else
878     {
879       emitcode ("mov", "dptr,#%s", sym->rname);
880     }
881   aop->size = getSize (sym->type);
882
883   /* if it is in code space */
884   if (IN_CODESPACE (space))
885     aop->code = 1;
886
887   return aop;
888 }
889
890 /*-----------------------------------------------------------------*/
891 /* aopForRemat - rematerialzes an object                           */
892 /*-----------------------------------------------------------------*/
893 static asmop *
894 aopForRemat (symbol * sym)
895 {
896   iCode *ic = sym->rematiCode;
897   asmop *aop = newAsmop (AOP_IMMD);
898   int ptr_type = 0;
899   int val = 0;
900
901   for (;;)
902     {
903       if (ic->op == '+')
904         val += (int) operandLitValue (IC_RIGHT (ic));
905       else if (ic->op == '-')
906         val -= (int) operandLitValue (IC_RIGHT (ic));
907       else if (IS_CAST_ICODE(ic)) {
908               sym_link *from_type = operandType(IC_RIGHT(ic));
909               aop->aopu.aop_immd.from_cast_remat = 1;
910               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
911               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
912               continue;
913       } else break;
914
915       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
916     }
917
918   if (val)
919   {
920       SNPRINTF (buffer, sizeof(buffer),
921                 "(%s %c 0x%06x)",
922                 OP_SYMBOL (IC_LEFT (ic))->rname,
923                 val >= 0 ? '+' : '-',
924                 abs (val) & 0xffffff);
925   }
926   else
927   {
928       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
929       {
930           SNPRINTF(buffer, sizeof(buffer),
931                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
932       }
933       else
934       {
935           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
936       }
937   }
938
939   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
940   /* set immd2 field if required */
941   if (aop->aopu.aop_immd.from_cast_remat)
942   {
943       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
944       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
945   }
946
947   return aop;
948 }
949
950 /*-----------------------------------------------------------------*/
951 /* aopHasRegs - returns true if aop has regs between from-to       */
952 /*-----------------------------------------------------------------*/
953 static int aopHasRegs(asmop *aop, int from, int to)
954 {
955     int size =0;
956
957     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
958
959     for (; size < aop->size ; size++) {
960         int reg;
961         for (reg = from ; reg <= to ; reg++)
962             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
963     }
964     return 0;
965 }
966
967 /*-----------------------------------------------------------------*/
968 /* regsInCommon - two operands have some registers in common       */
969 /*-----------------------------------------------------------------*/
970 static bool
971 regsInCommon (operand * op1, operand * op2)
972 {
973   symbol *sym1, *sym2;
974   int i;
975
976   /* if they have registers in common */
977   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
978     return FALSE;
979
980   sym1 = OP_SYMBOL (op1);
981   sym2 = OP_SYMBOL (op2);
982
983   if (sym1->nRegs == 0 || sym2->nRegs == 0)
984     return FALSE;
985
986   for (i = 0; i < sym1->nRegs; i++)
987     {
988       int j;
989       if (!sym1->regs[i])
990         continue;
991
992       for (j = 0; j < sym2->nRegs; j++)
993         {
994           if (!sym2->regs[j])
995             continue;
996
997           if (sym2->regs[j] == sym1->regs[i])
998             return TRUE;
999         }
1000     }
1001
1002   return FALSE;
1003 }
1004
1005 /*-----------------------------------------------------------------*/
1006 /* operandsEqu - equivalent                                        */
1007 /*-----------------------------------------------------------------*/
1008 static bool
1009 operandsEqu (operand * op1, operand * op2)
1010 {
1011   symbol *sym1, *sym2;
1012
1013   /* if they're not symbols */
1014   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1015     return FALSE;
1016
1017   sym1 = OP_SYMBOL (op1);
1018   sym2 = OP_SYMBOL (op2);
1019
1020   /* if both are itemps & one is spilt
1021      and the other is not then false */
1022   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1023       sym1->isspilt != sym2->isspilt)
1024     return FALSE;
1025
1026   /* if they are the same */
1027   if (sym1 == sym2)
1028     return TRUE;
1029
1030   /* if they have the same rname */
1031   if (sym1->rname[0] && sym2->rname[0] &&
1032       strcmp (sym1->rname, sym2->rname) == 0 &&
1033       !(IS_PARM (op2) && IS_ITEMP (op1)))
1034     return TRUE;
1035
1036   /* if left is a tmp & right is not */
1037   if (IS_ITEMP (op1) &&
1038       !IS_ITEMP (op2) &&
1039       sym1->isspilt &&
1040       (sym1->usl.spillLoc == sym2))
1041     return TRUE;
1042
1043   if (IS_ITEMP (op2) &&
1044       !IS_ITEMP (op1) &&
1045       sym2->isspilt &&
1046       sym1->level > 0 &&
1047       (sym2->usl.spillLoc == sym1))
1048     return TRUE;
1049
1050   /* are they spilt to the same location */
1051   if (IS_ITEMP (op2) &&
1052       IS_ITEMP (op1) &&
1053       sym2->isspilt &&
1054       sym1->isspilt &&
1055       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1056     return TRUE;
1057
1058   return FALSE;
1059 }
1060
1061 /*-----------------------------------------------------------------*/
1062 /* sameRegs - two asmops have the same registers                   */
1063 /*-----------------------------------------------------------------*/
1064 static bool
1065 sameRegs (asmop * aop1, asmop * aop2)
1066 {
1067   int i;
1068
1069   if (aop1 == aop2)
1070     {
1071       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1072         {
1073           return FALSE;
1074         }
1075       return TRUE;
1076     }
1077
1078   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1079     return FALSE;
1080
1081   if (aop1->type != aop2->type)
1082     return FALSE;
1083
1084   if (aop1->size != aop2->size)
1085     return FALSE;
1086
1087   for (i = 0; i < aop1->size; i++)
1088     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1089       return FALSE;
1090
1091   return TRUE;
1092 }
1093
1094 /*-----------------------------------------------------------------*/
1095 /* aopOp - allocates an asmop for an operand  :                    */
1096 /*-----------------------------------------------------------------*/
1097 static void
1098 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1099 {
1100   asmop *aop;
1101   symbol *sym;
1102   int i;
1103
1104   if (!op)
1105     return;
1106
1107   /* if this a literal */
1108   if (IS_OP_LITERAL (op))
1109     {
1110       op->aop = aop = newAsmop (AOP_LIT);
1111       aop->aopu.aop_lit = op->operand.valOperand;
1112       aop->size = getSize (operandType (op));
1113       return;
1114     }
1115
1116   /* if already has a asmop then continue */
1117   if (op->aop)
1118     {
1119       if ((op->aop->type == AOP_DPTR && useDP2)
1120           || (op->aop->type == AOP_DPTR2 && !useDP2))
1121         op->aop = NULL;
1122       else
1123         {
1124           op->aop->allocated++;
1125           return;
1126         }
1127     }
1128
1129   /* if the underlying symbol has a aop */
1130   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1131     {
1132       op->aop = OP_SYMBOL (op)->aop;
1133       if ((op->aop->type == AOP_DPTR && useDP2)
1134           || (op->aop->type == AOP_DPTR2 && !useDP2))
1135         op->aop = NULL;
1136       else
1137         {
1138           op->aop->allocated++;
1139           return;
1140         }
1141     }
1142
1143   /* if this is a true symbol */
1144   if (IS_TRUE_SYMOP (op))
1145     {
1146       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1147       return;
1148     }
1149
1150   /* this is a temporary : this has
1151      only five choices :
1152      a) register
1153      b) spillocation
1154      c) rematerialize
1155      d) conditional
1156      e) can be a return use only */
1157
1158   sym = OP_SYMBOL (op);
1159
1160   /* if the type is a conditional */
1161   if (sym->regType == REG_CND)
1162     {
1163       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1164       aop->size = 0;
1165       return;
1166     }
1167
1168   /* if it is spilt then two situations
1169      a) is rematerialize
1170      b) has a spill location */
1171   if (sym->isspilt || sym->nRegs == 0)
1172     {
1173
1174       /* rematerialize it NOW */
1175       if (sym->remat)
1176         {
1177           sym->aop = op->aop = aop =
1178             aopForRemat (sym);
1179           aop->size = getSize (sym->type);
1180           return;
1181         }
1182
1183       if (sym->accuse)
1184         {
1185           int i;
1186           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1187           aop->size = getSize (sym->type);
1188           for (i = 0; i < 2; i++)
1189             aop->aopu.aop_str[i] = accUse[i];
1190           return;
1191         }
1192
1193       if (sym->ruonly)
1194         {
1195           unsigned i;
1196
1197           if (useDP2)
1198             {
1199               /* a AOP_STR uses DPTR, but DPTR is already in use;
1200                * we're just hosed.
1201                */
1202                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1203             }
1204
1205           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1206           aop->size = getSize (sym->type);
1207           for (i = 0; i < fReturnSizeDS390; i++)
1208             aop->aopu.aop_str[i] = fReturn[i];
1209           return;
1210         }
1211
1212       if (sym->dptr) { /* has been allocated to a DPTRn */
1213           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1214           aop->size = getSize (sym->type);
1215           aop->aopu.dptr = sym->dptr;
1216           return ;
1217       }
1218
1219       if (sym->usl.spillLoc)
1220         {
1221           asmop *oldAsmOp = NULL;
1222
1223           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1224             {
1225               /* force a new aop if sizes differ */
1226               oldAsmOp = sym->usl.spillLoc->aop;
1227               sym->usl.spillLoc->aop = NULL;
1228             }
1229           sym->aop = op->aop = aop =
1230                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1231           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1232             {
1233               /* Don't reuse the new aop, go with the last one */
1234               sym->usl.spillLoc->aop = oldAsmOp;
1235             }
1236           aop->size = getSize (sym->type);
1237           return;
1238         }
1239
1240       /* else must be a dummy iTemp */
1241       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1242       aop->size = getSize (sym->type);
1243       return;
1244     }
1245
1246   /* if the type is a bit register */
1247   if (sym->regType == REG_BIT)
1248     {
1249       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1250       aop->size = sym->nRegs;//1???
1251       aop->aopu.aop_reg[0] = sym->regs[0];
1252       aop->aopu.aop_dir = sym->regs[0]->name;
1253       return;
1254     }
1255
1256   /* must be in a register */
1257   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1258   aop->size = sym->nRegs;
1259   for (i = 0; i < sym->nRegs; i++)
1260     aop->aopu.aop_reg[i] = sym->regs[i];
1261 }
1262
1263 /*-----------------------------------------------------------------*/
1264 /* freeAsmop - free up the asmop given to an operand               */
1265 /*----------------------------------------------------------------*/
1266 static void
1267 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1268 {
1269   asmop *aop;
1270
1271   if (!op)
1272     aop = aaop;
1273   else
1274     aop = op->aop;
1275
1276   if (!aop)
1277     return;
1278
1279   aop->allocated--;
1280
1281   if (aop->allocated)
1282     goto dealloc;
1283
1284   /* depending on the asmop type only three cases need work
1285      AOP_R0, AOP_R1 & AOP_STK */
1286   switch (aop->type)
1287     {
1288     case AOP_R0:
1289       if (_G.r0Pushed)
1290         {
1291           if (pop)
1292             {
1293               emitcode ("pop", "ar0");
1294               _G.r0Pushed--;
1295             }
1296         }
1297       bitVectUnSetBit (ic->rUsed, R0_IDX);
1298       break;
1299
1300     case AOP_R1:
1301       if (_G.r1Pushed)
1302         {
1303           if (pop)
1304             {
1305               emitcode ("pop", "ar1");
1306               _G.r1Pushed--;
1307             }
1308         }
1309       bitVectUnSetBit (ic->rUsed, R1_IDX);
1310       break;
1311
1312     case AOP_STK:
1313       {
1314         int sz = aop->size;
1315         int stk = aop->aopu.aop_stk + aop->size;
1316         bitVectUnSetBit (ic->rUsed, R0_IDX);
1317         bitVectUnSetBit (ic->rUsed, R1_IDX);
1318
1319         getFreePtr (ic, &aop, FALSE);
1320
1321         if (options.stack10bit)
1322           {
1323             /* I'm not sure what to do here yet... */
1324             /* #STUB */
1325             fprintf (stderr,
1326                      "*** Warning: probably generating bad code for "
1327                      "10 bit stack mode.\n");
1328           }
1329
1330         if (stk)
1331           {
1332             emitcode ("mov", "a,_bp");
1333             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1334             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1335           }
1336         else
1337           {
1338             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1339           }
1340
1341         while (sz--)
1342           {
1343             emitcode ("pop", "acc");
1344             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1345             if (!sz)
1346               break;
1347             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1348           }
1349         op->aop = aop;
1350         freeAsmop (op, NULL, ic, TRUE);
1351         if (_G.r1Pushed)
1352           {
1353             emitcode ("pop", "ar1");
1354             _G.r1Pushed--;
1355           }
1356         if (_G.r0Pushed)
1357           {
1358             emitcode ("pop", "ar0");
1359             _G.r0Pushed--;
1360           }
1361       }
1362     case AOP_DPTR2:
1363         if (_G.dptr1InUse) {
1364             emitcode ("pop","dpx1");
1365             emitcode ("pop","dph1");
1366             emitcode ("pop","dpl1");
1367         }
1368         break;
1369     case AOP_DPTR:
1370         if (_G.dptrInUse) {
1371             emitcode ("pop","dpx");
1372             emitcode ("pop","dph");
1373             emitcode ("pop","dpl");
1374         }
1375         break;
1376     }
1377
1378 dealloc:
1379   /* all other cases just dealloc */
1380   if (op)
1381     {
1382       op->aop = NULL;
1383       if (IS_SYMOP (op))
1384         {
1385           OP_SYMBOL (op)->aop = NULL;
1386           /* if the symbol has a spill */
1387           if (SPIL_LOC (op))
1388             SPIL_LOC (op)->aop = NULL;
1389         }
1390     }
1391 }
1392
1393 #define DEFAULT_ACC_WARNING 0
1394 static int saveAccWarn = DEFAULT_ACC_WARNING;
1395
1396
1397 /*-----------------------------------------------------------------*/
1398 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1399 /*                 clobber the accumulator                         */
1400 /*-----------------------------------------------------------------*/
1401 static bool
1402 aopGetUsesAcc (operand * oper, int offset)
1403 {
1404   asmop * aop = AOP (oper);
1405
1406   if (offset > (aop->size - 1))
1407     return FALSE;
1408
1409   switch (aop->type)
1410     {
1411
1412     case AOP_R0:
1413     case AOP_R1:
1414       if (aop->paged)
1415         return TRUE;
1416       return FALSE;
1417     case AOP_DPTR:
1418     case AOP_DPTR2:
1419     case AOP_DPTRn:
1420       return TRUE;
1421     case AOP_IMMD:
1422       return FALSE;
1423     case AOP_DIR:
1424       return FALSE;
1425     case AOP_REG:
1426       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1427       return FALSE;
1428     case AOP_CRY:
1429       return TRUE;
1430     case AOP_ACC:
1431       if (offset)
1432         return FALSE;
1433       return TRUE;
1434     case AOP_LIT:
1435       return FALSE;
1436     case AOP_STR:
1437       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1438         return TRUE;
1439       return FALSE;
1440     case AOP_DUMMY:
1441       return FALSE;
1442     default:
1443       /* Error case --- will have been caught already */
1444       wassert(0);
1445       return FALSE;
1446     }
1447 }
1448
1449 /*-------------------------------------------------------------------*/
1450 /* aopGet - for fetching value of the aop                            */
1451 /*                                                                   */
1452 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1453 /* in the accumulator. Set it to the name of a free register         */
1454 /* if acc must be preserved; the register will be used to preserve   */
1455 /* acc temporarily and to return the result byte.                    */
1456 /*-------------------------------------------------------------------*/
1457 static char *
1458 aopGet (operand * oper,
1459         int   offset,
1460         bool  bit16,
1461         bool  dname,
1462         char  *saveAcc)
1463 {
1464   asmop * aop = AOP (oper);
1465
1466   /* offset is greater than
1467      size then zero */
1468   if (offset > (aop->size - 1) &&
1469       aop->type != AOP_LIT)
1470     return zero;
1471
1472   /* depending on type */
1473   switch (aop->type)
1474     {
1475     case AOP_DUMMY:
1476       return zero;
1477
1478     case AOP_R0:
1479     case AOP_R1:
1480       /* if we need to increment it */
1481       while (offset > aop->coff)
1482         {
1483           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1484           aop->coff++;
1485         }
1486
1487       while (offset < aop->coff)
1488         {
1489           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1490           aop->coff--;
1491         }
1492
1493       aop->coff = offset;
1494       if (aop->paged)
1495         {
1496           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1497           return (dname ? "acc" : "a");
1498         }
1499       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1500       return Safe_strdup(buffer);
1501
1502     case AOP_DPTRn:
1503         assert(offset <= 3);
1504         return dptrn[aop->aopu.dptr][offset];
1505
1506     case AOP_DPTR:
1507     case AOP_DPTR2:
1508
1509       if (aop->type == AOP_DPTR2)
1510         {
1511           genSetDPTR (1);
1512         }
1513
1514       if (saveAcc)
1515         {
1516             TR_AP("#1");
1517 //          if (aop->type != AOP_DPTR2)
1518 //          {
1519 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1520 //              emitcode(";", "spanky: saveAcc for DPTR");
1521 //          }
1522
1523             emitcode ("xch", "a, %s", saveAcc);
1524         }
1525
1526       _flushLazyDPS ();
1527
1528       while (offset > aop->coff)
1529         {
1530           emitcode ("inc", "dptr");
1531           aop->coff++;
1532         }
1533
1534       while (offset < aop->coff)
1535         {
1536           emitcode ("lcall", "__decdptr");
1537           aop->coff--;
1538         }
1539
1540       aop->coff = offset;
1541       if (aop->code)
1542         {
1543           emitcode ("clr", "a");
1544           emitcode ("movc", "a,@a+dptr");
1545         }
1546       else
1547         {
1548           emitcode ("movx", "a,@dptr");
1549         }
1550
1551       if (aop->type == AOP_DPTR2)
1552         {
1553           genSetDPTR (0);
1554         }
1555
1556       if (saveAcc)
1557         {
1558           TR_AP("#2");
1559           emitcode ("xch", "a, %s", saveAcc);
1560 //        if (strcmp(saveAcc, "_ap"))
1561 //          {
1562 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1563 //          }
1564
1565           return saveAcc;
1566         }
1567       return (dname ? "acc" : "a");
1568
1569     case AOP_IMMD:
1570       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1571         {
1572           SNPRINTF(buffer, sizeof(buffer),
1573                    "%s",aop->aopu.aop_immd.aop_immd2);
1574         }
1575       else if (bit16)
1576         {
1577           SNPRINTF(buffer, sizeof(buffer),
1578                    "#%s", aop->aopu.aop_immd.aop_immd1);
1579         }
1580       else if (offset)
1581         {
1582           switch (offset) {
1583           case 1:
1584               tsprintf(buffer, sizeof(buffer),
1585                        "#!his",aop->aopu.aop_immd.aop_immd1);
1586               break;
1587           case 2:
1588               tsprintf(buffer, sizeof(buffer),
1589                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1590               break;
1591           case 3:
1592               tsprintf(buffer, sizeof(buffer),
1593                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1594               break;
1595           default: /* should not need this (just in case) */
1596               SNPRINTF (buffer, sizeof(buffer),
1597                         "#(%s >> %d)",
1598                        aop->aopu.aop_immd.aop_immd1,
1599                        offset * 8);
1600           }
1601         }
1602       else
1603         {
1604           SNPRINTF (buffer, sizeof(buffer),
1605                     "#%s",
1606                     aop->aopu.aop_immd.aop_immd1);
1607         }
1608       return Safe_strdup(buffer);
1609
1610     case AOP_DIR:
1611       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1612         {
1613           SNPRINTF (buffer, sizeof(buffer),
1614                     "(%s >> %d)",
1615                     aop->aopu.aop_dir, offset * 8);
1616         }
1617       else if (offset)
1618         {
1619           SNPRINTF (buffer, sizeof(buffer),
1620                     "(%s + %d)",
1621                    aop->aopu.aop_dir,
1622                    offset);
1623         }
1624       else
1625         {
1626           SNPRINTF (buffer, sizeof(buffer),
1627                     "%s",
1628                     aop->aopu.aop_dir);
1629         }
1630
1631       return Safe_strdup(buffer);
1632
1633     case AOP_REG:
1634       if (dname)
1635         return aop->aopu.aop_reg[offset]->dname;
1636       else
1637         return aop->aopu.aop_reg[offset]->name;
1638
1639     case AOP_CRY:
1640       emitcode ("clr", "a");
1641       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1642       emitcode ("rlc", "a");
1643       return (dname ? "acc" : "a");
1644
1645     case AOP_ACC:
1646       if (!offset && dname)
1647         return "acc";
1648       return aop->aopu.aop_str[offset];
1649
1650     case AOP_LIT:
1651       return aopLiteral (aop->aopu.aop_lit, offset);
1652
1653     case AOP_STR:
1654       aop->coff = offset;
1655       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1656           dname)
1657         return "acc";
1658
1659       return aop->aopu.aop_str[offset];
1660
1661     }
1662
1663   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1664           "aopget got unsupported aop->type");
1665   exit (1);
1666
1667   return NULL;  // not reached, but makes compiler happy.
1668 }
1669
1670 /*-----------------------------------------------------------------*/
1671 /* aopPut - puts a string for a aop and indicates if acc is in use */
1672 /*-----------------------------------------------------------------*/
1673 static bool
1674 aopPut (operand * result, const char *s, int offset)
1675 {
1676   bool bvolatile = isOperandVolatile (result, FALSE);
1677   bool accuse = FALSE;
1678   asmop * aop = AOP (result);
1679
1680   if (aop->size && offset > (aop->size - 1))
1681     {
1682       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1683               "aopPut got offset > aop->size");
1684       exit (1);
1685     }
1686
1687   /* will assign value to value */
1688   /* depending on where it is ofcourse */
1689   switch (aop->type)
1690     {
1691     case AOP_DUMMY:
1692       MOVA (s);         /* read s in case it was volatile */
1693       accuse = TRUE;
1694       break;
1695
1696     case AOP_DIR:
1697       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1698         {
1699           SNPRINTF (buffer, sizeof(buffer),
1700                     "(%s >> %d)",
1701                     aop->aopu.aop_dir, offset * 8);
1702         }
1703       else if (offset)
1704         {
1705           SNPRINTF (buffer, sizeof(buffer),
1706                     "(%s + %d)",
1707                     aop->aopu.aop_dir, offset);
1708         }
1709       else
1710         {
1711           SNPRINTF (buffer, sizeof(buffer),
1712                     "%s",
1713                     aop->aopu.aop_dir);
1714         }
1715
1716       if (strcmp (buffer, s) || bvolatile)
1717         {
1718           emitcode ("mov", "%s,%s", buffer, s);
1719         }
1720       if (!strcmp (buffer, "acc"))
1721         {
1722           accuse = TRUE;
1723         }
1724       break;
1725
1726     case AOP_REG:
1727       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1728           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1729         {
1730           if (*s == '@' ||
1731               strcmp (s, "r0") == 0 ||
1732               strcmp (s, "r1") == 0 ||
1733               strcmp (s, "r2") == 0 ||
1734               strcmp (s, "r3") == 0 ||
1735               strcmp (s, "r4") == 0 ||
1736               strcmp (s, "r5") == 0 ||
1737               strcmp (s, "r6") == 0 ||
1738               strcmp (s, "r7") == 0)
1739             {
1740               emitcode ("mov", "%s,%s",
1741                         aop->aopu.aop_reg[offset]->dname, s);
1742             }
1743             else
1744             {
1745               emitcode ("mov", "%s,%s",
1746                         aop->aopu.aop_reg[offset]->name, s);
1747             }
1748         }
1749       break;
1750
1751     case AOP_DPTRn:
1752         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1753         break;
1754
1755     case AOP_DPTR:
1756     case AOP_DPTR2:
1757
1758       if (aop->type == AOP_DPTR2)
1759         {
1760           genSetDPTR (1);
1761         }
1762       _flushLazyDPS ();
1763
1764       if (aop->code)
1765         {
1766           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1767                   "aopPut writing to code space");
1768           exit (1);
1769         }
1770
1771       while (offset > aop->coff)
1772         {
1773           aop->coff++;
1774           emitcode ("inc", "dptr");
1775         }
1776
1777       while (offset < aop->coff)
1778         {
1779           aop->coff--;
1780           emitcode ("lcall", "__decdptr");
1781         }
1782
1783       aop->coff = offset;
1784
1785       /* if not in accumulator */
1786       MOVA (s);
1787
1788       emitcode ("movx", "@dptr,a");
1789
1790       if (aop->type == AOP_DPTR2)
1791         {
1792           genSetDPTR (0);
1793         }
1794       break;
1795
1796     case AOP_R0:
1797     case AOP_R1:
1798       while (offset > aop->coff)
1799         {
1800           aop->coff++;
1801           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1802         }
1803       while (offset < aop->coff)
1804         {
1805           aop->coff--;
1806           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1807         }
1808       aop->coff = offset;
1809
1810       if (aop->paged)
1811         {
1812           MOVA (s);
1813           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1814         }
1815       else if (*s == '@')
1816         {
1817           MOVA (s);
1818           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1819         }
1820       else if (strcmp (s, "r0") == 0 ||
1821                strcmp (s, "r1") == 0 ||
1822                strcmp (s, "r2") == 0 ||
1823                strcmp (s, "r3") == 0 ||
1824                strcmp (s, "r4") == 0 ||
1825                strcmp (s, "r5") == 0 ||
1826                strcmp (s, "r6") == 0 ||
1827                strcmp (s, "r7") == 0)
1828         {
1829           char buffer[10];
1830           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1831           emitcode ("mov", "@%s,%s",
1832                     aop->aopu.aop_ptr->name, buffer);
1833         }
1834         else
1835         {
1836             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1837         }
1838       break;
1839
1840     case AOP_STK:
1841       if (strcmp (s, "a") == 0)
1842         emitcode ("push", "acc");
1843       else
1844         if (*s=='@') {
1845           MOVA(s);
1846           emitcode ("push", "acc");
1847         } else {
1848           emitcode ("push", s);
1849         }
1850
1851       break;
1852
1853     case AOP_CRY:
1854       /* if not bit variable */
1855       if (!aop->aopu.aop_dir)
1856         {
1857           /* inefficient: move carry into A and use jz/jnz */
1858           emitcode ("clr", "a");
1859           emitcode ("rlc", "a");
1860           accuse = TRUE;
1861         }
1862       else
1863         {
1864           if (s == zero)
1865             emitcode ("clr", "%s", aop->aopu.aop_dir);
1866           else if (s == one)
1867             emitcode ("setb", "%s", aop->aopu.aop_dir);
1868           else if (!strcmp (s, "c"))
1869             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1870           else if (strcmp (s, aop->aopu.aop_dir))
1871             {
1872               MOVA (s);
1873               /* set C, if a >= 1 */
1874               emitcode ("add", "a,#!constbyte",0xff);
1875               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1876             }
1877         }
1878       break;
1879
1880     case AOP_STR:
1881       aop->coff = offset;
1882       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1883         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1884       break;
1885
1886     case AOP_ACC:
1887       accuse = TRUE;
1888       aop->coff = offset;
1889       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1890         break;
1891
1892       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1893         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1894       break;
1895
1896     default:
1897       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1898               "aopPut got unsupported aop->type");
1899       exit (1);
1900     }
1901
1902     return accuse;
1903 }
1904
1905
1906 /*--------------------------------------------------------------------*/
1907 /* reAdjustPreg - points a register back to where it should (coff==0) */
1908 /*--------------------------------------------------------------------*/
1909 static void
1910 reAdjustPreg (asmop * aop)
1911 {
1912   if ((aop->coff==0) || (aop->size <= 1))
1913     return;
1914
1915   switch (aop->type)
1916     {
1917     case AOP_R0:
1918     case AOP_R1:
1919       while (aop->coff--)
1920         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1921       break;
1922     case AOP_DPTR:
1923     case AOP_DPTR2:
1924       if (aop->type == AOP_DPTR2)
1925         {
1926           genSetDPTR (1);
1927           _flushLazyDPS ();
1928         }
1929       while (aop->coff--)
1930         {
1931           emitcode ("lcall", "__decdptr");
1932         }
1933
1934       if (aop->type == AOP_DPTR2)
1935         {
1936           genSetDPTR (0);
1937         }
1938       break;
1939     }
1940   aop->coff = 0;
1941 }
1942
1943 /*-----------------------------------------------------------------*/
1944 /* opIsGptr: returns non-zero if the passed operand is       */
1945 /* a generic pointer type.             */
1946 /*-----------------------------------------------------------------*/
1947 static int
1948 opIsGptr (operand * op)
1949 {
1950   sym_link *type = operandType (op);
1951
1952   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1953     {
1954       return 1;
1955     }
1956   return 0;
1957 }
1958
1959 /*-----------------------------------------------------------------*/
1960 /* getDataSize - get the operand data size                         */
1961 /*-----------------------------------------------------------------*/
1962 static int
1963 getDataSize (operand * op)
1964 {
1965   int size;
1966   size = AOP_SIZE (op);
1967   if (size == GPTRSIZE)
1968     {
1969       sym_link *type = operandType (op);
1970       if (IS_GENPTR (type))
1971         {
1972           /* generic pointer; arithmetic operations
1973            * should ignore the high byte (pointer type).
1974            */
1975           size--;
1976         }
1977     }
1978   return size;
1979 }
1980
1981 /*-----------------------------------------------------------------*/
1982 /* outAcc - output Acc                                             */
1983 /*-----------------------------------------------------------------*/
1984 static void
1985 outAcc (operand * result)
1986 {
1987   int size, offset;
1988   size = getDataSize (result);
1989   if (size)
1990     {
1991       aopPut (result, "a", 0);
1992       size--;
1993       offset = 1;
1994       /* unsigned or positive */
1995       while (size--)
1996         {
1997           aopPut (result, zero, offset++);
1998         }
1999     }
2000 }
2001
2002 /*-----------------------------------------------------------------*/
2003 /* outBitC - output a bit C                                        */
2004 /*-----------------------------------------------------------------*/
2005 static void
2006 outBitC (operand * result)
2007 {
2008   /* if the result is bit */
2009   if (AOP_TYPE (result) == AOP_CRY)
2010     {
2011       aopPut (result, "c", 0);
2012     }
2013   else
2014     {
2015       emitcode ("clr", "a");
2016       emitcode ("rlc", "a");
2017       outAcc (result);
2018     }
2019 }
2020
2021 /*-----------------------------------------------------------------*/
2022 /* toBoolean - emit code for orl a,operator(sizeop)                */
2023 /*-----------------------------------------------------------------*/
2024 static void
2025 toBoolean (operand * oper)
2026 {
2027   int  size = AOP_SIZE (oper) - 1;
2028   int  offset = 1;
2029   bool pushedB;
2030
2031   /* The generic part of a generic pointer should
2032    * not participate in it's truth value.
2033    *
2034    * i.e. 0x10000000 is zero.
2035    */
2036   if (opIsGptr (oper))
2037     {
2038       D (emitcode (";", "toBoolean: generic ptr special case."));
2039       size--;
2040     }
2041
2042   _startLazyDPSEvaluation ();
2043   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2044   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2045     {
2046       pushedB = pushB ();
2047       emitcode("mov", "b,a");
2048       while (--size)
2049         {
2050           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2051           emitcode ("orl", "b,a");
2052         }
2053       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2054       emitcode ("orl", "a,b");
2055       popB (pushedB);
2056     }
2057   else
2058     {
2059       while (size--)
2060         {
2061           emitcode ("orl", "a,%s",
2062                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2063         }
2064     }
2065   _endLazyDPSEvaluation ();
2066 }
2067
2068
2069 /*-----------------------------------------------------------------*/
2070 /* genNot - generate code for ! operation                          */
2071 /*-----------------------------------------------------------------*/
2072 static void
2073 genNot (iCode * ic)
2074 {
2075   symbol *tlbl;
2076
2077   D (emitcode (";", "genNot"));
2078
2079   /* assign asmOps to operand & result */
2080   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2081   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2082
2083   /* if in bit space then a special case */
2084   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2085     {
2086       /* if left==result then cpl bit */
2087       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2088         {
2089           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2090         }
2091       else
2092         {
2093           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2094           emitcode ("cpl", "c");
2095           outBitC (IC_RESULT (ic));
2096         }
2097       goto release;
2098     }
2099
2100   toBoolean (IC_LEFT (ic));
2101
2102   /* set C, if a == 0 */
2103   tlbl = newiTempLabel (NULL);
2104   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2105   emitLabel (tlbl);
2106   outBitC (IC_RESULT (ic));
2107
2108 release:
2109   /* release the aops */
2110   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2111   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2112 }
2113
2114
2115 /*-----------------------------------------------------------------*/
2116 /* genCpl - generate code for complement                           */
2117 /*-----------------------------------------------------------------*/
2118 static void
2119 genCpl (iCode * ic)
2120 {
2121   int offset = 0;
2122   int size;
2123   symbol *tlbl;
2124   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2125
2126   D(emitcode (";", "genCpl"));
2127
2128   /* assign asmOps to operand & result */
2129   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2130   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2131
2132   /* special case if in bit space */
2133   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2134     {
2135       char *l;
2136
2137       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2138           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2139         {
2140           /* promotion rules are responsible for this strange result:
2141              bit -> int -> ~int -> bit
2142              uchar -> int -> ~int -> bit
2143           */
2144           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2145           goto release;
2146         }
2147
2148       tlbl=newiTempLabel(NULL);
2149       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2150       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2151           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2152           IS_AOP_PREG (IC_LEFT (ic)))
2153         {
2154           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2155         }
2156       else
2157         {
2158           MOVA (l);
2159           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2160         }
2161       emitLabel (tlbl);
2162       outBitC (IC_RESULT(ic));
2163       goto release;
2164     }
2165
2166   size = AOP_SIZE (IC_RESULT (ic));
2167   _startLazyDPSEvaluation ();
2168   while (size--)
2169     {
2170       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2171       MOVA (l);
2172       emitcode ("cpl", "a");
2173       aopPut (IC_RESULT (ic), "a", offset++);
2174     }
2175   _endLazyDPSEvaluation ();
2176
2177
2178 release:
2179   /* release the aops */
2180   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2181   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2182 }
2183
2184 /*-----------------------------------------------------------------*/
2185 /* genUminusFloat - unary minus for floating points                */
2186 /*-----------------------------------------------------------------*/
2187 static void
2188 genUminusFloat (operand * op, operand * result)
2189 {
2190   int size, offset = 0;
2191   char *l;
2192
2193   D (emitcode (";", "genUminusFloat"));
2194
2195   /* for this we just copy and then flip the bit */
2196
2197   _startLazyDPSEvaluation ();
2198   size = AOP_SIZE (op) - 1;
2199
2200   while (size--)
2201     {
2202       aopPut (result,
2203               aopGet (op, offset, FALSE, FALSE, NULL),
2204               offset);
2205       offset++;
2206     }
2207
2208   l = aopGet (op, offset, FALSE, FALSE, NULL);
2209   MOVA (l);
2210
2211   emitcode ("cpl", "acc.7");
2212   aopPut (result, "a", offset);
2213   _endLazyDPSEvaluation ();
2214 }
2215
2216 /*-----------------------------------------------------------------*/
2217 /* genUminus - unary minus code generation                         */
2218 /*-----------------------------------------------------------------*/
2219 static void
2220 genUminus (iCode * ic)
2221 {
2222   int offset, size;
2223   sym_link *optype;
2224
2225   D (emitcode (";", "genUminus"));
2226
2227   /* assign asmops */
2228   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2229   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2230
2231   /* if both in bit space then special
2232      case */
2233   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2234       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2235     {
2236
2237       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2238       emitcode ("cpl", "c");
2239       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2240       goto release;
2241     }
2242
2243   optype = operandType (IC_LEFT (ic));
2244
2245   /* if float then do float stuff */
2246   if (IS_FLOAT (optype))
2247     {
2248       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2249       goto release;
2250     }
2251
2252   /* otherwise subtract from zero */
2253   size = AOP_SIZE (IC_LEFT (ic));
2254   offset = 0;
2255   _startLazyDPSEvaluation ();
2256   while (size--)
2257     {
2258       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2259       if (!strcmp (l, "a"))
2260         {
2261           if (offset == 0)
2262             SETC;
2263           emitcode ("cpl", "a");
2264           emitcode ("addc", "a,#0");
2265         }
2266       else
2267         {
2268           if (offset == 0)
2269             CLRC;
2270           emitcode ("clr", "a");
2271           emitcode ("subb", "a,%s", l);
2272         }
2273       aopPut (IC_RESULT (ic), "a", offset++);
2274     }
2275   _endLazyDPSEvaluation ();
2276
2277   /* if any remaining bytes in the result */
2278   /* we just need to propagate the sign   */
2279   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2280     {
2281       emitcode ("rlc", "a");
2282       emitcode ("subb", "a,acc");
2283       while (size--)
2284         aopPut (IC_RESULT (ic), "a", offset++);
2285     }
2286
2287 release:
2288   /* release the aops */
2289   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2290   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2291 }
2292
2293 /*-----------------------------------------------------------------*/
2294 /* savermask - saves registers in the mask                         */
2295 /*-----------------------------------------------------------------*/
2296 static void savermask(bitVect *rs_mask)
2297 {
2298   int i;
2299
2300   if (options.useXstack)
2301     {
2302       if (bitVectBitValue (rs_mask, R0_IDX))
2303           emitcode ("mov", "b,r0");
2304       emitcode ("mov", "r0,%s", spname);
2305       for (i = 0; i < ds390_nRegs; i++)
2306         {
2307           if (bitVectBitValue (rs_mask, i))
2308             {
2309               if (i == R0_IDX)
2310                   emitcode ("mov", "a,b");
2311               else
2312                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2313               emitcode ("movx", "@r0,a");
2314               emitcode ("inc", "r0");
2315             }
2316         }
2317       emitcode ("mov", "%s,r0", spname);
2318       if (bitVectBitValue (rs_mask, R0_IDX))
2319           emitcode ("mov", "r0,b");
2320     }
2321   else
2322     {
2323       bool bits_pushed = FALSE;
2324       for (i = 0; i < ds390_nRegs; i++)
2325         {
2326           if (bitVectBitValue (rs_mask, i))
2327             {
2328               bits_pushed = pushReg (i, bits_pushed);
2329             }
2330         }
2331     }
2332 }
2333
2334 /*-----------------------------------------------------------------*/
2335 /* saveRegisters - will look for a call and save the registers     */
2336 /*-----------------------------------------------------------------*/
2337 static void
2338 saveRegisters (iCode * lic)
2339 {
2340   iCode *ic;
2341   bitVect *rsave;
2342
2343   /* look for call */
2344   for (ic = lic; ic; ic = ic->next)
2345     if (ic->op == CALL || ic->op == PCALL)
2346       break;
2347
2348   if (!ic)
2349     {
2350       fprintf (stderr, "found parameter push with no function call\n");
2351       return;
2352     }
2353
2354   /* if the registers have been saved already or don't need to be then
2355      do nothing */
2356   if (ic->regsSaved
2357       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2358     return;
2359
2360   /* special case if DPTR alive across a function call then must save it
2361      even though callee saves */
2362   if (IS_SYMOP(IC_LEFT(ic)) &&
2363       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2364     {
2365       int i;
2366       rsave = newBitVect(ic->rMask->size);
2367       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2368           if (bitVectBitValue(ic->rMask,i))
2369               rsave = bitVectSetBit(rsave,i);
2370       }
2371       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2372     }
2373   else
2374     {
2375       /* save the registers in use at this time but skip the
2376          ones for the result */
2377       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2378                              ds390_rUmaskForOp (IC_RESULT(ic)));
2379     }
2380   ic->regsSaved = 1;
2381   savermask(rsave);
2382 }
2383
2384 /*-----------------------------------------------------------------*/
2385 /* usavermask - restore registers with mask                        */
2386 /*-----------------------------------------------------------------*/
2387 static void unsavermask(bitVect *rs_mask)
2388 {
2389   int i;
2390
2391   if (options.useXstack)
2392     {
2393       emitcode ("mov", "r0,%s", spname);
2394       for (i = ds390_nRegs; i >= 0; i--)
2395         {
2396           if (bitVectBitValue (rs_mask, i))
2397             {
2398               regs * reg = REG_WITH_INDEX (i);
2399               emitcode ("dec", "r0");
2400               emitcode ("movx", "a,@r0");
2401               if (i == R0_IDX)
2402                 {
2403                   emitcode ("push", "acc");
2404                 }
2405               else
2406                 {
2407                   emitcode ("mov", "%s,a", reg->name);
2408                 }
2409             }
2410         }
2411       emitcode ("mov", "%s,r0", spname);
2412       if (bitVectBitValue (rs_mask, R0_IDX))
2413         {
2414           emitcode ("pop", "ar0");
2415         }
2416     }
2417   else
2418     {
2419       bool bits_popped = FALSE;
2420       for (i = ds390_nRegs; i >= 0; i--)
2421         {
2422           if (bitVectBitValue (rs_mask, i))
2423             {
2424               bits_popped = popReg (i, bits_popped);
2425             }
2426         }
2427     }
2428 }
2429
2430 /*-----------------------------------------------------------------*/
2431 /* unsaveRegisters - pop the pushed registers                      */
2432 /*-----------------------------------------------------------------*/
2433 static void
2434 unsaveRegisters (iCode * ic)
2435 {
2436   bitVect *rsave;
2437
2438   if (IS_SYMOP(IC_LEFT (ic)) &&
2439       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2440       int i;
2441       rsave = newBitVect(ic->rMask->size);
2442       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2443           if (bitVectBitValue(ic->rMask,i))
2444               rsave = bitVectSetBit(rsave,i);
2445       }
2446       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2447   } else {
2448     /* restore the registers in use at this time but skip the
2449        ones for the result */
2450     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2451                            ds390_rUmaskForOp (IC_RESULT(ic)));
2452   }
2453   unsavermask(rsave);
2454 }
2455
2456
2457 /*-----------------------------------------------------------------*/
2458 /* pushSide -                                                      */
2459 /*-----------------------------------------------------------------*/
2460 static void
2461 pushSide (operand * oper, int size, iCode * ic)
2462 {
2463   int offset = 0;
2464   int nPushed = _G.r0Pushed + _G.r1Pushed;
2465
2466   aopOp (oper, ic, FALSE, FALSE);
2467
2468   if (nPushed != _G.r0Pushed + _G.r1Pushed)
2469     {
2470       while (offset < size)
2471         {
2472           char *l = aopGet (oper, offset, FALSE, TRUE, NULL);
2473           emitcode ("mov", "%s,%s", fReturn[offset++], l);
2474         }
2475       freeAsmop (oper, NULL, ic, TRUE);
2476       offset = 0;
2477       while (offset < size)
2478         {
2479           emitcode ("push", "%s", fReturn[offset++]);
2480         }
2481       return;
2482     }
2483
2484   _startLazyDPSEvaluation ();
2485   while (size--)
2486     {
2487       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2488       if (AOP_TYPE (oper) != AOP_REG &&
2489           AOP_TYPE (oper) != AOP_DIR &&
2490           strcmp (l, "a"))
2491         {
2492           MOVA (l);
2493           emitcode ("push", "acc");
2494         }
2495       else
2496         {
2497           emitcode ("push", "%s", l);
2498         }
2499     }
2500   _endLazyDPSEvaluation ();
2501   freeAsmop (oper, NULL, ic, TRUE);
2502 }
2503
2504 /*-----------------------------------------------------------------*/
2505 /* assignResultValue - also indicates if acc is in use afterwards  */
2506 /*-----------------------------------------------------------------*/
2507 static bool
2508 assignResultValue (operand * oper, operand * func)
2509 {
2510   int offset = 0;
2511   unsigned size = AOP_SIZE (oper);
2512   bool accuse = FALSE;
2513   bool pushedA = FALSE;
2514
2515   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2516     {
2517       outBitC (oper);
2518       return FALSE;
2519     }
2520
2521   if (size == fReturnSizeDS390)
2522   {
2523       /* I don't think this case can ever happen... */
2524       /* ACC is the last part of this. If writing the result
2525        * uses ACC, we must preserve it.
2526        */
2527       if (AOP_NEEDSACC(oper))
2528       {
2529           emitcode(";", "assignResultValue special case for ACC.");
2530           emitcode("push", "acc");
2531           pushedA = TRUE;
2532           size--;
2533       }
2534   }
2535
2536   _startLazyDPSEvaluation ();
2537   while (size--)
2538     {
2539       accuse |= aopPut (oper, fReturn[offset], offset);
2540       offset++;
2541     }
2542   _endLazyDPSEvaluation ();
2543
2544   if (pushedA)
2545     {
2546         emitcode ("pop", "acc");
2547         accuse |= aopPut (oper, "a", offset);
2548     }
2549   return accuse;
2550 }
2551
2552
2553 /*-----------------------------------------------------------------*/
2554 /* genXpush - pushes onto the external stack                       */
2555 /*-----------------------------------------------------------------*/
2556 static void
2557 genXpush (iCode * ic)
2558 {
2559   asmop *aop = newAsmop (0);
2560   regs *r;
2561   int size, offset = 0;
2562
2563   D (emitcode (";", "genXpush"));
2564
2565   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2566   r = getFreePtr (ic, &aop, FALSE);
2567
2568   size = AOP_SIZE (IC_LEFT (ic));
2569
2570   if (size == 1)
2571     {
2572       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2573       emitcode ("mov", "%s,_spx", r->name);
2574       emitcode ("inc", "_spx"); // allocate space first
2575       emitcode ("movx", "@%s,a", r->name);
2576     }
2577   else
2578     {
2579       // allocate space first
2580       emitcode ("mov", "%s,_spx", r->name);
2581       MOVA (r->name);
2582       emitcode ("add", "a,#%d", size);
2583       emitcode ("mov", "_spx,a");
2584
2585       _startLazyDPSEvaluation ();
2586       while (size--)
2587         {
2588           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2589           emitcode ("movx", "@%s,a", r->name);
2590           emitcode ("inc", "%s", r->name);
2591         }
2592       _endLazyDPSEvaluation ();
2593     }
2594
2595   freeAsmop (NULL, aop, ic, TRUE);
2596   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2597 }
2598
2599 /*-----------------------------------------------------------------*/
2600 /* genIpush - generate code for pushing this gets a little complex  */
2601 /*-----------------------------------------------------------------*/
2602 static void
2603 genIpush (iCode * ic)
2604 {
2605   int size, offset = 0;
2606   char *l;
2607   char *prev = "";
2608
2609   D (emitcode (";", "genIpush"));
2610
2611   /* if this is not a parm push : ie. it is spill push
2612      and spill push is always done on the local stack */
2613   if (!ic->parmPush)
2614     {
2615
2616       /* and the item is spilt then do nothing */
2617       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2618         return;
2619
2620       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2621       size = AOP_SIZE (IC_LEFT (ic));
2622       /* push it on the stack */
2623       _startLazyDPSEvaluation ();
2624       while (size--)
2625         {
2626           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2627           if (*l == '#')
2628             {
2629               MOVA (l);
2630               l = "acc";
2631             }
2632           emitcode ("push", "%s", l);
2633         }
2634       _endLazyDPSEvaluation ();
2635       return;
2636     }
2637
2638   /* this is a parameter push: in this case we call
2639      the routine to find the call and save those
2640      registers that need to be saved */
2641   saveRegisters (ic);
2642
2643   /* if use external stack then call the external
2644      stack pushing routine */
2645   if (options.useXstack)
2646     {
2647       genXpush (ic);
2648       return;
2649     }
2650
2651   /* then do the push */
2652   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2653
2654   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2655   size = AOP_SIZE (IC_LEFT (ic));
2656
2657   _startLazyDPSEvaluation ();
2658   while (size--)
2659     {
2660       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2661       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2662           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2663           strcmp (l, "acc"))
2664         {
2665           if (strcmp (l, prev) || *l == '@')
2666             MOVA (l);
2667           emitcode ("push", "acc");
2668         }
2669       else
2670         {
2671             emitcode ("push", "%s", l);
2672         }
2673       prev = l;
2674     }
2675   _endLazyDPSEvaluation ();
2676
2677   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2678 }
2679
2680 /*-----------------------------------------------------------------*/
2681 /* genIpop - recover the registers: can happen only for spilling   */
2682 /*-----------------------------------------------------------------*/
2683 static void
2684 genIpop (iCode * ic)
2685 {
2686   int size, offset;
2687
2688   D (emitcode (";", "genIpop"));
2689
2690   /* if the temp was not pushed then */
2691   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2692     return;
2693
2694   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2695   size = AOP_SIZE (IC_LEFT (ic));
2696   offset = (size - 1);
2697   _startLazyDPSEvaluation ();
2698   while (size--)
2699     {
2700       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2701                                      FALSE, TRUE, NULL));
2702     }
2703   _endLazyDPSEvaluation ();
2704
2705   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2706 }
2707
2708 /*-----------------------------------------------------------------*/
2709 /* saveRBank - saves an entire register bank on the stack          */
2710 /*-----------------------------------------------------------------*/
2711 static void
2712 saveRBank (int bank, iCode * ic, bool pushPsw)
2713 {
2714   int i;
2715   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2716   asmop *aop = NULL;
2717   regs *r = NULL;
2718
2719   if (options.useXstack)
2720     {
2721       if (!ic)
2722         {
2723           /* Assume r0 is available for use. */
2724           r = REG_WITH_INDEX (R0_IDX);;
2725         }
2726       else
2727         {
2728           aop = newAsmop (0);
2729           r = getFreePtr (ic, &aop, FALSE);
2730         }
2731       // allocate space first
2732       emitcode ("mov", "%s,_spx", r->name);
2733       MOVA (r->name);
2734       emitcode ("add", "a,#%d", count);
2735       emitcode ("mov", "_spx,a");
2736     }
2737
2738   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2739     {
2740       if (options.useXstack)
2741         {
2742           emitcode ("mov", "a,(%s+%d)",
2743                     regs390[i].base, 8 * bank + regs390[i].offset);
2744           emitcode ("movx", "@%s,a", r->name);
2745           if (--count)
2746             emitcode ("inc", "%s", r->name);
2747         }
2748       else
2749         emitcode ("push", "(%s+%d)",
2750                   regs390[i].base, 8 * bank + regs390[i].offset);
2751     }
2752
2753   if (ds390_nBitRegs > 0)
2754     {
2755       if (options.useXstack)
2756         {
2757           emitcode ("mov", "a,bits");
2758           emitcode ("movx", "@%s,a", r->name);
2759           if (--count)
2760             emitcode ("inc", "%s", r->name);
2761         }
2762       else
2763         {
2764           emitcode ("push", "bits");
2765         }
2766       BitBankUsed = 1;
2767     }
2768
2769   if (pushPsw)
2770     {
2771       if (options.useXstack)
2772         {
2773           emitcode ("mov", "a,psw");
2774           emitcode ("movx", "@%s,a", r->name);
2775         }
2776       else
2777       {
2778         emitcode ("push", "psw");
2779       }
2780
2781       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2782     }
2783
2784   if (aop)
2785     {
2786       freeAsmop (NULL, aop, ic, TRUE);
2787     }
2788
2789   if (ic)
2790   {
2791     ic->bankSaved = 1;
2792   }
2793 }
2794
2795 /*-----------------------------------------------------------------*/
2796 /* unsaveRBank - restores the register bank from stack             */
2797 /*-----------------------------------------------------------------*/
2798 static void
2799 unsaveRBank (int bank, iCode * ic, bool popPsw)
2800 {
2801   int i;
2802   asmop *aop = NULL;
2803   regs *r = NULL;
2804
2805   if (options.useXstack)
2806     {
2807       if (!ic)
2808         {
2809           /* Assume r0 is available for use. */
2810           r = REG_WITH_INDEX (R0_IDX);;
2811         }
2812       else
2813         {
2814           aop = newAsmop (0);
2815           r = getFreePtr (ic, &aop, FALSE);
2816         }
2817       emitcode ("mov", "%s,_spx", r->name);
2818     }
2819
2820   if (popPsw)
2821     {
2822       if (options.useXstack)
2823         {
2824           emitcode ("dec", "%s", r->name);
2825           emitcode ("movx", "a,@%s", r->name);
2826           emitcode ("mov", "psw,a");
2827         }
2828       else
2829       {
2830         emitcode ("pop", "psw");
2831       }
2832     }
2833
2834   if (ds390_nBitRegs > 0)
2835     {
2836       if (options.useXstack)
2837         {
2838           emitcode ("dec", "%s", r->name);
2839           emitcode ("movx", "a,@%s", r->name);
2840           emitcode ("mov", "bits,a");
2841         }
2842       else
2843         {
2844           emitcode ("pop", "bits");
2845         }
2846     }
2847
2848   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2849     {
2850       if (options.useXstack)
2851         {
2852           emitcode ("dec", "%s", r->name);
2853           emitcode ("movx", "a,@%s", r->name);
2854           emitcode ("mov", "(%s+%d),a",
2855                     regs390[i].base, 8 * bank + regs390[i].offset);
2856         }
2857       else
2858         {
2859           emitcode ("pop", "(%s+%d)",
2860                     regs390[i].base, 8 * bank + regs390[i].offset);
2861         }
2862     }
2863
2864   if (options.useXstack)
2865     {
2866       emitcode ("mov", "_spx,%s", r->name);
2867     }
2868
2869   if (aop)
2870     {
2871       freeAsmop (NULL, aop, ic, TRUE);
2872     }
2873 }
2874
2875 /*-----------------------------------------------------------------*/
2876 /* genSend - gen code for SEND                                     */
2877 /*-----------------------------------------------------------------*/
2878 static void genSend(set *sendSet)
2879 {
2880   iCode *sic;
2881   int bit_count = 0;
2882   int sendCount = 0 ;
2883   static int rb1_count = 0;
2884
2885   /* first we do all bit parameters */
2886   for (sic = setFirstItem (sendSet); sic;
2887        sic = setNextItem (sendSet))
2888     {
2889       if (sic->argreg > 12)
2890         {
2891           int bit = sic->argreg-13;
2892
2893           aopOp (IC_LEFT (sic), sic, FALSE,
2894                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2895
2896           /* if left is a literal then
2897              we know what the value is */
2898           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2899             {
2900               if (((int) operandLitValue (IC_LEFT (sic))))
2901                   emitcode ("setb", "b[%d]", bit);
2902               else
2903                   emitcode ("clr", "b[%d]", bit);
2904             }
2905           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2906             {
2907               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2908                 if (strcmp (l, "c"))
2909                     emitcode ("mov", "c,%s", l);
2910                 emitcode ("mov", "b[%d],c", bit);
2911             }
2912           else
2913             {
2914               /* we need to or */
2915               toBoolean (IC_LEFT (sic));
2916               /* set C, if a >= 1 */
2917               emitcode ("add", "a,#0xff");
2918               emitcode ("mov", "b[%d],c", bit);
2919             }
2920           bit_count++;
2921           BitBankUsed = 1;
2922
2923           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2924         }
2925     }
2926
2927   if (bit_count)
2928     {
2929       saveRegisters (setFirstItem (sendSet));
2930       emitcode ("mov", "bits,b");
2931     }
2932
2933   /* then we do all other parameters */
2934   for (sic = setFirstItem (sendSet); sic;
2935        sic = setNextItem (sendSet))
2936     {
2937       if (sic->argreg <= 12)
2938       {
2939         int size, offset = 0;
2940
2941         size = getSize (operandType (IC_LEFT (sic)));
2942         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2943         if (sendCount == 0) { /* first parameter */
2944             // we know that dpl(hxb) is the result, so
2945             rb1_count = 0 ;
2946             _startLazyDPSEvaluation ();
2947             if (size>1) {
2948                 aopOp (IC_LEFT (sic), sic, FALSE,
2949                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2950             } else {
2951                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2952             }
2953             while (size--)
2954               {
2955                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2956                 if (strcmp (l, fReturn[offset]))
2957                   {
2958                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2959                   }
2960                 offset++;
2961               }
2962             _endLazyDPSEvaluation ();
2963             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2964             rb1_count =0;
2965         } else { /* if more parameter in registers */
2966             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2967             while (size--) {
2968                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2969                                                                 FALSE, FALSE, NULL));
2970             }
2971             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2972         }
2973         sendCount++;
2974       }
2975     }
2976 }
2977
2978 static void
2979 adjustEsp(const char *reg)
2980 {
2981     emitcode ("anl","%s,#3", reg);
2982     if (TARGET_IS_DS400)
2983     {
2984         emitcode ("orl","%s,#!constbyte",
2985                   reg,
2986                   (options.stack_loc >> 8) & 0xff);
2987     }
2988 }
2989
2990 /*-----------------------------------------------------------------*/
2991 /* selectRegBank - emit code to select the register bank           */
2992 /*-----------------------------------------------------------------*/
2993 static void
2994 selectRegBank (short bank, bool keepFlags)
2995 {
2996   /* if f.e. result is in carry */
2997   if (keepFlags)
2998     {
2999       emitcode ("anl", "psw,#0xE7");
3000       if (bank)
3001         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
3002     }
3003   else
3004     {
3005       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
3006     }
3007 }
3008
3009 /*-----------------------------------------------------------------*/
3010 /* genCall - generates a call statement                            */
3011 /*-----------------------------------------------------------------*/
3012 static void
3013 genCall (iCode * ic)
3014 {
3015   sym_link *dtype;
3016   sym_link *etype;
3017   bool restoreBank = FALSE;
3018   bool swapBanks = FALSE;
3019   bool accuse = FALSE;
3020   bool accPushed = FALSE;
3021   bool resultInF0 = FALSE;
3022   bool assignResultGenerated = FALSE;
3023
3024   D (emitcode (";", "genCall"));
3025
3026   /* if we are calling a not _naked function that is not using
3027      the same register bank then we need to save the
3028      destination registers on the stack */
3029   dtype = operandType (IC_LEFT (ic));
3030   etype = getSpec(dtype);
3031   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3032       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3033       IFFUNC_ISISR (currFunc->type))
3034   {
3035       if (!ic->bankSaved)
3036       {
3037            /* This is unexpected; the bank should have been saved in
3038             * genFunction.
3039             */
3040            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3041            restoreBank = TRUE;
3042       }
3043       swapBanks = TRUE;
3044   }
3045
3046   /* if caller saves & we have not saved then */
3047   if (!ic->regsSaved)
3048       saveRegisters (ic);
3049
3050   /* if send set is not empty then assign */
3051   /* We've saved all the registers we care about;
3052   * therefore, we may clobber any register not used
3053   * in the calling convention (i.e. anything not in
3054   * fReturn.
3055   */
3056   if (_G.sendSet)
3057     {
3058         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3059             genSend(reverseSet(_G.sendSet));
3060         } else {
3061             genSend(_G.sendSet);
3062         }
3063       _G.sendSet = NULL;
3064     }
3065
3066   if (swapBanks)
3067     {
3068       emitcode ("mov", "psw,#!constbyte",
3069          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3070     }
3071
3072   /* make the call */
3073   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3074                             OP_SYMBOL (IC_LEFT (ic))->rname :
3075                             OP_SYMBOL (IC_LEFT (ic))->name));
3076
3077   if (swapBanks)
3078     {
3079       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3080     }
3081
3082   /* if we need assign a result value */
3083   if ((IS_ITEMP (IC_RESULT (ic)) &&
3084        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3085        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3086         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3087         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3088       IS_TRUE_SYMOP (IC_RESULT (ic)))
3089     {
3090       if (isOperandInFarSpace (IC_RESULT (ic))
3091           && getSize (operandType (IC_RESULT (ic))) <= 2)
3092         {
3093           int size = getSize (operandType (IC_RESULT (ic)));
3094           bool pushedB = FALSE;
3095
3096           /* Special case for 1 or 2 byte return in far space. */
3097           MOVA (fReturn[0]);
3098           if (size > 1)
3099             {
3100               pushedB = pushB ();
3101               emitcode ("mov", "b,%s", fReturn[1]);
3102             }
3103
3104           _G.accInUse++;
3105           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3106           _G.accInUse--;
3107
3108           popB (pushedB);
3109
3110           aopPut (IC_RESULT (ic), "a", 0);
3111
3112           if (size > 1)
3113             {
3114               aopPut (IC_RESULT (ic), "b", 1);
3115             }
3116           assignResultGenerated = TRUE;
3117           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3118         }
3119       else
3120         {
3121           bool pushedB = pushB ();
3122           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3123           popB (pushedB);
3124
3125           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3126           assignResultGenerated = TRUE;
3127           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3128         }
3129     }
3130
3131   /* adjust the stack for parameters if required */
3132   if (ic->parmBytes)
3133     {
3134       int i;
3135       if (options.stack10bit) {
3136           if (ic->parmBytes <= 10) {
3137               emitcode(";","stack adjustment for parms");
3138               for (i=0; i < ic->parmBytes ; i++) {
3139                   emitcode("pop","acc");
3140               }
3141           } else {
3142               PROTECT_SP;
3143               emitcode ("clr","c");
3144               emitcode ("mov","a,sp");
3145               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3146               emitcode ("mov","sp,a");
3147               emitcode ("mov","a,esp");
3148               adjustEsp("a");
3149               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3150               emitcode ("mov","esp,a");
3151               UNPROTECT_SP;
3152           }
3153       } else {
3154           if (ic->parmBytes > 3)
3155             {
3156               if (accuse)
3157                 {
3158                   emitcode ("push", "acc");
3159                   accPushed = TRUE;
3160                 }
3161               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3162                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3163                   !assignResultGenerated)
3164                 {
3165                   emitcode ("mov", "F0,c");
3166                   resultInF0 = TRUE;
3167                 }
3168
3169               emitcode ("mov", "a,%s", spname);
3170               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3171               emitcode ("mov", "%s,a", spname);
3172
3173               /* unsaveRegisters from xstack needs acc, but */
3174               /* unsaveRegisters from stack needs this popped */
3175               if (accPushed && !options.useXstack)
3176                 {
3177                   emitcode ("pop", "acc");
3178                   accPushed = FALSE;
3179                 }
3180             }
3181           else
3182               for (i = 0; i < ic->parmBytes; i++)
3183                   emitcode ("dec", "%s", spname);
3184       }
3185   }
3186
3187   /* if we had saved some registers then unsave them */
3188   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3189     {
3190       if (accuse && !accPushed && options.useXstack)
3191         {
3192           /* xstack needs acc, but doesn't touch normal stack */
3193           emitcode ("push", "acc");
3194           accPushed = TRUE;
3195         }
3196       unsaveRegisters (ic);
3197     }
3198
3199   /* if register bank was saved then pop them */
3200   if (restoreBank)
3201     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3202
3203   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3204     {
3205       if (resultInF0)
3206           emitcode ("mov", "c,F0");
3207
3208       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3209       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3210       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3211     }
3212
3213   if (accPushed)
3214     emitcode ("pop", "acc");
3215 }
3216
3217 /*-----------------------------------------------------------------*/
3218 /* genPcall - generates a call by pointer statement                */
3219 /*-----------------------------------------------------------------*/
3220 static void
3221 genPcall (iCode * ic)
3222 {
3223   sym_link *dtype;
3224   sym_link *etype;
3225   symbol *rlbl = newiTempLabel (NULL);
3226   bool restoreBank=FALSE;
3227   bool resultInF0 = FALSE;
3228
3229   D (emitcode (";", "genPcall"));
3230
3231   dtype = operandType (IC_LEFT (ic))->next;
3232   etype = getSpec(dtype);
3233   /* if caller saves & we have not saved then */
3234   if (!ic->regsSaved)
3235     saveRegisters (ic);
3236
3237   /* if we are calling a not _naked function that is not using
3238      the same register bank then we need to save the
3239      destination registers on the stack */
3240   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3241       IFFUNC_ISISR (currFunc->type) &&
3242       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3243     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3244     restoreBank=TRUE;
3245   }
3246
3247   /* push the return address on to the stack */
3248   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3249   emitcode ("push", "acc");
3250   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3251   emitcode ("push", "acc");
3252
3253   if (options.model == MODEL_FLAT24)
3254     {
3255       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3256       emitcode ("push", "acc");
3257     }
3258
3259   /* now push the function address */
3260   pushSide (IC_LEFT (ic), FPTRSIZE, ic);
3261
3262   /* if send set is not empty then assign */
3263   if (_G.sendSet)
3264     {
3265         genSend(reverseSet(_G.sendSet));
3266         _G.sendSet = NULL;
3267     }
3268
3269   /* make the call */
3270   emitcode ("ret", "");
3271   emitLabel (rlbl);
3272
3273
3274   /* if we need assign a result value */
3275   if ((IS_ITEMP (IC_RESULT (ic)) &&
3276        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3277        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3278         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3279       IS_TRUE_SYMOP (IC_RESULT (ic)))
3280     {
3281
3282       _G.accInUse++;
3283       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3284       _G.accInUse--;
3285
3286       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3287
3288       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3289     }
3290
3291   /* adjust the stack for parameters if required */
3292   if (ic->parmBytes)
3293     {
3294       int i;
3295       if (options.stack10bit) {
3296           if (ic->parmBytes <= 10) {
3297               emitcode(";","stack adjustment for parms");
3298               for (i=0; i < ic->parmBytes ; i++) {
3299                   emitcode("pop","acc");
3300               }
3301           } else {
3302               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3303                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3304                 {
3305                   emitcode ("mov", "F0,c");
3306                   resultInF0 = TRUE;
3307                 }
3308
3309               PROTECT_SP;
3310               emitcode ("clr","c");
3311               emitcode ("mov","a,sp");
3312               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3313               emitcode ("mov","sp,a");
3314               emitcode ("mov","a,esp");
3315               adjustEsp("a");
3316               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3317               emitcode ("mov","esp,a");
3318               UNPROTECT_SP;
3319           }
3320       } else {
3321           if (ic->parmBytes > 3) {
3322               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3323                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3324                 {
3325                   emitcode ("mov", "F0,c");
3326                   resultInF0 = TRUE;
3327                 }
3328
3329               emitcode ("mov", "a,%s", spname);
3330               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3331               emitcode ("mov", "%s,a", spname);
3332           }
3333           else
3334               for (i = 0; i < ic->parmBytes; i++)
3335                   emitcode ("dec", "%s", spname);
3336       }
3337     }
3338   /* if register bank was saved then unsave them */
3339   if (restoreBank)
3340     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3341
3342   /* if we had saved some registers then unsave them */
3343   if (ic->regsSaved)
3344     unsaveRegisters (ic);
3345
3346   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3347     {
3348       if (resultInF0)
3349           emitcode ("mov", "c,F0");
3350
3351       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3352       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3353       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3354     }
3355 }
3356
3357 /*-----------------------------------------------------------------*/
3358 /* resultRemat - result  is rematerializable                       */
3359 /*-----------------------------------------------------------------*/
3360 static int
3361 resultRemat (iCode * ic)
3362 {
3363   if (SKIP_IC (ic) || ic->op == IFX)
3364     return 0;
3365
3366   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3367     {
3368       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3369       if (sym->remat && !POINTER_SET (ic))
3370         return 1;
3371     }
3372
3373   return 0;
3374 }
3375
3376 /*-----------------------------------------------------------------*/
3377 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3378 /*-----------------------------------------------------------------*/
3379 static int
3380 regsCmp(void *p1, void *p2)
3381 {
3382   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3383 }
3384
3385 static bool
3386 inExcludeList (char *s)
3387 {
3388   const char *p = setFirstItem(options.excludeRegsSet);
3389
3390   if (p == NULL || STRCASECMP(p, "none") == 0)
3391     return FALSE;
3392
3393
3394   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3395 }
3396
3397 /*-----------------------------------------------------------------*/
3398 /* genFunction - generated code for function entry                 */
3399 /*-----------------------------------------------------------------*/
3400 static void
3401 genFunction (iCode * ic)
3402 {
3403   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3404   sym_link *ftype;
3405   bool     switchedPSW = FALSE;
3406   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3407
3408   D (emitcode (";", "genFunction"));
3409
3410   _G.nRegsSaved = 0;
3411   /* create the function header */
3412   emitcode (";", "-----------------------------------------");
3413   emitcode (";", " function %s", sym->name);
3414   emitcode (";", "-----------------------------------------");
3415
3416   emitcode ("", "%s:", sym->rname);
3417   lineCurr->isLabel = 1;
3418   ftype = operandType (IC_LEFT (ic));
3419   _G.currentFunc = sym;
3420
3421   if (IFFUNC_ISNAKED(ftype))
3422   {
3423       emitcode(";", "naked function: no prologue.");
3424       return;
3425   }
3426
3427   if (options.stack_probe)
3428       emitcode ("lcall","__stack_probe");
3429
3430   /* here we need to generate the equates for the
3431      register bank if required */
3432   if (FUNC_REGBANK (ftype) != rbank)
3433     {
3434       int i;
3435
3436       rbank = FUNC_REGBANK (ftype);
3437       for (i = 0; i < ds390_nRegs; i++)
3438         {
3439           if (regs390[i].print) {
3440               if (strcmp (regs390[i].base, "0") == 0)
3441                   emitcode ("", "%s !equ !constbyte",
3442                             regs390[i].dname,
3443                             8 * rbank + regs390[i].offset);
3444               else
3445                   emitcode ("", "%s !equ %s + !constbyte",
3446                             regs390[i].dname,
3447                             regs390[i].base,
3448                             8 * rbank + regs390[i].offset);
3449           }
3450         }
3451     }
3452
3453   /* if this is an interrupt service routine then
3454      save acc, b, dpl, dph  */
3455   if (IFFUNC_ISISR (sym->type))
3456       { /* is ISR */
3457       if (!inExcludeList ("acc"))
3458         emitcode ("push", "acc");
3459       if (!inExcludeList ("b"))
3460         emitcode ("push", "b");
3461       if (!inExcludeList ("dpl"))
3462         emitcode ("push", "dpl");
3463       if (!inExcludeList ("dph"))
3464         emitcode ("push", "dph");
3465       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3466         {
3467           emitcode ("push", "dpx");
3468           /* Make sure we're using standard DPTR */
3469           emitcode ("push", "dps");
3470           emitcode ("mov", "dps,#0");
3471           if (options.stack10bit)
3472             {
3473               /* This ISR could conceivably use DPTR2. Better save it. */
3474               emitcode ("push", "dpl1");
3475               emitcode ("push", "dph1");
3476               emitcode ("push", "dpx1");
3477               emitcode ("push",  DP2_RESULT_REG);
3478             }
3479         }
3480       /* if this isr has no bank i.e. is going to
3481          run with bank 0 , then we need to save more
3482          registers :-) */
3483       if (!FUNC_REGBANK (sym->type))
3484         {
3485             int i;
3486
3487           /* if this function does not call any other
3488              function then we can be economical and
3489              save only those registers that are used */
3490           if (!IFFUNC_HASFCALL(sym->type))
3491             {
3492               /* if any registers used */
3493               if (sym->regsUsed)
3494                 {
3495                   bool bits_pushed = FALSE;
3496                   /* save the registers used */
3497                   for (i = 0; i < sym->regsUsed->size; i++)
3498                     {
3499                       if (bitVectBitValue (sym->regsUsed, i))
3500                         bits_pushed = pushReg (i, bits_pushed);
3501                     }
3502                 }
3503             }
3504           else
3505             {
3506               /* this function has a function call. We cannot
3507                  determine register usage so we will have to push the
3508                  entire bank */
3509               saveRBank (0, ic, FALSE);
3510               if (options.parms_in_bank1) {
3511                   for (i=0; i < 8 ; i++ ) {
3512                       emitcode ("push","%s",rb1regs[i]);
3513                   }
3514               }
3515             }
3516         }
3517         else
3518         {
3519             /* This ISR uses a non-zero bank.
3520              *
3521              * We assume that the bank is available for our
3522              * exclusive use.
3523              *
3524              * However, if this ISR calls a function which uses some
3525              * other bank, we must save that bank entirely.
3526              */
3527             unsigned long banksToSave = 0;
3528
3529             if (IFFUNC_HASFCALL(sym->type))
3530             {
3531
3532 #define MAX_REGISTER_BANKS 4
3533
3534                 iCode *i;
3535                 int ix;
3536
3537                 for (i = ic; i; i = i->next)
3538                 {
3539                     if (i->op == ENDFUNCTION)
3540                     {
3541                         /* we got to the end OK. */
3542                         break;
3543                     }
3544
3545                     if (i->op == CALL)
3546                     {
3547                         sym_link *dtype;
3548
3549                         dtype = operandType (IC_LEFT(i));
3550                         if (dtype
3551                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3552                         {
3553                              /* Mark this bank for saving. */
3554                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3555                              {
3556                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3557                              }
3558                              else
3559                              {
3560                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3561                              }
3562
3563                              /* And note that we don't need to do it in
3564                               * genCall.
3565                               */
3566                              i->bankSaved = 1;
3567                         }
3568                     }
3569                     if (i->op == PCALL)
3570                     {
3571                         /* This is a mess; we have no idea what
3572                          * register bank the called function might
3573                          * use.
3574                          *
3575                          * The only thing I can think of to do is
3576                          * throw a warning and hope.
3577                          */
3578                         werror(W_FUNCPTR_IN_USING_ISR);
3579                     }
3580                 }
3581
3582                 if (banksToSave && options.useXstack)
3583                 {
3584                     /* Since we aren't passing it an ic,
3585                      * saveRBank will assume r0 is available to abuse.
3586                      *
3587                      * So switch to our (trashable) bank now, so
3588                      * the caller's R0 isn't trashed.
3589                      */
3590                     emitcode ("push", "psw");
3591                     emitcode ("mov", "psw,#!constbyte",
3592                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3593                     switchedPSW = TRUE;
3594                 }
3595
3596                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3597                 {
3598                      if (banksToSave & (1 << ix))
3599                      {
3600                          saveRBank(ix, NULL, FALSE);
3601                      }
3602                 }
3603             }
3604             // TODO: this needs a closer look
3605             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3606         }
3607     }
3608   else
3609     {
3610       /* if callee-save to be used for this function
3611          then save the registers being used in this function */
3612       if (IFFUNC_CALLEESAVES(sym->type))
3613         {
3614           int i;
3615
3616           /* if any registers used */
3617           if (sym->regsUsed)
3618             {
3619               bool bits_pushed = FALSE;
3620               /* save the registers used */
3621               for (i = 0; i < sym->regsUsed->size; i++)
3622                 {
3623                   if (bitVectBitValue (sym->regsUsed, i))
3624                     {
3625                       bits_pushed = pushReg (i, bits_pushed);
3626                       _G.nRegsSaved++;
3627                     }
3628                 }
3629             }
3630         }
3631     }
3632
3633   /* set the register bank to the desired value */
3634   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3635    && !switchedPSW)
3636     {
3637       emitcode ("push", "psw");
3638       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3639     }
3640
3641   if (fReentrant &&
3642        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3643       if (options.stack10bit) {
3644           emitcode ("push","_bpx");
3645           emitcode ("push","_bpx+1");
3646           emitcode ("mov","_bpx,%s",spname);
3647           emitcode ("mov","_bpx+1,esp");
3648           adjustEsp("_bpx+1");
3649       } else {
3650           if (options.useXstack)
3651           {
3652               emitcode ("mov", "r0,%s", spname);
3653               emitcode ("mov", "a,_bp");
3654               emitcode ("movx", "@r0,a");
3655               emitcode ("inc", "%s", spname);
3656           } else {
3657               /* set up the stack */
3658               emitcode ("push", "_bp"); /* save the callers stack  */
3659           }
3660           emitcode ("mov", "_bp,%s", spname);
3661       }
3662   }
3663
3664   /* adjust the stack for the function */
3665   if (sym->stack) {
3666       int i = sym->stack;
3667       if (options.stack10bit) {
3668           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3669           assert (sym->recvSize <= 4);
3670           if (sym->stack <= 8) {
3671               while (i--) emitcode ("push","acc");
3672           } else {
3673               PROTECT_SP;
3674               emitcode ("mov","a,sp");
3675               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3676               emitcode ("mov","sp,a");
3677               emitcode ("mov","a,esp");
3678               adjustEsp("a");
3679               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3680               emitcode ("mov","esp,a");
3681               UNPROTECT_SP;
3682           }
3683       } else {
3684           if (i > 256)
3685               werror (W_STACK_OVERFLOW, sym->name);
3686
3687           if (i > 3 && sym->recvSize < 4) {
3688
3689               emitcode ("mov", "a,sp");
3690               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3691               emitcode ("mov", "sp,a");
3692
3693           } else
3694               while (i--)
3695                   emitcode ("inc", "sp");
3696       }
3697   }
3698
3699   if (sym->xstack)
3700     {
3701
3702       emitcode ("mov", "a,_spx");
3703       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3704       emitcode ("mov", "_spx,a");
3705     }
3706
3707   /* if critical function then turn interrupts off */
3708   if (IFFUNC_ISCRITICAL (ftype))
3709     {
3710       symbol *tlbl = newiTempLabel (NULL);
3711       emitcode ("setb", "c");
3712       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3713       emitcode ("clr", "c");
3714       emitLabel (tlbl);
3715       emitcode ("push", "psw"); /* save old ea via c in psw */
3716     }
3717 }
3718
3719 /*-----------------------------------------------------------------*/
3720 /* genEndFunction - generates epilogue for functions               */
3721 /*-----------------------------------------------------------------*/
3722 static void
3723 genEndFunction (iCode * ic)
3724 {
3725   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3726   lineNode *lnp = lineCurr;
3727   bitVect *regsUsed;
3728   bitVect *regsUsedPrologue;
3729   bitVect *regsUnneeded;
3730   int idx;
3731
3732   D (emitcode (";", "genEndFunction"));
3733
3734   _G.currentFunc = NULL;
3735   if (IFFUNC_ISNAKED(sym->type))
3736   {
3737       emitcode(";", "naked function: no epilogue.");
3738       if (options.debug && currFunc)
3739         debugFile->writeEndFunction (currFunc, ic, 0);
3740       return;
3741   }
3742
3743   if (IFFUNC_ISCRITICAL (sym->type))
3744     {
3745       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3746         {
3747           emitcode ("rlc", "a");   /* save c in a */
3748           emitcode ("pop", "psw"); /* restore ea via c in psw */
3749           emitcode ("mov", "ea,c");
3750           emitcode ("rrc", "a");   /* restore c from a */
3751         }
3752       else
3753         {
3754           emitcode ("pop", "psw"); /* restore ea via c in psw */
3755           emitcode ("mov", "ea,c");
3756         }
3757     }
3758
3759   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3760        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3761
3762       if (options.stack10bit) {
3763           PROTECT_SP;
3764           emitcode ("mov", "sp,_bpx", spname);
3765           emitcode ("mov", "esp,_bpx+1", spname);
3766           UNPROTECT_SP;
3767       } else {
3768           emitcode ("mov", "%s,_bp", spname);
3769       }
3770   }
3771
3772   /* if use external stack but some variables were
3773      added to the local stack then decrement the
3774      local stack */
3775   if (options.useXstack && sym->stack) {
3776       emitcode ("mov", "a,sp");
3777       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3778       emitcode ("mov", "sp,a");
3779   }
3780
3781
3782   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3783        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3784
3785       if (options.useXstack) {
3786           emitcode ("mov", "r0,%s", spname);
3787           emitcode ("movx", "a,@r0");
3788           emitcode ("mov", "_bp,a");
3789           emitcode ("dec", "%s", spname);
3790       } else {
3791           if (options.stack10bit) {
3792               emitcode ("pop", "_bpx+1");
3793               emitcode ("pop", "_bpx");
3794           } else {
3795               emitcode ("pop", "_bp");
3796           }
3797       }
3798   }
3799
3800   /* restore the register bank  */
3801   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3802   {
3803     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3804      || !options.useXstack)
3805     {
3806         /* Special case of ISR using non-zero bank with useXstack
3807          * is handled below.
3808          */
3809         emitcode ("pop", "psw");
3810     }
3811   }
3812
3813   if (IFFUNC_ISISR (sym->type))
3814     { /* is ISR */
3815
3816       /* now we need to restore the registers */
3817       /* if this isr has no bank i.e. is going to
3818          run with bank 0 , then we need to save more
3819          registers :-) */
3820       if (!FUNC_REGBANK (sym->type))
3821         {
3822           int i;
3823           /* if this function does not call any other
3824              function then we can be economical and
3825              save only those registers that are used */
3826           if (!IFFUNC_HASFCALL(sym->type))
3827             {
3828               /* if any registers used */
3829               if (sym->regsUsed)
3830                 {
3831                   bool bits_popped = FALSE;
3832                   /* save the registers used */
3833                   for (i = sym->regsUsed->size; i >= 0; i--)
3834                     {
3835                       if (bitVectBitValue (sym->regsUsed, i))
3836                         bits_popped = popReg (i, bits_popped);
3837                     }
3838                 }
3839             }
3840           else
3841             {
3842               /* this function has a function call. We cannot
3843                  determine register usage so we will have to pop the
3844                  entire bank */
3845               if (options.parms_in_bank1) {
3846                   for (i = 7 ; i >= 0 ; i-- ) {
3847                       emitcode ("pop","%s",rb1regs[i]);
3848                   }
3849               }
3850               unsaveRBank (0, ic, FALSE);
3851             }
3852         }
3853       else
3854         {
3855             /* This ISR uses a non-zero bank.
3856              *
3857              * Restore any register banks saved by genFunction
3858              * in reverse order.
3859              */
3860             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3861             int ix;
3862
3863             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3864             {
3865                 if (savedBanks & (1 << ix))
3866                 {
3867                     unsaveRBank(ix, NULL, FALSE);
3868                 }
3869             }
3870
3871             if (options.useXstack)
3872             {
3873                 /* Restore bank AFTER calling unsaveRBank,
3874                  * since it can trash r0.
3875                  */
3876                 emitcode ("pop", "psw");
3877             }
3878         }
3879
3880       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3881         {
3882           if (options.stack10bit)
3883             {
3884               emitcode ("pop", DP2_RESULT_REG);
3885               emitcode ("pop", "dpx1");
3886               emitcode ("pop", "dph1");
3887               emitcode ("pop", "dpl1");
3888             }
3889           emitcode ("pop", "dps");
3890           emitcode ("pop", "dpx");
3891         }
3892       if (!inExcludeList ("dph"))
3893         emitcode ("pop", "dph");
3894       if (!inExcludeList ("dpl"))
3895         emitcode ("pop", "dpl");
3896       if (!inExcludeList ("b"))
3897         emitcode ("pop", "b");
3898       if (!inExcludeList ("acc"))
3899         emitcode ("pop", "acc");
3900
3901       /* if debug then send end of function */
3902       if (options.debug && currFunc)
3903         {
3904           debugFile->writeEndFunction (currFunc, ic, 1);
3905         }
3906
3907       emitcode ("reti", "");
3908     }
3909   else
3910     {
3911       if (IFFUNC_CALLEESAVES(sym->type))
3912         {
3913           int i;
3914
3915           /* if any registers used */
3916           if (sym->regsUsed)
3917             {
3918               /* save the registers used */
3919               for (i = sym->regsUsed->size; i >= 0; i--)
3920                 {
3921                   if (bitVectBitValue (sym->regsUsed, i))
3922                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3923                 }
3924             }
3925         }
3926
3927       /* if debug then send end of function */
3928       if (options.debug && currFunc)
3929         {
3930           debugFile->writeEndFunction (currFunc, ic, 1);
3931         }
3932
3933       emitcode ("ret", "");
3934     }
3935
3936   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3937     return;
3938
3939   /* If this was an interrupt handler using bank 0 that called another */
3940   /* function, then all registers must be saved; nothing to optimized. */
3941   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3942       && !FUNC_REGBANK(sym->type))
3943     return;
3944
3945   /* There are no push/pops to optimize if not callee-saves or ISR */
3946   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3947     return;
3948
3949   /* If there were stack parameters, we cannot optimize without also    */
3950   /* fixing all of the stack offsets; this is too dificult to consider. */
3951   if (FUNC_HASSTACKPARM(sym->type))
3952     return;
3953
3954   /* Compute the registers actually used */
3955   regsUsed = newBitVect (ds390_nRegs);
3956   regsUsedPrologue = newBitVect (ds390_nRegs);
3957   while (lnp)
3958     {
3959       if (lnp->ic && lnp->ic->op == FUNCTION)
3960         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3961       else
3962         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3963
3964       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3965           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3966         break;
3967       if (!lnp->prev)
3968         break;
3969       lnp = lnp->prev;
3970     }
3971
3972   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3973       && !bitVectBitValue (regsUsed, DPS_IDX))
3974     {
3975       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3976     }
3977
3978   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3979       && !bitVectBitValue (regsUsed, CND_IDX))
3980     {
3981       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3982       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3983           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3984         bitVectUnSetBit (regsUsed, CND_IDX);
3985     }
3986   else
3987     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3988
3989   /* If this was an interrupt handler that called another function */
3990   /* function, then assume working registers may be modified by it. */
3991   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3992     {
3993       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3994       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3995       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3996       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3997       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3998       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3999       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4000       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
4001       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4002       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4003       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4004     }
4005
4006   /* Remove the unneeded push/pops */
4007   regsUnneeded = newBitVect (ds390_nRegs);
4008   while (lnp)
4009     {
4010       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4011         {
4012           if (!strncmp(lnp->line, "push", 4))
4013             {
4014               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4015               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4016                 {
4017                   connectLine (lnp->prev, lnp->next);
4018                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4019                 }
4020             }
4021           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4022             {
4023               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4024               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4025                 {
4026                   connectLine (lnp->prev, lnp->next);
4027                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4028                 }
4029             }
4030         }
4031       lnp = lnp->next;
4032     }
4033
4034   for (idx = 0; idx < regsUnneeded->size; idx++)
4035     if (bitVectBitValue (regsUnneeded, idx))
4036       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4037
4038   freeBitVect (regsUnneeded);
4039   freeBitVect (regsUsed);
4040   freeBitVect (regsUsedPrologue);
4041 }
4042
4043 /*-----------------------------------------------------------------*/
4044 /* genJavaNativeRet - generate code for return JavaNative          */
4045 /*-----------------------------------------------------------------*/
4046 static void genJavaNativeRet(iCode *ic)
4047 {
4048     int i, size;
4049
4050     aopOp (IC_LEFT (ic), ic, FALSE,
4051            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4052     size = AOP_SIZE (IC_LEFT (ic));
4053
4054     assert (size <= 4);
4055
4056     /* it is assigned to GPR0-R3 then push them */
4057     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4058         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4059         for (i = 0 ; i < size ; i++ ) {
4060             emitcode ("push","%s",
4061                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4062         }
4063         for (i = (size-1) ; i >= 0 ; i--) {
4064             emitcode ("pop","a%s",javaRet[i]);
4065         }
4066     } else {
4067         for (i = 0 ; i < size ; i++)
4068             emitcode ("mov","%s,%s",javaRet[i],
4069                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4070     }
4071     for (i = size ; i < 4 ; i++ )
4072             emitcode ("mov","%s,#0",javaRet[i]);
4073     return;
4074 }
4075
4076 /*-----------------------------------------------------------------*/
4077 /* genRet - generate code for return statement                     */
4078 /*-----------------------------------------------------------------*/
4079 static void
4080 genRet (iCode * ic)
4081 {
4082   int size, offset = 0, pushed = 0;
4083
4084   D (emitcode (";", "genRet"));
4085
4086   /* if we have no return value then
4087      just generate the "ret" */
4088   if (!IC_LEFT (ic))
4089     goto jumpret;
4090
4091   /* if this is a JavaNative function then return
4092      value in different register */
4093   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4094       genJavaNativeRet(ic);
4095       goto jumpret;
4096   }
4097   /* we have something to return then
4098      move the return value into place */
4099   aopOp (IC_LEFT (ic), ic, FALSE,
4100          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4101   size = AOP_SIZE (IC_LEFT (ic));
4102
4103   _startLazyDPSEvaluation ();
4104
4105   if (IS_BIT(_G.currentFunc->etype))
4106     {
4107       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4108       size = 0;
4109     }
4110
4111   while (size--)
4112     {
4113       char *l;
4114       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4115         {
4116           l = aopGet (IC_LEFT (ic), offset++,
4117                       FALSE, TRUE, NULL);
4118           emitcode ("push", "%s", l);
4119           pushed++;
4120         }
4121       else
4122         {
4123           /* Since A is the last element of fReturn,
4124            * it is OK to clobber it in the aopGet.
4125            */
4126           l = aopGet (IC_LEFT (ic), offset,
4127                       FALSE, FALSE, NULL);
4128           if (strcmp (fReturn[offset], l))
4129             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4130         }
4131     }
4132   _endLazyDPSEvaluation ();
4133
4134   while (pushed)
4135     {
4136       pushed--;
4137       if (strcmp (fReturn[pushed], "a"))
4138         emitcode ("pop", fReturn[pushed]);
4139       else
4140         emitcode ("pop", "acc");
4141     }
4142   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4143
4144 jumpret:
4145   /* generate a jump to the return label
4146      if the next is not the return statement */
4147   if (!(ic->next && ic->next->op == LABEL &&
4148         IC_LABEL (ic->next) == returnLabel))
4149
4150     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4151
4152 }
4153
4154 /*-----------------------------------------------------------------*/
4155 /* genLabel - generates a label                                    */
4156 /*-----------------------------------------------------------------*/
4157 static void
4158 genLabel (iCode * ic)
4159 {
4160   /* special case never generate */
4161   if (IC_LABEL (ic) == entryLabel)
4162     return;
4163
4164   D (emitcode (";", "genLabel"));
4165
4166   emitLabel (IC_LABEL (ic));
4167 }
4168
4169 /*-----------------------------------------------------------------*/
4170 /* genGoto - generates a ljmp                                      */
4171 /*-----------------------------------------------------------------*/
4172 static void
4173 genGoto (iCode * ic)
4174 {
4175   D (emitcode (";", "genGoto"));
4176
4177   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4178 }
4179
4180 /*-----------------------------------------------------------------*/
4181 /* findLabelBackwards: walks back through the iCode chain looking  */
4182 /* for the given label. Returns number of iCode instructions     */
4183 /* between that label and given ic.          */
4184 /* Returns zero if label not found.          */
4185 /*-----------------------------------------------------------------*/
4186 static int
4187 findLabelBackwards (iCode * ic, int key)
4188 {
4189   int count = 0;
4190
4191   while (ic->prev)
4192     {
4193       ic = ic->prev;
4194       count++;
4195
4196       /* If we have any pushes or pops, we cannot predict the distance.
4197          I don't like this at all, this should be dealt with in the
4198          back-end */
4199       if (ic->op == IPUSH || ic->op == IPOP) {
4200         return 0;
4201       }
4202
4203       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4204         {
4205           /* printf("findLabelBackwards = %d\n", count); */
4206           return count;
4207         }
4208     }
4209
4210   return 0;
4211 }
4212
4213 /*-----------------------------------------------------------------*/
4214 /* genPlusIncr :- does addition with increment if possible         */
4215 /*-----------------------------------------------------------------*/
4216 static bool
4217 genPlusIncr (iCode * ic)
4218 {
4219   unsigned int icount;
4220   unsigned int size = getDataSize (IC_RESULT (ic));
4221
4222   /* will try to generate an increment */
4223   /* if the right side is not a literal
4224      we cannot */
4225   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4226     return FALSE;
4227
4228   /* if the literal value of the right hand side
4229      is greater than 4 then it is not worth it */
4230   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4231     return FALSE;
4232
4233   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4234       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4235       while (icount--) {
4236           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4237       }
4238       return TRUE;
4239   }
4240   /* if increment 16 bits in register */
4241   if (
4242        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4243        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4244        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4245        (size > 1) &&
4246        (icount == 1))
4247     {
4248       symbol  *tlbl;
4249       int     emitTlbl;
4250       int     labelRange;
4251       char    *l;
4252
4253       /* If the next instruction is a goto and the goto target
4254        * is <= 5 instructions previous to this, we can generate
4255        * jumps straight to that target.
4256        */
4257       if (ic->next && ic->next->op == GOTO
4258           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4259           && labelRange <= 5)
4260         {
4261           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4262           tlbl = IC_LABEL (ic->next);
4263           emitTlbl = 0;
4264         }
4265       else
4266         {
4267           tlbl = newiTempLabel (NULL);
4268           emitTlbl = 1;
4269         }
4270       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4271       emitcode ("inc", "%s", l);
4272
4273       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4274           IS_AOP_PREG (IC_RESULT (ic)))
4275         {
4276           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4277         }
4278       else
4279         {
4280           emitcode ("clr", "a");
4281           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4282         }
4283
4284       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4285       emitcode ("inc", "%s", l);
4286       if (size > 2)
4287         {
4288           if (!strcmp(l, "acc"))
4289             {
4290                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4291             }
4292           else 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 ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4300             }
4301
4302           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4303           emitcode ("inc", "%s", l);
4304         }
4305       if (size > 3)
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), MSB32, FALSE, FALSE, NULL);
4322           emitcode ("inc", "%s", l);
4323         }
4324
4325       if (emitTlbl)
4326         {
4327           emitLabel (tlbl);
4328         }
4329       return TRUE;
4330     }
4331
4332   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4333       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4334       options.model == MODEL_FLAT24 )
4335     {
4336       if (IC_RESULT(ic)->isGptr)
4337         {
4338           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4339         }
4340       switch (size) {
4341       case 3:
4342           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4343       case 2:
4344           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4345       case 1:
4346           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4347           break;
4348       }
4349       while (icount--)
4350         emitcode ("inc", "dptr");
4351       return TRUE;
4352   }
4353
4354   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4355       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4356       icount <= 5 ) {
4357       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4358       while (icount--)
4359         emitcode ("inc", "dptr");
4360       emitcode ("mov", "dps,#0");
4361       return TRUE;
4362   }
4363
4364   /* if the sizes are greater than 1 then we cannot */
4365   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4366       AOP_SIZE (IC_LEFT (ic)) > 1)
4367     return FALSE;
4368
4369   /* we can if the aops of the left & result match or
4370      if they are in registers and the registers are the
4371      same */
4372   if (
4373        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4374        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4375        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4376     {
4377       if (icount > 3)
4378         {
4379           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4380           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4381           aopPut (IC_RESULT (ic), "a", 0);
4382         }
4383       else
4384         {
4385           _startLazyDPSEvaluation ();
4386           while (icount--)
4387             {
4388               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4389             }
4390           _endLazyDPSEvaluation ();
4391         }
4392
4393       return TRUE;
4394     }
4395
4396   return FALSE;
4397 }
4398
4399 /*-----------------------------------------------------------------*/
4400 /* outBitAcc - output a bit in acc                                 */
4401 /*-----------------------------------------------------------------*/
4402 static void
4403 outBitAcc (operand * result)
4404 {
4405   symbol *tlbl = newiTempLabel (NULL);
4406   /* if the result is a bit */
4407   if (AOP_TYPE (result) == AOP_CRY)
4408     {
4409       aopPut (result, "a", 0);
4410     }
4411   else
4412     {
4413       emitcode ("jz", "!tlabel", tlbl->key + 100);
4414       emitcode ("mov", "a,%s", one);
4415       emitLabel (tlbl);
4416       outAcc (result);
4417     }
4418 }
4419
4420 /*-----------------------------------------------------------------*/
4421 /* genPlusBits - generates code for addition of two bits           */
4422 /*-----------------------------------------------------------------*/
4423 static void
4424 genPlusBits (iCode * ic)
4425 {
4426   D (emitcode (";", "genPlusBits"));
4427
4428   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4429     {
4430       symbol *lbl = newiTempLabel (NULL);
4431       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4432       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4433       emitcode ("cpl", "c");
4434       emitLabel (lbl);
4435       outBitC (IC_RESULT (ic));
4436     }
4437   else
4438     {
4439       emitcode ("clr", "a");
4440       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4441       emitcode ("rlc", "a");
4442       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4443       emitcode ("addc", "a,%s", zero);
4444       outAcc (IC_RESULT (ic));
4445     }
4446 }
4447
4448 static void
4449 adjustArithmeticResult (iCode * ic)
4450 {
4451   if (opIsGptr (IC_RESULT (ic)) &&
4452       opIsGptr (IC_LEFT (ic)) &&
4453       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4454     {
4455       aopPut (IC_RESULT (ic),
4456               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4457               GPTRSIZE - 1);
4458     }
4459
4460   if (opIsGptr (IC_RESULT (ic)) &&
4461       opIsGptr (IC_RIGHT (ic)) &&
4462       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4463     {
4464       aopPut (IC_RESULT (ic),
4465               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4466               GPTRSIZE - 1);
4467     }
4468
4469   if (opIsGptr (IC_RESULT (ic)) &&
4470       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4471       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4472       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4473       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4474     {
4475       char buffer[5];
4476       SNPRINTF (buffer, sizeof(buffer),
4477                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4478       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4479     }
4480 }
4481
4482 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4483 // generates the result if possible. If result is generated, returns TRUE; otherwise
4484 // returns false and caller must deal with fact that result isn't aopOp'd.
4485 bool aopOp3(iCode * ic)
4486 {
4487     bool dp1InUse, dp2InUse;
4488     bool useDp2;
4489
4490     // First, generate the right opcode. DPTR may be used if neither left nor result are
4491     // of type AOP_STR.
4492
4493 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4494 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4495 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4496 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4497 //      );
4498 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4499 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4500 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4501 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4502 //      );
4503
4504     // Right uses DPTR unless left or result is an AOP_STR; however,
4505     // if right is an AOP_STR, it must use DPTR regardless.
4506     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4507      && !AOP_IS_STR (IC_RIGHT (ic)))
4508     {
4509         useDp2 = TRUE;
4510     }
4511     else
4512     {
4513         useDp2 = FALSE;
4514     }
4515
4516     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4517
4518     // if the right used DPTR, left MUST use DPTR2.
4519     // if the right used DPTR2, left MUST use DPTR.
4520     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4521     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4522     // enabling us to assign DPTR to result.
4523
4524     if (AOP_USESDPTR (IC_RIGHT (ic)))
4525     {
4526         useDp2 = TRUE;
4527     }
4528     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4529     {
4530         useDp2 = FALSE;
4531     }
4532     else
4533     {
4534         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4535         {
4536             useDp2 = TRUE;
4537         }
4538         else
4539         {
4540             useDp2 = FALSE;
4541         }
4542     }
4543
4544     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4545
4546
4547     // We've op'd the left & right. So, if left or right are the same operand as result,
4548     // we know aopOp will succeed, and we can just do it & bail.
4549     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4550       {
4551         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4552         return TRUE;
4553       }
4554     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4555       {
4556 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4557         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4558         return TRUE;
4559       }
4560
4561     // Operands may be equivalent (but not equal) if they share a spill location. If
4562     // so, use the same DPTR or DPTR2.
4563     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4564       {
4565         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4566         return TRUE;
4567       }
4568     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4569       {
4570         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4571         return TRUE;
4572       }
4573
4574     // Note which dptrs are currently in use.
4575     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4576     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4577
4578     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4579     // generate it.
4580     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4581     {
4582         return FALSE;
4583     }
4584
4585     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4586     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4587     {
4588         return FALSE;
4589     }
4590
4591     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4592     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4593     {
4594         return FALSE;
4595     }
4596
4597     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4598
4599     // Some sanity checking...
4600     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4601     {
4602         fprintf(stderr,
4603                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4604                 __FILE__, __LINE__, ic->filename, ic->lineno);
4605         emitcode(";", ">>> unexpected DPTR here.");
4606     }
4607
4608     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4609     {
4610         fprintf(stderr,
4611                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4612                 __FILE__, __LINE__, ic->filename, ic->lineno);
4613         emitcode(";", ">>> unexpected DPTR2 here.");
4614     }
4615
4616     return TRUE;
4617 }
4618
4619 // Macro to aopOp all three operands of an ic. If this cannot be done,
4620 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4621 // will be set TRUE. The caller must then handle the case specially, noting
4622 // that the IC_RESULT operand is not aopOp'd.
4623 //
4624 #define AOP_OP_3_NOFATAL(ic, rc) \
4625             do { rc = !aopOp3(ic); } while (0)
4626
4627 // aopOp the left & right operands of an ic.
4628 #define AOP_OP_2(ic) \
4629     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4630     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4631
4632 // convienience macro.
4633 #define AOP_SET_LOCALS(ic) \
4634     left = IC_LEFT(ic); \
4635     right = IC_RIGHT(ic); \
4636     result = IC_RESULT(ic);
4637
4638
4639 // Given an integer value of pushedSize bytes on the stack,
4640 // adjust it to be resultSize bytes, either by discarding
4641 // the most significant bytes or by zero-padding.
4642 //
4643 // On exit from this macro, pushedSize will have been adjusted to
4644 // equal resultSize, and ACC may be trashed.
4645 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4646       /* If the pushed data is bigger than the result,          \
4647        * simply discard unused bytes. Icky, but works.          \
4648        */                                                       \
4649       while (pushedSize > resultSize)                           \
4650       {                                                         \
4651           D (emitcode (";", "discarding unused result byte.")); \
4652           emitcode ("pop", "acc");                              \
4653           pushedSize--;                                         \
4654       }                                                         \
4655       if (pushedSize < resultSize)                              \
4656       {                                                         \
4657           emitcode ("clr", "a");                                \
4658           /* Conversly, we haven't pushed enough here.          \
4659            * just zero-pad, and all is well.                    \
4660            */                                                   \
4661           while (pushedSize < resultSize)                       \
4662           {                                                     \
4663               emitcode("push", "acc");                          \
4664               pushedSize++;                                     \
4665           }                                                     \
4666       }                                                         \
4667       assert(pushedSize == resultSize);
4668
4669 /*-----------------------------------------------------------------*/
4670 /* genPlus - generates code for addition                           */
4671 /*-----------------------------------------------------------------*/
4672 static void
4673 genPlus (iCode * ic)
4674 {
4675   int size, offset = 0;
4676   bool pushResult;
4677   int rSize;
4678   bool swappedLR = FALSE;
4679
4680   D (emitcode (";", "genPlus"));
4681
4682   /* special cases :- */
4683   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4684       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4685       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4686       size = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4687       if (size <= 9) {
4688           while (size--) emitcode ("inc","dptr");
4689       } else {
4690           emitcode ("mov", "a,dpl");
4691           emitcode ("add", "a,#!constbyte", size & 0xff);
4692           emitcode ("mov", "dpl,a");
4693           emitcode ("mov", "a,dph");
4694           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4695           emitcode ("mov", "dph,a");
4696           emitcode ("mov", "a,dpx");
4697           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4698           emitcode ("mov", "dpx,a");
4699       }
4700       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4701       return ;
4702   }
4703   if ( IS_SYMOP (IC_LEFT (ic)) &&
4704        OP_SYMBOL (IC_LEFT (ic))->remat &&
4705        isOperandInFarSpace (IC_RIGHT (ic))) {
4706       operand *op = IC_RIGHT(ic);
4707       IC_RIGHT(ic) = IC_LEFT(ic);
4708       IC_LEFT(ic) = op;
4709   }
4710
4711   AOP_OP_3_NOFATAL (ic, pushResult);
4712
4713   if (pushResult)
4714     {
4715       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4716     }
4717
4718   if (!pushResult)
4719     {
4720       /* if literal, literal on the right or
4721          if left requires ACC or right is already
4722          in ACC */
4723       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4724           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4725           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4726         {
4727           operand *t = IC_RIGHT (ic);
4728           IC_RIGHT (ic) = IC_LEFT (ic);
4729           IC_LEFT (ic) = t;
4730           swappedLR = TRUE;
4731           D (emitcode (";", "Swapped plus args."));
4732         }
4733
4734       /* if both left & right are in bit
4735          space */
4736       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4737           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4738         {
4739           genPlusBits (ic);
4740           goto release;
4741         }
4742
4743       /* if left in bit space & right literal */
4744       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4745           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4746         {
4747           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4748           /* if result in bit space */
4749           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4750             {
4751               if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4752                 emitcode ("cpl", "c");
4753               outBitC (IC_RESULT (ic));
4754             }
4755           else
4756             {
4757               size = getDataSize (IC_RESULT (ic));
4758               _startLazyDPSEvaluation ();
4759               while (size--)
4760                 {
4761                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4762                   emitcode ("addc", "a,%s", zero);
4763                   aopPut (IC_RESULT (ic), "a", offset++);
4764                 }
4765               _endLazyDPSEvaluation ();
4766             }
4767           goto release;
4768         }
4769
4770       /* if I can do an increment instead
4771          of add then GOOD for ME */
4772       if (genPlusIncr (ic) == TRUE)
4773         {
4774           D (emitcode (";", "did genPlusIncr"));
4775           goto release;
4776         }
4777
4778     }
4779   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4780
4781   _startLazyDPSEvaluation ();
4782   while (size--)
4783     {
4784       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4785         {
4786           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4787           if (offset == 0)
4788             emitcode ("add", "a,%s",
4789                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4790           else
4791             emitcode ("addc", "a,%s",
4792                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4793         }
4794       else
4795         {
4796           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4797           {
4798               /* right is going to use ACC or we would have taken the
4799                * above branch.
4800                */
4801               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4802               TR_AP("#3");
4803               D(emitcode(";", "+ AOP_ACC special case."););
4804               emitcode("xch", "a, %s", DP2_RESULT_REG);
4805           }
4806           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4807           if (offset == 0)
4808           {
4809             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4810             {
4811                 TR_AP("#4");
4812                 emitcode("add", "a, %s", DP2_RESULT_REG);
4813             }
4814             else
4815             {
4816                 emitcode ("add", "a,%s",
4817                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4818                                   DP2_RESULT_REG));
4819             }
4820           }
4821           else
4822           {
4823             emitcode ("addc", "a,%s",
4824                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4825                           DP2_RESULT_REG));
4826           }
4827         }
4828       if (!pushResult)
4829         {
4830           aopPut (IC_RESULT (ic), "a", offset);
4831         }
4832       else
4833         {
4834           emitcode ("push", "acc");
4835         }
4836       offset++;
4837     }
4838   _endLazyDPSEvaluation ();
4839
4840   if (pushResult)
4841     {
4842       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4843
4844       size = getDataSize (IC_LEFT (ic));
4845       rSize = getDataSize (IC_RESULT (ic));
4846
4847       ADJUST_PUSHED_RESULT(size, rSize);
4848
4849       _startLazyDPSEvaluation ();
4850       while (size--)
4851         {
4852           emitcode ("pop", "acc");
4853           aopPut (IC_RESULT (ic), "a", size);
4854         }
4855       _endLazyDPSEvaluation ();
4856     }
4857
4858   adjustArithmeticResult (ic);
4859
4860 release:
4861   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4862   if (!swappedLR)
4863     {
4864       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4865       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4866     }
4867   else
4868     {
4869       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4870       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4871     }
4872 }
4873
4874 /*-----------------------------------------------------------------*/
4875 /* genMinusDec :- does subtraction with decrement if possible      */
4876 /*-----------------------------------------------------------------*/
4877 static bool
4878 genMinusDec (iCode * ic)
4879 {
4880   unsigned int icount;
4881   unsigned int size = getDataSize (IC_RESULT (ic));
4882
4883   /* will try to generate an increment */
4884   /* if the right side is not a literal
4885      we cannot */
4886   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4887     return FALSE;
4888
4889   /* if the literal value of the right hand side
4890      is greater than 4 then it is not worth it */
4891   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4892     return FALSE;
4893
4894   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4895       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4896       while (icount--) {
4897           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4898       }
4899       return TRUE;
4900   }
4901   /* if decrement 16 bits in register */
4902   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4903       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4904       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4905       (size > 1) &&
4906       (icount == 1))
4907     {
4908       symbol *tlbl;
4909       int    emitTlbl;
4910       int    labelRange;
4911       char   *l;
4912
4913       /* If the next instruction is a goto and the goto target
4914          * is <= 5 instructions previous to this, we can generate
4915          * jumps straight to that target.
4916        */
4917       if (ic->next && ic->next->op == GOTO
4918           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4919           && labelRange <= 5)
4920         {
4921           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4922           tlbl = IC_LABEL (ic->next);
4923           emitTlbl = 0;
4924         }
4925       else
4926         {
4927           tlbl = newiTempLabel (NULL);
4928           emitTlbl = 1;
4929         }
4930
4931       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4932       emitcode ("dec", "%s", l);
4933
4934       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4935           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4936           IS_AOP_PREG (IC_RESULT (ic)))
4937       {
4938           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4939       }
4940       else
4941       {
4942           emitcode ("mov", "a,#!constbyte",0xff);
4943           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4944       }
4945       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4946       emitcode ("dec", "%s", l);
4947       if (size > 2)
4948         {
4949             if (!strcmp(l, "acc"))
4950             {
4951                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4952             }
4953             else 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), MSB24, FALSE, FALSE, NULL);
4965             emitcode ("dec", "%s", l);
4966         }
4967       if (size > 3)
4968         {
4969             if (!strcmp(l, "acc"))
4970             {
4971                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4972             }
4973             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4974                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4975                      IS_AOP_PREG (IC_RESULT (ic)))
4976             {
4977                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4978             }
4979             else
4980             {
4981                 emitcode ("mov", "a,#!constbyte",0xff);
4982                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4983             }
4984             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4985             emitcode ("dec", "%s", l);
4986         }
4987       if (emitTlbl)
4988         {
4989           emitLabel (tlbl);
4990         }
4991       return TRUE;
4992     }
4993
4994   /* if the sizes are greater than 1 then we cannot */
4995   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4996       AOP_SIZE (IC_LEFT (ic)) > 1)
4997     return FALSE;
4998
4999   /* we can if the aops of the left & result match or
5000      if they are in registers and the registers are the
5001      same */
5002   if (
5003        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
5004        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
5005        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
5006     {
5007       char *l;
5008
5009       if (aopGetUsesAcc (IC_LEFT (ic), 0))
5010         {
5011           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
5012           l = "a";
5013         }
5014       else
5015         {
5016           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5017         }
5018
5019       _startLazyDPSEvaluation ();
5020       while (icount--)
5021         {
5022           emitcode ("dec", "%s", l);
5023         }
5024       _endLazyDPSEvaluation ();
5025
5026       if (AOP_NEEDSACC (IC_RESULT (ic)))
5027         aopPut (IC_RESULT (ic), "a", 0);
5028
5029       return TRUE;
5030     }
5031
5032   return FALSE;
5033 }
5034
5035 /*-----------------------------------------------------------------*/
5036 /* addSign - complete with sign                                    */
5037 /*-----------------------------------------------------------------*/
5038 static void
5039 addSign (operand * result, int offset, int sign)
5040 {
5041   int size = (getDataSize (result) - offset);
5042   if (size > 0)
5043     {
5044       _startLazyDPSEvaluation();
5045       if (sign)
5046         {
5047           emitcode ("rlc", "a");
5048           emitcode ("subb", "a,acc");
5049           while (size--)
5050             {
5051               aopPut (result, "a", offset++);
5052             }
5053         }
5054       else
5055       {
5056         while (size--)
5057         {
5058           aopPut (result, zero, offset++);
5059         }
5060       }
5061       _endLazyDPSEvaluation();
5062     }
5063 }
5064
5065 /*-----------------------------------------------------------------*/
5066 /* genMinusBits - generates code for subtraction  of two bits      */
5067 /*-----------------------------------------------------------------*/
5068 static void
5069 genMinusBits (iCode * ic)
5070 {
5071   symbol *lbl = newiTempLabel (NULL);
5072
5073   D (emitcode (";", "genMinusBits"));
5074
5075   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5076     {
5077       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5078       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5079       emitcode ("cpl", "c");
5080       emitLabel (lbl);
5081       outBitC (IC_RESULT (ic));
5082     }
5083   else
5084     {
5085       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5086       emitcode ("subb", "a,acc");
5087       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5088       emitcode ("inc", "a");
5089       emitLabel (lbl);
5090       aopPut (IC_RESULT (ic), "a", 0);
5091       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5092     }
5093 }
5094
5095 /*-----------------------------------------------------------------*/
5096 /* genMinus - generates code for subtraction                       */
5097 /*-----------------------------------------------------------------*/
5098 static void
5099 genMinus (iCode * ic)
5100 {
5101     int size, offset = 0;
5102     int rSize;
5103     long lit = 0L;
5104     bool pushResult;
5105
5106     D (emitcode (";", "genMinus"));
5107
5108     AOP_OP_3_NOFATAL(ic, pushResult);
5109
5110     if (!pushResult)
5111     {
5112       /* special cases :- */
5113       /* if both left & right are in bit space */
5114       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5115           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5116         {
5117           genMinusBits (ic);
5118           goto release;
5119         }
5120
5121       /* if I can do an decrement instead
5122          of subtract then GOOD for ME */
5123       if (genMinusDec (ic) == TRUE)
5124         goto release;
5125
5126     }
5127
5128   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5129
5130   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5131     {
5132       CLRC;
5133     }
5134   else
5135     {
5136       lit = (long) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5137       lit = -lit;
5138     }
5139
5140
5141   /* if literal, add a,#-lit, else normal subb */
5142   _startLazyDPSEvaluation ();
5143   while (size--) {
5144       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5145           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5146               emitcode ("mov","b,%s",
5147                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5148               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5149               emitcode ("subb","a,b");
5150           } else {
5151               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5152               emitcode ("subb", "a,%s",
5153                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5154                                 DP2_RESULT_REG));
5155           }
5156       } else {
5157           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5158           /* first add without previous c */
5159           if (!offset) {
5160               if (!size && lit==-1) {
5161                   emitcode ("dec", "a");
5162               } else {
5163                   emitcode ("add", "a,#!constbyte",
5164                             (unsigned int) (lit & 0x0FFL));
5165               }
5166           } else {
5167               emitcode ("addc", "a,#!constbyte",
5168                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5169           }
5170       }
5171
5172       if (pushResult) {
5173           emitcode ("push", "acc");
5174       } else {
5175           aopPut (IC_RESULT (ic), "a", offset);
5176       }
5177       offset++;
5178   }
5179   _endLazyDPSEvaluation ();
5180
5181   if (pushResult)
5182     {
5183       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5184
5185       size = getDataSize (IC_LEFT (ic));
5186       rSize = getDataSize (IC_RESULT (ic));
5187
5188       ADJUST_PUSHED_RESULT(size, rSize);
5189
5190       _startLazyDPSEvaluation ();
5191       while (size--)
5192         {
5193           emitcode ("pop", "acc");
5194           aopPut (IC_RESULT (ic), "a", size);
5195         }
5196       _endLazyDPSEvaluation ();
5197     }
5198
5199   adjustArithmeticResult (ic);
5200
5201 release:
5202   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5203   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5204   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5205 }
5206
5207
5208 /*-----------------------------------------------------------------*/
5209 /* genMultbits :- multiplication of bits                           */
5210 /*-----------------------------------------------------------------*/
5211 static void
5212 genMultbits (operand * left,
5213              operand * right,
5214              operand * result,
5215              iCode   * ic)
5216 {
5217   D (emitcode (";", "genMultbits"));
5218
5219   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5220   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5221   aopOp(result, ic, TRUE, FALSE);
5222   outBitC (result);
5223 }
5224
5225 /*-----------------------------------------------------------------*/
5226 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5227 /*-----------------------------------------------------------------*/
5228 static void
5229 genMultOneByte (operand * left,
5230                 operand * right,
5231                 operand * result,
5232                 iCode   * ic)
5233 {
5234   symbol *lbl;
5235   int size;
5236   bool runtimeSign, compiletimeSign;
5237   bool lUnsigned, rUnsigned, pushedB;
5238
5239   /* (if two literals: the value is computed before) */
5240   /* if one literal, literal on the right */
5241   if (AOP_TYPE (left) == AOP_LIT)
5242     {
5243       operand *t = right;
5244       right = left;
5245       left = t;
5246       /* emitcode (";", "swapped left and right"); */
5247     }
5248   /* if no literal, unsigned on the right: shorter code */
5249   if (   AOP_TYPE (right) != AOP_LIT
5250       && SPEC_USIGN (getSpec (operandType (left))))
5251     {
5252       operand *t = right;
5253       right = left;
5254       left = t;
5255     }
5256
5257   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5258   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5259
5260   pushedB = pushB ();
5261
5262   if ((lUnsigned && rUnsigned)
5263 /* sorry, I don't know how to get size
5264    without calling aopOp (result,...);
5265    see Feature Request  */
5266       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5267                    no need to take care about the signedness! */
5268     {
5269       /* just an unsigned 8 * 8 = 8 multiply
5270          or 8u * 8u = 16u */
5271       /* emitcode (";","unsigned"); */
5272       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5273       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5274       emitcode ("mul", "ab");
5275
5276       _G.accInUse++;
5277       aopOp (result, ic, TRUE, FALSE);
5278       size = AOP_SIZE (result);
5279
5280       if (size < 1 || size > 2)
5281         {
5282           /* this should never happen */
5283           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5284                    size, __FILE__, lineno);
5285           exit (1);
5286         }
5287
5288       aopPut (result, "a", 0);
5289       _G.accInUse--;
5290       if (size == 2)
5291         aopPut (result, "b", 1);
5292
5293       popB (pushedB);
5294       return;
5295     }
5296
5297   /* we have to do a signed multiply */
5298   /* emitcode (";", "signed"); */
5299
5300   /* now sign adjust for both left & right */
5301
5302   /* let's see what's needed: */
5303   /* apply negative sign during runtime */
5304   runtimeSign = FALSE;
5305   /* negative sign from literals */
5306   compiletimeSign = FALSE;
5307
5308   if (!lUnsigned)
5309     {
5310       if (AOP_TYPE(left) == AOP_LIT)
5311         {
5312           /* signed literal */
5313           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5314           if (val < 0)
5315             compiletimeSign = TRUE;
5316         }
5317       else
5318         /* signed but not literal */
5319         runtimeSign = TRUE;
5320     }
5321
5322   if (!rUnsigned)
5323     {
5324       if (AOP_TYPE(right) == AOP_LIT)
5325         {
5326           /* signed literal */
5327           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5328           if (val < 0)
5329             compiletimeSign ^= TRUE;
5330         }
5331       else
5332         /* signed but not literal */
5333         runtimeSign = TRUE;
5334     }
5335
5336   /* initialize F0, which stores the runtime sign */
5337   if (runtimeSign)
5338     {
5339       if (compiletimeSign)
5340         emitcode ("setb", "F0"); /* set sign flag */
5341       else
5342         emitcode ("clr", "F0"); /* reset sign flag */
5343     }
5344
5345   /* save the signs of the operands */
5346   if (AOP_TYPE(right) == AOP_LIT)
5347     {
5348       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5349
5350       if (!rUnsigned && val < 0)
5351         emitcode ("mov", "b,#!constbyte", -val);
5352       else
5353         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5354     }
5355   else /* ! literal */
5356     {
5357       if (rUnsigned)  /* emitcode (";", "signed"); */
5358         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5359       else
5360         {
5361           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5362           lbl = newiTempLabel (NULL);
5363           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5364           emitcode ("cpl", "F0"); /* complement sign flag */
5365           emitcode ("cpl", "a");  /* 2's complement */
5366           emitcode ("inc", "a");
5367           emitLabel (lbl);
5368           emitcode ("mov", "b,a");
5369         }
5370     }
5371
5372   if (AOP_TYPE(left) == AOP_LIT)
5373     {
5374       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5375
5376       if (!lUnsigned && val < 0)
5377         emitcode ("mov", "a,#!constbyte", -val);
5378       else
5379         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5380     }
5381   else /* ! literal */
5382     {
5383       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5384
5385       if (!lUnsigned)  /* emitcode (";", "signed"); */
5386         {
5387           lbl = newiTempLabel (NULL);
5388           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5389           emitcode ("cpl", "F0"); /* complement sign flag */
5390           emitcode ("cpl", "a");  /* 2's complement */
5391           emitcode ("inc", "a");
5392           emitLabel (lbl);
5393         }
5394     }
5395
5396   /* now the multiplication */
5397   emitcode ("mul", "ab");
5398   _G.accInUse++;
5399   aopOp(result, ic, TRUE, FALSE);
5400   size = AOP_SIZE (result);
5401
5402   if (size < 1 || size > 2)
5403     {
5404       /* this should never happen */
5405       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5406                size, __FILE__, lineno);
5407       exit (1);
5408     }
5409
5410   if (runtimeSign || compiletimeSign)
5411     {
5412       lbl = newiTempLabel (NULL);
5413       if (runtimeSign)
5414         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5415       emitcode ("cpl", "a"); /* lsb 2's complement */
5416       if (size != 2)
5417         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5418       else
5419         {
5420           emitcode ("add", "a,#1"); /* this sets carry flag */
5421           emitcode ("xch", "a,b");
5422           emitcode ("cpl", "a"); /* msb 2's complement */
5423           emitcode ("addc", "a,#0");
5424           emitcode ("xch", "a,b");
5425         }
5426       emitLabel (lbl);
5427     }
5428   aopPut (result, "a", 0);
5429   _G.accInUse--;
5430   if (size == 2)
5431     aopPut (result, "b", 1);
5432
5433   popB (pushedB);
5434 }
5435
5436 /*-----------------------------------------------------------------*/
5437 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5438 /*-----------------------------------------------------------------*/
5439 static void genMultTwoByte (operand *left, operand *right,
5440                             operand *result, iCode *ic)
5441 {
5442         sym_link *retype = getSpec(operandType(right));
5443         sym_link *letype = getSpec(operandType(left));
5444         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5445         symbol *lbl;
5446
5447         if (AOP_TYPE (left) == AOP_LIT) {
5448                 operand *t = right;
5449                 right = left;
5450                 left = t;
5451         }
5452         /* save EA bit in F1 */
5453         lbl = newiTempLabel(NULL);
5454         emitcode ("setb","F1");
5455         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5456         emitcode ("clr","F1");
5457         emitLabel (lbl);
5458
5459         /* load up MB with right */
5460         if (!umult) {
5461                 emitcode("clr","F0");
5462                 if (AOP_TYPE(right) == AOP_LIT) {
5463                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
5464                         if (val < 0) {
5465                                 emitcode("setb","F0");
5466                                 val = -val;
5467                         }
5468                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5469                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5470                 } else {
5471                         lbl = newiTempLabel(NULL);
5472                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5473                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5474                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5475                         emitcode ("xch", "a,b");
5476                         emitcode ("cpl","a");
5477                         emitcode ("add", "a,#1");
5478                         emitcode ("xch", "a,b");
5479                         emitcode ("cpl", "a"); // msb
5480                         emitcode ("addc", "a,#0");
5481                         emitcode ("setb","F0");
5482                         emitLabel (lbl);
5483                         emitcode ("mov","mb,b");
5484                         emitcode ("mov","mb,a");
5485                 }
5486         } else {
5487                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5488                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5489         }
5490         /* load up MA with left */
5491         if (!umult) {
5492                 lbl = newiTempLabel(NULL);
5493                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5494                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5495                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5496                 emitcode ("xch", "a,b");
5497                 emitcode ("cpl","a");
5498                 emitcode ("add", "a,#1");
5499                 emitcode ("xch", "a,b");
5500                 emitcode ("cpl", "a"); // msb
5501                 emitcode ("addc","a,#0");
5502                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5503                 emitcode ("setb","F0");
5504                 emitLabel (lbl);
5505                 emitcode ("mov","ma,b");
5506                 emitcode ("mov","ma,a");
5507         } else {
5508                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5509                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5510         }
5511         /* wait for multiplication to finish */
5512         lbl = newiTempLabel(NULL);
5513         emitLabel (lbl);
5514         emitcode("mov","a,mcnt1");
5515         emitcode("anl","a,#!constbyte",0x80);
5516         emitcode("jnz","!tlabel",lbl->key+100);
5517
5518         freeAsmop (left, NULL, ic, TRUE);
5519         freeAsmop (right, NULL, ic,TRUE);
5520         aopOp(result, ic, TRUE, FALSE);
5521
5522         /* if unsigned then simple */
5523         if (umult) {
5524                 emitcode ("mov","a,ma");
5525                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5526                 emitcode ("mov","a,ma");
5527                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5528                 aopPut(result,"ma",1);
5529                 aopPut(result,"ma",0);
5530         } else {
5531                 emitcode("push","ma");
5532                 emitcode("push","ma");
5533                 emitcode("push","ma");
5534                 MOVA("ma");
5535                 /* negate result if needed */
5536                 lbl = newiTempLabel(NULL);
5537                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5538                 emitcode("cpl","a");
5539                 emitcode("add","a,#1");
5540                 emitLabel (lbl);
5541                 if (AOP_TYPE(result) == AOP_ACC)
5542                 {
5543                     D (emitcode(";", "ACC special case."));
5544                     /* We know result is the only live aop, and
5545                      * it's obviously not a DPTR2, so AP is available.
5546                      */
5547                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5548                 }
5549                 else
5550                 {
5551                     aopPut(result,"a",0);
5552                 }
5553
5554                 emitcode("pop","acc");
5555                 lbl = newiTempLabel(NULL);
5556                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5557                 emitcode("cpl","a");
5558                 emitcode("addc","a,#0");
5559                 emitLabel (lbl);
5560                 aopPut(result,"a",1);
5561                 emitcode("pop","acc");
5562                 if (AOP_SIZE(result) >= 3) {
5563                         lbl = newiTempLabel(NULL);
5564                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5565                         emitcode("cpl","a");
5566                         emitcode("addc","a,#0");
5567                         emitLabel (lbl);
5568                         aopPut(result,"a",2);
5569                 }
5570                 emitcode("pop","acc");
5571                 if (AOP_SIZE(result) >= 4) {
5572                         lbl = newiTempLabel(NULL);
5573                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5574                         emitcode("cpl","a");
5575                         emitcode("addc","a,#0");
5576                         emitLabel (lbl);
5577                         aopPut(result,"a",3);
5578                 }
5579                 if (AOP_TYPE(result) == AOP_ACC)
5580                 {
5581                     /* We stashed the result away above. */
5582                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5583                 }
5584
5585         }
5586         freeAsmop (result, NULL, ic, TRUE);
5587
5588         /* restore EA bit in F1 */
5589         lbl = newiTempLabel(NULL);
5590         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5591         emitcode ("setb","EA");
5592         emitLabel (lbl);
5593         return ;
5594 }
5595
5596 /*-----------------------------------------------------------------*/
5597 /* genMult - generates code for multiplication                     */
5598 /*-----------------------------------------------------------------*/
5599 static void
5600 genMult (iCode * ic)
5601 {
5602   operand *left = IC_LEFT (ic);
5603   operand *right = IC_RIGHT (ic);
5604   operand *result = IC_RESULT (ic);
5605
5606   D (emitcode (";", "genMult"));
5607
5608   /* assign the asmops */
5609   AOP_OP_2 (ic);
5610
5611   /* special cases first */
5612   /* both are bits */
5613   if (AOP_TYPE (left) == AOP_CRY &&
5614       AOP_TYPE (right) == AOP_CRY)
5615     {
5616       genMultbits (left, right, result, ic);
5617       goto release;
5618     }
5619
5620   /* if both are of size == 1 */
5621   if (AOP_SIZE (left) == 1 &&
5622       AOP_SIZE (right) == 1)
5623     {
5624       genMultOneByte (left, right, result, ic);
5625       goto release;
5626     }
5627
5628   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5629           /* use the ds390 ARITHMETIC accel UNIT */
5630           genMultTwoByte (left, right, result, ic);
5631           return ;
5632   }
5633   /* should have been converted to function call */
5634   assert (0);
5635
5636 release:
5637   freeAsmop (result, NULL, ic, TRUE);
5638   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5639   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5640 }
5641
5642 /*-----------------------------------------------------------------*/
5643 /* genDivbits :- division of bits                                  */
5644 /*-----------------------------------------------------------------*/
5645 static void
5646 genDivbits (operand * left,
5647             operand * right,
5648             operand * result,
5649             iCode   * ic)
5650 {
5651   char *l;
5652   bool pushedB;
5653
5654   D(emitcode (";", "genDivbits"));
5655
5656   pushedB = pushB ();
5657
5658   /* the result must be bit */
5659   LOAD_AB_FOR_DIV (left, right, l);
5660   emitcode ("div", "ab");
5661   emitcode ("rrc", "a");
5662   aopOp(result, ic, TRUE, FALSE);
5663
5664   popB (pushedB);
5665
5666   aopPut (result, "c", 0);
5667 }
5668
5669 /*-----------------------------------------------------------------*/
5670 /* genDivOneByte : 8 bit division                                  */
5671 /*-----------------------------------------------------------------*/
5672 static void
5673 genDivOneByte (operand * left,
5674                operand * right,
5675                operand * result,
5676                iCode   * ic)
5677 {
5678   bool lUnsigned, rUnsigned, pushedB;
5679   bool runtimeSign, compiletimeSign;
5680   char *l;
5681   symbol *lbl;
5682   int size, offset;
5683
5684   D(emitcode (";", "genDivOneByte"));
5685
5686   offset = 1;
5687   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5688   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5689
5690   pushedB = pushB ();
5691
5692   /* signed or unsigned */
5693   if (lUnsigned && rUnsigned)
5694     {
5695       /* unsigned is easy */
5696       LOAD_AB_FOR_DIV (left, right, l);
5697       emitcode ("div", "ab");
5698
5699       _G.accInUse++;
5700       aopOp (result, ic, TRUE, FALSE);
5701       aopPut (result, "a", 0);
5702       _G.accInUse--;
5703
5704       size = AOP_SIZE (result) - 1;
5705
5706       while (size--)
5707         aopPut (result, zero, offset++);
5708
5709       popB (pushedB);
5710       return;
5711     }
5712
5713   /* signed is a little bit more difficult */
5714
5715   /* now sign adjust for both left & right */
5716
5717   /* let's see what's needed: */
5718   /* apply negative sign during runtime */
5719   runtimeSign = FALSE;
5720   /* negative sign from literals */
5721   compiletimeSign = FALSE;
5722
5723   if (!lUnsigned)
5724     {
5725       if (AOP_TYPE(left) == AOP_LIT)
5726         {
5727           /* signed literal */
5728           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5729           if (val < 0)
5730             compiletimeSign = TRUE;
5731         }
5732       else
5733         /* signed but not literal */
5734         runtimeSign = TRUE;
5735     }
5736
5737   if (!rUnsigned)
5738     {
5739       if (AOP_TYPE(right) == AOP_LIT)
5740         {
5741           /* signed literal */
5742           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5743           if (val < 0)
5744             compiletimeSign ^= TRUE;
5745         }
5746       else
5747         /* signed but not literal */
5748         runtimeSign = TRUE;
5749     }
5750
5751   /* initialize F0, which stores the runtime sign */
5752   if (runtimeSign)
5753     {
5754       if (compiletimeSign)
5755         emitcode ("setb", "F0"); /* set sign flag */
5756       else
5757         emitcode ("clr", "F0"); /* reset sign flag */
5758     }
5759
5760   /* save the signs of the operands */
5761   if (AOP_TYPE(right) == AOP_LIT)
5762     {
5763       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5764
5765       if (!rUnsigned && val < 0)
5766         emitcode ("mov", "b,#0x%02x", -val);
5767       else
5768         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5769     }
5770   else /* ! literal */
5771     {
5772       if (rUnsigned)
5773         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5774       else
5775         {
5776           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5777           lbl = newiTempLabel (NULL);
5778           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5779           emitcode ("cpl", "F0"); /* complement sign flag */
5780           emitcode ("cpl", "a");  /* 2's complement */
5781           emitcode ("inc", "a");
5782           emitLabel (lbl);
5783           emitcode ("mov", "b,a");
5784         }
5785     }
5786
5787   if (AOP_TYPE(left) == AOP_LIT)
5788     {
5789       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5790
5791       if (!lUnsigned && val < 0)
5792         emitcode ("mov", "a,#0x%02x", -val);
5793       else
5794         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5795     }
5796   else /* ! literal */
5797     {
5798       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5799
5800       if (!lUnsigned)
5801         {
5802           lbl = newiTempLabel (NULL);
5803           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5804           emitcode ("cpl", "F0"); /* complement sign flag */
5805           emitcode ("cpl", "a");  /* 2's complement */
5806           emitcode ("inc", "a");
5807           emitLabel (lbl);
5808         }
5809     }
5810
5811   /* now the division */
5812   emitcode ("nop", "; workaround for DS80C390 div bug.");
5813   emitcode ("div", "ab");
5814
5815   if (runtimeSign || compiletimeSign)
5816     {
5817       lbl = newiTempLabel (NULL);
5818       if (runtimeSign)
5819         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5820       emitcode ("cpl", "a"); /* lsb 2's complement */
5821       emitcode ("inc", "a");
5822       emitLabel (lbl);
5823
5824       _G.accInUse++;
5825       aopOp (result, ic, TRUE, FALSE);
5826       size = AOP_SIZE (result) - 1;
5827
5828       if (size > 0)
5829         {
5830           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5831              then the result will be in b, a */
5832           emitcode ("mov", "b,a"); /* 1 */
5833           /* msb is 0x00 or 0xff depending on the sign */
5834           if (runtimeSign)
5835             {
5836               emitcode ("mov",  "c,F0");
5837               emitcode ("subb", "a,acc");
5838               emitcode ("xch",  "a,b"); /* 2 */
5839               while (size--)
5840                 aopPut (result, "b", offset++); /* write msb's */
5841             }
5842           else /* compiletimeSign */
5843             while (size--)
5844               aopPut (result, "#0xff", offset++); /* write msb's */
5845         }
5846       aopPut (result, "a", 0); /* 3: write lsb */
5847     }
5848   else
5849     {
5850       _G.accInUse++;
5851       aopOp(result, ic, TRUE, FALSE);
5852       size = AOP_SIZE (result) - 1;
5853
5854       aopPut (result, "a", 0);
5855       while (size--)
5856         aopPut (result, zero, offset++);
5857     }
5858   _G.accInUse--;
5859   popB (pushedB);
5860 }
5861
5862 /*-----------------------------------------------------------------*/
5863 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5864 /*-----------------------------------------------------------------*/
5865 static void genDivTwoByte (operand *left, operand *right,
5866                             operand *result, iCode *ic)
5867 {
5868         sym_link *retype = getSpec(operandType(right));
5869         sym_link *letype = getSpec(operandType(left));
5870         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5871         symbol *lbl;
5872
5873         /* save EA bit in F1 */
5874         lbl = newiTempLabel(NULL);
5875         emitcode ("setb","F1");
5876         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5877         emitcode ("clr","F1");
5878         emitLabel (lbl);
5879
5880         /* load up MA with left */
5881         if (!umult) {
5882                 emitcode("clr","F0");
5883                 lbl = newiTempLabel(NULL);
5884                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5885                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5886                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5887                 emitcode ("xch", "a,b");
5888                 emitcode ("cpl","a");
5889                 emitcode ("add", "a,#1");
5890                 emitcode ("xch", "a,b");
5891                 emitcode ("cpl", "a"); // msb
5892                 emitcode ("addc","a,#0");
5893                 emitcode ("setb","F0");
5894                 emitLabel (lbl);
5895                 emitcode ("mov","ma,b");
5896                 emitcode ("mov","ma,a");
5897         } else {
5898                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5899                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5900         }
5901
5902         /* load up MB with right */
5903         if (!umult) {
5904                 if (AOP_TYPE(right) == AOP_LIT) {
5905                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
5906                         if (val < 0) {
5907                                 lbl = newiTempLabel(NULL);
5908                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5909                                 emitcode("setb","F0");
5910                                 emitLabel (lbl);
5911                                 val = -val;
5912                         }
5913                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5914                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5915                 } else {
5916                         lbl = newiTempLabel(NULL);
5917                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5918                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5919                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5920                         emitcode ("xch", "a,b");
5921                         emitcode ("cpl","a");
5922                         emitcode ("add", "a,#1");
5923                         emitcode ("xch", "a,b");
5924                         emitcode ("cpl", "a"); // msb
5925                         emitcode ("addc", "a,#0");
5926                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5927                         emitcode ("setb","F0");
5928                         emitLabel (lbl);
5929                         emitcode ("mov","mb,b");
5930                         emitcode ("mov","mb,a");
5931                 }
5932         } else {
5933                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5934                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5935         }
5936
5937         /* wait for multiplication to finish */
5938         lbl = newiTempLabel(NULL);
5939         emitLabel (lbl);
5940         emitcode("mov","a,mcnt1");
5941         emitcode("anl","a,#!constbyte",0x80);
5942         emitcode("jnz","!tlabel",lbl->key+100);
5943
5944         freeAsmop (left, NULL, ic, TRUE);
5945         freeAsmop (right, NULL, ic,TRUE);
5946         aopOp(result, ic, TRUE, FALSE);
5947
5948         /* if unsigned then simple */
5949         if (umult) {
5950                 aopPut(result,"ma",1);
5951                 aopPut(result,"ma",0);
5952         } else {
5953                 emitcode("push","ma");
5954                 MOVA("ma");
5955                 /* negate result if needed */
5956                 lbl = newiTempLabel(NULL);
5957                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5958                 emitcode("cpl","a");
5959                 emitcode("add","a,#1");
5960                 emitLabel (lbl);
5961                 aopPut(result,"a",0);
5962                 emitcode("pop","acc");
5963                 lbl = newiTempLabel(NULL);
5964                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5965                 emitcode("cpl","a");
5966                 emitcode("addc","a,#0");
5967                 emitLabel (lbl);
5968                 aopPut(result,"a",1);
5969         }
5970         freeAsmop (result, NULL, ic, TRUE);
5971         /* restore EA bit in F1 */
5972         lbl = newiTempLabel(NULL);
5973         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5974         emitcode ("setb","EA");
5975         emitLabel (lbl);
5976         return ;
5977 }
5978
5979 /*-----------------------------------------------------------------*/
5980 /* genDiv - generates code for division                            */
5981 /*-----------------------------------------------------------------*/
5982 static void
5983 genDiv (iCode * ic)
5984 {
5985   operand *left = IC_LEFT (ic);
5986   operand *right = IC_RIGHT (ic);
5987   operand *result = IC_RESULT (ic);
5988
5989   D (emitcode (";", "genDiv"));
5990
5991   /* assign the amsops */
5992   AOP_OP_2 (ic);
5993
5994   /* special cases first */
5995   /* both are bits */
5996   if (AOP_TYPE (left) == AOP_CRY &&
5997       AOP_TYPE (right) == AOP_CRY)
5998     {
5999       genDivbits (left, right, result, ic);
6000       goto release;
6001     }
6002
6003   /* if both are of size == 1 */
6004   if (AOP_SIZE (left) == 1 &&
6005       AOP_SIZE (right) == 1)
6006     {
6007       genDivOneByte (left, right, result, ic);
6008       goto release;
6009     }
6010
6011   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6012           /* use the ds390 ARITHMETIC accel UNIT */
6013           genDivTwoByte (left, right, result, ic);
6014           return ;
6015   }
6016   /* should have been converted to function call */
6017   assert (0);
6018 release:
6019   freeAsmop (result, NULL, ic, TRUE);
6020   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6021   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6022 }
6023
6024 /*-----------------------------------------------------------------*/
6025 /* genModbits :- modulus of bits                                   */
6026 /*-----------------------------------------------------------------*/
6027 static void
6028 genModbits (operand * left,
6029             operand * right,
6030             operand * result,
6031             iCode   * ic)
6032 {
6033   char *l;
6034   bool pushedB;
6035
6036   D (emitcode (";", "genModbits"));
6037
6038   pushedB = pushB ();
6039
6040   /* the result must be bit */
6041   LOAD_AB_FOR_DIV (left, right, l);
6042   emitcode ("div", "ab");
6043   emitcode ("mov", "a,b");
6044   emitcode ("rrc", "a");
6045   aopOp(result, ic, TRUE, FALSE);
6046
6047   popB (pushedB);
6048
6049   aopPut (result, "c", 0);
6050 }
6051
6052 /*-----------------------------------------------------------------*/
6053 /* genModOneByte : 8 bit modulus                                   */
6054 /*-----------------------------------------------------------------*/
6055 static void
6056 genModOneByte (operand * left,
6057                operand * right,
6058                operand * result,
6059                iCode   * ic)
6060 {
6061   bool lUnsigned, rUnsigned, pushedB;
6062   bool runtimeSign, compiletimeSign;
6063   char *l;
6064   symbol *lbl;
6065   int size, offset;
6066
6067   D (emitcode (";", "genModOneByte"));
6068
6069   offset = 1;
6070   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6071   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6072
6073   pushedB = pushB ();
6074
6075   /* signed or unsigned */
6076   if (lUnsigned && rUnsigned)
6077     {
6078       /* unsigned is easy */
6079       LOAD_AB_FOR_DIV (left, right, l);
6080       emitcode ("div", "ab");
6081       aopOp (result, ic, TRUE, FALSE);
6082       aopPut (result, "b", 0);
6083
6084       for (size = AOP_SIZE (result) - 1; size--;)
6085         aopPut (result, zero, offset++);
6086
6087       popB (pushedB);
6088       return;
6089     }
6090
6091   /* signed is a little bit more difficult */
6092
6093   /* now sign adjust for both left & right */
6094
6095   /* modulus: sign of the right operand has no influence on the result! */
6096   if (AOP_TYPE(right) == AOP_LIT)
6097     {
6098       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
6099
6100       if (!rUnsigned && val < 0)
6101         emitcode ("mov", "b,#0x%02x", -val);
6102       else
6103         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6104     }
6105   else /* not literal */
6106     {
6107       if (rUnsigned)
6108         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6109       else
6110         {
6111           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6112           lbl = newiTempLabel (NULL);
6113           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6114           emitcode ("cpl", "a");  /* 2's complement */
6115           emitcode ("inc", "a");
6116           emitLabel (lbl);
6117           emitcode ("mov", "b,a");
6118         }
6119     }
6120
6121   /* let's see what's needed: */
6122   /* apply negative sign during runtime */
6123   runtimeSign = FALSE;
6124   /* negative sign from literals */
6125   compiletimeSign = FALSE;
6126
6127   /* sign adjust left side */
6128   if (AOP_TYPE(left) == AOP_LIT)
6129     {
6130       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
6131
6132       if (!lUnsigned && val < 0)
6133         {
6134           compiletimeSign = TRUE; /* set sign flag */
6135           emitcode ("mov", "a,#0x%02x", -val);
6136         }
6137       else
6138         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6139     }
6140   else /* ! literal */
6141     {
6142       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6143
6144       if (!lUnsigned)
6145         {
6146           runtimeSign = TRUE;
6147           emitcode ("clr", "F0"); /* clear sign flag */
6148
6149           lbl = newiTempLabel (NULL);
6150           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6151           emitcode ("setb", "F0"); /* set sign flag */
6152           emitcode ("cpl", "a");   /* 2's complement */
6153           emitcode ("inc", "a");
6154           emitLabel (lbl);
6155         }
6156     }
6157
6158   /* now the modulus */
6159   emitcode ("nop", "; workaround for DS80C390 div bug.");
6160   emitcode ("div", "ab");
6161
6162   if (runtimeSign || compiletimeSign)
6163     {
6164       emitcode ("mov", "a,b");
6165       lbl = newiTempLabel (NULL);
6166       if (runtimeSign)
6167         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6168       emitcode ("cpl", "a"); /* lsb 2's complement */
6169       emitcode ("inc", "a");
6170       emitLabel (lbl);
6171
6172       _G.accInUse++;
6173       aopOp (result, ic, TRUE, FALSE);
6174       size = AOP_SIZE (result) - 1;
6175
6176       if (size > 0)
6177         {
6178           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6179              then the result will be in b, a */
6180           emitcode ("mov", "b,a"); /* 1 */
6181           /* msb is 0x00 or 0xff depending on the sign */
6182           if (runtimeSign)
6183             {
6184               emitcode ("mov",  "c,F0");
6185               emitcode ("subb", "a,acc");
6186               emitcode ("xch",  "a,b"); /* 2 */
6187               while (size--)
6188                 aopPut (result, "b", offset++); /* write msb's */
6189             }
6190           else /* compiletimeSign */
6191             while (size--)
6192               aopPut (result, "#0xff", offset++); /* write msb's */
6193         }
6194       aopPut (result, "a", 0); /* 3: write lsb */
6195     }
6196   else
6197     {
6198       _G.accInUse++;
6199       aopOp(result, ic, TRUE, FALSE);
6200       size = AOP_SIZE (result) - 1;
6201
6202       aopPut (result, "b", 0);
6203       while (size--)
6204         aopPut (result, zero, offset++);
6205     }
6206   _G.accInUse--;
6207   popB (pushedB);
6208 }
6209
6210 /*-----------------------------------------------------------------*/
6211 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6212 /*-----------------------------------------------------------------*/
6213 static void genModTwoByte (operand *left, operand *right,
6214                             operand *result, iCode *ic)
6215 {
6216         sym_link *retype = getSpec(operandType(right));
6217         sym_link *letype = getSpec(operandType(left));
6218         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6219         symbol *lbl;
6220
6221         /* load up MA with left */
6222         /* save EA bit in F1 */
6223         lbl = newiTempLabel(NULL);
6224         emitcode ("setb","F1");
6225         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6226         emitcode ("clr","F1");
6227         emitLabel (lbl);
6228
6229         if (!umult) {
6230                 lbl = newiTempLabel(NULL);
6231                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6232                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6233                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6234                 emitcode ("xch", "a,b");
6235                 emitcode ("cpl","a");
6236                 emitcode ("add", "a,#1");
6237                 emitcode ("xch", "a,b");
6238                 emitcode ("cpl", "a"); // msb
6239                 emitcode ("addc","a,#0");
6240                 emitLabel (lbl);
6241                 emitcode ("mov","ma,b");
6242                 emitcode ("mov","ma,a");
6243         } else {
6244                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6245                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6246         }
6247
6248         /* load up MB with right */
6249         if (!umult) {
6250                 if (AOP_TYPE(right) == AOP_LIT) {
6251                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
6252                         if (val < 0) {
6253                                 val = -val;
6254                         }
6255                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6256                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6257                 } else {
6258                         lbl = newiTempLabel(NULL);
6259                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6260                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6261                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6262                         emitcode ("xch", "a,b");
6263                         emitcode ("cpl","a");
6264                         emitcode ("add", "a,#1");
6265                         emitcode ("xch", "a,b");
6266                         emitcode ("cpl", "a"); // msb
6267                         emitcode ("addc", "a,#0");
6268                         emitLabel (lbl);
6269                         emitcode ("mov","mb,b");
6270                         emitcode ("mov","mb,a");
6271                 }
6272         } else {
6273                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6274                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6275         }
6276
6277         /* wait for multiplication to finish */
6278         lbl = newiTempLabel(NULL);
6279         emitLabel (lbl);
6280         emitcode("mov","a,mcnt1");
6281         emitcode("anl","a,#!constbyte",0x80);
6282         emitcode("jnz","!tlabel",lbl->key+100);
6283
6284         freeAsmop (left, NULL, ic, TRUE);
6285         freeAsmop (right, NULL, ic,TRUE);
6286         aopOp(result, ic, TRUE, FALSE);
6287
6288         aopPut(result,"mb",1);
6289         aopPut(result,"mb",0);
6290         freeAsmop (result, NULL, ic, TRUE);
6291
6292         /* restore EA bit in F1 */
6293         lbl = newiTempLabel(NULL);
6294         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6295         emitcode ("setb","EA");
6296         emitLabel (lbl);
6297 }
6298
6299 /*-----------------------------------------------------------------*/
6300 /* genMod - generates code for division                            */
6301 /*-----------------------------------------------------------------*/
6302 static void
6303 genMod (iCode * ic)
6304 {
6305   operand *left = IC_LEFT (ic);
6306   operand *right = IC_RIGHT (ic);
6307   operand *result = IC_RESULT (ic);
6308
6309   D (emitcode (";", "genMod"));
6310
6311   /* assign the asmops */
6312   AOP_OP_2 (ic);
6313
6314   /* special cases first */
6315   /* both are bits */
6316   if (AOP_TYPE (left) == AOP_CRY &&
6317       AOP_TYPE (right) == AOP_CRY)
6318     {
6319       genModbits (left, right, result, ic);
6320       goto release;
6321     }
6322
6323   /* if both are of size == 1 */
6324   if (AOP_SIZE (left) == 1 &&
6325       AOP_SIZE (right) == 1)
6326     {
6327       genModOneByte (left, right, result, ic);
6328       goto release;
6329     }
6330
6331   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6332           /* use the ds390 ARITHMETIC accel UNIT */
6333           genModTwoByte (left, right, result, ic);
6334           return ;
6335   }
6336
6337   /* should have been converted to function call */
6338   assert (0);
6339
6340 release:
6341   freeAsmop (result, NULL, ic, TRUE);
6342   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6343   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6344 }
6345
6346 /*-----------------------------------------------------------------*/
6347 /* genIfxJump :- will create a jump depending on the ifx           */
6348 /*-----------------------------------------------------------------*/
6349 static void
6350 genIfxJump (iCode * ic, char *jval)
6351 {
6352   symbol *jlbl;
6353   symbol *tlbl = newiTempLabel (NULL);
6354   char *inst;
6355
6356   D (emitcode (";", "genIfxJump"));
6357
6358   /* if true label then we jump if condition
6359      supplied is true */
6360   if (IC_TRUE (ic))
6361     {
6362       jlbl = IC_TRUE (ic);
6363       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6364                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6365     }
6366   else
6367     {
6368       /* false label is present */
6369       jlbl = IC_FALSE (ic);
6370       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6371                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6372     }
6373   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6374     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6375   else
6376     emitcode (inst, "!tlabel", tlbl->key + 100);
6377   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6378   emitLabel (tlbl);
6379
6380   /* mark the icode as generated */
6381   ic->generated = 1;
6382 }
6383
6384 /*-----------------------------------------------------------------*/
6385 /* genCmp :- greater or less than comparison                       */
6386 /*-----------------------------------------------------------------*/
6387 static void
6388 genCmp (operand * left, operand * right,
6389         iCode * ic, iCode * ifx, int sign)
6390 {
6391   int size, offset = 0;
6392   unsigned long lit = 0L;
6393   operand *result;
6394
6395   D (emitcode (";", "genCmp"));
6396
6397   result = IC_RESULT (ic);
6398
6399   /* if left & right are bit variables */
6400   if (AOP_TYPE (left) == AOP_CRY &&
6401       AOP_TYPE (right) == AOP_CRY)
6402     {
6403       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6404       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6405     }
6406   else
6407     {
6408       /* subtract right from left if at the
6409          end the carry flag is set then we know that
6410          left is greater than right */
6411       size = max (AOP_SIZE (left), AOP_SIZE (right));
6412
6413       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6414       if ((size == 1) && !sign &&
6415           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6416         {
6417           symbol *lbl = newiTempLabel (NULL);
6418           emitcode ("cjne", "%s,%s,!tlabel",
6419                     aopGet (left, offset, FALSE, FALSE, NULL),
6420                     aopGet (right, offset, FALSE, FALSE, NULL),
6421                     lbl->key + 100);
6422           emitLabel (lbl);
6423         }
6424       else
6425         {
6426           if (AOP_TYPE (right) == AOP_LIT)
6427             {
6428               lit = ulFromVal (AOP (right)->aopu.aop_lit);
6429               /* optimize if(x < 0) or if(x >= 0) */
6430               if (lit == 0L)
6431                 {
6432                   if (!sign)
6433                     {
6434                       CLRC;
6435                     }
6436                   else
6437                     {
6438                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6439
6440                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6441                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6442
6443                       aopOp (result, ic, FALSE, FALSE);
6444
6445                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6446                         {
6447                           freeAsmop (result, NULL, ic, TRUE);
6448                           genIfxJump (ifx, "acc.7");
6449                           return;
6450                         }
6451                       else
6452                         {
6453                           emitcode ("rlc", "a");
6454                         }
6455                       goto release_freedLR;
6456                     }
6457                   goto release;
6458                 }
6459             }
6460           CLRC;
6461           while (size--)
6462             {
6463               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6464               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6465               // emitcode (";", "genCmp #2");
6466               if (sign && (size == 0))
6467                 {
6468                   // emitcode (";", "genCmp #3");
6469                   emitcode ("xrl", "a,#!constbyte",0x80);
6470                   if (AOP_TYPE (right) == AOP_LIT)
6471                     {
6472                       unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
6473                       // emitcode (";", "genCmp #3.1");
6474                       emitcode ("subb", "a,#!constbyte",
6475                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6476                     }
6477                   else
6478                     {
6479                       // emitcode (";", "genCmp #3.2");
6480                       saveAccWarn = 0;
6481                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6482                       saveAccWarn = DEFAULT_ACC_WARNING;
6483                       emitcode ("xrl", "b,#!constbyte",0x80);
6484                       emitcode ("subb", "a,b");
6485                     }
6486                 }
6487               else
6488                 {
6489                   const char *s;
6490
6491                   // emitcode (";", "genCmp #4");
6492                   saveAccWarn = 0;
6493                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6494                   saveAccWarn = DEFAULT_ACC_WARNING;
6495
6496                   emitcode ("subb", "a,%s", s);
6497                 }
6498             }
6499         }
6500     }
6501
6502 release:
6503 /* Don't need the left & right operands any more; do need the result. */
6504   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6505   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6506
6507   aopOp (result, ic, FALSE, FALSE);
6508
6509 release_freedLR:
6510
6511   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6512     {
6513       outBitC (result);
6514     }
6515   else
6516     {
6517       /* if the result is used in the next
6518          ifx conditional branch then generate
6519          code a little differently */
6520       if (ifx)
6521         {
6522           genIfxJump (ifx, "c");
6523         }
6524       else
6525         {
6526           outBitC (result);
6527         }
6528       /* leave the result in acc */
6529     }
6530   freeAsmop (result, NULL, ic, TRUE);
6531 }
6532
6533 /*-----------------------------------------------------------------*/
6534 /* genCmpGt :- greater than comparison                             */
6535 /*-----------------------------------------------------------------*/
6536 static void
6537 genCmpGt (iCode * ic, iCode * ifx)
6538 {
6539   operand *left, *right;
6540   sym_link *letype, *retype;
6541   int sign;
6542
6543   D (emitcode (";", "genCmpGt"));
6544
6545   left = IC_LEFT (ic);
6546   right = IC_RIGHT (ic);
6547
6548   letype = getSpec (operandType (left));
6549   retype = getSpec (operandType (right));
6550   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6551
6552   /* assign the left & right amsops */
6553   AOP_OP_2 (ic);
6554
6555   genCmp (right, left, ic, ifx, sign);
6556 }
6557
6558 /*-----------------------------------------------------------------*/
6559 /* genCmpLt - less than comparisons                                */
6560 /*-----------------------------------------------------------------*/
6561 static void
6562 genCmpLt (iCode * ic, iCode * ifx)
6563 {
6564   operand *left, *right;
6565   sym_link *letype, *retype;
6566   int sign;
6567
6568   D (emitcode (";", "genCmpLt"));
6569
6570   left = IC_LEFT (ic);
6571   right = IC_RIGHT (ic);
6572
6573   letype = getSpec (operandType (left));
6574   retype = getSpec (operandType (right));
6575   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6576
6577   /* assign the left & right amsops */
6578   AOP_OP_2 (ic);
6579
6580   genCmp (left, right, ic, ifx, sign);
6581 }
6582
6583 /*-----------------------------------------------------------------*/
6584 /* gencjneshort - compare and jump if not equal                    */
6585 /*-----------------------------------------------------------------*/
6586 static void
6587 gencjneshort (operand * left, operand * right, symbol * lbl)
6588 {
6589   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6590   int offset = 0;
6591   unsigned long lit = 0L;
6592
6593   D (emitcode (";", "gencjneshort"));
6594
6595   /* if the left side is a literal or
6596      if the right is in a pointer register and left
6597      is not */
6598   if ((AOP_TYPE (left) == AOP_LIT) ||
6599       (AOP_TYPE (left) == AOP_IMMD) ||
6600       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6601     {
6602       operand *t = right;
6603       right = left;
6604       left = t;
6605     }
6606
6607   if (AOP_TYPE (right) == AOP_LIT)
6608     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6609
6610   if (opIsGptr (left) || opIsGptr (right))
6611     {
6612       /* We are comparing a generic pointer to something.
6613        * Exclude the generic type byte from the comparison.
6614        */
6615       size--;
6616       D (emitcode (";", "cjneshort: generic ptr special case."););
6617     }
6618
6619
6620   /* if the right side is a literal then anything goes */
6621   if (AOP_TYPE (right) == AOP_LIT &&
6622       AOP_TYPE (left) != AOP_DIR)
6623     {
6624       while (size--)
6625         {
6626           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6627           emitcode ("cjne", "a,%s,!tlabel",
6628                     aopGet (right, offset, FALSE, FALSE, NULL),
6629                     lbl->key + 100);
6630           offset++;
6631         }
6632     }
6633
6634   /* if the right side is in a register or in direct space or
6635      if the left is a pointer register & right is not */
6636   else if (AOP_TYPE (right) == AOP_REG ||
6637            AOP_TYPE (right) == AOP_DIR ||
6638            AOP_TYPE (right) == AOP_LIT ||
6639            AOP_TYPE (right) == AOP_IMMD ||
6640            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6641            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6642     {
6643       while (size--)
6644         {
6645           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6646           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6647               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6648             emitcode ("jnz", "!tlabel", lbl->key + 100);
6649           else
6650             emitcode ("cjne", "a,%s,!tlabel",
6651                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6652                       lbl->key + 100);
6653           offset++;
6654         }
6655     }
6656   else
6657     {
6658       /* right is a pointer reg need both a & b */
6659       while (size--)
6660         {
6661           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6662           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6663           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6664           offset++;
6665         }
6666     }
6667 }
6668
6669 /*-----------------------------------------------------------------*/
6670 /* gencjne - compare and jump if not equal                         */
6671 /*-----------------------------------------------------------------*/
6672 static void
6673 gencjne (operand * left, operand * right, symbol * lbl)
6674 {
6675   symbol *tlbl = newiTempLabel (NULL);
6676
6677   D (emitcode (";", "gencjne"));
6678
6679   gencjneshort (left, right, lbl);
6680
6681   emitcode ("mov", "a,%s", one);
6682   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6683   emitLabel (lbl);
6684   emitcode ("clr", "a");
6685   emitLabel (tlbl);
6686 }
6687
6688 /*-----------------------------------------------------------------*/
6689 /* genCmpEq - generates code for equal to                          */
6690 /*-----------------------------------------------------------------*/
6691 static void
6692 genCmpEq (iCode * ic, iCode * ifx)
6693 {
6694   operand *left, *right, *result;
6695
6696   D (emitcode (";", "genCmpEq"));
6697
6698   AOP_OP_2 (ic);
6699   AOP_SET_LOCALS (ic);
6700
6701   /* if literal, literal on the right or
6702      if the right is in a pointer register and left
6703      is not */
6704   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6705       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6706     {
6707       operand *t = IC_RIGHT (ic);
6708       IC_RIGHT (ic) = IC_LEFT (ic);
6709       IC_LEFT (ic) = t;
6710     }
6711
6712   if (ifx &&                    /* !AOP_SIZE(result) */
6713       OP_SYMBOL (result) &&
6714       OP_SYMBOL (result)->regType == REG_CND)
6715     {
6716       symbol *tlbl;
6717       /* if they are both bit variables */
6718       if (AOP_TYPE (left) == AOP_CRY &&
6719           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6720         {
6721           if (AOP_TYPE (right) == AOP_LIT)
6722             {
6723               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6724               if (lit == 0L)
6725                 {
6726                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6727                   emitcode ("cpl", "c");
6728                 }
6729               else if (lit == 1L)
6730                 {
6731                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6732                 }
6733               else
6734                 {
6735                   emitcode ("clr", "c");
6736                 }
6737               /* AOP_TYPE(right) == AOP_CRY */
6738             }
6739           else
6740             {
6741               symbol *lbl = newiTempLabel (NULL);
6742               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6743               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6744               emitcode ("cpl", "c");
6745               emitLabel (lbl);
6746             }
6747           /* if true label then we jump if condition
6748              supplied is true */
6749           tlbl = newiTempLabel (NULL);
6750           if (IC_TRUE (ifx))
6751             {
6752               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6753               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6754             }
6755           else
6756             {
6757               emitcode ("jc", "!tlabel", tlbl->key + 100);
6758               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6759             }
6760           emitLabel (tlbl);
6761         }
6762       else
6763         {
6764           tlbl = newiTempLabel (NULL);
6765           gencjneshort (left, right, tlbl);
6766           if (IC_TRUE (ifx))
6767             {
6768               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6769               emitLabel (tlbl);
6770             }
6771           else
6772             {
6773               symbol *lbl = newiTempLabel (NULL);
6774               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6775               emitLabel (tlbl);
6776               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6777               emitLabel (lbl);
6778             }
6779         }
6780       /* mark the icode as generated */
6781       ifx->generated = 1;
6782
6783       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6784       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6785       return;
6786     }
6787
6788   /* if they are both bit variables */
6789   if (AOP_TYPE (left) == AOP_CRY &&
6790       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6791     {
6792       if (AOP_TYPE (right) == AOP_LIT)
6793         {
6794           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6795           if (lit == 0L)
6796             {
6797               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6798               emitcode ("cpl", "c");
6799             }
6800           else if (lit == 1L)
6801             {
6802               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6803             }
6804           else
6805             {
6806               emitcode ("clr", "c");
6807             }
6808           /* AOP_TYPE(right) == AOP_CRY */
6809         }
6810       else
6811         {
6812           symbol *lbl = newiTempLabel (NULL);
6813           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6814           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6815           emitcode ("cpl", "c");
6816           emitLabel (lbl);
6817         }
6818
6819       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6820       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6821
6822       aopOp (result, ic, TRUE, FALSE);
6823
6824       /* c = 1 if egal */
6825       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6826         {
6827           outBitC (result);
6828           goto release;
6829         }
6830       if (ifx)
6831         {
6832           genIfxJump (ifx, "c");
6833           goto release;
6834         }
6835       /* if the result is used in an arithmetic operation
6836          then put the result in place */
6837       outBitC (result);
6838     }
6839   else
6840     {
6841       gencjne (left, right, newiTempLabel (NULL));
6842
6843       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6844       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6845
6846       aopOp (result, ic, TRUE, FALSE);
6847
6848       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6849         {
6850           aopPut (result, "a", 0);
6851           goto release;
6852         }
6853       if (ifx)
6854         {
6855           genIfxJump (ifx, "a");
6856           goto release;
6857         }
6858       /* if the result is used in an arithmetic operation
6859          then put the result in place */
6860       if (AOP_TYPE (result) != AOP_CRY)
6861         outAcc (result);
6862       /* leave the result in acc */
6863     }
6864
6865 release:
6866   freeAsmop (result, NULL, ic, TRUE);
6867 }
6868
6869 /*-----------------------------------------------------------------*/
6870 /* ifxForOp - returns the icode containing the ifx for operand     */
6871 /*-----------------------------------------------------------------*/
6872 static iCode *
6873 ifxForOp (operand * op, iCode * ic)
6874 {
6875   /* if true symbol then needs to be assigned */
6876   if (IS_TRUE_SYMOP (op))
6877     return NULL;
6878
6879   /* if this has register type condition and
6880      the next instruction is ifx with the same operand
6881      and live to of the operand is upto the ifx only then */
6882   if (ic->next &&
6883       ic->next->op == IFX &&
6884       IC_COND (ic->next)->key == op->key &&
6885       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6886     return ic->next;
6887
6888   return NULL;
6889 }
6890
6891 /*-----------------------------------------------------------------*/
6892 /* hasInc - operand is incremented before any other use            */
6893 /*-----------------------------------------------------------------*/
6894 static iCode *
6895 hasInc (operand *op, iCode *ic, int osize)
6896 {
6897   sym_link *type = operandType(op);
6898   sym_link *retype = getSpec (type);
6899   iCode *lic = ic->next;
6900   int isize ;
6901
6902   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6903   if (!IS_SYMOP(op)) return NULL;
6904
6905   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6906   if (IS_AGGREGATE(type->next)) return NULL;
6907   if (osize != (isize = getSize(type->next))) return NULL;
6908
6909   while (lic) {
6910       /* if operand of the form op = op + <sizeof *op> */
6911       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6912           isOperandEqual(IC_RESULT(lic),op) &&
6913           isOperandLiteral(IC_RIGHT(lic)) &&
6914           operandLitValue(IC_RIGHT(lic)) == isize) {
6915           return lic;
6916       }
6917       /* if the operand used or deffed */
6918       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6919           return NULL;
6920       }
6921       /* if GOTO or IFX */
6922       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6923       lic = lic->next;
6924   }
6925   return NULL;
6926 }
6927
6928 /*-----------------------------------------------------------------*/
6929 /* genAndOp - for && operation                                     */
6930 /*-----------------------------------------------------------------*/
6931 static void
6932 genAndOp (iCode * ic)
6933 {
6934   operand *left, *right, *result;
6935   symbol *tlbl;
6936
6937   D (emitcode (";", "genAndOp"));
6938
6939   /* note here that && operations that are in an
6940      if statement are taken away by backPatchLabels
6941      only those used in arthmetic operations remain */
6942   AOP_OP_2 (ic);
6943   AOP_SET_LOCALS (ic);
6944
6945   /* if both are bit variables */
6946   if (AOP_TYPE (left) == AOP_CRY &&
6947       AOP_TYPE (right) == AOP_CRY)
6948     {
6949       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6950       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6951       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6952       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6953
6954       aopOp (result,ic,FALSE, FALSE);
6955       outBitC (result);
6956     }
6957   else
6958     {
6959       tlbl = newiTempLabel (NULL);
6960       toBoolean (left);
6961       emitcode ("jz", "!tlabel", tlbl->key + 100);
6962       toBoolean (right);
6963       emitLabel (tlbl);
6964       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6965       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6966
6967       aopOp (result,ic,FALSE, FALSE);
6968       outBitAcc (result);
6969     }
6970
6971     freeAsmop (result, NULL, ic, TRUE);
6972 }
6973
6974
6975 /*-----------------------------------------------------------------*/
6976 /* genOrOp - for || operation                                      */
6977 /*-----------------------------------------------------------------*/
6978 static void
6979 genOrOp (iCode * ic)
6980 {
6981   operand *left, *right, *result;
6982   symbol *tlbl;
6983
6984   D (emitcode (";", "genOrOp"));
6985
6986   /* note here that || operations that are in an
6987      if statement are taken away by backPatchLabels
6988      only those used in arthmetic operations remain */
6989   AOP_OP_2 (ic);
6990   AOP_SET_LOCALS (ic);
6991
6992   /* if both are bit variables */
6993   if (AOP_TYPE (left) == AOP_CRY &&
6994       AOP_TYPE (right) == AOP_CRY)
6995     {
6996       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6997       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6998       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6999       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7000
7001       aopOp (result,ic,FALSE, FALSE);
7002
7003       outBitC (result);
7004     }
7005   else
7006     {
7007       tlbl = newiTempLabel (NULL);
7008       toBoolean (left);
7009       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7010       toBoolean (right);
7011       emitLabel (tlbl);
7012       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7013       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7014
7015       aopOp (result,ic,FALSE, FALSE);
7016
7017       outBitAcc (result);
7018     }
7019
7020   freeAsmop (result, NULL, ic, TRUE);
7021 }
7022
7023 /*-----------------------------------------------------------------*/
7024 /* isLiteralBit - test if lit == 2^n                               */
7025 /*-----------------------------------------------------------------*/
7026 static int
7027 isLiteralBit (unsigned long lit)
7028 {
7029   unsigned long pw[32] =
7030   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7031    0x100L, 0x200L, 0x400L, 0x800L,
7032    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7033    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7034    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7035    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7036    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7037   int idx;
7038
7039   for (idx = 0; idx < 32; idx++)
7040     if (lit == pw[idx])
7041       return idx + 1;
7042   return 0;
7043 }
7044
7045 /*-----------------------------------------------------------------*/
7046 /* continueIfTrue -                                                */
7047 /*-----------------------------------------------------------------*/
7048 static void
7049 continueIfTrue (iCode * ic)
7050 {
7051   if (IC_TRUE (ic))
7052     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7053   ic->generated = 1;
7054 }
7055
7056 /*-----------------------------------------------------------------*/
7057 /* jmpIfTrue -                                                     */
7058 /*-----------------------------------------------------------------*/
7059 static void
7060 jumpIfTrue (iCode * ic)
7061 {
7062   if (!IC_TRUE (ic))
7063     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7064   ic->generated = 1;
7065 }
7066
7067 /*-----------------------------------------------------------------*/
7068 /* jmpTrueOrFalse -                                                */
7069 /*-----------------------------------------------------------------*/
7070 static void
7071 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7072 {
7073   // ugly but optimized by peephole
7074   if (IC_TRUE (ic))
7075     {
7076       symbol *nlbl = newiTempLabel (NULL);
7077       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7078       emitLabel (tlbl);
7079       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7080       emitLabel (nlbl);
7081     }
7082   else
7083     {
7084       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7085       emitLabel (tlbl);
7086     }
7087   ic->generated = 1;
7088 }
7089
7090 // Generate code to perform a bit-wise logic operation
7091 // on two operands in far space (assumed to already have been
7092 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7093 // in far space. This requires pushing the result on the stack
7094 // then popping it into the result.
7095 static void
7096 genFarFarLogicOp(iCode *ic, char *logicOp)
7097 {
7098       int size, resultSize, compSize;
7099       int offset = 0;
7100
7101       TR_AP("#5");
7102       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7103       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7104                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7105
7106       _startLazyDPSEvaluation();
7107       for (size = compSize; (size--); offset++)
7108       {
7109           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7110           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7111           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7112
7113           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7114           emitcode ("push", "acc");
7115       }
7116       _endLazyDPSEvaluation();
7117
7118       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7119       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7120       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7121
7122       resultSize = AOP_SIZE(IC_RESULT(ic));
7123
7124       ADJUST_PUSHED_RESULT(compSize, resultSize);
7125
7126       _startLazyDPSEvaluation();
7127       while (compSize--)
7128       {
7129           emitcode ("pop", "acc");
7130           aopPut (IC_RESULT (ic), "a", compSize);
7131       }
7132       _endLazyDPSEvaluation();
7133       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7134 }
7135
7136
7137 /*-----------------------------------------------------------------*/
7138 /* genAnd  - code for and                                          */
7139 /*-----------------------------------------------------------------*/
7140 static void
7141 genAnd (iCode * ic, iCode * ifx)
7142 {
7143   operand *left, *right, *result;
7144   int size, offset = 0;
7145   unsigned long lit = 0L;
7146   int bytelit = 0;
7147   char buffer[10];
7148   bool pushResult;
7149
7150   D (emitcode (";", "genAnd"));
7151
7152   AOP_OP_3_NOFATAL (ic, pushResult);
7153   AOP_SET_LOCALS (ic);
7154
7155   if (pushResult)
7156   {
7157       genFarFarLogicOp(ic, "anl");
7158       return;
7159   }
7160
7161 #ifdef DEBUG_TYPE
7162   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7163             AOP_TYPE (result),
7164             AOP_TYPE (left), AOP_TYPE (right));
7165   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7166             AOP_SIZE (result),
7167             AOP_SIZE (left), AOP_SIZE (right));
7168 #endif
7169
7170   /* if left is a literal & right is not then exchange them */
7171   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7172 #ifdef LOGIC_OPS_BROKEN
7173     ||  AOP_NEEDSACC (left)
7174 #endif
7175     )
7176     {
7177       operand *tmp = right;
7178       right = left;
7179       left = tmp;
7180     }
7181
7182   /* if result = right then exchange left and right */
7183   if (sameRegs (AOP (result), AOP (right)))
7184     {
7185       operand *tmp = right;
7186       right = left;
7187       left = tmp;
7188     }
7189
7190   /* if right is bit then exchange them */
7191   if (AOP_TYPE (right) == AOP_CRY &&
7192       AOP_TYPE (left) != AOP_CRY)
7193     {
7194       operand *tmp = right;
7195       right = left;
7196       left = tmp;
7197     }
7198   if (AOP_TYPE (right) == AOP_LIT)
7199     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7200
7201   size = AOP_SIZE (result);
7202
7203   // if(bit & yy)
7204   // result = bit & yy;
7205   if (AOP_TYPE (left) == AOP_CRY)
7206     {
7207       // c = bit & literal;
7208       if (AOP_TYPE (right) == AOP_LIT)
7209         {
7210           if (lit & 1)
7211             {
7212               if (size && sameRegs (AOP (result), AOP (left)))
7213                 // no change
7214                 goto release;
7215               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7216             }
7217           else
7218             {
7219               // bit(result) = 0;
7220               if (size && (AOP_TYPE (result) == AOP_CRY))
7221                 {
7222                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7223                   goto release;
7224                 }
7225               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7226                 {
7227                   jumpIfTrue (ifx);
7228                   goto release;
7229                 }
7230               emitcode ("clr", "c");
7231             }
7232         }
7233       else
7234         {
7235           if (AOP_TYPE (right) == AOP_CRY)
7236             {
7237               // c = bit & bit;
7238               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7239               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7240             }
7241           else
7242             {
7243               // c = bit & val;
7244               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7245               // c = lsb
7246               emitcode ("rrc", "a");
7247               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7248             }
7249         }
7250       // bit = c
7251       // val = c
7252       if (size)
7253         outBitC (result);
7254       // if(bit & ...)
7255       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7256         genIfxJump (ifx, "c");
7257       goto release;
7258     }
7259
7260   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7261   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7262   if ((AOP_TYPE (right) == AOP_LIT) &&
7263       (AOP_TYPE (result) == AOP_CRY) &&
7264       (AOP_TYPE (left) != AOP_CRY))
7265     {
7266       int posbit = isLiteralBit (lit);
7267       /* left &  2^n */
7268       if (posbit)
7269         {
7270           posbit--;
7271           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7272           // bit = left & 2^n
7273           if (size)
7274             {
7275               switch (posbit & 0x07)
7276                 {
7277                   case 0: emitcode ("rrc", "a");
7278                           break;
7279                   case 7: emitcode ("rlc", "a");
7280                           break;
7281                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7282                           break;
7283                 }
7284             }
7285           // if(left &  2^n)
7286           else
7287             {
7288               if (ifx)
7289                 {
7290                   SNPRINTF (buffer, sizeof(buffer),
7291                             "acc.%d", posbit & 0x07);
7292                   genIfxJump (ifx, buffer);
7293                 }
7294               else
7295                 {
7296                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7297                 }
7298               goto release;
7299             }
7300         }
7301       else
7302         {
7303           symbol *tlbl = newiTempLabel (NULL);
7304           int sizel = AOP_SIZE (left);
7305           if (size)
7306             emitcode ("setb", "c");
7307           while (sizel--)
7308             {
7309               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7310                 {
7311                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7312                   // byte ==  2^n ?
7313                   if ((posbit = isLiteralBit (bytelit)) != 0)
7314                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7315                   else
7316                     {
7317                       if (bytelit != 0x0FFL)
7318                         emitcode ("anl", "a,%s",
7319                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7320                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7321                     }
7322                 }
7323               offset++;
7324             }
7325           // bit = left & literal
7326           if (size)
7327             {
7328               emitcode ("clr", "c");
7329               emitLabel (tlbl);
7330             }
7331           // if(left & literal)
7332           else
7333             {
7334               if (ifx)
7335                 jmpTrueOrFalse (ifx, tlbl);
7336               else
7337                 emitLabel (tlbl);
7338               goto release;
7339             }
7340         }
7341       outBitC (result);
7342       goto release;
7343     }
7344
7345   /* if left is same as result */
7346   if (sameRegs (AOP (result), AOP (left)))
7347     {
7348       for (; size--; offset++)
7349         {
7350           if (AOP_TYPE (right) == AOP_LIT)
7351             {
7352               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7353               if (bytelit == 0x0FF)
7354                 {
7355                   /* dummy read of volatile operand */
7356                   if (isOperandVolatile (left, FALSE))
7357                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7358                   else
7359                     continue;
7360                 }
7361               else if (bytelit == 0)
7362                 {
7363                   aopPut (result, zero, offset);
7364                 }
7365               else if (IS_AOP_PREG (result))
7366                 {
7367                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7368                   emitcode ("anl", "a,%s",
7369                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7370                   aopPut (result, "a", offset);
7371                 }
7372               else
7373                 emitcode ("anl", "%s,%s",
7374                           aopGet (left, offset, FALSE, TRUE, NULL),
7375                           aopGet (right, offset, FALSE, FALSE, NULL));
7376             }
7377           else
7378             {
7379               if (AOP_TYPE (left) == AOP_ACC)
7380                 {
7381                   if (offset)
7382                     emitcode("mov", "a,b");
7383                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7384                 }
7385               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7386                 {
7387                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7388                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7389                   emitcode ("anl", "a,b");
7390                   aopPut (result, "a", offset);
7391                 }
7392               else if (aopGetUsesAcc (left, offset))
7393                 {
7394                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7395                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7396                   aopPut (result, "a", offset);
7397                 }
7398               else
7399                 {
7400                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7401                   if (IS_AOP_PREG (result))
7402                     {
7403                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7404                       aopPut (result, "a", offset);
7405                     }
7406                   else
7407                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7408                 }
7409             }
7410         }
7411     }
7412   else
7413     {
7414       // left & result in different registers
7415       if (AOP_TYPE (result) == AOP_CRY)
7416         {
7417           // result = bit
7418           // if(size), result in bit
7419           // if(!size && ifx), conditional oper: if(left & right)
7420           symbol *tlbl = newiTempLabel (NULL);
7421           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7422           if (size)
7423             emitcode ("setb", "c");
7424           while (sizer--)
7425             {
7426               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7427                   && AOP_TYPE(left)==AOP_ACC)
7428                 {
7429                   if (offset)
7430                     emitcode("mov", "a,b");
7431                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7432                 }
7433               else if (AOP_TYPE(left)==AOP_ACC)
7434                 {
7435                   if (!offset)
7436                     {
7437                       bool pushedB = pushB ();
7438                       emitcode("mov", "b,a");
7439                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7440                       emitcode("anl", "a,b");
7441                       popB (pushedB);
7442                     }
7443                   else
7444                     {
7445                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7446                       emitcode("anl", "a,b");
7447                     }
7448                 }
7449               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7450                 {
7451                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7452                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7453                   emitcode ("anl", "a,b");
7454                 }
7455               else if (aopGetUsesAcc (left, offset))
7456                 {
7457                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7458                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7459                 }
7460               else
7461                 {
7462                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7463                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7464                 }
7465
7466               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7467               offset++;
7468             }
7469           if (size)
7470             {
7471               CLRC;
7472               emitLabel (tlbl);
7473               outBitC (result);
7474             }
7475           else if (ifx)
7476             jmpTrueOrFalse (ifx, tlbl);
7477           else
7478             emitLabel (tlbl);
7479         }
7480       else
7481         {
7482           for (; (size--); offset++)
7483             {
7484               // normal case
7485               // result = left & right
7486               if (AOP_TYPE (right) == AOP_LIT)
7487                 {
7488                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7489                   if (bytelit == 0x0FF)
7490                     {
7491                       aopPut (result,
7492                               aopGet (left, offset, FALSE, FALSE, NULL),
7493                               offset);
7494                       continue;
7495                     }
7496                   else if (bytelit == 0)
7497                     {
7498                       /* dummy read of volatile operand */
7499                       if (isOperandVolatile (left, FALSE))
7500                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7501                       aopPut (result, zero, offset);
7502                       continue;
7503                     }
7504                   else if (AOP_TYPE (left) == AOP_ACC)
7505                     {
7506                       if (!offset)
7507                         {
7508                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7509                           aopPut (result, "a", offset);
7510                           continue;
7511                         }
7512                       else
7513                         {
7514                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7515                           aopPut (result, "b", offset);
7516                           continue;
7517                         }
7518                     }
7519                 }
7520               // faster than result <- left, anl result,right
7521               // and better if result is SFR
7522               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7523                   && AOP_TYPE(left)==AOP_ACC)
7524                 {
7525                   if (offset)
7526                     emitcode("mov", "a,b");
7527                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7528                 }
7529               else if (AOP_TYPE(left)==AOP_ACC)
7530                 {
7531                   if (!offset)
7532                     {
7533                       bool pushedB = pushB ();
7534                       emitcode("mov", "b,a");
7535                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7536                       emitcode("anl", "a,b");
7537                       popB (pushedB);
7538                     }
7539                   else
7540                     {
7541                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7542                       emitcode("anl", "a,b");
7543                     }
7544                 }
7545               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7546                 {
7547                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7548                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7549                   emitcode ("anl", "a,b");
7550                 }
7551               else if (aopGetUsesAcc (left, offset))
7552                 {
7553                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7554                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7555                 }
7556               else
7557                 {
7558                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7559                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7560                 }
7561               aopPut (result, "a", offset);
7562             }
7563         }
7564     }
7565
7566 release:
7567   freeAsmop (result, NULL, ic, TRUE);
7568   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7569   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7570 }
7571
7572 /*-----------------------------------------------------------------*/
7573 /* genOr  - code for or                                            */
7574 /*-----------------------------------------------------------------*/
7575 static void
7576 genOr (iCode * ic, iCode * ifx)
7577 {
7578   operand *left, *right, *result;
7579   int size, offset = 0;
7580   unsigned long lit = 0L;
7581   int bytelit = 0;
7582   bool     pushResult;
7583
7584   D (emitcode (";", "genOr"));
7585
7586   AOP_OP_3_NOFATAL (ic, pushResult);
7587   AOP_SET_LOCALS (ic);
7588
7589   if (pushResult)
7590   {
7591       genFarFarLogicOp(ic, "orl");
7592       return;
7593   }
7594
7595
7596 #ifdef DEBUG_TYPE
7597   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7598             AOP_TYPE (result),
7599             AOP_TYPE (left), AOP_TYPE (right));
7600   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7601             AOP_SIZE (result),
7602             AOP_SIZE (left), AOP_SIZE (right));
7603 #endif
7604
7605   /* if left is a literal & right is not then exchange them */
7606   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7607 #ifdef LOGIC_OPS_BROKEN
7608    || AOP_NEEDSACC (left) // I think this is a net loss now.
7609 #endif
7610       )
7611     {
7612       operand *tmp = right;
7613       right = left;
7614       left = tmp;
7615     }
7616
7617   /* if result = right then exchange them */
7618   if (sameRegs (AOP (result), AOP (right)))
7619     {
7620       operand *tmp = right;
7621       right = left;
7622       left = tmp;
7623     }
7624
7625   /* if right is bit then exchange them */
7626   if (AOP_TYPE (right) == AOP_CRY &&
7627       AOP_TYPE (left) != AOP_CRY)
7628     {
7629       operand *tmp = right;
7630       right = left;
7631       left = tmp;
7632     }
7633   if (AOP_TYPE (right) == AOP_LIT)
7634     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7635
7636   size = AOP_SIZE (result);
7637
7638   // if(bit | yy)
7639   // xx = bit | yy;
7640   if (AOP_TYPE (left) == AOP_CRY)
7641     {
7642       if (AOP_TYPE (right) == AOP_LIT)
7643         {
7644           // c = bit | literal;
7645           if (lit)
7646             {
7647               // lit != 0 => result = 1
7648               if (AOP_TYPE (result) == AOP_CRY)
7649                 {
7650                   if (size)
7651                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7652                   else if (ifx)
7653                     continueIfTrue (ifx);
7654                   goto release;
7655                 }
7656               emitcode ("setb", "c");
7657             }
7658           else
7659             {
7660               // lit == 0 => result = left
7661               if (size && sameRegs (AOP (result), AOP (left)))
7662                 goto release;
7663               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7664             }
7665         }
7666       else
7667         {
7668           if (AOP_TYPE (right) == AOP_CRY)
7669             {
7670               // c = bit | bit;
7671               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7672               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7673             }
7674           else
7675             {
7676               // c = bit | val;
7677               symbol *tlbl = newiTempLabel (NULL);
7678               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7679                 emitcode ("setb", "c");
7680               emitcode ("jb", "%s,!tlabel",
7681                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7682               toBoolean (right);
7683               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7684               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7685                 {
7686                   jmpTrueOrFalse (ifx, tlbl);
7687                   goto release;
7688                 }
7689               else
7690                 {
7691                   CLRC;
7692                   emitLabel (tlbl);
7693                 }
7694             }
7695         }
7696       // bit = c
7697       // val = c
7698       if (size)
7699         outBitC (result);
7700       // if(bit | ...)
7701       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7702            genIfxJump (ifx, "c");
7703       goto release;
7704     }
7705
7706   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7707   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7708   if ((AOP_TYPE (right) == AOP_LIT) &&
7709       (AOP_TYPE (result) == AOP_CRY) &&
7710       (AOP_TYPE (left) != AOP_CRY))
7711     {
7712       if (lit)
7713         {
7714           // result = 1
7715           if (size)
7716             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7717           else
7718             continueIfTrue (ifx);
7719           goto release;
7720         }
7721       else
7722         {
7723           // lit = 0, result = boolean(left)
7724           if (size)
7725             emitcode ("setb", "c");
7726           toBoolean (right);
7727           if (size)
7728             {
7729               symbol *tlbl = newiTempLabel (NULL);
7730               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7731               CLRC;
7732               emitLabel (tlbl);
7733             }
7734           else
7735             {
7736               genIfxJump (ifx, "a");
7737               goto release;
7738             }
7739         }
7740       outBitC (result);
7741       goto release;
7742     }
7743
7744   /* if left is same as result */
7745   if (sameRegs (AOP (result), AOP (left)))
7746     {
7747       for (; size--; offset++)
7748         {
7749           if (AOP_TYPE (right) == AOP_LIT)
7750             {
7751               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7752               if (bytelit == 0)
7753                 {
7754                   /* dummy read of volatile operand */
7755                   if (isOperandVolatile (left, FALSE))
7756                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7757                   else
7758                     continue;
7759                 }
7760               else if (bytelit == 0x0FF)
7761                 {
7762                   aopPut (result, "#0xFF", offset);
7763                 }
7764               else if (IS_AOP_PREG (left))
7765                 {
7766                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7767                   emitcode ("orl", "a,%s",
7768                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7769                   aopPut (result, "a", offset);
7770                 }
7771               else
7772                 {
7773                   emitcode ("orl", "%s,%s",
7774                             aopGet (left, offset, FALSE, TRUE, NULL),
7775                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7776                 }
7777             }
7778           else
7779             {
7780               if (AOP_TYPE (left) == AOP_ACC)
7781                 {
7782                   if (offset)
7783                     emitcode("mov", "a,b");
7784                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7785                 }
7786               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7787                 {
7788                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7789                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7790                   emitcode ("orl", "a,b");
7791                   aopPut (result, "a", offset);
7792                 }
7793               else if (aopGetUsesAcc (left, offset))
7794                 {
7795                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7796                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7797                   aopPut (result, "a", offset);
7798                 }
7799               else
7800                 {
7801                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7802                   if (IS_AOP_PREG (left))
7803                     {
7804                       emitcode ("orl", "a,%s",
7805                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7806                       aopPut (result, "a", offset);
7807                     }
7808                   else
7809                     {
7810                       emitcode ("orl", "%s,a",
7811                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7812                     }
7813                 }
7814             }
7815         }
7816     }
7817   else
7818     {
7819       // left & result in different registers
7820       if (AOP_TYPE (result) == AOP_CRY)
7821         {
7822           // result = bit
7823           // if(size), result in bit
7824           // if(!size && ifx), conditional oper: if(left | right)
7825           symbol *tlbl = newiTempLabel (NULL);
7826           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7827           if (size)
7828             emitcode ("setb", "c");
7829           while (sizer--)
7830             {
7831               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7832                   && AOP_TYPE(left)==AOP_ACC)
7833                 {
7834                   if (offset)
7835                     emitcode("mov", "a,b");
7836                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7837                 }
7838               else if (AOP_TYPE(left)==AOP_ACC)
7839                 {
7840                   if (!offset)
7841                     {
7842                       bool pushedB = pushB ();
7843                       emitcode("mov", "b,a");
7844                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7845                       emitcode("orl", "a,b");
7846                       popB (pushedB);
7847                     }
7848                   else
7849                     {
7850                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7851                       emitcode("orl", "a,b");
7852                     }
7853                 }
7854               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7855                 {
7856                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7857                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7858                   emitcode ("orl", "a,b");
7859                 }
7860               else if (aopGetUsesAcc (left, offset))
7861                 {
7862                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7863                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7864                 }
7865               else
7866                 {
7867                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7868                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7869               }
7870
7871               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7872               offset++;
7873             }
7874           if (size)
7875             {
7876               CLRC;
7877               emitLabel (tlbl);
7878               outBitC (result);
7879             }
7880           else if (ifx)
7881             jmpTrueOrFalse (ifx, tlbl);
7882           else
7883             emitLabel (tlbl);
7884         }
7885       else
7886         {
7887             _startLazyDPSEvaluation();
7888           for (; (size--); offset++)
7889             {
7890               // normal case
7891               // result = left | right
7892               if (AOP_TYPE (right) == AOP_LIT)
7893                 {
7894                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7895                   if (bytelit == 0)
7896                     {
7897                       aopPut (result,
7898                               aopGet (left, offset, FALSE, FALSE, NULL),
7899                               offset);
7900                       continue;
7901                     }
7902                   else if (bytelit == 0x0FF)
7903                     {
7904                       /* dummy read of volatile operand */
7905                       if (isOperandVolatile (left, FALSE))
7906                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7907                       aopPut (result, "#0xFF", offset);
7908                       continue;
7909                     }
7910                 }
7911               // faster than result <- left, orl result,right
7912               // and better if result is SFR
7913               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7914                   && AOP_TYPE(left)==AOP_ACC)
7915                 {
7916                   if (offset)
7917                     emitcode("mov", "a,b");
7918                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7919                 }
7920               else if (AOP_TYPE(left)==AOP_ACC)
7921                 {
7922                   if (!offset)
7923                     {
7924                       bool pushedB = pushB ();
7925                       emitcode("mov", "b,a");
7926                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7927                       emitcode("orl", "a,b");
7928                       popB (pushedB);
7929                     }
7930                   else
7931                     {
7932                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7933                       emitcode("orl", "a,b");
7934                     }
7935                 }
7936               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7937                 {
7938                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7939                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7940                   emitcode ("orl", "a,b");
7941                 }
7942               else if (aopGetUsesAcc (left, offset))
7943                 {
7944                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7945                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7946                 }
7947               else
7948                 {
7949                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7950                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7951                 }
7952               aopPut (result, "a", offset);
7953             }
7954             _endLazyDPSEvaluation();
7955         }
7956     }
7957
7958 release:
7959   freeAsmop (result, NULL, ic, TRUE);
7960   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7961   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7962 }
7963
7964 /*-----------------------------------------------------------------*/
7965 /* genXor - code for xclusive or                                   */
7966 /*-----------------------------------------------------------------*/
7967 static void
7968 genXor (iCode * ic, iCode * ifx)
7969 {
7970   operand *left, *right, *result;
7971   int size, offset = 0;
7972   unsigned long lit = 0L;
7973   int bytelit = 0;
7974   bool pushResult;
7975
7976   D (emitcode (";", "genXor"));
7977
7978   AOP_OP_3_NOFATAL (ic, pushResult);
7979   AOP_SET_LOCALS (ic);
7980
7981   if (pushResult)
7982   {
7983       genFarFarLogicOp(ic, "xrl");
7984       return;
7985   }
7986
7987 #ifdef DEBUG_TYPE
7988   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7989             AOP_TYPE (result),
7990             AOP_TYPE (left), AOP_TYPE (right));
7991   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7992             AOP_SIZE (result),
7993             AOP_SIZE (left), AOP_SIZE (right));
7994 #endif
7995
7996   /* if left is a literal & right is not ||
7997      if left needs acc & right does not */
7998   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7999 #ifdef LOGIC_OPS_BROKEN
8000       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
8001 #endif
8002      )
8003     {
8004       operand *tmp = right;
8005       right = left;
8006       left = tmp;
8007     }
8008
8009   /* if result = right then exchange them */
8010   if (sameRegs (AOP (result), AOP (right)))
8011     {
8012       operand *tmp = right;
8013       right = left;
8014       left = tmp;
8015     }
8016
8017   /* if right is bit then exchange them */
8018   if (AOP_TYPE (right) == AOP_CRY &&
8019       AOP_TYPE (left) != AOP_CRY)
8020     {
8021       operand *tmp = right;
8022       right = left;
8023       left = tmp;
8024     }
8025   if (AOP_TYPE (right) == AOP_LIT)
8026     lit = ulFromVal (AOP (right)->aopu.aop_lit);
8027
8028   size = AOP_SIZE (result);
8029
8030   // if(bit ^ yy)
8031   // xx = bit ^ yy;
8032   if (AOP_TYPE (left) == AOP_CRY)
8033     {
8034       if (AOP_TYPE (right) == AOP_LIT)
8035         {
8036           // c = bit & literal;
8037           if (lit >> 1)
8038             {
8039               // lit>>1  != 0 => result = 1
8040               if (AOP_TYPE (result) == AOP_CRY)
8041                 {
8042                   if (size)
8043                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8044                   else if (ifx)
8045                     continueIfTrue (ifx);
8046                   goto release;
8047                 }
8048               emitcode ("setb", "c");
8049             }
8050           else
8051             {
8052               // lit == (0 or 1)
8053               if (lit == 0)
8054                 {
8055                   // lit == 0, result = left
8056                   if (size && sameRegs (AOP (result), AOP (left)))
8057                     goto release;
8058                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8059                 }
8060               else
8061                 {
8062                   // lit == 1, result = not(left)
8063                   if (size && sameRegs (AOP (result), AOP (left)))
8064                     {
8065                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8066                       goto release;
8067                     }
8068                   else
8069                     {
8070                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8071                       emitcode ("cpl", "c");
8072                     }
8073                 }
8074             }
8075         }
8076       else
8077         {
8078           // right != literal
8079           symbol *tlbl = newiTempLabel (NULL);
8080           if (AOP_TYPE (right) == AOP_CRY)
8081             {
8082               // c = bit ^ bit;
8083               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8084             }
8085           else
8086             {
8087               int sizer = AOP_SIZE (right);
8088               // c = bit ^ val
8089               // if val>>1 != 0, result = 1
8090               emitcode ("setb", "c");
8091               while (sizer)
8092                 {
8093                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8094                   if (sizer == 1)
8095                     // test the msb of the lsb
8096                     emitcode ("anl", "a,#!constbyte",0xfe);
8097                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8098                   sizer--;
8099                 }
8100               // val = (0,1)
8101               emitcode ("rrc", "a");
8102             }
8103           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8104           emitcode ("cpl", "c");
8105           emitLabel (tlbl);
8106         }
8107       // bit = c
8108       // val = c
8109       if (size)
8110         outBitC (result);
8111       // if(bit | ...)
8112       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8113         genIfxJump (ifx, "c");
8114       goto release;
8115     }
8116
8117   /* if left is same as result */
8118   if (sameRegs (AOP (result), AOP (left)))
8119     {
8120       for (; size--; offset++)
8121         {
8122           if (AOP_TYPE (right) == AOP_LIT)
8123             {
8124               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8125               if (bytelit == 0)
8126                 {
8127                   /* dummy read of volatile operand */
8128                   if (isOperandVolatile (left, FALSE))
8129                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8130                   else
8131                     continue;
8132                 }
8133               else if (IS_AOP_PREG (left))
8134                 {
8135                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8136                   emitcode ("xrl", "a,%s",
8137                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8138                   aopPut (result, "a", offset);
8139                 }
8140               else
8141                 {
8142                   emitcode ("xrl", "%s,%s",
8143                             aopGet (left, offset, FALSE, TRUE, NULL),
8144                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8145                 }
8146             }
8147           else
8148             {
8149               if (AOP_TYPE (left) == AOP_ACC)
8150                 {
8151                   if (offset)
8152                     emitcode("mov", "a,b");
8153                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8154                 }
8155               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8156                 {
8157                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8158                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8159                   emitcode ("xrl", "a,b");
8160                   aopPut (result, "a", offset);
8161                 }
8162               else if (aopGetUsesAcc (left, offset))
8163                 {
8164                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8165                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8166                   aopPut (result, "a", offset);
8167                 }
8168               else
8169                 {
8170                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8171                   if (IS_AOP_PREG (left))
8172                     {
8173                       emitcode ("xrl", "a,%s",
8174                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8175                       aopPut (result, "a", offset);
8176                     }
8177                   else
8178                     emitcode ("xrl", "%s,a",
8179                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8180                 }
8181             }
8182         }
8183     }
8184   else
8185     {
8186       // left & result in different registers
8187       if (AOP_TYPE (result) == AOP_CRY)
8188         {
8189           // result = bit
8190           // if(size), result in bit
8191           // if(!size && ifx), conditional oper: if(left ^ right)
8192           symbol *tlbl = newiTempLabel (NULL);
8193           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8194
8195           if (size)
8196             emitcode ("setb", "c");
8197           while (sizer--)
8198             {
8199               if ((AOP_TYPE (right) == AOP_LIT) &&
8200                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8201                 {
8202                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8203                 }
8204               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8205                   && AOP_TYPE(left)==AOP_ACC)
8206                 {
8207                   if (offset)
8208                     emitcode("mov", "a,b");
8209                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8210                 }
8211               else if (AOP_TYPE(left)==AOP_ACC)
8212                 {
8213                   if (!offset)
8214                     {
8215                       bool pushedB = pushB ();
8216                       emitcode("mov", "b,a");
8217                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8218                       emitcode("xrl", "a,b");
8219                       popB (pushedB);
8220                     }
8221                   else
8222                     {
8223                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8224                       emitcode("xrl", "a,b");
8225                     }
8226                 }
8227               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8228                 {
8229                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8230                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8231                   emitcode ("xrl", "a,b");
8232                 }
8233               else if (aopGetUsesAcc (left, offset))
8234                 {
8235                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8236                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8237                 }
8238               else
8239                 {
8240                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8241                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8242                 }
8243
8244               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8245               offset++;
8246             }
8247           if (size)
8248             {
8249               CLRC;
8250               emitLabel (tlbl);
8251               outBitC (result);
8252             }
8253           else if (ifx)
8254             jmpTrueOrFalse (ifx, tlbl);
8255         }
8256       else
8257         {
8258         for (; (size--); offset++)
8259           {
8260             // normal case
8261             // result = left ^ right
8262             if (AOP_TYPE (right) == AOP_LIT)
8263               {
8264                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8265                 if (bytelit == 0)
8266                   {
8267                     aopPut (result,
8268                             aopGet (left, offset, FALSE, FALSE, NULL),
8269                             offset);
8270                     continue;
8271                   }
8272                 D (emitcode (";", "better literal XOR."));
8273                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8274                 emitcode ("xrl", "a, %s",
8275                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8276               }
8277             else
8278               {
8279                 // faster than result <- left, anl result,right
8280                 // and better if result is SFR
8281                 if (AOP_TYPE (left) == AOP_ACC)
8282                   {
8283                     emitcode ("xrl", "a,%s",
8284                               aopGet (right, offset,
8285                                       FALSE, FALSE, DP2_RESULT_REG));
8286                   }
8287                 else
8288                   {
8289                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8290                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8291                       {
8292                           emitcode("mov", "b,a");
8293                           rOp = "b";
8294                       }
8295
8296                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8297                       emitcode ("xrl", "a,%s", rOp);
8298                   }
8299               }
8300             aopPut (result, "a", offset);
8301           }
8302         }
8303     }
8304
8305 release:
8306   freeAsmop (result, NULL, ic, TRUE);
8307   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8308   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8309 }
8310
8311 /*-----------------------------------------------------------------*/
8312 /* genInline - write the inline code out                           */
8313 /*-----------------------------------------------------------------*/
8314 static void
8315 genInline (iCode * ic)
8316 {
8317   char *buffer, *bp, *bp1;
8318   bool inComment = FALSE;
8319
8320   D (emitcode (";", "genInline"));
8321
8322   _G.inLine += (!options.asmpeep);
8323
8324   buffer = bp = bp1 = Safe_strdup (IC_INLINE(ic));
8325
8326   /* emit each line as a code */
8327   while (*bp)
8328     {
8329       switch (*bp)
8330         {
8331         case ';':
8332           inComment = TRUE;
8333           ++bp;
8334           break;
8335
8336         case '\n':
8337           inComment = FALSE;
8338           *bp++ = '\0';
8339           emitcode (bp1, "");
8340           bp1 = bp;
8341           break;
8342
8343         default:
8344           /* Add \n for labels, not dirs such as c:\mydir */
8345           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
8346             {
8347               ++bp;
8348               *bp = '\0';
8349               ++bp;
8350               emitcode (bp1, "");
8351               bp1 = bp;
8352             }
8353           else
8354             ++bp;
8355           break;
8356         }
8357     }
8358   if (bp1 != bp)
8359     emitcode (bp1, "");
8360
8361   Safe_free (buffer);
8362
8363   _G.inLine -= (!options.asmpeep);
8364 }
8365
8366 /*-----------------------------------------------------------------*/
8367 /* genRRC - rotate right with carry                                */
8368 /*-----------------------------------------------------------------*/
8369 static void
8370 genRRC (iCode * ic)
8371 {
8372   operand *left, *result;
8373   int     size, offset;
8374   char *l;
8375
8376   D (emitcode (";", "genRRC"));
8377
8378   /* rotate right with carry */
8379   left = IC_LEFT (ic);
8380   result = IC_RESULT (ic);
8381   aopOp (left, ic, FALSE, FALSE);
8382   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8383
8384   /* move it to the result */
8385   size = AOP_SIZE (result);
8386   offset = size - 1;
8387   CLRC;
8388
8389   _startLazyDPSEvaluation ();
8390   while (size--)
8391     {
8392       l = aopGet (left, offset, FALSE, FALSE, NULL);
8393       MOVA (l);
8394       emitcode ("rrc", "a");
8395       if (AOP_SIZE (result) > 1)
8396         aopPut (result, "a", offset--);
8397     }
8398   _endLazyDPSEvaluation ();
8399
8400   /* now we need to put the carry into the
8401      highest order byte of the result */
8402   if (AOP_SIZE (result) > 1)
8403     {
8404       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8405       MOVA (l);
8406     }
8407   emitcode ("mov", "acc.7,c");
8408   aopPut (result, "a", AOP_SIZE (result) - 1);
8409   freeAsmop (result, NULL, ic, TRUE);
8410   freeAsmop (left, NULL, ic, TRUE);
8411 }
8412
8413 /*-----------------------------------------------------------------*/
8414 /* genRLC - generate code for rotate left with carry               */
8415 /*-----------------------------------------------------------------*/
8416 static void
8417 genRLC (iCode * ic)
8418 {
8419   operand *left, *result;
8420   int size, offset;
8421   char *l;
8422
8423   D (emitcode (";", "genRLC"));
8424
8425   /* rotate right with carry */
8426   left = IC_LEFT (ic);
8427   result = IC_RESULT (ic);
8428   aopOp (left, ic, FALSE, FALSE);
8429   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8430
8431   /* move it to the result */
8432   size = AOP_SIZE (result);
8433   offset = 0;
8434   if (size--)
8435     {
8436       l = aopGet (left, offset, FALSE, FALSE, NULL);
8437       MOVA (l);
8438       emitcode ("add", "a,acc");
8439       if (AOP_SIZE (result) > 1)
8440         {
8441           aopPut (result, "a", offset++);
8442         }
8443
8444       _startLazyDPSEvaluation ();
8445       while (size--)
8446         {
8447           l = aopGet (left, offset, FALSE, FALSE, NULL);
8448           MOVA (l);
8449           emitcode ("rlc", "a");
8450           if (AOP_SIZE (result) > 1)
8451             aopPut (result, "a", offset++);
8452         }
8453       _endLazyDPSEvaluation ();
8454     }
8455   /* now we need to put the carry into the
8456      highest order byte of the result */
8457   if (AOP_SIZE (result) > 1)
8458     {
8459       l = aopGet (result, 0, FALSE, FALSE, NULL);
8460       MOVA (l);
8461     }
8462   emitcode ("mov", "acc.0,c");
8463   aopPut (result, "a", 0);
8464   freeAsmop (result, NULL, ic, TRUE);
8465   freeAsmop (left, NULL, ic, TRUE);
8466 }
8467
8468 /*-----------------------------------------------------------------*/
8469 /* genGetHbit - generates code get highest order bit               */
8470 /*-----------------------------------------------------------------*/
8471 static void
8472 genGetHbit (iCode * ic)
8473 {
8474   operand *left, *result;
8475
8476   D (emitcode (";", "genGetHbit"));
8477
8478   left = IC_LEFT (ic);
8479   result = IC_RESULT (ic);
8480   aopOp (left, ic, FALSE, FALSE);
8481   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8482
8483   /* get the highest order byte into a */
8484   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8485   if (AOP_TYPE (result) == AOP_CRY)
8486     {
8487       emitcode ("rlc", "a");
8488       outBitC (result);
8489     }
8490   else
8491     {
8492       emitcode ("rl", "a");
8493       emitcode ("anl", "a,#1");
8494       outAcc (result);
8495     }
8496
8497
8498   freeAsmop (result, NULL, ic, TRUE);
8499   freeAsmop (left, NULL, ic, TRUE);
8500 }
8501
8502 /*-----------------------------------------------------------------*/
8503 /* genSwap - generates code to swap nibbles or bytes               */
8504 /*-----------------------------------------------------------------*/
8505 static void
8506 genSwap (iCode * ic)
8507 {
8508   operand *left, *result;
8509
8510   D(emitcode (";", "genSwap"));
8511
8512   left = IC_LEFT (ic);
8513   result = IC_RESULT (ic);
8514   aopOp (left, ic, FALSE, FALSE);
8515   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8516
8517   _startLazyDPSEvaluation ();
8518   switch (AOP_SIZE (left))
8519     {
8520     case 1: /* swap nibbles in byte */
8521       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8522       emitcode ("swap", "a");
8523       aopPut (result, "a", 0);
8524       break;
8525     case 2: /* swap bytes in word */
8526       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8527         {
8528           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8529           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8530           aopPut (result, "a", 1);
8531         }
8532       else if (operandsEqu (left, result))
8533         {
8534           char * reg = "a";
8535           bool pushedB = FALSE, leftInB = FALSE;
8536
8537           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8538           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8539             {
8540               pushedB = pushB ();
8541               emitcode ("mov", "b,a");
8542               reg = "b";
8543               leftInB = TRUE;
8544             }
8545           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8546           aopPut (result, reg, 1);
8547
8548           if (leftInB)
8549             popB (pushedB);
8550         }
8551       else
8552         {
8553           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8554           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8555         }
8556       break;
8557     default:
8558       wassertl(FALSE, "unsupported SWAP operand size");
8559     }
8560   _endLazyDPSEvaluation ();
8561
8562   freeAsmop (result, NULL, ic, TRUE);
8563   freeAsmop (left, NULL, ic, TRUE);
8564 }
8565
8566 /*-----------------------------------------------------------------*/
8567 /* AccRol - rotate left accumulator by known count                 */
8568 /*-----------------------------------------------------------------*/
8569 static void
8570 AccRol (int shCount)
8571 {
8572   shCount &= 0x0007;            // shCount : 0..7
8573
8574   switch (shCount)
8575     {
8576     case 0:
8577       break;
8578     case 1:
8579       emitcode ("rl", "a");
8580       break;
8581     case 2:
8582       emitcode ("rl", "a");
8583       emitcode ("rl", "a");
8584       break;
8585     case 3:
8586       emitcode ("swap", "a");
8587       emitcode ("rr", "a");
8588       break;
8589     case 4:
8590       emitcode ("swap", "a");
8591       break;
8592     case 5:
8593       emitcode ("swap", "a");
8594       emitcode ("rl", "a");
8595       break;
8596     case 6:
8597       emitcode ("rr", "a");
8598       emitcode ("rr", "a");
8599       break;
8600     case 7:
8601       emitcode ("rr", "a");
8602       break;
8603     }
8604 }
8605
8606 /*-----------------------------------------------------------------*/
8607 /* AccLsh - left shift accumulator by known count                  */
8608 /*-----------------------------------------------------------------*/
8609 static void
8610 AccLsh (int shCount)
8611 {
8612   if (shCount != 0)
8613     {
8614       if (shCount == 1)
8615         emitcode ("add", "a,acc");
8616       else if (shCount == 2)
8617         {
8618           emitcode ("add", "a,acc");
8619           emitcode ("add", "a,acc");
8620         }
8621       else
8622         {
8623           /* rotate left accumulator */
8624           AccRol (shCount);
8625           /* and kill the lower order bits */
8626           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8627         }
8628     }
8629 }
8630
8631 /*-----------------------------------------------------------------*/
8632 /* AccRsh - right shift accumulator by known count                 */
8633 /*-----------------------------------------------------------------*/
8634 static void
8635 AccRsh (int shCount)
8636 {
8637   if (shCount != 0)
8638     {
8639       if (shCount == 1)
8640         {
8641           CLRC;
8642           emitcode ("rrc", "a");
8643         }
8644       else
8645         {
8646           /* rotate right accumulator */
8647           AccRol (8 - shCount);
8648           /* and kill the higher order bits */
8649           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8650         }
8651     }
8652 }
8653
8654 #ifdef BETTER_LITERAL_SHIFT
8655 /*-----------------------------------------------------------------*/
8656 /* AccSRsh - signed right shift accumulator by known count                 */
8657 /*-----------------------------------------------------------------*/
8658 static void
8659 AccSRsh (int shCount)
8660 {
8661   symbol *tlbl;
8662   if (shCount != 0)
8663     {
8664       if (shCount == 1)
8665         {
8666           emitcode ("mov", "c,acc.7");
8667           emitcode ("rrc", "a");
8668         }
8669       else if (shCount == 2)
8670         {
8671           emitcode ("mov", "c,acc.7");
8672           emitcode ("rrc", "a");
8673           emitcode ("mov", "c,acc.7");
8674           emitcode ("rrc", "a");
8675         }
8676       else
8677         {
8678           tlbl = newiTempLabel (NULL);
8679           /* rotate right accumulator */
8680           AccRol (8 - shCount);
8681           /* and kill the higher order bits */
8682           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8683           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8684           emitcode ("orl", "a,#!constbyte",
8685                     (unsigned char) ~SRMask[shCount]);
8686           emitLabel (tlbl);
8687         }
8688     }
8689 }
8690 #endif
8691
8692 #ifdef BETTER_LITERAL_SHIFT
8693 /*-----------------------------------------------------------------*/
8694 /* shiftR1Left2Result - shift right one byte from left to result   */
8695 /*-----------------------------------------------------------------*/
8696 static void
8697 shiftR1Left2Result (operand * left, int offl,
8698                     operand * result, int offr,
8699                     int shCount, int sign)
8700 {
8701   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8702   /* shift right accumulator */
8703   if (sign)
8704     AccSRsh (shCount);
8705   else
8706     AccRsh (shCount);
8707   aopPut (result, "a", offr);
8708 }
8709 #endif
8710
8711 #ifdef BETTER_LITERAL_SHIFT
8712 /*-----------------------------------------------------------------*/
8713 /* shiftL1Left2Result - shift left one byte from left to result    */
8714 /*-----------------------------------------------------------------*/
8715 static void
8716 shiftL1Left2Result (operand * left, int offl,
8717                     operand * result, int offr, int shCount)
8718 {
8719   char *l;
8720   l = aopGet (left, offl, FALSE, FALSE, NULL);
8721   MOVA (l);
8722   /* shift left accumulator */
8723   AccLsh (shCount);
8724   aopPut (result, "a", offr);
8725 }
8726 #endif
8727
8728 #ifdef BETTER_LITERAL_SHIFT
8729 /*-----------------------------------------------------------------*/
8730 /* movLeft2Result - move byte from left to result                  */
8731 /*-----------------------------------------------------------------*/
8732 static void
8733 movLeft2Result (operand * left, int offl,
8734                 operand * result, int offr, int sign)
8735 {
8736   char *l;
8737   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8738   {
8739       l = aopGet (left, offl, FALSE, FALSE, NULL);
8740
8741       if (*l == '@' && (IS_AOP_PREG (result)))
8742       {
8743           emitcode ("mov", "a,%s", l);
8744           aopPut (result, "a", offr);
8745       }
8746       else
8747       {
8748           if (!sign)
8749             {
8750               aopPut (result, l, offr);
8751             }
8752           else
8753             {
8754               /* MSB sign in acc.7 ! */
8755               if (getDataSize (left) == offl + 1)
8756                 {
8757                   MOVA (l);
8758                   aopPut (result, "a", offr);
8759                 }
8760             }
8761       }
8762   }
8763 }
8764 #endif
8765
8766 #ifdef BETTER_LITERAL_SHIFT
8767 /*-----------------------------------------------------------------*/
8768 /* AccAXRrl1 - right rotate a:x by 1                               */
8769 /*-----------------------------------------------------------------*/
8770 static void
8771 AccAXRrl1 (char *x)
8772 {
8773   emitcode ("mov", "c,acc.0");
8774   emitcode ("xch", "a,%s", x);
8775   emitcode ("rrc", "a");
8776   emitcode ("xch", "a,%s", x);
8777   emitcode ("rrc", "a");
8778 }
8779 #endif
8780
8781 #ifdef BETTER_LITERAL_SHIFT
8782 //REMOVE ME!!!
8783 /*-----------------------------------------------------------------*/
8784 /* AccAXLrl1 - left rotate a:x by 1                                */
8785 /*-----------------------------------------------------------------*/
8786 static void
8787 AccAXLrl1 (char *x)
8788 {
8789   emitcode ("mov", "c,acc.7");
8790   emitcode ("xch", "a,%s", x);
8791   emitcode ("rlc", "a");
8792   emitcode ("xch", "a,%s", x);
8793   emitcode ("rlc", "a");
8794 }
8795 #endif
8796
8797 #ifdef BETTER_LITERAL_SHIFT
8798 /*-----------------------------------------------------------------*/
8799 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8800 /*-----------------------------------------------------------------*/
8801 static void
8802 AccAXRsh1 (char *x)
8803 {
8804   emitcode ("rrc", "a");
8805   emitcode ("xch", "a,%s", x);
8806   emitcode ("rrc", "a");
8807   emitcode ("xch", "a,%s", x);
8808 }
8809 #endif
8810
8811 #ifdef BETTER_LITERAL_SHIFT
8812 /*-----------------------------------------------------------------*/
8813 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8814 /*-----------------------------------------------------------------*/
8815 static void
8816 AccAXLsh1 (char *x)
8817 {
8818   emitcode ("xch", "a,%s", x);
8819   emitcode ("add", "a,acc");
8820   emitcode ("xch", "a,%s", x);
8821   emitcode ("rlc", "a");
8822 }
8823 #endif
8824
8825 #ifdef BETTER_LITERAL_SHIFT
8826 /*-----------------------------------------------------------------*/
8827 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8828 /*-----------------------------------------------------------------*/
8829 static void
8830 AccAXLsh (char *x, int shCount)
8831 {
8832   switch (shCount)
8833     {
8834     case 0:
8835       break;
8836     case 1:
8837       AccAXLsh1 (x);
8838       break;
8839     case 2:
8840       AccAXLsh1 (x);
8841       AccAXLsh1 (x);
8842       break;
8843     case 3:
8844     case 4:
8845     case 5:                             // AAAAABBB:CCCCCDDD
8846
8847       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8848
8849       emitcode ("anl", "a,#!constbyte",
8850                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8851
8852       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8853
8854       AccRol (shCount);                 // DDDCCCCC:BBB00000
8855
8856       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8857
8858       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8859
8860       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8861
8862       emitcode ("anl", "a,#!constbyte",
8863                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8864
8865       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8866
8867       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8868
8869       break;
8870     case 6:                             // AAAAAABB:CCCCCCDD
8871       emitcode ("anl", "a,#!constbyte",
8872                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8873 #if 1
8874       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8875       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8876       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8877 #else
8878       emitcode ("mov", "c,acc.0");      // c = B
8879       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8880       emitcode("rrc","a");
8881       emitcode("xch","a,%s", x);
8882       emitcode("rrc","a");
8883       emitcode("mov","c,acc.0"); //<< get correct bit
8884       emitcode("xch","a,%s", x);
8885
8886       emitcode("rrc","a");
8887       emitcode("xch","a,%s", x);
8888       emitcode("rrc","a");
8889       emitcode("xch","a,%s", x);
8890 #endif
8891       break;
8892     case 7:                             // a:x <<= 7
8893
8894       emitcode ("anl", "a,#!constbyte",
8895                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8896
8897       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8898
8899       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8900
8901       break;
8902     default:
8903       break;
8904     }
8905 }
8906 #endif
8907
8908 #ifdef BETTER_LITERAL_SHIFT
8909 //REMOVE ME!!!
8910 /*-----------------------------------------------------------------*/
8911 /* AccAXRsh - right shift a:x known count (0..7)                   */
8912 /*-----------------------------------------------------------------*/
8913 static void
8914 AccAXRsh (char *x, int shCount)
8915 {
8916   switch (shCount)
8917     {
8918     case 0:
8919       break;
8920     case 1:
8921       CLRC;
8922       AccAXRsh1 (x);                    // 0->a:x
8923
8924       break;
8925     case 2:
8926       CLRC;
8927       AccAXRsh1 (x);                    // 0->a:x
8928
8929       CLRC;
8930       AccAXRsh1 (x);                    // 0->a:x
8931
8932       break;
8933     case 3:
8934     case 4:
8935     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8936
8937       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8938
8939       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8940
8941       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8942
8943       emitcode ("anl", "a,#!constbyte",
8944                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8945
8946       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8947
8948       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8949
8950       emitcode ("anl", "a,#!constbyte",
8951                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8952
8953       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8954
8955       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8956
8957       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8958
8959       break;
8960     case 6:                             // AABBBBBB:CCDDDDDD
8961
8962       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8963       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8964
8965       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8966
8967       emitcode ("anl", "a,#!constbyte",
8968                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8969
8970       break;
8971     case 7:                             // ABBBBBBB:CDDDDDDD
8972
8973       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8974
8975       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8976
8977       emitcode ("anl", "a,#!constbyte",
8978                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8979
8980       break;
8981     default:
8982       break;
8983     }
8984 }
8985 #endif
8986
8987 #ifdef BETTER_LITERAL_SHIFT
8988 /*-----------------------------------------------------------------*/
8989 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8990 /*-----------------------------------------------------------------*/
8991 static void
8992 AccAXRshS (char *x, int shCount)
8993 {
8994   symbol *tlbl;
8995   switch (shCount)
8996     {
8997     case 0:
8998       break;
8999     case 1:
9000       emitcode ("mov", "c,acc.7");
9001       AccAXRsh1 (x);                    // s->a:x
9002
9003       break;
9004     case 2:
9005       emitcode ("mov", "c,acc.7");
9006       AccAXRsh1 (x);                    // s->a:x
9007
9008       emitcode ("mov", "c,acc.7");
9009       AccAXRsh1 (x);                    // s->a:x
9010
9011       break;
9012     case 3:
9013     case 4:
9014     case 5:                             // AAAAABBB:CCCCCDDD = a:x
9015
9016       tlbl = newiTempLabel (NULL);
9017       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
9018
9019       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
9020
9021       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
9022
9023       emitcode ("anl", "a,#!constbyte",
9024                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
9025
9026       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9027
9028       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9029
9030       emitcode ("anl", "a,#!constbyte",
9031                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9032
9033       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9034
9035       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9036
9037       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9038
9039       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9040       emitcode ("orl", "a,#!constbyte",
9041                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9042
9043       emitLabel (tlbl);
9044       break;                            // SSSSAAAA:BBBCCCCC
9045
9046     case 6:                             // AABBBBBB:CCDDDDDD
9047
9048       tlbl = newiTempLabel (NULL);
9049
9050       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9051       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9052
9053       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9054
9055       emitcode ("anl", "a,#!constbyte",
9056                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9057
9058       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9059       emitcode ("orl", "a,#!constbyte",
9060                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9061
9062       emitLabel (tlbl);
9063       break;
9064     case 7:                             // ABBBBBBB:CDDDDDDD
9065
9066       tlbl = newiTempLabel (NULL);
9067
9068       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9069
9070       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9071
9072       emitcode ("anl", "a,#!constbyte",
9073                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9074
9075       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9076       emitcode ("orl", "a,#!constbyte",
9077                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9078
9079       emitLabel (tlbl);
9080       break;
9081     default:
9082       break;
9083     }
9084 }
9085 #endif
9086
9087 #ifdef BETTER_LITERAL_SHIFT
9088 static void
9089 _loadLeftIntoAx(char    **lsb,
9090                 operand *left,
9091                 operand *result,
9092                 int     offl,
9093                 int     offr)
9094 {
9095   // Get the initial value from left into a pair of registers.
9096   // MSB must be in A, LSB can be any register.
9097   //
9098   // If the result is held in registers, it is an optimization
9099   // if the LSB can be held in the register which will hold the,
9100   // result LSB since this saves us from having to copy it into
9101   // the result following AccAXLsh.
9102   //
9103   // If the result is addressed indirectly, this is not a gain.
9104   if (AOP_NEEDSACC(result))
9105   {
9106        char *leftByte;
9107
9108        _startLazyDPSEvaluation();
9109       if (AOP_TYPE(left) == AOP_DPTR2)
9110        {
9111            // Get MSB in A.
9112            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9113            // get LSB in DP2_RESULT_REG.
9114            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9115            assert(!strcmp(leftByte, DP2_RESULT_REG));
9116        }
9117        else
9118        {
9119            // get LSB into DP2_RESULT_REG
9120            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9121            if (strcmp(leftByte, DP2_RESULT_REG))
9122            {
9123                TR_AP("#7");
9124                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9125            }
9126            // And MSB in A.
9127            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9128            assert(strcmp(leftByte, DP2_RESULT_REG));
9129            MOVA (leftByte);
9130        }
9131        _endLazyDPSEvaluation();
9132        *lsb = DP2_RESULT_REG;
9133   }
9134   else
9135   {
9136       if (sameRegs (AOP (result), AOP (left)) &&
9137         ((offl + MSB16) == offr))
9138       {
9139           /* don't crash result[offr] */
9140           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9141           emitcode ("xch", "a,%s",
9142                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9143       }
9144       else
9145       {
9146           movLeft2Result (left, offl, result, offr, 0);
9147           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9148       }
9149       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9150       assert(strcmp(*lsb,"a"));
9151   }
9152 }
9153
9154 static void
9155 _storeAxResults(char    *lsb,
9156                 operand *result,
9157                 int     offr)
9158 {
9159   _startLazyDPSEvaluation();
9160   if (AOP_NEEDSACC(result))
9161   {
9162       /* We have to explicitly update the result LSB.
9163        */
9164       emitcode ("xch","a,%s", lsb);
9165       aopPut (result, "a", offr);
9166       emitcode ("mov","a,%s", lsb);
9167   }
9168   if (getDataSize (result) > 1)
9169   {
9170       aopPut (result, "a", offr + MSB16);
9171   }
9172   _endLazyDPSEvaluation();
9173 }
9174
9175 /*-----------------------------------------------------------------*/
9176 /* shiftL2Left2Result - shift left two bytes from left to result   */
9177 /*-----------------------------------------------------------------*/
9178 static void
9179 shiftL2Left2Result (operand * left, int offl,
9180                     operand * result, int offr, int shCount)
9181 {
9182   char *lsb;
9183
9184   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9185
9186   AccAXLsh (lsb, shCount);
9187
9188   _storeAxResults(lsb, result, offr);
9189 }
9190 #endif
9191
9192 #ifdef BETTER_LITERAL_SHIFT
9193 /*-----------------------------------------------------------------*/
9194 /* shiftR2Left2Result - shift right two bytes from left to result  */
9195 /*-----------------------------------------------------------------*/
9196 static void
9197 shiftR2Left2Result (operand * left, int offl,
9198                     operand * result, int offr,
9199                     int shCount, int sign)
9200 {
9201   char *lsb;
9202
9203   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9204
9205   /* a:x >> shCount (x = lsb(result)) */
9206   if (sign)
9207   {
9208      AccAXRshS(lsb, shCount);
9209   }
9210   else
9211   {
9212     AccAXRsh(lsb, shCount);
9213   }
9214
9215   _storeAxResults(lsb, result, offr);
9216 }
9217 #endif
9218
9219 /*-----------------------------------------------------------------*/
9220 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9221 /*-----------------------------------------------------------------*/
9222 static void
9223 shiftLLeftOrResult (operand * left, int offl,
9224                     operand * result, int offr, int shCount)
9225 {
9226   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9227   /* shift left accumulator */
9228   AccLsh (shCount);
9229   /* or with result */
9230   emitcode ("orl", "a,%s",
9231             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9232   /* back to result */
9233   aopPut (result, "a", offr);
9234 }
9235
9236 #if 0
9237 //REMOVE ME!!!
9238 /*-----------------------------------------------------------------*/
9239 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9240 /*-----------------------------------------------------------------*/
9241 static void
9242 shiftRLeftOrResult (operand * left, int offl,
9243                     operand * result, int offr, int shCount)
9244 {
9245   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9246   /* shift right accumulator */
9247   AccRsh (shCount);
9248   /* or with result */
9249   emitcode ("orl", "a,%s",
9250             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9251   /* back to result */
9252   aopPut (result, "a", offr);
9253 }
9254 #endif
9255
9256 #ifdef BETTER_LITERAL_SHIFT
9257 /*-----------------------------------------------------------------*/
9258 /* genlshOne - left shift a one byte quantity by known count       */
9259 /*-----------------------------------------------------------------*/
9260 static void
9261 genlshOne (operand * result, operand * left, int shCount)
9262 {
9263   D (emitcode (";", "genlshOne"));
9264
9265   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9266 }
9267 #endif
9268
9269 #ifdef BETTER_LITERAL_SHIFT
9270 /*-----------------------------------------------------------------*/
9271 /* genlshTwo - left shift two bytes by known amount != 0           */
9272 /*-----------------------------------------------------------------*/
9273 static void
9274 genlshTwo (operand * result, operand * left, int shCount)
9275 {
9276   int size;
9277
9278   D (emitcode (";", "genlshTwo"));
9279
9280   size = getDataSize (result);
9281
9282   /* if shCount >= 8 */
9283   if (shCount >= 8)
9284   {
9285       shCount -= 8;
9286
9287       _startLazyDPSEvaluation();
9288
9289       if (size > 1)
9290         {
9291           if (shCount)
9292           {
9293             _endLazyDPSEvaluation();
9294             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9295             aopPut (result, zero, LSB);
9296           }
9297           else
9298           {
9299             movLeft2Result (left, LSB, result, MSB16, 0);
9300             aopPut (result, zero, LSB);
9301             _endLazyDPSEvaluation();
9302           }
9303         }
9304         else
9305         {
9306           aopPut (result, zero, LSB);
9307           _endLazyDPSEvaluation();
9308         }
9309   }
9310
9311   /*  1 <= shCount <= 7 */
9312   else
9313     {
9314       if (size == 1)
9315         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9316       else
9317         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9318     }
9319 }
9320 #endif
9321
9322 #if 0
9323 //REMOVE ME!!!
9324 /*-----------------------------------------------------------------*/
9325 /* shiftLLong - shift left one long from left to result            */
9326 /* offl = LSB or MSB16                                             */
9327 /*-----------------------------------------------------------------*/
9328 static void
9329 shiftLLong (operand * left, operand * result, int offr)
9330 {
9331   char *l;
9332   int size = AOP_SIZE (result);
9333
9334   if (size >= LSB + offr)
9335     {
9336       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9337       MOVA (l);
9338       emitcode ("add", "a,acc");
9339       if (sameRegs (AOP (left), AOP (result)) &&
9340           size >= MSB16 + offr && offr != LSB)
9341         emitcode ("xch", "a,%s",
9342                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9343       else
9344         aopPut (result, "a", LSB + offr);
9345     }
9346
9347   if (size >= MSB16 + offr)
9348     {
9349       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9350         {
9351           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9352           MOVA (l);
9353         }
9354       emitcode ("rlc", "a");
9355       if (sameRegs (AOP (left), AOP (result)) &&
9356           size >= MSB24 + offr && offr != LSB)
9357         emitcode ("xch", "a,%s",
9358                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9359       else
9360         aopPut (result, "a", MSB16 + offr);
9361     }
9362
9363   if (size >= MSB24 + offr)
9364     {
9365       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9366         {
9367           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9368           MOVA (l);
9369         }
9370       emitcode ("rlc", "a");
9371       if (sameRegs (AOP (left), AOP (result)) &&
9372           size >= MSB32 + offr && offr != LSB)
9373         emitcode ("xch", "a,%s",
9374                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9375       else
9376         aopPut (result, "a", MSB24 + offr);
9377     }
9378
9379   if (size > MSB32 + offr)
9380     {
9381       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9382         {
9383           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9384           MOVA (l);
9385         }
9386       emitcode ("rlc", "a");
9387       aopPut (result, "a", MSB32 + offr);
9388     }
9389   if (offr != LSB)
9390     aopPut (result, zero, LSB);
9391 }
9392 #endif
9393
9394 #if 0
9395 //REMOVE ME!!!
9396 /*-----------------------------------------------------------------*/
9397 /* genlshFour - shift four byte by a known amount != 0             */
9398 /*-----------------------------------------------------------------*/
9399 static void
9400 genlshFour (operand * result, operand * left, int shCount)
9401 {
9402   int size;
9403
9404   D (emitcode (";", "genlshFour"));
9405
9406   size = AOP_SIZE (result);
9407
9408   /* if shifting more that 3 bytes */
9409   if (shCount >= 24)
9410     {
9411       shCount -= 24;
9412       if (shCount)
9413         /* lowest order of left goes to the highest
9414            order of the destination */
9415         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9416       else
9417         movLeft2Result (left, LSB, result, MSB32, 0);
9418       aopPut (result, zero, LSB);
9419       aopPut (result, zero, MSB16);
9420       aopPut (result, zero, MSB24);
9421       return;
9422     }
9423
9424   /* more than two bytes */
9425   else if (shCount >= 16)
9426     {
9427       /* lower order two bytes goes to higher order two bytes */
9428       shCount -= 16;
9429       /* if some more remaining */
9430       if (shCount)
9431         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9432       else
9433         {
9434           movLeft2Result (left, MSB16, result, MSB32, 0);
9435           movLeft2Result (left, LSB, result, MSB24, 0);
9436         }
9437       aopPut (result, zero, MSB16);
9438       aopPut (result, zero, LSB);
9439       return;
9440     }
9441
9442   /* if more than 1 byte */
9443   else if (shCount >= 8)
9444     {
9445       /* lower order three bytes goes to higher order  three bytes */
9446       shCount -= 8;
9447       if (size == 2)
9448         {
9449           if (shCount)
9450             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9451           else
9452             movLeft2Result (left, LSB, result, MSB16, 0);
9453         }
9454       else
9455         {                       /* size = 4 */
9456           if (shCount == 0)
9457             {
9458               movLeft2Result (left, MSB24, result, MSB32, 0);
9459               movLeft2Result (left, MSB16, result, MSB24, 0);
9460               movLeft2Result (left, LSB, result, MSB16, 0);
9461               aopPut (result, zero, LSB);
9462             }
9463           else if (shCount == 1)
9464             shiftLLong (left, result, MSB16);
9465           else
9466             {
9467               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9468               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9469               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9470               aopPut (result, zero, LSB);
9471             }
9472         }
9473     }
9474
9475   /* 1 <= shCount <= 7 */
9476   else if (shCount <= 2)
9477     {
9478       shiftLLong (left, result, LSB);
9479       if (shCount == 2)
9480         shiftLLong (result, result, LSB);
9481     }
9482   /* 3 <= shCount <= 7, optimize */
9483   else
9484     {
9485       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9486       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9487       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9488     }
9489 }
9490 #endif
9491
9492 #ifdef BETTER_LITERAL_SHIFT
9493 /*-----------------------------------------------------------------*/
9494 /* genLeftShiftLiteral - left shifting by known count              */
9495 /*-----------------------------------------------------------------*/
9496 static bool
9497 genLeftShiftLiteral (operand * left,
9498                      operand * right,
9499                      operand * result,
9500                      iCode * ic)
9501 {
9502   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9503   int size;
9504
9505   size = getSize (operandType (result));
9506
9507   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9508
9509   /* We only handle certain easy cases so far. */
9510   if ((shCount != 0)
9511    && (shCount < (size * 8))
9512    && (size != 1)
9513    && (size != 2))
9514   {
9515       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9516       return FALSE;
9517   }
9518
9519   freeAsmop (right, NULL, ic, TRUE);
9520
9521   aopOp(left, ic, FALSE, FALSE);
9522   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9523
9524 #if 0 // debug spew
9525   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9526   {
9527         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9528         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9529         {
9530            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9531         }
9532   }
9533   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9534   {
9535         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9536         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9537         {
9538            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9539         }
9540   }
9541 #endif
9542
9543 #if VIEW_SIZE
9544   emitcode ("; shift left ", "result %d, left %d", size,
9545             AOP_SIZE (left));
9546 #endif
9547
9548   /* I suppose that the left size >= result size */
9549   if (shCount == 0)
9550   {
9551         _startLazyDPSEvaluation();
9552         while (size--)
9553         {
9554           movLeft2Result (left, size, result, size, 0);
9555         }
9556         _endLazyDPSEvaluation();
9557   }
9558   else if (shCount >= (size * 8))
9559   {
9560     _startLazyDPSEvaluation();
9561     while (size--)
9562     {
9563       aopPut (result, zero, size);
9564     }
9565     _endLazyDPSEvaluation();
9566   }
9567   else
9568   {
9569       switch (size)
9570         {
9571         case 1:
9572           genlshOne (result, left, shCount);
9573           break;
9574
9575         case 2:
9576           genlshTwo (result, left, shCount);
9577           break;
9578 #if 0
9579         case 4:
9580           genlshFour (result, left, shCount);
9581           break;
9582 #endif
9583         default:
9584           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9585                   "*** ack! mystery literal shift!\n");
9586           break;
9587         }
9588     }
9589   freeAsmop (result, NULL, ic, TRUE);
9590   freeAsmop (left, NULL, ic, TRUE);
9591   return TRUE;
9592 }
9593 #endif
9594
9595 /*-----------------------------------------------------------------*/
9596 /* genLeftShift - generates code for left shifting                 */
9597 /*-----------------------------------------------------------------*/
9598 static void
9599 genLeftShift (iCode * ic)
9600 {
9601   operand *left, *right, *result;
9602   int size, offset;
9603   char *l;
9604   symbol *tlbl, *tlbl1;
9605   bool pushedB;
9606
9607   D (emitcode (";", "genLeftShift"));
9608
9609   right = IC_RIGHT (ic);
9610   left = IC_LEFT (ic);
9611   result = IC_RESULT (ic);
9612
9613   aopOp (right, ic, FALSE, FALSE);
9614
9615
9616 #ifdef BETTER_LITERAL_SHIFT
9617   /* if the shift count is known then do it
9618      as efficiently as possible */
9619   if (AOP_TYPE (right) == AOP_LIT)
9620     {
9621       if (genLeftShiftLiteral (left, right, result, ic))
9622       {
9623         return;
9624       }
9625     }
9626 #endif
9627
9628   /* shift count is unknown then we have to form
9629      a loop get the loop count in B : Note: we take
9630      only the lower order byte since shifting
9631      more that 32 bits make no sense anyway, ( the
9632      largest size of an object can be only 32 bits ) */
9633
9634   pushedB = pushB ();
9635   if (AOP_TYPE (right) == AOP_LIT)
9636   {
9637       /* Really should be handled by genLeftShiftLiteral,
9638        * but since I'm too lazy to fix that today, at least we can make
9639        * some small improvement.
9640        */
9641        emitcode("mov", "b,#!constbyte",
9642                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
9643   }
9644   else
9645   {
9646       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9647       emitcode ("inc", "b");
9648   }
9649   freeAsmop (right, NULL, ic, TRUE);
9650   aopOp (left, ic, FALSE, FALSE);
9651   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9652
9653   /* now move the left to the result if they are not the same */
9654   if (!sameRegs (AOP (left), AOP (result)) &&
9655       AOP_SIZE (result) > 1)
9656     {
9657
9658       size = AOP_SIZE (result);
9659       offset = 0;
9660       _startLazyDPSEvaluation ();
9661       while (size--)
9662         {
9663           l = aopGet (left, offset, FALSE, TRUE, NULL);
9664           if (*l == '@' && (IS_AOP_PREG (result)))
9665             {
9666
9667               emitcode ("mov", "a,%s", l);
9668               aopPut (result, "a", offset);
9669             }
9670           else
9671             aopPut (result, l, offset);
9672           offset++;
9673         }
9674       _endLazyDPSEvaluation ();
9675     }
9676
9677   tlbl = newiTempLabel (NULL);
9678   size = AOP_SIZE (result);
9679   offset = 0;
9680   tlbl1 = newiTempLabel (NULL);
9681
9682   /* if it is only one byte then */
9683   if (size == 1)
9684     {
9685       symbol *tlbl1 = newiTempLabel (NULL);
9686
9687       l = aopGet (left, 0, FALSE, FALSE, NULL);
9688       MOVA (l);
9689       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9690       emitLabel (tlbl);
9691       emitcode ("add", "a,acc");
9692       emitLabel (tlbl1);
9693       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9694       popB (pushedB);
9695       aopPut (result, "a", 0);
9696       goto release;
9697     }
9698
9699   reAdjustPreg (AOP (result));
9700
9701   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9702   emitLabel (tlbl);
9703   l = aopGet (result, offset, FALSE, FALSE, NULL);
9704   MOVA (l);
9705   emitcode ("add", "a,acc");
9706   aopPut (result, "a", offset++);
9707   _startLazyDPSEvaluation ();
9708   while (--size)
9709     {
9710       l = aopGet (result, offset, FALSE, FALSE, NULL);
9711       MOVA (l);
9712       emitcode ("rlc", "a");
9713       aopPut (result, "a", offset++);
9714     }
9715   _endLazyDPSEvaluation ();
9716   reAdjustPreg (AOP (result));
9717
9718   emitLabel (tlbl1);
9719   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9720   popB (pushedB);
9721 release:
9722   freeAsmop (result, NULL, ic, TRUE);
9723   freeAsmop (left, NULL, ic, TRUE);
9724 }
9725
9726 #ifdef BETTER_LITERAL_SHIFT
9727 /*-----------------------------------------------------------------*/
9728 /* genrshOne - right shift a one byte quantity by known count      */
9729 /*-----------------------------------------------------------------*/
9730 static void
9731 genrshOne (operand * result, operand * left,
9732            int shCount, int sign)
9733 {
9734   D (emitcode (";", "genrshOne"));
9735
9736   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9737 }
9738 #endif
9739
9740 #ifdef BETTER_LITERAL_SHIFT
9741 /*-----------------------------------------------------------------*/
9742 /* genrshTwo - right shift two bytes by known amount != 0          */
9743 /*-----------------------------------------------------------------*/
9744 static void
9745 genrshTwo (operand * result, operand * left,
9746            int shCount, int sign)
9747 {
9748   D (emitcode (";", "genrshTwo"));
9749
9750   /* if shCount >= 8 */
9751   if (shCount >= 8)
9752     {
9753       shCount -= 8;
9754       _startLazyDPSEvaluation();
9755       if (shCount)
9756         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9757       else
9758         movLeft2Result (left, MSB16, result, LSB, sign);
9759       addSign (result, MSB16, sign);
9760       _endLazyDPSEvaluation();
9761     }
9762
9763   /*  1 <= shCount <= 7 */
9764   else
9765     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9766 }
9767 #endif
9768
9769 /*-----------------------------------------------------------------*/
9770 /* shiftRLong - shift right one long from left to result           */
9771 /* offl = LSB or MSB16                                             */
9772 /*-----------------------------------------------------------------*/
9773 static void
9774 shiftRLong (operand * left, int offl,
9775             operand * result, int sign)
9776 {
9777   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9778
9779   if (overlapping && offl>1)
9780     {
9781       // we are in big trouble, but this shouldn't happen
9782       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9783     }
9784
9785   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9786
9787   if (offl==MSB16)
9788     {
9789       // shift is > 8
9790       if (sign)
9791         {
9792           emitcode ("rlc", "a");
9793           emitcode ("subb", "a,acc");
9794           emitcode ("xch", "a,%s",
9795                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9796         }
9797       else
9798         {
9799           aopPut (result, zero, MSB32);
9800         }
9801     }
9802
9803   if (!sign)
9804     {
9805       emitcode ("clr", "c");
9806     }
9807   else
9808     {
9809       emitcode ("mov", "c,acc.7");
9810     }
9811
9812   emitcode ("rrc", "a");
9813
9814   if (overlapping && offl==MSB16)
9815     {
9816       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9817     }
9818   else
9819     {
9820       aopPut (result, "a", MSB32 - offl);
9821       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9822     }
9823
9824   emitcode ("rrc", "a");
9825
9826   if (overlapping && offl==MSB16)
9827     {
9828       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9829     }
9830   else
9831     {
9832       aopPut (result, "a", MSB24 - offl);
9833       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9834     }
9835
9836   emitcode ("rrc", "a");
9837   if (offl != LSB)
9838     {
9839       aopPut (result, "a", MSB16 - offl);
9840     }
9841   else
9842     {
9843       if (overlapping && offl==MSB16)
9844         {
9845           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9846         }
9847       else
9848         {
9849           aopPut (result, "a", MSB16 - offl);
9850           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9851         }
9852       emitcode ("rrc", "a");
9853       aopPut (result, "a", LSB);
9854     }
9855 }
9856
9857 /*-----------------------------------------------------------------*/
9858 /* genrshFour - shift four byte by a known amount != 0             */
9859 /*-----------------------------------------------------------------*/
9860 static void
9861 genrshFour (operand * result, operand * left,
9862             int shCount, int sign)
9863 {
9864   D (emitcode (";", "genrshFour"));
9865
9866   /* if shifting more that 3 bytes */
9867   if (shCount >= 24)
9868     {
9869       shCount -= 24;
9870       _startLazyDPSEvaluation();
9871       if (shCount)
9872         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9873       else
9874         movLeft2Result (left, MSB32, result, LSB, sign);
9875       addSign (result, MSB16, sign);
9876       _endLazyDPSEvaluation();
9877     }
9878   else if (shCount >= 16)
9879     {
9880       shCount -= 16;
9881       _startLazyDPSEvaluation();
9882       if (shCount)
9883         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9884       else
9885         {
9886           movLeft2Result (left, MSB24, result, LSB, 0);
9887           movLeft2Result (left, MSB32, result, MSB16, sign);
9888         }
9889       addSign (result, MSB24, sign);
9890       _endLazyDPSEvaluation();
9891     }
9892   else if (shCount >= 8)
9893     {
9894       shCount -= 8;
9895       _startLazyDPSEvaluation();
9896       if (shCount == 1)
9897         {
9898           shiftRLong (left, MSB16, result, sign);
9899         }
9900       else if (shCount == 0)
9901         {
9902           movLeft2Result (left, MSB16, result, LSB, 0);
9903           movLeft2Result (left, MSB24, result, MSB16, 0);
9904           movLeft2Result (left, MSB32, result, MSB24, sign);
9905           addSign (result, MSB32, sign);
9906         }
9907       else
9908         {
9909           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9910           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9911           /* the last shift is signed */
9912           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9913           addSign (result, MSB32, sign);
9914         }
9915         _endLazyDPSEvaluation();
9916     }
9917   else
9918     {
9919       /* 1 <= shCount <= 7 */
9920       if (shCount <= 2)
9921         {
9922           shiftRLong (left, LSB, result, sign);
9923           if (shCount == 2)
9924             shiftRLong (result, LSB, result, sign);
9925         }
9926       else
9927         {
9928           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9929           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9930           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9931         }
9932     }
9933 }
9934
9935 #ifdef BETTER_LITERAL_SHIFT
9936 /*-----------------------------------------------------------------*/
9937 /* genRightShiftLiteral - right shifting by known count            */
9938 /*-----------------------------------------------------------------*/
9939 static bool
9940 genRightShiftLiteral (operand * left,
9941                       operand * right,
9942                       operand * result,
9943                       iCode * ic,
9944                       int sign)
9945 {
9946   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9947   int size;
9948
9949   size = getSize (operandType (result));
9950
9951   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9952
9953   /* We only handle certain easy cases so far. */
9954   if ((shCount != 0)
9955    && (shCount < (size * 8))
9956    && (size != 1)
9957    && (size != 2)
9958    && (size != 4))
9959   {
9960       D(emitcode (";", "genRightShiftLiteral wimping out"););
9961       return FALSE;
9962   }
9963
9964   freeAsmop (right, NULL, ic, TRUE);
9965
9966   aopOp (left, ic, FALSE, FALSE);
9967   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9968
9969 #if VIEW_SIZE
9970   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9971             AOP_SIZE (left));
9972 #endif
9973
9974   /* test the LEFT size !!! */
9975
9976   /* I suppose that the left size >= result size */
9977   if (shCount == 0)
9978   {
9979       size = getDataSize (result);
9980       _startLazyDPSEvaluation();
9981       while (size--)
9982         movLeft2Result (left, size, result, size, 0);
9983       _endLazyDPSEvaluation();
9984   }
9985   else if (shCount >= (size * 8))
9986     {
9987       if (sign)
9988         {
9989           /* get sign in acc.7 */
9990           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9991         }
9992       addSign (result, LSB, sign);
9993     }
9994   else
9995     {
9996       switch (size)
9997         {
9998         case 1:
9999           genrshOne (result, left, shCount, sign);
10000           break;
10001
10002         case 2:
10003           genrshTwo (result, left, shCount, sign);
10004           break;
10005 #if 1
10006         case 4:
10007           genrshFour (result, left, shCount, sign);
10008           break;
10009 #endif
10010         default:
10011           break;
10012         }
10013     }
10014   freeAsmop (result, NULL, ic, TRUE);
10015   freeAsmop (left, NULL, ic, TRUE);
10016
10017   return TRUE;
10018 }
10019 #endif
10020
10021 /*-----------------------------------------------------------------*/
10022 /* genSignedRightShift - right shift of signed number              */
10023 /*-----------------------------------------------------------------*/
10024 static void
10025 genSignedRightShift (iCode * ic)
10026 {
10027   operand *right, *left, *result;
10028   int size, offset;
10029   char *l;
10030   symbol *tlbl, *tlbl1;
10031   bool pushedB;
10032
10033   D (emitcode (";", "genSignedRightShift"));
10034
10035   /* we do it the hard way put the shift count in b
10036      and loop thru preserving the sign */
10037
10038   right = IC_RIGHT (ic);
10039   left = IC_LEFT (ic);
10040   result = IC_RESULT (ic);
10041
10042   aopOp (right, ic, FALSE, FALSE);
10043
10044 #ifdef BETTER_LITERAL_SHIFT
10045   if (AOP_TYPE (right) == AOP_LIT)
10046     {
10047       if (genRightShiftLiteral (left, right, result, ic, 1))
10048       {
10049         return;
10050       }
10051     }
10052 #endif
10053   /* shift count is unknown then we have to form
10054      a loop get the loop count in B : Note: we take
10055      only the lower order byte since shifting
10056      more that 32 bits make no sense anyway, ( the
10057      largest size of an object can be only 32 bits ) */
10058
10059   pushedB = pushB ();
10060   if (AOP_TYPE (right) == AOP_LIT)
10061   {
10062       /* Really should be handled by genRightShiftLiteral,
10063        * but since I'm too lazy to fix that today, at least we can make
10064        * some small improvement.
10065        */
10066        emitcode("mov", "b,#!constbyte",
10067                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
10068   }
10069   else
10070   {
10071         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10072         emitcode ("inc", "b");
10073   }
10074   freeAsmop (right, NULL, ic, TRUE);
10075   aopOp (left, ic, FALSE, FALSE);
10076   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10077
10078   /* now move the left to the result if they are not the
10079      same */
10080   if (!sameRegs (AOP (left), AOP (result)) &&
10081       AOP_SIZE (result) > 1)
10082     {
10083
10084       size = AOP_SIZE (result);
10085       offset = 0;
10086       _startLazyDPSEvaluation ();
10087       while (size--)
10088         {
10089           l = aopGet (left, offset, FALSE, TRUE, NULL);
10090           if (*l == '@' && IS_AOP_PREG (result))
10091             {
10092
10093               emitcode ("mov", "a,%s", l);
10094               aopPut (result, "a", offset);
10095             }
10096           else
10097             aopPut (result, l, offset);
10098           offset++;
10099         }
10100       _endLazyDPSEvaluation ();
10101     }
10102
10103   /* mov the highest order bit to OVR */
10104   tlbl = newiTempLabel (NULL);
10105   tlbl1 = newiTempLabel (NULL);
10106
10107   size = AOP_SIZE (result);
10108   offset = size - 1;
10109   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10110   emitcode ("rlc", "a");
10111   emitcode ("mov", "ov,c");
10112   /* if it is only one byte then */
10113   if (size == 1)
10114     {
10115       l = aopGet (left, 0, FALSE, FALSE, NULL);
10116       MOVA (l);
10117       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10118       emitLabel (tlbl);
10119       emitcode ("mov", "c,ov");
10120       emitcode ("rrc", "a");
10121       emitLabel (tlbl1);
10122       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10123       popB (pushedB);
10124       aopPut (result, "a", 0);
10125       goto release;
10126     }
10127
10128   reAdjustPreg (AOP (result));
10129   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10130   emitLabel (tlbl);
10131   emitcode ("mov", "c,ov");
10132   _startLazyDPSEvaluation ();
10133   while (size--)
10134     {
10135       l = aopGet (result, offset, FALSE, FALSE, NULL);
10136       MOVA (l);
10137       emitcode ("rrc", "a");
10138       aopPut (result, "a", offset--);
10139     }
10140   _endLazyDPSEvaluation ();
10141   reAdjustPreg (AOP (result));
10142   emitLabel (tlbl1);
10143   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10144   popB (pushedB);
10145
10146 release:
10147   freeAsmop (result, NULL, ic, TRUE);
10148   freeAsmop (left, NULL, ic, TRUE);
10149 }
10150
10151 /*-----------------------------------------------------------------*/
10152 /* genRightShift - generate code for right shifting                */
10153 /*-----------------------------------------------------------------*/
10154 static void
10155 genRightShift (iCode * ic)
10156 {
10157   operand *right, *left, *result;
10158   sym_link *letype;
10159   int size, offset;
10160   char *l;
10161   symbol *tlbl, *tlbl1;
10162   bool pushedB;
10163
10164   D (emitcode (";", "genRightShift"));
10165
10166   /* if signed then we do it the hard way preserve the
10167      sign bit moving it inwards */
10168   letype = getSpec (operandType (IC_LEFT (ic)));
10169
10170   if (!SPEC_USIGN (letype))
10171     {
10172       genSignedRightShift (ic);
10173       return;
10174     }
10175
10176   /* signed & unsigned types are treated the same : i.e. the
10177      signed is NOT propagated inwards : quoting from the
10178      ANSI - standard : "for E1 >> E2, is equivalent to division
10179      by 2**E2 if unsigned or if it has a non-negative value,
10180      otherwise the result is implementation defined ", MY definition
10181      is that the sign does not get propagated */
10182
10183   right = IC_RIGHT (ic);
10184   left = IC_LEFT (ic);
10185   result = IC_RESULT (ic);
10186
10187   aopOp (right, ic, FALSE, FALSE);
10188
10189 #ifdef BETTER_LITERAL_SHIFT
10190   /* if the shift count is known then do it
10191      as efficiently as possible */
10192   if (AOP_TYPE (right) == AOP_LIT)
10193     {
10194       if (genRightShiftLiteral (left, right, result, ic, 0))
10195       {
10196         return;
10197       }
10198     }
10199 #endif
10200
10201   /* shift count is unknown then we have to form
10202      a loop get the loop count in B : Note: we take
10203      only the lower order byte since shifting
10204      more that 32 bits make no sense anyway, ( the
10205      largest size of an object can be only 32 bits ) */
10206
10207   pushedB = pushB ();
10208   if (AOP_TYPE (right) == AOP_LIT)
10209   {
10210       /* Really should be handled by genRightShiftLiteral,
10211        * but since I'm too lazy to fix that today, at least we can make
10212        * some small improvement.
10213        */
10214        emitcode("mov", "b,#!constbyte",
10215                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
10216   }
10217   else
10218   {
10219       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10220       emitcode ("inc", "b");
10221   }
10222   freeAsmop (right, NULL, ic, TRUE);
10223   aopOp (left, ic, FALSE, FALSE);
10224   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10225
10226   /* now move the left to the result if they are not the
10227      same */
10228   if (!sameRegs (AOP (left), AOP (result)) &&
10229       AOP_SIZE (result) > 1)
10230     {
10231       size = AOP_SIZE (result);
10232       offset = 0;
10233       _startLazyDPSEvaluation ();
10234       while (size--)
10235         {
10236           l = aopGet (left, offset, FALSE, TRUE, NULL);
10237           if (*l == '@' && IS_AOP_PREG (result))
10238             {
10239
10240               emitcode ("mov", "a,%s", l);
10241               aopPut (result, "a", offset);
10242             }
10243           else
10244             aopPut (result, l, offset);
10245           offset++;
10246         }
10247       _endLazyDPSEvaluation ();
10248     }
10249
10250   tlbl = newiTempLabel (NULL);
10251   tlbl1 = newiTempLabel (NULL);
10252   size = AOP_SIZE (result);
10253   offset = size - 1;
10254
10255   /* if it is only one byte then */
10256   if (size == 1)
10257     {
10258       l = aopGet (left, 0, FALSE, FALSE, NULL);
10259       MOVA (l);
10260       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10261       emitLabel (tlbl);
10262       CLRC;
10263       emitcode ("rrc", "a");
10264       emitLabel (tlbl1);
10265       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10266       popB (pushedB);
10267       aopPut (result, "a", 0);
10268       goto release;
10269     }
10270
10271   reAdjustPreg (AOP (result));
10272   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10273   emitLabel (tlbl);
10274   CLRC;
10275   _startLazyDPSEvaluation ();
10276   while (size--)
10277     {
10278       l = aopGet (result, offset, FALSE, FALSE, NULL);
10279       MOVA (l);
10280       emitcode ("rrc", "a");
10281       aopPut (result, "a", offset--);
10282     }
10283   _endLazyDPSEvaluation ();
10284   reAdjustPreg (AOP (result));
10285
10286   emitLabel (tlbl1);
10287   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10288   popB (pushedB);
10289
10290 release:
10291   freeAsmop (result, NULL, ic, TRUE);
10292   freeAsmop (left, NULL, ic, TRUE);
10293 }
10294
10295 /*-----------------------------------------------------------------*/
10296 /* emitPtrByteGet - emits code to get a byte into A through a      */
10297 /*                  pointer register (R0, R1, or DPTR). The        */
10298 /*                  original value of A can be preserved in B.     */
10299 /*-----------------------------------------------------------------*/
10300 static void
10301 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10302 {
10303   switch (p_type)
10304     {
10305     case IPOINTER:
10306     case POINTER:
10307       if (preserveAinB)
10308         emitcode ("mov", "b,a");
10309       emitcode ("mov", "a,@%s", rname);
10310       break;
10311
10312     case PPOINTER:
10313       if (preserveAinB)
10314         emitcode ("mov", "b,a");
10315       emitcode ("movx", "a,@%s", rname);
10316       break;
10317
10318     case FPOINTER:
10319       if (preserveAinB)
10320         emitcode ("mov", "b,a");
10321       emitcode ("movx", "a,@dptr");
10322       break;
10323
10324     case CPOINTER:
10325       if (preserveAinB)
10326         emitcode ("mov", "b,a");
10327       emitcode ("clr", "a");
10328       emitcode ("movc", "a,@a+dptr");
10329       break;
10330
10331     case GPOINTER:
10332       if (preserveAinB)
10333         {
10334           emitcode ("push", "b");
10335           emitcode ("push", "acc");
10336         }
10337       emitcode ("lcall", "__gptrget");
10338       if (preserveAinB)
10339         emitcode ("pop", "b");
10340       break;
10341     }
10342 }
10343
10344 /*-----------------------------------------------------------------*/
10345 /* emitPtrByteSet - emits code to set a byte from src through a    */
10346 /*                  pointer register (R0, R1, or DPTR).            */
10347 /*-----------------------------------------------------------------*/
10348 static void
10349 emitPtrByteSet (char *rname, int p_type, char *src)
10350 {
10351   switch (p_type)
10352     {
10353     case IPOINTER:
10354     case POINTER:
10355       if (*src=='@')
10356         {
10357           MOVA (src);
10358           emitcode ("mov", "@%s,a", rname);
10359         }
10360       else
10361         emitcode ("mov", "@%s,%s", rname, src);
10362       break;
10363
10364     case PPOINTER:
10365       MOVA (src);
10366       emitcode ("movx", "@%s,a", rname);
10367       break;
10368
10369     case FPOINTER:
10370       MOVA (src);
10371       emitcode ("movx", "@dptr,a");
10372       break;
10373
10374     case GPOINTER:
10375       MOVA (src);
10376       emitcode ("lcall", "__gptrput");
10377       break;
10378     }
10379 }
10380
10381 /*-----------------------------------------------------------------*/
10382 /* genUnpackBits - generates code for unpacking bits               */
10383 /*-----------------------------------------------------------------*/
10384 static void
10385 genUnpackBits (operand * result, char *rname, int ptype)
10386 {
10387   int offset = 0;       /* result byte offset */
10388   int rsize;            /* result size */
10389   int rlen = 0;         /* remaining bitfield length */
10390   sym_link *etype;      /* bitfield type information */
10391   int blen;             /* bitfield length */
10392   int bstr;             /* bitfield starting bit within byte */
10393
10394   D(emitcode (";", "genUnpackBits"));
10395
10396   etype = getSpec (operandType (result));
10397   rsize = getSize (operandType (result));
10398   blen = SPEC_BLEN (etype);
10399   bstr = SPEC_BSTR (etype);
10400
10401   /* If the bitfield length is less than a byte */
10402   if (blen < 8)
10403     {
10404       emitPtrByteGet (rname, ptype, FALSE);
10405       AccRol (8 - bstr);
10406       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10407       if (!SPEC_USIGN (etype))
10408         {
10409           /* signed bitfield */
10410           symbol *tlbl = newiTempLabel (NULL);
10411
10412           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10413           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10414           emitLabel (tlbl);
10415         }
10416       aopPut (result, "a", offset++);
10417       goto finish;
10418     }
10419
10420   /* Bit field did not fit in a byte. Copy all
10421      but the partial byte at the end.  */
10422   for (rlen=blen;rlen>=8;rlen-=8)
10423     {
10424       emitPtrByteGet (rname, ptype, FALSE);
10425       aopPut (result, "a", offset++);
10426       if (rlen>8)
10427         emitcode ("inc", "%s", rname);
10428     }
10429
10430   /* Handle the partial byte at the end */
10431   if (rlen)
10432     {
10433       emitPtrByteGet (rname, ptype, FALSE);
10434       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10435       if (!SPEC_USIGN (etype))
10436         {
10437           /* signed bitfield */
10438           symbol *tlbl = newiTempLabel (NULL);
10439
10440           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10441           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10442           emitLabel (tlbl);
10443         }
10444       aopPut (result, "a", offset++);
10445     }
10446
10447 finish:
10448   if (offset < rsize)
10449     {
10450       char *source;
10451
10452       if (SPEC_USIGN (etype))
10453         source = zero;
10454       else
10455         {
10456           /* signed bitfield: sign extension with 0x00 or 0xff */
10457           emitcode ("rlc", "a");
10458           emitcode ("subb", "a,acc");
10459
10460           source = "a";
10461         }
10462       rsize -= offset;
10463       while (rsize--)
10464         aopPut (result, source, offset++);
10465     }
10466 }
10467
10468
10469 /*-----------------------------------------------------------------*/
10470 /* genDataPointerGet - generates code when ptr offset is known     */
10471 /*-----------------------------------------------------------------*/
10472 static void
10473 genDataPointerGet (operand * left,
10474                    operand * result,
10475                    iCode * ic)
10476 {
10477   char *l;
10478   char buffer[256];
10479   int size, offset = 0;
10480   aopOp (result, ic, TRUE, FALSE);
10481
10482   /* get the string representation of the name */
10483   l = aopGet (left, 0, FALSE, TRUE, NULL);
10484   size = AOP_SIZE (result);
10485   _startLazyDPSEvaluation ();
10486   while (size--)
10487     {
10488         if (offset)
10489         {
10490             SNPRINTF (buffer, sizeof(buffer),
10491                       "(%s + %d)", l + 1, offset);
10492         }
10493         else
10494         {
10495             SNPRINTF (buffer, sizeof(buffer),
10496                       "%s", l + 1);
10497         }
10498       aopPut (result, buffer, offset++);
10499     }
10500   _endLazyDPSEvaluation ();
10501
10502   freeAsmop (result, NULL, ic, TRUE);
10503   freeAsmop (left, NULL, ic, TRUE);
10504 }
10505
10506 /*-----------------------------------------------------------------*/
10507 /* genNearPointerGet - emitcode for near pointer fetch             */
10508 /*-----------------------------------------------------------------*/
10509 static void
10510 genNearPointerGet (operand * left,
10511                    operand * result,
10512                    iCode * ic,
10513                    iCode *pi)
10514 {
10515   asmop *aop = NULL;
10516   regs *preg;
10517   char *rname;
10518   sym_link *rtype, *retype, *letype;
10519   sym_link *ltype = operandType (left);
10520   char buffer[80];
10521
10522   rtype = operandType (result);
10523   retype = getSpec (rtype);
10524   letype = getSpec (ltype);
10525
10526   aopOp (left, ic, FALSE, FALSE);
10527
10528   /* if left is rematerialisable and
10529      result is not bitfield variable type and
10530      the left is pointer to data space i.e
10531      lower 128 bytes of space */
10532   if (AOP_TYPE (left) == AOP_IMMD &&
10533       !IS_BITFIELD (retype) &&
10534       !IS_BITFIELD (letype) &&
10535       DCL_TYPE (ltype) == POINTER)
10536     {
10537       genDataPointerGet (left, result, ic);
10538       return;
10539     }
10540
10541   /* if the value is already in a pointer register
10542      then don't need anything more */
10543   if (!AOP_INPREG (AOP (left)))
10544     {
10545       /* otherwise get a free pointer register */
10546       aop = newAsmop (0);
10547       preg = getFreePtr (ic, &aop, FALSE);
10548       emitcode ("mov", "%s,%s",
10549                 preg->name,
10550                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10551       rname = preg->name;
10552     }
10553   else
10554     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10555
10556   freeAsmop (left, NULL, ic, TRUE);
10557   aopOp (result, ic, FALSE, FALSE);
10558
10559   /* if bitfield then unpack the bits */
10560   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10561     genUnpackBits (result, rname, POINTER);
10562   else
10563     {
10564       /* we have can just get the values */
10565       int size = AOP_SIZE (result);
10566       int offset = 0;
10567
10568       while (size--)
10569         {
10570           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10571             {
10572
10573               emitcode ("mov", "a,@%s", rname);
10574               aopPut (result, "a", offset);
10575             }
10576           else
10577             {
10578               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10579               aopPut (result, buffer, offset);
10580             }
10581           offset++;
10582           if (size || pi)
10583             emitcode ("inc", "%s", rname);
10584         }
10585     }
10586
10587   /* now some housekeeping stuff */
10588   if (aop)      /* we had to allocate for this iCode */
10589     {
10590       if (pi) { /* post increment present */
10591         aopPut (left, rname, 0);
10592       }
10593       freeAsmop (NULL, aop, ic, TRUE);
10594     }
10595   else
10596     {
10597       /* we did not allocate which means left
10598          already in a pointer register, then
10599          if size > 0 && this could be used again
10600          we have to point it back to where it
10601          belongs */
10602       if (AOP_SIZE (result) > 1 &&
10603           !OP_SYMBOL (left)->remat &&
10604           (OP_SYMBOL (left)->liveTo > ic->seq ||
10605            ic->depth) &&
10606           !pi)
10607         {
10608           int size = AOP_SIZE (result) - 1;
10609           while (size--)
10610             emitcode ("dec", "%s", rname);
10611         }
10612     }
10613
10614   /* done */
10615   freeAsmop (result, NULL, ic, TRUE);
10616   if (pi) pi->generated = 1;
10617 }
10618
10619 /*-----------------------------------------------------------------*/
10620 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10621 /*-----------------------------------------------------------------*/
10622 static void
10623 genPagedPointerGet (operand * left,
10624                     operand * result,
10625                     iCode * ic,
10626                     iCode * pi)
10627 {
10628   asmop *aop = NULL;
10629   regs *preg;
10630   char *rname;
10631   sym_link *rtype, *retype, *letype;
10632
10633   rtype = operandType (result);
10634   retype = getSpec (rtype);
10635   letype = getSpec (operandType (left));
10636   aopOp (left, ic, FALSE, FALSE);
10637
10638   /* if the value is already in a pointer register
10639      then don't need anything more */
10640   if (!AOP_INPREG (AOP (left)))
10641     {
10642       /* otherwise get a free pointer register */
10643       aop = newAsmop (0);
10644       preg = getFreePtr (ic, &aop, FALSE);
10645       emitcode ("mov", "%s,%s",
10646                 preg->name,
10647                 aopGet (left, 0, FALSE, TRUE, NULL));
10648       rname = preg->name;
10649     }
10650   else
10651     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10652
10653   freeAsmop (left, NULL, ic, TRUE);
10654   aopOp (result, ic, FALSE, FALSE);
10655
10656   /* if bitfield then unpack the bits */
10657   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10658     genUnpackBits (result, rname, PPOINTER);
10659   else
10660     {
10661       /* we have can just get the values */
10662       int size = AOP_SIZE (result);
10663       int offset = 0;
10664
10665       while (size--)
10666         {
10667
10668           emitcode ("movx", "a,@%s", rname);
10669           aopPut (result, "a", offset);
10670
10671           offset++;
10672
10673           if (size || pi)
10674             emitcode ("inc", "%s", rname);
10675         }
10676     }
10677
10678   /* now some housekeeping stuff */
10679   if (aop)      /* we had to allocate for this iCode */
10680     {
10681       if (pi)
10682         aopPut (left, rname, 0);
10683       freeAsmop (NULL, aop, ic, TRUE);
10684     }
10685   else
10686     {
10687       /* we did not allocate which means left
10688          already in a pointer register, then
10689          if size > 0 && this could be used again
10690          we have to point it back to where it
10691          belongs */
10692       if (AOP_SIZE (result) > 1 &&
10693           !OP_SYMBOL (left)->remat &&
10694           (OP_SYMBOL (left)->liveTo > ic->seq ||
10695            ic->depth) &&
10696           !pi)
10697         {
10698           int size = AOP_SIZE (result) - 1;
10699           while (size--)
10700             emitcode ("dec", "%s", rname);
10701         }
10702     }
10703
10704   /* done */
10705   freeAsmop (result, NULL, ic, TRUE);
10706   if (pi) pi->generated = 1;
10707 }
10708
10709 /*-----------------------------------------------------------------*/
10710 /* genFarPointerGet - get value from far space                     */
10711 /*-----------------------------------------------------------------*/
10712 static void
10713 genFarPointerGet (operand * left,
10714                   operand * result, iCode * ic, iCode *pi)
10715 {
10716   int size, offset, dopi=1;
10717   sym_link *retype = getSpec (operandType (result));
10718   sym_link *letype = getSpec (operandType (left));
10719   D (emitcode (";", "genFarPointerGet"););
10720
10721   aopOp (left, ic, FALSE, FALSE);
10722
10723   /* if the operand is already in dptr
10724      then we do nothing else we move the value to dptr */
10725   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10726     {
10727       /* if this is rematerializable */
10728       if (AOP_TYPE (left) == AOP_IMMD)
10729         {
10730           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10731         }
10732       else
10733         {
10734           /* we need to get it byte by byte */
10735           _startLazyDPSEvaluation ();
10736           if (AOP_TYPE (left) != AOP_DPTR)
10737             {
10738               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10739               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10740               if (options.model == MODEL_FLAT24)
10741                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10742             }
10743           else
10744             {
10745               /* We need to generate a load to DPTR indirect through DPTR. */
10746               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10747               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10748               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10749               if (options.model == MODEL_FLAT24)
10750                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10751               emitcode ("pop", "dph");
10752               emitcode ("pop", "dpl");
10753               dopi =0;
10754             }
10755           _endLazyDPSEvaluation ();
10756         }
10757     }
10758   /* so dptr now contains the address */
10759   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10760
10761   /* if bit then unpack */
10762   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10763       if (AOP_INDPTRn(left)) {
10764           genSetDPTR(AOP(left)->aopu.dptr);
10765       }
10766       genUnpackBits (result, "dptr", FPOINTER);
10767       if (AOP_INDPTRn(left)) {
10768           genSetDPTR(0);
10769       }
10770   } else
10771     {
10772       size = AOP_SIZE (result);
10773       offset = 0;
10774
10775       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10776           while (size--) {
10777               genSetDPTR(AOP(left)->aopu.dptr);
10778               emitcode ("movx", "a,@dptr");
10779               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10780                   emitcode ("inc", "dptr");
10781               genSetDPTR (0);
10782               aopPut (result, "a", offset++);
10783           }
10784       } else {
10785           _startLazyDPSEvaluation ();
10786           while (size--) {
10787               if (AOP_INDPTRn(left)) {
10788                   genSetDPTR(AOP(left)->aopu.dptr);
10789               } else {
10790                   genSetDPTR (0);
10791               }
10792               _flushLazyDPS ();
10793
10794               emitcode ("movx", "a,@dptr");
10795               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10796                   emitcode ("inc", "dptr");
10797
10798               aopPut (result, "a", offset++);
10799           }
10800           _endLazyDPSEvaluation ();
10801       }
10802     }
10803   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10804       if (!AOP_INDPTRn(left)) {
10805           _startLazyDPSEvaluation ();
10806           aopPut (left, "dpl", 0);
10807           aopPut (left, "dph", 1);
10808           if (options.model == MODEL_FLAT24)
10809               aopPut (left, "dpx", 2);
10810           _endLazyDPSEvaluation ();
10811       }
10812     pi->generated = 1;
10813   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10814              AOP_SIZE(result) > 1 &&
10815              IS_SYMOP(left) &&
10816              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10817
10818       size = AOP_SIZE (result) - 1;
10819       if (AOP_INDPTRn(left)) {
10820           genSetDPTR(AOP(left)->aopu.dptr);
10821       }
10822       while (size--) emitcode ("lcall","__decdptr");
10823       if (AOP_INDPTRn(left)) {
10824           genSetDPTR(0);
10825       }
10826   }
10827
10828   freeAsmop (result, NULL, ic, TRUE);
10829   freeAsmop (left, NULL, ic, TRUE);
10830 }
10831
10832 /*-----------------------------------------------------------------*/
10833 /* genCodePointerGet - get value from code space                   */
10834 /*-----------------------------------------------------------------*/
10835 static void
10836 genCodePointerGet (operand * left,
10837                     operand * result, iCode * ic, iCode *pi)
10838 {
10839   int size, offset, dopi=1;
10840   sym_link *retype = getSpec (operandType (result));
10841
10842   aopOp (left, ic, FALSE, FALSE);
10843
10844   /* if the operand is already in dptr
10845      then we do nothing else we move the value to dptr */
10846   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10847     {
10848       /* if this is rematerializable */
10849       if (AOP_TYPE (left) == AOP_IMMD)
10850         {
10851           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10852         }
10853       else
10854         {                       /* we need to get it byte by byte */
10855           _startLazyDPSEvaluation ();
10856           if (AOP_TYPE (left) != AOP_DPTR)
10857             {
10858               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10859               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10860               if (options.model == MODEL_FLAT24)
10861                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10862             }
10863           else
10864             {
10865               /* We need to generate a load to DPTR indirect through DPTR. */
10866               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10867               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10868               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10869               if (options.model == MODEL_FLAT24)
10870                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10871               emitcode ("pop", "dph");
10872               emitcode ("pop", "dpl");
10873               dopi=0;
10874             }
10875           _endLazyDPSEvaluation ();
10876         }
10877     }
10878   /* so dptr now contains the address */
10879   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10880
10881   /* if bit then unpack */
10882   if (IS_BITFIELD (retype)) {
10883       if (AOP_INDPTRn(left)) {
10884           genSetDPTR(AOP(left)->aopu.dptr);
10885       }
10886       genUnpackBits (result, "dptr", CPOINTER);
10887       if (AOP_INDPTRn(left)) {
10888           genSetDPTR(0);
10889       }
10890   } else
10891     {
10892       size = AOP_SIZE (result);
10893       offset = 0;
10894       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10895           while (size--) {
10896               genSetDPTR(AOP(left)->aopu.dptr);
10897               emitcode ("clr", "a");
10898               emitcode ("movc", "a,@a+dptr");
10899               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10900                   emitcode ("inc", "dptr");
10901               genSetDPTR (0);
10902               aopPut (result, "a", offset++);
10903           }
10904       } else {
10905           _startLazyDPSEvaluation ();
10906           while (size--)
10907               {
10908                   if (AOP_INDPTRn(left)) {
10909                       genSetDPTR(AOP(left)->aopu.dptr);
10910                   } else {
10911                       genSetDPTR (0);
10912                   }
10913                   _flushLazyDPS ();
10914
10915                   emitcode ("clr", "a");
10916                   emitcode ("movc", "a,@a+dptr");
10917                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10918                       emitcode ("inc", "dptr");
10919                   aopPut (result, "a", offset++);
10920               }
10921           _endLazyDPSEvaluation ();
10922       }
10923     }
10924   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10925       if (!AOP_INDPTRn(left)) {
10926           _startLazyDPSEvaluation ();
10927
10928           aopPut (left, "dpl", 0);
10929           aopPut (left, "dph", 1);
10930           if (options.model == MODEL_FLAT24)
10931               aopPut (left, "dpx", 2);
10932
10933           _endLazyDPSEvaluation ();
10934       }
10935       pi->generated = 1;
10936   } else if (IS_SYMOP(left) &&
10937              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10938              AOP_SIZE(result) > 1 &&
10939              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10940
10941       size = AOP_SIZE (result) - 1;
10942       if (AOP_INDPTRn(left)) {
10943           genSetDPTR(AOP(left)->aopu.dptr);
10944       }
10945       while (size--) emitcode ("lcall","__decdptr");
10946       if (AOP_INDPTRn(left)) {
10947           genSetDPTR(0);
10948       }
10949   }
10950
10951   freeAsmop (result, NULL, ic, TRUE);
10952   freeAsmop (left, NULL, ic, TRUE);
10953 }
10954
10955 /*-----------------------------------------------------------------*/
10956 /* genGenPointerGet - get value from generic pointer space         */
10957 /*-----------------------------------------------------------------*/
10958 static void
10959 genGenPointerGet (operand * left,
10960                   operand * result, iCode * ic, iCode * pi)
10961 {
10962   int size, offset;
10963   bool pushedB;
10964   sym_link *retype = getSpec (operandType (result));
10965   sym_link *letype = getSpec (operandType (left));
10966
10967   D (emitcode (";", "genGenPointerGet"));
10968
10969   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10970
10971   pushedB = pushB ();
10972   /* if the operand is already in dptr
10973      then we do nothing else we move the value to dptr */
10974   if (AOP_TYPE (left) != AOP_STR)
10975     {
10976       /* if this is rematerializable */
10977       if (AOP_TYPE (left) == AOP_IMMD)
10978         {
10979           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10980           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10981             {
10982               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10983             }
10984           else
10985             {
10986               emitcode ("mov", "b,#%d", pointerCode (retype));
10987             }
10988         }
10989       else
10990         {                       /* we need to get it byte by byte */
10991           _startLazyDPSEvaluation ();
10992           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10993           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10994           if (options.model == MODEL_FLAT24) {
10995               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10996               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10997           } else {
10998               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10999           }
11000           _endLazyDPSEvaluation ();
11001         }
11002     }
11003
11004   /* so dptr-b now contains the address */
11005   aopOp (result, ic, FALSE, TRUE);
11006
11007   /* if bit then unpack */
11008   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11009   {
11010     genUnpackBits (result, "dptr", GPOINTER);
11011   }
11012   else
11013     {
11014         size = AOP_SIZE (result);
11015         offset = 0;
11016
11017         while (size--)
11018         {
11019             if (size)
11020             {
11021                 // Get two bytes at a time, results in _AP & A.
11022                 // dptr will be incremented ONCE by __gptrgetWord.
11023                 //
11024                 // Note: any change here must be coordinated
11025                 // with the implementation of __gptrgetWord
11026                 // in device/lib/_gptrget.c
11027                 emitcode ("lcall", "__gptrgetWord");
11028                 aopPut (result, "a", offset++);
11029                 aopPut (result, DP2_RESULT_REG, offset++);
11030                 size--;
11031             }
11032             else
11033             {
11034                 // Only one byte to get.
11035                 emitcode ("lcall", "__gptrget");
11036                 aopPut (result, "a", offset++);
11037             }
11038
11039             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11040             {
11041                 emitcode ("inc", "dptr");
11042             }
11043         }
11044     }
11045
11046   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11047     _startLazyDPSEvaluation ();
11048
11049     aopPut (left, "dpl", 0);
11050     aopPut (left, "dph", 1);
11051     if (options.model == MODEL_FLAT24) {
11052         aopPut (left, "dpx", 2);
11053         aopPut (left, "b", 3);
11054     } else  aopPut (left, "b", 2);
11055
11056     _endLazyDPSEvaluation ();
11057
11058     pi->generated = 1;
11059   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11060              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11061
11062       size = AOP_SIZE (result) - 1;
11063       while (size--) emitcode ("lcall","__decdptr");
11064   }
11065   popB (pushedB);
11066
11067   freeAsmop (result, NULL, ic, TRUE);
11068   freeAsmop (left, NULL, ic, TRUE);
11069 }
11070
11071 /*-----------------------------------------------------------------*/
11072 /* genPointerGet - generate code for pointer get                   */
11073 /*-----------------------------------------------------------------*/
11074 static void
11075 genPointerGet (iCode * ic, iCode *pi)
11076 {
11077   operand *left, *result;
11078   sym_link *type, *etype;
11079   int p_type;
11080
11081   D (emitcode (";", "genPointerGet"));
11082
11083   left = IC_LEFT (ic);
11084   result = IC_RESULT (ic);
11085
11086   /* depending on the type of pointer we need to
11087      move it to the correct pointer register */
11088   type = operandType (left);
11089   etype = getSpec (type);
11090   /* if left is of type of pointer then it is simple */
11091   if (IS_PTR (type) && !IS_FUNC (type->next))
11092     p_type = DCL_TYPE (type);
11093   else
11094     {
11095       /* we have to go by the storage class */
11096       p_type = PTR_TYPE (SPEC_OCLS (etype));
11097     }
11098
11099   /* special case when cast remat */
11100   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11101       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11102     {
11103       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11104       type = operandType (left);
11105       p_type = DCL_TYPE (type);
11106     }
11107   /* now that we have the pointer type we assign
11108      the pointer values */
11109   switch (p_type)
11110     {
11111
11112     case POINTER:
11113     case IPOINTER:
11114       genNearPointerGet (left, result, ic, pi);
11115       break;
11116
11117     case PPOINTER:
11118       genPagedPointerGet (left, result, ic, pi);
11119       break;
11120
11121     case FPOINTER:
11122       genFarPointerGet (left, result, ic, pi);
11123       break;
11124
11125     case CPOINTER:
11126       genCodePointerGet (left, result, ic, pi);
11127       break;
11128
11129     case GPOINTER:
11130       genGenPointerGet (left, result, ic, pi);
11131       break;
11132     }
11133 }
11134
11135
11136 /*-----------------------------------------------------------------*/
11137 /* genPackBits - generates code for packed bit storage             */
11138 /*-----------------------------------------------------------------*/
11139 static void
11140 genPackBits (sym_link * etype,
11141              operand * right,
11142              char *rname, int p_type)
11143 {
11144   int offset = 0;       /* source byte offset */
11145   int rlen = 0;         /* remaining bitfield length */
11146   int blen;             /* bitfield length */
11147   int bstr;             /* bitfield starting bit within byte */
11148   int litval;           /* source literal value (if AOP_LIT) */
11149   unsigned char mask;   /* bitmask within current byte */
11150
11151   D(emitcode (";", "genPackBits"));
11152
11153   blen = SPEC_BLEN (etype);
11154   bstr = SPEC_BSTR (etype);
11155
11156   /* If the bitfield length is less than a byte */
11157   if (blen < 8)
11158     {
11159       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11160               (unsigned char) (0xFF >> (8 - bstr)));
11161
11162       if (AOP_TYPE (right) == AOP_LIT)
11163         {
11164           /* Case with a bitfield length <8 and literal source
11165           */
11166           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
11167           litval <<= bstr;
11168           litval &= (~mask) & 0xff;
11169           emitPtrByteGet (rname, p_type, FALSE);
11170           if ((mask|litval)!=0xff)
11171             emitcode ("anl","a,#!constbyte", mask);
11172           if (litval)
11173             emitcode ("orl","a,#!constbyte", litval);
11174         }
11175       else
11176         {
11177           if ((blen==1) && (p_type!=GPOINTER))
11178             {
11179               /* Case with a bitfield length == 1 and no generic pointer
11180               */
11181               if (AOP_TYPE (right) == AOP_CRY)
11182                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11183               else
11184                 {
11185                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11186                   emitcode ("rrc","a");
11187                 }
11188               emitPtrByteGet (rname, p_type, FALSE);
11189               emitcode ("mov","acc.%d,c",bstr);
11190             }
11191           else
11192             {
11193               bool pushedB;
11194               /* Case with a bitfield length < 8 and arbitrary source
11195               */
11196               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11197               /* shift and mask source value */
11198               AccLsh (bstr);
11199               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11200
11201               pushedB = pushB ();
11202               /* transfer A to B and get next byte */
11203               emitPtrByteGet (rname, p_type, TRUE);
11204
11205               emitcode ("anl", "a,#!constbyte", mask);
11206               emitcode ("orl", "a,b");
11207               if (p_type == GPOINTER)
11208                 emitcode ("pop", "b");
11209
11210               popB (pushedB);
11211            }
11212         }
11213
11214       emitPtrByteSet (rname, p_type, "a");
11215       return;
11216     }
11217
11218   /* Bit length is greater than 7 bits. In this case, copy  */
11219   /* all except the partial byte at the end                 */
11220   for (rlen=blen;rlen>=8;rlen-=8)
11221     {
11222       emitPtrByteSet (rname, p_type,
11223                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11224       if (rlen>8)
11225         emitcode ("inc", "%s", rname);
11226     }
11227
11228   /* If there was a partial byte at the end */
11229   if (rlen)
11230     {
11231       mask = (((unsigned char) -1 << rlen) & 0xff);
11232
11233       if (AOP_TYPE (right) == AOP_LIT)
11234         {
11235           /* Case with partial byte and literal source
11236           */
11237           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
11238           litval >>= (blen-rlen);
11239           litval &= (~mask) & 0xff;
11240           emitPtrByteGet (rname, p_type, FALSE);
11241           if ((mask|litval)!=0xff)
11242             emitcode ("anl","a,#!constbyte", mask);
11243           if (litval)
11244             emitcode ("orl","a,#!constbyte", litval);
11245         }
11246       else
11247         {
11248           bool pushedB;
11249           /* Case with partial byte and arbitrary source
11250           */
11251           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11252           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11253
11254           pushedB = pushB ();
11255           /* transfer A to B and get next byte */
11256           emitPtrByteGet (rname, p_type, TRUE);
11257
11258           emitcode ("anl", "a,#!constbyte", mask);
11259           emitcode ("orl", "a,b");
11260           if (p_type == GPOINTER)
11261             emitcode ("pop", "b");
11262
11263           popB (pushedB);
11264         }
11265       emitPtrByteSet (rname, p_type, "a");
11266     }
11267 }
11268
11269
11270 /*-----------------------------------------------------------------*/
11271 /* genDataPointerSet - remat pointer to data space                 */
11272 /*-----------------------------------------------------------------*/
11273 static void
11274 genDataPointerSet (operand * right,
11275                    operand * result,
11276                    iCode * ic)
11277 {
11278   int size, offset = 0;
11279   char *l, buffer[256];
11280
11281   D (emitcode (";", "genDataPointerSet"));
11282
11283   aopOp (right, ic, FALSE, FALSE);
11284
11285   l = aopGet (result, 0, FALSE, TRUE, NULL);
11286   size = AOP_SIZE (right);
11287   while (size--)
11288     {
11289       if (offset)
11290           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11291       else
11292           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11293       emitcode ("mov", "%s,%s", buffer,
11294                 aopGet (right, offset++, FALSE, FALSE, NULL));
11295     }
11296
11297   freeAsmop (result, NULL, ic, TRUE);
11298   freeAsmop (right, NULL, ic, TRUE);
11299 }
11300
11301 /*-----------------------------------------------------------------*/
11302 /* genNearPointerSet - emitcode for near pointer put                */
11303 /*-----------------------------------------------------------------*/
11304 static void
11305 genNearPointerSet (operand * right,
11306                    operand * result,
11307                    iCode * ic,
11308                    iCode * pi)
11309 {
11310   asmop *aop = NULL;
11311   char *rname, *l;
11312   sym_link *retype, *letype;
11313   sym_link *ptype = operandType (result);
11314
11315   D (emitcode (";", "genNearPointerSet"));
11316
11317   retype = getSpec (operandType (right));
11318   letype = getSpec (ptype);
11319
11320   aopOp (result, ic, FALSE, FALSE);
11321
11322   /* if the result is rematerializable &
11323      in data space & not a bit variable */
11324   if (AOP_TYPE (result) == AOP_IMMD &&
11325       DCL_TYPE (ptype) == POINTER &&
11326       !IS_BITVAR (retype) &&
11327       !IS_BITVAR (letype))
11328     {
11329       genDataPointerSet (right, result, ic);
11330       return;
11331     }
11332
11333   /* if the value is already in a pointer register
11334      then don't need anything more */
11335   if (!AOP_INPREG (AOP (result)))
11336     {
11337       /* otherwise get a free pointer register */
11338       regs *preg;
11339
11340       aop = newAsmop (0);
11341       preg = getFreePtr (ic, &aop, FALSE);
11342       emitcode ("mov", "%s,%s",
11343                 preg->name,
11344                 aopGet (result, 0, FALSE, TRUE, NULL));
11345       rname = preg->name;
11346     }
11347   else
11348     {
11349       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11350     }
11351
11352   aopOp (right, ic, FALSE, FALSE);
11353
11354   /* if bitfield then unpack the bits */
11355   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11356     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11357   else
11358     {
11359       /* we can just get the values */
11360       int size = AOP_SIZE (right);
11361       int offset = 0;
11362
11363       while (size--)
11364         {
11365           l = aopGet (right, offset, FALSE, TRUE, NULL);
11366           if ((*l == '@') || (strcmp (l, "acc") == 0))
11367             {
11368               MOVA (l);
11369               emitcode ("mov", "@%s,a", rname);
11370             }
11371           else
11372             emitcode ("mov", "@%s,%s", rname, l);
11373           if (size || pi)
11374             emitcode ("inc", "%s", rname);
11375           offset++;
11376         }
11377     }
11378
11379   /* now some housekeeping stuff */
11380   if (aop)      /* we had to allocate for this iCode */
11381     {
11382       if (pi)
11383         aopPut (result, rname, 0);
11384       freeAsmop (NULL, aop, ic, TRUE);
11385     }
11386   else
11387     {
11388       /* we did not allocate which means left
11389          already in a pointer register, then
11390          if size > 0 && this could be used again
11391          we have to point it back to where it
11392          belongs */
11393       if (AOP_SIZE (right) > 1 &&
11394           !OP_SYMBOL (result)->remat &&
11395           (OP_SYMBOL (result)->liveTo > ic->seq ||
11396            ic->depth) &&
11397           !pi)
11398         {
11399           int size = AOP_SIZE (right) - 1;
11400           while (size--)
11401             emitcode ("dec", "%s", rname);
11402         }
11403     }
11404
11405   /* done */
11406   if (pi) pi->generated = 1;
11407   freeAsmop (result, NULL, ic, TRUE);
11408   freeAsmop (right, NULL, ic, TRUE);
11409 }
11410
11411 /*-----------------------------------------------------------------*/
11412 /* genPagedPointerSet - emitcode for Paged pointer put             */
11413 /*-----------------------------------------------------------------*/
11414 static void
11415 genPagedPointerSet (operand * right,
11416                     operand * result,
11417                     iCode * ic,
11418                     iCode *pi)
11419 {
11420   asmop *aop = NULL;
11421   char *rname, *l;
11422   sym_link *retype, *letype;
11423
11424   D (emitcode (";", "genPagedPointerSet"));
11425
11426   retype = getSpec (operandType (right));
11427   letype = getSpec (operandType (result));
11428
11429   aopOp (result, ic, FALSE, FALSE);
11430
11431   /* if the value is already in a pointer register
11432      then don't need anything more */
11433   if (!AOP_INPREG (AOP (result)))
11434     {
11435       /* otherwise get a free pointer register */
11436       regs *preg;
11437
11438       aop = newAsmop (0);
11439       preg = getFreePtr (ic, &aop, FALSE);
11440       emitcode ("mov", "%s,%s",
11441                 preg->name,
11442                 aopGet (result, 0, FALSE, TRUE, NULL));
11443       rname = preg->name;
11444     }
11445   else
11446     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11447
11448   aopOp (right, ic, FALSE, FALSE);
11449
11450   /* if bitfield then unpack the bits */
11451   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11452     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11453   else
11454     {
11455       /* we have can just get the values */
11456       int size = AOP_SIZE (right);
11457       int offset = 0;
11458
11459       while (size--)
11460         {
11461           l = aopGet (right, offset, FALSE, TRUE, NULL);
11462           MOVA (l);
11463           emitcode ("movx", "@%s,a", rname);
11464
11465           if (size || pi)
11466             emitcode ("inc", "%s", rname);
11467
11468           offset++;
11469         }
11470     }
11471
11472   /* now some housekeeping stuff */
11473   if (aop)
11474     {
11475       if (pi)
11476         aopPut (result, rname, 0);
11477       /* we had to allocate for this iCode */
11478       freeAsmop (NULL, aop, ic, TRUE);
11479     }
11480   else
11481     {
11482       /* we did not allocate which means left
11483          already in a pointer register, then
11484          if size > 0 && this could be used again
11485          we have to point it back to where it
11486          belongs */
11487       if (AOP_SIZE (right) > 1 &&
11488           !OP_SYMBOL (result)->remat &&
11489           (OP_SYMBOL (result)->liveTo > ic->seq ||
11490            ic->depth) &&
11491           !pi)
11492         {
11493           int size = AOP_SIZE (right) - 1;
11494           while (size--)
11495             emitcode ("dec", "%s", rname);
11496         }
11497     }
11498
11499   /* done */
11500   if (pi) pi->generated = 1;
11501   freeAsmop (result, NULL, ic, TRUE);
11502   freeAsmop (right, NULL, ic, TRUE);
11503 }
11504
11505 /*-----------------------------------------------------------------*/
11506 /* genFarPointerSet - set value from far space                     */
11507 /*-----------------------------------------------------------------*/
11508 static void
11509 genFarPointerSet (operand * right,
11510                   operand * result, iCode * ic, iCode *pi)
11511 {
11512   int size, offset, dopi=1;
11513   sym_link *retype = getSpec (operandType (right));
11514   sym_link *letype = getSpec (operandType (result));
11515
11516   aopOp (result, ic, FALSE, FALSE);
11517
11518   /* if the operand is already in dptr
11519      then we do nothing else we move the value to dptr */
11520   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11521     {
11522       /* if this is remateriazable */
11523       if (AOP_TYPE (result) == AOP_IMMD)
11524         emitcode ("mov", "dptr,%s",
11525                   aopGet (result, 0, TRUE, FALSE, NULL));
11526       else
11527         {
11528           /* we need to get it byte by byte */
11529           _startLazyDPSEvaluation ();
11530           if (AOP_TYPE (result) != AOP_DPTR)
11531             {
11532               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11533               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11534               if (options.model == MODEL_FLAT24)
11535                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11536             }
11537           else
11538             {
11539               /* We need to generate a load to DPTR indirect through DPTR. */
11540               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11541
11542               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11543               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11544               if (options.model == MODEL_FLAT24)
11545                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11546               emitcode ("pop", "dph");
11547               emitcode ("pop", "dpl");
11548               dopi=0;
11549             }
11550           _endLazyDPSEvaluation ();
11551         }
11552     }
11553   /* so dptr now contains the address */
11554   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11555
11556   /* if bit then unpack */
11557   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11558   {
11559       if (AOP_INDPTRn(result)) {
11560           genSetDPTR(AOP(result)->aopu.dptr);
11561       }
11562       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11563       if (AOP_INDPTRn(result)) {
11564           genSetDPTR(0);
11565       }
11566   } else {
11567       size = AOP_SIZE (right);
11568       offset = 0;
11569       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11570           while (size--) {
11571               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11572
11573               genSetDPTR(AOP(result)->aopu.dptr);
11574               emitcode ("movx", "@dptr,a");
11575               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11576                   emitcode ("inc", "dptr");
11577               genSetDPTR (0);
11578           }
11579       } else {
11580           _startLazyDPSEvaluation ();
11581           while (size--) {
11582               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11583
11584               if (AOP_INDPTRn(result)) {
11585                   genSetDPTR(AOP(result)->aopu.dptr);
11586               } else {
11587                   genSetDPTR (0);
11588               }
11589               _flushLazyDPS ();
11590
11591               emitcode ("movx", "@dptr,a");
11592               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11593                   emitcode ("inc", "dptr");
11594           }
11595           _endLazyDPSEvaluation ();
11596       }
11597   }
11598
11599   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11600       if (!AOP_INDPTRn(result)) {
11601           _startLazyDPSEvaluation ();
11602
11603           aopPut (result,"dpl",0);
11604           aopPut (result,"dph",1);
11605           if (options.model == MODEL_FLAT24)
11606               aopPut (result,"dpx",2);
11607
11608           _endLazyDPSEvaluation ();
11609       }
11610       pi->generated=1;
11611   } else if (IS_SYMOP (result) &&
11612              (OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11613              AOP_SIZE(right) > 1 &&
11614              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11615
11616       size = AOP_SIZE (right) - 1;
11617       if (AOP_INDPTRn(result)) {
11618           genSetDPTR(AOP(result)->aopu.dptr);
11619       }
11620       while (size--) emitcode ("lcall","__decdptr");
11621       if (AOP_INDPTRn(result)) {
11622           genSetDPTR(0);
11623       }
11624   }
11625   freeAsmop (result, NULL, ic, TRUE);
11626   freeAsmop (right, NULL, ic, TRUE);
11627 }
11628
11629 /*-----------------------------------------------------------------*/
11630 /* genGenPointerSet - set value from generic pointer space         */
11631 /*-----------------------------------------------------------------*/
11632 static void
11633 genGenPointerSet (operand * right,
11634                   operand * result, iCode * ic, iCode *pi)
11635 {
11636   int size, offset;
11637   bool pushedB;
11638   sym_link *retype = getSpec (operandType (right));
11639   sym_link *letype = getSpec (operandType (result));
11640
11641   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11642
11643   pushedB = pushB ();
11644   /* if the operand is already in dptr
11645      then we do nothing else we move the value to dptr */
11646   if (AOP_TYPE (result) != AOP_STR)
11647     {
11648       _startLazyDPSEvaluation ();
11649       /* if this is remateriazable */
11650       if (AOP_TYPE (result) == AOP_IMMD)
11651         {
11652           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11653           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11654           {
11655               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11656           }
11657           else
11658           {
11659               emitcode ("mov",
11660                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11661           }
11662         }
11663       else
11664         {                       /* we need to get it byte by byte */
11665           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11666           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11667           if (options.model == MODEL_FLAT24) {
11668             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11669             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11670           } else {
11671             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11672           }
11673         }
11674       _endLazyDPSEvaluation ();
11675     }
11676   /* so dptr + b now contains the address */
11677   aopOp (right, ic, FALSE, TRUE);
11678
11679   /* if bit then unpack */
11680   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11681     {
11682         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11683     }
11684   else
11685     {
11686         size = AOP_SIZE (right);
11687         offset = 0;
11688
11689         _startLazyDPSEvaluation ();
11690         while (size--)
11691         {
11692             if (size)
11693             {
11694                 // Set two bytes at a time, passed in _AP & A.
11695                 // dptr will be incremented ONCE by __gptrputWord.
11696                 //
11697                 // Note: any change here must be coordinated
11698                 // with the implementation of __gptrputWord
11699                 // in device/lib/_gptrput.c
11700                 emitcode("mov", "_ap, %s",
11701                          aopGet (right, offset++, FALSE, FALSE, NULL));
11702                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11703
11704                 genSetDPTR (0);
11705                 _flushLazyDPS ();
11706                 emitcode ("lcall", "__gptrputWord");
11707                 size--;
11708             }
11709             else
11710             {
11711                 // Only one byte to put.
11712                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11713
11714                 genSetDPTR (0);
11715                 _flushLazyDPS ();
11716                 emitcode ("lcall", "__gptrput");
11717             }
11718
11719             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11720             {
11721                 emitcode ("inc", "dptr");
11722             }
11723         }
11724         _endLazyDPSEvaluation ();
11725     }
11726
11727   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11728       _startLazyDPSEvaluation ();
11729
11730       aopPut (result, "dpl",0);
11731       aopPut (result, "dph",1);
11732       if (options.model == MODEL_FLAT24) {
11733           aopPut (result, "dpx",2);
11734           aopPut (result, "b",3);
11735       } else {
11736           aopPut (result, "b",2);
11737       }
11738       _endLazyDPSEvaluation ();
11739
11740       pi->generated=1;
11741   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11742              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11743
11744       size = AOP_SIZE (right) - 1;
11745       while (size--) emitcode ("lcall","__decdptr");
11746   }
11747   popB (pushedB);
11748
11749   freeAsmop (result, NULL, ic, TRUE);
11750   freeAsmop (right, NULL, ic, TRUE);
11751 }
11752
11753 /*-----------------------------------------------------------------*/
11754 /* genPointerSet - stores the value into a pointer location        */
11755 /*-----------------------------------------------------------------*/
11756 static void
11757 genPointerSet (iCode * ic, iCode *pi)
11758 {
11759   operand *right, *result;
11760   sym_link *type, *etype;
11761   int p_type;
11762
11763   D (emitcode (";", "genPointerSet"));
11764
11765   right = IC_RIGHT (ic);
11766   result = IC_RESULT (ic);
11767
11768   /* depending on the type of pointer we need to
11769      move it to the correct pointer register */
11770   type = operandType (result);
11771   etype = getSpec (type);
11772   /* if left is of type of pointer then it is simple */
11773   if (IS_PTR (type) && !IS_FUNC (type->next))
11774     {
11775       p_type = DCL_TYPE (type);
11776     }
11777   else
11778     {
11779       /* we have to go by the storage class */
11780       p_type = PTR_TYPE (SPEC_OCLS (etype));
11781     }
11782
11783   /* special case when cast remat */
11784   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11785       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11786           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11787           type = operandType (result);
11788           p_type = DCL_TYPE (type);
11789   }
11790
11791   /* now that we have the pointer type we assign
11792      the pointer values */
11793   switch (p_type)
11794     {
11795
11796     case POINTER:
11797     case IPOINTER:
11798       genNearPointerSet (right, result, ic, pi);
11799       break;
11800
11801     case PPOINTER:
11802       genPagedPointerSet (right, result, ic, pi);
11803       break;
11804
11805     case FPOINTER:
11806       genFarPointerSet (right, result, ic, pi);
11807       break;
11808
11809     case GPOINTER:
11810       genGenPointerSet (right, result, ic, pi);
11811       break;
11812
11813     default:
11814       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11815               "genPointerSet: illegal pointer type");
11816     }
11817 }
11818
11819 /*-----------------------------------------------------------------*/
11820 /* genIfx - generate code for Ifx statement                        */
11821 /*-----------------------------------------------------------------*/
11822 static void
11823 genIfx (iCode * ic, iCode * popIc)
11824 {
11825   operand *cond = IC_COND (ic);
11826   int isbit = 0;
11827   char *dup = NULL;
11828
11829   D (emitcode (";", "genIfx"));
11830
11831   aopOp (cond, ic, FALSE, FALSE);
11832
11833   /* get the value into acc */
11834   if (AOP_TYPE (cond) != AOP_CRY)
11835     {
11836       toBoolean (cond);
11837     }
11838   else
11839     {
11840       isbit = 1;
11841       if (AOP(cond)->aopu.aop_dir)
11842         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11843     }
11844
11845   /* the result is now in the accumulator or a directly addressable bit */
11846   freeAsmop (cond, NULL, ic, TRUE);
11847
11848   /* if there was something to be popped then do it */
11849   if (popIc)
11850     genIpop (popIc);
11851
11852   /* if the condition is a bit variable */
11853   if (isbit && dup)
11854     genIfxJump (ic, dup);
11855   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11856     genIfxJump (ic, SPIL_LOC (cond)->rname);
11857   else if (isbit && !IS_ITEMP (cond))
11858     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11859   else
11860     genIfxJump (ic, "a");
11861
11862   ic->generated = 1;
11863 }
11864
11865 /*-----------------------------------------------------------------*/
11866 /* genAddrOf - generates code for address of                       */
11867 /*-----------------------------------------------------------------*/
11868 static void
11869 genAddrOf (iCode * ic)
11870 {
11871   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11872   int size, offset;
11873
11874   D (emitcode (";", "genAddrOf"));
11875
11876   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11877
11878   /* if the operand is on the stack then we
11879      need to get the stack offset of this
11880      variable */
11881   if (sym->onStack)
11882   {
11883
11884       /* if 10 bit stack */
11885       if (options.stack10bit) {
11886           char buff[10];
11887           int  offset;
11888
11889           tsprintf(buff, sizeof(buff),
11890                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11891           /* if it has an offset then we need to compute it */
11892 /*        emitcode ("subb", "a,#!constbyte", */
11893 /*                  -((sym->stack < 0) ? */
11894 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11895 /*                    ((short) sym->stack)) & 0xff); */
11896 /*        emitcode ("mov","b,a"); */
11897 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11898 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11899 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11900           if (sym->stack) {
11901               emitcode ("mov", "a,_bpx");
11902               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11903                                              ((char) (sym->stack - _G.nRegsSaved)) :
11904                                              ((char) sym->stack )) & 0xff);
11905               emitcode ("mov", "b,a");
11906               emitcode ("mov", "a,_bpx+1");
11907
11908               offset = (((sym->stack < 0) ?
11909                          ((short) (sym->stack - _G.nRegsSaved)) :
11910                          ((short) sym->stack )) >> 8) & 0xff;
11911
11912               emitcode ("addc","a,#!constbyte", offset);
11913
11914               aopPut (IC_RESULT (ic), "b", 0);
11915               aopPut (IC_RESULT (ic), "a", 1);
11916               aopPut (IC_RESULT (ic), buff, 2);
11917           } else {
11918               /* we can just move _bp */
11919               aopPut (IC_RESULT (ic), "_bpx", 0);
11920               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11921               aopPut (IC_RESULT (ic), buff, 2);
11922           }
11923       } else {
11924           /* if it has an offset then we need to compute it */
11925           if (sym->stack)
11926             {
11927               emitcode ("mov", "a,_bp");
11928               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11929               aopPut (IC_RESULT (ic), "a", 0);
11930             }
11931           else
11932             {
11933               /* we can just move _bp */
11934               aopPut (IC_RESULT (ic), "_bp", 0);
11935             }
11936           /* fill the result with zero */
11937           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11938
11939
11940           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11941               fprintf (stderr,
11942                        "*** warning: pointer to stack var truncated.\n");
11943           }
11944
11945           offset = 1;
11946           while (size--)
11947             {
11948               aopPut (IC_RESULT (ic), zero, offset++);
11949             }
11950       }
11951       goto release;
11952   }
11953
11954   /* object not on stack then we need the name */
11955   size = AOP_SIZE (IC_RESULT (ic));
11956   offset = 0;
11957
11958   while (size--)
11959     {
11960       char s[SDCC_NAME_MAX];
11961       if (offset) {
11962           switch (offset) {
11963           case 1:
11964               tsprintf(s, sizeof(s), "#!his",sym->rname);
11965               break;
11966           case 2:
11967               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11968               break;
11969           case 3:
11970               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11971               break;
11972           default: /* should not need this (just in case) */
11973               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11974                        sym->rname,
11975                        offset * 8);
11976           }
11977       }
11978       else
11979       {
11980           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11981       }
11982
11983       aopPut (IC_RESULT (ic), s, offset++);
11984     }
11985
11986 release:
11987   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11988
11989 }
11990
11991 #if 0 // obsolete, and buggy for != xdata
11992 /*-----------------------------------------------------------------*/
11993 /* genArrayInit - generates code for address of                       */
11994 /*-----------------------------------------------------------------*/
11995 static void
11996 genArrayInit (iCode * ic)
11997 {
11998     literalList *iLoop;
11999     int         ix, count;
12000     int         elementSize = 0, eIndex;
12001     unsigned    val, lastVal;
12002     sym_link    *type;
12003     operand     *left=IC_LEFT(ic);
12004
12005     D (emitcode (";", "genArrayInit"));
12006
12007     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
12008
12009     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
12010     {
12011         // Load immediate value into DPTR.
12012         emitcode("mov", "dptr, %s",
12013              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
12014     }
12015     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
12016     {
12017 #if 0
12018       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12019               "Unexpected operand to genArrayInit.\n");
12020       exit(1);
12021 #else
12022       // a regression because of SDCCcse.c:1.52
12023       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
12024       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
12025       if (options.model == MODEL_FLAT24)
12026         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
12027 #endif
12028     }
12029
12030     type = operandType(IC_LEFT(ic));
12031
12032     if (type && type->next)
12033     {
12034         elementSize = getSize(type->next);
12035     }
12036     else
12037     {
12038         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12039                                 "can't determine element size in genArrayInit.\n");
12040         exit(1);
12041     }
12042
12043     iLoop = IC_ARRAYILIST(ic);
12044     lastVal = 0xffff;
12045
12046     while (iLoop)
12047     {
12048         bool firstpass = TRUE;
12049
12050         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12051                  iLoop->count, (int)iLoop->literalValue, elementSize);
12052
12053         ix = iLoop->count;
12054
12055         while (ix)
12056         {
12057             symbol *tlbl = NULL;
12058
12059             count = ix > 256 ? 256 : ix;
12060
12061             if (count > 1)
12062             {
12063                 tlbl = newiTempLabel (NULL);
12064                 if (firstpass || (count & 0xff))
12065                 {
12066                     emitcode("mov", "b, #!constbyte", count & 0xff);
12067                 }
12068
12069                 emitLabel (tlbl);
12070             }
12071
12072             firstpass = FALSE;
12073
12074             for (eIndex = 0; eIndex < elementSize; eIndex++)
12075             {
12076                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12077                 if (val != lastVal)
12078                 {
12079                     emitcode("mov", "a, #!constbyte", val);
12080                     lastVal = val;
12081                 }
12082
12083                 emitcode("movx", "@dptr, a");
12084                 emitcode("inc", "dptr");
12085             }
12086
12087             if (count > 1)
12088             {
12089                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12090             }
12091
12092             ix -= count;
12093         }
12094
12095         iLoop = iLoop->next;
12096     }
12097
12098     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12099 }
12100 #endif
12101
12102 /*-----------------------------------------------------------------*/
12103 /* genFarFarAssign - assignment when both are in far space         */
12104 /*-----------------------------------------------------------------*/
12105 static void
12106 genFarFarAssign (operand * result, operand * right, iCode * ic)
12107 {
12108   int size = AOP_SIZE (right);
12109   int offset = 0;
12110   symbol *rSym = NULL;
12111
12112   if (size == 1)
12113   {
12114       /* quick & easy case. */
12115       D (emitcode(";","genFarFarAssign (1 byte case)"));
12116       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12117       freeAsmop (right, NULL, ic, FALSE);
12118       /* now assign DPTR to result */
12119       _G.accInUse++;
12120       aopOp(result, ic, FALSE, FALSE);
12121       _G.accInUse--;
12122       aopPut (result, "a", 0);
12123       freeAsmop(result, NULL, ic, FALSE);
12124       return;
12125   }
12126
12127   /* See if we've got an underlying symbol to abuse. */
12128   if (IS_SYMOP(result) && OP_SYMBOL(result))
12129   {
12130       if (IS_TRUE_SYMOP(result))
12131       {
12132           rSym = OP_SYMBOL(result);
12133       }
12134       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12135       {
12136           rSym = OP_SYMBOL(result)->usl.spillLoc;
12137       }
12138   }
12139
12140   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12141   {
12142       /* We can use the '390 auto-toggle feature to good effect here. */
12143
12144       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12145       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12146       emitcode ("mov", "dptr,#%s", rSym->rname);
12147       /* DP2 = result, DP1 = right, DP1 is current. */
12148       while (size)
12149       {
12150           emitcode("movx", "a,@dptr");
12151           emitcode("movx", "@dptr,a");
12152           if (--size)
12153           {
12154                emitcode("inc", "dptr");
12155                emitcode("inc", "dptr");
12156           }
12157       }
12158       emitcode("mov", "dps,#0");
12159       freeAsmop (right, NULL, ic, FALSE);
12160 #if 0
12161 some alternative code for processors without auto-toggle
12162 no time to test now, so later well put in...kpb
12163         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12164         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12165         emitcode ("mov", "dptr,#%s", rSym->rname);
12166         /* DP2 = result, DP1 = right, DP1 is current. */
12167         while (size)
12168         {
12169           --size;
12170           emitcode("movx", "a,@dptr");
12171           if (size)
12172             emitcode("inc", "dptr");
12173           emitcode("inc", "dps");
12174           emitcode("movx", "@dptr,a");
12175           if (size)
12176             emitcode("inc", "dptr");
12177           emitcode("inc", "dps");
12178         }
12179         emitcode("mov", "dps,#0");
12180         freeAsmop (right, NULL, ic, FALSE);
12181 #endif
12182   }
12183   else
12184   {
12185       D (emitcode (";", "genFarFarAssign"));
12186       aopOp (result, ic, TRUE, TRUE);
12187
12188       _startLazyDPSEvaluation ();
12189
12190       while (size--)
12191         {
12192           aopPut (result,
12193                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12194           offset++;
12195         }
12196       _endLazyDPSEvaluation ();
12197       freeAsmop (result, NULL, ic, FALSE);
12198       freeAsmop (right, NULL, ic, FALSE);
12199   }
12200 }
12201
12202 /*-----------------------------------------------------------------*/
12203 /* genAssign - generate code for assignment                        */
12204 /*-----------------------------------------------------------------*/
12205 static void
12206 genAssign (iCode * ic)
12207 {
12208   operand *result, *right;
12209   int size, offset;
12210   unsigned long lit = 0L;
12211
12212   D (emitcode (";", "genAssign"));
12213
12214   result = IC_RESULT (ic);
12215   right = IC_RIGHT (ic);
12216
12217   /* if they are the same */
12218   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12219     return;
12220
12221   aopOp (right, ic, FALSE, FALSE);
12222
12223   emitcode (";", "genAssign: resultIsFar = %s",
12224             isOperandInFarSpace (result) ?
12225             "TRUE" : "FALSE");
12226
12227   /* special case both in far space */
12228   if ((AOP_TYPE (right) == AOP_DPTR ||
12229        AOP_TYPE (right) == AOP_DPTR2) &&
12230   /* IS_TRUE_SYMOP(result)       && */
12231       isOperandInFarSpace (result))
12232     {
12233       genFarFarAssign (result, right, ic);
12234       return;
12235     }
12236
12237   aopOp (result, ic, TRUE, FALSE);
12238
12239   /* if they are the same registers */
12240   if (sameRegs (AOP (right), AOP (result)))
12241     goto release;
12242
12243   /* if the result is a bit */
12244   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12245     {
12246       /* if the right size is a literal then
12247          we know what the value is */
12248       if (AOP_TYPE (right) == AOP_LIT)
12249         {
12250           if (((int) operandLitValue (right)))
12251             aopPut (result, one, 0);
12252           else
12253             aopPut (result, zero, 0);
12254           goto release;
12255         }
12256
12257       /* the right is also a bit variable */
12258       if (AOP_TYPE (right) == AOP_CRY)
12259         {
12260           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12261           aopPut (result, "c", 0);
12262           goto release;
12263         }
12264
12265       /* we need to or */
12266       toBoolean (right);
12267       aopPut (result, "a", 0);
12268       goto release;
12269     }
12270
12271   /* bit variables done */
12272   /* general case */
12273   size = AOP_SIZE (result);
12274   offset = 0;
12275   if (AOP_TYPE (right) == AOP_LIT)
12276     lit = ulFromVal (AOP (right)->aopu.aop_lit);
12277
12278   if ((size > 1) &&
12279       (AOP_TYPE (result) != AOP_REG) &&
12280       (AOP_TYPE (right) == AOP_LIT) &&
12281       !IS_FLOAT (operandType (right)))
12282     {
12283       _startLazyDPSEvaluation ();
12284       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12285         {
12286           aopPut (result,
12287                   aopGet (right, offset, FALSE, FALSE, NULL),
12288                   offset);
12289           offset++;
12290           size--;
12291         }
12292       /* And now fill the rest with zeros. */
12293       if (size)
12294         {
12295           emitcode ("clr", "a");
12296         }
12297       while (size--)
12298         {
12299           aopPut (result, "a", offset++);
12300         }
12301       _endLazyDPSEvaluation ();
12302     }
12303   else
12304     {
12305       _startLazyDPSEvaluation ();
12306       while (size--)
12307         {
12308           aopPut (result,
12309                   aopGet (right, offset, FALSE, FALSE, NULL),
12310                   offset);
12311           offset++;
12312         }
12313       _endLazyDPSEvaluation ();
12314     }
12315
12316 release:
12317   freeAsmop (result, NULL, ic, TRUE);
12318   freeAsmop (right, NULL, ic, TRUE);
12319 }
12320
12321 /*-----------------------------------------------------------------*/
12322 /* genJumpTab - generates code for jump table                      */
12323 /*-----------------------------------------------------------------*/
12324 static void
12325 genJumpTab (iCode * ic)
12326 {
12327   symbol *jtab;
12328   char *l;
12329
12330   D (emitcode (";", "genJumpTab"));
12331
12332   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12333   /* get the condition into accumulator */
12334   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12335   MOVA (l);
12336   /* multiply by four! */
12337   emitcode ("add", "a,acc");
12338   emitcode ("add", "a,acc");
12339   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12340
12341   jtab = newiTempLabel (NULL);
12342   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12343   emitcode ("jmp", "@a+dptr");
12344   emitLabel (jtab);
12345   /* now generate the jump labels */
12346   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12347        jtab = setNextItem (IC_JTLABELS (ic)))
12348     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12349
12350 }
12351
12352 /*-----------------------------------------------------------------*/
12353 /* genCast - gen code for casting                                  */
12354 /*-----------------------------------------------------------------*/
12355 static void
12356 genCast (iCode * ic)
12357 {
12358   operand *result = IC_RESULT (ic);
12359   sym_link *ctype = operandType (IC_LEFT (ic));
12360   sym_link *rtype = operandType (IC_RIGHT (ic));
12361   operand *right = IC_RIGHT (ic);
12362   int size, offset;
12363
12364   D (emitcode (";", "genCast"));
12365
12366   /* if they are equivalent then do nothing */
12367   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12368     return;
12369
12370   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12371   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12372
12373   /* if the result is a bit (and not a bitfield) */
12374   if (IS_BIT (OP_SYMBOL (result)->type))
12375     {
12376       /* if the right size is a literal then
12377          we know what the value is */
12378       if (AOP_TYPE (right) == AOP_LIT)
12379         {
12380           if (((int) operandLitValue (right)))
12381             aopPut (result, one, 0);
12382           else
12383             aopPut (result, zero, 0);
12384
12385           goto release;
12386         }
12387
12388       /* the right is also a bit variable */
12389       if (AOP_TYPE (right) == AOP_CRY)
12390         {
12391           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12392           aopPut (result, "c", 0);
12393           goto release;
12394         }
12395
12396       /* we need to or */
12397       toBoolean (right);
12398       aopPut (result, "a", 0);
12399       goto release;
12400     }
12401
12402   /* if they are the same size : or less */
12403   if (AOP_SIZE (result) <= AOP_SIZE (right))
12404     {
12405
12406       /* if they are in the same place */
12407       if (sameRegs (AOP (right), AOP (result)))
12408         goto release;
12409
12410       /* if they in different places then copy */
12411       size = AOP_SIZE (result);
12412       offset = 0;
12413       _startLazyDPSEvaluation ();
12414       while (size--)
12415         {
12416           aopPut (result,
12417                   aopGet (right, offset, FALSE, FALSE, NULL),
12418                   offset);
12419           offset++;
12420         }
12421       _endLazyDPSEvaluation ();
12422       goto release;
12423     }
12424
12425   /* if the result is of type pointer */
12426   if (IS_PTR (ctype))
12427     {
12428
12429       int p_type;
12430       sym_link *type = operandType (right);
12431
12432       /* pointer to generic pointer */
12433       if (IS_GENPTR (ctype))
12434         {
12435           if (IS_PTR (type))
12436             {
12437               p_type = DCL_TYPE (type);
12438             }
12439           else
12440             {
12441 #if OLD_CAST_BEHAVIOR
12442               /* KV: we are converting a non-pointer type to
12443                * a generic pointer. This (ifdef'd out) code
12444                * says that the resulting generic pointer
12445                * should have the same class as the storage
12446                * location of the non-pointer variable.
12447                *
12448                * For example, converting an int (which happens
12449                * to be stored in DATA space) to a pointer results
12450                * in a DATA generic pointer; if the original int
12451                * in XDATA space, so will be the resulting pointer.
12452                *
12453                * I don't like that behavior, and thus this change:
12454                * all such conversions will be forced to XDATA and
12455                * throw a warning. If you want some non-XDATA
12456                * type, or you want to suppress the warning, you
12457                * must go through an intermediate cast, like so:
12458                *
12459                * char _generic *gp = (char _xdata *)(intVar);
12460                */
12461               sym_link *etype = getSpec (type);
12462
12463               /* we have to go by the storage class */
12464               if (SPEC_OCLS (etype) != generic)
12465                 {
12466                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12467                 }
12468               else
12469 #endif
12470                 {
12471                   /* Converting unknown class (i.e. register variable)
12472                    * to generic pointer. This is not good, but
12473                    * we'll make a guess (and throw a warning).
12474                    */
12475                   p_type = FPOINTER;
12476                   werror (W_INT_TO_GEN_PTR_CAST);
12477                 }
12478             }
12479
12480           /* the first two bytes are known */
12481           size = GPTRSIZE - 1;
12482           offset = 0;
12483           _startLazyDPSEvaluation ();
12484           while (size--)
12485             {
12486               aopPut (result,
12487                       aopGet (right, offset, FALSE, FALSE, NULL),
12488                       offset);
12489               offset++;
12490             }
12491           _endLazyDPSEvaluation ();
12492
12493           /* the last byte depending on type */
12494             {
12495                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12496                 char gpValStr[10];
12497
12498                 if (gpVal == -1)
12499                 {
12500                     // pointerTypeToGPByte will have bitched.
12501                     exit(1);
12502                 }
12503
12504                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12505                 aopPut (result, gpValStr, GPTRSIZE - 1);
12506             }
12507           goto release;
12508         }
12509
12510       /* just copy the pointers */
12511       size = AOP_SIZE (result);
12512       offset = 0;
12513       _startLazyDPSEvaluation ();
12514       while (size--)
12515         {
12516           aopPut (result,
12517                   aopGet (right, offset, FALSE, FALSE, NULL),
12518                   offset);
12519           offset++;
12520         }
12521       _endLazyDPSEvaluation ();
12522       goto release;
12523     }
12524
12525   /* so we now know that the size of destination is greater
12526      than the size of the source */
12527   /* we move to result for the size of source */
12528   size = AOP_SIZE (right);
12529   offset = 0;
12530   _startLazyDPSEvaluation ();
12531   while (size--)
12532     {
12533       aopPut (result,
12534               aopGet (right, offset, FALSE, FALSE, NULL),
12535               offset);
12536       offset++;
12537     }
12538   _endLazyDPSEvaluation ();
12539
12540   /* now depending on the sign of the source && destination */
12541   size = AOP_SIZE (result) - AOP_SIZE (right);
12542   /* if unsigned or not an integral type */
12543   /* also, if the source is a bit, we don't need to sign extend, because
12544    * it can't possibly have set the sign bit.
12545    */
12546   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12547     {
12548       while (size--)
12549         {
12550           aopPut (result, zero, offset++);
12551         }
12552     }
12553   else
12554     {
12555       /* we need to extend the sign :{ */
12556       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12557                         FALSE, FALSE, NULL));
12558       emitcode ("rlc", "a");
12559       emitcode ("subb", "a,acc");
12560       while (size--)
12561         aopPut (result, "a", offset++);
12562     }
12563
12564   /* we are done hurray !!!! */
12565
12566 release:
12567   freeAsmop (right, NULL, ic, TRUE);
12568   freeAsmop (result, NULL, ic, TRUE);
12569
12570 }
12571
12572 /*-----------------------------------------------------------------*/
12573 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12574 /*-----------------------------------------------------------------*/
12575 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12576 {
12577     operand *from , *to , *count;
12578     symbol *lbl;
12579     bitVect *rsave;
12580     int i;
12581
12582     /* we know it has to be 3 parameters */
12583     assert (nparms == 3);
12584
12585     rsave = newBitVect(16);
12586     /* save DPTR if it needs to be saved */
12587     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12588             if (bitVectBitValue(ic->rMask,i))
12589                     rsave = bitVectSetBit(rsave,i);
12590     }
12591     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12592                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12593     savermask(rsave);
12594
12595     to = parms[0];
12596     from = parms[1];
12597     count = parms[2];
12598
12599     aopOp (from, ic->next, FALSE, FALSE);
12600
12601     /* get from into DPTR1 */
12602     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12603     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12604     if (options.model == MODEL_FLAT24) {
12605         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12606     }
12607
12608     freeAsmop (from, NULL, ic, FALSE);
12609     aopOp (to, ic, FALSE, FALSE);
12610     /* get "to" into DPTR */
12611     /* if the operand is already in dptr
12612        then we do nothing else we move the value to dptr */
12613     if (AOP_TYPE (to) != AOP_STR) {
12614         /* if already in DPTR then we need to push */
12615         if (AOP_TYPE(to) == AOP_DPTR) {
12616             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12617             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12618             if (options.model == MODEL_FLAT24)
12619                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12620             emitcode ("pop", "dph");
12621             emitcode ("pop", "dpl");
12622         } else {
12623             _startLazyDPSEvaluation ();
12624             /* if this is remateriazable */
12625             if (AOP_TYPE (to) == AOP_IMMD) {
12626                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12627             } else {                    /* we need to get it byte by byte */
12628                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12629                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12630                 if (options.model == MODEL_FLAT24) {
12631                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12632                 }
12633             }
12634             _endLazyDPSEvaluation ();
12635         }
12636     }
12637     freeAsmop (to, NULL, ic, FALSE);
12638     _G.dptrInUse = _G.dptr1InUse = 1;
12639     aopOp (count, ic->next->next, FALSE,FALSE);
12640     lbl =newiTempLabel(NULL);
12641
12642     /* now for the actual copy */
12643     if (AOP_TYPE(count) == AOP_LIT &&
12644         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12645         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12646         if (fromc) {
12647             emitcode ("lcall","__bi_memcpyc2x_s");
12648         } else {
12649             emitcode ("lcall","__bi_memcpyx2x_s");
12650         }
12651         freeAsmop (count, NULL, ic, FALSE);
12652     } else {
12653         symbol *lbl1 = newiTempLabel(NULL);
12654
12655         emitcode (";"," Auto increment but no djnz");
12656         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12657         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12658         freeAsmop (count, NULL, ic, FALSE);
12659         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12660         emitLabel (lbl);
12661         if (fromc) {
12662             emitcode ("clr","a");
12663             emitcode ("movc", "a,@a+dptr");
12664         } else
12665             emitcode ("movx", "a,@dptr");
12666         emitcode ("movx", "@dptr,a");
12667         emitcode ("inc", "dptr");
12668         emitcode ("inc", "dptr");
12669         emitcode ("mov","a,b");
12670         emitcode ("orl","a,_ap");
12671         emitcode ("jz","!tlabel",lbl1->key+100);
12672         emitcode ("mov","a,_ap");
12673         emitcode ("add","a,#!constbyte",0xFF);
12674         emitcode ("mov","_ap,a");
12675         emitcode ("mov","a,b");
12676         emitcode ("addc","a,#!constbyte",0xFF);
12677         emitcode ("mov","b,a");
12678         emitcode ("sjmp","!tlabel",lbl->key+100);
12679         emitLabel (lbl1);
12680     }
12681     emitcode ("mov", "dps,#0");
12682     _G.dptrInUse = _G.dptr1InUse = 0;
12683     unsavermask(rsave);
12684
12685 }
12686
12687 /*-----------------------------------------------------------------*/
12688 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12689 /*-----------------------------------------------------------------*/
12690 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12691 {
12692     operand *from , *to , *count;
12693     symbol *lbl,*lbl2;
12694     bitVect *rsave;
12695     int i;
12696
12697     /* we know it has to be 3 parameters */
12698     assert (nparms == 3);
12699
12700     rsave = newBitVect(16);
12701     /* save DPTR if it needs to be saved */
12702     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12703             if (bitVectBitValue(ic->rMask,i))
12704                     rsave = bitVectSetBit(rsave,i);
12705     }
12706     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12707                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12708     savermask(rsave);
12709
12710     to = parms[0];
12711     from = parms[1];
12712     count = parms[2];
12713
12714     aopOp (from, ic->next, FALSE, FALSE);
12715
12716     /* get from into DPTR1 */
12717     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12718     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12719     if (options.model == MODEL_FLAT24) {
12720         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12721     }
12722
12723     freeAsmop (from, NULL, ic, FALSE);
12724     aopOp (to, ic, FALSE, FALSE);
12725     /* get "to" into DPTR */
12726     /* if the operand is already in dptr
12727        then we do nothing else we move the value to dptr */
12728     if (AOP_TYPE (to) != AOP_STR) {
12729         /* if already in DPTR then we need to push */
12730         if (AOP_TYPE(to) == AOP_DPTR) {
12731             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12732             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12733             if (options.model == MODEL_FLAT24)
12734                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12735             emitcode ("pop", "dph");
12736             emitcode ("pop", "dpl");
12737         } else {
12738             _startLazyDPSEvaluation ();
12739             /* if this is remateriazable */
12740             if (AOP_TYPE (to) == AOP_IMMD) {
12741                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12742             } else {                    /* we need to get it byte by byte */
12743                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12744                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12745                 if (options.model == MODEL_FLAT24) {
12746                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12747                 }
12748             }
12749             _endLazyDPSEvaluation ();
12750         }
12751     }
12752     freeAsmop (to, NULL, ic, FALSE);
12753     _G.dptrInUse = _G.dptr1InUse = 1;
12754     aopOp (count, ic->next->next, FALSE,FALSE);
12755     lbl =newiTempLabel(NULL);
12756     lbl2 =newiTempLabel(NULL);
12757
12758     /* now for the actual compare */
12759     if (AOP_TYPE(count) == AOP_LIT &&
12760         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12761         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12762         if (fromc)
12763             emitcode("lcall","__bi_memcmpc2x_s");
12764         else
12765             emitcode("lcall","__bi_memcmpx2x_s");
12766         freeAsmop (count, NULL, ic, FALSE);
12767         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12768         aopPut(IC_RESULT(ic),"a",0);
12769         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12770     } else {
12771         symbol *lbl1 = newiTempLabel(NULL);
12772
12773         emitcode("push","ar0");
12774         emitcode (";"," Auto increment but no djnz");
12775         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12776         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12777         freeAsmop (count, NULL, ic, FALSE);
12778         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12779         emitLabel (lbl);
12780         if (fromc) {
12781             emitcode ("clr","a");
12782             emitcode ("movc", "a,@a+dptr");
12783         } else
12784             emitcode ("movx", "a,@dptr");
12785         emitcode ("mov","r0,a");
12786         emitcode ("movx", "a,@dptr");
12787         emitcode ("clr","c");
12788         emitcode ("subb","a,r0");
12789         emitcode ("jnz","!tlabel",lbl2->key+100);
12790         emitcode ("inc", "dptr");
12791         emitcode ("inc", "dptr");
12792         emitcode ("mov","a,b");
12793         emitcode ("orl","a,_ap");
12794         emitcode ("jz","!tlabel",lbl1->key+100);
12795         emitcode ("mov","a,_ap");
12796         emitcode ("add","a,#!constbyte",0xFF);
12797         emitcode ("mov","_ap,a");
12798         emitcode ("mov","a,b");
12799         emitcode ("addc","a,#!constbyte",0xFF);
12800         emitcode ("mov","b,a");
12801         emitcode ("sjmp","!tlabel",lbl->key+100);
12802         emitLabel (lbl1);
12803         emitcode ("clr","a");
12804         emitLabel (lbl2);
12805         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12806         aopPut(IC_RESULT(ic),"a",0);
12807         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12808         emitcode("pop","ar0");
12809         emitcode ("mov", "dps,#0");
12810     }
12811     _G.dptrInUse = _G.dptr1InUse = 0;
12812     unsavermask(rsave);
12813
12814 }
12815
12816 /*-----------------------------------------------------------------*/
12817 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12818 /* port, first parameter output area second parameter pointer to   */
12819 /* port third parameter count                                      */
12820 /*-----------------------------------------------------------------*/
12821 static void genInp( iCode *ic, int nparms, operand **parms)
12822 {
12823     operand *from , *to , *count;
12824     symbol *lbl;
12825     bitVect *rsave;
12826     int i;
12827
12828     /* we know it has to be 3 parameters */
12829     assert (nparms == 3);
12830
12831     rsave = newBitVect(16);
12832     /* save DPTR if it needs to be saved */
12833     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12834             if (bitVectBitValue(ic->rMask,i))
12835                     rsave = bitVectSetBit(rsave,i);
12836     }
12837     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12838                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12839     savermask(rsave);
12840
12841     to = parms[0];
12842     from = parms[1];
12843     count = parms[2];
12844
12845     aopOp (from, ic->next, FALSE, FALSE);
12846
12847     /* get from into DPTR1 */
12848     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12849     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12850     if (options.model == MODEL_FLAT24) {
12851         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12852     }
12853
12854     freeAsmop (from, NULL, ic, FALSE);
12855     aopOp (to, ic, FALSE, FALSE);
12856     /* get "to" into DPTR */
12857     /* if the operand is already in dptr
12858        then we do nothing else we move the value to dptr */
12859     if (AOP_TYPE (to) != AOP_STR) {
12860         /* if already in DPTR then we need to push */
12861         if (AOP_TYPE(to) == AOP_DPTR) {
12862             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12863             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12864             if (options.model == MODEL_FLAT24)
12865                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12866             emitcode ("pop", "dph");
12867             emitcode ("pop", "dpl");
12868         } else {
12869             _startLazyDPSEvaluation ();
12870             /* if this is remateriazable */
12871             if (AOP_TYPE (to) == AOP_IMMD) {
12872                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12873             } else {                    /* we need to get it byte by byte */
12874                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12875                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12876                 if (options.model == MODEL_FLAT24) {
12877                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12878                 }
12879             }
12880             _endLazyDPSEvaluation ();
12881         }
12882     }
12883     freeAsmop (to, NULL, ic, FALSE);
12884
12885     _G.dptrInUse = _G.dptr1InUse = 1;
12886     aopOp (count, ic->next->next, FALSE,FALSE);
12887     lbl =newiTempLabel(NULL);
12888
12889     /* now for the actual copy */
12890     if (AOP_TYPE(count) == AOP_LIT &&
12891         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12892         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12893         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12894         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12895         freeAsmop (count, NULL, ic, FALSE);
12896         emitLabel (lbl);
12897         emitcode ("movx", "a,@dptr");   /* read data from port */
12898         emitcode ("dec","dps");         /* switch to DPTR */
12899         emitcode ("movx", "@dptr,a");   /* save into location */
12900         emitcode ("inc", "dptr");       /* point to next area */
12901         emitcode ("inc","dps");         /* switch to DPTR2 */
12902         emitcode ("djnz","b,!tlabel",lbl->key+100);
12903     } else {
12904         symbol *lbl1 = newiTempLabel(NULL);
12905
12906         emitcode (";"," Auto increment but no djnz");
12907         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12908         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12909         freeAsmop (count, NULL, ic, FALSE);
12910         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12911         emitLabel (lbl);
12912         emitcode ("movx", "a,@dptr");
12913         emitcode ("dec","dps");         /* switch to DPTR */
12914         emitcode ("movx", "@dptr,a");
12915         emitcode ("inc", "dptr");
12916         emitcode ("inc","dps");         /* switch to DPTR2 */
12917 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12918 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12919         emitcode ("mov","a,b");
12920         emitcode ("orl","a,_ap");
12921         emitcode ("jz","!tlabel",lbl1->key+100);
12922         emitcode ("mov","a,_ap");
12923         emitcode ("add","a,#!constbyte",0xFF);
12924         emitcode ("mov","_ap,a");
12925         emitcode ("mov","a,b");
12926         emitcode ("addc","a,#!constbyte",0xFF);
12927         emitcode ("mov","b,a");
12928         emitcode ("sjmp","!tlabel",lbl->key+100);
12929         emitLabel (lbl1);
12930     }
12931     emitcode ("mov", "dps,#0");
12932     _G.dptrInUse = _G.dptr1InUse = 0;
12933     unsavermask(rsave);
12934
12935 }
12936
12937 /*-----------------------------------------------------------------*/
12938 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12939 /* port, first parameter output area second parameter pointer to   */
12940 /* port third parameter count                                      */
12941 /*-----------------------------------------------------------------*/
12942 static void genOutp( iCode *ic, int nparms, operand **parms)
12943 {
12944     operand *from , *to , *count;
12945     symbol *lbl;
12946     bitVect *rsave;
12947     int i;
12948
12949     /* we know it has to be 3 parameters */
12950     assert (nparms == 3);
12951
12952     rsave = newBitVect(16);
12953     /* save DPTR if it needs to be saved */
12954     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12955             if (bitVectBitValue(ic->rMask,i))
12956                     rsave = bitVectSetBit(rsave,i);
12957     }
12958     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12959                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12960     savermask(rsave);
12961
12962     to = parms[0];
12963     from = parms[1];
12964     count = parms[2];
12965
12966     aopOp (from, ic->next, FALSE, FALSE);
12967
12968     /* get from into DPTR1 */
12969     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12970     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12971     if (options.model == MODEL_FLAT24) {
12972         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12973     }
12974
12975     freeAsmop (from, NULL, ic, FALSE);
12976     aopOp (to, ic, FALSE, FALSE);
12977     /* get "to" into DPTR */
12978     /* if the operand is already in dptr
12979        then we do nothing else we move the value to dptr */
12980     if (AOP_TYPE (to) != AOP_STR) {
12981         /* if already in DPTR then we need to push */
12982         if (AOP_TYPE(to) == AOP_DPTR) {
12983             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12984             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12985             if (options.model == MODEL_FLAT24)
12986                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12987             emitcode ("pop", "dph");
12988             emitcode ("pop", "dpl");
12989         } else {
12990             _startLazyDPSEvaluation ();
12991             /* if this is remateriazable */
12992             if (AOP_TYPE (to) == AOP_IMMD) {
12993                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12994             } else {                    /* we need to get it byte by byte */
12995                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12996                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12997                 if (options.model == MODEL_FLAT24) {
12998                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12999                 }
13000             }
13001             _endLazyDPSEvaluation ();
13002         }
13003     }
13004     freeAsmop (to, NULL, ic, FALSE);
13005
13006     _G.dptrInUse = _G.dptr1InUse = 1;
13007     aopOp (count, ic->next->next, FALSE,FALSE);
13008     lbl =newiTempLabel(NULL);
13009
13010     /* now for the actual copy */
13011     if (AOP_TYPE(count) == AOP_LIT &&
13012         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13013         emitcode (";","OH  JOY auto increment with djnz (very fast)");
13014         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13015         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13016         emitLabel (lbl);
13017         emitcode ("movx", "a,@dptr");   /* read data from port */
13018         emitcode ("inc","dps");         /* switch to DPTR2 */
13019         emitcode ("movx", "@dptr,a");   /* save into location */
13020         emitcode ("inc", "dptr");       /* point to next area */
13021         emitcode ("dec","dps");         /* switch to DPTR */
13022         emitcode ("djnz","b,!tlabel",lbl->key+100);
13023         freeAsmop (count, NULL, ic, FALSE);
13024     } else {
13025         symbol *lbl1 = newiTempLabel(NULL);
13026
13027         emitcode (";"," Auto increment but no djnz");
13028         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13029         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13030         freeAsmop (count, NULL, ic, FALSE);
13031         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13032         emitLabel (lbl);
13033         emitcode ("movx", "a,@dptr");
13034         emitcode ("inc", "dptr");
13035         emitcode ("inc","dps");         /* switch to DPTR2 */
13036         emitcode ("movx", "@dptr,a");
13037         emitcode ("dec","dps");         /* switch to DPTR */
13038         emitcode ("mov","a,b");
13039         emitcode ("orl","a,_ap");
13040         emitcode ("jz","!tlabel",lbl1->key+100);
13041         emitcode ("mov","a,_ap");
13042         emitcode ("add","a,#!constbyte",0xFF);
13043         emitcode ("mov","_ap,a");
13044         emitcode ("mov","a,b");
13045         emitcode ("addc","a,#!constbyte",0xFF);
13046         emitcode ("mov","b,a");
13047         emitcode ("sjmp","!tlabel",lbl->key+100);
13048         emitLabel (lbl1);
13049     }
13050     emitcode ("mov", "dps,#0");
13051     _G.dptrInUse = _G.dptr1InUse = 0;
13052     unsavermask(rsave);
13053
13054 }
13055
13056 /*-----------------------------------------------------------------*/
13057 /* genSwapW - swap lower & high order bytes                        */
13058 /*-----------------------------------------------------------------*/
13059 static void genSwapW(iCode *ic, int nparms, operand **parms)
13060 {
13061     operand *dest;
13062     operand *src;
13063     assert (nparms==1);
13064
13065     src = parms[0];
13066     dest=IC_RESULT(ic);
13067
13068     assert(getSize(operandType(src))==2);
13069
13070     aopOp (src, ic, FALSE, FALSE);
13071     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13072     _G.accInUse++;
13073     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13074     _G.accInUse--;
13075     freeAsmop (src, NULL, ic, FALSE);
13076
13077     aopOp (dest,ic, FALSE, FALSE);
13078     aopPut(dest,"b",0);
13079     aopPut(dest,"a",1);
13080     freeAsmop (dest, NULL, ic, FALSE);
13081 }
13082
13083 /*-----------------------------------------------------------------*/
13084 /* genMemsetX - gencode for memSetX data                           */
13085 /*-----------------------------------------------------------------*/
13086 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13087 {
13088     operand *to , *val , *count;
13089     symbol *lbl;
13090     char *l;
13091     int i;
13092     bitVect *rsave;
13093
13094     /* we know it has to be 3 parameters */
13095     assert (nparms == 3);
13096
13097     to = parms[0];
13098     val = parms[1];
13099     count = parms[2];
13100
13101     /* save DPTR if it needs to be saved */
13102     rsave = newBitVect(16);
13103     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13104             if (bitVectBitValue(ic->rMask,i))
13105                     rsave = bitVectSetBit(rsave,i);
13106     }
13107     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13108                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13109     savermask(rsave);
13110
13111     aopOp (to, ic, FALSE, FALSE);
13112     /* get "to" into DPTR */
13113     /* if the operand is already in dptr
13114        then we do nothing else we move the value to dptr */
13115     if (AOP_TYPE (to) != AOP_STR) {
13116         /* if already in DPTR then we need to push */
13117         if (AOP_TYPE(to) == AOP_DPTR) {
13118             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13119             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13120             if (options.model == MODEL_FLAT24)
13121                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13122             emitcode ("pop", "dph");
13123             emitcode ("pop", "dpl");
13124         } else {
13125             _startLazyDPSEvaluation ();
13126             /* if this is remateriazable */
13127             if (AOP_TYPE (to) == AOP_IMMD) {
13128                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13129             } else {                    /* we need to get it byte by byte */
13130                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13131                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13132                 if (options.model == MODEL_FLAT24) {
13133                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13134                 }
13135             }
13136             _endLazyDPSEvaluation ();
13137         }
13138     }
13139     freeAsmop (to, NULL, ic, FALSE);
13140
13141     aopOp (val, ic->next->next, FALSE,FALSE);
13142     aopOp (count, ic->next->next, FALSE,FALSE);
13143     lbl =newiTempLabel(NULL);
13144     /* now for the actual copy */
13145     if (AOP_TYPE(count) == AOP_LIT &&
13146         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13147         l = aopGet(val, 0, FALSE, FALSE, NULL);
13148         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13149         MOVA(l);
13150         emitLabel (lbl);
13151         emitcode ("movx", "@dptr,a");
13152         emitcode ("inc", "dptr");
13153         emitcode ("djnz","b,!tlabel",lbl->key+100);
13154     } else {
13155         symbol *lbl1 = newiTempLabel(NULL);
13156
13157         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13158         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13159         emitLabel (lbl);
13160         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13161         emitcode ("movx", "@dptr,a");
13162         emitcode ("inc", "dptr");
13163         emitcode ("mov","a,b");
13164         emitcode ("orl","a,_ap");
13165         emitcode ("jz","!tlabel",lbl1->key+100);
13166         emitcode ("mov","a,_ap");
13167         emitcode ("add","a,#!constbyte",0xFF);
13168         emitcode ("mov","_ap,a");
13169         emitcode ("mov","a,b");
13170         emitcode ("addc","a,#!constbyte",0xFF);
13171         emitcode ("mov","b,a");
13172         emitcode ("sjmp","!tlabel",lbl->key+100);
13173         emitLabel (lbl1);
13174     }
13175     freeAsmop (count, NULL, ic, FALSE);
13176     unsavermask(rsave);
13177 }
13178
13179 /*-----------------------------------------------------------------*/
13180 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13181 /*-----------------------------------------------------------------*/
13182 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13183 {
13184         bitVect *rsave ;
13185         operand *pnum, *result;
13186         int i;
13187
13188         assert (nparms==1);
13189         /* save registers that need to be saved */
13190         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13191                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13192
13193         pnum = parms[0];
13194         aopOp (pnum, ic, FALSE, FALSE);
13195         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13196         freeAsmop (pnum, NULL, ic, FALSE);
13197         emitcode ("lcall","NatLib_LoadPrimitive");
13198         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13199         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13200             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13201                 for (i = (size-1) ; i >= 0 ; i-- ) {
13202                         emitcode ("push","a%s",javaRet[i]);
13203                 }
13204                 for (i=0; i < size ; i++ ) {
13205                         emitcode ("pop","a%s",
13206                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13207                 }
13208         } else {
13209                 for (i = 0 ; i < size ; i++ ) {
13210                         aopPut(result,javaRet[i],i);
13211                 }
13212         }
13213         freeAsmop (result, NULL, ic, FALSE);
13214         unsavermask(rsave);
13215 }
13216
13217 /*-----------------------------------------------------------------*/
13218 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13219 /*-----------------------------------------------------------------*/
13220 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13221 {
13222         bitVect *rsave ;
13223         operand *pnum, *result;
13224         int size = 3;
13225         int i;
13226
13227         assert (nparms==1);
13228         /* save registers that need to be saved */
13229         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13230                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13231
13232         pnum = parms[0];
13233         aopOp (pnum, ic, FALSE, FALSE);
13234         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13235         freeAsmop (pnum, NULL, ic, FALSE);
13236         emitcode ("lcall","NatLib_LoadPointer");
13237         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13238         if (AOP_TYPE(result)!=AOP_STR) {
13239                 for (i = 0 ; i < size ; i++ ) {
13240                         aopPut(result,fReturn[i],i);
13241                 }
13242         }
13243         freeAsmop (result, NULL, ic, FALSE);
13244         unsavermask(rsave);
13245 }
13246
13247 /*-----------------------------------------------------------------*/
13248 /* genNatLibInstallStateBlock -                                    */
13249 /*-----------------------------------------------------------------*/
13250 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13251                                        operand **parms, const char *name)
13252 {
13253         bitVect *rsave ;
13254         operand *psb, *handle;
13255         assert (nparms==2);
13256
13257         /* save registers that need to be saved */
13258         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13259                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13260         psb = parms[0];
13261         handle = parms[1];
13262
13263         /* put pointer to state block into DPTR1 */
13264         aopOp (psb, ic, FALSE, FALSE);
13265         if (AOP_TYPE (psb) == AOP_IMMD) {
13266                 emitcode ("mov","dps,#1");
13267                 emitcode ("mov", "dptr,%s",
13268                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13269                 emitcode ("mov","dps,#0");
13270         } else {
13271                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13272                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13273                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13274         }
13275         freeAsmop (psb, NULL, ic, FALSE);
13276
13277         /* put libraryID into DPTR */
13278         emitcode ("mov","dptr,#LibraryID");
13279
13280         /* put handle into r3:r2 */
13281         aopOp (handle, ic, FALSE, FALSE);
13282         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13283                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13284                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13285                 emitcode ("pop","ar3");
13286                 emitcode ("pop","ar2");
13287         } else {
13288                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13289                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13290         }
13291         freeAsmop (psb, NULL, ic, FALSE);
13292
13293         /* make the call */
13294         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13295
13296         /* put return value into place*/
13297         _G.accInUse++;
13298         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13299         _G.accInUse--;
13300         aopPut(IC_RESULT(ic),"a",0);
13301         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13302         unsavermask(rsave);
13303 }
13304
13305 /*-----------------------------------------------------------------*/
13306 /* genNatLibRemoveStateBlock -                                     */
13307 /*-----------------------------------------------------------------*/
13308 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13309 {
13310         bitVect *rsave ;
13311
13312         assert(nparms==0);
13313
13314         /* save registers that need to be saved */
13315         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13316                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13317
13318         /* put libraryID into DPTR */
13319         emitcode ("mov","dptr,#LibraryID");
13320         /* make the call */
13321         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13322         unsavermask(rsave);
13323 }
13324
13325 /*-----------------------------------------------------------------*/
13326 /* genNatLibGetStateBlock -                                        */
13327 /*-----------------------------------------------------------------*/
13328 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13329                                    operand **parms,const char *name)
13330 {
13331         bitVect *rsave ;
13332         symbol *lbl = newiTempLabel(NULL);
13333
13334         assert(nparms==0);
13335         /* save registers that need to be saved */
13336         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13337                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13338
13339         /* put libraryID into DPTR */
13340         emitcode ("mov","dptr,#LibraryID");
13341         /* make the call */
13342         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13343         emitcode ("jnz","!tlabel",lbl->key+100);
13344
13345         /* put return value into place */
13346         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13347         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13348                 emitcode ("push","ar3");
13349                 emitcode ("push","ar2");
13350                 emitcode ("pop","%s",
13351                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13352                 emitcode ("pop","%s",
13353                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13354         } else {
13355                 aopPut(IC_RESULT(ic),"r2",0);
13356                 aopPut(IC_RESULT(ic),"r3",1);
13357         }
13358         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13359         emitLabel (lbl);
13360         unsavermask(rsave);
13361 }
13362
13363 /*-----------------------------------------------------------------*/
13364 /* genMMMalloc -                                                   */
13365 /*-----------------------------------------------------------------*/
13366 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13367                          int size, const char *name)
13368 {
13369         bitVect *rsave ;
13370         operand *bsize;
13371         symbol *rsym;
13372         symbol *lbl = newiTempLabel(NULL);
13373
13374         assert (nparms == 1);
13375         /* save registers that need to be saved */
13376         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13377                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13378
13379         bsize=parms[0];
13380         aopOp (bsize,ic,FALSE,FALSE);
13381
13382         /* put the size in R4-R2 */
13383         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13384                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13385                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13386                 if (size==3) {
13387                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13388                         emitcode("pop","ar4");
13389                 }
13390                 emitcode("pop","ar3");
13391                 emitcode("pop","ar2");
13392         } else {
13393                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13394                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13395                 if (size==3) {
13396                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13397                 }
13398         }
13399         freeAsmop (bsize, NULL, ic, FALSE);
13400
13401         /* make the call */
13402         emitcode ("lcall","MM_%s",name);
13403         emitcode ("jz","!tlabel",lbl->key+100);
13404         emitcode ("mov","r2,#!constbyte",0xff);
13405         emitcode ("mov","r3,#!constbyte",0xff);
13406         emitLabel (lbl);
13407         /* we don't care about the pointer : we just save the handle */
13408         rsym = OP_SYMBOL(IC_RESULT(ic));
13409         if (rsym->liveFrom != rsym->liveTo) {
13410                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13411                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13412                         emitcode ("push","ar3");
13413                         emitcode ("push","ar2");
13414                         emitcode ("pop","%s",
13415                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13416                         emitcode ("pop","%s",
13417                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13418                 } else {
13419                         aopPut(IC_RESULT(ic),"r2",0);
13420                         aopPut(IC_RESULT(ic),"r3",1);
13421                 }
13422                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13423         }
13424         unsavermask(rsave);
13425 }
13426
13427 /*-----------------------------------------------------------------*/
13428 /* genMMDeref -                                                    */
13429 /*-----------------------------------------------------------------*/
13430 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13431 {
13432         bitVect *rsave ;
13433         operand *handle;
13434
13435         assert (nparms == 1);
13436         /* save registers that need to be saved */
13437         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13438                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13439
13440         handle=parms[0];
13441         aopOp (handle,ic,FALSE,FALSE);
13442
13443         /* put the size in R4-R2 */
13444         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13445                 emitcode("push","%s",
13446                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13447                 emitcode("push","%s",
13448                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13449                 emitcode("pop","ar3");
13450                 emitcode("pop","ar2");
13451         } else {
13452                 emitcode ("mov","r2,%s",
13453                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13454                 emitcode ("mov","r3,%s",
13455                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13456         }
13457         freeAsmop (handle, NULL, ic, FALSE);
13458
13459         /* make the call */
13460         emitcode ("lcall","MM_Deref");
13461
13462         {
13463                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13464                 if (rsym->liveFrom != rsym->liveTo) {
13465                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13466                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13467                             _startLazyDPSEvaluation ();
13468
13469                             aopPut(IC_RESULT(ic),"dpl",0);
13470                             aopPut(IC_RESULT(ic),"dph",1);
13471                             aopPut(IC_RESULT(ic),"dpx",2);
13472
13473                             _endLazyDPSEvaluation ();
13474
13475                         }
13476                 }
13477         }
13478         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13479         unsavermask(rsave);
13480 }
13481
13482 /*-----------------------------------------------------------------*/
13483 /* genMMUnrestrictedPersist -                                      */
13484 /*-----------------------------------------------------------------*/
13485 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13486 {
13487         bitVect *rsave ;
13488         operand *handle;
13489
13490         assert (nparms == 1);
13491         /* save registers that need to be saved */
13492         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13493                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13494
13495         handle=parms[0];
13496         aopOp (handle,ic,FALSE,FALSE);
13497
13498         /* put the size in R3-R2 */
13499         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13500                 emitcode("push","%s",
13501                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13502                 emitcode("push","%s",
13503                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13504                 emitcode("pop","ar3");
13505                 emitcode("pop","ar2");
13506         } else {
13507                 emitcode ("mov","r2,%s",
13508                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13509                 emitcode ("mov","r3,%s",
13510                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13511         }
13512         freeAsmop (handle, NULL, ic, FALSE);
13513
13514         /* make the call */
13515         emitcode ("lcall","MM_UnrestrictedPersist");
13516
13517         {
13518                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13519                 if (rsym->liveFrom != rsym->liveTo) {
13520                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13521                         aopPut(IC_RESULT(ic),"a",0);
13522                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13523                 }
13524         }
13525         unsavermask(rsave);
13526 }
13527
13528 /*-----------------------------------------------------------------*/
13529 /* genSystemExecJavaProcess -                                      */
13530 /*-----------------------------------------------------------------*/
13531 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13532 {
13533         bitVect *rsave ;
13534         operand *handle, *pp;
13535
13536         assert (nparms==2);
13537         /* save registers that need to be saved */
13538         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13539                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13540
13541         pp = parms[0];
13542         handle = parms[1];
13543
13544         /* put the handle in R3-R2 */
13545         aopOp (handle,ic,FALSE,FALSE);
13546         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13547                 emitcode("push","%s",
13548                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13549                 emitcode("push","%s",
13550                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13551                 emitcode("pop","ar3");
13552                 emitcode("pop","ar2");
13553         } else {
13554                 emitcode ("mov","r2,%s",
13555                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13556                 emitcode ("mov","r3,%s",
13557                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13558         }
13559         freeAsmop (handle, NULL, ic, FALSE);
13560
13561         /* put pointer in DPTR */
13562         aopOp (pp,ic,FALSE,FALSE);
13563         if (AOP_TYPE(pp) == AOP_IMMD) {
13564                 emitcode ("mov", "dptr,%s",
13565                           aopGet (pp, 0, TRUE, FALSE, NULL));
13566         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13567                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13568                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13569                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13570         }
13571         freeAsmop (handle, NULL, ic, FALSE);
13572
13573         /* make the call */
13574         emitcode ("lcall","System_ExecJavaProcess");
13575
13576         /* put result in place */
13577         {
13578                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13579                 if (rsym->liveFrom != rsym->liveTo) {
13580                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13581                         aopPut(IC_RESULT(ic),"a",0);
13582                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13583                 }
13584         }
13585
13586         unsavermask(rsave);
13587 }
13588
13589 /*-----------------------------------------------------------------*/
13590 /* genSystemRTCRegisters -                                         */
13591 /*-----------------------------------------------------------------*/
13592 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13593                                   char *name)
13594 {
13595         bitVect *rsave ;
13596         operand *pp;
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         pp=parms[0];
13604         /* put pointer in DPTR */
13605         aopOp (pp,ic,FALSE,FALSE);
13606         if (AOP_TYPE (pp) == AOP_IMMD) {
13607                 emitcode ("mov","dps,#1");
13608                 emitcode ("mov", "dptr,%s",
13609                           aopGet (pp, 0, TRUE, FALSE, NULL));
13610                 emitcode ("mov","dps,#0");
13611         } else {
13612                 emitcode ("mov","dpl1,%s",
13613                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13614                 emitcode ("mov","dph1,%s",
13615                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13616                 emitcode ("mov","dpx1,%s",
13617                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13618         }
13619         freeAsmop (pp, NULL, ic, FALSE);
13620
13621         /* make the call */
13622         emitcode ("lcall","System_%sRTCRegisters",name);
13623
13624         unsavermask(rsave);
13625 }
13626
13627 /*-----------------------------------------------------------------*/
13628 /* genSystemThreadSleep -                                          */
13629 /*-----------------------------------------------------------------*/
13630 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13631 {
13632         bitVect *rsave ;
13633         operand *to, *s;
13634
13635         assert (nparms==1);
13636         /* save registers that need to be saved */
13637         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13638                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13639
13640         to = parms[0];
13641         aopOp(to,ic,FALSE,FALSE);
13642         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13643             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13644                 emitcode ("push","%s",
13645                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13646                 emitcode ("push","%s",
13647                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13648                 emitcode ("push","%s",
13649                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13650                 emitcode ("push","%s",
13651                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13652                 emitcode ("pop","ar3");
13653                 emitcode ("pop","ar2");
13654                 emitcode ("pop","ar1");
13655                 emitcode ("pop","ar0");
13656         } else {
13657                 emitcode ("mov","r0,%s",
13658                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13659                 emitcode ("mov","r1,%s",
13660                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13661                 emitcode ("mov","r2,%s",
13662                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13663                 emitcode ("mov","r3,%s",
13664                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13665         }
13666         freeAsmop (to, NULL, ic, FALSE);
13667
13668         /* suspend in acc */
13669         s = parms[1];
13670         aopOp(s,ic,FALSE,FALSE);
13671         emitcode ("mov","a,%s",
13672                   aopGet(s,0,FALSE,TRUE,NULL));
13673         freeAsmop (s, NULL, ic, FALSE);
13674
13675         /* make the call */
13676         emitcode ("lcall","System_%s",name);
13677
13678         unsavermask(rsave);
13679 }
13680
13681 /*-----------------------------------------------------------------*/
13682 /* genSystemThreadResume -                                         */
13683 /*-----------------------------------------------------------------*/
13684 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13685 {
13686         bitVect *rsave ;
13687         operand *tid,*pid;
13688
13689         assert (nparms==2);
13690         /* save registers that need to be saved */
13691         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13692                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13693
13694         tid = parms[0];
13695         pid = parms[1];
13696
13697         /* PID in R0 */
13698         aopOp(pid,ic,FALSE,FALSE);
13699         emitcode ("mov","r0,%s",
13700                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13701         freeAsmop (pid, NULL, ic, FALSE);
13702
13703         /* tid into ACC */
13704         aopOp(tid,ic,FALSE,FALSE);
13705         emitcode ("mov","a,%s",
13706                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13707         freeAsmop (tid, NULL, ic, FALSE);
13708
13709         emitcode ("lcall","System_ThreadResume");
13710
13711         /* put result into place */
13712         {
13713                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13714                 if (rsym->liveFrom != rsym->liveTo) {
13715                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13716                         aopPut(IC_RESULT(ic),"a",0);
13717                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13718                 }
13719         }
13720         unsavermask(rsave);
13721 }
13722
13723 /*-----------------------------------------------------------------*/
13724 /* genSystemProcessResume -                                        */
13725 /*-----------------------------------------------------------------*/
13726 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13727 {
13728         bitVect *rsave ;
13729         operand *pid;
13730
13731         assert (nparms==1);
13732         /* save registers that need to be saved */
13733         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13734                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13735
13736         pid = parms[0];
13737
13738         /* pid into ACC */
13739         aopOp(pid,ic,FALSE,FALSE);
13740         emitcode ("mov","a,%s",
13741                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13742         freeAsmop (pid, NULL, ic, FALSE);
13743
13744         emitcode ("lcall","System_ProcessResume");
13745
13746         unsavermask(rsave);
13747 }
13748
13749 /*-----------------------------------------------------------------*/
13750 /* genSystem -                                                     */
13751 /*-----------------------------------------------------------------*/
13752 static void genSystem (iCode *ic,int nparms,char *name)
13753 {
13754         assert(nparms == 0);
13755
13756         emitcode ("lcall","System_%s",name);
13757 }
13758
13759 /*-----------------------------------------------------------------*/
13760 /* genSystemPoll -                                                  */
13761 /*-----------------------------------------------------------------*/
13762 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13763 {
13764         bitVect *rsave ;
13765         operand *fp;
13766
13767         assert (nparms==1);
13768         /* save registers that need to be saved */
13769         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13770                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13771
13772         fp = parms[0];
13773         aopOp (fp,ic,FALSE,FALSE);
13774         if (AOP_TYPE (fp) == AOP_IMMD) {
13775                 emitcode ("mov", "dptr,%s",
13776                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13777         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13778                 emitcode ("mov","dpl,%s",
13779                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13780                 emitcode ("mov","dph,%s",
13781                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13782                 emitcode ("mov","dpx,%s",
13783                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13784         }
13785         freeAsmop (fp, NULL, ic, FALSE);
13786
13787         emitcode ("lcall","System_%sPoll",name);
13788
13789         /* put result into place */
13790         {
13791                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13792                 if (rsym->liveFrom != rsym->liveTo) {
13793                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13794                         aopPut(IC_RESULT(ic),"a",0);
13795                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13796                 }
13797         }
13798         unsavermask(rsave);
13799 }
13800
13801 /*-----------------------------------------------------------------*/
13802 /* genSystemGetCurrentID -                                         */
13803 /*-----------------------------------------------------------------*/
13804 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13805 {
13806         assert (nparms==0);
13807
13808         emitcode ("lcall","System_GetCurrent%sId",name);
13809         /* put result into place */
13810         {
13811                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13812                 if (rsym->liveFrom != rsym->liveTo) {
13813                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13814                         aopPut(IC_RESULT(ic),"a",0);
13815                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13816                 }
13817         }
13818 }
13819
13820 /*-----------------------------------------------------------------*/
13821 /* genDjnz - generate decrement & jump if not zero instrucion      */
13822 /*-----------------------------------------------------------------*/
13823 static int
13824 genDjnz (iCode * ic, iCode * ifx)
13825 {
13826   symbol *lbl, *lbl1;
13827   if (!ifx)
13828     return 0;
13829
13830   /* if the if condition has a false label
13831      then we cannot save */
13832   if (IC_FALSE (ifx))
13833     return 0;
13834
13835   /* if the minus is not of the form a = a - 1 */
13836   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13837       !IS_OP_LITERAL (IC_RIGHT (ic)))
13838     return 0;
13839
13840   if (operandLitValue (IC_RIGHT (ic)) != 1)
13841     return 0;
13842
13843   /* if the size of this greater than one then no
13844      saving */
13845   if (getSize (operandType (IC_RESULT (ic))) > 1)
13846     return 0;
13847
13848   /* otherwise we can save BIG */
13849
13850   D (emitcode (";", "genDjnz"));
13851
13852   lbl = newiTempLabel (NULL);
13853   lbl1 = newiTempLabel (NULL);
13854
13855   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13856
13857   if (AOP_NEEDSACC(IC_RESULT(ic)))
13858   {
13859       /* If the result is accessed indirectly via
13860        * the accumulator, we must explicitly write
13861        * it back after the decrement.
13862        */
13863       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13864
13865       if (strcmp(rByte, "a"))
13866       {
13867            /* Something is hopelessly wrong */
13868            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13869                    __FILE__, __LINE__);
13870            /* We can just give up; the generated code will be inefficient,
13871             * but what the hey.
13872             */
13873            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13874            return 0;
13875       }
13876       emitcode ("dec", "%s", rByte);
13877       aopPut (IC_RESULT (ic), rByte, 0);
13878       emitcode ("jnz", "!tlabel", lbl->key + 100);
13879   }
13880   else if (IS_AOP_PREG (IC_RESULT (ic)))
13881     {
13882       emitcode ("dec", "%s",
13883                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13884       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13885       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13886       ifx->generated = 1;
13887       emitcode ("jnz", "!tlabel", lbl->key + 100);
13888     }
13889   else
13890     {
13891       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13892                 lbl->key + 100);
13893     }
13894   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13895   emitLabel (lbl);
13896   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13897   emitLabel (lbl1);
13898
13899   if (!ifx->generated)
13900       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13901   ifx->generated = 1;
13902   return 1;
13903 }
13904
13905 /*-----------------------------------------------------------------*/
13906 /* genReceive - generate code for a receive iCode                  */
13907 /*-----------------------------------------------------------------*/
13908 static void
13909 genReceive (iCode * ic)
13910 {
13911     int size = getSize (operandType (IC_RESULT (ic)));
13912     int offset = 0;
13913     int rb1off ;
13914
13915     D (emitcode (";", "genReceive"));
13916
13917     if (ic->argreg == 1)
13918     {
13919         /* first parameter */
13920         if (AOP_IS_STR(IC_RESULT(ic)))
13921         {
13922             /* Nothing to do: it's already in the proper place. */
13923             return;
13924         }
13925         else
13926         {
13927             bool useDp2;
13928
13929             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13930                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13931                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13932
13933             _G.accInUse++;
13934             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13935             _G.accInUse--;
13936
13937             /* Sanity checking... */
13938             if (AOP_USESDPTR(IC_RESULT(ic)))
13939             {
13940                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13941                         "genReceive got unexpected DPTR.");
13942             }
13943             assignResultValue (IC_RESULT (ic), NULL);
13944         }
13945     }
13946     else if (ic->argreg > 12)
13947     { /* bit parameters */
13948       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13949         {
13950           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13951           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13952           outBitC(IC_RESULT (ic));
13953         }
13954     }
13955     else
13956     {
13957         /* second receive onwards */
13958         /* this gets a little tricky since unused receives will be
13959          eliminated, we have saved the reg in the type field . and
13960          we use that to figure out which register to use */
13961         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13962         rb1off = ic->argreg;
13963         while (size--)
13964         {
13965             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13966         }
13967     }
13968     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13969 }
13970
13971 /*-----------------------------------------------------------------*/
13972 /* genDummyRead - generate code for dummy read of volatiles        */
13973 /*-----------------------------------------------------------------*/
13974 static void
13975 genDummyRead (iCode * ic)
13976 {
13977   operand *op;
13978   int size, offset;
13979
13980   D (emitcode(";", "genDummyRead"));
13981
13982   op = IC_RIGHT (ic);
13983   if (op && IS_SYMOP (op))
13984     {
13985       aopOp (op, ic, FALSE, FALSE);
13986
13987       /* if the result is a bit */
13988       if (AOP_TYPE (op) == AOP_CRY)
13989         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13990       else
13991         {
13992           /* bit variables done */
13993           /* general case */
13994           size = AOP_SIZE (op);
13995           offset = 0;
13996           while (size--)
13997           {
13998             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13999             offset++;
14000           }
14001         }
14002
14003       freeAsmop (op, NULL, ic, TRUE);
14004     }
14005
14006   op = IC_LEFT (ic);
14007   if (op && IS_SYMOP (op))
14008     {
14009       aopOp (op, ic, FALSE, FALSE);
14010
14011       /* if the result is a bit */
14012       if (AOP_TYPE (op) == AOP_CRY)
14013         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
14014       else
14015         {
14016           /* bit variables done */
14017           /* general case */
14018           size = AOP_SIZE (op);
14019           offset = 0;
14020           while (size--)
14021           {
14022             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
14023             offset++;
14024           }
14025         }
14026
14027       freeAsmop (op, NULL, ic, TRUE);
14028     }
14029 }
14030
14031 /*-----------------------------------------------------------------*/
14032 /* genCritical - generate code for start of a critical sequence    */
14033 /*-----------------------------------------------------------------*/
14034 static void
14035 genCritical (iCode *ic)
14036 {
14037   symbol *tlbl = newiTempLabel (NULL);
14038
14039   D (emitcode(";", "genCritical"));
14040
14041   if (IC_RESULT (ic))
14042     {
14043       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14044       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14045       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14046       aopPut (IC_RESULT (ic), zero, 0);
14047       emitLabel (tlbl);
14048       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14049     }
14050   else
14051     {
14052       emitcode ("setb", "c");
14053       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14054       emitcode ("clr", "c");
14055       emitLabel (tlbl);
14056       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14057     }
14058 }
14059
14060 /*-----------------------------------------------------------------*/
14061 /* genEndCritical - generate code for end of a critical sequence   */
14062 /*-----------------------------------------------------------------*/
14063 static void
14064 genEndCritical (iCode *ic)
14065 {
14066   D(emitcode(";", "genEndCritical"));
14067
14068   if (IC_RIGHT (ic))
14069     {
14070       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14071       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14072         {
14073           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14074           emitcode ("mov", "ea,c");
14075         }
14076       else
14077         {
14078           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14079           emitcode ("rrc", "a");
14080           emitcode ("mov", "ea,c");
14081         }
14082       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14083     }
14084   else
14085     {
14086       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14087       emitcode ("mov", "ea,c");
14088     }
14089 }
14090
14091
14092
14093 /*-----------------------------------------------------------------*/
14094 /* genBuiltIn - calls the appropriate function to  generating code */
14095 /* for a built in function                                         */
14096 /*-----------------------------------------------------------------*/
14097 static void genBuiltIn (iCode *ic)
14098 {
14099         operand *bi_parms[MAX_BUILTIN_ARGS];
14100         int nbi_parms;
14101         iCode *bi_iCode;
14102         symbol *bif;
14103
14104         /* get all the arguments for a built in function */
14105         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14106
14107         /* which function is it */
14108         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14109         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14110                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14111         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14112                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14113         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14114                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14115         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14116                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14117         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14118                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14119         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14120                 genInp(bi_iCode,nbi_parms,bi_parms);
14121         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14122                 genOutp(bi_iCode,nbi_parms,bi_parms);
14123         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14124                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14125                 /* JavaNative builtIns */
14126         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14127                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14128         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14129                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14130         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14131                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14132         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14133                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14134         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14135                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14136         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14137                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14138         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14139                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14140         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14141                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14142         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14143                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14144         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14145                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14146         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14147                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14148         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14149                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14150         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14151                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14152         } else if (strcmp(bif->name,"MM_Free")==0) {
14153                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14154         } else if (strcmp(bif->name,"MM_Deref")==0) {
14155                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14156         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14157                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14158         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14159                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14160         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14161                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14162         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14163                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14164         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14165                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14166         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14167                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14168         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14169                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14170         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14171                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14172         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14173                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14174         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14175                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14176         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14177                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14178         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14179                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14180         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14181                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14182         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14183                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14184         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14185                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14186         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14187                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14188         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14189                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14190         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14191                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14192         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14193                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14194         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14195                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14196         } else {
14197                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14198                 return ;
14199         }
14200         return ;
14201 }
14202
14203 /*-----------------------------------------------------------------*/
14204 /* gen390Code - generate code for Dallas 390 based controllers     */
14205 /*-----------------------------------------------------------------*/
14206 void
14207 gen390Code (iCode * lic)
14208 {
14209   iCode *ic;
14210   int cln = 0;
14211
14212   _G.currentFunc = NULL;
14213   lineHead = lineCurr = NULL;
14214   dptrn[1][0] = "dpl1";
14215   dptrn[1][1] = "dph1";
14216   dptrn[1][2] = "dpx1";
14217
14218   if (options.model == MODEL_FLAT24) {
14219     fReturnSizeDS390 = 5;
14220     fReturn = fReturn24;
14221   } else {
14222     fReturnSizeDS390 = 4;
14223     fReturn = fReturn16;
14224     options.stack10bit=0;
14225   }
14226 #if 1
14227   /* print the allocation information */
14228   if (allocInfo && currFunc)
14229     printAllocInfo (currFunc, codeOutBuf);
14230 #endif
14231   /* if debug information required */
14232   if (options.debug && currFunc)
14233     {
14234       debugFile->writeFunction (currFunc, lic);
14235     }
14236   /* stack pointer name */
14237   if (options.useXstack)
14238     spname = "_spx";
14239   else
14240     spname = "sp";
14241
14242
14243   for (ic = lic; ic; ic = ic->next)
14244     {
14245       _G.current_iCode = ic;
14246
14247       if (ic->lineno && cln != ic->lineno)
14248         {
14249           if (options.debug)
14250             {
14251               debugFile->writeCLine (ic);
14252             }
14253           if (!options.noCcodeInAsm) {
14254             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
14255                       printCLine(ic->filename, ic->lineno));
14256           }
14257           cln = ic->lineno;
14258         }
14259       if (options.iCodeInAsm) {
14260         const char *iLine = printILine(ic);
14261         emitcode(";", "ic:%d: %s", ic->key, iLine);
14262         dbuf_free(iLine);
14263       }
14264       /* if the result is marked as
14265          spilt and rematerializable or code for
14266          this has already been generated then
14267          do nothing */
14268       if (resultRemat (ic) || ic->generated)
14269         continue;
14270
14271       /* depending on the operation */
14272       switch (ic->op)
14273         {
14274         case '!':
14275           genNot (ic);
14276           break;
14277
14278         case '~':
14279           genCpl (ic);
14280           break;
14281
14282         case UNARYMINUS:
14283           genUminus (ic);
14284           break;
14285
14286         case IPUSH:
14287           genIpush (ic);
14288           break;
14289
14290         case IPOP:
14291           /* IPOP happens only when trying to restore a
14292              spilt live range, if there is an ifx statement
14293              following this pop then the if statement might
14294              be using some of the registers being popped which
14295              would destory the contents of the register so
14296              we need to check for this condition and handle it */
14297           if (ic->next &&
14298               ic->next->op == IFX &&
14299               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14300             genIfx (ic->next, ic);
14301           else
14302             genIpop (ic);
14303           break;
14304
14305         case CALL:
14306           genCall (ic);
14307           break;
14308
14309         case PCALL:
14310           genPcall (ic);
14311           break;
14312
14313         case FUNCTION:
14314           genFunction (ic);
14315           break;
14316
14317         case ENDFUNCTION:
14318           genEndFunction (ic);
14319           break;
14320
14321         case RETURN:
14322           genRet (ic);
14323           break;
14324
14325         case LABEL:
14326           genLabel (ic);
14327           break;
14328
14329         case GOTO:
14330           genGoto (ic);
14331           break;
14332
14333         case '+':
14334           genPlus (ic);
14335           break;
14336
14337         case '-':
14338           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14339             genMinus (ic);
14340           break;
14341
14342         case '*':
14343           genMult (ic);
14344           break;
14345
14346         case '/':
14347           genDiv (ic);
14348           break;
14349
14350         case '%':
14351           genMod (ic);
14352           break;
14353
14354         case '>':
14355           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14356           break;
14357
14358         case '<':
14359           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14360           break;
14361
14362         case LE_OP:
14363         case GE_OP:
14364         case NE_OP:
14365
14366           /* note these two are xlated by algebraic equivalence
14367              during parsing SDCC.y */
14368           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14369                   "got '>=' or '<=' shouldn't have come here");
14370           break;
14371
14372         case EQ_OP:
14373           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14374           break;
14375
14376         case AND_OP:
14377           genAndOp (ic);
14378           break;
14379
14380         case OR_OP:
14381           genOrOp (ic);
14382           break;
14383
14384         case '^':
14385           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14386           break;
14387
14388         case '|':
14389           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14390           break;
14391
14392         case BITWISEAND:
14393           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14394           break;
14395
14396         case INLINEASM:
14397           genInline (ic);
14398           break;
14399
14400         case RRC:
14401           genRRC (ic);
14402           break;
14403
14404         case RLC:
14405           genRLC (ic);
14406           break;
14407
14408         case GETHBIT:
14409           genGetHbit (ic);
14410           break;
14411
14412         case LEFT_OP:
14413           genLeftShift (ic);
14414           break;
14415
14416         case RIGHT_OP:
14417           genRightShift (ic);
14418           break;
14419
14420         case GET_VALUE_AT_ADDRESS:
14421           genPointerGet (ic,
14422                          hasInc (IC_LEFT (ic), ic,
14423                                  getSize (operandType (IC_RESULT (ic)))));
14424           break;
14425
14426         case '=':
14427           if (POINTER_SET (ic))
14428             genPointerSet (ic,
14429                            hasInc (IC_RESULT (ic), ic,
14430                                    getSize (operandType (IC_RIGHT (ic)))));
14431           else
14432             genAssign (ic);
14433           break;
14434
14435         case IFX:
14436           genIfx (ic, NULL);
14437           break;
14438
14439         case ADDRESS_OF:
14440           genAddrOf (ic);
14441           break;
14442
14443         case JUMPTABLE:
14444           genJumpTab (ic);
14445           break;
14446
14447         case CAST:
14448           genCast (ic);
14449           break;
14450
14451         case RECEIVE:
14452           genReceive (ic);
14453           break;
14454
14455         case SEND:
14456           if (ic->builtinSEND)
14457             genBuiltIn(ic);
14458           else
14459             addSet (&_G.sendSet, ic);
14460           break;
14461
14462         case DUMMY_READ_VOLATILE:
14463           genDummyRead (ic);
14464           break;
14465
14466         case CRITICAL:
14467           genCritical (ic);
14468           break;
14469
14470         case ENDCRITICAL:
14471           genEndCritical (ic);
14472           break;
14473
14474         case SWAP:
14475           genSwap (ic);
14476           break;
14477
14478 #if 0 // obsolete, and buggy for != xdata
14479         case ARRAYINIT:
14480             genArrayInit(ic);
14481             break;
14482 #endif
14483
14484         default:
14485             /* This should never happen, right? */
14486             fprintf(stderr, "*** Probable error: unsupported op 0x%x (%c) in %s @ %d\n",
14487                     ic->op, ic->op, __FILE__, __LINE__);
14488             ic = ic;
14489         }
14490     }
14491
14492
14493   /* now we are ready to call the
14494      peep hole optimizer */
14495   if (!options.nopeep)
14496     peepHole (&lineHead);
14497
14498   /* now do the actual printing */
14499   printLine (lineHead, codeOutBuf);
14500   return;
14501 }