* src/SDCCpeeph.c: made labelHashEntry global, made pcDistance, FBYNAME static,
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for DS80C390
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7   DS390 adaptation by Kevin Vigor <kevin@vigor.nu>
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23   In other words, you are welcome to use, share and improve this program.
24   You are forbidden to forbid anyone else to use, share and improve
25   what you give them.   Help stamp out software-hoarding!
26 -------------------------------------------------------------------------*/
27
28 //#define D(x)
29 #define D(x) x
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "SDCCglobl.h"
36 #include "newalloc.h"
37
38 #include "common.h"
39 #include "main.h"
40 #include "ralloc.h"
41 #include "gen.h"
42
43 #define BETTER_LITERAL_SHIFT
44
45 char *aopLiteral (value * val, int offset);
46 extern int allocInfo;
47
48 /* this is the down and dirty file with all kinds of
49    kludgy & hacky stuff. This is what it is all about
50    CODE GENERATION for a specific MCU . some of the
51    routines may be reusable, will have to see */
52
53 static char *zero = "#0";
54 static char *one = "#1";
55 static char *spname;
56
57 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
58 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
59
60 unsigned fReturnSizeDS390 = 5;
61 static char *fReturn24[] =
62 {"dpl", "dph", "dpx", "b", "a"};
63 static char *fReturn16[] =
64 {"dpl", "dph", "b", "a"};
65 static char **fReturn = fReturn24;
66 static char *accUse[] =
67 {"a", "b"};
68 static char *dptrn[2][3];
69 static char *javaRet[] = { "r0","r1","r2","r3"};
70 static short rbank = -1;
71
72 #define REG_WITH_INDEX   ds390_regWithIdx
73
74 #define AOP(op) op->aop
75 #define AOP_TYPE(op) AOP(op)->type
76 #define AOP_SIZE(op) AOP(op)->size
77 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
78                        AOP_TYPE(x) == AOP_R0))
79
80 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
81                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
82                          AOP(x)->paged))
83
84 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
85                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
86                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
87 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
88 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
89 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
90
91 // The following two macros can be used even if the aop has not yet been aopOp'd.
92 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
93 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
94
95 /* Workaround for DS80C390 bug: div ab may return bogus results
96  * if A is accessed in instruction immediately before the div.
97  *
98  * Will be fixed in B4 rev of processor, Dallas claims.
99  */
100
101 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
102     if (!AOP_NEEDSACC(RIGHT))         \
103     {               \
104       /* We can load A first, then B, since     \
105        * B (the RIGHT operand) won't clobber A,   \
106        * thus avoiding touching A right before the div. \
107        */             \
108       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
109       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
110       MOVA(L);            \
111       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
112       MOVB(L); \
113     }               \
114     else              \
115     {               \
116       /* Just stuff in a nop after loading A. */    \
117       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
118       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
119       MOVA(L);            \
120       emitcode("nop", "; workaround for DS80C390 div bug.");  \
121     }
122
123 #define R0INB   _G.bu.bs.r0InB
124 #define R1INB   _G.bu.bs.r1InB
125 #define OPINB   _G.bu.bs.OpInB
126 #define BINUSE  _G.bu.BInUse
127
128 static struct
129   {
130     short r0Pushed;
131     short r1Pushed;
132     union
133       {
134         struct
135           {
136             short r0InB : 2;//2 so we can see it overflow
137             short r1InB : 2;//2 so we can see it overflow
138             short OpInB : 2;//2 so we can see it overflow
139           } bs;
140         short BInUse;
141       } bu;
142     short accInUse;
143     short inLine;
144     short debugLine;
145     short nRegsSaved;
146     short dptrInUse;
147     short dptr1InUse;
148     set *sendSet;
149     iCode *current_iCode;
150     symbol *currentFunc;
151   }
152 _G;
153
154 static char *rb1regs[] = {
155     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
156     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
157 };
158
159 static void saveRBank (int, iCode *, bool);
160
161 #define RESULTONSTACK(x) \
162                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
163                          IC_RESULT(x)->aop->type == AOP_STK )
164
165 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
166 #define MOVB(x)  movb(x)
167
168 #define CLRC    emitcode("clr","c")
169 #define SETC    emitcode("setb","c")
170
171 // A scratch register which will be used to hold
172 // result bytes from operands in far space via DPTR2.
173 #define DP2_RESULT_REG  "_ap"
174
175 static lineNode *lineHead = NULL;
176 static lineNode *lineCurr = NULL;
177
178 static unsigned char SLMask[] =
179 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
180  0xE0, 0xC0, 0x80, 0x00};
181 static unsigned char SRMask[] =
182 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
183  0x07, 0x03, 0x01, 0x00};
184
185 #define LSB     0
186 #define MSB16   1
187 #define MSB24   2
188 #define MSB32   3
189 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
190                                 symbol *lbl = newiTempLabel(NULL);              \
191                                 emitcode ("setb","F1");                         \
192                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
193                                 emitcode ("clr","F1");                          \
194                                 emitLabel (lbl);                                \
195                         }}
196 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
197                                 emitcode ("mov","EA,F1");                       \
198                         }}
199
200 static int _currentDPS;         /* Current processor DPS. */
201 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
202 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
203
204 /*-----------------------------------------------------------------*/
205 /* emitcode - writes the code into a file : for now it is simple    */
206 /*-----------------------------------------------------------------*/
207 static void
208 emitcode (char *inst, const char *fmt,...)
209 {
210   va_list ap;
211   char lb[INITIAL_INLINEASM];
212   char *lbp = lb;
213
214   va_start (ap, fmt);
215
216   if (inst && *inst)
217     {
218       if (fmt && *fmt)
219         {
220           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
221         }
222       else
223         {
224           SNPRINTF (lb, sizeof(lb), "%s", inst);
225         }
226
227       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
228     }
229   else
230     {
231       tvsprintf (lb, sizeof(lb), fmt, ap);
232     }
233
234   while (isspace ((unsigned char)*lbp))
235     {
236       lbp++;
237     }
238
239   if (lbp && *lbp)
240     {
241       lineCurr = (lineCurr ?
242                   connectLine (lineCurr, newLineNode (lb)) :
243                   (lineHead = newLineNode (lb)));
244     }
245
246   lineCurr->isInline = _G.inLine;
247   lineCurr->isDebug = _G.debugLine;
248   lineCurr->ic = _G.current_iCode;
249   lineCurr->aln = ds390newAsmLineNode(_currentDPS);
250   lineCurr->isComment = (*lbp == ';');
251   va_end (ap);
252 }
253
254 static void
255 emitLabel (symbol *tlbl)
256 {
257   emitcode ("", "!tlabeldef", tlbl->key + 100);
258   lineCurr->isLabel = 1;
259 }
260
261 /*-----------------------------------------------------------------*/
262 /* ds390_emitDebuggerSymbol - associate the current code location  */
263 /*   with a debugger symbol                                        */
264 /*-----------------------------------------------------------------*/
265 void
266 ds390_emitDebuggerSymbol (char * debugSym)
267 {
268   _G.debugLine = 1;
269   emitcode ("", "%s ==.", debugSym);
270   _G.debugLine = 0;
271 }
272
273 /*-----------------------------------------------------------------*/
274 /* mova - moves specified value into accumulator                   */
275 /*-----------------------------------------------------------------*/
276 static void
277 mova (const char *x)
278 {
279   /* do some early peephole optimization */
280   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
281     return;
282
283   emitcode("mov", "a,%s", x);
284 }
285
286 /*-----------------------------------------------------------------*/
287 /* movb - moves specified value into register b                    */
288 /*-----------------------------------------------------------------*/
289 static void
290 movb (const char *x)
291 {
292   /* do some early peephole optimization */
293   if (!strncmp(x, "b", 2))
294     return;
295
296   emitcode("mov","b,%s", x);
297 }
298
299 /*-----------------------------------------------------------------*/
300 /* movc - moves specified value into the carry                     */
301 /*-----------------------------------------------------------------*/
302 static void
303 movc (const char *s)
304 {
305   if (s == zero)
306     CLRC;
307   else if (s == one)
308     SETC;
309   else if (strcmp (s, "c"))
310     {/* it's not in carry already */
311       MOVA (s);
312       /* set C, if a >= 1 */
313       emitcode ("add", "a,#0xff");
314     }
315 }
316
317 /*-----------------------------------------------------------------*/
318 /* pushB - saves register B if necessary                           */
319 /*-----------------------------------------------------------------*/
320 static bool
321 pushB (void)
322 {
323   bool pushedB = FALSE;
324
325   if (BINUSE)
326     {
327       emitcode ("push", "b");
328 //    printf("B was in use !\n");
329       pushedB = TRUE;
330     }
331   else
332     {
333       OPINB++;
334     }
335   return pushedB;
336 }
337
338 /*-----------------------------------------------------------------*/
339 /* popB - restores value of register B if necessary                */
340 /*-----------------------------------------------------------------*/
341 static void
342 popB (bool pushedB)
343 {
344   if (pushedB)
345     {
346       emitcode ("pop", "b");
347     }
348   else
349     {
350       OPINB--;
351     }
352 }
353
354 /*-----------------------------------------------------------------*/
355 /* pushReg - saves register                                        */
356 /*-----------------------------------------------------------------*/
357 static bool
358 pushReg (int index, bool bits_pushed)
359 {
360   regs * reg = REG_WITH_INDEX (index);
361   if (reg->type == REG_BIT)
362     {
363       if (!bits_pushed)
364         emitcode ("push", "%s", reg->base);
365       return TRUE;
366     }
367   else
368     emitcode ("push", "%s", reg->dname);
369   return bits_pushed;
370 }
371
372 /*-----------------------------------------------------------------*/
373 /* popReg - restores register                                      */
374 /*-----------------------------------------------------------------*/
375 static bool
376 popReg (int index, bool bits_popped)
377 {
378   regs * reg = REG_WITH_INDEX (index);
379   if (reg->type == REG_BIT)
380     {
381       if (!bits_popped)
382         emitcode ("pop", "%s", reg->base);
383       return TRUE;
384     }
385   else
386     emitcode ("pop", "%s", reg->dname);
387   return bits_popped;
388 }
389
390 /*-----------------------------------------------------------------*/
391 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
392 /*-----------------------------------------------------------------*/
393 static regs *
394 getFreePtr (iCode * ic, asmop ** aopp, bool result)
395 {
396   bool r0iu, r1iu;
397   bool r0ou, r1ou;
398
399   /* the logic: if r0 & r1 used in the instruction
400      then we are in trouble otherwise */
401
402   /* first check if r0 & r1 are used by this
403      instruction, in which case we are in trouble */
404   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
405   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
406   if (r0iu && r1iu) {
407       goto endOfWorld;
408     }
409
410   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
411   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
412
413   /* if no usage of r0 then return it */
414   if (!r0iu && !r0ou)
415     {
416       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
417       (*aopp)->type = AOP_R0;
418
419       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
420     }
421
422   /* if no usage of r1 then return it */
423   if (!r1iu && !r1ou)
424     {
425       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
426       (*aopp)->type = AOP_R1;
427
428       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
429     }
430
431   /* now we know they both have usage */
432   /* if r0 not used in this instruction */
433   if (!r0iu)
434     {
435       /* push it if not already pushed */
436       if (!_G.r0Pushed)
437         {
438           emitcode ("push", "%s",
439                     REG_WITH_INDEX (R0_IDX)->dname);
440           _G.r0Pushed++;
441         }
442
443       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
444       (*aopp)->type = AOP_R0;
445
446       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
447     }
448
449   /* if r1 not used then */
450
451   if (!r1iu)
452     {
453       /* push it if not already pushed */
454       if (!_G.r1Pushed)
455         {
456           emitcode ("push", "%s",
457                     REG_WITH_INDEX (R1_IDX)->dname);
458           _G.r1Pushed++;
459         }
460
461       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
462       (*aopp)->type = AOP_R1;
463       return REG_WITH_INDEX (R1_IDX);
464     }
465
466 endOfWorld:
467   /* I said end of world, but not quite end of world yet */
468   /* if this is a result then we can push it on the stack */
469   if (result)
470     {
471       (*aopp)->type = AOP_STK;
472       return NULL;
473     }
474
475   /* now this is REALLY the end of the world */
476   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
477           "getFreePtr should never reach here");
478   exit (1);
479
480   return NULL; // notreached, but makes compiler happy.
481 }
482
483
484 /*-----------------------------------------------------------------*/
485 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
486 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
487 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
488 /*-----------------------------------------------------------------*/
489 static void
490 genSetDPTR (int n)
491 {
492
493   /* If we are doing lazy evaluation, simply note the desired
494    * change, but don't emit any code yet.
495    */
496   if (_lazyDPS)
497     {
498       _desiredDPS = n;
499       return;
500     }
501
502   if (!n)
503     {
504       emitcode ("mov", "dps,#0");
505     }
506   else
507     {
508       TR_DPTR("#1");
509       emitcode ("mov", "dps,#1");
510     }
511 }
512
513 /*------------------------------------------------------------------*/
514 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
515 /*                                                                  */
516 /* Any code that operates on DPTR (NB: not on the individual        */
517 /* components, like DPH) *must* call _flushLazyDPS() before using   */
518 /* DPTR within a lazy DPS evaluation block.                         */
519 /*                                                                  */
520 /* Note that aopPut and aopGet already contain the proper calls to  */
521 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
522 /* DPS evaluation block.                                            */
523 /*                                                                  */
524 /* Also, _flushLazyDPS must be called before any flow control       */
525 /* operations that could potentially branch out of the block.       */
526 /*                                                                  */
527 /* Lazy DPS evaluation is simply an optimization (though an         */
528 /* important one), so if in doubt, leave it out.                    */
529 /*------------------------------------------------------------------*/
530 static void
531 _startLazyDPSEvaluation (void)
532 {
533   _currentDPS = 0;
534   _desiredDPS = 0;
535 #ifdef BETTER_LITERAL_SHIFT
536   _lazyDPS++;
537 #else
538   _lazyDPS = 1;
539 #endif
540 }
541
542 /*------------------------------------------------------------------*/
543 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
544 /* desired one. Call before using DPTR within a lazy DPS evaluation */
545 /* block.                                                           */
546 /*------------------------------------------------------------------*/
547 static void
548 _flushLazyDPS (void)
549 {
550   if (!_lazyDPS)
551     {
552       /* nothing to do. */
553       return;
554     }
555
556   if (_desiredDPS != _currentDPS)
557     {
558       if (_desiredDPS)
559         {
560           emitcode ("inc", "dps");
561         }
562       else
563         {
564           emitcode ("dec", "dps");
565         }
566       _currentDPS = _desiredDPS;
567     }
568 }
569
570 /*-----------------------------------------------------------------*/
571 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
572 /*                                                                 */
573 /* Forces us back to the safe state (standard DPTR selected).      */
574 /*-----------------------------------------------------------------*/
575 static void
576 _endLazyDPSEvaluation (void)
577 {
578 #ifdef BETTER_LITERAL_SHIFT
579   _lazyDPS--;
580 #else
581   _lazyDPS = 0;
582 #endif
583   if (!_lazyDPS)
584   {
585     if (_currentDPS)
586     {
587       genSetDPTR (0);
588       _flushLazyDPS ();
589     }
590     _currentDPS = 0;
591     _desiredDPS = 0;
592   }
593 }
594
595
596 /*-----------------------------------------------------------------*/
597 /* newAsmop - creates a new asmOp                                  */
598 /*-----------------------------------------------------------------*/
599 static asmop *
600 newAsmop (short type)
601 {
602   asmop *aop;
603
604   aop = Safe_calloc (1, sizeof (asmop));
605   aop->type = type;
606   aop->allocated = 1;
607   return aop;
608 }
609
610 /*-----------------------------------------------------------------*/
611 /* pointerCode - returns the code for a pointer type               */
612 /*-----------------------------------------------------------------*/
613 static int
614 pointerCode (sym_link * etype)
615 {
616
617   return PTR_TYPE (SPEC_OCLS (etype));
618
619 }
620
621 /*-----------------------------------------------------------------*/
622 /* leftRightUseAcc - returns size of accumulator use by operands   */
623 /*-----------------------------------------------------------------*/
624 static int
625 leftRightUseAcc(iCode *ic)
626 {
627   operand *op;
628   int size;
629   int accuseSize = 0;
630   int accuse = 0;
631
632   if (!ic)
633     {
634       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
635               "null iCode pointer");
636       return 0;
637     }
638
639   if (ic->op == IFX)
640     {
641       op = IC_COND (ic);
642       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
643         {
644           accuse = 1;
645           size = getSize (OP_SYMBOL (op)->type);
646           if (size>accuseSize)
647             accuseSize = size;
648         }
649     }
650   else if (ic->op == JUMPTABLE)
651     {
652       op = IC_JTCOND (ic);
653       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
654         {
655           accuse = 1;
656           size = getSize (OP_SYMBOL (op)->type);
657           if (size>accuseSize)
658             accuseSize = size;
659         }
660     }
661   else
662     {
663       op = IC_LEFT (ic);
664       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
665         {
666           accuse = 1;
667           size = getSize (OP_SYMBOL (op)->type);
668           if (size>accuseSize)
669             accuseSize = size;
670         }
671       op = IC_RIGHT (ic);
672       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
673         {
674           accuse = 1;
675           size = getSize (OP_SYMBOL (op)->type);
676           if (size>accuseSize)
677             accuseSize = size;
678         }
679     }
680
681   if (accuseSize)
682     return accuseSize;
683   else
684     return accuse;
685 }
686
687 /*-----------------------------------------------------------------*/
688 /* aopForSym - for a true symbol                                   */
689 /*-----------------------------------------------------------------*/
690 static asmop *
691 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
692 {
693   asmop *aop;
694   memmap *space;
695   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
696   char *dpl = useDP2 ? "dpl1" : "dpl";
697   char *dph = useDP2 ? "dph1" : "dph";
698   char *dpx = useDP2 ? "dpx1" : "dpx";
699
700   wassertl (ic != NULL, "Got a null iCode");
701   wassertl (sym != NULL, "Got a null symbol");
702
703   space = SPEC_OCLS (sym->etype);
704
705   /* if already has one */
706   if (sym->aop)
707     {
708       if ((sym->aop->type == AOP_DPTR && useDP2)
709           || (sym->aop->type == AOP_DPTR2 && !useDP2))
710         sym->aop = NULL;
711       else
712         {
713           sym->aop->allocated++;
714           return sym->aop;
715         }
716     }
717
718   /* assign depending on the storage class */
719   /* if it is on the stack or indirectly addressable */
720   /* space we need to assign either r0 or r1 to it   */
721   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
722     {
723       sym->aop = aop = newAsmop (0);
724       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
725       aop->size = getSize (sym->type);
726
727       /* now assign the address of the variable to
728          the pointer register */
729       if (aop->type != AOP_STK)
730         {
731           if (sym->onStack)
732             {
733               signed char offset = ((sym->stack < 0) ?
734                          ((signed char) (sym->stack - _G.nRegsSaved)) :
735                          ((signed char) sym->stack)) & 0xff;
736
737               if ((abs(offset) <= 3) ||
738                   (accuse && (abs(offset) <= 7)))
739                 {
740                   emitcode ("mov", "%s,_bp",
741                             aop->aopu.aop_ptr->name);
742                   while (offset < 0)
743                     {
744                       emitcode ("dec", aop->aopu.aop_ptr->name);
745                       offset++;
746                     }
747                   while (offset > 0)
748                     {
749                       emitcode ("inc", aop->aopu.aop_ptr->name);
750                       offset--;
751                     }
752                 }
753               else
754                 {
755                   if (accuse)
756                     emitcode ("push", "acc");
757                   emitcode ("mov", "a,_bp");
758                   emitcode ("add", "a,#!constbyte", offset);
759                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
760                   if (accuse)
761                     emitcode ("pop", "acc");
762                 }
763             }
764           else
765             {
766               emitcode ("mov", "%s,#%s",
767                         aop->aopu.aop_ptr->name,
768                         sym->rname);
769             }
770           aop->paged = space->paged;
771         }
772       else
773         aop->aopu.aop_stk = sym->stack;
774       return aop;
775     }
776
777   if (sym->onStack && options.stack10bit)
778     {
779       short stack_val = -((sym->stack < 0) ?
780                           ((short) (sym->stack - _G.nRegsSaved)) :
781                           ((short) sym->stack)) ;
782       if (_G.dptrInUse ) {
783           emitcode ("push",dpl);
784           emitcode ("push",dph);
785           emitcode ("push",dpx);
786       }
787       /* It's on the 10 bit stack, which is located in
788        * far data space.
789        */
790       if (stack_val < 0 && stack_val > -5)
791         { /* between -5 & -1 */
792           if (options.model == MODEL_FLAT24)
793             {
794               emitcode ("mov", "%s,#!constbyte", dpx,
795                         (options.stack_loc >> 16) & 0xff);
796             }
797           emitcode ("mov", "%s,_bpx+1", dph);
798           emitcode ("mov", "%s,_bpx", dpl);
799           if (useDP2) {
800               emitcode ("mov","dps,#1");
801           }
802           stack_val = -stack_val;
803           while (stack_val--) {
804               emitcode ("inc","dptr");
805           }
806           if (useDP2) {
807               emitcode("mov","dps,#0");
808           }
809         }
810       else
811         {
812           if (accuse)
813               emitcode ("push", "acc");
814
815           emitcode ("mov", "a,_bpx");
816           emitcode ("clr","c");
817           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
818           emitcode ("mov","%s,a", dpl);
819           emitcode ("mov","a,_bpx+1");
820           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
821           emitcode ("mov", "%s,a", dph);
822           if (options.model == MODEL_FLAT24)
823             {
824               emitcode ("mov", "%s,#!constbyte", dpx,
825                         (options.stack_loc >> 16) & 0xff);
826             }
827
828           if (accuse)
829               emitcode ("pop", "acc");
830         }
831       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
832       aop->size = getSize (sym->type);
833       return aop;
834     }
835
836   /* if in bit space */
837   if (IN_BITSPACE (space))
838     {
839       sym->aop = aop = newAsmop (AOP_CRY);
840       aop->aopu.aop_dir = sym->rname;
841       aop->size = getSize (sym->type);
842       return aop;
843     }
844   /* if it is in direct space */
845   if (IN_DIRSPACE (space))
846     {
847       sym->aop = aop = newAsmop (AOP_DIR);
848       aop->aopu.aop_dir = sym->rname;
849       aop->size = getSize (sym->type);
850       return aop;
851     }
852
853   /* special case for a function */
854   if (IS_FUNC (sym->type) && !(sym->isitmp))
855     {
856       sym->aop = aop = newAsmop (AOP_IMMD);
857       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
858       aop->size = FPTRSIZE;
859       return aop;
860     }
861
862   /* only remaining is far space */
863   /* in which case DPTR gets the address */
864   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
865   if (useDP2)
866     {
867       genSetDPTR (1);
868       _flushLazyDPS ();
869       emitcode ("mov", "dptr,#%s", sym->rname);
870       genSetDPTR (0);
871     }
872   else
873     {
874       emitcode ("mov", "dptr,#%s", sym->rname);
875     }
876   aop->size = getSize (sym->type);
877
878   /* if it is in code space */
879   if (IN_CODESPACE (space))
880     aop->code = 1;
881
882   return aop;
883 }
884
885 /*-----------------------------------------------------------------*/
886 /* aopForRemat - rematerialzes an object                           */
887 /*-----------------------------------------------------------------*/
888 static asmop *
889 aopForRemat (symbol * sym)
890 {
891   iCode *ic = sym->rematiCode;
892   asmop *aop = newAsmop (AOP_IMMD);
893   int ptr_type = 0;
894   int val = 0;
895
896   for (;;)
897     {
898       if (ic->op == '+')
899         val += (int) operandLitValue (IC_RIGHT (ic));
900       else if (ic->op == '-')
901         val -= (int) operandLitValue (IC_RIGHT (ic));
902       else if (IS_CAST_ICODE(ic)) {
903               sym_link *from_type = operandType(IC_RIGHT(ic));
904               aop->aopu.aop_immd.from_cast_remat = 1;
905               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
906               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
907               continue;
908       } else break;
909
910       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
911     }
912
913   if (val)
914   {
915       SNPRINTF (buffer, sizeof(buffer),
916                 "(%s %c 0x%06x)",
917                 OP_SYMBOL (IC_LEFT (ic))->rname,
918                 val >= 0 ? '+' : '-',
919                 abs (val) & 0xffffff);
920   }
921   else
922   {
923       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
924       {
925           SNPRINTF(buffer, sizeof(buffer),
926                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
927       }
928       else
929       {
930           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
931       }
932   }
933
934   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
935   /* set immd2 field if required */
936   if (aop->aopu.aop_immd.from_cast_remat)
937   {
938       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
939       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
940   }
941
942   return aop;
943 }
944
945 /*-----------------------------------------------------------------*/
946 /* aopHasRegs - returns true if aop has regs between from-to       */
947 /*-----------------------------------------------------------------*/
948 static int aopHasRegs(asmop *aop, int from, int to)
949 {
950     int size =0;
951
952     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
953
954     for (; size < aop->size ; size++) {
955         int reg;
956         for (reg = from ; reg <= to ; reg++)
957             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
958     }
959     return 0;
960 }
961
962 /*-----------------------------------------------------------------*/
963 /* regsInCommon - two operands have some registers in common       */
964 /*-----------------------------------------------------------------*/
965 static bool
966 regsInCommon (operand * op1, operand * op2)
967 {
968   symbol *sym1, *sym2;
969   int i;
970
971   /* if they have registers in common */
972   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
973     return FALSE;
974
975   sym1 = OP_SYMBOL (op1);
976   sym2 = OP_SYMBOL (op2);
977
978   if (sym1->nRegs == 0 || sym2->nRegs == 0)
979     return FALSE;
980
981   for (i = 0; i < sym1->nRegs; i++)
982     {
983       int j;
984       if (!sym1->regs[i])
985         continue;
986
987       for (j = 0; j < sym2->nRegs; j++)
988         {
989           if (!sym2->regs[j])
990             continue;
991
992           if (sym2->regs[j] == sym1->regs[i])
993             return TRUE;
994         }
995     }
996
997   return FALSE;
998 }
999
1000 /*-----------------------------------------------------------------*/
1001 /* operandsEqu - equivalent                                        */
1002 /*-----------------------------------------------------------------*/
1003 static bool
1004 operandsEqu (operand * op1, operand * op2)
1005 {
1006   symbol *sym1, *sym2;
1007
1008   /* if they're not symbols */
1009   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1010     return FALSE;
1011
1012   sym1 = OP_SYMBOL (op1);
1013   sym2 = OP_SYMBOL (op2);
1014
1015   /* if both are itemps & one is spilt
1016      and the other is not then false */
1017   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1018       sym1->isspilt != sym2->isspilt)
1019     return FALSE;
1020
1021   /* if they are the same */
1022   if (sym1 == sym2)
1023     return TRUE;
1024
1025   /* if they have the same rname */
1026   if (sym1->rname[0] && sym2->rname[0] &&
1027       strcmp (sym1->rname, sym2->rname) == 0 &&
1028       !(IS_PARM (op2) && IS_ITEMP (op1)))
1029     return TRUE;
1030
1031   /* if left is a tmp & right is not */
1032   if (IS_ITEMP (op1) &&
1033       !IS_ITEMP (op2) &&
1034       sym1->isspilt &&
1035       (sym1->usl.spillLoc == sym2))
1036     return TRUE;
1037
1038   if (IS_ITEMP (op2) &&
1039       !IS_ITEMP (op1) &&
1040       sym2->isspilt &&
1041       sym1->level > 0 &&
1042       (sym2->usl.spillLoc == sym1))
1043     return TRUE;
1044
1045   /* are they spilt to the same location */
1046   if (IS_ITEMP (op2) &&
1047       IS_ITEMP (op1) &&
1048       sym2->isspilt &&
1049       sym1->isspilt &&
1050       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1051     return TRUE;
1052
1053   return FALSE;
1054 }
1055
1056 /*-----------------------------------------------------------------*/
1057 /* sameRegs - two asmops have the same registers                   */
1058 /*-----------------------------------------------------------------*/
1059 static bool
1060 sameRegs (asmop * aop1, asmop * aop2)
1061 {
1062   int i;
1063
1064   if (aop1 == aop2)
1065     {
1066       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1067         {
1068           return FALSE;
1069         }
1070       return TRUE;
1071     }
1072
1073   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1074     return FALSE;
1075
1076   if (aop1->type != aop2->type)
1077     return FALSE;
1078
1079   if (aop1->size != aop2->size)
1080     return FALSE;
1081
1082   for (i = 0; i < aop1->size; i++)
1083     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1084       return FALSE;
1085
1086   return TRUE;
1087 }
1088
1089 /*-----------------------------------------------------------------*/
1090 /* aopOp - allocates an asmop for an operand  :                    */
1091 /*-----------------------------------------------------------------*/
1092 static void
1093 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1094 {
1095   asmop *aop;
1096   symbol *sym;
1097   int i;
1098
1099   if (!op)
1100     return;
1101
1102   /* if this a literal */
1103   if (IS_OP_LITERAL (op))
1104     {
1105       op->aop = aop = newAsmop (AOP_LIT);
1106       aop->aopu.aop_lit = op->operand.valOperand;
1107       aop->size = getSize (operandType (op));
1108       return;
1109     }
1110
1111   /* if already has a asmop then continue */
1112   if (op->aop)
1113     {
1114       if ((op->aop->type == AOP_DPTR && useDP2)
1115           || (op->aop->type == AOP_DPTR2 && !useDP2))
1116         op->aop = NULL;
1117       else
1118         {
1119           op->aop->allocated++;
1120           return;
1121         }
1122     }
1123
1124   /* if the underlying symbol has a aop */
1125   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1126     {
1127       op->aop = OP_SYMBOL (op)->aop;
1128       if ((op->aop->type == AOP_DPTR && useDP2)
1129           || (op->aop->type == AOP_DPTR2 && !useDP2))
1130         op->aop = NULL;
1131       else
1132         {
1133           op->aop->allocated++;
1134           return;
1135         }
1136     }
1137
1138   /* if this is a true symbol */
1139   if (IS_TRUE_SYMOP (op))
1140     {
1141       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1142       return;
1143     }
1144
1145   /* this is a temporary : this has
1146      only five choices :
1147      a) register
1148      b) spillocation
1149      c) rematerialize
1150      d) conditional
1151      e) can be a return use only */
1152
1153   sym = OP_SYMBOL (op);
1154
1155   /* if the type is a conditional */
1156   if (sym->regType == REG_CND)
1157     {
1158       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1159       aop->size = 0;
1160       return;
1161     }
1162
1163   /* if it is spilt then two situations
1164      a) is rematerialize
1165      b) has a spill location */
1166   if (sym->isspilt || sym->nRegs == 0)
1167     {
1168
1169       /* rematerialize it NOW */
1170       if (sym->remat)
1171         {
1172           sym->aop = op->aop = aop =
1173             aopForRemat (sym);
1174           aop->size = getSize (sym->type);
1175           return;
1176         }
1177
1178       if (sym->accuse)
1179         {
1180           int i;
1181           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1182           aop->size = getSize (sym->type);
1183           for (i = 0; i < 2; i++)
1184             aop->aopu.aop_str[i] = accUse[i];
1185           return;
1186         }
1187
1188       if (sym->ruonly)
1189         {
1190           unsigned i;
1191
1192           if (useDP2)
1193             {
1194               /* a AOP_STR uses DPTR, but DPTR is already in use;
1195                * we're just hosed.
1196                */
1197                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1198             }
1199
1200           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1201           aop->size = getSize (sym->type);
1202           for (i = 0; i < fReturnSizeDS390; i++)
1203             aop->aopu.aop_str[i] = fReturn[i];
1204           return;
1205         }
1206
1207       if (sym->dptr) { /* has been allocated to a DPTRn */
1208           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1209           aop->size = getSize (sym->type);
1210           aop->aopu.dptr = sym->dptr;
1211           return ;
1212       }
1213
1214       if (sym->usl.spillLoc)
1215         {
1216           asmop *oldAsmOp = NULL;
1217
1218           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1219             {
1220               /* force a new aop if sizes differ */
1221               oldAsmOp = sym->usl.spillLoc->aop;
1222               sym->usl.spillLoc->aop = NULL;
1223             }
1224           sym->aop = op->aop = aop =
1225                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1226           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1227             {
1228               /* Don't reuse the new aop, go with the last one */
1229               sym->usl.spillLoc->aop = oldAsmOp;
1230             }
1231           aop->size = getSize (sym->type);
1232           return;
1233         }
1234
1235       /* else must be a dummy iTemp */
1236       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1237       aop->size = getSize (sym->type);
1238       return;
1239     }
1240
1241   /* if the type is a bit register */
1242   if (sym->regType == REG_BIT)
1243     {
1244       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1245       aop->size = sym->nRegs;//1???
1246       aop->aopu.aop_reg[0] = sym->regs[0];
1247       aop->aopu.aop_dir = sym->regs[0]->name;
1248       return;
1249     }
1250
1251   /* must be in a register */
1252   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1253   aop->size = sym->nRegs;
1254   for (i = 0; i < sym->nRegs; i++)
1255     aop->aopu.aop_reg[i] = sym->regs[i];
1256 }
1257
1258 /*-----------------------------------------------------------------*/
1259 /* freeAsmop - free up the asmop given to an operand               */
1260 /*----------------------------------------------------------------*/
1261 static void
1262 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1263 {
1264   asmop *aop;
1265
1266   if (!op)
1267     aop = aaop;
1268   else
1269     aop = op->aop;
1270
1271   if (!aop)
1272     return;
1273
1274   aop->allocated--;
1275
1276   if (aop->allocated)
1277     goto dealloc;
1278
1279   /* depending on the asmop type only three cases need work
1280      AOP_R0, AOP_R1 & AOP_STK */
1281   switch (aop->type)
1282     {
1283     case AOP_R0:
1284       if (_G.r0Pushed)
1285         {
1286           if (pop)
1287             {
1288               emitcode ("pop", "ar0");
1289               _G.r0Pushed--;
1290             }
1291         }
1292       bitVectUnSetBit (ic->rUsed, R0_IDX);
1293       break;
1294
1295     case AOP_R1:
1296       if (_G.r1Pushed)
1297         {
1298           if (pop)
1299             {
1300               emitcode ("pop", "ar1");
1301               _G.r1Pushed--;
1302             }
1303         }
1304       bitVectUnSetBit (ic->rUsed, R1_IDX);
1305       break;
1306
1307     case AOP_STK:
1308       {
1309         int sz = aop->size;
1310         int stk = aop->aopu.aop_stk + aop->size;
1311         bitVectUnSetBit (ic->rUsed, R0_IDX);
1312         bitVectUnSetBit (ic->rUsed, R1_IDX);
1313
1314         getFreePtr (ic, &aop, FALSE);
1315
1316         if (options.stack10bit)
1317           {
1318             /* I'm not sure what to do here yet... */
1319             /* #STUB */
1320             fprintf (stderr,
1321                      "*** Warning: probably generating bad code for "
1322                      "10 bit stack mode.\n");
1323           }
1324
1325         if (stk)
1326           {
1327             emitcode ("mov", "a,_bp");
1328             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1329             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1330           }
1331         else
1332           {
1333             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1334           }
1335
1336         while (sz--)
1337           {
1338             emitcode ("pop", "acc");
1339             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1340             if (!sz)
1341               break;
1342             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1343           }
1344         op->aop = aop;
1345         freeAsmop (op, NULL, ic, TRUE);
1346         if (_G.r1Pushed)
1347           {
1348             emitcode ("pop", "ar1");
1349             _G.r1Pushed--;
1350           }
1351         if (_G.r0Pushed)
1352           {
1353             emitcode ("pop", "ar0");
1354             _G.r0Pushed--;
1355           }
1356       }
1357     case AOP_DPTR2:
1358         if (_G.dptr1InUse) {
1359             emitcode ("pop","dpx1");
1360             emitcode ("pop","dph1");
1361             emitcode ("pop","dpl1");
1362         }
1363         break;
1364     case AOP_DPTR:
1365         if (_G.dptrInUse) {
1366             emitcode ("pop","dpx");
1367             emitcode ("pop","dph");
1368             emitcode ("pop","dpl");
1369         }
1370         break;
1371     }
1372
1373 dealloc:
1374   /* all other cases just dealloc */
1375   if (op)
1376     {
1377       op->aop = NULL;
1378       if (IS_SYMOP (op))
1379         {
1380           OP_SYMBOL (op)->aop = NULL;
1381           /* if the symbol has a spill */
1382           if (SPIL_LOC (op))
1383             SPIL_LOC (op)->aop = NULL;
1384         }
1385     }
1386 }
1387
1388 #define DEFAULT_ACC_WARNING 0
1389 static int saveAccWarn = DEFAULT_ACC_WARNING;
1390
1391
1392 /*-----------------------------------------------------------------*/
1393 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1394 /*                 clobber the accumulator                         */
1395 /*-----------------------------------------------------------------*/
1396 static bool
1397 aopGetUsesAcc (operand * oper, int offset)
1398 {
1399   asmop * aop = AOP (oper);
1400
1401   if (offset > (aop->size - 1))
1402     return FALSE;
1403
1404   switch (aop->type)
1405     {
1406
1407     case AOP_R0:
1408     case AOP_R1:
1409       if (aop->paged)
1410         return TRUE;
1411       return FALSE;
1412     case AOP_DPTR:
1413     case AOP_DPTR2:
1414     case AOP_DPTRn:
1415       return TRUE;
1416     case AOP_IMMD:
1417       return FALSE;
1418     case AOP_DIR:
1419       return FALSE;
1420     case AOP_REG:
1421       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1422       return FALSE;
1423     case AOP_CRY:
1424       return TRUE;
1425     case AOP_ACC:
1426       if (offset)
1427         return FALSE;
1428       return TRUE;
1429     case AOP_LIT:
1430       return FALSE;
1431     case AOP_STR:
1432       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1433         return TRUE;
1434       return FALSE;
1435     case AOP_DUMMY:
1436       return FALSE;
1437     default:
1438       /* Error case --- will have been caught already */
1439       wassert(0);
1440       return FALSE;
1441     }
1442 }
1443
1444 /*-------------------------------------------------------------------*/
1445 /* aopGet - for fetching value of the aop                            */
1446 /*                                                                   */
1447 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1448 /* in the accumulator. Set it to the name of a free register         */
1449 /* if acc must be preserved; the register will be used to preserve   */
1450 /* acc temporarily and to return the result byte.                    */
1451 /*-------------------------------------------------------------------*/
1452 static char *
1453 aopGet (operand * oper,
1454         int   offset,
1455         bool  bit16,
1456         bool  dname,
1457         char  *saveAcc)
1458 {
1459   asmop * aop = AOP (oper);
1460
1461   /* offset is greater than
1462      size then zero */
1463   if (offset > (aop->size - 1) &&
1464       aop->type != AOP_LIT)
1465     return zero;
1466
1467   /* depending on type */
1468   switch (aop->type)
1469     {
1470     case AOP_DUMMY:
1471       return zero;
1472
1473     case AOP_R0:
1474     case AOP_R1:
1475       /* if we need to increment it */
1476       while (offset > aop->coff)
1477         {
1478           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1479           aop->coff++;
1480         }
1481
1482       while (offset < aop->coff)
1483         {
1484           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1485           aop->coff--;
1486         }
1487
1488       aop->coff = offset;
1489       if (aop->paged)
1490         {
1491           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1492           return (dname ? "acc" : "a");
1493         }
1494       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1495       return Safe_strdup(buffer);
1496
1497     case AOP_DPTRn:
1498         assert(offset <= 3);
1499         return dptrn[aop->aopu.dptr][offset];
1500
1501     case AOP_DPTR:
1502     case AOP_DPTR2:
1503
1504       if (aop->type == AOP_DPTR2)
1505         {
1506           genSetDPTR (1);
1507         }
1508
1509       if (saveAcc)
1510         {
1511             TR_AP("#1");
1512 //          if (aop->type != AOP_DPTR2)
1513 //          {
1514 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1515 //              emitcode(";", "spanky: saveAcc for DPTR");
1516 //          }
1517
1518             emitcode ("xch", "a, %s", saveAcc);
1519         }
1520
1521       _flushLazyDPS ();
1522
1523       while (offset > aop->coff)
1524         {
1525           emitcode ("inc", "dptr");
1526           aop->coff++;
1527         }
1528
1529       while (offset < aop->coff)
1530         {
1531           emitcode ("lcall", "__decdptr");
1532           aop->coff--;
1533         }
1534
1535       aop->coff = offset;
1536       if (aop->code)
1537         {
1538           emitcode ("clr", "a");
1539           emitcode ("movc", "a,@a+dptr");
1540         }
1541       else
1542         {
1543           emitcode ("movx", "a,@dptr");
1544         }
1545
1546       if (aop->type == AOP_DPTR2)
1547         {
1548           genSetDPTR (0);
1549         }
1550
1551       if (saveAcc)
1552         {
1553           TR_AP("#2");
1554           emitcode ("xch", "a, %s", saveAcc);
1555 //        if (strcmp(saveAcc, "_ap"))
1556 //          {
1557 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1558 //          }
1559
1560           return saveAcc;
1561         }
1562       return (dname ? "acc" : "a");
1563
1564     case AOP_IMMD:
1565       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1566         {
1567           SNPRINTF(buffer, sizeof(buffer),
1568                    "%s",aop->aopu.aop_immd.aop_immd2);
1569         }
1570       else if (bit16)
1571         {
1572           SNPRINTF(buffer, sizeof(buffer),
1573                    "#%s", aop->aopu.aop_immd.aop_immd1);
1574         }
1575       else if (offset)
1576         {
1577           switch (offset) {
1578           case 1:
1579               tsprintf(buffer, sizeof(buffer),
1580                        "#!his",aop->aopu.aop_immd.aop_immd1);
1581               break;
1582           case 2:
1583               tsprintf(buffer, sizeof(buffer),
1584                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1585               break;
1586           case 3:
1587               tsprintf(buffer, sizeof(buffer),
1588                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1589               break;
1590           default: /* should not need this (just in case) */
1591               SNPRINTF (buffer, sizeof(buffer),
1592                         "#(%s >> %d)",
1593                        aop->aopu.aop_immd.aop_immd1,
1594                        offset * 8);
1595           }
1596         }
1597       else
1598         {
1599           SNPRINTF (buffer, sizeof(buffer),
1600                     "#%s",
1601                     aop->aopu.aop_immd.aop_immd1);
1602         }
1603       return Safe_strdup(buffer);
1604
1605     case AOP_DIR:
1606       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1607         {
1608           SNPRINTF (buffer, sizeof(buffer),
1609                     "(%s >> %d)",
1610                     aop->aopu.aop_dir, offset * 8);
1611         }
1612       else if (offset)
1613         {
1614           SNPRINTF (buffer, sizeof(buffer),
1615                     "(%s + %d)",
1616                    aop->aopu.aop_dir,
1617                    offset);
1618         }
1619       else
1620         {
1621           SNPRINTF (buffer, sizeof(buffer),
1622                     "%s",
1623                     aop->aopu.aop_dir);
1624         }
1625
1626       return Safe_strdup(buffer);
1627
1628     case AOP_REG:
1629       if (dname)
1630         return aop->aopu.aop_reg[offset]->dname;
1631       else
1632         return aop->aopu.aop_reg[offset]->name;
1633
1634     case AOP_CRY:
1635       emitcode ("clr", "a");
1636       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1637       emitcode ("rlc", "a");
1638       return (dname ? "acc" : "a");
1639
1640     case AOP_ACC:
1641       if (!offset && dname)
1642         return "acc";
1643       return aop->aopu.aop_str[offset];
1644
1645     case AOP_LIT:
1646       return aopLiteral (aop->aopu.aop_lit, offset);
1647
1648     case AOP_STR:
1649       aop->coff = offset;
1650       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1651           dname)
1652         return "acc";
1653
1654       return aop->aopu.aop_str[offset];
1655
1656     }
1657
1658   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1659           "aopget got unsupported aop->type");
1660   exit (1);
1661
1662   return NULL;  // not reached, but makes compiler happy.
1663 }
1664
1665 /*-----------------------------------------------------------------*/
1666 /* aopPut - puts a string for a aop and indicates if acc is in use */
1667 /*-----------------------------------------------------------------*/
1668 static bool
1669 aopPut (operand * result, const char *s, int offset)
1670 {
1671   bool bvolatile = isOperandVolatile (result, FALSE);
1672   bool accuse = FALSE;
1673   asmop * aop = AOP (result);
1674
1675   if (aop->size && offset > (aop->size - 1))
1676     {
1677       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1678               "aopPut got offset > aop->size");
1679       exit (1);
1680     }
1681
1682   /* will assign value to value */
1683   /* depending on where it is ofcourse */
1684   switch (aop->type)
1685     {
1686     case AOP_DUMMY:
1687       MOVA (s);         /* read s in case it was volatile */
1688       accuse = TRUE;
1689       break;
1690
1691     case AOP_DIR:
1692       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1693         {
1694           SNPRINTF (buffer, sizeof(buffer),
1695                     "(%s >> %d)",
1696                     aop->aopu.aop_dir, offset * 8);
1697         }
1698       else if (offset)
1699         {
1700           SNPRINTF (buffer, sizeof(buffer),
1701                     "(%s + %d)",
1702                     aop->aopu.aop_dir, offset);
1703         }
1704       else
1705         {
1706           SNPRINTF (buffer, sizeof(buffer),
1707                     "%s",
1708                     aop->aopu.aop_dir);
1709         }
1710
1711       if (strcmp (buffer, s) || bvolatile)
1712         {
1713           emitcode ("mov", "%s,%s", buffer, s);
1714         }
1715       if (!strcmp (buffer, "acc"))
1716         {
1717           accuse = TRUE;
1718         }
1719       break;
1720
1721     case AOP_REG:
1722       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1723           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1724         {
1725           if (*s == '@' ||
1726               strcmp (s, "r0") == 0 ||
1727               strcmp (s, "r1") == 0 ||
1728               strcmp (s, "r2") == 0 ||
1729               strcmp (s, "r3") == 0 ||
1730               strcmp (s, "r4") == 0 ||
1731               strcmp (s, "r5") == 0 ||
1732               strcmp (s, "r6") == 0 ||
1733               strcmp (s, "r7") == 0)
1734             {
1735               emitcode ("mov", "%s,%s",
1736                         aop->aopu.aop_reg[offset]->dname, s);
1737             }
1738             else
1739             {
1740               emitcode ("mov", "%s,%s",
1741                         aop->aopu.aop_reg[offset]->name, s);
1742             }
1743         }
1744       break;
1745
1746     case AOP_DPTRn:
1747         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1748         break;
1749
1750     case AOP_DPTR:
1751     case AOP_DPTR2:
1752
1753       if (aop->type == AOP_DPTR2)
1754         {
1755           genSetDPTR (1);
1756         }
1757       _flushLazyDPS ();
1758
1759       if (aop->code)
1760         {
1761           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1762                   "aopPut writing to code space");
1763           exit (1);
1764         }
1765
1766       while (offset > aop->coff)
1767         {
1768           aop->coff++;
1769           emitcode ("inc", "dptr");
1770         }
1771
1772       while (offset < aop->coff)
1773         {
1774           aop->coff--;
1775           emitcode ("lcall", "__decdptr");
1776         }
1777
1778       aop->coff = offset;
1779
1780       /* if not in accumulator */
1781       MOVA (s);
1782
1783       emitcode ("movx", "@dptr,a");
1784
1785       if (aop->type == AOP_DPTR2)
1786         {
1787           genSetDPTR (0);
1788         }
1789       break;
1790
1791     case AOP_R0:
1792     case AOP_R1:
1793       while (offset > aop->coff)
1794         {
1795           aop->coff++;
1796           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1797         }
1798       while (offset < aop->coff)
1799         {
1800           aop->coff--;
1801           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1802         }
1803       aop->coff = offset;
1804
1805       if (aop->paged)
1806         {
1807           MOVA (s);
1808           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1809         }
1810       else if (*s == '@')
1811         {
1812           MOVA (s);
1813           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1814         }
1815       else if (strcmp (s, "r0") == 0 ||
1816                strcmp (s, "r1") == 0 ||
1817                strcmp (s, "r2") == 0 ||
1818                strcmp (s, "r3") == 0 ||
1819                strcmp (s, "r4") == 0 ||
1820                strcmp (s, "r5") == 0 ||
1821                strcmp (s, "r6") == 0 ||
1822                strcmp (s, "r7") == 0)
1823         {
1824           char buffer[10];
1825           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1826           emitcode ("mov", "@%s,%s",
1827                     aop->aopu.aop_ptr->name, buffer);
1828         }
1829         else
1830         {
1831             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1832         }
1833       break;
1834
1835     case AOP_STK:
1836       if (strcmp (s, "a") == 0)
1837         emitcode ("push", "acc");
1838       else
1839         if (*s=='@') {
1840           MOVA(s);
1841           emitcode ("push", "acc");
1842         } else {
1843           emitcode ("push", s);
1844         }
1845
1846       break;
1847
1848     case AOP_CRY:
1849       /* if not bit variable */
1850       if (!aop->aopu.aop_dir)
1851         {
1852           /* inefficient: move carry into A and use jz/jnz */
1853           emitcode ("clr", "a");
1854           emitcode ("rlc", "a");
1855           accuse = TRUE;
1856         }
1857       else
1858         {
1859           if (s == zero)
1860             emitcode ("clr", "%s", aop->aopu.aop_dir);
1861           else if (s == one)
1862             emitcode ("setb", "%s", aop->aopu.aop_dir);
1863           else if (!strcmp (s, "c"))
1864             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1865           else if (strcmp (s, aop->aopu.aop_dir))
1866             {
1867               MOVA (s);
1868               /* set C, if a >= 1 */
1869               emitcode ("add", "a,#!constbyte",0xff);
1870               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1871             }
1872         }
1873       break;
1874
1875     case AOP_STR:
1876       aop->coff = offset;
1877       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1878         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1879       break;
1880
1881     case AOP_ACC:
1882       accuse = TRUE;
1883       aop->coff = offset;
1884       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1885         break;
1886
1887       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1888         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1889       break;
1890
1891     default:
1892       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1893               "aopPut got unsupported aop->type");
1894       exit (1);
1895     }
1896
1897     return accuse;
1898 }
1899
1900
1901 /*--------------------------------------------------------------------*/
1902 /* reAdjustPreg - points a register back to where it should (coff==0) */
1903 /*--------------------------------------------------------------------*/
1904 static void
1905 reAdjustPreg (asmop * aop)
1906 {
1907   if ((aop->coff==0) || (aop->size <= 1))
1908     return;
1909
1910   switch (aop->type)
1911     {
1912     case AOP_R0:
1913     case AOP_R1:
1914       while (aop->coff--)
1915         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1916       break;
1917     case AOP_DPTR:
1918     case AOP_DPTR2:
1919       if (aop->type == AOP_DPTR2)
1920         {
1921           genSetDPTR (1);
1922           _flushLazyDPS ();
1923         }
1924       while (aop->coff--)
1925         {
1926           emitcode ("lcall", "__decdptr");
1927         }
1928
1929       if (aop->type == AOP_DPTR2)
1930         {
1931           genSetDPTR (0);
1932         }
1933       break;
1934     }
1935   aop->coff = 0;
1936 }
1937
1938 /*-----------------------------------------------------------------*/
1939 /* opIsGptr: returns non-zero if the passed operand is       */
1940 /* a generic pointer type.             */
1941 /*-----------------------------------------------------------------*/
1942 static int
1943 opIsGptr (operand * op)
1944 {
1945   sym_link *type = operandType (op);
1946
1947   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1948     {
1949       return 1;
1950     }
1951   return 0;
1952 }
1953
1954 /*-----------------------------------------------------------------*/
1955 /* getDataSize - get the operand data size                         */
1956 /*-----------------------------------------------------------------*/
1957 static int
1958 getDataSize (operand * op)
1959 {
1960   int size;
1961   size = AOP_SIZE (op);
1962   if (size == GPTRSIZE)
1963     {
1964       sym_link *type = operandType (op);
1965       if (IS_GENPTR (type))
1966         {
1967           /* generic pointer; arithmetic operations
1968            * should ignore the high byte (pointer type).
1969            */
1970           size--;
1971         }
1972     }
1973   return size;
1974 }
1975
1976 /*-----------------------------------------------------------------*/
1977 /* outAcc - output Acc                                             */
1978 /*-----------------------------------------------------------------*/
1979 static void
1980 outAcc (operand * result)
1981 {
1982   int size, offset;
1983   size = getDataSize (result);
1984   if (size)
1985     {
1986       aopPut (result, "a", 0);
1987       size--;
1988       offset = 1;
1989       /* unsigned or positive */
1990       while (size--)
1991         {
1992           aopPut (result, zero, offset++);
1993         }
1994     }
1995 }
1996
1997 /*-----------------------------------------------------------------*/
1998 /* outBitC - output a bit C                                        */
1999 /*-----------------------------------------------------------------*/
2000 static void
2001 outBitC (operand * result)
2002 {
2003   /* if the result is bit */
2004   if (AOP_TYPE (result) == AOP_CRY)
2005     {
2006       aopPut (result, "c", 0);
2007     }
2008   else
2009     {
2010       emitcode ("clr", "a");
2011       emitcode ("rlc", "a");
2012       outAcc (result);
2013     }
2014 }
2015
2016 /*-----------------------------------------------------------------*/
2017 /* toBoolean - emit code for orl a,operator(sizeop)                */
2018 /*-----------------------------------------------------------------*/
2019 static void
2020 toBoolean (operand * oper)
2021 {
2022   int  size = AOP_SIZE (oper) - 1;
2023   int  offset = 1;
2024   bool pushedB;
2025
2026   /* The generic part of a generic pointer should
2027    * not participate in it's truth value.
2028    *
2029    * i.e. 0x10000000 is zero.
2030    */
2031   if (opIsGptr (oper))
2032     {
2033       D (emitcode (";", "toBoolean: generic ptr special case."));
2034       size--;
2035     }
2036
2037   _startLazyDPSEvaluation ();
2038   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2039   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2040     {
2041       pushedB = pushB ();
2042       emitcode("mov", "b,a");
2043       while (--size)
2044         {
2045           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2046           emitcode ("orl", "b,a");
2047         }
2048       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2049       emitcode ("orl", "a,b");
2050       popB (pushedB);
2051     }
2052   else
2053     {
2054       while (size--)
2055         {
2056           emitcode ("orl", "a,%s",
2057                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2058         }
2059     }
2060   _endLazyDPSEvaluation ();
2061 }
2062
2063
2064 /*-----------------------------------------------------------------*/
2065 /* genNot - generate code for ! operation                          */
2066 /*-----------------------------------------------------------------*/
2067 static void
2068 genNot (iCode * ic)
2069 {
2070   symbol *tlbl;
2071
2072   D (emitcode (";", "genNot"));
2073
2074   /* assign asmOps to operand & result */
2075   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2076   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2077
2078   /* if in bit space then a special case */
2079   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2080     {
2081       /* if left==result then cpl bit */
2082       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2083         {
2084           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2085         }
2086       else
2087         {
2088           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2089           emitcode ("cpl", "c");
2090           outBitC (IC_RESULT (ic));
2091         }
2092       goto release;
2093     }
2094
2095   toBoolean (IC_LEFT (ic));
2096
2097   /* set C, if a == 0 */
2098   tlbl = newiTempLabel (NULL);
2099   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2100   emitLabel (tlbl);
2101   outBitC (IC_RESULT (ic));
2102
2103 release:
2104   /* release the aops */
2105   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2106   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2107 }
2108
2109
2110 /*-----------------------------------------------------------------*/
2111 /* genCpl - generate code for complement                           */
2112 /*-----------------------------------------------------------------*/
2113 static void
2114 genCpl (iCode * ic)
2115 {
2116   int offset = 0;
2117   int size;
2118   symbol *tlbl;
2119   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2120
2121   D(emitcode (";", "genCpl"));
2122
2123   /* assign asmOps to operand & result */
2124   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2125   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2126
2127   /* special case if in bit space */
2128   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2129     {
2130       char *l;
2131
2132       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2133           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2134         {
2135           /* promotion rules are responsible for this strange result:
2136              bit -> int -> ~int -> bit
2137              uchar -> int -> ~int -> bit
2138           */
2139           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2140           goto release;
2141         }
2142
2143       tlbl=newiTempLabel(NULL);
2144       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2145       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2146           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2147           IS_AOP_PREG (IC_LEFT (ic)))
2148         {
2149           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2150         }
2151       else
2152         {
2153           MOVA (l);
2154           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2155         }
2156       emitLabel (tlbl);
2157       outBitC (IC_RESULT(ic));
2158       goto release;
2159     }
2160
2161   size = AOP_SIZE (IC_RESULT (ic));
2162   _startLazyDPSEvaluation ();
2163   while (size--)
2164     {
2165       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2166       MOVA (l);
2167       emitcode ("cpl", "a");
2168       aopPut (IC_RESULT (ic), "a", offset++);
2169     }
2170   _endLazyDPSEvaluation ();
2171
2172
2173 release:
2174   /* release the aops */
2175   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2176   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2177 }
2178
2179 /*-----------------------------------------------------------------*/
2180 /* genUminusFloat - unary minus for floating points                */
2181 /*-----------------------------------------------------------------*/
2182 static void
2183 genUminusFloat (operand * op, operand * result)
2184 {
2185   int size, offset = 0;
2186   char *l;
2187
2188   D (emitcode (";", "genUminusFloat"));
2189
2190   /* for this we just copy and then flip the bit */
2191
2192   _startLazyDPSEvaluation ();
2193   size = AOP_SIZE (op) - 1;
2194
2195   while (size--)
2196     {
2197       aopPut (result,
2198               aopGet (op, offset, FALSE, FALSE, NULL),
2199               offset);
2200       offset++;
2201     }
2202
2203   l = aopGet (op, offset, FALSE, FALSE, NULL);
2204   MOVA (l);
2205
2206   emitcode ("cpl", "acc.7");
2207   aopPut (result, "a", offset);
2208   _endLazyDPSEvaluation ();
2209 }
2210
2211 /*-----------------------------------------------------------------*/
2212 /* genUminus - unary minus code generation                         */
2213 /*-----------------------------------------------------------------*/
2214 static void
2215 genUminus (iCode * ic)
2216 {
2217   int offset, size;
2218   sym_link *optype;
2219
2220   D (emitcode (";", "genUminus"));
2221
2222   /* assign asmops */
2223   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2224   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2225
2226   /* if both in bit space then special
2227      case */
2228   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2229       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2230     {
2231
2232       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2233       emitcode ("cpl", "c");
2234       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2235       goto release;
2236     }
2237
2238   optype = operandType (IC_LEFT (ic));
2239
2240   /* if float then do float stuff */
2241   if (IS_FLOAT (optype))
2242     {
2243       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2244       goto release;
2245     }
2246
2247   /* otherwise subtract from zero */
2248   size = AOP_SIZE (IC_LEFT (ic));
2249   offset = 0;
2250   _startLazyDPSEvaluation ();
2251   while (size--)
2252     {
2253       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2254       if (!strcmp (l, "a"))
2255         {
2256           if (offset == 0)
2257             SETC;
2258           emitcode ("cpl", "a");
2259           emitcode ("addc", "a,#0");
2260         }
2261       else
2262         {
2263           if (offset == 0)
2264             CLRC;
2265           emitcode ("clr", "a");
2266           emitcode ("subb", "a,%s", l);
2267         }
2268       aopPut (IC_RESULT (ic), "a", offset++);
2269     }
2270   _endLazyDPSEvaluation ();
2271
2272   /* if any remaining bytes in the result */
2273   /* we just need to propagate the sign   */
2274   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2275     {
2276       emitcode ("rlc", "a");
2277       emitcode ("subb", "a,acc");
2278       while (size--)
2279         aopPut (IC_RESULT (ic), "a", offset++);
2280     }
2281
2282 release:
2283   /* release the aops */
2284   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2285   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2286 }
2287
2288 /*-----------------------------------------------------------------*/
2289 /* savermask - saves registers in the mask                         */
2290 /*-----------------------------------------------------------------*/
2291 static void savermask(bitVect *rs_mask)
2292 {
2293   int i;
2294
2295   if (options.useXstack)
2296     {
2297       if (bitVectBitValue (rs_mask, R0_IDX))
2298           emitcode ("mov", "b,r0");
2299       emitcode ("mov", "r0,%s", spname);
2300       for (i = 0; i < ds390_nRegs; i++)
2301         {
2302           if (bitVectBitValue (rs_mask, i))
2303             {
2304               if (i == R0_IDX)
2305                   emitcode ("mov", "a,b");
2306               else
2307                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2308               emitcode ("movx", "@r0,a");
2309               emitcode ("inc", "r0");
2310             }
2311         }
2312       emitcode ("mov", "%s,r0", spname);
2313       if (bitVectBitValue (rs_mask, R0_IDX))
2314           emitcode ("mov", "r0,b");
2315     }
2316   else
2317     {
2318       bool bits_pushed = FALSE;
2319       for (i = 0; i < ds390_nRegs; i++)
2320         {
2321           if (bitVectBitValue (rs_mask, i))
2322             {
2323               bits_pushed = pushReg (i, bits_pushed);
2324             }
2325         }
2326     }
2327 }
2328
2329 /*-----------------------------------------------------------------*/
2330 /* saveRegisters - will look for a call and save the registers     */
2331 /*-----------------------------------------------------------------*/
2332 static void
2333 saveRegisters (iCode * lic)
2334 {
2335   iCode *ic;
2336   bitVect *rsave;
2337
2338   /* look for call */
2339   for (ic = lic; ic; ic = ic->next)
2340     if (ic->op == CALL || ic->op == PCALL)
2341       break;
2342
2343   if (!ic)
2344     {
2345       fprintf (stderr, "found parameter push with no function call\n");
2346       return;
2347     }
2348
2349   /* if the registers have been saved already or don't need to be then
2350      do nothing */
2351   if (ic->regsSaved
2352       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2353     return;
2354
2355   /* special case if DPTR alive across a function call then must save it
2356      even though callee saves */
2357   if (IS_SYMOP(IC_LEFT(ic)) &&
2358       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2359     {
2360       int i;
2361       rsave = newBitVect(ic->rMask->size);
2362       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2363           if (bitVectBitValue(ic->rMask,i))
2364               rsave = bitVectSetBit(rsave,i);
2365       }
2366       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2367     }
2368   else
2369     {
2370       /* save the registers in use at this time but skip the
2371          ones for the result */
2372       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2373                              ds390_rUmaskForOp (IC_RESULT(ic)));
2374     }
2375   ic->regsSaved = 1;
2376   savermask(rsave);
2377 }
2378
2379 /*-----------------------------------------------------------------*/
2380 /* usavermask - restore registers with mask                        */
2381 /*-----------------------------------------------------------------*/
2382 static void unsavermask(bitVect *rs_mask)
2383 {
2384   int i;
2385
2386   if (options.useXstack)
2387     {
2388       emitcode ("mov", "r0,%s", spname);
2389       for (i = ds390_nRegs; i >= 0; i--)
2390         {
2391           if (bitVectBitValue (rs_mask, i))
2392             {
2393               regs * reg = REG_WITH_INDEX (i);
2394               emitcode ("dec", "r0");
2395               emitcode ("movx", "a,@r0");
2396               if (i == R0_IDX)
2397                 {
2398                   emitcode ("push", "acc");
2399                 }
2400               else
2401                 {
2402                   emitcode ("mov", "%s,a", reg->name);
2403                 }
2404             }
2405         }
2406       emitcode ("mov", "%s,r0", spname);
2407       if (bitVectBitValue (rs_mask, R0_IDX))
2408         {
2409           emitcode ("pop", "ar0");
2410         }
2411     }
2412   else
2413     {
2414       bool bits_popped = FALSE;
2415       for (i = ds390_nRegs; i >= 0; i--)
2416         {
2417           if (bitVectBitValue (rs_mask, i))
2418             {
2419               bits_popped = popReg (i, bits_popped);
2420             }
2421         }
2422     }
2423 }
2424
2425 /*-----------------------------------------------------------------*/
2426 /* unsaveRegisters - pop the pushed registers                      */
2427 /*-----------------------------------------------------------------*/
2428 static void
2429 unsaveRegisters (iCode * ic)
2430 {
2431   bitVect *rsave;
2432
2433   if (IS_SYMOP(IC_LEFT (ic)) &&
2434       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2435       int i;
2436       rsave = newBitVect(ic->rMask->size);
2437       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2438           if (bitVectBitValue(ic->rMask,i))
2439               rsave = bitVectSetBit(rsave,i);
2440       }
2441       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2442   } else {
2443     /* restore the registers in use at this time but skip the
2444        ones for the result */
2445     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2446                            ds390_rUmaskForOp (IC_RESULT(ic)));
2447   }
2448   unsavermask(rsave);
2449 }
2450
2451
2452 /*-----------------------------------------------------------------*/
2453 /* pushSide -                */
2454 /*-----------------------------------------------------------------*/
2455 static void
2456 pushSide (operand * oper, int size)
2457 {
2458   int offset = 0;
2459   _startLazyDPSEvaluation ();
2460   while (size--)
2461     {
2462       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2463       if (AOP_TYPE (oper) != AOP_REG &&
2464           AOP_TYPE (oper) != AOP_DIR &&
2465           strcmp (l, "a"))
2466         {
2467           MOVA (l);
2468           emitcode ("push", "acc");
2469         }
2470       else
2471         {
2472           emitcode ("push", "%s", l);
2473         }
2474     }
2475   _endLazyDPSEvaluation ();
2476 }
2477
2478 /*-----------------------------------------------------------------*/
2479 /* assignResultValue - also indicates if acc is in use afterwards  */
2480 /*-----------------------------------------------------------------*/
2481 static bool
2482 assignResultValue (operand * oper, operand * func)
2483 {
2484   int offset = 0;
2485   unsigned size = AOP_SIZE (oper);
2486   bool accuse = FALSE;
2487   bool pushedA = FALSE;
2488
2489   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2490     {
2491       outBitC (oper);
2492       return FALSE;
2493     }
2494
2495   if (size == fReturnSizeDS390)
2496   {
2497       /* I don't think this case can ever happen... */
2498       /* ACC is the last part of this. If writing the result
2499        * uses ACC, we must preserve it.
2500        */
2501       if (AOP_NEEDSACC(oper))
2502       {
2503           emitcode(";", "assignResultValue special case for ACC.");
2504           emitcode("push", "acc");
2505           pushedA = TRUE;
2506           size--;
2507       }
2508   }
2509
2510   _startLazyDPSEvaluation ();
2511   while (size--)
2512     {
2513       accuse |= aopPut (oper, fReturn[offset], offset);
2514       offset++;
2515     }
2516   _endLazyDPSEvaluation ();
2517
2518   if (pushedA)
2519     {
2520         emitcode ("pop", "acc");
2521         accuse |= aopPut (oper, "a", offset);
2522     }
2523   return accuse;
2524 }
2525
2526
2527 /*-----------------------------------------------------------------*/
2528 /* genXpush - pushes onto the external stack                       */
2529 /*-----------------------------------------------------------------*/
2530 static void
2531 genXpush (iCode * ic)
2532 {
2533   asmop *aop = newAsmop (0);
2534   regs *r;
2535   int size, offset = 0;
2536
2537   D (emitcode (";", "genXpush"));
2538
2539   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2540   r = getFreePtr (ic, &aop, FALSE);
2541
2542   size = AOP_SIZE (IC_LEFT (ic));
2543
2544   if (size == 1)
2545     {
2546       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2547       emitcode ("mov", "%s,_spx", r->name);
2548       emitcode ("inc", "_spx"); // allocate space first
2549       emitcode ("movx", "@%s,a", r->name);
2550     }
2551   else
2552     {
2553       // allocate space first
2554       emitcode ("mov", "%s,_spx", r->name);
2555       MOVA (r->name);
2556       emitcode ("add", "a,#%d", size);
2557       emitcode ("mov", "_spx,a");
2558
2559       _startLazyDPSEvaluation ();
2560       while (size--)
2561         {
2562           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2563           emitcode ("movx", "@%s,a", r->name);
2564           emitcode ("inc", "%s", r->name);
2565         }
2566       _endLazyDPSEvaluation ();
2567     }
2568
2569   freeAsmop (NULL, aop, ic, TRUE);
2570   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2571 }
2572
2573 /*-----------------------------------------------------------------*/
2574 /* genIpush - generate code for pushing this gets a little complex  */
2575 /*-----------------------------------------------------------------*/
2576 static void
2577 genIpush (iCode * ic)
2578 {
2579   int size, offset = 0;
2580   char *l;
2581   char *prev = "";
2582
2583   D (emitcode (";", "genIpush"));
2584
2585   /* if this is not a parm push : ie. it is spill push
2586      and spill push is always done on the local stack */
2587   if (!ic->parmPush)
2588     {
2589
2590       /* and the item is spilt then do nothing */
2591       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2592         return;
2593
2594       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2595       size = AOP_SIZE (IC_LEFT (ic));
2596       /* push it on the stack */
2597       _startLazyDPSEvaluation ();
2598       while (size--)
2599         {
2600           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2601           if (*l == '#')
2602             {
2603               MOVA (l);
2604               l = "acc";
2605             }
2606           emitcode ("push", "%s", l);
2607         }
2608       _endLazyDPSEvaluation ();
2609       return;
2610     }
2611
2612   /* this is a parameter push: in this case we call
2613      the routine to find the call and save those
2614      registers that need to be saved */
2615   saveRegisters (ic);
2616
2617   /* if use external stack then call the external
2618      stack pushing routine */
2619   if (options.useXstack)
2620     {
2621       genXpush (ic);
2622       return;
2623     }
2624
2625   /* then do the push */
2626   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2627
2628   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2629   size = AOP_SIZE (IC_LEFT (ic));
2630
2631   _startLazyDPSEvaluation ();
2632   while (size--)
2633     {
2634       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2635       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2636           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2637           strcmp (l, "acc"))
2638         {
2639           if (strcmp (l, prev) || *l == '@')
2640             MOVA (l);
2641           emitcode ("push", "acc");
2642         }
2643       else
2644         {
2645             emitcode ("push", "%s", l);
2646         }
2647       prev = l;
2648     }
2649   _endLazyDPSEvaluation ();
2650
2651   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2652 }
2653
2654 /*-----------------------------------------------------------------*/
2655 /* genIpop - recover the registers: can happen only for spilling   */
2656 /*-----------------------------------------------------------------*/
2657 static void
2658 genIpop (iCode * ic)
2659 {
2660   int size, offset;
2661
2662   D (emitcode (";", "genIpop"));
2663
2664   /* if the temp was not pushed then */
2665   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2666     return;
2667
2668   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2669   size = AOP_SIZE (IC_LEFT (ic));
2670   offset = (size - 1);
2671   _startLazyDPSEvaluation ();
2672   while (size--)
2673     {
2674       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2675                                      FALSE, TRUE, NULL));
2676     }
2677   _endLazyDPSEvaluation ();
2678
2679   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2680 }
2681
2682 /*-----------------------------------------------------------------*/
2683 /* saveRBank - saves an entire register bank on the stack          */
2684 /*-----------------------------------------------------------------*/
2685 static void
2686 saveRBank (int bank, iCode * ic, bool pushPsw)
2687 {
2688   int i;
2689   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2690   asmop *aop = NULL;
2691   regs *r = NULL;
2692
2693   if (options.useXstack)
2694     {
2695       if (!ic)
2696         {
2697           /* Assume r0 is available for use. */
2698           r = REG_WITH_INDEX (R0_IDX);;
2699         }
2700       else
2701         {
2702           aop = newAsmop (0);
2703           r = getFreePtr (ic, &aop, FALSE);
2704         }
2705       // allocate space first
2706       emitcode ("mov", "%s,_spx", r->name);
2707       MOVA (r->name);
2708       emitcode ("add", "a,#%d", count);
2709       emitcode ("mov", "_spx,a");
2710     }
2711
2712   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2713     {
2714       if (options.useXstack)
2715         {
2716           emitcode ("mov", "a,(%s+%d)",
2717                     regs390[i].base, 8 * bank + regs390[i].offset);
2718           emitcode ("movx", "@%s,a", r->name);
2719           if (--count)
2720             emitcode ("inc", "%s", r->name);
2721         }
2722       else
2723         emitcode ("push", "(%s+%d)",
2724                   regs390[i].base, 8 * bank + regs390[i].offset);
2725     }
2726
2727   if (ds390_nBitRegs > 0)
2728     {
2729       if (options.useXstack)
2730         {
2731           emitcode ("mov", "a,bits");
2732           emitcode ("movx", "@%s,a", r->name);
2733           if (--count)
2734             emitcode ("inc", "%s", r->name);
2735         }
2736       else
2737         {
2738           emitcode ("push", "bits");
2739         }
2740       BitBankUsed = 1;
2741     }
2742
2743   if (pushPsw)
2744     {
2745       if (options.useXstack)
2746         {
2747           emitcode ("mov", "a,psw");
2748           emitcode ("movx", "@%s,a", r->name);
2749         }
2750       else
2751       {
2752         emitcode ("push", "psw");
2753       }
2754
2755       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2756     }
2757
2758   if (aop)
2759     {
2760       freeAsmop (NULL, aop, ic, TRUE);
2761     }
2762
2763   if (ic)
2764   {
2765     ic->bankSaved = 1;
2766   }
2767 }
2768
2769 /*-----------------------------------------------------------------*/
2770 /* unsaveRBank - restores the register bank from stack             */
2771 /*-----------------------------------------------------------------*/
2772 static void
2773 unsaveRBank (int bank, iCode * ic, bool popPsw)
2774 {
2775   int i;
2776   asmop *aop = NULL;
2777   regs *r = NULL;
2778
2779   if (options.useXstack)
2780     {
2781       if (!ic)
2782         {
2783           /* Assume r0 is available for use. */
2784           r = REG_WITH_INDEX (R0_IDX);;
2785         }
2786       else
2787         {
2788           aop = newAsmop (0);
2789           r = getFreePtr (ic, &aop, FALSE);
2790         }
2791       emitcode ("mov", "%s,_spx", r->name);
2792     }
2793
2794   if (popPsw)
2795     {
2796       if (options.useXstack)
2797         {
2798           emitcode ("dec", "%s", r->name);
2799           emitcode ("movx", "a,@%s", r->name);
2800           emitcode ("mov", "psw,a");
2801         }
2802       else
2803       {
2804         emitcode ("pop", "psw");
2805       }
2806     }
2807
2808   if (ds390_nBitRegs > 0)
2809     {
2810       if (options.useXstack)
2811         {
2812           emitcode ("dec", "%s", r->name);
2813           emitcode ("movx", "a,@%s", r->name);
2814           emitcode ("mov", "bits,a");
2815         }
2816       else
2817         {
2818           emitcode ("pop", "bits");
2819         }
2820     }
2821
2822   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2823     {
2824       if (options.useXstack)
2825         {
2826           emitcode ("dec", "%s", r->name);
2827           emitcode ("movx", "a,@%s", r->name);
2828           emitcode ("mov", "(%s+%d),a",
2829                     regs390[i].base, 8 * bank + regs390[i].offset);
2830         }
2831       else
2832         {
2833           emitcode ("pop", "(%s+%d)",
2834                     regs390[i].base, 8 * bank + regs390[i].offset);
2835         }
2836     }
2837
2838   if (options.useXstack)
2839     {
2840       emitcode ("mov", "_spx,%s", r->name);
2841     }
2842
2843   if (aop)
2844     {
2845       freeAsmop (NULL, aop, ic, TRUE);
2846     }
2847 }
2848
2849 /*-----------------------------------------------------------------*/
2850 /* genSend - gen code for SEND                                     */
2851 /*-----------------------------------------------------------------*/
2852 static void genSend(set *sendSet)
2853 {
2854   iCode *sic;
2855   int bit_count = 0;
2856   int sendCount = 0 ;
2857   static int rb1_count = 0;
2858
2859   /* first we do all bit parameters */
2860   for (sic = setFirstItem (sendSet); sic;
2861        sic = setNextItem (sendSet))
2862     {
2863       if (sic->argreg > 12)
2864         {
2865           int bit = sic->argreg-13;
2866
2867           aopOp (IC_LEFT (sic), sic, FALSE,
2868                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2869
2870           /* if left is a literal then
2871              we know what the value is */
2872           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2873             {
2874               if (((int) operandLitValue (IC_LEFT (sic))))
2875                   emitcode ("setb", "b[%d]", bit);
2876               else
2877                   emitcode ("clr", "b[%d]", bit);
2878             }
2879           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2880             {
2881               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2882                 if (strcmp (l, "c"))
2883                     emitcode ("mov", "c,%s", l);
2884                 emitcode ("mov", "b[%d],c", bit);
2885             }
2886           else
2887             {
2888               /* we need to or */
2889               toBoolean (IC_LEFT (sic));
2890               /* set C, if a >= 1 */
2891               emitcode ("add", "a,#0xff");
2892               emitcode ("mov", "b[%d],c", bit);
2893             }
2894           bit_count++;
2895           BitBankUsed = 1;
2896
2897           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2898         }
2899     }
2900
2901   if (bit_count)
2902     {
2903       saveRegisters (setFirstItem (sendSet));
2904       emitcode ("mov", "bits,b");
2905     }
2906
2907   /* then we do all other parameters */
2908   for (sic = setFirstItem (sendSet); sic;
2909        sic = setNextItem (sendSet))
2910     {
2911       if (sic->argreg <= 12)
2912       {
2913         int size, offset = 0;
2914
2915         size = getSize (operandType (IC_LEFT (sic)));
2916         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2917         if (sendCount == 0) { /* first parameter */
2918             // we know that dpl(hxb) is the result, so
2919             rb1_count = 0 ;
2920             _startLazyDPSEvaluation ();
2921             if (size>1) {
2922                 aopOp (IC_LEFT (sic), sic, FALSE,
2923                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2924             } else {
2925                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2926             }
2927             while (size--)
2928               {
2929                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2930                 if (strcmp (l, fReturn[offset]))
2931                   {
2932                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2933                   }
2934                 offset++;
2935               }
2936             _endLazyDPSEvaluation ();
2937             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2938             rb1_count =0;
2939         } else { /* if more parameter in registers */
2940             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2941             while (size--) {
2942                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2943                                                                 FALSE, FALSE, NULL));
2944             }
2945             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2946         }
2947         sendCount++;
2948       }
2949     }
2950 }
2951
2952 static void
2953 adjustEsp(const char *reg)
2954 {
2955     emitcode ("anl","%s,#3", reg);
2956     if (TARGET_IS_DS400)
2957     {
2958         emitcode ("orl","%s,#!constbyte",
2959                   reg,
2960                   (options.stack_loc >> 8) & 0xff);
2961     }
2962 }
2963
2964 /*-----------------------------------------------------------------*/
2965 /* selectRegBank - emit code to select the register bank           */
2966 /*-----------------------------------------------------------------*/
2967 static void
2968 selectRegBank (short bank, bool keepFlags)
2969 {
2970   /* if f.e. result is in carry */
2971   if (keepFlags)
2972     {
2973       emitcode ("anl", "psw,#0xE7");
2974       if (bank)
2975         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2976     }
2977   else
2978     {
2979       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2980     }
2981 }
2982
2983 /*-----------------------------------------------------------------*/
2984 /* genCall - generates a call statement                            */
2985 /*-----------------------------------------------------------------*/
2986 static void
2987 genCall (iCode * ic)
2988 {
2989   sym_link *dtype;
2990   sym_link *etype;
2991   bool restoreBank = FALSE;
2992   bool swapBanks = FALSE;
2993   bool accuse = FALSE;
2994   bool accPushed = FALSE;
2995   bool resultInF0 = FALSE;
2996   bool assignResultGenerated = FALSE;
2997
2998   D (emitcode (";", "genCall"));
2999
3000   /* if we are calling a not _naked function that is not using
3001      the same register bank then we need to save the
3002      destination registers on the stack */
3003   dtype = operandType (IC_LEFT (ic));
3004   etype = getSpec(dtype);
3005   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3006       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3007       IFFUNC_ISISR (currFunc->type))
3008   {
3009       if (!ic->bankSaved)
3010       {
3011            /* This is unexpected; the bank should have been saved in
3012             * genFunction.
3013             */
3014            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3015            restoreBank = TRUE;
3016       }
3017       swapBanks = TRUE;
3018   }
3019
3020   /* if caller saves & we have not saved then */
3021   if (!ic->regsSaved)
3022       saveRegisters (ic);
3023
3024   /* if send set is not empty then assign */
3025   /* We've saved all the registers we care about;
3026   * therefore, we may clobber any register not used
3027   * in the calling convention (i.e. anything not in
3028   * fReturn.
3029   */
3030   if (_G.sendSet)
3031     {
3032         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3033             genSend(reverseSet(_G.sendSet));
3034         } else {
3035             genSend(_G.sendSet);
3036         }
3037       _G.sendSet = NULL;
3038     }
3039
3040   if (swapBanks)
3041     {
3042       emitcode ("mov", "psw,#!constbyte",
3043          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3044     }
3045
3046   /* make the call */
3047   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3048                             OP_SYMBOL (IC_LEFT (ic))->rname :
3049                             OP_SYMBOL (IC_LEFT (ic))->name));
3050
3051   if (swapBanks)
3052     {
3053       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3054     }
3055
3056   /* if we need assign a result value */
3057   if ((IS_ITEMP (IC_RESULT (ic)) &&
3058        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3059        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3060         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3061         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3062       IS_TRUE_SYMOP (IC_RESULT (ic)))
3063     {
3064       if (isOperandInFarSpace (IC_RESULT (ic))
3065           && getSize (operandType (IC_RESULT (ic))) <= 2)
3066         {
3067           int size = getSize (operandType (IC_RESULT (ic)));
3068           bool pushedB = FALSE;
3069
3070           /* Special case for 1 or 2 byte return in far space. */
3071           MOVA (fReturn[0]);
3072           if (size > 1)
3073             {
3074               pushedB = pushB ();
3075               emitcode ("mov", "b,%s", fReturn[1]);
3076             }
3077
3078           _G.accInUse++;
3079           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3080           _G.accInUse--;
3081
3082           popB (pushedB);
3083
3084           aopPut (IC_RESULT (ic), "a", 0);
3085
3086           if (size > 1)
3087             {
3088               aopPut (IC_RESULT (ic), "b", 1);
3089             }
3090           assignResultGenerated = TRUE;
3091           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3092         }
3093       else
3094         {
3095           bool pushedB = pushB ();
3096           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3097           popB (pushedB);
3098
3099           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3100           assignResultGenerated = TRUE;
3101           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3102         }
3103     }
3104
3105   /* adjust the stack for parameters if required */
3106   if (ic->parmBytes)
3107     {
3108       int i;
3109       if (options.stack10bit) {
3110           if (ic->parmBytes <= 10) {
3111               emitcode(";","stack adjustment for parms");
3112               for (i=0; i < ic->parmBytes ; i++) {
3113                   emitcode("pop","acc");
3114               }
3115           } else {
3116               PROTECT_SP;
3117               emitcode ("clr","c");
3118               emitcode ("mov","a,sp");
3119               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3120               emitcode ("mov","sp,a");
3121               emitcode ("mov","a,esp");
3122               adjustEsp("a");
3123               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3124               emitcode ("mov","esp,a");
3125               UNPROTECT_SP;
3126           }
3127       } else {
3128           if (ic->parmBytes > 3)
3129             {
3130               if (accuse)
3131                 {
3132                   emitcode ("push", "acc");
3133                   accPushed = TRUE;
3134                 }
3135               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3136                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3137                   !assignResultGenerated)
3138                 {
3139                   emitcode ("mov", "F0,c");
3140                   resultInF0 = TRUE;
3141                 }
3142
3143               emitcode ("mov", "a,%s", spname);
3144               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3145               emitcode ("mov", "%s,a", spname);
3146
3147               /* unsaveRegisters from xstack needs acc, but */
3148               /* unsaveRegisters from stack needs this popped */
3149               if (accPushed && !options.useXstack)
3150                 {
3151                   emitcode ("pop", "acc");
3152                   accPushed = FALSE;
3153                 }
3154             }
3155           else
3156               for (i = 0; i < ic->parmBytes; i++)
3157                   emitcode ("dec", "%s", spname);
3158       }
3159   }
3160
3161   /* if we had saved some registers then unsave them */
3162   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3163     {
3164       if (accuse && !accPushed && options.useXstack)
3165         {
3166           /* xstack needs acc, but doesn't touch normal stack */
3167           emitcode ("push", "acc");
3168           accPushed = TRUE;
3169         }
3170       unsaveRegisters (ic);
3171     }
3172
3173   /* if register bank was saved then pop them */
3174   if (restoreBank)
3175     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3176
3177   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3178     {
3179       if (resultInF0)
3180           emitcode ("mov", "c,F0");
3181
3182       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3183       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3184       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3185     }
3186
3187   if (accPushed)
3188     emitcode ("pop", "acc");
3189 }
3190
3191 /*-----------------------------------------------------------------*/
3192 /* genPcall - generates a call by pointer statement                */
3193 /*-----------------------------------------------------------------*/
3194 static void
3195 genPcall (iCode * ic)
3196 {
3197   sym_link *dtype;
3198   sym_link *etype;
3199   symbol *rlbl = newiTempLabel (NULL);
3200   bool restoreBank=FALSE;
3201   bool resultInF0 = FALSE;
3202
3203   D (emitcode (";", "genPcall"));
3204
3205   dtype = operandType (IC_LEFT (ic))->next;
3206   etype = getSpec(dtype);
3207   /* if caller saves & we have not saved then */
3208   if (!ic->regsSaved)
3209     saveRegisters (ic);
3210
3211   /* if we are calling a not _naked function that is not using
3212      the same register bank then we need to save the
3213      destination registers on the stack */
3214   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3215       IFFUNC_ISISR (currFunc->type) &&
3216       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3217     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3218     restoreBank=TRUE;
3219   }
3220
3221   /* push the return address on to the stack */
3222   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3223   emitcode ("push", "acc");
3224   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3225   emitcode ("push", "acc");
3226
3227   if (options.model == MODEL_FLAT24)
3228     {
3229       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3230       emitcode ("push", "acc");
3231     }
3232
3233   /* now push the calling address */
3234   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3235
3236   pushSide (IC_LEFT (ic), FPTRSIZE);
3237
3238   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3239
3240   /* if send set is not empty the assign */
3241   if (_G.sendSet)
3242     {
3243         genSend(reverseSet(_G.sendSet));
3244         _G.sendSet = NULL;
3245     }
3246
3247   /* make the call */
3248   emitcode ("ret", "");
3249   emitLabel (rlbl);
3250
3251
3252   /* if we need assign a result value */
3253   if ((IS_ITEMP (IC_RESULT (ic)) &&
3254        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3255        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3256         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3257       IS_TRUE_SYMOP (IC_RESULT (ic)))
3258     {
3259
3260       _G.accInUse++;
3261       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3262       _G.accInUse--;
3263
3264       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3265
3266       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3267     }
3268
3269   /* adjust the stack for parameters if required */
3270   if (ic->parmBytes)
3271     {
3272       int i;
3273       if (options.stack10bit) {
3274           if (ic->parmBytes <= 10) {
3275               emitcode(";","stack adjustment for parms");
3276               for (i=0; i < ic->parmBytes ; i++) {
3277                   emitcode("pop","acc");
3278               }
3279           } else {
3280               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3281                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3282                 {
3283                   emitcode ("mov", "F0,c");
3284                   resultInF0 = TRUE;
3285                 }
3286
3287               PROTECT_SP;
3288               emitcode ("clr","c");
3289               emitcode ("mov","a,sp");
3290               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3291               emitcode ("mov","sp,a");
3292               emitcode ("mov","a,esp");
3293               adjustEsp("a");
3294               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3295               emitcode ("mov","esp,a");
3296               UNPROTECT_SP;
3297           }
3298       } else {
3299           if (ic->parmBytes > 3) {
3300               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3301                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3302                 {
3303                   emitcode ("mov", "F0,c");
3304                   resultInF0 = TRUE;
3305                 }
3306
3307               emitcode ("mov", "a,%s", spname);
3308               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3309               emitcode ("mov", "%s,a", spname);
3310           }
3311           else
3312               for (i = 0; i < ic->parmBytes; i++)
3313                   emitcode ("dec", "%s", spname);
3314       }
3315     }
3316   /* if register bank was saved then unsave them */
3317   if (restoreBank)
3318     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3319
3320   /* if we had saved some registers then unsave them */
3321   if (ic->regsSaved)
3322     unsaveRegisters (ic);
3323
3324   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3325     {
3326       if (resultInF0)
3327           emitcode ("mov", "c,F0");
3328
3329       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3330       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3331       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3332     }
3333 }
3334
3335 /*-----------------------------------------------------------------*/
3336 /* resultRemat - result  is rematerializable                       */
3337 /*-----------------------------------------------------------------*/
3338 static int
3339 resultRemat (iCode * ic)
3340 {
3341   if (SKIP_IC (ic) || ic->op == IFX)
3342     return 0;
3343
3344   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3345     {
3346       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3347       if (sym->remat && !POINTER_SET (ic))
3348         return 1;
3349     }
3350
3351   return 0;
3352 }
3353
3354 #if defined(__BORLANDC__) || defined(_MSC_VER)
3355 #define STRCASECMP stricmp
3356 #else
3357 #define STRCASECMP strcasecmp
3358 #endif
3359
3360 /*-----------------------------------------------------------------*/
3361 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3362 /*-----------------------------------------------------------------*/
3363 static int
3364 regsCmp(void *p1, void *p2)
3365 {
3366   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3367 }
3368
3369 static bool
3370 inExcludeList (char *s)
3371 {
3372   const char *p = setFirstItem(options.excludeRegsSet);
3373
3374   if (p == NULL || STRCASECMP(p, "none") == 0)
3375     return FALSE;
3376
3377
3378   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3379 }
3380
3381 /*-----------------------------------------------------------------*/
3382 /* genFunction - generated code for function entry                 */
3383 /*-----------------------------------------------------------------*/
3384 static void
3385 genFunction (iCode * ic)
3386 {
3387   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3388   sym_link *ftype;
3389   bool     switchedPSW = FALSE;
3390   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3391
3392   D (emitcode (";", "genFunction"));
3393
3394   _G.nRegsSaved = 0;
3395   /* create the function header */
3396   emitcode (";", "-----------------------------------------");
3397   emitcode (";", " function %s", sym->name);
3398   emitcode (";", "-----------------------------------------");
3399
3400   emitcode ("", "%s:", sym->rname);
3401   lineCurr->isLabel = 1;
3402   ftype = operandType (IC_LEFT (ic));
3403   _G.currentFunc = sym;
3404
3405   if (IFFUNC_ISNAKED(ftype))
3406   {
3407       emitcode(";", "naked function: no prologue.");
3408       return;
3409   }
3410
3411   if (options.stack_probe)
3412       emitcode ("lcall","__stack_probe");
3413
3414   /* here we need to generate the equates for the
3415      register bank if required */
3416   if (FUNC_REGBANK (ftype) != rbank)
3417     {
3418       int i;
3419
3420       rbank = FUNC_REGBANK (ftype);
3421       for (i = 0; i < ds390_nRegs; i++)
3422         {
3423           if (regs390[i].print) {
3424               if (strcmp (regs390[i].base, "0") == 0)
3425                   emitcode ("", "%s !equ !constbyte",
3426                             regs390[i].dname,
3427                             8 * rbank + regs390[i].offset);
3428               else
3429                   emitcode ("", "%s !equ %s + !constbyte",
3430                             regs390[i].dname,
3431                             regs390[i].base,
3432                             8 * rbank + regs390[i].offset);
3433           }
3434         }
3435     }
3436
3437   /* if this is an interrupt service routine then
3438      save acc, b, dpl, dph  */
3439   if (IFFUNC_ISISR (sym->type))
3440       { /* is ISR */
3441       if (!inExcludeList ("acc"))
3442         emitcode ("push", "acc");
3443       if (!inExcludeList ("b"))
3444         emitcode ("push", "b");
3445       if (!inExcludeList ("dpl"))
3446         emitcode ("push", "dpl");
3447       if (!inExcludeList ("dph"))
3448         emitcode ("push", "dph");
3449       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3450         {
3451           emitcode ("push", "dpx");
3452           /* Make sure we're using standard DPTR */
3453           emitcode ("push", "dps");
3454           emitcode ("mov", "dps,#0");
3455           if (options.stack10bit)
3456             {
3457               /* This ISR could conceivably use DPTR2. Better save it. */
3458               emitcode ("push", "dpl1");
3459               emitcode ("push", "dph1");
3460               emitcode ("push", "dpx1");
3461               emitcode ("push",  DP2_RESULT_REG);
3462             }
3463         }
3464       /* if this isr has no bank i.e. is going to
3465          run with bank 0 , then we need to save more
3466          registers :-) */
3467       if (!FUNC_REGBANK (sym->type))
3468         {
3469             int i;
3470
3471           /* if this function does not call any other
3472              function then we can be economical and
3473              save only those registers that are used */
3474           if (!IFFUNC_HASFCALL(sym->type))
3475             {
3476               /* if any registers used */
3477               if (sym->regsUsed)
3478                 {
3479                   bool bits_pushed = FALSE;
3480                   /* save the registers used */
3481                   for (i = 0; i < sym->regsUsed->size; i++)
3482                     {
3483                       if (bitVectBitValue (sym->regsUsed, i))
3484                         bits_pushed = pushReg (i, bits_pushed);
3485                     }
3486                 }
3487             }
3488           else
3489             {
3490               /* this function has a function call. We cannot
3491                  determine register usage so we will have to push the
3492                  entire bank */
3493               saveRBank (0, ic, FALSE);
3494               if (options.parms_in_bank1) {
3495                   for (i=0; i < 8 ; i++ ) {
3496                       emitcode ("push","%s",rb1regs[i]);
3497                   }
3498               }
3499             }
3500         }
3501         else
3502         {
3503             /* This ISR uses a non-zero bank.
3504              *
3505              * We assume that the bank is available for our
3506              * exclusive use.
3507              *
3508              * However, if this ISR calls a function which uses some
3509              * other bank, we must save that bank entirely.
3510              */
3511             unsigned long banksToSave = 0;
3512
3513             if (IFFUNC_HASFCALL(sym->type))
3514             {
3515
3516 #define MAX_REGISTER_BANKS 4
3517
3518                 iCode *i;
3519                 int ix;
3520
3521                 for (i = ic; i; i = i->next)
3522                 {
3523                     if (i->op == ENDFUNCTION)
3524                     {
3525                         /* we got to the end OK. */
3526                         break;
3527                     }
3528
3529                     if (i->op == CALL)
3530                     {
3531                         sym_link *dtype;
3532
3533                         dtype = operandType (IC_LEFT(i));
3534                         if (dtype
3535                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3536                         {
3537                              /* Mark this bank for saving. */
3538                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3539                              {
3540                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3541                              }
3542                              else
3543                              {
3544                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3545                              }
3546
3547                              /* And note that we don't need to do it in
3548                               * genCall.
3549                               */
3550                              i->bankSaved = 1;
3551                         }
3552                     }
3553                     if (i->op == PCALL)
3554                     {
3555                         /* This is a mess; we have no idea what
3556                          * register bank the called function might
3557                          * use.
3558                          *
3559                          * The only thing I can think of to do is
3560                          * throw a warning and hope.
3561                          */
3562                         werror(W_FUNCPTR_IN_USING_ISR);
3563                     }
3564                 }
3565
3566                 if (banksToSave && options.useXstack)
3567                 {
3568                     /* Since we aren't passing it an ic,
3569                      * saveRBank will assume r0 is available to abuse.
3570                      *
3571                      * So switch to our (trashable) bank now, so
3572                      * the caller's R0 isn't trashed.
3573                      */
3574                     emitcode ("push", "psw");
3575                     emitcode ("mov", "psw,#!constbyte",
3576                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3577                     switchedPSW = TRUE;
3578                 }
3579
3580                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3581                 {
3582                      if (banksToSave & (1 << ix))
3583                      {
3584                          saveRBank(ix, NULL, FALSE);
3585                      }
3586                 }
3587             }
3588             // TODO: this needs a closer look
3589             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3590         }
3591     }
3592   else
3593     {
3594       /* if callee-save to be used for this function
3595          then save the registers being used in this function */
3596       if (IFFUNC_CALLEESAVES(sym->type))
3597         {
3598           int i;
3599
3600           /* if any registers used */
3601           if (sym->regsUsed)
3602             {
3603               bool bits_pushed = FALSE;
3604               /* save the registers used */
3605               for (i = 0; i < sym->regsUsed->size; i++)
3606                 {
3607                   if (bitVectBitValue (sym->regsUsed, i))
3608                     {
3609                       bits_pushed = pushReg (i, bits_pushed);
3610                       _G.nRegsSaved++;
3611                     }
3612                 }
3613             }
3614         }
3615     }
3616
3617   /* set the register bank to the desired value */
3618   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3619    && !switchedPSW)
3620     {
3621       emitcode ("push", "psw");
3622       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3623     }
3624
3625   if (fReentrant &&
3626        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3627       if (options.stack10bit) {
3628           emitcode ("push","_bpx");
3629           emitcode ("push","_bpx+1");
3630           emitcode ("mov","_bpx,%s",spname);
3631           emitcode ("mov","_bpx+1,esp");
3632           adjustEsp("_bpx+1");
3633       } else {
3634           if (options.useXstack)
3635           {
3636               emitcode ("mov", "r0,%s", spname);
3637               emitcode ("mov", "a,_bp");
3638               emitcode ("movx", "@r0,a");
3639               emitcode ("inc", "%s", spname);
3640           } else {
3641               /* set up the stack */
3642               emitcode ("push", "_bp"); /* save the callers stack  */
3643           }
3644           emitcode ("mov", "_bp,%s", spname);
3645       }
3646   }
3647
3648   /* adjust the stack for the function */
3649   if (sym->stack) {
3650       int i = sym->stack;
3651       if (options.stack10bit) {
3652           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3653           assert (sym->recvSize <= 4);
3654           if (sym->stack <= 8) {
3655               while (i--) emitcode ("push","acc");
3656           } else {
3657               PROTECT_SP;
3658               emitcode ("mov","a,sp");
3659               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3660               emitcode ("mov","sp,a");
3661               emitcode ("mov","a,esp");
3662               adjustEsp("a");
3663               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3664               emitcode ("mov","esp,a");
3665               UNPROTECT_SP;
3666           }
3667       } else {
3668           if (i > 256)
3669               werror (W_STACK_OVERFLOW, sym->name);
3670
3671           if (i > 3 && sym->recvSize < 4) {
3672
3673               emitcode ("mov", "a,sp");
3674               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3675               emitcode ("mov", "sp,a");
3676
3677           } else
3678               while (i--)
3679                   emitcode ("inc", "sp");
3680       }
3681   }
3682
3683   if (sym->xstack)
3684     {
3685
3686       emitcode ("mov", "a,_spx");
3687       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3688       emitcode ("mov", "_spx,a");
3689     }
3690
3691   /* if critical function then turn interrupts off */
3692   if (IFFUNC_ISCRITICAL (ftype))
3693     {
3694       symbol *tlbl = newiTempLabel (NULL);
3695       emitcode ("setb", "c");
3696       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3697       emitcode ("clr", "c");
3698       emitLabel (tlbl);
3699       emitcode ("push", "psw"); /* save old ea via c in psw */
3700     }
3701 }
3702
3703 /*-----------------------------------------------------------------*/
3704 /* genEndFunction - generates epilogue for functions               */
3705 /*-----------------------------------------------------------------*/
3706 static void
3707 genEndFunction (iCode * ic)
3708 {
3709   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3710   lineNode *lnp = lineCurr;
3711   bitVect *regsUsed;
3712   bitVect *regsUsedPrologue;
3713   bitVect *regsUnneeded;
3714   int idx;
3715
3716   D (emitcode (";", "genEndFunction"));
3717
3718   _G.currentFunc = NULL;
3719   if (IFFUNC_ISNAKED(sym->type))
3720   {
3721       emitcode(";", "naked function: no epilogue.");
3722       if (options.debug && currFunc)
3723         debugFile->writeEndFunction (currFunc, ic, 0);
3724       return;
3725   }
3726
3727   if (IFFUNC_ISCRITICAL (sym->type))
3728     {
3729       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3730         {
3731           emitcode ("rlc", "a");   /* save c in a */
3732           emitcode ("pop", "psw"); /* restore ea via c in psw */
3733           emitcode ("mov", "ea,c");
3734           emitcode ("rrc", "a");   /* restore c from a */
3735         }
3736       else
3737         {
3738           emitcode ("pop", "psw"); /* restore ea via c in psw */
3739           emitcode ("mov", "ea,c");
3740         }
3741     }
3742
3743   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3744        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3745
3746       if (options.stack10bit) {
3747           PROTECT_SP;
3748           emitcode ("mov", "sp,_bpx", spname);
3749           emitcode ("mov", "esp,_bpx+1", spname);
3750           UNPROTECT_SP;
3751       } else {
3752           emitcode ("mov", "%s,_bp", spname);
3753       }
3754   }
3755
3756   /* if use external stack but some variables were
3757      added to the local stack then decrement the
3758      local stack */
3759   if (options.useXstack && sym->stack) {
3760       emitcode ("mov", "a,sp");
3761       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3762       emitcode ("mov", "sp,a");
3763   }
3764
3765
3766   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3767        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3768
3769       if (options.useXstack) {
3770           emitcode ("mov", "r0,%s", spname);
3771           emitcode ("movx", "a,@r0");
3772           emitcode ("mov", "_bp,a");
3773           emitcode ("dec", "%s", spname);
3774       } else {
3775           if (options.stack10bit) {
3776               emitcode ("pop", "_bpx+1");
3777               emitcode ("pop", "_bpx");
3778           } else {
3779               emitcode ("pop", "_bp");
3780           }
3781       }
3782   }
3783
3784   /* restore the register bank  */
3785   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3786   {
3787     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3788      || !options.useXstack)
3789     {
3790         /* Special case of ISR using non-zero bank with useXstack
3791          * is handled below.
3792          */
3793         emitcode ("pop", "psw");
3794     }
3795   }
3796
3797   if (IFFUNC_ISISR (sym->type))
3798     { /* is ISR */
3799
3800       /* now we need to restore the registers */
3801       /* if this isr has no bank i.e. is going to
3802          run with bank 0 , then we need to save more
3803          registers :-) */
3804       if (!FUNC_REGBANK (sym->type))
3805         {
3806           int i;
3807           /* if this function does not call any other
3808              function then we can be economical and
3809              save only those registers that are used */
3810           if (!IFFUNC_HASFCALL(sym->type))
3811             {
3812               /* if any registers used */
3813               if (sym->regsUsed)
3814                 {
3815                   bool bits_popped = FALSE;
3816                   /* save the registers used */
3817                   for (i = sym->regsUsed->size; i >= 0; i--)
3818                     {
3819                       if (bitVectBitValue (sym->regsUsed, i))
3820                         bits_popped = popReg (i, bits_popped);
3821                     }
3822                 }
3823             }
3824           else
3825             {
3826               /* this function has a function call. We cannot
3827                  determine register usage so we will have to pop the
3828                  entire bank */
3829               if (options.parms_in_bank1) {
3830                   for (i = 7 ; i >= 0 ; i-- ) {
3831                       emitcode ("pop","%s",rb1regs[i]);
3832                   }
3833               }
3834               unsaveRBank (0, ic, FALSE);
3835             }
3836         }
3837       else
3838         {
3839             /* This ISR uses a non-zero bank.
3840              *
3841              * Restore any register banks saved by genFunction
3842              * in reverse order.
3843              */
3844             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3845             int ix;
3846
3847             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3848             {
3849                 if (savedBanks & (1 << ix))
3850                 {
3851                     unsaveRBank(ix, NULL, FALSE);
3852                 }
3853             }
3854
3855             if (options.useXstack)
3856             {
3857                 /* Restore bank AFTER calling unsaveRBank,
3858                  * since it can trash r0.
3859                  */
3860                 emitcode ("pop", "psw");
3861             }
3862         }
3863
3864       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3865         {
3866           if (options.stack10bit)
3867             {
3868               emitcode ("pop", DP2_RESULT_REG);
3869               emitcode ("pop", "dpx1");
3870               emitcode ("pop", "dph1");
3871               emitcode ("pop", "dpl1");
3872             }
3873           emitcode ("pop", "dps");
3874           emitcode ("pop", "dpx");
3875         }
3876       if (!inExcludeList ("dph"))
3877         emitcode ("pop", "dph");
3878       if (!inExcludeList ("dpl"))
3879         emitcode ("pop", "dpl");
3880       if (!inExcludeList ("b"))
3881         emitcode ("pop", "b");
3882       if (!inExcludeList ("acc"))
3883         emitcode ("pop", "acc");
3884
3885       /* if debug then send end of function */
3886       if (options.debug && currFunc)
3887         {
3888           debugFile->writeEndFunction (currFunc, ic, 1);
3889         }
3890
3891       emitcode ("reti", "");
3892     }
3893   else
3894     {
3895       if (IFFUNC_CALLEESAVES(sym->type))
3896         {
3897           int i;
3898
3899           /* if any registers used */
3900           if (sym->regsUsed)
3901             {
3902               /* save the registers used */
3903               for (i = sym->regsUsed->size; i >= 0; i--)
3904                 {
3905                   if (bitVectBitValue (sym->regsUsed, i))
3906                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3907                 }
3908             }
3909         }
3910
3911       /* if debug then send end of function */
3912       if (options.debug && currFunc)
3913         {
3914           debugFile->writeEndFunction (currFunc, ic, 1);
3915         }
3916
3917       emitcode ("ret", "");
3918     }
3919
3920   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3921     return;
3922
3923   /* If this was an interrupt handler using bank 0 that called another */
3924   /* function, then all registers must be saved; nothing to optimized. */
3925   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3926       && !FUNC_REGBANK(sym->type))
3927     return;
3928
3929   /* There are no push/pops to optimize if not callee-saves or ISR */
3930   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3931     return;
3932
3933   /* If there were stack parameters, we cannot optimize without also    */
3934   /* fixing all of the stack offsets; this is too dificult to consider. */
3935   if (FUNC_HASSTACKPARM(sym->type))
3936     return;
3937
3938   /* Compute the registers actually used */
3939   regsUsed = newBitVect (ds390_nRegs);
3940   regsUsedPrologue = newBitVect (ds390_nRegs);
3941   while (lnp)
3942     {
3943       if (lnp->ic && lnp->ic->op == FUNCTION)
3944         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3945       else
3946         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3947
3948       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3949           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3950         break;
3951       if (!lnp->prev)
3952         break;
3953       lnp = lnp->prev;
3954     }
3955
3956   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3957       && !bitVectBitValue (regsUsed, DPS_IDX))
3958     {
3959       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3960     }
3961
3962   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3963       && !bitVectBitValue (regsUsed, CND_IDX))
3964     {
3965       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3966       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3967           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3968         bitVectUnSetBit (regsUsed, CND_IDX);
3969     }
3970   else
3971     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3972
3973   /* If this was an interrupt handler that called another function */
3974   /* function, then assume working registers may be modified by it. */
3975   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3976     {
3977       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3978       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3979       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3980       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3981       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3982       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3983       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3984       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3985       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3986       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3987       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3988     }
3989
3990   /* Remove the unneeded push/pops */
3991   regsUnneeded = newBitVect (ds390_nRegs);
3992   while (lnp)
3993     {
3994       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3995         {
3996           if (!strncmp(lnp->line, "push", 4))
3997             {
3998               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3999               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4000                 {
4001                   connectLine (lnp->prev, lnp->next);
4002                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4003                 }
4004             }
4005           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4006             {
4007               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4008               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4009                 {
4010                   connectLine (lnp->prev, lnp->next);
4011                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4012                 }
4013             }
4014         }
4015       lnp = lnp->next;
4016     }
4017
4018   for (idx = 0; idx < regsUnneeded->size; idx++)
4019     if (bitVectBitValue (regsUnneeded, idx))
4020       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4021
4022   freeBitVect (regsUnneeded);
4023   freeBitVect (regsUsed);
4024   freeBitVect (regsUsedPrologue);
4025 }
4026
4027 /*-----------------------------------------------------------------*/
4028 /* genJavaNativeRet - generate code for return JavaNative          */
4029 /*-----------------------------------------------------------------*/
4030 static void genJavaNativeRet(iCode *ic)
4031 {
4032     int i, size;
4033
4034     aopOp (IC_LEFT (ic), ic, FALSE,
4035            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4036     size = AOP_SIZE (IC_LEFT (ic));
4037
4038     assert (size <= 4);
4039
4040     /* it is assigned to GPR0-R3 then push them */
4041     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4042         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4043         for (i = 0 ; i < size ; i++ ) {
4044             emitcode ("push","%s",
4045                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4046         }
4047         for (i = (size-1) ; i >= 0 ; i--) {
4048             emitcode ("pop","a%s",javaRet[i]);
4049         }
4050     } else {
4051         for (i = 0 ; i < size ; i++)
4052             emitcode ("mov","%s,%s",javaRet[i],
4053                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4054     }
4055     for (i = size ; i < 4 ; i++ )
4056             emitcode ("mov","%s,#0",javaRet[i]);
4057     return;
4058 }
4059
4060 /*-----------------------------------------------------------------*/
4061 /* genRet - generate code for return statement                     */
4062 /*-----------------------------------------------------------------*/
4063 static void
4064 genRet (iCode * ic)
4065 {
4066   int size, offset = 0, pushed = 0;
4067
4068   D (emitcode (";", "genRet"));
4069
4070   /* if we have no return value then
4071      just generate the "ret" */
4072   if (!IC_LEFT (ic))
4073     goto jumpret;
4074
4075   /* if this is a JavaNative function then return
4076      value in different register */
4077   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4078       genJavaNativeRet(ic);
4079       goto jumpret;
4080   }
4081   /* we have something to return then
4082      move the return value into place */
4083   aopOp (IC_LEFT (ic), ic, FALSE,
4084          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4085   size = AOP_SIZE (IC_LEFT (ic));
4086
4087   _startLazyDPSEvaluation ();
4088
4089   if (IS_BIT(_G.currentFunc->etype))
4090     {
4091       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4092       size = 0;
4093     }
4094
4095   while (size--)
4096     {
4097       char *l;
4098       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4099         {
4100           l = aopGet (IC_LEFT (ic), offset++,
4101                       FALSE, TRUE, NULL);
4102           emitcode ("push", "%s", l);
4103           pushed++;
4104         }
4105       else
4106         {
4107           /* Since A is the last element of fReturn,
4108            * it is OK to clobber it in the aopGet.
4109            */
4110           l = aopGet (IC_LEFT (ic), offset,
4111                       FALSE, FALSE, NULL);
4112           if (strcmp (fReturn[offset], l))
4113             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4114         }
4115     }
4116   _endLazyDPSEvaluation ();
4117
4118   while (pushed)
4119     {
4120       pushed--;
4121       if (strcmp (fReturn[pushed], "a"))
4122         emitcode ("pop", fReturn[pushed]);
4123       else
4124         emitcode ("pop", "acc");
4125     }
4126   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4127
4128 jumpret:
4129   /* generate a jump to the return label
4130      if the next is not the return statement */
4131   if (!(ic->next && ic->next->op == LABEL &&
4132         IC_LABEL (ic->next) == returnLabel))
4133
4134     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4135
4136 }
4137
4138 /*-----------------------------------------------------------------*/
4139 /* genLabel - generates a label                                    */
4140 /*-----------------------------------------------------------------*/
4141 static void
4142 genLabel (iCode * ic)
4143 {
4144   /* special case never generate */
4145   if (IC_LABEL (ic) == entryLabel)
4146     return;
4147
4148   D (emitcode (";", "genLabel"));
4149
4150   emitLabel (IC_LABEL (ic));
4151 }
4152
4153 /*-----------------------------------------------------------------*/
4154 /* genGoto - generates a ljmp                                      */
4155 /*-----------------------------------------------------------------*/
4156 static void
4157 genGoto (iCode * ic)
4158 {
4159   D (emitcode (";", "genGoto"));
4160
4161   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4162 }
4163
4164 /*-----------------------------------------------------------------*/
4165 /* findLabelBackwards: walks back through the iCode chain looking  */
4166 /* for the given label. Returns number of iCode instructions     */
4167 /* between that label and given ic.          */
4168 /* Returns zero if label not found.          */
4169 /*-----------------------------------------------------------------*/
4170 static int
4171 findLabelBackwards (iCode * ic, int key)
4172 {
4173   int count = 0;
4174
4175   while (ic->prev)
4176     {
4177       ic = ic->prev;
4178       count++;
4179
4180       /* If we have any pushes or pops, we cannot predict the distance.
4181          I don't like this at all, this should be dealt with in the
4182          back-end */
4183       if (ic->op == IPUSH || ic->op == IPOP) {
4184         return 0;
4185       }
4186
4187       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4188         {
4189           /* printf("findLabelBackwards = %d\n", count); */
4190           return count;
4191         }
4192     }
4193
4194   return 0;
4195 }
4196
4197 /*-----------------------------------------------------------------*/
4198 /* genPlusIncr :- does addition with increment if possible         */
4199 /*-----------------------------------------------------------------*/
4200 static bool
4201 genPlusIncr (iCode * ic)
4202 {
4203   unsigned int icount;
4204   unsigned int size = getDataSize (IC_RESULT (ic));
4205
4206   /* will try to generate an increment */
4207   /* if the right side is not a literal
4208      we cannot */
4209   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4210     return FALSE;
4211
4212   /* if the literal value of the right hand side
4213      is greater than 4 then it is not worth it */
4214   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4215     return FALSE;
4216
4217   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4218       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4219       while (icount--) {
4220           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4221       }
4222       return TRUE;
4223   }
4224   /* if increment 16 bits in register */
4225   if (
4226        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4227        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4228        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4229        (size > 1) &&
4230        (icount == 1))
4231     {
4232       symbol  *tlbl;
4233       int     emitTlbl;
4234       int     labelRange;
4235       char    *l;
4236
4237       /* If the next instruction is a goto and the goto target
4238        * is <= 5 instructions previous to this, we can generate
4239        * jumps straight to that target.
4240        */
4241       if (ic->next && ic->next->op == GOTO
4242           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4243           && labelRange <= 5)
4244         {
4245           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4246           tlbl = IC_LABEL (ic->next);
4247           emitTlbl = 0;
4248         }
4249       else
4250         {
4251           tlbl = newiTempLabel (NULL);
4252           emitTlbl = 1;
4253         }
4254       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4255       emitcode ("inc", "%s", l);
4256
4257       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4258           IS_AOP_PREG (IC_RESULT (ic)))
4259         {
4260           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4261         }
4262       else
4263         {
4264           emitcode ("clr", "a");
4265           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4266         }
4267
4268       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4269       emitcode ("inc", "%s", l);
4270       if (size > 2)
4271         {
4272           if (!strcmp(l, "acc"))
4273             {
4274                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4275             }
4276           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4277                    IS_AOP_PREG (IC_RESULT (ic)))
4278             {
4279                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4280             }
4281           else
4282             {
4283                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4284             }
4285
4286           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4287           emitcode ("inc", "%s", l);
4288         }
4289       if (size > 3)
4290         {
4291           if (!strcmp(l, "acc"))
4292             {
4293                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4294             }
4295           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4296                    IS_AOP_PREG (IC_RESULT (ic)))
4297             {
4298                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4299             }
4300           else
4301             {
4302                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4303             }
4304
4305           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4306           emitcode ("inc", "%s", l);
4307         }
4308
4309       if (emitTlbl)
4310         {
4311           emitLabel (tlbl);
4312         }
4313       return TRUE;
4314     }
4315
4316   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4317       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4318       options.model == MODEL_FLAT24 )
4319     {
4320       if (IC_RESULT(ic)->isGptr)
4321         {
4322           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4323         }
4324       switch (size) {
4325       case 3:
4326           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4327       case 2:
4328           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4329       case 1:
4330           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4331           break;
4332       }
4333       while (icount--)
4334         emitcode ("inc", "dptr");
4335       return TRUE;
4336   }
4337
4338   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4339       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4340       icount <= 5 ) {
4341       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4342       while (icount--)
4343         emitcode ("inc", "dptr");
4344       emitcode ("mov", "dps,#0");
4345       return TRUE;
4346   }
4347
4348   /* if the sizes are greater than 1 then we cannot */
4349   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4350       AOP_SIZE (IC_LEFT (ic)) > 1)
4351     return FALSE;
4352
4353   /* we can if the aops of the left & result match or
4354      if they are in registers and the registers are the
4355      same */
4356   if (
4357        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4358        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4359        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4360     {
4361       if (icount > 3)
4362         {
4363           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4364           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4365           aopPut (IC_RESULT (ic), "a", 0);
4366         }
4367       else
4368         {
4369           _startLazyDPSEvaluation ();
4370           while (icount--)
4371             {
4372               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4373             }
4374           _endLazyDPSEvaluation ();
4375         }
4376
4377       return TRUE;
4378     }
4379
4380   return FALSE;
4381 }
4382
4383 /*-----------------------------------------------------------------*/
4384 /* outBitAcc - output a bit in acc                                 */
4385 /*-----------------------------------------------------------------*/
4386 static void
4387 outBitAcc (operand * result)
4388 {
4389   symbol *tlbl = newiTempLabel (NULL);
4390   /* if the result is a bit */
4391   if (AOP_TYPE (result) == AOP_CRY)
4392     {
4393       aopPut (result, "a", 0);
4394     }
4395   else
4396     {
4397       emitcode ("jz", "!tlabel", tlbl->key + 100);
4398       emitcode ("mov", "a,%s", one);
4399       emitLabel (tlbl);
4400       outAcc (result);
4401     }
4402 }
4403
4404 /*-----------------------------------------------------------------*/
4405 /* genPlusBits - generates code for addition of two bits           */
4406 /*-----------------------------------------------------------------*/
4407 static void
4408 genPlusBits (iCode * ic)
4409 {
4410   D (emitcode (";", "genPlusBits"));
4411
4412   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4413     {
4414       symbol *lbl = newiTempLabel (NULL);
4415       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4416       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4417       emitcode ("cpl", "c");
4418       emitLabel (lbl);
4419       outBitC (IC_RESULT (ic));
4420     }
4421   else
4422     {
4423       emitcode ("clr", "a");
4424       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4425       emitcode ("rlc", "a");
4426       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4427       emitcode ("addc", "a,%s", zero);
4428       outAcc (IC_RESULT (ic));
4429     }
4430 }
4431
4432 static void
4433 adjustArithmeticResult (iCode * ic)
4434 {
4435   if (opIsGptr (IC_RESULT (ic)) &&
4436       opIsGptr (IC_LEFT (ic)) &&
4437       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4438     {
4439       aopPut (IC_RESULT (ic),
4440               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4441               GPTRSIZE - 1);
4442     }
4443
4444   if (opIsGptr (IC_RESULT (ic)) &&
4445       opIsGptr (IC_RIGHT (ic)) &&
4446       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4447     {
4448       aopPut (IC_RESULT (ic),
4449               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4450               GPTRSIZE - 1);
4451     }
4452
4453   if (opIsGptr (IC_RESULT (ic)) &&
4454       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4455       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4456       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4457       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4458     {
4459       char buffer[5];
4460       SNPRINTF (buffer, sizeof(buffer),
4461                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4462       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4463     }
4464 }
4465
4466 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4467 // generates the result if possible. If result is generated, returns TRUE; otherwise
4468 // returns false and caller must deal with fact that result isn't aopOp'd.
4469 bool aopOp3(iCode * ic)
4470 {
4471     bool dp1InUse, dp2InUse;
4472     bool useDp2;
4473
4474     // First, generate the right opcode. DPTR may be used if neither left nor result are
4475     // of type AOP_STR.
4476
4477 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4478 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4479 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4480 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4481 //      );
4482 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4483 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4484 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4485 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4486 //      );
4487
4488     // Right uses DPTR unless left or result is an AOP_STR; however,
4489     // if right is an AOP_STR, it must use DPTR regardless.
4490     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4491      && !AOP_IS_STR (IC_RIGHT (ic)))
4492     {
4493         useDp2 = TRUE;
4494     }
4495     else
4496     {
4497         useDp2 = FALSE;
4498     }
4499
4500     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4501
4502     // if the right used DPTR, left MUST use DPTR2.
4503     // if the right used DPTR2, left MUST use DPTR.
4504     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4505     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4506     // enabling us to assign DPTR to result.
4507
4508     if (AOP_USESDPTR (IC_RIGHT (ic)))
4509     {
4510         useDp2 = TRUE;
4511     }
4512     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4513     {
4514         useDp2 = FALSE;
4515     }
4516     else
4517     {
4518         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4519         {
4520             useDp2 = TRUE;
4521         }
4522         else
4523         {
4524             useDp2 = FALSE;
4525         }
4526     }
4527
4528     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4529
4530
4531     // We've op'd the left & right. So, if left or right are the same operand as result,
4532     // we know aopOp will succeed, and we can just do it & bail.
4533     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4534       {
4535         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4536         return TRUE;
4537       }
4538     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4539       {
4540 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4541         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4542         return TRUE;
4543       }
4544
4545     // Operands may be equivalent (but not equal) if they share a spill location. If
4546     // so, use the same DPTR or DPTR2.
4547     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4548       {
4549         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4550         return TRUE;
4551       }
4552     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4553       {
4554         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4555         return TRUE;
4556       }
4557
4558     // Note which dptrs are currently in use.
4559     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4560     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4561
4562     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4563     // generate it.
4564     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4565     {
4566         return FALSE;
4567     }
4568
4569     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4570     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4571     {
4572         return FALSE;
4573     }
4574
4575     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4576     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4577     {
4578         return FALSE;
4579     }
4580
4581     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4582
4583     // Some sanity checking...
4584     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4585     {
4586         fprintf(stderr,
4587                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4588                 __FILE__, __LINE__, ic->filename, ic->lineno);
4589         emitcode(";", ">>> unexpected DPTR here.");
4590     }
4591
4592     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4593     {
4594         fprintf(stderr,
4595                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4596                 __FILE__, __LINE__, ic->filename, ic->lineno);
4597         emitcode(";", ">>> unexpected DPTR2 here.");
4598     }
4599
4600     return TRUE;
4601 }
4602
4603 // Macro to aopOp all three operands of an ic. If this cannot be done,
4604 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4605 // will be set TRUE. The caller must then handle the case specially, noting
4606 // that the IC_RESULT operand is not aopOp'd.
4607 //
4608 #define AOP_OP_3_NOFATAL(ic, rc) \
4609             do { rc = !aopOp3(ic); } while (0)
4610
4611 // aopOp the left & right operands of an ic.
4612 #define AOP_OP_2(ic) \
4613     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4614     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4615
4616 // convienience macro.
4617 #define AOP_SET_LOCALS(ic) \
4618     left = IC_LEFT(ic); \
4619     right = IC_RIGHT(ic); \
4620     result = IC_RESULT(ic);
4621
4622
4623 // Given an integer value of pushedSize bytes on the stack,
4624 // adjust it to be resultSize bytes, either by discarding
4625 // the most significant bytes or by zero-padding.
4626 //
4627 // On exit from this macro, pushedSize will have been adjusted to
4628 // equal resultSize, and ACC may be trashed.
4629 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4630       /* If the pushed data is bigger than the result,          \
4631        * simply discard unused bytes. Icky, but works.          \
4632        */                                                       \
4633       while (pushedSize > resultSize)                           \
4634       {                                                         \
4635           D (emitcode (";", "discarding unused result byte.")); \
4636           emitcode ("pop", "acc");                              \
4637           pushedSize--;                                         \
4638       }                                                         \
4639       if (pushedSize < resultSize)                              \
4640       {                                                         \
4641           emitcode ("clr", "a");                                \
4642           /* Conversly, we haven't pushed enough here.          \
4643            * just zero-pad, and all is well.                    \
4644            */                                                   \
4645           while (pushedSize < resultSize)                       \
4646           {                                                     \
4647               emitcode("push", "acc");                          \
4648               pushedSize++;                                     \
4649           }                                                     \
4650       }                                                         \
4651       assert(pushedSize == resultSize);
4652
4653 /*-----------------------------------------------------------------*/
4654 /* genPlus - generates code for addition                           */
4655 /*-----------------------------------------------------------------*/
4656 static void
4657 genPlus (iCode * ic)
4658 {
4659   int size, offset = 0;
4660   bool pushResult;
4661   int rSize;
4662   bool swappedLR = FALSE;
4663
4664   D (emitcode (";", "genPlus"));
4665
4666   /* special cases :- */
4667   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4668       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4669       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4670       size = (int)floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4671       if (size <= 9) {
4672           while (size--) emitcode ("inc","dptr");
4673       } else {
4674           emitcode ("mov", "a,dpl");
4675           emitcode ("add", "a,#!constbyte", size & 0xff);
4676           emitcode ("mov", "dpl,a");
4677           emitcode ("mov", "a,dph");
4678           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4679           emitcode ("mov", "dph,a");
4680           emitcode ("mov", "a,dpx");
4681           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4682           emitcode ("mov", "dpx,a");
4683       }
4684       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4685       return ;
4686   }
4687   if ( IS_SYMOP (IC_LEFT (ic)) &&
4688        OP_SYMBOL (IC_LEFT (ic))->remat &&
4689        isOperandInFarSpace (IC_RIGHT (ic))) {
4690       operand *op = IC_RIGHT(ic);
4691       IC_RIGHT(ic) = IC_LEFT(ic);
4692       IC_LEFT(ic) = op;
4693   }
4694
4695   AOP_OP_3_NOFATAL (ic, pushResult);
4696
4697   if (pushResult)
4698     {
4699       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4700     }
4701
4702   if (!pushResult)
4703     {
4704       /* if literal, literal on the right or
4705          if left requires ACC or right is already
4706          in ACC */
4707       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4708           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4709           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4710         {
4711           operand *t = IC_RIGHT (ic);
4712           IC_RIGHT (ic) = IC_LEFT (ic);
4713           IC_LEFT (ic) = t;
4714           swappedLR = TRUE;
4715           D (emitcode (";", "Swapped plus args."));
4716         }
4717
4718       /* if both left & right are in bit
4719          space */
4720       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4721           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4722         {
4723           genPlusBits (ic);
4724           goto release;
4725         }
4726
4727       /* if left in bit space & right literal */
4728       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4729           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4730         {
4731           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4732           /* if result in bit space */
4733           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4734             {
4735               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4736                 emitcode ("cpl", "c");
4737               outBitC (IC_RESULT (ic));
4738             }
4739           else
4740             {
4741               size = getDataSize (IC_RESULT (ic));
4742               _startLazyDPSEvaluation ();
4743               while (size--)
4744                 {
4745                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4746                   emitcode ("addc", "a,%s", zero);
4747                   aopPut (IC_RESULT (ic), "a", offset++);
4748                 }
4749               _endLazyDPSEvaluation ();
4750             }
4751           goto release;
4752         }
4753
4754       /* if I can do an increment instead
4755          of add then GOOD for ME */
4756       if (genPlusIncr (ic) == TRUE)
4757         {
4758           D (emitcode (";", "did genPlusIncr"));
4759           goto release;
4760         }
4761
4762     }
4763   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4764
4765   _startLazyDPSEvaluation ();
4766   while (size--)
4767     {
4768       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4769         {
4770           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4771           if (offset == 0)
4772             emitcode ("add", "a,%s",
4773                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4774           else
4775             emitcode ("addc", "a,%s",
4776                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4777         }
4778       else
4779         {
4780           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4781           {
4782               /* right is going to use ACC or we would have taken the
4783                * above branch.
4784                */
4785               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4786               TR_AP("#3");
4787               D(emitcode(";", "+ AOP_ACC special case."););
4788               emitcode("xch", "a, %s", DP2_RESULT_REG);
4789           }
4790           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4791           if (offset == 0)
4792           {
4793             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4794             {
4795                 TR_AP("#4");
4796                 emitcode("add", "a, %s", DP2_RESULT_REG);
4797             }
4798             else
4799             {
4800                 emitcode ("add", "a,%s",
4801                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4802                                   DP2_RESULT_REG));
4803             }
4804           }
4805           else
4806           {
4807             emitcode ("addc", "a,%s",
4808                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4809                           DP2_RESULT_REG));
4810           }
4811         }
4812       if (!pushResult)
4813         {
4814           aopPut (IC_RESULT (ic), "a", offset);
4815         }
4816       else
4817         {
4818           emitcode ("push", "acc");
4819         }
4820       offset++;
4821     }
4822   _endLazyDPSEvaluation ();
4823
4824   if (pushResult)
4825     {
4826       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4827
4828       size = getDataSize (IC_LEFT (ic));
4829       rSize = getDataSize (IC_RESULT (ic));
4830
4831       ADJUST_PUSHED_RESULT(size, rSize);
4832
4833       _startLazyDPSEvaluation ();
4834       while (size--)
4835         {
4836           emitcode ("pop", "acc");
4837           aopPut (IC_RESULT (ic), "a", size);
4838         }
4839       _endLazyDPSEvaluation ();
4840     }
4841
4842   adjustArithmeticResult (ic);
4843
4844 release:
4845   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4846   if (!swappedLR)
4847     {
4848       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4849       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4850     }
4851   else
4852     {
4853       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4854       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4855     }
4856 }
4857
4858 /*-----------------------------------------------------------------*/
4859 /* genMinusDec :- does subtraction with decrement if possible      */
4860 /*-----------------------------------------------------------------*/
4861 static bool
4862 genMinusDec (iCode * ic)
4863 {
4864   unsigned int icount;
4865   unsigned int size = getDataSize (IC_RESULT (ic));
4866
4867   /* will try to generate an increment */
4868   /* if the right side is not a literal
4869      we cannot */
4870   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4871     return FALSE;
4872
4873   /* if the literal value of the right hand side
4874      is greater than 4 then it is not worth it */
4875   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4876     return FALSE;
4877
4878   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4879       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4880       while (icount--) {
4881           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4882       }
4883       return TRUE;
4884   }
4885   /* if decrement 16 bits in register */
4886   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4887       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4888       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4889       (size > 1) &&
4890       (icount == 1))
4891     {
4892       symbol *tlbl;
4893       int    emitTlbl;
4894       int    labelRange;
4895       char   *l;
4896
4897       /* If the next instruction is a goto and the goto target
4898          * is <= 5 instructions previous to this, we can generate
4899          * jumps straight to that target.
4900        */
4901       if (ic->next && ic->next->op == GOTO
4902           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4903           && labelRange <= 5)
4904         {
4905           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4906           tlbl = IC_LABEL (ic->next);
4907           emitTlbl = 0;
4908         }
4909       else
4910         {
4911           tlbl = newiTempLabel (NULL);
4912           emitTlbl = 1;
4913         }
4914
4915       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4916       emitcode ("dec", "%s", l);
4917
4918       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4919           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4920           IS_AOP_PREG (IC_RESULT (ic)))
4921       {
4922           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4923       }
4924       else
4925       {
4926           emitcode ("mov", "a,#!constbyte",0xff);
4927           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4928       }
4929       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4930       emitcode ("dec", "%s", l);
4931       if (size > 2)
4932         {
4933             if (!strcmp(l, "acc"))
4934             {
4935                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4936             }
4937             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4938                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4939                      IS_AOP_PREG (IC_RESULT (ic)))
4940             {
4941                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4942             }
4943             else
4944             {
4945                 emitcode ("mov", "a,#!constbyte",0xff);
4946                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4947             }
4948             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4949             emitcode ("dec", "%s", l);
4950         }
4951       if (size > 3)
4952         {
4953             if (!strcmp(l, "acc"))
4954             {
4955                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4956             }
4957             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4958                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4959                      IS_AOP_PREG (IC_RESULT (ic)))
4960             {
4961                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4962             }
4963             else
4964             {
4965                 emitcode ("mov", "a,#!constbyte",0xff);
4966                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4967             }
4968             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4969             emitcode ("dec", "%s", l);
4970         }
4971       if (emitTlbl)
4972         {
4973           emitLabel (tlbl);
4974         }
4975       return TRUE;
4976     }
4977
4978   /* if the sizes are greater than 1 then we cannot */
4979   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4980       AOP_SIZE (IC_LEFT (ic)) > 1)
4981     return FALSE;
4982
4983   /* we can if the aops of the left & result match or
4984      if they are in registers and the registers are the
4985      same */
4986   if (
4987        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4988        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4989        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4990     {
4991       char *l;
4992
4993       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4994         {
4995           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
4996           l = "a";
4997         }
4998       else
4999         {
5000           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5001         }
5002
5003       _startLazyDPSEvaluation ();
5004       while (icount--)
5005         {
5006           emitcode ("dec", "%s", l);
5007         }
5008       _endLazyDPSEvaluation ();
5009
5010       if (AOP_NEEDSACC (IC_RESULT (ic)))
5011         aopPut (IC_RESULT (ic), "a", 0);
5012
5013       return TRUE;
5014     }
5015
5016   return FALSE;
5017 }
5018
5019 /*-----------------------------------------------------------------*/
5020 /* addSign - complete with sign                                    */
5021 /*-----------------------------------------------------------------*/
5022 static void
5023 addSign (operand * result, int offset, int sign)
5024 {
5025   int size = (getDataSize (result) - offset);
5026   if (size > 0)
5027     {
5028       _startLazyDPSEvaluation();
5029       if (sign)
5030         {
5031           emitcode ("rlc", "a");
5032           emitcode ("subb", "a,acc");
5033           while (size--)
5034             {
5035               aopPut (result, "a", offset++);
5036             }
5037         }
5038       else
5039       {
5040         while (size--)
5041         {
5042           aopPut (result, zero, offset++);
5043         }
5044       }
5045       _endLazyDPSEvaluation();
5046     }
5047 }
5048
5049 /*-----------------------------------------------------------------*/
5050 /* genMinusBits - generates code for subtraction  of two bits      */
5051 /*-----------------------------------------------------------------*/
5052 static void
5053 genMinusBits (iCode * ic)
5054 {
5055   symbol *lbl = newiTempLabel (NULL);
5056
5057   D (emitcode (";", "genMinusBits"));
5058
5059   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5060     {
5061       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5062       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5063       emitcode ("cpl", "c");
5064       emitLabel (lbl);
5065       outBitC (IC_RESULT (ic));
5066     }
5067   else
5068     {
5069       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5070       emitcode ("subb", "a,acc");
5071       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5072       emitcode ("inc", "a");
5073       emitLabel (lbl);
5074       aopPut (IC_RESULT (ic), "a", 0);
5075       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5076     }
5077 }
5078
5079 /*-----------------------------------------------------------------*/
5080 /* genMinus - generates code for subtraction                       */
5081 /*-----------------------------------------------------------------*/
5082 static void
5083 genMinus (iCode * ic)
5084 {
5085     int size, offset = 0;
5086     int rSize;
5087     long lit = 0L;
5088     bool pushResult;
5089
5090     D (emitcode (";", "genMinus"));
5091
5092     AOP_OP_3_NOFATAL(ic, pushResult);
5093
5094     if (!pushResult)
5095     {
5096       /* special cases :- */
5097       /* if both left & right are in bit space */
5098       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5099           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5100         {
5101           genMinusBits (ic);
5102           goto release;
5103         }
5104
5105       /* if I can do an decrement instead
5106          of subtract then GOOD for ME */
5107       if (genMinusDec (ic) == TRUE)
5108         goto release;
5109
5110     }
5111
5112   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5113
5114   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5115     {
5116       CLRC;
5117     }
5118   else
5119     {
5120       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5121       lit = -lit;
5122     }
5123
5124
5125   /* if literal, add a,#-lit, else normal subb */
5126   _startLazyDPSEvaluation ();
5127   while (size--) {
5128       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5129           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5130               emitcode ("mov","b,%s",
5131                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5132               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5133               emitcode ("subb","a,b");
5134           } else {
5135               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5136               emitcode ("subb", "a,%s",
5137                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5138                                 DP2_RESULT_REG));
5139           }
5140       } else {
5141           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5142           /* first add without previous c */
5143           if (!offset) {
5144               if (!size && lit==-1) {
5145                   emitcode ("dec", "a");
5146               } else {
5147                   emitcode ("add", "a,#!constbyte",
5148                             (unsigned int) (lit & 0x0FFL));
5149               }
5150           } else {
5151               emitcode ("addc", "a,#!constbyte",
5152                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5153           }
5154       }
5155
5156       if (pushResult) {
5157           emitcode ("push", "acc");
5158       } else {
5159           aopPut (IC_RESULT (ic), "a", offset);
5160       }
5161       offset++;
5162   }
5163   _endLazyDPSEvaluation ();
5164
5165   if (pushResult)
5166     {
5167       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5168
5169       size = getDataSize (IC_LEFT (ic));
5170       rSize = getDataSize (IC_RESULT (ic));
5171
5172       ADJUST_PUSHED_RESULT(size, rSize);
5173
5174       _startLazyDPSEvaluation ();
5175       while (size--)
5176         {
5177           emitcode ("pop", "acc");
5178           aopPut (IC_RESULT (ic), "a", size);
5179         }
5180       _endLazyDPSEvaluation ();
5181     }
5182
5183   adjustArithmeticResult (ic);
5184
5185 release:
5186   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5187   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5188   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5189 }
5190
5191
5192 /*-----------------------------------------------------------------*/
5193 /* genMultbits :- multiplication of bits                           */
5194 /*-----------------------------------------------------------------*/
5195 static void
5196 genMultbits (operand * left,
5197              operand * right,
5198              operand * result,
5199              iCode   * ic)
5200 {
5201   D (emitcode (";", "genMultbits"));
5202
5203   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5204   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5205   aopOp(result, ic, TRUE, FALSE);
5206   outBitC (result);
5207 }
5208
5209 /*-----------------------------------------------------------------*/
5210 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5211 /*-----------------------------------------------------------------*/
5212 static void
5213 genMultOneByte (operand * left,
5214                 operand * right,
5215                 operand * result,
5216                 iCode   * ic)
5217 {
5218   symbol *lbl;
5219   int size;
5220   bool runtimeSign, compiletimeSign;
5221   bool lUnsigned, rUnsigned, pushedB;
5222
5223   /* (if two literals: the value is computed before) */
5224   /* if one literal, literal on the right */
5225   if (AOP_TYPE (left) == AOP_LIT)
5226     {
5227       operand *t = right;
5228       right = left;
5229       left = t;
5230       /* emitcode (";", "swapped left and right"); */
5231     }
5232   /* if no literal, unsigned on the right: shorter code */
5233   if (   AOP_TYPE (right) != AOP_LIT
5234       && SPEC_USIGN (getSpec (operandType (left))))
5235     {
5236       operand *t = right;
5237       right = left;
5238       left = t;
5239     }
5240
5241   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5242   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5243
5244   pushedB = pushB ();
5245
5246   if ((lUnsigned && rUnsigned)
5247 /* sorry, I don't know how to get size
5248    without calling aopOp (result,...);
5249    see Feature Request  */
5250       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5251                    no need to take care about the signedness! */
5252     {
5253       /* just an unsigned 8 * 8 = 8 multiply
5254          or 8u * 8u = 16u */
5255       /* emitcode (";","unsigned"); */
5256       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5257       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5258       emitcode ("mul", "ab");
5259
5260       _G.accInUse++;
5261       aopOp (result, ic, TRUE, FALSE);
5262       size = AOP_SIZE (result);
5263
5264       if (size < 1 || size > 2)
5265         {
5266           /* this should never happen */
5267           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5268                    size, __FILE__, lineno);
5269           exit (1);
5270         }
5271
5272       aopPut (result, "a", 0);
5273       _G.accInUse--;
5274       if (size == 2)
5275         aopPut (result, "b", 1);
5276
5277       popB (pushedB);
5278       return;
5279     }
5280
5281   /* we have to do a signed multiply */
5282   /* emitcode (";", "signed"); */
5283
5284   /* now sign adjust for both left & right */
5285
5286   /* let's see what's needed: */
5287   /* apply negative sign during runtime */
5288   runtimeSign = FALSE;
5289   /* negative sign from literals */
5290   compiletimeSign = FALSE;
5291
5292   if (!lUnsigned)
5293     {
5294       if (AOP_TYPE(left) == AOP_LIT)
5295         {
5296           /* signed literal */
5297           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5298           if (val < 0)
5299             compiletimeSign = TRUE;
5300         }
5301       else
5302         /* signed but not literal */
5303         runtimeSign = TRUE;
5304     }
5305
5306   if (!rUnsigned)
5307     {
5308       if (AOP_TYPE(right) == AOP_LIT)
5309         {
5310           /* signed literal */
5311           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5312           if (val < 0)
5313             compiletimeSign ^= TRUE;
5314         }
5315       else
5316         /* signed but not literal */
5317         runtimeSign = TRUE;
5318     }
5319
5320   /* initialize F0, which stores the runtime sign */
5321   if (runtimeSign)
5322     {
5323       if (compiletimeSign)
5324         emitcode ("setb", "F0"); /* set sign flag */
5325       else
5326         emitcode ("clr", "F0"); /* reset sign flag */
5327     }
5328
5329   /* save the signs of the operands */
5330   if (AOP_TYPE(right) == AOP_LIT)
5331     {
5332       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5333
5334       if (!rUnsigned && val < 0)
5335         emitcode ("mov", "b,#!constbyte", -val);
5336       else
5337         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5338     }
5339   else /* ! literal */
5340     {
5341       if (rUnsigned)  /* emitcode (";", "signed"); */
5342         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5343       else
5344         {
5345           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5346           lbl = newiTempLabel (NULL);
5347           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5348           emitcode ("cpl", "F0"); /* complement sign flag */
5349           emitcode ("cpl", "a");  /* 2's complement */
5350           emitcode ("inc", "a");
5351           emitLabel (lbl);
5352           emitcode ("mov", "b,a");
5353         }
5354     }
5355
5356   if (AOP_TYPE(left) == AOP_LIT)
5357     {
5358       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5359
5360       if (!lUnsigned && val < 0)
5361         emitcode ("mov", "a,#!constbyte", -val);
5362       else
5363         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5364     }
5365   else /* ! literal */
5366     {
5367       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5368
5369       if (!lUnsigned)  /* emitcode (";", "signed"); */
5370         {
5371           lbl = newiTempLabel (NULL);
5372           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5373           emitcode ("cpl", "F0"); /* complement sign flag */
5374           emitcode ("cpl", "a");  /* 2's complement */
5375           emitcode ("inc", "a");
5376           emitLabel (lbl);
5377         }
5378     }
5379
5380   /* now the multiplication */
5381   emitcode ("mul", "ab");
5382   _G.accInUse++;
5383   aopOp(result, ic, TRUE, FALSE);
5384   size = AOP_SIZE (result);
5385
5386   if (size < 1 || size > 2)
5387     {
5388       /* this should never happen */
5389       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5390                size, __FILE__, lineno);
5391       exit (1);
5392     }
5393
5394   if (runtimeSign || compiletimeSign)
5395     {
5396       lbl = newiTempLabel (NULL);
5397       if (runtimeSign)
5398         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5399       emitcode ("cpl", "a"); /* lsb 2's complement */
5400       if (size != 2)
5401         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5402       else
5403         {
5404           emitcode ("add", "a,#1"); /* this sets carry flag */
5405           emitcode ("xch", "a,b");
5406           emitcode ("cpl", "a"); /* msb 2's complement */
5407           emitcode ("addc", "a,#0");
5408           emitcode ("xch", "a,b");
5409         }
5410       emitLabel (lbl);
5411     }
5412   aopPut (result, "a", 0);
5413   _G.accInUse--;
5414   if (size == 2)
5415     aopPut (result, "b", 1);
5416
5417   popB (pushedB);
5418 }
5419
5420 /*-----------------------------------------------------------------*/
5421 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5422 /*-----------------------------------------------------------------*/
5423 static void genMultTwoByte (operand *left, operand *right,
5424                             operand *result, iCode *ic)
5425 {
5426         sym_link *retype = getSpec(operandType(right));
5427         sym_link *letype = getSpec(operandType(left));
5428         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5429         symbol *lbl;
5430
5431         if (AOP_TYPE (left) == AOP_LIT) {
5432                 operand *t = right;
5433                 right = left;
5434                 left = t;
5435         }
5436         /* save EA bit in F1 */
5437         lbl = newiTempLabel(NULL);
5438         emitcode ("setb","F1");
5439         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5440         emitcode ("clr","F1");
5441         emitLabel (lbl);
5442
5443         /* load up MB with right */
5444         if (!umult) {
5445                 emitcode("clr","F0");
5446                 if (AOP_TYPE(right) == AOP_LIT) {
5447                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5448                         if (val < 0) {
5449                                 emitcode("setb","F0");
5450                                 val = -val;
5451                         }
5452                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5453                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5454                 } else {
5455                         lbl = newiTempLabel(NULL);
5456                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5457                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5458                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5459                         emitcode ("xch", "a,b");
5460                         emitcode ("cpl","a");
5461                         emitcode ("add", "a,#1");
5462                         emitcode ("xch", "a,b");
5463                         emitcode ("cpl", "a"); // msb
5464                         emitcode ("addc", "a,#0");
5465                         emitcode ("setb","F0");
5466                         emitLabel (lbl);
5467                         emitcode ("mov","mb,b");
5468                         emitcode ("mov","mb,a");
5469                 }
5470         } else {
5471                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5472                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5473         }
5474         /* load up MA with left */
5475         if (!umult) {
5476                 lbl = newiTempLabel(NULL);
5477                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5478                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5479                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5480                 emitcode ("xch", "a,b");
5481                 emitcode ("cpl","a");
5482                 emitcode ("add", "a,#1");
5483                 emitcode ("xch", "a,b");
5484                 emitcode ("cpl", "a"); // msb
5485                 emitcode ("addc","a,#0");
5486                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5487                 emitcode ("setb","F0");
5488                 emitLabel (lbl);
5489                 emitcode ("mov","ma,b");
5490                 emitcode ("mov","ma,a");
5491         } else {
5492                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5493                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5494         }
5495         /* wait for multiplication to finish */
5496         lbl = newiTempLabel(NULL);
5497         emitLabel (lbl);
5498         emitcode("mov","a,mcnt1");
5499         emitcode("anl","a,#!constbyte",0x80);
5500         emitcode("jnz","!tlabel",lbl->key+100);
5501
5502         freeAsmop (left, NULL, ic, TRUE);
5503         freeAsmop (right, NULL, ic,TRUE);
5504         aopOp(result, ic, TRUE, FALSE);
5505
5506         /* if unsigned then simple */
5507         if (umult) {
5508                 emitcode ("mov","a,ma");
5509                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5510                 emitcode ("mov","a,ma");
5511                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5512                 aopPut(result,"ma",1);
5513                 aopPut(result,"ma",0);
5514         } else {
5515                 emitcode("push","ma");
5516                 emitcode("push","ma");
5517                 emitcode("push","ma");
5518                 MOVA("ma");
5519                 /* negate result if needed */
5520                 lbl = newiTempLabel(NULL);
5521                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5522                 emitcode("cpl","a");
5523                 emitcode("add","a,#1");
5524                 emitLabel (lbl);
5525                 if (AOP_TYPE(result) == AOP_ACC)
5526                 {
5527                     D (emitcode(";", "ACC special case."));
5528                     /* We know result is the only live aop, and
5529                      * it's obviously not a DPTR2, so AP is available.
5530                      */
5531                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5532                 }
5533                 else
5534                 {
5535                     aopPut(result,"a",0);
5536                 }
5537
5538                 emitcode("pop","acc");
5539                 lbl = newiTempLabel(NULL);
5540                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5541                 emitcode("cpl","a");
5542                 emitcode("addc","a,#0");
5543                 emitLabel (lbl);
5544                 aopPut(result,"a",1);
5545                 emitcode("pop","acc");
5546                 if (AOP_SIZE(result) >= 3) {
5547                         lbl = newiTempLabel(NULL);
5548                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5549                         emitcode("cpl","a");
5550                         emitcode("addc","a,#0");
5551                         emitLabel (lbl);
5552                         aopPut(result,"a",2);
5553                 }
5554                 emitcode("pop","acc");
5555                 if (AOP_SIZE(result) >= 4) {
5556                         lbl = newiTempLabel(NULL);
5557                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5558                         emitcode("cpl","a");
5559                         emitcode("addc","a,#0");
5560                         emitLabel (lbl);
5561                         aopPut(result,"a",3);
5562                 }
5563                 if (AOP_TYPE(result) == AOP_ACC)
5564                 {
5565                     /* We stashed the result away above. */
5566                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5567                 }
5568
5569         }
5570         freeAsmop (result, NULL, ic, TRUE);
5571
5572         /* restore EA bit in F1 */
5573         lbl = newiTempLabel(NULL);
5574         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5575         emitcode ("setb","EA");
5576         emitLabel (lbl);
5577         return ;
5578 }
5579
5580 /*-----------------------------------------------------------------*/
5581 /* genMult - generates code for multiplication                     */
5582 /*-----------------------------------------------------------------*/
5583 static void
5584 genMult (iCode * ic)
5585 {
5586   operand *left = IC_LEFT (ic);
5587   operand *right = IC_RIGHT (ic);
5588   operand *result = IC_RESULT (ic);
5589
5590   D (emitcode (";", "genMult"));
5591
5592   /* assign the asmops */
5593   AOP_OP_2 (ic);
5594
5595   /* special cases first */
5596   /* both are bits */
5597   if (AOP_TYPE (left) == AOP_CRY &&
5598       AOP_TYPE (right) == AOP_CRY)
5599     {
5600       genMultbits (left, right, result, ic);
5601       goto release;
5602     }
5603
5604   /* if both are of size == 1 */
5605   if (AOP_SIZE (left) == 1 &&
5606       AOP_SIZE (right) == 1)
5607     {
5608       genMultOneByte (left, right, result, ic);
5609       goto release;
5610     }
5611
5612   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5613           /* use the ds390 ARITHMETIC accel UNIT */
5614           genMultTwoByte (left, right, result, ic);
5615           return ;
5616   }
5617   /* should have been converted to function call */
5618   assert (0);
5619
5620 release:
5621   freeAsmop (result, NULL, ic, TRUE);
5622   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5623   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5624 }
5625
5626 /*-----------------------------------------------------------------*/
5627 /* genDivbits :- division of bits                                  */
5628 /*-----------------------------------------------------------------*/
5629 static void
5630 genDivbits (operand * left,
5631             operand * right,
5632             operand * result,
5633             iCode   * ic)
5634 {
5635   char *l;
5636   bool pushedB;
5637
5638   D(emitcode (";     genDivbits",""));
5639
5640   pushedB = pushB ();
5641
5642   /* the result must be bit */
5643   LOAD_AB_FOR_DIV (left, right, l);
5644   emitcode ("div", "ab");
5645   emitcode ("rrc", "a");
5646   aopOp(result, ic, TRUE, FALSE);
5647
5648   popB (pushedB);
5649
5650   aopPut (result, "c", 0);
5651 }
5652
5653 /*-----------------------------------------------------------------*/
5654 /* genDivOneByte : 8 bit division                                  */
5655 /*-----------------------------------------------------------------*/
5656 static void
5657 genDivOneByte (operand * left,
5658                operand * right,
5659                operand * result,
5660                iCode   * ic)
5661 {
5662   bool lUnsigned, rUnsigned, pushedB;
5663   bool runtimeSign, compiletimeSign;
5664   char *l;
5665   symbol *lbl;
5666   int size, offset;
5667
5668   D(emitcode (";     genDivOneByte",""));
5669
5670   offset = 1;
5671   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5672   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5673
5674   pushedB = pushB ();
5675
5676   /* signed or unsigned */
5677   if (lUnsigned && rUnsigned)
5678     {
5679       /* unsigned is easy */
5680       LOAD_AB_FOR_DIV (left, right, l);
5681       emitcode ("div", "ab");
5682
5683       _G.accInUse++;
5684       aopOp (result, ic, TRUE, FALSE);
5685       aopPut (result, "a", 0);
5686       _G.accInUse--;
5687
5688       size = AOP_SIZE (result) - 1;
5689
5690       while (size--)
5691         aopPut (result, zero, offset++);
5692
5693       popB (pushedB);
5694       return;
5695     }
5696
5697   /* signed is a little bit more difficult */
5698
5699   /* now sign adjust for both left & right */
5700
5701   /* let's see what's needed: */
5702   /* apply negative sign during runtime */
5703   runtimeSign = FALSE;
5704   /* negative sign from literals */
5705   compiletimeSign = FALSE;
5706
5707   if (!lUnsigned)
5708     {
5709       if (AOP_TYPE(left) == AOP_LIT)
5710         {
5711           /* signed literal */
5712           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5713           if (val < 0)
5714             compiletimeSign = TRUE;
5715         }
5716       else
5717         /* signed but not literal */
5718         runtimeSign = TRUE;
5719     }
5720
5721   if (!rUnsigned)
5722     {
5723       if (AOP_TYPE(right) == AOP_LIT)
5724         {
5725           /* signed literal */
5726           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5727           if (val < 0)
5728             compiletimeSign ^= TRUE;
5729         }
5730       else
5731         /* signed but not literal */
5732         runtimeSign = TRUE;
5733     }
5734
5735   /* initialize F0, which stores the runtime sign */
5736   if (runtimeSign)
5737     {
5738       if (compiletimeSign)
5739         emitcode ("setb", "F0"); /* set sign flag */
5740       else
5741         emitcode ("clr", "F0"); /* reset sign flag */
5742     }
5743
5744   /* save the signs of the operands */
5745   if (AOP_TYPE(right) == AOP_LIT)
5746     {
5747       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5748
5749       if (!rUnsigned && val < 0)
5750         emitcode ("mov", "b,#0x%02x", -val);
5751       else
5752         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5753     }
5754   else /* ! literal */
5755     {
5756       if (rUnsigned)
5757         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5758       else
5759         {
5760           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5761           lbl = newiTempLabel (NULL);
5762           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5763           emitcode ("cpl", "F0"); /* complement sign flag */
5764           emitcode ("cpl", "a");  /* 2's complement */
5765           emitcode ("inc", "a");
5766           emitLabel (lbl);
5767           emitcode ("mov", "b,a");
5768         }
5769     }
5770
5771   if (AOP_TYPE(left) == AOP_LIT)
5772     {
5773       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5774
5775       if (!lUnsigned && val < 0)
5776         emitcode ("mov", "a,#0x%02x", -val);
5777       else
5778         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5779     }
5780   else /* ! literal */
5781     {
5782       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5783
5784       if (!lUnsigned)
5785         {
5786           lbl = newiTempLabel (NULL);
5787           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5788           emitcode ("cpl", "F0"); /* complement sign flag */
5789           emitcode ("cpl", "a");  /* 2's complement */
5790           emitcode ("inc", "a");
5791           emitLabel (lbl);
5792         }
5793     }
5794
5795   /* now the division */
5796   emitcode ("nop", "; workaround for DS80C390 div bug.");
5797   emitcode ("div", "ab");
5798
5799   if (runtimeSign || compiletimeSign)
5800     {
5801       lbl = newiTempLabel (NULL);
5802       if (runtimeSign)
5803         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5804       emitcode ("cpl", "a"); /* lsb 2's complement */
5805       emitcode ("inc", "a");
5806       emitLabel (lbl);
5807
5808       _G.accInUse++;
5809       aopOp (result, ic, TRUE, FALSE);
5810       size = AOP_SIZE (result) - 1;
5811
5812       if (size > 0)
5813         {
5814           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5815              then the result will be in b, a */
5816           emitcode ("mov", "b,a"); /* 1 */
5817           /* msb is 0x00 or 0xff depending on the sign */
5818           if (runtimeSign)
5819             {
5820               emitcode ("mov",  "c,F0");
5821               emitcode ("subb", "a,acc");
5822               emitcode ("xch",  "a,b"); /* 2 */
5823               while (size--)
5824                 aopPut (result, "b", offset++); /* write msb's */
5825             }
5826           else /* compiletimeSign */
5827             while (size--)
5828               aopPut (result, "#0xff", offset++); /* write msb's */
5829         }
5830       aopPut (result, "a", 0); /* 3: write lsb */
5831     }
5832   else
5833     {
5834       _G.accInUse++;
5835       aopOp(result, ic, TRUE, FALSE);
5836       size = AOP_SIZE (result) - 1;
5837
5838       aopPut (result, "a", 0);
5839       while (size--)
5840         aopPut (result, zero, offset++);
5841     }
5842   _G.accInUse--;
5843   popB (pushedB);
5844 }
5845
5846 /*-----------------------------------------------------------------*/
5847 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5848 /*-----------------------------------------------------------------*/
5849 static void genDivTwoByte (operand *left, operand *right,
5850                             operand *result, iCode *ic)
5851 {
5852         sym_link *retype = getSpec(operandType(right));
5853         sym_link *letype = getSpec(operandType(left));
5854         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5855         symbol *lbl;
5856
5857         /* save EA bit in F1 */
5858         lbl = newiTempLabel(NULL);
5859         emitcode ("setb","F1");
5860         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5861         emitcode ("clr","F1");
5862         emitLabel (lbl);
5863
5864         /* load up MA with left */
5865         if (!umult) {
5866                 emitcode("clr","F0");
5867                 lbl = newiTempLabel(NULL);
5868                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5869                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5870                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5871                 emitcode ("xch", "a,b");
5872                 emitcode ("cpl","a");
5873                 emitcode ("add", "a,#1");
5874                 emitcode ("xch", "a,b");
5875                 emitcode ("cpl", "a"); // msb
5876                 emitcode ("addc","a,#0");
5877                 emitcode ("setb","F0");
5878                 emitLabel (lbl);
5879                 emitcode ("mov","ma,b");
5880                 emitcode ("mov","ma,a");
5881         } else {
5882                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5883                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5884         }
5885
5886         /* load up MB with right */
5887         if (!umult) {
5888                 if (AOP_TYPE(right) == AOP_LIT) {
5889                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5890                         if (val < 0) {
5891                                 lbl = newiTempLabel(NULL);
5892                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5893                                 emitcode("setb","F0");
5894                                 emitLabel (lbl);
5895                                 val = -val;
5896                         }
5897                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5898                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5899                 } else {
5900                         lbl = newiTempLabel(NULL);
5901                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5902                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5903                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5904                         emitcode ("xch", "a,b");
5905                         emitcode ("cpl","a");
5906                         emitcode ("add", "a,#1");
5907                         emitcode ("xch", "a,b");
5908                         emitcode ("cpl", "a"); // msb
5909                         emitcode ("addc", "a,#0");
5910                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5911                         emitcode ("setb","F0");
5912                         emitLabel (lbl);
5913                         emitcode ("mov","mb,b");
5914                         emitcode ("mov","mb,a");
5915                 }
5916         } else {
5917                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5918                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5919         }
5920
5921         /* wait for multiplication to finish */
5922         lbl = newiTempLabel(NULL);
5923         emitLabel (lbl);
5924         emitcode("mov","a,mcnt1");
5925         emitcode("anl","a,#!constbyte",0x80);
5926         emitcode("jnz","!tlabel",lbl->key+100);
5927
5928         freeAsmop (left, NULL, ic, TRUE);
5929         freeAsmop (right, NULL, ic,TRUE);
5930         aopOp(result, ic, TRUE, FALSE);
5931
5932         /* if unsigned then simple */
5933         if (umult) {
5934                 aopPut(result,"ma",1);
5935                 aopPut(result,"ma",0);
5936         } else {
5937                 emitcode("push","ma");
5938                 MOVA("ma");
5939                 /* negate result if needed */
5940                 lbl = newiTempLabel(NULL);
5941                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5942                 emitcode("cpl","a");
5943                 emitcode("add","a,#1");
5944                 emitLabel (lbl);
5945                 aopPut(result,"a",0);
5946                 emitcode("pop","acc");
5947                 lbl = newiTempLabel(NULL);
5948                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5949                 emitcode("cpl","a");
5950                 emitcode("addc","a,#0");
5951                 emitLabel (lbl);
5952                 aopPut(result,"a",1);
5953         }
5954         freeAsmop (result, NULL, ic, TRUE);
5955         /* restore EA bit in F1 */
5956         lbl = newiTempLabel(NULL);
5957         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5958         emitcode ("setb","EA");
5959         emitLabel (lbl);
5960         return ;
5961 }
5962
5963 /*-----------------------------------------------------------------*/
5964 /* genDiv - generates code for division                            */
5965 /*-----------------------------------------------------------------*/
5966 static void
5967 genDiv (iCode * ic)
5968 {
5969   operand *left = IC_LEFT (ic);
5970   operand *right = IC_RIGHT (ic);
5971   operand *result = IC_RESULT (ic);
5972
5973   D (emitcode (";", "genDiv"));
5974
5975   /* assign the amsops */
5976   AOP_OP_2 (ic);
5977
5978   /* special cases first */
5979   /* both are bits */
5980   if (AOP_TYPE (left) == AOP_CRY &&
5981       AOP_TYPE (right) == AOP_CRY)
5982     {
5983       genDivbits (left, right, result, ic);
5984       goto release;
5985     }
5986
5987   /* if both are of size == 1 */
5988   if (AOP_SIZE (left) == 1 &&
5989       AOP_SIZE (right) == 1)
5990     {
5991       genDivOneByte (left, right, result, ic);
5992       goto release;
5993     }
5994
5995   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5996           /* use the ds390 ARITHMETIC accel UNIT */
5997           genDivTwoByte (left, right, result, ic);
5998           return ;
5999   }
6000   /* should have been converted to function call */
6001   assert (0);
6002 release:
6003   freeAsmop (result, NULL, ic, TRUE);
6004   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6005   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6006 }
6007
6008 /*-----------------------------------------------------------------*/
6009 /* genModbits :- modulus of bits                                   */
6010 /*-----------------------------------------------------------------*/
6011 static void
6012 genModbits (operand * left,
6013             operand * right,
6014             operand * result,
6015             iCode   * ic)
6016 {
6017   char *l;
6018   bool pushedB;
6019
6020   D (emitcode (";", "genModbits"));
6021
6022   pushedB = pushB ();
6023
6024   /* the result must be bit */
6025   LOAD_AB_FOR_DIV (left, right, l);
6026   emitcode ("div", "ab");
6027   emitcode ("mov", "a,b");
6028   emitcode ("rrc", "a");
6029   aopOp(result, ic, TRUE, FALSE);
6030
6031   popB (pushedB);
6032
6033   aopPut (result, "c", 0);
6034 }
6035
6036 /*-----------------------------------------------------------------*/
6037 /* genModOneByte : 8 bit modulus                                   */
6038 /*-----------------------------------------------------------------*/
6039 static void
6040 genModOneByte (operand * left,
6041                operand * right,
6042                operand * result,
6043                iCode   * ic)
6044 {
6045   bool lUnsigned, rUnsigned, pushedB;
6046   bool runtimeSign, compiletimeSign;
6047   char *l;
6048   symbol *lbl;
6049   int size, offset;
6050
6051   D (emitcode (";", "genModOneByte"));
6052
6053   offset = 1;
6054   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6055   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6056
6057   pushedB = pushB ();
6058
6059   /* signed or unsigned */
6060   if (lUnsigned && rUnsigned)
6061     {
6062       /* unsigned is easy */
6063       LOAD_AB_FOR_DIV (left, right, l);
6064       emitcode ("div", "ab");
6065       aopOp (result, ic, TRUE, FALSE);
6066       aopPut (result, "b", 0);
6067
6068       for (size = AOP_SIZE (result) - 1; size--;)
6069         aopPut (result, zero, offset++);
6070
6071       popB (pushedB);
6072       return;
6073     }
6074
6075   /* signed is a little bit more difficult */
6076
6077   /* now sign adjust for both left & right */
6078
6079   /* modulus: sign of the right operand has no influence on the result! */
6080   if (AOP_TYPE(right) == AOP_LIT)
6081     {
6082       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6083
6084       if (!rUnsigned && val < 0)
6085         emitcode ("mov", "b,#0x%02x", -val);
6086       else
6087         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6088     }
6089   else /* not literal */
6090     {
6091       if (rUnsigned)
6092         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6093       else
6094         {
6095           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6096           lbl = newiTempLabel (NULL);
6097           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6098           emitcode ("cpl", "a");  /* 2's complement */
6099           emitcode ("inc", "a");
6100           emitLabel (lbl);
6101           emitcode ("mov", "b,a");
6102         }
6103     }
6104
6105   /* let's see what's needed: */
6106   /* apply negative sign during runtime */
6107   runtimeSign = FALSE;
6108   /* negative sign from literals */
6109   compiletimeSign = FALSE;
6110
6111   /* sign adjust left side */
6112   if (AOP_TYPE(left) == AOP_LIT)
6113     {
6114       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6115
6116       if (!lUnsigned && val < 0)
6117         {
6118           compiletimeSign = TRUE; /* set sign flag */
6119           emitcode ("mov", "a,#0x%02x", -val);
6120         }
6121       else
6122         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6123     }
6124   else /* ! literal */
6125     {
6126       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6127
6128       if (!lUnsigned)
6129         {
6130           runtimeSign = TRUE;
6131           emitcode ("clr", "F0"); /* clear sign flag */
6132
6133           lbl = newiTempLabel (NULL);
6134           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6135           emitcode ("setb", "F0"); /* set sign flag */
6136           emitcode ("cpl", "a");   /* 2's complement */
6137           emitcode ("inc", "a");
6138           emitLabel (lbl);
6139         }
6140     }
6141
6142   /* now the modulus */
6143   emitcode ("nop", "; workaround for DS80C390 div bug.");
6144   emitcode ("div", "ab");
6145
6146   if (runtimeSign || compiletimeSign)
6147     {
6148       emitcode ("mov", "a,b");
6149       lbl = newiTempLabel (NULL);
6150       if (runtimeSign)
6151         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6152       emitcode ("cpl", "a"); /* lsb 2's complement */
6153       emitcode ("inc", "a");
6154       emitLabel (lbl);
6155
6156       _G.accInUse++;
6157       aopOp (result, ic, TRUE, FALSE);
6158       size = AOP_SIZE (result) - 1;
6159
6160       if (size > 0)
6161         {
6162           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6163              then the result will be in b, a */
6164           emitcode ("mov", "b,a"); /* 1 */
6165           /* msb is 0x00 or 0xff depending on the sign */
6166           if (runtimeSign)
6167             {
6168               emitcode ("mov",  "c,F0");
6169               emitcode ("subb", "a,acc");
6170               emitcode ("xch",  "a,b"); /* 2 */
6171               while (size--)
6172                 aopPut (result, "b", offset++); /* write msb's */
6173             }
6174           else /* compiletimeSign */
6175             while (size--)
6176               aopPut (result, "#0xff", offset++); /* write msb's */
6177         }
6178       aopPut (result, "a", 0); /* 3: write lsb */
6179     }
6180   else
6181     {
6182       _G.accInUse++;
6183       aopOp(result, ic, TRUE, FALSE);
6184       size = AOP_SIZE (result) - 1;
6185
6186       aopPut (result, "b", 0);
6187       while (size--)
6188         aopPut (result, zero, offset++);
6189     }
6190   _G.accInUse--;
6191   popB (pushedB);
6192 }
6193
6194 /*-----------------------------------------------------------------*/
6195 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6196 /*-----------------------------------------------------------------*/
6197 static void genModTwoByte (operand *left, operand *right,
6198                             operand *result, iCode *ic)
6199 {
6200         sym_link *retype = getSpec(operandType(right));
6201         sym_link *letype = getSpec(operandType(left));
6202         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6203         symbol *lbl;
6204
6205         /* load up MA with left */
6206         /* save EA bit in F1 */
6207         lbl = newiTempLabel(NULL);
6208         emitcode ("setb","F1");
6209         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6210         emitcode ("clr","F1");
6211         emitLabel (lbl);
6212
6213         if (!umult) {
6214                 lbl = newiTempLabel(NULL);
6215                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6216                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6217                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6218                 emitcode ("xch", "a,b");
6219                 emitcode ("cpl","a");
6220                 emitcode ("add", "a,#1");
6221                 emitcode ("xch", "a,b");
6222                 emitcode ("cpl", "a"); // msb
6223                 emitcode ("addc","a,#0");
6224                 emitLabel (lbl);
6225                 emitcode ("mov","ma,b");
6226                 emitcode ("mov","ma,a");
6227         } else {
6228                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6229                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6230         }
6231
6232         /* load up MB with right */
6233         if (!umult) {
6234                 if (AOP_TYPE(right) == AOP_LIT) {
6235                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6236                         if (val < 0) {
6237                                 val = -val;
6238                         }
6239                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6240                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6241                 } else {
6242                         lbl = newiTempLabel(NULL);
6243                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6244                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6245                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6246                         emitcode ("xch", "a,b");
6247                         emitcode ("cpl","a");
6248                         emitcode ("add", "a,#1");
6249                         emitcode ("xch", "a,b");
6250                         emitcode ("cpl", "a"); // msb
6251                         emitcode ("addc", "a,#0");
6252                         emitLabel (lbl);
6253                         emitcode ("mov","mb,b");
6254                         emitcode ("mov","mb,a");
6255                 }
6256         } else {
6257                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6258                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6259         }
6260
6261         /* wait for multiplication to finish */
6262         lbl = newiTempLabel(NULL);
6263         emitLabel (lbl);
6264         emitcode("mov","a,mcnt1");
6265         emitcode("anl","a,#!constbyte",0x80);
6266         emitcode("jnz","!tlabel",lbl->key+100);
6267
6268         freeAsmop (left, NULL, ic, TRUE);
6269         freeAsmop (right, NULL, ic,TRUE);
6270         aopOp(result, ic, TRUE, FALSE);
6271
6272         aopPut(result,"mb",1);
6273         aopPut(result,"mb",0);
6274         freeAsmop (result, NULL, ic, TRUE);
6275
6276         /* restore EA bit in F1 */
6277         lbl = newiTempLabel(NULL);
6278         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6279         emitcode ("setb","EA");
6280         emitLabel (lbl);
6281 }
6282
6283 /*-----------------------------------------------------------------*/
6284 /* genMod - generates code for division                            */
6285 /*-----------------------------------------------------------------*/
6286 static void
6287 genMod (iCode * ic)
6288 {
6289   operand *left = IC_LEFT (ic);
6290   operand *right = IC_RIGHT (ic);
6291   operand *result = IC_RESULT (ic);
6292
6293   D (emitcode (";", "genMod"));
6294
6295   /* assign the asmops */
6296   AOP_OP_2 (ic);
6297
6298   /* special cases first */
6299   /* both are bits */
6300   if (AOP_TYPE (left) == AOP_CRY &&
6301       AOP_TYPE (right) == AOP_CRY)
6302     {
6303       genModbits (left, right, result, ic);
6304       goto release;
6305     }
6306
6307   /* if both are of size == 1 */
6308   if (AOP_SIZE (left) == 1 &&
6309       AOP_SIZE (right) == 1)
6310     {
6311       genModOneByte (left, right, result, ic);
6312       goto release;
6313     }
6314
6315   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6316           /* use the ds390 ARITHMETIC accel UNIT */
6317           genModTwoByte (left, right, result, ic);
6318           return ;
6319   }
6320
6321   /* should have been converted to function call */
6322   assert (0);
6323
6324 release:
6325   freeAsmop (result, NULL, ic, TRUE);
6326   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6327   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6328 }
6329
6330 /*-----------------------------------------------------------------*/
6331 /* genIfxJump :- will create a jump depending on the ifx           */
6332 /*-----------------------------------------------------------------*/
6333 static void
6334 genIfxJump (iCode * ic, char *jval)
6335 {
6336   symbol *jlbl;
6337   symbol *tlbl = newiTempLabel (NULL);
6338   char *inst;
6339
6340   D (emitcode (";", "genIfxJump"));
6341
6342   /* if true label then we jump if condition
6343      supplied is true */
6344   if (IC_TRUE (ic))
6345     {
6346       jlbl = IC_TRUE (ic);
6347       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6348                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6349     }
6350   else
6351     {
6352       /* false label is present */
6353       jlbl = IC_FALSE (ic);
6354       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6355                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6356     }
6357   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6358     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6359   else
6360     emitcode (inst, "!tlabel", tlbl->key + 100);
6361   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6362   emitLabel (tlbl);
6363
6364   /* mark the icode as generated */
6365   ic->generated = 1;
6366 }
6367
6368 /*-----------------------------------------------------------------*/
6369 /* genCmp :- greater or less than comparison                       */
6370 /*-----------------------------------------------------------------*/
6371 static void
6372 genCmp (operand * left, operand * right,
6373         iCode * ic, iCode * ifx, int sign)
6374 {
6375   int size, offset = 0;
6376   unsigned long lit = 0L;
6377   operand *result;
6378
6379   D (emitcode (";", "genCmp"));
6380
6381   result = IC_RESULT (ic);
6382
6383   /* if left & right are bit variables */
6384   if (AOP_TYPE (left) == AOP_CRY &&
6385       AOP_TYPE (right) == AOP_CRY)
6386     {
6387       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6388       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6389     }
6390   else
6391     {
6392       /* subtract right from left if at the
6393          end the carry flag is set then we know that
6394          left is greater than right */
6395       size = max (AOP_SIZE (left), AOP_SIZE (right));
6396
6397       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6398       if ((size == 1) && !sign &&
6399           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6400         {
6401           symbol *lbl = newiTempLabel (NULL);
6402           emitcode ("cjne", "%s,%s,!tlabel",
6403                     aopGet (left, offset, FALSE, FALSE, NULL),
6404                     aopGet (right, offset, FALSE, FALSE, NULL),
6405                     lbl->key + 100);
6406           emitLabel (lbl);
6407         }
6408       else
6409         {
6410           if (AOP_TYPE (right) == AOP_LIT)
6411             {
6412               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6413               /* optimize if(x < 0) or if(x >= 0) */
6414               if (lit == 0L)
6415                 {
6416                   if (!sign)
6417                     {
6418                       CLRC;
6419                     }
6420                   else
6421                     {
6422                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6423
6424                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6425                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6426
6427                       aopOp (result, ic, FALSE, FALSE);
6428
6429                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6430                         {
6431                           freeAsmop (result, NULL, ic, TRUE);
6432                           genIfxJump (ifx, "acc.7");
6433                           return;
6434                         }
6435                       else
6436                         {
6437                           emitcode ("rlc", "a");
6438                         }
6439                       goto release_freedLR;
6440                     }
6441                   goto release;
6442                 }
6443             }
6444           CLRC;
6445           while (size--)
6446             {
6447               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6448               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6449               // emitcode (";", "genCmp #2");
6450               if (sign && (size == 0))
6451                 {
6452                   // emitcode (";", "genCmp #3");
6453                   emitcode ("xrl", "a,#!constbyte",0x80);
6454                   if (AOP_TYPE (right) == AOP_LIT)
6455                     {
6456                       unsigned long lit = (unsigned long)
6457                       floatFromVal (AOP (right)->aopu.aop_lit);
6458                       // emitcode (";", "genCmp #3.1");
6459                       emitcode ("subb", "a,#!constbyte",
6460                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6461                     }
6462                   else
6463                     {
6464                       // emitcode (";", "genCmp #3.2");
6465                       saveAccWarn = 0;
6466                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6467                       saveAccWarn = DEFAULT_ACC_WARNING;
6468                       emitcode ("xrl", "b,#!constbyte",0x80);
6469                       emitcode ("subb", "a,b");
6470                     }
6471                 }
6472               else
6473                 {
6474                   const char *s;
6475
6476                   // emitcode (";", "genCmp #4");
6477                   saveAccWarn = 0;
6478                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6479                   saveAccWarn = DEFAULT_ACC_WARNING;
6480
6481                   emitcode ("subb", "a,%s", s);
6482                 }
6483             }
6484         }
6485     }
6486
6487 release:
6488 /* Don't need the left & right operands any more; do need the result. */
6489   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6490   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6491
6492   aopOp (result, ic, FALSE, FALSE);
6493
6494 release_freedLR:
6495
6496   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6497     {
6498       outBitC (result);
6499     }
6500   else
6501     {
6502       /* if the result is used in the next
6503          ifx conditional branch then generate
6504          code a little differently */
6505       if (ifx)
6506         {
6507           genIfxJump (ifx, "c");
6508         }
6509       else
6510         {
6511           outBitC (result);
6512         }
6513       /* leave the result in acc */
6514     }
6515   freeAsmop (result, NULL, ic, TRUE);
6516 }
6517
6518 /*-----------------------------------------------------------------*/
6519 /* genCmpGt :- greater than comparison                             */
6520 /*-----------------------------------------------------------------*/
6521 static void
6522 genCmpGt (iCode * ic, iCode * ifx)
6523 {
6524   operand *left, *right;
6525   sym_link *letype, *retype;
6526   int sign;
6527
6528   D (emitcode (";", "genCmpGt"));
6529
6530   left = IC_LEFT (ic);
6531   right = IC_RIGHT (ic);
6532
6533   letype = getSpec (operandType (left));
6534   retype = getSpec (operandType (right));
6535   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6536
6537   /* assign the left & right amsops */
6538   AOP_OP_2 (ic);
6539
6540   genCmp (right, left, ic, ifx, sign);
6541 }
6542
6543 /*-----------------------------------------------------------------*/
6544 /* genCmpLt - less than comparisons                                */
6545 /*-----------------------------------------------------------------*/
6546 static void
6547 genCmpLt (iCode * ic, iCode * ifx)
6548 {
6549   operand *left, *right;
6550   sym_link *letype, *retype;
6551   int sign;
6552
6553   D (emitcode (";", "genCmpLt"));
6554
6555   left = IC_LEFT (ic);
6556   right = IC_RIGHT (ic);
6557
6558   letype = getSpec (operandType (left));
6559   retype = getSpec (operandType (right));
6560   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6561
6562   /* assign the left & right amsops */
6563   AOP_OP_2 (ic);
6564
6565   genCmp (left, right, ic, ifx, sign);
6566 }
6567
6568 /*-----------------------------------------------------------------*/
6569 /* gencjneshort - compare and jump if not equal                    */
6570 /*-----------------------------------------------------------------*/
6571 static void
6572 gencjneshort (operand * left, operand * right, symbol * lbl)
6573 {
6574   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6575   int offset = 0;
6576   unsigned long lit = 0L;
6577
6578   D (emitcode (";", "gencjneshort"));
6579
6580   /* if the left side is a literal or
6581      if the right is in a pointer register and left
6582      is not */
6583   if ((AOP_TYPE (left) == AOP_LIT) ||
6584       (AOP_TYPE (left) == AOP_IMMD) ||
6585       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6586     {
6587       operand *t = right;
6588       right = left;
6589       left = t;
6590     }
6591
6592   if (AOP_TYPE (right) == AOP_LIT)
6593     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6594
6595   if (opIsGptr (left) || opIsGptr (right))
6596     {
6597       /* We are comparing a generic pointer to something.
6598        * Exclude the generic type byte from the comparison.
6599        */
6600       size--;
6601       D (emitcode (";", "cjneshort: generic ptr special case."););
6602     }
6603
6604
6605   /* if the right side is a literal then anything goes */
6606   if (AOP_TYPE (right) == AOP_LIT &&
6607       AOP_TYPE (left) != AOP_DIR)
6608     {
6609       while (size--)
6610         {
6611           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6612           emitcode ("cjne", "a,%s,!tlabel",
6613                     aopGet (right, offset, FALSE, FALSE, NULL),
6614                     lbl->key + 100);
6615           offset++;
6616         }
6617     }
6618
6619   /* if the right side is in a register or in direct space or
6620      if the left is a pointer register & right is not */
6621   else if (AOP_TYPE (right) == AOP_REG ||
6622            AOP_TYPE (right) == AOP_DIR ||
6623            AOP_TYPE (right) == AOP_LIT ||
6624            AOP_TYPE (right) == AOP_IMMD ||
6625            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6626            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6627     {
6628       while (size--)
6629         {
6630           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6631           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6632               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6633             emitcode ("jnz", "!tlabel", lbl->key + 100);
6634           else
6635             emitcode ("cjne", "a,%s,!tlabel",
6636                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6637                       lbl->key + 100);
6638           offset++;
6639         }
6640     }
6641   else
6642     {
6643       /* right is a pointer reg need both a & b */
6644       while (size--)
6645         {
6646           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6647           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6648           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6649           offset++;
6650         }
6651     }
6652 }
6653
6654 /*-----------------------------------------------------------------*/
6655 /* gencjne - compare and jump if not equal                         */
6656 /*-----------------------------------------------------------------*/
6657 static void
6658 gencjne (operand * left, operand * right, symbol * lbl)
6659 {
6660   symbol *tlbl = newiTempLabel (NULL);
6661
6662   D (emitcode (";", "gencjne"));
6663
6664   gencjneshort (left, right, lbl);
6665
6666   emitcode ("mov", "a,%s", one);
6667   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6668   emitLabel (lbl);
6669   emitcode ("clr", "a");
6670   emitLabel (tlbl);
6671 }
6672
6673 /*-----------------------------------------------------------------*/
6674 /* genCmpEq - generates code for equal to                          */
6675 /*-----------------------------------------------------------------*/
6676 static void
6677 genCmpEq (iCode * ic, iCode * ifx)
6678 {
6679   operand *left, *right, *result;
6680
6681   D (emitcode (";", "genCmpEq"));
6682
6683   AOP_OP_2 (ic);
6684   AOP_SET_LOCALS (ic);
6685
6686   /* if literal, literal on the right or
6687      if the right is in a pointer register and left
6688      is not */
6689   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6690       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6691     {
6692       operand *t = IC_RIGHT (ic);
6693       IC_RIGHT (ic) = IC_LEFT (ic);
6694       IC_LEFT (ic) = t;
6695     }
6696
6697   if (ifx &&                    /* !AOP_SIZE(result) */
6698       OP_SYMBOL (result) &&
6699       OP_SYMBOL (result)->regType == REG_CND)
6700     {
6701       symbol *tlbl;
6702       /* if they are both bit variables */
6703       if (AOP_TYPE (left) == AOP_CRY &&
6704           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6705         {
6706           if (AOP_TYPE (right) == AOP_LIT)
6707             {
6708               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6709               if (lit == 0L)
6710                 {
6711                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6712                   emitcode ("cpl", "c");
6713                 }
6714               else if (lit == 1L)
6715                 {
6716                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6717                 }
6718               else
6719                 {
6720                   emitcode ("clr", "c");
6721                 }
6722               /* AOP_TYPE(right) == AOP_CRY */
6723             }
6724           else
6725             {
6726               symbol *lbl = newiTempLabel (NULL);
6727               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6728               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6729               emitcode ("cpl", "c");
6730               emitLabel (lbl);
6731             }
6732           /* if true label then we jump if condition
6733              supplied is true */
6734           tlbl = newiTempLabel (NULL);
6735           if (IC_TRUE (ifx))
6736             {
6737               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6738               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6739             }
6740           else
6741             {
6742               emitcode ("jc", "!tlabel", tlbl->key + 100);
6743               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6744             }
6745           emitLabel (tlbl);
6746         }
6747       else
6748         {
6749           tlbl = newiTempLabel (NULL);
6750           gencjneshort (left, right, tlbl);
6751           if (IC_TRUE (ifx))
6752             {
6753               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6754               emitLabel (tlbl);
6755             }
6756           else
6757             {
6758               symbol *lbl = newiTempLabel (NULL);
6759               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6760               emitLabel (tlbl);
6761               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6762               emitLabel (lbl);
6763             }
6764         }
6765       /* mark the icode as generated */
6766       ifx->generated = 1;
6767
6768       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6769       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6770       return;
6771     }
6772
6773   /* if they are both bit variables */
6774   if (AOP_TYPE (left) == AOP_CRY &&
6775       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6776     {
6777       if (AOP_TYPE (right) == AOP_LIT)
6778         {
6779           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6780           if (lit == 0L)
6781             {
6782               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6783               emitcode ("cpl", "c");
6784             }
6785           else if (lit == 1L)
6786             {
6787               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6788             }
6789           else
6790             {
6791               emitcode ("clr", "c");
6792             }
6793           /* AOP_TYPE(right) == AOP_CRY */
6794         }
6795       else
6796         {
6797           symbol *lbl = newiTempLabel (NULL);
6798           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6799           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6800           emitcode ("cpl", "c");
6801           emitLabel (lbl);
6802         }
6803
6804       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6805       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6806
6807       aopOp (result, ic, TRUE, FALSE);
6808
6809       /* c = 1 if egal */
6810       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6811         {
6812           outBitC (result);
6813           goto release;
6814         }
6815       if (ifx)
6816         {
6817           genIfxJump (ifx, "c");
6818           goto release;
6819         }
6820       /* if the result is used in an arithmetic operation
6821          then put the result in place */
6822       outBitC (result);
6823     }
6824   else
6825     {
6826       gencjne (left, right, newiTempLabel (NULL));
6827
6828       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6829       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6830
6831       aopOp (result, ic, TRUE, FALSE);
6832
6833       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6834         {
6835           aopPut (result, "a", 0);
6836           goto release;
6837         }
6838       if (ifx)
6839         {
6840           genIfxJump (ifx, "a");
6841           goto release;
6842         }
6843       /* if the result is used in an arithmetic operation
6844          then put the result in place */
6845       if (AOP_TYPE (result) != AOP_CRY)
6846         outAcc (result);
6847       /* leave the result in acc */
6848     }
6849
6850 release:
6851   freeAsmop (result, NULL, ic, TRUE);
6852 }
6853
6854 /*-----------------------------------------------------------------*/
6855 /* ifxForOp - returns the icode containing the ifx for operand     */
6856 /*-----------------------------------------------------------------*/
6857 static iCode *
6858 ifxForOp (operand * op, iCode * ic)
6859 {
6860   /* if true symbol then needs to be assigned */
6861   if (IS_TRUE_SYMOP (op))
6862     return NULL;
6863
6864   /* if this has register type condition and
6865      the next instruction is ifx with the same operand
6866      and live to of the operand is upto the ifx only then */
6867   if (ic->next &&
6868       ic->next->op == IFX &&
6869       IC_COND (ic->next)->key == op->key &&
6870       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6871     return ic->next;
6872
6873   return NULL;
6874 }
6875
6876 /*-----------------------------------------------------------------*/
6877 /* hasInc - operand is incremented before any other use            */
6878 /*-----------------------------------------------------------------*/
6879 static iCode *
6880 hasInc (operand *op, iCode *ic, int osize)
6881 {
6882   sym_link *type = operandType(op);
6883   sym_link *retype = getSpec (type);
6884   iCode *lic = ic->next;
6885   int isize ;
6886
6887   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6888   if (!IS_SYMOP(op)) return NULL;
6889
6890   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6891   if (IS_AGGREGATE(type->next)) return NULL;
6892   if (osize != (isize = getSize(type->next))) return NULL;
6893
6894   while (lic) {
6895       /* if operand of the form op = op + <sizeof *op> */
6896       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6897           isOperandEqual(IC_RESULT(lic),op) &&
6898           isOperandLiteral(IC_RIGHT(lic)) &&
6899           operandLitValue(IC_RIGHT(lic)) == isize) {
6900           return lic;
6901       }
6902       /* if the operand used or deffed */
6903       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6904           return NULL;
6905       }
6906       /* if GOTO or IFX */
6907       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6908       lic = lic->next;
6909   }
6910   return NULL;
6911 }
6912
6913 /*-----------------------------------------------------------------*/
6914 /* genAndOp - for && operation                                     */
6915 /*-----------------------------------------------------------------*/
6916 static void
6917 genAndOp (iCode * ic)
6918 {
6919   operand *left, *right, *result;
6920   symbol *tlbl;
6921
6922   D (emitcode (";", "genAndOp"));
6923
6924   /* note here that && operations that are in an
6925      if statement are taken away by backPatchLabels
6926      only those used in arthmetic operations remain */
6927   AOP_OP_2 (ic);
6928   AOP_SET_LOCALS (ic);
6929
6930   /* if both are bit variables */
6931   if (AOP_TYPE (left) == AOP_CRY &&
6932       AOP_TYPE (right) == AOP_CRY)
6933     {
6934       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6935       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6936       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6937       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6938
6939       aopOp (result,ic,FALSE, FALSE);
6940       outBitC (result);
6941     }
6942   else
6943     {
6944       tlbl = newiTempLabel (NULL);
6945       toBoolean (left);
6946       emitcode ("jz", "!tlabel", tlbl->key + 100);
6947       toBoolean (right);
6948       emitLabel (tlbl);
6949       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6950       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6951
6952       aopOp (result,ic,FALSE, FALSE);
6953       outBitAcc (result);
6954     }
6955
6956     freeAsmop (result, NULL, ic, TRUE);
6957 }
6958
6959
6960 /*-----------------------------------------------------------------*/
6961 /* genOrOp - for || operation                                      */
6962 /*-----------------------------------------------------------------*/
6963 static void
6964 genOrOp (iCode * ic)
6965 {
6966   operand *left, *right, *result;
6967   symbol *tlbl;
6968
6969   D (emitcode (";", "genOrOp"));
6970
6971   /* note here that || operations that are in an
6972      if statement are taken away by backPatchLabels
6973      only those used in arthmetic operations remain */
6974   AOP_OP_2 (ic);
6975   AOP_SET_LOCALS (ic);
6976
6977   /* if both are bit variables */
6978   if (AOP_TYPE (left) == AOP_CRY &&
6979       AOP_TYPE (right) == AOP_CRY)
6980     {
6981       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6982       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6983       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6984       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6985
6986       aopOp (result,ic,FALSE, FALSE);
6987
6988       outBitC (result);
6989     }
6990   else
6991     {
6992       tlbl = newiTempLabel (NULL);
6993       toBoolean (left);
6994       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6995       toBoolean (right);
6996       emitLabel (tlbl);
6997       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6998       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6999
7000       aopOp (result,ic,FALSE, FALSE);
7001
7002       outBitAcc (result);
7003     }
7004
7005   freeAsmop (result, NULL, ic, TRUE);
7006 }
7007
7008 /*-----------------------------------------------------------------*/
7009 /* isLiteralBit - test if lit == 2^n                               */
7010 /*-----------------------------------------------------------------*/
7011 static int
7012 isLiteralBit (unsigned long lit)
7013 {
7014   unsigned long pw[32] =
7015   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7016    0x100L, 0x200L, 0x400L, 0x800L,
7017    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7018    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7019    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7020    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7021    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7022   int idx;
7023
7024   for (idx = 0; idx < 32; idx++)
7025     if (lit == pw[idx])
7026       return idx + 1;
7027   return 0;
7028 }
7029
7030 /*-----------------------------------------------------------------*/
7031 /* continueIfTrue -                                                */
7032 /*-----------------------------------------------------------------*/
7033 static void
7034 continueIfTrue (iCode * ic)
7035 {
7036   if (IC_TRUE (ic))
7037     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7038   ic->generated = 1;
7039 }
7040
7041 /*-----------------------------------------------------------------*/
7042 /* jmpIfTrue -                                                     */
7043 /*-----------------------------------------------------------------*/
7044 static void
7045 jumpIfTrue (iCode * ic)
7046 {
7047   if (!IC_TRUE (ic))
7048     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7049   ic->generated = 1;
7050 }
7051
7052 /*-----------------------------------------------------------------*/
7053 /* jmpTrueOrFalse -                                                */
7054 /*-----------------------------------------------------------------*/
7055 static void
7056 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7057 {
7058   // ugly but optimized by peephole
7059   if (IC_TRUE (ic))
7060     {
7061       symbol *nlbl = newiTempLabel (NULL);
7062       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7063       emitLabel (tlbl);
7064       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7065       emitLabel (nlbl);
7066     }
7067   else
7068     {
7069       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7070       emitLabel (tlbl);
7071     }
7072   ic->generated = 1;
7073 }
7074
7075 // Generate code to perform a bit-wise logic operation
7076 // on two operands in far space (assumed to already have been
7077 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7078 // in far space. This requires pushing the result on the stack
7079 // then popping it into the result.
7080 static void
7081 genFarFarLogicOp(iCode *ic, char *logicOp)
7082 {
7083       int size, resultSize, compSize;
7084       int offset = 0;
7085
7086       TR_AP("#5");
7087       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7088       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7089                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7090
7091       _startLazyDPSEvaluation();
7092       for (size = compSize; (size--); offset++)
7093       {
7094           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7095           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7096           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7097
7098           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7099           emitcode ("push", "acc");
7100       }
7101       _endLazyDPSEvaluation();
7102
7103       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7104       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7105       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7106
7107       resultSize = AOP_SIZE(IC_RESULT(ic));
7108
7109       ADJUST_PUSHED_RESULT(compSize, resultSize);
7110
7111       _startLazyDPSEvaluation();
7112       while (compSize--)
7113       {
7114           emitcode ("pop", "acc");
7115           aopPut (IC_RESULT (ic), "a", compSize);
7116       }
7117       _endLazyDPSEvaluation();
7118       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7119 }
7120
7121
7122 /*-----------------------------------------------------------------*/
7123 /* genAnd  - code for and                                          */
7124 /*-----------------------------------------------------------------*/
7125 static void
7126 genAnd (iCode * ic, iCode * ifx)
7127 {
7128   operand *left, *right, *result;
7129   int size, offset = 0;
7130   unsigned long lit = 0L;
7131   int bytelit = 0;
7132   char buffer[10];
7133   bool pushResult;
7134
7135   D (emitcode (";", "genAnd"));
7136
7137   AOP_OP_3_NOFATAL (ic, pushResult);
7138   AOP_SET_LOCALS (ic);
7139
7140   if (pushResult)
7141   {
7142       genFarFarLogicOp(ic, "anl");
7143       return;
7144   }
7145
7146 #ifdef DEBUG_TYPE
7147   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7148             AOP_TYPE (result),
7149             AOP_TYPE (left), AOP_TYPE (right));
7150   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7151             AOP_SIZE (result),
7152             AOP_SIZE (left), AOP_SIZE (right));
7153 #endif
7154
7155   /* if left is a literal & right is not then exchange them */
7156   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7157 #ifdef LOGIC_OPS_BROKEN
7158     ||  AOP_NEEDSACC (left)
7159 #endif
7160     )
7161     {
7162       operand *tmp = right;
7163       right = left;
7164       left = tmp;
7165     }
7166
7167   /* if result = right then exchange left and right */
7168   if (sameRegs (AOP (result), AOP (right)))
7169     {
7170       operand *tmp = right;
7171       right = left;
7172       left = tmp;
7173     }
7174
7175   /* if right is bit then exchange them */
7176   if (AOP_TYPE (right) == AOP_CRY &&
7177       AOP_TYPE (left) != AOP_CRY)
7178     {
7179       operand *tmp = right;
7180       right = left;
7181       left = tmp;
7182     }
7183   if (AOP_TYPE (right) == AOP_LIT)
7184     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7185
7186   size = AOP_SIZE (result);
7187
7188   // if(bit & yy)
7189   // result = bit & yy;
7190   if (AOP_TYPE (left) == AOP_CRY)
7191     {
7192       // c = bit & literal;
7193       if (AOP_TYPE (right) == AOP_LIT)
7194         {
7195           if (lit & 1)
7196             {
7197               if (size && sameRegs (AOP (result), AOP (left)))
7198                 // no change
7199                 goto release;
7200               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7201             }
7202           else
7203             {
7204               // bit(result) = 0;
7205               if (size && (AOP_TYPE (result) == AOP_CRY))
7206                 {
7207                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7208                   goto release;
7209                 }
7210               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7211                 {
7212                   jumpIfTrue (ifx);
7213                   goto release;
7214                 }
7215               emitcode ("clr", "c");
7216             }
7217         }
7218       else
7219         {
7220           if (AOP_TYPE (right) == AOP_CRY)
7221             {
7222               // c = bit & bit;
7223               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7224               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7225             }
7226           else
7227             {
7228               // c = bit & val;
7229               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7230               // c = lsb
7231               emitcode ("rrc", "a");
7232               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7233             }
7234         }
7235       // bit = c
7236       // val = c
7237       if (size)
7238         outBitC (result);
7239       // if(bit & ...)
7240       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7241         genIfxJump (ifx, "c");
7242       goto release;
7243     }
7244
7245   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7246   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7247   if ((AOP_TYPE (right) == AOP_LIT) &&
7248       (AOP_TYPE (result) == AOP_CRY) &&
7249       (AOP_TYPE (left) != AOP_CRY))
7250     {
7251       int posbit = isLiteralBit (lit);
7252       /* left &  2^n */
7253       if (posbit)
7254         {
7255           posbit--;
7256           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7257           // bit = left & 2^n
7258           if (size)
7259             {
7260               switch (posbit & 0x07)
7261                 {
7262                   case 0: emitcode ("rrc", "a");
7263                           break;
7264                   case 7: emitcode ("rlc", "a");
7265                           break;
7266                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7267                           break;
7268                 }
7269             }
7270           // if(left &  2^n)
7271           else
7272             {
7273               if (ifx)
7274                 {
7275                   SNPRINTF (buffer, sizeof(buffer),
7276                             "acc.%d", posbit & 0x07);
7277                   genIfxJump (ifx, buffer);
7278                 }
7279               else
7280                 {
7281                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7282                 }
7283               goto release;
7284             }
7285         }
7286       else
7287         {
7288           symbol *tlbl = newiTempLabel (NULL);
7289           int sizel = AOP_SIZE (left);
7290           if (size)
7291             emitcode ("setb", "c");
7292           while (sizel--)
7293             {
7294               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7295                 {
7296                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7297                   // byte ==  2^n ?
7298                   if ((posbit = isLiteralBit (bytelit)) != 0)
7299                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7300                   else
7301                     {
7302                       if (bytelit != 0x0FFL)
7303                         emitcode ("anl", "a,%s",
7304                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7305                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7306                     }
7307                 }
7308               offset++;
7309             }
7310           // bit = left & literal
7311           if (size)
7312             {
7313               emitcode ("clr", "c");
7314               emitLabel (tlbl);
7315             }
7316           // if(left & literal)
7317           else
7318             {
7319               if (ifx)
7320                 jmpTrueOrFalse (ifx, tlbl);
7321               else
7322                 emitLabel (tlbl);
7323               goto release;
7324             }
7325         }
7326       outBitC (result);
7327       goto release;
7328     }
7329
7330   /* if left is same as result */
7331   if (sameRegs (AOP (result), AOP (left)))
7332     {
7333       for (; size--; offset++)
7334         {
7335           if (AOP_TYPE (right) == AOP_LIT)
7336             {
7337               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7338               if (bytelit == 0x0FF)
7339                 {
7340                   /* dummy read of volatile operand */
7341                   if (isOperandVolatile (left, FALSE))
7342                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7343                   else
7344                     continue;
7345                 }
7346               else if (bytelit == 0)
7347                 {
7348                   aopPut (result, zero, offset);
7349                 }
7350               else if (IS_AOP_PREG (result))
7351                 {
7352                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7353                   emitcode ("anl", "a,%s",
7354                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7355                   aopPut (result, "a", offset);
7356                 }
7357               else
7358                 emitcode ("anl", "%s,%s",
7359                           aopGet (left, offset, FALSE, TRUE, NULL),
7360                           aopGet (right, offset, FALSE, FALSE, NULL));
7361             }
7362           else
7363             {
7364               if (AOP_TYPE (left) == AOP_ACC)
7365                 {
7366                   if (offset)
7367                     emitcode("mov", "a,b");
7368                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7369                 }
7370               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7371                 {
7372                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7373                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7374                   emitcode ("anl", "a,b");
7375                   aopPut (result, "a", offset);
7376                 }
7377               else if (aopGetUsesAcc (left, offset))
7378                 {
7379                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7380                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7381                   aopPut (result, "a", offset);
7382                 }
7383               else
7384                 {
7385                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7386                   if (IS_AOP_PREG (result))
7387                     {
7388                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7389                       aopPut (result, "a", offset);
7390                     }
7391                   else
7392                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7393                 }
7394             }
7395         }
7396     }
7397   else
7398     {
7399       // left & result in different registers
7400       if (AOP_TYPE (result) == AOP_CRY)
7401         {
7402           // result = bit
7403           // if(size), result in bit
7404           // if(!size && ifx), conditional oper: if(left & right)
7405           symbol *tlbl = newiTempLabel (NULL);
7406           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7407           if (size)
7408             emitcode ("setb", "c");
7409           while (sizer--)
7410             {
7411               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7412                   && AOP_TYPE(left)==AOP_ACC)
7413                 {
7414                   if (offset)
7415                     emitcode("mov", "a,b");
7416                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7417                 }
7418               else if (AOP_TYPE(left)==AOP_ACC)
7419                 {
7420                   if (!offset)
7421                     {
7422                       bool pushedB = pushB ();
7423                       emitcode("mov", "b,a");
7424                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7425                       emitcode("anl", "a,b");
7426                       popB (pushedB);
7427                     }
7428                   else
7429                     {
7430                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7431                       emitcode("anl", "a,b");
7432                     }
7433                 }
7434               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7435                 {
7436                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7437                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7438                   emitcode ("anl", "a,b");
7439                 }
7440               else if (aopGetUsesAcc (left, offset))
7441                 {
7442                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7443                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7444                 }
7445               else
7446                 {
7447                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7448                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7449                 }
7450
7451               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7452               offset++;
7453             }
7454           if (size)
7455             {
7456               CLRC;
7457               emitLabel (tlbl);
7458               outBitC (result);
7459             }
7460           else if (ifx)
7461             jmpTrueOrFalse (ifx, tlbl);
7462           else
7463             emitLabel (tlbl);
7464         }
7465       else
7466         {
7467           for (; (size--); offset++)
7468             {
7469               // normal case
7470               // result = left & right
7471               if (AOP_TYPE (right) == AOP_LIT)
7472                 {
7473                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7474                   if (bytelit == 0x0FF)
7475                     {
7476                       aopPut (result,
7477                               aopGet (left, offset, FALSE, FALSE, NULL),
7478                               offset);
7479                       continue;
7480                     }
7481                   else if (bytelit == 0)
7482                     {
7483                       /* dummy read of volatile operand */
7484                       if (isOperandVolatile (left, FALSE))
7485                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7486                       aopPut (result, zero, offset);
7487                       continue;
7488                     }
7489                   else if (AOP_TYPE (left) == AOP_ACC)
7490                     {
7491                       if (!offset)
7492                         {
7493                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7494                           aopPut (result, "a", offset);
7495                           continue;
7496                         }
7497                       else
7498                         {
7499                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7500                           aopPut (result, "b", offset);
7501                           continue;
7502                         }
7503                     }
7504                 }
7505               // faster than result <- left, anl result,right
7506               // and better if result is SFR
7507               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7508                   && AOP_TYPE(left)==AOP_ACC)
7509                 {
7510                   if (offset)
7511                     emitcode("mov", "a,b");
7512                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7513                 }
7514               else if (AOP_TYPE(left)==AOP_ACC)
7515                 {
7516                   if (!offset)
7517                     {
7518                       bool pushedB = pushB ();
7519                       emitcode("mov", "b,a");
7520                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7521                       emitcode("anl", "a,b");
7522                       popB (pushedB);
7523                     }
7524                   else
7525                     {
7526                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7527                       emitcode("anl", "a,b");
7528                     }
7529                 }
7530               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7531                 {
7532                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7533                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7534                   emitcode ("anl", "a,b");
7535                 }
7536               else if (aopGetUsesAcc (left, offset))
7537                 {
7538                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7539                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7540                 }
7541               else
7542                 {
7543                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7544                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7545                 }
7546               aopPut (result, "a", offset);
7547             }
7548         }
7549     }
7550
7551 release:
7552   freeAsmop (result, NULL, ic, TRUE);
7553   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7554   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7555 }
7556
7557 /*-----------------------------------------------------------------*/
7558 /* genOr  - code for or                                            */
7559 /*-----------------------------------------------------------------*/
7560 static void
7561 genOr (iCode * ic, iCode * ifx)
7562 {
7563   operand *left, *right, *result;
7564   int size, offset = 0;
7565   unsigned long lit = 0L;
7566   int bytelit = 0;
7567   bool     pushResult;
7568
7569   D (emitcode (";", "genOr"));
7570
7571   AOP_OP_3_NOFATAL (ic, pushResult);
7572   AOP_SET_LOCALS (ic);
7573
7574   if (pushResult)
7575   {
7576       genFarFarLogicOp(ic, "orl");
7577       return;
7578   }
7579
7580
7581 #ifdef DEBUG_TYPE
7582   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7583             AOP_TYPE (result),
7584             AOP_TYPE (left), AOP_TYPE (right));
7585   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7586             AOP_SIZE (result),
7587             AOP_SIZE (left), AOP_SIZE (right));
7588 #endif
7589
7590   /* if left is a literal & right is not then exchange them */
7591   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7592 #ifdef LOGIC_OPS_BROKEN
7593    || AOP_NEEDSACC (left) // I think this is a net loss now.
7594 #endif
7595       )
7596     {
7597       operand *tmp = right;
7598       right = left;
7599       left = tmp;
7600     }
7601
7602   /* if result = right then exchange them */
7603   if (sameRegs (AOP (result), AOP (right)))
7604     {
7605       operand *tmp = right;
7606       right = left;
7607       left = tmp;
7608     }
7609
7610   /* if right is bit then exchange them */
7611   if (AOP_TYPE (right) == AOP_CRY &&
7612       AOP_TYPE (left) != AOP_CRY)
7613     {
7614       operand *tmp = right;
7615       right = left;
7616       left = tmp;
7617     }
7618   if (AOP_TYPE (right) == AOP_LIT)
7619     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7620
7621   size = AOP_SIZE (result);
7622
7623   // if(bit | yy)
7624   // xx = bit | yy;
7625   if (AOP_TYPE (left) == AOP_CRY)
7626     {
7627       if (AOP_TYPE (right) == AOP_LIT)
7628         {
7629           // c = bit | literal;
7630           if (lit)
7631             {
7632               // lit != 0 => result = 1
7633               if (AOP_TYPE (result) == AOP_CRY)
7634                 {
7635                   if (size)
7636                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7637                   else if (ifx)
7638                     continueIfTrue (ifx);
7639                   goto release;
7640                 }
7641               emitcode ("setb", "c");
7642             }
7643           else
7644             {
7645               // lit == 0 => result = left
7646               if (size && sameRegs (AOP (result), AOP (left)))
7647                 goto release;
7648               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7649             }
7650         }
7651       else
7652         {
7653           if (AOP_TYPE (right) == AOP_CRY)
7654             {
7655               // c = bit | bit;
7656               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7657               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7658             }
7659           else
7660             {
7661               // c = bit | val;
7662               symbol *tlbl = newiTempLabel (NULL);
7663               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7664                 emitcode ("setb", "c");
7665               emitcode ("jb", "%s,!tlabel",
7666                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7667               toBoolean (right);
7668               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7669               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7670                 {
7671                   jmpTrueOrFalse (ifx, tlbl);
7672                   goto release;
7673                 }
7674               else
7675                 {
7676                   CLRC;
7677                   emitLabel (tlbl);
7678                 }
7679             }
7680         }
7681       // bit = c
7682       // val = c
7683       if (size)
7684         outBitC (result);
7685       // if(bit | ...)
7686       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7687            genIfxJump (ifx, "c");
7688       goto release;
7689     }
7690
7691   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7692   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7693   if ((AOP_TYPE (right) == AOP_LIT) &&
7694       (AOP_TYPE (result) == AOP_CRY) &&
7695       (AOP_TYPE (left) != AOP_CRY))
7696     {
7697       if (lit)
7698         {
7699           // result = 1
7700           if (size)
7701             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7702           else
7703             continueIfTrue (ifx);
7704           goto release;
7705         }
7706       else
7707         {
7708           // lit = 0, result = boolean(left)
7709           if (size)
7710             emitcode ("setb", "c");
7711           toBoolean (right);
7712           if (size)
7713             {
7714               symbol *tlbl = newiTempLabel (NULL);
7715               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7716               CLRC;
7717               emitLabel (tlbl);
7718             }
7719           else
7720             {
7721               genIfxJump (ifx, "a");
7722               goto release;
7723             }
7724         }
7725       outBitC (result);
7726       goto release;
7727     }
7728
7729   /* if left is same as result */
7730   if (sameRegs (AOP (result), AOP (left)))
7731     {
7732       for (; size--; offset++)
7733         {
7734           if (AOP_TYPE (right) == AOP_LIT)
7735             {
7736               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7737               if (bytelit == 0)
7738                 {
7739                   /* dummy read of volatile operand */
7740                   if (isOperandVolatile (left, FALSE))
7741                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7742                   else
7743                     continue;
7744                 }
7745               else if (bytelit == 0x0FF)
7746                 {
7747                   aopPut (result, "#0xFF", offset);
7748                 }
7749               else if (IS_AOP_PREG (left))
7750                 {
7751                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7752                   emitcode ("orl", "a,%s",
7753                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7754                   aopPut (result, "a", offset);
7755                 }
7756               else
7757                 {
7758                   emitcode ("orl", "%s,%s",
7759                             aopGet (left, offset, FALSE, TRUE, NULL),
7760                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7761                 }
7762             }
7763           else
7764             {
7765               if (AOP_TYPE (left) == AOP_ACC)
7766                 {
7767                   if (offset)
7768                     emitcode("mov", "a,b");
7769                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7770                 }
7771               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7772                 {
7773                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7774                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7775                   emitcode ("orl", "a,b");
7776                   aopPut (result, "a", offset);
7777                 }
7778               else if (aopGetUsesAcc (left, offset))
7779                 {
7780                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7781                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7782                   aopPut (result, "a", offset);
7783                 }
7784               else
7785                 {
7786                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7787                   if (IS_AOP_PREG (left))
7788                     {
7789                       emitcode ("orl", "a,%s",
7790                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7791                       aopPut (result, "a", offset);
7792                     }
7793                   else
7794                     {
7795                       emitcode ("orl", "%s,a",
7796                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7797                     }
7798                 }
7799             }
7800         }
7801     }
7802   else
7803     {
7804       // left & result in different registers
7805       if (AOP_TYPE (result) == AOP_CRY)
7806         {
7807           // result = bit
7808           // if(size), result in bit
7809           // if(!size && ifx), conditional oper: if(left | right)
7810           symbol *tlbl = newiTempLabel (NULL);
7811           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7812           if (size)
7813             emitcode ("setb", "c");
7814           while (sizer--)
7815             {
7816               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7817                   && AOP_TYPE(left)==AOP_ACC)
7818                 {
7819                   if (offset)
7820                     emitcode("mov", "a,b");
7821                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7822                 }
7823               else if (AOP_TYPE(left)==AOP_ACC)
7824                 {
7825                   if (!offset)
7826                     {
7827                       bool pushedB = pushB ();
7828                       emitcode("mov", "b,a");
7829                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7830                       emitcode("orl", "a,b");
7831                       popB (pushedB);
7832                     }
7833                   else
7834                     {
7835                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7836                       emitcode("orl", "a,b");
7837                     }
7838                 }
7839               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7840                 {
7841                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7842                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7843                   emitcode ("orl", "a,b");
7844                 }
7845               else if (aopGetUsesAcc (left, offset))
7846                 {
7847                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7848                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7849                 }
7850               else
7851                 {
7852                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7853                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7854               }
7855
7856               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7857               offset++;
7858             }
7859           if (size)
7860             {
7861               CLRC;
7862               emitLabel (tlbl);
7863               outBitC (result);
7864             }
7865           else if (ifx)
7866             jmpTrueOrFalse (ifx, tlbl);
7867           else
7868             emitLabel (tlbl);
7869         }
7870       else
7871         {
7872             _startLazyDPSEvaluation();
7873           for (; (size--); offset++)
7874             {
7875               // normal case
7876               // result = left | right
7877               if (AOP_TYPE (right) == AOP_LIT)
7878                 {
7879                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7880                   if (bytelit == 0)
7881                     {
7882                       aopPut (result,
7883                               aopGet (left, offset, FALSE, FALSE, NULL),
7884                               offset);
7885                       continue;
7886                     }
7887                   else if (bytelit == 0x0FF)
7888                     {
7889                       /* dummy read of volatile operand */
7890                       if (isOperandVolatile (left, FALSE))
7891                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7892                       aopPut (result, "#0xFF", offset);
7893                       continue;
7894                     }
7895                 }
7896               // faster than result <- left, orl result,right
7897               // and better if result is SFR
7898               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7899                   && AOP_TYPE(left)==AOP_ACC)
7900                 {
7901                   if (offset)
7902                     emitcode("mov", "a,b");
7903                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7904                 }
7905               else if (AOP_TYPE(left)==AOP_ACC)
7906                 {
7907                   if (!offset)
7908                     {
7909                       bool pushedB = pushB ();
7910                       emitcode("mov", "b,a");
7911                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7912                       emitcode("orl", "a,b");
7913                       popB (pushedB);
7914                     }
7915                   else
7916                     {
7917                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7918                       emitcode("orl", "a,b");
7919                     }
7920                 }
7921               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7922                 {
7923                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7924                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7925                   emitcode ("orl", "a,b");
7926                 }
7927               else if (aopGetUsesAcc (left, offset))
7928                 {
7929                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7930                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7931                 }
7932               else
7933                 {
7934                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7935                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7936                 }
7937               aopPut (result, "a", offset);
7938             }
7939             _endLazyDPSEvaluation();
7940         }
7941     }
7942
7943 release:
7944   freeAsmop (result, NULL, ic, TRUE);
7945   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7946   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7947 }
7948
7949 /*-----------------------------------------------------------------*/
7950 /* genXor - code for xclusive or                                   */
7951 /*-----------------------------------------------------------------*/
7952 static void
7953 genXor (iCode * ic, iCode * ifx)
7954 {
7955   operand *left, *right, *result;
7956   int size, offset = 0;
7957   unsigned long lit = 0L;
7958   int bytelit = 0;
7959   bool pushResult;
7960
7961   D (emitcode (";", "genXor"));
7962
7963   AOP_OP_3_NOFATAL (ic, pushResult);
7964   AOP_SET_LOCALS (ic);
7965
7966   if (pushResult)
7967   {
7968       genFarFarLogicOp(ic, "xrl");
7969       return;
7970   }
7971
7972 #ifdef DEBUG_TYPE
7973   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7974             AOP_TYPE (result),
7975             AOP_TYPE (left), AOP_TYPE (right));
7976   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7977             AOP_SIZE (result),
7978             AOP_SIZE (left), AOP_SIZE (right));
7979 #endif
7980
7981   /* if left is a literal & right is not ||
7982      if left needs acc & right does not */
7983   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7984 #ifdef LOGIC_OPS_BROKEN
7985       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7986 #endif
7987      )
7988     {
7989       operand *tmp = right;
7990       right = left;
7991       left = tmp;
7992     }
7993
7994   /* if result = right then exchange them */
7995   if (sameRegs (AOP (result), AOP (right)))
7996     {
7997       operand *tmp = right;
7998       right = left;
7999       left = tmp;
8000     }
8001
8002   /* if right is bit then exchange them */
8003   if (AOP_TYPE (right) == AOP_CRY &&
8004       AOP_TYPE (left) != AOP_CRY)
8005     {
8006       operand *tmp = right;
8007       right = left;
8008       left = tmp;
8009     }
8010   if (AOP_TYPE (right) == AOP_LIT)
8011     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
8012
8013   size = AOP_SIZE (result);
8014
8015   // if(bit ^ yy)
8016   // xx = bit ^ yy;
8017   if (AOP_TYPE (left) == AOP_CRY)
8018     {
8019       if (AOP_TYPE (right) == AOP_LIT)
8020         {
8021           // c = bit & literal;
8022           if (lit >> 1)
8023             {
8024               // lit>>1  != 0 => result = 1
8025               if (AOP_TYPE (result) == AOP_CRY)
8026                 {
8027                   if (size)
8028                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8029                   else if (ifx)
8030                     continueIfTrue (ifx);
8031                   goto release;
8032                 }
8033               emitcode ("setb", "c");
8034             }
8035           else
8036             {
8037               // lit == (0 or 1)
8038               if (lit == 0)
8039                 {
8040                   // lit == 0, result = left
8041                   if (size && sameRegs (AOP (result), AOP (left)))
8042                     goto release;
8043                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8044                 }
8045               else
8046                 {
8047                   // lit == 1, result = not(left)
8048                   if (size && sameRegs (AOP (result), AOP (left)))
8049                     {
8050                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8051                       goto release;
8052                     }
8053                   else
8054                     {
8055                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8056                       emitcode ("cpl", "c");
8057                     }
8058                 }
8059             }
8060         }
8061       else
8062         {
8063           // right != literal
8064           symbol *tlbl = newiTempLabel (NULL);
8065           if (AOP_TYPE (right) == AOP_CRY)
8066             {
8067               // c = bit ^ bit;
8068               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8069             }
8070           else
8071             {
8072               int sizer = AOP_SIZE (right);
8073               // c = bit ^ val
8074               // if val>>1 != 0, result = 1
8075               emitcode ("setb", "c");
8076               while (sizer)
8077                 {
8078                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8079                   if (sizer == 1)
8080                     // test the msb of the lsb
8081                     emitcode ("anl", "a,#!constbyte",0xfe);
8082                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8083                   sizer--;
8084                 }
8085               // val = (0,1)
8086               emitcode ("rrc", "a");
8087             }
8088           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8089           emitcode ("cpl", "c");
8090           emitLabel (tlbl);
8091         }
8092       // bit = c
8093       // val = c
8094       if (size)
8095         outBitC (result);
8096       // if(bit | ...)
8097       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8098         genIfxJump (ifx, "c");
8099       goto release;
8100     }
8101
8102   /* if left is same as result */
8103   if (sameRegs (AOP (result), AOP (left)))
8104     {
8105       for (; size--; offset++)
8106         {
8107           if (AOP_TYPE (right) == AOP_LIT)
8108             {
8109               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8110               if (bytelit == 0)
8111                 {
8112                   /* dummy read of volatile operand */
8113                   if (isOperandVolatile (left, FALSE))
8114                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8115                   else
8116                     continue;
8117                 }
8118               else if (IS_AOP_PREG (left))
8119                 {
8120                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8121                   emitcode ("xrl", "a,%s",
8122                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8123                   aopPut (result, "a", offset);
8124                 }
8125               else
8126                 {
8127                   emitcode ("xrl", "%s,%s",
8128                             aopGet (left, offset, FALSE, TRUE, NULL),
8129                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8130                 }
8131             }
8132           else
8133             {
8134               if (AOP_TYPE (left) == AOP_ACC)
8135                 {
8136                   if (offset)
8137                     emitcode("mov", "a,b");
8138                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8139                 }
8140               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8141                 {
8142                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8143                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8144                   emitcode ("xrl", "a,b");
8145                   aopPut (result, "a", offset);
8146                 }
8147               else if (aopGetUsesAcc (left, offset))
8148                 {
8149                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8150                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8151                   aopPut (result, "a", offset);
8152                 }
8153               else
8154                 {
8155                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8156                   if (IS_AOP_PREG (left))
8157                     {
8158                       emitcode ("xrl", "a,%s",
8159                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8160                       aopPut (result, "a", offset);
8161                     }
8162                   else
8163                     emitcode ("xrl", "%s,a",
8164                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8165                 }
8166             }
8167         }
8168     }
8169   else
8170     {
8171       // left & result in different registers
8172       if (AOP_TYPE (result) == AOP_CRY)
8173         {
8174           // result = bit
8175           // if(size), result in bit
8176           // if(!size && ifx), conditional oper: if(left ^ right)
8177           symbol *tlbl = newiTempLabel (NULL);
8178           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8179
8180           if (size)
8181             emitcode ("setb", "c");
8182           while (sizer--)
8183             {
8184               if ((AOP_TYPE (right) == AOP_LIT) &&
8185                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8186                 {
8187                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8188                 }
8189               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8190                   && AOP_TYPE(left)==AOP_ACC)
8191                 {
8192                   if (offset)
8193                     emitcode("mov", "a,b");
8194                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8195                 }
8196               else if (AOP_TYPE(left)==AOP_ACC)
8197                 {
8198                   if (!offset)
8199                     {
8200                       bool pushedB = pushB ();
8201                       emitcode("mov", "b,a");
8202                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8203                       emitcode("xrl", "a,b");
8204                       popB (pushedB);
8205                     }
8206                   else
8207                     {
8208                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8209                       emitcode("xrl", "a,b");
8210                     }
8211                 }
8212               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8213                 {
8214                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8215                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8216                   emitcode ("xrl", "a,b");
8217                 }
8218               else if (aopGetUsesAcc (left, offset))
8219                 {
8220                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8221                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8222                 }
8223               else
8224                 {
8225                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8226                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8227                 }
8228
8229               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8230               offset++;
8231             }
8232           if (size)
8233             {
8234               CLRC;
8235               emitLabel (tlbl);
8236               outBitC (result);
8237             }
8238           else if (ifx)
8239             jmpTrueOrFalse (ifx, tlbl);
8240         }
8241       else
8242         {
8243         for (; (size--); offset++)
8244           {
8245             // normal case
8246             // result = left ^ right
8247             if (AOP_TYPE (right) == AOP_LIT)
8248               {
8249                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8250                 if (bytelit == 0)
8251                   {
8252                     aopPut (result,
8253                             aopGet (left, offset, FALSE, FALSE, NULL),
8254                             offset);
8255                     continue;
8256                   }
8257                 D (emitcode (";", "better literal XOR."));
8258                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8259                 emitcode ("xrl", "a, %s",
8260                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8261               }
8262             else
8263               {
8264                 // faster than result <- left, anl result,right
8265                 // and better if result is SFR
8266                 if (AOP_TYPE (left) == AOP_ACC)
8267                   {
8268                     emitcode ("xrl", "a,%s",
8269                               aopGet (right, offset,
8270                                       FALSE, FALSE, DP2_RESULT_REG));
8271                   }
8272                 else
8273                   {
8274                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8275                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8276                       {
8277                           emitcode("mov", "b,a");
8278                           rOp = "b";
8279                       }
8280
8281                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8282                       emitcode ("xrl", "a,%s", rOp);
8283                   }
8284               }
8285             aopPut (result, "a", offset);
8286           }
8287         }
8288     }
8289
8290 release:
8291   freeAsmop (result, NULL, ic, TRUE);
8292   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8293   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8294 }
8295
8296 /*-----------------------------------------------------------------*/
8297 /* genInline - write the inline code out                           */
8298 /*-----------------------------------------------------------------*/
8299 static void
8300 genInline (iCode * ic)
8301 {
8302   char *buffer, *bp, *bp1;
8303
8304   D (emitcode (";", "genInline"));
8305
8306   _G.inLine += (!options.asmpeep);
8307
8308   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
8309
8310   /* emit each line as a code */
8311   while (*bp)
8312     {
8313       if (*bp == '\n')
8314         {
8315           *bp++ = '\0';
8316           emitcode (bp1, "");
8317           bp1 = bp;
8318         }
8319       else
8320         {
8321           /* Add \n for labels, not dirs such as c:\mydir */
8322           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
8323             {
8324               bp++;
8325               *bp = '\0';
8326               bp++;
8327               emitcode (bp1, "");
8328               bp1 = bp;
8329             }
8330           else
8331             bp++;
8332         }
8333     }
8334   if (bp1 != bp)
8335     emitcode (bp1, "");
8336   /*     emitcode("",buffer); */
8337   _G.inLine -= (!options.asmpeep);
8338 }
8339
8340 /*-----------------------------------------------------------------*/
8341 /* genRRC - rotate right with carry                                */
8342 /*-----------------------------------------------------------------*/
8343 static void
8344 genRRC (iCode * ic)
8345 {
8346   operand *left, *result;
8347   int     size, offset;
8348   char *l;
8349
8350   D (emitcode (";", "genRRC"));
8351
8352   /* rotate right with carry */
8353   left = IC_LEFT (ic);
8354   result = IC_RESULT (ic);
8355   aopOp (left, ic, FALSE, FALSE);
8356   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8357
8358   /* move it to the result */
8359   size = AOP_SIZE (result);
8360   offset = size - 1;
8361   CLRC;
8362
8363   _startLazyDPSEvaluation ();
8364   while (size--)
8365     {
8366       l = aopGet (left, offset, FALSE, FALSE, NULL);
8367       MOVA (l);
8368       emitcode ("rrc", "a");
8369       if (AOP_SIZE (result) > 1)
8370         aopPut (result, "a", offset--);
8371     }
8372   _endLazyDPSEvaluation ();
8373
8374   /* now we need to put the carry into the
8375      highest order byte of the result */
8376   if (AOP_SIZE (result) > 1)
8377     {
8378       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8379       MOVA (l);
8380     }
8381   emitcode ("mov", "acc.7,c");
8382   aopPut (result, "a", AOP_SIZE (result) - 1);
8383   freeAsmop (result, NULL, ic, TRUE);
8384   freeAsmop (left, NULL, ic, TRUE);
8385 }
8386
8387 /*-----------------------------------------------------------------*/
8388 /* genRLC - generate code for rotate left with carry               */
8389 /*-----------------------------------------------------------------*/
8390 static void
8391 genRLC (iCode * ic)
8392 {
8393   operand *left, *result;
8394   int size, offset;
8395   char *l;
8396
8397   D (emitcode (";", "genRLC"));
8398
8399   /* rotate right with carry */
8400   left = IC_LEFT (ic);
8401   result = IC_RESULT (ic);
8402   aopOp (left, ic, FALSE, FALSE);
8403   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8404
8405   /* move it to the result */
8406   size = AOP_SIZE (result);
8407   offset = 0;
8408   if (size--)
8409     {
8410       l = aopGet (left, offset, FALSE, FALSE, NULL);
8411       MOVA (l);
8412       emitcode ("add", "a,acc");
8413       if (AOP_SIZE (result) > 1)
8414         {
8415           aopPut (result, "a", offset++);
8416         }
8417
8418       _startLazyDPSEvaluation ();
8419       while (size--)
8420         {
8421           l = aopGet (left, offset, FALSE, FALSE, NULL);
8422           MOVA (l);
8423           emitcode ("rlc", "a");
8424           if (AOP_SIZE (result) > 1)
8425             aopPut (result, "a", offset++);
8426         }
8427       _endLazyDPSEvaluation ();
8428     }
8429   /* now we need to put the carry into the
8430      highest order byte of the result */
8431   if (AOP_SIZE (result) > 1)
8432     {
8433       l = aopGet (result, 0, FALSE, FALSE, NULL);
8434       MOVA (l);
8435     }
8436   emitcode ("mov", "acc.0,c");
8437   aopPut (result, "a", 0);
8438   freeAsmop (result, NULL, ic, TRUE);
8439   freeAsmop (left, NULL, ic, TRUE);
8440 }
8441
8442 /*-----------------------------------------------------------------*/
8443 /* genGetHbit - generates code get highest order bit               */
8444 /*-----------------------------------------------------------------*/
8445 static void
8446 genGetHbit (iCode * ic)
8447 {
8448   operand *left, *result;
8449
8450   D (emitcode (";", "genGetHbit"));
8451
8452   left = IC_LEFT (ic);
8453   result = IC_RESULT (ic);
8454   aopOp (left, ic, FALSE, FALSE);
8455   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8456
8457   /* get the highest order byte into a */
8458   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8459   if (AOP_TYPE (result) == AOP_CRY)
8460     {
8461       emitcode ("rlc", "a");
8462       outBitC (result);
8463     }
8464   else
8465     {
8466       emitcode ("rl", "a");
8467       emitcode ("anl", "a,#1");
8468       outAcc (result);
8469     }
8470
8471
8472   freeAsmop (result, NULL, ic, TRUE);
8473   freeAsmop (left, NULL, ic, TRUE);
8474 }
8475
8476 /*-----------------------------------------------------------------*/
8477 /* genSwap - generates code to swap nibbles or bytes               */
8478 /*-----------------------------------------------------------------*/
8479 static void
8480 genSwap (iCode * ic)
8481 {
8482   operand *left, *result;
8483
8484   D(emitcode (";     genSwap",""));
8485
8486   left = IC_LEFT (ic);
8487   result = IC_RESULT (ic);
8488   aopOp (left, ic, FALSE, FALSE);
8489   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8490
8491   _startLazyDPSEvaluation ();
8492   switch (AOP_SIZE (left))
8493     {
8494     case 1: /* swap nibbles in byte */
8495       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8496       emitcode ("swap", "a");
8497       aopPut (result, "a", 0);
8498       break;
8499     case 2: /* swap bytes in word */
8500       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8501         {
8502           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8503           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8504           aopPut (result, "a", 1);
8505         }
8506       else if (operandsEqu (left, result))
8507         {
8508           char * reg = "a";
8509           bool pushedB = FALSE, leftInB = FALSE;
8510
8511           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8512           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8513             {
8514               pushedB = pushB ();
8515               emitcode ("mov", "b,a");
8516               reg = "b";
8517               leftInB = TRUE;
8518             }
8519           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8520           aopPut (result, reg, 1);
8521
8522           if (leftInB)
8523             popB (pushedB);
8524         }
8525       else
8526         {
8527           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8528           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8529         }
8530       break;
8531     default:
8532       wassertl(FALSE, "unsupported SWAP operand size");
8533     }
8534   _endLazyDPSEvaluation ();
8535
8536   freeAsmop (result, NULL, ic, TRUE);
8537   freeAsmop (left, NULL, ic, TRUE);
8538 }
8539
8540 /*-----------------------------------------------------------------*/
8541 /* AccRol - rotate left accumulator by known count                 */
8542 /*-----------------------------------------------------------------*/
8543 static void
8544 AccRol (int shCount)
8545 {
8546   shCount &= 0x0007;            // shCount : 0..7
8547
8548   switch (shCount)
8549     {
8550     case 0:
8551       break;
8552     case 1:
8553       emitcode ("rl", "a");
8554       break;
8555     case 2:
8556       emitcode ("rl", "a");
8557       emitcode ("rl", "a");
8558       break;
8559     case 3:
8560       emitcode ("swap", "a");
8561       emitcode ("rr", "a");
8562       break;
8563     case 4:
8564       emitcode ("swap", "a");
8565       break;
8566     case 5:
8567       emitcode ("swap", "a");
8568       emitcode ("rl", "a");
8569       break;
8570     case 6:
8571       emitcode ("rr", "a");
8572       emitcode ("rr", "a");
8573       break;
8574     case 7:
8575       emitcode ("rr", "a");
8576       break;
8577     }
8578 }
8579
8580 /*-----------------------------------------------------------------*/
8581 /* AccLsh - left shift accumulator by known count                  */
8582 /*-----------------------------------------------------------------*/
8583 static void
8584 AccLsh (int shCount)
8585 {
8586   if (shCount != 0)
8587     {
8588       if (shCount == 1)
8589         emitcode ("add", "a,acc");
8590       else if (shCount == 2)
8591         {
8592           emitcode ("add", "a,acc");
8593           emitcode ("add", "a,acc");
8594         }
8595       else
8596         {
8597           /* rotate left accumulator */
8598           AccRol (shCount);
8599           /* and kill the lower order bits */
8600           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8601         }
8602     }
8603 }
8604
8605 /*-----------------------------------------------------------------*/
8606 /* AccRsh - right shift accumulator by known count                 */
8607 /*-----------------------------------------------------------------*/
8608 static void
8609 AccRsh (int shCount)
8610 {
8611   if (shCount != 0)
8612     {
8613       if (shCount == 1)
8614         {
8615           CLRC;
8616           emitcode ("rrc", "a");
8617         }
8618       else
8619         {
8620           /* rotate right accumulator */
8621           AccRol (8 - shCount);
8622           /* and kill the higher order bits */
8623           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8624         }
8625     }
8626 }
8627
8628 #ifdef BETTER_LITERAL_SHIFT
8629 /*-----------------------------------------------------------------*/
8630 /* AccSRsh - signed right shift accumulator by known count                 */
8631 /*-----------------------------------------------------------------*/
8632 static void
8633 AccSRsh (int shCount)
8634 {
8635   symbol *tlbl;
8636   if (shCount != 0)
8637     {
8638       if (shCount == 1)
8639         {
8640           emitcode ("mov", "c,acc.7");
8641           emitcode ("rrc", "a");
8642         }
8643       else if (shCount == 2)
8644         {
8645           emitcode ("mov", "c,acc.7");
8646           emitcode ("rrc", "a");
8647           emitcode ("mov", "c,acc.7");
8648           emitcode ("rrc", "a");
8649         }
8650       else
8651         {
8652           tlbl = newiTempLabel (NULL);
8653           /* rotate right accumulator */
8654           AccRol (8 - shCount);
8655           /* and kill the higher order bits */
8656           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8657           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8658           emitcode ("orl", "a,#!constbyte",
8659                     (unsigned char) ~SRMask[shCount]);
8660           emitLabel (tlbl);
8661         }
8662     }
8663 }
8664 #endif
8665
8666 #ifdef BETTER_LITERAL_SHIFT
8667 /*-----------------------------------------------------------------*/
8668 /* shiftR1Left2Result - shift right one byte from left to result   */
8669 /*-----------------------------------------------------------------*/
8670 static void
8671 shiftR1Left2Result (operand * left, int offl,
8672                     operand * result, int offr,
8673                     int shCount, int sign)
8674 {
8675   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8676   /* shift right accumulator */
8677   if (sign)
8678     AccSRsh (shCount);
8679   else
8680     AccRsh (shCount);
8681   aopPut (result, "a", offr);
8682 }
8683 #endif
8684
8685 #ifdef BETTER_LITERAL_SHIFT
8686 /*-----------------------------------------------------------------*/
8687 /* shiftL1Left2Result - shift left one byte from left to result    */
8688 /*-----------------------------------------------------------------*/
8689 static void
8690 shiftL1Left2Result (operand * left, int offl,
8691                     operand * result, int offr, int shCount)
8692 {
8693   char *l;
8694   l = aopGet (left, offl, FALSE, FALSE, NULL);
8695   MOVA (l);
8696   /* shift left accumulator */
8697   AccLsh (shCount);
8698   aopPut (result, "a", offr);
8699 }
8700 #endif
8701
8702 #ifdef BETTER_LITERAL_SHIFT
8703 /*-----------------------------------------------------------------*/
8704 /* movLeft2Result - move byte from left to result                  */
8705 /*-----------------------------------------------------------------*/
8706 static void
8707 movLeft2Result (operand * left, int offl,
8708                 operand * result, int offr, int sign)
8709 {
8710   char *l;
8711   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8712   {
8713       l = aopGet (left, offl, FALSE, FALSE, NULL);
8714
8715       if (*l == '@' && (IS_AOP_PREG (result)))
8716       {
8717           emitcode ("mov", "a,%s", l);
8718           aopPut (result, "a", offr);
8719       }
8720       else
8721       {
8722           if (!sign)
8723             {
8724               aopPut (result, l, offr);
8725             }
8726           else
8727             {
8728               /* MSB sign in acc.7 ! */
8729               if (getDataSize (left) == offl + 1)
8730                 {
8731                   MOVA (l);
8732                   aopPut (result, "a", offr);
8733                 }
8734             }
8735       }
8736   }
8737 }
8738 #endif
8739
8740 #ifdef BETTER_LITERAL_SHIFT
8741 /*-----------------------------------------------------------------*/
8742 /* AccAXRrl1 - right rotate a:x by 1                               */
8743 /*-----------------------------------------------------------------*/
8744 static void
8745 AccAXRrl1 (char *x)
8746 {
8747   emitcode ("mov", "c,acc.0");
8748   emitcode ("xch", "a,%s", x);
8749   emitcode ("rrc", "a");
8750   emitcode ("xch", "a,%s", x);
8751   emitcode ("rrc", "a");
8752 }
8753 #endif
8754
8755 #ifdef BETTER_LITERAL_SHIFT
8756 //REMOVE ME!!!
8757 /*-----------------------------------------------------------------*/
8758 /* AccAXLrl1 - left rotate a:x by 1                                */
8759 /*-----------------------------------------------------------------*/
8760 static void
8761 AccAXLrl1 (char *x)
8762 {
8763   emitcode ("mov", "c,acc.7");
8764   emitcode ("xch", "a,%s", x);
8765   emitcode ("rlc", "a");
8766   emitcode ("xch", "a,%s", x);
8767   emitcode ("rlc", "a");
8768 }
8769 #endif
8770
8771 #ifdef BETTER_LITERAL_SHIFT
8772 /*-----------------------------------------------------------------*/
8773 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8774 /*-----------------------------------------------------------------*/
8775 static void
8776 AccAXRsh1 (char *x)
8777 {
8778   emitcode ("rrc", "a");
8779   emitcode ("xch", "a,%s", x);
8780   emitcode ("rrc", "a");
8781   emitcode ("xch", "a,%s", x);
8782 }
8783 #endif
8784
8785 #ifdef BETTER_LITERAL_SHIFT
8786 /*-----------------------------------------------------------------*/
8787 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8788 /*-----------------------------------------------------------------*/
8789 static void
8790 AccAXLsh1 (char *x)
8791 {
8792   emitcode ("xch", "a,%s", x);
8793   emitcode ("add", "a,acc");
8794   emitcode ("xch", "a,%s", x);
8795   emitcode ("rlc", "a");
8796 }
8797 #endif
8798
8799 #ifdef BETTER_LITERAL_SHIFT
8800 /*-----------------------------------------------------------------*/
8801 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8802 /*-----------------------------------------------------------------*/
8803 static void
8804 AccAXLsh (char *x, int shCount)
8805 {
8806   switch (shCount)
8807     {
8808     case 0:
8809       break;
8810     case 1:
8811       AccAXLsh1 (x);
8812       break;
8813     case 2:
8814       AccAXLsh1 (x);
8815       AccAXLsh1 (x);
8816       break;
8817     case 3:
8818     case 4:
8819     case 5:                             // AAAAABBB:CCCCCDDD
8820
8821       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8822
8823       emitcode ("anl", "a,#!constbyte",
8824                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8825
8826       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8827
8828       AccRol (shCount);                 // DDDCCCCC:BBB00000
8829
8830       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8831
8832       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8833
8834       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8835
8836       emitcode ("anl", "a,#!constbyte",
8837                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8838
8839       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8840
8841       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8842
8843       break;
8844     case 6:                             // AAAAAABB:CCCCCCDD
8845       emitcode ("anl", "a,#!constbyte",
8846                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8847 #if 1
8848       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8849       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8850       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8851 #else
8852       emitcode ("mov", "c,acc.0");      // c = B
8853       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8854       emitcode("rrc","a");
8855       emitcode("xch","a,%s", x);
8856       emitcode("rrc","a");
8857       emitcode("mov","c,acc.0"); //<< get correct bit
8858       emitcode("xch","a,%s", x);
8859
8860       emitcode("rrc","a");
8861       emitcode("xch","a,%s", x);
8862       emitcode("rrc","a");
8863       emitcode("xch","a,%s", x);
8864 #endif
8865       break;
8866     case 7:                             // a:x <<= 7
8867
8868       emitcode ("anl", "a,#!constbyte",
8869                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8870
8871       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8872
8873       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8874
8875       break;
8876     default:
8877       break;
8878     }
8879 }
8880 #endif
8881
8882 #ifdef BETTER_LITERAL_SHIFT
8883 //REMOVE ME!!!
8884 /*-----------------------------------------------------------------*/
8885 /* AccAXRsh - right shift a:x known count (0..7)                   */
8886 /*-----------------------------------------------------------------*/
8887 static void
8888 AccAXRsh (char *x, int shCount)
8889 {
8890   switch (shCount)
8891     {
8892     case 0:
8893       break;
8894     case 1:
8895       CLRC;
8896       AccAXRsh1 (x);                    // 0->a:x
8897
8898       break;
8899     case 2:
8900       CLRC;
8901       AccAXRsh1 (x);                    // 0->a:x
8902
8903       CLRC;
8904       AccAXRsh1 (x);                    // 0->a:x
8905
8906       break;
8907     case 3:
8908     case 4:
8909     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8910
8911       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8912
8913       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8914
8915       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8916
8917       emitcode ("anl", "a,#!constbyte",
8918                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8919
8920       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8921
8922       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8923
8924       emitcode ("anl", "a,#!constbyte",
8925                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8926
8927       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8928
8929       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8930
8931       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8932
8933       break;
8934     case 6:                             // AABBBBBB:CCDDDDDD
8935
8936       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8937       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8938
8939       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8940
8941       emitcode ("anl", "a,#!constbyte",
8942                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8943
8944       break;
8945     case 7:                             // ABBBBBBB:CDDDDDDD
8946
8947       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8948
8949       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8950
8951       emitcode ("anl", "a,#!constbyte",
8952                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8953
8954       break;
8955     default:
8956       break;
8957     }
8958 }
8959 #endif
8960
8961 #ifdef BETTER_LITERAL_SHIFT
8962 /*-----------------------------------------------------------------*/
8963 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8964 /*-----------------------------------------------------------------*/
8965 static void
8966 AccAXRshS (char *x, int shCount)
8967 {
8968   symbol *tlbl;
8969   switch (shCount)
8970     {
8971     case 0:
8972       break;
8973     case 1:
8974       emitcode ("mov", "c,acc.7");
8975       AccAXRsh1 (x);                    // s->a:x
8976
8977       break;
8978     case 2:
8979       emitcode ("mov", "c,acc.7");
8980       AccAXRsh1 (x);                    // s->a:x
8981
8982       emitcode ("mov", "c,acc.7");
8983       AccAXRsh1 (x);                    // s->a:x
8984
8985       break;
8986     case 3:
8987     case 4:
8988     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8989
8990       tlbl = newiTempLabel (NULL);
8991       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8992
8993       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8994
8995       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8996
8997       emitcode ("anl", "a,#!constbyte",
8998                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8999
9000       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9001
9002       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9003
9004       emitcode ("anl", "a,#!constbyte",
9005                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9006
9007       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9008
9009       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9010
9011       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9012
9013       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9014       emitcode ("orl", "a,#!constbyte",
9015                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9016
9017       emitLabel (tlbl);
9018       break;                            // SSSSAAAA:BBBCCCCC
9019
9020     case 6:                             // AABBBBBB:CCDDDDDD
9021
9022       tlbl = newiTempLabel (NULL);
9023
9024       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9025       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9026
9027       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9028
9029       emitcode ("anl", "a,#!constbyte",
9030                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9031
9032       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9033       emitcode ("orl", "a,#!constbyte",
9034                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9035
9036       emitLabel (tlbl);
9037       break;
9038     case 7:                             // ABBBBBBB:CDDDDDDD
9039
9040       tlbl = newiTempLabel (NULL);
9041
9042       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9043
9044       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9045
9046       emitcode ("anl", "a,#!constbyte",
9047                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9048
9049       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9050       emitcode ("orl", "a,#!constbyte",
9051                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9052
9053       emitLabel (tlbl);
9054       break;
9055     default:
9056       break;
9057     }
9058 }
9059 #endif
9060
9061 #ifdef BETTER_LITERAL_SHIFT
9062 static void
9063 _loadLeftIntoAx(char    **lsb,
9064                 operand *left,
9065                 operand *result,
9066                 int     offl,
9067                 int     offr)
9068 {
9069   // Get the initial value from left into a pair of registers.
9070   // MSB must be in A, LSB can be any register.
9071   //
9072   // If the result is held in registers, it is an optimization
9073   // if the LSB can be held in the register which will hold the,
9074   // result LSB since this saves us from having to copy it into
9075   // the result following AccAXLsh.
9076   //
9077   // If the result is addressed indirectly, this is not a gain.
9078   if (AOP_NEEDSACC(result))
9079   {
9080        char *leftByte;
9081
9082        _startLazyDPSEvaluation();
9083       if (AOP_TYPE(left) == AOP_DPTR2)
9084        {
9085            // Get MSB in A.
9086            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9087            // get LSB in DP2_RESULT_REG.
9088            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9089            assert(!strcmp(leftByte, DP2_RESULT_REG));
9090        }
9091        else
9092        {
9093            // get LSB into DP2_RESULT_REG
9094            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9095            if (strcmp(leftByte, DP2_RESULT_REG))
9096            {
9097                TR_AP("#7");
9098                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9099            }
9100            // And MSB in A.
9101            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9102            assert(strcmp(leftByte, DP2_RESULT_REG));
9103            MOVA (leftByte);
9104        }
9105        _endLazyDPSEvaluation();
9106        *lsb = DP2_RESULT_REG;
9107   }
9108   else
9109   {
9110       if (sameRegs (AOP (result), AOP (left)) &&
9111         ((offl + MSB16) == offr))
9112       {
9113           /* don't crash result[offr] */
9114           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9115           emitcode ("xch", "a,%s",
9116                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9117       }
9118       else
9119       {
9120           movLeft2Result (left, offl, result, offr, 0);
9121           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9122       }
9123       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9124       assert(strcmp(*lsb,"a"));
9125   }
9126 }
9127
9128 static void
9129 _storeAxResults(char    *lsb,
9130                 operand *result,
9131                 int     offr)
9132 {
9133   _startLazyDPSEvaluation();
9134   if (AOP_NEEDSACC(result))
9135   {
9136       /* We have to explicitly update the result LSB.
9137        */
9138       emitcode ("xch","a,%s", lsb);
9139       aopPut (result, "a", offr);
9140       emitcode ("mov","a,%s", lsb);
9141   }
9142   if (getDataSize (result) > 1)
9143   {
9144       aopPut (result, "a", offr + MSB16);
9145   }
9146   _endLazyDPSEvaluation();
9147 }
9148
9149 /*-----------------------------------------------------------------*/
9150 /* shiftL2Left2Result - shift left two bytes from left to result   */
9151 /*-----------------------------------------------------------------*/
9152 static void
9153 shiftL2Left2Result (operand * left, int offl,
9154                     operand * result, int offr, int shCount)
9155 {
9156   char *lsb;
9157
9158   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9159
9160   AccAXLsh (lsb, shCount);
9161
9162   _storeAxResults(lsb, result, offr);
9163 }
9164 #endif
9165
9166 #ifdef BETTER_LITERAL_SHIFT
9167 /*-----------------------------------------------------------------*/
9168 /* shiftR2Left2Result - shift right two bytes from left to result  */
9169 /*-----------------------------------------------------------------*/
9170 static void
9171 shiftR2Left2Result (operand * left, int offl,
9172                     operand * result, int offr,
9173                     int shCount, int sign)
9174 {
9175   char *lsb;
9176
9177   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9178
9179   /* a:x >> shCount (x = lsb(result)) */
9180   if (sign)
9181   {
9182      AccAXRshS(lsb, shCount);
9183   }
9184   else
9185   {
9186     AccAXRsh(lsb, shCount);
9187   }
9188
9189   _storeAxResults(lsb, result, offr);
9190 }
9191 #endif
9192
9193 /*-----------------------------------------------------------------*/
9194 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9195 /*-----------------------------------------------------------------*/
9196 static void
9197 shiftLLeftOrResult (operand * left, int offl,
9198                     operand * result, int offr, int shCount)
9199 {
9200   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9201   /* shift left accumulator */
9202   AccLsh (shCount);
9203   /* or with result */
9204   emitcode ("orl", "a,%s",
9205             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9206   /* back to result */
9207   aopPut (result, "a", offr);
9208 }
9209
9210 #if 0
9211 //REMOVE ME!!!
9212 /*-----------------------------------------------------------------*/
9213 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9214 /*-----------------------------------------------------------------*/
9215 static void
9216 shiftRLeftOrResult (operand * left, int offl,
9217                     operand * result, int offr, int shCount)
9218 {
9219   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9220   /* shift right accumulator */
9221   AccRsh (shCount);
9222   /* or with result */
9223   emitcode ("orl", "a,%s",
9224             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9225   /* back to result */
9226   aopPut (result, "a", offr);
9227 }
9228 #endif
9229
9230 #ifdef BETTER_LITERAL_SHIFT
9231 /*-----------------------------------------------------------------*/
9232 /* genlshOne - left shift a one byte quantity by known count       */
9233 /*-----------------------------------------------------------------*/
9234 static void
9235 genlshOne (operand * result, operand * left, int shCount)
9236 {
9237   D (emitcode (";", "genlshOne"));
9238
9239   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9240 }
9241 #endif
9242
9243 #ifdef BETTER_LITERAL_SHIFT
9244 /*-----------------------------------------------------------------*/
9245 /* genlshTwo - left shift two bytes by known amount != 0           */
9246 /*-----------------------------------------------------------------*/
9247 static void
9248 genlshTwo (operand * result, operand * left, int shCount)
9249 {
9250   int size;
9251
9252   D (emitcode (";", "genlshTwo"));
9253
9254   size = getDataSize (result);
9255
9256   /* if shCount >= 8 */
9257   if (shCount >= 8)
9258   {
9259       shCount -= 8;
9260
9261       _startLazyDPSEvaluation();
9262
9263       if (size > 1)
9264         {
9265           if (shCount)
9266           {
9267             _endLazyDPSEvaluation();
9268             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9269             aopPut (result, zero, LSB);
9270           }
9271           else
9272           {
9273             movLeft2Result (left, LSB, result, MSB16, 0);
9274             aopPut (result, zero, LSB);
9275             _endLazyDPSEvaluation();
9276           }
9277         }
9278         else
9279         {
9280           aopPut (result, zero, LSB);
9281           _endLazyDPSEvaluation();
9282         }
9283   }
9284
9285   /*  1 <= shCount <= 7 */
9286   else
9287     {
9288       if (size == 1)
9289         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9290       else
9291         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9292     }
9293 }
9294 #endif
9295
9296 #if 0
9297 //REMOVE ME!!!
9298 /*-----------------------------------------------------------------*/
9299 /* shiftLLong - shift left one long from left to result            */
9300 /* offl = LSB or MSB16                                             */
9301 /*-----------------------------------------------------------------*/
9302 static void
9303 shiftLLong (operand * left, operand * result, int offr)
9304 {
9305   char *l;
9306   int size = AOP_SIZE (result);
9307
9308   if (size >= LSB + offr)
9309     {
9310       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9311       MOVA (l);
9312       emitcode ("add", "a,acc");
9313       if (sameRegs (AOP (left), AOP (result)) &&
9314           size >= MSB16 + offr && offr != LSB)
9315         emitcode ("xch", "a,%s",
9316                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9317       else
9318         aopPut (result, "a", LSB + offr);
9319     }
9320
9321   if (size >= MSB16 + offr)
9322     {
9323       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9324         {
9325           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9326           MOVA (l);
9327         }
9328       emitcode ("rlc", "a");
9329       if (sameRegs (AOP (left), AOP (result)) &&
9330           size >= MSB24 + offr && offr != LSB)
9331         emitcode ("xch", "a,%s",
9332                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9333       else
9334         aopPut (result, "a", MSB16 + offr);
9335     }
9336
9337   if (size >= MSB24 + offr)
9338     {
9339       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9340         {
9341           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9342           MOVA (l);
9343         }
9344       emitcode ("rlc", "a");
9345       if (sameRegs (AOP (left), AOP (result)) &&
9346           size >= MSB32 + offr && offr != LSB)
9347         emitcode ("xch", "a,%s",
9348                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9349       else
9350         aopPut (result, "a", MSB24 + offr);
9351     }
9352
9353   if (size > MSB32 + offr)
9354     {
9355       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9356         {
9357           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9358           MOVA (l);
9359         }
9360       emitcode ("rlc", "a");
9361       aopPut (result, "a", MSB32 + offr);
9362     }
9363   if (offr != LSB)
9364     aopPut (result, zero, LSB);
9365 }
9366 #endif
9367
9368 #if 0
9369 //REMOVE ME!!!
9370 /*-----------------------------------------------------------------*/
9371 /* genlshFour - shift four byte by a known amount != 0             */
9372 /*-----------------------------------------------------------------*/
9373 static void
9374 genlshFour (operand * result, operand * left, int shCount)
9375 {
9376   int size;
9377
9378   D (emitcode (";", "genlshFour"));
9379
9380   size = AOP_SIZE (result);
9381
9382   /* if shifting more that 3 bytes */
9383   if (shCount >= 24)
9384     {
9385       shCount -= 24;
9386       if (shCount)
9387         /* lowest order of left goes to the highest
9388            order of the destination */
9389         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9390       else
9391         movLeft2Result (left, LSB, result, MSB32, 0);
9392       aopPut (result, zero, LSB);
9393       aopPut (result, zero, MSB16);
9394       aopPut (result, zero, MSB24);
9395       return;
9396     }
9397
9398   /* more than two bytes */
9399   else if (shCount >= 16)
9400     {
9401       /* lower order two bytes goes to higher order two bytes */
9402       shCount -= 16;
9403       /* if some more remaining */
9404       if (shCount)
9405         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9406       else
9407         {
9408           movLeft2Result (left, MSB16, result, MSB32, 0);
9409           movLeft2Result (left, LSB, result, MSB24, 0);
9410         }
9411       aopPut (result, zero, MSB16);
9412       aopPut (result, zero, LSB);
9413       return;
9414     }
9415
9416   /* if more than 1 byte */
9417   else if (shCount >= 8)
9418     {
9419       /* lower order three bytes goes to higher order  three bytes */
9420       shCount -= 8;
9421       if (size == 2)
9422         {
9423           if (shCount)
9424             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9425           else
9426             movLeft2Result (left, LSB, result, MSB16, 0);
9427         }
9428       else
9429         {                       /* size = 4 */
9430           if (shCount == 0)
9431             {
9432               movLeft2Result (left, MSB24, result, MSB32, 0);
9433               movLeft2Result (left, MSB16, result, MSB24, 0);
9434               movLeft2Result (left, LSB, result, MSB16, 0);
9435               aopPut (result, zero, LSB);
9436             }
9437           else if (shCount == 1)
9438             shiftLLong (left, result, MSB16);
9439           else
9440             {
9441               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9442               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9443               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9444               aopPut (result, zero, LSB);
9445             }
9446         }
9447     }
9448
9449   /* 1 <= shCount <= 7 */
9450   else if (shCount <= 2)
9451     {
9452       shiftLLong (left, result, LSB);
9453       if (shCount == 2)
9454         shiftLLong (result, result, LSB);
9455     }
9456   /* 3 <= shCount <= 7, optimize */
9457   else
9458     {
9459       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9460       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9461       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9462     }
9463 }
9464 #endif
9465
9466 #ifdef BETTER_LITERAL_SHIFT
9467 /*-----------------------------------------------------------------*/
9468 /* genLeftShiftLiteral - left shifting by known count              */
9469 /*-----------------------------------------------------------------*/
9470 static bool
9471 genLeftShiftLiteral (operand * left,
9472                      operand * right,
9473                      operand * result,
9474                      iCode * ic)
9475 {
9476   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9477   int size;
9478
9479   size = getSize (operandType (result));
9480
9481   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9482
9483   /* We only handle certain easy cases so far. */
9484   if ((shCount != 0)
9485    && (shCount < (size * 8))
9486    && (size != 1)
9487    && (size != 2))
9488   {
9489       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9490       return FALSE;
9491   }
9492
9493   freeAsmop (right, NULL, ic, TRUE);
9494
9495   aopOp(left, ic, FALSE, FALSE);
9496   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9497
9498 #if 0 // debug spew
9499   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9500   {
9501         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9502         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9503         {
9504            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9505         }
9506   }
9507   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9508   {
9509         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9510         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9511         {
9512            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9513         }
9514   }
9515 #endif
9516
9517 #if VIEW_SIZE
9518   emitcode ("; shift left ", "result %d, left %d", size,
9519             AOP_SIZE (left));
9520 #endif
9521
9522   /* I suppose that the left size >= result size */
9523   if (shCount == 0)
9524   {
9525         _startLazyDPSEvaluation();
9526         while (size--)
9527         {
9528           movLeft2Result (left, size, result, size, 0);
9529         }
9530         _endLazyDPSEvaluation();
9531   }
9532   else if (shCount >= (size * 8))
9533   {
9534     _startLazyDPSEvaluation();
9535     while (size--)
9536     {
9537       aopPut (result, zero, size);
9538     }
9539     _endLazyDPSEvaluation();
9540   }
9541   else
9542   {
9543       switch (size)
9544         {
9545         case 1:
9546           genlshOne (result, left, shCount);
9547           break;
9548
9549         case 2:
9550           genlshTwo (result, left, shCount);
9551           break;
9552 #if 0
9553         case 4:
9554           genlshFour (result, left, shCount);
9555           break;
9556 #endif
9557         default:
9558           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9559                   "*** ack! mystery literal shift!\n");
9560           break;
9561         }
9562     }
9563   freeAsmop (result, NULL, ic, TRUE);
9564   freeAsmop (left, NULL, ic, TRUE);
9565   return TRUE;
9566 }
9567 #endif
9568
9569 /*-----------------------------------------------------------------*/
9570 /* genLeftShift - generates code for left shifting                 */
9571 /*-----------------------------------------------------------------*/
9572 static void
9573 genLeftShift (iCode * ic)
9574 {
9575   operand *left, *right, *result;
9576   int size, offset;
9577   char *l;
9578   symbol *tlbl, *tlbl1;
9579   bool pushedB;
9580
9581   D (emitcode (";", "genLeftShift"));
9582
9583   right = IC_RIGHT (ic);
9584   left = IC_LEFT (ic);
9585   result = IC_RESULT (ic);
9586
9587   aopOp (right, ic, FALSE, FALSE);
9588
9589
9590 #ifdef BETTER_LITERAL_SHIFT
9591   /* if the shift count is known then do it
9592      as efficiently as possible */
9593   if (AOP_TYPE (right) == AOP_LIT)
9594     {
9595       if (genLeftShiftLiteral (left, right, result, ic))
9596       {
9597         return;
9598       }
9599     }
9600 #endif
9601
9602   /* shift count is unknown then we have to form
9603      a loop get the loop count in B : Note: we take
9604      only the lower order byte since shifting
9605      more that 32 bits make no sense anyway, ( the
9606      largest size of an object can be only 32 bits ) */
9607
9608   pushedB = pushB ();
9609   if (AOP_TYPE (right) == AOP_LIT)
9610   {
9611       /* Really should be handled by genLeftShiftLiteral,
9612        * but since I'm too lazy to fix that today, at least we can make
9613        * some small improvement.
9614        */
9615        emitcode("mov", "b,#!constbyte",
9616                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9617   }
9618   else
9619   {
9620       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9621       emitcode ("inc", "b");
9622   }
9623   freeAsmop (right, NULL, ic, TRUE);
9624   aopOp (left, ic, FALSE, FALSE);
9625   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9626
9627   /* now move the left to the result if they are not the same */
9628   if (!sameRegs (AOP (left), AOP (result)) &&
9629       AOP_SIZE (result) > 1)
9630     {
9631
9632       size = AOP_SIZE (result);
9633       offset = 0;
9634       _startLazyDPSEvaluation ();
9635       while (size--)
9636         {
9637           l = aopGet (left, offset, FALSE, TRUE, NULL);
9638           if (*l == '@' && (IS_AOP_PREG (result)))
9639             {
9640
9641               emitcode ("mov", "a,%s", l);
9642               aopPut (result, "a", offset);
9643             }
9644           else
9645             aopPut (result, l, offset);
9646           offset++;
9647         }
9648       _endLazyDPSEvaluation ();
9649     }
9650
9651   tlbl = newiTempLabel (NULL);
9652   size = AOP_SIZE (result);
9653   offset = 0;
9654   tlbl1 = newiTempLabel (NULL);
9655
9656   /* if it is only one byte then */
9657   if (size == 1)
9658     {
9659       symbol *tlbl1 = newiTempLabel (NULL);
9660
9661       l = aopGet (left, 0, FALSE, FALSE, NULL);
9662       MOVA (l);
9663       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9664       emitLabel (tlbl);
9665       emitcode ("add", "a,acc");
9666       emitLabel (tlbl1);
9667       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9668       popB (pushedB);
9669       aopPut (result, "a", 0);
9670       goto release;
9671     }
9672
9673   reAdjustPreg (AOP (result));
9674
9675   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9676   emitLabel (tlbl);
9677   l = aopGet (result, offset, FALSE, FALSE, NULL);
9678   MOVA (l);
9679   emitcode ("add", "a,acc");
9680   aopPut (result, "a", offset++);
9681   _startLazyDPSEvaluation ();
9682   while (--size)
9683     {
9684       l = aopGet (result, offset, FALSE, FALSE, NULL);
9685       MOVA (l);
9686       emitcode ("rlc", "a");
9687       aopPut (result, "a", offset++);
9688     }
9689   _endLazyDPSEvaluation ();
9690   reAdjustPreg (AOP (result));
9691
9692   emitLabel (tlbl1);
9693   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9694   popB (pushedB);
9695 release:
9696   freeAsmop (result, NULL, ic, TRUE);
9697   freeAsmop (left, NULL, ic, TRUE);
9698 }
9699
9700 #ifdef BETTER_LITERAL_SHIFT
9701 /*-----------------------------------------------------------------*/
9702 /* genrshOne - right shift a one byte quantity by known count      */
9703 /*-----------------------------------------------------------------*/
9704 static void
9705 genrshOne (operand * result, operand * left,
9706            int shCount, int sign)
9707 {
9708   D (emitcode (";", "genrshOne"));
9709
9710   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9711 }
9712 #endif
9713
9714 #ifdef BETTER_LITERAL_SHIFT
9715 /*-----------------------------------------------------------------*/
9716 /* genrshTwo - right shift two bytes by known amount != 0          */
9717 /*-----------------------------------------------------------------*/
9718 static void
9719 genrshTwo (operand * result, operand * left,
9720            int shCount, int sign)
9721 {
9722   D (emitcode (";", "genrshTwo"));
9723
9724   /* if shCount >= 8 */
9725   if (shCount >= 8)
9726     {
9727       shCount -= 8;
9728       _startLazyDPSEvaluation();
9729       if (shCount)
9730         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9731       else
9732         movLeft2Result (left, MSB16, result, LSB, sign);
9733       addSign (result, MSB16, sign);
9734       _endLazyDPSEvaluation();
9735     }
9736
9737   /*  1 <= shCount <= 7 */
9738   else
9739     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9740 }
9741 #endif
9742
9743 /*-----------------------------------------------------------------*/
9744 /* shiftRLong - shift right one long from left to result           */
9745 /* offl = LSB or MSB16                                             */
9746 /*-----------------------------------------------------------------*/
9747 static void
9748 shiftRLong (operand * left, int offl,
9749             operand * result, int sign)
9750 {
9751   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9752
9753   if (overlapping && offl>1)
9754     {
9755       // we are in big trouble, but this shouldn't happen
9756       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9757     }
9758
9759   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9760
9761   if (offl==MSB16)
9762     {
9763       // shift is > 8
9764       if (sign)
9765         {
9766           emitcode ("rlc", "a");
9767           emitcode ("subb", "a,acc");
9768           emitcode ("xch", "a,%s",
9769                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9770         }
9771       else
9772         {
9773           aopPut (result, zero, MSB32);
9774         }
9775     }
9776
9777   if (!sign)
9778     {
9779       emitcode ("clr", "c");
9780     }
9781   else
9782     {
9783       emitcode ("mov", "c,acc.7");
9784     }
9785
9786   emitcode ("rrc", "a");
9787
9788   if (overlapping && offl==MSB16)
9789     {
9790       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9791     }
9792   else
9793     {
9794       aopPut (result, "a", MSB32 - offl);
9795       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9796     }
9797
9798   emitcode ("rrc", "a");
9799
9800   if (overlapping && offl==MSB16)
9801     {
9802       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9803     }
9804   else
9805     {
9806       aopPut (result, "a", MSB24 - offl);
9807       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9808     }
9809
9810   emitcode ("rrc", "a");
9811   if (offl != LSB)
9812     {
9813       aopPut (result, "a", MSB16 - offl);
9814     }
9815   else
9816     {
9817       if (overlapping && offl==MSB16)
9818         {
9819           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9820         }
9821       else
9822         {
9823           aopPut (result, "a", MSB16 - offl);
9824           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9825         }
9826       emitcode ("rrc", "a");
9827       aopPut (result, "a", LSB);
9828     }
9829 }
9830
9831 /*-----------------------------------------------------------------*/
9832 /* genrshFour - shift four byte by a known amount != 0             */
9833 /*-----------------------------------------------------------------*/
9834 static void
9835 genrshFour (operand * result, operand * left,
9836             int shCount, int sign)
9837 {
9838   D (emitcode (";", "genrshFour"));
9839
9840   /* if shifting more that 3 bytes */
9841   if (shCount >= 24)
9842     {
9843       shCount -= 24;
9844       _startLazyDPSEvaluation();
9845       if (shCount)
9846         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9847       else
9848         movLeft2Result (left, MSB32, result, LSB, sign);
9849       addSign (result, MSB16, sign);
9850       _endLazyDPSEvaluation();
9851     }
9852   else if (shCount >= 16)
9853     {
9854       shCount -= 16;
9855       _startLazyDPSEvaluation();
9856       if (shCount)
9857         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9858       else
9859         {
9860           movLeft2Result (left, MSB24, result, LSB, 0);
9861           movLeft2Result (left, MSB32, result, MSB16, sign);
9862         }
9863       addSign (result, MSB24, sign);
9864       _endLazyDPSEvaluation();
9865     }
9866   else if (shCount >= 8)
9867     {
9868       shCount -= 8;
9869       _startLazyDPSEvaluation();
9870       if (shCount == 1)
9871         {
9872             shiftRLong (left, MSB16, result, sign);
9873         }
9874       else if (shCount == 0)
9875         {
9876           movLeft2Result (left, MSB16, result, LSB, 0);
9877           movLeft2Result (left, MSB24, result, MSB16, 0);
9878           movLeft2Result (left, MSB32, result, MSB24, sign);
9879           addSign (result, MSB32, sign);
9880         }
9881       else
9882         {
9883           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9884           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9885           /* the last shift is signed */
9886           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9887           addSign (result, MSB32, sign);
9888         }
9889         _endLazyDPSEvaluation();
9890     }
9891   else
9892     {
9893       /* 1 <= shCount <= 7 */
9894       if (shCount <= 2)
9895         {
9896           shiftRLong (left, LSB, result, sign);
9897           if (shCount == 2)
9898             shiftRLong (result, LSB, result, sign);
9899         }
9900       else
9901         {
9902           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9903           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9904           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9905         }
9906     }
9907 }
9908
9909 #ifdef BETTER_LITERAL_SHIFT
9910 /*-----------------------------------------------------------------*/
9911 /* genRightShiftLiteral - right shifting by known count            */
9912 /*-----------------------------------------------------------------*/
9913 static bool
9914 genRightShiftLiteral (operand * left,
9915                       operand * right,
9916                       operand * result,
9917                       iCode * ic,
9918                       int sign)
9919 {
9920   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9921   int size;
9922
9923   size = getSize (operandType (result));
9924
9925   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9926
9927   /* We only handle certain easy cases so far. */
9928   if ((shCount != 0)
9929    && (shCount < (size * 8))
9930    && (size != 1)
9931    && (size != 2)
9932    && (size != 4))
9933   {
9934       D(emitcode (";", "genRightShiftLiteral wimping out"););
9935       return FALSE;
9936   }
9937
9938   freeAsmop (right, NULL, ic, TRUE);
9939
9940   aopOp (left, ic, FALSE, FALSE);
9941   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9942
9943 #if VIEW_SIZE
9944   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9945             AOP_SIZE (left));
9946 #endif
9947
9948   /* test the LEFT size !!! */
9949
9950   /* I suppose that the left size >= result size */
9951   if (shCount == 0)
9952   {
9953       size = getDataSize (result);
9954       _startLazyDPSEvaluation();
9955       while (size--)
9956         movLeft2Result (left, size, result, size, 0);
9957       _endLazyDPSEvaluation();
9958   }
9959   else if (shCount >= (size * 8))
9960     {
9961       if (sign)
9962         {
9963           /* get sign in acc.7 */
9964           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9965         }
9966       addSign (result, LSB, sign);
9967     }
9968   else
9969     {
9970       switch (size)
9971         {
9972         case 1:
9973           genrshOne (result, left, shCount, sign);
9974           break;
9975
9976         case 2:
9977           genrshTwo (result, left, shCount, sign);
9978           break;
9979 #if 1
9980         case 4:
9981           genrshFour (result, left, shCount, sign);
9982           break;
9983 #endif
9984         default:
9985           break;
9986         }
9987     }
9988   freeAsmop (result, NULL, ic, TRUE);
9989   freeAsmop (left, NULL, ic, TRUE);
9990
9991   return TRUE;
9992 }
9993 #endif
9994
9995 /*-----------------------------------------------------------------*/
9996 /* genSignedRightShift - right shift of signed number              */
9997 /*-----------------------------------------------------------------*/
9998 static void
9999 genSignedRightShift (iCode * ic)
10000 {
10001   operand *right, *left, *result;
10002   int size, offset;
10003   char *l;
10004   symbol *tlbl, *tlbl1;
10005   bool pushedB;
10006
10007   D (emitcode (";", "genSignedRightShift"));
10008
10009   /* we do it the hard way put the shift count in b
10010      and loop thru preserving the sign */
10011
10012   right = IC_RIGHT (ic);
10013   left = IC_LEFT (ic);
10014   result = IC_RESULT (ic);
10015
10016   aopOp (right, ic, FALSE, FALSE);
10017
10018 #ifdef BETTER_LITERAL_SHIFT
10019   if (AOP_TYPE (right) == AOP_LIT)
10020     {
10021       if (genRightShiftLiteral (left, right, result, ic, 1))
10022       {
10023         return;
10024       }
10025     }
10026 #endif
10027   /* shift count is unknown then we have to form
10028      a loop get the loop count in B : Note: we take
10029      only the lower order byte since shifting
10030      more that 32 bits make no sense anyway, ( the
10031      largest size of an object can be only 32 bits ) */
10032
10033   pushedB = pushB ();
10034   if (AOP_TYPE (right) == AOP_LIT)
10035   {
10036       /* Really should be handled by genRightShiftLiteral,
10037        * but since I'm too lazy to fix that today, at least we can make
10038        * some small improvement.
10039        */
10040        emitcode("mov", "b,#!constbyte",
10041                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10042   }
10043   else
10044   {
10045         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10046         emitcode ("inc", "b");
10047   }
10048   freeAsmop (right, NULL, ic, TRUE);
10049   aopOp (left, ic, FALSE, FALSE);
10050   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10051
10052   /* now move the left to the result if they are not the
10053      same */
10054   if (!sameRegs (AOP (left), AOP (result)) &&
10055       AOP_SIZE (result) > 1)
10056     {
10057
10058       size = AOP_SIZE (result);
10059       offset = 0;
10060       _startLazyDPSEvaluation ();
10061       while (size--)
10062         {
10063           l = aopGet (left, offset, FALSE, TRUE, NULL);
10064           if (*l == '@' && IS_AOP_PREG (result))
10065             {
10066
10067               emitcode ("mov", "a,%s", l);
10068               aopPut (result, "a", offset);
10069             }
10070           else
10071             aopPut (result, l, offset);
10072           offset++;
10073         }
10074       _endLazyDPSEvaluation ();
10075     }
10076
10077   /* mov the highest order bit to OVR */
10078   tlbl = newiTempLabel (NULL);
10079   tlbl1 = newiTempLabel (NULL);
10080
10081   size = AOP_SIZE (result);
10082   offset = size - 1;
10083   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10084   emitcode ("rlc", "a");
10085   emitcode ("mov", "ov,c");
10086   /* if it is only one byte then */
10087   if (size == 1)
10088     {
10089       l = aopGet (left, 0, FALSE, FALSE, NULL);
10090       MOVA (l);
10091       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10092       emitLabel (tlbl);
10093       emitcode ("mov", "c,ov");
10094       emitcode ("rrc", "a");
10095       emitLabel (tlbl1);
10096       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10097       popB (pushedB);
10098       aopPut (result, "a", 0);
10099       goto release;
10100     }
10101
10102   reAdjustPreg (AOP (result));
10103   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10104   emitLabel (tlbl);
10105   emitcode ("mov", "c,ov");
10106   _startLazyDPSEvaluation ();
10107   while (size--)
10108     {
10109       l = aopGet (result, offset, FALSE, FALSE, NULL);
10110       MOVA (l);
10111       emitcode ("rrc", "a");
10112       aopPut (result, "a", offset--);
10113     }
10114   _endLazyDPSEvaluation ();
10115   reAdjustPreg (AOP (result));
10116   emitLabel (tlbl1);
10117   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10118   popB (pushedB);
10119
10120 release:
10121   freeAsmop (result, NULL, ic, TRUE);
10122   freeAsmop (left, NULL, ic, TRUE);
10123 }
10124
10125 /*-----------------------------------------------------------------*/
10126 /* genRightShift - generate code for right shifting                */
10127 /*-----------------------------------------------------------------*/
10128 static void
10129 genRightShift (iCode * ic)
10130 {
10131   operand *right, *left, *result;
10132   sym_link *letype;
10133   int size, offset;
10134   char *l;
10135   symbol *tlbl, *tlbl1;
10136   bool pushedB;
10137
10138   D (emitcode (";", "genRightShift"));
10139
10140   /* if signed then we do it the hard way preserve the
10141      sign bit moving it inwards */
10142   letype = getSpec (operandType (IC_LEFT (ic)));
10143
10144   if (!SPEC_USIGN (letype))
10145     {
10146       genSignedRightShift (ic);
10147       return;
10148     }
10149
10150   /* signed & unsigned types are treated the same : i.e. the
10151      signed is NOT propagated inwards : quoting from the
10152      ANSI - standard : "for E1 >> E2, is equivalent to division
10153      by 2**E2 if unsigned or if it has a non-negative value,
10154      otherwise the result is implementation defined ", MY definition
10155      is that the sign does not get propagated */
10156
10157   right = IC_RIGHT (ic);
10158   left = IC_LEFT (ic);
10159   result = IC_RESULT (ic);
10160
10161   aopOp (right, ic, FALSE, FALSE);
10162
10163 #ifdef BETTER_LITERAL_SHIFT
10164   /* if the shift count is known then do it
10165      as efficiently as possible */
10166   if (AOP_TYPE (right) == AOP_LIT)
10167     {
10168       if (genRightShiftLiteral (left, right, result, ic, 0))
10169       {
10170         return;
10171       }
10172     }
10173 #endif
10174
10175   /* shift count is unknown then we have to form
10176      a loop get the loop count in B : Note: we take
10177      only the lower order byte since shifting
10178      more that 32 bits make no sense anyway, ( the
10179      largest size of an object can be only 32 bits ) */
10180
10181   pushedB = pushB ();
10182   if (AOP_TYPE (right) == AOP_LIT)
10183   {
10184       /* Really should be handled by genRightShiftLiteral,
10185        * but since I'm too lazy to fix that today, at least we can make
10186        * some small improvement.
10187        */
10188        emitcode("mov", "b,#!constbyte",
10189                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10190   }
10191   else
10192   {
10193       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10194       emitcode ("inc", "b");
10195   }
10196   freeAsmop (right, NULL, ic, TRUE);
10197   aopOp (left, ic, FALSE, FALSE);
10198   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10199
10200   /* now move the left to the result if they are not the
10201      same */
10202   if (!sameRegs (AOP (left), AOP (result)) &&
10203       AOP_SIZE (result) > 1)
10204     {
10205       size = AOP_SIZE (result);
10206       offset = 0;
10207       _startLazyDPSEvaluation ();
10208       while (size--)
10209         {
10210           l = aopGet (left, offset, FALSE, TRUE, NULL);
10211           if (*l == '@' && IS_AOP_PREG (result))
10212             {
10213
10214               emitcode ("mov", "a,%s", l);
10215               aopPut (result, "a", offset);
10216             }
10217           else
10218             aopPut (result, l, offset);
10219           offset++;
10220         }
10221       _endLazyDPSEvaluation ();
10222     }
10223
10224   tlbl = newiTempLabel (NULL);
10225   tlbl1 = newiTempLabel (NULL);
10226   size = AOP_SIZE (result);
10227   offset = size - 1;
10228
10229   /* if it is only one byte then */
10230   if (size == 1)
10231     {
10232       l = aopGet (left, 0, FALSE, FALSE, NULL);
10233       MOVA (l);
10234       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10235       emitLabel (tlbl);
10236       CLRC;
10237       emitcode ("rrc", "a");
10238       emitLabel (tlbl1);
10239       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10240       popB (pushedB);
10241       aopPut (result, "a", 0);
10242       goto release;
10243     }
10244
10245   reAdjustPreg (AOP (result));
10246   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10247   emitLabel (tlbl);
10248   CLRC;
10249   _startLazyDPSEvaluation ();
10250   while (size--)
10251     {
10252       l = aopGet (result, offset, FALSE, FALSE, NULL);
10253       MOVA (l);
10254       emitcode ("rrc", "a");
10255       aopPut (result, "a", offset--);
10256     }
10257   _endLazyDPSEvaluation ();
10258   reAdjustPreg (AOP (result));
10259
10260   emitLabel (tlbl1);
10261   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10262   popB (pushedB);
10263
10264 release:
10265   freeAsmop (result, NULL, ic, TRUE);
10266   freeAsmop (left, NULL, ic, TRUE);
10267 }
10268
10269 /*-----------------------------------------------------------------*/
10270 /* emitPtrByteGet - emits code to get a byte into A through a      */
10271 /*                  pointer register (R0, R1, or DPTR). The        */
10272 /*                  original value of A can be preserved in B.     */
10273 /*-----------------------------------------------------------------*/
10274 static void
10275 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10276 {
10277   switch (p_type)
10278     {
10279     case IPOINTER:
10280     case POINTER:
10281       if (preserveAinB)
10282         emitcode ("mov", "b,a");
10283       emitcode ("mov", "a,@%s", rname);
10284       break;
10285
10286     case PPOINTER:
10287       if (preserveAinB)
10288         emitcode ("mov", "b,a");
10289       emitcode ("movx", "a,@%s", rname);
10290       break;
10291
10292     case FPOINTER:
10293       if (preserveAinB)
10294         emitcode ("mov", "b,a");
10295       emitcode ("movx", "a,@dptr");
10296       break;
10297
10298     case CPOINTER:
10299       if (preserveAinB)
10300         emitcode ("mov", "b,a");
10301       emitcode ("clr", "a");
10302       emitcode ("movc", "a,@a+dptr");
10303       break;
10304
10305     case GPOINTER:
10306       if (preserveAinB)
10307         {
10308           emitcode ("push", "b");
10309           emitcode ("push", "acc");
10310         }
10311       emitcode ("lcall", "__gptrget");
10312       if (preserveAinB)
10313         emitcode ("pop", "b");
10314       break;
10315     }
10316 }
10317
10318 /*-----------------------------------------------------------------*/
10319 /* emitPtrByteSet - emits code to set a byte from src through a    */
10320 /*                  pointer register (R0, R1, or DPTR).            */
10321 /*-----------------------------------------------------------------*/
10322 static void
10323 emitPtrByteSet (char *rname, int p_type, char *src)
10324 {
10325   switch (p_type)
10326     {
10327     case IPOINTER:
10328     case POINTER:
10329       if (*src=='@')
10330         {
10331           MOVA (src);
10332           emitcode ("mov", "@%s,a", rname);
10333         }
10334       else
10335         emitcode ("mov", "@%s,%s", rname, src);
10336       break;
10337
10338     case PPOINTER:
10339       MOVA (src);
10340       emitcode ("movx", "@%s,a", rname);
10341       break;
10342
10343     case FPOINTER:
10344       MOVA (src);
10345       emitcode ("movx", "@dptr,a");
10346       break;
10347
10348     case GPOINTER:
10349       MOVA (src);
10350       emitcode ("lcall", "__gptrput");
10351       break;
10352     }
10353 }
10354
10355 /*-----------------------------------------------------------------*/
10356 /* genUnpackBits - generates code for unpacking bits               */
10357 /*-----------------------------------------------------------------*/
10358 static void
10359 genUnpackBits (operand * result, char *rname, int ptype)
10360 {
10361   int offset = 0;       /* result byte offset */
10362   int rsize;            /* result size */
10363   int rlen = 0;         /* remaining bitfield length */
10364   sym_link *etype;      /* bitfield type information */
10365   int blen;             /* bitfield length */
10366   int bstr;             /* bitfield starting bit within byte */
10367
10368   D(emitcode (";     genUnpackBits",""));
10369
10370   etype = getSpec (operandType (result));
10371   rsize = getSize (operandType (result));
10372   blen = SPEC_BLEN (etype);
10373   bstr = SPEC_BSTR (etype);
10374
10375   /* If the bitfield length is less than a byte */
10376   if (blen < 8)
10377     {
10378       emitPtrByteGet (rname, ptype, FALSE);
10379       AccRol (8 - bstr);
10380       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10381       if (!SPEC_USIGN (etype))
10382         {
10383           /* signed bitfield */
10384           symbol *tlbl = newiTempLabel (NULL);
10385
10386           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10387           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10388           emitLabel (tlbl);
10389         }
10390       aopPut (result, "a", offset++);
10391       goto finish;
10392     }
10393
10394   /* Bit field did not fit in a byte. Copy all
10395      but the partial byte at the end.  */
10396   for (rlen=blen;rlen>=8;rlen-=8)
10397     {
10398       emitPtrByteGet (rname, ptype, FALSE);
10399       aopPut (result, "a", offset++);
10400       if (rlen>8)
10401         emitcode ("inc", "%s", rname);
10402     }
10403
10404   /* Handle the partial byte at the end */
10405   if (rlen)
10406     {
10407       emitPtrByteGet (rname, ptype, FALSE);
10408       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10409       if (!SPEC_USIGN (etype))
10410         {
10411           /* signed bitfield */
10412           symbol *tlbl = newiTempLabel (NULL);
10413
10414           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10415           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10416           emitLabel (tlbl);
10417         }
10418       aopPut (result, "a", offset++);
10419     }
10420
10421 finish:
10422   if (offset < rsize)
10423     {
10424       char *source;
10425
10426       if (SPEC_USIGN (etype))
10427         source = zero;
10428       else
10429         {
10430           /* signed bitfield: sign extension with 0x00 or 0xff */
10431           emitcode ("rlc", "a");
10432           emitcode ("subb", "a,acc");
10433
10434           source = "a";
10435         }
10436       rsize -= offset;
10437       while (rsize--)
10438         aopPut (result, source, offset++);
10439     }
10440 }
10441
10442
10443 /*-----------------------------------------------------------------*/
10444 /* genDataPointerGet - generates code when ptr offset is known     */
10445 /*-----------------------------------------------------------------*/
10446 static void
10447 genDataPointerGet (operand * left,
10448                    operand * result,
10449                    iCode * ic)
10450 {
10451   char *l;
10452   char buffer[256];
10453   int size, offset = 0;
10454   aopOp (result, ic, TRUE, FALSE);
10455
10456   /* get the string representation of the name */
10457   l = aopGet (left, 0, FALSE, TRUE, NULL);
10458   size = AOP_SIZE (result);
10459   _startLazyDPSEvaluation ();
10460   while (size--)
10461     {
10462         if (offset)
10463         {
10464             SNPRINTF (buffer, sizeof(buffer),
10465                       "(%s + %d)", l + 1, offset);
10466         }
10467         else
10468         {
10469             SNPRINTF (buffer, sizeof(buffer),
10470                       "%s", l + 1);
10471         }
10472       aopPut (result, buffer, offset++);
10473     }
10474   _endLazyDPSEvaluation ();
10475
10476   freeAsmop (result, NULL, ic, TRUE);
10477   freeAsmop (left, NULL, ic, TRUE);
10478 }
10479
10480 /*-----------------------------------------------------------------*/
10481 /* genNearPointerGet - emitcode for near pointer fetch             */
10482 /*-----------------------------------------------------------------*/
10483 static void
10484 genNearPointerGet (operand * left,
10485                    operand * result,
10486                    iCode * ic,
10487                    iCode *pi)
10488 {
10489   asmop *aop = NULL;
10490   regs *preg;
10491   char *rname;
10492   sym_link *rtype, *retype, *letype;
10493   sym_link *ltype = operandType (left);
10494   char buffer[80];
10495
10496   rtype = operandType (result);
10497   retype = getSpec (rtype);
10498   letype = getSpec (ltype);
10499
10500   aopOp (left, ic, FALSE, FALSE);
10501
10502   /* if left is rematerialisable and
10503      result is not bitfield variable type and
10504      the left is pointer to data space i.e
10505      lower 128 bytes of space */
10506   if (AOP_TYPE (left) == AOP_IMMD &&
10507       !IS_BITFIELD (retype) &&
10508       !IS_BITFIELD (letype) &&
10509       DCL_TYPE (ltype) == POINTER)
10510     {
10511       genDataPointerGet (left, result, ic);
10512       return;
10513     }
10514
10515   /* if the value is already in a pointer register
10516      then don't need anything more */
10517   if (!AOP_INPREG (AOP (left)))
10518     {
10519       /* otherwise get a free pointer register */
10520       aop = newAsmop (0);
10521       preg = getFreePtr (ic, &aop, FALSE);
10522       emitcode ("mov", "%s,%s",
10523                 preg->name,
10524                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10525       rname = preg->name;
10526     }
10527   else
10528     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10529
10530   freeAsmop (left, NULL, ic, TRUE);
10531   aopOp (result, ic, FALSE, FALSE);
10532
10533   /* if bitfield then unpack the bits */
10534   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10535     genUnpackBits (result, rname, POINTER);
10536   else
10537     {
10538       /* we have can just get the values */
10539       int size = AOP_SIZE (result);
10540       int offset = 0;
10541
10542       while (size--)
10543         {
10544           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10545             {
10546
10547               emitcode ("mov", "a,@%s", rname);
10548               aopPut (result, "a", offset);
10549             }
10550           else
10551             {
10552               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10553               aopPut (result, buffer, offset);
10554             }
10555           offset++;
10556           if (size || pi)
10557             emitcode ("inc", "%s", rname);
10558         }
10559     }
10560
10561   /* now some housekeeping stuff */
10562   if (aop)      /* we had to allocate for this iCode */
10563     {
10564       if (pi) { /* post increment present */
10565         aopPut (left, rname, 0);
10566       }
10567       freeAsmop (NULL, aop, ic, TRUE);
10568     }
10569   else
10570     {
10571       /* we did not allocate which means left
10572          already in a pointer register, then
10573          if size > 0 && this could be used again
10574          we have to point it back to where it
10575          belongs */
10576       if (AOP_SIZE (result) > 1 &&
10577           !OP_SYMBOL (left)->remat &&
10578           (OP_SYMBOL (left)->liveTo > ic->seq ||
10579            ic->depth) &&
10580           !pi)
10581         {
10582           int size = AOP_SIZE (result) - 1;
10583           while (size--)
10584             emitcode ("dec", "%s", rname);
10585         }
10586     }
10587
10588   /* done */
10589   freeAsmop (result, NULL, ic, TRUE);
10590   if (pi) pi->generated = 1;
10591 }
10592
10593 /*-----------------------------------------------------------------*/
10594 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10595 /*-----------------------------------------------------------------*/
10596 static void
10597 genPagedPointerGet (operand * left,
10598                     operand * result,
10599                     iCode * ic,
10600                     iCode * pi)
10601 {
10602   asmop *aop = NULL;
10603   regs *preg;
10604   char *rname;
10605   sym_link *rtype, *retype, *letype;
10606
10607   rtype = operandType (result);
10608   retype = getSpec (rtype);
10609   letype = getSpec (operandType (left));
10610   aopOp (left, ic, FALSE, FALSE);
10611
10612   /* if the value is already in a pointer register
10613      then don't need anything more */
10614   if (!AOP_INPREG (AOP (left)))
10615     {
10616       /* otherwise get a free pointer register */
10617       aop = newAsmop (0);
10618       preg = getFreePtr (ic, &aop, FALSE);
10619       emitcode ("mov", "%s,%s",
10620                 preg->name,
10621                 aopGet (left, 0, FALSE, TRUE, NULL));
10622       rname = preg->name;
10623     }
10624   else
10625     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10626
10627   freeAsmop (left, NULL, ic, TRUE);
10628   aopOp (result, ic, FALSE, FALSE);
10629
10630   /* if bitfield then unpack the bits */
10631   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10632     genUnpackBits (result, rname, PPOINTER);
10633   else
10634     {
10635       /* we have can just get the values */
10636       int size = AOP_SIZE (result);
10637       int offset = 0;
10638
10639       while (size--)
10640         {
10641
10642           emitcode ("movx", "a,@%s", rname);
10643           aopPut (result, "a", offset);
10644
10645           offset++;
10646
10647           if (size || pi)
10648             emitcode ("inc", "%s", rname);
10649         }
10650     }
10651
10652   /* now some housekeeping stuff */
10653   if (aop)      /* we had to allocate for this iCode */
10654     {
10655       if (pi)
10656         aopPut (left, rname, 0);
10657       freeAsmop (NULL, aop, ic, TRUE);
10658     }
10659   else
10660     {
10661       /* we did not allocate which means left
10662          already in a pointer register, then
10663          if size > 0 && this could be used again
10664          we have to point it back to where it
10665          belongs */
10666       if (AOP_SIZE (result) > 1 &&
10667           !OP_SYMBOL (left)->remat &&
10668           (OP_SYMBOL (left)->liveTo > ic->seq ||
10669            ic->depth) &&
10670           !pi)
10671         {
10672           int size = AOP_SIZE (result) - 1;
10673           while (size--)
10674             emitcode ("dec", "%s", rname);
10675         }
10676     }
10677
10678   /* done */
10679   freeAsmop (result, NULL, ic, TRUE);
10680   if (pi) pi->generated = 1;
10681 }
10682
10683 /*-----------------------------------------------------------------*/
10684 /* genFarPointerGet - get value from far space                     */
10685 /*-----------------------------------------------------------------*/
10686 static void
10687 genFarPointerGet (operand * left,
10688                   operand * result, iCode * ic, iCode *pi)
10689 {
10690   int size, offset, dopi=1;
10691   sym_link *retype = getSpec (operandType (result));
10692   sym_link *letype = getSpec (operandType (left));
10693   D (emitcode (";", "genFarPointerGet"););
10694
10695   aopOp (left, ic, FALSE, FALSE);
10696
10697   /* if the operand is already in dptr
10698      then we do nothing else we move the value to dptr */
10699   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10700     {
10701       /* if this is rematerializable */
10702       if (AOP_TYPE (left) == AOP_IMMD)
10703         {
10704           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10705         }
10706       else
10707         {
10708           /* we need to get it byte by byte */
10709           _startLazyDPSEvaluation ();
10710           if (AOP_TYPE (left) != AOP_DPTR)
10711             {
10712               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10713               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10714               if (options.model == MODEL_FLAT24)
10715                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10716             }
10717           else
10718             {
10719               /* We need to generate a load to DPTR indirect through DPTR. */
10720               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10721               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10722               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10723               if (options.model == MODEL_FLAT24)
10724                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10725               emitcode ("pop", "dph");
10726               emitcode ("pop", "dpl");
10727               dopi =0;
10728             }
10729           _endLazyDPSEvaluation ();
10730         }
10731     }
10732   /* so dptr now contains the address */
10733   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10734
10735   /* if bit then unpack */
10736   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10737       if (AOP_INDPTRn(left)) {
10738           genSetDPTR(AOP(left)->aopu.dptr);
10739       }
10740       genUnpackBits (result, "dptr", FPOINTER);
10741       if (AOP_INDPTRn(left)) {
10742           genSetDPTR(0);
10743       }
10744   } else
10745     {
10746       size = AOP_SIZE (result);
10747       offset = 0;
10748
10749       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10750           while (size--) {
10751               genSetDPTR(AOP(left)->aopu.dptr);
10752               emitcode ("movx", "a,@dptr");
10753               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10754                   emitcode ("inc", "dptr");
10755               genSetDPTR (0);
10756               aopPut (result, "a", offset++);
10757           }
10758       } else {
10759           _startLazyDPSEvaluation ();
10760           while (size--) {
10761               if (AOP_INDPTRn(left)) {
10762                   genSetDPTR(AOP(left)->aopu.dptr);
10763               } else {
10764                   genSetDPTR (0);
10765               }
10766               _flushLazyDPS ();
10767
10768               emitcode ("movx", "a,@dptr");
10769               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10770                   emitcode ("inc", "dptr");
10771
10772               aopPut (result, "a", offset++);
10773           }
10774           _endLazyDPSEvaluation ();
10775       }
10776     }
10777   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10778       if (!AOP_INDPTRn(left)) {
10779           _startLazyDPSEvaluation ();
10780           aopPut (left, "dpl", 0);
10781           aopPut (left, "dph", 1);
10782           if (options.model == MODEL_FLAT24)
10783               aopPut (left, "dpx", 2);
10784           _endLazyDPSEvaluation ();
10785       }
10786     pi->generated = 1;
10787   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10788              AOP_SIZE(result) > 1 &&
10789              IS_SYMOP(left) &&
10790              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10791
10792       size = AOP_SIZE (result) - 1;
10793       if (AOP_INDPTRn(left)) {
10794           genSetDPTR(AOP(left)->aopu.dptr);
10795       }
10796       while (size--) emitcode ("lcall","__decdptr");
10797       if (AOP_INDPTRn(left)) {
10798           genSetDPTR(0);
10799       }
10800   }
10801
10802   freeAsmop (result, NULL, ic, TRUE);
10803   freeAsmop (left, NULL, ic, TRUE);
10804 }
10805
10806 /*-----------------------------------------------------------------*/
10807 /* genCodePointerGet - get value from code space                   */
10808 /*-----------------------------------------------------------------*/
10809 static void
10810 genCodePointerGet (operand * left,
10811                     operand * result, iCode * ic, iCode *pi)
10812 {
10813   int size, offset, dopi=1;
10814   sym_link *retype = getSpec (operandType (result));
10815
10816   aopOp (left, ic, FALSE, FALSE);
10817
10818   /* if the operand is already in dptr
10819      then we do nothing else we move the value to dptr */
10820   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10821     {
10822       /* if this is rematerializable */
10823       if (AOP_TYPE (left) == AOP_IMMD)
10824         {
10825           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10826         }
10827       else
10828         {                       /* we need to get it byte by byte */
10829           _startLazyDPSEvaluation ();
10830           if (AOP_TYPE (left) != AOP_DPTR)
10831             {
10832               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10833               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10834               if (options.model == MODEL_FLAT24)
10835                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10836             }
10837           else
10838             {
10839               /* We need to generate a load to DPTR indirect through DPTR. */
10840               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10841               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10842               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10843               if (options.model == MODEL_FLAT24)
10844                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10845               emitcode ("pop", "dph");
10846               emitcode ("pop", "dpl");
10847               dopi=0;
10848             }
10849           _endLazyDPSEvaluation ();
10850         }
10851     }
10852   /* so dptr now contains the address */
10853   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10854
10855   /* if bit then unpack */
10856   if (IS_BITFIELD (retype)) {
10857       if (AOP_INDPTRn(left)) {
10858           genSetDPTR(AOP(left)->aopu.dptr);
10859       }
10860       genUnpackBits (result, "dptr", CPOINTER);
10861       if (AOP_INDPTRn(left)) {
10862           genSetDPTR(0);
10863       }
10864   } else
10865     {
10866       size = AOP_SIZE (result);
10867       offset = 0;
10868       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10869           while (size--) {
10870               genSetDPTR(AOP(left)->aopu.dptr);
10871               emitcode ("clr", "a");
10872               emitcode ("movc", "a,@a+dptr");
10873               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10874                   emitcode ("inc", "dptr");
10875               genSetDPTR (0);
10876               aopPut (result, "a", offset++);
10877           }
10878       } else {
10879           _startLazyDPSEvaluation ();
10880           while (size--)
10881               {
10882                   if (AOP_INDPTRn(left)) {
10883                       genSetDPTR(AOP(left)->aopu.dptr);
10884                   } else {
10885                       genSetDPTR (0);
10886                   }
10887                   _flushLazyDPS ();
10888
10889                   emitcode ("clr", "a");
10890                   emitcode ("movc", "a,@a+dptr");
10891                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10892                       emitcode ("inc", "dptr");
10893                   aopPut (result, "a", offset++);
10894               }
10895           _endLazyDPSEvaluation ();
10896       }
10897     }
10898   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10899       if (!AOP_INDPTRn(left)) {
10900           _startLazyDPSEvaluation ();
10901
10902           aopPut (left, "dpl", 0);
10903           aopPut (left, "dph", 1);
10904           if (options.model == MODEL_FLAT24)
10905               aopPut (left, "dpx", 2);
10906
10907           _endLazyDPSEvaluation ();
10908       }
10909       pi->generated = 1;
10910   } else if (IS_SYMOP(left) &&
10911              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10912              AOP_SIZE(result) > 1 &&
10913              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10914
10915       size = AOP_SIZE (result) - 1;
10916       if (AOP_INDPTRn(left)) {
10917           genSetDPTR(AOP(left)->aopu.dptr);
10918       }
10919       while (size--) emitcode ("lcall","__decdptr");
10920       if (AOP_INDPTRn(left)) {
10921           genSetDPTR(0);
10922       }
10923   }
10924
10925   freeAsmop (result, NULL, ic, TRUE);
10926   freeAsmop (left, NULL, ic, TRUE);
10927 }
10928
10929 /*-----------------------------------------------------------------*/
10930 /* genGenPointerGet - get value from generic pointer space         */
10931 /*-----------------------------------------------------------------*/
10932 static void
10933 genGenPointerGet (operand * left,
10934                   operand * result, iCode * ic, iCode * pi)
10935 {
10936   int size, offset;
10937   bool pushedB;
10938   sym_link *retype = getSpec (operandType (result));
10939   sym_link *letype = getSpec (operandType (left));
10940
10941   D (emitcode (";", "genGenPointerGet"));
10942
10943   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10944
10945   pushedB = pushB ();
10946   /* if the operand is already in dptr
10947      then we do nothing else we move the value to dptr */
10948   if (AOP_TYPE (left) != AOP_STR)
10949     {
10950       /* if this is rematerializable */
10951       if (AOP_TYPE (left) == AOP_IMMD)
10952         {
10953           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10954           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10955             {
10956               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10957             }
10958           else
10959             {
10960               emitcode ("mov", "b,#%d", pointerCode (retype));
10961             }
10962         }
10963       else
10964         {                       /* we need to get it byte by byte */
10965           _startLazyDPSEvaluation ();
10966           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10967           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10968           if (options.model == MODEL_FLAT24) {
10969               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10970               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10971           } else {
10972               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10973           }
10974           _endLazyDPSEvaluation ();
10975         }
10976     }
10977
10978   /* so dptr-b now contains the address */
10979   aopOp (result, ic, FALSE, TRUE);
10980
10981   /* if bit then unpack */
10982   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10983   {
10984     genUnpackBits (result, "dptr", GPOINTER);
10985   }
10986   else
10987     {
10988         size = AOP_SIZE (result);
10989         offset = 0;
10990
10991         while (size--)
10992         {
10993             if (size)
10994             {
10995                 // Get two bytes at a time, results in _AP & A.
10996                 // dptr will be incremented ONCE by __gptrgetWord.
10997                 //
10998                 // Note: any change here must be coordinated
10999                 // with the implementation of __gptrgetWord
11000                 // in device/lib/_gptrget.c
11001                 emitcode ("lcall", "__gptrgetWord");
11002                 aopPut (result, DP2_RESULT_REG, offset++);
11003                 aopPut (result, "a", offset++);
11004                 size--;
11005             }
11006             else
11007             {
11008                 // Only one byte to get.
11009                 emitcode ("lcall", "__gptrget");
11010                 aopPut (result, "a", offset++);
11011             }
11012
11013             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11014             {
11015                 emitcode ("inc", "dptr");
11016             }
11017         }
11018     }
11019
11020   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11021     _startLazyDPSEvaluation ();
11022
11023     aopPut (left, "dpl", 0);
11024     aopPut (left, "dph", 1);
11025     if (options.model == MODEL_FLAT24) {
11026         aopPut (left, "dpx", 2);
11027         aopPut (left, "b", 3);
11028     } else  aopPut (left, "b", 2);
11029
11030     _endLazyDPSEvaluation ();
11031
11032     pi->generated = 1;
11033   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11034              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11035
11036       size = AOP_SIZE (result) - 1;
11037       while (size--) emitcode ("lcall","__decdptr");
11038   }
11039   popB (pushedB);
11040
11041   freeAsmop (result, NULL, ic, TRUE);
11042   freeAsmop (left, NULL, ic, TRUE);
11043 }
11044
11045 /*-----------------------------------------------------------------*/
11046 /* genPointerGet - generate code for pointer get                   */
11047 /*-----------------------------------------------------------------*/
11048 static void
11049 genPointerGet (iCode * ic, iCode *pi)
11050 {
11051   operand *left, *result;
11052   sym_link *type, *etype;
11053   int p_type;
11054
11055   D (emitcode (";", "genPointerGet"));
11056
11057   left = IC_LEFT (ic);
11058   result = IC_RESULT (ic);
11059
11060   /* depending on the type of pointer we need to
11061      move it to the correct pointer register */
11062   type = operandType (left);
11063   etype = getSpec (type);
11064   /* if left is of type of pointer then it is simple */
11065   if (IS_PTR (type) && !IS_FUNC (type->next))
11066     p_type = DCL_TYPE (type);
11067   else
11068     {
11069       /* we have to go by the storage class */
11070       p_type = PTR_TYPE (SPEC_OCLS (etype));
11071     }
11072
11073   /* special case when cast remat */
11074   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11075       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11076     {
11077       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11078       type = operandType (left);
11079       p_type = DCL_TYPE (type);
11080     }
11081   /* now that we have the pointer type we assign
11082      the pointer values */
11083   switch (p_type)
11084     {
11085
11086     case POINTER:
11087     case IPOINTER:
11088       genNearPointerGet (left, result, ic, pi);
11089       break;
11090
11091     case PPOINTER:
11092       genPagedPointerGet (left, result, ic, pi);
11093       break;
11094
11095     case FPOINTER:
11096       genFarPointerGet (left, result, ic, pi);
11097       break;
11098
11099     case CPOINTER:
11100       genCodePointerGet (left, result, ic, pi);
11101       break;
11102
11103     case GPOINTER:
11104       genGenPointerGet (left, result, ic, pi);
11105       break;
11106     }
11107 }
11108
11109
11110 /*-----------------------------------------------------------------*/
11111 /* genPackBits - generates code for packed bit storage             */
11112 /*-----------------------------------------------------------------*/
11113 static void
11114 genPackBits (sym_link * etype,
11115              operand * right,
11116              char *rname, int p_type)
11117 {
11118   int offset = 0;       /* source byte offset */
11119   int rlen = 0;         /* remaining bitfield length */
11120   int blen;             /* bitfield length */
11121   int bstr;             /* bitfield starting bit within byte */
11122   int litval;           /* source literal value (if AOP_LIT) */
11123   unsigned char mask;   /* bitmask within current byte */
11124
11125   D(emitcode (";     genPackBits",""));
11126
11127   blen = SPEC_BLEN (etype);
11128   bstr = SPEC_BSTR (etype);
11129
11130   /* If the bitfield length is less than a byte */
11131   if (blen < 8)
11132     {
11133       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11134               (unsigned char) (0xFF >> (8 - bstr)));
11135
11136       if (AOP_TYPE (right) == AOP_LIT)
11137         {
11138           /* Case with a bitfield length <8 and literal source
11139           */
11140           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11141           litval <<= bstr;
11142           litval &= (~mask) & 0xff;
11143           emitPtrByteGet (rname, p_type, FALSE);
11144           if ((mask|litval)!=0xff)
11145             emitcode ("anl","a,#!constbyte", mask);
11146           if (litval)
11147             emitcode ("orl","a,#!constbyte", litval);
11148         }
11149       else
11150         {
11151           if ((blen==1) && (p_type!=GPOINTER))
11152             {
11153               /* Case with a bitfield length == 1 and no generic pointer
11154               */
11155               if (AOP_TYPE (right) == AOP_CRY)
11156                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11157               else
11158                 {
11159                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11160                   emitcode ("rrc","a");
11161                 }
11162               emitPtrByteGet (rname, p_type, FALSE);
11163               emitcode ("mov","acc.%d,c",bstr);
11164             }
11165           else
11166             {
11167               bool pushedB;
11168               /* Case with a bitfield length < 8 and arbitrary source
11169               */
11170               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11171               /* shift and mask source value */
11172               AccLsh (bstr);
11173               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11174
11175               pushedB = pushB ();
11176               /* transfer A to B and get next byte */
11177               emitPtrByteGet (rname, p_type, TRUE);
11178
11179               emitcode ("anl", "a,#!constbyte", mask);
11180               emitcode ("orl", "a,b");
11181               if (p_type == GPOINTER)
11182                 emitcode ("pop", "b");
11183
11184               popB (pushedB);
11185            }
11186         }
11187
11188       emitPtrByteSet (rname, p_type, "a");
11189       return;
11190     }
11191
11192   /* Bit length is greater than 7 bits. In this case, copy  */
11193   /* all except the partial byte at the end                 */
11194   for (rlen=blen;rlen>=8;rlen-=8)
11195     {
11196       emitPtrByteSet (rname, p_type,
11197                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11198       if (rlen>8)
11199         emitcode ("inc", "%s", rname);
11200     }
11201
11202   /* If there was a partial byte at the end */
11203   if (rlen)
11204     {
11205       mask = (((unsigned char) -1 << rlen) & 0xff);
11206
11207       if (AOP_TYPE (right) == AOP_LIT)
11208         {
11209           /* Case with partial byte and literal source
11210           */
11211           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11212           litval >>= (blen-rlen);
11213           litval &= (~mask) & 0xff;
11214           emitPtrByteGet (rname, p_type, FALSE);
11215           if ((mask|litval)!=0xff)
11216             emitcode ("anl","a,#!constbyte", mask);
11217           if (litval)
11218             emitcode ("orl","a,#!constbyte", litval);
11219         }
11220       else
11221         {
11222           bool pushedB;
11223           /* Case with partial byte and arbitrary source
11224           */
11225           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11226           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11227
11228           pushedB = pushB ();
11229           /* transfer A to B and get next byte */
11230           emitPtrByteGet (rname, p_type, TRUE);
11231
11232           emitcode ("anl", "a,#!constbyte", mask);
11233           emitcode ("orl", "a,b");
11234           if (p_type == GPOINTER)
11235             emitcode ("pop", "b");
11236
11237           popB (pushedB);
11238         }
11239       emitPtrByteSet (rname, p_type, "a");
11240     }
11241 }
11242
11243
11244 /*-----------------------------------------------------------------*/
11245 /* genDataPointerSet - remat pointer to data space                 */
11246 /*-----------------------------------------------------------------*/
11247 static void
11248 genDataPointerSet (operand * right,
11249                    operand * result,
11250                    iCode * ic)
11251 {
11252   int size, offset = 0;
11253   char *l, buffer[256];
11254
11255   D (emitcode (";", "genDataPointerSet"));
11256
11257   aopOp (right, ic, FALSE, FALSE);
11258
11259   l = aopGet (result, 0, FALSE, TRUE, NULL);
11260   size = AOP_SIZE (right);
11261   while (size--)
11262     {
11263       if (offset)
11264           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11265       else
11266           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11267       emitcode ("mov", "%s,%s", buffer,
11268                 aopGet (right, offset++, FALSE, FALSE, NULL));
11269     }
11270
11271   freeAsmop (result, NULL, ic, TRUE);
11272   freeAsmop (right, NULL, ic, TRUE);
11273 }
11274
11275 /*-----------------------------------------------------------------*/
11276 /* genNearPointerSet - emitcode for near pointer put                */
11277 /*-----------------------------------------------------------------*/
11278 static void
11279 genNearPointerSet (operand * right,
11280                    operand * result,
11281                    iCode * ic,
11282                    iCode * pi)
11283 {
11284   asmop *aop = NULL;
11285   char *rname, *l;
11286   sym_link *retype, *letype;
11287   sym_link *ptype = operandType (result);
11288
11289   D (emitcode (";", "genNearPointerSet"));
11290
11291   retype = getSpec (operandType (right));
11292   letype = getSpec (ptype);
11293
11294   aopOp (result, ic, FALSE, FALSE);
11295
11296   /* if the result is rematerializable &
11297      in data space & not a bit variable */
11298   if (AOP_TYPE (result) == AOP_IMMD &&
11299       DCL_TYPE (ptype) == POINTER &&
11300       !IS_BITVAR (retype) &&
11301       !IS_BITVAR (letype))
11302     {
11303       genDataPointerSet (right, result, ic);
11304       return;
11305     }
11306
11307   /* if the value is already in a pointer register
11308      then don't need anything more */
11309   if (!AOP_INPREG (AOP (result)))
11310     {
11311       /* otherwise get a free pointer register */
11312       regs *preg;
11313
11314       aop = newAsmop (0);
11315       preg = getFreePtr (ic, &aop, FALSE);
11316       emitcode ("mov", "%s,%s",
11317                 preg->name,
11318                 aopGet (result, 0, FALSE, TRUE, NULL));
11319       rname = preg->name;
11320     }
11321   else
11322     {
11323       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11324     }
11325
11326   aopOp (right, ic, FALSE, FALSE);
11327
11328   /* if bitfield then unpack the bits */
11329   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11330     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11331   else
11332     {
11333       /* we can just get the values */
11334       int size = AOP_SIZE (right);
11335       int offset = 0;
11336
11337       while (size--)
11338         {
11339           l = aopGet (right, offset, FALSE, TRUE, NULL);
11340           if ((*l == '@') || (strcmp (l, "acc") == 0))
11341             {
11342               MOVA (l);
11343               emitcode ("mov", "@%s,a", rname);
11344             }
11345           else
11346             emitcode ("mov", "@%s,%s", rname, l);
11347           if (size || pi)
11348             emitcode ("inc", "%s", rname);
11349           offset++;
11350         }
11351     }
11352
11353   /* now some housekeeping stuff */
11354   if (aop)      /* we had to allocate for this iCode */
11355     {
11356       if (pi)
11357         aopPut (result, rname, 0);
11358       freeAsmop (NULL, aop, ic, TRUE);
11359     }
11360   else
11361     {
11362       /* we did not allocate which means left
11363          already in a pointer register, then
11364          if size > 0 && this could be used again
11365          we have to point it back to where it
11366          belongs */
11367       if (AOP_SIZE (right) > 1 &&
11368           !OP_SYMBOL (result)->remat &&
11369           (OP_SYMBOL (result)->liveTo > ic->seq ||
11370            ic->depth) &&
11371           !pi)
11372         {
11373           int size = AOP_SIZE (right) - 1;
11374           while (size--)
11375             emitcode ("dec", "%s", rname);
11376         }
11377     }
11378
11379   /* done */
11380   if (pi) pi->generated = 1;
11381   freeAsmop (result, NULL, ic, TRUE);
11382   freeAsmop (right, NULL, ic, TRUE);
11383 }
11384
11385 /*-----------------------------------------------------------------*/
11386 /* genPagedPointerSet - emitcode for Paged pointer put             */
11387 /*-----------------------------------------------------------------*/
11388 static void
11389 genPagedPointerSet (operand * right,
11390                     operand * result,
11391                     iCode * ic,
11392                     iCode *pi)
11393 {
11394   asmop *aop = NULL;
11395   char *rname, *l;
11396   sym_link *retype, *letype;
11397
11398   D (emitcode (";", "genPagedPointerSet"));
11399
11400   retype = getSpec (operandType (right));
11401   letype = getSpec (operandType (result));
11402
11403   aopOp (result, ic, FALSE, FALSE);
11404
11405   /* if the value is already in a pointer register
11406      then don't need anything more */
11407   if (!AOP_INPREG (AOP (result)))
11408     {
11409       /* otherwise get a free pointer register */
11410       regs *preg;
11411
11412       aop = newAsmop (0);
11413       preg = getFreePtr (ic, &aop, FALSE);
11414       emitcode ("mov", "%s,%s",
11415                 preg->name,
11416                 aopGet (result, 0, FALSE, TRUE, NULL));
11417       rname = preg->name;
11418     }
11419   else
11420     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11421
11422   aopOp (right, ic, FALSE, FALSE);
11423
11424   /* if bitfield then unpack the bits */
11425   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11426     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11427   else
11428     {
11429       /* we have can just get the values */
11430       int size = AOP_SIZE (right);
11431       int offset = 0;
11432
11433       while (size--)
11434         {
11435           l = aopGet (right, offset, FALSE, TRUE, NULL);
11436           MOVA (l);
11437           emitcode ("movx", "@%s,a", rname);
11438
11439           if (size || pi)
11440             emitcode ("inc", "%s", rname);
11441
11442           offset++;
11443         }
11444     }
11445
11446   /* now some housekeeping stuff */
11447   if (aop)
11448     {
11449       if (pi)
11450         aopPut (result, rname, 0);
11451       /* we had to allocate for this iCode */
11452       freeAsmop (NULL, aop, ic, TRUE);
11453     }
11454   else
11455     {
11456       /* we did not allocate which means left
11457          already in a pointer register, then
11458          if size > 0 && this could be used again
11459          we have to point it back to where it
11460          belongs */
11461       if (AOP_SIZE (right) > 1 &&
11462           !OP_SYMBOL (result)->remat &&
11463           (OP_SYMBOL (result)->liveTo > ic->seq ||
11464            ic->depth) &&
11465           !pi)
11466         {
11467           int size = AOP_SIZE (right) - 1;
11468           while (size--)
11469             emitcode ("dec", "%s", rname);
11470         }
11471     }
11472
11473   /* done */
11474   if (pi) pi->generated = 1;
11475   freeAsmop (result, NULL, ic, TRUE);
11476   freeAsmop (right, NULL, ic, TRUE);
11477 }
11478
11479 /*-----------------------------------------------------------------*/
11480 /* genFarPointerSet - set value from far space                     */
11481 /*-----------------------------------------------------------------*/
11482 static void
11483 genFarPointerSet (operand * right,
11484                   operand * result, iCode * ic, iCode *pi)
11485 {
11486   int size, offset, dopi=1;
11487   sym_link *retype = getSpec (operandType (right));
11488   sym_link *letype = getSpec (operandType (result));
11489
11490   aopOp (result, ic, FALSE, FALSE);
11491
11492   /* if the operand is already in dptr
11493      then we do nothing else we move the value to dptr */
11494   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11495     {
11496       /* if this is remateriazable */
11497       if (AOP_TYPE (result) == AOP_IMMD)
11498         emitcode ("mov", "dptr,%s",
11499                   aopGet (result, 0, TRUE, FALSE, NULL));
11500       else
11501         {
11502           /* we need to get it byte by byte */
11503           _startLazyDPSEvaluation ();
11504           if (AOP_TYPE (result) != AOP_DPTR)
11505             {
11506               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11507               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11508               if (options.model == MODEL_FLAT24)
11509                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11510             }
11511           else
11512             {
11513               /* We need to generate a load to DPTR indirect through DPTR. */
11514               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11515
11516               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11517               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11518               if (options.model == MODEL_FLAT24)
11519                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11520               emitcode ("pop", "dph");
11521               emitcode ("pop", "dpl");
11522               dopi=0;
11523             }
11524           _endLazyDPSEvaluation ();
11525         }
11526     }
11527   /* so dptr now contains the address */
11528   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11529
11530   /* if bit then unpack */
11531   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11532   {
11533       if (AOP_INDPTRn(result)) {
11534           genSetDPTR(AOP(result)->aopu.dptr);
11535       }
11536       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11537       if (AOP_INDPTRn(result)) {
11538           genSetDPTR(0);
11539       }
11540   } else {
11541       size = AOP_SIZE (right);
11542       offset = 0;
11543       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11544           while (size--) {
11545               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11546
11547               genSetDPTR(AOP(result)->aopu.dptr);
11548               emitcode ("movx", "@dptr,a");
11549               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11550                   emitcode ("inc", "dptr");
11551               genSetDPTR (0);
11552           }
11553       } else {
11554           _startLazyDPSEvaluation ();
11555           while (size--) {
11556               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11557
11558               if (AOP_INDPTRn(result)) {
11559                   genSetDPTR(AOP(result)->aopu.dptr);
11560               } else {
11561                   genSetDPTR (0);
11562               }
11563               _flushLazyDPS ();
11564
11565               emitcode ("movx", "@dptr,a");
11566               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11567                   emitcode ("inc", "dptr");
11568           }
11569           _endLazyDPSEvaluation ();
11570       }
11571   }
11572
11573   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11574       if (!AOP_INDPTRn(result)) {
11575           _startLazyDPSEvaluation ();
11576
11577           aopPut (result,"dpl",0);
11578           aopPut (result,"dph",1);
11579           if (options.model == MODEL_FLAT24)
11580               aopPut (result,"dpx",2);
11581
11582           _endLazyDPSEvaluation ();
11583       }
11584       pi->generated=1;
11585   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11586              AOP_SIZE(right) > 1 &&
11587              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11588
11589       size = AOP_SIZE (right) - 1;
11590       if (AOP_INDPTRn(result)) {
11591           genSetDPTR(AOP(result)->aopu.dptr);
11592       }
11593       while (size--) emitcode ("lcall","__decdptr");
11594       if (AOP_INDPTRn(result)) {
11595           genSetDPTR(0);
11596       }
11597   }
11598   freeAsmop (result, NULL, ic, TRUE);
11599   freeAsmop (right, NULL, ic, TRUE);
11600 }
11601
11602 /*-----------------------------------------------------------------*/
11603 /* genGenPointerSet - set value from generic pointer space         */
11604 /*-----------------------------------------------------------------*/
11605 static void
11606 genGenPointerSet (operand * right,
11607                   operand * result, iCode * ic, iCode *pi)
11608 {
11609   int size, offset;
11610   bool pushedB;
11611   sym_link *retype = getSpec (operandType (right));
11612   sym_link *letype = getSpec (operandType (result));
11613
11614   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11615
11616   pushedB = pushB ();
11617   /* if the operand is already in dptr
11618      then we do nothing else we move the value to dptr */
11619   if (AOP_TYPE (result) != AOP_STR)
11620     {
11621       _startLazyDPSEvaluation ();
11622       /* if this is remateriazable */
11623       if (AOP_TYPE (result) == AOP_IMMD)
11624         {
11625           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11626           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11627           {
11628               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11629           }
11630           else
11631           {
11632               emitcode ("mov",
11633                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11634           }
11635         }
11636       else
11637         {                       /* we need to get it byte by byte */
11638           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11639           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11640           if (options.model == MODEL_FLAT24) {
11641             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11642             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11643           } else {
11644             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11645           }
11646         }
11647       _endLazyDPSEvaluation ();
11648     }
11649   /* so dptr + b now contains the address */
11650   aopOp (right, ic, FALSE, TRUE);
11651
11652   /* if bit then unpack */
11653   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11654     {
11655         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11656     }
11657   else
11658     {
11659         size = AOP_SIZE (right);
11660         offset = 0;
11661
11662         _startLazyDPSEvaluation ();
11663         while (size--)
11664         {
11665             if (size)
11666             {
11667                 // Set two bytes at a time, passed in _AP & A.
11668                 // dptr will be incremented ONCE by __gptrputWord.
11669                 //
11670                 // Note: any change here must be coordinated
11671                 // with the implementation of __gptrputWord
11672                 // in device/lib/_gptrput.c
11673                 emitcode("mov", "_ap, %s",
11674                          aopGet (right, offset++, FALSE, FALSE, NULL));
11675                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11676
11677                 genSetDPTR (0);
11678                 _flushLazyDPS ();
11679                 emitcode ("lcall", "__gptrputWord");
11680                 size--;
11681             }
11682             else
11683             {
11684                 // Only one byte to put.
11685                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11686
11687                 genSetDPTR (0);
11688                 _flushLazyDPS ();
11689                 emitcode ("lcall", "__gptrput");
11690             }
11691
11692             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11693             {
11694                 emitcode ("inc", "dptr");
11695             }
11696         }
11697         _endLazyDPSEvaluation ();
11698     }
11699
11700   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11701       _startLazyDPSEvaluation ();
11702
11703       aopPut (result, "dpl",0);
11704       aopPut (result, "dph",1);
11705       if (options.model == MODEL_FLAT24) {
11706           aopPut (result, "dpx",2);
11707           aopPut (result, "b",3);
11708       } else {
11709           aopPut (result, "b",2);
11710       }
11711       _endLazyDPSEvaluation ();
11712
11713       pi->generated=1;
11714   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11715              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11716
11717       size = AOP_SIZE (right) - 1;
11718       while (size--) emitcode ("lcall","__decdptr");
11719   }
11720   popB (pushedB);
11721
11722   freeAsmop (result, NULL, ic, TRUE);
11723   freeAsmop (right, NULL, ic, TRUE);
11724 }
11725
11726 /*-----------------------------------------------------------------*/
11727 /* genPointerSet - stores the value into a pointer location        */
11728 /*-----------------------------------------------------------------*/
11729 static void
11730 genPointerSet (iCode * ic, iCode *pi)
11731 {
11732   operand *right, *result;
11733   sym_link *type, *etype;
11734   int p_type;
11735
11736   D (emitcode (";", "genPointerSet"));
11737
11738   right = IC_RIGHT (ic);
11739   result = IC_RESULT (ic);
11740
11741   /* depending on the type of pointer we need to
11742      move it to the correct pointer register */
11743   type = operandType (result);
11744   etype = getSpec (type);
11745   /* if left is of type of pointer then it is simple */
11746   if (IS_PTR (type) && !IS_FUNC (type->next))
11747     {
11748       p_type = DCL_TYPE (type);
11749     }
11750   else
11751     {
11752       /* we have to go by the storage class */
11753       p_type = PTR_TYPE (SPEC_OCLS (etype));
11754     }
11755
11756   /* special case when cast remat */
11757   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11758       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11759           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11760           type = operandType (result);
11761           p_type = DCL_TYPE (type);
11762   }
11763
11764   /* now that we have the pointer type we assign
11765      the pointer values */
11766   switch (p_type)
11767     {
11768
11769     case POINTER:
11770     case IPOINTER:
11771       genNearPointerSet (right, result, ic, pi);
11772       break;
11773
11774     case PPOINTER:
11775       genPagedPointerSet (right, result, ic, pi);
11776       break;
11777
11778     case FPOINTER:
11779       genFarPointerSet (right, result, ic, pi);
11780       break;
11781
11782     case GPOINTER:
11783       genGenPointerSet (right, result, ic, pi);
11784       break;
11785
11786     default:
11787       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11788               "genPointerSet: illegal pointer type");
11789     }
11790 }
11791
11792 /*-----------------------------------------------------------------*/
11793 /* genIfx - generate code for Ifx statement                        */
11794 /*-----------------------------------------------------------------*/
11795 static void
11796 genIfx (iCode * ic, iCode * popIc)
11797 {
11798   operand *cond = IC_COND (ic);
11799   int isbit = 0;
11800   char *dup = NULL;
11801
11802   D (emitcode (";", "genIfx"));
11803
11804   aopOp (cond, ic, FALSE, FALSE);
11805
11806   /* get the value into acc */
11807   if (AOP_TYPE (cond) != AOP_CRY)
11808     {
11809       toBoolean (cond);
11810     }
11811   else
11812     {
11813       isbit = 1;
11814       if (AOP(cond)->aopu.aop_dir)
11815         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11816     }
11817
11818   /* the result is now in the accumulator or a directly addressable bit */
11819   freeAsmop (cond, NULL, ic, TRUE);
11820
11821   /* if there was something to be popped then do it */
11822   if (popIc)
11823     genIpop (popIc);
11824
11825   /* if the condition is a bit variable */
11826   if (isbit && dup)
11827     genIfxJump (ic, dup);
11828   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11829     genIfxJump (ic, SPIL_LOC (cond)->rname);
11830   else if (isbit && !IS_ITEMP (cond))
11831     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11832   else
11833     genIfxJump (ic, "a");
11834
11835   ic->generated = 1;
11836 }
11837
11838 /*-----------------------------------------------------------------*/
11839 /* genAddrOf - generates code for address of                       */
11840 /*-----------------------------------------------------------------*/
11841 static void
11842 genAddrOf (iCode * ic)
11843 {
11844   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11845   int size, offset;
11846
11847   D (emitcode (";", "genAddrOf"));
11848
11849   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11850
11851   /* if the operand is on the stack then we
11852      need to get the stack offset of this
11853      variable */
11854   if (sym->onStack)
11855   {
11856
11857       /* if 10 bit stack */
11858       if (options.stack10bit) {
11859           char buff[10];
11860           int  offset;
11861
11862           tsprintf(buff, sizeof(buff),
11863                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11864           /* if it has an offset then we need to compute it */
11865 /*        emitcode ("subb", "a,#!constbyte", */
11866 /*                  -((sym->stack < 0) ? */
11867 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11868 /*                    ((short) sym->stack)) & 0xff); */
11869 /*        emitcode ("mov","b,a"); */
11870 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11871 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11872 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11873           if (sym->stack) {
11874               emitcode ("mov", "a,_bpx");
11875               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11876                                              ((char) (sym->stack - _G.nRegsSaved)) :
11877                                              ((char) sym->stack )) & 0xff);
11878               emitcode ("mov", "b,a");
11879               emitcode ("mov", "a,_bpx+1");
11880
11881               offset = (((sym->stack < 0) ?
11882                          ((short) (sym->stack - _G.nRegsSaved)) :
11883                          ((short) sym->stack )) >> 8) & 0xff;
11884
11885               emitcode ("addc","a,#!constbyte", offset);
11886
11887               aopPut (IC_RESULT (ic), "b", 0);
11888               aopPut (IC_RESULT (ic), "a", 1);
11889               aopPut (IC_RESULT (ic), buff, 2);
11890           } else {
11891               /* we can just move _bp */
11892               aopPut (IC_RESULT (ic), "_bpx", 0);
11893               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11894               aopPut (IC_RESULT (ic), buff, 2);
11895           }
11896       } else {
11897           /* if it has an offset then we need to compute it */
11898           if (sym->stack)
11899             {
11900               emitcode ("mov", "a,_bp");
11901               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11902               aopPut (IC_RESULT (ic), "a", 0);
11903             }
11904           else
11905             {
11906               /* we can just move _bp */
11907               aopPut (IC_RESULT (ic), "_bp", 0);
11908             }
11909           /* fill the result with zero */
11910           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11911
11912
11913           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11914               fprintf (stderr,
11915                        "*** warning: pointer to stack var truncated.\n");
11916           }
11917
11918           offset = 1;
11919           while (size--)
11920             {
11921               aopPut (IC_RESULT (ic), zero, offset++);
11922             }
11923       }
11924       goto release;
11925   }
11926
11927   /* object not on stack then we need the name */
11928   size = AOP_SIZE (IC_RESULT (ic));
11929   offset = 0;
11930
11931   while (size--)
11932     {
11933       char s[SDCC_NAME_MAX];
11934       if (offset) {
11935           switch (offset) {
11936           case 1:
11937               tsprintf(s, sizeof(s), "#!his",sym->rname);
11938               break;
11939           case 2:
11940               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11941               break;
11942           case 3:
11943               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11944               break;
11945           default: /* should not need this (just in case) */
11946               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11947                        sym->rname,
11948                        offset * 8);
11949           }
11950       }
11951       else
11952       {
11953           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11954       }
11955
11956       aopPut (IC_RESULT (ic), s, offset++);
11957     }
11958
11959 release:
11960   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11961
11962 }
11963
11964 #if 0 // obsolete, and buggy for != xdata
11965 /*-----------------------------------------------------------------*/
11966 /* genArrayInit - generates code for address of                       */
11967 /*-----------------------------------------------------------------*/
11968 static void
11969 genArrayInit (iCode * ic)
11970 {
11971     literalList *iLoop;
11972     int         ix, count;
11973     int         elementSize = 0, eIndex;
11974     unsigned    val, lastVal;
11975     sym_link    *type;
11976     operand     *left=IC_LEFT(ic);
11977
11978     D (emitcode (";", "genArrayInit"));
11979
11980     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11981
11982     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11983     {
11984         // Load immediate value into DPTR.
11985         emitcode("mov", "dptr, %s",
11986              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11987     }
11988     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11989     {
11990 #if 0
11991       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11992               "Unexpected operand to genArrayInit.\n");
11993       exit(1);
11994 #else
11995       // a regression because of SDCCcse.c:1.52
11996       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11997       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11998       if (options.model == MODEL_FLAT24)
11999         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
12000 #endif
12001     }
12002
12003     type = operandType(IC_LEFT(ic));
12004
12005     if (type && type->next)
12006     {
12007         elementSize = getSize(type->next);
12008     }
12009     else
12010     {
12011         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12012                                 "can't determine element size in genArrayInit.\n");
12013         exit(1);
12014     }
12015
12016     iLoop = IC_ARRAYILIST(ic);
12017     lastVal = 0xffff;
12018
12019     while (iLoop)
12020     {
12021         bool firstpass = TRUE;
12022
12023         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12024                  iLoop->count, (int)iLoop->literalValue, elementSize);
12025
12026         ix = iLoop->count;
12027
12028         while (ix)
12029         {
12030             symbol *tlbl = NULL;
12031
12032             count = ix > 256 ? 256 : ix;
12033
12034             if (count > 1)
12035             {
12036                 tlbl = newiTempLabel (NULL);
12037                 if (firstpass || (count & 0xff))
12038                 {
12039                     emitcode("mov", "b, #!constbyte", count & 0xff);
12040                 }
12041
12042                 emitLabel (tlbl);
12043             }
12044
12045             firstpass = FALSE;
12046
12047             for (eIndex = 0; eIndex < elementSize; eIndex++)
12048             {
12049                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12050                 if (val != lastVal)
12051                 {
12052                     emitcode("mov", "a, #!constbyte", val);
12053                     lastVal = val;
12054                 }
12055
12056                 emitcode("movx", "@dptr, a");
12057                 emitcode("inc", "dptr");
12058             }
12059
12060             if (count > 1)
12061             {
12062                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12063             }
12064
12065             ix -= count;
12066         }
12067
12068         iLoop = iLoop->next;
12069     }
12070
12071     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12072 }
12073 #endif
12074
12075 /*-----------------------------------------------------------------*/
12076 /* genFarFarAssign - assignment when both are in far space         */
12077 /*-----------------------------------------------------------------*/
12078 static void
12079 genFarFarAssign (operand * result, operand * right, iCode * ic)
12080 {
12081   int size = AOP_SIZE (right);
12082   int offset = 0;
12083   symbol *rSym = NULL;
12084
12085   if (size == 1)
12086   {
12087       /* quick & easy case. */
12088       D (emitcode(";","genFarFarAssign (1 byte case)"));
12089       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12090       freeAsmop (right, NULL, ic, FALSE);
12091       /* now assign DPTR to result */
12092       _G.accInUse++;
12093       aopOp(result, ic, FALSE, FALSE);
12094       _G.accInUse--;
12095       aopPut (result, "a", 0);
12096       freeAsmop(result, NULL, ic, FALSE);
12097       return;
12098   }
12099
12100   /* See if we've got an underlying symbol to abuse. */
12101   if (IS_SYMOP(result) && OP_SYMBOL(result))
12102   {
12103       if (IS_TRUE_SYMOP(result))
12104       {
12105           rSym = OP_SYMBOL(result);
12106       }
12107       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12108       {
12109           rSym = OP_SYMBOL(result)->usl.spillLoc;
12110       }
12111   }
12112
12113   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12114   {
12115       /* We can use the '390 auto-toggle feature to good effect here. */
12116
12117       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12118       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12119       emitcode ("mov", "dptr,#%s", rSym->rname);
12120       /* DP2 = result, DP1 = right, DP1 is current. */
12121       while (size)
12122       {
12123           emitcode("movx", "a,@dptr");
12124           emitcode("movx", "@dptr,a");
12125           if (--size)
12126           {
12127                emitcode("inc", "dptr");
12128                emitcode("inc", "dptr");
12129           }
12130       }
12131       emitcode("mov", "dps,#0");
12132       freeAsmop (right, NULL, ic, FALSE);
12133 #if 0
12134 some alternative code for processors without auto-toggle
12135 no time to test now, so later well put in...kpb
12136         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12137         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12138         emitcode ("mov", "dptr,#%s", rSym->rname);
12139         /* DP2 = result, DP1 = right, DP1 is current. */
12140         while (size)
12141         {
12142           --size;
12143           emitcode("movx", "a,@dptr");
12144           if (size)
12145             emitcode("inc", "dptr");
12146           emitcode("inc", "dps");
12147           emitcode("movx", "@dptr,a");
12148           if (size)
12149             emitcode("inc", "dptr");
12150           emitcode("inc", "dps");
12151         }
12152         emitcode("mov", "dps,#0");
12153         freeAsmop (right, NULL, ic, FALSE);
12154 #endif
12155   }
12156   else
12157   {
12158       D (emitcode (";", "genFarFarAssign"));
12159       aopOp (result, ic, TRUE, TRUE);
12160
12161       _startLazyDPSEvaluation ();
12162
12163       while (size--)
12164         {
12165           aopPut (result,
12166                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12167           offset++;
12168         }
12169       _endLazyDPSEvaluation ();
12170       freeAsmop (result, NULL, ic, FALSE);
12171       freeAsmop (right, NULL, ic, FALSE);
12172   }
12173 }
12174
12175 /*-----------------------------------------------------------------*/
12176 /* genAssign - generate code for assignment                        */
12177 /*-----------------------------------------------------------------*/
12178 static void
12179 genAssign (iCode * ic)
12180 {
12181   operand *result, *right;
12182   int size, offset;
12183   unsigned long lit = 0L;
12184
12185   D (emitcode (";", "genAssign"));
12186
12187   result = IC_RESULT (ic);
12188   right = IC_RIGHT (ic);
12189
12190   /* if they are the same */
12191   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12192     return;
12193
12194   aopOp (right, ic, FALSE, FALSE);
12195
12196   emitcode (";", "genAssign: resultIsFar = %s",
12197             isOperandInFarSpace (result) ?
12198             "TRUE" : "FALSE");
12199
12200   /* special case both in far space */
12201   if ((AOP_TYPE (right) == AOP_DPTR ||
12202        AOP_TYPE (right) == AOP_DPTR2) &&
12203   /* IS_TRUE_SYMOP(result)       && */
12204       isOperandInFarSpace (result))
12205     {
12206       genFarFarAssign (result, right, ic);
12207       return;
12208     }
12209
12210   aopOp (result, ic, TRUE, FALSE);
12211
12212   /* if they are the same registers */
12213   if (sameRegs (AOP (right), AOP (result)))
12214     goto release;
12215
12216   /* if the result is a bit */
12217   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12218     {
12219       /* if the right size is a literal then
12220          we know what the value is */
12221       if (AOP_TYPE (right) == AOP_LIT)
12222         {
12223           if (((int) operandLitValue (right)))
12224             aopPut (result, one, 0);
12225           else
12226             aopPut (result, zero, 0);
12227           goto release;
12228         }
12229
12230       /* the right is also a bit variable */
12231       if (AOP_TYPE (right) == AOP_CRY)
12232         {
12233           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12234           aopPut (result, "c", 0);
12235           goto release;
12236         }
12237
12238       /* we need to or */
12239       toBoolean (right);
12240       aopPut (result, "a", 0);
12241       goto release;
12242     }
12243
12244   /* bit variables done */
12245   /* general case */
12246   size = AOP_SIZE (result);
12247   offset = 0;
12248   if (AOP_TYPE (right) == AOP_LIT)
12249     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12250
12251   if ((size > 1) &&
12252       (AOP_TYPE (result) != AOP_REG) &&
12253       (AOP_TYPE (right) == AOP_LIT) &&
12254       !IS_FLOAT (operandType (right)))
12255     {
12256       _startLazyDPSEvaluation ();
12257       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12258         {
12259           aopPut (result,
12260                   aopGet (right, offset, FALSE, FALSE, NULL),
12261                   offset);
12262           offset++;
12263           size--;
12264         }
12265       /* And now fill the rest with zeros. */
12266       if (size)
12267         {
12268           emitcode ("clr", "a");
12269         }
12270       while (size--)
12271         {
12272           aopPut (result, "a", offset++);
12273         }
12274       _endLazyDPSEvaluation ();
12275     }
12276   else
12277     {
12278       _startLazyDPSEvaluation ();
12279       while (size--)
12280         {
12281           aopPut (result,
12282                   aopGet (right, offset, FALSE, FALSE, NULL),
12283                   offset);
12284           offset++;
12285         }
12286       _endLazyDPSEvaluation ();
12287     }
12288
12289 release:
12290   freeAsmop (result, NULL, ic, TRUE);
12291   freeAsmop (right, NULL, ic, TRUE);
12292 }
12293
12294 /*-----------------------------------------------------------------*/
12295 /* genJumpTab - generates code for jump table                      */
12296 /*-----------------------------------------------------------------*/
12297 static void
12298 genJumpTab (iCode * ic)
12299 {
12300   symbol *jtab;
12301   char *l;
12302
12303   D (emitcode (";", "genJumpTab"));
12304
12305   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12306   /* get the condition into accumulator */
12307   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12308   MOVA (l);
12309   /* multiply by four! */
12310   emitcode ("add", "a,acc");
12311   emitcode ("add", "a,acc");
12312   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12313
12314   jtab = newiTempLabel (NULL);
12315   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12316   emitcode ("jmp", "@a+dptr");
12317   emitLabel (jtab);
12318   /* now generate the jump labels */
12319   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12320        jtab = setNextItem (IC_JTLABELS (ic)))
12321     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12322
12323 }
12324
12325 /*-----------------------------------------------------------------*/
12326 /* genCast - gen code for casting                                  */
12327 /*-----------------------------------------------------------------*/
12328 static void
12329 genCast (iCode * ic)
12330 {
12331   operand *result = IC_RESULT (ic);
12332   sym_link *ctype = operandType (IC_LEFT (ic));
12333   sym_link *rtype = operandType (IC_RIGHT (ic));
12334   operand *right = IC_RIGHT (ic);
12335   int size, offset;
12336
12337   D (emitcode (";", "genCast"));
12338
12339   /* if they are equivalent then do nothing */
12340   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12341     return;
12342
12343   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12344   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12345
12346   /* if the result is a bit (and not a bitfield) */
12347   if (IS_BIT (OP_SYMBOL (result)->type))
12348     {
12349       /* if the right size is a literal then
12350          we know what the value is */
12351       if (AOP_TYPE (right) == AOP_LIT)
12352         {
12353           if (((int) operandLitValue (right)))
12354             aopPut (result, one, 0);
12355           else
12356             aopPut (result, zero, 0);
12357
12358           goto release;
12359         }
12360
12361       /* the right is also a bit variable */
12362       if (AOP_TYPE (right) == AOP_CRY)
12363         {
12364           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12365           aopPut (result, "c", 0);
12366           goto release;
12367         }
12368
12369       /* we need to or */
12370       toBoolean (right);
12371       aopPut (result, "a", 0);
12372       goto release;
12373     }
12374
12375   /* if they are the same size : or less */
12376   if (AOP_SIZE (result) <= AOP_SIZE (right))
12377     {
12378
12379       /* if they are in the same place */
12380       if (sameRegs (AOP (right), AOP (result)))
12381         goto release;
12382
12383       /* if they in different places then copy */
12384       size = AOP_SIZE (result);
12385       offset = 0;
12386       _startLazyDPSEvaluation ();
12387       while (size--)
12388         {
12389           aopPut (result,
12390                   aopGet (right, offset, FALSE, FALSE, NULL),
12391                   offset);
12392           offset++;
12393         }
12394       _endLazyDPSEvaluation ();
12395       goto release;
12396     }
12397
12398   /* if the result is of type pointer */
12399   if (IS_PTR (ctype))
12400     {
12401
12402       int p_type;
12403       sym_link *type = operandType (right);
12404
12405       /* pointer to generic pointer */
12406       if (IS_GENPTR (ctype))
12407         {
12408           if (IS_PTR (type))
12409             {
12410               p_type = DCL_TYPE (type);
12411             }
12412           else
12413             {
12414 #if OLD_CAST_BEHAVIOR
12415               /* KV: we are converting a non-pointer type to
12416                * a generic pointer. This (ifdef'd out) code
12417                * says that the resulting generic pointer
12418                * should have the same class as the storage
12419                * location of the non-pointer variable.
12420                *
12421                * For example, converting an int (which happens
12422                * to be stored in DATA space) to a pointer results
12423                * in a DATA generic pointer; if the original int
12424                * in XDATA space, so will be the resulting pointer.
12425                *
12426                * I don't like that behavior, and thus this change:
12427                * all such conversions will be forced to XDATA and
12428                * throw a warning. If you want some non-XDATA
12429                * type, or you want to suppress the warning, you
12430                * must go through an intermediate cast, like so:
12431                *
12432                * char _generic *gp = (char _xdata *)(intVar);
12433                */
12434               sym_link *etype = getSpec (type);
12435
12436               /* we have to go by the storage class */
12437               if (SPEC_OCLS (etype) != generic)
12438                 {
12439                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12440                 }
12441               else
12442 #endif
12443                 {
12444                   /* Converting unknown class (i.e. register variable)
12445                    * to generic pointer. This is not good, but
12446                    * we'll make a guess (and throw a warning).
12447                    */
12448                   p_type = FPOINTER;
12449                   werror (W_INT_TO_GEN_PTR_CAST);
12450                 }
12451             }
12452
12453           /* the first two bytes are known */
12454           size = GPTRSIZE - 1;
12455           offset = 0;
12456           _startLazyDPSEvaluation ();
12457           while (size--)
12458             {
12459               aopPut (result,
12460                       aopGet (right, offset, FALSE, FALSE, NULL),
12461                       offset);
12462               offset++;
12463             }
12464           _endLazyDPSEvaluation ();
12465
12466           /* the last byte depending on type */
12467             {
12468                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12469                 char gpValStr[10];
12470
12471                 if (gpVal == -1)
12472                 {
12473                     // pointerTypeToGPByte will have bitched.
12474                     exit(1);
12475                 }
12476
12477                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12478                 aopPut (result, gpValStr, GPTRSIZE - 1);
12479             }
12480           goto release;
12481         }
12482
12483       /* just copy the pointers */
12484       size = AOP_SIZE (result);
12485       offset = 0;
12486       _startLazyDPSEvaluation ();
12487       while (size--)
12488         {
12489           aopPut (result,
12490                   aopGet (right, offset, FALSE, FALSE, NULL),
12491                   offset);
12492           offset++;
12493         }
12494       _endLazyDPSEvaluation ();
12495       goto release;
12496     }
12497
12498   /* so we now know that the size of destination is greater
12499      than the size of the source */
12500   /* we move to result for the size of source */
12501   size = AOP_SIZE (right);
12502   offset = 0;
12503   _startLazyDPSEvaluation ();
12504   while (size--)
12505     {
12506       aopPut (result,
12507               aopGet (right, offset, FALSE, FALSE, NULL),
12508               offset);
12509       offset++;
12510     }
12511   _endLazyDPSEvaluation ();
12512
12513   /* now depending on the sign of the source && destination */
12514   size = AOP_SIZE (result) - AOP_SIZE (right);
12515   /* if unsigned or not an integral type */
12516   /* also, if the source is a bit, we don't need to sign extend, because
12517    * it can't possibly have set the sign bit.
12518    */
12519   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12520     {
12521       while (size--)
12522         {
12523           aopPut (result, zero, offset++);
12524         }
12525     }
12526   else
12527     {
12528       /* we need to extend the sign :{ */
12529       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12530                         FALSE, FALSE, NULL));
12531       emitcode ("rlc", "a");
12532       emitcode ("subb", "a,acc");
12533       while (size--)
12534         aopPut (result, "a", offset++);
12535     }
12536
12537   /* we are done hurray !!!! */
12538
12539 release:
12540   freeAsmop (right, NULL, ic, TRUE);
12541   freeAsmop (result, NULL, ic, TRUE);
12542
12543 }
12544
12545 /*-----------------------------------------------------------------*/
12546 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12547 /*-----------------------------------------------------------------*/
12548 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12549 {
12550     operand *from , *to , *count;
12551     symbol *lbl;
12552     bitVect *rsave;
12553     int i;
12554
12555     /* we know it has to be 3 parameters */
12556     assert (nparms == 3);
12557
12558     rsave = newBitVect(16);
12559     /* save DPTR if it needs to be saved */
12560     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12561             if (bitVectBitValue(ic->rMask,i))
12562                     rsave = bitVectSetBit(rsave,i);
12563     }
12564     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12565                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12566     savermask(rsave);
12567
12568     to = parms[0];
12569     from = parms[1];
12570     count = parms[2];
12571
12572     aopOp (from, ic->next, FALSE, FALSE);
12573
12574     /* get from into DPTR1 */
12575     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12576     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12577     if (options.model == MODEL_FLAT24) {
12578         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12579     }
12580
12581     freeAsmop (from, NULL, ic, FALSE);
12582     aopOp (to, ic, FALSE, FALSE);
12583     /* get "to" into DPTR */
12584     /* if the operand is already in dptr
12585        then we do nothing else we move the value to dptr */
12586     if (AOP_TYPE (to) != AOP_STR) {
12587         /* if already in DPTR then we need to push */
12588         if (AOP_TYPE(to) == AOP_DPTR) {
12589             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12590             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12591             if (options.model == MODEL_FLAT24)
12592                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12593             emitcode ("pop", "dph");
12594             emitcode ("pop", "dpl");
12595         } else {
12596             _startLazyDPSEvaluation ();
12597             /* if this is remateriazable */
12598             if (AOP_TYPE (to) == AOP_IMMD) {
12599                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12600             } else {                    /* we need to get it byte by byte */
12601                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12602                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12603                 if (options.model == MODEL_FLAT24) {
12604                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12605                 }
12606             }
12607             _endLazyDPSEvaluation ();
12608         }
12609     }
12610     freeAsmop (to, NULL, ic, FALSE);
12611     _G.dptrInUse = _G.dptr1InUse = 1;
12612     aopOp (count, ic->next->next, FALSE,FALSE);
12613     lbl =newiTempLabel(NULL);
12614
12615     /* now for the actual copy */
12616     if (AOP_TYPE(count) == AOP_LIT &&
12617         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12618         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12619         if (fromc) {
12620             emitcode ("lcall","__bi_memcpyc2x_s");
12621         } else {
12622             emitcode ("lcall","__bi_memcpyx2x_s");
12623         }
12624         freeAsmop (count, NULL, ic, FALSE);
12625     } else {
12626         symbol *lbl1 = newiTempLabel(NULL);
12627
12628         emitcode (";"," Auto increment but no djnz");
12629         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12630         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12631         freeAsmop (count, NULL, ic, FALSE);
12632         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12633         emitLabel (lbl);
12634         if (fromc) {
12635             emitcode ("clr","a");
12636             emitcode ("movc", "a,@a+dptr");
12637         } else
12638             emitcode ("movx", "a,@dptr");
12639         emitcode ("movx", "@dptr,a");
12640         emitcode ("inc", "dptr");
12641         emitcode ("inc", "dptr");
12642         emitcode ("mov","a,b");
12643         emitcode ("orl","a,_ap");
12644         emitcode ("jz","!tlabel",lbl1->key+100);
12645         emitcode ("mov","a,_ap");
12646         emitcode ("add","a,#!constbyte",0xFF);
12647         emitcode ("mov","_ap,a");
12648         emitcode ("mov","a,b");
12649         emitcode ("addc","a,#!constbyte",0xFF);
12650         emitcode ("mov","b,a");
12651         emitcode ("sjmp","!tlabel",lbl->key+100);
12652         emitLabel (lbl1);
12653     }
12654     emitcode ("mov", "dps,#0");
12655     _G.dptrInUse = _G.dptr1InUse = 0;
12656     unsavermask(rsave);
12657
12658 }
12659
12660 /*-----------------------------------------------------------------*/
12661 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12662 /*-----------------------------------------------------------------*/
12663 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12664 {
12665     operand *from , *to , *count;
12666     symbol *lbl,*lbl2;
12667     bitVect *rsave;
12668     int i;
12669
12670     /* we know it has to be 3 parameters */
12671     assert (nparms == 3);
12672
12673     rsave = newBitVect(16);
12674     /* save DPTR if it needs to be saved */
12675     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12676             if (bitVectBitValue(ic->rMask,i))
12677                     rsave = bitVectSetBit(rsave,i);
12678     }
12679     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12680                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12681     savermask(rsave);
12682
12683     to = parms[0];
12684     from = parms[1];
12685     count = parms[2];
12686
12687     aopOp (from, ic->next, FALSE, FALSE);
12688
12689     /* get from into DPTR1 */
12690     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12691     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12692     if (options.model == MODEL_FLAT24) {
12693         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12694     }
12695
12696     freeAsmop (from, NULL, ic, FALSE);
12697     aopOp (to, ic, FALSE, FALSE);
12698     /* get "to" into DPTR */
12699     /* if the operand is already in dptr
12700        then we do nothing else we move the value to dptr */
12701     if (AOP_TYPE (to) != AOP_STR) {
12702         /* if already in DPTR then we need to push */
12703         if (AOP_TYPE(to) == AOP_DPTR) {
12704             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12705             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12706             if (options.model == MODEL_FLAT24)
12707                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12708             emitcode ("pop", "dph");
12709             emitcode ("pop", "dpl");
12710         } else {
12711             _startLazyDPSEvaluation ();
12712             /* if this is remateriazable */
12713             if (AOP_TYPE (to) == AOP_IMMD) {
12714                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12715             } else {                    /* we need to get it byte by byte */
12716                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12717                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12718                 if (options.model == MODEL_FLAT24) {
12719                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12720                 }
12721             }
12722             _endLazyDPSEvaluation ();
12723         }
12724     }
12725     freeAsmop (to, NULL, ic, FALSE);
12726     _G.dptrInUse = _G.dptr1InUse = 1;
12727     aopOp (count, ic->next->next, FALSE,FALSE);
12728     lbl =newiTempLabel(NULL);
12729     lbl2 =newiTempLabel(NULL);
12730
12731     /* now for the actual compare */
12732     if (AOP_TYPE(count) == AOP_LIT &&
12733         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12734         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12735         if (fromc)
12736             emitcode("lcall","__bi_memcmpc2x_s");
12737         else
12738             emitcode("lcall","__bi_memcmpx2x_s");
12739         freeAsmop (count, NULL, ic, FALSE);
12740         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12741         aopPut(IC_RESULT(ic),"a",0);
12742         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12743     } else {
12744         symbol *lbl1 = newiTempLabel(NULL);
12745
12746         emitcode("push","ar0");
12747         emitcode (";"," Auto increment but no djnz");
12748         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12749         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12750         freeAsmop (count, NULL, ic, FALSE);
12751         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12752         emitLabel (lbl);
12753         if (fromc) {
12754             emitcode ("clr","a");
12755             emitcode ("movc", "a,@a+dptr");
12756         } else
12757             emitcode ("movx", "a,@dptr");
12758         emitcode ("mov","r0,a");
12759         emitcode ("movx", "a,@dptr");
12760         emitcode ("clr","c");
12761         emitcode ("subb","a,r0");
12762         emitcode ("jnz","!tlabel",lbl2->key+100);
12763         emitcode ("inc", "dptr");
12764         emitcode ("inc", "dptr");
12765         emitcode ("mov","a,b");
12766         emitcode ("orl","a,_ap");
12767         emitcode ("jz","!tlabel",lbl1->key+100);
12768         emitcode ("mov","a,_ap");
12769         emitcode ("add","a,#!constbyte",0xFF);
12770         emitcode ("mov","_ap,a");
12771         emitcode ("mov","a,b");
12772         emitcode ("addc","a,#!constbyte",0xFF);
12773         emitcode ("mov","b,a");
12774         emitcode ("sjmp","!tlabel",lbl->key+100);
12775         emitLabel (lbl1);
12776         emitcode ("clr","a");
12777         emitLabel (lbl2);
12778         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12779         aopPut(IC_RESULT(ic),"a",0);
12780         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12781         emitcode("pop","ar0");
12782         emitcode ("mov", "dps,#0");
12783     }
12784     _G.dptrInUse = _G.dptr1InUse = 0;
12785     unsavermask(rsave);
12786
12787 }
12788
12789 /*-----------------------------------------------------------------*/
12790 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12791 /* port, first parameter output area second parameter pointer to   */
12792 /* port third parameter count                                      */
12793 /*-----------------------------------------------------------------*/
12794 static void genInp( iCode *ic, int nparms, operand **parms)
12795 {
12796     operand *from , *to , *count;
12797     symbol *lbl;
12798     bitVect *rsave;
12799     int i;
12800
12801     /* we know it has to be 3 parameters */
12802     assert (nparms == 3);
12803
12804     rsave = newBitVect(16);
12805     /* save DPTR if it needs to be saved */
12806     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12807             if (bitVectBitValue(ic->rMask,i))
12808                     rsave = bitVectSetBit(rsave,i);
12809     }
12810     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12811                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12812     savermask(rsave);
12813
12814     to = parms[0];
12815     from = parms[1];
12816     count = parms[2];
12817
12818     aopOp (from, ic->next, FALSE, FALSE);
12819
12820     /* get from into DPTR1 */
12821     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12822     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12823     if (options.model == MODEL_FLAT24) {
12824         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12825     }
12826
12827     freeAsmop (from, NULL, ic, FALSE);
12828     aopOp (to, ic, FALSE, FALSE);
12829     /* get "to" into DPTR */
12830     /* if the operand is already in dptr
12831        then we do nothing else we move the value to dptr */
12832     if (AOP_TYPE (to) != AOP_STR) {
12833         /* if already in DPTR then we need to push */
12834         if (AOP_TYPE(to) == AOP_DPTR) {
12835             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12836             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12837             if (options.model == MODEL_FLAT24)
12838                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12839             emitcode ("pop", "dph");
12840             emitcode ("pop", "dpl");
12841         } else {
12842             _startLazyDPSEvaluation ();
12843             /* if this is remateriazable */
12844             if (AOP_TYPE (to) == AOP_IMMD) {
12845                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12846             } else {                    /* we need to get it byte by byte */
12847                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12848                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12849                 if (options.model == MODEL_FLAT24) {
12850                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12851                 }
12852             }
12853             _endLazyDPSEvaluation ();
12854         }
12855     }
12856     freeAsmop (to, NULL, ic, FALSE);
12857
12858     _G.dptrInUse = _G.dptr1InUse = 1;
12859     aopOp (count, ic->next->next, FALSE,FALSE);
12860     lbl =newiTempLabel(NULL);
12861
12862     /* now for the actual copy */
12863     if (AOP_TYPE(count) == AOP_LIT &&
12864         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12865         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12866         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12867         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12868         freeAsmop (count, NULL, ic, FALSE);
12869         emitLabel (lbl);
12870         emitcode ("movx", "a,@dptr");   /* read data from port */
12871         emitcode ("dec","dps");         /* switch to DPTR */
12872         emitcode ("movx", "@dptr,a");   /* save into location */
12873         emitcode ("inc", "dptr");       /* point to next area */
12874         emitcode ("inc","dps");         /* switch to DPTR2 */
12875         emitcode ("djnz","b,!tlabel",lbl->key+100);
12876     } else {
12877         symbol *lbl1 = newiTempLabel(NULL);
12878
12879         emitcode (";"," Auto increment but no djnz");
12880         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12881         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12882         freeAsmop (count, NULL, ic, FALSE);
12883         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12884         emitLabel (lbl);
12885         emitcode ("movx", "a,@dptr");
12886         emitcode ("dec","dps");         /* switch to DPTR */
12887         emitcode ("movx", "@dptr,a");
12888         emitcode ("inc", "dptr");
12889         emitcode ("inc","dps");         /* switch to DPTR2 */
12890 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12891 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12892         emitcode ("mov","a,b");
12893         emitcode ("orl","a,_ap");
12894         emitcode ("jz","!tlabel",lbl1->key+100);
12895         emitcode ("mov","a,_ap");
12896         emitcode ("add","a,#!constbyte",0xFF);
12897         emitcode ("mov","_ap,a");
12898         emitcode ("mov","a,b");
12899         emitcode ("addc","a,#!constbyte",0xFF);
12900         emitcode ("mov","b,a");
12901         emitcode ("sjmp","!tlabel",lbl->key+100);
12902         emitLabel (lbl1);
12903     }
12904     emitcode ("mov", "dps,#0");
12905     _G.dptrInUse = _G.dptr1InUse = 0;
12906     unsavermask(rsave);
12907
12908 }
12909
12910 /*-----------------------------------------------------------------*/
12911 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12912 /* port, first parameter output area second parameter pointer to   */
12913 /* port third parameter count                                      */
12914 /*-----------------------------------------------------------------*/
12915 static void genOutp( iCode *ic, int nparms, operand **parms)
12916 {
12917     operand *from , *to , *count;
12918     symbol *lbl;
12919     bitVect *rsave;
12920     int i;
12921
12922     /* we know it has to be 3 parameters */
12923     assert (nparms == 3);
12924
12925     rsave = newBitVect(16);
12926     /* save DPTR if it needs to be saved */
12927     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12928             if (bitVectBitValue(ic->rMask,i))
12929                     rsave = bitVectSetBit(rsave,i);
12930     }
12931     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12932                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12933     savermask(rsave);
12934
12935     to = parms[0];
12936     from = parms[1];
12937     count = parms[2];
12938
12939     aopOp (from, ic->next, FALSE, FALSE);
12940
12941     /* get from into DPTR1 */
12942     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12943     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12944     if (options.model == MODEL_FLAT24) {
12945         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12946     }
12947
12948     freeAsmop (from, NULL, ic, FALSE);
12949     aopOp (to, ic, FALSE, FALSE);
12950     /* get "to" into DPTR */
12951     /* if the operand is already in dptr
12952        then we do nothing else we move the value to dptr */
12953     if (AOP_TYPE (to) != AOP_STR) {
12954         /* if already in DPTR then we need to push */
12955         if (AOP_TYPE(to) == AOP_DPTR) {
12956             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12957             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12958             if (options.model == MODEL_FLAT24)
12959                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12960             emitcode ("pop", "dph");
12961             emitcode ("pop", "dpl");
12962         } else {
12963             _startLazyDPSEvaluation ();
12964             /* if this is remateriazable */
12965             if (AOP_TYPE (to) == AOP_IMMD) {
12966                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12967             } else {                    /* we need to get it byte by byte */
12968                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12969                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12970                 if (options.model == MODEL_FLAT24) {
12971                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12972                 }
12973             }
12974             _endLazyDPSEvaluation ();
12975         }
12976     }
12977     freeAsmop (to, NULL, ic, FALSE);
12978
12979     _G.dptrInUse = _G.dptr1InUse = 1;
12980     aopOp (count, ic->next->next, FALSE,FALSE);
12981     lbl =newiTempLabel(NULL);
12982
12983     /* now for the actual copy */
12984     if (AOP_TYPE(count) == AOP_LIT &&
12985         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12986         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12987         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12988         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12989         emitLabel (lbl);
12990         emitcode ("movx", "a,@dptr");   /* read data from port */
12991         emitcode ("inc","dps");         /* switch to DPTR2 */
12992         emitcode ("movx", "@dptr,a");   /* save into location */
12993         emitcode ("inc", "dptr");       /* point to next area */
12994         emitcode ("dec","dps");         /* switch to DPTR */
12995         emitcode ("djnz","b,!tlabel",lbl->key+100);
12996         freeAsmop (count, NULL, ic, FALSE);
12997     } else {
12998         symbol *lbl1 = newiTempLabel(NULL);
12999
13000         emitcode (";"," Auto increment but no djnz");
13001         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13002         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13003         freeAsmop (count, NULL, ic, FALSE);
13004         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13005         emitLabel (lbl);
13006         emitcode ("movx", "a,@dptr");
13007         emitcode ("inc", "dptr");
13008         emitcode ("inc","dps");         /* switch to DPTR2 */
13009         emitcode ("movx", "@dptr,a");
13010         emitcode ("dec","dps");         /* switch to DPTR */
13011         emitcode ("mov","a,b");
13012         emitcode ("orl","a,_ap");
13013         emitcode ("jz","!tlabel",lbl1->key+100);
13014         emitcode ("mov","a,_ap");
13015         emitcode ("add","a,#!constbyte",0xFF);
13016         emitcode ("mov","_ap,a");
13017         emitcode ("mov","a,b");
13018         emitcode ("addc","a,#!constbyte",0xFF);
13019         emitcode ("mov","b,a");
13020         emitcode ("sjmp","!tlabel",lbl->key+100);
13021         emitLabel (lbl1);
13022     }
13023     emitcode ("mov", "dps,#0");
13024     _G.dptrInUse = _G.dptr1InUse = 0;
13025     unsavermask(rsave);
13026
13027 }
13028
13029 /*-----------------------------------------------------------------*/
13030 /* genSwapW - swap lower & high order bytes                        */
13031 /*-----------------------------------------------------------------*/
13032 static void genSwapW(iCode *ic, int nparms, operand **parms)
13033 {
13034     operand *dest;
13035     operand *src;
13036     assert (nparms==1);
13037
13038     src = parms[0];
13039     dest=IC_RESULT(ic);
13040
13041     assert(getSize(operandType(src))==2);
13042
13043     aopOp (src, ic, FALSE, FALSE);
13044     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13045     _G.accInUse++;
13046     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13047     _G.accInUse--;
13048     freeAsmop (src, NULL, ic, FALSE);
13049
13050     aopOp (dest,ic, FALSE, FALSE);
13051     aopPut(dest,"b",0);
13052     aopPut(dest,"a",1);
13053     freeAsmop (dest, NULL, ic, FALSE);
13054 }
13055
13056 /*-----------------------------------------------------------------*/
13057 /* genMemsetX - gencode for memSetX data                           */
13058 /*-----------------------------------------------------------------*/
13059 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13060 {
13061     operand *to , *val , *count;
13062     symbol *lbl;
13063     char *l;
13064     int i;
13065     bitVect *rsave;
13066
13067     /* we know it has to be 3 parameters */
13068     assert (nparms == 3);
13069
13070     to = parms[0];
13071     val = parms[1];
13072     count = parms[2];
13073
13074     /* save DPTR if it needs to be saved */
13075     rsave = newBitVect(16);
13076     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13077             if (bitVectBitValue(ic->rMask,i))
13078                     rsave = bitVectSetBit(rsave,i);
13079     }
13080     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13081                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13082     savermask(rsave);
13083
13084     aopOp (to, ic, FALSE, FALSE);
13085     /* get "to" into DPTR */
13086     /* if the operand is already in dptr
13087        then we do nothing else we move the value to dptr */
13088     if (AOP_TYPE (to) != AOP_STR) {
13089         /* if already in DPTR then we need to push */
13090         if (AOP_TYPE(to) == AOP_DPTR) {
13091             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13092             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13093             if (options.model == MODEL_FLAT24)
13094                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13095             emitcode ("pop", "dph");
13096             emitcode ("pop", "dpl");
13097         } else {
13098             _startLazyDPSEvaluation ();
13099             /* if this is remateriazable */
13100             if (AOP_TYPE (to) == AOP_IMMD) {
13101                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13102             } else {                    /* we need to get it byte by byte */
13103                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13104                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13105                 if (options.model == MODEL_FLAT24) {
13106                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13107                 }
13108             }
13109             _endLazyDPSEvaluation ();
13110         }
13111     }
13112     freeAsmop (to, NULL, ic, FALSE);
13113
13114     aopOp (val, ic->next->next, FALSE,FALSE);
13115     aopOp (count, ic->next->next, FALSE,FALSE);
13116     lbl =newiTempLabel(NULL);
13117     /* now for the actual copy */
13118     if (AOP_TYPE(count) == AOP_LIT &&
13119         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13120         l = aopGet(val, 0, FALSE, FALSE, NULL);
13121         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13122         MOVA(l);
13123         emitLabel (lbl);
13124         emitcode ("movx", "@dptr,a");
13125         emitcode ("inc", "dptr");
13126         emitcode ("djnz","b,!tlabel",lbl->key+100);
13127     } else {
13128         symbol *lbl1 = newiTempLabel(NULL);
13129
13130         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13131         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13132         emitLabel (lbl);
13133         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13134         emitcode ("movx", "@dptr,a");
13135         emitcode ("inc", "dptr");
13136         emitcode ("mov","a,b");
13137         emitcode ("orl","a,_ap");
13138         emitcode ("jz","!tlabel",lbl1->key+100);
13139         emitcode ("mov","a,_ap");
13140         emitcode ("add","a,#!constbyte",0xFF);
13141         emitcode ("mov","_ap,a");
13142         emitcode ("mov","a,b");
13143         emitcode ("addc","a,#!constbyte",0xFF);
13144         emitcode ("mov","b,a");
13145         emitcode ("sjmp","!tlabel",lbl->key+100);
13146         emitLabel (lbl1);
13147     }
13148     freeAsmop (count, NULL, ic, FALSE);
13149     unsavermask(rsave);
13150 }
13151
13152 /*-----------------------------------------------------------------*/
13153 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13154 /*-----------------------------------------------------------------*/
13155 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13156 {
13157         bitVect *rsave ;
13158         operand *pnum, *result;
13159         int i;
13160
13161         assert (nparms==1);
13162         /* save registers that need to be saved */
13163         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13164                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13165
13166         pnum = parms[0];
13167         aopOp (pnum, ic, FALSE, FALSE);
13168         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13169         freeAsmop (pnum, NULL, ic, FALSE);
13170         emitcode ("lcall","NatLib_LoadPrimitive");
13171         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13172         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13173             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13174                 for (i = (size-1) ; i >= 0 ; i-- ) {
13175                         emitcode ("push","a%s",javaRet[i]);
13176                 }
13177                 for (i=0; i < size ; i++ ) {
13178                         emitcode ("pop","a%s",
13179                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13180                 }
13181         } else {
13182                 for (i = 0 ; i < size ; i++ ) {
13183                         aopPut(result,javaRet[i],i);
13184                 }
13185         }
13186         freeAsmop (result, NULL, ic, FALSE);
13187         unsavermask(rsave);
13188 }
13189
13190 /*-----------------------------------------------------------------*/
13191 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13192 /*-----------------------------------------------------------------*/
13193 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13194 {
13195         bitVect *rsave ;
13196         operand *pnum, *result;
13197         int size = 3;
13198         int i;
13199
13200         assert (nparms==1);
13201         /* save registers that need to be saved */
13202         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13203                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13204
13205         pnum = parms[0];
13206         aopOp (pnum, ic, FALSE, FALSE);
13207         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13208         freeAsmop (pnum, NULL, ic, FALSE);
13209         emitcode ("lcall","NatLib_LoadPointer");
13210         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13211         if (AOP_TYPE(result)!=AOP_STR) {
13212                 for (i = 0 ; i < size ; i++ ) {
13213                         aopPut(result,fReturn[i],i);
13214                 }
13215         }
13216         freeAsmop (result, NULL, ic, FALSE);
13217         unsavermask(rsave);
13218 }
13219
13220 /*-----------------------------------------------------------------*/
13221 /* genNatLibInstallStateBlock -                                    */
13222 /*-----------------------------------------------------------------*/
13223 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13224                                        operand **parms, const char *name)
13225 {
13226         bitVect *rsave ;
13227         operand *psb, *handle;
13228         assert (nparms==2);
13229
13230         /* save registers that need to be saved */
13231         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13232                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13233         psb = parms[0];
13234         handle = parms[1];
13235
13236         /* put pointer to state block into DPTR1 */
13237         aopOp (psb, ic, FALSE, FALSE);
13238         if (AOP_TYPE (psb) == AOP_IMMD) {
13239                 emitcode ("mov","dps,#1");
13240                 emitcode ("mov", "dptr,%s",
13241                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13242                 emitcode ("mov","dps,#0");
13243         } else {
13244                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13245                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13246                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13247         }
13248         freeAsmop (psb, NULL, ic, FALSE);
13249
13250         /* put libraryID into DPTR */
13251         emitcode ("mov","dptr,#LibraryID");
13252
13253         /* put handle into r3:r2 */
13254         aopOp (handle, ic, FALSE, FALSE);
13255         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13256                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13257                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13258                 emitcode ("pop","ar3");
13259                 emitcode ("pop","ar2");
13260         } else {
13261                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13262                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13263         }
13264         freeAsmop (psb, NULL, ic, FALSE);
13265
13266         /* make the call */
13267         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13268
13269         /* put return value into place*/
13270         _G.accInUse++;
13271         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13272         _G.accInUse--;
13273         aopPut(IC_RESULT(ic),"a",0);
13274         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13275         unsavermask(rsave);
13276 }
13277
13278 /*-----------------------------------------------------------------*/
13279 /* genNatLibRemoveStateBlock -                                     */
13280 /*-----------------------------------------------------------------*/
13281 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13282 {
13283         bitVect *rsave ;
13284
13285         assert(nparms==0);
13286
13287         /* save registers that need to be saved */
13288         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13289                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13290
13291         /* put libraryID into DPTR */
13292         emitcode ("mov","dptr,#LibraryID");
13293         /* make the call */
13294         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13295         unsavermask(rsave);
13296 }
13297
13298 /*-----------------------------------------------------------------*/
13299 /* genNatLibGetStateBlock -                                        */
13300 /*-----------------------------------------------------------------*/
13301 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13302                                    operand **parms,const char *name)
13303 {
13304         bitVect *rsave ;
13305         symbol *lbl = newiTempLabel(NULL);
13306
13307         assert(nparms==0);
13308         /* save registers that need to be saved */
13309         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13310                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13311
13312         /* put libraryID into DPTR */
13313         emitcode ("mov","dptr,#LibraryID");
13314         /* make the call */
13315         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13316         emitcode ("jnz","!tlabel",lbl->key+100);
13317
13318         /* put return value into place */
13319         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13320         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13321                 emitcode ("push","ar3");
13322                 emitcode ("push","ar2");
13323                 emitcode ("pop","%s",
13324                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13325                 emitcode ("pop","%s",
13326                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13327         } else {
13328                 aopPut(IC_RESULT(ic),"r2",0);
13329                 aopPut(IC_RESULT(ic),"r3",1);
13330         }
13331         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13332         emitLabel (lbl);
13333         unsavermask(rsave);
13334 }
13335
13336 /*-----------------------------------------------------------------*/
13337 /* genMMMalloc -                                                   */
13338 /*-----------------------------------------------------------------*/
13339 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13340                          int size, const char *name)
13341 {
13342         bitVect *rsave ;
13343         operand *bsize;
13344         symbol *rsym;
13345         symbol *lbl = newiTempLabel(NULL);
13346
13347         assert (nparms == 1);
13348         /* save registers that need to be saved */
13349         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13350                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13351
13352         bsize=parms[0];
13353         aopOp (bsize,ic,FALSE,FALSE);
13354
13355         /* put the size in R4-R2 */
13356         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13357                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13358                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13359                 if (size==3) {
13360                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13361                         emitcode("pop","ar4");
13362                 }
13363                 emitcode("pop","ar3");
13364                 emitcode("pop","ar2");
13365         } else {
13366                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13367                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13368                 if (size==3) {
13369                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13370                 }
13371         }
13372         freeAsmop (bsize, NULL, ic, FALSE);
13373
13374         /* make the call */
13375         emitcode ("lcall","MM_%s",name);
13376         emitcode ("jz","!tlabel",lbl->key+100);
13377         emitcode ("mov","r2,#!constbyte",0xff);
13378         emitcode ("mov","r3,#!constbyte",0xff);
13379         emitLabel (lbl);
13380         /* we don't care about the pointer : we just save the handle */
13381         rsym = OP_SYMBOL(IC_RESULT(ic));
13382         if (rsym->liveFrom != rsym->liveTo) {
13383                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13384                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13385                         emitcode ("push","ar3");
13386                         emitcode ("push","ar2");
13387                         emitcode ("pop","%s",
13388                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13389                         emitcode ("pop","%s",
13390                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13391                 } else {
13392                         aopPut(IC_RESULT(ic),"r2",0);
13393                         aopPut(IC_RESULT(ic),"r3",1);
13394                 }
13395                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13396         }
13397         unsavermask(rsave);
13398 }
13399
13400 /*-----------------------------------------------------------------*/
13401 /* genMMDeref -                                                    */
13402 /*-----------------------------------------------------------------*/
13403 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13404 {
13405         bitVect *rsave ;
13406         operand *handle;
13407
13408         assert (nparms == 1);
13409         /* save registers that need to be saved */
13410         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13411                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13412
13413         handle=parms[0];
13414         aopOp (handle,ic,FALSE,FALSE);
13415
13416         /* put the size in R4-R2 */
13417         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13418                 emitcode("push","%s",
13419                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13420                 emitcode("push","%s",
13421                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13422                 emitcode("pop","ar3");
13423                 emitcode("pop","ar2");
13424         } else {
13425                 emitcode ("mov","r2,%s",
13426                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13427                 emitcode ("mov","r3,%s",
13428                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13429         }
13430         freeAsmop (handle, NULL, ic, FALSE);
13431
13432         /* make the call */
13433         emitcode ("lcall","MM_Deref");
13434
13435         {
13436                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13437                 if (rsym->liveFrom != rsym->liveTo) {
13438                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13439                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13440                             _startLazyDPSEvaluation ();
13441
13442                             aopPut(IC_RESULT(ic),"dpl",0);
13443                             aopPut(IC_RESULT(ic),"dph",1);
13444                             aopPut(IC_RESULT(ic),"dpx",2);
13445
13446                             _endLazyDPSEvaluation ();
13447
13448                         }
13449                 }
13450         }
13451         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13452         unsavermask(rsave);
13453 }
13454
13455 /*-----------------------------------------------------------------*/
13456 /* genMMUnrestrictedPersist -                                      */
13457 /*-----------------------------------------------------------------*/
13458 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13459 {
13460         bitVect *rsave ;
13461         operand *handle;
13462
13463         assert (nparms == 1);
13464         /* save registers that need to be saved */
13465         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13466                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13467
13468         handle=parms[0];
13469         aopOp (handle,ic,FALSE,FALSE);
13470
13471         /* put the size in R3-R2 */
13472         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13473                 emitcode("push","%s",
13474                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13475                 emitcode("push","%s",
13476                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13477                 emitcode("pop","ar3");
13478                 emitcode("pop","ar2");
13479         } else {
13480                 emitcode ("mov","r2,%s",
13481                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13482                 emitcode ("mov","r3,%s",
13483                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13484         }
13485         freeAsmop (handle, NULL, ic, FALSE);
13486
13487         /* make the call */
13488         emitcode ("lcall","MM_UnrestrictedPersist");
13489
13490         {
13491                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13492                 if (rsym->liveFrom != rsym->liveTo) {
13493                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13494                         aopPut(IC_RESULT(ic),"a",0);
13495                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13496                 }
13497         }
13498         unsavermask(rsave);
13499 }
13500
13501 /*-----------------------------------------------------------------*/
13502 /* genSystemExecJavaProcess -                                      */
13503 /*-----------------------------------------------------------------*/
13504 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13505 {
13506         bitVect *rsave ;
13507         operand *handle, *pp;
13508
13509         assert (nparms==2);
13510         /* save registers that need to be saved */
13511         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13512                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13513
13514         pp = parms[0];
13515         handle = parms[1];
13516
13517         /* put the handle in R3-R2 */
13518         aopOp (handle,ic,FALSE,FALSE);
13519         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13520                 emitcode("push","%s",
13521                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13522                 emitcode("push","%s",
13523                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13524                 emitcode("pop","ar3");
13525                 emitcode("pop","ar2");
13526         } else {
13527                 emitcode ("mov","r2,%s",
13528                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13529                 emitcode ("mov","r3,%s",
13530                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13531         }
13532         freeAsmop (handle, NULL, ic, FALSE);
13533
13534         /* put pointer in DPTR */
13535         aopOp (pp,ic,FALSE,FALSE);
13536         if (AOP_TYPE(pp) == AOP_IMMD) {
13537                 emitcode ("mov", "dptr,%s",
13538                           aopGet (pp, 0, TRUE, FALSE, NULL));
13539         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13540                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13541                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13542                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13543         }
13544         freeAsmop (handle, NULL, ic, FALSE);
13545
13546         /* make the call */
13547         emitcode ("lcall","System_ExecJavaProcess");
13548
13549         /* put result in place */
13550         {
13551                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13552                 if (rsym->liveFrom != rsym->liveTo) {
13553                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13554                         aopPut(IC_RESULT(ic),"a",0);
13555                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13556                 }
13557         }
13558
13559         unsavermask(rsave);
13560 }
13561
13562 /*-----------------------------------------------------------------*/
13563 /* genSystemRTCRegisters -                                         */
13564 /*-----------------------------------------------------------------*/
13565 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13566                                   char *name)
13567 {
13568         bitVect *rsave ;
13569         operand *pp;
13570
13571         assert (nparms==1);
13572         /* save registers that need to be saved */
13573         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13574                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13575
13576         pp=parms[0];
13577         /* put pointer in DPTR */
13578         aopOp (pp,ic,FALSE,FALSE);
13579         if (AOP_TYPE (pp) == AOP_IMMD) {
13580                 emitcode ("mov","dps,#1");
13581                 emitcode ("mov", "dptr,%s",
13582                           aopGet (pp, 0, TRUE, FALSE, NULL));
13583                 emitcode ("mov","dps,#0");
13584         } else {
13585                 emitcode ("mov","dpl1,%s",
13586                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13587                 emitcode ("mov","dph1,%s",
13588                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13589                 emitcode ("mov","dpx1,%s",
13590                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13591         }
13592         freeAsmop (pp, NULL, ic, FALSE);
13593
13594         /* make the call */
13595         emitcode ("lcall","System_%sRTCRegisters",name);
13596
13597         unsavermask(rsave);
13598 }
13599
13600 /*-----------------------------------------------------------------*/
13601 /* genSystemThreadSleep -                                          */
13602 /*-----------------------------------------------------------------*/
13603 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13604 {
13605         bitVect *rsave ;
13606         operand *to, *s;
13607
13608         assert (nparms==1);
13609         /* save registers that need to be saved */
13610         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13611                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13612
13613         to = parms[0];
13614         aopOp(to,ic,FALSE,FALSE);
13615         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13616             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13617                 emitcode ("push","%s",
13618                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13619                 emitcode ("push","%s",
13620                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13621                 emitcode ("push","%s",
13622                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13623                 emitcode ("push","%s",
13624                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13625                 emitcode ("pop","ar3");
13626                 emitcode ("pop","ar2");
13627                 emitcode ("pop","ar1");
13628                 emitcode ("pop","ar0");
13629         } else {
13630                 emitcode ("mov","r0,%s",
13631                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13632                 emitcode ("mov","r1,%s",
13633                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13634                 emitcode ("mov","r2,%s",
13635                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13636                 emitcode ("mov","r3,%s",
13637                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13638         }
13639         freeAsmop (to, NULL, ic, FALSE);
13640
13641         /* suspend in acc */
13642         s = parms[1];
13643         aopOp(s,ic,FALSE,FALSE);
13644         emitcode ("mov","a,%s",
13645                   aopGet(s,0,FALSE,TRUE,NULL));
13646         freeAsmop (s, NULL, ic, FALSE);
13647
13648         /* make the call */
13649         emitcode ("lcall","System_%s",name);
13650
13651         unsavermask(rsave);
13652 }
13653
13654 /*-----------------------------------------------------------------*/
13655 /* genSystemThreadResume -                                         */
13656 /*-----------------------------------------------------------------*/
13657 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13658 {
13659         bitVect *rsave ;
13660         operand *tid,*pid;
13661
13662         assert (nparms==2);
13663         /* save registers that need to be saved */
13664         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13665                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13666
13667         tid = parms[0];
13668         pid = parms[1];
13669
13670         /* PID in R0 */
13671         aopOp(pid,ic,FALSE,FALSE);
13672         emitcode ("mov","r0,%s",
13673                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13674         freeAsmop (pid, NULL, ic, FALSE);
13675
13676         /* tid into ACC */
13677         aopOp(tid,ic,FALSE,FALSE);
13678         emitcode ("mov","a,%s",
13679                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13680         freeAsmop (tid, NULL, ic, FALSE);
13681
13682         emitcode ("lcall","System_ThreadResume");
13683
13684         /* put result into place */
13685         {
13686                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13687                 if (rsym->liveFrom != rsym->liveTo) {
13688                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13689                         aopPut(IC_RESULT(ic),"a",0);
13690                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13691                 }
13692         }
13693         unsavermask(rsave);
13694 }
13695
13696 /*-----------------------------------------------------------------*/
13697 /* genSystemProcessResume -                                        */
13698 /*-----------------------------------------------------------------*/
13699 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13700 {
13701         bitVect *rsave ;
13702         operand *pid;
13703
13704         assert (nparms==1);
13705         /* save registers that need to be saved */
13706         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13707                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13708
13709         pid = parms[0];
13710
13711         /* pid into ACC */
13712         aopOp(pid,ic,FALSE,FALSE);
13713         emitcode ("mov","a,%s",
13714                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13715         freeAsmop (pid, NULL, ic, FALSE);
13716
13717         emitcode ("lcall","System_ProcessResume");
13718
13719         unsavermask(rsave);
13720 }
13721
13722 /*-----------------------------------------------------------------*/
13723 /* genSystem -                                                     */
13724 /*-----------------------------------------------------------------*/
13725 static void genSystem (iCode *ic,int nparms,char *name)
13726 {
13727         assert(nparms == 0);
13728
13729         emitcode ("lcall","System_%s",name);
13730 }
13731
13732 /*-----------------------------------------------------------------*/
13733 /* genSystemPoll -                                                  */
13734 /*-----------------------------------------------------------------*/
13735 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13736 {
13737         bitVect *rsave ;
13738         operand *fp;
13739
13740         assert (nparms==1);
13741         /* save registers that need to be saved */
13742         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13743                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13744
13745         fp = parms[0];
13746         aopOp (fp,ic,FALSE,FALSE);
13747         if (AOP_TYPE (fp) == AOP_IMMD) {
13748                 emitcode ("mov", "dptr,%s",
13749                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13750         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13751                 emitcode ("mov","dpl,%s",
13752                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13753                 emitcode ("mov","dph,%s",
13754                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13755                 emitcode ("mov","dpx,%s",
13756                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13757         }
13758         freeAsmop (fp, NULL, ic, FALSE);
13759
13760         emitcode ("lcall","System_%sPoll",name);
13761
13762         /* put result into place */
13763         {
13764                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13765                 if (rsym->liveFrom != rsym->liveTo) {
13766                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13767                         aopPut(IC_RESULT(ic),"a",0);
13768                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13769                 }
13770         }
13771         unsavermask(rsave);
13772 }
13773
13774 /*-----------------------------------------------------------------*/
13775 /* genSystemGetCurrentID -                                         */
13776 /*-----------------------------------------------------------------*/
13777 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13778 {
13779         assert (nparms==0);
13780
13781         emitcode ("lcall","System_GetCurrent%sId",name);
13782         /* put result into place */
13783         {
13784                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13785                 if (rsym->liveFrom != rsym->liveTo) {
13786                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13787                         aopPut(IC_RESULT(ic),"a",0);
13788                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13789                 }
13790         }
13791 }
13792
13793 /*-----------------------------------------------------------------*/
13794 /* genDjnz - generate decrement & jump if not zero instrucion      */
13795 /*-----------------------------------------------------------------*/
13796 static int
13797 genDjnz (iCode * ic, iCode * ifx)
13798 {
13799   symbol *lbl, *lbl1;
13800   if (!ifx)
13801     return 0;
13802
13803   /* if the if condition has a false label
13804      then we cannot save */
13805   if (IC_FALSE (ifx))
13806     return 0;
13807
13808   /* if the minus is not of the form a = a - 1 */
13809   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13810       !IS_OP_LITERAL (IC_RIGHT (ic)))
13811     return 0;
13812
13813   if (operandLitValue (IC_RIGHT (ic)) != 1)
13814     return 0;
13815
13816   /* if the size of this greater than one then no
13817      saving */
13818   if (getSize (operandType (IC_RESULT (ic))) > 1)
13819     return 0;
13820
13821   /* otherwise we can save BIG */
13822
13823   D (emitcode (";", "genDjnz"));
13824
13825   lbl = newiTempLabel (NULL);
13826   lbl1 = newiTempLabel (NULL);
13827
13828   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13829
13830   if (AOP_NEEDSACC(IC_RESULT(ic)))
13831   {
13832       /* If the result is accessed indirectly via
13833        * the accumulator, we must explicitly write
13834        * it back after the decrement.
13835        */
13836       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13837
13838       if (strcmp(rByte, "a"))
13839       {
13840            /* Something is hopelessly wrong */
13841            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13842                    __FILE__, __LINE__);
13843            /* We can just give up; the generated code will be inefficient,
13844             * but what the hey.
13845             */
13846            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13847            return 0;
13848       }
13849       emitcode ("dec", "%s", rByte);
13850       aopPut (IC_RESULT (ic), rByte, 0);
13851       emitcode ("jnz", "!tlabel", lbl->key + 100);
13852   }
13853   else if (IS_AOP_PREG (IC_RESULT (ic)))
13854     {
13855       emitcode ("dec", "%s",
13856                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13857       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13858       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13859       ifx->generated = 1;
13860       emitcode ("jnz", "!tlabel", lbl->key + 100);
13861     }
13862   else
13863     {
13864       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13865                 lbl->key + 100);
13866     }
13867   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13868   emitLabel (lbl);
13869   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13870   emitLabel (lbl1);
13871
13872   if (!ifx->generated)
13873       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13874   ifx->generated = 1;
13875   return 1;
13876 }
13877
13878 /*-----------------------------------------------------------------*/
13879 /* genReceive - generate code for a receive iCode                  */
13880 /*-----------------------------------------------------------------*/
13881 static void
13882 genReceive (iCode * ic)
13883 {
13884     int size = getSize (operandType (IC_RESULT (ic)));
13885     int offset = 0;
13886     int rb1off ;
13887
13888     D (emitcode (";", "genReceive"));
13889
13890     if (ic->argreg == 1)
13891     {
13892         /* first parameter */
13893         if (AOP_IS_STR(IC_RESULT(ic)))
13894         {
13895             /* Nothing to do: it's already in the proper place. */
13896             return;
13897         }
13898         else
13899         {
13900             bool useDp2;
13901
13902             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13903                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13904                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13905
13906             _G.accInUse++;
13907             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13908             _G.accInUse--;
13909
13910             /* Sanity checking... */
13911             if (AOP_USESDPTR(IC_RESULT(ic)))
13912             {
13913                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13914                         "genReceive got unexpected DPTR.");
13915             }
13916             assignResultValue (IC_RESULT (ic), NULL);
13917         }
13918     }
13919     else if (ic->argreg > 12)
13920     { /* bit parameters */
13921       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13922         {
13923           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13924           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13925           outBitC(IC_RESULT (ic));
13926         }
13927     }
13928     else
13929     {
13930         /* second receive onwards */
13931         /* this gets a little tricky since unused receives will be
13932          eliminated, we have saved the reg in the type field . and
13933          we use that to figure out which register to use */
13934         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13935         rb1off = ic->argreg;
13936         while (size--)
13937         {
13938             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13939         }
13940     }
13941     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13942 }
13943
13944 /*-----------------------------------------------------------------*/
13945 /* genDummyRead - generate code for dummy read of volatiles        */
13946 /*-----------------------------------------------------------------*/
13947 static void
13948 genDummyRead (iCode * ic)
13949 {
13950   operand *op;
13951   int size, offset;
13952
13953   D (emitcode(";", "genDummyRead"));
13954
13955   op = IC_RIGHT (ic);
13956   if (op && IS_SYMOP (op))
13957     {
13958       aopOp (op, ic, FALSE, FALSE);
13959
13960       /* if the result is a bit */
13961       if (AOP_TYPE (op) == AOP_CRY)
13962         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13963       else
13964         {
13965           /* bit variables done */
13966           /* general case */
13967           size = AOP_SIZE (op);
13968           offset = 0;
13969           while (size--)
13970           {
13971             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13972             offset++;
13973           }
13974         }
13975
13976       freeAsmop (op, NULL, ic, TRUE);
13977     }
13978
13979   op = IC_LEFT (ic);
13980   if (op && IS_SYMOP (op))
13981     {
13982       aopOp (op, ic, FALSE, FALSE);
13983
13984       /* if the result is a bit */
13985       if (AOP_TYPE (op) == AOP_CRY)
13986         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13987       else
13988         {
13989           /* bit variables done */
13990           /* general case */
13991           size = AOP_SIZE (op);
13992           offset = 0;
13993           while (size--)
13994           {
13995             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13996             offset++;
13997           }
13998         }
13999
14000       freeAsmop (op, NULL, ic, TRUE);
14001     }
14002 }
14003
14004 /*-----------------------------------------------------------------*/
14005 /* genCritical - generate code for start of a critical sequence    */
14006 /*-----------------------------------------------------------------*/
14007 static void
14008 genCritical (iCode *ic)
14009 {
14010   symbol *tlbl = newiTempLabel (NULL);
14011
14012   D (emitcode(";", "genCritical"));
14013
14014   if (IC_RESULT (ic))
14015     {
14016       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14017       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14018       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14019       aopPut (IC_RESULT (ic), zero, 0);
14020       emitLabel (tlbl);
14021       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14022     }
14023   else
14024     {
14025       emitcode ("setb", "c");
14026       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14027       emitcode ("clr", "c");
14028       emitLabel (tlbl);
14029       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14030     }
14031 }
14032
14033 /*-----------------------------------------------------------------*/
14034 /* genEndCritical - generate code for end of a critical sequence   */
14035 /*-----------------------------------------------------------------*/
14036 static void
14037 genEndCritical (iCode *ic)
14038 {
14039   D(emitcode(";     genEndCritical",""));
14040
14041   if (IC_RIGHT (ic))
14042     {
14043       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14044       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14045         {
14046           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14047           emitcode ("mov", "ea,c");
14048         }
14049       else
14050         {
14051           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14052           emitcode ("rrc", "a");
14053           emitcode ("mov", "ea,c");
14054         }
14055       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14056     }
14057   else
14058     {
14059       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14060       emitcode ("mov", "ea,c");
14061     }
14062 }
14063
14064
14065
14066 /*-----------------------------------------------------------------*/
14067 /* genBuiltIn - calls the appropriate function to  generating code */
14068 /* for a built in function                                         */
14069 /*-----------------------------------------------------------------*/
14070 static void genBuiltIn (iCode *ic)
14071 {
14072         operand *bi_parms[MAX_BUILTIN_ARGS];
14073         int nbi_parms;
14074         iCode *bi_iCode;
14075         symbol *bif;
14076
14077         /* get all the arguments for a built in function */
14078         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14079
14080         /* which function is it */
14081         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14082         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14083                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14084         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14085                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14086         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14087                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14088         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14089                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14090         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14091                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14092         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14093                 genInp(bi_iCode,nbi_parms,bi_parms);
14094         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14095                 genOutp(bi_iCode,nbi_parms,bi_parms);
14096         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14097                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14098                 /* JavaNative builtIns */
14099         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14100                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14101         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14102                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14103         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14104                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14105         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14106                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14107         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14108                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14109         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14110                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14111         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14112                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14113         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14114                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14115         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14116                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14117         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14118                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14119         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14120                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14121         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14122                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14123         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14124                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14125         } else if (strcmp(bif->name,"MM_Free")==0) {
14126                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14127         } else if (strcmp(bif->name,"MM_Deref")==0) {
14128                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14129         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14130                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14131         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14132                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14133         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14134                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14135         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14136                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14137         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14138                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14139         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14140                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14141         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14142                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14143         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14144                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14145         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14146                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14147         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14148                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14149         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14150                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14151         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14152                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14153         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14154                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14155         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14156                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14157         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14158                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14159         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14160                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14161         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14162                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14163         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14164                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14165         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14166                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14167         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14168                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14169         } else {
14170                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14171                 return ;
14172         }
14173         return ;
14174 }
14175
14176 /*-----------------------------------------------------------------*/
14177 /* gen390Code - generate code for Dallas 390 based controllers     */
14178 /*-----------------------------------------------------------------*/
14179 void
14180 gen390Code (iCode * lic)
14181 {
14182   iCode *ic;
14183   int cln = 0;
14184
14185   _G.currentFunc = NULL;
14186   lineHead = lineCurr = NULL;
14187   dptrn[1][0] = "dpl1";
14188   dptrn[1][1] = "dph1";
14189   dptrn[1][2] = "dpx1";
14190
14191   if (options.model == MODEL_FLAT24) {
14192     fReturnSizeDS390 = 5;
14193     fReturn = fReturn24;
14194   } else {
14195     fReturnSizeDS390 = 4;
14196     fReturn = fReturn16;
14197     options.stack10bit=0;
14198   }
14199 #if 1
14200   /* print the allocation information */
14201   if (allocInfo && currFunc)
14202     printAllocInfo (currFunc, codeOutFile);
14203 #endif
14204   /* if debug information required */
14205   if (options.debug && currFunc)
14206     {
14207       debugFile->writeFunction (currFunc, lic);
14208     }
14209   /* stack pointer name */
14210   if (options.useXstack)
14211     spname = "_spx";
14212   else
14213     spname = "sp";
14214
14215
14216   for (ic = lic; ic; ic = ic->next)
14217     {
14218       _G.current_iCode = ic;
14219
14220       if (ic->lineno && cln != ic->lineno)
14221         {
14222           if (options.debug)
14223             {
14224               debugFile->writeCLine (ic);
14225             }
14226           if (!options.noCcodeInAsm) {
14227             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14228                       printCLine(ic->filename, ic->lineno));
14229           }
14230           cln = ic->lineno;
14231         }
14232       if (options.iCodeInAsm) {
14233         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
14234       }
14235       /* if the result is marked as
14236          spilt and rematerializable or code for
14237          this has already been generated then
14238          do nothing */
14239       if (resultRemat (ic) || ic->generated)
14240         continue;
14241
14242       /* depending on the operation */
14243       switch (ic->op)
14244         {
14245         case '!':
14246           genNot (ic);
14247           break;
14248
14249         case '~':
14250           genCpl (ic);
14251           break;
14252
14253         case UNARYMINUS:
14254           genUminus (ic);
14255           break;
14256
14257         case IPUSH:
14258           genIpush (ic);
14259           break;
14260
14261         case IPOP:
14262           /* IPOP happens only when trying to restore a
14263              spilt live range, if there is an ifx statement
14264              following this pop then the if statement might
14265              be using some of the registers being popped which
14266              would destory the contents of the register so
14267              we need to check for this condition and handle it */
14268           if (ic->next &&
14269               ic->next->op == IFX &&
14270               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14271             genIfx (ic->next, ic);
14272           else
14273             genIpop (ic);
14274           break;
14275
14276         case CALL:
14277           genCall (ic);
14278           break;
14279
14280         case PCALL:
14281           genPcall (ic);
14282           break;
14283
14284         case FUNCTION:
14285           genFunction (ic);
14286           break;
14287
14288         case ENDFUNCTION:
14289           genEndFunction (ic);
14290           break;
14291
14292         case RETURN:
14293           genRet (ic);
14294           break;
14295
14296         case LABEL:
14297           genLabel (ic);
14298           break;
14299
14300         case GOTO:
14301           genGoto (ic);
14302           break;
14303
14304         case '+':
14305           genPlus (ic);
14306           break;
14307
14308         case '-':
14309           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14310             genMinus (ic);
14311           break;
14312
14313         case '*':
14314           genMult (ic);
14315           break;
14316
14317         case '/':
14318           genDiv (ic);
14319           break;
14320
14321         case '%':
14322           genMod (ic);
14323           break;
14324
14325         case '>':
14326           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14327           break;
14328
14329         case '<':
14330           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14331           break;
14332
14333         case LE_OP:
14334         case GE_OP:
14335         case NE_OP:
14336
14337           /* note these two are xlated by algebraic equivalence
14338              during parsing SDCC.y */
14339           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14340                   "got '>=' or '<=' shouldn't have come here");
14341           break;
14342
14343         case EQ_OP:
14344           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14345           break;
14346
14347         case AND_OP:
14348           genAndOp (ic);
14349           break;
14350
14351         case OR_OP:
14352           genOrOp (ic);
14353           break;
14354
14355         case '^':
14356           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14357           break;
14358
14359         case '|':
14360           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14361           break;
14362
14363         case BITWISEAND:
14364           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14365           break;
14366
14367         case INLINEASM:
14368           genInline (ic);
14369           break;
14370
14371         case RRC:
14372           genRRC (ic);
14373           break;
14374
14375         case RLC:
14376           genRLC (ic);
14377           break;
14378
14379         case GETHBIT:
14380           genGetHbit (ic);
14381           break;
14382
14383         case LEFT_OP:
14384           genLeftShift (ic);
14385           break;
14386
14387         case RIGHT_OP:
14388           genRightShift (ic);
14389           break;
14390
14391         case GET_VALUE_AT_ADDRESS:
14392           genPointerGet (ic,
14393                          hasInc (IC_LEFT (ic), ic,
14394                                  getSize (operandType (IC_RESULT (ic)))));
14395           break;
14396
14397         case '=':
14398           if (POINTER_SET (ic))
14399             genPointerSet (ic,
14400                            hasInc (IC_RESULT (ic), ic,
14401                                    getSize (operandType (IC_RIGHT (ic)))));
14402           else
14403             genAssign (ic);
14404           break;
14405
14406         case IFX:
14407           genIfx (ic, NULL);
14408           break;
14409
14410         case ADDRESS_OF:
14411           genAddrOf (ic);
14412           break;
14413
14414         case JUMPTABLE:
14415           genJumpTab (ic);
14416           break;
14417
14418         case CAST:
14419           genCast (ic);
14420           break;
14421
14422         case RECEIVE:
14423           genReceive (ic);
14424           break;
14425
14426         case SEND:
14427           if (ic->builtinSEND)
14428             genBuiltIn(ic);
14429           else
14430             addSet (&_G.sendSet, ic);
14431           break;
14432
14433         case DUMMY_READ_VOLATILE:
14434           genDummyRead (ic);
14435           break;
14436
14437         case CRITICAL:
14438           genCritical (ic);
14439           break;
14440
14441         case ENDCRITICAL:
14442           genEndCritical (ic);
14443           break;
14444
14445         case SWAP:
14446           genSwap (ic);
14447           break;
14448
14449 #if 0 // obsolete, and buggy for != xdata
14450         case ARRAYINIT:
14451             genArrayInit(ic);
14452             break;
14453 #endif
14454
14455         default:
14456           ic = ic;
14457         }
14458     }
14459
14460
14461   /* now we are ready to call the
14462      peep hole optimizer */
14463   if (!options.nopeep)
14464     peepHole (&lineHead);
14465
14466   /* now do the actual printing */
14467   printLine (lineHead, codeOutFile);
14468   return;
14469 }