* src/avr/gen.c (aopop),
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for DS80C390
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7   DS390 adaptation by Kevin Vigor <kevin@vigor.nu>
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23   In other words, you are welcome to use, share and improve this program.
24   You are forbidden to forbid anyone else to use, share and improve
25   what you give them.   Help stamp out software-hoarding!
26 -------------------------------------------------------------------------*/
27
28 //#define D(x)
29 #define D(x) x
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "SDCCglobl.h"
36 #include "newalloc.h"
37
38 #include "common.h"
39 #include "main.h"
40 #include "ralloc.h"
41 #include "gen.h"
42
43 #define BETTER_LITERAL_SHIFT
44
45 char *aopLiteral (value * val, int offset);
46 extern int allocInfo;
47
48 /* this is the down and dirty file with all kinds of
49    kludgy & hacky stuff. This is what it is all about
50    CODE GENERATION for a specific MCU . some of the
51    routines may be reusable, will have to see */
52
53 static char *zero = "#0";
54 static char *one = "#1";
55 static char *spname;
56
57 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
58 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
59
60 unsigned fReturnSizeDS390 = 5;
61 static char *fReturn24[] =
62 {"dpl", "dph", "dpx", "b", "a"};
63 static char *fReturn16[] =
64 {"dpl", "dph", "b", "a"};
65 static char **fReturn = fReturn24;
66 static char *accUse[] =
67 {"a", "b"};
68 static char *dptrn[2][3];
69 static char *javaRet[] = { "r0","r1","r2","r3"};
70 static short rbank = -1;
71
72 #define REG_WITH_INDEX   ds390_regWithIdx
73
74 #define AOP(op) op->aop
75 #define AOP_TYPE(op) AOP(op)->type
76 #define AOP_SIZE(op) AOP(op)->size
77 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
78                        AOP_TYPE(x) == AOP_R0))
79
80 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
81                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
82                          AOP(x)->paged))
83
84 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
85                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
86                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
87 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
88 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
89 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
90
91 // The following two macros can be used even if the aop has not yet been aopOp'd.
92 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
93 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
94
95 /* Workaround for DS80C390 bug: div ab may return bogus results
96  * if A is accessed in instruction immediately before the div.
97  *
98  * Will be fixed in B4 rev of processor, Dallas claims.
99  */
100
101 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
102     if (!AOP_NEEDSACC(RIGHT))         \
103     {               \
104       /* We can load A first, then B, since     \
105        * B (the RIGHT operand) won't clobber A,   \
106        * thus avoiding touching A right before the div. \
107        */             \
108       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
109       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
110       MOVA(L);            \
111       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
112       MOVB(L); \
113     }               \
114     else              \
115     {               \
116       /* Just stuff in a nop after loading A. */    \
117       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
118       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
119       MOVA(L);            \
120       emitcode("nop", "; workaround for DS80C390 div bug.");  \
121     }
122
123 #define R0INB   _G.bu.bs.r0InB
124 #define R1INB   _G.bu.bs.r1InB
125 #define OPINB   _G.bu.bs.OpInB
126 #define BINUSE  _G.bu.BInUse
127
128 static struct
129   {
130     short r0Pushed;
131     short r1Pushed;
132     union
133       {
134         struct
135           {
136             short r0InB : 2;//2 so we can see it overflow
137             short r1InB : 2;//2 so we can see it overflow
138             short OpInB : 2;//2 so we can see it overflow
139           } bs;
140         short BInUse;
141       } bu;
142     short accInUse;
143     short inLine;
144     short debugLine;
145     short nRegsSaved;
146     short dptrInUse;
147     short dptr1InUse;
148     set *sendSet;
149     iCode *current_iCode;
150     symbol *currentFunc;
151   }
152 _G;
153
154 static char *rb1regs[] = {
155     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
156     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
157 };
158
159 static void saveRBank (int, iCode *, bool);
160
161 #define RESULTONSTACK(x) \
162                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
163                          IC_RESULT(x)->aop->type == AOP_STK )
164
165 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
166 #define MOVB(x)  movb(x)
167
168 #define CLRC    emitcode("clr","c")
169 #define SETC    emitcode("setb","c")
170
171 // A scratch register which will be used to hold
172 // result bytes from operands in far space via DPTR2.
173 #define DP2_RESULT_REG  "_ap"
174
175 static lineNode *lineHead = NULL;
176 static lineNode *lineCurr = NULL;
177
178 static unsigned char SLMask[] =
179 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
180  0xE0, 0xC0, 0x80, 0x00};
181 static unsigned char SRMask[] =
182 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
183  0x07, 0x03, 0x01, 0x00};
184
185 #define LSB     0
186 #define MSB16   1
187 #define MSB24   2
188 #define MSB32   3
189 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
190                                 symbol *lbl = newiTempLabel(NULL);              \
191                                 emitcode ("setb","F1");                         \
192                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
193                                 emitcode ("clr","F1");                          \
194                                 emitcode ("","!tlabeldef",lbl->key+100);        \
195                         }}
196 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
197                                 emitcode ("mov","EA,F1");                       \
198                         }}
199
200 static int _currentDPS;         /* Current processor DPS. */
201 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
202 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
203
204 /*-----------------------------------------------------------------*/
205 /* emitcode - writes the code into a file : for now it is simple    */
206 /*-----------------------------------------------------------------*/
207 static void
208 emitcode (char *inst, const char *fmt,...)
209 {
210   va_list ap;
211   char lb[INITIAL_INLINEASM];
212   char *lbp = lb;
213
214   va_start (ap, fmt);
215
216   if (inst && *inst)
217     {
218       if (fmt && *fmt)
219         {
220           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
221         }
222       else
223         {
224           SNPRINTF (lb, sizeof(lb), "%s", inst);
225         }
226
227       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
228     }
229   else
230     {
231       tvsprintf (lb, sizeof(lb), fmt, ap);
232     }
233
234   while (isspace ((unsigned char)*lbp))
235     {
236       lbp++;
237     }
238
239   if (lbp && *lbp)
240     {
241       lineCurr = (lineCurr ?
242                   connectLine (lineCurr, newLineNode (lb)) :
243                   (lineHead = newLineNode (lb)));
244     }
245
246   lineCurr->isInline = _G.inLine;
247   lineCurr->isDebug = _G.debugLine;
248   lineCurr->ic = _G.current_iCode;
249   lineCurr->aln = ds390newAsmLineNode(_currentDPS);
250   va_end (ap);
251 }
252
253 /*-----------------------------------------------------------------*/
254 /* ds390_emitDebuggerSymbol - associate the current code location  */
255 /*   with a debugger symbol                                        */
256 /*-----------------------------------------------------------------*/
257 void
258 ds390_emitDebuggerSymbol (char * debugSym)
259 {
260   _G.debugLine = 1;
261   emitcode ("", "%s ==.", debugSym);
262   _G.debugLine = 0;
263 }
264
265 /*-----------------------------------------------------------------*/
266 /* mova - moves specified value into accumulator                   */
267 /*-----------------------------------------------------------------*/
268 static void
269 mova (const char *x)
270 {
271   /* do some early peephole optimization */
272   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
273     return;
274
275   emitcode("mov", "a,%s", x);
276 }
277
278 /*-----------------------------------------------------------------*/
279 /* movb - moves specified value into register b                    */
280 /*-----------------------------------------------------------------*/
281 static void
282 movb (const char *x)
283 {
284   /* do some early peephole optimization */
285   if (!strncmp(x, "b", 2))
286     return;
287
288   emitcode("mov","b,%s", x);
289 }
290
291 /*-----------------------------------------------------------------*/
292 /* movc - moves specified value into the carry                     */
293 /*-----------------------------------------------------------------*/
294 static void
295 movc (const char *s)
296 {
297   if (s == zero)
298     CLRC;
299   else if (s == one)
300     SETC;
301   else if (strcmp (s, "c"))
302     {/* it's not in carry already */
303       MOVA (s);
304       /* set C, if a >= 1 */
305       emitcode ("add", "a,#0xff");
306     }
307 }
308
309 /*-----------------------------------------------------------------*/
310 /* pushB - saves register B if necessary                           */
311 /*-----------------------------------------------------------------*/
312 static bool
313 pushB (void)
314 {
315   bool pushedB = FALSE;
316
317   if (BINUSE)
318     {
319       emitcode ("push", "b");
320 //    printf("B was in use !\n");
321       pushedB = TRUE;
322     }
323   else
324     {
325       OPINB++;
326     }
327   return pushedB;
328 }
329
330 /*-----------------------------------------------------------------*/
331 /* popB - restores value of register B if necessary                */
332 /*-----------------------------------------------------------------*/
333 static void
334 popB (bool pushedB)
335 {
336   if (pushedB)
337     {
338       emitcode ("pop", "b");
339     }
340   else
341     {
342       OPINB--;
343     }
344 }
345
346 /*-----------------------------------------------------------------*/
347 /* pushReg - saves register                                        */
348 /*-----------------------------------------------------------------*/
349 static bool
350 pushReg (int index, bool bits_pushed)
351 {
352   regs * reg = REG_WITH_INDEX (index);
353   if (reg->type == REG_BIT)
354     {
355       if (!bits_pushed)
356         emitcode ("push", "%s", reg->base);
357       return TRUE;
358     }
359   else
360     emitcode ("push", "%s", reg->dname);
361   return bits_pushed;
362 }
363
364 /*-----------------------------------------------------------------*/
365 /* popReg - restores register                                      */
366 /*-----------------------------------------------------------------*/
367 static bool
368 popReg (int index, bool bits_popped)
369 {
370   regs * reg = REG_WITH_INDEX (index);
371   if (reg->type == REG_BIT)
372     {
373       if (!bits_popped)
374         emitcode ("pop", "%s", reg->base);
375       return TRUE;
376     }
377   else
378     emitcode ("pop", "%s", reg->dname);
379   return bits_popped;
380 }
381
382 /*-----------------------------------------------------------------*/
383 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
384 /*-----------------------------------------------------------------*/
385 static regs *
386 getFreePtr (iCode * ic, asmop ** aopp, bool result)
387 {
388   bool r0iu, r1iu;
389   bool r0ou, r1ou;
390
391   /* the logic: if r0 & r1 used in the instruction
392      then we are in trouble otherwise */
393
394   /* first check if r0 & r1 are used by this
395      instruction, in which case we are in trouble */
396   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
397   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
398   if (r0iu && r1iu) {
399       goto endOfWorld;
400     }
401
402   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
403   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
404
405   /* if no usage of r0 then return it */
406   if (!r0iu && !r0ou)
407     {
408       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
409       (*aopp)->type = AOP_R0;
410
411       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
412     }
413
414   /* if no usage of r1 then return it */
415   if (!r1iu && !r1ou)
416     {
417       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
418       (*aopp)->type = AOP_R1;
419
420       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
421     }
422
423   /* now we know they both have usage */
424   /* if r0 not used in this instruction */
425   if (!r0iu)
426     {
427       /* push it if not already pushed */
428       if (!_G.r0Pushed)
429         {
430           emitcode ("push", "%s",
431                     REG_WITH_INDEX (R0_IDX)->dname);
432           _G.r0Pushed++;
433         }
434
435       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
436       (*aopp)->type = AOP_R0;
437
438       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
439     }
440
441   /* if r1 not used then */
442
443   if (!r1iu)
444     {
445       /* push it if not already pushed */
446       if (!_G.r1Pushed)
447         {
448           emitcode ("push", "%s",
449                     REG_WITH_INDEX (R1_IDX)->dname);
450           _G.r1Pushed++;
451         }
452
453       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
454       (*aopp)->type = AOP_R1;
455       return REG_WITH_INDEX (R1_IDX);
456     }
457
458 endOfWorld:
459   /* I said end of world, but not quite end of world yet */
460   /* if this is a result then we can push it on the stack */
461   if (result)
462     {
463       (*aopp)->type = AOP_STK;
464       return NULL;
465     }
466
467   /* now this is REALLY the end of the world */
468   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
469           "getFreePtr should never reach here");
470   exit (1);
471
472   return NULL; // notreached, but makes compiler happy.
473 }
474
475
476 /*-----------------------------------------------------------------*/
477 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
478 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
479 /* alternate DPTR (DPL1/DPH1/DPX1).          */
480 /*-----------------------------------------------------------------*/
481 static void
482 genSetDPTR (int n)
483 {
484
485   /* If we are doing lazy evaluation, simply note the desired
486    * change, but don't emit any code yet.
487    */
488   if (_lazyDPS)
489     {
490       _desiredDPS = n;
491       return;
492     }
493
494   if (!n)
495     {
496       emitcode ("mov", "dps,#0");
497     }
498   else
499     {
500       TR_DPTR("#1");
501       emitcode ("mov", "dps,#1");
502     }
503 }
504
505 /*------------------------------------------------------------------*/
506 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
507 /*                                                                  */
508 /* Any code that operates on DPTR (NB: not on the individual        */
509 /* components, like DPH) *must* call _flushLazyDPS() before using   */
510 /* DPTR within a lazy DPS evaluation block.                         */
511 /*                                                                  */
512 /* Note that aopPut and aopGet already contain the proper calls to  */
513 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
514 /* DPS evaluation block.                                            */
515 /*                                                                  */
516 /* Also, _flushLazyDPS must be called before any flow control       */
517 /* operations that could potentially branch out of the block.       */
518 /*                                                                  */
519 /* Lazy DPS evaluation is simply an optimization (though an         */
520 /* important one), so if in doubt, leave it out.                    */
521 /*------------------------------------------------------------------*/
522 static void
523 _startLazyDPSEvaluation (void)
524 {
525   _currentDPS = 0;
526   _desiredDPS = 0;
527 #ifdef BETTER_LITERAL_SHIFT
528   _lazyDPS++;
529 #else
530   _lazyDPS = 1;
531 #endif
532 }
533
534 /*------------------------------------------------------------------*/
535 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
536 /* desired one. Call before using DPTR within a lazy DPS evaluation */
537 /* block.                                                           */
538 /*------------------------------------------------------------------*/
539 static void
540 _flushLazyDPS (void)
541 {
542   if (!_lazyDPS)
543     {
544       /* nothing to do. */
545       return;
546     }
547
548   if (_desiredDPS != _currentDPS)
549     {
550       if (_desiredDPS)
551         {
552           emitcode ("inc", "dps");
553         }
554       else
555         {
556           emitcode ("dec", "dps");
557         }
558       _currentDPS = _desiredDPS;
559     }
560 }
561
562 /*-----------------------------------------------------------------*/
563 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.     */
564 /*                   */
565 /* Forces us back to the safe state (standard DPTR selected).    */
566 /*-----------------------------------------------------------------*/
567 static void
568 _endLazyDPSEvaluation (void)
569 {
570 #ifdef BETTER_LITERAL_SHIFT
571   _lazyDPS--;
572 #else
573   _lazyDPS = 0;
574 #endif
575   if (!_lazyDPS)
576   {
577     if (_currentDPS)
578     {
579       genSetDPTR (0);
580       _flushLazyDPS ();
581     }
582     _currentDPS = 0;
583     _desiredDPS = 0;
584   }
585 }
586
587
588 /*-----------------------------------------------------------------*/
589 /* newAsmop - creates a new asmOp                                  */
590 /*-----------------------------------------------------------------*/
591 static asmop *
592 newAsmop (short type)
593 {
594   asmop *aop;
595
596   aop = Safe_calloc (1, sizeof (asmop));
597   aop->type = type;
598   aop->allocated = 1;
599   return aop;
600 }
601
602 /*-----------------------------------------------------------------*/
603 /* pointerCode - returns the code for a pointer type               */
604 /*-----------------------------------------------------------------*/
605 static int
606 pointerCode (sym_link * etype)
607 {
608
609   return PTR_TYPE (SPEC_OCLS (etype));
610
611 }
612
613 /*-----------------------------------------------------------------*/
614 /* leftRightUseAcc - returns size of accumulator use by operands   */
615 /*-----------------------------------------------------------------*/
616 static int
617 leftRightUseAcc(iCode *ic)
618 {
619   operand *op;
620   int size;
621   int accuseSize = 0;
622   int accuse = 0;
623
624   if (!ic)
625     {
626       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
627               "null iCode pointer");
628       return 0;
629     }
630
631   if (ic->op == IFX)
632     {
633       op = IC_COND (ic);
634       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
635         {
636           accuse = 1;
637           size = getSize (OP_SYMBOL (op)->type);
638           if (size>accuseSize)
639             accuseSize = size;
640         }
641     }
642   else if (ic->op == JUMPTABLE)
643     {
644       op = IC_JTCOND (ic);
645       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
646         {
647           accuse = 1;
648           size = getSize (OP_SYMBOL (op)->type);
649           if (size>accuseSize)
650             accuseSize = size;
651         }
652     }
653   else
654     {
655       op = IC_LEFT (ic);
656       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
657         {
658           accuse = 1;
659           size = getSize (OP_SYMBOL (op)->type);
660           if (size>accuseSize)
661             accuseSize = size;
662         }
663       op = IC_RIGHT (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     }
672
673   if (accuseSize)
674     return accuseSize;
675   else
676     return accuse;
677 }
678
679 /*-----------------------------------------------------------------*/
680 /* aopForSym - for a true symbol                                   */
681 /*-----------------------------------------------------------------*/
682 static asmop *
683 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
684 {
685   asmop *aop;
686   memmap *space;
687   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
688   char *dpl = useDP2 ? "dpl1" : "dpl";
689   char *dph = useDP2 ? "dph1" : "dph";
690   char *dpx = useDP2 ? "dpx1" : "dpx";
691
692   wassertl (ic != NULL, "Got a null iCode");
693   wassertl (sym != NULL, "Got a null symbol");
694
695   space = SPEC_OCLS (sym->etype);
696
697   /* if already has one */
698   if (sym->aop)
699     {
700       if ((sym->aop->type == AOP_DPTR && useDP2)
701           || (sym->aop->type == AOP_DPTR2 && !useDP2))
702         sym->aop = NULL;
703       else
704         {
705           sym->aop->allocated++;
706           return sym->aop;
707         }
708     }
709
710   /* assign depending on the storage class */
711   /* if it is on the stack or indirectly addressable */
712   /* space we need to assign either r0 or r1 to it   */
713   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
714     {
715       sym->aop = aop = newAsmop (0);
716       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
717       aop->size = getSize (sym->type);
718
719       /* now assign the address of the variable to
720          the pointer register */
721       if (aop->type != AOP_STK)
722         {
723           if (sym->onStack)
724             {
725               char offset = ((sym->stack < 0) ?
726                          ((char) (sym->stack - _G.nRegsSaved)) :
727                          ((char) sym->stack)) & 0xff;
728
729               if ((abs(offset) <= 3) ||
730                   (accuse && (abs(offset) <= 7)))
731                 {
732                   emitcode ("mov", "%s,_bp",
733                             aop->aopu.aop_ptr->name);
734                   while (offset < 0)
735                     {
736                       emitcode ("dec", aop->aopu.aop_ptr->name);
737                       offset++;
738                     }
739                   while (offset > 0)
740                     {
741                       emitcode ("inc", aop->aopu.aop_ptr->name);
742                       offset--;
743                     }
744                 }
745               else
746                 {
747                   if (accuse)
748                     emitcode ("push", "acc");
749                   emitcode ("mov", "a,_bp");
750                   emitcode ("add", "a,#!constbyte", offset);
751                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
752                   if (accuse)
753                     emitcode ("pop", "acc");
754                 }
755             }
756           else
757             {
758               emitcode ("mov", "%s,#%s",
759                         aop->aopu.aop_ptr->name,
760                         sym->rname);
761             }
762           aop->paged = space->paged;
763         }
764       else
765         aop->aopu.aop_stk = sym->stack;
766       return aop;
767     }
768
769   if (sym->onStack && options.stack10bit)
770     {
771         short stack_val = -((sym->stack < 0) ?
772                             ((short) (sym->stack - _G.nRegsSaved)) :
773                             ((short) sym->stack)) ;
774         if (_G.dptrInUse ) {
775             emitcode ("push",dpl);
776             emitcode ("push",dph);
777             emitcode ("push",dpx);
778         }
779       /* It's on the 10 bit stack, which is located in
780        * far data space.
781        */
782       if (stack_val < 0 && stack_val > -5)
783         { /* between -5 & -1 */
784           if (options.model == MODEL_FLAT24)
785             {
786                 emitcode ("mov", "%s,#!constbyte", dpx,
787                           (options.stack_loc >> 16) & 0xff);
788             }
789           emitcode ("mov", "%s,_bpx+1", dph);
790           emitcode ("mov", "%s,_bpx", dpl);
791           if (useDP2) {
792               emitcode ("mov","dps,#1");
793           }
794           stack_val = -stack_val;
795           while (stack_val--) {
796               emitcode ("inc","dptr");
797           }
798           if (useDP2) {
799               emitcode("mov","dps,#0");
800           }
801         }
802       else
803         {
804           if (accuse)
805               emitcode ("push", "acc");
806
807           emitcode ("mov", "a,_bpx");
808           emitcode ("clr","c");
809           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
810           emitcode ("mov","%s,a", dpl);
811           emitcode ("mov","a,_bpx+1");
812           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
813           emitcode ("mov", "%s,a", dph);
814           if (options.model == MODEL_FLAT24)
815             {
816               emitcode ("mov", "%s,#!constbyte", dpx,
817                         (options.stack_loc >> 16) & 0xff);
818             }
819
820           if (accuse)
821               emitcode ("pop", "acc");
822         }
823       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
824       aop->size = getSize (sym->type);
825       return aop;
826     }
827
828   /* if in bit space */
829   if (IN_BITSPACE (space))
830     {
831       sym->aop = aop = newAsmop (AOP_CRY);
832       aop->aopu.aop_dir = sym->rname;
833       aop->size = getSize (sym->type);
834       return aop;
835     }
836   /* if it is in direct space */
837   if (IN_DIRSPACE (space))
838     {
839       sym->aop = aop = newAsmop (AOP_DIR);
840       aop->aopu.aop_dir = sym->rname;
841       aop->size = getSize (sym->type);
842       return aop;
843     }
844
845   /* special case for a function */
846   if (IS_FUNC (sym->type) && !(sym->isitmp))
847     {
848       sym->aop = aop = newAsmop (AOP_IMMD);
849       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
850       aop->size = FPTRSIZE;
851       return aop;
852     }
853
854   /* only remaining is far space */
855   /* in which case DPTR gets the address */
856   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
857   if (useDP2)
858     {
859       genSetDPTR (1);
860       _flushLazyDPS ();
861       emitcode ("mov", "dptr,#%s", sym->rname);
862       genSetDPTR (0);
863     }
864   else
865     {
866       emitcode ("mov", "dptr,#%s", sym->rname);
867     }
868   aop->size = getSize (sym->type);
869
870   /* if it is in code space */
871   if (IN_CODESPACE (space))
872     aop->code = 1;
873
874   return aop;
875 }
876
877 /*-----------------------------------------------------------------*/
878 /* aopForRemat - rematerialzes an object                           */
879 /*-----------------------------------------------------------------*/
880 static asmop *
881 aopForRemat (symbol * sym)
882 {
883   iCode *ic = sym->rematiCode;
884   asmop *aop = newAsmop (AOP_IMMD);
885   int ptr_type = 0;
886   int val = 0;
887
888   for (;;)
889     {
890       if (ic->op == '+')
891         val += (int) operandLitValue (IC_RIGHT (ic));
892       else if (ic->op == '-')
893         val -= (int) operandLitValue (IC_RIGHT (ic));
894       else if (IS_CAST_ICODE(ic)) {
895               sym_link *from_type = operandType(IC_RIGHT(ic));
896               aop->aopu.aop_immd.from_cast_remat = 1;
897               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
898               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
899               continue;
900       } else break;
901
902       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
903     }
904
905   if (val)
906   {
907       SNPRINTF (buffer, sizeof(buffer),
908                 "(%s %c 0x%06x)",
909                 OP_SYMBOL (IC_LEFT (ic))->rname,
910                 val >= 0 ? '+' : '-',
911                 abs (val) & 0xffffff);
912   }
913   else
914   {
915       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
916       {
917           SNPRINTF(buffer, sizeof(buffer),
918                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
919       }
920       else
921       {
922           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
923       }
924   }
925
926   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
927   /* set immd2 field if required */
928   if (aop->aopu.aop_immd.from_cast_remat)
929   {
930       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
931       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
932   }
933
934   return aop;
935 }
936
937 /*-----------------------------------------------------------------*/
938 /* aopHasRegs - returns true if aop has regs between from-to       */
939 /*-----------------------------------------------------------------*/
940 static int aopHasRegs(asmop *aop, int from, int to)
941 {
942     int size =0;
943
944     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
945
946     for (; size < aop->size ; size++) {
947         int reg;
948         for (reg = from ; reg <= to ; reg++)
949             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
950     }
951     return 0;
952 }
953
954 /*-----------------------------------------------------------------*/
955 /* regsInCommon - two operands have some registers in common       */
956 /*-----------------------------------------------------------------*/
957 static bool
958 regsInCommon (operand * op1, operand * op2)
959 {
960   symbol *sym1, *sym2;
961   int i;
962
963   /* if they have registers in common */
964   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
965     return FALSE;
966
967   sym1 = OP_SYMBOL (op1);
968   sym2 = OP_SYMBOL (op2);
969
970   if (sym1->nRegs == 0 || sym2->nRegs == 0)
971     return FALSE;
972
973   for (i = 0; i < sym1->nRegs; i++)
974     {
975       int j;
976       if (!sym1->regs[i])
977         continue;
978
979       for (j = 0; j < sym2->nRegs; j++)
980         {
981           if (!sym2->regs[j])
982             continue;
983
984           if (sym2->regs[j] == sym1->regs[i])
985             return TRUE;
986         }
987     }
988
989   return FALSE;
990 }
991
992 /*-----------------------------------------------------------------*/
993 /* operandsEqu - equivalent                                        */
994 /*-----------------------------------------------------------------*/
995 static bool
996 operandsEqu (operand * op1, operand * op2)
997 {
998   symbol *sym1, *sym2;
999
1000   /* if they're not symbols */
1001   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1002     return FALSE;
1003
1004   sym1 = OP_SYMBOL (op1);
1005   sym2 = OP_SYMBOL (op2);
1006
1007   /* if both are itemps & one is spilt
1008      and the other is not then false */
1009   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1010       sym1->isspilt != sym2->isspilt)
1011     return FALSE;
1012
1013   /* if they are the same */
1014   if (sym1 == sym2)
1015     return TRUE;
1016
1017   /* if they have the same rname */
1018   if (sym1->rname[0] && sym2->rname[0] &&
1019       strcmp (sym1->rname, sym2->rname) == 0 &&
1020       !(IS_PARM (op2) && IS_ITEMP (op1)))
1021     return TRUE;
1022
1023   /* if left is a tmp & right is not */
1024   if (IS_ITEMP (op1) &&
1025       !IS_ITEMP (op2) &&
1026       sym1->isspilt &&
1027       (sym1->usl.spillLoc == sym2))
1028     return TRUE;
1029
1030   if (IS_ITEMP (op2) &&
1031       !IS_ITEMP (op1) &&
1032       sym2->isspilt &&
1033       sym1->level > 0 &&
1034       (sym2->usl.spillLoc == sym1))
1035     return TRUE;
1036
1037   /* are they spilt to the same location */
1038   if (IS_ITEMP (op2) &&
1039       IS_ITEMP (op1) &&
1040       sym2->isspilt &&
1041       sym1->isspilt &&
1042       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1043     return TRUE;
1044
1045   return FALSE;
1046 }
1047
1048 /*-----------------------------------------------------------------*/
1049 /* sameRegs - two asmops have the same registers                   */
1050 /*-----------------------------------------------------------------*/
1051 static bool
1052 sameRegs (asmop * aop1, asmop * aop2)
1053 {
1054   int i;
1055
1056   if (aop1 == aop2)
1057     {
1058       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1059         {
1060           return FALSE;
1061         }
1062       return TRUE;
1063     }
1064
1065   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1066     return FALSE;
1067
1068   if (aop1->type != aop2->type)
1069     return FALSE;
1070
1071   if (aop1->size != aop2->size)
1072     return FALSE;
1073
1074   for (i = 0; i < aop1->size; i++)
1075     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1076       return FALSE;
1077
1078   return TRUE;
1079 }
1080
1081 /*-----------------------------------------------------------------*/
1082 /* aopOp - allocates an asmop for an operand  :                    */
1083 /*-----------------------------------------------------------------*/
1084 static void
1085 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1086 {
1087   asmop *aop;
1088   symbol *sym;
1089   int i;
1090
1091   if (!op)
1092     return;
1093
1094   /* if this a literal */
1095   if (IS_OP_LITERAL (op))
1096     {
1097       op->aop = aop = newAsmop (AOP_LIT);
1098       aop->aopu.aop_lit = op->operand.valOperand;
1099       aop->size = getSize (operandType (op));
1100       return;
1101     }
1102
1103   /* if already has a asmop then continue */
1104   if (op->aop)
1105     {
1106       if ((op->aop->type == AOP_DPTR && useDP2)
1107           || (op->aop->type == AOP_DPTR2 && !useDP2))
1108         op->aop = NULL;
1109       else
1110         {
1111           op->aop->allocated++;
1112           return;
1113         }
1114     }
1115
1116   /* if the underlying symbol has a aop */
1117   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1118     {
1119       op->aop = OP_SYMBOL (op)->aop;
1120       if ((op->aop->type == AOP_DPTR && useDP2)
1121           || (op->aop->type == AOP_DPTR2 && !useDP2))
1122         op->aop = NULL;
1123       else
1124         {
1125           op->aop->allocated++;
1126           return;
1127         }
1128     }
1129
1130   /* if this is a true symbol */
1131   if (IS_TRUE_SYMOP (op))
1132     {
1133       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1134       return;
1135     }
1136
1137   /* this is a temporary : this has
1138      only five choices :
1139      a) register
1140      b) spillocation
1141      c) rematerialize
1142      d) conditional
1143      e) can be a return use only */
1144
1145   sym = OP_SYMBOL (op);
1146
1147   /* if the type is a conditional */
1148   if (sym->regType == REG_CND)
1149     {
1150       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1151       aop->size = 0;
1152       return;
1153     }
1154
1155   /* if it is spilt then two situations
1156      a) is rematerialize
1157      b) has a spill location */
1158   if (sym->isspilt || sym->nRegs == 0)
1159     {
1160
1161       /* rematerialize it NOW */
1162       if (sym->remat)
1163         {
1164           sym->aop = op->aop = aop =
1165             aopForRemat (sym);
1166           aop->size = getSize (sym->type);
1167           return;
1168         }
1169
1170       if (sym->accuse)
1171         {
1172           int i;
1173           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1174           aop->size = getSize (sym->type);
1175           for (i = 0; i < 2; i++)
1176             aop->aopu.aop_str[i] = accUse[i];
1177           return;
1178         }
1179
1180       if (sym->ruonly)
1181         {
1182           unsigned i;
1183
1184           if (useDP2)
1185             {
1186               /* a AOP_STR uses DPTR, but DPTR is already in use;
1187                * we're just hosed.
1188                */
1189                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1190             }
1191
1192           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1193           aop->size = getSize (sym->type);
1194           for (i = 0; i < fReturnSizeDS390; i++)
1195             aop->aopu.aop_str[i] = fReturn[i];
1196           return;
1197         }
1198
1199       if (sym->dptr) { /* has been allocated to a DPTRn */
1200           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1201           aop->size = getSize (sym->type);
1202           aop->aopu.dptr = sym->dptr;
1203           return ;
1204       }
1205
1206       if (sym->usl.spillLoc)
1207         {
1208           asmop *oldAsmOp = NULL;
1209
1210           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1211             {
1212               /* force a new aop if sizes differ */
1213               oldAsmOp = sym->usl.spillLoc->aop;
1214               sym->usl.spillLoc->aop = NULL;
1215             }
1216           sym->aop = op->aop = aop =
1217                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1218           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1219             {
1220               /* Don't reuse the new aop, go with the last one */
1221               sym->usl.spillLoc->aop = oldAsmOp;
1222             }
1223           aop->size = getSize (sym->type);
1224           return;
1225         }
1226
1227       /* else must be a dummy iTemp */
1228       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1229       aop->size = getSize (sym->type);
1230       return;
1231     }
1232
1233   /* if the type is a bit register */
1234   if (sym->regType == REG_BIT)
1235     {
1236       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1237       aop->size = sym->nRegs;//1???
1238       aop->aopu.aop_reg[0] = sym->regs[0];
1239       aop->aopu.aop_dir = sym->regs[0]->name;
1240       return;
1241     }
1242
1243   /* must be in a register */
1244   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1245   aop->size = sym->nRegs;
1246   for (i = 0; i < sym->nRegs; i++)
1247     aop->aopu.aop_reg[i] = sym->regs[i];
1248 }
1249
1250 /*-----------------------------------------------------------------*/
1251 /* freeAsmop - free up the asmop given to an operand               */
1252 /*----------------------------------------------------------------*/
1253 static void
1254 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1255 {
1256   asmop *aop;
1257
1258   if (!op)
1259     aop = aaop;
1260   else
1261     aop = op->aop;
1262
1263   if (!aop)
1264     return;
1265
1266   aop->allocated--;
1267
1268   if (aop->allocated)
1269     goto dealloc;
1270
1271   /* depending on the asmop type only three cases need work
1272      AOP_R0, AOP_R1 & AOP_STK */
1273   switch (aop->type)
1274     {
1275     case AOP_R0:
1276       if (_G.r0Pushed)
1277         {
1278           if (pop)
1279             {
1280               emitcode ("pop", "ar0");
1281               _G.r0Pushed--;
1282             }
1283         }
1284       bitVectUnSetBit (ic->rUsed, R0_IDX);
1285       break;
1286
1287     case AOP_R1:
1288       if (_G.r1Pushed)
1289         {
1290           if (pop)
1291             {
1292               emitcode ("pop", "ar1");
1293               _G.r1Pushed--;
1294             }
1295         }
1296       bitVectUnSetBit (ic->rUsed, R1_IDX);
1297       break;
1298
1299     case AOP_STK:
1300       {
1301         int sz = aop->size;
1302         int stk = aop->aopu.aop_stk + aop->size;
1303         bitVectUnSetBit (ic->rUsed, R0_IDX);
1304         bitVectUnSetBit (ic->rUsed, R1_IDX);
1305
1306         getFreePtr (ic, &aop, FALSE);
1307
1308         if (options.stack10bit)
1309           {
1310             /* I'm not sure what to do here yet... */
1311             /* #STUB */
1312             fprintf (stderr,
1313                      "*** Warning: probably generating bad code for "
1314                      "10 bit stack mode.\n");
1315           }
1316
1317         if (stk)
1318           {
1319             emitcode ("mov", "a,_bp");
1320             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1321             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1322           }
1323         else
1324           {
1325             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1326           }
1327
1328         while (sz--)
1329           {
1330             emitcode ("pop", "acc");
1331             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1332             if (!sz)
1333               break;
1334             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1335           }
1336         op->aop = aop;
1337         freeAsmop (op, NULL, ic, TRUE);
1338         if (_G.r1Pushed)
1339           {
1340             emitcode ("pop", "ar1");
1341             _G.r1Pushed--;
1342           }
1343         if (_G.r0Pushed)
1344           {
1345             emitcode ("pop", "ar0");
1346             _G.r0Pushed--;
1347           }
1348       }
1349     case AOP_DPTR2:
1350         if (_G.dptr1InUse) {
1351             emitcode ("pop","dpx1");
1352             emitcode ("pop","dph1");
1353             emitcode ("pop","dpl1");
1354         }
1355         break;
1356     case AOP_DPTR:
1357         if (_G.dptrInUse) {
1358             emitcode ("pop","dpx");
1359             emitcode ("pop","dph");
1360             emitcode ("pop","dpl");
1361         }
1362         break;
1363     }
1364
1365 dealloc:
1366   /* all other cases just dealloc */
1367   if (op)
1368     {
1369       op->aop = NULL;
1370       if (IS_SYMOP (op))
1371         {
1372           OP_SYMBOL (op)->aop = NULL;
1373           /* if the symbol has a spill */
1374           if (SPIL_LOC (op))
1375             SPIL_LOC (op)->aop = NULL;
1376         }
1377     }
1378 }
1379
1380 #define DEFAULT_ACC_WARNING 0
1381 static int saveAccWarn = DEFAULT_ACC_WARNING;
1382
1383
1384 /*-----------------------------------------------------------------*/
1385 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1386 /*                 clobber the accumulator                         */
1387 /*-----------------------------------------------------------------*/
1388 static bool
1389 aopGetUsesAcc (operand * oper, int offset)
1390 {
1391   asmop * aop = AOP (oper);
1392
1393   if (offset > (aop->size - 1))
1394     return FALSE;
1395
1396   switch (aop->type)
1397     {
1398
1399     case AOP_R0:
1400     case AOP_R1:
1401       if (aop->paged)
1402         return TRUE;
1403       return FALSE;
1404     case AOP_DPTR:
1405       return TRUE;
1406     case AOP_IMMD:
1407       return FALSE;
1408     case AOP_DIR:
1409       return FALSE;
1410     case AOP_REG:
1411       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1412       return FALSE;
1413     case AOP_CRY:
1414       return TRUE;
1415     case AOP_ACC:
1416       if (offset)
1417         return FALSE;
1418       return TRUE;
1419     case AOP_LIT:
1420       return FALSE;
1421     case AOP_STR:
1422       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1423         return TRUE;
1424       return FALSE;
1425     case AOP_DUMMY:
1426       return FALSE;
1427     default:
1428       /* Error case --- will have been caught already */
1429       wassert(0);
1430       return FALSE;
1431     }
1432 }
1433
1434 /*-------------------------------------------------------------------*/
1435 /* aopGet - for fetching value of the aop                            */
1436 /*                                                                   */
1437 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1438 /* in the accumulator. Set it to the name of a free register         */
1439 /* if acc must be preserved; the register will be used to preserve   */
1440 /* acc temporarily and to return the result byte.                    */
1441 /*-------------------------------------------------------------------*/
1442 static char *
1443 aopGet (operand * oper,
1444         int   offset,
1445         bool  bit16,
1446         bool  dname,
1447         char  *saveAcc)
1448 {
1449   asmop * aop = AOP (oper);
1450
1451   /* offset is greater than
1452      size then zero */
1453   if (offset > (aop->size - 1) &&
1454       aop->type != AOP_LIT)
1455     return zero;
1456
1457   /* depending on type */
1458   switch (aop->type)
1459     {
1460     case AOP_DUMMY:
1461       return zero;
1462
1463     case AOP_R0:
1464     case AOP_R1:
1465       /* if we need to increment it */
1466       while (offset > aop->coff)
1467         {
1468           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1469           aop->coff++;
1470         }
1471
1472       while (offset < aop->coff)
1473         {
1474           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1475           aop->coff--;
1476         }
1477
1478       aop->coff = offset;
1479       if (aop->paged)
1480         {
1481           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1482           return (dname ? "acc" : "a");
1483         }
1484       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1485       return Safe_strdup(buffer);
1486
1487     case AOP_DPTRn:
1488         assert(offset <= 3);
1489         return dptrn[aop->aopu.dptr][offset];
1490
1491     case AOP_DPTR:
1492     case AOP_DPTR2:
1493
1494       if (aop->type == AOP_DPTR2)
1495         {
1496           genSetDPTR (1);
1497         }
1498
1499       if (saveAcc)
1500         {
1501             TR_AP("#1");
1502 //          if (aop->type != AOP_DPTR2)
1503 //          {
1504 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1505 //              emitcode(";", "spanky: saveAcc for DPTR");
1506 //          }
1507
1508             emitcode ("xch", "a, %s", saveAcc);
1509         }
1510
1511       _flushLazyDPS ();
1512
1513       while (offset > aop->coff)
1514         {
1515           emitcode ("inc", "dptr");
1516           aop->coff++;
1517         }
1518
1519       while (offset < aop->coff)
1520         {
1521           emitcode ("lcall", "__decdptr");
1522           aop->coff--;
1523         }
1524
1525       aop->coff = offset;
1526       if (aop->code)
1527         {
1528           emitcode ("clr", "a");
1529           emitcode ("movc", "a,@a+dptr");
1530         }
1531       else
1532         {
1533           emitcode ("movx", "a,@dptr");
1534         }
1535
1536       if (aop->type == AOP_DPTR2)
1537         {
1538           genSetDPTR (0);
1539         }
1540
1541         if (saveAcc)
1542         {
1543        TR_AP("#2");
1544               emitcode ("xch", "a, %s", saveAcc);
1545 //            if (strcmp(saveAcc, "_ap"))
1546 //            {
1547 //                emitcode(";", "spiffy: non _ap return from aopGet.");
1548 //            }
1549
1550               return saveAcc;
1551         }
1552       return (dname ? "acc" : "a");
1553
1554     case AOP_IMMD:
1555       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1556       {
1557           SNPRINTF(buffer, sizeof(buffer),
1558                    "%s",aop->aopu.aop_immd.aop_immd2);
1559       }
1560       else if (bit16)
1561       {
1562          SNPRINTF(buffer, sizeof(buffer),
1563                   "#%s", aop->aopu.aop_immd.aop_immd1);
1564       }
1565       else if (offset)
1566       {
1567           switch (offset) {
1568           case 1:
1569               tsprintf(buffer, sizeof(buffer),
1570                        "#!his",aop->aopu.aop_immd.aop_immd1);
1571               break;
1572           case 2:
1573               tsprintf(buffer, sizeof(buffer),
1574                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1575               break;
1576           case 3:
1577               tsprintf(buffer, sizeof(buffer),
1578                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1579               break;
1580           default: /* should not need this (just in case) */
1581               SNPRINTF (buffer, sizeof(buffer),
1582                         "#(%s >> %d)",
1583                        aop->aopu.aop_immd.aop_immd1,
1584                        offset * 8);
1585           }
1586       }
1587       else
1588       {
1589         SNPRINTF (buffer, sizeof(buffer),
1590                   "#%s", aop->aopu.aop_immd.aop_immd1);
1591       }
1592       return Safe_strdup(buffer);
1593
1594     case AOP_DIR:
1595       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1596         {
1597           SNPRINTF (buffer, sizeof(buffer),
1598                     "(%s >> %d)",
1599                     aop->aopu.aop_dir, offset * 8);
1600         }
1601       else if (offset)
1602         {
1603           SNPRINTF (buffer, sizeof(buffer),
1604                     "(%s + %d)",
1605                    aop->aopu.aop_dir,
1606                    offset);
1607         }
1608       else
1609         {
1610           SNPRINTF (buffer, sizeof(buffer),
1611                    "%s", aop->aopu.aop_dir);
1612         }
1613
1614       return Safe_strdup(buffer);
1615
1616     case AOP_REG:
1617       if (dname)
1618         return aop->aopu.aop_reg[offset]->dname;
1619       else
1620         return aop->aopu.aop_reg[offset]->name;
1621
1622     case AOP_CRY:
1623       emitcode ("clr", "a");
1624       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1625       emitcode ("rlc", "a");
1626       return (dname ? "acc" : "a");
1627
1628     case AOP_ACC:
1629       if (!offset && dname)
1630         return "acc";
1631       return aop->aopu.aop_str[offset];
1632
1633     case AOP_LIT:
1634       return aopLiteral (aop->aopu.aop_lit, offset);
1635
1636     case AOP_STR:
1637       aop->coff = offset;
1638       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1639           dname)
1640         return "acc";
1641
1642       return aop->aopu.aop_str[offset];
1643
1644     }
1645
1646   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1647           "aopget got unsupported aop->type");
1648   exit (1);
1649
1650   return NULL;  // not reached, but makes compiler happy.
1651 }
1652
1653 /*-----------------------------------------------------------------*/
1654 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1655 /*                 clobber the accumulator                         */
1656 /*-----------------------------------------------------------------*/
1657 static bool
1658 aopPutUsesAcc (operand * oper, const char *s, int offset)
1659 {
1660   asmop * aop = AOP (oper);
1661
1662   if (offset > (aop->size - 1))
1663     return FALSE;
1664
1665   switch (aop->type)
1666     {
1667     case AOP_DUMMY:
1668       return TRUE;
1669     case AOP_DIR:
1670       return FALSE;
1671     case AOP_REG:
1672       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1673       return FALSE;
1674     case AOP_DPTR:
1675       return TRUE;
1676     case AOP_R0:
1677     case AOP_R1:
1678       return ((aop->paged) || (*s == '@'));
1679     case AOP_STK:
1680       return (*s == '@');
1681     case AOP_CRY:
1682       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1683     case AOP_STR:
1684       return FALSE;
1685     case AOP_IMMD:
1686       return FALSE;
1687     case AOP_ACC:
1688       return FALSE;
1689     default:
1690       /* Error case --- will have been caught already */
1691       wassert(0);
1692       return FALSE;
1693     }
1694 }
1695
1696 /*-----------------------------------------------------------------*/
1697 /* aopPut - puts a string for a aop and indicates if acc is in use */
1698 /*-----------------------------------------------------------------*/
1699 static bool
1700 aopPut (operand * result, const char *s, int offset)
1701 {
1702   bool bvolatile = isOperandVolatile (result, FALSE);
1703   bool accuse = FALSE;
1704   asmop * aop = AOP (result);
1705
1706   if (aop->size && offset > (aop->size - 1))
1707     {
1708       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1709               "aopPut got offset > aop->size");
1710       exit (1);
1711     }
1712
1713   /* will assign value to value */
1714   /* depending on where it is ofcourse */
1715   switch (aop->type)
1716     {
1717     case AOP_DUMMY:
1718       MOVA (s);         /* read s in case it was volatile */
1719       accuse = TRUE;
1720       break;
1721
1722     case AOP_DIR:
1723       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1724         {
1725           SNPRINTF (buffer, sizeof(buffer),
1726                     "(%s >> %d)",
1727                     aop->aopu.aop_dir, offset * 8);
1728         }
1729       else if (offset)
1730         {
1731             SNPRINTF (buffer, sizeof(buffer),
1732                       "(%s + %d)",
1733                       aop->aopu.aop_dir, offset);
1734         }
1735       else
1736         {
1737             SNPRINTF (buffer, sizeof(buffer),
1738                      "%s", aop->aopu.aop_dir);
1739         }
1740
1741       if (strcmp (buffer, s) || bvolatile)
1742         {
1743             emitcode ("mov", "%s,%s", buffer, s);
1744         }
1745       if (!strcmp (buffer, "acc"))
1746         {
1747           accuse = TRUE;
1748         }
1749       break;
1750
1751     case AOP_REG:
1752       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1753           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1754         {
1755           if (*s == '@' ||
1756               strcmp (s, "r0") == 0 ||
1757               strcmp (s, "r1") == 0 ||
1758               strcmp (s, "r2") == 0 ||
1759               strcmp (s, "r3") == 0 ||
1760               strcmp (s, "r4") == 0 ||
1761               strcmp (s, "r5") == 0 ||
1762               strcmp (s, "r6") == 0 ||
1763               strcmp (s, "r7") == 0)
1764             {
1765                 emitcode ("mov", "%s,%s",
1766                           aop->aopu.aop_reg[offset]->dname, s);
1767             }
1768             else
1769             {
1770                 emitcode ("mov", "%s,%s",
1771                           aop->aopu.aop_reg[offset]->name, s);
1772             }
1773         }
1774       break;
1775
1776     case AOP_DPTRn:
1777         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1778         break;
1779
1780     case AOP_DPTR:
1781     case AOP_DPTR2:
1782
1783       if (aop->type == AOP_DPTR2)
1784         {
1785           genSetDPTR (1);
1786         }
1787       _flushLazyDPS ();
1788
1789       if (aop->code)
1790         {
1791           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1792                   "aopPut writing to code space");
1793           exit (1);
1794         }
1795
1796       while (offset > aop->coff)
1797         {
1798           aop->coff++;
1799           emitcode ("inc", "dptr");
1800         }
1801
1802       while (offset < aop->coff)
1803         {
1804           aop->coff--;
1805           emitcode ("lcall", "__decdptr");
1806         }
1807
1808       aop->coff = offset;
1809
1810       /* if not in accumulator */
1811       MOVA (s);
1812
1813       emitcode ("movx", "@dptr,a");
1814
1815       if (aop->type == AOP_DPTR2)
1816         {
1817           genSetDPTR (0);
1818         }
1819       break;
1820
1821     case AOP_R0:
1822     case AOP_R1:
1823       while (offset > aop->coff)
1824         {
1825           aop->coff++;
1826           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1827         }
1828       while (offset < aop->coff)
1829         {
1830           aop->coff--;
1831           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1832         }
1833       aop->coff = offset;
1834
1835       if (aop->paged)
1836         {
1837           MOVA (s);
1838           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1839         }
1840       else if (*s == '@')
1841         {
1842           MOVA (s);
1843           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1844         }
1845       else if (strcmp (s, "r0") == 0 ||
1846                strcmp (s, "r1") == 0 ||
1847                strcmp (s, "r2") == 0 ||
1848                strcmp (s, "r3") == 0 ||
1849                strcmp (s, "r4") == 0 ||
1850                strcmp (s, "r5") == 0 ||
1851                strcmp (s, "r6") == 0 ||
1852                strcmp (s, "r7") == 0)
1853         {
1854           char buffer[10];
1855           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1856           emitcode ("mov", "@%s,%s",
1857                     aop->aopu.aop_ptr->name, buffer);
1858         }
1859         else
1860         {
1861             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1862         }
1863       break;
1864
1865     case AOP_STK:
1866       if (strcmp (s, "a") == 0)
1867         emitcode ("push", "acc");
1868       else
1869         if (*s=='@') {
1870           MOVA(s);
1871           emitcode ("push", "acc");
1872         } else {
1873           emitcode ("push", s);
1874         }
1875
1876       break;
1877
1878     case AOP_CRY:
1879       /* if not bit variable */
1880       if (!aop->aopu.aop_dir)
1881         {
1882           /* inefficient: move carry into A and use jz/jnz */
1883           emitcode ("clr", "a");
1884           emitcode ("rlc", "a");
1885           accuse = TRUE;
1886         }
1887       else
1888         {
1889           if (s == zero)
1890             emitcode ("clr", "%s", aop->aopu.aop_dir);
1891           else if (s == one)
1892             emitcode ("setb", "%s", aop->aopu.aop_dir);
1893           else if (!strcmp (s, "c"))
1894             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1895           else if (strcmp (s, aop->aopu.aop_dir))
1896             {
1897                   MOVA (s);
1898                 /* set C, if a >= 1 */
1899                 emitcode ("add", "a,#!constbyte",0xff);
1900                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1901               }
1902             }
1903       break;
1904
1905     case AOP_STR:
1906       aop->coff = offset;
1907       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1908         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1909       break;
1910
1911     case AOP_ACC:
1912       accuse = TRUE;
1913       aop->coff = offset;
1914       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1915         break;
1916
1917       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1918         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1919       break;
1920
1921     default:
1922       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1923               "aopPut got unsupported aop->type");
1924       exit (1);
1925     }
1926
1927     return accuse;
1928 }
1929
1930
1931 /*--------------------------------------------------------------------*/
1932 /* reAdjustPreg - points a register back to where it should (coff==0) */
1933 /*--------------------------------------------------------------------*/
1934 static void
1935 reAdjustPreg (asmop * aop)
1936 {
1937   if ((aop->coff==0) || (aop->size <= 1))
1938     return;
1939
1940   switch (aop->type)
1941     {
1942     case AOP_R0:
1943     case AOP_R1:
1944       while (aop->coff--)
1945         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1946       break;
1947     case AOP_DPTR:
1948     case AOP_DPTR2:
1949       if (aop->type == AOP_DPTR2)
1950         {
1951           genSetDPTR (1);
1952           _flushLazyDPS ();
1953         }
1954       while (aop->coff--)
1955         {
1956           emitcode ("lcall", "__decdptr");
1957         }
1958
1959       if (aop->type == AOP_DPTR2)
1960         {
1961           genSetDPTR (0);
1962         }
1963       break;
1964     }
1965   aop->coff = 0;
1966 }
1967
1968 /*-----------------------------------------------------------------*/
1969 /* opIsGptr: returns non-zero if the passed operand is       */
1970 /* a generic pointer type.             */
1971 /*-----------------------------------------------------------------*/
1972 static int
1973 opIsGptr (operand * op)
1974 {
1975   sym_link *type = operandType (op);
1976
1977   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1978     {
1979       return 1;
1980     }
1981   return 0;
1982 }
1983
1984 /*-----------------------------------------------------------------*/
1985 /* getDataSize - get the operand data size                         */
1986 /*-----------------------------------------------------------------*/
1987 static int
1988 getDataSize (operand * op)
1989 {
1990   int size;
1991   size = AOP_SIZE (op);
1992   if (size == GPTRSIZE)
1993     {
1994       sym_link *type = operandType (op);
1995       if (IS_GENPTR (type))
1996         {
1997           /* generic pointer; arithmetic operations
1998            * should ignore the high byte (pointer type).
1999            */
2000           size--;
2001         }
2002     }
2003   return size;
2004 }
2005
2006 /*-----------------------------------------------------------------*/
2007 /* outAcc - output Acc                                             */
2008 /*-----------------------------------------------------------------*/
2009 static void
2010 outAcc (operand * result)
2011 {
2012   int size, offset;
2013   size = getDataSize (result);
2014   if (size)
2015     {
2016       aopPut (result, "a", 0);
2017       size--;
2018       offset = 1;
2019       /* unsigned or positive */
2020       while (size--)
2021         {
2022           aopPut (result, zero, offset++);
2023         }
2024     }
2025 }
2026
2027 /*-----------------------------------------------------------------*/
2028 /* outBitC - output a bit C                                        */
2029 /*-----------------------------------------------------------------*/
2030 static void
2031 outBitC (operand * result)
2032 {
2033   /* if the result is bit */
2034   if (AOP_TYPE (result) == AOP_CRY)
2035     {
2036       aopPut (result, "c", 0);
2037     }
2038   else
2039     {
2040       emitcode ("clr", "a");
2041       emitcode ("rlc", "a");
2042       outAcc (result);
2043     }
2044 }
2045
2046 /*-----------------------------------------------------------------*/
2047 /* toBoolean - emit code for orl a,operator(sizeop)                */
2048 /*-----------------------------------------------------------------*/
2049 static void
2050 toBoolean (operand * oper)
2051 {
2052   int  size = AOP_SIZE (oper) - 1;
2053   int  offset = 1;
2054   bool pushedB;
2055
2056   /* The generic part of a generic pointer should
2057    * not participate in it's truth value.
2058    *
2059    * i.e. 0x10000000 is zero.
2060    */
2061   if (opIsGptr (oper))
2062     {
2063       D (emitcode (";", "toBoolean: generic ptr special case."));
2064       size--;
2065     }
2066
2067   _startLazyDPSEvaluation ();
2068   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2069   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2070     {
2071       pushedB = pushB ();
2072       emitcode("mov", "b,a");
2073       while (--size)
2074         {
2075         MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2076           emitcode ("orl", "b,a");
2077         }
2078       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2079       emitcode ("orl", "a,b");
2080       popB (pushedB);
2081     }
2082   else
2083     {
2084       while (size--)
2085         {
2086           emitcode ("orl", "a,%s",
2087                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2088         }
2089     }
2090   _endLazyDPSEvaluation ();
2091 }
2092
2093
2094 /*-----------------------------------------------------------------*/
2095 /* genNot - generate code for ! operation                          */
2096 /*-----------------------------------------------------------------*/
2097 static void
2098 genNot (iCode * ic)
2099 {
2100   symbol *tlbl;
2101
2102   D (emitcode (";", "genNot "));
2103
2104   /* assign asmOps to operand & result */
2105   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2106   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2107
2108   /* if in bit space then a special case */
2109   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2110     {
2111       /* if left==result then cpl bit */
2112       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2113         {
2114           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2115         }
2116       else
2117         {
2118           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2119           emitcode ("cpl", "c");
2120           outBitC (IC_RESULT (ic));
2121         }
2122       goto release;
2123     }
2124
2125   toBoolean (IC_LEFT (ic));
2126
2127   /* set C, if a == 0 */
2128   tlbl = newiTempLabel (NULL);
2129   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2130   emitcode ("", "!tlabeldef", tlbl->key + 100);
2131   outBitC (IC_RESULT (ic));
2132
2133 release:
2134   /* release the aops */
2135   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2136   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2137 }
2138
2139
2140 /*-----------------------------------------------------------------*/
2141 /* genCpl - generate code for complement                           */
2142 /*-----------------------------------------------------------------*/
2143 static void
2144 genCpl (iCode * ic)
2145 {
2146   int offset = 0;
2147   int size;
2148   symbol *tlbl;
2149   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2150
2151   D(emitcode (";", "genCpl"));
2152
2153   /* assign asmOps to operand & result */
2154   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2155   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2156
2157   /* special case if in bit space */
2158   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2159     {
2160       char *l;
2161
2162       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2163           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2164         {
2165           /* promotion rules are responsible for this strange result:
2166              bit -> int -> ~int -> bit
2167              uchar -> int -> ~int -> bit
2168           */
2169           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2170           goto release;
2171         }
2172
2173       tlbl=newiTempLabel(NULL);
2174       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2175       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2176           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2177           IS_AOP_PREG (IC_LEFT (ic)))
2178         {
2179           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2180         }
2181       else
2182         {
2183           MOVA (l);
2184           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2185         }
2186       emitcode ("", "%05d$:", tlbl->key + 100);
2187       outBitC (IC_RESULT(ic));
2188       goto release;
2189     }
2190
2191   size = AOP_SIZE (IC_RESULT (ic));
2192   _startLazyDPSEvaluation ();
2193   while (size--)
2194     {
2195       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2196       MOVA (l);
2197       emitcode ("cpl", "a");
2198       aopPut (IC_RESULT (ic), "a", offset++);
2199     }
2200   _endLazyDPSEvaluation ();
2201
2202
2203 release:
2204   /* release the aops */
2205   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2206   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2207 }
2208
2209 /*-----------------------------------------------------------------*/
2210 /* genUminusFloat - unary minus for floating points                */
2211 /*-----------------------------------------------------------------*/
2212 static void
2213 genUminusFloat (operand * op, operand * result)
2214 {
2215   int size, offset = 0;
2216   char *l;
2217
2218   D(emitcode (";", "genUminusFloat"));
2219
2220   /* for this we just copy and then flip the bit */
2221
2222   _startLazyDPSEvaluation ();
2223   size = AOP_SIZE (op) - 1;
2224
2225   while (size--)
2226     {
2227       aopPut (result,
2228               aopGet (op, offset, FALSE, FALSE, NULL),
2229               offset);
2230       offset++;
2231     }
2232
2233   l = aopGet (op, offset, FALSE, FALSE, NULL);
2234   MOVA (l);
2235
2236   emitcode ("cpl", "acc.7");
2237   aopPut (result, "a", offset);
2238   _endLazyDPSEvaluation ();
2239 }
2240
2241 /*-----------------------------------------------------------------*/
2242 /* genUminus - unary minus code generation                         */
2243 /*-----------------------------------------------------------------*/
2244 static void
2245 genUminus (iCode * ic)
2246 {
2247   int offset, size;
2248   sym_link *optype;
2249
2250   D (emitcode (";", "genUminus "));
2251
2252   /* assign asmops */
2253   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2254   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2255
2256   /* if both in bit space then special
2257      case */
2258   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2259       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2260     {
2261
2262       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2263       emitcode ("cpl", "c");
2264       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2265       goto release;
2266     }
2267
2268   optype = operandType (IC_LEFT (ic));
2269
2270   /* if float then do float stuff */
2271   if (IS_FLOAT (optype))
2272     {
2273       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2274       goto release;
2275     }
2276
2277   /* otherwise subtract from zero */
2278   size = AOP_SIZE (IC_LEFT (ic));
2279   offset = 0;
2280   _startLazyDPSEvaluation ();
2281   while (size--)
2282     {
2283       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2284       if (!strcmp (l, "a"))
2285         {
2286           if (offset == 0)
2287             SETC;
2288           emitcode ("cpl", "a");
2289           emitcode ("addc", "a,#0");
2290         }
2291       else
2292         {
2293           if (offset == 0)
2294             CLRC;
2295           emitcode ("clr", "a");
2296           emitcode ("subb", "a,%s", l);
2297         }
2298       aopPut (IC_RESULT (ic), "a", offset++);
2299     }
2300   _endLazyDPSEvaluation ();
2301
2302   /* if any remaining bytes in the result */
2303   /* we just need to propagate the sign   */
2304   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))) != 0)
2305     {
2306       emitcode ("rlc", "a");
2307       emitcode ("subb", "a,acc");
2308       while (size--)
2309         aopPut (IC_RESULT (ic), "a", offset++);
2310     }
2311
2312 release:
2313   /* release the aops */
2314   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2315   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2316 }
2317
2318 /*-----------------------------------------------------------------*/
2319 /* savermask - saves registers in the mask                         */
2320 /*-----------------------------------------------------------------*/
2321 static void savermask(bitVect *rs_mask)
2322 {
2323   int i;
2324   if (options.useXstack)
2325     {
2326       if (bitVectBitValue (rs_mask, R0_IDX))
2327           emitcode ("mov", "b,r0");
2328       emitcode ("mov", "r0,%s", spname);
2329       for (i = 0; i < ds390_nRegs; i++)
2330         {
2331           if (bitVectBitValue (rs_mask, i))
2332             {
2333               if (i == R0_IDX)
2334                   emitcode ("mov", "a,b");
2335               else
2336                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2337               emitcode ("movx", "@r0,a");
2338               emitcode ("inc", "r0");
2339             }
2340         }
2341       emitcode ("mov", "%s,r0", spname);
2342       if (bitVectBitValue (rs_mask, R0_IDX))
2343           emitcode ("mov", "r0,b");
2344     }
2345   else
2346     {
2347       bool bits_pushed = FALSE;
2348       for (i = 0; i < ds390_nRegs; i++)
2349         {
2350           if (bitVectBitValue (rs_mask, i))
2351             {
2352               bits_pushed = pushReg (i, bits_pushed);
2353             }
2354         }
2355     }
2356 }
2357
2358 /*-----------------------------------------------------------------*/
2359 /* saveRegisters - will look for a call and save the registers     */
2360 /*-----------------------------------------------------------------*/
2361 static void
2362 saveRegisters (iCode * lic)
2363 {
2364   iCode *ic;
2365   bitVect *rsave;
2366
2367   /* look for call */
2368   for (ic = lic; ic; ic = ic->next)
2369     if (ic->op == CALL || ic->op == PCALL)
2370       break;
2371
2372   if (!ic)
2373     {
2374       fprintf (stderr, "found parameter push with no function call\n");
2375       return;
2376     }
2377
2378   /* if the registers have been saved already or don't need to be then
2379      do nothing */
2380   if (ic->regsSaved
2381       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2382     return ;
2383
2384   /* special case if DPTR alive across a function call then must save it
2385      even though callee saves */
2386   if (IS_SYMOP(IC_LEFT(ic)) &&
2387       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2388     {
2389       int i;
2390       rsave = newBitVect(ic->rMask->size);
2391       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2392           if (bitVectBitValue(ic->rMask,i))
2393               rsave = bitVectSetBit(rsave,i);
2394       }
2395       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2396     }
2397   else
2398     {
2399       /* save the registers in use at this time but skip the
2400          ones for the result */
2401       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2402                              ds390_rUmaskForOp (IC_RESULT(ic)));
2403     }
2404   ic->regsSaved = 1;
2405   savermask(rsave);
2406 }
2407
2408 /*-----------------------------------------------------------------*/
2409 /* usavermask - restore registers with mask                        */
2410 /*-----------------------------------------------------------------*/
2411 static void unsavermask(bitVect *rs_mask)
2412 {
2413     int i;
2414     if (options.useXstack) {
2415         emitcode ("mov", "r0,%s", spname);
2416       for (i = ds390_nRegs; i >= 0; i--)
2417         {
2418           if (bitVectBitValue (rs_mask, i))
2419             {
2420               regs * reg = REG_WITH_INDEX (i);
2421               emitcode ("dec", "r0");
2422               emitcode ("movx", "a,@r0");
2423               if (i == R0_IDX)
2424                 {
2425                   emitcode ("push", "acc");
2426                 }
2427               else
2428                 {
2429                   emitcode ("mov", "%s,a", reg->name);
2430                 }
2431             }
2432         }
2433       emitcode ("mov", "%s,r0", spname);
2434       if (bitVectBitValue (rs_mask, R0_IDX))
2435         {
2436           emitcode ("pop", "ar0");
2437         }
2438     }
2439   else
2440     {
2441       bool bits_popped = FALSE;
2442       for (i = ds390_nRegs; i >= 0; i--)
2443         {
2444             if (bitVectBitValue (rs_mask, i))
2445             {
2446               bits_popped = popReg (i, bits_popped);
2447             }
2448         }
2449     }
2450 }
2451
2452 /*-----------------------------------------------------------------*/
2453 /* unsaveRegisters - pop the pushed registers                      */
2454 /*-----------------------------------------------------------------*/
2455 static void
2456 unsaveRegisters (iCode * ic)
2457 {
2458   bitVect *rsave;
2459
2460   if (IS_SYMOP(IC_LEFT (ic)) &&
2461       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2462       int i;
2463       rsave = newBitVect(ic->rMask->size);
2464       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2465           if (bitVectBitValue(ic->rMask,i))
2466               rsave = bitVectSetBit(rsave,i);
2467       }
2468       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2469   } else {
2470     /* restore the registers in use at this time but skip the
2471        ones for the result */
2472     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2473                            ds390_rUmaskForOp (IC_RESULT(ic)));
2474   }
2475   unsavermask(rsave);
2476 }
2477
2478
2479 /*-----------------------------------------------------------------*/
2480 /* pushSide -                */
2481 /*-----------------------------------------------------------------*/
2482 static void
2483 pushSide (operand * oper, int size)
2484 {
2485   int offset = 0;
2486   _startLazyDPSEvaluation ();
2487   while (size--)
2488     {
2489       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2490       if (AOP_TYPE (oper) != AOP_REG &&
2491           AOP_TYPE (oper) != AOP_DIR &&
2492           strcmp (l, "a"))
2493         {
2494           MOVA (l);
2495           emitcode ("push", "acc");
2496         }
2497       else
2498         {
2499         emitcode ("push", "%s", l);
2500     }
2501     }
2502   _endLazyDPSEvaluation ();
2503 }
2504
2505 /*-----------------------------------------------------------------*/
2506 /* assignResultValue - also indicates if acc is in use afterwards  */
2507 /*-----------------------------------------------------------------*/
2508 static bool
2509 assignResultValue (operand * oper, operand * func)
2510 {
2511   int offset = 0;
2512   unsigned size = AOP_SIZE (oper);
2513   bool accuse = FALSE;
2514   bool pushedA = FALSE;
2515
2516   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2517     {
2518       outBitC (oper);
2519       return FALSE;
2520     }
2521
2522   if (size == fReturnSizeDS390)
2523   {
2524       /* I don't think this case can ever happen... */
2525       /* ACC is the last part of this. If writing the result
2526        * uses ACC, we must preserve it.
2527        */
2528       if (AOP_NEEDSACC(oper))
2529       {
2530           emitcode(";", "assignResultValue special case for ACC.");
2531           emitcode("push", "acc");
2532           pushedA = TRUE;
2533           size--;
2534       }
2535   }
2536
2537   _startLazyDPSEvaluation ();
2538   while (size--)
2539     {
2540       accuse |= aopPut (oper, fReturn[offset], offset);
2541       offset++;
2542     }
2543   _endLazyDPSEvaluation ();
2544
2545   if (pushedA)
2546     {
2547         emitcode ("pop", "acc");
2548         accuse |= aopPut (oper, "a", offset);
2549     }
2550   return accuse;
2551 }
2552
2553
2554 /*-----------------------------------------------------------------*/
2555 /* genXpush - pushes onto the external stack                       */
2556 /*-----------------------------------------------------------------*/
2557 static void
2558 genXpush (iCode * ic)
2559 {
2560   asmop *aop = newAsmop (0);
2561   regs *r;
2562   int size, offset = 0;
2563
2564   D (emitcode (";", "genXpush "));
2565
2566   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2567   r = getFreePtr (ic, &aop, FALSE);
2568
2569   size = AOP_SIZE (IC_LEFT (ic));
2570
2571   if (size == 1)
2572     {
2573       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2574       emitcode ("mov", "%s,_spx", r->name);
2575       emitcode ("inc", "_spx"); // allocate space first
2576       emitcode ("movx", "@%s,a", r->name);
2577     }
2578   else
2579     {
2580       // allocate space first
2581       emitcode ("mov", "%s,_spx", r->name);
2582       MOVA (r->name);
2583       emitcode ("add", "a,#%d", size);
2584       emitcode ("mov", "_spx,a");
2585
2586       _startLazyDPSEvaluation ();
2587       while (size--)
2588         {
2589           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2590           emitcode ("movx", "@%s,a", r->name);
2591           emitcode ("inc", "%s", r->name);
2592         }
2593       _endLazyDPSEvaluation ();
2594     }
2595
2596   freeAsmop (NULL, aop, ic, TRUE);
2597   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2598 }
2599
2600 /*-----------------------------------------------------------------*/
2601 /* genIpush - generate code for pushing this gets a little complex  */
2602 /*-----------------------------------------------------------------*/
2603 static void
2604 genIpush (iCode * ic)
2605 {
2606   int size, offset = 0;
2607   char *l;
2608   char *prev = "";
2609
2610   D (emitcode (";", "genIpush "));
2611
2612   /* if this is not a parm push : ie. it is spill push
2613      and spill push is always done on the local stack */
2614   if (!ic->parmPush)
2615     {
2616
2617       /* and the item is spilt then do nothing */
2618       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2619         return;
2620
2621       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2622       size = AOP_SIZE (IC_LEFT (ic));
2623       /* push it on the stack */
2624       _startLazyDPSEvaluation ();
2625       while (size--)
2626         {
2627           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2628           if (*l == '#')
2629             {
2630               MOVA (l);
2631               l = "acc";
2632             }
2633           emitcode ("push", "%s", l);
2634         }
2635       _endLazyDPSEvaluation ();
2636       return;
2637     }
2638
2639   /* this is a parameter push: in this case we call
2640      the routine to find the call and save those
2641      registers that need to be saved */
2642   saveRegisters (ic);
2643
2644   /* if use external stack then call the external
2645      stack pushing routine */
2646   if (options.useXstack)
2647     {
2648       genXpush (ic);
2649       return;
2650     }
2651
2652   /* then do the push */
2653   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2654
2655   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2656   size = AOP_SIZE (IC_LEFT (ic));
2657
2658   _startLazyDPSEvaluation ();
2659   while (size--)
2660     {
2661       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2662       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2663           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2664           strcmp (l, "acc"))
2665         {
2666           if (strcmp (l, prev) || *l == '@')
2667             MOVA (l);
2668           emitcode ("push", "acc");
2669         }
2670       else
2671         {
2672             emitcode ("push", "%s", l);
2673         }
2674       prev = l;
2675     }
2676   _endLazyDPSEvaluation ();
2677
2678   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2679 }
2680
2681 /*-----------------------------------------------------------------*/
2682 /* genIpop - recover the registers: can happen only for spilling   */
2683 /*-----------------------------------------------------------------*/
2684 static void
2685 genIpop (iCode * ic)
2686 {
2687   int size, offset;
2688
2689   D (emitcode (";", "genIpop "));
2690
2691   /* if the temp was not pushed then */
2692   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2693     return;
2694
2695   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2696   size = AOP_SIZE (IC_LEFT (ic));
2697   offset = (size - 1);
2698   _startLazyDPSEvaluation ();
2699   while (size--)
2700     {
2701       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2702                                      FALSE, TRUE, NULL));
2703     }
2704   _endLazyDPSEvaluation ();
2705
2706   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2707 }
2708
2709 /*-----------------------------------------------------------------*/
2710 /* saveRBank - saves an entire register bank on the stack          */
2711 /*-----------------------------------------------------------------*/
2712 static void
2713 saveRBank (int bank, iCode * ic, bool pushPsw)
2714 {
2715   int i;
2716   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2717   asmop *aop = NULL;
2718   regs *r = NULL;
2719
2720   if (options.useXstack)
2721   {
2722       if (!ic)
2723       {
2724           /* Assume r0 is available for use. */
2725           r = REG_WITH_INDEX (R0_IDX);;
2726       }
2727       else
2728       {
2729           aop = newAsmop (0);
2730           r = getFreePtr (ic, &aop, FALSE);
2731       }
2732       // allocate space first
2733       emitcode ("mov", "%s,_spx", r->name);
2734       MOVA (r->name);
2735       emitcode ("add", "a,#%d", count);
2736       emitcode ("mov", "_spx,a");
2737   }
2738
2739   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2740     {
2741       if (options.useXstack)
2742       {
2743           emitcode ("mov", "a,(%s+%d)",
2744                     regs390[i].base, 8 * bank + regs390[i].offset);
2745           emitcode ("movx", "@%s,a", r->name);
2746           if (--count)
2747             emitcode ("inc", "%s", r->name);
2748         }
2749       else
2750         emitcode ("push", "(%s+%d)",
2751                   regs390[i].base, 8 * bank + regs390[i].offset);
2752     }
2753
2754   if (ds390_nBitRegs > 0)
2755     {
2756       if (options.useXstack)
2757         {
2758           emitcode ("mov", "a,bits");
2759           emitcode ("movx", "@%s,a", r->name);
2760           if (--count)
2761             emitcode ("inc", "%s", r->name);
2762         }
2763       else
2764         {
2765           emitcode ("push", "bits");
2766         }
2767       BitBankUsed = 1;
2768     }
2769
2770   if (pushPsw)
2771     {
2772       if (options.useXstack)
2773         {
2774           emitcode ("mov", "a,psw");
2775           emitcode ("movx", "@%s,a", r->name);
2776         }
2777       else
2778       {
2779         emitcode ("push", "psw");
2780     }
2781
2782       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2783     }
2784
2785   if (aop)
2786   {
2787       freeAsmop (NULL, aop, ic, TRUE);
2788   }
2789
2790   if (ic)
2791   {
2792     ic->bankSaved = 1;
2793   }
2794 }
2795
2796 /*-----------------------------------------------------------------*/
2797 /* unsaveRBank - restores the register bank from stack             */
2798 /*-----------------------------------------------------------------*/
2799 static void
2800 unsaveRBank (int bank, iCode * ic, bool popPsw)
2801 {
2802   int i;
2803   asmop *aop = NULL;
2804   regs *r = NULL;
2805
2806   if (options.useXstack)
2807     {
2808         if (!ic)
2809         {
2810           /* Assume r0 is available for use. */
2811           r = REG_WITH_INDEX (R0_IDX);;
2812         }
2813         else
2814         {
2815           aop = newAsmop (0);
2816           r = getFreePtr (ic, &aop, FALSE);
2817         }
2818         emitcode ("mov", "%s,_spx", r->name);
2819     }
2820
2821   if (popPsw)
2822     {
2823       if (options.useXstack)
2824         {
2825           emitcode ("dec", "%s", r->name);
2826           emitcode ("movx", "a,@%s", r->name);
2827           emitcode ("mov", "psw,a");
2828         }
2829       else
2830       {
2831         emitcode ("pop", "psw");
2832       }
2833     }
2834
2835   if (ds390_nBitRegs > 0)
2836     {
2837       if (options.useXstack)
2838         {
2839           emitcode ("dec", "%s", r->name);
2840           emitcode ("movx", "a,@%s", r->name);
2841           emitcode ("mov", "bits,a");
2842         }
2843       else
2844         {
2845           emitcode ("pop", "bits");
2846         }
2847     }
2848
2849   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2850     {
2851       if (options.useXstack)
2852         {
2853           emitcode ("dec", "%s", r->name);
2854           emitcode ("movx", "a,@%s", r->name);
2855           emitcode ("mov", "(%s+%d),a",
2856                     regs390[i].base, 8 * bank + regs390[i].offset);
2857         }
2858       else
2859         {
2860           emitcode ("pop", "(%s+%d)",
2861                   regs390[i].base, 8 * bank + regs390[i].offset);
2862         }
2863     }
2864
2865   if (options.useXstack)
2866     {
2867       emitcode ("mov", "_spx,%s", r->name);
2868     }
2869
2870   if (aop)
2871   {
2872     freeAsmop (NULL, aop, ic, TRUE);
2873   }
2874 }
2875
2876 /*-----------------------------------------------------------------*/
2877 /* genSend - gen code for SEND                                     */
2878 /*-----------------------------------------------------------------*/
2879 static void genSend(set *sendSet)
2880 {
2881     iCode *sic;
2882   int bit_count = 0;
2883     int sendCount = 0 ;
2884     static int rb1_count = 0;
2885
2886   /* first we do all bit parameters */
2887     for (sic = setFirstItem (sendSet); sic;
2888        sic = setNextItem (sendSet))
2889     {
2890       if (sic->argreg > 12)
2891         {
2892           int bit = sic->argreg-13;
2893
2894           aopOp (IC_LEFT (sic), sic, FALSE,
2895                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2896
2897           /* if left is a literal then
2898              we know what the value is */
2899           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2900             {
2901               if (((int) operandLitValue (IC_LEFT (sic))))
2902                   emitcode ("setb", "b[%d]", bit);
2903               else
2904                   emitcode ("clr", "b[%d]", bit);
2905             }
2906           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2907             {
2908               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2909                 if (strcmp (l, "c"))
2910                     emitcode ("mov", "c,%s", l);
2911                 emitcode ("mov", "b[%d],c", bit);
2912             }
2913           else
2914             {
2915               /* we need to or */
2916               toBoolean (IC_LEFT (sic));
2917               /* set C, if a >= 1 */
2918               emitcode ("add", "a,#0xff");
2919               emitcode ("mov", "b[%d],c", bit);
2920             }
2921           bit_count++;
2922           BitBankUsed = 1;
2923
2924           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2925         }
2926     }
2927
2928   if (bit_count)
2929     {
2930       saveRegisters (setFirstItem (sendSet));
2931       emitcode ("mov", "bits,b");
2932     }
2933
2934   /* then we do all other parameters */
2935   for (sic = setFirstItem (sendSet); sic;
2936        sic = setNextItem (sendSet))
2937     {
2938       if (sic->argreg <= 12)
2939       {
2940         int size, offset = 0;
2941
2942         size=getSize(operandType(IC_LEFT(sic)));
2943         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2944         if (sendCount == 0) { /* first parameter */
2945             // we know that dpl(hxb) is the result, so
2946             rb1_count = 0 ;
2947             _startLazyDPSEvaluation ();
2948             if (size>1) {
2949                 aopOp (IC_LEFT (sic), sic, FALSE,
2950                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2951             } else {
2952                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2953             }
2954             while (size--)
2955               {
2956                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2957                 if (strcmp (l, fReturn[offset]))
2958                   {
2959                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2960                 }
2961                 offset++;
2962             }
2963             _endLazyDPSEvaluation ();
2964             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2965             rb1_count =0;
2966         } else { /* if more parameter in registers */
2967             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2968             while (size--) {
2969                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2970                                                                 FALSE, FALSE, NULL));
2971             }
2972             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2973         }
2974         sendCount++;
2975       }
2976     }
2977 }
2978
2979 static void
2980 adjustEsp(const char *reg)
2981 {
2982     emitcode ("anl","%s,#3", reg);
2983     if (TARGET_IS_DS400)
2984     {
2985         emitcode ("orl","%s,#!constbyte",
2986                   reg,
2987                   (options.stack_loc >> 8) & 0xff);
2988     }
2989 }
2990
2991 /*-----------------------------------------------------------------*/
2992 /* selectRegBank - emit code to select the register bank           */
2993 /*-----------------------------------------------------------------*/
2994 static void
2995 selectRegBank (short bank, bool keepFlags)
2996 {
2997   /* if f.e. result is in carry */
2998   if (keepFlags)
2999     {
3000       emitcode ("anl", "psw,#0xE7");
3001       if (bank)
3002         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
3003     }
3004   else
3005     {
3006       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
3007     }
3008 }
3009
3010 /*-----------------------------------------------------------------*/
3011 /* genCall - generates a call statement                            */
3012 /*-----------------------------------------------------------------*/
3013 static void
3014 genCall (iCode * ic)
3015 {
3016   sym_link *dtype;
3017   sym_link *etype;
3018   bool restoreBank = FALSE;
3019   bool swapBanks = FALSE;
3020   bool accuse = FALSE;
3021   bool accPushed = FALSE;
3022   bool resultInF0 = FALSE;
3023   bool assignResultGenerated = FALSE;
3024
3025   D (emitcode (";", "genCall "));
3026
3027   /* if we are calling a not _naked function that is not using
3028      the same register bank then we need to save the
3029      destination registers on the stack */
3030   dtype = operandType (IC_LEFT (ic));
3031   etype = getSpec(dtype);
3032   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3033       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3034       IFFUNC_ISISR (currFunc->type))
3035   {
3036       if (!ic->bankSaved)
3037       {
3038            /* This is unexpected; the bank should have been saved in
3039             * genFunction.
3040             */
3041            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3042            restoreBank = TRUE;
3043       }
3044       swapBanks = TRUE;
3045   }
3046
3047     /* if caller saves & we have not saved then */
3048     if (!ic->regsSaved)
3049       saveRegisters (ic);
3050
3051   /* if send set is not empty then assign */
3052   /* We've saved all the registers we care about;
3053   * therefore, we may clobber any register not used
3054   * in the calling convention (i.e. anything not in
3055   * fReturn.
3056   */
3057   if (_G.sendSet)
3058     {
3059         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3060             genSend(reverseSet(_G.sendSet));
3061         } else {
3062             genSend(_G.sendSet);
3063         }
3064       _G.sendSet = NULL;
3065     }
3066
3067   if (swapBanks)
3068   {
3069         emitcode ("mov", "psw,#!constbyte",
3070            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3071   }
3072
3073   /* make the call */
3074   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3075                             OP_SYMBOL (IC_LEFT (ic))->rname :
3076                             OP_SYMBOL (IC_LEFT (ic))->name));
3077
3078   if (swapBanks)
3079     {
3080       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3081     }
3082
3083   /* if we need assign a result value */
3084   if ((IS_ITEMP (IC_RESULT (ic)) &&
3085        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3086        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3087         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3088         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3089       IS_TRUE_SYMOP (IC_RESULT (ic)))
3090     {
3091       if (isOperandInFarSpace (IC_RESULT (ic))
3092           && getSize (operandType (IC_RESULT (ic))) <= 2)
3093         {
3094           int size = getSize (operandType (IC_RESULT (ic)));
3095           bool pushedB = FALSE;
3096
3097           /* Special case for 1 or 2 byte return in far space. */
3098           MOVA (fReturn[0]);
3099           if (size > 1)
3100             {
3101               pushedB = pushB ();
3102               emitcode ("mov", "b,%s", fReturn[1]);
3103             }
3104
3105           _G.accInUse++;
3106           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3107           _G.accInUse--;
3108
3109           popB (pushedB);
3110
3111           aopPut (IC_RESULT (ic), "a", 0);
3112
3113           if (size > 1)
3114             {
3115               aopPut (IC_RESULT (ic), "b", 1);
3116             }
3117           assignResultGenerated = TRUE;
3118           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3119         }
3120       else
3121         {
3122           bool pushedB = pushB ();
3123           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3124           popB (pushedB);
3125
3126           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3127           assignResultGenerated = TRUE;
3128           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3129         }
3130     }
3131
3132   /* adjust the stack for parameters if required */
3133   if (ic->parmBytes)
3134     {
3135       int i;
3136       if (options.stack10bit) {
3137           if (ic->parmBytes <= 10) {
3138               emitcode(";","stack adjustment for parms");
3139               for (i=0; i < ic->parmBytes ; i++) {
3140                   emitcode("pop","acc");
3141               }
3142           } else {
3143               PROTECT_SP;
3144               emitcode ("clr","c");
3145               emitcode ("mov","a,sp");
3146               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3147               emitcode ("mov","sp,a");
3148               emitcode ("mov","a,esp");
3149               adjustEsp("a");
3150               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3151               emitcode ("mov","esp,a");
3152               UNPROTECT_SP;
3153           }
3154       } else {
3155           if (ic->parmBytes > 3)
3156             {
3157               if (accuse)
3158                 {
3159                   emitcode ("push", "acc");
3160                   accPushed = TRUE;
3161                 }
3162             if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3163                 IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3164                 !assignResultGenerated)
3165               {
3166                 emitcode ("mov", "F0,c");
3167                 resultInF0 = TRUE;
3168               }
3169               emitcode ("mov", "a,%s", spname);
3170               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3171               emitcode ("mov", "%s,a", spname);
3172
3173               /* unsaveRegisters from xstack needs acc, but */
3174               /* unsaveRegisters from stack needs this popped */
3175               if (accPushed && !options.useXstack)
3176                 {
3177                   emitcode ("pop", "acc");
3178                   accPushed = FALSE;
3179                 }
3180             }
3181           else
3182               for (i = 0; i < ic->parmBytes; i++)
3183                   emitcode ("dec", "%s", spname);
3184       }
3185   }
3186
3187   /* if we had saved some registers then unsave them */
3188   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3189     {
3190       if (accuse && !accPushed && options.useXstack)
3191         {
3192           /* xstack needs acc, but doesn't touch normal stack */
3193           emitcode ("push", "acc");
3194           accPushed = TRUE;
3195         }
3196       unsaveRegisters (ic);
3197     }
3198
3199   /* if register bank was saved then pop them */
3200   if (restoreBank)
3201     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3202
3203   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3204     {
3205       if (resultInF0)
3206           emitcode ("mov", "c,F0");
3207
3208       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3209       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3210       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3211     }
3212
3213   if (accPushed)
3214     emitcode ("pop", "acc");
3215 }
3216
3217 /*-----------------------------------------------------------------*/
3218 /* genPcall - generates a call by pointer statement                */
3219 /*-----------------------------------------------------------------*/
3220 static void
3221 genPcall (iCode * ic)
3222 {
3223   sym_link *dtype;
3224   sym_link *etype;
3225   symbol *rlbl = newiTempLabel (NULL);
3226   bool restoreBank=FALSE;
3227   bool resultInF0 = FALSE;
3228
3229   D (emitcode (";", "genPcall "));
3230
3231   dtype = operandType (IC_LEFT (ic))->next;
3232   etype = getSpec(dtype);
3233   /* if caller saves & we have not saved then */
3234   if (!ic->regsSaved)
3235     saveRegisters (ic);
3236
3237   /* if we are calling a not _naked function that is not using
3238      the same register bank then we need to save the
3239      destination registers on the stack */
3240   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3241       IFFUNC_ISISR (currFunc->type) &&
3242       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3243     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3244     restoreBank=TRUE;
3245   }
3246
3247   /* push the return address on to the stack */
3248   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3249   emitcode ("push", "acc");
3250   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3251   emitcode ("push", "acc");
3252
3253   if (options.model == MODEL_FLAT24)
3254     {
3255       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3256       emitcode ("push", "acc");
3257     }
3258
3259   /* now push the calling address */
3260   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3261
3262   pushSide (IC_LEFT (ic), FPTRSIZE);
3263
3264   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3265
3266   /* if send set is not empty the assign */
3267   if (_G.sendSet)
3268     {
3269         genSend(reverseSet(_G.sendSet));
3270         _G.sendSet = NULL;
3271     }
3272
3273   emitcode ("ret", "");
3274   emitcode ("", "!tlabeldef", (rlbl->key + 100));
3275
3276
3277   /* if we need assign a result value */
3278   if ((IS_ITEMP (IC_RESULT (ic)) &&
3279        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3280        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3281         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3282       IS_TRUE_SYMOP (IC_RESULT (ic)))
3283     {
3284
3285       _G.accInUse++;
3286       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3287       _G.accInUse--;
3288
3289       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3290
3291       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3292     }
3293
3294   /* adjust the stack for parameters if required */
3295   if (ic->parmBytes)
3296     {
3297       int i;
3298       if (options.stack10bit) {
3299           if (ic->parmBytes <= 10) {
3300               emitcode(";","stack adjustment for parms");
3301               for (i=0; i < ic->parmBytes ; i++) {
3302                   emitcode("pop","acc");
3303               }
3304           } else {
3305               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3306                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3307                 {
3308                   emitcode ("mov", "F0,c");
3309                   resultInF0 = TRUE;
3310                 }
3311
3312               PROTECT_SP;
3313               emitcode ("clr","c");
3314               emitcode ("mov","a,sp");
3315               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3316               emitcode ("mov","sp,a");
3317               emitcode ("mov","a,esp");
3318               adjustEsp("a");
3319               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3320               emitcode ("mov","esp,a");
3321               UNPROTECT_SP;
3322           }
3323       } else {
3324           if (ic->parmBytes > 3) {
3325               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3326                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3327                 {
3328                   emitcode ("mov", "F0,c");
3329                   resultInF0 = TRUE;
3330                 }
3331
3332               emitcode ("mov", "a,%s", spname);
3333               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3334               emitcode ("mov", "%s,a", spname);
3335             }
3336           else
3337               for (i = 0; i < ic->parmBytes; i++)
3338                   emitcode ("dec", "%s", spname);
3339       }
3340     }
3341   /* if register bank was saved then unsave them */
3342   if (restoreBank)
3343     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3344
3345   /* if we had saved some registers then unsave them */
3346   if (ic->regsSaved)
3347     unsaveRegisters (ic);
3348
3349   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3350     {
3351       if (resultInF0)
3352           emitcode ("mov", "c,F0");
3353
3354       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3355       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3356       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3357     }
3358 }
3359
3360 /*-----------------------------------------------------------------*/
3361 /* resultRemat - result  is rematerializable                       */
3362 /*-----------------------------------------------------------------*/
3363 static int
3364 resultRemat (iCode * ic)
3365 {
3366   if (SKIP_IC (ic) || ic->op == IFX)
3367     return 0;
3368
3369   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3370     {
3371       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3372       if (sym->remat && !POINTER_SET (ic))
3373         return 1;
3374     }
3375
3376   return 0;
3377 }
3378
3379 #if defined(__BORLANDC__) || defined(_MSC_VER)
3380 #define STRCASECMP stricmp
3381 #else
3382 #define STRCASECMP strcasecmp
3383 #endif
3384
3385 /*-----------------------------------------------------------------*/
3386 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3387 /*-----------------------------------------------------------------*/
3388 static int
3389 regsCmp(void *p1, void *p2)
3390 {
3391   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3392 }
3393
3394 static bool
3395 inExcludeList (char *s)
3396 {
3397   const char *p = setFirstItem(options.excludeRegsSet);
3398
3399   if (p == NULL || STRCASECMP(p, "none") == 0)
3400     return FALSE;
3401
3402
3403   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3404 }
3405
3406 /*-----------------------------------------------------------------*/
3407 /* genFunction - generated code for function entry                 */
3408 /*-----------------------------------------------------------------*/
3409 static void
3410 genFunction (iCode * ic)
3411 {
3412   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3413   sym_link *ftype;
3414   bool   switchedPSW = FALSE;
3415   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3416
3417   D (emitcode (";", "genFunction "));
3418
3419   _G.nRegsSaved = 0;
3420   /* create the function header */
3421   emitcode (";", "-----------------------------------------");
3422   emitcode (";", " function %s", sym->name);
3423   emitcode (";", "-----------------------------------------");
3424
3425   emitcode ("", "%s:", sym->rname);
3426   ftype = operandType (IC_LEFT (ic));
3427   _G.currentFunc = sym;
3428
3429   if (IFFUNC_ISNAKED(ftype))
3430   {
3431       emitcode(";", "naked function: no prologue.");
3432       return;
3433   }
3434
3435   if (options.stack_probe)
3436       emitcode ("lcall","__stack_probe");
3437
3438   /* here we need to generate the equates for the
3439      register bank if required */
3440   if (FUNC_REGBANK (ftype) != rbank)
3441     {
3442       int i;
3443
3444       rbank = FUNC_REGBANK (ftype);
3445       for (i = 0; i < ds390_nRegs; i++)
3446         {
3447           if (regs390[i].print) {
3448               if (strcmp (regs390[i].base, "0") == 0)
3449                   emitcode ("", "%s !equ !constbyte",
3450                             regs390[i].dname,
3451                             8 * rbank + regs390[i].offset);
3452               else
3453                   emitcode ("", "%s !equ %s + !constbyte",
3454                             regs390[i].dname,
3455                             regs390[i].base,
3456                             8 * rbank + regs390[i].offset);
3457           }
3458         }
3459     }
3460
3461   /* if this is an interrupt service routine then
3462      save acc, b, dpl, dph  */
3463   if (IFFUNC_ISISR (sym->type))
3464       { /* is ISR */
3465       if (!inExcludeList ("acc"))
3466         emitcode ("push", "acc");
3467       if (!inExcludeList ("b"))
3468         emitcode ("push", "b");
3469       if (!inExcludeList ("dpl"))
3470         emitcode ("push", "dpl");
3471       if (!inExcludeList ("dph"))
3472         emitcode ("push", "dph");
3473       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3474         {
3475           emitcode ("push", "dpx");
3476           /* Make sure we're using standard DPTR */
3477           emitcode ("push", "dps");
3478           emitcode ("mov", "dps,#0");
3479           if (options.stack10bit)
3480             {
3481               /* This ISR could conceivably use DPTR2. Better save it. */
3482               emitcode ("push", "dpl1");
3483               emitcode ("push", "dph1");
3484               emitcode ("push", "dpx1");
3485               emitcode ("push",  DP2_RESULT_REG);
3486             }
3487         }
3488       /* if this isr has no bank i.e. is going to
3489          run with bank 0 , then we need to save more
3490          registers :-) */
3491       if (!FUNC_REGBANK (sym->type))
3492         {
3493             int i;
3494
3495           /* if this function does not call any other
3496              function then we can be economical and
3497              save only those registers that are used */
3498           if (!IFFUNC_HASFCALL(sym->type))
3499             {
3500               /* if any registers used */
3501               if (sym->regsUsed)
3502                 {
3503                   bool bits_pushed = FALSE;
3504                   /* save the registers used */
3505                   for (i = 0; i < sym->regsUsed->size; i++)
3506                     {
3507                       if (bitVectBitValue (sym->regsUsed, i))
3508                         bits_pushed = pushReg (i, bits_pushed);
3509                     }
3510                 }
3511             }
3512           else
3513             {
3514               /* this function has a function call. We cannot
3515                  determine register usage so we will have to push the
3516                  entire bank */
3517               saveRBank (0, ic, FALSE);
3518               if (options.parms_in_bank1) {
3519                   for (i=0; i < 8 ; i++ ) {
3520                       emitcode ("push","%s",rb1regs[i]);
3521                   }
3522               }
3523             }
3524         }
3525         else
3526         {
3527             /* This ISR uses a non-zero bank.
3528              *
3529              * We assume that the bank is available for our
3530              * exclusive use.
3531              *
3532              * However, if this ISR calls a function which uses some
3533              * other bank, we must save that bank entirely.
3534              */
3535             unsigned long banksToSave = 0;
3536
3537             if (IFFUNC_HASFCALL(sym->type))
3538             {
3539
3540 #define MAX_REGISTER_BANKS 4
3541
3542                 iCode *i;
3543                 int ix;
3544
3545                 for (i = ic; i; i = i->next)
3546                 {
3547                     if (i->op == ENDFUNCTION)
3548                     {
3549                         /* we got to the end OK. */
3550                         break;
3551                     }
3552
3553                     if (i->op == CALL)
3554                     {
3555                         sym_link *dtype;
3556
3557                         dtype = operandType (IC_LEFT(i));
3558                         if (dtype
3559                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3560                         {
3561                              /* Mark this bank for saving. */
3562                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3563                              {
3564                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3565                              }
3566                              else
3567                              {
3568                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3569                              }
3570
3571                              /* And note that we don't need to do it in
3572                               * genCall.
3573                               */
3574                              i->bankSaved = 1;
3575                         }
3576                     }
3577                     if (i->op == PCALL)
3578                     {
3579                         /* This is a mess; we have no idea what
3580                          * register bank the called function might
3581                          * use.
3582                          *
3583                          * The only thing I can think of to do is
3584                          * throw a warning and hope.
3585                          */
3586                         werror(W_FUNCPTR_IN_USING_ISR);
3587                     }
3588                 }
3589
3590                 if (banksToSave && options.useXstack)
3591                 {
3592                     /* Since we aren't passing it an ic,
3593                      * saveRBank will assume r0 is available to abuse.
3594                      *
3595                      * So switch to our (trashable) bank now, so
3596                      * the caller's R0 isn't trashed.
3597                      */
3598                     emitcode ("push", "psw");
3599                     emitcode ("mov", "psw,#!constbyte",
3600                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3601                     switchedPSW = TRUE;
3602                 }
3603
3604                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3605                 {
3606                      if (banksToSave & (1 << ix))
3607                      {
3608                          saveRBank(ix, NULL, FALSE);
3609                      }
3610                 }
3611             }
3612             // TODO: this needs a closer look
3613             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3614         }
3615     }
3616   else
3617     {
3618       /* if callee-save to be used for this function
3619          then save the registers being used in this function */
3620       if (IFFUNC_CALLEESAVES(sym->type))
3621         {
3622           int i;
3623
3624           /* if any registers used */
3625           if (sym->regsUsed)
3626             {
3627               bool bits_pushed = FALSE;
3628               /* save the registers used */
3629               for (i = 0; i < sym->regsUsed->size; i++)
3630                 {
3631                   if (bitVectBitValue (sym->regsUsed, i))
3632                     {
3633                       bits_pushed = pushReg (i, bits_pushed);
3634                       _G.nRegsSaved++;
3635                     }
3636                 }
3637             }
3638         }
3639     }
3640
3641   /* set the register bank to the desired value */
3642   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3643    && !switchedPSW)
3644     {
3645       emitcode ("push", "psw");
3646       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3647     }
3648
3649   if (fReentrant &&
3650        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3651       if (options.stack10bit) {
3652           emitcode ("push","_bpx");
3653           emitcode ("push","_bpx+1");
3654           emitcode ("mov","_bpx,%s",spname);
3655           emitcode ("mov","_bpx+1,esp");
3656           adjustEsp("_bpx+1");
3657       } else {
3658           if (options.useXstack)
3659           {
3660               emitcode ("mov", "r0,%s", spname);
3661               emitcode ("mov", "a,_bp");
3662               emitcode ("movx", "@r0,a");
3663               emitcode ("inc", "%s", spname);
3664           } else {
3665               /* set up the stack */
3666               emitcode ("push", "_bp"); /* save the callers stack  */
3667           }
3668           emitcode ("mov", "_bp,%s", spname);
3669       }
3670   }
3671
3672   /* adjust the stack for the function */
3673   if (sym->stack) {
3674       int i = sym->stack;
3675       if (options.stack10bit) {
3676           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3677           assert (sym->recvSize <= 4);
3678           if (sym->stack <= 8) {
3679               while (i--) emitcode ("push","acc");
3680           } else {
3681               PROTECT_SP;
3682               emitcode ("mov","a,sp");
3683               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3684               emitcode ("mov","sp,a");
3685               emitcode ("mov","a,esp");
3686               adjustEsp("a");
3687               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3688               emitcode ("mov","esp,a");
3689               UNPROTECT_SP;
3690           }
3691       } else {
3692           if (i > 256)
3693               werror (W_STACK_OVERFLOW, sym->name);
3694
3695           if (i > 3 && sym->recvSize < 4) {
3696
3697               emitcode ("mov", "a,sp");
3698               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3699               emitcode ("mov", "sp,a");
3700
3701           } else
3702               while (i--)
3703                   emitcode ("inc", "sp");
3704       }
3705   }
3706
3707   if (sym->xstack)
3708     {
3709
3710       emitcode ("mov", "a,_spx");
3711       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3712       emitcode ("mov", "_spx,a");
3713     }
3714
3715   /* if critical function then turn interrupts off */
3716   if (IFFUNC_ISCRITICAL (ftype))
3717     {
3718       symbol *tlbl = newiTempLabel (NULL);
3719       emitcode ("setb", "c");
3720       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3721       emitcode ("clr", "c");
3722       emitcode ("", "%05d$:", (tlbl->key + 100));
3723       emitcode ("push", "psw"); /* save old ea via c in psw */
3724     }
3725 }
3726
3727 /*-----------------------------------------------------------------*/
3728 /* genEndFunction - generates epilogue for functions               */
3729 /*-----------------------------------------------------------------*/
3730 static void
3731 genEndFunction (iCode * ic)
3732 {
3733   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3734   lineNode *lnp = lineCurr;
3735   bitVect *regsUsed;
3736   bitVect *regsUsedPrologue;
3737   bitVect *regsUnneeded;
3738   int idx;
3739
3740   D (emitcode (";", "genEndFunction "););
3741
3742   _G.currentFunc = NULL;
3743   if (IFFUNC_ISNAKED(sym->type))
3744   {
3745       emitcode(";", "naked function: no epilogue.");
3746       if (options.debug && currFunc)
3747         debugFile->writeEndFunction (currFunc, ic, 0);
3748       return;
3749   }
3750
3751   if (IFFUNC_ISCRITICAL (sym->type))
3752     {
3753       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3754         {
3755           emitcode ("rlc", "a");   /* save c in a */
3756           emitcode ("pop", "psw"); /* restore ea via c in psw */
3757           emitcode ("mov", "ea,c");
3758           emitcode ("rrc", "a");   /* restore c from a */
3759         }
3760       else
3761         {
3762           emitcode ("pop", "psw"); /* restore ea via c in psw */
3763           emitcode ("mov", "ea,c");
3764         }
3765     }
3766
3767   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3768        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3769
3770       if (options.stack10bit) {
3771           PROTECT_SP;
3772           emitcode ("mov", "sp,_bpx", spname);
3773           emitcode ("mov", "esp,_bpx+1", spname);
3774           UNPROTECT_SP;
3775       } else {
3776           emitcode ("mov", "%s,_bp", spname);
3777       }
3778   }
3779
3780   /* if use external stack but some variables were
3781      added to the local stack then decrement the
3782      local stack */
3783   if (options.useXstack && sym->stack) {
3784       emitcode ("mov", "a,sp");
3785       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3786       emitcode ("mov", "sp,a");
3787   }
3788
3789
3790   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3791        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3792
3793       if (options.useXstack) {
3794           emitcode ("mov", "r0,%s", spname);
3795           emitcode ("movx", "a,@r0");
3796           emitcode ("mov", "_bp,a");
3797           emitcode ("dec", "%s", spname);
3798       } else {
3799           if (options.stack10bit) {
3800               emitcode ("pop", "_bpx+1");
3801               emitcode ("pop", "_bpx");
3802           } else {
3803               emitcode ("pop", "_bp");
3804           }
3805       }
3806   }
3807
3808   /* restore the register bank  */
3809   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3810   {
3811     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3812      || !options.useXstack)
3813     {
3814         /* Special case of ISR using non-zero bank with useXstack
3815          * is handled below.
3816          */
3817         emitcode ("pop", "psw");
3818     }
3819   }
3820
3821   if (IFFUNC_ISISR (sym->type))
3822       { /* is ISR */
3823
3824       /* now we need to restore the registers */
3825       /* if this isr has no bank i.e. is going to
3826          run with bank 0 , then we need to save more
3827          registers :-) */
3828       if (!FUNC_REGBANK (sym->type))
3829         {
3830             int i;
3831           /* if this function does not call any other
3832              function then we can be economical and
3833              save only those registers that are used */
3834           if (!IFFUNC_HASFCALL(sym->type))
3835             {
3836               /* if any registers used */
3837               if (sym->regsUsed)
3838                 {
3839                   bool bits_popped = FALSE;
3840                   /* save the registers used */
3841                   for (i = sym->regsUsed->size; i >= 0; i--)
3842                     {
3843                       if (bitVectBitValue (sym->regsUsed, i))
3844                         bits_popped = popReg (i, bits_popped);
3845                     }
3846                 }
3847             }
3848           else
3849             {
3850               /* this function has a function call. We cannot
3851                  determine register usage so we will have to pop the
3852                  entire bank */
3853               if (options.parms_in_bank1) {
3854                   for (i = 7 ; i >= 0 ; i-- ) {
3855                       emitcode ("pop","%s",rb1regs[i]);
3856                   }
3857               }
3858               unsaveRBank (0, ic, FALSE);
3859             }
3860         }
3861         else
3862         {
3863             /* This ISR uses a non-zero bank.
3864              *
3865              * Restore any register banks saved by genFunction
3866              * in reverse order.
3867              */
3868             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3869             int ix;
3870
3871             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3872             {
3873                 if (savedBanks & (1 << ix))
3874                 {
3875                     unsaveRBank(ix, NULL, FALSE);
3876                 }
3877             }
3878
3879             if (options.useXstack)
3880             {
3881                 /* Restore bank AFTER calling unsaveRBank,
3882                  * since it can trash r0.
3883                  */
3884                 emitcode ("pop", "psw");
3885             }
3886         }
3887
3888       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3889         {
3890           if (options.stack10bit)
3891             {
3892               emitcode ("pop", DP2_RESULT_REG);
3893               emitcode ("pop", "dpx1");
3894               emitcode ("pop", "dph1");
3895               emitcode ("pop", "dpl1");
3896             }
3897           emitcode ("pop", "dps");
3898           emitcode ("pop", "dpx");
3899         }
3900       if (!inExcludeList ("dph"))
3901         emitcode ("pop", "dph");
3902       if (!inExcludeList ("dpl"))
3903         emitcode ("pop", "dpl");
3904       if (!inExcludeList ("b"))
3905         emitcode ("pop", "b");
3906       if (!inExcludeList ("acc"))
3907         emitcode ("pop", "acc");
3908
3909       /* if debug then send end of function */
3910       if (options.debug && currFunc)
3911         {
3912           debugFile->writeEndFunction (currFunc, ic, 1);
3913         }
3914
3915       emitcode ("reti", "");
3916     }
3917   else
3918     {
3919       if (IFFUNC_CALLEESAVES(sym->type))
3920         {
3921           int i;
3922
3923           /* if any registers used */
3924           if (sym->regsUsed)
3925             {
3926               /* save the registers used */
3927               for (i = sym->regsUsed->size; i >= 0; i--)
3928                 {
3929                   if (bitVectBitValue (sym->regsUsed, i))
3930                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3931                 }
3932             }
3933         }
3934
3935       /* if debug then send end of function */
3936       if (options.debug && currFunc)
3937         {
3938           debugFile->writeEndFunction (currFunc, ic, 1);
3939         }
3940
3941       emitcode ("ret", "");
3942     }
3943
3944   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3945     return;
3946
3947   /* If this was an interrupt handler using bank 0 that called another */
3948   /* function, then all registers must be saved; nothing to optimized. */
3949   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3950       && !FUNC_REGBANK(sym->type))
3951     return;
3952
3953   /* There are no push/pops to optimize if not callee-saves or ISR */
3954   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3955     return;
3956
3957   /* If there were stack parameters, we cannot optimize without also    */
3958   /* fixing all of the stack offsets; this is too dificult to consider. */
3959   if (FUNC_HASSTACKPARM(sym->type))
3960     return;
3961
3962   /* Compute the registers actually used */
3963   regsUsed = newBitVect (ds390_nRegs);
3964   regsUsedPrologue = newBitVect (ds390_nRegs);
3965   while (lnp)
3966     {
3967       if (lnp->ic && lnp->ic->op == FUNCTION)
3968         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3969       else
3970         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3971
3972       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3973           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3974         break;
3975       if (!lnp->prev)
3976         break;
3977       lnp = lnp->prev;
3978     }
3979
3980   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3981       && !bitVectBitValue (regsUsed, DPS_IDX))
3982     {
3983       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3984     }
3985
3986   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3987       && !bitVectBitValue (regsUsed, CND_IDX))
3988     {
3989       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3990       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3991           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3992         bitVectUnSetBit (regsUsed, CND_IDX);
3993     }
3994   else
3995     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3996
3997   /* If this was an interrupt handler that called another function */
3998   /* function, then assume working registers may be modified by it. */
3999   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
4000     {
4001       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
4002       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
4003       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
4004       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
4005       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
4006       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
4007       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4008       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
4009       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4010       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4011       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4012     }
4013
4014   /* Remove the unneeded push/pops */
4015   regsUnneeded = newBitVect (ds390_nRegs);
4016   while (lnp)
4017     {
4018       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4019         {
4020           if (!strncmp(lnp->line, "push", 4))
4021             {
4022               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4023               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4024                 {
4025                   connectLine (lnp->prev, lnp->next);
4026                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4027                 }
4028             }
4029           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4030             {
4031               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4032               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4033                 {
4034                   connectLine (lnp->prev, lnp->next);
4035                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4036                 }
4037             }
4038         }
4039       lnp = lnp->next;
4040     }
4041
4042   for (idx = 0; idx < regsUnneeded->size; idx++)
4043     if (bitVectBitValue (regsUnneeded, idx))
4044       emitcode ("", ";\teliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4045
4046   freeBitVect (regsUnneeded);
4047   freeBitVect (regsUsed);
4048   freeBitVect (regsUsedPrologue);
4049 }
4050
4051 /*-----------------------------------------------------------------*/
4052 /* genJavaNativeRet - generate code for return JavaNative          */
4053 /*-----------------------------------------------------------------*/
4054 static void genJavaNativeRet(iCode *ic)
4055 {
4056     int i, size;
4057
4058     aopOp (IC_LEFT (ic), ic, FALSE,
4059            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4060     size = AOP_SIZE (IC_LEFT (ic));
4061
4062     assert (size <= 4);
4063
4064     /* it is assigned to GPR0-R3 then push them */
4065     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4066         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4067         for (i = 0 ; i < size ; i++ ) {
4068             emitcode ("push","%s",
4069                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4070         }
4071         for (i = (size-1) ; i >= 0 ; i--) {
4072             emitcode ("pop","a%s",javaRet[i]);
4073         }
4074     } else {
4075         for (i = 0 ; i < size ; i++)
4076             emitcode ("mov","%s,%s",javaRet[i],
4077                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4078     }
4079     for (i = size ; i < 4 ; i++ )
4080             emitcode ("mov","%s,#0",javaRet[i]);
4081     return;
4082 }
4083
4084 /*-----------------------------------------------------------------*/
4085 /* genRet - generate code for return statement                     */
4086 /*-----------------------------------------------------------------*/
4087 static void
4088 genRet (iCode * ic)
4089 {
4090   int size, offset = 0, pushed = 0;
4091
4092   D (emitcode (";", "genRet"));
4093
4094   /* if we have no return value then
4095      just generate the "ret" */
4096   if (!IC_LEFT (ic))
4097     goto jumpret;
4098
4099   /* if this is a JavaNative function then return
4100      value in different register */
4101   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4102       genJavaNativeRet(ic);
4103       goto jumpret;
4104   }
4105   /* we have something to return then
4106      move the return value into place */
4107   aopOp (IC_LEFT (ic), ic, FALSE,
4108          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4109   size = AOP_SIZE (IC_LEFT (ic));
4110
4111   _startLazyDPSEvaluation ();
4112
4113   if (IS_BIT(_G.currentFunc->etype))
4114     {
4115       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4116       size = 0;
4117     }
4118
4119   while (size--)
4120     {
4121       char *l;
4122       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4123         {
4124           l = aopGet (IC_LEFT (ic), offset++,
4125                       FALSE, TRUE, NULL);
4126           emitcode ("push", "%s", l);
4127           pushed++;
4128         }
4129       else
4130         {
4131           /* Since A is the last element of fReturn,
4132            * it is OK to clobber it in the aopGet.
4133            */
4134           l = aopGet (IC_LEFT (ic), offset,
4135                       FALSE, FALSE, NULL);
4136           if (strcmp (fReturn[offset], l))
4137             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4138         }
4139     }
4140   _endLazyDPSEvaluation ();
4141
4142   while (pushed)
4143     {
4144       pushed--;
4145       if (strcmp (fReturn[pushed], "a"))
4146         emitcode ("pop", fReturn[pushed]);
4147       else
4148         emitcode ("pop", "acc");
4149     }
4150   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4151
4152 jumpret:
4153   /* generate a jump to the return label
4154      if the next is not the return statement */
4155   if (!(ic->next && ic->next->op == LABEL &&
4156         IC_LABEL (ic->next) == returnLabel))
4157
4158     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4159
4160 }
4161
4162 /*-----------------------------------------------------------------*/
4163 /* genLabel - generates a label                                    */
4164 /*-----------------------------------------------------------------*/
4165 static void
4166 genLabel (iCode * ic)
4167 {
4168   /* special case never generate */
4169   if (IC_LABEL (ic) == entryLabel)
4170     return;
4171
4172   D (emitcode (";", "genLabel "));
4173
4174   emitcode ("", "!tlabeldef", (IC_LABEL (ic)->key + 100));
4175 }
4176
4177 /*-----------------------------------------------------------------*/
4178 /* genGoto - generates a ljmp                                      */
4179 /*-----------------------------------------------------------------*/
4180 static void
4181 genGoto (iCode * ic)
4182 {
4183   D (emitcode (";", "genGoto "));
4184
4185   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4186 }
4187
4188 /*-----------------------------------------------------------------*/
4189 /* findLabelBackwards: walks back through the iCode chain looking  */
4190 /* for the given label. Returns number of iCode instructions     */
4191 /* between that label and given ic.          */
4192 /* Returns zero if label not found.          */
4193 /*-----------------------------------------------------------------*/
4194 static int
4195 findLabelBackwards (iCode * ic, int key)
4196 {
4197   int count = 0;
4198
4199   while (ic->prev)
4200     {
4201       ic = ic->prev;
4202       count++;
4203
4204       /* If we have any pushes or pops, we cannot predict the distance.
4205          I don't like this at all, this should be dealt with in the
4206          back-end */
4207       if (ic->op == IPUSH || ic->op == IPOP) {
4208         return 0;
4209       }
4210
4211       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4212         {
4213           /* printf("findLabelBackwards = %d\n", count); */
4214           return count;
4215         }
4216     }
4217
4218   return 0;
4219 }
4220
4221 /*-----------------------------------------------------------------*/
4222 /* genPlusIncr :- does addition with increment if possible         */
4223 /*-----------------------------------------------------------------*/
4224 static bool
4225 genPlusIncr (iCode * ic)
4226 {
4227   unsigned int icount;
4228   unsigned int size = getDataSize (IC_RESULT (ic));
4229
4230   /* will try to generate an increment */
4231   /* if the right side is not a literal
4232      we cannot */
4233   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4234     return FALSE;
4235
4236   /* if the literal value of the right hand side
4237      is greater than 4 then it is not worth it */
4238   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4239     return FALSE;
4240
4241   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4242       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4243       while (icount--) {
4244           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4245       }
4246       return TRUE;
4247   }
4248   /* if increment 16 bits in register */
4249   if (
4250        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4251        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4252        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4253        (size > 1) &&
4254        (icount == 1))
4255     {
4256       symbol  *tlbl;
4257       int     emitTlbl;
4258       int     labelRange;
4259       char    *l;
4260
4261       /* If the next instruction is a goto and the goto target
4262        * is <= 5 instructions previous to this, we can generate
4263        * jumps straight to that target.
4264        */
4265       if (ic->next && ic->next->op == GOTO
4266           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4267           && labelRange <= 5)
4268         {
4269           D(emitcode (";", "tail increment optimized (range %d)", labelRange););
4270           tlbl = IC_LABEL (ic->next);
4271           emitTlbl = 0;
4272         }
4273       else
4274         {
4275           tlbl = newiTempLabel (NULL);
4276           emitTlbl = 1;
4277         }
4278       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4279       emitcode ("inc", "%s", l);
4280
4281       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4282           IS_AOP_PREG (IC_RESULT (ic)))
4283         {
4284           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4285         }
4286       else
4287         {
4288           emitcode ("clr", "a");
4289           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4290         }
4291
4292       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4293       emitcode ("inc", "%s", l);
4294       if (size > 2)
4295         {
4296           if (!strcmp(l, "acc"))
4297             {
4298                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4299             }
4300           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4301                    IS_AOP_PREG (IC_RESULT (ic)))
4302             {
4303                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4304             }
4305           else
4306             {
4307                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4308             }
4309
4310           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4311           emitcode ("inc", "%s", l);
4312         }
4313       if (size > 3)
4314         {
4315           if (!strcmp(l, "acc"))
4316             {
4317                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4318             }
4319           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4320                    IS_AOP_PREG (IC_RESULT (ic)))
4321             {
4322                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4323             }
4324           else
4325             {
4326                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4327             }
4328
4329           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4330           emitcode ("inc", "%s", l);
4331         }
4332
4333       if (emitTlbl)
4334         {
4335           emitcode ("", "!tlabeldef", tlbl->key + 100);
4336         }
4337       return TRUE;
4338     }
4339
4340   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4341       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4342       options.model == MODEL_FLAT24 )
4343     {
4344       if (IC_RESULT(ic)->isGptr)
4345         {
4346           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4347         }
4348       switch (size) {
4349       case 3:
4350           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4351       case 2:
4352           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4353       case 1:
4354           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4355           break;
4356       }
4357       while (icount--)
4358         emitcode ("inc", "dptr");
4359       return TRUE;
4360   }
4361
4362   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4363       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4364       icount <= 5 ) {
4365       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4366       while (icount--)
4367         emitcode ("inc", "dptr");
4368       emitcode ("mov", "dps,#0");
4369       return TRUE;
4370   }
4371
4372   /* if the sizes are greater than 1 then we cannot */
4373   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4374       AOP_SIZE (IC_LEFT (ic)) > 1)
4375     return FALSE;
4376
4377   /* we can if the aops of the left & result match or
4378      if they are in registers and the registers are the
4379      same */
4380   if (
4381        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4382        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4383        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4384     {
4385       if (icount > 3)
4386         {
4387           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4388           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4389           aopPut (IC_RESULT (ic), "a", 0);
4390         }
4391       else
4392         {
4393           _startLazyDPSEvaluation ();
4394           while (icount--)
4395             {
4396               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4397             }
4398           _endLazyDPSEvaluation ();
4399         }
4400
4401       return TRUE;
4402     }
4403
4404   return FALSE;
4405 }
4406
4407 /*-----------------------------------------------------------------*/
4408 /* outBitAcc - output a bit in acc                                 */
4409 /*-----------------------------------------------------------------*/
4410 static void
4411 outBitAcc (operand * result)
4412 {
4413   symbol *tlbl = newiTempLabel (NULL);
4414   /* if the result is a bit */
4415   if (AOP_TYPE (result) == AOP_CRY)
4416     {
4417       aopPut (result, "a", 0);
4418     }
4419   else
4420     {
4421       emitcode ("jz", "!tlabel", tlbl->key + 100);
4422       emitcode ("mov", "a,%s", one);
4423       emitcode ("", "!tlabeldef", tlbl->key + 100);
4424       outAcc (result);
4425     }
4426 }
4427
4428 /*-----------------------------------------------------------------*/
4429 /* genPlusBits - generates code for addition of two bits           */
4430 /*-----------------------------------------------------------------*/
4431 static void
4432 genPlusBits (iCode * ic)
4433 {
4434   D (emitcode (";", "genPlusBits "));
4435
4436   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4437     {
4438       symbol *lbl = newiTempLabel (NULL);
4439       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4440       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4441       emitcode ("cpl", "c");
4442       emitcode ("", "!tlabeldef", (lbl->key + 100));
4443       outBitC (IC_RESULT (ic));
4444     }
4445   else
4446     {
4447       emitcode ("clr", "a");
4448       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4449       emitcode ("rlc", "a");
4450       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4451       emitcode ("addc", "a,%s", zero);
4452       outAcc (IC_RESULT (ic));
4453     }
4454 }
4455
4456 static void
4457 adjustArithmeticResult (iCode * ic)
4458 {
4459   if (opIsGptr (IC_RESULT (ic)) &&
4460       opIsGptr (IC_LEFT (ic)) &&
4461       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4462     {
4463       aopPut (IC_RESULT (ic),
4464               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4465               GPTRSIZE - 1);
4466     }
4467
4468   if (opIsGptr (IC_RESULT (ic)) &&
4469       opIsGptr (IC_RIGHT (ic)) &&
4470       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4471     {
4472       aopPut (IC_RESULT (ic),
4473             aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4474               GPTRSIZE - 1);
4475     }
4476
4477   if (opIsGptr (IC_RESULT (ic)) &&
4478       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4479       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4480       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4481       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4482     {
4483       char buffer[5];
4484       SNPRINTF (buffer, sizeof(buffer),
4485                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4486       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4487     }
4488 }
4489
4490 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4491 // generates the result if possible. If result is generated, returns TRUE; otherwise
4492 // returns false and caller must deal with fact that result isn't aopOp'd.
4493 bool aopOp3(iCode * ic)
4494 {
4495     bool dp1InUse, dp2InUse;
4496     bool useDp2;
4497
4498     // First, generate the right opcode. DPTR may be used if neither left nor result are
4499     // of type AOP_STR.
4500
4501 //    D(emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4502 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4503 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4504 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4505 //      );
4506 //    D(emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4507 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4508 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4509 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4510 //      );
4511
4512     // Right uses DPTR unless left or result is an AOP_STR; however,
4513     // if right is an AOP_STR, it must use DPTR regardless.
4514     if ((AOP_IS_STR(IC_LEFT(ic)) || AOP_IS_STR(IC_RESULT(ic)))
4515      && !AOP_IS_STR(IC_RIGHT(ic)))
4516     {
4517         useDp2 = TRUE;
4518     }
4519     else
4520     {
4521         useDp2 = FALSE;
4522     }
4523
4524     aopOp (IC_RIGHT(ic),ic,FALSE, useDp2);
4525
4526     // if the right used DPTR, left MUST use DPTR2.
4527     // if the right used DPTR2, left MUST use DPTR.
4528     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4529     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4530     // enabling us to assign DPTR to result.
4531
4532     if (AOP_USESDPTR(IC_RIGHT(ic)))
4533     {
4534         useDp2 = TRUE;
4535     }
4536     else if (AOP_USESDPTR2(IC_RIGHT(ic)))
4537     {
4538         useDp2 = FALSE;
4539     }
4540     else
4541     {
4542         if (AOP_IS_STR(IC_RESULT(ic)) && !AOP_IS_STR(IC_LEFT(ic)))
4543         {
4544             useDp2 = TRUE;
4545         }
4546         else
4547         {
4548             useDp2 = FALSE;
4549         }
4550     }
4551
4552     aopOp(IC_LEFT(ic), ic, FALSE, useDp2);
4553
4554
4555     // We've op'd the left & right. So, if left or right are the same operand as result,
4556     // we know aopOp will succeed, and we can just do it & bail.
4557     if (isOperandEqual(IC_LEFT(ic),IC_RESULT(ic)))
4558       {
4559         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4560         return TRUE;
4561       }
4562     if (isOperandEqual(IC_RIGHT(ic),IC_RESULT(ic)))
4563       {
4564 //      D(emitcode(";", "aopOp3: (left | right) & result equal"););
4565         aopOp(IC_RESULT(ic),ic,TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4566         return TRUE;
4567       }
4568
4569     // Operands may be equivalent (but not equal) if they share a spill location. If
4570     // so, use the same DPTR or DPTR2.
4571     if (operandsEqu (IC_LEFT(ic), IC_RESULT(ic)))
4572       {
4573         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4574         return TRUE;
4575       }
4576     if (operandsEqu (IC_RIGHT(ic), IC_RESULT(ic)))
4577       {
4578         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4579         return TRUE;
4580       }
4581
4582     // Note which dptrs are currently in use.
4583     dp1InUse = AOP_USESDPTR(IC_LEFT(ic)) || AOP_USESDPTR(IC_RIGHT(ic));
4584     dp2InUse = AOP_USESDPTR2(IC_LEFT(ic)) || AOP_USESDPTR2(IC_RIGHT(ic));
4585
4586     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4587     // generate it.
4588     if (dp1InUse && AOP_IS_STR(IC_RESULT(ic)))
4589     {
4590         return FALSE;
4591     }
4592
4593     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4594     if (dp2InUse && AOP_IS_DPTRn(IC_RESULT(ic)))
4595     {
4596         return FALSE;
4597     }
4598
4599     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4600     if (dp1InUse && dp2InUse && isOperandInFarSpace(IC_RESULT(ic)))
4601     {
4602         return FALSE;
4603     }
4604
4605     aopOp (IC_RESULT(ic),ic,TRUE, dp1InUse);
4606
4607     // Some sanity checking...
4608     if (dp1InUse && AOP_USESDPTR(IC_RESULT(ic)))
4609     {
4610         fprintf(stderr,
4611                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4612                 __FILE__, __LINE__, ic->filename, ic->lineno);
4613         emitcode(";", ">>> unexpected DPTR here.");
4614     }
4615
4616     if (dp2InUse && AOP_USESDPTR2(IC_RESULT(ic)))
4617     {
4618         fprintf(stderr,
4619                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4620                 __FILE__, __LINE__, ic->filename, ic->lineno);
4621         emitcode(";", ">>> unexpected DPTR2 here.");
4622     }
4623
4624     return TRUE;
4625 }
4626
4627 // Macro to aopOp all three operands of an ic. If this cannot be done,
4628 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4629 // will be set TRUE. The caller must then handle the case specially, noting
4630 // that the IC_RESULT operand is not aopOp'd.
4631 //
4632 #define AOP_OP_3_NOFATAL(ic, rc) \
4633             do { rc = !aopOp3(ic); } while (0)
4634
4635 // aopOp the left & right operands of an ic.
4636 #define AOP_OP_2(ic) \
4637     aopOp (IC_RIGHT(ic),ic,FALSE, AOP_IS_STR(IC_LEFT(ic))); \
4638     aopOp (IC_LEFT(ic),ic,FALSE, AOP_USESDPTR(IC_RIGHT(ic)));
4639
4640 // convienience macro.
4641 #define AOP_SET_LOCALS(ic) \
4642     left = IC_LEFT(ic); \
4643     right = IC_RIGHT(ic); \
4644     result = IC_RESULT(ic);
4645
4646
4647 // Given an integer value of pushedSize bytes on the stack,
4648 // adjust it to be resultSize bytes, either by discarding
4649 // the most significant bytes or by zero-padding.
4650 //
4651 // On exit from this macro, pushedSize will have been adjusted to
4652 // equal resultSize, and ACC may be trashed.
4653 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4654       /* If the pushed data is bigger than the result,          \
4655        * simply discard unused bytes. Icky, but works.          \
4656        */                                                       \
4657       while (pushedSize > resultSize)                           \
4658       {                                                         \
4659           D (emitcode (";", "discarding unused result byte."););\
4660           emitcode ("pop", "acc");                              \
4661           pushedSize--;                                         \
4662       }                                                         \
4663       if (pushedSize < resultSize)                              \
4664       {                                                         \
4665           emitcode ("clr", "a");                                \
4666           /* Conversly, we haven't pushed enough here.          \
4667            * just zero-pad, and all is well.                    \
4668            */                                                   \
4669           while (pushedSize < resultSize)                       \
4670           {                                                     \
4671               emitcode("push", "acc");                          \
4672               pushedSize++;                                     \
4673           }                                                     \
4674       }                                                         \
4675       assert(pushedSize == resultSize);
4676
4677 /*-----------------------------------------------------------------*/
4678 /* genPlus - generates code for addition                           */
4679 /*-----------------------------------------------------------------*/
4680 static void
4681 genPlus (iCode * ic)
4682 {
4683   int size, offset = 0;
4684   bool pushResult;
4685   int rSize;
4686   bool swappedLR = FALSE;
4687
4688   D (emitcode (";", "genPlus "));
4689
4690   /* special cases :- */
4691   if ( AOP_IS_STR(IC_LEFT(ic)) &&
4692       isOperandLiteral(IC_RIGHT(ic)) && OP_SYMBOL(IC_RESULT(ic))->ruonly) {
4693       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4694       size = (int)floatFromVal (AOP (IC_RIGHT(ic))->aopu.aop_lit);
4695       if (size <= 9) {
4696           while (size--) emitcode ("inc","dptr");
4697       } else {
4698           emitcode ("mov","a,dpl");
4699           emitcode ("add","a,#!constbyte",size & 0xff);
4700           emitcode ("mov","dpl,a");
4701           emitcode ("mov","a,dph");
4702           emitcode ("addc","a,#!constbyte",(size >> 8) & 0xff);
4703           emitcode ("mov","dph,a");
4704           emitcode ("mov","a,dpx");
4705           emitcode ("addc","a,#!constbyte",(size >> 16) & 0xff);
4706           emitcode ("mov","dpx,a");
4707       }
4708       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4709       return ;
4710   }
4711   if ( IS_SYMOP(IC_LEFT(ic)) &&
4712        OP_SYMBOL(IC_LEFT(ic))->remat &&
4713        isOperandInFarSpace(IC_RIGHT(ic))) {
4714       operand *op = IC_RIGHT(ic);
4715       IC_RIGHT(ic) = IC_LEFT(ic);
4716       IC_LEFT(ic) = op;
4717   }
4718
4719   AOP_OP_3_NOFATAL (ic, pushResult);
4720
4721   if (pushResult)
4722     {
4723       D (emitcode (";", "genPlus: must push result: 3 ops in far space"););
4724     }
4725
4726   if (!pushResult)
4727     {
4728       /* if literal, literal on the right or
4729          if left requires ACC or right is already
4730          in ACC */
4731       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4732        || ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic))))
4733           || AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4734         {
4735           operand *t = IC_RIGHT (ic);
4736           IC_RIGHT (ic) = IC_LEFT (ic);
4737           IC_LEFT (ic) = t;
4738           swappedLR = TRUE;
4739           emitcode (";", "Swapped plus args.");
4740         }
4741
4742       /* if both left & right are in bit
4743          space */
4744       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4745           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4746         {
4747           genPlusBits (ic);
4748           goto release;
4749         }
4750
4751       /* if left in bit space & right literal */
4752       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4753           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4754         {
4755           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4756           /* if result in bit space */
4757           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4758             {
4759               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4760                 emitcode ("cpl", "c");
4761               outBitC (IC_RESULT (ic));
4762             }
4763           else
4764             {
4765               size = getDataSize (IC_RESULT (ic));
4766               _startLazyDPSEvaluation ();
4767               while (size--)
4768                 {
4769                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4770                   emitcode ("addc", "a,%s", zero);
4771                   aopPut (IC_RESULT (ic), "a", offset++);
4772                 }
4773               _endLazyDPSEvaluation ();
4774             }
4775           goto release;
4776         }
4777
4778       /* if I can do an increment instead
4779          of add then GOOD for ME */
4780       if (genPlusIncr (ic) == TRUE)
4781         {
4782           emitcode (";", "did genPlusIncr");
4783           goto release;
4784         }
4785
4786     }
4787   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4788
4789   _startLazyDPSEvaluation ();
4790   while (size--)
4791     {
4792       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4793         {
4794           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4795           if (offset == 0)
4796             emitcode ("add", "a,%s",
4797                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4798           else
4799             emitcode ("addc", "a,%s",
4800                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4801         }
4802       else
4803         {
4804           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4805           {
4806               /* right is going to use ACC or we would have taken the
4807                * above branch.
4808                */
4809               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4810        TR_AP("#3");
4811               D(emitcode(";", "+ AOP_ACC special case."););
4812               emitcode("xch", "a, %s", DP2_RESULT_REG);
4813           }
4814           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4815           if (offset == 0)
4816           {
4817             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4818             {
4819          TR_AP("#4");
4820                 emitcode("add", "a, %s", DP2_RESULT_REG);
4821             }
4822             else
4823             {
4824                 emitcode ("add", "a,%s",
4825                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4826                                   DP2_RESULT_REG));
4827             }
4828           }
4829           else
4830           {
4831             emitcode ("addc", "a,%s",
4832                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4833                           DP2_RESULT_REG));
4834           }
4835         }
4836       if (!pushResult)
4837         {
4838           aopPut (IC_RESULT (ic), "a", offset);
4839         }
4840       else
4841         {
4842           emitcode ("push", "acc");
4843         }
4844       offset++;
4845     }
4846   _endLazyDPSEvaluation ();
4847
4848   if (pushResult)
4849     {
4850       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4851
4852       size = getDataSize (IC_LEFT (ic));
4853       rSize = getDataSize (IC_RESULT (ic));
4854
4855       ADJUST_PUSHED_RESULT(size, rSize);
4856
4857       _startLazyDPSEvaluation ();
4858       while (size--)
4859         {
4860           emitcode ("pop", "acc");
4861           aopPut (IC_RESULT (ic), "a", size);
4862         }
4863       _endLazyDPSEvaluation ();
4864     }
4865
4866   adjustArithmeticResult (ic);
4867
4868 release:
4869   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4870   if (!swappedLR)
4871     {
4872       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4873       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4874     }
4875   else
4876     {
4877       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4878       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4879     }
4880 }
4881
4882 /*-----------------------------------------------------------------*/
4883 /* genMinusDec :- does subtraction with decrement if possible      */
4884 /*-----------------------------------------------------------------*/
4885 static bool
4886 genMinusDec (iCode * ic)
4887 {
4888   unsigned int icount;
4889   unsigned int size = getDataSize (IC_RESULT (ic));
4890
4891   /* will try to generate an increment */
4892   /* if the right side is not a literal
4893      we cannot */
4894   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4895     return FALSE;
4896
4897   /* if the literal value of the right hand side
4898      is greater than 4 then it is not worth it */
4899   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4900     return FALSE;
4901
4902   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4903       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4904       while (icount--) {
4905           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4906       }
4907       return TRUE;
4908   }
4909   /* if decrement 16 bits in register */
4910   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4911       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4912       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4913       (size > 1) &&
4914       (icount == 1))
4915     {
4916       symbol *tlbl;
4917       int    emitTlbl;
4918       int    labelRange;
4919       char   *l;
4920
4921       /* If the next instruction is a goto and the goto target
4922          * is <= 5 instructions previous to this, we can generate
4923          * jumps straight to that target.
4924        */
4925       if (ic->next && ic->next->op == GOTO
4926           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4927           && labelRange <= 5)
4928         {
4929           emitcode (";", "tail decrement optimized (range %d)", labelRange);
4930           tlbl = IC_LABEL (ic->next);
4931           emitTlbl = 0;
4932         }
4933       else
4934         {
4935           tlbl = newiTempLabel (NULL);
4936           emitTlbl = 1;
4937         }
4938
4939       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4940       emitcode ("dec", "%s", l);
4941
4942       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4943           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4944           IS_AOP_PREG (IC_RESULT (ic)))
4945       {
4946           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4947       }
4948       else
4949       {
4950           emitcode ("mov", "a,#!constbyte",0xff);
4951           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4952       }
4953       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4954       emitcode ("dec", "%s", l);
4955       if (size > 2)
4956         {
4957             if (!strcmp(l, "acc"))
4958             {
4959                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4960             }
4961             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4962                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4963                      IS_AOP_PREG (IC_RESULT (ic)))
4964             {
4965                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4966             }
4967             else
4968             {
4969                 emitcode ("mov", "a,#!constbyte",0xff);
4970                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4971             }
4972             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4973             emitcode ("dec", "%s", l);
4974         }
4975       if (size > 3)
4976         {
4977             if (!strcmp(l, "acc"))
4978             {
4979                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4980             }
4981             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4982                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4983                      IS_AOP_PREG (IC_RESULT (ic)))
4984             {
4985                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4986             }
4987             else
4988             {
4989                 emitcode ("mov", "a,#!constbyte",0xff);
4990                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4991             }
4992             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4993             emitcode ("dec", "%s", l);
4994         }
4995       if (emitTlbl)
4996         {
4997           emitcode ("", "!tlabeldef", tlbl->key + 100);
4998         }
4999       return TRUE;
5000     }
5001
5002   /* if the sizes are greater than 1 then we cannot */
5003   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
5004       AOP_SIZE (IC_LEFT (ic)) > 1)
5005     return FALSE;
5006
5007   /* we can if the aops of the left & result match or
5008      if they are in registers and the registers are the
5009      same */
5010   if (
5011        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
5012        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
5013        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
5014     {
5015       char *l;
5016
5017       if (aopGetUsesAcc (IC_LEFT (ic), 0))
5018         {
5019           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
5020           l = "a";
5021         }
5022       else
5023         {
5024           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5025         }
5026
5027       _startLazyDPSEvaluation ();
5028       while (icount--)
5029         {
5030           emitcode ("dec", "%s", l);
5031         }
5032       _endLazyDPSEvaluation ();
5033
5034       if (AOP_NEEDSACC (IC_RESULT (ic)))
5035         aopPut (IC_RESULT (ic), "a", 0);
5036
5037       return TRUE;
5038     }
5039
5040   return FALSE;
5041 }
5042
5043 /*-----------------------------------------------------------------*/
5044 /* addSign - complete with sign                                    */
5045 /*-----------------------------------------------------------------*/
5046 static void
5047 addSign (operand * result, int offset, int sign)
5048 {
5049   int size = (getDataSize (result) - offset);
5050   if (size > 0)
5051     {
5052       _startLazyDPSEvaluation();
5053       if (sign)
5054         {
5055           emitcode ("rlc", "a");
5056           emitcode ("subb", "a,acc");
5057           while (size--)
5058           {
5059             aopPut (result, "a", offset++);
5060           }
5061         }
5062       else
5063       {
5064         while (size--)
5065         {
5066           aopPut (result, zero, offset++);
5067         }
5068       }
5069       _endLazyDPSEvaluation();
5070     }
5071 }
5072
5073 /*-----------------------------------------------------------------*/
5074 /* genMinusBits - generates code for subtraction  of two bits      */
5075 /*-----------------------------------------------------------------*/
5076 static void
5077 genMinusBits (iCode * ic)
5078 {
5079   symbol *lbl = newiTempLabel (NULL);
5080
5081   D (emitcode (";", "genMinusBits "));
5082
5083   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5084     {
5085       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5086       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5087       emitcode ("cpl", "c");
5088       emitcode ("", "!tlabeldef", (lbl->key + 100));
5089       outBitC (IC_RESULT (ic));
5090     }
5091   else
5092     {
5093       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5094       emitcode ("subb", "a,acc");
5095       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5096       emitcode ("inc", "a");
5097       emitcode ("", "!tlabeldef", (lbl->key + 100));
5098       aopPut (IC_RESULT (ic), "a", 0);
5099       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5100     }
5101 }
5102
5103 /*-----------------------------------------------------------------*/
5104 /* genMinus - generates code for subtraction                       */
5105 /*-----------------------------------------------------------------*/
5106 static void
5107 genMinus (iCode * ic)
5108 {
5109     int size, offset = 0;
5110     int rSize;
5111     long lit = 0L;
5112     bool pushResult;
5113
5114     D (emitcode (";", "genMinus "));
5115
5116     AOP_OP_3_NOFATAL(ic, pushResult);
5117
5118     if (!pushResult)
5119     {
5120       /* special cases :- */
5121       /* if both left & right are in bit space */
5122       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5123           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5124         {
5125           genMinusBits (ic);
5126           goto release;
5127         }
5128
5129       /* if I can do an decrement instead
5130          of subtract then GOOD for ME */
5131       if (genMinusDec (ic) == TRUE)
5132         goto release;
5133
5134     }
5135
5136   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5137
5138   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5139     {
5140       CLRC;
5141     }
5142   else
5143     {
5144       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5145       lit = -lit;
5146     }
5147
5148
5149   /* if literal, add a,#-lit, else normal subb */
5150   _startLazyDPSEvaluation ();
5151   while (size--) {
5152       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5153           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5154               emitcode ("mov","b,%s",
5155                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5156               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5157               emitcode ("subb","a,b");
5158           } else {
5159               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5160               emitcode ("subb", "a,%s",
5161                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5162                                 DP2_RESULT_REG));
5163           }
5164       } else {
5165           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5166           /* first add without previous c */
5167           if (!offset) {
5168               if (!size && lit==-1) {
5169                   emitcode ("dec", "a");
5170               } else {
5171                   emitcode ("add", "a,#!constbyte",
5172                             (unsigned int) (lit & 0x0FFL));
5173               }
5174           } else {
5175               emitcode ("addc", "a,#!constbyte",
5176                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5177           }
5178       }
5179
5180       if (pushResult) {
5181           emitcode ("push", "acc");
5182       } else {
5183           aopPut (IC_RESULT (ic), "a", offset);
5184       }
5185       offset++;
5186   }
5187   _endLazyDPSEvaluation ();
5188
5189   if (pushResult)
5190     {
5191       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5192
5193       size = getDataSize (IC_LEFT (ic));
5194       rSize = getDataSize (IC_RESULT (ic));
5195
5196       ADJUST_PUSHED_RESULT(size, rSize);
5197
5198       _startLazyDPSEvaluation ();
5199       while (size--)
5200         {
5201           emitcode ("pop", "acc");
5202           aopPut (IC_RESULT (ic), "a", size);
5203         }
5204       _endLazyDPSEvaluation ();
5205     }
5206
5207   adjustArithmeticResult (ic);
5208
5209 release:
5210   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5211   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5212   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5213 }
5214
5215
5216 /*-----------------------------------------------------------------*/
5217 /* genMultbits :- multiplication of bits                           */
5218 /*-----------------------------------------------------------------*/
5219 static void
5220 genMultbits (operand * left,
5221              operand * right,
5222              operand * result,
5223              iCode   * ic)
5224 {
5225   D(emitcode (";", "genMultbits"));
5226
5227   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5228   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5229   aopOp(result, ic, TRUE, FALSE);
5230   outBitC (result);
5231 }
5232
5233 /*-----------------------------------------------------------------*/
5234 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5235 /*-----------------------------------------------------------------*/
5236 static void
5237 genMultOneByte (operand * left,
5238                 operand * right,
5239                 operand * result,
5240                 iCode   * ic)
5241 {
5242   symbol *lbl;
5243   int size;
5244   bool runtimeSign, compiletimeSign;
5245   bool lUnsigned, rUnsigned, pushedB;
5246
5247   /* (if two literals: the value is computed before) */
5248   /* if one literal, literal on the right */
5249   if (AOP_TYPE (left) == AOP_LIT)
5250     {
5251       operand *t = right;
5252       right = left;
5253       left = t;
5254       /* emitcode (";", "swapped left and right"); */
5255     }
5256   /* if no literal, unsigned on the right: shorter code */
5257   if (   AOP_TYPE (right) != AOP_LIT
5258       && SPEC_USIGN (getSpec (operandType (left))))
5259     {
5260       operand *t = right;
5261       right = left;
5262       left = t;
5263     }
5264
5265   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5266   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5267
5268   pushedB = pushB ();
5269
5270   if ((lUnsigned && rUnsigned)
5271 /* sorry, I don't know how to get size
5272    without calling aopOp (result,...);
5273    see Feature Request  */
5274       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5275                    no need to take care about the signedness! */
5276     {
5277       /* just an unsigned 8 * 8 = 8 multiply
5278          or 8u * 8u = 16u */
5279       /* emitcode (";","unsigned"); */
5280       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5281       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5282       emitcode ("mul", "ab");
5283
5284       _G.accInUse++;
5285       aopOp (result, ic, TRUE, FALSE);
5286       size = AOP_SIZE (result);
5287
5288       if (size < 1 || size > 2)
5289         {
5290           /* this should never happen */
5291           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5292                    size, __FILE__, lineno);
5293           exit (1);
5294         }
5295
5296       aopPut (result, "a", 0);
5297       _G.accInUse--;
5298       if (size == 2)
5299         aopPut (result, "b", 1);
5300
5301       popB (pushedB);
5302       return;
5303     }
5304
5305   /* we have to do a signed multiply */
5306   /* emitcode (";", "signed"); */
5307
5308   /* now sign adjust for both left & right */
5309
5310   /* let's see what's needed: */
5311   /* apply negative sign during runtime */
5312   runtimeSign = FALSE;
5313   /* negative sign from literals */
5314   compiletimeSign = FALSE;
5315
5316   if (!lUnsigned)
5317     {
5318       if (AOP_TYPE(left) == AOP_LIT)
5319         {
5320           /* signed literal */
5321           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5322           if (val < 0)
5323             compiletimeSign = TRUE;
5324         }
5325       else
5326         /* signed but not literal */
5327         runtimeSign = TRUE;
5328     }
5329
5330   if (!rUnsigned)
5331     {
5332       if (AOP_TYPE(right) == AOP_LIT)
5333         {
5334           /* signed literal */
5335           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5336           if (val < 0)
5337             compiletimeSign ^= TRUE;
5338         }
5339       else
5340         /* signed but not literal */
5341         runtimeSign = TRUE;
5342     }
5343
5344   /* initialize F0, which stores the runtime sign */
5345   if (runtimeSign)
5346     {
5347       if (compiletimeSign)
5348         emitcode ("setb", "F0"); /* set sign flag */
5349       else
5350         emitcode ("clr", "F0"); /* reset sign flag */
5351     }
5352
5353   /* save the signs of the operands */
5354   if (AOP_TYPE(right) == AOP_LIT)
5355     {
5356       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5357
5358       if (!rUnsigned && val < 0)
5359         emitcode ("mov", "b,#!constbyte", -val);
5360       else
5361         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5362     }
5363   else /* ! literal */
5364     {
5365       if (rUnsigned)  /* emitcode (";", "signed"); */
5366         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5367       else
5368         {
5369           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5370           lbl = newiTempLabel (NULL);
5371           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5372           emitcode ("cpl", "F0"); /* complement sign flag */
5373           emitcode ("cpl", "a");  /* 2's complement */
5374           emitcode ("inc", "a");
5375           emitcode ("", "!tlabeldef", lbl->key + 100);
5376           emitcode ("mov", "b,a");
5377         }
5378     }
5379
5380   if (AOP_TYPE(left) == AOP_LIT)
5381     {
5382       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5383
5384       if (!lUnsigned && val < 0)
5385         emitcode ("mov", "a,#!constbyte", -val);
5386       else
5387         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5388     }
5389   else /* ! literal */
5390     {
5391       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5392
5393       if (!lUnsigned)  /* emitcode (";", "signed"); */
5394         {
5395           lbl = newiTempLabel (NULL);
5396           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5397           emitcode ("cpl", "F0"); /* complement sign flag */
5398           emitcode ("cpl", "a");  /* 2's complement */
5399           emitcode ("inc", "a");
5400           emitcode ("", "!tlabeldef", lbl->key + 100);
5401         }
5402     }
5403
5404   /* now the multiplication */
5405   emitcode ("mul", "ab");
5406   _G.accInUse++;
5407   aopOp(result, ic, TRUE, FALSE);
5408   size = AOP_SIZE (result);
5409
5410   if (size < 1 || size > 2)
5411     {
5412       /* this should never happen */
5413       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5414                size, __FILE__, lineno);
5415       exit (1);
5416     }
5417
5418   if (runtimeSign || compiletimeSign)
5419     {
5420       lbl = newiTempLabel (NULL);
5421       if (runtimeSign)
5422         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5423       emitcode ("cpl", "a"); /* lsb 2's complement */
5424       if (size != 2)
5425         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5426       else
5427         {
5428           emitcode ("add", "a,#1"); /* this sets carry flag */
5429           emitcode ("xch", "a,b");
5430           emitcode ("cpl", "a"); /* msb 2's complement */
5431           emitcode ("addc", "a,#0");
5432           emitcode ("xch", "a,b");
5433         }
5434       emitcode ("", "!tlabeldef", lbl->key + 100);
5435     }
5436   aopPut (result, "a", 0);
5437   _G.accInUse--;
5438   if (size == 2)
5439     aopPut (result, "b", 1);
5440
5441   popB (pushedB);
5442 }
5443
5444 /*-----------------------------------------------------------------*/
5445 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5446 /*-----------------------------------------------------------------*/
5447 static void genMultTwoByte (operand *left, operand *right,
5448                             operand *result, iCode *ic)
5449 {
5450         sym_link *retype = getSpec(operandType(right));
5451         sym_link *letype = getSpec(operandType(left));
5452         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5453         symbol *lbl;
5454
5455         if (AOP_TYPE (left) == AOP_LIT) {
5456                 operand *t = right;
5457                 right = left;
5458                 left = t;
5459         }
5460         /* save EA bit in F1 */
5461         lbl = newiTempLabel(NULL);
5462         emitcode ("setb","F1");
5463         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5464         emitcode ("clr","F1");
5465         emitcode("","!tlabeldef",lbl->key+100);
5466
5467         /* load up MB with right */
5468         if (!umult) {
5469                 emitcode("clr","F0");
5470                 if (AOP_TYPE(right) == AOP_LIT) {
5471                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5472                         if (val < 0) {
5473                                 emitcode("setb","F0");
5474                                 val = -val;
5475                         }
5476                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5477                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5478                 } else {
5479                         lbl = newiTempLabel(NULL);
5480                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5481                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5482                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5483                         emitcode ("xch", "a,b");
5484                         emitcode ("cpl","a");
5485                         emitcode ("add", "a,#1");
5486                         emitcode ("xch", "a,b");
5487                         emitcode ("cpl", "a"); // msb
5488                         emitcode ("addc", "a,#0");
5489                         emitcode ("setb","F0");
5490                         emitcode ("","!tlabeldef",lbl->key+100);
5491                         emitcode ("mov","mb,b");
5492                         emitcode ("mov","mb,a");
5493                 }
5494         } else {
5495                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5496                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5497         }
5498         /* load up MA with left */
5499         if (!umult) {
5500                 lbl = newiTempLabel(NULL);
5501                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5502                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5503                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5504                 emitcode ("xch", "a,b");
5505                 emitcode ("cpl","a");
5506                 emitcode ("add", "a,#1");
5507                 emitcode ("xch", "a,b");
5508                 emitcode ("cpl", "a"); // msb
5509                 emitcode ("addc","a,#0");
5510                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5511                 emitcode ("setb","F0");
5512                 emitcode ("","!tlabeldef",lbl->key+100);
5513                 emitcode ("mov","ma,b");
5514                 emitcode ("mov","ma,a");
5515         } else {
5516                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5517                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5518         }
5519         /* wait for multiplication to finish */
5520         lbl = newiTempLabel(NULL);
5521         emitcode("","!tlabeldef", lbl->key+100);
5522         emitcode("mov","a,mcnt1");
5523         emitcode("anl","a,#!constbyte",0x80);
5524         emitcode("jnz","!tlabel",lbl->key+100);
5525
5526         freeAsmop (left, NULL, ic, TRUE);
5527         freeAsmop (right, NULL, ic,TRUE);
5528         aopOp(result, ic, TRUE, FALSE);
5529
5530         /* if unsigned then simple */
5531         if (umult) {
5532                 emitcode ("mov","a,ma");
5533                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5534                 emitcode ("mov","a,ma");
5535                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5536                 aopPut(result,"ma",1);
5537                 aopPut(result,"ma",0);
5538         } else {
5539                 emitcode("push","ma");
5540                 emitcode("push","ma");
5541                 emitcode("push","ma");
5542                 MOVA("ma");
5543                 /* negate result if needed */
5544                 lbl = newiTempLabel(NULL);
5545                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5546                 emitcode("cpl","a");
5547                 emitcode("add","a,#1");
5548                 emitcode("","!tlabeldef", lbl->key+100);
5549                 if (AOP_TYPE(result) == AOP_ACC)
5550                 {
5551                     D(emitcode(";", "ACC special case."););
5552                     /* We know result is the only live aop, and
5553                      * it's obviously not a DPTR2, so AP is available.
5554                      */
5555                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5556                 }
5557                 else
5558                 {
5559                     aopPut(result,"a",0);
5560                 }
5561
5562                 emitcode("pop","acc");
5563                 lbl = newiTempLabel(NULL);
5564                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5565                 emitcode("cpl","a");
5566                 emitcode("addc","a,#0");
5567                 emitcode("","!tlabeldef", lbl->key+100);
5568                 aopPut(result,"a",1);
5569                 emitcode("pop","acc");
5570                 if (AOP_SIZE(result) >= 3) {
5571                         lbl = newiTempLabel(NULL);
5572                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5573                         emitcode("cpl","a");
5574                         emitcode("addc","a,#0");
5575                         emitcode("","!tlabeldef", lbl->key+100);
5576                         aopPut(result,"a",2);
5577                 }
5578                 emitcode("pop","acc");
5579                 if (AOP_SIZE(result) >= 4) {
5580                         lbl = newiTempLabel(NULL);
5581                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5582                         emitcode("cpl","a");
5583                         emitcode("addc","a,#0");
5584                         emitcode("","!tlabeldef", lbl->key+100);
5585                         aopPut(result,"a",3);
5586                 }
5587                 if (AOP_TYPE(result) == AOP_ACC)
5588                 {
5589                     /* We stashed the result away above. */
5590                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5591                 }
5592
5593         }
5594         freeAsmop (result, NULL, ic, TRUE);
5595
5596         /* restore EA bit in F1 */
5597         lbl = newiTempLabel(NULL);
5598         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5599         emitcode ("setb","EA");
5600         emitcode("","!tlabeldef",lbl->key+100);
5601         return ;
5602 }
5603
5604 /*-----------------------------------------------------------------*/
5605 /* genMult - generates code for multiplication                     */
5606 /*-----------------------------------------------------------------*/
5607 static void
5608 genMult (iCode * ic)
5609 {
5610   operand *left = IC_LEFT (ic);
5611   operand *right = IC_RIGHT (ic);
5612   operand *result = IC_RESULT (ic);
5613
5614   D (emitcode (";", "genMult "));
5615
5616   /* assign the asmops */
5617   AOP_OP_2 (ic);
5618
5619   /* special cases first */
5620   /* both are bits */
5621   if (AOP_TYPE (left) == AOP_CRY &&
5622       AOP_TYPE (right) == AOP_CRY)
5623     {
5624       genMultbits (left, right, result, ic);
5625       goto release;
5626     }
5627
5628   /* if both are of size == 1 */
5629   if (AOP_SIZE (left) == 1 &&
5630       AOP_SIZE (right) == 1)
5631     {
5632       genMultOneByte (left, right, result, ic);
5633       goto release;
5634     }
5635
5636   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5637           /* use the ds390 ARITHMETIC accel UNIT */
5638           genMultTwoByte (left, right, result, ic);
5639           return ;
5640   }
5641   /* should have been converted to function call */
5642   assert (0);
5643
5644 release:
5645   freeAsmop (result, NULL, ic, TRUE);
5646   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5647   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5648 }
5649
5650 /*-----------------------------------------------------------------*/
5651 /* genDivbits :- division of bits                                  */
5652 /*-----------------------------------------------------------------*/
5653 static void
5654 genDivbits (operand * left,
5655             operand * right,
5656             operand * result,
5657             iCode   * ic)
5658 {
5659   char *l;
5660   bool pushedB;
5661
5662   D(emitcode (";     genDivbits",""));
5663
5664   pushedB = pushB ();
5665
5666   /* the result must be bit */
5667   LOAD_AB_FOR_DIV (left, right, l);
5668   emitcode ("div", "ab");
5669   emitcode ("rrc", "a");
5670   aopOp(result, ic, TRUE, FALSE);
5671
5672   popB (pushedB);
5673
5674   aopPut (result, "c", 0);
5675 }
5676
5677 /*-----------------------------------------------------------------*/
5678 /* genDivOneByte : 8 bit division                                  */
5679 /*-----------------------------------------------------------------*/
5680 static void
5681 genDivOneByte (operand * left,
5682                operand * right,
5683                operand * result,
5684                iCode   * ic)
5685 {
5686   bool lUnsigned, rUnsigned, pushedB;
5687   bool runtimeSign, compiletimeSign;
5688   char *l;
5689   symbol *lbl;
5690   int size, offset;
5691
5692   D(emitcode (";     genDivOneByte",""));
5693
5694   offset = 1;
5695   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5696   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5697
5698   pushedB = pushB ();
5699
5700   /* signed or unsigned */
5701   if (lUnsigned && rUnsigned)
5702     {
5703       /* unsigned is easy */
5704       LOAD_AB_FOR_DIV (left, right, l);
5705       emitcode ("div", "ab");
5706
5707       _G.accInUse++;
5708       aopOp (result, ic, TRUE, FALSE);
5709       aopPut (result, "a", 0);
5710       _G.accInUse--;
5711
5712       size = AOP_SIZE (result) - 1;
5713
5714       while (size--)
5715         aopPut (result, zero, offset++);
5716
5717       popB (pushedB);
5718       return;
5719     }
5720
5721   /* signed is a little bit more difficult */
5722
5723   /* now sign adjust for both left & right */
5724
5725   /* let's see what's needed: */
5726   /* apply negative sign during runtime */
5727   runtimeSign = FALSE;
5728   /* negative sign from literals */
5729   compiletimeSign = FALSE;
5730
5731   if (!lUnsigned)
5732     {
5733       if (AOP_TYPE(left) == AOP_LIT)
5734         {
5735           /* signed literal */
5736           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5737           if (val < 0)
5738             compiletimeSign = TRUE;
5739         }
5740       else
5741         /* signed but not literal */
5742         runtimeSign = TRUE;
5743     }
5744
5745   if (!rUnsigned)
5746     {
5747       if (AOP_TYPE(right) == AOP_LIT)
5748         {
5749           /* signed literal */
5750           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5751           if (val < 0)
5752             compiletimeSign ^= TRUE;
5753         }
5754       else
5755         /* signed but not literal */
5756         runtimeSign = TRUE;
5757     }
5758
5759   /* initialize F0, which stores the runtime sign */
5760   if (runtimeSign)
5761     {
5762       if (compiletimeSign)
5763         emitcode ("setb", "F0"); /* set sign flag */
5764       else
5765         emitcode ("clr", "F0"); /* reset sign flag */
5766     }
5767
5768   /* save the signs of the operands */
5769   if (AOP_TYPE(right) == AOP_LIT)
5770     {
5771       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5772
5773       if (!rUnsigned && val < 0)
5774         emitcode ("mov", "b,#0x%02x", -val);
5775       else
5776         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5777     }
5778   else /* ! literal */
5779     {
5780       if (rUnsigned)
5781         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5782       else
5783         {
5784           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5785           lbl = newiTempLabel (NULL);
5786           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5787           emitcode ("cpl", "F0"); /* complement sign flag */
5788           emitcode ("cpl", "a");  /* 2's complement */
5789           emitcode ("inc", "a");
5790           emitcode ("", "!tlabeldef", lbl->key + 100);
5791           emitcode ("mov", "b,a");
5792         }
5793     }
5794
5795   if (AOP_TYPE(left) == AOP_LIT)
5796     {
5797       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5798
5799       if (!lUnsigned && val < 0)
5800         emitcode ("mov", "a,#0x%02x", -val);
5801       else
5802         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5803     }
5804   else /* ! literal */
5805     {
5806       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5807
5808       if (!lUnsigned)
5809         {
5810           lbl = newiTempLabel (NULL);
5811           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5812           emitcode ("cpl", "F0"); /* complement sign flag */
5813           emitcode ("cpl", "a");  /* 2's complement */
5814           emitcode ("inc", "a");
5815           emitcode ("", "!tlabeldef", lbl->key + 100);
5816         }
5817     }
5818
5819   /* now the division */
5820   emitcode ("nop", "; workaround for DS80C390 div bug.");
5821   emitcode ("div", "ab");
5822
5823   if (runtimeSign || compiletimeSign)
5824     {
5825       lbl = newiTempLabel (NULL);
5826       if (runtimeSign)
5827         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5828       emitcode ("cpl", "a"); /* lsb 2's complement */
5829       emitcode ("inc", "a");
5830       emitcode ("", "!tlabeldef", lbl->key + 100);
5831
5832       _G.accInUse++;
5833       aopOp (result, ic, TRUE, FALSE);
5834       size = AOP_SIZE (result) - 1;
5835
5836       if (size > 0)
5837         {
5838           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5839              then the result will be in b, a */
5840           emitcode ("mov", "b,a"); /* 1 */
5841           /* msb is 0x00 or 0xff depending on the sign */
5842           if (runtimeSign)
5843             {
5844               emitcode ("mov",  "c,F0");
5845               emitcode ("subb", "a,acc");
5846               emitcode ("xch",  "a,b"); /* 2 */
5847               while (size--)
5848                 aopPut (result, "b", offset++); /* write msb's */
5849             }
5850           else /* compiletimeSign */
5851             while (size--)
5852               aopPut (result, "#0xff", offset++); /* write msb's */
5853         }
5854       aopPut (result, "a", 0); /* 3: write lsb */
5855     }
5856   else
5857     {
5858       _G.accInUse++;
5859       aopOp(result, ic, TRUE, FALSE);
5860       size = AOP_SIZE (result) - 1;
5861
5862       aopPut (result, "a", 0);
5863       while (size--)
5864         aopPut (result, zero, offset++);
5865     }
5866   _G.accInUse--;
5867   popB (pushedB);
5868 }
5869
5870 /*-----------------------------------------------------------------*/
5871 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5872 /*-----------------------------------------------------------------*/
5873 static void genDivTwoByte (operand *left, operand *right,
5874                             operand *result, iCode *ic)
5875 {
5876         sym_link *retype = getSpec(operandType(right));
5877         sym_link *letype = getSpec(operandType(left));
5878         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5879         symbol *lbl;
5880
5881         /* save EA bit in F1 */
5882         lbl = newiTempLabel(NULL);
5883         emitcode ("setb","F1");
5884         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5885         emitcode ("clr","F1");
5886         emitcode("","!tlabeldef",lbl->key+100);
5887
5888         /* load up MA with left */
5889         if (!umult) {
5890                 emitcode("clr","F0");
5891                 lbl = newiTempLabel(NULL);
5892                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5893                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5894                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5895                 emitcode ("xch", "a,b");
5896                 emitcode ("cpl","a");
5897                 emitcode ("add", "a,#1");
5898                 emitcode ("xch", "a,b");
5899                 emitcode ("cpl", "a"); // msb
5900                 emitcode ("addc","a,#0");
5901                 emitcode ("setb","F0");
5902                 emitcode ("","!tlabeldef",lbl->key+100);
5903                 emitcode ("mov","ma,b");
5904                 emitcode ("mov","ma,a");
5905         } else {
5906                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5907                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5908         }
5909
5910         /* load up MB with right */
5911         if (!umult) {
5912                 if (AOP_TYPE(right) == AOP_LIT) {
5913                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5914                         if (val < 0) {
5915                                 lbl = newiTempLabel(NULL);
5916                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5917                                 emitcode("setb","F0");
5918                                 emitcode ("","!tlabeldef",lbl->key+100);
5919                                 val = -val;
5920                         }
5921                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5922                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5923                 } else {
5924                         lbl = newiTempLabel(NULL);
5925                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5926                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5927                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5928                         emitcode ("xch", "a,b");
5929                         emitcode ("cpl","a");
5930                         emitcode ("add", "a,#1");
5931                         emitcode ("xch", "a,b");
5932                         emitcode ("cpl", "a"); // msb
5933                         emitcode ("addc", "a,#0");
5934                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5935                         emitcode ("setb","F0");
5936                         emitcode ("","!tlabeldef",lbl->key+100);
5937                         emitcode ("mov","mb,b");
5938                         emitcode ("mov","mb,a");
5939                 }
5940         } else {
5941                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5942                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5943         }
5944
5945         /* wait for multiplication to finish */
5946         lbl = newiTempLabel(NULL);
5947         emitcode("","!tlabeldef", lbl->key+100);
5948         emitcode("mov","a,mcnt1");
5949         emitcode("anl","a,#!constbyte",0x80);
5950         emitcode("jnz","!tlabel",lbl->key+100);
5951
5952         freeAsmop (left, NULL, ic, TRUE);
5953         freeAsmop (right, NULL, ic,TRUE);
5954         aopOp(result, ic, TRUE, FALSE);
5955
5956         /* if unsigned then simple */
5957         if (umult) {
5958                 aopPut(result,"ma",1);
5959                 aopPut(result,"ma",0);
5960         } else {
5961                 emitcode("push","ma");
5962                 MOVA("ma");
5963                 /* negate result if needed */
5964                 lbl = newiTempLabel(NULL);
5965                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5966                 emitcode("cpl","a");
5967                 emitcode("add","a,#1");
5968                 emitcode("","!tlabeldef", lbl->key+100);
5969                 aopPut(result,"a",0);
5970                 emitcode("pop","acc");
5971                 lbl = newiTempLabel(NULL);
5972                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5973                 emitcode("cpl","a");
5974                 emitcode("addc","a,#0");
5975                 emitcode("","!tlabeldef", lbl->key+100);
5976                 aopPut(result,"a",1);
5977         }
5978         freeAsmop (result, NULL, ic, TRUE);
5979         /* restore EA bit in F1 */
5980         lbl = newiTempLabel(NULL);
5981         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5982         emitcode ("setb","EA");
5983         emitcode("","!tlabeldef",lbl->key+100);
5984         return ;
5985 }
5986
5987 /*-----------------------------------------------------------------*/
5988 /* genDiv - generates code for division                            */
5989 /*-----------------------------------------------------------------*/
5990 static void
5991 genDiv (iCode * ic)
5992 {
5993   operand *left = IC_LEFT (ic);
5994   operand *right = IC_RIGHT (ic);
5995   operand *result = IC_RESULT (ic);
5996
5997   D (emitcode (";", "genDiv "));
5998
5999   /* assign the amsops */
6000   AOP_OP_2 (ic);
6001
6002   /* special cases first */
6003   /* both are bits */
6004   if (AOP_TYPE (left) == AOP_CRY &&
6005       AOP_TYPE (right) == AOP_CRY)
6006     {
6007       genDivbits (left, right, result, ic);
6008       goto release;
6009     }
6010
6011   /* if both are of size == 1 */
6012   if (AOP_SIZE (left) == 1 &&
6013       AOP_SIZE (right) == 1)
6014     {
6015       genDivOneByte (left, right, result, ic);
6016       goto release;
6017     }
6018
6019   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6020           /* use the ds390 ARITHMETIC accel UNIT */
6021           genDivTwoByte (left, right, result, ic);
6022           return ;
6023   }
6024   /* should have been converted to function call */
6025   assert (0);
6026 release:
6027   freeAsmop (result, NULL, ic, TRUE);
6028   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6029   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6030 }
6031
6032 /*-----------------------------------------------------------------*/
6033 /* genModbits :- modulus of bits                                   */
6034 /*-----------------------------------------------------------------*/
6035 static void
6036 genModbits (operand * left,
6037             operand * right,
6038             operand * result,
6039             iCode   * ic)
6040 {
6041   char *l;
6042   bool pushedB;
6043
6044   D(emitcode (";     genModbits",""));
6045
6046   pushedB = pushB ();
6047
6048   /* the result must be bit */
6049   LOAD_AB_FOR_DIV (left, right, l);
6050   emitcode ("div", "ab");
6051   emitcode ("mov", "a,b");
6052   emitcode ("rrc", "a");
6053   aopOp(result, ic, TRUE, FALSE);
6054
6055   popB (pushedB);
6056
6057   aopPut (result, "c", 0);
6058 }
6059
6060 /*-----------------------------------------------------------------*/
6061 /* genModOneByte : 8 bit modulus                                   */
6062 /*-----------------------------------------------------------------*/
6063 static void
6064 genModOneByte (operand * left,
6065                operand * right,
6066                operand * result,
6067                iCode   * ic)
6068 {
6069   bool lUnsigned, rUnsigned, pushedB;
6070   bool runtimeSign, compiletimeSign;
6071   char *l;
6072   symbol *lbl;
6073   int size, offset;
6074
6075   D(emitcode (";     genModOneByte",""));
6076
6077   offset = 1;
6078   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6079   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6080
6081   pushedB = pushB ();
6082
6083   /* signed or unsigned */
6084   if (lUnsigned && rUnsigned)
6085     {
6086       /* unsigned is easy */
6087       LOAD_AB_FOR_DIV (left, right, l);
6088       emitcode ("div", "ab");
6089       aopOp (result, ic, TRUE, FALSE);
6090       aopPut (result, "b", 0);
6091
6092       for (size = AOP_SIZE (result) - 1; size--;)
6093         aopPut (result, zero, offset++);
6094
6095       popB (pushedB);
6096       return;
6097     }
6098
6099   /* signed is a little bit more difficult */
6100
6101   /* now sign adjust for both left & right */
6102
6103   /* modulus: sign of the right operand has no influence on the result! */
6104   if (AOP_TYPE(right) == AOP_LIT)
6105     {
6106       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6107
6108       if (!rUnsigned && val < 0)
6109         emitcode ("mov", "b,#0x%02x", -val);
6110       else
6111         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6112     }
6113   else /* not literal */
6114     {
6115       if (rUnsigned)
6116         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6117       else
6118         {
6119           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6120           lbl = newiTempLabel (NULL);
6121           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6122           emitcode ("cpl", "a");  /* 2's complement */
6123           emitcode ("inc", "a");
6124           emitcode ("", "!tlabeldef", lbl->key + 100);
6125           emitcode ("mov", "b,a");
6126         }
6127     }
6128
6129   /* let's see what's needed: */
6130   /* apply negative sign during runtime */
6131   runtimeSign = FALSE;
6132   /* negative sign from literals */
6133   compiletimeSign = FALSE;
6134
6135   /* sign adjust left side */
6136   if (AOP_TYPE(left) == AOP_LIT)
6137     {
6138       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6139
6140       if (!lUnsigned && val < 0)
6141         {
6142           compiletimeSign = TRUE; /* set sign flag */
6143           emitcode ("mov", "a,#0x%02x", -val);
6144         }
6145       else
6146         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6147     }
6148   else /* ! literal */
6149     {
6150       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6151
6152       if (!lUnsigned)
6153         {
6154           runtimeSign = TRUE;
6155           emitcode ("clr", "F0"); /* clear sign flag */
6156
6157           lbl = newiTempLabel (NULL);
6158           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6159           emitcode ("setb", "F0"); /* set sign flag */
6160           emitcode ("cpl", "a");   /* 2's complement */
6161           emitcode ("inc", "a");
6162           emitcode ("", "!tlabeldef", lbl->key + 100);
6163         }
6164     }
6165
6166   /* now the modulus */
6167   emitcode ("nop", "; workaround for DS80C390 div bug.");
6168   emitcode ("div", "ab");
6169
6170   if (runtimeSign || compiletimeSign)
6171     {
6172       emitcode ("mov", "a,b");
6173       lbl = newiTempLabel (NULL);
6174       if (runtimeSign)
6175         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6176       emitcode ("cpl", "a"); /* lsb 2's complement */
6177       emitcode ("inc", "a");
6178       emitcode ("", "!tlabeldef", lbl->key + 100);
6179
6180       _G.accInUse++;
6181       aopOp (result, ic, TRUE, FALSE);
6182       size = AOP_SIZE (result) - 1;
6183
6184       if (size > 0)
6185         {
6186           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6187              then the result will be in b, a */
6188           emitcode ("mov", "b,a"); /* 1 */
6189           /* msb is 0x00 or 0xff depending on the sign */
6190           if (runtimeSign)
6191             {
6192               emitcode ("mov",  "c,F0");
6193               emitcode ("subb", "a,acc");
6194               emitcode ("xch",  "a,b"); /* 2 */
6195               while (size--)
6196                 aopPut (result, "b", offset++); /* write msb's */
6197             }
6198           else /* compiletimeSign */
6199             while (size--)
6200               aopPut (result, "#0xff", offset++); /* write msb's */
6201         }
6202       aopPut (result, "a", 0); /* 3: write lsb */
6203     }
6204   else
6205     {
6206       _G.accInUse++;
6207       aopOp(result, ic, TRUE, FALSE);
6208       size = AOP_SIZE (result) - 1;
6209
6210       aopPut (result, "b", 0);
6211       while (size--)
6212         aopPut (result, zero, offset++);
6213     }
6214   _G.accInUse--;
6215   popB (pushedB);
6216 }
6217
6218 /*-----------------------------------------------------------------*/
6219 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6220 /*-----------------------------------------------------------------*/
6221 static void genModTwoByte (operand *left, operand *right,
6222                             operand *result, iCode *ic)
6223 {
6224         sym_link *retype = getSpec(operandType(right));
6225         sym_link *letype = getSpec(operandType(left));
6226         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6227         symbol *lbl;
6228
6229         /* load up MA with left */
6230         /* save EA bit in F1 */
6231         lbl = newiTempLabel(NULL);
6232         emitcode ("setb","F1");
6233         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6234         emitcode ("clr","F1");
6235         emitcode("","!tlabeldef",lbl->key+100);
6236
6237         if (!umult) {
6238                 lbl = newiTempLabel(NULL);
6239                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6240                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6241                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6242                 emitcode ("xch", "a,b");
6243                 emitcode ("cpl","a");
6244                 emitcode ("add", "a,#1");
6245                 emitcode ("xch", "a,b");
6246                 emitcode ("cpl", "a"); // msb
6247                 emitcode ("addc","a,#0");
6248                 emitcode ("","!tlabeldef",lbl->key+100);
6249                 emitcode ("mov","ma,b");
6250                 emitcode ("mov","ma,a");
6251         } else {
6252                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6253                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6254         }
6255
6256         /* load up MB with right */
6257         if (!umult) {
6258                 if (AOP_TYPE(right) == AOP_LIT) {
6259                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6260                         if (val < 0) {
6261                                 val = -val;
6262                         }
6263                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6264                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6265                 } else {
6266                         lbl = newiTempLabel(NULL);
6267                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6268                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6269                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6270                         emitcode ("xch", "a,b");
6271                         emitcode ("cpl","a");
6272                         emitcode ("add", "a,#1");
6273                         emitcode ("xch", "a,b");
6274                         emitcode ("cpl", "a"); // msb
6275                         emitcode ("addc", "a,#0");
6276                         emitcode ("","!tlabeldef",lbl->key+100);
6277                         emitcode ("mov","mb,b");
6278                         emitcode ("mov","mb,a");
6279                 }
6280         } else {
6281                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6282                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6283         }
6284
6285         /* wait for multiplication to finish */
6286         lbl = newiTempLabel(NULL);
6287         emitcode("","!tlabeldef", lbl->key+100);
6288         emitcode("mov","a,mcnt1");
6289         emitcode("anl","a,#!constbyte",0x80);
6290         emitcode("jnz","!tlabel",lbl->key+100);
6291
6292         freeAsmop (left, NULL, ic, TRUE);
6293         freeAsmop (right, NULL, ic,TRUE);
6294         aopOp(result, ic, TRUE, FALSE);
6295
6296         aopPut(result,"mb",1);
6297         aopPut(result,"mb",0);
6298         freeAsmop (result, NULL, ic, TRUE);
6299
6300         /* restore EA bit in F1 */
6301         lbl = newiTempLabel(NULL);
6302         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6303         emitcode ("setb","EA");
6304         emitcode("","!tlabeldef",lbl->key+100);
6305         return ;
6306 }
6307
6308 /*-----------------------------------------------------------------*/
6309 /* genMod - generates code for division                            */
6310 /*-----------------------------------------------------------------*/
6311 static void
6312 genMod (iCode * ic)
6313 {
6314   operand *left = IC_LEFT (ic);
6315   operand *right = IC_RIGHT (ic);
6316   operand *result = IC_RESULT (ic);
6317
6318   D (emitcode (";", "genMod "));
6319
6320   /* assign the asmops */
6321   AOP_OP_2 (ic);
6322
6323   /* special cases first */
6324   /* both are bits */
6325   if (AOP_TYPE (left) == AOP_CRY &&
6326       AOP_TYPE (right) == AOP_CRY)
6327     {
6328       genModbits (left, right, result, ic);
6329       goto release;
6330     }
6331
6332   /* if both are of size == 1 */
6333   if (AOP_SIZE (left) == 1 &&
6334       AOP_SIZE (right) == 1)
6335     {
6336       genModOneByte (left, right, result, ic);
6337       goto release;
6338     }
6339
6340   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6341           /* use the ds390 ARITHMETIC accel UNIT */
6342           genModTwoByte (left, right, result, ic);
6343           return ;
6344   }
6345
6346   /* should have been converted to function call */
6347   assert (0);
6348
6349 release:
6350   freeAsmop (result, NULL, ic, TRUE);
6351   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6352   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6353 }
6354
6355 /*-----------------------------------------------------------------*/
6356 /* genIfxJump :- will create a jump depending on the ifx           */
6357 /*-----------------------------------------------------------------*/
6358 static void
6359 genIfxJump (iCode * ic, char *jval)
6360 {
6361   symbol *jlbl;
6362   symbol *tlbl = newiTempLabel (NULL);
6363   char *inst;
6364
6365   D (emitcode (";", "genIfxJump"));
6366
6367   /* if true label then we jump if condition
6368      supplied is true */
6369   if (IC_TRUE (ic))
6370     {
6371       jlbl = IC_TRUE (ic);
6372       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6373                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6374     }
6375   else
6376     {
6377       /* false label is present */
6378       jlbl = IC_FALSE (ic);
6379       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6380                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6381     }
6382   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6383     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6384   else
6385     emitcode (inst, "!tlabel", tlbl->key + 100);
6386   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6387   emitcode ("", "!tlabeldef", tlbl->key + 100);
6388
6389   /* mark the icode as generated */
6390   ic->generated = 1;
6391 }
6392
6393 /*-----------------------------------------------------------------*/
6394 /* genCmp :- greater or less than comparison                       */
6395 /*-----------------------------------------------------------------*/
6396 static void
6397 genCmp (operand * left, operand * right,
6398         iCode * ic, iCode * ifx, int sign)
6399 {
6400   int size, offset = 0;
6401   unsigned long lit = 0L;
6402   operand *result;
6403
6404   D (emitcode (";", "genCmp"));
6405
6406   result = IC_RESULT (ic);
6407
6408   /* if left & right are bit variables */
6409   if (AOP_TYPE (left) == AOP_CRY &&
6410       AOP_TYPE (right) == AOP_CRY)
6411     {
6412       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6413       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6414     }
6415   else
6416     {
6417       /* subtract right from left if at the
6418          end the carry flag is set then we know that
6419          left is greater than right */
6420       size = max (AOP_SIZE (left), AOP_SIZE (right));
6421
6422       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6423       if ((size == 1) && !sign &&
6424           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6425         {
6426           symbol *lbl = newiTempLabel (NULL);
6427           emitcode ("cjne", "%s,%s,!tlabel",
6428                     aopGet (left, offset, FALSE, FALSE, NULL),
6429                     aopGet (right, offset, FALSE, FALSE, NULL),
6430                     lbl->key + 100);
6431           emitcode ("", "!tlabeldef", lbl->key + 100);
6432         }
6433       else
6434         {
6435           if (AOP_TYPE (right) == AOP_LIT)
6436             {
6437               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6438               /* optimize if(x < 0) or if(x >= 0) */
6439               if (lit == 0L)
6440                 {
6441                   if (!sign)
6442                     {
6443                       CLRC;
6444                     }
6445                   else
6446                     {
6447                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6448
6449                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6450                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6451
6452                       aopOp (result, ic, FALSE, FALSE);
6453
6454                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6455                         {
6456                           freeAsmop (result, NULL, ic, TRUE);
6457                           genIfxJump (ifx, "acc.7");
6458                           return;
6459                         }
6460                       else
6461                         {
6462                           emitcode ("rlc", "a");
6463                         }
6464                       goto release_freedLR;
6465                     }
6466                   goto release;
6467                 }
6468             }
6469           CLRC;
6470           while (size--)
6471             {
6472               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6473               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6474               // emitcode (";", "genCmp #2");
6475               if (sign && (size == 0))
6476                 {
6477                   // emitcode (";", "genCmp #3");
6478                   emitcode ("xrl", "a,#!constbyte",0x80);
6479                   if (AOP_TYPE (right) == AOP_LIT)
6480                     {
6481                       unsigned long lit = (unsigned long)
6482                       floatFromVal (AOP (right)->aopu.aop_lit);
6483                       // emitcode (";", "genCmp #3.1");
6484                       emitcode ("subb", "a,#!constbyte",
6485                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6486                     }
6487                   else
6488                     {
6489                       // emitcode (";", "genCmp #3.2");
6490                       saveAccWarn = 0;
6491                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6492                       saveAccWarn = DEFAULT_ACC_WARNING;
6493                       emitcode ("xrl", "b,#!constbyte",0x80);
6494                       emitcode ("subb", "a,b");
6495                     }
6496                 }
6497               else
6498                 {
6499                   const char *s;
6500
6501                   // emitcode (";", "genCmp #4");
6502                   saveAccWarn = 0;
6503                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6504                   saveAccWarn = DEFAULT_ACC_WARNING;
6505
6506                   emitcode ("subb", "a,%s", s);
6507                 }
6508             }
6509         }
6510     }
6511
6512 release:
6513 /* Don't need the left & right operands any more; do need the result. */
6514   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6515   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6516
6517   aopOp (result, ic, FALSE, FALSE);
6518
6519 release_freedLR:
6520
6521   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6522     {
6523       outBitC (result);
6524     }
6525   else
6526     {
6527       /* if the result is used in the next
6528          ifx conditional branch then generate
6529          code a little differently */
6530       if (ifx)
6531         {
6532           genIfxJump (ifx, "c");
6533         }
6534       else
6535         {
6536           outBitC (result);
6537         }
6538       /* leave the result in acc */
6539     }
6540   freeAsmop (result, NULL, ic, TRUE);
6541 }
6542
6543 /*-----------------------------------------------------------------*/
6544 /* genCmpGt :- greater than comparison                             */
6545 /*-----------------------------------------------------------------*/
6546 static void
6547 genCmpGt (iCode * ic, iCode * ifx)
6548 {
6549   operand *left, *right;
6550   sym_link *letype, *retype;
6551   int sign;
6552
6553   D (emitcode (";", "genCmpGt"));
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 (right, left, ic, ifx, sign);
6566 }
6567
6568 /*-----------------------------------------------------------------*/
6569 /* genCmpLt - less than comparisons                                */
6570 /*-----------------------------------------------------------------*/
6571 static void
6572 genCmpLt (iCode * ic, iCode * ifx)
6573 {
6574   operand *left, *right;
6575   sym_link *letype, *retype;
6576   int sign;
6577
6578   D (emitcode (";", "genCmpLt "));
6579
6580   left = IC_LEFT (ic);
6581   right = IC_RIGHT (ic);
6582
6583   letype = getSpec (operandType (left));
6584   retype = getSpec (operandType (right));
6585   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6586
6587   /* assign the left & right amsops */
6588   AOP_OP_2 (ic);
6589
6590   genCmp (left, right, ic, ifx, sign);
6591 }
6592
6593 /*-----------------------------------------------------------------*/
6594 /* gencjneshort - compare and jump if not equal                    */
6595 /*-----------------------------------------------------------------*/
6596 static void
6597 gencjneshort (operand * left, operand * right, symbol * lbl)
6598 {
6599   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6600   int offset = 0;
6601   unsigned long lit = 0L;
6602
6603   D (emitcode (";", "gencjneshort"));
6604
6605   /* if the left side is a literal or
6606      if the right is in a pointer register and left
6607      is not */
6608   if ((AOP_TYPE (left) == AOP_LIT) ||
6609       (AOP_TYPE (left) == AOP_IMMD) ||
6610       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6611     {
6612       operand *t = right;
6613       right = left;
6614       left = t;
6615     }
6616
6617   if (AOP_TYPE (right) == AOP_LIT)
6618     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6619
6620   if (opIsGptr (left) || opIsGptr (right))
6621     {
6622       /* We are comparing a generic pointer to something.
6623        * Exclude the generic type byte from the comparison.
6624        */
6625       size--;
6626       D (emitcode (";", "cjneshort: generic ptr special case."););
6627     }
6628
6629
6630   /* if the right side is a literal then anything goes */
6631   if (AOP_TYPE (right) == AOP_LIT &&
6632       AOP_TYPE (left) != AOP_DIR)
6633     {
6634       while (size--)
6635         {
6636           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6637           emitcode ("cjne", "a,%s,!tlabel",
6638                     aopGet (right, offset, FALSE, FALSE, NULL),
6639                     lbl->key + 100);
6640           offset++;
6641         }
6642     }
6643
6644   /* if the right side is in a register or in direct space or
6645      if the left is a pointer register & right is not */
6646   else if (AOP_TYPE (right) == AOP_REG ||
6647            AOP_TYPE (right) == AOP_DIR ||
6648            AOP_TYPE (right) == AOP_LIT ||
6649            AOP_TYPE (right) == AOP_IMMD ||
6650            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6651            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6652     {
6653       while (size--)
6654         {
6655           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6656           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6657               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6658             emitcode ("jnz", "!tlabel", lbl->key + 100);
6659           else
6660             emitcode ("cjne", "a,%s,!tlabel",
6661                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6662                       lbl->key + 100);
6663           offset++;
6664         }
6665     }
6666   else
6667     {
6668       /* right is a pointer reg need both a & b */
6669       while (size--)
6670         {
6671           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6672           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6673           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6674           offset++;
6675         }
6676     }
6677 }
6678
6679 /*-----------------------------------------------------------------*/
6680 /* gencjne - compare and jump if not equal                         */
6681 /*-----------------------------------------------------------------*/
6682 static void
6683 gencjne (operand * left, operand * right, symbol * lbl)
6684 {
6685   symbol *tlbl = newiTempLabel (NULL);
6686
6687   D (emitcode (";", "gencjne"));
6688
6689   gencjneshort (left, right, lbl);
6690
6691   emitcode ("mov", "a,%s", one);
6692   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6693   emitcode ("", "!tlabeldef", lbl->key + 100);
6694   emitcode ("clr", "a");
6695   emitcode ("", "!tlabeldef", tlbl->key + 100);
6696 }
6697
6698 /*-----------------------------------------------------------------*/
6699 /* genCmpEq - generates code for equal to                          */
6700 /*-----------------------------------------------------------------*/
6701 static void
6702 genCmpEq (iCode * ic, iCode * ifx)
6703 {
6704   operand *left, *right, *result;
6705
6706   D (emitcode (";", "genCmpEq"));
6707
6708   AOP_OP_2 (ic);
6709   AOP_SET_LOCALS (ic);
6710
6711   /* if literal, literal on the right or
6712      if the right is in a pointer register and left
6713      is not */
6714   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6715       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6716     {
6717       operand *t = IC_RIGHT (ic);
6718       IC_RIGHT (ic) = IC_LEFT (ic);
6719       IC_LEFT (ic) = t;
6720     }
6721
6722   if (ifx &&                    /* !AOP_SIZE(result) */
6723       OP_SYMBOL (result) &&
6724       OP_SYMBOL (result)->regType == REG_CND)
6725     {
6726       symbol *tlbl;
6727       /* if they are both bit variables */
6728       if (AOP_TYPE (left) == AOP_CRY &&
6729           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6730         {
6731           if (AOP_TYPE (right) == AOP_LIT)
6732             {
6733               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6734               if (lit == 0L)
6735                 {
6736                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6737                   emitcode ("cpl", "c");
6738                 }
6739               else if (lit == 1L)
6740                 {
6741                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6742                 }
6743               else
6744                 {
6745                   emitcode ("clr", "c");
6746                 }
6747               /* AOP_TYPE(right) == AOP_CRY */
6748             }
6749           else
6750             {
6751               symbol *lbl = newiTempLabel (NULL);
6752               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6753               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6754               emitcode ("cpl", "c");
6755               emitcode ("", "!tlabeldef", (lbl->key + 100));
6756             }
6757           /* if true label then we jump if condition
6758              supplied is true */
6759           tlbl = newiTempLabel (NULL);
6760           if (IC_TRUE (ifx))
6761             {
6762               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6763               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6764             }
6765           else
6766             {
6767               emitcode ("jc", "!tlabel", tlbl->key + 100);
6768               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6769             }
6770           emitcode ("", "!tlabeldef", tlbl->key + 100);
6771         }
6772       else
6773         {
6774           tlbl = newiTempLabel (NULL);
6775           gencjneshort (left, right, tlbl);
6776           if (IC_TRUE (ifx))
6777             {
6778               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6779               emitcode ("", "!tlabeldef", tlbl->key + 100);
6780             }
6781           else
6782             {
6783               symbol *lbl = newiTempLabel (NULL);
6784               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6785               emitcode ("", "!tlabeldef", tlbl->key + 100);
6786               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6787               emitcode ("", "!tlabeldef", lbl->key + 100);
6788             }
6789         }
6790       /* mark the icode as generated */
6791       ifx->generated = 1;
6792
6793       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6794       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6795       return;
6796     }
6797
6798   /* if they are both bit variables */
6799   if (AOP_TYPE (left) == AOP_CRY &&
6800       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6801     {
6802       if (AOP_TYPE (right) == AOP_LIT)
6803         {
6804           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6805           if (lit == 0L)
6806             {
6807               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6808               emitcode ("cpl", "c");
6809             }
6810           else if (lit == 1L)
6811             {
6812               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6813             }
6814           else
6815             {
6816               emitcode ("clr", "c");
6817             }
6818           /* AOP_TYPE(right) == AOP_CRY */
6819         }
6820       else
6821         {
6822           symbol *lbl = newiTempLabel (NULL);
6823           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6824           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6825           emitcode ("cpl", "c");
6826           emitcode ("", "!tlabeldef", (lbl->key + 100));
6827         }
6828
6829       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6830       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6831
6832       aopOp (result, ic, TRUE, FALSE);
6833
6834       /* c = 1 if egal */
6835       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6836         {
6837           outBitC (result);
6838           goto release;
6839         }
6840       if (ifx)
6841         {
6842           genIfxJump (ifx, "c");
6843           goto release;
6844         }
6845       /* if the result is used in an arithmetic operation
6846          then put the result in place */
6847       outBitC (result);
6848     }
6849   else
6850     {
6851       gencjne (left, right, newiTempLabel (NULL));
6852
6853       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6854       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6855
6856       aopOp (result, ic, TRUE, FALSE);
6857
6858       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6859         {
6860           aopPut (result, "a", 0);
6861           goto release;
6862         }
6863       if (ifx)
6864         {
6865           genIfxJump (ifx, "a");
6866           goto release;
6867         }
6868       /* if the result is used in an arithmetic operation
6869          then put the result in place */
6870       if (AOP_TYPE (result) != AOP_CRY)
6871         outAcc (result);
6872       /* leave the result in acc */
6873     }
6874
6875 release:
6876   freeAsmop (result, NULL, ic, TRUE);
6877 }
6878
6879 /*-----------------------------------------------------------------*/
6880 /* ifxForOp - returns the icode containing the ifx for operand     */
6881 /*-----------------------------------------------------------------*/
6882 static iCode *
6883 ifxForOp (operand * op, iCode * ic)
6884 {
6885   /* if true symbol then needs to be assigned */
6886   if (IS_TRUE_SYMOP (op))
6887     return NULL;
6888
6889   /* if this has register type condition and
6890      the next instruction is ifx with the same operand
6891      and live to of the operand is upto the ifx only then */
6892   if (ic->next &&
6893       ic->next->op == IFX &&
6894       IC_COND (ic->next)->key == op->key &&
6895       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6896     return ic->next;
6897
6898   return NULL;
6899 }
6900
6901 /*-----------------------------------------------------------------*/
6902 /* hasInc - operand is incremented before any other use            */
6903 /*-----------------------------------------------------------------*/
6904 static iCode *
6905 hasInc (operand *op, iCode *ic, int osize)
6906 {
6907   sym_link *type = operandType(op);
6908   sym_link *retype = getSpec (type);
6909   iCode *lic = ic->next;
6910   int isize ;
6911
6912   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6913   if (!IS_SYMOP(op)) return NULL;
6914
6915   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6916   if (IS_AGGREGATE(type->next)) return NULL;
6917   if (osize != (isize = getSize(type->next))) return NULL;
6918
6919   while (lic) {
6920       /* if operand of the form op = op + <sizeof *op> */
6921       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6922           isOperandEqual(IC_RESULT(lic),op) &&
6923           isOperandLiteral(IC_RIGHT(lic)) &&
6924           operandLitValue(IC_RIGHT(lic)) == isize) {
6925           return lic;
6926       }
6927       /* if the operand used or deffed */
6928       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6929           return NULL;
6930       }
6931       /* if GOTO or IFX */
6932       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6933       lic = lic->next;
6934   }
6935   return NULL;
6936 }
6937
6938 /*-----------------------------------------------------------------*/
6939 /* genAndOp - for && operation                                     */
6940 /*-----------------------------------------------------------------*/
6941 static void
6942 genAndOp (iCode * ic)
6943 {
6944   operand *left, *right, *result;
6945   symbol *tlbl;
6946
6947   D (emitcode (";", "genAndOp "));
6948
6949   /* note here that && operations that are in an
6950      if statement are taken away by backPatchLabels
6951      only those used in arthmetic operations remain */
6952   AOP_OP_2 (ic);
6953   AOP_SET_LOCALS (ic);
6954
6955   /* if both are bit variables */
6956   if (AOP_TYPE (left) == AOP_CRY &&
6957       AOP_TYPE (right) == AOP_CRY)
6958     {
6959       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6960       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6961       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6962       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6963
6964       aopOp (result,ic,FALSE, FALSE);
6965       outBitC (result);
6966     }
6967   else
6968     {
6969       tlbl = newiTempLabel (NULL);
6970       toBoolean (left);
6971       emitcode ("jz", "!tlabel", tlbl->key + 100);
6972       toBoolean (right);
6973       emitcode ("", "!tlabeldef", tlbl->key + 100);
6974       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6975       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6976
6977       aopOp (result,ic,FALSE, FALSE);
6978       outBitAcc (result);
6979     }
6980     freeAsmop (result, NULL, ic, TRUE);
6981 }
6982
6983
6984 /*-----------------------------------------------------------------*/
6985 /* genOrOp - for || operation                                      */
6986 /*-----------------------------------------------------------------*/
6987 static void
6988 genOrOp (iCode * ic)
6989 {
6990   operand *left, *right, *result;
6991   symbol *tlbl;
6992
6993   D (emitcode (";", "genOrOp "));
6994
6995   /* note here that || operations that are in an
6996      if statement are taken away by backPatchLabels
6997      only those used in arthmetic operations remain */
6998   AOP_OP_2 (ic);
6999   AOP_SET_LOCALS (ic);
7000
7001   /* if both are bit variables */
7002   if (AOP_TYPE (left) == AOP_CRY &&
7003       AOP_TYPE (right) == AOP_CRY)
7004     {
7005       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7006       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7007       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7008       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7009
7010       aopOp (result,ic,FALSE, FALSE);
7011
7012       outBitC (result);
7013     }
7014   else
7015     {
7016       tlbl = newiTempLabel (NULL);
7017       toBoolean (left);
7018       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7019       toBoolean (right);
7020       emitcode ("", "!tlabeldef", tlbl->key + 100);
7021       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7022       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7023
7024       aopOp (result,ic,FALSE, FALSE);
7025
7026       outBitAcc (result);
7027     }
7028
7029   freeAsmop (result, NULL, ic, TRUE);
7030 }
7031
7032 /*-----------------------------------------------------------------*/
7033 /* isLiteralBit - test if lit == 2^n                               */
7034 /*-----------------------------------------------------------------*/
7035 static int
7036 isLiteralBit (unsigned long lit)
7037 {
7038   unsigned long pw[32] =
7039   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7040    0x100L, 0x200L, 0x400L, 0x800L,
7041    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7042    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7043    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7044    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7045    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7046   int idx;
7047
7048   for (idx = 0; idx < 32; idx++)
7049     if (lit == pw[idx])
7050       return idx + 1;
7051   return 0;
7052 }
7053
7054 /*-----------------------------------------------------------------*/
7055 /* continueIfTrue -                                                */
7056 /*-----------------------------------------------------------------*/
7057 static void
7058 continueIfTrue (iCode * ic)
7059 {
7060   if (IC_TRUE (ic))
7061     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7062   ic->generated = 1;
7063 }
7064
7065 /*-----------------------------------------------------------------*/
7066 /* jmpIfTrue -                                                     */
7067 /*-----------------------------------------------------------------*/
7068 static void
7069 jumpIfTrue (iCode * ic)
7070 {
7071   if (!IC_TRUE (ic))
7072     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7073   ic->generated = 1;
7074 }
7075
7076 /*-----------------------------------------------------------------*/
7077 /* jmpTrueOrFalse -                                                */
7078 /*-----------------------------------------------------------------*/
7079 static void
7080 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7081 {
7082   // ugly but optimized by peephole
7083   if (IC_TRUE (ic))
7084     {
7085       symbol *nlbl = newiTempLabel (NULL);
7086       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7087       emitcode ("", "!tlabeldef", tlbl->key + 100);
7088       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7089       emitcode ("", "!tlabeldef", nlbl->key + 100);
7090     }
7091   else
7092     {
7093       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7094       emitcode ("", "!tlabeldef", tlbl->key + 100);
7095     }
7096   ic->generated = 1;
7097 }
7098
7099 // Generate code to perform a bit-wise logic operation
7100 // on two operands in far space (assumed to already have been
7101 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7102 // in far space. This requires pushing the result on the stack
7103 // then popping it into the result.
7104 static void
7105 genFarFarLogicOp(iCode *ic, char *logicOp)
7106 {
7107       int size, resultSize, compSize;
7108       int offset = 0;
7109
7110       TR_AP("#5");
7111       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7112       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7113                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7114
7115       _startLazyDPSEvaluation();
7116       for (size = compSize; (size--); offset++)
7117       {
7118           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7119           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7120           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7121
7122           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7123           emitcode ("push", "acc");
7124       }
7125       _endLazyDPSEvaluation();
7126
7127       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7128       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7129       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7130
7131       resultSize = AOP_SIZE(IC_RESULT(ic));
7132
7133       ADJUST_PUSHED_RESULT(compSize, resultSize);
7134
7135       _startLazyDPSEvaluation();
7136       while (compSize--)
7137       {
7138           emitcode ("pop", "acc");
7139           aopPut (IC_RESULT (ic), "a", compSize);
7140       }
7141       _endLazyDPSEvaluation();
7142       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7143 }
7144
7145
7146 /*-----------------------------------------------------------------*/
7147 /* genAnd  - code for and                                          */
7148 /*-----------------------------------------------------------------*/
7149 static void
7150 genAnd (iCode * ic, iCode * ifx)
7151 {
7152   operand *left, *right, *result;
7153   int size, offset = 0;
7154   unsigned long lit = 0L;
7155   int bytelit = 0;
7156   char buffer[10];
7157   bool pushResult;
7158
7159   D (emitcode (";", "genAnd"));
7160
7161   AOP_OP_3_NOFATAL (ic, pushResult);
7162   AOP_SET_LOCALS (ic);
7163
7164   if (pushResult)
7165   {
7166       genFarFarLogicOp(ic, "anl");
7167       return;
7168   }
7169
7170 #ifdef DEBUG_TYPE
7171   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7172             AOP_TYPE (result),
7173             AOP_TYPE (left), AOP_TYPE (right));
7174   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7175             AOP_SIZE (result),
7176             AOP_SIZE (left), AOP_SIZE (right));
7177 #endif
7178
7179   /* if left is a literal & right is not then exchange them */
7180   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7181 #ifdef LOGIC_OPS_BROKEN
7182     ||  AOP_NEEDSACC (left)
7183 #endif
7184     )
7185     {
7186       operand *tmp = right;
7187       right = left;
7188       left = tmp;
7189     }
7190
7191   /* if result = right then exchange left and right */
7192   if (sameRegs (AOP (result), AOP (right)))
7193     {
7194       operand *tmp = right;
7195       right = left;
7196       left = tmp;
7197     }
7198
7199   /* if right is bit then exchange them */
7200   if (AOP_TYPE (right) == AOP_CRY &&
7201       AOP_TYPE (left) != AOP_CRY)
7202     {
7203       operand *tmp = right;
7204       right = left;
7205       left = tmp;
7206     }
7207   if (AOP_TYPE (right) == AOP_LIT)
7208     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7209
7210   size = AOP_SIZE (result);
7211
7212   // if(bit & yy)
7213   // result = bit & yy;
7214   if (AOP_TYPE (left) == AOP_CRY)
7215     {
7216       // c = bit & literal;
7217       if (AOP_TYPE (right) == AOP_LIT)
7218         {
7219           if (lit & 1)
7220             {
7221               if (size && sameRegs (AOP (result), AOP (left)))
7222                 // no change
7223                 goto release;
7224               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7225             }
7226           else
7227             {
7228               // bit(result) = 0;
7229               if (size && (AOP_TYPE (result) == AOP_CRY))
7230                 {
7231                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7232                   goto release;
7233                 }
7234               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7235                 {
7236                   jumpIfTrue (ifx);
7237                   goto release;
7238                 }
7239               emitcode ("clr", "c");
7240             }
7241         }
7242       else
7243         {
7244           if (AOP_TYPE (right) == AOP_CRY)
7245             {
7246               // c = bit & bit;
7247               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7248               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7249             }
7250           else
7251             {
7252               // c = bit & val;
7253               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7254               // c = lsb
7255               emitcode ("rrc", "a");
7256               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7257             }
7258         }
7259       // bit = c
7260       // val = c
7261       if (size)
7262         outBitC (result);
7263       // if(bit & ...)
7264       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7265         genIfxJump (ifx, "c");
7266       goto release;
7267     }
7268
7269   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7270   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7271   if ((AOP_TYPE (right) == AOP_LIT) &&
7272       (AOP_TYPE (result) == AOP_CRY) &&
7273       (AOP_TYPE (left) != AOP_CRY))
7274     {
7275       int posbit = isLiteralBit (lit);
7276       /* left &  2^n */
7277       if (posbit)
7278         {
7279           posbit--;
7280           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7281           // bit = left & 2^n
7282           if (size)
7283             {
7284               switch (posbit & 0x07)
7285                 {
7286                   case 0: emitcode ("rrc", "a");
7287                           break;
7288                   case 7: emitcode ("rlc", "a");
7289                           break;
7290                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7291                           break;
7292                 }
7293             }
7294           // if(left &  2^n)
7295           else
7296             {
7297               if (ifx)
7298                 {
7299                   SNPRINTF (buffer, sizeof(buffer),
7300                             "acc.%d", posbit & 0x07);
7301                   genIfxJump (ifx, buffer);
7302                 }
7303               else
7304                   {
7305                       emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7306                   }
7307               goto release;
7308             }
7309         }
7310       else
7311         {
7312           symbol *tlbl = newiTempLabel (NULL);
7313           int sizel = AOP_SIZE (left);
7314           if (size)
7315             emitcode ("setb", "c");
7316           while (sizel--)
7317             {
7318               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7319                 {
7320                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7321                   // byte ==  2^n ?
7322                   if ((posbit = isLiteralBit (bytelit)) != 0)
7323                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7324                   else
7325                     {
7326                       if (bytelit != 0x0FFL)
7327                         emitcode ("anl", "a,%s",
7328                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7329                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7330                     }
7331                 }
7332               offset++;
7333             }
7334           // bit = left & literal
7335           if (size)
7336             {
7337               emitcode ("clr", "c");
7338               emitcode ("", "!tlabeldef", tlbl->key + 100);
7339             }
7340           // if(left & literal)
7341           else
7342             {
7343               if (ifx)
7344                 jmpTrueOrFalse (ifx, tlbl);
7345               else
7346                 emitcode ("", "!tlabeldef", tlbl->key + 100);
7347               goto release;
7348             }
7349         }
7350       outBitC (result);
7351       goto release;
7352     }
7353
7354   /* if left is same as result */
7355   if (sameRegs (AOP (result), AOP (left)))
7356     {
7357       for (; size--; offset++)
7358         {
7359           if (AOP_TYPE (right) == AOP_LIT)
7360             {
7361               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7362               if (bytelit == 0x0FF)
7363                 {
7364                   /* dummy read of volatile operand */
7365                   if (isOperandVolatile (left, FALSE))
7366                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7367                   else
7368                     continue;
7369                 }
7370               else if (bytelit == 0)
7371                 {
7372                   aopPut (result, zero, offset);
7373                 }
7374               else if (IS_AOP_PREG (result))
7375                 {
7376                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7377                   emitcode ("anl", "a,%s",
7378                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7379                   aopPut (result, "a", offset);
7380                 }
7381               else
7382                 emitcode ("anl", "%s,%s",
7383                           aopGet (left, offset, FALSE, TRUE, NULL),
7384                           aopGet (right, offset, FALSE, FALSE, NULL));
7385             }
7386           else
7387             {
7388               if (AOP_TYPE (left) == AOP_ACC)
7389                 emitcode ("anl", "a,%s",
7390                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7391               else
7392                 {
7393                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7394                   if (IS_AOP_PREG (result))
7395                     {
7396                       emitcode ("anl", "a,%s",
7397                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7398                       aopPut (result, "a", offset);
7399                     }
7400                   else
7401                     emitcode ("anl", "%s,a",
7402                               aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7403                 }
7404             }
7405         }
7406     }
7407   else
7408     {
7409       // left & result in different registers
7410       if (AOP_TYPE (result) == AOP_CRY)
7411         {
7412           // result = bit
7413           // if(size), result in bit
7414           // if(!size && ifx), conditional oper: if(left & right)
7415           symbol *tlbl = newiTempLabel (NULL);
7416           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7417           if (size)
7418             emitcode ("setb", "c");
7419           while (sizer--)
7420             {
7421               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7422                 emitcode ("anl", "a,%s",
7423                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7424               } else {
7425                 if (AOP_TYPE(left)==AOP_ACC)
7426                 {
7427                   bool pushedB = pushB ();
7428                   emitcode("mov", "b,a");
7429                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7430                   emitcode("anl", "a,b");
7431                   popB (pushedB);
7432                 }
7433                 else
7434                 {
7435                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7436                   emitcode ("anl", "a,%s",
7437                             aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7438                 }
7439               }
7440               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7441               offset++;
7442             }
7443           if (size)
7444             {
7445               CLRC;
7446               emitcode ("", "!tlabeldef", tlbl->key + 100);
7447               outBitC (result);
7448             }
7449           else if (ifx)
7450             jmpTrueOrFalse (ifx, tlbl);
7451           else
7452             emitcode ("", "!tlabeldef", tlbl->key + 100);
7453         }
7454       else
7455         {
7456           for (; (size--); offset++)
7457             {
7458               // normal case
7459               // result = left & right
7460               if (AOP_TYPE (right) == AOP_LIT)
7461                 {
7462                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7463                   if (bytelit == 0x0FF)
7464                     {
7465                       aopPut (result,
7466                               aopGet (left, offset, FALSE, FALSE, NULL),
7467                               offset);
7468                       continue;
7469                     }
7470                   else if (bytelit == 0)
7471                     {
7472                       /* dummy read of volatile operand */
7473                       if (isOperandVolatile (left, FALSE))
7474                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7475                       aopPut (result, zero, offset);
7476                       continue;
7477                     }
7478                   D (emitcode (";", "better literal AND."););
7479                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7480                   emitcode ("anl", "a, %s", aopGet (right, offset,
7481                                                     FALSE, FALSE, DP2_RESULT_REG));
7482
7483                 }
7484               else
7485                 {
7486                   // faster than result <- left, anl result,right
7487                   // and better if result is SFR
7488                   if (AOP_TYPE (left) == AOP_ACC)
7489                     {
7490                       emitcode ("anl", "a,%s",
7491                                 aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7492                     }
7493                   else
7494                     {
7495                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
7496                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7497                       {
7498                           emitcode("mov", "b,a");
7499                           rOp = "b";
7500                       }
7501
7502                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7503                       emitcode ("anl", "a,%s", rOp);
7504                     }
7505                 }
7506               aopPut (result, "a", offset);
7507             }
7508         }
7509     }
7510
7511 release:
7512   freeAsmop (result, NULL, ic, TRUE);
7513   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7514   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7515 }
7516
7517 /*-----------------------------------------------------------------*/
7518 /* genOr  - code for or                                            */
7519 /*-----------------------------------------------------------------*/
7520 static void
7521 genOr (iCode * ic, iCode * ifx)
7522 {
7523   operand *left, *right, *result;
7524   int size, offset = 0;
7525   unsigned long lit = 0L;
7526   int bytelit = 0;
7527   bool     pushResult;
7528
7529   D (emitcode (";", "genOr "));
7530
7531   AOP_OP_3_NOFATAL (ic, pushResult);
7532   AOP_SET_LOCALS (ic);
7533
7534   if (pushResult)
7535   {
7536       genFarFarLogicOp(ic, "orl");
7537       return;
7538   }
7539
7540
7541 #ifdef DEBUG_TYPE
7542   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7543             AOP_TYPE (result),
7544             AOP_TYPE (left), AOP_TYPE (right));
7545   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7546             AOP_SIZE (result),
7547             AOP_SIZE (left), AOP_SIZE (right));
7548 #endif
7549
7550   /* if left is a literal & right is not then exchange them */
7551   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7552 #ifdef LOGIC_OPS_BROKEN
7553    || AOP_NEEDSACC (left) // I think this is a net loss now.
7554 #endif
7555       )
7556     {
7557       operand *tmp = right;
7558       right = left;
7559       left = tmp;
7560     }
7561
7562   /* if result = right then exchange them */
7563   if (sameRegs (AOP (result), AOP (right)))
7564     {
7565       operand *tmp = right;
7566       right = left;
7567       left = tmp;
7568     }
7569
7570   /* if right is bit then exchange them */
7571   if (AOP_TYPE (right) == AOP_CRY &&
7572       AOP_TYPE (left) != AOP_CRY)
7573     {
7574       operand *tmp = right;
7575       right = left;
7576       left = tmp;
7577     }
7578   if (AOP_TYPE (right) == AOP_LIT)
7579     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7580
7581   size = AOP_SIZE (result);
7582
7583   // if(bit | yy)
7584   // xx = bit | yy;
7585   if (AOP_TYPE (left) == AOP_CRY)
7586     {
7587       if (AOP_TYPE (right) == AOP_LIT)
7588         {
7589           // c = bit | literal;
7590           if (lit)
7591             {
7592               // lit != 0 => result = 1
7593               if (AOP_TYPE (result) == AOP_CRY)
7594                 {
7595                   if (size)
7596                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7597                   else if (ifx)
7598                     continueIfTrue (ifx);
7599                   goto release;
7600                 }
7601               emitcode ("setb", "c");
7602             }
7603           else
7604             {
7605               // lit == 0 => result = left
7606               if (size && sameRegs (AOP (result), AOP (left)))
7607                 goto release;
7608               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7609             }
7610         }
7611       else
7612         {
7613           if (AOP_TYPE (right) == AOP_CRY)
7614             {
7615               // c = bit | bit;
7616               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7617               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7618             }
7619           else
7620             {
7621               // c = bit | val;
7622               symbol *tlbl = newiTempLabel (NULL);
7623               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7624                 emitcode ("setb", "c");
7625               emitcode ("jb", "%s,!tlabel",
7626                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7627               toBoolean (right);
7628               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7629               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7630                 {
7631                   jmpTrueOrFalse (ifx, tlbl);
7632                   goto release;
7633                 }
7634               else
7635                 {
7636                   CLRC;
7637                   emitcode ("", "!tlabeldef", tlbl->key + 100);
7638                 }
7639             }
7640         }
7641       // bit = c
7642       // val = c
7643       if (size)
7644         outBitC (result);
7645       // if(bit | ...)
7646       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7647            genIfxJump (ifx, "c");
7648       goto release;
7649     }
7650
7651   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7652   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7653   if ((AOP_TYPE (right) == AOP_LIT) &&
7654       (AOP_TYPE (result) == AOP_CRY) &&
7655       (AOP_TYPE (left) != AOP_CRY))
7656     {
7657       if (lit)
7658         {
7659           // result = 1
7660           if (size)
7661             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7662           else
7663             continueIfTrue (ifx);
7664           goto release;
7665         }
7666       else
7667         {
7668           // lit = 0, result = boolean(left)
7669           if (size)
7670             emitcode ("setb", "c");
7671           toBoolean (right);
7672           if (size)
7673             {
7674               symbol *tlbl = newiTempLabel (NULL);
7675               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7676               CLRC;
7677               emitcode ("", "!tlabeldef", tlbl->key + 100);
7678             }
7679           else
7680             {
7681               genIfxJump (ifx, "a");
7682               goto release;
7683             }
7684         }
7685       outBitC (result);
7686       goto release;
7687     }
7688
7689   /* if left is same as result */
7690   if (sameRegs (AOP (result), AOP (left)))
7691     {
7692       for (; size--; offset++)
7693         {
7694           if (AOP_TYPE (right) == AOP_LIT)
7695             {
7696               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7697               if (bytelit == 0)
7698                 {
7699                   /* dummy read of volatile operand */
7700                   if (isOperandVolatile (left, FALSE))
7701                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7702                   else
7703                     continue;
7704                 }
7705               else if (bytelit == 0x0FF)
7706                 {
7707                   aopPut (result, "#0xFF", offset);
7708                 }
7709               else if (IS_AOP_PREG (left))
7710                 {
7711                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7712                   emitcode ("orl", "a,%s",
7713                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7714                   aopPut (result, "a", offset);
7715                 }
7716               else
7717                 {
7718                   emitcode ("orl", "%s,%s",
7719                             aopGet (left, offset, FALSE, TRUE, NULL),
7720                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7721                 }
7722             }
7723           else
7724             {
7725               if (AOP_TYPE (left) == AOP_ACC)
7726                 {
7727                   emitcode ("orl", "a,%s",
7728                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7729                 }
7730               else
7731                 {
7732                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7733                   if (IS_AOP_PREG (left))
7734                     {
7735                       emitcode ("orl", "a,%s",
7736                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7737                       aopPut (result, "a", offset);
7738                     }
7739                   else
7740                     {
7741                       emitcode ("orl", "%s,a",
7742                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7743                     }
7744                 }
7745             }
7746         }
7747     }
7748   else
7749     {
7750       // left & result in different registers
7751       if (AOP_TYPE (result) == AOP_CRY)
7752         {
7753           // result = bit
7754           // if(size), result in bit
7755           // if(!size && ifx), conditional oper: if(left | right)
7756           symbol *tlbl = newiTempLabel (NULL);
7757           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7758           if (size)
7759             emitcode ("setb", "c");
7760           while (sizer--)
7761             {
7762               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7763                 emitcode ("orl", "a,%s",
7764                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7765               } else {
7766                 MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7767                 emitcode ("orl", "a,%s",
7768                           aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7769               }
7770               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7771               offset++;
7772             }
7773           if (size)
7774             {
7775               CLRC;
7776               emitcode ("", "!tlabeldef", tlbl->key + 100);
7777               outBitC (result);
7778             }
7779           else if (ifx)
7780             jmpTrueOrFalse (ifx, tlbl);
7781           else
7782             emitcode ("", "!tlabeldef", tlbl->key + 100);
7783         }
7784       else
7785         {
7786             _startLazyDPSEvaluation();
7787           for (; (size--); offset++)
7788             {
7789               // normal case
7790               // result = left | right
7791               if (AOP_TYPE (right) == AOP_LIT)
7792                 {
7793                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7794                   if (bytelit == 0)
7795                     {
7796                       aopPut (result,
7797                               aopGet (left, offset, FALSE, FALSE, NULL),
7798                               offset);
7799                       continue;
7800                     }
7801                   else if (bytelit == 0x0FF)
7802                     {
7803                       /* dummy read of volatile operand */
7804                       if (isOperandVolatile (left, FALSE))
7805                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7806                       aopPut (result, "#0xFF", offset);
7807                       continue;
7808                     }
7809                   D (emitcode (";", "better literal OR."););
7810                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7811                   emitcode ("orl", "a, %s",
7812                             aopGet (right, offset,
7813                                     FALSE, FALSE, DP2_RESULT_REG));
7814
7815                 }
7816               else
7817                 {
7818                   // faster than result <- left, anl result,right
7819                   // and better if result is SFR
7820                   if (AOP_TYPE (left) == AOP_ACC)
7821                     {
7822                       emitcode ("orl", "a,%s",
7823                                 aopGet (right, offset,
7824                                         FALSE, FALSE, DP2_RESULT_REG));
7825                     }
7826                   else
7827                     {
7828                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
7829
7830                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7831                       {
7832                           emitcode("mov", "b,a");
7833                           rOp = "b";
7834                       }
7835
7836                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7837                       emitcode ("orl", "a,%s", rOp);
7838                     }
7839                 }
7840               aopPut (result, "a", offset);
7841             }
7842             _endLazyDPSEvaluation();
7843         }
7844     }
7845
7846 release:
7847   freeAsmop (result, NULL, ic, TRUE);
7848   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7849   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7850 }
7851
7852 /*-----------------------------------------------------------------*/
7853 /* genXor - code for xclusive or                                   */
7854 /*-----------------------------------------------------------------*/
7855 static void
7856 genXor (iCode * ic, iCode * ifx)
7857 {
7858   operand *left, *right, *result;
7859   int size, offset = 0;
7860   unsigned long lit = 0L;
7861   int bytelit = 0;
7862   bool pushResult;
7863
7864   D (emitcode (";", "genXor "));
7865
7866   AOP_OP_3_NOFATAL (ic, pushResult);
7867   AOP_SET_LOCALS (ic);
7868
7869   if (pushResult)
7870   {
7871       genFarFarLogicOp(ic, "xrl");
7872       return;
7873   }
7874
7875 #ifdef DEBUG_TYPE
7876   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7877             AOP_TYPE (result),
7878             AOP_TYPE (left), AOP_TYPE (right));
7879   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7880             AOP_SIZE (result),
7881             AOP_SIZE (left), AOP_SIZE (right));
7882 #endif
7883
7884   /* if left is a literal & right is not ||
7885      if left needs acc & right does not */
7886   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7887 #ifdef LOGIC_OPS_BROKEN
7888       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7889 #endif
7890      )
7891     {
7892       operand *tmp = right;
7893       right = left;
7894       left = tmp;
7895     }
7896
7897   /* if result = right then exchange them */
7898   if (sameRegs (AOP (result), AOP (right)))
7899     {
7900       operand *tmp = right;
7901       right = left;
7902       left = tmp;
7903     }
7904
7905   /* if right is bit then exchange them */
7906   if (AOP_TYPE (right) == AOP_CRY &&
7907       AOP_TYPE (left) != AOP_CRY)
7908     {
7909       operand *tmp = right;
7910       right = left;
7911       left = tmp;
7912     }
7913   if (AOP_TYPE (right) == AOP_LIT)
7914     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7915
7916   size = AOP_SIZE (result);
7917
7918   // if(bit ^ yy)
7919   // xx = bit ^ yy;
7920   if (AOP_TYPE (left) == AOP_CRY)
7921     {
7922       if (AOP_TYPE (right) == AOP_LIT)
7923         {
7924           // c = bit & literal;
7925           if (lit >> 1)
7926             {
7927               // lit>>1  != 0 => result = 1
7928               if (AOP_TYPE (result) == AOP_CRY)
7929                 {
7930                   if (size)
7931                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7932                   else if (ifx)
7933                     continueIfTrue (ifx);
7934                   goto release;
7935                 }
7936               emitcode ("setb", "c");
7937             }
7938           else
7939             {
7940               // lit == (0 or 1)
7941               if (lit == 0)
7942                 {
7943                   // lit == 0, result = left
7944                   if (size && sameRegs (AOP (result), AOP (left)))
7945                     goto release;
7946                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7947                 }
7948               else
7949                 {
7950                   // lit == 1, result = not(left)
7951                   if (size && sameRegs (AOP (result), AOP (left)))
7952                     {
7953                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7954                       goto release;
7955                     }
7956                   else
7957                     {
7958                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7959                       emitcode ("cpl", "c");
7960                     }
7961                 }
7962             }
7963
7964         }
7965       else
7966         {
7967           // right != literal
7968           symbol *tlbl = newiTempLabel (NULL);
7969           if (AOP_TYPE (right) == AOP_CRY)
7970             {
7971               // c = bit ^ bit;
7972               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7973             }
7974           else
7975             {
7976               int sizer = AOP_SIZE (right);
7977               // c = bit ^ val
7978               // if val>>1 != 0, result = 1
7979               emitcode ("setb", "c");
7980               while (sizer)
7981                 {
7982                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
7983                   if (sizer == 1)
7984                     // test the msb of the lsb
7985                     emitcode ("anl", "a,#!constbyte",0xfe);
7986                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
7987                   sizer--;
7988                 }
7989               // val = (0,1)
7990               emitcode ("rrc", "a");
7991             }
7992           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7993           emitcode ("cpl", "c");
7994           emitcode ("", "!tlabeldef", (tlbl->key + 100));
7995         }
7996       // bit = c
7997       // val = c
7998       if (size)
7999         outBitC (result);
8000       // if(bit | ...)
8001       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8002         genIfxJump (ifx, "c");
8003       goto release;
8004     }
8005
8006   /* if left is same as result */
8007   if (sameRegs (AOP (result), AOP (left)))
8008     {
8009       for (; size--; offset++)
8010         {
8011           if (AOP_TYPE (right) == AOP_LIT)
8012             {
8013               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8014               if (bytelit == 0)
8015                 {
8016                   /* dummy read of volatile operand */
8017                   if (isOperandVolatile (left, FALSE))
8018                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8019                   else
8020                     continue;
8021                 }
8022               else if (IS_AOP_PREG (left))
8023                 {
8024                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8025                   emitcode ("xrl", "a,%s",
8026                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8027                   aopPut (result, "a", offset);
8028                 }
8029               else
8030                 {
8031                   emitcode ("xrl", "%s,%s",
8032                             aopGet (left, offset, FALSE, TRUE, NULL),
8033                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8034                 }
8035             }
8036           else
8037             {
8038               if (AOP_TYPE (left) == AOP_ACC)
8039                 emitcode ("xrl", "a,%s",
8040                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8041               else
8042                 {
8043                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8044                   if (IS_AOP_PREG (left))
8045                     {
8046                       emitcode ("xrl", "a,%s",
8047                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8048                       aopPut (result, "a", offset);
8049                     }
8050                   else
8051                     emitcode ("xrl", "%s,a",
8052                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8053                 }
8054             }
8055         }
8056     }
8057   else
8058     {
8059       // left & result in different registers
8060       if (AOP_TYPE (result) == AOP_CRY)
8061         {
8062           // result = bit
8063           // if(size), result in bit
8064           // if(!size && ifx), conditional oper: if(left ^ right)
8065           symbol *tlbl = newiTempLabel (NULL);
8066           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8067
8068           if (size)
8069             emitcode ("setb", "c");
8070           while (sizer--)
8071             {
8072               if ((AOP_TYPE (right) == AOP_LIT) &&
8073                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8074                 {
8075                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8076                 }
8077               else
8078                 {
8079                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
8080                     emitcode ("xrl", "a,%s",
8081                               aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8082                   } else {
8083                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8084                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8085                       {
8086                           emitcode("mov", "b,a");
8087                           rOp = "b";
8088                       }
8089
8090                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8091                       emitcode ("xrl", "a,%s", rOp);
8092                   }
8093                 }
8094               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8095               offset++;
8096             }
8097           if (size)
8098             {
8099               CLRC;
8100               emitcode ("", "!tlabeldef", tlbl->key + 100);
8101               outBitC (result);
8102             }
8103           else if (ifx)
8104             jmpTrueOrFalse (ifx, tlbl);
8105         }
8106       else
8107         {
8108         for (; (size--); offset++)
8109           {
8110             // normal case
8111             // result = left ^ right
8112             if (AOP_TYPE (right) == AOP_LIT)
8113               {
8114                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8115                 if (bytelit == 0)
8116                   {
8117                     aopPut (result,
8118                             aopGet (left, offset, FALSE, FALSE, NULL),
8119                             offset);
8120                     continue;
8121                   }
8122                 D (emitcode (";", "better literal XOR."););
8123                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8124                 emitcode ("xrl", "a, %s",
8125                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8126               }
8127             else
8128               {
8129                 // faster than result <- left, anl result,right
8130                 // and better if result is SFR
8131                 if (AOP_TYPE (left) == AOP_ACC)
8132                   {
8133                     emitcode ("xrl", "a,%s",
8134                               aopGet (right, offset,
8135                                       FALSE, FALSE, DP2_RESULT_REG));
8136                   }
8137                 else
8138                   {
8139                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8140                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8141                       {
8142                           emitcode("mov", "b,a");
8143                           rOp = "b";
8144                       }
8145
8146                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8147                       emitcode ("xrl", "a,%s", rOp);
8148                   }
8149               }
8150             aopPut (result, "a", offset);
8151           }
8152         }
8153     }
8154
8155 release:
8156   freeAsmop (result, NULL, ic, TRUE);
8157   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8158   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8159 }
8160
8161 /*-----------------------------------------------------------------*/
8162 /* genInline - write the inline code out                           */
8163 /*-----------------------------------------------------------------*/
8164 static void
8165 genInline (iCode * ic)
8166 {
8167   char *buffer, *bp, *bp1;
8168
8169   D (emitcode (";", "genInline "));
8170
8171   _G.inLine += (!options.asmpeep);
8172
8173   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
8174
8175   /* emit each line as a code */
8176   while (*bp)
8177     {
8178       if (*bp == '\n')
8179         {
8180           *bp++ = '\0';
8181           emitcode (bp1, "");
8182           bp1 = bp;
8183         }
8184       else
8185         {
8186           /* Add \n for labels, not dirs such as c:\mydir */
8187           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
8188             {
8189               bp++;
8190               *bp = '\0';
8191               bp++;
8192               emitcode (bp1, "");
8193               bp1 = bp;
8194             }
8195           else
8196             bp++;
8197         }
8198     }
8199   if (bp1 != bp)
8200     emitcode (bp1, "");
8201   /*     emitcode("",buffer); */
8202   _G.inLine -= (!options.asmpeep);
8203 }
8204
8205 /*-----------------------------------------------------------------*/
8206 /* genRRC - rotate right with carry                                */
8207 /*-----------------------------------------------------------------*/
8208 static void
8209 genRRC (iCode * ic)
8210 {
8211   operand *left, *result;
8212   int     size, offset;
8213   char *l;
8214
8215   D (emitcode (";", "genRRC"));
8216
8217   /* rotate right with carry */
8218   left = IC_LEFT (ic);
8219   result = IC_RESULT (ic);
8220   aopOp (left, ic, FALSE, FALSE);
8221   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8222
8223   /* move it to the result */
8224   size = AOP_SIZE (result);
8225   offset = size - 1;
8226   CLRC;
8227
8228   _startLazyDPSEvaluation ();
8229   while (size--)
8230     {
8231       l = aopGet (left, offset, FALSE, FALSE, NULL);
8232       MOVA (l);
8233       emitcode ("rrc", "a");
8234       if (AOP_SIZE (result) > 1)
8235         aopPut (result, "a", offset--);
8236     }
8237   _endLazyDPSEvaluation ();
8238
8239   /* now we need to put the carry into the
8240      highest order byte of the result */
8241   if (AOP_SIZE (result) > 1)
8242     {
8243       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8244       MOVA (l);
8245     }
8246   emitcode ("mov", "acc.7,c");
8247   aopPut (result, "a", AOP_SIZE (result) - 1);
8248   freeAsmop (result, NULL, ic, TRUE);
8249   freeAsmop (left, NULL, ic, TRUE);
8250 }
8251
8252 /*-----------------------------------------------------------------*/
8253 /* genRLC - generate code for rotate left with carry               */
8254 /*-----------------------------------------------------------------*/
8255 static void
8256 genRLC (iCode * ic)
8257 {
8258   operand *left, *result;
8259   int size, offset;
8260   char *l;
8261
8262   D (emitcode (";", "genRLC "));
8263
8264   /* rotate right with carry */
8265   left = IC_LEFT (ic);
8266   result = IC_RESULT (ic);
8267   aopOp (left, ic, FALSE, FALSE);
8268   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8269
8270   /* move it to the result */
8271   size = AOP_SIZE (result);
8272   offset = 0;
8273   if (size--)
8274     {
8275       l = aopGet (left, offset, FALSE, FALSE, NULL);
8276       MOVA (l);
8277       emitcode ("add", "a,acc");
8278       if (AOP_SIZE (result) > 1)
8279         {
8280           aopPut (result, "a", offset++);
8281         }
8282
8283       _startLazyDPSEvaluation ();
8284       while (size--)
8285         {
8286           l = aopGet (left, offset, FALSE, FALSE, NULL);
8287           MOVA (l);
8288           emitcode ("rlc", "a");
8289           if (AOP_SIZE (result) > 1)
8290             aopPut (result, "a", offset++);
8291         }
8292       _endLazyDPSEvaluation ();
8293     }
8294   /* now we need to put the carry into the
8295      highest order byte of the result */
8296   if (AOP_SIZE (result) > 1)
8297     {
8298       l = aopGet (result, 0, FALSE, FALSE, NULL);
8299       MOVA (l);
8300     }
8301   emitcode ("mov", "acc.0,c");
8302   aopPut (result, "a", 0);
8303   freeAsmop (result, NULL, ic, TRUE);
8304   freeAsmop (left, NULL, ic, TRUE);
8305 }
8306
8307 /*-----------------------------------------------------------------*/
8308 /* genGetHbit - generates code get highest order bit               */
8309 /*-----------------------------------------------------------------*/
8310 static void
8311 genGetHbit (iCode * ic)
8312 {
8313   operand *left, *result;
8314
8315   D (emitcode (";", "genGetHbit"));
8316
8317   left = IC_LEFT (ic);
8318   result = IC_RESULT (ic);
8319   aopOp (left, ic, FALSE, FALSE);
8320   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8321
8322   /* get the highest order byte into a */
8323   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8324   if (AOP_TYPE (result) == AOP_CRY)
8325     {
8326       emitcode ("rlc", "a");
8327       outBitC (result);
8328     }
8329   else
8330     {
8331       emitcode ("rl", "a");
8332       emitcode ("anl", "a,#1");
8333       outAcc (result);
8334     }
8335
8336
8337   freeAsmop (result, NULL, ic, TRUE);
8338   freeAsmop (left, NULL, ic, TRUE);
8339 }
8340
8341 /*-----------------------------------------------------------------*/
8342 /* genSwap - generates code to swap nibbles or bytes               */
8343 /*-----------------------------------------------------------------*/
8344 static void
8345 genSwap (iCode * ic)
8346 {
8347   operand *left, *result;
8348
8349   D(emitcode (";     genSwap",""));
8350
8351   left = IC_LEFT (ic);
8352   result = IC_RESULT (ic);
8353   aopOp (left, ic, FALSE, FALSE);
8354   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8355
8356   _startLazyDPSEvaluation ();
8357   switch (AOP_SIZE (left))
8358     {
8359     case 1: /* swap nibbles in byte */
8360       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8361       emitcode ("swap", "a");
8362       aopPut (result, "a", 0);
8363       break;
8364     case 2: /* swap bytes in word */
8365       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8366         {
8367           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8368           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8369           aopPut (result, "a", 1);
8370         }
8371       else if (operandsEqu (left, result))
8372         {
8373           char * reg = "a";
8374           bool pushedB = FALSE, leftInB = FALSE;
8375
8376           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8377           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8378             {
8379               pushedB = pushB ();
8380               emitcode ("mov", "b,a");
8381               reg = "b";
8382               leftInB = TRUE;
8383             }
8384           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8385           aopPut (result, reg, 1);
8386
8387           if (leftInB)
8388             popB (pushedB);
8389         }
8390       else
8391         {
8392           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8393           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8394         }
8395       break;
8396     default:
8397       wassertl(FALSE, "unsupported SWAP operand size");
8398     }
8399   _endLazyDPSEvaluation ();
8400
8401   freeAsmop (result, NULL, ic, TRUE);
8402   freeAsmop (left, NULL, ic, TRUE);
8403 }
8404
8405 /*-----------------------------------------------------------------*/
8406 /* AccRol - rotate left accumulator by known count                 */
8407 /*-----------------------------------------------------------------*/
8408 static void
8409 AccRol (int shCount)
8410 {
8411   shCount &= 0x0007;            // shCount : 0..7
8412
8413   switch (shCount)
8414     {
8415     case 0:
8416       break;
8417     case 1:
8418       emitcode ("rl", "a");
8419       break;
8420     case 2:
8421       emitcode ("rl", "a");
8422       emitcode ("rl", "a");
8423       break;
8424     case 3:
8425       emitcode ("swap", "a");
8426       emitcode ("rr", "a");
8427       break;
8428     case 4:
8429       emitcode ("swap", "a");
8430       break;
8431     case 5:
8432       emitcode ("swap", "a");
8433       emitcode ("rl", "a");
8434       break;
8435     case 6:
8436       emitcode ("rr", "a");
8437       emitcode ("rr", "a");
8438       break;
8439     case 7:
8440       emitcode ("rr", "a");
8441       break;
8442     }
8443 }
8444
8445 /*-----------------------------------------------------------------*/
8446 /* AccLsh - left shift accumulator by known count                  */
8447 /*-----------------------------------------------------------------*/
8448 static void
8449 AccLsh (int shCount)
8450 {
8451   if (shCount != 0)
8452     {
8453       if (shCount == 1)
8454         emitcode ("add", "a,acc");
8455       else if (shCount == 2)
8456         {
8457           emitcode ("add", "a,acc");
8458           emitcode ("add", "a,acc");
8459         }
8460       else
8461         {
8462           /* rotate left accumulator */
8463           AccRol (shCount);
8464           /* and kill the lower order bits */
8465           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8466         }
8467     }
8468 }
8469
8470 /*-----------------------------------------------------------------*/
8471 /* AccRsh - right shift accumulator by known count                 */
8472 /*-----------------------------------------------------------------*/
8473 static void
8474 AccRsh (int shCount)
8475 {
8476   if (shCount != 0)
8477     {
8478       if (shCount == 1)
8479         {
8480           CLRC;
8481           emitcode ("rrc", "a");
8482         }
8483       else
8484         {
8485           /* rotate right accumulator */
8486           AccRol (8 - shCount);
8487           /* and kill the higher order bits */
8488           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8489         }
8490     }
8491 }
8492
8493 #ifdef BETTER_LITERAL_SHIFT
8494 /*-----------------------------------------------------------------*/
8495 /* AccSRsh - signed right shift accumulator by known count                 */
8496 /*-----------------------------------------------------------------*/
8497 static void
8498 AccSRsh (int shCount)
8499 {
8500   symbol *tlbl;
8501   if (shCount != 0)
8502     {
8503       if (shCount == 1)
8504         {
8505           emitcode ("mov", "c,acc.7");
8506           emitcode ("rrc", "a");
8507         }
8508       else if (shCount == 2)
8509         {
8510           emitcode ("mov", "c,acc.7");
8511           emitcode ("rrc", "a");
8512           emitcode ("mov", "c,acc.7");
8513           emitcode ("rrc", "a");
8514         }
8515       else
8516         {
8517           tlbl = newiTempLabel (NULL);
8518           /* rotate right accumulator */
8519           AccRol (8 - shCount);
8520           /* and kill the higher order bits */
8521           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8522           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8523           emitcode ("orl", "a,#!constbyte",
8524                     (unsigned char) ~SRMask[shCount]);
8525           emitcode ("", "!tlabeldef", tlbl->key + 100);
8526         }
8527     }
8528 }
8529 #endif
8530
8531 #ifdef BETTER_LITERAL_SHIFT
8532 /*-----------------------------------------------------------------*/
8533 /* shiftR1Left2Result - shift right one byte from left to result   */
8534 /*-----------------------------------------------------------------*/
8535 static void
8536 shiftR1Left2Result (operand * left, int offl,
8537                     operand * result, int offr,
8538                     int shCount, int sign)
8539 {
8540   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8541   /* shift right accumulator */
8542   if (sign)
8543     AccSRsh (shCount);
8544   else
8545     AccRsh (shCount);
8546   aopPut (result, "a", offr);
8547 }
8548 #endif
8549
8550 #ifdef BETTER_LITERAL_SHIFT
8551 /*-----------------------------------------------------------------*/
8552 /* shiftL1Left2Result - shift left one byte from left to result    */
8553 /*-----------------------------------------------------------------*/
8554 static void
8555 shiftL1Left2Result (operand * left, int offl,
8556                     operand * result, int offr, int shCount)
8557 {
8558   char *l;
8559   l = aopGet (left, offl, FALSE, FALSE, NULL);
8560   MOVA (l);
8561   /* shift left accumulator */
8562   AccLsh (shCount);
8563   aopPut (result, "a", offr);
8564 }
8565 #endif
8566
8567 #ifdef BETTER_LITERAL_SHIFT
8568 /*-----------------------------------------------------------------*/
8569 /* movLeft2Result - move byte from left to result                  */
8570 /*-----------------------------------------------------------------*/
8571 static void
8572 movLeft2Result (operand * left, int offl,
8573                 operand * result, int offr, int sign)
8574 {
8575   char *l;
8576   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8577   {
8578       l = aopGet (left, offl, FALSE, FALSE, NULL);
8579
8580       if (*l == '@' && (IS_AOP_PREG (result)))
8581       {
8582           emitcode ("mov", "a,%s", l);
8583           aopPut (result, "a", offr);
8584       }
8585       else
8586       {
8587           if (!sign)
8588           {
8589             aopPut (result, l, offr);
8590           }
8591           else
8592             {
8593               /* MSB sign in acc.7 ! */
8594               if (getDataSize (left) == offl + 1)
8595                 {
8596                   MOVA (l);
8597                   aopPut (result, "a", offr);
8598                 }
8599             }
8600       }
8601   }
8602 }
8603 #endif
8604
8605 #ifdef BETTER_LITERAL_SHIFT
8606 /*-----------------------------------------------------------------*/
8607 /* AccAXRrl1 - right rotate a:x by 1                               */
8608 /*-----------------------------------------------------------------*/
8609 static void
8610 AccAXRrl1 (char *x)
8611 {
8612   emitcode ("mov", "c,acc.0");
8613   emitcode ("xch", "a,%s", x);
8614   emitcode ("rrc", "a");
8615   emitcode ("xch", "a,%s", x);
8616   emitcode ("rrc", "a");
8617 }
8618 #endif
8619
8620 #ifdef BETTER_LITERAL_SHIFT
8621 //REMOVE ME!!!
8622 /*-----------------------------------------------------------------*/
8623 /* AccAXLrl1 - left rotate a:x by 1                                */
8624 /*-----------------------------------------------------------------*/
8625 static void
8626 AccAXLrl1 (char *x)
8627 {
8628   emitcode ("mov", "c,acc.7");
8629   emitcode ("xch", "a,%s", x);
8630   emitcode ("rlc", "a");
8631   emitcode ("xch", "a,%s", x);
8632   emitcode ("rlc", "a");
8633 }
8634 #endif
8635
8636 #ifdef BETTER_LITERAL_SHIFT
8637 /*-----------------------------------------------------------------*/
8638 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8639 /*-----------------------------------------------------------------*/
8640 static void
8641 AccAXRsh1 (char *x)
8642 {
8643   emitcode ("rrc", "a");
8644   emitcode ("xch", "a,%s", x);
8645   emitcode ("rrc", "a");
8646   emitcode ("xch", "a,%s", x);
8647 }
8648 #endif
8649
8650 #ifdef BETTER_LITERAL_SHIFT
8651 /*-----------------------------------------------------------------*/
8652 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8653 /*-----------------------------------------------------------------*/
8654 static void
8655 AccAXLsh1 (char *x)
8656 {
8657   emitcode ("xch", "a,%s", x);
8658   emitcode ("add", "a,acc");
8659   emitcode ("xch", "a,%s", x);
8660   emitcode ("rlc", "a");
8661 }
8662 #endif
8663
8664 #ifdef BETTER_LITERAL_SHIFT
8665 /*-----------------------------------------------------------------*/
8666 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8667 /*-----------------------------------------------------------------*/
8668 static void
8669 AccAXLsh (char *x, int shCount)
8670 {
8671   switch (shCount)
8672     {
8673     case 0:
8674       break;
8675     case 1:
8676       AccAXLsh1 (x);
8677       break;
8678     case 2:
8679       AccAXLsh1 (x);
8680       AccAXLsh1 (x);
8681       break;
8682     case 3:
8683     case 4:
8684     case 5:                             // AAAAABBB:CCCCCDDD
8685
8686       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8687
8688       emitcode ("anl", "a,#!constbyte",
8689                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8690
8691       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8692
8693       AccRol (shCount);                 // DDDCCCCC:BBB00000
8694
8695       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8696
8697       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8698
8699       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8700
8701       emitcode ("anl", "a,#!constbyte",
8702                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8703
8704       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8705
8706       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8707
8708       break;
8709     case 6:                             // AAAAAABB:CCCCCCDD
8710       emitcode ("anl", "a,#!constbyte",
8711                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8712 #if 1
8713       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8714       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8715       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8716 #else
8717       emitcode ("mov", "c,acc.0");      // c = B
8718       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8719       emitcode("rrc","a");
8720       emitcode("xch","a,%s", x);
8721       emitcode("rrc","a");
8722       emitcode("mov","c,acc.0"); //<< get correct bit
8723       emitcode("xch","a,%s", x);
8724
8725       emitcode("rrc","a");
8726       emitcode("xch","a,%s", x);
8727       emitcode("rrc","a");
8728       emitcode("xch","a,%s", x);
8729 #endif
8730       break;
8731     case 7:                             // a:x <<= 7
8732
8733       emitcode ("anl", "a,#!constbyte",
8734                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8735
8736       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8737
8738       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8739
8740       break;
8741     default:
8742       break;
8743     }
8744 }
8745 #endif
8746
8747 #ifdef BETTER_LITERAL_SHIFT
8748 //REMOVE ME!!!
8749 /*-----------------------------------------------------------------*/
8750 /* AccAXRsh - right shift a:x known count (0..7)                   */
8751 /*-----------------------------------------------------------------*/
8752 static void
8753 AccAXRsh (char *x, int shCount)
8754 {
8755   switch (shCount)
8756     {
8757     case 0:
8758       break;
8759     case 1:
8760       CLRC;
8761       AccAXRsh1 (x);                    // 0->a:x
8762
8763       break;
8764     case 2:
8765       CLRC;
8766       AccAXRsh1 (x);                    // 0->a:x
8767
8768       CLRC;
8769       AccAXRsh1 (x);                    // 0->a:x
8770
8771       break;
8772     case 3:
8773     case 4:
8774     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8775
8776       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8777
8778       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8779
8780       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8781
8782       emitcode ("anl", "a,#!constbyte",
8783                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8784
8785       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8786
8787       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8788
8789       emitcode ("anl", "a,#!constbyte",
8790                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8791
8792       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8793
8794       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8795
8796       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8797
8798       break;
8799     case 6:                             // AABBBBBB:CCDDDDDD
8800
8801       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8802       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8803
8804       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8805
8806       emitcode ("anl", "a,#!constbyte",
8807                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8808
8809       break;
8810     case 7:                             // ABBBBBBB:CDDDDDDD
8811
8812       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8813
8814       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8815
8816       emitcode ("anl", "a,#!constbyte",
8817                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8818
8819       break;
8820     default:
8821       break;
8822     }
8823 }
8824 #endif
8825
8826 #ifdef BETTER_LITERAL_SHIFT
8827 /*-----------------------------------------------------------------*/
8828 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8829 /*-----------------------------------------------------------------*/
8830 static void
8831 AccAXRshS (char *x, int shCount)
8832 {
8833   symbol *tlbl;
8834   switch (shCount)
8835     {
8836     case 0:
8837       break;
8838     case 1:
8839       emitcode ("mov", "c,acc.7");
8840       AccAXRsh1 (x);                    // s->a:x
8841
8842       break;
8843     case 2:
8844       emitcode ("mov", "c,acc.7");
8845       AccAXRsh1 (x);                    // s->a:x
8846
8847       emitcode ("mov", "c,acc.7");
8848       AccAXRsh1 (x);                    // s->a:x
8849
8850       break;
8851     case 3:
8852     case 4:
8853     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8854
8855       tlbl = newiTempLabel (NULL);
8856       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8857
8858       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8859
8860       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8861
8862       emitcode ("anl", "a,#!constbyte",
8863                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8864
8865       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8866
8867       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8868
8869       emitcode ("anl", "a,#!constbyte",
8870                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8871
8872       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8873
8874       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8875
8876       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8877
8878       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8879       emitcode ("orl", "a,#!constbyte",
8880                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8881
8882       emitcode ("", "!tlabeldef", tlbl->key + 100);
8883       break;                            // SSSSAAAA:BBBCCCCC
8884
8885     case 6:                             // AABBBBBB:CCDDDDDD
8886
8887       tlbl = newiTempLabel (NULL);
8888
8889       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
8890       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8891
8892       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8893
8894       emitcode ("anl", "a,#!constbyte",
8895                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8896
8897       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8898       emitcode ("orl", "a,#!constbyte",
8899                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8900
8901       emitcode ("", "!tlabeldef", tlbl->key + 100);
8902       break;
8903     case 7:                             // ABBBBBBB:CDDDDDDD
8904
8905       tlbl = newiTempLabel (NULL);
8906
8907       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8908
8909       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8910
8911       emitcode ("anl", "a,#!constbyte",
8912                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8913
8914       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8915       emitcode ("orl", "a,#!constbyte",
8916                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8917
8918       emitcode ("", "!tlabeldef", tlbl->key + 100);
8919       break;
8920     default:
8921       break;
8922     }
8923 }
8924 #endif
8925
8926 #ifdef BETTER_LITERAL_SHIFT
8927 static void
8928 _loadLeftIntoAx(char    **lsb,
8929                 operand *left,
8930                 operand *result,
8931                 int     offl,
8932                 int     offr)
8933 {
8934   // Get the initial value from left into a pair of registers.
8935   // MSB must be in A, LSB can be any register.
8936   //
8937   // If the result is held in registers, it is an optimization
8938   // if the LSB can be held in the register which will hold the,
8939   // result LSB since this saves us from having to copy it into
8940   // the result following AccAXLsh.
8941   //
8942   // If the result is addressed indirectly, this is not a gain.
8943   if (AOP_NEEDSACC(result))
8944   {
8945        char *leftByte;
8946
8947        _startLazyDPSEvaluation();
8948       if (AOP_TYPE(left) == AOP_DPTR2)
8949        {
8950            // Get MSB in A.
8951            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
8952            // get LSB in DP2_RESULT_REG.
8953            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
8954            assert(!strcmp(leftByte, DP2_RESULT_REG));
8955        }
8956        else
8957        {
8958            // get LSB into DP2_RESULT_REG
8959            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
8960            if (strcmp(leftByte, DP2_RESULT_REG))
8961            {
8962                TR_AP("#7");
8963                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
8964            }
8965            // And MSB in A.
8966            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
8967            assert(strcmp(leftByte, DP2_RESULT_REG));
8968            MOVA (leftByte);
8969        }
8970        _endLazyDPSEvaluation();
8971        *lsb = DP2_RESULT_REG;
8972   }
8973   else
8974   {
8975       if (sameRegs (AOP (result), AOP (left)) &&
8976         ((offl + MSB16) == offr))
8977       {
8978           /* don't crash result[offr] */
8979           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8980           emitcode ("xch", "a,%s",
8981                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
8982       }
8983       else
8984       {
8985           movLeft2Result (left, offl, result, offr, 0);
8986           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
8987       }
8988       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
8989       assert(strcmp(*lsb,"a"));
8990   }
8991 }
8992
8993 static void
8994 _storeAxResults(char    *lsb,
8995                 operand *result,
8996                 int     offr)
8997 {
8998   _startLazyDPSEvaluation();
8999   if (AOP_NEEDSACC(result))
9000   {
9001       /* We have to explicitly update the result LSB.
9002        */
9003       emitcode ("xch","a,%s", lsb);
9004       aopPut (result, "a", offr);
9005       emitcode ("mov","a,%s", lsb);
9006   }
9007   if (getDataSize (result) > 1)
9008   {
9009       aopPut (result, "a", offr + MSB16);
9010   }
9011   _endLazyDPSEvaluation();
9012 }
9013
9014 /*-----------------------------------------------------------------*/
9015 /* shiftL2Left2Result - shift left two bytes from left to result   */
9016 /*-----------------------------------------------------------------*/
9017 static void
9018 shiftL2Left2Result (operand * left, int offl,
9019                     operand * result, int offr, int shCount)
9020 {
9021   char *lsb;
9022
9023   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9024
9025   AccAXLsh (lsb, shCount);
9026
9027   _storeAxResults(lsb, result, offr);
9028 }
9029 #endif
9030
9031 #ifdef BETTER_LITERAL_SHIFT
9032 /*-----------------------------------------------------------------*/
9033 /* shiftR2Left2Result - shift right two bytes from left to result  */
9034 /*-----------------------------------------------------------------*/
9035 static void
9036 shiftR2Left2Result (operand * left, int offl,
9037                     operand * result, int offr,
9038                     int shCount, int sign)
9039 {
9040   char *lsb;
9041
9042   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9043
9044   /* a:x >> shCount (x = lsb(result)) */
9045   if (sign)
9046   {
9047      AccAXRshS(lsb, shCount);
9048   }
9049   else
9050   {
9051     AccAXRsh(lsb, shCount);
9052   }
9053
9054   _storeAxResults(lsb, result, offr);
9055 }
9056 #endif
9057
9058 /*-----------------------------------------------------------------*/
9059 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9060 /*-----------------------------------------------------------------*/
9061 static void
9062 shiftLLeftOrResult (operand * left, int offl,
9063                     operand * result, int offr, int shCount)
9064 {
9065   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9066   /* shift left accumulator */
9067   AccLsh (shCount);
9068   /* or with result */
9069   emitcode ("orl", "a,%s",
9070             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9071   /* back to result */
9072   aopPut (result, "a", offr);
9073 }
9074
9075 #if 0
9076 //REMOVE ME!!!
9077 /*-----------------------------------------------------------------*/
9078 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9079 /*-----------------------------------------------------------------*/
9080 static void
9081 shiftRLeftOrResult (operand * left, int offl,
9082                     operand * result, int offr, int shCount)
9083 {
9084   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9085   /* shift right accumulator */
9086   AccRsh (shCount);
9087   /* or with result */
9088   emitcode ("orl", "a,%s",
9089             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9090   /* back to result */
9091   aopPut (result, "a", offr);
9092 }
9093 #endif
9094
9095 #ifdef BETTER_LITERAL_SHIFT
9096 /*-----------------------------------------------------------------*/
9097 /* genlshOne - left shift a one byte quantity by known count       */
9098 /*-----------------------------------------------------------------*/
9099 static void
9100 genlshOne (operand * result, operand * left, int shCount)
9101 {
9102   D (emitcode (";", "genlshOne "));
9103
9104   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9105 }
9106 #endif
9107
9108 #ifdef BETTER_LITERAL_SHIFT
9109 /*-----------------------------------------------------------------*/
9110 /* genlshTwo - left shift two bytes by known amount != 0           */
9111 /*-----------------------------------------------------------------*/
9112 static void
9113 genlshTwo (operand * result, operand * left, int shCount)
9114 {
9115   int size;
9116
9117   D (emitcode (";", "genlshTwo"));
9118
9119   size = getDataSize (result);
9120
9121   /* if shCount >= 8 */
9122   if (shCount >= 8)
9123   {
9124       shCount -= 8;
9125
9126       _startLazyDPSEvaluation();
9127
9128       if (size > 1)
9129         {
9130           if (shCount)
9131           {
9132             _endLazyDPSEvaluation();
9133             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9134             aopPut (result, zero, LSB);
9135           }
9136           else
9137           {
9138             movLeft2Result (left, LSB, result, MSB16, 0);
9139             aopPut (result, zero, LSB);
9140             _endLazyDPSEvaluation();
9141           }
9142         }
9143         else
9144         {
9145           aopPut (result, zero, LSB);
9146           _endLazyDPSEvaluation();
9147         }
9148   }
9149
9150   /*  1 <= shCount <= 7 */
9151   else
9152     {
9153       if (size == 1)
9154         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9155       else
9156         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9157       }
9158 }
9159 #endif
9160
9161 #if 0
9162 //REMOVE ME!!!
9163 /*-----------------------------------------------------------------*/
9164 /* shiftLLong - shift left one long from left to result            */
9165 /* offl = LSB or MSB16                                             */
9166 /*-----------------------------------------------------------------*/
9167 static void
9168 shiftLLong (operand * left, operand * result, int offr)
9169 {
9170   char *l;
9171   int size = AOP_SIZE (result);
9172
9173   if (size >= LSB + offr)
9174     {
9175       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9176       MOVA (l);
9177       emitcode ("add", "a,acc");
9178       if (sameRegs (AOP (left), AOP (result)) &&
9179           size >= MSB16 + offr && offr != LSB)
9180         emitcode ("xch", "a,%s",
9181                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9182       else
9183         aopPut (result, "a", LSB + offr);
9184     }
9185
9186   if (size >= MSB16 + offr)
9187     {
9188       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9189         {
9190           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9191           MOVA (l);
9192         }
9193       emitcode ("rlc", "a");
9194       if (sameRegs (AOP (left), AOP (result)) &&
9195           size >= MSB24 + offr && offr != LSB)
9196         emitcode ("xch", "a,%s",
9197                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9198       else
9199         aopPut (result, "a", MSB16 + offr);
9200     }
9201
9202   if (size >= MSB24 + offr)
9203     {
9204       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9205         {
9206           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9207           MOVA (l);
9208         }
9209       emitcode ("rlc", "a");
9210       if (sameRegs (AOP (left), AOP (result)) &&
9211           size >= MSB32 + offr && offr != LSB)
9212         emitcode ("xch", "a,%s",
9213                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9214       else
9215         aopPut (result, "a", MSB24 + offr);
9216     }
9217
9218   if (size > MSB32 + offr)
9219     {
9220       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9221         {
9222           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9223           MOVA (l);
9224         }
9225       emitcode ("rlc", "a");
9226       aopPut (result, "a", MSB32 + offr);
9227     }
9228   if (offr != LSB)
9229     aopPut (result, zero, LSB);
9230 }
9231 #endif
9232
9233 #if 0
9234 //REMOVE ME!!!
9235 /*-----------------------------------------------------------------*/
9236 /* genlshFour - shift four byte by a known amount != 0             */
9237 /*-----------------------------------------------------------------*/
9238 static void
9239 genlshFour (operand * result, operand * left, int shCount)
9240 {
9241   int size;
9242
9243   D (emitcode (";", "genlshFour "));
9244
9245   size = AOP_SIZE (result);
9246
9247   /* if shifting more that 3 bytes */
9248   if (shCount >= 24)
9249     {
9250       shCount -= 24;
9251       if (shCount)
9252         /* lowest order of left goes to the highest
9253            order of the destination */
9254         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9255       else
9256         movLeft2Result (left, LSB, result, MSB32, 0);
9257       aopPut (result, zero, LSB);
9258       aopPut (result, zero, MSB16);
9259       aopPut (result, zero, MSB24);
9260       return;
9261     }
9262
9263   /* more than two bytes */
9264   else if (shCount >= 16)
9265     {
9266       /* lower order two bytes goes to higher order two bytes */
9267       shCount -= 16;
9268       /* if some more remaining */
9269       if (shCount)
9270         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9271       else
9272         {
9273           movLeft2Result (left, MSB16, result, MSB32, 0);
9274           movLeft2Result (left, LSB, result, MSB24, 0);
9275         }
9276       aopPut (result, zero, MSB16);
9277       aopPut (result, zero, LSB);
9278       return;
9279     }
9280
9281   /* if more than 1 byte */
9282   else if (shCount >= 8)
9283     {
9284       /* lower order three bytes goes to higher order  three bytes */
9285       shCount -= 8;
9286       if (size == 2)
9287         {
9288           if (shCount)
9289             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9290           else
9291             movLeft2Result (left, LSB, result, MSB16, 0);
9292         }
9293       else
9294         {                       /* size = 4 */
9295           if (shCount == 0)
9296             {
9297               movLeft2Result (left, MSB24, result, MSB32, 0);
9298               movLeft2Result (left, MSB16, result, MSB24, 0);
9299               movLeft2Result (left, LSB, result, MSB16, 0);
9300               aopPut (result, zero, LSB);
9301             }
9302           else if (shCount == 1)
9303             shiftLLong (left, result, MSB16);
9304           else
9305             {
9306               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9307               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9308               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9309               aopPut (result, zero, LSB);
9310             }
9311         }
9312     }
9313
9314   /* 1 <= shCount <= 7 */
9315   else if (shCount <= 2)
9316     {
9317       shiftLLong (left, result, LSB);
9318       if (shCount == 2)
9319         shiftLLong (result, result, LSB);
9320     }
9321   /* 3 <= shCount <= 7, optimize */
9322   else
9323     {
9324       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9325       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9326       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9327     }
9328 }
9329 #endif
9330
9331 #ifdef BETTER_LITERAL_SHIFT
9332 /*-----------------------------------------------------------------*/
9333 /* genLeftShiftLiteral - left shifting by known count              */
9334 /*-----------------------------------------------------------------*/
9335 static bool
9336 genLeftShiftLiteral (operand * left,
9337                      operand * right,
9338                      operand * result,
9339                      iCode * ic)
9340 {
9341   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9342   int size;
9343
9344   size = getSize (operandType (result));
9345
9346   D(emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9347
9348   /* We only handle certain easy cases so far. */
9349   if ((shCount != 0)
9350    && (shCount < (size * 8))
9351    && (size != 1)
9352    && (size != 2))
9353   {
9354       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9355       return FALSE;
9356   }
9357
9358   freeAsmop (right, NULL, ic, TRUE);
9359
9360   aopOp(left, ic, FALSE, FALSE);
9361   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9362
9363 #if 0 // debug spew
9364   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9365   {
9366         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9367         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9368         {
9369            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9370         }
9371   }
9372   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9373   {
9374         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9375         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9376         {
9377            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9378         }
9379   }
9380 #endif
9381
9382 #if VIEW_SIZE
9383   emitcode ("; shift left ", "result %d, left %d", size,
9384             AOP_SIZE (left));
9385 #endif
9386
9387   /* I suppose that the left size >= result size */
9388   if (shCount == 0)
9389   {
9390         _startLazyDPSEvaluation();
9391         while (size--)
9392         {
9393           movLeft2Result (left, size, result, size, 0);
9394         }
9395         _endLazyDPSEvaluation();
9396   }
9397   else if (shCount >= (size * 8))
9398   {
9399     _startLazyDPSEvaluation();
9400     while (size--)
9401     {
9402       aopPut (result, zero, size);
9403     }
9404     _endLazyDPSEvaluation();
9405   }
9406   else
9407   {
9408       switch (size)
9409         {
9410         case 1:
9411           genlshOne (result, left, shCount);
9412           break;
9413
9414         case 2:
9415           genlshTwo (result, left, shCount);
9416           break;
9417 #if 0
9418         case 4:
9419           genlshFour (result, left, shCount);
9420           break;
9421 #endif
9422         default:
9423           fprintf(stderr, "*** ack! mystery literal shift!\n");
9424           break;
9425         }
9426     }
9427   freeAsmop (result, NULL, ic, TRUE);
9428   freeAsmop (left, NULL, ic, TRUE);
9429   return TRUE;
9430 }
9431 #endif
9432
9433 /*-----------------------------------------------------------------*/
9434 /* genLeftShift - generates code for left shifting                 */
9435 /*-----------------------------------------------------------------*/
9436 static void
9437 genLeftShift (iCode * ic)
9438 {
9439   operand *left, *right, *result;
9440   int size, offset;
9441   char *l;
9442   symbol *tlbl, *tlbl1;
9443   bool pushedB;
9444
9445   D (emitcode (";", "genLeftShift "));
9446
9447   right = IC_RIGHT (ic);
9448   left = IC_LEFT (ic);
9449   result = IC_RESULT (ic);
9450
9451   aopOp (right, ic, FALSE, FALSE);
9452
9453
9454 #ifdef BETTER_LITERAL_SHIFT
9455   /* if the shift count is known then do it
9456      as efficiently as possible */
9457   if (AOP_TYPE (right) == AOP_LIT)
9458     {
9459       if (genLeftShiftLiteral (left, right, result, ic))
9460       {
9461         return;
9462       }
9463     }
9464 #endif
9465
9466   /* shift count is unknown then we have to form
9467      a loop get the loop count in B : Note: we take
9468      only the lower order byte since shifting
9469      more that 32 bits make no sense anyway, ( the
9470      largest size of an object can be only 32 bits ) */
9471
9472   pushedB = pushB ();
9473   if (AOP_TYPE (right) == AOP_LIT)
9474   {
9475       /* Really should be handled by genLeftShiftLiteral,
9476        * but since I'm too lazy to fix that today, at least we can make
9477        * some small improvement.
9478        */
9479        emitcode("mov", "b,#!constbyte",
9480                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9481   }
9482   else
9483   {
9484       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9485       emitcode ("inc", "b");
9486   }
9487   freeAsmop (right, NULL, ic, TRUE);
9488   aopOp (left, ic, FALSE, FALSE);
9489   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9490
9491   /* now move the left to the result if they are not the same */
9492   if (!sameRegs (AOP (left), AOP (result)) &&
9493       AOP_SIZE (result) > 1)
9494     {
9495
9496       size = AOP_SIZE (result);
9497       offset = 0;
9498       _startLazyDPSEvaluation ();
9499       while (size--)
9500         {
9501           l = aopGet (left, offset, FALSE, TRUE, NULL);
9502           if (*l == '@' && (IS_AOP_PREG (result)))
9503             {
9504
9505               emitcode ("mov", "a,%s", l);
9506               aopPut (result, "a", offset);
9507             }
9508           else
9509             aopPut (result, l, offset);
9510           offset++;
9511         }
9512       _endLazyDPSEvaluation ();
9513     }
9514
9515   tlbl = newiTempLabel (NULL);
9516   size = AOP_SIZE (result);
9517   offset = 0;
9518   tlbl1 = newiTempLabel (NULL);
9519
9520   /* if it is only one byte then */
9521   if (size == 1)
9522     {
9523       symbol *tlbl1 = newiTempLabel (NULL);
9524
9525       l = aopGet (left, 0, FALSE, FALSE, NULL);
9526       MOVA (l);
9527       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9528       emitcode ("", "!tlabeldef", tlbl->key + 100);
9529       emitcode ("add", "a,acc");
9530       emitcode ("", "!tlabeldef", tlbl1->key + 100);
9531       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9532       popB (pushedB);
9533       aopPut (result, "a", 0);
9534       goto release;
9535     }
9536
9537   reAdjustPreg (AOP (result));
9538
9539   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9540   emitcode ("", "!tlabeldef", tlbl->key + 100);
9541   l = aopGet (result, offset, FALSE, FALSE, NULL);
9542   MOVA (l);
9543   emitcode ("add", "a,acc");
9544   aopPut (result, "a", offset++);
9545   _startLazyDPSEvaluation ();
9546   while (--size)
9547     {
9548       l = aopGet (result, offset, FALSE, FALSE, NULL);
9549       MOVA (l);
9550       emitcode ("rlc", "a");
9551       aopPut (result, "a", offset++);
9552     }
9553   _endLazyDPSEvaluation ();
9554   reAdjustPreg (AOP (result));
9555
9556   emitcode ("", "!tlabeldef", tlbl1->key + 100);
9557   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9558   popB (pushedB);
9559 release:
9560   freeAsmop (result, NULL, ic, TRUE);
9561   freeAsmop (left, NULL, ic, TRUE);
9562 }
9563
9564 #ifdef BETTER_LITERAL_SHIFT
9565 /*-----------------------------------------------------------------*/
9566 /* genrshOne - right shift a one byte quantity by known count      */
9567 /*-----------------------------------------------------------------*/
9568 static void
9569 genrshOne (operand * result, operand * left,
9570            int shCount, int sign)
9571 {
9572   D (emitcode (";", "genrshOne"));
9573   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9574 }
9575 #endif
9576
9577 #ifdef BETTER_LITERAL_SHIFT
9578 /*-----------------------------------------------------------------*/
9579 /* genrshTwo - right shift two bytes by known amount != 0          */
9580 /*-----------------------------------------------------------------*/
9581 static void
9582 genrshTwo (operand * result, operand * left,
9583            int shCount, int sign)
9584 {
9585   D (emitcode (";", "genrshTwo"));
9586
9587   /* if shCount >= 8 */
9588   if (shCount >= 8)
9589     {
9590       shCount -= 8;
9591       _startLazyDPSEvaluation();
9592       if (shCount)
9593         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9594       else
9595         movLeft2Result (left, MSB16, result, LSB, sign);
9596       addSign (result, MSB16, sign);
9597       _endLazyDPSEvaluation();
9598     }
9599
9600   /*  1 <= shCount <= 7 */
9601   else
9602     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9603 }
9604 #endif
9605
9606 /*-----------------------------------------------------------------*/
9607 /* shiftRLong - shift right one long from left to result           */
9608 /* offl = LSB or MSB16                                             */
9609 /*-----------------------------------------------------------------*/
9610 static void
9611 shiftRLong (operand * left, int offl,
9612             operand * result, int sign)
9613 {
9614   int isSameRegs=sameRegs(AOP(left),AOP(result));
9615
9616   if (isSameRegs && offl>1) {
9617     // we are in big trouble, but this shouldn't happen
9618     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9619   }
9620
9621   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9622
9623   if (offl==MSB16)
9624     {
9625       // shift is > 8
9626       if (sign)
9627         {
9628           emitcode ("rlc", "a");
9629           emitcode ("subb", "a,acc");
9630           emitcode ("xch", "a,%s",
9631                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9632         }
9633       else
9634         {
9635           aopPut (result, zero, MSB32);
9636         }
9637     }
9638
9639   if (!sign)
9640     {
9641       emitcode ("clr", "c");
9642     }
9643   else
9644     {
9645       emitcode ("mov", "c,acc.7");
9646     }
9647
9648   emitcode ("rrc", "a");
9649
9650   if (isSameRegs && offl==MSB16) {
9651     emitcode ("xch",
9652               "a,%s",aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9653   } else {
9654     aopPut (result, "a", MSB32);
9655     MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9656   }
9657
9658   emitcode ("rrc", "a");
9659   if (isSameRegs && offl==1) {
9660     emitcode ("xch", "a,%s",
9661               aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9662   } else {
9663     aopPut (result, "a", MSB24);
9664     MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9665   }
9666   emitcode ("rrc", "a");
9667   aopPut (result, "a", MSB16 - offl);
9668
9669   if (offl == LSB)
9670     {
9671       MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9672       emitcode ("rrc", "a");
9673       aopPut (result, "a", LSB);
9674     }
9675 }
9676
9677 /*-----------------------------------------------------------------*/
9678 /* genrshFour - shift four byte by a known amount != 0             */
9679 /*-----------------------------------------------------------------*/
9680 static void
9681 genrshFour (operand * result, operand * left,
9682             int shCount, int sign)
9683 {
9684   D (emitcode (";", "genrshFour"));
9685
9686   /* if shifting more that 3 bytes */
9687   if (shCount >= 24)
9688     {
9689       shCount -= 24;
9690       _startLazyDPSEvaluation();
9691       if (shCount)
9692         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9693       else
9694         movLeft2Result (left, MSB32, result, LSB, sign);
9695       addSign (result, MSB16, sign);
9696       _endLazyDPSEvaluation();
9697     }
9698   else if (shCount >= 16)
9699     {
9700       shCount -= 16;
9701       _startLazyDPSEvaluation();
9702       if (shCount)
9703         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9704       else
9705         {
9706           movLeft2Result (left, MSB24, result, LSB, 0);
9707           movLeft2Result (left, MSB32, result, MSB16, sign);
9708         }
9709       addSign (result, MSB24, sign);
9710       _endLazyDPSEvaluation();
9711     }
9712   else if (shCount >= 8)
9713     {
9714       shCount -= 8;
9715       _startLazyDPSEvaluation();
9716       if (shCount == 1)
9717         {
9718             shiftRLong (left, MSB16, result, sign);
9719         }
9720       else if (shCount == 0)
9721         {
9722           movLeft2Result (left, MSB16, result, LSB, 0);
9723           movLeft2Result (left, MSB24, result, MSB16, 0);
9724           movLeft2Result (left, MSB32, result, MSB24, sign);
9725           addSign (result, MSB32, sign);
9726         }
9727       else
9728         {
9729           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9730           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9731           /* the last shift is signed */
9732           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9733           addSign (result, MSB32, sign);
9734         }
9735         _endLazyDPSEvaluation();
9736     }
9737   else
9738     {
9739         /* 1 <= shCount <= 7 */
9740       if (shCount <= 2)
9741         {
9742           shiftRLong (left, LSB, result, sign);
9743           if (shCount == 2)
9744             shiftRLong (result, LSB, result, sign);
9745         }
9746       else
9747         {
9748           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9749           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9750           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9751         }
9752     }
9753 }
9754
9755 #ifdef BETTER_LITERAL_SHIFT
9756 /*-----------------------------------------------------------------*/
9757 /* genRightShiftLiteral - right shifting by known count            */
9758 /*-----------------------------------------------------------------*/
9759 static bool
9760 genRightShiftLiteral (operand * left,
9761                       operand * right,
9762                       operand * result,
9763                       iCode * ic,
9764                       int sign)
9765 {
9766   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9767   int size;
9768
9769   size = getSize (operandType (result));
9770
9771   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9772
9773   /* We only handle certain easy cases so far. */
9774   if ((shCount != 0)
9775    && (shCount < (size * 8))
9776    && (size != 1)
9777    && (size != 2)
9778    && (size != 4))
9779   {
9780       D(emitcode (";", "genRightShiftLiteral wimping out"););
9781       return FALSE;
9782   }
9783
9784   freeAsmop (right, NULL, ic, TRUE);
9785
9786   aopOp (left, ic, FALSE, FALSE);
9787   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9788
9789 #if VIEW_SIZE
9790   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9791             AOP_SIZE (left));
9792 #endif
9793
9794   /* test the LEFT size !!! */
9795
9796   /* I suppose that the left size >= result size */
9797   if (shCount == 0)
9798   {
9799       size = getDataSize (result);
9800       _startLazyDPSEvaluation();
9801       while (size--)
9802         movLeft2Result (left, size, result, size, 0);
9803       _endLazyDPSEvaluation();
9804   }
9805   else if (shCount >= (size * 8))
9806     {
9807       if (sign)
9808       {
9809         /* get sign in acc.7 */
9810         MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9811       }
9812       addSign (result, LSB, sign);
9813     }
9814   else
9815     {
9816       switch (size)
9817         {
9818         case 1:
9819           genrshOne (result, left, shCount, sign);
9820           break;
9821
9822         case 2:
9823           genrshTwo (result, left, shCount, sign);
9824           break;
9825 #if 1
9826         case 4:
9827           genrshFour (result, left, shCount, sign);
9828           break;
9829 #endif
9830         default:
9831           break;
9832         }
9833     }
9834   freeAsmop (result, NULL, ic, TRUE);
9835   freeAsmop (left, NULL, ic, TRUE);
9836
9837   return TRUE;
9838 }
9839 #endif
9840
9841 /*-----------------------------------------------------------------*/
9842 /* genSignedRightShift - right shift of signed number              */
9843 /*-----------------------------------------------------------------*/
9844 static void
9845 genSignedRightShift (iCode * ic)
9846 {
9847   operand *right, *left, *result;
9848   int size, offset;
9849   char *l;
9850   symbol *tlbl, *tlbl1;
9851   bool pushedB;
9852
9853   D (emitcode (";", "genSignedRightShift"));
9854
9855   /* we do it the hard way put the shift count in b
9856      and loop thru preserving the sign */
9857
9858   right = IC_RIGHT (ic);
9859   left = IC_LEFT (ic);
9860   result = IC_RESULT (ic);
9861
9862   aopOp (right, ic, FALSE, FALSE);
9863
9864 #ifdef BETTER_LITERAL_SHIFT
9865   if (AOP_TYPE (right) == AOP_LIT)
9866     {
9867       if (genRightShiftLiteral (left, right, result, ic, 1))
9868       {
9869         return;
9870       }
9871     }
9872 #endif
9873   /* shift count is unknown then we have to form
9874      a loop get the loop count in B : Note: we take
9875      only the lower order byte since shifting
9876      more that 32 bits make no sense anyway, ( the
9877      largest size of an object can be only 32 bits ) */
9878
9879   pushedB = pushB ();
9880   if (AOP_TYPE (right) == AOP_LIT)
9881   {
9882       /* Really should be handled by genRightShiftLiteral,
9883        * but since I'm too lazy to fix that today, at least we can make
9884        * some small improvement.
9885        */
9886        emitcode("mov", "b,#!constbyte",
9887                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9888   }
9889   else
9890   {
9891         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9892         emitcode ("inc", "b");
9893   }
9894   freeAsmop (right, NULL, ic, TRUE);
9895   aopOp (left, ic, FALSE, FALSE);
9896   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9897
9898   /* now move the left to the result if they are not the
9899      same */
9900   if (!sameRegs (AOP (left), AOP (result)) &&
9901       AOP_SIZE (result) > 1)
9902     {
9903
9904       size = AOP_SIZE (result);
9905       offset = 0;
9906       _startLazyDPSEvaluation ();
9907       while (size--)
9908         {
9909           l = aopGet (left, offset, FALSE, TRUE, NULL);
9910           if (*l == '@' && IS_AOP_PREG (result))
9911             {
9912
9913               emitcode ("mov", "a,%s", l);
9914               aopPut (result, "a", offset);
9915             }
9916           else
9917             aopPut (result, l, offset);
9918           offset++;
9919         }
9920       _endLazyDPSEvaluation ();
9921     }
9922
9923   /* mov the highest order bit to OVR */
9924   tlbl = newiTempLabel (NULL);
9925   tlbl1 = newiTempLabel (NULL);
9926
9927   size = AOP_SIZE (result);
9928   offset = size - 1;
9929   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
9930   emitcode ("rlc", "a");
9931   emitcode ("mov", "ov,c");
9932   /* if it is only one byte then */
9933   if (size == 1)
9934     {
9935       l = aopGet (left, 0, FALSE, FALSE, NULL);
9936       MOVA (l);
9937       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9938       emitcode ("", "!tlabeldef", tlbl->key + 100);
9939       emitcode ("mov", "c,ov");
9940       emitcode ("rrc", "a");
9941       emitcode ("", "!tlabeldef", tlbl1->key + 100);
9942       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9943       popB (pushedB);
9944       aopPut (result, "a", 0);
9945       goto release;
9946     }
9947
9948   reAdjustPreg (AOP (result));
9949   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9950   emitcode ("", "!tlabeldef", tlbl->key + 100);
9951   emitcode ("mov", "c,ov");
9952   _startLazyDPSEvaluation ();
9953   while (size--)
9954     {
9955       l = aopGet (result, offset, FALSE, FALSE, NULL);
9956       MOVA (l);
9957       emitcode ("rrc", "a");
9958       aopPut (result, "a", offset--);
9959     }
9960   _endLazyDPSEvaluation ();
9961   reAdjustPreg (AOP (result));
9962   emitcode ("", "!tlabeldef", tlbl1->key + 100);
9963   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9964   popB (pushedB);
9965
9966 release:
9967   freeAsmop (result, NULL, ic, TRUE);
9968   freeAsmop (left, NULL, ic, TRUE);
9969 }
9970
9971 /*-----------------------------------------------------------------*/
9972 /* genRightShift - generate code for right shifting                */
9973 /*-----------------------------------------------------------------*/
9974 static void
9975 genRightShift (iCode * ic)
9976 {
9977   operand *right, *left, *result;
9978   sym_link *letype;
9979   int size, offset;
9980   char *l;
9981   symbol *tlbl, *tlbl1;
9982   bool pushedB;
9983
9984   D (emitcode (";", "genRightShift"));
9985
9986   /* if signed then we do it the hard way preserve the
9987      sign bit moving it inwards */
9988   letype = getSpec (operandType (IC_LEFT (ic)));
9989
9990   if (!SPEC_USIGN (letype))
9991     {
9992       genSignedRightShift (ic);
9993       return;
9994     }
9995
9996   /* signed & unsigned types are treated the same : i.e. the
9997      signed is NOT propagated inwards : quoting from the
9998      ANSI - standard : "for E1 >> E2, is equivalent to division
9999      by 2**E2 if unsigned or if it has a non-negative value,
10000      otherwise the result is implementation defined ", MY definition
10001      is that the sign does not get propagated */
10002
10003   right = IC_RIGHT (ic);
10004   left = IC_LEFT (ic);
10005   result = IC_RESULT (ic);
10006
10007   aopOp (right, ic, FALSE, FALSE);
10008
10009 #ifdef BETTER_LITERAL_SHIFT
10010   /* if the shift count is known then do it
10011      as efficiently as possible */
10012   if (AOP_TYPE (right) == AOP_LIT)
10013     {
10014       if (genRightShiftLiteral (left, right, result, ic, 0))
10015       {
10016         return;
10017       }
10018     }
10019 #endif
10020
10021   /* shift count is unknown then we have to form
10022      a loop get the loop count in B : Note: we take
10023      only the lower order byte since shifting
10024      more that 32 bits make no sense anyway, ( the
10025      largest size of an object can be only 32 bits ) */
10026
10027   pushedB = pushB ();
10028   if (AOP_TYPE (right) == AOP_LIT)
10029   {
10030       /* Really should be handled by genRightShiftLiteral,
10031        * but since I'm too lazy to fix that today, at least we can make
10032        * some small improvement.
10033        */
10034        emitcode("mov", "b,#!constbyte",
10035                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10036   }
10037   else
10038   {
10039       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10040       emitcode ("inc", "b");
10041   }
10042   freeAsmop (right, NULL, ic, TRUE);
10043   aopOp (left, ic, FALSE, FALSE);
10044   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10045
10046   /* now move the left to the result if they are not the
10047      same */
10048   if (!sameRegs (AOP (left), AOP (result)) &&
10049       AOP_SIZE (result) > 1)
10050     {
10051       size = AOP_SIZE (result);
10052       offset = 0;
10053       _startLazyDPSEvaluation ();
10054       while (size--)
10055         {
10056           l = aopGet (left, offset, FALSE, TRUE, NULL);
10057           if (*l == '@' && IS_AOP_PREG (result))
10058             {
10059
10060               emitcode ("mov", "a,%s", l);
10061               aopPut (result, "a", offset);
10062             }
10063           else
10064             aopPut (result, l, offset);
10065           offset++;
10066         }
10067       _endLazyDPSEvaluation ();
10068     }
10069
10070   tlbl = newiTempLabel (NULL);
10071   tlbl1 = newiTempLabel (NULL);
10072   size = AOP_SIZE (result);
10073   offset = size - 1;
10074
10075   /* if it is only one byte then */
10076   if (size == 1)
10077     {
10078       l = aopGet (left, 0, FALSE, FALSE, NULL);
10079       MOVA (l);
10080       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10081       emitcode ("", "!tlabeldef", tlbl->key + 100);
10082       CLRC;
10083       emitcode ("rrc", "a");
10084       emitcode ("", "!tlabeldef", tlbl1->key + 100);
10085       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10086       popB (pushedB);
10087       aopPut (result, "a", 0);
10088       goto release;
10089     }
10090
10091   reAdjustPreg (AOP (result));
10092   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10093   emitcode ("", "!tlabeldef", tlbl->key + 100);
10094   CLRC;
10095   _startLazyDPSEvaluation ();
10096   while (size--)
10097     {
10098       l = aopGet (result, offset, FALSE, FALSE, NULL);
10099       MOVA (l);
10100       emitcode ("rrc", "a");
10101       aopPut (result, "a", offset--);
10102     }
10103   _endLazyDPSEvaluation ();
10104   reAdjustPreg (AOP (result));
10105
10106   emitcode ("", "!tlabeldef", tlbl1->key + 100);
10107   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10108   popB (pushedB);
10109
10110 release:
10111   freeAsmop (result, NULL, ic, TRUE);
10112   freeAsmop (left, NULL, ic, TRUE);
10113 }
10114
10115 /*-----------------------------------------------------------------*/
10116 /* emitPtrByteGet - emits code to get a byte into A through a      */
10117 /*                  pointer register (R0, R1, or DPTR). The        */
10118 /*                  original value of A can be preserved in B.     */
10119 /*-----------------------------------------------------------------*/
10120 static void
10121 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10122 {
10123   switch (p_type)
10124     {
10125     case IPOINTER:
10126     case POINTER:
10127       if (preserveAinB)
10128         emitcode ("mov", "b,a");
10129       emitcode ("mov", "a,@%s", rname);
10130       break;
10131
10132     case PPOINTER:
10133       if (preserveAinB)
10134         emitcode ("mov", "b,a");
10135       emitcode ("movx", "a,@%s", rname);
10136       break;
10137
10138     case FPOINTER:
10139       if (preserveAinB)
10140         emitcode ("mov", "b,a");
10141       emitcode ("movx", "a,@dptr");
10142       break;
10143
10144     case CPOINTER:
10145       if (preserveAinB)
10146         emitcode ("mov", "b,a");
10147       emitcode ("clr", "a");
10148       emitcode ("movc", "a,@a+dptr");
10149       break;
10150
10151     case GPOINTER:
10152       if (preserveAinB)
10153         {
10154           emitcode ("push", "b");
10155           emitcode ("push", "acc");
10156         }
10157       emitcode ("lcall", "__gptrget");
10158       if (preserveAinB)
10159         emitcode ("pop", "b");
10160       break;
10161     }
10162 }
10163
10164 /*-----------------------------------------------------------------*/
10165 /* emitPtrByteSet - emits code to set a byte from src through a    */
10166 /*                  pointer register (R0, R1, or DPTR).            */
10167 /*-----------------------------------------------------------------*/
10168 static void
10169 emitPtrByteSet (char *rname, int p_type, char *src)
10170 {
10171   switch (p_type)
10172     {
10173     case IPOINTER:
10174     case POINTER:
10175       if (*src=='@')
10176         {
10177           MOVA (src);
10178           emitcode ("mov", "@%s,a", rname);
10179         }
10180       else
10181         emitcode ("mov", "@%s,%s", rname, src);
10182       break;
10183
10184     case PPOINTER:
10185       MOVA (src);
10186       emitcode ("movx", "@%s,a", rname);
10187       break;
10188
10189     case FPOINTER:
10190       MOVA (src);
10191       emitcode ("movx", "@dptr,a");
10192       break;
10193
10194     case GPOINTER:
10195       MOVA (src);
10196       emitcode ("lcall", "__gptrput");
10197       break;
10198     }
10199 }
10200
10201 /*-----------------------------------------------------------------*/
10202 /* genUnpackBits - generates code for unpacking bits               */
10203 /*-----------------------------------------------------------------*/
10204 static void
10205 genUnpackBits (operand * result, char *rname, int ptype)
10206 {
10207   int offset = 0;       /* result byte offset */
10208   int rsize;            /* result size */
10209   int rlen = 0;         /* remaining bitfield length */
10210   sym_link *etype;      /* bitfield type information */
10211   int blen;             /* bitfield length */
10212   int bstr;             /* bitfield starting bit within byte */
10213
10214   D(emitcode (";     genUnpackBits",""));
10215
10216   etype = getSpec (operandType (result));
10217   rsize = getSize (operandType (result));
10218   blen = SPEC_BLEN (etype);
10219   bstr = SPEC_BSTR (etype);
10220
10221   /* If the bitfield length is less than a byte */
10222   if (blen < 8)
10223     {
10224       emitPtrByteGet (rname, ptype, FALSE);
10225       AccRol (8 - bstr);
10226       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10227       if (!SPEC_USIGN (etype))
10228         {
10229           /* signed bitfield */
10230           symbol *tlbl = newiTempLabel (NULL);
10231
10232           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10233           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10234           emitcode ("", "%05d$:", tlbl->key + 100);
10235         }
10236       aopPut (result, "a", offset++);
10237       goto finish;
10238     }
10239
10240   /* Bit field did not fit in a byte. Copy all
10241      but the partial byte at the end.  */
10242   for (rlen=blen;rlen>=8;rlen-=8)
10243     {
10244       emitPtrByteGet (rname, ptype, FALSE);
10245       aopPut (result, "a", offset++);
10246       if (rlen>8)
10247         emitcode ("inc", "%s", rname);
10248     }
10249
10250   /* Handle the partial byte at the end */
10251   if (rlen)
10252     {
10253       emitPtrByteGet (rname, ptype, FALSE);
10254       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10255       if (!SPEC_USIGN (etype))
10256         {
10257           /* signed bitfield */
10258           symbol *tlbl = newiTempLabel (NULL);
10259
10260           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10261           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10262           emitcode ("", "%05d$:", tlbl->key + 100);
10263         }
10264       aopPut (result, "a", offset++);
10265     }
10266
10267 finish:
10268   if (offset < rsize)
10269     {
10270       char *source;
10271
10272       if (SPEC_USIGN (etype))
10273         source = zero;
10274       else
10275         {
10276           /* signed bitfield: sign extension with 0x00 or 0xff */
10277           emitcode ("rlc", "a");
10278           emitcode ("subb", "a,acc");
10279
10280           source = "a";
10281         }
10282       rsize -= offset;
10283       while (rsize--)
10284         aopPut (result, source, offset++);
10285     }
10286 }
10287
10288
10289 /*-----------------------------------------------------------------*/
10290 /* genDataPointerGet - generates code when ptr offset is known     */
10291 /*-----------------------------------------------------------------*/
10292 static void
10293 genDataPointerGet (operand * left,
10294                    operand * result,
10295                    iCode * ic)
10296 {
10297   char *l;
10298   char buffer[256];
10299   int size, offset = 0;
10300   aopOp (result, ic, TRUE, FALSE);
10301
10302   /* get the string representation of the name */
10303   l = aopGet (left, 0, FALSE, TRUE, NULL);
10304   size = AOP_SIZE (result);
10305   _startLazyDPSEvaluation ();
10306   while (size--)
10307     {
10308         if (offset)
10309         {
10310             SNPRINTF (buffer, sizeof(buffer),
10311                       "(%s + %d)", l + 1, offset);
10312         }
10313         else
10314         {
10315             SNPRINTF (buffer, sizeof(buffer),
10316                       "%s", l + 1);
10317         }
10318       aopPut (result, buffer, offset++);
10319     }
10320   _endLazyDPSEvaluation ();
10321
10322   freeAsmop (result, NULL, ic, TRUE);
10323   freeAsmop (left, NULL, ic, TRUE);
10324 }
10325
10326 /*-----------------------------------------------------------------*/
10327 /* genNearPointerGet - emitcode for near pointer fetch             */
10328 /*-----------------------------------------------------------------*/
10329 static void
10330 genNearPointerGet (operand * left,
10331                    operand * result,
10332                    iCode * ic,
10333                    iCode *pi)
10334 {
10335   asmop *aop = NULL;
10336   regs *preg;
10337   char *rname;
10338   sym_link *rtype, *retype, *letype;
10339   sym_link *ltype = operandType (left);
10340   char buffer[80];
10341
10342   rtype = operandType (result);
10343   retype = getSpec (rtype);
10344   letype = getSpec (ltype);
10345
10346   aopOp (left, ic, FALSE, FALSE);
10347
10348   /* if left is rematerialisable and
10349      result is not bitfield variable type and
10350      the left is pointer to data space i.e
10351      lower 128 bytes of space */
10352   if (AOP_TYPE (left) == AOP_IMMD &&
10353       !IS_BITFIELD (retype) &&
10354       !IS_BITFIELD (letype) &&
10355       DCL_TYPE (ltype) == POINTER)
10356     {
10357       genDataPointerGet (left, result, ic);
10358       return;
10359     }
10360
10361   /* if the value is already in a pointer register
10362      then don't need anything more */
10363   if (!AOP_INPREG (AOP (left)))
10364     {
10365       /* otherwise get a free pointer register */
10366       aop = newAsmop (0);
10367       preg = getFreePtr (ic, &aop, FALSE);
10368       emitcode ("mov", "%s,%s",
10369                 preg->name,
10370                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10371       rname = preg->name;
10372     }
10373   else
10374     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10375
10376   freeAsmop (left, NULL, ic, TRUE);
10377   aopOp (result, ic, FALSE, FALSE);
10378
10379   /* if bitfield then unpack the bits */
10380   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10381     genUnpackBits (result, rname, POINTER);
10382   else
10383     {
10384       /* we have can just get the values */
10385       int size = AOP_SIZE (result);
10386       int offset = 0;
10387
10388       while (size--)
10389         {
10390           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10391             {
10392
10393               emitcode ("mov", "a,@%s", rname);
10394               aopPut (result, "a", offset);
10395             }
10396           else
10397             {
10398               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10399               aopPut (result, buffer, offset);
10400             }
10401           offset++;
10402           if (size || pi)
10403                 emitcode ("inc", "%s", rname);
10404             }
10405         }
10406
10407   /* now some housekeeping stuff */
10408   if (aop)      /* we had to allocate for this iCode */
10409     {
10410       if (pi) { /* post increment present */
10411         aopPut (left, rname, 0);
10412       }
10413       freeAsmop (NULL, aop, ic, TRUE);
10414     }
10415   else
10416     {
10417       /* we did not allocate which means left
10418          already in a pointer register, then
10419          if size > 0 && this could be used again
10420          we have to point it back to where it
10421          belongs */
10422       if (AOP_SIZE (result) > 1 &&
10423           !OP_SYMBOL (left)->remat &&
10424           (OP_SYMBOL (left)->liveTo > ic->seq ||
10425            ic->depth) &&
10426           !pi)
10427         {
10428           int size = AOP_SIZE (result) - 1;
10429           while (size--)
10430             emitcode ("dec", "%s", rname);
10431         }
10432     }
10433
10434   /* done */
10435   freeAsmop (result, NULL, ic, TRUE);
10436   if (pi) pi->generated = 1;
10437 }
10438
10439 /*-----------------------------------------------------------------*/
10440 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10441 /*-----------------------------------------------------------------*/
10442 static void
10443 genPagedPointerGet (operand * left,
10444                     operand * result,
10445                     iCode * ic,
10446                     iCode * pi)
10447 {
10448   asmop *aop = NULL;
10449   regs *preg;
10450   char *rname;
10451   sym_link *rtype, *retype, *letype;
10452
10453   rtype = operandType (result);
10454   retype = getSpec (rtype);
10455   letype = getSpec (operandType (left));
10456   aopOp (left, ic, FALSE, FALSE);
10457
10458   /* if the value is already in a pointer register
10459      then don't need anything more */
10460   if (!AOP_INPREG (AOP (left)))
10461     {
10462       /* otherwise get a free pointer register */
10463       aop = newAsmop (0);
10464       preg = getFreePtr (ic, &aop, FALSE);
10465       emitcode ("mov", "%s,%s",
10466                 preg->name,
10467                 aopGet (left, 0, FALSE, TRUE, NULL));
10468       rname = preg->name;
10469     }
10470   else
10471     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10472
10473   freeAsmop (left, NULL, ic, TRUE);
10474   aopOp (result, ic, FALSE, FALSE);
10475
10476   /* if bitfield then unpack the bits */
10477   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10478     genUnpackBits (result, rname, PPOINTER);
10479   else
10480     {
10481       /* we have can just get the values */
10482       int size = AOP_SIZE (result);
10483       int offset = 0;
10484
10485       while (size--)
10486         {
10487
10488           emitcode ("movx", "a,@%s", rname);
10489           aopPut (result, "a", offset);
10490
10491           offset++;
10492
10493           if (size || pi)
10494             emitcode ("inc", "%s", rname);
10495         }
10496     }
10497
10498   /* now some housekeeping stuff */
10499   if (aop)      /* we had to allocate for this iCode */
10500     {
10501       if (pi) aopPut (left, rname, 0);
10502       freeAsmop (NULL, aop, ic, TRUE);
10503     }
10504   else
10505     {
10506       /* we did not allocate which means left
10507          already in a pointer register, then
10508          if size > 0 && this could be used again
10509          we have to point it back to where it
10510          belongs */
10511       if (AOP_SIZE (result) > 1 &&
10512           !OP_SYMBOL (left)->remat &&
10513           (OP_SYMBOL (left)->liveTo > ic->seq ||
10514            ic->depth) &&
10515           !pi)
10516         {
10517           int size = AOP_SIZE (result) - 1;
10518           while (size--)
10519             emitcode ("dec", "%s", rname);
10520         }
10521     }
10522
10523   /* done */
10524   freeAsmop (result, NULL, ic, TRUE);
10525   if (pi) pi->generated = 1;
10526 }
10527
10528 /*-----------------------------------------------------------------*/
10529 /* genFarPointerGet - get value from far space                     */
10530 /*-----------------------------------------------------------------*/
10531 static void
10532 genFarPointerGet (operand * left,
10533                   operand * result, iCode * ic, iCode *pi)
10534 {
10535     int size, offset, dopi=1;
10536   sym_link *retype = getSpec (operandType (result));
10537   sym_link *letype = getSpec (operandType (left));
10538   D (emitcode (";", "genFarPointerGet"););
10539
10540   aopOp (left, ic, FALSE, FALSE);
10541
10542   /* if the operand is already in dptr
10543      then we do nothing else we move the value to dptr */
10544   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10545     {
10546       /* if this is rematerializable */
10547       if (AOP_TYPE (left) == AOP_IMMD)
10548         {
10549           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10550         }
10551       else
10552         {
10553           /* we need to get it byte by byte */
10554           _startLazyDPSEvaluation ();
10555           if (AOP_TYPE (left) != AOP_DPTR)
10556             {
10557               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10558               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10559               if (options.model == MODEL_FLAT24)
10560                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10561             }
10562           else
10563             {
10564               /* We need to generate a load to DPTR indirect through DPTR. */
10565               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10566               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10567               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10568               if (options.model == MODEL_FLAT24)
10569                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10570               emitcode ("pop", "dph");
10571               emitcode ("pop", "dpl");
10572               dopi =0;
10573             }
10574           _endLazyDPSEvaluation ();
10575         }
10576     }
10577   /* so dptr know contains the address */
10578   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10579
10580   /* if bit then unpack */
10581   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10582       if (AOP_INDPTRn(left)) {
10583           genSetDPTR(AOP(left)->aopu.dptr);
10584       }
10585       genUnpackBits (result, "dptr", FPOINTER);
10586       if (AOP_INDPTRn(left)) {
10587           genSetDPTR(0);
10588       }
10589   } else
10590     {
10591       size = AOP_SIZE (result);
10592       offset = 0;
10593
10594       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10595           while (size--) {
10596               genSetDPTR(AOP(left)->aopu.dptr);
10597               emitcode ("movx", "a,@dptr");
10598               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10599                   emitcode ("inc", "dptr");
10600               genSetDPTR (0);
10601               aopPut (result, "a", offset++);
10602           }
10603       } else {
10604           _startLazyDPSEvaluation ();
10605           while (size--) {
10606               if (AOP_INDPTRn(left)) {
10607                   genSetDPTR(AOP(left)->aopu.dptr);
10608               } else {
10609                   genSetDPTR (0);
10610               }
10611               _flushLazyDPS ();
10612
10613               emitcode ("movx", "a,@dptr");
10614               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10615                   emitcode ("inc", "dptr");
10616
10617               aopPut (result, "a", offset++);
10618           }
10619           _endLazyDPSEvaluation ();
10620       }
10621     }
10622   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10623       if (!AOP_INDPTRn(left)) {
10624           _startLazyDPSEvaluation ();
10625           aopPut (left, "dpl", 0);
10626           aopPut (left, "dph", 1);
10627           if (options.model == MODEL_FLAT24)
10628               aopPut (left, "dpx", 2);
10629           _endLazyDPSEvaluation ();
10630       }
10631     pi->generated = 1;
10632   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10633              AOP_SIZE(result) > 1 &&
10634              IS_SYMOP(left) &&
10635              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10636
10637       size = AOP_SIZE (result) - 1;
10638       if (AOP_INDPTRn(left)) {
10639           genSetDPTR(AOP(left)->aopu.dptr);
10640       }
10641       while (size--) emitcode ("lcall","__decdptr");
10642       if (AOP_INDPTRn(left)) {
10643           genSetDPTR(0);
10644       }
10645   }
10646
10647   freeAsmop (left, NULL, ic, TRUE);
10648   freeAsmop (result, NULL, ic, TRUE);
10649 }
10650
10651 /*-----------------------------------------------------------------*/
10652 /* genCodePointerGet - get value from code space                  */
10653 /*-----------------------------------------------------------------*/
10654 static void
10655 genCodePointerGet (operand * left,
10656                     operand * result, iCode * ic, iCode *pi)
10657 {
10658   int size, offset, dopi=1;
10659   sym_link *retype = getSpec (operandType (result));
10660
10661   aopOp (left, ic, FALSE, FALSE);
10662
10663   /* if the operand is already in dptr
10664      then we do nothing else we move the value to dptr */
10665   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10666     {
10667       /* if this is rematerializable */
10668       if (AOP_TYPE (left) == AOP_IMMD)
10669         {
10670           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10671         }
10672       else
10673         {                       /* we need to get it byte by byte */
10674           _startLazyDPSEvaluation ();
10675           if (AOP_TYPE (left) != AOP_DPTR)
10676             {
10677               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10678               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10679               if (options.model == MODEL_FLAT24)
10680                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10681             }
10682           else
10683             {
10684               /* We need to generate a load to DPTR indirect through DPTR. */
10685               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10686               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10687               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10688               if (options.model == MODEL_FLAT24)
10689                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10690               emitcode ("pop", "dph");
10691               emitcode ("pop", "dpl");
10692               dopi=0;
10693             }
10694           _endLazyDPSEvaluation ();
10695         }
10696     }
10697   /* so dptr know contains the address */
10698   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10699
10700   /* if bit then unpack */
10701   if (IS_BITFIELD (retype)) {
10702       if (AOP_INDPTRn(left)) {
10703           genSetDPTR(AOP(left)->aopu.dptr);
10704       }
10705       genUnpackBits (result, "dptr", CPOINTER);
10706       if (AOP_INDPTRn(left)) {
10707           genSetDPTR(0);
10708       }
10709   } else
10710     {
10711       size = AOP_SIZE (result);
10712       offset = 0;
10713       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10714           while (size--) {
10715               genSetDPTR(AOP(left)->aopu.dptr);
10716               emitcode ("clr", "a");
10717               emitcode ("movc", "a,@a+dptr");
10718               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10719                   emitcode ("inc", "dptr");
10720               genSetDPTR (0);
10721               aopPut (result, "a", offset++);
10722           }
10723       } else {
10724           _startLazyDPSEvaluation ();
10725           while (size--)
10726               {
10727                   if (AOP_INDPTRn(left)) {
10728                       genSetDPTR(AOP(left)->aopu.dptr);
10729                   } else {
10730                       genSetDPTR (0);
10731                   }
10732                   _flushLazyDPS ();
10733
10734                   emitcode ("clr", "a");
10735                   emitcode ("movc", "a,@a+dptr");
10736                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10737                       emitcode ("inc", "dptr");
10738                   aopPut (result, "a", offset++);
10739               }
10740           _endLazyDPSEvaluation ();
10741       }
10742     }
10743   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10744       if (!AOP_INDPTRn(left)) {
10745           _startLazyDPSEvaluation ();
10746
10747           aopPut (left, "dpl", 0);
10748           aopPut (left, "dph", 1);
10749           if (options.model == MODEL_FLAT24)
10750               aopPut (left, "dpx", 2);
10751
10752           _endLazyDPSEvaluation ();
10753       }
10754       pi->generated = 1;
10755   } else if ((OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10756              AOP_SIZE(result) > 1 &&
10757              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10758
10759       size = AOP_SIZE (result) - 1;
10760       if (AOP_INDPTRn(left)) {
10761           genSetDPTR(AOP(left)->aopu.dptr);
10762       }
10763       while (size--) emitcode ("lcall","__decdptr");
10764       if (AOP_INDPTRn(left)) {
10765           genSetDPTR(0);
10766       }
10767   }
10768
10769   freeAsmop (result, NULL, ic, TRUE);
10770   freeAsmop (left, NULL, ic, TRUE);
10771 }
10772
10773 /*-----------------------------------------------------------------*/
10774 /* genGenPointerGet - gget value from generic pointer space        */
10775 /*-----------------------------------------------------------------*/
10776 static void
10777 genGenPointerGet (operand * left,
10778                   operand * result, iCode * ic, iCode * pi)
10779 {
10780   int size, offset;
10781   bool pushedB;
10782   sym_link *retype = getSpec (operandType (result));
10783   sym_link *letype = getSpec (operandType (left));
10784
10785   D (emitcode (";", "genGenPointerGet"));
10786
10787   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10788
10789   pushedB = pushB ();
10790   /* if the operand is already in dptr
10791      then we do nothing else we move the value to dptr */
10792   if (AOP_TYPE (left) != AOP_STR)
10793     {
10794       /* if this is rematerializable */
10795       if (AOP_TYPE (left) == AOP_IMMD)
10796         {
10797           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10798           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10799             {
10800               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10801             }
10802           else
10803             {
10804               emitcode ("mov", "b,#%d", pointerCode (retype));
10805             }
10806         }
10807       else
10808         {                       /* we need to get it byte by byte */
10809           _startLazyDPSEvaluation ();
10810           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10811           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10812           if (options.model == MODEL_FLAT24) {
10813               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10814               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10815           } else {
10816               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10817           }
10818           _endLazyDPSEvaluation ();
10819         }
10820     }
10821
10822   /* so dptr-b now contains the address */
10823   aopOp (result, ic, FALSE, TRUE);
10824
10825   /* if bit then unpack */
10826   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10827   {
10828     genUnpackBits (result, "dptr", GPOINTER);
10829   }
10830   else
10831     {
10832         size = AOP_SIZE (result);
10833         offset = 0;
10834
10835         while (size--)
10836         {
10837             if (size)
10838             {
10839                 // Get two bytes at a time, results in _AP & A.
10840                 // dptr will be incremented ONCE by __gptrgetWord.
10841                 //
10842                 // Note: any change here must be coordinated
10843                 // with the implementation of __gptrgetWord
10844                 // in device/lib/_gptrget.c
10845                 emitcode ("lcall", "__gptrgetWord");
10846                 aopPut (result, DP2_RESULT_REG, offset++);
10847                 aopPut (result, "a", offset++);
10848                 size--;
10849             }
10850             else
10851             {
10852                 // Only one byte to get.
10853                 emitcode ("lcall", "__gptrget");
10854                 aopPut (result, "a", offset++);
10855             }
10856
10857             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
10858             {
10859                 emitcode ("inc", "dptr");
10860             }
10861         }
10862     }
10863
10864   if (pi && AOP_TYPE (left) != AOP_IMMD) {
10865     _startLazyDPSEvaluation ();
10866
10867     aopPut (left, "dpl", 0);
10868     aopPut (left, "dph", 1);
10869     if (options.model == MODEL_FLAT24) {
10870         aopPut (left, "dpx", 2);
10871         aopPut (left, "b", 3);
10872     } else  aopPut (left, "b", 2);
10873
10874     _endLazyDPSEvaluation ();
10875
10876     pi->generated = 1;
10877   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
10878              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10879
10880       size = AOP_SIZE (result) - 1;
10881       while (size--) emitcode ("lcall","__decdptr");
10882   }
10883   popB (pushedB);
10884
10885   freeAsmop (result, NULL, ic, TRUE);
10886   freeAsmop (left, NULL, ic, TRUE);
10887 }
10888
10889 /*-----------------------------------------------------------------*/
10890 /* genPointerGet - generate code for pointer get                   */
10891 /*-----------------------------------------------------------------*/
10892 static void
10893 genPointerGet (iCode * ic, iCode *pi)
10894 {
10895   operand *left, *result;
10896   sym_link *type, *etype;
10897   int p_type;
10898
10899   D (emitcode (";", "genPointerGet "));
10900
10901   left = IC_LEFT (ic);
10902   result = IC_RESULT (ic);
10903
10904   /* depending on the type of pointer we need to
10905      move it to the correct pointer register */
10906   type = operandType (left);
10907   etype = getSpec (type);
10908   /* if left is of type of pointer then it is simple */
10909   if (IS_PTR (type) && !IS_FUNC (type->next))
10910     p_type = DCL_TYPE (type);
10911   else
10912     {
10913       /* we have to go by the storage class */
10914       p_type = PTR_TYPE (SPEC_OCLS (etype));
10915     }
10916
10917   /* special case when cast remat */
10918   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10919       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10920     {
10921       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10922       type = operandType (left);
10923       p_type = DCL_TYPE (type);
10924     }
10925   /* now that we have the pointer type we assign
10926      the pointer values */
10927   switch (p_type)
10928     {
10929
10930     case POINTER:
10931     case IPOINTER:
10932       genNearPointerGet (left, result, ic, pi);
10933       break;
10934
10935     case PPOINTER:
10936       genPagedPointerGet (left, result, ic, pi);
10937       break;
10938
10939     case FPOINTER:
10940       genFarPointerGet (left, result, ic, pi);
10941       break;
10942
10943     case CPOINTER:
10944       genCodePointerGet (left, result, ic, pi);
10945       break;
10946
10947     case GPOINTER:
10948       genGenPointerGet (left, result, ic, pi);
10949       break;
10950     }
10951 }
10952
10953 /*-----------------------------------------------------------------*/
10954 /* genPackBits - generates code for packed bit storage             */
10955 /*-----------------------------------------------------------------*/
10956 static void
10957 genPackBits (sym_link * etype,
10958              operand * right,
10959              char *rname, int p_type)
10960 {
10961   int offset = 0;       /* source byte offset */
10962   int rlen = 0;         /* remaining bitfield length */
10963   int blen;             /* bitfield length */
10964   int bstr;             /* bitfield starting bit within byte */
10965   int litval;           /* source literal value (if AOP_LIT) */
10966   unsigned char mask;   /* bitmask within current byte */
10967
10968   D(emitcode (";     genPackBits",""));
10969
10970   blen = SPEC_BLEN (etype);
10971   bstr = SPEC_BSTR (etype);
10972
10973   /* If the bitfield length is less than a byte */
10974   if (blen < 8)
10975     {
10976       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10977               (unsigned char) (0xFF >> (8 - bstr)));
10978
10979       if (AOP_TYPE (right) == AOP_LIT)
10980         {
10981           /* Case with a bitfield length <8 and literal source
10982           */
10983           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10984           litval <<= bstr;
10985           litval &= (~mask) & 0xff;
10986           emitPtrByteGet (rname, p_type, FALSE);
10987           if ((mask|litval)!=0xff)
10988             emitcode ("anl","a,#!constbyte", mask);
10989           if (litval)
10990             emitcode ("orl","a,#!constbyte", litval);
10991         }
10992       else
10993         {
10994           if ((blen==1) && (p_type!=GPOINTER))
10995             {
10996               /* Case with a bitfield length == 1 and no generic pointer
10997               */
10998               if (AOP_TYPE (right) == AOP_CRY)
10999                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11000               else
11001                 {
11002                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11003                   emitcode ("rrc","a");
11004                 }
11005               emitPtrByteGet (rname, p_type, FALSE);
11006               emitcode ("mov","acc.%d,c",bstr);
11007             }
11008           else
11009             {
11010               bool pushedB;
11011               /* Case with a bitfield length < 8 and arbitrary source
11012               */
11013               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11014               /* shift and mask source value */
11015               AccLsh (bstr);
11016               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11017
11018               pushedB = pushB ();
11019               /* transfer A to B and get next byte */
11020               emitPtrByteGet (rname, p_type, TRUE);
11021
11022               emitcode ("anl", "a,#!constbyte", mask);
11023               emitcode ("orl", "a,b");
11024               if (p_type == GPOINTER)
11025                 emitcode ("pop", "b");
11026
11027               popB (pushedB);
11028            }
11029         }
11030
11031       emitPtrByteSet (rname, p_type, "a");
11032       return;
11033     }
11034
11035   /* Bit length is greater than 7 bits. In this case, copy  */
11036   /* all except the partial byte at the end                 */
11037   for (rlen=blen;rlen>=8;rlen-=8)
11038     {
11039       emitPtrByteSet (rname, p_type,
11040                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11041       if (rlen>8)
11042         emitcode ("inc", "%s", rname);
11043     }
11044
11045   /* If there was a partial byte at the end */
11046   if (rlen)
11047     {
11048       mask = (((unsigned char) -1 << rlen) & 0xff);
11049
11050       if (AOP_TYPE (right) == AOP_LIT)
11051         {
11052           /* Case with partial byte and literal source
11053           */
11054           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11055           litval >>= (blen-rlen);
11056           litval &= (~mask) & 0xff;
11057           emitPtrByteGet (rname, p_type, FALSE);
11058           if ((mask|litval)!=0xff)
11059             emitcode ("anl","a,#!constbyte", mask);
11060           if (litval)
11061             emitcode ("orl","a,#!constbyte", litval);
11062         }
11063       else
11064         {
11065           bool pushedB;
11066           /* Case with partial byte and arbitrary source
11067           */
11068           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11069           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11070
11071           pushedB = pushB ();
11072           /* transfer A to B and get next byte */
11073           emitPtrByteGet (rname, p_type, TRUE);
11074
11075           emitcode ("anl", "a,#!constbyte", mask);
11076           emitcode ("orl", "a,b");
11077           if (p_type == GPOINTER)
11078             emitcode ("pop", "b");
11079
11080           popB (pushedB);
11081         }
11082       emitPtrByteSet (rname, p_type, "a");
11083     }
11084 }
11085
11086
11087 /*-----------------------------------------------------------------*/
11088 /* genDataPointerSet - remat pointer to data space                 */
11089 /*-----------------------------------------------------------------*/
11090 static void
11091 genDataPointerSet (operand * right,
11092                    operand * result,
11093                    iCode * ic)
11094 {
11095   int size, offset = 0;
11096   char *l, buffer[256];
11097
11098   D (emitcode (";", "genDataPointerSet"));
11099
11100   aopOp (right, ic, FALSE, FALSE);
11101
11102   l = aopGet (result, 0, FALSE, TRUE, NULL);
11103   size = AOP_SIZE (right);
11104   while (size--)
11105     {
11106       if (offset)
11107           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11108       else
11109           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11110       emitcode ("mov", "%s,%s", buffer,
11111                 aopGet (right, offset++, FALSE, FALSE, NULL));
11112     }
11113
11114   freeAsmop (result, NULL, ic, TRUE);
11115   freeAsmop (right, NULL, ic, TRUE);
11116 }
11117
11118 /*-----------------------------------------------------------------*/
11119 /* genNearPointerSet - emitcode for near pointer put                */
11120 /*-----------------------------------------------------------------*/
11121 static void
11122 genNearPointerSet (operand * right,
11123                    operand * result,
11124                    iCode * ic,
11125                    iCode * pi)
11126 {
11127   asmop *aop = NULL;
11128   char *rname, *l;
11129   sym_link *retype, *letype;
11130   sym_link *ptype = operandType (result);
11131
11132   D(emitcode (";", "genNearPointerSet"));
11133
11134   retype = getSpec (operandType (right));
11135   letype = getSpec (ptype);
11136
11137   aopOp (result, ic, FALSE, FALSE);
11138
11139   /* if the result is rematerializable &
11140      in data space & not a bit variable */
11141   if (AOP_TYPE (result) == AOP_IMMD &&
11142       DCL_TYPE (ptype) == POINTER &&
11143       !IS_BITVAR (retype) &&
11144       !IS_BITVAR (letype))
11145     {
11146       genDataPointerSet (right, result, ic);
11147       return;
11148     }
11149
11150   /* if the value is already in a pointer register
11151      then don't need anything more */
11152   if (!AOP_INPREG (AOP (result)))
11153     {
11154       /* otherwise get a free pointer register */
11155       regs *preg;
11156
11157       aop = newAsmop (0);
11158       preg = getFreePtr (ic, &aop, FALSE);
11159       emitcode ("mov", "%s,%s",
11160                 preg->name,
11161                 aopGet (result, 0, FALSE, TRUE, NULL));
11162       rname = preg->name;
11163     }
11164   else
11165     {
11166       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11167     }
11168
11169   aopOp (right, ic, FALSE, FALSE);
11170
11171   /* if bitfield then unpack the bits */
11172   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11173     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11174   else
11175     {
11176       /* we have can just get the values */
11177       int size = AOP_SIZE (right);
11178       int offset = 0;
11179
11180       while (size--)
11181         {
11182           l = aopGet (right, offset, FALSE, TRUE, NULL);
11183           if (*l == '@')
11184             {
11185               MOVA (l);
11186               emitcode ("mov", "@%s,a", rname);
11187             }
11188           else
11189             emitcode ("mov", "@%s,%s", rname, l);
11190           if (size || pi)
11191             emitcode ("inc", "%s", rname);
11192           offset++;
11193         }
11194     }
11195
11196   /* now some housekeeping stuff */
11197   if (aop)      /* we had to allocate for this iCode */
11198     {
11199       if (pi) aopPut (result,rname,0);
11200       freeAsmop (NULL, aop, ic, TRUE);
11201     }
11202   else
11203     {
11204       /* we did not allocate which means left
11205          already in a pointer register, then
11206          if size > 0 && this could be used again
11207          we have to point it back to where it
11208          belongs */
11209       if (AOP_SIZE (right) > 1 &&
11210           !OP_SYMBOL (result)->remat &&
11211           (OP_SYMBOL (result)->liveTo > ic->seq ||
11212            ic->depth) &&
11213           !pi)
11214         {
11215           int size = AOP_SIZE (right) - 1;
11216           while (size--)
11217             emitcode ("dec", "%s", rname);
11218         }
11219     }
11220
11221   /* done */
11222   if (pi) pi->generated = 1;
11223   freeAsmop (result, NULL, ic, TRUE);
11224   freeAsmop (right, NULL, ic, TRUE);
11225 }
11226
11227 /*-----------------------------------------------------------------*/
11228 /* genPagedPointerSet - emitcode for Paged pointer put             */
11229 /*-----------------------------------------------------------------*/
11230 static void
11231 genPagedPointerSet (operand * right,
11232                     operand * result,
11233                     iCode * ic,
11234                     iCode *pi)
11235 {
11236   asmop *aop = NULL;
11237   char *rname, *l;
11238   sym_link *retype, *letype;
11239
11240   D (emitcode (";", "genPagedPointerSet"));
11241
11242   retype = getSpec (operandType (right));
11243   letype = getSpec (operandType (result));
11244
11245   aopOp (result, ic, FALSE, FALSE);
11246
11247   /* if the value is already in a pointer register
11248      then don't need anything more */
11249   if (!AOP_INPREG (AOP (result)))
11250     {
11251       /* otherwise get a free pointer register */
11252       regs *preg;
11253
11254       aop = newAsmop (0);
11255       preg = getFreePtr (ic, &aop, FALSE);
11256       emitcode ("mov", "%s,%s",
11257                 preg->name,
11258                 aopGet (result, 0, FALSE, TRUE, NULL));
11259       rname = preg->name;
11260     }
11261   else
11262     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11263
11264   aopOp (right, ic, FALSE, FALSE);
11265
11266   /* if bitfield then unpack the bits */
11267   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11268     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11269   else
11270     {
11271       /* we have can just get the values */
11272       int size = AOP_SIZE (right);
11273       int offset = 0;
11274
11275       while (size--)
11276         {
11277           l = aopGet (right, offset, FALSE, TRUE, NULL);
11278           MOVA (l);
11279           emitcode ("movx", "@%s,a", rname);
11280
11281           if (size || pi)
11282             emitcode ("inc", "%s", rname);
11283
11284           offset++;
11285         }
11286     }
11287
11288   /* now some housekeeping stuff */
11289   if (aop)
11290     {
11291       if (pi)
11292         aopPut (result, rname, 0);
11293       /* we had to allocate for this iCode */
11294       freeAsmop (NULL, aop, ic, TRUE);
11295     }
11296   else
11297     {
11298       /* we did not allocate which means left
11299          already in a pointer register, then
11300          if size > 0 && this could be used again
11301          we have to point it back to where it
11302          belongs */
11303       if (AOP_SIZE (right) > 1 &&
11304           !OP_SYMBOL (result)->remat &&
11305           (OP_SYMBOL (result)->liveTo > ic->seq ||
11306            ic->depth) &&
11307           !pi)
11308         {
11309           int size = AOP_SIZE (right) - 1;
11310           while (size--)
11311             emitcode ("dec", "%s", rname);
11312         }
11313     }
11314
11315   /* done */
11316   if (pi) pi->generated = 1;
11317   freeAsmop (result, NULL, ic, TRUE);
11318   freeAsmop (right, NULL, ic, TRUE);
11319 }
11320
11321 /*-----------------------------------------------------------------*/
11322 /* genFarPointerSet - set value from far space                     */
11323 /*-----------------------------------------------------------------*/
11324 static void
11325 genFarPointerSet (operand * right,
11326                   operand * result, iCode * ic, iCode *pi)
11327 {
11328   int size, offset, dopi=1;
11329   sym_link *retype = getSpec (operandType (right));
11330   sym_link *letype = getSpec (operandType (result));
11331
11332   aopOp (result, ic, FALSE, FALSE);
11333
11334   /* if the operand is already in dptr
11335      then we do nothing else we move the value to dptr */
11336   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11337     {
11338       /* if this is remateriazable */
11339       if (AOP_TYPE (result) == AOP_IMMD)
11340         emitcode ("mov", "dptr,%s",
11341                   aopGet (result, 0, TRUE, FALSE, NULL));
11342       else
11343         {
11344           /* we need to get it byte by byte */
11345           _startLazyDPSEvaluation ();
11346           if (AOP_TYPE (result) != AOP_DPTR)
11347             {
11348               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11349               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11350               if (options.model == MODEL_FLAT24)
11351                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11352             }
11353           else
11354             {
11355               /* We need to generate a load to DPTR indirect through DPTR. */
11356               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11357
11358               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11359               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11360               if (options.model == MODEL_FLAT24)
11361                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11362               emitcode ("pop", "dph");
11363               emitcode ("pop", "dpl");
11364               dopi=0;
11365             }
11366           _endLazyDPSEvaluation ();
11367         }
11368     }
11369   /* so dptr know contains the address */
11370   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11371
11372   /* if bit then unpack */
11373   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11374   {
11375       if (AOP_INDPTRn(result)) {
11376           genSetDPTR(AOP(result)->aopu.dptr);
11377       }
11378       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11379       if (AOP_INDPTRn(result)) {
11380           genSetDPTR(0);
11381       }
11382   } else {
11383       size = AOP_SIZE (right);
11384       offset = 0;
11385       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11386           while (size--) {
11387               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11388
11389               genSetDPTR(AOP(result)->aopu.dptr);
11390               emitcode ("movx", "@dptr,a");
11391               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11392                   emitcode ("inc", "dptr");
11393               genSetDPTR (0);
11394           }
11395       } else {
11396           _startLazyDPSEvaluation ();
11397           while (size--) {
11398               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11399
11400               if (AOP_INDPTRn(result)) {
11401                   genSetDPTR(AOP(result)->aopu.dptr);
11402               } else {
11403                   genSetDPTR (0);
11404               }
11405               _flushLazyDPS ();
11406
11407               emitcode ("movx", "@dptr,a");
11408               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11409                   emitcode ("inc", "dptr");
11410           }
11411           _endLazyDPSEvaluation ();
11412       }
11413   }
11414
11415   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11416       if (!AOP_INDPTRn(result)) {
11417           _startLazyDPSEvaluation ();
11418
11419           aopPut (result,"dpl",0);
11420           aopPut (result,"dph",1);
11421           if (options.model == MODEL_FLAT24)
11422               aopPut (result,"dpx",2);
11423
11424           _endLazyDPSEvaluation ();
11425       }
11426       pi->generated=1;
11427   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11428              AOP_SIZE(right) > 1 &&
11429              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11430
11431       size = AOP_SIZE (right) - 1;
11432       if (AOP_INDPTRn(result)) {
11433           genSetDPTR(AOP(result)->aopu.dptr);
11434       }
11435       while (size--) emitcode ("lcall","__decdptr");
11436       if (AOP_INDPTRn(result)) {
11437           genSetDPTR(0);
11438       }
11439   }
11440   freeAsmop (result, NULL, ic, TRUE);
11441   freeAsmop (right, NULL, ic, TRUE);
11442 }
11443
11444 /*-----------------------------------------------------------------*/
11445 /* genGenPointerSet - set value from generic pointer space         */
11446 /*-----------------------------------------------------------------*/
11447 static void
11448 genGenPointerSet (operand * right,
11449                   operand * result, iCode * ic, iCode *pi)
11450 {
11451   int size, offset;
11452   bool pushedB;
11453   sym_link *retype = getSpec (operandType (right));
11454   sym_link *letype = getSpec (operandType (result));
11455
11456   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11457
11458   pushedB = pushB ();
11459   /* if the operand is already in dptr
11460      then we do nothing else we move the value to dptr */
11461   if (AOP_TYPE (result) != AOP_STR)
11462     {
11463       _startLazyDPSEvaluation ();
11464       /* if this is remateriazable */
11465       if (AOP_TYPE (result) == AOP_IMMD)
11466         {
11467           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11468           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11469           {
11470               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11471           }
11472           else
11473           {
11474               emitcode ("mov",
11475                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11476           }
11477         }
11478       else
11479         {                       /* we need to get it byte by byte */
11480           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11481           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11482           if (options.model == MODEL_FLAT24) {
11483             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11484             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11485           } else {
11486             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11487           }
11488         }
11489       _endLazyDPSEvaluation ();
11490     }
11491   /* so dptr + b now contains the address */
11492   aopOp (right, ic, FALSE, TRUE);
11493
11494   /* if bit then unpack */
11495   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11496     {
11497         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11498     }
11499   else
11500     {
11501         size = AOP_SIZE (right);
11502         offset = 0;
11503
11504         _startLazyDPSEvaluation ();
11505         while (size--)
11506         {
11507             if (size)
11508             {
11509                 // Set two bytes at a time, passed in _AP & A.
11510                 // dptr will be incremented ONCE by __gptrputWord.
11511                 //
11512                 // Note: any change here must be coordinated
11513                 // with the implementation of __gptrputWord
11514                 // in device/lib/_gptrput.c
11515                 emitcode("mov", "_ap, %s",
11516                          aopGet (right, offset++, FALSE, FALSE, NULL));
11517                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11518
11519                 genSetDPTR (0);
11520                 _flushLazyDPS ();
11521                 emitcode ("lcall", "__gptrputWord");
11522                 size--;
11523             }
11524             else
11525             {
11526                 // Only one byte to put.
11527                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11528
11529                 genSetDPTR (0);
11530                 _flushLazyDPS ();
11531                 emitcode ("lcall", "__gptrput");
11532             }
11533
11534             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11535             {
11536                 emitcode ("inc", "dptr");
11537             }
11538         }
11539         _endLazyDPSEvaluation ();
11540     }
11541
11542   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11543       _startLazyDPSEvaluation ();
11544
11545       aopPut (result, "dpl",0);
11546       aopPut (result, "dph",1);
11547       if (options.model == MODEL_FLAT24) {
11548           aopPut (result, "dpx",2);
11549           aopPut (result, "b",3);
11550       } else {
11551           aopPut (result, "b",2);
11552       }
11553       _endLazyDPSEvaluation ();
11554
11555       pi->generated=1;
11556   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11557              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11558
11559       size = AOP_SIZE (right) - 1;
11560       while (size--) emitcode ("lcall","__decdptr");
11561   }
11562   popB (pushedB);
11563
11564   freeAsmop (result, NULL, ic, TRUE);
11565   freeAsmop (right, NULL, ic, TRUE);
11566 }
11567
11568 /*-----------------------------------------------------------------*/
11569 /* genPointerSet - stores the value into a pointer location        */
11570 /*-----------------------------------------------------------------*/
11571 static void
11572 genPointerSet (iCode * ic, iCode *pi)
11573 {
11574   operand *right, *result;
11575   sym_link *type, *etype;
11576   int p_type;
11577
11578   D (emitcode (";", "genPointerSet"));
11579
11580   right = IC_RIGHT (ic);
11581   result = IC_RESULT (ic);
11582
11583   /* depending on the type of pointer we need to
11584      move it to the correct pointer register */
11585   type = operandType (result);
11586   etype = getSpec (type);
11587   /* if left is of type of pointer then it is simple */
11588   if (IS_PTR (type) && !IS_FUNC (type->next))
11589     {
11590       p_type = DCL_TYPE (type);
11591     }
11592   else
11593     {
11594       /* we have to go by the storage class */
11595       p_type = PTR_TYPE (SPEC_OCLS (etype));
11596     }
11597
11598   /* special case when cast remat */
11599   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11600       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11601           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11602           type = operandType (result);
11603           p_type = DCL_TYPE (type);
11604   }
11605
11606   /* now that we have the pointer type we assign
11607      the pointer values */
11608   switch (p_type)
11609     {
11610
11611     case POINTER:
11612     case IPOINTER:
11613       genNearPointerSet (right, result, ic, pi);
11614       break;
11615
11616     case PPOINTER:
11617       genPagedPointerSet (right, result, ic, pi);
11618       break;
11619
11620     case FPOINTER:
11621       genFarPointerSet (right, result, ic, pi);
11622       break;
11623
11624     case GPOINTER:
11625       genGenPointerSet (right, result, ic, pi);
11626       break;
11627
11628     default:
11629       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11630               "genPointerSet: illegal pointer type");
11631     }
11632 }
11633
11634 /*-----------------------------------------------------------------*/
11635 /* genIfx - generate code for Ifx statement                        */
11636 /*-----------------------------------------------------------------*/
11637 static void
11638 genIfx (iCode * ic, iCode * popIc)
11639 {
11640   operand *cond = IC_COND (ic);
11641   int isbit = 0;
11642   char *dup = NULL;
11643
11644   D (emitcode (";", "genIfx "));
11645
11646   aopOp (cond, ic, FALSE, FALSE);
11647
11648   /* get the value into acc */
11649   if (AOP_TYPE (cond) != AOP_CRY)
11650     {
11651         toBoolean (cond);
11652     }
11653   else
11654     {
11655         isbit = 1;
11656       if (AOP(cond)->aopu.aop_dir)
11657         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11658     }
11659
11660   /* the result is now in the accumulator or a directly addressable bit */
11661   freeAsmop (cond, NULL, ic, TRUE);
11662
11663   /* if there was something to be popped then do it */
11664   if (popIc)
11665     genIpop (popIc);
11666
11667   /* if the condition is  a bit variable */
11668   if (isbit && dup)
11669     {
11670         genIfxJump (ic, dup);
11671     }
11672   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11673     {
11674         genIfxJump (ic, SPIL_LOC (cond)->rname);
11675     }
11676   else if (isbit && !IS_ITEMP (cond))
11677     {
11678         genIfxJump (ic, OP_SYMBOL (cond)->rname);
11679     }
11680   else
11681     {
11682         genIfxJump (ic, "a");
11683     }
11684
11685   ic->generated = 1;
11686 }
11687
11688 /*-----------------------------------------------------------------*/
11689 /* genAddrOf - generates code for address of                       */
11690 /*-----------------------------------------------------------------*/
11691 static void
11692 genAddrOf (iCode * ic)
11693 {
11694   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11695   int size, offset;
11696
11697   D (emitcode (";", "genAddrOf"));
11698
11699   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11700
11701   /* if the operand is on the stack then we
11702      need to get the stack offset of this
11703      variable */
11704   if (sym->onStack)
11705   {
11706
11707       /* if 10 bit stack */
11708       if (options.stack10bit) {
11709           char buff[10];
11710           int  offset;
11711
11712           tsprintf(buff, sizeof(buff),
11713                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11714           /* if it has an offset then we need to compute it */
11715 /*        emitcode ("subb", "a,#!constbyte", */
11716 /*                  -((sym->stack < 0) ? */
11717 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11718 /*                    ((short) sym->stack)) & 0xff); */
11719 /*        emitcode ("mov","b,a"); */
11720 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11721 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11722 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11723           if (sym->stack) {
11724               emitcode ("mov", "a,_bpx");
11725               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11726                                              ((char) (sym->stack - _G.nRegsSaved)) :
11727                                              ((char) sym->stack )) & 0xff);
11728               emitcode ("mov", "b,a");
11729               emitcode ("mov", "a,_bpx+1");
11730
11731               offset = (((sym->stack < 0) ?
11732                          ((short) (sym->stack - _G.nRegsSaved)) :
11733                          ((short) sym->stack )) >> 8) & 0xff;
11734
11735               emitcode ("addc","a,#!constbyte", offset);
11736
11737               aopPut (IC_RESULT (ic), "b", 0);
11738               aopPut (IC_RESULT (ic), "a", 1);
11739               aopPut (IC_RESULT (ic), buff, 2);
11740           } else {
11741               /* we can just move _bp */
11742               aopPut (IC_RESULT (ic), "_bpx", 0);
11743               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11744               aopPut (IC_RESULT (ic), buff, 2);
11745           }
11746       } else {
11747           /* if it has an offset then we need to compute it */
11748           if (sym->stack)
11749             {
11750               emitcode ("mov", "a,_bp");
11751               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11752               aopPut (IC_RESULT (ic), "a", 0);
11753             }
11754           else
11755             {
11756               /* we can just move _bp */
11757               aopPut (IC_RESULT (ic), "_bp", 0);
11758             }
11759           /* fill the result with zero */
11760           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11761
11762
11763           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11764               fprintf (stderr,
11765                        "*** warning: pointer to stack var truncated.\n");
11766           }
11767
11768           offset = 1;
11769           while (size--)
11770             {
11771               aopPut (IC_RESULT (ic), zero, offset++);
11772           }
11773       }
11774       goto release;
11775   }
11776
11777   /* object not on stack then we need the name */
11778   size = AOP_SIZE (IC_RESULT (ic));
11779   offset = 0;
11780
11781   while (size--)
11782     {
11783       char s[SDCC_NAME_MAX];
11784       if (offset) {
11785           switch (offset) {
11786           case 1:
11787               tsprintf(s, sizeof(s), "#!his",sym->rname);
11788               break;
11789           case 2:
11790               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11791               break;
11792           case 3:
11793               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11794               break;
11795           default: /* should not need this (just in case) */
11796               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11797                        sym->rname,
11798                        offset * 8);
11799           }
11800       }
11801       else
11802       {
11803           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11804       }
11805
11806       aopPut (IC_RESULT (ic), s, offset++);
11807     }
11808
11809 release:
11810   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11811
11812 }
11813
11814 #if 0 // obsolete, and buggy for != xdata
11815 /*-----------------------------------------------------------------*/
11816 /* genArrayInit - generates code for address of                       */
11817 /*-----------------------------------------------------------------*/
11818 static void
11819 genArrayInit (iCode * ic)
11820 {
11821     literalList *iLoop;
11822     int         ix, count;
11823     int         elementSize = 0, eIndex;
11824     unsigned    val, lastVal;
11825     sym_link    *type;
11826     operand     *left=IC_LEFT(ic);
11827
11828     D (emitcode (";", "genArrayInit "););
11829
11830     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11831
11832     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11833     {
11834         // Load immediate value into DPTR.
11835         emitcode("mov", "dptr, %s",
11836              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11837     }
11838     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11839     {
11840 #if 0
11841       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11842               "Unexpected operand to genArrayInit.\n");
11843       exit(1);
11844 #else
11845       // a regression because of SDCCcse.c:1.52
11846       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11847       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11848       if (options.model == MODEL_FLAT24)
11849         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
11850 #endif
11851     }
11852
11853     type = operandType(IC_LEFT(ic));
11854
11855     if (type && type->next)
11856     {
11857         elementSize = getSize(type->next);
11858     }
11859     else
11860     {
11861         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11862                                 "can't determine element size in genArrayInit.\n");
11863         exit(1);
11864     }
11865
11866     iLoop = IC_ARRAYILIST(ic);
11867     lastVal = 0xffff;
11868
11869     while (iLoop)
11870     {
11871         bool firstpass = TRUE;
11872
11873         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
11874                  iLoop->count, (int)iLoop->literalValue, elementSize);
11875
11876         ix = iLoop->count;
11877
11878         while (ix)
11879         {
11880             symbol *tlbl = NULL;
11881
11882             count = ix > 256 ? 256 : ix;
11883
11884             if (count > 1)
11885             {
11886                 tlbl = newiTempLabel (NULL);
11887                 if (firstpass || (count & 0xff))
11888                 {
11889                     emitcode("mov", "b, #!constbyte", count & 0xff);
11890                 }
11891
11892                 emitcode ("", "!tlabeldef", tlbl->key + 100);
11893             }
11894
11895             firstpass = FALSE;
11896
11897             for (eIndex = 0; eIndex < elementSize; eIndex++)
11898             {
11899                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
11900                 if (val != lastVal)
11901                 {
11902                     emitcode("mov", "a, #!constbyte", val);
11903                     lastVal = val;
11904                 }
11905
11906                 emitcode("movx", "@dptr, a");
11907                 emitcode("inc", "dptr");
11908             }
11909
11910             if (count > 1)
11911             {
11912                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
11913             }
11914
11915             ix -= count;
11916         }
11917
11918         iLoop = iLoop->next;
11919     }
11920
11921     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
11922 }
11923 #endif
11924
11925 /*-----------------------------------------------------------------*/
11926 /* genFarFarAssign - assignment when both are in far space         */
11927 /*-----------------------------------------------------------------*/
11928 static void
11929 genFarFarAssign (operand * result, operand * right, iCode * ic)
11930 {
11931   int size = AOP_SIZE (right);
11932   int offset = 0;
11933   symbol *rSym = NULL;
11934
11935   if (size == 1)
11936   {
11937       /* quick & easy case. */
11938       D(emitcode(";","genFarFarAssign (1 byte case)"););
11939       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11940       freeAsmop (right, NULL, ic, FALSE);
11941       /* now assign DPTR to result */
11942       _G.accInUse++;
11943       aopOp(result, ic, FALSE, FALSE);
11944       _G.accInUse--;
11945       aopPut (result, "a", 0);
11946       freeAsmop(result, NULL, ic, FALSE);
11947       return;
11948   }
11949
11950   /* See if we've got an underlying symbol to abuse. */
11951   if (IS_SYMOP(result) && OP_SYMBOL(result))
11952   {
11953       if (IS_TRUE_SYMOP(result))
11954       {
11955           rSym = OP_SYMBOL(result);
11956       }
11957       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
11958       {
11959           rSym = OP_SYMBOL(result)->usl.spillLoc;
11960       }
11961   }
11962
11963   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
11964   {
11965       /* We can use the '390 auto-toggle feature to good effect here. */
11966
11967       D(emitcode(";","genFarFarAssign (390 auto-toggle fun)"););
11968       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
11969       emitcode ("mov", "dptr,#%s", rSym->rname);
11970       /* DP2 = result, DP1 = right, DP1 is current. */
11971       while (size)
11972       {
11973           emitcode("movx", "a,@dptr");
11974           emitcode("movx", "@dptr,a");
11975           if (--size)
11976           {
11977                emitcode("inc", "dptr");
11978                emitcode("inc", "dptr");
11979           }
11980       }
11981       emitcode("mov", "dps,#0");
11982       freeAsmop (right, NULL, ic, FALSE);
11983 #if 0
11984 some alternative code for processors without auto-toggle
11985 no time to test now, so later well put in...kpb
11986         D(emitcode(";","genFarFarAssign (dual-dptr fun)"););
11987         emitcode("mov", "dps,#1");      /* Select DPTR2. */
11988         emitcode ("mov", "dptr,#%s", rSym->rname);
11989         /* DP2 = result, DP1 = right, DP1 is current. */
11990         while (size)
11991         {
11992           --size;
11993           emitcode("movx", "a,@dptr");
11994           if (size)
11995             emitcode("inc", "dptr");
11996           emitcode("inc", "dps");
11997           emitcode("movx", "@dptr,a");
11998           if (size)
11999             emitcode("inc", "dptr");
12000           emitcode("inc", "dps");
12001         }
12002         emitcode("mov", "dps,#0");
12003         freeAsmop (right, NULL, ic, FALSE);
12004 #endif
12005   }
12006   else
12007   {
12008       D (emitcode (";", "genFarFarAssign"););
12009       aopOp (result, ic, TRUE, TRUE);
12010
12011       _startLazyDPSEvaluation ();
12012
12013       while (size--)
12014         {
12015           aopPut (result,
12016                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12017           offset++;
12018         }
12019       _endLazyDPSEvaluation ();
12020       freeAsmop (result, NULL, ic, FALSE);
12021       freeAsmop (right, NULL, ic, FALSE);
12022   }
12023 }
12024
12025 /*-----------------------------------------------------------------*/
12026 /* genAssign - generate code for assignment                        */
12027 /*-----------------------------------------------------------------*/
12028 static void
12029 genAssign (iCode * ic)
12030 {
12031   operand *result, *right;
12032   int size, offset;
12033   unsigned long lit = 0L;
12034
12035   D (emitcode (";", "genAssign "));
12036
12037   result = IC_RESULT (ic);
12038   right = IC_RIGHT (ic);
12039
12040   /* if they are the same */
12041   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12042     return;
12043
12044   aopOp (right, ic, FALSE, FALSE);
12045
12046   emitcode (";", "genAssign: resultIsFar = %s",
12047             isOperandInFarSpace (result) ?
12048             "TRUE" : "FALSE");
12049
12050   /* special case both in far space */
12051   if ((AOP_TYPE (right) == AOP_DPTR ||
12052        AOP_TYPE (right) == AOP_DPTR2) &&
12053   /* IS_TRUE_SYMOP(result)       && */
12054       isOperandInFarSpace (result))
12055     {
12056       genFarFarAssign (result, right, ic);
12057       return;
12058     }
12059
12060   aopOp (result, ic, TRUE, FALSE);
12061
12062   /* if they are the same registers */
12063   if (sameRegs (AOP (right), AOP (result)))
12064     goto release;
12065
12066   /* if the result is a bit */
12067   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12068     {
12069       /* if the right size is a literal then
12070          we know what the value is */
12071       if (AOP_TYPE (right) == AOP_LIT)
12072         {
12073           if (((int) operandLitValue (right)))
12074             aopPut (result, one, 0);
12075           else
12076             aopPut (result, zero, 0);
12077           goto release;
12078         }
12079
12080       /* the right is also a bit variable */
12081       if (AOP_TYPE (right) == AOP_CRY)
12082         {
12083           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12084           aopPut (result, "c", 0);
12085           goto release;
12086         }
12087
12088       /* we need to or */
12089       toBoolean (right);
12090       aopPut (result, "a", 0);
12091       goto release;
12092     }
12093
12094   /* bit variables done */
12095   /* general case */
12096   size = AOP_SIZE (result);
12097   offset = 0;
12098   if (AOP_TYPE (right) == AOP_LIT)
12099     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12100
12101   if ((size > 1) &&
12102       (AOP_TYPE (result) != AOP_REG) &&
12103       (AOP_TYPE (right) == AOP_LIT) &&
12104       !IS_FLOAT (operandType (right)))
12105     {
12106       _startLazyDPSEvaluation ();
12107       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12108         {
12109           aopPut (result,
12110                   aopGet (right, offset, FALSE, FALSE, NULL),
12111                   offset);
12112           offset++;
12113           size--;
12114         }
12115       /* And now fill the rest with zeros. */
12116       if (size)
12117         {
12118           emitcode ("clr", "a");
12119         }
12120       while (size--)
12121         {
12122           aopPut (result, "a", offset++);
12123         }
12124       _endLazyDPSEvaluation ();
12125     }
12126   else
12127     {
12128       _startLazyDPSEvaluation ();
12129       while (size--)
12130         {
12131           aopPut (result,
12132                   aopGet (right, offset, FALSE, FALSE, NULL),
12133                   offset);
12134           offset++;
12135         }
12136       _endLazyDPSEvaluation ();
12137     }
12138
12139 release:
12140   freeAsmop (result, NULL, ic, TRUE);
12141   freeAsmop (right, NULL, ic, TRUE);
12142 }
12143
12144 /*-----------------------------------------------------------------*/
12145 /* genJumpTab - generates code for jump table                      */
12146 /*-----------------------------------------------------------------*/
12147 static void
12148 genJumpTab (iCode * ic)
12149 {
12150   symbol *jtab;
12151   char *l;
12152
12153   D (emitcode (";", "genJumpTab ");
12154     );
12155
12156   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12157   /* get the condition into accumulator */
12158   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12159   MOVA (l);
12160   /* multiply by four! */
12161   emitcode ("add", "a,acc");
12162   emitcode ("add", "a,acc");
12163   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12164
12165   jtab = newiTempLabel (NULL);
12166   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12167   emitcode ("jmp", "@a+dptr");
12168   emitcode ("", "!tlabeldef", jtab->key + 100);
12169   /* now generate the jump labels */
12170   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12171        jtab = setNextItem (IC_JTLABELS (ic)))
12172     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12173
12174 }
12175
12176 /*-----------------------------------------------------------------*/
12177 /* genCast - gen code for casting                                  */
12178 /*-----------------------------------------------------------------*/
12179 static void
12180 genCast (iCode * ic)
12181 {
12182   operand *result = IC_RESULT (ic);
12183   sym_link *ctype = operandType (IC_LEFT (ic));
12184   sym_link *rtype = operandType (IC_RIGHT (ic));
12185   operand *right = IC_RIGHT (ic);
12186   int size, offset;
12187
12188   D (emitcode (";", "genCast "));
12189
12190   /* if they are equivalent then do nothing */
12191   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12192     return;
12193
12194   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12195   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12196
12197   /* if the result is a bit */
12198   if (IS_BITVAR (OP_SYMBOL (result)->type)
12199       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
12200     {
12201       /* if the right size is a literal then
12202          we know what the value is */
12203       if (AOP_TYPE (right) == AOP_LIT)
12204         {
12205           if (((int) operandLitValue (right)))
12206             aopPut (result, one, 0);
12207           else
12208             aopPut (result, zero, 0);
12209
12210           goto release;
12211         }
12212
12213       /* the right is also a bit variable */
12214       if (AOP_TYPE (right) == AOP_CRY)
12215         {
12216           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12217           aopPut (result, "c", 0);
12218           goto release;
12219         }
12220
12221       /* we need to or */
12222       toBoolean (right);
12223       aopPut (result, "a", 0);
12224       goto release;
12225     }
12226
12227   /* if they are the same size : or less */
12228   if (AOP_SIZE (result) <= AOP_SIZE (right))
12229     {
12230
12231       /* if they are in the same place */
12232       if (sameRegs (AOP (right), AOP (result)))
12233         goto release;
12234
12235       /* if they in different places then copy */
12236       size = AOP_SIZE (result);
12237       offset = 0;
12238       _startLazyDPSEvaluation ();
12239       while (size--)
12240         {
12241           aopPut (result,
12242                   aopGet (right, offset, FALSE, FALSE, NULL),
12243                   offset);
12244           offset++;
12245         }
12246       _endLazyDPSEvaluation ();
12247       goto release;
12248     }
12249
12250   /* if the result is of type pointer */
12251   if (IS_PTR (ctype))
12252     {
12253
12254       int p_type;
12255       sym_link *type = operandType (right);
12256
12257       /* pointer to generic pointer */
12258       if (IS_GENPTR (ctype))
12259         {
12260           if (IS_PTR (type))
12261             {
12262               p_type = DCL_TYPE (type);
12263             }
12264           else
12265             {
12266 #if OLD_CAST_BEHAVIOR
12267               /* KV: we are converting a non-pointer type to
12268                * a generic pointer. This (ifdef'd out) code
12269                * says that the resulting generic pointer
12270                * should have the same class as the storage
12271                * location of the non-pointer variable.
12272                *
12273                * For example, converting an int (which happens
12274                * to be stored in DATA space) to a pointer results
12275                * in a DATA generic pointer; if the original int
12276                * in XDATA space, so will be the resulting pointer.
12277                *
12278                * I don't like that behavior, and thus this change:
12279                * all such conversions will be forced to XDATA and
12280                * throw a warning. If you want some non-XDATA
12281                * type, or you want to suppress the warning, you
12282                * must go through an intermediate cast, like so:
12283                *
12284                * char _generic *gp = (char _xdata *)(intVar);
12285                */
12286               sym_link *etype = getSpec (type);
12287
12288               /* we have to go by the storage class */
12289               if (SPEC_OCLS (etype) != generic)
12290                 {
12291                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12292                 }
12293               else
12294 #endif
12295                 {
12296                   /* Converting unknown class (i.e. register variable)
12297                    * to generic pointer. This is not good, but
12298                    * we'll make a guess (and throw a warning).
12299                    */
12300                   p_type = FPOINTER;
12301                   werror (W_INT_TO_GEN_PTR_CAST);
12302                 }
12303             }
12304
12305           /* the first two bytes are known */
12306           size = GPTRSIZE - 1;
12307           offset = 0;
12308           _startLazyDPSEvaluation ();
12309           while (size--)
12310             {
12311               aopPut (result,
12312                       aopGet (right, offset, FALSE, FALSE, NULL),
12313                       offset);
12314               offset++;
12315             }
12316           _endLazyDPSEvaluation ();
12317
12318           /* the last byte depending on type */
12319             {
12320                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12321                 char gpValStr[10];
12322
12323                 if (gpVal == -1)
12324                 {
12325                     // pointerTypeToGPByte will have bitched.
12326                     exit(1);
12327                 }
12328
12329                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12330                 aopPut (result, gpValStr, GPTRSIZE - 1);
12331             }
12332           goto release;
12333         }
12334
12335       /* just copy the pointers */
12336       size = AOP_SIZE (result);
12337       offset = 0;
12338       _startLazyDPSEvaluation ();
12339       while (size--)
12340         {
12341           aopPut (result,
12342                   aopGet (right, offset, FALSE, FALSE, NULL),
12343                   offset);
12344           offset++;
12345         }
12346       _endLazyDPSEvaluation ();
12347       goto release;
12348     }
12349
12350   /* so we now know that the size of destination is greater
12351      than the size of the source */
12352   /* we move to result for the size of source */
12353   size = AOP_SIZE (right);
12354   offset = 0;
12355   _startLazyDPSEvaluation ();
12356   while (size--)
12357     {
12358       aopPut (result,
12359               aopGet (right, offset, FALSE, FALSE, NULL),
12360               offset);
12361       offset++;
12362     }
12363   _endLazyDPSEvaluation ();
12364
12365   /* now depending on the sign of the source && destination */
12366   size = AOP_SIZE (result) - AOP_SIZE (right);
12367   /* if unsigned or not an integral type */
12368   /* also, if the source is a bit, we don't need to sign extend, because
12369    * it can't possibly have set the sign bit.
12370    */
12371   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12372     {
12373       while (size--)
12374         {
12375           aopPut (result, zero, offset++);
12376         }
12377     }
12378   else
12379     {
12380       /* we need to extend the sign :{ */
12381       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12382                         FALSE, FALSE, NULL));
12383       emitcode ("rlc", "a");
12384       emitcode ("subb", "a,acc");
12385       while (size--)
12386         aopPut (result, "a", offset++);
12387     }
12388
12389   /* we are done hurray !!!! */
12390
12391 release:
12392   freeAsmop (right, NULL, ic, TRUE);
12393   freeAsmop (result, NULL, ic, TRUE);
12394
12395 }
12396
12397 /*-----------------------------------------------------------------*/
12398 /* genDjnz - generate decrement & jump if not zero instrucion      */
12399 /*-----------------------------------------------------------------*/
12400 static int
12401 genDjnz (iCode * ic, iCode * ifx)
12402 {
12403   symbol *lbl, *lbl1;
12404   if (!ifx)
12405     return 0;
12406
12407   /* if the if condition has a false label
12408      then we cannot save */
12409   if (IC_FALSE (ifx))
12410     return 0;
12411
12412   /* if the minus is not of the form
12413      a = a - 1 */
12414   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
12415       !IS_OP_LITERAL (IC_RIGHT (ic)))
12416     return 0;
12417
12418   if (operandLitValue (IC_RIGHT (ic)) != 1)
12419     return 0;
12420
12421   /* if the size of this greater than one then no
12422      saving */
12423   if (getSize (operandType (IC_RESULT (ic))) > 1)
12424     return 0;
12425
12426   /* otherwise we can save BIG */
12427   D(emitcode(";", "genDjnz"););
12428
12429   lbl = newiTempLabel (NULL);
12430   lbl1 = newiTempLabel (NULL);
12431
12432   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
12433
12434   if (AOP_NEEDSACC(IC_RESULT(ic)))
12435   {
12436       /* If the result is accessed indirectly via
12437        * the accumulator, we must explicitly write
12438        * it back after the decrement.
12439        */
12440       char *rByte = aopGet(IC_RESULT(ic), 0, FALSE, FALSE, NULL);
12441
12442       if (strcmp(rByte, "a"))
12443       {
12444            /* Something is hopelessly wrong */
12445            fprintf(stderr, "*** warning: internal error at %s:%d\n",
12446                    __FILE__, __LINE__);
12447            /* We can just give up; the generated code will be inefficient,
12448             * but what the hey.
12449             */
12450            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
12451            return 0;
12452       }
12453       emitcode ("dec", "%s", rByte);
12454       aopPut(IC_RESULT(ic), rByte, 0);
12455       emitcode ("jnz", "!tlabel", lbl->key + 100);
12456   }
12457   else if (IS_AOP_PREG (IC_RESULT (ic)))
12458     {
12459       emitcode ("dec", "%s",
12460                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
12461       emitcode ("mov", "a,%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
12462       emitcode ("jnz", "!tlabel", lbl->key + 100);
12463     }
12464   else
12465     {
12466       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
12467                 lbl->key + 100);
12468     }
12469   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
12470   emitcode ("", "!tlabeldef", lbl->key + 100);
12471   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
12472   emitcode ("", "!tlabeldef", lbl1->key + 100);
12473
12474   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
12475   ifx->generated = 1;
12476   return 1;
12477 }
12478
12479 /*-----------------------------------------------------------------*/
12480 /* genReceive - generate code for a receive iCode                  */
12481 /*-----------------------------------------------------------------*/
12482 static void
12483 genReceive (iCode * ic)
12484 {
12485     int size = getSize (operandType (IC_RESULT (ic)));
12486     int offset = 0;
12487     int rb1off ;
12488
12489     D (emitcode (";", "genReceive "));
12490
12491     if (ic->argreg == 1)
12492     {
12493         /* first parameter */
12494         if (AOP_IS_STR(IC_RESULT(ic)))
12495         {
12496             /* Nothing to do: it's already in the proper place. */
12497             return;
12498         }
12499         else
12500         {
12501             bool useDp2;
12502
12503             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
12504                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
12505                  IS_TRUE_SYMOP (IC_RESULT (ic)));
12506
12507             _G.accInUse++;
12508             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
12509             _G.accInUse--;
12510
12511             /* Sanity checking... */
12512             if (AOP_USESDPTR(IC_RESULT(ic)))
12513             {
12514                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12515                         "genReceive got unexpected DPTR.");
12516             }
12517             assignResultValue (IC_RESULT (ic), NULL);
12518         }
12519     }
12520     else if (ic->argreg > 12)
12521     { /* bit parameters */
12522       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
12523         {
12524           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
12525           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
12526           outBitC(IC_RESULT (ic));
12527         }
12528     }
12529     else
12530     {
12531         /* second receive onwards */
12532         /* this gets a little tricky since unused receives will be
12533          eliminated, we have saved the reg in the type field . and
12534          we use that to figure out which register to use */
12535         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
12536         rb1off = ic->argreg;
12537         while (size--)
12538         {
12539             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
12540         }
12541     }
12542     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
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         emitcode ("","!tlabeldef",lbl->key+100);
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         emitcode ("","!tlabeldef",lbl1->key+100);
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         emitcode ("","!tlabeldef",lbl->key+100);
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         emitcode ("","!tlabeldef",lbl1->key+100);
12776         emitcode ("clr","a");
12777         emitcode ("","!tlabeldef",lbl2->key+100);
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         emitcode ("","!tlabeldef",lbl->key+100);
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         emitcode ("","!tlabeldef",lbl->key+100);
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         emitcode ("","!tlabeldef",lbl1->key+100);
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         emitcode ("","!tlabeldef",lbl->key+100);
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         emitcode ("","!tlabeldef",lbl->key+100);
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         emitcode ("","!tlabeldef",lbl1->key+100);
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         emitcode ("","!tlabeldef",lbl->key+100);
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         emitcode ("","!tlabeldef",lbl->key+100);
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         emitcode ("","!tlabeldef",lbl1->key+100);
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         emitcode ("","!tlabeldef",lbl->key+100);
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         emitcode ("","!tlabeldef",lbl->key+100);
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 /* genDummyRead - generate code for dummy read of volatiles        */
13795 /*-----------------------------------------------------------------*/
13796 static void
13797 genDummyRead (iCode * ic)
13798 {
13799   operand *op;
13800   int size, offset;
13801
13802   D (emitcode(";", "genDummyRead"));
13803
13804   op = IC_RIGHT (ic);
13805   if (op && IS_SYMOP (op))
13806     {
13807       aopOp (op, ic, FALSE, FALSE);
13808
13809       /* if the result is a bit */
13810       if (AOP_TYPE (op) == AOP_CRY)
13811         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13812       else
13813         {
13814           /* bit variables done */
13815           /* general case */
13816           size = AOP_SIZE (op);
13817           offset = 0;
13818           while (size--)
13819           {
13820             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13821             offset++;
13822           }
13823         }
13824
13825       freeAsmop (op, NULL, ic, TRUE);
13826     }
13827
13828   op = IC_LEFT (ic);
13829   if (op && IS_SYMOP (op))
13830     {
13831       aopOp (op, ic, FALSE, FALSE);
13832
13833       /* if the result is a bit */
13834       if (AOP_TYPE (op) == AOP_CRY)
13835         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13836       else
13837         {
13838           /* bit variables done */
13839           /* general case */
13840           size = AOP_SIZE (op);
13841           offset = 0;
13842           while (size--)
13843           {
13844             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13845             offset++;
13846           }
13847         }
13848
13849       freeAsmop (op, NULL, ic, TRUE);
13850     }
13851 }
13852
13853 /*-----------------------------------------------------------------*/
13854 /* genCritical - generate code for start of a critical sequence    */
13855 /*-----------------------------------------------------------------*/
13856 static void
13857 genCritical (iCode *ic)
13858 {
13859   symbol *tlbl = newiTempLabel (NULL);
13860
13861   D (emitcode(";", "genCritical"));
13862
13863   if (IC_RESULT (ic))
13864     aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
13865
13866   emitcode ("setb", "c");
13867   emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
13868   emitcode ("clr", "c");
13869   emitcode ("", "%05d$:", (tlbl->key + 100));
13870
13871   if (IC_RESULT (ic))
13872     outBitC (IC_RESULT (ic)); /* save old ea in an operand */
13873   else
13874     emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
13875
13876   if (IC_RESULT (ic))
13877     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13878 }
13879
13880 /*-----------------------------------------------------------------*/
13881 /* genEndCritical - generate code for end of a critical sequence   */
13882 /*-----------------------------------------------------------------*/
13883 static void
13884 genEndCritical (iCode *ic)
13885 {
13886   D(emitcode(";     genEndCritical",""));
13887
13888   if (IC_RIGHT (ic))
13889     {
13890       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
13891       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
13892         {
13893           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
13894           emitcode ("mov", "ea,c");
13895         }
13896       else
13897         {
13898           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
13899           emitcode ("rrc", "a");
13900           emitcode ("mov", "ea,c");
13901         }
13902       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
13903     }
13904   else
13905     {
13906       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
13907       emitcode ("mov", "ea,c");
13908     }
13909 }
13910
13911
13912
13913 /*-----------------------------------------------------------------*/
13914 /* genBuiltIn - calls the appropriate function to  generating code */
13915 /* for a built in function                                         */
13916 /*-----------------------------------------------------------------*/
13917 static void genBuiltIn (iCode *ic)
13918 {
13919         operand *bi_parms[MAX_BUILTIN_ARGS];
13920         int nbi_parms;
13921         iCode *bi_iCode;
13922         symbol *bif;
13923
13924         /* get all the arguments for a built in function */
13925         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
13926
13927         /* which function is it */
13928         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
13929         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
13930                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
13931         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
13932                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
13933         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
13934                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
13935         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
13936                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
13937         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
13938                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
13939         } else if (strcmp(bif->name,"__builtin_inp")==0) {
13940                 genInp(bi_iCode,nbi_parms,bi_parms);
13941         } else if (strcmp(bif->name,"__builtin_outp")==0) {
13942                 genOutp(bi_iCode,nbi_parms,bi_parms);
13943         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
13944                 genSwapW(bi_iCode,nbi_parms,bi_parms);
13945                 /* JavaNative builtIns */
13946         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
13947                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
13948         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
13949                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
13950         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
13951                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
13952         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
13953                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
13954         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
13955                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13956         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
13957                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13958         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
13959                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
13960         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
13961                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
13962         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
13963                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13964         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
13965                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13966         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
13967                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
13968         } else if (strcmp(bif->name,"MM_Malloc")==0) {
13969                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
13970         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
13971                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
13972         } else if (strcmp(bif->name,"MM_Free")==0) {
13973                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
13974         } else if (strcmp(bif->name,"MM_Deref")==0) {
13975                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
13976         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
13977                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
13978         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
13979                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
13980         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
13981                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
13982         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
13983                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
13984         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
13985                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
13986         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
13987                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
13988         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
13989                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
13990         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
13991                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
13992         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
13993                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13994         } else if (strcmp(bif->name,"System_SaveThread")==0) {
13995                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13996         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
13997                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13998         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
13999                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14000         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14001                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14002         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14003                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14004         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14005                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14006         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14007                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14008         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14009                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14010         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14011                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14012         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14013                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14014         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14015                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14016         } else {
14017                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14018                 return ;
14019         }
14020         return ;
14021 }
14022
14023 /*-----------------------------------------------------------------*/
14024 /* gen390Code - generate code for Dallas 390 based controllers     */
14025 /*-----------------------------------------------------------------*/
14026 void
14027 gen390Code (iCode * lic)
14028 {
14029   iCode *ic;
14030   int cln = 0;
14031
14032   _G.currentFunc = NULL;
14033   lineHead = lineCurr = NULL;
14034   dptrn[1][0] = "dpl1";
14035   dptrn[1][1] = "dph1";
14036   dptrn[1][2] = "dpx1";
14037
14038   if (options.model == MODEL_FLAT24) {
14039     fReturnSizeDS390 = 5;
14040     fReturn = fReturn24;
14041   } else {
14042     fReturnSizeDS390 = 4;
14043     fReturn = fReturn16;
14044     options.stack10bit=0;
14045   }
14046 #if 1
14047   /* print the allocation information */
14048   if (allocInfo && currFunc)
14049     printAllocInfo (currFunc, codeOutFile);
14050 #endif
14051   /* if debug information required */
14052   if (options.debug && currFunc)
14053     {
14054       debugFile->writeFunction (currFunc, lic);
14055     }
14056   /* stack pointer name */
14057   if (options.useXstack)
14058     spname = "_spx";
14059   else
14060     spname = "sp";
14061
14062
14063   for (ic = lic; ic; ic = ic->next)
14064     {
14065       _G.current_iCode = ic;
14066
14067       if (ic->lineno && cln != ic->lineno)
14068         {
14069           if (options.debug)
14070             {
14071               debugFile->writeCLine (ic);
14072             }
14073           if (!options.noCcodeInAsm) {
14074             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14075                       printCLine(ic->filename, ic->lineno));
14076           }
14077           cln = ic->lineno;
14078         }
14079       if (options.iCodeInAsm) {
14080         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
14081       }
14082       /* if the result is marked as
14083          spilt and rematerializable or code for
14084          this has already been generated then
14085          do nothing */
14086       if (resultRemat (ic) || ic->generated)
14087         continue;
14088
14089       /* depending on the operation */
14090       switch (ic->op)
14091         {
14092         case '!':
14093           genNot (ic);
14094           break;
14095
14096         case '~':
14097           genCpl (ic);
14098           break;
14099
14100         case UNARYMINUS:
14101           genUminus (ic);
14102           break;
14103
14104         case IPUSH:
14105           genIpush (ic);
14106           break;
14107
14108         case IPOP:
14109           /* IPOP happens only when trying to restore a
14110              spilt live range, if there is an ifx statement
14111              following this pop then the if statement might
14112              be using some of the registers being popped which
14113              would destory the contents of the register so
14114              we need to check for this condition and handle it */
14115           if (ic->next &&
14116               ic->next->op == IFX &&
14117               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14118             genIfx (ic->next, ic);
14119           else
14120             genIpop (ic);
14121           break;
14122
14123         case CALL:
14124           genCall (ic);
14125           break;
14126
14127         case PCALL:
14128           genPcall (ic);
14129           break;
14130
14131         case FUNCTION:
14132           genFunction (ic);
14133           break;
14134
14135         case ENDFUNCTION:
14136           genEndFunction (ic);
14137           break;
14138
14139         case RETURN:
14140           genRet (ic);
14141           break;
14142
14143         case LABEL:
14144           genLabel (ic);
14145           break;
14146
14147         case GOTO:
14148           genGoto (ic);
14149           break;
14150
14151         case '+':
14152           genPlus (ic);
14153           break;
14154
14155         case '-':
14156           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14157             genMinus (ic);
14158           break;
14159
14160         case '*':
14161           genMult (ic);
14162           break;
14163
14164         case '/':
14165           genDiv (ic);
14166           break;
14167
14168         case '%':
14169           genMod (ic);
14170           break;
14171
14172         case '>':
14173           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14174           break;
14175
14176         case '<':
14177           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14178           break;
14179
14180         case LE_OP:
14181         case GE_OP:
14182         case NE_OP:
14183
14184           /* note these two are xlated by algebraic equivalence
14185              during parsing SDCC.y */
14186           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14187                   "got '>=' or '<=' shouldn't have come here");
14188           break;
14189
14190         case EQ_OP:
14191           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14192           break;
14193
14194         case AND_OP:
14195           genAndOp (ic);
14196           break;
14197
14198         case OR_OP:
14199           genOrOp (ic);
14200           break;
14201
14202         case '^':
14203           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14204           break;
14205
14206         case '|':
14207           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14208           break;
14209
14210         case BITWISEAND:
14211           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14212           break;
14213
14214         case INLINEASM:
14215           genInline (ic);
14216           break;
14217
14218         case RRC:
14219           genRRC (ic);
14220           break;
14221
14222         case RLC:
14223           genRLC (ic);
14224           break;
14225
14226         case GETHBIT:
14227           genGetHbit (ic);
14228           break;
14229
14230         case LEFT_OP:
14231           genLeftShift (ic);
14232           break;
14233
14234         case RIGHT_OP:
14235           genRightShift (ic);
14236           break;
14237
14238         case GET_VALUE_AT_ADDRESS:
14239           genPointerGet (ic,hasInc(IC_LEFT(ic),ic, getSize(operandType(IC_RESULT(ic)))));
14240           break;
14241
14242         case '=':
14243           if (POINTER_SET (ic))
14244             genPointerSet (ic,hasInc(IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
14245           else
14246             genAssign (ic);
14247           break;
14248
14249         case IFX:
14250           genIfx (ic, NULL);
14251           break;
14252
14253         case ADDRESS_OF:
14254           genAddrOf (ic);
14255           break;
14256
14257         case JUMPTABLE:
14258           genJumpTab (ic);
14259           break;
14260
14261         case CAST:
14262           genCast (ic);
14263           break;
14264
14265         case RECEIVE:
14266           genReceive (ic);
14267           break;
14268
14269         case SEND:
14270           if (ic->builtinSEND)
14271             genBuiltIn(ic);
14272           else
14273             addSet (&_G.sendSet, ic);
14274           break;
14275
14276         case DUMMY_READ_VOLATILE:
14277           genDummyRead (ic);
14278           break;
14279
14280         case CRITICAL:
14281           genCritical (ic);
14282           break;
14283
14284         case ENDCRITICAL:
14285           genEndCritical (ic);
14286           break;
14287
14288         case SWAP:
14289           genSwap (ic);
14290           break;
14291
14292 #if 0 // obsolete, and buggy for != xdata
14293         case ARRAYINIT:
14294             genArrayInit(ic);
14295             break;
14296 #endif
14297
14298         default:
14299           ic = ic;
14300         }
14301     }
14302
14303
14304   /* now we are ready to call the
14305      peep hole optimizer */
14306   if (!options.nopeep)
14307     peepHole (&lineHead);
14308
14309   /* now do the actual printing */
14310   printLine (lineHead, codeOutFile);
14311   return;
14312 }