* doc/sdccman.lyx: documented numeric ranges, WEBDOC #1442369
[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           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1209             {
1210               /* force a new aop if sizes differ */
1211               sym->usl.spillLoc->aop = NULL;
1212             }
1213           sym->aop = op->aop = aop =
1214                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1215           aop->size = getSize (sym->type);
1216           return;
1217         }
1218
1219       /* else must be a dummy iTemp */
1220       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1221       aop->size = getSize (sym->type);
1222       return;
1223     }
1224
1225   /* if the type is a bit register */
1226   if (sym->regType == REG_BIT)
1227     {
1228       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1229       aop->size = sym->nRegs;//1???
1230       aop->aopu.aop_reg[0] = sym->regs[0];
1231       aop->aopu.aop_dir = sym->regs[0]->name;
1232       return;
1233     }
1234
1235   /* must be in a register */
1236   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1237   aop->size = sym->nRegs;
1238   for (i = 0; i < sym->nRegs; i++)
1239     aop->aopu.aop_reg[i] = sym->regs[i];
1240 }
1241
1242 /*-----------------------------------------------------------------*/
1243 /* freeAsmop - free up the asmop given to an operand               */
1244 /*----------------------------------------------------------------*/
1245 static void
1246 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1247 {
1248   asmop *aop;
1249
1250   if (!op)
1251     aop = aaop;
1252   else
1253     aop = op->aop;
1254
1255   if (!aop)
1256     return;
1257
1258   aop->allocated--;
1259
1260   if (aop->allocated)
1261     goto dealloc;
1262
1263   /* depending on the asmop type only three cases need work
1264      AOP_R0, AOP_R1 & AOP_STK */
1265   switch (aop->type)
1266     {
1267     case AOP_R0:
1268       if (_G.r0Pushed)
1269         {
1270           if (pop)
1271             {
1272               emitcode ("pop", "ar0");
1273               _G.r0Pushed--;
1274             }
1275         }
1276       bitVectUnSetBit (ic->rUsed, R0_IDX);
1277       break;
1278
1279     case AOP_R1:
1280       if (_G.r1Pushed)
1281         {
1282           if (pop)
1283             {
1284               emitcode ("pop", "ar1");
1285               _G.r1Pushed--;
1286             }
1287         }
1288       bitVectUnSetBit (ic->rUsed, R1_IDX);
1289       break;
1290
1291     case AOP_STK:
1292       {
1293         int sz = aop->size;
1294         int stk = aop->aopu.aop_stk + aop->size;
1295         bitVectUnSetBit (ic->rUsed, R0_IDX);
1296         bitVectUnSetBit (ic->rUsed, R1_IDX);
1297
1298         getFreePtr (ic, &aop, FALSE);
1299
1300         if (options.stack10bit)
1301           {
1302             /* I'm not sure what to do here yet... */
1303             /* #STUB */
1304             fprintf (stderr,
1305                      "*** Warning: probably generating bad code for "
1306                      "10 bit stack mode.\n");
1307           }
1308
1309         if (stk)
1310           {
1311             emitcode ("mov", "a,_bp");
1312             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1313             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1314           }
1315         else
1316           {
1317             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1318           }
1319
1320         while (sz--)
1321           {
1322             emitcode ("pop", "acc");
1323             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1324             if (!sz)
1325               break;
1326             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1327           }
1328         op->aop = aop;
1329         freeAsmop (op, NULL, ic, TRUE);
1330         if (_G.r1Pushed)
1331           {
1332             emitcode ("pop", "ar1");
1333             _G.r1Pushed--;
1334           }
1335         if (_G.r0Pushed)
1336           {
1337             emitcode ("pop", "ar0");
1338             _G.r0Pushed--;
1339           }
1340       }
1341     case AOP_DPTR2:
1342         if (_G.dptr1InUse) {
1343             emitcode ("pop","dpx1");
1344             emitcode ("pop","dph1");
1345             emitcode ("pop","dpl1");
1346         }
1347         break;
1348     case AOP_DPTR:
1349         if (_G.dptrInUse) {
1350             emitcode ("pop","dpx");
1351             emitcode ("pop","dph");
1352             emitcode ("pop","dpl");
1353         }
1354         break;
1355     }
1356
1357 dealloc:
1358   /* all other cases just dealloc */
1359   if (op)
1360     {
1361       op->aop = NULL;
1362       if (IS_SYMOP (op))
1363         {
1364           OP_SYMBOL (op)->aop = NULL;
1365           /* if the symbol has a spill */
1366           if (SPIL_LOC (op))
1367             SPIL_LOC (op)->aop = NULL;
1368         }
1369     }
1370 }
1371
1372 #define DEFAULT_ACC_WARNING 0
1373 static int saveAccWarn = DEFAULT_ACC_WARNING;
1374
1375
1376 /*-----------------------------------------------------------------*/
1377 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1378 /*                 clobber the accumulator                         */
1379 /*-----------------------------------------------------------------*/
1380 static bool
1381 aopGetUsesAcc (operand * oper, int offset)
1382 {
1383   asmop * aop = AOP (oper);
1384
1385   if (offset > (aop->size - 1))
1386     return FALSE;
1387
1388   switch (aop->type)
1389     {
1390
1391     case AOP_R0:
1392     case AOP_R1:
1393       if (aop->paged)
1394         return TRUE;
1395       return FALSE;
1396     case AOP_DPTR:
1397       return TRUE;
1398     case AOP_IMMD:
1399       return FALSE;
1400     case AOP_DIR:
1401       return FALSE;
1402     case AOP_REG:
1403       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1404       return FALSE;
1405     case AOP_CRY:
1406       return TRUE;
1407     case AOP_ACC:
1408       if (offset)
1409         return FALSE;
1410       return TRUE;
1411     case AOP_LIT:
1412       return FALSE;
1413     case AOP_STR:
1414       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1415         return TRUE;
1416       return FALSE;
1417     case AOP_DUMMY:
1418       return FALSE;
1419     default:
1420       /* Error case --- will have been caught already */
1421       wassert(0);
1422       return FALSE;
1423     }
1424 }
1425
1426 /*-------------------------------------------------------------------*/
1427 /* aopGet - for fetching value of the aop                            */
1428 /*                                                                   */
1429 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1430 /* in the accumulator. Set it to the name of a free register         */
1431 /* if acc must be preserved; the register will be used to preserve   */
1432 /* acc temporarily and to return the result byte.                    */
1433 /*-------------------------------------------------------------------*/
1434 static char *
1435 aopGet (operand * oper,
1436         int   offset,
1437         bool  bit16,
1438         bool  dname,
1439         char  *saveAcc)
1440 {
1441   asmop * aop = AOP (oper);
1442
1443   /* offset is greater than
1444      size then zero */
1445   if (offset > (aop->size - 1) &&
1446       aop->type != AOP_LIT)
1447     return zero;
1448
1449   /* depending on type */
1450   switch (aop->type)
1451     {
1452     case AOP_DUMMY:
1453       return zero;
1454
1455     case AOP_R0:
1456     case AOP_R1:
1457       /* if we need to increment it */
1458       while (offset > aop->coff)
1459         {
1460           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1461           aop->coff++;
1462         }
1463
1464       while (offset < aop->coff)
1465         {
1466           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1467           aop->coff--;
1468         }
1469
1470       aop->coff = offset;
1471       if (aop->paged)
1472         {
1473           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1474           return (dname ? "acc" : "a");
1475         }
1476       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1477       return Safe_strdup(buffer);
1478
1479     case AOP_DPTRn:
1480         assert(offset <= 3);
1481         return dptrn[aop->aopu.dptr][offset];
1482
1483     case AOP_DPTR:
1484     case AOP_DPTR2:
1485
1486       if (aop->type == AOP_DPTR2)
1487         {
1488           genSetDPTR (1);
1489         }
1490
1491       if (saveAcc)
1492         {
1493             TR_AP("#1");
1494 //          if (aop->type != AOP_DPTR2)
1495 //          {
1496 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1497 //              emitcode(";", "spanky: saveAcc for DPTR");
1498 //          }
1499
1500             emitcode ("xch", "a, %s", saveAcc);
1501         }
1502
1503       _flushLazyDPS ();
1504
1505       while (offset > aop->coff)
1506         {
1507           emitcode ("inc", "dptr");
1508           aop->coff++;
1509         }
1510
1511       while (offset < aop->coff)
1512         {
1513           emitcode ("lcall", "__decdptr");
1514           aop->coff--;
1515         }
1516
1517       aop->coff = offset;
1518       if (aop->code)
1519         {
1520           emitcode ("clr", "a");
1521           emitcode ("movc", "a,@a+dptr");
1522         }
1523       else
1524         {
1525           emitcode ("movx", "a,@dptr");
1526         }
1527
1528       if (aop->type == AOP_DPTR2)
1529         {
1530           genSetDPTR (0);
1531         }
1532
1533         if (saveAcc)
1534         {
1535        TR_AP("#2");
1536               emitcode ("xch", "a, %s", saveAcc);
1537 //            if (strcmp(saveAcc, "_ap"))
1538 //            {
1539 //                emitcode(";", "spiffy: non _ap return from aopGet.");
1540 //            }
1541
1542               return saveAcc;
1543         }
1544       return (dname ? "acc" : "a");
1545
1546     case AOP_IMMD:
1547       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1548       {
1549           SNPRINTF(buffer, sizeof(buffer),
1550                    "%s",aop->aopu.aop_immd.aop_immd2);
1551       }
1552       else if (bit16)
1553       {
1554          SNPRINTF(buffer, sizeof(buffer),
1555                   "#%s", aop->aopu.aop_immd.aop_immd1);
1556       }
1557       else if (offset)
1558       {
1559           switch (offset) {
1560           case 1:
1561               tsprintf(buffer, sizeof(buffer),
1562                        "#!his",aop->aopu.aop_immd.aop_immd1);
1563               break;
1564           case 2:
1565               tsprintf(buffer, sizeof(buffer),
1566                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1567               break;
1568           case 3:
1569               tsprintf(buffer, sizeof(buffer),
1570                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1571               break;
1572           default: /* should not need this (just in case) */
1573               SNPRINTF (buffer, sizeof(buffer),
1574                         "#(%s >> %d)",
1575                        aop->aopu.aop_immd.aop_immd1,
1576                        offset * 8);
1577           }
1578       }
1579       else
1580       {
1581         SNPRINTF (buffer, sizeof(buffer),
1582                   "#%s", aop->aopu.aop_immd.aop_immd1);
1583       }
1584       return Safe_strdup(buffer);
1585
1586     case AOP_DIR:
1587       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1588         {
1589           SNPRINTF (buffer, sizeof(buffer),
1590                     "(%s >> %d)",
1591                     aop->aopu.aop_dir, offset * 8);
1592         }
1593       else if (offset)
1594         {
1595           SNPRINTF (buffer, sizeof(buffer),
1596                     "(%s + %d)",
1597                    aop->aopu.aop_dir,
1598                    offset);
1599         }
1600       else
1601         {
1602           SNPRINTF (buffer, sizeof(buffer),
1603                    "%s", aop->aopu.aop_dir);
1604         }
1605
1606       return Safe_strdup(buffer);
1607
1608     case AOP_REG:
1609       if (dname)
1610         return aop->aopu.aop_reg[offset]->dname;
1611       else
1612         return aop->aopu.aop_reg[offset]->name;
1613
1614     case AOP_CRY:
1615       emitcode ("clr", "a");
1616       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1617       emitcode ("rlc", "a");
1618       return (dname ? "acc" : "a");
1619
1620     case AOP_ACC:
1621       if (!offset && dname)
1622         return "acc";
1623       return aop->aopu.aop_str[offset];
1624
1625     case AOP_LIT:
1626       return aopLiteral (aop->aopu.aop_lit, offset);
1627
1628     case AOP_STR:
1629       aop->coff = offset;
1630       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1631           dname)
1632         return "acc";
1633
1634       return aop->aopu.aop_str[offset];
1635
1636     }
1637
1638   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1639           "aopget got unsupported aop->type");
1640   exit (1);
1641
1642   return NULL;  // not reached, but makes compiler happy.
1643 }
1644
1645 /*-----------------------------------------------------------------*/
1646 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1647 /*                 clobber the accumulator                         */
1648 /*-----------------------------------------------------------------*/
1649 static bool
1650 aopPutUsesAcc (operand * oper, const char *s, int offset)
1651 {
1652   asmop * aop = AOP (oper);
1653
1654   if (offset > (aop->size - 1))
1655     return FALSE;
1656
1657   switch (aop->type)
1658     {
1659     case AOP_DUMMY:
1660       return TRUE;
1661     case AOP_DIR:
1662       return FALSE;
1663     case AOP_REG:
1664       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1665       return FALSE;
1666     case AOP_DPTR:
1667       return TRUE;
1668     case AOP_R0:
1669     case AOP_R1:
1670       return ((aop->paged) || (*s == '@'));
1671     case AOP_STK:
1672       return (*s == '@');
1673     case AOP_CRY:
1674       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1675     case AOP_STR:
1676       return FALSE;
1677     case AOP_IMMD:
1678       return FALSE;
1679     case AOP_ACC:
1680       return FALSE;
1681     default:
1682       /* Error case --- will have been caught already */
1683       wassert(0);
1684       return FALSE;
1685     }
1686 }
1687
1688 /*-----------------------------------------------------------------*/
1689 /* aopPut - puts a string for a aop and indicates if acc is in use */
1690 /*-----------------------------------------------------------------*/
1691 static bool
1692 aopPut (operand * result, const char *s, int offset)
1693 {
1694   bool bvolatile = isOperandVolatile (result, FALSE);
1695   bool accuse = FALSE;
1696   asmop * aop = AOP (result);
1697
1698   if (aop->size && offset > (aop->size - 1))
1699     {
1700       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1701               "aopPut got offset > aop->size");
1702       exit (1);
1703     }
1704
1705   /* will assign value to value */
1706   /* depending on where it is ofcourse */
1707   switch (aop->type)
1708     {
1709     case AOP_DUMMY:
1710       MOVA (s);         /* read s in case it was volatile */
1711       accuse = TRUE;
1712       break;
1713
1714     case AOP_DIR:
1715       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1716         {
1717           SNPRINTF (buffer, sizeof(buffer),
1718                     "(%s >> %d)",
1719                     aop->aopu.aop_dir, offset * 8);
1720         }
1721       else if (offset)
1722         {
1723             SNPRINTF (buffer, sizeof(buffer),
1724                       "(%s + %d)",
1725                       aop->aopu.aop_dir, offset);
1726         }
1727       else
1728         {
1729             SNPRINTF (buffer, sizeof(buffer),
1730                      "%s", aop->aopu.aop_dir);
1731         }
1732
1733       if (strcmp (buffer, s) || bvolatile)
1734         {
1735             emitcode ("mov", "%s,%s", buffer, s);
1736         }
1737       if (!strcmp (buffer, "acc"))
1738         {
1739           accuse = TRUE;
1740         }
1741       break;
1742
1743     case AOP_REG:
1744       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1745           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1746         {
1747           if (*s == '@' ||
1748               strcmp (s, "r0") == 0 ||
1749               strcmp (s, "r1") == 0 ||
1750               strcmp (s, "r2") == 0 ||
1751               strcmp (s, "r3") == 0 ||
1752               strcmp (s, "r4") == 0 ||
1753               strcmp (s, "r5") == 0 ||
1754               strcmp (s, "r6") == 0 ||
1755               strcmp (s, "r7") == 0)
1756             {
1757                 emitcode ("mov", "%s,%s",
1758                           aop->aopu.aop_reg[offset]->dname, s);
1759             }
1760             else
1761             {
1762                 emitcode ("mov", "%s,%s",
1763                           aop->aopu.aop_reg[offset]->name, s);
1764             }
1765         }
1766       break;
1767
1768     case AOP_DPTRn:
1769         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1770         break;
1771
1772     case AOP_DPTR:
1773     case AOP_DPTR2:
1774
1775       if (aop->type == AOP_DPTR2)
1776         {
1777           genSetDPTR (1);
1778         }
1779       _flushLazyDPS ();
1780
1781       if (aop->code)
1782         {
1783           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1784                   "aopPut writing to code space");
1785           exit (1);
1786         }
1787
1788       while (offset > aop->coff)
1789         {
1790           aop->coff++;
1791           emitcode ("inc", "dptr");
1792         }
1793
1794       while (offset < aop->coff)
1795         {
1796           aop->coff--;
1797           emitcode ("lcall", "__decdptr");
1798         }
1799
1800       aop->coff = offset;
1801
1802       /* if not in accumulator */
1803       MOVA (s);
1804
1805       emitcode ("movx", "@dptr,a");
1806
1807       if (aop->type == AOP_DPTR2)
1808         {
1809           genSetDPTR (0);
1810         }
1811       break;
1812
1813     case AOP_R0:
1814     case AOP_R1:
1815       while (offset > aop->coff)
1816         {
1817           aop->coff++;
1818           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1819         }
1820       while (offset < aop->coff)
1821         {
1822           aop->coff--;
1823           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1824         }
1825       aop->coff = offset;
1826
1827       if (aop->paged)
1828         {
1829           MOVA (s);
1830           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1831         }
1832       else if (*s == '@')
1833         {
1834           MOVA (s);
1835           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1836         }
1837       else if (strcmp (s, "r0") == 0 ||
1838                strcmp (s, "r1") == 0 ||
1839                strcmp (s, "r2") == 0 ||
1840                strcmp (s, "r3") == 0 ||
1841                strcmp (s, "r4") == 0 ||
1842                strcmp (s, "r5") == 0 ||
1843                strcmp (s, "r6") == 0 ||
1844                strcmp (s, "r7") == 0)
1845         {
1846           char buffer[10];
1847           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1848           emitcode ("mov", "@%s,%s",
1849                     aop->aopu.aop_ptr->name, buffer);
1850         }
1851         else
1852         {
1853             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1854         }
1855       break;
1856
1857     case AOP_STK:
1858       if (strcmp (s, "a") == 0)
1859         emitcode ("push", "acc");
1860       else
1861         if (*s=='@') {
1862           MOVA(s);
1863           emitcode ("push", "acc");
1864         } else {
1865           emitcode ("push", s);
1866         }
1867
1868       break;
1869
1870     case AOP_CRY:
1871       /* if not bit variable */
1872       if (!aop->aopu.aop_dir)
1873         {
1874           /* inefficient: move carry into A and use jz/jnz */
1875           emitcode ("clr", "a");
1876           emitcode ("rlc", "a");
1877           accuse = TRUE;
1878         }
1879       else
1880         {
1881           if (s == zero)
1882             emitcode ("clr", "%s", aop->aopu.aop_dir);
1883           else if (s == one)
1884             emitcode ("setb", "%s", aop->aopu.aop_dir);
1885           else if (!strcmp (s, "c"))
1886             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1887           else if (strcmp (s, aop->aopu.aop_dir))
1888             {
1889                   MOVA (s);
1890                 /* set C, if a >= 1 */
1891                 emitcode ("add", "a,#!constbyte",0xff);
1892                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1893               }
1894             }
1895       break;
1896
1897     case AOP_STR:
1898       aop->coff = offset;
1899       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1900         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1901       break;
1902
1903     case AOP_ACC:
1904       accuse = TRUE;
1905       aop->coff = offset;
1906       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1907         break;
1908
1909       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1910         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1911       break;
1912
1913     default:
1914       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1915               "aopPut got unsupported aop->type");
1916       exit (1);
1917     }
1918
1919     return accuse;
1920 }
1921
1922
1923 /*--------------------------------------------------------------------*/
1924 /* reAdjustPreg - points a register back to where it should (coff==0) */
1925 /*--------------------------------------------------------------------*/
1926 static void
1927 reAdjustPreg (asmop * aop)
1928 {
1929   if ((aop->coff==0) || (aop->size <= 1))
1930     return;
1931
1932   switch (aop->type)
1933     {
1934     case AOP_R0:
1935     case AOP_R1:
1936       while (aop->coff--)
1937         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1938       break;
1939     case AOP_DPTR:
1940     case AOP_DPTR2:
1941       if (aop->type == AOP_DPTR2)
1942         {
1943           genSetDPTR (1);
1944           _flushLazyDPS ();
1945         }
1946       while (aop->coff--)
1947         {
1948           emitcode ("lcall", "__decdptr");
1949         }
1950
1951       if (aop->type == AOP_DPTR2)
1952         {
1953           genSetDPTR (0);
1954         }
1955       break;
1956     }
1957   aop->coff = 0;
1958 }
1959
1960 /*-----------------------------------------------------------------*/
1961 /* opIsGptr: returns non-zero if the passed operand is       */
1962 /* a generic pointer type.             */
1963 /*-----------------------------------------------------------------*/
1964 static int
1965 opIsGptr (operand * op)
1966 {
1967   sym_link *type = operandType (op);
1968
1969   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1970     {
1971       return 1;
1972     }
1973   return 0;
1974 }
1975
1976 /*-----------------------------------------------------------------*/
1977 /* getDataSize - get the operand data size                         */
1978 /*-----------------------------------------------------------------*/
1979 static int
1980 getDataSize (operand * op)
1981 {
1982   int size;
1983   size = AOP_SIZE (op);
1984   if (size == GPTRSIZE)
1985     {
1986       sym_link *type = operandType (op);
1987       if (IS_GENPTR (type))
1988         {
1989           /* generic pointer; arithmetic operations
1990            * should ignore the high byte (pointer type).
1991            */
1992           size--;
1993         }
1994     }
1995   return size;
1996 }
1997
1998 /*-----------------------------------------------------------------*/
1999 /* outAcc - output Acc                                             */
2000 /*-----------------------------------------------------------------*/
2001 static void
2002 outAcc (operand * result)
2003 {
2004   int size, offset;
2005   size = getDataSize (result);
2006   if (size)
2007     {
2008       aopPut (result, "a", 0);
2009       size--;
2010       offset = 1;
2011       /* unsigned or positive */
2012       while (size--)
2013         {
2014           aopPut (result, zero, offset++);
2015         }
2016     }
2017 }
2018
2019 /*-----------------------------------------------------------------*/
2020 /* outBitC - output a bit C                                        */
2021 /*-----------------------------------------------------------------*/
2022 static void
2023 outBitC (operand * result)
2024 {
2025   /* if the result is bit */
2026   if (AOP_TYPE (result) == AOP_CRY)
2027     {
2028       aopPut (result, "c", 0);
2029     }
2030   else
2031     {
2032       emitcode ("clr", "a");
2033       emitcode ("rlc", "a");
2034       outAcc (result);
2035     }
2036 }
2037
2038 /*-----------------------------------------------------------------*/
2039 /* toBoolean - emit code for orl a,operator(sizeop)                */
2040 /*-----------------------------------------------------------------*/
2041 static void
2042 toBoolean (operand * oper)
2043 {
2044   int  size = AOP_SIZE (oper) - 1;
2045   int  offset = 1;
2046   bool pushedB;
2047
2048   /* The generic part of a generic pointer should
2049    * not participate in it's truth value.
2050    *
2051    * i.e. 0x10000000 is zero.
2052    */
2053   if (opIsGptr (oper))
2054     {
2055       D (emitcode (";", "toBoolean: generic ptr special case."));
2056       size--;
2057     }
2058
2059   _startLazyDPSEvaluation ();
2060   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2061   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2062     {
2063       pushedB = pushB ();
2064       emitcode("mov", "b,a");
2065       while (--size)
2066         {
2067         MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2068           emitcode ("orl", "b,a");
2069         }
2070       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2071       emitcode ("orl", "a,b");
2072       popB (pushedB);
2073     }
2074   else
2075     {
2076       while (size--)
2077         {
2078           emitcode ("orl", "a,%s",
2079                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2080         }
2081     }
2082   _endLazyDPSEvaluation ();
2083 }
2084
2085
2086 /*-----------------------------------------------------------------*/
2087 /* genNot - generate code for ! operation                          */
2088 /*-----------------------------------------------------------------*/
2089 static void
2090 genNot (iCode * ic)
2091 {
2092   symbol *tlbl;
2093
2094   D (emitcode (";", "genNot "));
2095
2096   /* assign asmOps to operand & result */
2097   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2098   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2099
2100   /* if in bit space then a special case */
2101   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2102     {
2103       /* if left==result then cpl bit */
2104       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2105         {
2106           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2107         }
2108       else
2109         {
2110           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2111           emitcode ("cpl", "c");
2112           outBitC (IC_RESULT (ic));
2113         }
2114       goto release;
2115     }
2116
2117   toBoolean (IC_LEFT (ic));
2118
2119   /* set C, if a == 0 */
2120   tlbl = newiTempLabel (NULL);
2121   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2122   emitcode ("", "!tlabeldef", tlbl->key + 100);
2123   outBitC (IC_RESULT (ic));
2124
2125 release:
2126   /* release the aops */
2127   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2128   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2129 }
2130
2131
2132 /*-----------------------------------------------------------------*/
2133 /* genCpl - generate code for complement                           */
2134 /*-----------------------------------------------------------------*/
2135 static void
2136 genCpl (iCode * ic)
2137 {
2138   int offset = 0;
2139   int size;
2140   symbol *tlbl;
2141   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2142
2143   D(emitcode (";", "genCpl"));
2144
2145   /* assign asmOps to operand & result */
2146   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2147   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2148
2149   /* special case if in bit space */
2150   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2151     {
2152       char *l;
2153
2154       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2155           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2156         {
2157           /* promotion rules are responsible for this strange result:
2158              bit -> int -> ~int -> bit
2159              uchar -> int -> ~int -> bit
2160           */
2161           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2162           goto release;
2163         }
2164
2165       tlbl=newiTempLabel(NULL);
2166       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2167       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2168           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2169           IS_AOP_PREG (IC_LEFT (ic)))
2170         {
2171           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2172         }
2173       else
2174         {
2175           MOVA (l);
2176           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2177         }
2178       emitcode ("", "%05d$:", tlbl->key + 100);
2179       outBitC (IC_RESULT(ic));
2180       goto release;
2181     }
2182
2183   size = AOP_SIZE (IC_RESULT (ic));
2184   _startLazyDPSEvaluation ();
2185   while (size--)
2186     {
2187       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2188       MOVA (l);
2189       emitcode ("cpl", "a");
2190       aopPut (IC_RESULT (ic), "a", offset++);
2191     }
2192   _endLazyDPSEvaluation ();
2193
2194
2195 release:
2196   /* release the aops */
2197   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2198   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2199 }
2200
2201 /*-----------------------------------------------------------------*/
2202 /* genUminusFloat - unary minus for floating points                */
2203 /*-----------------------------------------------------------------*/
2204 static void
2205 genUminusFloat (operand * op, operand * result)
2206 {
2207   int size, offset = 0;
2208   char *l;
2209
2210   D(emitcode (";", "genUminusFloat"));
2211
2212   /* for this we just copy and then flip the bit */
2213
2214   _startLazyDPSEvaluation ();
2215   size = AOP_SIZE (op) - 1;
2216
2217   while (size--)
2218     {
2219       aopPut (result,
2220               aopGet (op, offset, FALSE, FALSE, NULL),
2221               offset);
2222       offset++;
2223     }
2224
2225   l = aopGet (op, offset, FALSE, FALSE, NULL);
2226   MOVA (l);
2227
2228   emitcode ("cpl", "acc.7");
2229   aopPut (result, "a", offset);
2230   _endLazyDPSEvaluation ();
2231 }
2232
2233 /*-----------------------------------------------------------------*/
2234 /* genUminus - unary minus code generation                         */
2235 /*-----------------------------------------------------------------*/
2236 static void
2237 genUminus (iCode * ic)
2238 {
2239   int offset, size;
2240   sym_link *optype;
2241
2242   D (emitcode (";", "genUminus "));
2243
2244   /* assign asmops */
2245   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2246   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2247
2248   /* if both in bit space then special
2249      case */
2250   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2251       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2252     {
2253
2254       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2255       emitcode ("cpl", "c");
2256       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2257       goto release;
2258     }
2259
2260   optype = operandType (IC_LEFT (ic));
2261
2262   /* if float then do float stuff */
2263   if (IS_FLOAT (optype))
2264     {
2265       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2266       goto release;
2267     }
2268
2269   /* otherwise subtract from zero */
2270   size = AOP_SIZE (IC_LEFT (ic));
2271   offset = 0;
2272   _startLazyDPSEvaluation ();
2273   while (size--)
2274     {
2275       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2276       if (!strcmp (l, "a"))
2277         {
2278           if (offset == 0)
2279             SETC;
2280           emitcode ("cpl", "a");
2281           emitcode ("addc", "a,#0");
2282         }
2283       else
2284         {
2285           if (offset == 0)
2286             CLRC;
2287           emitcode ("clr", "a");
2288           emitcode ("subb", "a,%s", l);
2289         }
2290       aopPut (IC_RESULT (ic), "a", offset++);
2291     }
2292   _endLazyDPSEvaluation ();
2293
2294   /* if any remaining bytes in the result */
2295   /* we just need to propagate the sign   */
2296   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))) != 0)
2297     {
2298       emitcode ("rlc", "a");
2299       emitcode ("subb", "a,acc");
2300       while (size--)
2301         aopPut (IC_RESULT (ic), "a", offset++);
2302     }
2303
2304 release:
2305   /* release the aops */
2306   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2307   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2308 }
2309
2310 /*-----------------------------------------------------------------*/
2311 /* savermask - saves registers in the mask                         */
2312 /*-----------------------------------------------------------------*/
2313 static void savermask(bitVect *rs_mask)
2314 {
2315   int i;
2316   if (options.useXstack)
2317     {
2318       if (bitVectBitValue (rs_mask, R0_IDX))
2319           emitcode ("mov", "b,r0");
2320       emitcode ("mov", "r0,%s", spname);
2321       for (i = 0; i < ds390_nRegs; i++)
2322         {
2323           if (bitVectBitValue (rs_mask, i))
2324             {
2325               if (i == R0_IDX)
2326                   emitcode ("mov", "a,b");
2327               else
2328                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2329               emitcode ("movx", "@r0,a");
2330               emitcode ("inc", "r0");
2331             }
2332         }
2333       emitcode ("mov", "%s,r0", spname);
2334       if (bitVectBitValue (rs_mask, R0_IDX))
2335           emitcode ("mov", "r0,b");
2336     }
2337   else
2338     {
2339       bool bits_pushed = FALSE;
2340       for (i = 0; i < ds390_nRegs; i++)
2341         {
2342           if (bitVectBitValue (rs_mask, i))
2343             {
2344               bits_pushed = pushReg (i, bits_pushed);
2345             }
2346         }
2347     }
2348 }
2349
2350 /*-----------------------------------------------------------------*/
2351 /* saveRegisters - will look for a call and save the registers     */
2352 /*-----------------------------------------------------------------*/
2353 static void
2354 saveRegisters (iCode * lic)
2355 {
2356   iCode *ic;
2357   bitVect *rsave;
2358
2359   /* look for call */
2360   for (ic = lic; ic; ic = ic->next)
2361     if (ic->op == CALL || ic->op == PCALL)
2362       break;
2363
2364   if (!ic)
2365     {
2366       fprintf (stderr, "found parameter push with no function call\n");
2367       return;
2368     }
2369
2370   /* if the registers have been saved already or don't need to be then
2371      do nothing */
2372   if (ic->regsSaved
2373       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2374     return ;
2375
2376   /* special case if DPTR alive across a function call then must save it
2377      even though callee saves */
2378   if (IS_SYMOP(IC_LEFT(ic)) &&
2379       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2380     {
2381       int i;
2382       rsave = newBitVect(ic->rMask->size);
2383       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2384           if (bitVectBitValue(ic->rMask,i))
2385               rsave = bitVectSetBit(rsave,i);
2386       }
2387       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2388     }
2389   else
2390     {
2391       /* save the registers in use at this time but skip the
2392          ones for the result */
2393       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2394                              ds390_rUmaskForOp (IC_RESULT(ic)));
2395     }
2396   ic->regsSaved = 1;
2397   savermask(rsave);
2398 }
2399
2400 /*-----------------------------------------------------------------*/
2401 /* usavermask - restore registers with mask                        */
2402 /*-----------------------------------------------------------------*/
2403 static void unsavermask(bitVect *rs_mask)
2404 {
2405     int i;
2406     if (options.useXstack) {
2407         emitcode ("mov", "r0,%s", spname);
2408       for (i = ds390_nRegs; i >= 0; i--)
2409         {
2410           if (bitVectBitValue (rs_mask, i))
2411             {
2412               regs * reg = REG_WITH_INDEX (i);
2413               emitcode ("dec", "r0");
2414               emitcode ("movx", "a,@r0");
2415               if (i == R0_IDX)
2416                 {
2417                   emitcode ("push", "acc");
2418                 }
2419               else
2420                 {
2421                   emitcode ("mov", "%s,a", reg->name);
2422                 }
2423             }
2424         }
2425       emitcode ("mov", "%s,r0", spname);
2426       if (bitVectBitValue (rs_mask, R0_IDX))
2427         {
2428           emitcode ("pop", "ar0");
2429         }
2430     }
2431   else
2432     {
2433       bool bits_popped = FALSE;
2434       for (i = ds390_nRegs; i >= 0; i--)
2435         {
2436             if (bitVectBitValue (rs_mask, i))
2437             {
2438               bits_popped = popReg (i, bits_popped);
2439             }
2440         }
2441     }
2442 }
2443
2444 /*-----------------------------------------------------------------*/
2445 /* unsaveRegisters - pop the pushed registers                      */
2446 /*-----------------------------------------------------------------*/
2447 static void
2448 unsaveRegisters (iCode * ic)
2449 {
2450   bitVect *rsave;
2451
2452   if (IS_SYMOP(IC_LEFT (ic)) &&
2453       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2454       int i;
2455       rsave = newBitVect(ic->rMask->size);
2456       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2457           if (bitVectBitValue(ic->rMask,i))
2458               rsave = bitVectSetBit(rsave,i);
2459       }
2460       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2461   } else {
2462     /* restore the registers in use at this time but skip the
2463        ones for the result */
2464     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2465                            ds390_rUmaskForOp (IC_RESULT(ic)));
2466   }
2467   unsavermask(rsave);
2468 }
2469
2470
2471 /*-----------------------------------------------------------------*/
2472 /* pushSide -                */
2473 /*-----------------------------------------------------------------*/
2474 static void
2475 pushSide (operand * oper, int size)
2476 {
2477   int offset = 0;
2478   _startLazyDPSEvaluation ();
2479   while (size--)
2480     {
2481       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2482       if (AOP_TYPE (oper) != AOP_REG &&
2483           AOP_TYPE (oper) != AOP_DIR &&
2484           strcmp (l, "a"))
2485         {
2486           MOVA (l);
2487           emitcode ("push", "acc");
2488         }
2489       else
2490         {
2491         emitcode ("push", "%s", l);
2492     }
2493     }
2494   _endLazyDPSEvaluation ();
2495 }
2496
2497 /*-----------------------------------------------------------------*/
2498 /* assignResultValue - also indicates if acc is in use afterwards  */
2499 /*-----------------------------------------------------------------*/
2500 static bool
2501 assignResultValue (operand * oper, operand * func)
2502 {
2503   int offset = 0;
2504   unsigned size = AOP_SIZE (oper);
2505   bool accuse = FALSE;
2506   bool pushedA = FALSE;
2507
2508   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2509     {
2510       outBitC (oper);
2511       return FALSE;
2512     }
2513
2514   if (size == fReturnSizeDS390)
2515   {
2516       /* I don't think this case can ever happen... */
2517       /* ACC is the last part of this. If writing the result
2518        * uses ACC, we must preserve it.
2519        */
2520       if (AOP_NEEDSACC(oper))
2521       {
2522           emitcode(";", "assignResultValue special case for ACC.");
2523           emitcode("push", "acc");
2524           pushedA = TRUE;
2525           size--;
2526       }
2527   }
2528
2529   _startLazyDPSEvaluation ();
2530   while (size--)
2531     {
2532       accuse |= aopPut (oper, fReturn[offset], offset);
2533       offset++;
2534     }
2535   _endLazyDPSEvaluation ();
2536
2537   if (pushedA)
2538     {
2539         emitcode ("pop", "acc");
2540         accuse |= aopPut (oper, "a", offset);
2541     }
2542   return accuse;
2543 }
2544
2545
2546 /*-----------------------------------------------------------------*/
2547 /* genXpush - pushes onto the external stack                       */
2548 /*-----------------------------------------------------------------*/
2549 static void
2550 genXpush (iCode * ic)
2551 {
2552   asmop *aop = newAsmop (0);
2553   regs *r;
2554   int size, offset = 0;
2555
2556   D (emitcode (";", "genXpush "));
2557
2558   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2559   r = getFreePtr (ic, &aop, FALSE);
2560
2561   size = AOP_SIZE (IC_LEFT (ic));
2562
2563   if (size == 1)
2564     {
2565       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2566       emitcode ("mov", "%s,_spx", r->name);
2567       emitcode ("inc", "_spx"); // allocate space first
2568       emitcode ("movx", "@%s,a", r->name);
2569     }
2570   else
2571     {
2572       // allocate space first
2573       emitcode ("mov", "%s,_spx", r->name);
2574       MOVA (r->name);
2575       emitcode ("add", "a,#%d", size);
2576       emitcode ("mov", "_spx,a");
2577
2578       _startLazyDPSEvaluation ();
2579       while (size--)
2580         {
2581           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2582           emitcode ("movx", "@%s,a", r->name);
2583           emitcode ("inc", "%s", r->name);
2584         }
2585       _endLazyDPSEvaluation ();
2586     }
2587
2588   freeAsmop (NULL, aop, ic, TRUE);
2589   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2590 }
2591
2592 /*-----------------------------------------------------------------*/
2593 /* genIpush - generate code for pushing this gets a little complex  */
2594 /*-----------------------------------------------------------------*/
2595 static void
2596 genIpush (iCode * ic)
2597 {
2598   int size, offset = 0;
2599   char *l;
2600   char *prev = "";
2601
2602   D (emitcode (";", "genIpush "));
2603
2604   /* if this is not a parm push : ie. it is spill push
2605      and spill push is always done on the local stack */
2606   if (!ic->parmPush)
2607     {
2608
2609       /* and the item is spilt then do nothing */
2610       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2611         return;
2612
2613       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2614       size = AOP_SIZE (IC_LEFT (ic));
2615       /* push it on the stack */
2616       _startLazyDPSEvaluation ();
2617       while (size--)
2618         {
2619           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2620           if (*l == '#')
2621             {
2622               MOVA (l);
2623               l = "acc";
2624             }
2625           emitcode ("push", "%s", l);
2626         }
2627       _endLazyDPSEvaluation ();
2628       return;
2629     }
2630
2631   /* this is a parameter push: in this case we call
2632      the routine to find the call and save those
2633      registers that need to be saved */
2634   saveRegisters (ic);
2635
2636   /* if use external stack then call the external
2637      stack pushing routine */
2638   if (options.useXstack)
2639     {
2640       genXpush (ic);
2641       return;
2642     }
2643
2644   /* then do the push */
2645   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2646
2647   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2648   size = AOP_SIZE (IC_LEFT (ic));
2649
2650   _startLazyDPSEvaluation ();
2651   while (size--)
2652     {
2653       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2654       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2655           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2656           strcmp (l, "acc"))
2657         {
2658           if (strcmp (l, prev) || *l == '@')
2659             MOVA (l);
2660           emitcode ("push", "acc");
2661         }
2662       else
2663         {
2664             emitcode ("push", "%s", l);
2665         }
2666       prev = l;
2667     }
2668   _endLazyDPSEvaluation ();
2669
2670   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2671 }
2672
2673 /*-----------------------------------------------------------------*/
2674 /* genIpop - recover the registers: can happen only for spilling   */
2675 /*-----------------------------------------------------------------*/
2676 static void
2677 genIpop (iCode * ic)
2678 {
2679   int size, offset;
2680
2681   D (emitcode (";", "genIpop "));
2682
2683   /* if the temp was not pushed then */
2684   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2685     return;
2686
2687   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2688   size = AOP_SIZE (IC_LEFT (ic));
2689   offset = (size - 1);
2690   _startLazyDPSEvaluation ();
2691   while (size--)
2692     {
2693       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2694                                      FALSE, TRUE, NULL));
2695     }
2696   _endLazyDPSEvaluation ();
2697
2698   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2699 }
2700
2701 /*-----------------------------------------------------------------*/
2702 /* saveRBank - saves an entire register bank on the stack          */
2703 /*-----------------------------------------------------------------*/
2704 static void
2705 saveRBank (int bank, iCode * ic, bool pushPsw)
2706 {
2707   int i;
2708   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2709   asmop *aop = NULL;
2710   regs *r = NULL;
2711
2712   if (options.useXstack)
2713   {
2714       if (!ic)
2715       {
2716           /* Assume r0 is available for use. */
2717           r = REG_WITH_INDEX (R0_IDX);;
2718       }
2719       else
2720       {
2721           aop = newAsmop (0);
2722           r = getFreePtr (ic, &aop, FALSE);
2723       }
2724       // allocate space first
2725       emitcode ("mov", "%s,_spx", r->name);
2726       MOVA (r->name);
2727       emitcode ("add", "a,#%d", count);
2728       emitcode ("mov", "_spx,a");
2729   }
2730
2731   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2732     {
2733       if (options.useXstack)
2734       {
2735           emitcode ("mov", "a,(%s+%d)",
2736                     regs390[i].base, 8 * bank + regs390[i].offset);
2737           emitcode ("movx", "@%s,a", r->name);
2738           if (--count)
2739             emitcode ("inc", "%s", r->name);
2740         }
2741       else
2742         emitcode ("push", "(%s+%d)",
2743                   regs390[i].base, 8 * bank + regs390[i].offset);
2744     }
2745
2746   if (ds390_nBitRegs > 0)
2747     {
2748       if (options.useXstack)
2749         {
2750           emitcode ("mov", "a,bits");
2751           emitcode ("movx", "@%s,a", r->name);
2752           if (--count)
2753             emitcode ("inc", "%s", r->name);
2754         }
2755       else
2756         {
2757           emitcode ("push", "bits");
2758         }
2759       BitBankUsed = 1;
2760     }
2761
2762   if (pushPsw)
2763     {
2764       if (options.useXstack)
2765         {
2766           emitcode ("mov", "a,psw");
2767           emitcode ("movx", "@%s,a", r->name);
2768         }
2769       else
2770       {
2771         emitcode ("push", "psw");
2772     }
2773
2774       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2775     }
2776
2777   if (aop)
2778   {
2779       freeAsmop (NULL, aop, ic, TRUE);
2780   }
2781
2782   if (ic)
2783   {
2784     ic->bankSaved = 1;
2785   }
2786 }
2787
2788 /*-----------------------------------------------------------------*/
2789 /* unsaveRBank - restores the register bank from stack             */
2790 /*-----------------------------------------------------------------*/
2791 static void
2792 unsaveRBank (int bank, iCode * ic, bool popPsw)
2793 {
2794   int i;
2795   asmop *aop = NULL;
2796   regs *r = NULL;
2797
2798   if (options.useXstack)
2799     {
2800         if (!ic)
2801         {
2802           /* Assume r0 is available for use. */
2803           r = REG_WITH_INDEX (R0_IDX);;
2804         }
2805         else
2806         {
2807           aop = newAsmop (0);
2808           r = getFreePtr (ic, &aop, FALSE);
2809         }
2810         emitcode ("mov", "%s,_spx", r->name);
2811     }
2812
2813   if (popPsw)
2814     {
2815       if (options.useXstack)
2816         {
2817           emitcode ("dec", "%s", r->name);
2818           emitcode ("movx", "a,@%s", r->name);
2819           emitcode ("mov", "psw,a");
2820         }
2821       else
2822       {
2823         emitcode ("pop", "psw");
2824       }
2825     }
2826
2827   if (ds390_nBitRegs > 0)
2828     {
2829       if (options.useXstack)
2830         {
2831           emitcode ("dec", "%s", r->name);
2832           emitcode ("movx", "a,@%s", r->name);
2833           emitcode ("mov", "bits,a");
2834         }
2835       else
2836         {
2837           emitcode ("pop", "bits");
2838         }
2839     }
2840
2841   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2842     {
2843       if (options.useXstack)
2844         {
2845           emitcode ("dec", "%s", r->name);
2846           emitcode ("movx", "a,@%s", r->name);
2847           emitcode ("mov", "(%s+%d),a",
2848                     regs390[i].base, 8 * bank + regs390[i].offset);
2849         }
2850       else
2851         {
2852           emitcode ("pop", "(%s+%d)",
2853                   regs390[i].base, 8 * bank + regs390[i].offset);
2854         }
2855     }
2856
2857   if (options.useXstack)
2858     {
2859       emitcode ("mov", "_spx,%s", r->name);
2860     }
2861
2862   if (aop)
2863   {
2864     freeAsmop (NULL, aop, ic, TRUE);
2865   }
2866 }
2867
2868 /*-----------------------------------------------------------------*/
2869 /* genSend - gen code for SEND                                     */
2870 /*-----------------------------------------------------------------*/
2871 static void genSend(set *sendSet)
2872 {
2873     iCode *sic;
2874   int bit_count = 0;
2875     int sendCount = 0 ;
2876     static int rb1_count = 0;
2877
2878   /* first we do all bit parameters */
2879     for (sic = setFirstItem (sendSet); sic;
2880        sic = setNextItem (sendSet))
2881     {
2882       if (sic->argreg > 12)
2883         {
2884           int bit = sic->argreg-13;
2885
2886           aopOp (IC_LEFT (sic), sic, FALSE,
2887                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2888
2889           /* if left is a literal then
2890              we know what the value is */
2891           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2892             {
2893               if (((int) operandLitValue (IC_LEFT (sic))))
2894                   emitcode ("setb", "b[%d]", bit);
2895               else
2896                   emitcode ("clr", "b[%d]", bit);
2897             }
2898           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2899             {
2900               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2901                 if (strcmp (l, "c"))
2902                     emitcode ("mov", "c,%s", l);
2903                 emitcode ("mov", "b[%d],c", bit);
2904             }
2905           else
2906             {
2907               /* we need to or */
2908               toBoolean (IC_LEFT (sic));
2909               /* set C, if a >= 1 */
2910               emitcode ("add", "a,#0xff");
2911               emitcode ("mov", "b[%d],c", bit);
2912             }
2913           bit_count++;
2914           BitBankUsed = 1;
2915
2916           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2917         }
2918     }
2919
2920   if (bit_count)
2921     {
2922       saveRegisters (setFirstItem (sendSet));
2923       emitcode ("mov", "bits,b");
2924     }
2925
2926   /* then we do all other parameters */
2927   for (sic = setFirstItem (sendSet); sic;
2928        sic = setNextItem (sendSet))
2929     {
2930       if (sic->argreg <= 12)
2931       {
2932         int size, offset = 0;
2933
2934         size=getSize(operandType(IC_LEFT(sic)));
2935         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2936         if (sendCount == 0) { /* first parameter */
2937             // we know that dpl(hxb) is the result, so
2938             rb1_count = 0 ;
2939             _startLazyDPSEvaluation ();
2940             if (size>1) {
2941                 aopOp (IC_LEFT (sic), sic, FALSE,
2942                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2943             } else {
2944                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2945             }
2946             while (size--)
2947               {
2948                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2949                 if (strcmp (l, fReturn[offset]))
2950                   {
2951                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2952                 }
2953                 offset++;
2954             }
2955             _endLazyDPSEvaluation ();
2956             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2957             rb1_count =0;
2958         } else { /* if more parameter in registers */
2959             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2960             while (size--) {
2961                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2962                                                                 FALSE, FALSE, NULL));
2963             }
2964             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2965         }
2966         sendCount++;
2967       }
2968     }
2969 }
2970
2971 static void
2972 adjustEsp(const char *reg)
2973 {
2974     emitcode ("anl","%s,#3", reg);
2975     if (TARGET_IS_DS400)
2976     {
2977         emitcode ("orl","%s,#!constbyte",
2978                   reg,
2979                   (options.stack_loc >> 8) & 0xff);
2980     }
2981 }
2982
2983 /*-----------------------------------------------------------------*/
2984 /* selectRegBank - emit code to select the register bank           */
2985 /*-----------------------------------------------------------------*/
2986 static void
2987 selectRegBank (short bank, bool keepFlags)
2988 {
2989   /* if f.e. result is in carry */
2990   if (keepFlags)
2991     {
2992       emitcode ("anl", "psw,#0xE7");
2993       if (bank)
2994         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2995     }
2996   else
2997     {
2998       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2999     }
3000 }
3001
3002 /*-----------------------------------------------------------------*/
3003 /* genCall - generates a call statement                            */
3004 /*-----------------------------------------------------------------*/
3005 static void
3006 genCall (iCode * ic)
3007 {
3008   sym_link *dtype;
3009   sym_link *etype;
3010   bool restoreBank = FALSE;
3011   bool swapBanks = FALSE;
3012   bool accuse = FALSE;
3013   bool accPushed = FALSE;
3014   bool resultInF0 = FALSE;
3015   bool assignResultGenerated = FALSE;
3016
3017   D (emitcode (";", "genCall "));
3018
3019   /* if we are calling a not _naked function that is not using
3020      the same register bank then we need to save the
3021      destination registers on the stack */
3022   dtype = operandType (IC_LEFT (ic));
3023   etype = getSpec(dtype);
3024   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3025       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3026       IFFUNC_ISISR (currFunc->type))
3027   {
3028       if (!ic->bankSaved)
3029       {
3030            /* This is unexpected; the bank should have been saved in
3031             * genFunction.
3032             */
3033            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3034            restoreBank = TRUE;
3035       }
3036       swapBanks = TRUE;
3037   }
3038
3039     /* if caller saves & we have not saved then */
3040     if (!ic->regsSaved)
3041       saveRegisters (ic);
3042
3043   /* if send set is not empty then assign */
3044   /* We've saved all the registers we care about;
3045   * therefore, we may clobber any register not used
3046   * in the calling convention (i.e. anything not in
3047   * fReturn.
3048   */
3049   if (_G.sendSet)
3050     {
3051         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3052             genSend(reverseSet(_G.sendSet));
3053         } else {
3054             genSend(_G.sendSet);
3055         }
3056       _G.sendSet = NULL;
3057     }
3058
3059   if (swapBanks)
3060   {
3061         emitcode ("mov", "psw,#!constbyte",
3062            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3063   }
3064
3065   /* make the call */
3066   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3067                             OP_SYMBOL (IC_LEFT (ic))->rname :
3068                             OP_SYMBOL (IC_LEFT (ic))->name));
3069
3070   if (swapBanks)
3071     {
3072       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3073     }
3074
3075   /* if we need assign a result value */
3076   if ((IS_ITEMP (IC_RESULT (ic)) &&
3077        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3078        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3079         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3080         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3081       IS_TRUE_SYMOP (IC_RESULT (ic)))
3082     {
3083       if (isOperandInFarSpace (IC_RESULT (ic))
3084           && getSize (operandType (IC_RESULT (ic))) <= 2)
3085         {
3086           int size = getSize (operandType (IC_RESULT (ic)));
3087           bool pushedB = FALSE;
3088
3089           /* Special case for 1 or 2 byte return in far space. */
3090           MOVA (fReturn[0]);
3091           if (size > 1)
3092             {
3093               pushedB = pushB ();
3094               emitcode ("mov", "b,%s", fReturn[1]);
3095             }
3096
3097           _G.accInUse++;
3098           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3099           _G.accInUse--;
3100
3101           popB (pushedB);
3102
3103           aopPut (IC_RESULT (ic), "a", 0);
3104
3105           if (size > 1)
3106             {
3107               aopPut (IC_RESULT (ic), "b", 1);
3108             }
3109           assignResultGenerated = TRUE;
3110           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3111         }
3112       else
3113         {
3114           bool pushedB = pushB ();
3115           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3116           popB (pushedB);
3117
3118           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3119           assignResultGenerated = TRUE;
3120           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3121         }
3122     }
3123
3124   /* adjust the stack for parameters if required */
3125   if (ic->parmBytes)
3126     {
3127       int i;
3128       if (options.stack10bit) {
3129           if (ic->parmBytes <= 10) {
3130               emitcode(";","stack adjustment for parms");
3131               for (i=0; i < ic->parmBytes ; i++) {
3132                   emitcode("pop","acc");
3133               }
3134           } else {
3135               PROTECT_SP;
3136               emitcode ("clr","c");
3137               emitcode ("mov","a,sp");
3138               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3139               emitcode ("mov","sp,a");
3140               emitcode ("mov","a,esp");
3141               adjustEsp("a");
3142               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3143               emitcode ("mov","esp,a");
3144               UNPROTECT_SP;
3145           }
3146       } else {
3147           if (ic->parmBytes > 3)
3148             {
3149               if (accuse)
3150                 {
3151                   emitcode ("push", "acc");
3152                   accPushed = TRUE;
3153                 }
3154             if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3155                 IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3156                 !assignResultGenerated)
3157               {
3158                 emitcode ("mov", "F0,c");
3159                 resultInF0 = TRUE;
3160               }
3161               emitcode ("mov", "a,%s", spname);
3162               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3163               emitcode ("mov", "%s,a", spname);
3164
3165               /* unsaveRegisters from xstack needs acc, but */
3166               /* unsaveRegisters from stack needs this popped */
3167               if (accPushed && !options.useXstack)
3168                 {
3169                   emitcode ("pop", "acc");
3170                   accPushed = FALSE;
3171                 }
3172             }
3173           else
3174               for (i = 0; i < ic->parmBytes; i++)
3175                   emitcode ("dec", "%s", spname);
3176       }
3177   }
3178
3179   /* if we had saved some registers then unsave them */
3180   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3181     {
3182       if (accuse && !accPushed && options.useXstack)
3183         {
3184           /* xstack needs acc, but doesn't touch normal stack */
3185           emitcode ("push", "acc");
3186           accPushed = TRUE;
3187         }
3188       unsaveRegisters (ic);
3189     }
3190
3191   /* if register bank was saved then pop them */
3192   if (restoreBank)
3193     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3194
3195   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3196     {
3197       if (resultInF0)
3198           emitcode ("mov", "c,F0");
3199
3200       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3201       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3202       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3203     }
3204
3205   if (accPushed)
3206     emitcode ("pop", "acc");
3207 }
3208
3209 /*-----------------------------------------------------------------*/
3210 /* genPcall - generates a call by pointer statement                */
3211 /*-----------------------------------------------------------------*/
3212 static void
3213 genPcall (iCode * ic)
3214 {
3215   sym_link *dtype;
3216   sym_link *etype;
3217   symbol *rlbl = newiTempLabel (NULL);
3218   bool restoreBank=FALSE;
3219   bool resultInF0 = FALSE;
3220
3221   D (emitcode (";", "genPcall "));
3222
3223   dtype = operandType (IC_LEFT (ic))->next;
3224   etype = getSpec(dtype);
3225   /* if caller saves & we have not saved then */
3226   if (!ic->regsSaved)
3227     saveRegisters (ic);
3228
3229   /* if we are calling a not _naked function that is not using
3230      the same register bank then we need to save the
3231      destination registers on the stack */
3232   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3233       IFFUNC_ISISR (currFunc->type) &&
3234       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3235     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3236     restoreBank=TRUE;
3237   }
3238
3239   /* push the return address on to the stack */
3240   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3241   emitcode ("push", "acc");
3242   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3243   emitcode ("push", "acc");
3244
3245   if (options.model == MODEL_FLAT24)
3246     {
3247       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3248       emitcode ("push", "acc");
3249     }
3250
3251   /* now push the calling address */
3252   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3253
3254   pushSide (IC_LEFT (ic), FPTRSIZE);
3255
3256   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3257
3258   /* if send set is not empty the assign */
3259   if (_G.sendSet)
3260     {
3261         genSend(reverseSet(_G.sendSet));
3262         _G.sendSet = NULL;
3263     }
3264
3265   emitcode ("ret", "");
3266   emitcode ("", "!tlabeldef", (rlbl->key + 100));
3267
3268
3269   /* if we need assign a result value */
3270   if ((IS_ITEMP (IC_RESULT (ic)) &&
3271        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3272        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3273         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3274       IS_TRUE_SYMOP (IC_RESULT (ic)))
3275     {
3276
3277       _G.accInUse++;
3278       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3279       _G.accInUse--;
3280
3281       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3282
3283       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3284     }
3285
3286   /* adjust the stack for parameters if required */
3287   if (ic->parmBytes)
3288     {
3289       int i;
3290       if (options.stack10bit) {
3291           if (ic->parmBytes <= 10) {
3292               emitcode(";","stack adjustment for parms");
3293               for (i=0; i < ic->parmBytes ; i++) {
3294                   emitcode("pop","acc");
3295               }
3296           } else {
3297               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3298                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3299                 {
3300                   emitcode ("mov", "F0,c");
3301                   resultInF0 = TRUE;
3302                 }
3303
3304               PROTECT_SP;
3305               emitcode ("clr","c");
3306               emitcode ("mov","a,sp");
3307               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3308               emitcode ("mov","sp,a");
3309               emitcode ("mov","a,esp");
3310               adjustEsp("a");
3311               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3312               emitcode ("mov","esp,a");
3313               UNPROTECT_SP;
3314           }
3315       } else {
3316           if (ic->parmBytes > 3) {
3317               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3318                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3319                 {
3320                   emitcode ("mov", "F0,c");
3321                   resultInF0 = TRUE;
3322                 }
3323
3324               emitcode ("mov", "a,%s", spname);
3325               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3326               emitcode ("mov", "%s,a", spname);
3327             }
3328           else
3329               for (i = 0; i < ic->parmBytes; i++)
3330                   emitcode ("dec", "%s", spname);
3331       }
3332     }
3333   /* if register bank was saved then unsave them */
3334   if (restoreBank)
3335     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3336
3337   /* if we had saved some registers then unsave them */
3338   if (ic->regsSaved)
3339     unsaveRegisters (ic);
3340
3341   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3342     {
3343       if (resultInF0)
3344           emitcode ("mov", "c,F0");
3345
3346       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3347       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3348       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3349     }
3350 }
3351
3352 /*-----------------------------------------------------------------*/
3353 /* resultRemat - result  is rematerializable                       */
3354 /*-----------------------------------------------------------------*/
3355 static int
3356 resultRemat (iCode * ic)
3357 {
3358   if (SKIP_IC (ic) || ic->op == IFX)
3359     return 0;
3360
3361   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3362     {
3363       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3364       if (sym->remat && !POINTER_SET (ic))
3365         return 1;
3366     }
3367
3368   return 0;
3369 }
3370
3371 #if defined(__BORLANDC__) || defined(_MSC_VER)
3372 #define STRCASECMP stricmp
3373 #else
3374 #define STRCASECMP strcasecmp
3375 #endif
3376
3377 /*-----------------------------------------------------------------*/
3378 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3379 /*-----------------------------------------------------------------*/
3380 static int
3381 regsCmp(void *p1, void *p2)
3382 {
3383   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3384 }
3385
3386 static bool
3387 inExcludeList (char *s)
3388 {
3389   const char *p = setFirstItem(options.excludeRegsSet);
3390
3391   if (p == NULL || STRCASECMP(p, "none") == 0)
3392     return FALSE;
3393
3394
3395   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3396 }
3397
3398 /*-----------------------------------------------------------------*/
3399 /* genFunction - generated code for function entry                 */
3400 /*-----------------------------------------------------------------*/
3401 static void
3402 genFunction (iCode * ic)
3403 {
3404   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3405   sym_link *ftype;
3406   bool   switchedPSW = FALSE;
3407   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3408
3409   D (emitcode (";", "genFunction "));
3410
3411   _G.nRegsSaved = 0;
3412   /* create the function header */
3413   emitcode (";", "-----------------------------------------");
3414   emitcode (";", " function %s", sym->name);
3415   emitcode (";", "-----------------------------------------");
3416
3417   emitcode ("", "%s:", sym->rname);
3418   ftype = operandType (IC_LEFT (ic));
3419   _G.currentFunc = sym;
3420
3421   if (IFFUNC_ISNAKED(ftype))
3422   {
3423       emitcode(";", "naked function: no prologue.");
3424       return;
3425   }
3426
3427   if (options.stack_probe)
3428       emitcode ("lcall","__stack_probe");
3429
3430   /* here we need to generate the equates for the
3431      register bank if required */
3432   if (FUNC_REGBANK (ftype) != rbank)
3433     {
3434       int i;
3435
3436       rbank = FUNC_REGBANK (ftype);
3437       for (i = 0; i < ds390_nRegs; i++)
3438         {
3439           if (regs390[i].print) {
3440               if (strcmp (regs390[i].base, "0") == 0)
3441                   emitcode ("", "%s !equ !constbyte",
3442                             regs390[i].dname,
3443                             8 * rbank + regs390[i].offset);
3444               else
3445                   emitcode ("", "%s !equ %s + !constbyte",
3446                             regs390[i].dname,
3447                             regs390[i].base,
3448                             8 * rbank + regs390[i].offset);
3449           }
3450         }
3451     }
3452
3453   /* if this is an interrupt service routine then
3454      save acc, b, dpl, dph  */
3455   if (IFFUNC_ISISR (sym->type))
3456       { /* is ISR */
3457       if (!inExcludeList ("acc"))
3458         emitcode ("push", "acc");
3459       if (!inExcludeList ("b"))
3460         emitcode ("push", "b");
3461       if (!inExcludeList ("dpl"))
3462         emitcode ("push", "dpl");
3463       if (!inExcludeList ("dph"))
3464         emitcode ("push", "dph");
3465       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3466         {
3467           emitcode ("push", "dpx");
3468           /* Make sure we're using standard DPTR */
3469           emitcode ("push", "dps");
3470           emitcode ("mov", "dps,#0");
3471           if (options.stack10bit)
3472             {
3473               /* This ISR could conceivably use DPTR2. Better save it. */
3474               emitcode ("push", "dpl1");
3475               emitcode ("push", "dph1");
3476               emitcode ("push", "dpx1");
3477               emitcode ("push",  DP2_RESULT_REG);
3478             }
3479         }
3480       /* if this isr has no bank i.e. is going to
3481          run with bank 0 , then we need to save more
3482          registers :-) */
3483       if (!FUNC_REGBANK (sym->type))
3484         {
3485             int i;
3486
3487           /* if this function does not call any other
3488              function then we can be economical and
3489              save only those registers that are used */
3490           if (!IFFUNC_HASFCALL(sym->type))
3491             {
3492               /* if any registers used */
3493               if (sym->regsUsed)
3494                 {
3495                   bool bits_pushed = FALSE;
3496                   /* save the registers used */
3497                   for (i = 0; i < sym->regsUsed->size; i++)
3498                     {
3499                       if (bitVectBitValue (sym->regsUsed, i))
3500                         bits_pushed = pushReg (i, bits_pushed);
3501                     }
3502                 }
3503             }
3504           else
3505             {
3506               /* this function has a function call. We cannot
3507                  determine register usage so we will have to push the
3508                  entire bank */
3509               saveRBank (0, ic, FALSE);
3510               if (options.parms_in_bank1) {
3511                   for (i=0; i < 8 ; i++ ) {
3512                       emitcode ("push","%s",rb1regs[i]);
3513                   }
3514               }
3515             }
3516         }
3517         else
3518         {
3519             /* This ISR uses a non-zero bank.
3520              *
3521              * We assume that the bank is available for our
3522              * exclusive use.
3523              *
3524              * However, if this ISR calls a function which uses some
3525              * other bank, we must save that bank entirely.
3526              */
3527             unsigned long banksToSave = 0;
3528
3529             if (IFFUNC_HASFCALL(sym->type))
3530             {
3531
3532 #define MAX_REGISTER_BANKS 4
3533
3534                 iCode *i;
3535                 int ix;
3536
3537                 for (i = ic; i; i = i->next)
3538                 {
3539                     if (i->op == ENDFUNCTION)
3540                     {
3541                         /* we got to the end OK. */
3542                         break;
3543                     }
3544
3545                     if (i->op == CALL)
3546                     {
3547                         sym_link *dtype;
3548
3549                         dtype = operandType (IC_LEFT(i));
3550                         if (dtype
3551                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3552                         {
3553                              /* Mark this bank for saving. */
3554                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3555                              {
3556                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3557                              }
3558                              else
3559                              {
3560                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3561                              }
3562
3563                              /* And note that we don't need to do it in
3564                               * genCall.
3565                               */
3566                              i->bankSaved = 1;
3567                         }
3568                     }
3569                     if (i->op == PCALL)
3570                     {
3571                         /* This is a mess; we have no idea what
3572                          * register bank the called function might
3573                          * use.
3574                          *
3575                          * The only thing I can think of to do is
3576                          * throw a warning and hope.
3577                          */
3578                         werror(W_FUNCPTR_IN_USING_ISR);
3579                     }
3580                 }
3581
3582                 if (banksToSave && options.useXstack)
3583                 {
3584                     /* Since we aren't passing it an ic,
3585                      * saveRBank will assume r0 is available to abuse.
3586                      *
3587                      * So switch to our (trashable) bank now, so
3588                      * the caller's R0 isn't trashed.
3589                      */
3590                     emitcode ("push", "psw");
3591                     emitcode ("mov", "psw,#!constbyte",
3592                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3593                     switchedPSW = TRUE;
3594                 }
3595
3596                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3597                 {
3598                      if (banksToSave & (1 << ix))
3599                      {
3600                          saveRBank(ix, NULL, FALSE);
3601                      }
3602                 }
3603             }
3604             // TODO: this needs a closer look
3605             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3606         }
3607     }
3608   else
3609     {
3610       /* if callee-save to be used for this function
3611          then save the registers being used in this function */
3612       if (IFFUNC_CALLEESAVES(sym->type))
3613         {
3614           int i;
3615
3616           /* if any registers used */
3617           if (sym->regsUsed)
3618             {
3619               bool bits_pushed = FALSE;
3620               /* save the registers used */
3621               for (i = 0; i < sym->regsUsed->size; i++)
3622                 {
3623                   if (bitVectBitValue (sym->regsUsed, i))
3624                     {
3625                       bits_pushed = pushReg (i, bits_pushed);
3626                       _G.nRegsSaved++;
3627                     }
3628                 }
3629             }
3630         }
3631     }
3632
3633   /* set the register bank to the desired value */
3634   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3635    && !switchedPSW)
3636     {
3637       emitcode ("push", "psw");
3638       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3639     }
3640
3641   if (fReentrant &&
3642        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3643       if (options.stack10bit) {
3644           emitcode ("push","_bpx");
3645           emitcode ("push","_bpx+1");
3646           emitcode ("mov","_bpx,%s",spname);
3647           emitcode ("mov","_bpx+1,esp");
3648           adjustEsp("_bpx+1");
3649       } else {
3650           if (options.useXstack)
3651           {
3652               emitcode ("mov", "r0,%s", spname);
3653               emitcode ("mov", "a,_bp");
3654               emitcode ("movx", "@r0,a");
3655               emitcode ("inc", "%s", spname);
3656           } else {
3657               /* set up the stack */
3658               emitcode ("push", "_bp"); /* save the callers stack  */
3659           }
3660           emitcode ("mov", "_bp,%s", spname);
3661       }
3662   }
3663
3664   /* adjust the stack for the function */
3665   if (sym->stack) {
3666       int i = sym->stack;
3667       if (options.stack10bit) {
3668           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3669           assert (sym->recvSize <= 4);
3670           if (sym->stack <= 8) {
3671               while (i--) emitcode ("push","acc");
3672           } else {
3673               PROTECT_SP;
3674               emitcode ("mov","a,sp");
3675               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3676               emitcode ("mov","sp,a");
3677               emitcode ("mov","a,esp");
3678               adjustEsp("a");
3679               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3680               emitcode ("mov","esp,a");
3681               UNPROTECT_SP;
3682           }
3683       } else {
3684           if (i > 256)
3685               werror (W_STACK_OVERFLOW, sym->name);
3686
3687           if (i > 3 && sym->recvSize < 4) {
3688
3689               emitcode ("mov", "a,sp");
3690               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3691               emitcode ("mov", "sp,a");
3692
3693           } else
3694               while (i--)
3695                   emitcode ("inc", "sp");
3696       }
3697   }
3698
3699   if (sym->xstack)
3700     {
3701
3702       emitcode ("mov", "a,_spx");
3703       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3704       emitcode ("mov", "_spx,a");
3705     }
3706
3707   /* if critical function then turn interrupts off */
3708   if (IFFUNC_ISCRITICAL (ftype))
3709     {
3710       symbol *tlbl = newiTempLabel (NULL);
3711       emitcode ("setb", "c");
3712       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3713       emitcode ("clr", "c");
3714       emitcode ("", "%05d$:", (tlbl->key + 100));
3715       emitcode ("push", "psw"); /* save old ea via c in psw */
3716     }
3717 }
3718
3719 /*-----------------------------------------------------------------*/
3720 /* genEndFunction - generates epilogue for functions               */
3721 /*-----------------------------------------------------------------*/
3722 static void
3723 genEndFunction (iCode * ic)
3724 {
3725   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3726   lineNode *lnp = lineCurr;
3727   bitVect *regsUsed;
3728   bitVect *regsUsedPrologue;
3729   bitVect *regsUnneeded;
3730   int idx;
3731
3732   D (emitcode (";", "genEndFunction "););
3733
3734   _G.currentFunc = NULL;
3735   if (IFFUNC_ISNAKED(sym->type))
3736   {
3737       emitcode(";", "naked function: no epilogue.");
3738       if (options.debug && currFunc)
3739         debugFile->writeEndFunction (currFunc, ic, 0);
3740       return;
3741   }
3742
3743   if (IFFUNC_ISCRITICAL (sym->type))
3744     {
3745       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3746         {
3747           emitcode ("rlc", "a");   /* save c in a */
3748           emitcode ("pop", "psw"); /* restore ea via c in psw */
3749           emitcode ("mov", "ea,c");
3750           emitcode ("rrc", "a");   /* restore c from a */
3751         }
3752       else
3753         {
3754           emitcode ("pop", "psw"); /* restore ea via c in psw */
3755           emitcode ("mov", "ea,c");
3756         }
3757     }
3758
3759   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3760        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3761
3762       if (options.stack10bit) {
3763           PROTECT_SP;
3764           emitcode ("mov", "sp,_bpx", spname);
3765           emitcode ("mov", "esp,_bpx+1", spname);
3766           UNPROTECT_SP;
3767       } else {
3768           emitcode ("mov", "%s,_bp", spname);
3769       }
3770   }
3771
3772   /* if use external stack but some variables were
3773      added to the local stack then decrement the
3774      local stack */
3775   if (options.useXstack && sym->stack) {
3776       emitcode ("mov", "a,sp");
3777       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3778       emitcode ("mov", "sp,a");
3779   }
3780
3781
3782   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3783        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3784
3785       if (options.useXstack) {
3786           emitcode ("mov", "r0,%s", spname);
3787           emitcode ("movx", "a,@r0");
3788           emitcode ("mov", "_bp,a");
3789           emitcode ("dec", "%s", spname);
3790       } else {
3791           if (options.stack10bit) {
3792               emitcode ("pop", "_bpx+1");
3793               emitcode ("pop", "_bpx");
3794           } else {
3795               emitcode ("pop", "_bp");
3796           }
3797       }
3798   }
3799
3800   /* restore the register bank  */
3801   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3802   {
3803     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3804      || !options.useXstack)
3805     {
3806         /* Special case of ISR using non-zero bank with useXstack
3807          * is handled below.
3808          */
3809         emitcode ("pop", "psw");
3810     }
3811   }
3812
3813   if (IFFUNC_ISISR (sym->type))
3814       { /* is ISR */
3815
3816       /* now we need to restore the registers */
3817       /* if this isr has no bank i.e. is going to
3818          run with bank 0 , then we need to save more
3819          registers :-) */
3820       if (!FUNC_REGBANK (sym->type))
3821         {
3822             int i;
3823           /* if this function does not call any other
3824              function then we can be economical and
3825              save only those registers that are used */
3826           if (!IFFUNC_HASFCALL(sym->type))
3827             {
3828               /* if any registers used */
3829               if (sym->regsUsed)
3830                 {
3831                   bool bits_popped = FALSE;
3832                   /* save the registers used */
3833                   for (i = sym->regsUsed->size; i >= 0; i--)
3834                     {
3835                       if (bitVectBitValue (sym->regsUsed, i))
3836                         bits_popped = popReg (i, bits_popped);
3837                     }
3838                 }
3839             }
3840           else
3841             {
3842               /* this function has a function call. We cannot
3843                  determine register usage so we will have to pop the
3844                  entire bank */
3845               if (options.parms_in_bank1) {
3846                   for (i = 7 ; i >= 0 ; i-- ) {
3847                       emitcode ("pop","%s",rb1regs[i]);
3848                   }
3849               }
3850               unsaveRBank (0, ic, FALSE);
3851             }
3852         }
3853         else
3854         {
3855             /* This ISR uses a non-zero bank.
3856              *
3857              * Restore any register banks saved by genFunction
3858              * in reverse order.
3859              */
3860             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3861             int ix;
3862
3863             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3864             {
3865                 if (savedBanks & (1 << ix))
3866                 {
3867                     unsaveRBank(ix, NULL, FALSE);
3868                 }
3869             }
3870
3871             if (options.useXstack)
3872             {
3873                 /* Restore bank AFTER calling unsaveRBank,
3874                  * since it can trash r0.
3875                  */
3876                 emitcode ("pop", "psw");
3877             }
3878         }
3879
3880       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3881         {
3882           if (options.stack10bit)
3883             {
3884               emitcode ("pop", DP2_RESULT_REG);
3885               emitcode ("pop", "dpx1");
3886               emitcode ("pop", "dph1");
3887               emitcode ("pop", "dpl1");
3888             }
3889           emitcode ("pop", "dps");
3890           emitcode ("pop", "dpx");
3891         }
3892       if (!inExcludeList ("dph"))
3893         emitcode ("pop", "dph");
3894       if (!inExcludeList ("dpl"))
3895         emitcode ("pop", "dpl");
3896       if (!inExcludeList ("b"))
3897         emitcode ("pop", "b");
3898       if (!inExcludeList ("acc"))
3899         emitcode ("pop", "acc");
3900
3901       /* if debug then send end of function */
3902       if (options.debug && currFunc)
3903         {
3904           debugFile->writeEndFunction (currFunc, ic, 1);
3905         }
3906
3907       emitcode ("reti", "");
3908     }
3909   else
3910     {
3911       if (IFFUNC_CALLEESAVES(sym->type))
3912         {
3913           int i;
3914
3915           /* if any registers used */
3916           if (sym->regsUsed)
3917             {
3918               /* save the registers used */
3919               for (i = sym->regsUsed->size; i >= 0; i--)
3920                 {
3921                   if (bitVectBitValue (sym->regsUsed, i))
3922                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3923                 }
3924             }
3925         }
3926
3927       /* if debug then send end of function */
3928       if (options.debug && currFunc)
3929         {
3930           debugFile->writeEndFunction (currFunc, ic, 1);
3931         }
3932
3933       emitcode ("ret", "");
3934     }
3935
3936   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3937     return;
3938
3939   /* If this was an interrupt handler using bank 0 that called another */
3940   /* function, then all registers must be saved; nothing to optimized. */
3941   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3942       && !FUNC_REGBANK(sym->type))
3943     return;
3944
3945   /* There are no push/pops to optimize if not callee-saves or ISR */
3946   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3947     return;
3948
3949   /* If there were stack parameters, we cannot optimize without also    */
3950   /* fixing all of the stack offsets; this is too dificult to consider. */
3951   if (FUNC_HASSTACKPARM(sym->type))
3952     return;
3953
3954   /* Compute the registers actually used */
3955   regsUsed = newBitVect (ds390_nRegs);
3956   regsUsedPrologue = newBitVect (ds390_nRegs);
3957   while (lnp)
3958     {
3959       if (lnp->ic && lnp->ic->op == FUNCTION)
3960         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3961       else
3962         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3963
3964       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3965           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3966         break;
3967       if (!lnp->prev)
3968         break;
3969       lnp = lnp->prev;
3970     }
3971
3972   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3973       && !bitVectBitValue (regsUsed, DPS_IDX))
3974     {
3975       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3976     }
3977
3978   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3979       && !bitVectBitValue (regsUsed, CND_IDX))
3980     {
3981       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3982       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3983           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3984         bitVectUnSetBit (regsUsed, CND_IDX);
3985     }
3986   else
3987     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3988
3989   /* If this was an interrupt handler that called another function */
3990   /* function, then assume working registers may be modified by it. */
3991   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3992     {
3993       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3994       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3995       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3996       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3997       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3998       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3999       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4000       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
4001       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4002       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4003       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4004     }
4005
4006   /* Remove the unneeded push/pops */
4007   regsUnneeded = newBitVect (ds390_nRegs);
4008   while (lnp)
4009     {
4010       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4011         {
4012           if (!strncmp(lnp->line, "push", 4))
4013             {
4014               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4015               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4016                 {
4017                   connectLine (lnp->prev, lnp->next);
4018                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4019                 }
4020             }
4021           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4022             {
4023               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4024               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4025                 {
4026                   connectLine (lnp->prev, lnp->next);
4027                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4028                 }
4029             }
4030         }
4031       lnp = lnp->next;
4032     }
4033
4034   for (idx = 0; idx < regsUnneeded->size; idx++)
4035     if (bitVectBitValue (regsUnneeded, idx))
4036       emitcode ("", ";\teliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4037
4038   freeBitVect (regsUnneeded);
4039   freeBitVect (regsUsed);
4040   freeBitVect (regsUsedPrologue);
4041 }
4042
4043 /*-----------------------------------------------------------------*/
4044 /* genJavaNativeRet - generate code for return JavaNative          */
4045 /*-----------------------------------------------------------------*/
4046 static void genJavaNativeRet(iCode *ic)
4047 {
4048     int i, size;
4049
4050     aopOp (IC_LEFT (ic), ic, FALSE,
4051            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4052     size = AOP_SIZE (IC_LEFT (ic));
4053
4054     assert (size <= 4);
4055
4056     /* it is assigned to GPR0-R3 then push them */
4057     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4058         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4059         for (i = 0 ; i < size ; i++ ) {
4060             emitcode ("push","%s",
4061                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4062         }
4063         for (i = (size-1) ; i >= 0 ; i--) {
4064             emitcode ("pop","a%s",javaRet[i]);
4065         }
4066     } else {
4067         for (i = 0 ; i < size ; i++)
4068             emitcode ("mov","%s,%s",javaRet[i],
4069                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4070     }
4071     for (i = size ; i < 4 ; i++ )
4072             emitcode ("mov","%s,#0",javaRet[i]);
4073     return;
4074 }
4075
4076 /*-----------------------------------------------------------------*/
4077 /* genRet - generate code for return statement                     */
4078 /*-----------------------------------------------------------------*/
4079 static void
4080 genRet (iCode * ic)
4081 {
4082   int size, offset = 0, pushed = 0;
4083
4084   D (emitcode (";", "genRet"));
4085
4086   /* if we have no return value then
4087      just generate the "ret" */
4088   if (!IC_LEFT (ic))
4089     goto jumpret;
4090
4091   /* if this is a JavaNative function then return
4092      value in different register */
4093   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4094       genJavaNativeRet(ic);
4095       goto jumpret;
4096   }
4097   /* we have something to return then
4098      move the return value into place */
4099   aopOp (IC_LEFT (ic), ic, FALSE,
4100          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4101   size = AOP_SIZE (IC_LEFT (ic));
4102
4103   _startLazyDPSEvaluation ();
4104
4105   if (IS_BIT(_G.currentFunc->etype))
4106     {
4107       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4108       size = 0;
4109     }
4110
4111   while (size--)
4112     {
4113       char *l;
4114       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4115         {
4116           l = aopGet (IC_LEFT (ic), offset++,
4117                       FALSE, TRUE, NULL);
4118           emitcode ("push", "%s", l);
4119           pushed++;
4120         }
4121       else
4122         {
4123           /* Since A is the last element of fReturn,
4124            * it is OK to clobber it in the aopGet.
4125            */
4126           l = aopGet (IC_LEFT (ic), offset,
4127                       FALSE, FALSE, NULL);
4128           if (strcmp (fReturn[offset], l))
4129             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4130         }
4131     }
4132   _endLazyDPSEvaluation ();
4133
4134   while (pushed)
4135     {
4136       pushed--;
4137       if (strcmp (fReturn[pushed], "a"))
4138         emitcode ("pop", fReturn[pushed]);
4139       else
4140         emitcode ("pop", "acc");
4141     }
4142   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4143
4144 jumpret:
4145   /* generate a jump to the return label
4146      if the next is not the return statement */
4147   if (!(ic->next && ic->next->op == LABEL &&
4148         IC_LABEL (ic->next) == returnLabel))
4149
4150     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4151
4152 }
4153
4154 /*-----------------------------------------------------------------*/
4155 /* genLabel - generates a label                                    */
4156 /*-----------------------------------------------------------------*/
4157 static void
4158 genLabel (iCode * ic)
4159 {
4160   /* special case never generate */
4161   if (IC_LABEL (ic) == entryLabel)
4162     return;
4163
4164   D (emitcode (";", "genLabel "));
4165
4166   emitcode ("", "!tlabeldef", (IC_LABEL (ic)->key + 100));
4167 }
4168
4169 /*-----------------------------------------------------------------*/
4170 /* genGoto - generates a ljmp                                      */
4171 /*-----------------------------------------------------------------*/
4172 static void
4173 genGoto (iCode * ic)
4174 {
4175   D (emitcode (";", "genGoto "));
4176
4177   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4178 }
4179
4180 /*-----------------------------------------------------------------*/
4181 /* findLabelBackwards: walks back through the iCode chain looking  */
4182 /* for the given label. Returns number of iCode instructions     */
4183 /* between that label and given ic.          */
4184 /* Returns zero if label not found.          */
4185 /*-----------------------------------------------------------------*/
4186 static int
4187 findLabelBackwards (iCode * ic, int key)
4188 {
4189   int count = 0;
4190
4191   while (ic->prev)
4192     {
4193       ic = ic->prev;
4194       count++;
4195
4196       /* If we have any pushes or pops, we cannot predict the distance.
4197          I don't like this at all, this should be dealt with in the
4198          back-end */
4199       if (ic->op == IPUSH || ic->op == IPOP) {
4200         return 0;
4201       }
4202
4203       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4204         {
4205           /* printf("findLabelBackwards = %d\n", count); */
4206           return count;
4207         }
4208     }
4209
4210   return 0;
4211 }
4212
4213 /*-----------------------------------------------------------------*/
4214 /* genPlusIncr :- does addition with increment if possible         */
4215 /*-----------------------------------------------------------------*/
4216 static bool
4217 genPlusIncr (iCode * ic)
4218 {
4219   unsigned int icount;
4220   unsigned int size = getDataSize (IC_RESULT (ic));
4221
4222   /* will try to generate an increment */
4223   /* if the right side is not a literal
4224      we cannot */
4225   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4226     return FALSE;
4227
4228   /* if the literal value of the right hand side
4229      is greater than 4 then it is not worth it */
4230   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4231     return FALSE;
4232
4233   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4234       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4235       while (icount--) {
4236           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4237       }
4238       return TRUE;
4239   }
4240   /* if increment 16 bits in register */
4241   if (
4242        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4243        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4244        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4245        (size > 1) &&
4246        (icount == 1))
4247     {
4248       symbol  *tlbl;
4249       int     emitTlbl;
4250       int     labelRange;
4251       char    *l;
4252
4253       /* If the next instruction is a goto and the goto target
4254        * is <= 5 instructions previous to this, we can generate
4255        * jumps straight to that target.
4256        */
4257       if (ic->next && ic->next->op == GOTO
4258           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4259           && labelRange <= 5)
4260         {
4261           D(emitcode (";", "tail increment optimized (range %d)", labelRange););
4262           tlbl = IC_LABEL (ic->next);
4263           emitTlbl = 0;
4264         }
4265       else
4266         {
4267           tlbl = newiTempLabel (NULL);
4268           emitTlbl = 1;
4269         }
4270       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4271       emitcode ("inc", "%s", l);
4272
4273       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4274           IS_AOP_PREG (IC_RESULT (ic)))
4275         {
4276           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4277         }
4278       else
4279         {
4280           emitcode ("clr", "a");
4281           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4282         }
4283
4284       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4285       emitcode ("inc", "%s", l);
4286       if (size > 2)
4287         {
4288           if (!strcmp(l, "acc"))
4289             {
4290                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4291             }
4292           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4293                    IS_AOP_PREG (IC_RESULT (ic)))
4294             {
4295                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4296             }
4297           else
4298             {
4299                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4300             }
4301
4302           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4303           emitcode ("inc", "%s", l);
4304         }
4305       if (size > 3)
4306         {
4307           if (!strcmp(l, "acc"))
4308             {
4309                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4310             }
4311           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4312                    IS_AOP_PREG (IC_RESULT (ic)))
4313             {
4314                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4315             }
4316           else
4317             {
4318                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4319             }
4320
4321           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4322           emitcode ("inc", "%s", l);
4323         }
4324
4325       if (emitTlbl)
4326         {
4327           emitcode ("", "!tlabeldef", tlbl->key + 100);
4328         }
4329       return TRUE;
4330     }
4331
4332   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4333       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4334       options.model == MODEL_FLAT24 )
4335     {
4336       if (IC_RESULT(ic)->isGptr)
4337         {
4338           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4339         }
4340       switch (size) {
4341       case 3:
4342           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4343       case 2:
4344           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4345       case 1:
4346           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4347           break;
4348       }
4349       while (icount--)
4350         emitcode ("inc", "dptr");
4351       return TRUE;
4352   }
4353
4354   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4355       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4356       icount <= 5 ) {
4357       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4358       while (icount--)
4359         emitcode ("inc", "dptr");
4360       emitcode ("mov", "dps,#0");
4361       return TRUE;
4362   }
4363
4364   /* if the sizes are greater than 1 then we cannot */
4365   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4366       AOP_SIZE (IC_LEFT (ic)) > 1)
4367     return FALSE;
4368
4369   /* we can if the aops of the left & result match or
4370      if they are in registers and the registers are the
4371      same */
4372   if (
4373        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4374        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4375        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4376     {
4377       if (icount > 3)
4378         {
4379           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4380           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4381           aopPut (IC_RESULT (ic), "a", 0);
4382         }
4383       else
4384         {
4385           _startLazyDPSEvaluation ();
4386           while (icount--)
4387             {
4388               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4389             }
4390           _endLazyDPSEvaluation ();
4391         }
4392
4393       return TRUE;
4394     }
4395
4396   return FALSE;
4397 }
4398
4399 /*-----------------------------------------------------------------*/
4400 /* outBitAcc - output a bit in acc                                 */
4401 /*-----------------------------------------------------------------*/
4402 static void
4403 outBitAcc (operand * result)
4404 {
4405   symbol *tlbl = newiTempLabel (NULL);
4406   /* if the result is a bit */
4407   if (AOP_TYPE (result) == AOP_CRY)
4408     {
4409       aopPut (result, "a", 0);
4410     }
4411   else
4412     {
4413       emitcode ("jz", "!tlabel", tlbl->key + 100);
4414       emitcode ("mov", "a,%s", one);
4415       emitcode ("", "!tlabeldef", tlbl->key + 100);
4416       outAcc (result);
4417     }
4418 }
4419
4420 /*-----------------------------------------------------------------*/
4421 /* genPlusBits - generates code for addition of two bits           */
4422 /*-----------------------------------------------------------------*/
4423 static void
4424 genPlusBits (iCode * ic)
4425 {
4426   D (emitcode (";", "genPlusBits "));
4427
4428   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4429     {
4430       symbol *lbl = newiTempLabel (NULL);
4431       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4432       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4433       emitcode ("cpl", "c");
4434       emitcode ("", "!tlabeldef", (lbl->key + 100));
4435       outBitC (IC_RESULT (ic));
4436     }
4437   else
4438     {
4439       emitcode ("clr", "a");
4440       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4441       emitcode ("rlc", "a");
4442       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4443       emitcode ("addc", "a,%s", zero);
4444       outAcc (IC_RESULT (ic));
4445     }
4446 }
4447
4448 static void
4449 adjustArithmeticResult (iCode * ic)
4450 {
4451   if (opIsGptr (IC_RESULT (ic)) &&
4452       opIsGptr (IC_LEFT (ic)) &&
4453       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4454     {
4455       aopPut (IC_RESULT (ic),
4456               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4457               GPTRSIZE - 1);
4458     }
4459
4460   if (opIsGptr (IC_RESULT (ic)) &&
4461       opIsGptr (IC_RIGHT (ic)) &&
4462       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4463     {
4464       aopPut (IC_RESULT (ic),
4465             aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4466               GPTRSIZE - 1);
4467     }
4468
4469   if (opIsGptr (IC_RESULT (ic)) &&
4470       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4471       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4472       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4473       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4474     {
4475       char buffer[5];
4476       SNPRINTF (buffer, sizeof(buffer),
4477                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4478       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4479     }
4480 }
4481
4482 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4483 // generates the result if possible. If result is generated, returns TRUE; otherwise
4484 // returns false and caller must deal with fact that result isn't aopOp'd.
4485 bool aopOp3(iCode * ic)
4486 {
4487     bool dp1InUse, dp2InUse;
4488     bool useDp2;
4489
4490     // First, generate the right opcode. DPTR may be used if neither left nor result are
4491     // of type AOP_STR.
4492
4493 //    D(emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4494 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4495 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4496 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4497 //      );
4498 //    D(emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4499 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4500 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4501 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4502 //      );
4503
4504     // Right uses DPTR unless left or result is an AOP_STR; however,
4505     // if right is an AOP_STR, it must use DPTR regardless.
4506     if ((AOP_IS_STR(IC_LEFT(ic)) || AOP_IS_STR(IC_RESULT(ic)))
4507      && !AOP_IS_STR(IC_RIGHT(ic)))
4508     {
4509         useDp2 = TRUE;
4510     }
4511     else
4512     {
4513         useDp2 = FALSE;
4514     }
4515
4516     aopOp (IC_RIGHT(ic),ic,FALSE, useDp2);
4517
4518     // if the right used DPTR, left MUST use DPTR2.
4519     // if the right used DPTR2, left MUST use DPTR.
4520     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4521     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4522     // enabling us to assign DPTR to result.
4523
4524     if (AOP_USESDPTR(IC_RIGHT(ic)))
4525     {
4526         useDp2 = TRUE;
4527     }
4528     else if (AOP_USESDPTR2(IC_RIGHT(ic)))
4529     {
4530         useDp2 = FALSE;
4531     }
4532     else
4533     {
4534         if (AOP_IS_STR(IC_RESULT(ic)) && !AOP_IS_STR(IC_LEFT(ic)))
4535         {
4536             useDp2 = TRUE;
4537         }
4538         else
4539         {
4540             useDp2 = FALSE;
4541         }
4542     }
4543
4544     aopOp(IC_LEFT(ic), ic, FALSE, useDp2);
4545
4546
4547     // We've op'd the left & right. So, if left or right are the same operand as result,
4548     // we know aopOp will succeed, and we can just do it & bail.
4549     if (isOperandEqual(IC_LEFT(ic),IC_RESULT(ic)))
4550       {
4551         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4552         return TRUE;
4553       }
4554     if (isOperandEqual(IC_RIGHT(ic),IC_RESULT(ic)))
4555       {
4556 //      D(emitcode(";", "aopOp3: (left | right) & result equal"););
4557         aopOp(IC_RESULT(ic),ic,TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4558         return TRUE;
4559       }
4560
4561     // Operands may be equivalent (but not equal) if they share a spill location. If
4562     // so, use the same DPTR or DPTR2.
4563     if (operandsEqu (IC_LEFT(ic), IC_RESULT(ic)))
4564       {
4565         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4566         return TRUE;
4567       }
4568     if (operandsEqu (IC_RIGHT(ic), IC_RESULT(ic)))
4569       {
4570         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4571         return TRUE;
4572       }
4573
4574     // Note which dptrs are currently in use.
4575     dp1InUse = AOP_USESDPTR(IC_LEFT(ic)) || AOP_USESDPTR(IC_RIGHT(ic));
4576     dp2InUse = AOP_USESDPTR2(IC_LEFT(ic)) || AOP_USESDPTR2(IC_RIGHT(ic));
4577
4578     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4579     // generate it.
4580     if (dp1InUse && AOP_IS_STR(IC_RESULT(ic)))
4581     {
4582         return FALSE;
4583     }
4584
4585     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4586     if (dp2InUse && AOP_IS_DPTRn(IC_RESULT(ic)))
4587     {
4588         return FALSE;
4589     }
4590
4591     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4592     if (dp1InUse && dp2InUse && isOperandInFarSpace(IC_RESULT(ic)))
4593     {
4594         return FALSE;
4595     }
4596
4597     aopOp (IC_RESULT(ic),ic,TRUE, dp1InUse);
4598
4599     // Some sanity checking...
4600     if (dp1InUse && AOP_USESDPTR(IC_RESULT(ic)))
4601     {
4602         fprintf(stderr,
4603                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4604                 __FILE__, __LINE__, ic->filename, ic->lineno);
4605         emitcode(";", ">>> unexpected DPTR here.");
4606     }
4607
4608     if (dp2InUse && AOP_USESDPTR2(IC_RESULT(ic)))
4609     {
4610         fprintf(stderr,
4611                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4612                 __FILE__, __LINE__, ic->filename, ic->lineno);
4613         emitcode(";", ">>> unexpected DPTR2 here.");
4614     }
4615
4616     return TRUE;
4617 }
4618
4619 // Macro to aopOp all three operands of an ic. If this cannot be done,
4620 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4621 // will be set TRUE. The caller must then handle the case specially, noting
4622 // that the IC_RESULT operand is not aopOp'd.
4623 //
4624 #define AOP_OP_3_NOFATAL(ic, rc) \
4625             do { rc = !aopOp3(ic); } while (0)
4626
4627 // aopOp the left & right operands of an ic.
4628 #define AOP_OP_2(ic) \
4629     aopOp (IC_RIGHT(ic),ic,FALSE, AOP_IS_STR(IC_LEFT(ic))); \
4630     aopOp (IC_LEFT(ic),ic,FALSE, AOP_USESDPTR(IC_RIGHT(ic)));
4631
4632 // convienience macro.
4633 #define AOP_SET_LOCALS(ic) \
4634     left = IC_LEFT(ic); \
4635     right = IC_RIGHT(ic); \
4636     result = IC_RESULT(ic);
4637
4638
4639 // Given an integer value of pushedSize bytes on the stack,
4640 // adjust it to be resultSize bytes, either by discarding
4641 // the most significant bytes or by zero-padding.
4642 //
4643 // On exit from this macro, pushedSize will have been adjusted to
4644 // equal resultSize, and ACC may be trashed.
4645 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4646       /* If the pushed data is bigger than the result,          \
4647        * simply discard unused bytes. Icky, but works.          \
4648        */                                                       \
4649       while (pushedSize > resultSize)                           \
4650       {                                                         \
4651           D (emitcode (";", "discarding unused result byte."););\
4652           emitcode ("pop", "acc");                              \
4653           pushedSize--;                                         \
4654       }                                                         \
4655       if (pushedSize < resultSize)                              \
4656       {                                                         \
4657           emitcode ("clr", "a");                                \
4658           /* Conversly, we haven't pushed enough here.          \
4659            * just zero-pad, and all is well.                    \
4660            */                                                   \
4661           while (pushedSize < resultSize)                       \
4662           {                                                     \
4663               emitcode("push", "acc");                          \
4664               pushedSize++;                                     \
4665           }                                                     \
4666       }                                                         \
4667       assert(pushedSize == resultSize);
4668
4669 /*-----------------------------------------------------------------*/
4670 /* genPlus - generates code for addition                           */
4671 /*-----------------------------------------------------------------*/
4672 static void
4673 genPlus (iCode * ic)
4674 {
4675   int size, offset = 0;
4676   bool pushResult;
4677   int rSize;
4678   bool swappedLR = FALSE;
4679
4680   D (emitcode (";", "genPlus "));
4681
4682   /* special cases :- */
4683   if ( AOP_IS_STR(IC_LEFT(ic)) &&
4684       isOperandLiteral(IC_RIGHT(ic)) && OP_SYMBOL(IC_RESULT(ic))->ruonly) {
4685       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4686       size = (int)floatFromVal (AOP (IC_RIGHT(ic))->aopu.aop_lit);
4687       if (size <= 9) {
4688           while (size--) emitcode ("inc","dptr");
4689       } else {
4690           emitcode ("mov","a,dpl");
4691           emitcode ("add","a,#!constbyte",size & 0xff);
4692           emitcode ("mov","dpl,a");
4693           emitcode ("mov","a,dph");
4694           emitcode ("addc","a,#!constbyte",(size >> 8) & 0xff);
4695           emitcode ("mov","dph,a");
4696           emitcode ("mov","a,dpx");
4697           emitcode ("addc","a,#!constbyte",(size >> 16) & 0xff);
4698           emitcode ("mov","dpx,a");
4699       }
4700       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4701       return ;
4702   }
4703   if ( IS_SYMOP(IC_LEFT(ic)) &&
4704        OP_SYMBOL(IC_LEFT(ic))->remat &&
4705        isOperandInFarSpace(IC_RIGHT(ic))) {
4706       operand *op = IC_RIGHT(ic);
4707       IC_RIGHT(ic) = IC_LEFT(ic);
4708       IC_LEFT(ic) = op;
4709   }
4710
4711   AOP_OP_3_NOFATAL (ic, pushResult);
4712
4713   if (pushResult)
4714     {
4715       D (emitcode (";", "genPlus: must push result: 3 ops in far space"););
4716     }
4717
4718   if (!pushResult)
4719     {
4720       /* if literal, literal on the right or
4721          if left requires ACC or right is already
4722          in ACC */
4723       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4724        || ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic))))
4725           || AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4726         {
4727           operand *t = IC_RIGHT (ic);
4728           IC_RIGHT (ic) = IC_LEFT (ic);
4729           IC_LEFT (ic) = t;
4730           swappedLR = TRUE;
4731           emitcode (";", "Swapped plus args.");
4732         }
4733
4734       /* if both left & right are in bit
4735          space */
4736       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4737           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4738         {
4739           genPlusBits (ic);
4740           goto release;
4741         }
4742
4743       /* if left in bit space & right literal */
4744       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4745           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4746         {
4747           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4748           /* if result in bit space */
4749           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4750             {
4751               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4752                 emitcode ("cpl", "c");
4753               outBitC (IC_RESULT (ic));
4754             }
4755           else
4756             {
4757               size = getDataSize (IC_RESULT (ic));
4758               _startLazyDPSEvaluation ();
4759               while (size--)
4760                 {
4761                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4762                   emitcode ("addc", "a,%s", zero);
4763                   aopPut (IC_RESULT (ic), "a", offset++);
4764                 }
4765               _endLazyDPSEvaluation ();
4766             }
4767           goto release;
4768         }
4769
4770       /* if I can do an increment instead
4771          of add then GOOD for ME */
4772       if (genPlusIncr (ic) == TRUE)
4773         {
4774           emitcode (";", "did genPlusIncr");
4775           goto release;
4776         }
4777
4778     }
4779   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4780
4781   _startLazyDPSEvaluation ();
4782   while (size--)
4783     {
4784       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4785         {
4786           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4787           if (offset == 0)
4788             emitcode ("add", "a,%s",
4789                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4790           else
4791             emitcode ("addc", "a,%s",
4792                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4793         }
4794       else
4795         {
4796           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4797           {
4798               /* right is going to use ACC or we would have taken the
4799                * above branch.
4800                */
4801               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4802        TR_AP("#3");
4803               D(emitcode(";", "+ AOP_ACC special case."););
4804               emitcode("xch", "a, %s", DP2_RESULT_REG);
4805           }
4806           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4807           if (offset == 0)
4808           {
4809             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4810             {
4811          TR_AP("#4");
4812                 emitcode("add", "a, %s", DP2_RESULT_REG);
4813             }
4814             else
4815             {
4816                 emitcode ("add", "a,%s",
4817                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4818                                   DP2_RESULT_REG));
4819             }
4820           }
4821           else
4822           {
4823             emitcode ("addc", "a,%s",
4824                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4825                           DP2_RESULT_REG));
4826           }
4827         }
4828       if (!pushResult)
4829         {
4830           aopPut (IC_RESULT (ic), "a", offset);
4831         }
4832       else
4833         {
4834           emitcode ("push", "acc");
4835         }
4836       offset++;
4837     }
4838   _endLazyDPSEvaluation ();
4839
4840   if (pushResult)
4841     {
4842       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4843
4844       size = getDataSize (IC_LEFT (ic));
4845       rSize = getDataSize (IC_RESULT (ic));
4846
4847       ADJUST_PUSHED_RESULT(size, rSize);
4848
4849       _startLazyDPSEvaluation ();
4850       while (size--)
4851         {
4852           emitcode ("pop", "acc");
4853           aopPut (IC_RESULT (ic), "a", size);
4854         }
4855       _endLazyDPSEvaluation ();
4856     }
4857
4858   adjustArithmeticResult (ic);
4859
4860 release:
4861   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4862   if (!swappedLR)
4863     {
4864       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4865       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4866     }
4867   else
4868     {
4869       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4870       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4871     }
4872 }
4873
4874 /*-----------------------------------------------------------------*/
4875 /* genMinusDec :- does subtraction with decrement if possible      */
4876 /*-----------------------------------------------------------------*/
4877 static bool
4878 genMinusDec (iCode * ic)
4879 {
4880   unsigned int icount;
4881   unsigned int size = getDataSize (IC_RESULT (ic));
4882
4883   /* will try to generate an increment */
4884   /* if the right side is not a literal
4885      we cannot */
4886   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4887     return FALSE;
4888
4889   /* if the literal value of the right hand side
4890      is greater than 4 then it is not worth it */
4891   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4892     return FALSE;
4893
4894   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4895       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4896       while (icount--) {
4897           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4898       }
4899       return TRUE;
4900   }
4901   /* if decrement 16 bits in register */
4902   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4903       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4904       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4905       (size > 1) &&
4906       (icount == 1))
4907     {
4908       symbol *tlbl;
4909       int    emitTlbl;
4910       int    labelRange;
4911       char   *l;
4912
4913       /* If the next instruction is a goto and the goto target
4914          * is <= 5 instructions previous to this, we can generate
4915          * jumps straight to that target.
4916        */
4917       if (ic->next && ic->next->op == GOTO
4918           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4919           && labelRange <= 5)
4920         {
4921           emitcode (";", "tail decrement optimized (range %d)", labelRange);
4922           tlbl = IC_LABEL (ic->next);
4923           emitTlbl = 0;
4924         }
4925       else
4926         {
4927           tlbl = newiTempLabel (NULL);
4928           emitTlbl = 1;
4929         }
4930
4931       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4932       emitcode ("dec", "%s", l);
4933
4934       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4935           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4936           IS_AOP_PREG (IC_RESULT (ic)))
4937       {
4938           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4939       }
4940       else
4941       {
4942           emitcode ("mov", "a,#!constbyte",0xff);
4943           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4944       }
4945       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4946       emitcode ("dec", "%s", l);
4947       if (size > 2)
4948         {
4949             if (!strcmp(l, "acc"))
4950             {
4951                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4952             }
4953             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4954                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4955                      IS_AOP_PREG (IC_RESULT (ic)))
4956             {
4957                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4958             }
4959             else
4960             {
4961                 emitcode ("mov", "a,#!constbyte",0xff);
4962                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4963             }
4964             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4965             emitcode ("dec", "%s", l);
4966         }
4967       if (size > 3)
4968         {
4969             if (!strcmp(l, "acc"))
4970             {
4971                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4972             }
4973             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4974                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4975                      IS_AOP_PREG (IC_RESULT (ic)))
4976             {
4977                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4978             }
4979             else
4980             {
4981                 emitcode ("mov", "a,#!constbyte",0xff);
4982                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4983             }
4984             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4985             emitcode ("dec", "%s", l);
4986         }
4987       if (emitTlbl)
4988         {
4989           emitcode ("", "!tlabeldef", tlbl->key + 100);
4990         }
4991       return TRUE;
4992     }
4993
4994   /* if the sizes are greater than 1 then we cannot */
4995   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4996       AOP_SIZE (IC_LEFT (ic)) > 1)
4997     return FALSE;
4998
4999   /* we can if the aops of the left & result match or
5000      if they are in registers and the registers are the
5001      same */
5002   if (
5003        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
5004        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
5005        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
5006     {
5007       char *l;
5008
5009       if (aopGetUsesAcc (IC_LEFT (ic), 0))
5010         {
5011           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
5012           l = "a";
5013         }
5014       else
5015         {
5016           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5017         }
5018
5019       _startLazyDPSEvaluation ();
5020       while (icount--)
5021         {
5022           emitcode ("dec", "%s", l);
5023         }
5024       _endLazyDPSEvaluation ();
5025
5026       if (AOP_NEEDSACC (IC_RESULT (ic)))
5027         aopPut (IC_RESULT (ic), "a", 0);
5028
5029       return TRUE;
5030     }
5031
5032   return FALSE;
5033 }
5034
5035 /*-----------------------------------------------------------------*/
5036 /* addSign - complete with sign                                    */
5037 /*-----------------------------------------------------------------*/
5038 static void
5039 addSign (operand * result, int offset, int sign)
5040 {
5041   int size = (getDataSize (result) - offset);
5042   if (size > 0)
5043     {
5044       _startLazyDPSEvaluation();
5045       if (sign)
5046         {
5047           emitcode ("rlc", "a");
5048           emitcode ("subb", "a,acc");
5049           while (size--)
5050           {
5051             aopPut (result, "a", offset++);
5052           }
5053         }
5054       else
5055       {
5056         while (size--)
5057         {
5058           aopPut (result, zero, offset++);
5059         }
5060       }
5061       _endLazyDPSEvaluation();
5062     }
5063 }
5064
5065 /*-----------------------------------------------------------------*/
5066 /* genMinusBits - generates code for subtraction  of two bits      */
5067 /*-----------------------------------------------------------------*/
5068 static void
5069 genMinusBits (iCode * ic)
5070 {
5071   symbol *lbl = newiTempLabel (NULL);
5072
5073   D (emitcode (";", "genMinusBits "));
5074
5075   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5076     {
5077       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5078       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5079       emitcode ("cpl", "c");
5080       emitcode ("", "!tlabeldef", (lbl->key + 100));
5081       outBitC (IC_RESULT (ic));
5082     }
5083   else
5084     {
5085       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5086       emitcode ("subb", "a,acc");
5087       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5088       emitcode ("inc", "a");
5089       emitcode ("", "!tlabeldef", (lbl->key + 100));
5090       aopPut (IC_RESULT (ic), "a", 0);
5091       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5092     }
5093 }
5094
5095 /*-----------------------------------------------------------------*/
5096 /* genMinus - generates code for subtraction                       */
5097 /*-----------------------------------------------------------------*/
5098 static void
5099 genMinus (iCode * ic)
5100 {
5101     int size, offset = 0;
5102     int rSize;
5103     long lit = 0L;
5104     bool pushResult;
5105
5106     D (emitcode (";", "genMinus "));
5107
5108     AOP_OP_3_NOFATAL(ic, pushResult);
5109
5110     if (!pushResult)
5111     {
5112       /* special cases :- */
5113       /* if both left & right are in bit space */
5114       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5115           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5116         {
5117           genMinusBits (ic);
5118           goto release;
5119         }
5120
5121       /* if I can do an decrement instead
5122          of subtract then GOOD for ME */
5123       if (genMinusDec (ic) == TRUE)
5124         goto release;
5125
5126     }
5127
5128   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5129
5130   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5131     {
5132       CLRC;
5133     }
5134   else
5135     {
5136       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5137       lit = -lit;
5138     }
5139
5140
5141   /* if literal, add a,#-lit, else normal subb */
5142   _startLazyDPSEvaluation ();
5143   while (size--) {
5144       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5145           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5146               emitcode ("mov","b,%s",
5147                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5148               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5149               emitcode ("subb","a,b");
5150           } else {
5151               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5152               emitcode ("subb", "a,%s",
5153                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5154                                 DP2_RESULT_REG));
5155           }
5156       } else {
5157           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5158           /* first add without previous c */
5159           if (!offset) {
5160               if (!size && lit==-1) {
5161                   emitcode ("dec", "a");
5162               } else {
5163                   emitcode ("add", "a,#!constbyte",
5164                             (unsigned int) (lit & 0x0FFL));
5165               }
5166           } else {
5167               emitcode ("addc", "a,#!constbyte",
5168                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5169           }
5170       }
5171
5172       if (pushResult) {
5173           emitcode ("push", "acc");
5174       } else {
5175           aopPut (IC_RESULT (ic), "a", offset);
5176       }
5177       offset++;
5178   }
5179   _endLazyDPSEvaluation ();
5180
5181   if (pushResult)
5182     {
5183       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5184
5185       size = getDataSize (IC_LEFT (ic));
5186       rSize = getDataSize (IC_RESULT (ic));
5187
5188       ADJUST_PUSHED_RESULT(size, rSize);
5189
5190       _startLazyDPSEvaluation ();
5191       while (size--)
5192         {
5193           emitcode ("pop", "acc");
5194           aopPut (IC_RESULT (ic), "a", size);
5195         }
5196       _endLazyDPSEvaluation ();
5197     }
5198
5199   adjustArithmeticResult (ic);
5200
5201 release:
5202   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5203   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5204   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5205 }
5206
5207
5208 /*-----------------------------------------------------------------*/
5209 /* genMultbits :- multiplication of bits                           */
5210 /*-----------------------------------------------------------------*/
5211 static void
5212 genMultbits (operand * left,
5213              operand * right,
5214              operand * result,
5215              iCode   * ic)
5216 {
5217   D(emitcode (";", "genMultbits"));
5218
5219   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5220   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5221   aopOp(result, ic, TRUE, FALSE);
5222   outBitC (result);
5223 }
5224
5225 /*-----------------------------------------------------------------*/
5226 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5227 /*-----------------------------------------------------------------*/
5228 static void
5229 genMultOneByte (operand * left,
5230                 operand * right,
5231                 operand * result,
5232                 iCode   * ic)
5233 {
5234   symbol *lbl;
5235   int size;
5236   bool runtimeSign, compiletimeSign;
5237   bool lUnsigned, rUnsigned, pushedB;
5238
5239   /* (if two literals: the value is computed before) */
5240   /* if one literal, literal on the right */
5241   if (AOP_TYPE (left) == AOP_LIT)
5242     {
5243       operand *t = right;
5244       right = left;
5245       left = t;
5246       /* emitcode (";", "swapped left and right"); */
5247     }
5248   /* if no literal, unsigned on the right: shorter code */
5249   if (   AOP_TYPE (right) != AOP_LIT
5250       && SPEC_USIGN (getSpec (operandType (left))))
5251     {
5252       operand *t = right;
5253       right = left;
5254       left = t;
5255     }
5256
5257   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5258   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5259
5260   pushedB = pushB ();
5261
5262   if ((lUnsigned && rUnsigned)
5263 /* sorry, I don't know how to get size
5264    without calling aopOp (result,...);
5265    see Feature Request  */
5266       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5267                    no need to take care about the signedness! */
5268     {
5269       /* just an unsigned 8 * 8 = 8 multiply
5270          or 8u * 8u = 16u */
5271       /* emitcode (";","unsigned"); */
5272       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5273       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5274       emitcode ("mul", "ab");
5275
5276       _G.accInUse++;
5277       aopOp (result, ic, TRUE, FALSE);
5278       size = AOP_SIZE (result);
5279
5280       if (size < 1 || size > 2)
5281         {
5282           /* this should never happen */
5283           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5284                    size, __FILE__, lineno);
5285           exit (1);
5286         }
5287
5288       aopPut (result, "a", 0);
5289       _G.accInUse--;
5290       if (size == 2)
5291         aopPut (result, "b", 1);
5292
5293       popB (pushedB);
5294       return;
5295     }
5296
5297   /* we have to do a signed multiply */
5298   /* emitcode (";", "signed"); */
5299
5300   /* now sign adjust for both left & right */
5301
5302   /* let's see what's needed: */
5303   /* apply negative sign during runtime */
5304   runtimeSign = FALSE;
5305   /* negative sign from literals */
5306   compiletimeSign = FALSE;
5307
5308   if (!lUnsigned)
5309     {
5310       if (AOP_TYPE(left) == AOP_LIT)
5311         {
5312           /* signed literal */
5313           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5314           if (val < 0)
5315             compiletimeSign = TRUE;
5316         }
5317       else
5318         /* signed but not literal */
5319         runtimeSign = TRUE;
5320     }
5321
5322   if (!rUnsigned)
5323     {
5324       if (AOP_TYPE(right) == AOP_LIT)
5325         {
5326           /* signed literal */
5327           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5328           if (val < 0)
5329             compiletimeSign ^= TRUE;
5330         }
5331       else
5332         /* signed but not literal */
5333         runtimeSign = TRUE;
5334     }
5335
5336   /* initialize F0, which stores the runtime sign */
5337   if (runtimeSign)
5338     {
5339       if (compiletimeSign)
5340         emitcode ("setb", "F0"); /* set sign flag */
5341       else
5342         emitcode ("clr", "F0"); /* reset sign flag */
5343     }
5344
5345   /* save the signs of the operands */
5346   if (AOP_TYPE(right) == AOP_LIT)
5347     {
5348       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5349
5350       if (!rUnsigned && val < 0)
5351         emitcode ("mov", "b,#!constbyte", -val);
5352       else
5353         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5354     }
5355   else /* ! literal */
5356     {
5357       if (rUnsigned)  /* emitcode (";", "signed"); */
5358         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5359       else
5360         {
5361           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5362           lbl = newiTempLabel (NULL);
5363           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5364           emitcode ("cpl", "F0"); /* complement sign flag */
5365           emitcode ("cpl", "a");  /* 2's complement */
5366           emitcode ("inc", "a");
5367           emitcode ("", "!tlabeldef", lbl->key + 100);
5368           emitcode ("mov", "b,a");
5369         }
5370     }
5371
5372   if (AOP_TYPE(left) == AOP_LIT)
5373     {
5374       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5375
5376       if (!lUnsigned && val < 0)
5377         emitcode ("mov", "a,#!constbyte", -val);
5378       else
5379         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5380     }
5381   else /* ! literal */
5382     {
5383       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5384
5385       if (!lUnsigned)  /* emitcode (";", "signed"); */
5386         {
5387           lbl = newiTempLabel (NULL);
5388           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5389           emitcode ("cpl", "F0"); /* complement sign flag */
5390           emitcode ("cpl", "a");  /* 2's complement */
5391           emitcode ("inc", "a");
5392           emitcode ("", "!tlabeldef", lbl->key + 100);
5393         }
5394     }
5395
5396   /* now the multiplication */
5397   emitcode ("mul", "ab");
5398   _G.accInUse++;
5399   aopOp(result, ic, TRUE, FALSE);
5400   size = AOP_SIZE (result);
5401
5402   if (size < 1 || size > 2)
5403     {
5404       /* this should never happen */
5405       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5406                size, __FILE__, lineno);
5407       exit (1);
5408     }
5409
5410   if (runtimeSign || compiletimeSign)
5411     {
5412       lbl = newiTempLabel (NULL);
5413       if (runtimeSign)
5414         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5415       emitcode ("cpl", "a"); /* lsb 2's complement */
5416       if (size != 2)
5417         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5418       else
5419         {
5420           emitcode ("add", "a,#1"); /* this sets carry flag */
5421           emitcode ("xch", "a,b");
5422           emitcode ("cpl", "a"); /* msb 2's complement */
5423           emitcode ("addc", "a,#0");
5424           emitcode ("xch", "a,b");
5425         }
5426       emitcode ("", "!tlabeldef", lbl->key + 100);
5427     }
5428   aopPut (result, "a", 0);
5429   _G.accInUse--;
5430   if (size == 2)
5431     aopPut (result, "b", 1);
5432
5433   popB (pushedB);
5434 }
5435
5436 /*-----------------------------------------------------------------*/
5437 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5438 /*-----------------------------------------------------------------*/
5439 static void genMultTwoByte (operand *left, operand *right,
5440                             operand *result, iCode *ic)
5441 {
5442         sym_link *retype = getSpec(operandType(right));
5443         sym_link *letype = getSpec(operandType(left));
5444         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5445         symbol *lbl;
5446
5447         if (AOP_TYPE (left) == AOP_LIT) {
5448                 operand *t = right;
5449                 right = left;
5450                 left = t;
5451         }
5452         /* save EA bit in F1 */
5453         lbl = newiTempLabel(NULL);
5454         emitcode ("setb","F1");
5455         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5456         emitcode ("clr","F1");
5457         emitcode("","!tlabeldef",lbl->key+100);
5458
5459         /* load up MB with right */
5460         if (!umult) {
5461                 emitcode("clr","F0");
5462                 if (AOP_TYPE(right) == AOP_LIT) {
5463                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5464                         if (val < 0) {
5465                                 emitcode("setb","F0");
5466                                 val = -val;
5467                         }
5468                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5469                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5470                 } else {
5471                         lbl = newiTempLabel(NULL);
5472                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5473                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5474                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5475                         emitcode ("xch", "a,b");
5476                         emitcode ("cpl","a");
5477                         emitcode ("add", "a,#1");
5478                         emitcode ("xch", "a,b");
5479                         emitcode ("cpl", "a"); // msb
5480                         emitcode ("addc", "a,#0");
5481                         emitcode ("setb","F0");
5482                         emitcode ("","!tlabeldef",lbl->key+100);
5483                         emitcode ("mov","mb,b");
5484                         emitcode ("mov","mb,a");
5485                 }
5486         } else {
5487                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5488                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5489         }
5490         /* load up MA with left */
5491         if (!umult) {
5492                 lbl = newiTempLabel(NULL);
5493                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5494                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5495                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5496                 emitcode ("xch", "a,b");
5497                 emitcode ("cpl","a");
5498                 emitcode ("add", "a,#1");
5499                 emitcode ("xch", "a,b");
5500                 emitcode ("cpl", "a"); // msb
5501                 emitcode ("addc","a,#0");
5502                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5503                 emitcode ("setb","F0");
5504                 emitcode ("","!tlabeldef",lbl->key+100);
5505                 emitcode ("mov","ma,b");
5506                 emitcode ("mov","ma,a");
5507         } else {
5508                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5509                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5510         }
5511         /* wait for multiplication to finish */
5512         lbl = newiTempLabel(NULL);
5513         emitcode("","!tlabeldef", lbl->key+100);
5514         emitcode("mov","a,mcnt1");
5515         emitcode("anl","a,#!constbyte",0x80);
5516         emitcode("jnz","!tlabel",lbl->key+100);
5517
5518         freeAsmop (left, NULL, ic, TRUE);
5519         freeAsmop (right, NULL, ic,TRUE);
5520         aopOp(result, ic, TRUE, FALSE);
5521
5522         /* if unsigned then simple */
5523         if (umult) {
5524                 emitcode ("mov","a,ma");
5525                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5526                 emitcode ("mov","a,ma");
5527                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5528                 aopPut(result,"ma",1);
5529                 aopPut(result,"ma",0);
5530         } else {
5531                 emitcode("push","ma");
5532                 emitcode("push","ma");
5533                 emitcode("push","ma");
5534                 MOVA("ma");
5535                 /* negate result if needed */
5536                 lbl = newiTempLabel(NULL);
5537                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5538                 emitcode("cpl","a");
5539                 emitcode("add","a,#1");
5540                 emitcode("","!tlabeldef", lbl->key+100);
5541                 if (AOP_TYPE(result) == AOP_ACC)
5542                 {
5543                     D(emitcode(";", "ACC special case."););
5544                     /* We know result is the only live aop, and
5545                      * it's obviously not a DPTR2, so AP is available.
5546                      */
5547                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5548                 }
5549                 else
5550                 {
5551                     aopPut(result,"a",0);
5552                 }
5553
5554                 emitcode("pop","acc");
5555                 lbl = newiTempLabel(NULL);
5556                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5557                 emitcode("cpl","a");
5558                 emitcode("addc","a,#0");
5559                 emitcode("","!tlabeldef", lbl->key+100);
5560                 aopPut(result,"a",1);
5561                 emitcode("pop","acc");
5562                 if (AOP_SIZE(result) >= 3) {
5563                         lbl = newiTempLabel(NULL);
5564                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5565                         emitcode("cpl","a");
5566                         emitcode("addc","a,#0");
5567                         emitcode("","!tlabeldef", lbl->key+100);
5568                         aopPut(result,"a",2);
5569                 }
5570                 emitcode("pop","acc");
5571                 if (AOP_SIZE(result) >= 4) {
5572                         lbl = newiTempLabel(NULL);
5573                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5574                         emitcode("cpl","a");
5575                         emitcode("addc","a,#0");
5576                         emitcode("","!tlabeldef", lbl->key+100);
5577                         aopPut(result,"a",3);
5578                 }
5579                 if (AOP_TYPE(result) == AOP_ACC)
5580                 {
5581                     /* We stashed the result away above. */
5582                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5583                 }
5584
5585         }
5586         freeAsmop (result, NULL, ic, TRUE);
5587
5588         /* restore EA bit in F1 */
5589         lbl = newiTempLabel(NULL);
5590         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5591         emitcode ("setb","EA");
5592         emitcode("","!tlabeldef",lbl->key+100);
5593         return ;
5594 }
5595
5596 /*-----------------------------------------------------------------*/
5597 /* genMult - generates code for multiplication                     */
5598 /*-----------------------------------------------------------------*/
5599 static void
5600 genMult (iCode * ic)
5601 {
5602   operand *left = IC_LEFT (ic);
5603   operand *right = IC_RIGHT (ic);
5604   operand *result = IC_RESULT (ic);
5605
5606   D (emitcode (";", "genMult "));
5607
5608   /* assign the asmops */
5609   AOP_OP_2 (ic);
5610
5611   /* special cases first */
5612   /* both are bits */
5613   if (AOP_TYPE (left) == AOP_CRY &&
5614       AOP_TYPE (right) == AOP_CRY)
5615     {
5616       genMultbits (left, right, result, ic);
5617       goto release;
5618     }
5619
5620   /* if both are of size == 1 */
5621   if (AOP_SIZE (left) == 1 &&
5622       AOP_SIZE (right) == 1)
5623     {
5624       genMultOneByte (left, right, result, ic);
5625       goto release;
5626     }
5627
5628   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5629           /* use the ds390 ARITHMETIC accel UNIT */
5630           genMultTwoByte (left, right, result, ic);
5631           return ;
5632   }
5633   /* should have been converted to function call */
5634   assert (0);
5635
5636 release:
5637   freeAsmop (result, NULL, ic, TRUE);
5638   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5639   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5640 }
5641
5642 /*-----------------------------------------------------------------*/
5643 /* genDivbits :- division of bits                                  */
5644 /*-----------------------------------------------------------------*/
5645 static void
5646 genDivbits (operand * left,
5647             operand * right,
5648             operand * result,
5649             iCode   * ic)
5650 {
5651   char *l;
5652   bool pushedB;
5653
5654   D(emitcode (";     genDivbits",""));
5655
5656   pushedB = pushB ();
5657
5658   /* the result must be bit */
5659   LOAD_AB_FOR_DIV (left, right, l);
5660   emitcode ("div", "ab");
5661   emitcode ("rrc", "a");
5662   aopOp(result, ic, TRUE, FALSE);
5663
5664   popB (pushedB);
5665
5666   aopPut (result, "c", 0);
5667 }
5668
5669 /*-----------------------------------------------------------------*/
5670 /* genDivOneByte : 8 bit division                                  */
5671 /*-----------------------------------------------------------------*/
5672 static void
5673 genDivOneByte (operand * left,
5674                operand * right,
5675                operand * result,
5676                iCode   * ic)
5677 {
5678   bool lUnsigned, rUnsigned, pushedB;
5679   bool runtimeSign, compiletimeSign;
5680   char *l;
5681   symbol *lbl;
5682   int size, offset;
5683
5684   D(emitcode (";     genDivOneByte",""));
5685
5686   offset = 1;
5687   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5688   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5689
5690   pushedB = pushB ();
5691
5692   /* signed or unsigned */
5693   if (lUnsigned && rUnsigned)
5694     {
5695       /* unsigned is easy */
5696       LOAD_AB_FOR_DIV (left, right, l);
5697       emitcode ("div", "ab");
5698
5699       _G.accInUse++;
5700       aopOp (result, ic, TRUE, FALSE);
5701       aopPut (result, "a", 0);
5702       _G.accInUse--;
5703
5704       size = AOP_SIZE (result) - 1;
5705
5706       while (size--)
5707         aopPut (result, zero, offset++);
5708
5709       popB (pushedB);
5710       return;
5711     }
5712
5713   /* signed is a little bit more difficult */
5714
5715   /* now sign adjust for both left & right */
5716
5717   /* let's see what's needed: */
5718   /* apply negative sign during runtime */
5719   runtimeSign = FALSE;
5720   /* negative sign from literals */
5721   compiletimeSign = FALSE;
5722
5723   if (!lUnsigned)
5724     {
5725       if (AOP_TYPE(left) == AOP_LIT)
5726         {
5727           /* signed literal */
5728           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5729           if (val < 0)
5730             compiletimeSign = TRUE;
5731         }
5732       else
5733         /* signed but not literal */
5734         runtimeSign = TRUE;
5735     }
5736
5737   if (!rUnsigned)
5738     {
5739       if (AOP_TYPE(right) == AOP_LIT)
5740         {
5741           /* signed literal */
5742           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5743           if (val < 0)
5744             compiletimeSign ^= TRUE;
5745         }
5746       else
5747         /* signed but not literal */
5748         runtimeSign = TRUE;
5749     }
5750
5751   /* initialize F0, which stores the runtime sign */
5752   if (runtimeSign)
5753     {
5754       if (compiletimeSign)
5755         emitcode ("setb", "F0"); /* set sign flag */
5756       else
5757         emitcode ("clr", "F0"); /* reset sign flag */
5758     }
5759
5760   /* save the signs of the operands */
5761   if (AOP_TYPE(right) == AOP_LIT)
5762     {
5763       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5764
5765       if (!rUnsigned && val < 0)
5766         emitcode ("mov", "b,#0x%02x", -val);
5767       else
5768         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5769     }
5770   else /* ! literal */
5771     {
5772       if (rUnsigned)
5773         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5774       else
5775         {
5776           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5777           lbl = newiTempLabel (NULL);
5778           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5779           emitcode ("cpl", "F0"); /* complement sign flag */
5780           emitcode ("cpl", "a");  /* 2's complement */
5781           emitcode ("inc", "a");
5782           emitcode ("", "!tlabeldef", lbl->key + 100);
5783           emitcode ("mov", "b,a");
5784         }
5785     }
5786
5787   if (AOP_TYPE(left) == AOP_LIT)
5788     {
5789       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5790
5791       if (!lUnsigned && val < 0)
5792         emitcode ("mov", "a,#0x%02x", -val);
5793       else
5794         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5795     }
5796   else /* ! literal */
5797     {
5798       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5799
5800       if (!lUnsigned)
5801         {
5802           lbl = newiTempLabel (NULL);
5803           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5804           emitcode ("cpl", "F0"); /* complement sign flag */
5805           emitcode ("cpl", "a");  /* 2's complement */
5806           emitcode ("inc", "a");
5807           emitcode ("", "!tlabeldef", lbl->key + 100);
5808         }
5809     }
5810
5811   /* now the division */
5812   emitcode ("nop", "; workaround for DS80C390 div bug.");
5813   emitcode ("div", "ab");
5814
5815   if (runtimeSign || compiletimeSign)
5816     {
5817       lbl = newiTempLabel (NULL);
5818       if (runtimeSign)
5819         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5820       emitcode ("cpl", "a"); /* lsb 2's complement */
5821       emitcode ("inc", "a");
5822       emitcode ("", "!tlabeldef", lbl->key + 100);
5823
5824       _G.accInUse++;
5825       aopOp (result, ic, TRUE, FALSE);
5826       size = AOP_SIZE (result) - 1;
5827
5828       if (size > 0)
5829         {
5830           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5831              then the result will be in b, a */
5832           emitcode ("mov", "b,a"); /* 1 */
5833           /* msb is 0x00 or 0xff depending on the sign */
5834           if (runtimeSign)
5835             {
5836               emitcode ("mov",  "c,F0");
5837               emitcode ("subb", "a,acc");
5838               emitcode ("xch",  "a,b"); /* 2 */
5839               while (size--)
5840                 aopPut (result, "b", offset++); /* write msb's */
5841             }
5842           else /* compiletimeSign */
5843             while (size--)
5844               aopPut (result, "#0xff", offset++); /* write msb's */
5845         }
5846       aopPut (result, "a", 0); /* 3: write lsb */
5847     }
5848   else
5849     {
5850       _G.accInUse++;
5851       aopOp(result, ic, TRUE, FALSE);
5852       size = AOP_SIZE (result) - 1;
5853
5854       aopPut (result, "a", 0);
5855       while (size--)
5856         aopPut (result, zero, offset++);
5857     }
5858   _G.accInUse--;
5859   popB (pushedB);
5860 }
5861
5862 /*-----------------------------------------------------------------*/
5863 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5864 /*-----------------------------------------------------------------*/
5865 static void genDivTwoByte (operand *left, operand *right,
5866                             operand *result, iCode *ic)
5867 {
5868         sym_link *retype = getSpec(operandType(right));
5869         sym_link *letype = getSpec(operandType(left));
5870         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5871         symbol *lbl;
5872
5873         /* save EA bit in F1 */
5874         lbl = newiTempLabel(NULL);
5875         emitcode ("setb","F1");
5876         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5877         emitcode ("clr","F1");
5878         emitcode("","!tlabeldef",lbl->key+100);
5879
5880         /* load up MA with left */
5881         if (!umult) {
5882                 emitcode("clr","F0");
5883                 lbl = newiTempLabel(NULL);
5884                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5885                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5886                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5887                 emitcode ("xch", "a,b");
5888                 emitcode ("cpl","a");
5889                 emitcode ("add", "a,#1");
5890                 emitcode ("xch", "a,b");
5891                 emitcode ("cpl", "a"); // msb
5892                 emitcode ("addc","a,#0");
5893                 emitcode ("setb","F0");
5894                 emitcode ("","!tlabeldef",lbl->key+100);
5895                 emitcode ("mov","ma,b");
5896                 emitcode ("mov","ma,a");
5897         } else {
5898                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5899                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5900         }
5901
5902         /* load up MB with right */
5903         if (!umult) {
5904                 if (AOP_TYPE(right) == AOP_LIT) {
5905                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5906                         if (val < 0) {
5907                                 lbl = newiTempLabel(NULL);
5908                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5909                                 emitcode("setb","F0");
5910                                 emitcode ("","!tlabeldef",lbl->key+100);
5911                                 val = -val;
5912                         }
5913                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5914                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5915                 } else {
5916                         lbl = newiTempLabel(NULL);
5917                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5918                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5919                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5920                         emitcode ("xch", "a,b");
5921                         emitcode ("cpl","a");
5922                         emitcode ("add", "a,#1");
5923                         emitcode ("xch", "a,b");
5924                         emitcode ("cpl", "a"); // msb
5925                         emitcode ("addc", "a,#0");
5926                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5927                         emitcode ("setb","F0");
5928                         emitcode ("","!tlabeldef",lbl->key+100);
5929                         emitcode ("mov","mb,b");
5930                         emitcode ("mov","mb,a");
5931                 }
5932         } else {
5933                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5934                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5935         }
5936
5937         /* wait for multiplication to finish */
5938         lbl = newiTempLabel(NULL);
5939         emitcode("","!tlabeldef", lbl->key+100);
5940         emitcode("mov","a,mcnt1");
5941         emitcode("anl","a,#!constbyte",0x80);
5942         emitcode("jnz","!tlabel",lbl->key+100);
5943
5944         freeAsmop (left, NULL, ic, TRUE);
5945         freeAsmop (right, NULL, ic,TRUE);
5946         aopOp(result, ic, TRUE, FALSE);
5947
5948         /* if unsigned then simple */
5949         if (umult) {
5950                 aopPut(result,"ma",1);
5951                 aopPut(result,"ma",0);
5952         } else {
5953                 emitcode("push","ma");
5954                 MOVA("ma");
5955                 /* negate result if needed */
5956                 lbl = newiTempLabel(NULL);
5957                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5958                 emitcode("cpl","a");
5959                 emitcode("add","a,#1");
5960                 emitcode("","!tlabeldef", lbl->key+100);
5961                 aopPut(result,"a",0);
5962                 emitcode("pop","acc");
5963                 lbl = newiTempLabel(NULL);
5964                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5965                 emitcode("cpl","a");
5966                 emitcode("addc","a,#0");
5967                 emitcode("","!tlabeldef", lbl->key+100);
5968                 aopPut(result,"a",1);
5969         }
5970         freeAsmop (result, NULL, ic, TRUE);
5971         /* restore EA bit in F1 */
5972         lbl = newiTempLabel(NULL);
5973         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5974         emitcode ("setb","EA");
5975         emitcode("","!tlabeldef",lbl->key+100);
5976         return ;
5977 }
5978
5979 /*-----------------------------------------------------------------*/
5980 /* genDiv - generates code for division                            */
5981 /*-----------------------------------------------------------------*/
5982 static void
5983 genDiv (iCode * ic)
5984 {
5985   operand *left = IC_LEFT (ic);
5986   operand *right = IC_RIGHT (ic);
5987   operand *result = IC_RESULT (ic);
5988
5989   D (emitcode (";", "genDiv "));
5990
5991   /* assign the amsops */
5992   AOP_OP_2 (ic);
5993
5994   /* special cases first */
5995   /* both are bits */
5996   if (AOP_TYPE (left) == AOP_CRY &&
5997       AOP_TYPE (right) == AOP_CRY)
5998     {
5999       genDivbits (left, right, result, ic);
6000       goto release;
6001     }
6002
6003   /* if both are of size == 1 */
6004   if (AOP_SIZE (left) == 1 &&
6005       AOP_SIZE (right) == 1)
6006     {
6007       genDivOneByte (left, right, result, ic);
6008       goto release;
6009     }
6010
6011   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6012           /* use the ds390 ARITHMETIC accel UNIT */
6013           genDivTwoByte (left, right, result, ic);
6014           return ;
6015   }
6016   /* should have been converted to function call */
6017   assert (0);
6018 release:
6019   freeAsmop (result, NULL, ic, TRUE);
6020   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6021   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6022 }
6023
6024 /*-----------------------------------------------------------------*/
6025 /* genModbits :- modulus of bits                                   */
6026 /*-----------------------------------------------------------------*/
6027 static void
6028 genModbits (operand * left,
6029             operand * right,
6030             operand * result,
6031             iCode   * ic)
6032 {
6033   char *l;
6034   bool pushedB;
6035
6036   D(emitcode (";     genModbits",""));
6037
6038   pushedB = pushB ();
6039
6040   /* the result must be bit */
6041   LOAD_AB_FOR_DIV (left, right, l);
6042   emitcode ("div", "ab");
6043   emitcode ("mov", "a,b");
6044   emitcode ("rrc", "a");
6045   aopOp(result, ic, TRUE, FALSE);
6046
6047   popB (pushedB);
6048
6049   aopPut (result, "c", 0);
6050 }
6051
6052 /*-----------------------------------------------------------------*/
6053 /* genModOneByte : 8 bit modulus                                   */
6054 /*-----------------------------------------------------------------*/
6055 static void
6056 genModOneByte (operand * left,
6057                operand * right,
6058                operand * result,
6059                iCode   * ic)
6060 {
6061   bool lUnsigned, rUnsigned, pushedB;
6062   bool runtimeSign, compiletimeSign;
6063   char *l;
6064   symbol *lbl;
6065   int size, offset;
6066
6067   D(emitcode (";     genModOneByte",""));
6068
6069   offset = 1;
6070   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6071   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6072
6073   pushedB = pushB ();
6074
6075   /* signed or unsigned */
6076   if (lUnsigned && rUnsigned)
6077     {
6078       /* unsigned is easy */
6079       LOAD_AB_FOR_DIV (left, right, l);
6080       emitcode ("div", "ab");
6081       aopOp (result, ic, TRUE, FALSE);
6082       aopPut (result, "b", 0);
6083
6084       for (size = AOP_SIZE (result) - 1; size--;)
6085         aopPut (result, zero, offset++);
6086
6087       popB (pushedB);
6088       return;
6089     }
6090
6091   /* signed is a little bit more difficult */
6092
6093   /* now sign adjust for both left & right */
6094
6095   /* modulus: sign of the right operand has no influence on the result! */
6096   if (AOP_TYPE(right) == AOP_LIT)
6097     {
6098       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6099
6100       if (!rUnsigned && val < 0)
6101         emitcode ("mov", "b,#0x%02x", -val);
6102       else
6103         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6104     }
6105   else /* not literal */
6106     {
6107       if (rUnsigned)
6108         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6109       else
6110         {
6111           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6112           lbl = newiTempLabel (NULL);
6113           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6114           emitcode ("cpl", "a");  /* 2's complement */
6115           emitcode ("inc", "a");
6116           emitcode ("", "!tlabeldef", lbl->key + 100);
6117           emitcode ("mov", "b,a");
6118         }
6119     }
6120
6121   /* let's see what's needed: */
6122   /* apply negative sign during runtime */
6123   runtimeSign = FALSE;
6124   /* negative sign from literals */
6125   compiletimeSign = FALSE;
6126
6127   /* sign adjust left side */
6128   if (AOP_TYPE(left) == AOP_LIT)
6129     {
6130       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6131
6132       if (!lUnsigned && val < 0)
6133         {
6134           compiletimeSign = TRUE; /* set sign flag */
6135           emitcode ("mov", "a,#0x%02x", -val);
6136         }
6137       else
6138         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6139     }
6140   else /* ! literal */
6141     {
6142       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6143
6144       if (!lUnsigned)
6145         {
6146           runtimeSign = TRUE;
6147           emitcode ("clr", "F0"); /* clear sign flag */
6148
6149           lbl = newiTempLabel (NULL);
6150           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6151           emitcode ("setb", "F0"); /* set sign flag */
6152           emitcode ("cpl", "a");   /* 2's complement */
6153           emitcode ("inc", "a");
6154           emitcode ("", "!tlabeldef", lbl->key + 100);
6155         }
6156     }
6157
6158   /* now the modulus */
6159   emitcode ("nop", "; workaround for DS80C390 div bug.");
6160   emitcode ("div", "ab");
6161
6162   if (runtimeSign || compiletimeSign)
6163     {
6164       emitcode ("mov", "a,b");
6165       lbl = newiTempLabel (NULL);
6166       if (runtimeSign)
6167         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6168       emitcode ("cpl", "a"); /* lsb 2's complement */
6169       emitcode ("inc", "a");
6170       emitcode ("", "!tlabeldef", lbl->key + 100);
6171
6172       _G.accInUse++;
6173       aopOp (result, ic, TRUE, FALSE);
6174       size = AOP_SIZE (result) - 1;
6175
6176       if (size > 0)
6177         {
6178           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6179              then the result will be in b, a */
6180           emitcode ("mov", "b,a"); /* 1 */
6181           /* msb is 0x00 or 0xff depending on the sign */
6182           if (runtimeSign)
6183             {
6184               emitcode ("mov",  "c,F0");
6185               emitcode ("subb", "a,acc");
6186               emitcode ("xch",  "a,b"); /* 2 */
6187               while (size--)
6188                 aopPut (result, "b", offset++); /* write msb's */
6189             }
6190           else /* compiletimeSign */
6191             while (size--)
6192               aopPut (result, "#0xff", offset++); /* write msb's */
6193         }
6194       aopPut (result, "a", 0); /* 3: write lsb */
6195     }
6196   else
6197     {
6198       _G.accInUse++;
6199       aopOp(result, ic, TRUE, FALSE);
6200       size = AOP_SIZE (result) - 1;
6201
6202       aopPut (result, "b", 0);
6203       while (size--)
6204         aopPut (result, zero, offset++);
6205     }
6206   _G.accInUse--;
6207   popB (pushedB);
6208 }
6209
6210 /*-----------------------------------------------------------------*/
6211 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6212 /*-----------------------------------------------------------------*/
6213 static void genModTwoByte (operand *left, operand *right,
6214                             operand *result, iCode *ic)
6215 {
6216         sym_link *retype = getSpec(operandType(right));
6217         sym_link *letype = getSpec(operandType(left));
6218         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6219         symbol *lbl;
6220
6221         /* load up MA with left */
6222         /* save EA bit in F1 */
6223         lbl = newiTempLabel(NULL);
6224         emitcode ("setb","F1");
6225         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6226         emitcode ("clr","F1");
6227         emitcode("","!tlabeldef",lbl->key+100);
6228
6229         if (!umult) {
6230                 lbl = newiTempLabel(NULL);
6231                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6232                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6233                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6234                 emitcode ("xch", "a,b");
6235                 emitcode ("cpl","a");
6236                 emitcode ("add", "a,#1");
6237                 emitcode ("xch", "a,b");
6238                 emitcode ("cpl", "a"); // msb
6239                 emitcode ("addc","a,#0");
6240                 emitcode ("","!tlabeldef",lbl->key+100);
6241                 emitcode ("mov","ma,b");
6242                 emitcode ("mov","ma,a");
6243         } else {
6244                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6245                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6246         }
6247
6248         /* load up MB with right */
6249         if (!umult) {
6250                 if (AOP_TYPE(right) == AOP_LIT) {
6251                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6252                         if (val < 0) {
6253                                 val = -val;
6254                         }
6255                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6256                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6257                 } else {
6258                         lbl = newiTempLabel(NULL);
6259                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6260                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6261                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6262                         emitcode ("xch", "a,b");
6263                         emitcode ("cpl","a");
6264                         emitcode ("add", "a,#1");
6265                         emitcode ("xch", "a,b");
6266                         emitcode ("cpl", "a"); // msb
6267                         emitcode ("addc", "a,#0");
6268                         emitcode ("","!tlabeldef",lbl->key+100);
6269                         emitcode ("mov","mb,b");
6270                         emitcode ("mov","mb,a");
6271                 }
6272         } else {
6273                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6274                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6275         }
6276
6277         /* wait for multiplication to finish */
6278         lbl = newiTempLabel(NULL);
6279         emitcode("","!tlabeldef", lbl->key+100);
6280         emitcode("mov","a,mcnt1");
6281         emitcode("anl","a,#!constbyte",0x80);
6282         emitcode("jnz","!tlabel",lbl->key+100);
6283
6284         freeAsmop (left, NULL, ic, TRUE);
6285         freeAsmop (right, NULL, ic,TRUE);
6286         aopOp(result, ic, TRUE, FALSE);
6287
6288         aopPut(result,"mb",1);
6289         aopPut(result,"mb",0);
6290         freeAsmop (result, NULL, ic, TRUE);
6291
6292         /* restore EA bit in F1 */
6293         lbl = newiTempLabel(NULL);
6294         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6295         emitcode ("setb","EA");
6296         emitcode("","!tlabeldef",lbl->key+100);
6297         return ;
6298 }
6299
6300 /*-----------------------------------------------------------------*/
6301 /* genMod - generates code for division                            */
6302 /*-----------------------------------------------------------------*/
6303 static void
6304 genMod (iCode * ic)
6305 {
6306   operand *left = IC_LEFT (ic);
6307   operand *right = IC_RIGHT (ic);
6308   operand *result = IC_RESULT (ic);
6309
6310   D (emitcode (";", "genMod "));
6311
6312   /* assign the asmops */
6313   AOP_OP_2 (ic);
6314
6315   /* special cases first */
6316   /* both are bits */
6317   if (AOP_TYPE (left) == AOP_CRY &&
6318       AOP_TYPE (right) == AOP_CRY)
6319     {
6320       genModbits (left, right, result, ic);
6321       goto release;
6322     }
6323
6324   /* if both are of size == 1 */
6325   if (AOP_SIZE (left) == 1 &&
6326       AOP_SIZE (right) == 1)
6327     {
6328       genModOneByte (left, right, result, ic);
6329       goto release;
6330     }
6331
6332   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6333           /* use the ds390 ARITHMETIC accel UNIT */
6334           genModTwoByte (left, right, result, ic);
6335           return ;
6336   }
6337
6338   /* should have been converted to function call */
6339   assert (0);
6340
6341 release:
6342   freeAsmop (result, NULL, ic, TRUE);
6343   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6344   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6345 }
6346
6347 /*-----------------------------------------------------------------*/
6348 /* genIfxJump :- will create a jump depending on the ifx           */
6349 /*-----------------------------------------------------------------*/
6350 static void
6351 genIfxJump (iCode * ic, char *jval)
6352 {
6353   symbol *jlbl;
6354   symbol *tlbl = newiTempLabel (NULL);
6355   char *inst;
6356
6357   D (emitcode (";", "genIfxJump"));
6358
6359   /* if true label then we jump if condition
6360      supplied is true */
6361   if (IC_TRUE (ic))
6362     {
6363       jlbl = IC_TRUE (ic);
6364       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6365                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6366     }
6367   else
6368     {
6369       /* false label is present */
6370       jlbl = IC_FALSE (ic);
6371       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6372                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6373     }
6374   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6375     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6376   else
6377     emitcode (inst, "!tlabel", tlbl->key + 100);
6378   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6379   emitcode ("", "!tlabeldef", tlbl->key + 100);
6380
6381   /* mark the icode as generated */
6382   ic->generated = 1;
6383 }
6384
6385 /*-----------------------------------------------------------------*/
6386 /* genCmp :- greater or less than comparison                       */
6387 /*-----------------------------------------------------------------*/
6388 static void
6389 genCmp (operand * left, operand * right,
6390         iCode * ic, iCode * ifx, int sign)
6391 {
6392   int size, offset = 0;
6393   unsigned long lit = 0L;
6394   operand *result;
6395
6396   D (emitcode (";", "genCmp"));
6397
6398   result = IC_RESULT (ic);
6399
6400   /* if left & right are bit variables */
6401   if (AOP_TYPE (left) == AOP_CRY &&
6402       AOP_TYPE (right) == AOP_CRY)
6403     {
6404       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6405       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6406     }
6407   else
6408     {
6409       /* subtract right from left if at the
6410          end the carry flag is set then we know that
6411          left is greater than right */
6412       size = max (AOP_SIZE (left), AOP_SIZE (right));
6413
6414       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6415       if ((size == 1) && !sign &&
6416           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6417         {
6418           symbol *lbl = newiTempLabel (NULL);
6419           emitcode ("cjne", "%s,%s,!tlabel",
6420                     aopGet (left, offset, FALSE, FALSE, NULL),
6421                     aopGet (right, offset, FALSE, FALSE, NULL),
6422                     lbl->key + 100);
6423           emitcode ("", "!tlabeldef", lbl->key + 100);
6424         }
6425       else
6426         {
6427           if (AOP_TYPE (right) == AOP_LIT)
6428             {
6429               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6430               /* optimize if(x < 0) or if(x >= 0) */
6431               if (lit == 0L)
6432                 {
6433                   if (!sign)
6434                     {
6435                       CLRC;
6436                     }
6437                   else
6438                     {
6439                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6440
6441                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6442                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6443
6444                       aopOp (result, ic, FALSE, FALSE);
6445
6446                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6447                         {
6448                           freeAsmop (result, NULL, ic, TRUE);
6449                           genIfxJump (ifx, "acc.7");
6450                           return;
6451                         }
6452                       else
6453                         {
6454                           emitcode ("rlc", "a");
6455                         }
6456                       goto release_freedLR;
6457                     }
6458                   goto release;
6459                 }
6460             }
6461           CLRC;
6462           while (size--)
6463             {
6464               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6465               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6466               // emitcode (";", "genCmp #2");
6467               if (sign && (size == 0))
6468                 {
6469                   // emitcode (";", "genCmp #3");
6470                   emitcode ("xrl", "a,#!constbyte",0x80);
6471                   if (AOP_TYPE (right) == AOP_LIT)
6472                     {
6473                       unsigned long lit = (unsigned long)
6474                       floatFromVal (AOP (right)->aopu.aop_lit);
6475                       // emitcode (";", "genCmp #3.1");
6476                       emitcode ("subb", "a,#!constbyte",
6477                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6478                     }
6479                   else
6480                     {
6481                       // emitcode (";", "genCmp #3.2");
6482                       saveAccWarn = 0;
6483                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6484                       saveAccWarn = DEFAULT_ACC_WARNING;
6485                       emitcode ("xrl", "b,#!constbyte",0x80);
6486                       emitcode ("subb", "a,b");
6487                     }
6488                 }
6489               else
6490                 {
6491                   const char *s;
6492
6493                   // emitcode (";", "genCmp #4");
6494                   saveAccWarn = 0;
6495                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6496                   saveAccWarn = DEFAULT_ACC_WARNING;
6497
6498                   emitcode ("subb", "a,%s", s);
6499                 }
6500             }
6501         }
6502     }
6503
6504 release:
6505 /* Don't need the left & right operands any more; do need the result. */
6506   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6507   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6508
6509   aopOp (result, ic, FALSE, FALSE);
6510
6511 release_freedLR:
6512
6513   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6514     {
6515       outBitC (result);
6516     }
6517   else
6518     {
6519       /* if the result is used in the next
6520          ifx conditional branch then generate
6521          code a little differently */
6522       if (ifx)
6523         {
6524           genIfxJump (ifx, "c");
6525         }
6526       else
6527         {
6528           outBitC (result);
6529         }
6530       /* leave the result in acc */
6531     }
6532   freeAsmop (result, NULL, ic, TRUE);
6533 }
6534
6535 /*-----------------------------------------------------------------*/
6536 /* genCmpGt :- greater than comparison                             */
6537 /*-----------------------------------------------------------------*/
6538 static void
6539 genCmpGt (iCode * ic, iCode * ifx)
6540 {
6541   operand *left, *right;
6542   sym_link *letype, *retype;
6543   int sign;
6544
6545   D (emitcode (";", "genCmpGt"));
6546
6547   left = IC_LEFT (ic);
6548   right = IC_RIGHT (ic);
6549
6550   letype = getSpec (operandType (left));
6551   retype = getSpec (operandType (right));
6552   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6553
6554   /* assign the left & right amsops */
6555   AOP_OP_2 (ic);
6556
6557   genCmp (right, left, ic, ifx, sign);
6558 }
6559
6560 /*-----------------------------------------------------------------*/
6561 /* genCmpLt - less than comparisons                                */
6562 /*-----------------------------------------------------------------*/
6563 static void
6564 genCmpLt (iCode * ic, iCode * ifx)
6565 {
6566   operand *left, *right;
6567   sym_link *letype, *retype;
6568   int sign;
6569
6570   D (emitcode (";", "genCmpLt "));
6571
6572   left = IC_LEFT (ic);
6573   right = IC_RIGHT (ic);
6574
6575   letype = getSpec (operandType (left));
6576   retype = getSpec (operandType (right));
6577   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6578
6579   /* assign the left & right amsops */
6580   AOP_OP_2 (ic);
6581
6582   genCmp (left, right, ic, ifx, sign);
6583 }
6584
6585 /*-----------------------------------------------------------------*/
6586 /* gencjneshort - compare and jump if not equal                    */
6587 /*-----------------------------------------------------------------*/
6588 static void
6589 gencjneshort (operand * left, operand * right, symbol * lbl)
6590 {
6591   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6592   int offset = 0;
6593   unsigned long lit = 0L;
6594
6595   D (emitcode (";", "gencjneshort"));
6596
6597   /* if the left side is a literal or
6598      if the right is in a pointer register and left
6599      is not */
6600   if ((AOP_TYPE (left) == AOP_LIT) ||
6601       (AOP_TYPE (left) == AOP_IMMD) ||
6602       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6603     {
6604       operand *t = right;
6605       right = left;
6606       left = t;
6607     }
6608
6609   if (AOP_TYPE (right) == AOP_LIT)
6610     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6611
6612   if (opIsGptr (left) || opIsGptr (right))
6613     {
6614       /* We are comparing a generic pointer to something.
6615        * Exclude the generic type byte from the comparison.
6616        */
6617       size--;
6618       D (emitcode (";", "cjneshort: generic ptr special case."););
6619     }
6620
6621
6622   /* if the right side is a literal then anything goes */
6623   if (AOP_TYPE (right) == AOP_LIT &&
6624       AOP_TYPE (left) != AOP_DIR)
6625     {
6626       while (size--)
6627         {
6628           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6629           emitcode ("cjne", "a,%s,!tlabel",
6630                     aopGet (right, offset, FALSE, FALSE, NULL),
6631                     lbl->key + 100);
6632           offset++;
6633         }
6634     }
6635
6636   /* if the right side is in a register or in direct space or
6637      if the left is a pointer register & right is not */
6638   else if (AOP_TYPE (right) == AOP_REG ||
6639            AOP_TYPE (right) == AOP_DIR ||
6640            AOP_TYPE (right) == AOP_LIT ||
6641            AOP_TYPE (right) == AOP_IMMD ||
6642            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6643            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6644     {
6645       while (size--)
6646         {
6647           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6648           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6649               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6650             emitcode ("jnz", "!tlabel", lbl->key + 100);
6651           else
6652             emitcode ("cjne", "a,%s,!tlabel",
6653                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6654                       lbl->key + 100);
6655           offset++;
6656         }
6657     }
6658   else
6659     {
6660       /* right is a pointer reg need both a & b */
6661       while (size--)
6662         {
6663           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6664           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6665           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6666           offset++;
6667         }
6668     }
6669 }
6670
6671 /*-----------------------------------------------------------------*/
6672 /* gencjne - compare and jump if not equal                         */
6673 /*-----------------------------------------------------------------*/
6674 static void
6675 gencjne (operand * left, operand * right, symbol * lbl)
6676 {
6677   symbol *tlbl = newiTempLabel (NULL);
6678
6679   D (emitcode (";", "gencjne"));
6680
6681   gencjneshort (left, right, lbl);
6682
6683   emitcode ("mov", "a,%s", one);
6684   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6685   emitcode ("", "!tlabeldef", lbl->key + 100);
6686   emitcode ("clr", "a");
6687   emitcode ("", "!tlabeldef", tlbl->key + 100);
6688 }
6689
6690 /*-----------------------------------------------------------------*/
6691 /* genCmpEq - generates code for equal to                          */
6692 /*-----------------------------------------------------------------*/
6693 static void
6694 genCmpEq (iCode * ic, iCode * ifx)
6695 {
6696   operand *left, *right, *result;
6697
6698   D (emitcode (";", "genCmpEq"));
6699
6700   AOP_OP_2 (ic);
6701   AOP_SET_LOCALS (ic);
6702
6703   /* if literal, literal on the right or
6704      if the right is in a pointer register and left
6705      is not */
6706   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6707       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6708     {
6709       operand *t = IC_RIGHT (ic);
6710       IC_RIGHT (ic) = IC_LEFT (ic);
6711       IC_LEFT (ic) = t;
6712     }
6713
6714   if (ifx &&                    /* !AOP_SIZE(result) */
6715       OP_SYMBOL (result) &&
6716       OP_SYMBOL (result)->regType == REG_CND)
6717     {
6718       symbol *tlbl;
6719       /* if they are both bit variables */
6720       if (AOP_TYPE (left) == AOP_CRY &&
6721           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6722         {
6723           if (AOP_TYPE (right) == AOP_LIT)
6724             {
6725               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6726               if (lit == 0L)
6727                 {
6728                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6729                   emitcode ("cpl", "c");
6730                 }
6731               else if (lit == 1L)
6732                 {
6733                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6734                 }
6735               else
6736                 {
6737                   emitcode ("clr", "c");
6738                 }
6739               /* AOP_TYPE(right) == AOP_CRY */
6740             }
6741           else
6742             {
6743               symbol *lbl = newiTempLabel (NULL);
6744               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6745               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6746               emitcode ("cpl", "c");
6747               emitcode ("", "!tlabeldef", (lbl->key + 100));
6748             }
6749           /* if true label then we jump if condition
6750              supplied is true */
6751           tlbl = newiTempLabel (NULL);
6752           if (IC_TRUE (ifx))
6753             {
6754               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6755               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6756             }
6757           else
6758             {
6759               emitcode ("jc", "!tlabel", tlbl->key + 100);
6760               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6761             }
6762           emitcode ("", "!tlabeldef", tlbl->key + 100);
6763         }
6764       else
6765         {
6766           tlbl = newiTempLabel (NULL);
6767           gencjneshort (left, right, tlbl);
6768           if (IC_TRUE (ifx))
6769             {
6770               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6771               emitcode ("", "!tlabeldef", tlbl->key + 100);
6772             }
6773           else
6774             {
6775               symbol *lbl = newiTempLabel (NULL);
6776               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6777               emitcode ("", "!tlabeldef", tlbl->key + 100);
6778               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6779               emitcode ("", "!tlabeldef", lbl->key + 100);
6780             }
6781         }
6782       /* mark the icode as generated */
6783       ifx->generated = 1;
6784
6785       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6786       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6787       return;
6788     }
6789
6790   /* if they are both bit variables */
6791   if (AOP_TYPE (left) == AOP_CRY &&
6792       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6793     {
6794       if (AOP_TYPE (right) == AOP_LIT)
6795         {
6796           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6797           if (lit == 0L)
6798             {
6799               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6800               emitcode ("cpl", "c");
6801             }
6802           else if (lit == 1L)
6803             {
6804               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6805             }
6806           else
6807             {
6808               emitcode ("clr", "c");
6809             }
6810           /* AOP_TYPE(right) == AOP_CRY */
6811         }
6812       else
6813         {
6814           symbol *lbl = newiTempLabel (NULL);
6815           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6816           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6817           emitcode ("cpl", "c");
6818           emitcode ("", "!tlabeldef", (lbl->key + 100));
6819         }
6820
6821       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6822       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6823
6824       aopOp (result, ic, TRUE, FALSE);
6825
6826       /* c = 1 if egal */
6827       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6828         {
6829           outBitC (result);
6830           goto release;
6831         }
6832       if (ifx)
6833         {
6834           genIfxJump (ifx, "c");
6835           goto release;
6836         }
6837       /* if the result is used in an arithmetic operation
6838          then put the result in place */
6839       outBitC (result);
6840     }
6841   else
6842     {
6843       gencjne (left, right, newiTempLabel (NULL));
6844
6845       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6846       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6847
6848       aopOp (result, ic, TRUE, FALSE);
6849
6850       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6851         {
6852           aopPut (result, "a", 0);
6853           goto release;
6854         }
6855       if (ifx)
6856         {
6857           genIfxJump (ifx, "a");
6858           goto release;
6859         }
6860       /* if the result is used in an arithmetic operation
6861          then put the result in place */
6862       if (AOP_TYPE (result) != AOP_CRY)
6863         outAcc (result);
6864       /* leave the result in acc */
6865     }
6866
6867 release:
6868   freeAsmop (result, NULL, ic, TRUE);
6869 }
6870
6871 /*-----------------------------------------------------------------*/
6872 /* ifxForOp - returns the icode containing the ifx for operand     */
6873 /*-----------------------------------------------------------------*/
6874 static iCode *
6875 ifxForOp (operand * op, iCode * ic)
6876 {
6877   /* if true symbol then needs to be assigned */
6878   if (IS_TRUE_SYMOP (op))
6879     return NULL;
6880
6881   /* if this has register type condition and
6882      the next instruction is ifx with the same operand
6883      and live to of the operand is upto the ifx only then */
6884   if (ic->next &&
6885       ic->next->op == IFX &&
6886       IC_COND (ic->next)->key == op->key &&
6887       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6888     return ic->next;
6889
6890   return NULL;
6891 }
6892
6893 /*-----------------------------------------------------------------*/
6894 /* hasInc - operand is incremented before any other use            */
6895 /*-----------------------------------------------------------------*/
6896 static iCode *
6897 hasInc (operand *op, iCode *ic, int osize)
6898 {
6899   sym_link *type = operandType(op);
6900   sym_link *retype = getSpec (type);
6901   iCode *lic = ic->next;
6902   int isize ;
6903
6904   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6905   if (!IS_SYMOP(op)) return NULL;
6906
6907   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6908   if (IS_AGGREGATE(type->next)) return NULL;
6909   if (osize != (isize = getSize(type->next))) return NULL;
6910
6911   while (lic) {
6912       /* if operand of the form op = op + <sizeof *op> */
6913       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6914           isOperandEqual(IC_RESULT(lic),op) &&
6915           isOperandLiteral(IC_RIGHT(lic)) &&
6916           operandLitValue(IC_RIGHT(lic)) == isize) {
6917           return lic;
6918       }
6919       /* if the operand used or deffed */
6920       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6921           return NULL;
6922       }
6923       /* if GOTO or IFX */
6924       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6925       lic = lic->next;
6926   }
6927   return NULL;
6928 }
6929
6930 /*-----------------------------------------------------------------*/
6931 /* genAndOp - for && operation                                     */
6932 /*-----------------------------------------------------------------*/
6933 static void
6934 genAndOp (iCode * ic)
6935 {
6936   operand *left, *right, *result;
6937   symbol *tlbl;
6938
6939   D (emitcode (";", "genAndOp "));
6940
6941   /* note here that && operations that are in an
6942      if statement are taken away by backPatchLabels
6943      only those used in arthmetic operations remain */
6944   AOP_OP_2 (ic);
6945   AOP_SET_LOCALS (ic);
6946
6947   /* if both are bit variables */
6948   if (AOP_TYPE (left) == AOP_CRY &&
6949       AOP_TYPE (right) == AOP_CRY)
6950     {
6951       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6952       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6953       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6954       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6955
6956       aopOp (result,ic,FALSE, FALSE);
6957       outBitC (result);
6958     }
6959   else
6960     {
6961       tlbl = newiTempLabel (NULL);
6962       toBoolean (left);
6963       emitcode ("jz", "!tlabel", tlbl->key + 100);
6964       toBoolean (right);
6965       emitcode ("", "!tlabeldef", tlbl->key + 100);
6966       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6967       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6968
6969       aopOp (result,ic,FALSE, FALSE);
6970       outBitAcc (result);
6971     }
6972     freeAsmop (result, NULL, ic, TRUE);
6973 }
6974
6975
6976 /*-----------------------------------------------------------------*/
6977 /* genOrOp - for || operation                                      */
6978 /*-----------------------------------------------------------------*/
6979 static void
6980 genOrOp (iCode * ic)
6981 {
6982   operand *left, *right, *result;
6983   symbol *tlbl;
6984
6985   D (emitcode (";", "genOrOp "));
6986
6987   /* note here that || operations that are in an
6988      if statement are taken away by backPatchLabels
6989      only those used in arthmetic operations remain */
6990   AOP_OP_2 (ic);
6991   AOP_SET_LOCALS (ic);
6992
6993   /* if both are bit variables */
6994   if (AOP_TYPE (left) == AOP_CRY &&
6995       AOP_TYPE (right) == AOP_CRY)
6996     {
6997       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6998       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6999       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7000       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7001
7002       aopOp (result,ic,FALSE, FALSE);
7003
7004       outBitC (result);
7005     }
7006   else
7007     {
7008       tlbl = newiTempLabel (NULL);
7009       toBoolean (left);
7010       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7011       toBoolean (right);
7012       emitcode ("", "!tlabeldef", tlbl->key + 100);
7013       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7014       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7015
7016       aopOp (result,ic,FALSE, FALSE);
7017
7018       outBitAcc (result);
7019     }
7020
7021   freeAsmop (result, NULL, ic, TRUE);
7022 }
7023
7024 /*-----------------------------------------------------------------*/
7025 /* isLiteralBit - test if lit == 2^n                               */
7026 /*-----------------------------------------------------------------*/
7027 static int
7028 isLiteralBit (unsigned long lit)
7029 {
7030   unsigned long pw[32] =
7031   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7032    0x100L, 0x200L, 0x400L, 0x800L,
7033    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7034    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7035    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7036    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7037    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7038   int idx;
7039
7040   for (idx = 0; idx < 32; idx++)
7041     if (lit == pw[idx])
7042       return idx + 1;
7043   return 0;
7044 }
7045
7046 /*-----------------------------------------------------------------*/
7047 /* continueIfTrue -                                                */
7048 /*-----------------------------------------------------------------*/
7049 static void
7050 continueIfTrue (iCode * ic)
7051 {
7052   if (IC_TRUE (ic))
7053     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7054   ic->generated = 1;
7055 }
7056
7057 /*-----------------------------------------------------------------*/
7058 /* jmpIfTrue -                                                     */
7059 /*-----------------------------------------------------------------*/
7060 static void
7061 jumpIfTrue (iCode * ic)
7062 {
7063   if (!IC_TRUE (ic))
7064     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7065   ic->generated = 1;
7066 }
7067
7068 /*-----------------------------------------------------------------*/
7069 /* jmpTrueOrFalse -                                                */
7070 /*-----------------------------------------------------------------*/
7071 static void
7072 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7073 {
7074   // ugly but optimized by peephole
7075   if (IC_TRUE (ic))
7076     {
7077       symbol *nlbl = newiTempLabel (NULL);
7078       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7079       emitcode ("", "!tlabeldef", tlbl->key + 100);
7080       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7081       emitcode ("", "!tlabeldef", nlbl->key + 100);
7082     }
7083   else
7084     {
7085       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7086       emitcode ("", "!tlabeldef", tlbl->key + 100);
7087     }
7088   ic->generated = 1;
7089 }
7090
7091 // Generate code to perform a bit-wise logic operation
7092 // on two operands in far space (assumed to already have been
7093 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7094 // in far space. This requires pushing the result on the stack
7095 // then popping it into the result.
7096 static void
7097 genFarFarLogicOp(iCode *ic, char *logicOp)
7098 {
7099       int size, resultSize, compSize;
7100       int offset = 0;
7101
7102       TR_AP("#5");
7103       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7104       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7105                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7106
7107       _startLazyDPSEvaluation();
7108       for (size = compSize; (size--); offset++)
7109       {
7110           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7111           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7112           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7113
7114           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7115           emitcode ("push", "acc");
7116       }
7117       _endLazyDPSEvaluation();
7118
7119       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7120       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7121       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7122
7123       resultSize = AOP_SIZE(IC_RESULT(ic));
7124
7125       ADJUST_PUSHED_RESULT(compSize, resultSize);
7126
7127       _startLazyDPSEvaluation();
7128       while (compSize--)
7129       {
7130           emitcode ("pop", "acc");
7131           aopPut (IC_RESULT (ic), "a", compSize);
7132       }
7133       _endLazyDPSEvaluation();
7134       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7135 }
7136
7137
7138 /*-----------------------------------------------------------------*/
7139 /* genAnd  - code for and                                          */
7140 /*-----------------------------------------------------------------*/
7141 static void
7142 genAnd (iCode * ic, iCode * ifx)
7143 {
7144   operand *left, *right, *result;
7145   int size, offset = 0;
7146   unsigned long lit = 0L;
7147   int bytelit = 0;
7148   char buffer[10];
7149   bool pushResult;
7150
7151   D (emitcode (";", "genAnd"));
7152
7153   AOP_OP_3_NOFATAL (ic, pushResult);
7154   AOP_SET_LOCALS (ic);
7155
7156   if (pushResult)
7157   {
7158       genFarFarLogicOp(ic, "anl");
7159       return;
7160   }
7161
7162 #ifdef DEBUG_TYPE
7163   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7164             AOP_TYPE (result),
7165             AOP_TYPE (left), AOP_TYPE (right));
7166   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7167             AOP_SIZE (result),
7168             AOP_SIZE (left), AOP_SIZE (right));
7169 #endif
7170
7171   /* if left is a literal & right is not then exchange them */
7172   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7173 #ifdef LOGIC_OPS_BROKEN
7174     ||  AOP_NEEDSACC (left)
7175 #endif
7176     )
7177     {
7178       operand *tmp = right;
7179       right = left;
7180       left = tmp;
7181     }
7182
7183   /* if result = right then exchange left and right */
7184   if (sameRegs (AOP (result), AOP (right)))
7185     {
7186       operand *tmp = right;
7187       right = left;
7188       left = tmp;
7189     }
7190
7191   /* if right is bit then exchange them */
7192   if (AOP_TYPE (right) == AOP_CRY &&
7193       AOP_TYPE (left) != AOP_CRY)
7194     {
7195       operand *tmp = right;
7196       right = left;
7197       left = tmp;
7198     }
7199   if (AOP_TYPE (right) == AOP_LIT)
7200     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7201
7202   size = AOP_SIZE (result);
7203
7204   // if(bit & yy)
7205   // result = bit & yy;
7206   if (AOP_TYPE (left) == AOP_CRY)
7207     {
7208       // c = bit & literal;
7209       if (AOP_TYPE (right) == AOP_LIT)
7210         {
7211           if (lit & 1)
7212             {
7213               if (size && sameRegs (AOP (result), AOP (left)))
7214                 // no change
7215                 goto release;
7216               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7217             }
7218           else
7219             {
7220               // bit(result) = 0;
7221               if (size && (AOP_TYPE (result) == AOP_CRY))
7222                 {
7223                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7224                   goto release;
7225                 }
7226               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7227                 {
7228                   jumpIfTrue (ifx);
7229                   goto release;
7230                 }
7231               emitcode ("clr", "c");
7232             }
7233         }
7234       else
7235         {
7236           if (AOP_TYPE (right) == AOP_CRY)
7237             {
7238               // c = bit & bit;
7239               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7240               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7241             }
7242           else
7243             {
7244               // c = bit & val;
7245               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7246               // c = lsb
7247               emitcode ("rrc", "a");
7248               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7249             }
7250         }
7251       // bit = c
7252       // val = c
7253       if (size)
7254         outBitC (result);
7255       // if(bit & ...)
7256       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7257         genIfxJump (ifx, "c");
7258       goto release;
7259     }
7260
7261   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7262   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7263   if ((AOP_TYPE (right) == AOP_LIT) &&
7264       (AOP_TYPE (result) == AOP_CRY) &&
7265       (AOP_TYPE (left) != AOP_CRY))
7266     {
7267       int posbit = isLiteralBit (lit);
7268       /* left &  2^n */
7269       if (posbit)
7270         {
7271           posbit--;
7272           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7273           // bit = left & 2^n
7274           if (size)
7275             {
7276               switch (posbit & 0x07)
7277                 {
7278                   case 0: emitcode ("rrc", "a");
7279                           break;
7280                   case 7: emitcode ("rlc", "a");
7281                           break;
7282                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7283                           break;
7284                 }
7285             }
7286           // if(left &  2^n)
7287           else
7288             {
7289               if (ifx)
7290                 {
7291                   SNPRINTF (buffer, sizeof(buffer),
7292                             "acc.%d", posbit & 0x07);
7293                   genIfxJump (ifx, buffer);
7294                 }
7295               else
7296                   {
7297                       emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7298                   }
7299               goto release;
7300             }
7301         }
7302       else
7303         {
7304           symbol *tlbl = newiTempLabel (NULL);
7305           int sizel = AOP_SIZE (left);
7306           if (size)
7307             emitcode ("setb", "c");
7308           while (sizel--)
7309             {
7310               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7311                 {
7312                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7313                   // byte ==  2^n ?
7314                   if ((posbit = isLiteralBit (bytelit)) != 0)
7315                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7316                   else
7317                     {
7318                       if (bytelit != 0x0FFL)
7319                         emitcode ("anl", "a,%s",
7320                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7321                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7322                     }
7323                 }
7324               offset++;
7325             }
7326           // bit = left & literal
7327           if (size)
7328             {
7329               emitcode ("clr", "c");
7330               emitcode ("", "!tlabeldef", tlbl->key + 100);
7331             }
7332           // if(left & literal)
7333           else
7334             {
7335               if (ifx)
7336                 jmpTrueOrFalse (ifx, tlbl);
7337               else
7338                 emitcode ("", "!tlabeldef", tlbl->key + 100);
7339               goto release;
7340             }
7341         }
7342       outBitC (result);
7343       goto release;
7344     }
7345
7346   /* if left is same as result */
7347   if (sameRegs (AOP (result), AOP (left)))
7348     {
7349       for (; size--; offset++)
7350         {
7351           if (AOP_TYPE (right) == AOP_LIT)
7352             {
7353               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7354               if (bytelit == 0x0FF)
7355                 {
7356                   /* dummy read of volatile operand */
7357                   if (isOperandVolatile (left, FALSE))
7358                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7359                   else
7360                     continue;
7361                 }
7362               else if (bytelit == 0)
7363                 {
7364                   aopPut (result, zero, offset);
7365                 }
7366               else if (IS_AOP_PREG (result))
7367                 {
7368                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7369                   emitcode ("anl", "a,%s",
7370                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7371                   aopPut (result, "a", offset);
7372                 }
7373               else
7374                 emitcode ("anl", "%s,%s",
7375                           aopGet (left, offset, FALSE, TRUE, NULL),
7376                           aopGet (right, offset, FALSE, FALSE, NULL));
7377             }
7378           else
7379             {
7380               if (AOP_TYPE (left) == AOP_ACC)
7381                 emitcode ("anl", "a,%s",
7382                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7383               else
7384                 {
7385                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7386                   if (IS_AOP_PREG (result))
7387                     {
7388                       emitcode ("anl", "a,%s",
7389                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7390                       aopPut (result, "a", offset);
7391                     }
7392                   else
7393                     emitcode ("anl", "%s,a",
7394                               aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7395                 }
7396             }
7397         }
7398     }
7399   else
7400     {
7401       // left & result in different registers
7402       if (AOP_TYPE (result) == AOP_CRY)
7403         {
7404           // result = bit
7405           // if(size), result in bit
7406           // if(!size && ifx), conditional oper: if(left & right)
7407           symbol *tlbl = newiTempLabel (NULL);
7408           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7409           if (size)
7410             emitcode ("setb", "c");
7411           while (sizer--)
7412             {
7413               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7414                 emitcode ("anl", "a,%s",
7415                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7416               } else {
7417                 if (AOP_TYPE(left)==AOP_ACC)
7418                 {
7419                   bool pushedB = pushB ();
7420                   emitcode("mov", "b,a");
7421                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7422                   emitcode("anl", "a,b");
7423                   popB (pushedB);
7424                 }
7425                 else
7426                 {
7427                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7428                   emitcode ("anl", "a,%s",
7429                             aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7430                 }
7431               }
7432               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7433               offset++;
7434             }
7435           if (size)
7436             {
7437               CLRC;
7438               emitcode ("", "!tlabeldef", tlbl->key + 100);
7439               outBitC (result);
7440             }
7441           else if (ifx)
7442             jmpTrueOrFalse (ifx, tlbl);
7443           else
7444             emitcode ("", "!tlabeldef", tlbl->key + 100);
7445         }
7446       else
7447         {
7448           for (; (size--); offset++)
7449             {
7450               // normal case
7451               // result = left & right
7452               if (AOP_TYPE (right) == AOP_LIT)
7453                 {
7454                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7455                   if (bytelit == 0x0FF)
7456                     {
7457                       aopPut (result,
7458                               aopGet (left, offset, FALSE, FALSE, NULL),
7459                               offset);
7460                       continue;
7461                     }
7462                   else if (bytelit == 0)
7463                     {
7464                       /* dummy read of volatile operand */
7465                       if (isOperandVolatile (left, FALSE))
7466                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7467                       aopPut (result, zero, offset);
7468                       continue;
7469                     }
7470                   D (emitcode (";", "better literal AND."););
7471                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7472                   emitcode ("anl", "a, %s", aopGet (right, offset,
7473                                                     FALSE, FALSE, DP2_RESULT_REG));
7474
7475                 }
7476               else
7477                 {
7478                   // faster than result <- left, anl result,right
7479                   // and better if result is SFR
7480                   if (AOP_TYPE (left) == AOP_ACC)
7481                     {
7482                       emitcode ("anl", "a,%s",
7483                                 aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7484                     }
7485                   else
7486                     {
7487                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
7488                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7489                       {
7490                           emitcode("mov", "b,a");
7491                           rOp = "b";
7492                       }
7493
7494                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7495                       emitcode ("anl", "a,%s", rOp);
7496                     }
7497                 }
7498               aopPut (result, "a", offset);
7499             }
7500         }
7501     }
7502
7503 release:
7504   freeAsmop (result, NULL, ic, TRUE);
7505   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7506   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7507 }
7508
7509 /*-----------------------------------------------------------------*/
7510 /* genOr  - code for or                                            */
7511 /*-----------------------------------------------------------------*/
7512 static void
7513 genOr (iCode * ic, iCode * ifx)
7514 {
7515   operand *left, *right, *result;
7516   int size, offset = 0;
7517   unsigned long lit = 0L;
7518   int bytelit = 0;
7519   bool     pushResult;
7520
7521   D (emitcode (";", "genOr "));
7522
7523   AOP_OP_3_NOFATAL (ic, pushResult);
7524   AOP_SET_LOCALS (ic);
7525
7526   if (pushResult)
7527   {
7528       genFarFarLogicOp(ic, "orl");
7529       return;
7530   }
7531
7532
7533 #ifdef DEBUG_TYPE
7534   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7535             AOP_TYPE (result),
7536             AOP_TYPE (left), AOP_TYPE (right));
7537   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7538             AOP_SIZE (result),
7539             AOP_SIZE (left), AOP_SIZE (right));
7540 #endif
7541
7542   /* if left is a literal & right is not then exchange them */
7543   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7544 #ifdef LOGIC_OPS_BROKEN
7545    || AOP_NEEDSACC (left) // I think this is a net loss now.
7546 #endif
7547       )
7548     {
7549       operand *tmp = right;
7550       right = left;
7551       left = tmp;
7552     }
7553
7554   /* if result = right then exchange them */
7555   if (sameRegs (AOP (result), AOP (right)))
7556     {
7557       operand *tmp = right;
7558       right = left;
7559       left = tmp;
7560     }
7561
7562   /* if right is bit then exchange them */
7563   if (AOP_TYPE (right) == AOP_CRY &&
7564       AOP_TYPE (left) != AOP_CRY)
7565     {
7566       operand *tmp = right;
7567       right = left;
7568       left = tmp;
7569     }
7570   if (AOP_TYPE (right) == AOP_LIT)
7571     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7572
7573   size = AOP_SIZE (result);
7574
7575   // if(bit | yy)
7576   // xx = bit | yy;
7577   if (AOP_TYPE (left) == AOP_CRY)
7578     {
7579       if (AOP_TYPE (right) == AOP_LIT)
7580         {
7581           // c = bit | literal;
7582           if (lit)
7583             {
7584               // lit != 0 => result = 1
7585               if (AOP_TYPE (result) == AOP_CRY)
7586                 {
7587                   if (size)
7588                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7589                   else if (ifx)
7590                     continueIfTrue (ifx);
7591                   goto release;
7592                 }
7593               emitcode ("setb", "c");
7594             }
7595           else
7596             {
7597               // lit == 0 => result = left
7598               if (size && sameRegs (AOP (result), AOP (left)))
7599                 goto release;
7600               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7601             }
7602         }
7603       else
7604         {
7605           if (AOP_TYPE (right) == AOP_CRY)
7606             {
7607               // c = bit | bit;
7608               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7609               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7610             }
7611           else
7612             {
7613               // c = bit | val;
7614               symbol *tlbl = newiTempLabel (NULL);
7615               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7616                 emitcode ("setb", "c");
7617               emitcode ("jb", "%s,!tlabel",
7618                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7619               toBoolean (right);
7620               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7621               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7622                 {
7623                   jmpTrueOrFalse (ifx, tlbl);
7624                   goto release;
7625                 }
7626               else
7627                 {
7628                   CLRC;
7629                   emitcode ("", "!tlabeldef", tlbl->key + 100);
7630                 }
7631             }
7632         }
7633       // bit = c
7634       // val = c
7635       if (size)
7636         outBitC (result);
7637       // if(bit | ...)
7638       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7639            genIfxJump (ifx, "c");
7640       goto release;
7641     }
7642
7643   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7644   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7645   if ((AOP_TYPE (right) == AOP_LIT) &&
7646       (AOP_TYPE (result) == AOP_CRY) &&
7647       (AOP_TYPE (left) != AOP_CRY))
7648     {
7649       if (lit)
7650         {
7651           // result = 1
7652           if (size)
7653             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7654           else
7655             continueIfTrue (ifx);
7656           goto release;
7657         }
7658       else
7659         {
7660           // lit = 0, result = boolean(left)
7661           if (size)
7662             emitcode ("setb", "c");
7663           toBoolean (right);
7664           if (size)
7665             {
7666               symbol *tlbl = newiTempLabel (NULL);
7667               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7668               CLRC;
7669               emitcode ("", "!tlabeldef", tlbl->key + 100);
7670             }
7671           else
7672             {
7673               genIfxJump (ifx, "a");
7674               goto release;
7675             }
7676         }
7677       outBitC (result);
7678       goto release;
7679     }
7680
7681   /* if left is same as result */
7682   if (sameRegs (AOP (result), AOP (left)))
7683     {
7684       for (; size--; offset++)
7685         {
7686           if (AOP_TYPE (right) == AOP_LIT)
7687             {
7688               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7689               if (bytelit == 0)
7690                 {
7691                   /* dummy read of volatile operand */
7692                   if (isOperandVolatile (left, FALSE))
7693                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7694                   else
7695                     continue;
7696                 }
7697               else if (bytelit == 0x0FF)
7698                 {
7699                   aopPut (result, "#0xFF", offset);
7700                 }
7701               else if (IS_AOP_PREG (left))
7702                 {
7703                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7704                   emitcode ("orl", "a,%s",
7705                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7706                   aopPut (result, "a", offset);
7707                 }
7708               else
7709                 {
7710                   emitcode ("orl", "%s,%s",
7711                             aopGet (left, offset, FALSE, TRUE, NULL),
7712                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7713                 }
7714             }
7715           else
7716             {
7717               if (AOP_TYPE (left) == AOP_ACC)
7718                 {
7719                   emitcode ("orl", "a,%s",
7720                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7721                 }
7722               else
7723                 {
7724                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7725                   if (IS_AOP_PREG (left))
7726                     {
7727                       emitcode ("orl", "a,%s",
7728                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7729                       aopPut (result, "a", offset);
7730                     }
7731                   else
7732                     {
7733                       emitcode ("orl", "%s,a",
7734                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7735                     }
7736                 }
7737             }
7738         }
7739     }
7740   else
7741     {
7742       // left & result in different registers
7743       if (AOP_TYPE (result) == AOP_CRY)
7744         {
7745           // result = bit
7746           // if(size), result in bit
7747           // if(!size && ifx), conditional oper: if(left | right)
7748           symbol *tlbl = newiTempLabel (NULL);
7749           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7750           if (size)
7751             emitcode ("setb", "c");
7752           while (sizer--)
7753             {
7754               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7755                 emitcode ("orl", "a,%s",
7756                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7757               } else {
7758                 MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7759                 emitcode ("orl", "a,%s",
7760                           aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7761               }
7762               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7763               offset++;
7764             }
7765           if (size)
7766             {
7767               CLRC;
7768               emitcode ("", "!tlabeldef", tlbl->key + 100);
7769               outBitC (result);
7770             }
7771           else if (ifx)
7772             jmpTrueOrFalse (ifx, tlbl);
7773           else
7774             emitcode ("", "!tlabeldef", tlbl->key + 100);
7775         }
7776       else
7777         {
7778             _startLazyDPSEvaluation();
7779           for (; (size--); offset++)
7780             {
7781               // normal case
7782               // result = left | right
7783               if (AOP_TYPE (right) == AOP_LIT)
7784                 {
7785                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7786                   if (bytelit == 0)
7787                     {
7788                       aopPut (result,
7789                               aopGet (left, offset, FALSE, FALSE, NULL),
7790                               offset);
7791                       continue;
7792                     }
7793                   else if (bytelit == 0x0FF)
7794                     {
7795                       /* dummy read of volatile operand */
7796                       if (isOperandVolatile (left, FALSE))
7797                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7798                       aopPut (result, "#0xFF", offset);
7799                       continue;
7800                     }
7801                   D (emitcode (";", "better literal OR."););
7802                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7803                   emitcode ("orl", "a, %s",
7804                             aopGet (right, offset,
7805                                     FALSE, FALSE, DP2_RESULT_REG));
7806
7807                 }
7808               else
7809                 {
7810                   // faster than result <- left, anl result,right
7811                   // and better if result is SFR
7812                   if (AOP_TYPE (left) == AOP_ACC)
7813                     {
7814                       emitcode ("orl", "a,%s",
7815                                 aopGet (right, offset,
7816                                         FALSE, FALSE, DP2_RESULT_REG));
7817                     }
7818                   else
7819                     {
7820                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
7821
7822                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7823                       {
7824                           emitcode("mov", "b,a");
7825                           rOp = "b";
7826                       }
7827
7828                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7829                       emitcode ("orl", "a,%s", rOp);
7830                     }
7831                 }
7832               aopPut (result, "a", offset);
7833             }
7834             _endLazyDPSEvaluation();
7835         }
7836     }
7837
7838 release:
7839   freeAsmop (result, NULL, ic, TRUE);
7840   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7841   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7842 }
7843
7844 /*-----------------------------------------------------------------*/
7845 /* genXor - code for xclusive or                                   */
7846 /*-----------------------------------------------------------------*/
7847 static void
7848 genXor (iCode * ic, iCode * ifx)
7849 {
7850   operand *left, *right, *result;
7851   int size, offset = 0;
7852   unsigned long lit = 0L;
7853   int bytelit = 0;
7854   bool pushResult;
7855
7856   D (emitcode (";", "genXor "));
7857
7858   AOP_OP_3_NOFATAL (ic, pushResult);
7859   AOP_SET_LOCALS (ic);
7860
7861   if (pushResult)
7862   {
7863       genFarFarLogicOp(ic, "xrl");
7864       return;
7865   }
7866
7867 #ifdef DEBUG_TYPE
7868   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7869             AOP_TYPE (result),
7870             AOP_TYPE (left), AOP_TYPE (right));
7871   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7872             AOP_SIZE (result),
7873             AOP_SIZE (left), AOP_SIZE (right));
7874 #endif
7875
7876   /* if left is a literal & right is not ||
7877      if left needs acc & right does not */
7878   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7879 #ifdef LOGIC_OPS_BROKEN
7880       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7881 #endif
7882      )
7883     {
7884       operand *tmp = right;
7885       right = left;
7886       left = tmp;
7887     }
7888
7889   /* if result = right then exchange them */
7890   if (sameRegs (AOP (result), AOP (right)))
7891     {
7892       operand *tmp = right;
7893       right = left;
7894       left = tmp;
7895     }
7896
7897   /* if right is bit then exchange them */
7898   if (AOP_TYPE (right) == AOP_CRY &&
7899       AOP_TYPE (left) != AOP_CRY)
7900     {
7901       operand *tmp = right;
7902       right = left;
7903       left = tmp;
7904     }
7905   if (AOP_TYPE (right) == AOP_LIT)
7906     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7907
7908   size = AOP_SIZE (result);
7909
7910   // if(bit ^ yy)
7911   // xx = bit ^ yy;
7912   if (AOP_TYPE (left) == AOP_CRY)
7913     {
7914       if (AOP_TYPE (right) == AOP_LIT)
7915         {
7916           // c = bit & literal;
7917           if (lit >> 1)
7918             {
7919               // lit>>1  != 0 => result = 1
7920               if (AOP_TYPE (result) == AOP_CRY)
7921                 {
7922                   if (size)
7923                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7924                   else if (ifx)
7925                     continueIfTrue (ifx);
7926                   goto release;
7927                 }
7928               emitcode ("setb", "c");
7929             }
7930           else
7931             {
7932               // lit == (0 or 1)
7933               if (lit == 0)
7934                 {
7935                   // lit == 0, result = left
7936                   if (size && sameRegs (AOP (result), AOP (left)))
7937                     goto release;
7938                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7939                 }
7940               else
7941                 {
7942                   // lit == 1, result = not(left)
7943                   if (size && sameRegs (AOP (result), AOP (left)))
7944                     {
7945                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7946                       goto release;
7947                     }
7948                   else
7949                     {
7950                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7951                       emitcode ("cpl", "c");
7952                     }
7953                 }
7954             }
7955
7956         }
7957       else
7958         {
7959           // right != literal
7960           symbol *tlbl = newiTempLabel (NULL);
7961           if (AOP_TYPE (right) == AOP_CRY)
7962             {
7963               // c = bit ^ bit;
7964               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7965             }
7966           else
7967             {
7968               int sizer = AOP_SIZE (right);
7969               // c = bit ^ val
7970               // if val>>1 != 0, result = 1
7971               emitcode ("setb", "c");
7972               while (sizer)
7973                 {
7974                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
7975                   if (sizer == 1)
7976                     // test the msb of the lsb
7977                     emitcode ("anl", "a,#!constbyte",0xfe);
7978                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
7979                   sizer--;
7980                 }
7981               // val = (0,1)
7982               emitcode ("rrc", "a");
7983             }
7984           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7985           emitcode ("cpl", "c");
7986           emitcode ("", "!tlabeldef", (tlbl->key + 100));
7987         }
7988       // bit = c
7989       // val = c
7990       if (size)
7991         outBitC (result);
7992       // if(bit | ...)
7993       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7994         genIfxJump (ifx, "c");
7995       goto release;
7996     }
7997
7998   /* if left is same as result */
7999   if (sameRegs (AOP (result), AOP (left)))
8000     {
8001       for (; size--; offset++)
8002         {
8003           if (AOP_TYPE (right) == AOP_LIT)
8004             {
8005               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8006               if (bytelit == 0)
8007                 {
8008                   /* dummy read of volatile operand */
8009                   if (isOperandVolatile (left, FALSE))
8010                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8011                   else
8012                     continue;
8013                 }
8014               else if (IS_AOP_PREG (left))
8015                 {
8016                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8017                   emitcode ("xrl", "a,%s",
8018                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8019                   aopPut (result, "a", offset);
8020                 }
8021               else
8022                 {
8023                   emitcode ("xrl", "%s,%s",
8024                             aopGet (left, offset, FALSE, TRUE, NULL),
8025                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8026                 }
8027             }
8028           else
8029             {
8030               if (AOP_TYPE (left) == AOP_ACC)
8031                 emitcode ("xrl", "a,%s",
8032                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8033               else
8034                 {
8035                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8036                   if (IS_AOP_PREG (left))
8037                     {
8038                       emitcode ("xrl", "a,%s",
8039                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8040                       aopPut (result, "a", offset);
8041                     }
8042                   else
8043                     emitcode ("xrl", "%s,a",
8044                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8045                 }
8046             }
8047         }
8048     }
8049   else
8050     {
8051       // left & result in different registers
8052       if (AOP_TYPE (result) == AOP_CRY)
8053         {
8054           // result = bit
8055           // if(size), result in bit
8056           // if(!size && ifx), conditional oper: if(left ^ right)
8057           symbol *tlbl = newiTempLabel (NULL);
8058           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8059
8060           if (size)
8061             emitcode ("setb", "c");
8062           while (sizer--)
8063             {
8064               if ((AOP_TYPE (right) == AOP_LIT) &&
8065                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8066                 {
8067                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8068                 }
8069               else
8070                 {
8071                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
8072                     emitcode ("xrl", "a,%s",
8073                               aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8074                   } else {
8075                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8076                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8077                       {
8078                           emitcode("mov", "b,a");
8079                           rOp = "b";
8080                       }
8081
8082                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8083                       emitcode ("xrl", "a,%s", rOp);
8084                   }
8085                 }
8086               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8087               offset++;
8088             }
8089           if (size)
8090             {
8091               CLRC;
8092               emitcode ("", "!tlabeldef", tlbl->key + 100);
8093               outBitC (result);
8094             }
8095           else if (ifx)
8096             jmpTrueOrFalse (ifx, tlbl);
8097         }
8098       else
8099         {
8100         for (; (size--); offset++)
8101           {
8102             // normal case
8103             // result = left ^ right
8104             if (AOP_TYPE (right) == AOP_LIT)
8105               {
8106                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8107                 if (bytelit == 0)
8108                   {
8109                     aopPut (result,
8110                             aopGet (left, offset, FALSE, FALSE, NULL),
8111                             offset);
8112                     continue;
8113                   }
8114                 D (emitcode (";", "better literal XOR."););
8115                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8116                 emitcode ("xrl", "a, %s",
8117                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8118               }
8119             else
8120               {
8121                 // faster than result <- left, anl result,right
8122                 // and better if result is SFR
8123                 if (AOP_TYPE (left) == AOP_ACC)
8124                   {
8125                     emitcode ("xrl", "a,%s",
8126                               aopGet (right, offset,
8127                                       FALSE, FALSE, DP2_RESULT_REG));
8128                   }
8129                 else
8130                   {
8131                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8132                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8133                       {
8134                           emitcode("mov", "b,a");
8135                           rOp = "b";
8136                       }
8137
8138                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8139                       emitcode ("xrl", "a,%s", rOp);
8140                   }
8141               }
8142             aopPut (result, "a", offset);
8143           }
8144         }
8145     }
8146
8147 release:
8148   freeAsmop (result, NULL, ic, TRUE);
8149   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8150   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8151 }
8152
8153 /*-----------------------------------------------------------------*/
8154 /* genInline - write the inline code out                           */
8155 /*-----------------------------------------------------------------*/
8156 static void
8157 genInline (iCode * ic)
8158 {
8159   char *buffer, *bp, *bp1;
8160
8161   D (emitcode (";", "genInline "));
8162
8163   _G.inLine += (!options.asmpeep);
8164
8165   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
8166
8167   /* emit each line as a code */
8168   while (*bp)
8169     {
8170       if (*bp == '\n')
8171         {
8172           *bp++ = '\0';
8173           emitcode (bp1, "");
8174           bp1 = bp;
8175         }
8176       else
8177         {
8178           /* Add \n for labels, not dirs such as c:\mydir */
8179           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
8180             {
8181               bp++;
8182               *bp = '\0';
8183               bp++;
8184               emitcode (bp1, "");
8185               bp1 = bp;
8186             }
8187           else
8188             bp++;
8189         }
8190     }
8191   if (bp1 != bp)
8192     emitcode (bp1, "");
8193   /*     emitcode("",buffer); */
8194   _G.inLine -= (!options.asmpeep);
8195 }
8196
8197 /*-----------------------------------------------------------------*/
8198 /* genRRC - rotate right with carry                                */
8199 /*-----------------------------------------------------------------*/
8200 static void
8201 genRRC (iCode * ic)
8202 {
8203   operand *left, *result;
8204   int     size, offset;
8205   char *l;
8206
8207   D (emitcode (";", "genRRC"));
8208
8209   /* rotate right with carry */
8210   left = IC_LEFT (ic);
8211   result = IC_RESULT (ic);
8212   aopOp (left, ic, FALSE, FALSE);
8213   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8214
8215   /* move it to the result */
8216   size = AOP_SIZE (result);
8217   offset = size - 1;
8218   CLRC;
8219
8220   _startLazyDPSEvaluation ();
8221   while (size--)
8222     {
8223       l = aopGet (left, offset, FALSE, FALSE, NULL);
8224       MOVA (l);
8225       emitcode ("rrc", "a");
8226       if (AOP_SIZE (result) > 1)
8227         aopPut (result, "a", offset--);
8228     }
8229   _endLazyDPSEvaluation ();
8230
8231   /* now we need to put the carry into the
8232      highest order byte of the result */
8233   if (AOP_SIZE (result) > 1)
8234     {
8235       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8236       MOVA (l);
8237     }
8238   emitcode ("mov", "acc.7,c");
8239   aopPut (result, "a", AOP_SIZE (result) - 1);
8240   freeAsmop (result, NULL, ic, TRUE);
8241   freeAsmop (left, NULL, ic, TRUE);
8242 }
8243
8244 /*-----------------------------------------------------------------*/
8245 /* genRLC - generate code for rotate left with carry               */
8246 /*-----------------------------------------------------------------*/
8247 static void
8248 genRLC (iCode * ic)
8249 {
8250   operand *left, *result;
8251   int size, offset;
8252   char *l;
8253
8254   D (emitcode (";", "genRLC "));
8255
8256   /* rotate right with carry */
8257   left = IC_LEFT (ic);
8258   result = IC_RESULT (ic);
8259   aopOp (left, ic, FALSE, FALSE);
8260   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8261
8262   /* move it to the result */
8263   size = AOP_SIZE (result);
8264   offset = 0;
8265   if (size--)
8266     {
8267       l = aopGet (left, offset, FALSE, FALSE, NULL);
8268       MOVA (l);
8269       emitcode ("add", "a,acc");
8270       if (AOP_SIZE (result) > 1)
8271         {
8272           aopPut (result, "a", offset++);
8273         }
8274
8275       _startLazyDPSEvaluation ();
8276       while (size--)
8277         {
8278           l = aopGet (left, offset, FALSE, FALSE, NULL);
8279           MOVA (l);
8280           emitcode ("rlc", "a");
8281           if (AOP_SIZE (result) > 1)
8282             aopPut (result, "a", offset++);
8283         }
8284       _endLazyDPSEvaluation ();
8285     }
8286   /* now we need to put the carry into the
8287      highest order byte of the result */
8288   if (AOP_SIZE (result) > 1)
8289     {
8290       l = aopGet (result, 0, FALSE, FALSE, NULL);
8291       MOVA (l);
8292     }
8293   emitcode ("mov", "acc.0,c");
8294   aopPut (result, "a", 0);
8295   freeAsmop (result, NULL, ic, TRUE);
8296   freeAsmop (left, NULL, ic, TRUE);
8297 }
8298
8299 /*-----------------------------------------------------------------*/
8300 /* genGetHbit - generates code get highest order bit               */
8301 /*-----------------------------------------------------------------*/
8302 static void
8303 genGetHbit (iCode * ic)
8304 {
8305   operand *left, *result;
8306
8307   D (emitcode (";", "genGetHbit"));
8308
8309   left = IC_LEFT (ic);
8310   result = IC_RESULT (ic);
8311   aopOp (left, ic, FALSE, FALSE);
8312   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8313
8314   /* get the highest order byte into a */
8315   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8316   if (AOP_TYPE (result) == AOP_CRY)
8317     {
8318       emitcode ("rlc", "a");
8319       outBitC (result);
8320     }
8321   else
8322     {
8323       emitcode ("rl", "a");
8324       emitcode ("anl", "a,#1");
8325       outAcc (result);
8326     }
8327
8328
8329   freeAsmop (result, NULL, ic, TRUE);
8330   freeAsmop (left, NULL, ic, TRUE);
8331 }
8332
8333 /*-----------------------------------------------------------------*/
8334 /* genSwap - generates code to swap nibbles or bytes               */
8335 /*-----------------------------------------------------------------*/
8336 static void
8337 genSwap (iCode * ic)
8338 {
8339   operand *left, *result;
8340
8341   D(emitcode (";     genSwap",""));
8342
8343   left = IC_LEFT (ic);
8344   result = IC_RESULT (ic);
8345   aopOp (left, ic, FALSE, FALSE);
8346   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8347
8348   _startLazyDPSEvaluation ();
8349   switch (AOP_SIZE (left))
8350     {
8351     case 1: /* swap nibbles in byte */
8352       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8353       emitcode ("swap", "a");
8354       aopPut (result, "a", 0);
8355       break;
8356     case 2: /* swap bytes in word */
8357       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8358         {
8359           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8360           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8361           aopPut (result, "a", 1);
8362         }
8363       else if (operandsEqu (left, result))
8364         {
8365           char * reg = "a";
8366           bool pushedB = FALSE, leftInB = FALSE;
8367
8368           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8369           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8370             {
8371               pushedB = pushB ();
8372               emitcode ("mov", "b,a");
8373               reg = "b";
8374               leftInB = TRUE;
8375             }
8376           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8377           aopPut (result, reg, 1);
8378
8379           if (leftInB)
8380             popB (pushedB);
8381         }
8382       else
8383         {
8384           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8385           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8386         }
8387       break;
8388     default:
8389       wassertl(FALSE, "unsupported SWAP operand size");
8390     }
8391   _endLazyDPSEvaluation ();
8392
8393   freeAsmop (result, NULL, ic, TRUE);
8394   freeAsmop (left, NULL, ic, TRUE);
8395 }
8396
8397 /*-----------------------------------------------------------------*/
8398 /* AccRol - rotate left accumulator by known count                 */
8399 /*-----------------------------------------------------------------*/
8400 static void
8401 AccRol (int shCount)
8402 {
8403   shCount &= 0x0007;            // shCount : 0..7
8404
8405   switch (shCount)
8406     {
8407     case 0:
8408       break;
8409     case 1:
8410       emitcode ("rl", "a");
8411       break;
8412     case 2:
8413       emitcode ("rl", "a");
8414       emitcode ("rl", "a");
8415       break;
8416     case 3:
8417       emitcode ("swap", "a");
8418       emitcode ("rr", "a");
8419       break;
8420     case 4:
8421       emitcode ("swap", "a");
8422       break;
8423     case 5:
8424       emitcode ("swap", "a");
8425       emitcode ("rl", "a");
8426       break;
8427     case 6:
8428       emitcode ("rr", "a");
8429       emitcode ("rr", "a");
8430       break;
8431     case 7:
8432       emitcode ("rr", "a");
8433       break;
8434     }
8435 }
8436
8437 /*-----------------------------------------------------------------*/
8438 /* AccLsh - left shift accumulator by known count                  */
8439 /*-----------------------------------------------------------------*/
8440 static void
8441 AccLsh (int shCount)
8442 {
8443   if (shCount != 0)
8444     {
8445       if (shCount == 1)
8446         emitcode ("add", "a,acc");
8447       else if (shCount == 2)
8448         {
8449           emitcode ("add", "a,acc");
8450           emitcode ("add", "a,acc");
8451         }
8452       else
8453         {
8454           /* rotate left accumulator */
8455           AccRol (shCount);
8456           /* and kill the lower order bits */
8457           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8458         }
8459     }
8460 }
8461
8462 /*-----------------------------------------------------------------*/
8463 /* AccRsh - right shift accumulator by known count                 */
8464 /*-----------------------------------------------------------------*/
8465 static void
8466 AccRsh (int shCount)
8467 {
8468   if (shCount != 0)
8469     {
8470       if (shCount == 1)
8471         {
8472           CLRC;
8473           emitcode ("rrc", "a");
8474         }
8475       else
8476         {
8477           /* rotate right accumulator */
8478           AccRol (8 - shCount);
8479           /* and kill the higher order bits */
8480           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8481         }
8482     }
8483 }
8484
8485 #ifdef BETTER_LITERAL_SHIFT
8486 /*-----------------------------------------------------------------*/
8487 /* AccSRsh - signed right shift accumulator by known count                 */
8488 /*-----------------------------------------------------------------*/
8489 static void
8490 AccSRsh (int shCount)
8491 {
8492   symbol *tlbl;
8493   if (shCount != 0)
8494     {
8495       if (shCount == 1)
8496         {
8497           emitcode ("mov", "c,acc.7");
8498           emitcode ("rrc", "a");
8499         }
8500       else if (shCount == 2)
8501         {
8502           emitcode ("mov", "c,acc.7");
8503           emitcode ("rrc", "a");
8504           emitcode ("mov", "c,acc.7");
8505           emitcode ("rrc", "a");
8506         }
8507       else
8508         {
8509           tlbl = newiTempLabel (NULL);
8510           /* rotate right accumulator */
8511           AccRol (8 - shCount);
8512           /* and kill the higher order bits */
8513           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8514           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8515           emitcode ("orl", "a,#!constbyte",
8516                     (unsigned char) ~SRMask[shCount]);
8517           emitcode ("", "!tlabeldef", tlbl->key + 100);
8518         }
8519     }
8520 }
8521 #endif
8522
8523 #ifdef BETTER_LITERAL_SHIFT
8524 /*-----------------------------------------------------------------*/
8525 /* shiftR1Left2Result - shift right one byte from left to result   */
8526 /*-----------------------------------------------------------------*/
8527 static void
8528 shiftR1Left2Result (operand * left, int offl,
8529                     operand * result, int offr,
8530                     int shCount, int sign)
8531 {
8532   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8533   /* shift right accumulator */
8534   if (sign)
8535     AccSRsh (shCount);
8536   else
8537     AccRsh (shCount);
8538   aopPut (result, "a", offr);
8539 }
8540 #endif
8541
8542 #ifdef BETTER_LITERAL_SHIFT
8543 /*-----------------------------------------------------------------*/
8544 /* shiftL1Left2Result - shift left one byte from left to result    */
8545 /*-----------------------------------------------------------------*/
8546 static void
8547 shiftL1Left2Result (operand * left, int offl,
8548                     operand * result, int offr, int shCount)
8549 {
8550   char *l;
8551   l = aopGet (left, offl, FALSE, FALSE, NULL);
8552   MOVA (l);
8553   /* shift left accumulator */
8554   AccLsh (shCount);
8555   aopPut (result, "a", offr);
8556 }
8557 #endif
8558
8559 #ifdef BETTER_LITERAL_SHIFT
8560 /*-----------------------------------------------------------------*/
8561 /* movLeft2Result - move byte from left to result                  */
8562 /*-----------------------------------------------------------------*/
8563 static void
8564 movLeft2Result (operand * left, int offl,
8565                 operand * result, int offr, int sign)
8566 {
8567   char *l;
8568   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8569   {
8570       l = aopGet (left, offl, FALSE, FALSE, NULL);
8571
8572       if (*l == '@' && (IS_AOP_PREG (result)))
8573       {
8574           emitcode ("mov", "a,%s", l);
8575           aopPut (result, "a", offr);
8576       }
8577       else
8578       {
8579           if (!sign)
8580           {
8581             aopPut (result, l, offr);
8582           }
8583           else
8584             {
8585               /* MSB sign in acc.7 ! */
8586               if (getDataSize (left) == offl + 1)
8587                 {
8588                   MOVA (l);
8589                   aopPut (result, "a", offr);
8590                 }
8591             }
8592       }
8593   }
8594 }
8595 #endif
8596
8597 #ifdef BETTER_LITERAL_SHIFT
8598 /*-----------------------------------------------------------------*/
8599 /* AccAXRrl1 - right rotate a:x by 1                               */
8600 /*-----------------------------------------------------------------*/
8601 static void
8602 AccAXRrl1 (char *x)
8603 {
8604   emitcode ("mov", "c,acc.0");
8605   emitcode ("xch", "a,%s", x);
8606   emitcode ("rrc", "a");
8607   emitcode ("xch", "a,%s", x);
8608   emitcode ("rrc", "a");
8609 }
8610 #endif
8611
8612 #ifdef BETTER_LITERAL_SHIFT
8613 //REMOVE ME!!!
8614 /*-----------------------------------------------------------------*/
8615 /* AccAXLrl1 - left rotate a:x by 1                                */
8616 /*-----------------------------------------------------------------*/
8617 static void
8618 AccAXLrl1 (char *x)
8619 {
8620   emitcode ("mov", "c,acc.7");
8621   emitcode ("xch", "a,%s", x);
8622   emitcode ("rlc", "a");
8623   emitcode ("xch", "a,%s", x);
8624   emitcode ("rlc", "a");
8625 }
8626 #endif
8627
8628 #ifdef BETTER_LITERAL_SHIFT
8629 /*-----------------------------------------------------------------*/
8630 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8631 /*-----------------------------------------------------------------*/
8632 static void
8633 AccAXRsh1 (char *x)
8634 {
8635   emitcode ("rrc", "a");
8636   emitcode ("xch", "a,%s", x);
8637   emitcode ("rrc", "a");
8638   emitcode ("xch", "a,%s", x);
8639 }
8640 #endif
8641
8642 #ifdef BETTER_LITERAL_SHIFT
8643 /*-----------------------------------------------------------------*/
8644 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8645 /*-----------------------------------------------------------------*/
8646 static void
8647 AccAXLsh1 (char *x)
8648 {
8649   emitcode ("xch", "a,%s", x);
8650   emitcode ("add", "a,acc");
8651   emitcode ("xch", "a,%s", x);
8652   emitcode ("rlc", "a");
8653 }
8654 #endif
8655
8656 #ifdef BETTER_LITERAL_SHIFT
8657 /*-----------------------------------------------------------------*/
8658 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8659 /*-----------------------------------------------------------------*/
8660 static void
8661 AccAXLsh (char *x, int shCount)
8662 {
8663   switch (shCount)
8664     {
8665     case 0:
8666       break;
8667     case 1:
8668       AccAXLsh1 (x);
8669       break;
8670     case 2:
8671       AccAXLsh1 (x);
8672       AccAXLsh1 (x);
8673       break;
8674     case 3:
8675     case 4:
8676     case 5:                             // AAAAABBB:CCCCCDDD
8677
8678       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8679
8680       emitcode ("anl", "a,#!constbyte",
8681                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8682
8683       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8684
8685       AccRol (shCount);                 // DDDCCCCC:BBB00000
8686
8687       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8688
8689       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8690
8691       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8692
8693       emitcode ("anl", "a,#!constbyte",
8694                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8695
8696       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8697
8698       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8699
8700       break;
8701     case 6:                             // AAAAAABB:CCCCCCDD
8702       emitcode ("anl", "a,#!constbyte",
8703                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8704 #if 1
8705       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8706       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8707       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8708 #else
8709       emitcode ("mov", "c,acc.0");      // c = B
8710       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8711       emitcode("rrc","a");
8712       emitcode("xch","a,%s", x);
8713       emitcode("rrc","a");
8714       emitcode("mov","c,acc.0"); //<< get correct bit
8715       emitcode("xch","a,%s", x);
8716
8717       emitcode("rrc","a");
8718       emitcode("xch","a,%s", x);
8719       emitcode("rrc","a");
8720       emitcode("xch","a,%s", x);
8721 #endif
8722       break;
8723     case 7:                             // a:x <<= 7
8724
8725       emitcode ("anl", "a,#!constbyte",
8726                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8727
8728       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8729
8730       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8731
8732       break;
8733     default:
8734       break;
8735     }
8736 }
8737 #endif
8738
8739 #ifdef BETTER_LITERAL_SHIFT
8740 //REMOVE ME!!!
8741 /*-----------------------------------------------------------------*/
8742 /* AccAXRsh - right shift a:x known count (0..7)                   */
8743 /*-----------------------------------------------------------------*/
8744 static void
8745 AccAXRsh (char *x, int shCount)
8746 {
8747   switch (shCount)
8748     {
8749     case 0:
8750       break;
8751     case 1:
8752       CLRC;
8753       AccAXRsh1 (x);                    // 0->a:x
8754
8755       break;
8756     case 2:
8757       CLRC;
8758       AccAXRsh1 (x);                    // 0->a:x
8759
8760       CLRC;
8761       AccAXRsh1 (x);                    // 0->a:x
8762
8763       break;
8764     case 3:
8765     case 4:
8766     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8767
8768       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8769
8770       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8771
8772       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8773
8774       emitcode ("anl", "a,#!constbyte",
8775                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8776
8777       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8778
8779       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8780
8781       emitcode ("anl", "a,#!constbyte",
8782                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8783
8784       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8785
8786       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8787
8788       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8789
8790       break;
8791     case 6:                             // AABBBBBB:CCDDDDDD
8792
8793       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8794       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8795
8796       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8797
8798       emitcode ("anl", "a,#!constbyte",
8799                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8800
8801       break;
8802     case 7:                             // ABBBBBBB:CDDDDDDD
8803
8804       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8805
8806       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8807
8808       emitcode ("anl", "a,#!constbyte",
8809                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8810
8811       break;
8812     default:
8813       break;
8814     }
8815 }
8816 #endif
8817
8818 #ifdef BETTER_LITERAL_SHIFT
8819 /*-----------------------------------------------------------------*/
8820 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8821 /*-----------------------------------------------------------------*/
8822 static void
8823 AccAXRshS (char *x, int shCount)
8824 {
8825   symbol *tlbl;
8826   switch (shCount)
8827     {
8828     case 0:
8829       break;
8830     case 1:
8831       emitcode ("mov", "c,acc.7");
8832       AccAXRsh1 (x);                    // s->a:x
8833
8834       break;
8835     case 2:
8836       emitcode ("mov", "c,acc.7");
8837       AccAXRsh1 (x);                    // s->a:x
8838
8839       emitcode ("mov", "c,acc.7");
8840       AccAXRsh1 (x);                    // s->a:x
8841
8842       break;
8843     case 3:
8844     case 4:
8845     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8846
8847       tlbl = newiTempLabel (NULL);
8848       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8849
8850       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8851
8852       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8853
8854       emitcode ("anl", "a,#!constbyte",
8855                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8856
8857       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8858
8859       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8860
8861       emitcode ("anl", "a,#!constbyte",
8862                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8863
8864       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8865
8866       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8867
8868       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8869
8870       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8871       emitcode ("orl", "a,#!constbyte",
8872                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8873
8874       emitcode ("", "!tlabeldef", tlbl->key + 100);
8875       break;                            // SSSSAAAA:BBBCCCCC
8876
8877     case 6:                             // AABBBBBB:CCDDDDDD
8878
8879       tlbl = newiTempLabel (NULL);
8880
8881       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
8882       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8883
8884       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8885
8886       emitcode ("anl", "a,#!constbyte",
8887                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8888
8889       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8890       emitcode ("orl", "a,#!constbyte",
8891                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8892
8893       emitcode ("", "!tlabeldef", tlbl->key + 100);
8894       break;
8895     case 7:                             // ABBBBBBB:CDDDDDDD
8896
8897       tlbl = newiTempLabel (NULL);
8898
8899       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8900
8901       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8902
8903       emitcode ("anl", "a,#!constbyte",
8904                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8905
8906       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8907       emitcode ("orl", "a,#!constbyte",
8908                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8909
8910       emitcode ("", "!tlabeldef", tlbl->key + 100);
8911       break;
8912     default:
8913       break;
8914     }
8915 }
8916 #endif
8917
8918 #ifdef BETTER_LITERAL_SHIFT
8919 static void
8920 _loadLeftIntoAx(char    **lsb,
8921                 operand *left,
8922                 operand *result,
8923                 int     offl,
8924                 int     offr)
8925 {
8926   // Get the initial value from left into a pair of registers.
8927   // MSB must be in A, LSB can be any register.
8928   //
8929   // If the result is held in registers, it is an optimization
8930   // if the LSB can be held in the register which will hold the,
8931   // result LSB since this saves us from having to copy it into
8932   // the result following AccAXLsh.
8933   //
8934   // If the result is addressed indirectly, this is not a gain.
8935   if (AOP_NEEDSACC(result))
8936   {
8937        char *leftByte;
8938
8939        _startLazyDPSEvaluation();
8940       if (AOP_TYPE(left) == AOP_DPTR2)
8941        {
8942            // Get MSB in A.
8943            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
8944            // get LSB in DP2_RESULT_REG.
8945            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
8946            assert(!strcmp(leftByte, DP2_RESULT_REG));
8947        }
8948        else
8949        {
8950            // get LSB into DP2_RESULT_REG
8951            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
8952            if (strcmp(leftByte, DP2_RESULT_REG))
8953            {
8954                TR_AP("#7");
8955                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
8956            }
8957            // And MSB in A.
8958            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
8959            assert(strcmp(leftByte, DP2_RESULT_REG));
8960            MOVA (leftByte);
8961        }
8962        _endLazyDPSEvaluation();
8963        *lsb = DP2_RESULT_REG;
8964   }
8965   else
8966   {
8967       if (sameRegs (AOP (result), AOP (left)) &&
8968         ((offl + MSB16) == offr))
8969       {
8970           /* don't crash result[offr] */
8971           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8972           emitcode ("xch", "a,%s",
8973                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
8974       }
8975       else
8976       {
8977           movLeft2Result (left, offl, result, offr, 0);
8978           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
8979       }
8980       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
8981       assert(strcmp(*lsb,"a"));
8982   }
8983 }
8984
8985 static void
8986 _storeAxResults(char    *lsb,
8987                 operand *result,
8988                 int     offr)
8989 {
8990   _startLazyDPSEvaluation();
8991   if (AOP_NEEDSACC(result))
8992   {
8993       /* We have to explicitly update the result LSB.
8994        */
8995       emitcode ("xch","a,%s", lsb);
8996       aopPut (result, "a", offr);
8997       emitcode ("mov","a,%s", lsb);
8998   }
8999   if (getDataSize (result) > 1)
9000   {
9001       aopPut (result, "a", offr + MSB16);
9002   }
9003   _endLazyDPSEvaluation();
9004 }
9005
9006 /*-----------------------------------------------------------------*/
9007 /* shiftL2Left2Result - shift left two bytes from left to result   */
9008 /*-----------------------------------------------------------------*/
9009 static void
9010 shiftL2Left2Result (operand * left, int offl,
9011                     operand * result, int offr, int shCount)
9012 {
9013   char *lsb;
9014
9015   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9016
9017   AccAXLsh (lsb, shCount);
9018
9019   _storeAxResults(lsb, result, offr);
9020 }
9021 #endif
9022
9023 #ifdef BETTER_LITERAL_SHIFT
9024 /*-----------------------------------------------------------------*/
9025 /* shiftR2Left2Result - shift right two bytes from left to result  */
9026 /*-----------------------------------------------------------------*/
9027 static void
9028 shiftR2Left2Result (operand * left, int offl,
9029                     operand * result, int offr,
9030                     int shCount, int sign)
9031 {
9032   char *lsb;
9033
9034   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9035
9036   /* a:x >> shCount (x = lsb(result)) */
9037   if (sign)
9038   {
9039      AccAXRshS(lsb, shCount);
9040   }
9041   else
9042   {
9043     AccAXRsh(lsb, shCount);
9044   }
9045
9046   _storeAxResults(lsb, result, offr);
9047 }
9048 #endif
9049
9050 /*-----------------------------------------------------------------*/
9051 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9052 /*-----------------------------------------------------------------*/
9053 static void
9054 shiftLLeftOrResult (operand * left, int offl,
9055                     operand * result, int offr, int shCount)
9056 {
9057   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9058   /* shift left accumulator */
9059   AccLsh (shCount);
9060   /* or with result */
9061   emitcode ("orl", "a,%s",
9062             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9063   /* back to result */
9064   aopPut (result, "a", offr);
9065 }
9066
9067 #if 0
9068 //REMOVE ME!!!
9069 /*-----------------------------------------------------------------*/
9070 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9071 /*-----------------------------------------------------------------*/
9072 static void
9073 shiftRLeftOrResult (operand * left, int offl,
9074                     operand * result, int offr, int shCount)
9075 {
9076   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9077   /* shift right accumulator */
9078   AccRsh (shCount);
9079   /* or with result */
9080   emitcode ("orl", "a,%s",
9081             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9082   /* back to result */
9083   aopPut (result, "a", offr);
9084 }
9085 #endif
9086
9087 #ifdef BETTER_LITERAL_SHIFT
9088 /*-----------------------------------------------------------------*/
9089 /* genlshOne - left shift a one byte quantity by known count       */
9090 /*-----------------------------------------------------------------*/
9091 static void
9092 genlshOne (operand * result, operand * left, int shCount)
9093 {
9094   D (emitcode (";", "genlshOne "));
9095
9096   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9097 }
9098 #endif
9099
9100 #ifdef BETTER_LITERAL_SHIFT
9101 /*-----------------------------------------------------------------*/
9102 /* genlshTwo - left shift two bytes by known amount != 0           */
9103 /*-----------------------------------------------------------------*/
9104 static void
9105 genlshTwo (operand * result, operand * left, int shCount)
9106 {
9107   int size;
9108
9109   D (emitcode (";", "genlshTwo"));
9110
9111   size = getDataSize (result);
9112
9113   /* if shCount >= 8 */
9114   if (shCount >= 8)
9115   {
9116       shCount -= 8;
9117
9118       _startLazyDPSEvaluation();
9119
9120       if (size > 1)
9121         {
9122           if (shCount)
9123           {
9124             _endLazyDPSEvaluation();
9125             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9126             aopPut (result, zero, LSB);
9127           }
9128           else
9129           {
9130             movLeft2Result (left, LSB, result, MSB16, 0);
9131             aopPut (result, zero, LSB);
9132             _endLazyDPSEvaluation();
9133           }
9134         }
9135         else
9136         {
9137           aopPut (result, zero, LSB);
9138           _endLazyDPSEvaluation();
9139         }
9140   }
9141
9142   /*  1 <= shCount <= 7 */
9143   else
9144     {
9145       if (size == 1)
9146         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9147       else
9148         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9149       }
9150 }
9151 #endif
9152
9153 #if 0
9154 //REMOVE ME!!!
9155 /*-----------------------------------------------------------------*/
9156 /* shiftLLong - shift left one long from left to result            */
9157 /* offl = LSB or MSB16                                             */
9158 /*-----------------------------------------------------------------*/
9159 static void
9160 shiftLLong (operand * left, operand * result, int offr)
9161 {
9162   char *l;
9163   int size = AOP_SIZE (result);
9164
9165   if (size >= LSB + offr)
9166     {
9167       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9168       MOVA (l);
9169       emitcode ("add", "a,acc");
9170       if (sameRegs (AOP (left), AOP (result)) &&
9171           size >= MSB16 + offr && offr != LSB)
9172         emitcode ("xch", "a,%s",
9173                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9174       else
9175         aopPut (result, "a", LSB + offr);
9176     }
9177
9178   if (size >= MSB16 + offr)
9179     {
9180       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9181         {
9182           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9183           MOVA (l);
9184         }
9185       emitcode ("rlc", "a");
9186       if (sameRegs (AOP (left), AOP (result)) &&
9187           size >= MSB24 + offr && offr != LSB)
9188         emitcode ("xch", "a,%s",
9189                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9190       else
9191         aopPut (result, "a", MSB16 + offr);
9192     }
9193
9194   if (size >= MSB24 + offr)
9195     {
9196       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9197         {
9198           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9199           MOVA (l);
9200         }
9201       emitcode ("rlc", "a");
9202       if (sameRegs (AOP (left), AOP (result)) &&
9203           size >= MSB32 + offr && offr != LSB)
9204         emitcode ("xch", "a,%s",
9205                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9206       else
9207         aopPut (result, "a", MSB24 + offr);
9208     }
9209
9210   if (size > MSB32 + offr)
9211     {
9212       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9213         {
9214           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9215           MOVA (l);
9216         }
9217       emitcode ("rlc", "a");
9218       aopPut (result, "a", MSB32 + offr);
9219     }
9220   if (offr != LSB)
9221     aopPut (result, zero, LSB);
9222 }
9223 #endif
9224
9225 #if 0
9226 //REMOVE ME!!!
9227 /*-----------------------------------------------------------------*/
9228 /* genlshFour - shift four byte by a known amount != 0             */
9229 /*-----------------------------------------------------------------*/
9230 static void
9231 genlshFour (operand * result, operand * left, int shCount)
9232 {
9233   int size;
9234
9235   D (emitcode (";", "genlshFour "));
9236
9237   size = AOP_SIZE (result);
9238
9239   /* if shifting more that 3 bytes */
9240   if (shCount >= 24)
9241     {
9242       shCount -= 24;
9243       if (shCount)
9244         /* lowest order of left goes to the highest
9245            order of the destination */
9246         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9247       else
9248         movLeft2Result (left, LSB, result, MSB32, 0);
9249       aopPut (result, zero, LSB);
9250       aopPut (result, zero, MSB16);
9251       aopPut (result, zero, MSB24);
9252       return;
9253     }
9254
9255   /* more than two bytes */
9256   else if (shCount >= 16)
9257     {
9258       /* lower order two bytes goes to higher order two bytes */
9259       shCount -= 16;
9260       /* if some more remaining */
9261       if (shCount)
9262         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9263       else
9264         {
9265           movLeft2Result (left, MSB16, result, MSB32, 0);
9266           movLeft2Result (left, LSB, result, MSB24, 0);
9267         }
9268       aopPut (result, zero, MSB16);
9269       aopPut (result, zero, LSB);
9270       return;
9271     }
9272
9273   /* if more than 1 byte */
9274   else if (shCount >= 8)
9275     {
9276       /* lower order three bytes goes to higher order  three bytes */
9277       shCount -= 8;
9278       if (size == 2)
9279         {
9280           if (shCount)
9281             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9282           else
9283             movLeft2Result (left, LSB, result, MSB16, 0);
9284         }
9285       else
9286         {                       /* size = 4 */
9287           if (shCount == 0)
9288             {
9289               movLeft2Result (left, MSB24, result, MSB32, 0);
9290               movLeft2Result (left, MSB16, result, MSB24, 0);
9291               movLeft2Result (left, LSB, result, MSB16, 0);
9292               aopPut (result, zero, LSB);
9293             }
9294           else if (shCount == 1)
9295             shiftLLong (left, result, MSB16);
9296           else
9297             {
9298               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9299               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9300               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9301               aopPut (result, zero, LSB);
9302             }
9303         }
9304     }
9305
9306   /* 1 <= shCount <= 7 */
9307   else if (shCount <= 2)
9308     {
9309       shiftLLong (left, result, LSB);
9310       if (shCount == 2)
9311         shiftLLong (result, result, LSB);
9312     }
9313   /* 3 <= shCount <= 7, optimize */
9314   else
9315     {
9316       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9317       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9318       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9319     }
9320 }
9321 #endif
9322
9323 #ifdef BETTER_LITERAL_SHIFT
9324 /*-----------------------------------------------------------------*/
9325 /* genLeftShiftLiteral - left shifting by known count              */
9326 /*-----------------------------------------------------------------*/
9327 static bool
9328 genLeftShiftLiteral (operand * left,
9329                      operand * right,
9330                      operand * result,
9331                      iCode * ic)
9332 {
9333   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9334   int size;
9335
9336   size = getSize (operandType (result));
9337
9338   D(emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9339
9340   /* We only handle certain easy cases so far. */
9341   if ((shCount != 0)
9342    && (shCount < (size * 8))
9343    && (size != 1)
9344    && (size != 2))
9345   {
9346       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9347       return FALSE;
9348   }
9349
9350   freeAsmop (right, NULL, ic, TRUE);
9351
9352   aopOp(left, ic, FALSE, FALSE);
9353   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9354
9355 #if 0 // debug spew
9356   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9357   {
9358         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9359         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9360         {
9361            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9362         }
9363   }
9364   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9365   {
9366         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9367         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9368         {
9369            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9370         }
9371   }
9372 #endif
9373
9374 #if VIEW_SIZE
9375   emitcode ("; shift left ", "result %d, left %d", size,
9376             AOP_SIZE (left));
9377 #endif
9378
9379   /* I suppose that the left size >= result size */
9380   if (shCount == 0)
9381   {
9382         _startLazyDPSEvaluation();
9383         while (size--)
9384         {
9385           movLeft2Result (left, size, result, size, 0);
9386         }
9387         _endLazyDPSEvaluation();
9388   }
9389   else if (shCount >= (size * 8))
9390   {
9391     _startLazyDPSEvaluation();
9392     while (size--)
9393     {
9394       aopPut (result, zero, size);
9395     }
9396     _endLazyDPSEvaluation();
9397   }
9398   else
9399   {
9400       switch (size)
9401         {
9402         case 1:
9403           genlshOne (result, left, shCount);
9404           break;
9405
9406         case 2:
9407           genlshTwo (result, left, shCount);
9408           break;
9409 #if 0
9410         case 4:
9411           genlshFour (result, left, shCount);
9412           break;
9413 #endif
9414         default:
9415           fprintf(stderr, "*** ack! mystery literal shift!\n");
9416           break;
9417         }
9418     }
9419   freeAsmop (result, NULL, ic, TRUE);
9420   freeAsmop (left, NULL, ic, TRUE);
9421   return TRUE;
9422 }
9423 #endif
9424
9425 /*-----------------------------------------------------------------*/
9426 /* genLeftShift - generates code for left shifting                 */
9427 /*-----------------------------------------------------------------*/
9428 static void
9429 genLeftShift (iCode * ic)
9430 {
9431   operand *left, *right, *result;
9432   int size, offset;
9433   char *l;
9434   symbol *tlbl, *tlbl1;
9435   bool pushedB;
9436
9437   D (emitcode (";", "genLeftShift "));
9438
9439   right = IC_RIGHT (ic);
9440   left = IC_LEFT (ic);
9441   result = IC_RESULT (ic);
9442
9443   aopOp (right, ic, FALSE, FALSE);
9444
9445
9446 #ifdef BETTER_LITERAL_SHIFT
9447   /* if the shift count is known then do it
9448      as efficiently as possible */
9449   if (AOP_TYPE (right) == AOP_LIT)
9450     {
9451       if (genLeftShiftLiteral (left, right, result, ic))
9452       {
9453         return;
9454       }
9455     }
9456 #endif
9457
9458   /* shift count is unknown then we have to form
9459      a loop get the loop count in B : Note: we take
9460      only the lower order byte since shifting
9461      more that 32 bits make no sense anyway, ( the
9462      largest size of an object can be only 32 bits ) */
9463
9464   pushedB = pushB ();
9465   if (AOP_TYPE (right) == AOP_LIT)
9466   {
9467       /* Really should be handled by genLeftShiftLiteral,
9468        * but since I'm too lazy to fix that today, at least we can make
9469        * some small improvement.
9470        */
9471        emitcode("mov", "b,#!constbyte",
9472                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9473   }
9474   else
9475   {
9476       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9477       emitcode ("inc", "b");
9478   }
9479   freeAsmop (right, NULL, ic, TRUE);
9480   aopOp (left, ic, FALSE, FALSE);
9481   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9482
9483   /* now move the left to the result if they are not the same */
9484   if (!sameRegs (AOP (left), AOP (result)) &&
9485       AOP_SIZE (result) > 1)
9486     {
9487
9488       size = AOP_SIZE (result);
9489       offset = 0;
9490       _startLazyDPSEvaluation ();
9491       while (size--)
9492         {
9493           l = aopGet (left, offset, FALSE, TRUE, NULL);
9494           if (*l == '@' && (IS_AOP_PREG (result)))
9495             {
9496
9497               emitcode ("mov", "a,%s", l);
9498               aopPut (result, "a", offset);
9499             }
9500           else
9501             aopPut (result, l, offset);
9502           offset++;
9503         }
9504       _endLazyDPSEvaluation ();
9505     }
9506
9507   tlbl = newiTempLabel (NULL);
9508   size = AOP_SIZE (result);
9509   offset = 0;
9510   tlbl1 = newiTempLabel (NULL);
9511
9512   /* if it is only one byte then */
9513   if (size == 1)
9514     {
9515       symbol *tlbl1 = newiTempLabel (NULL);
9516
9517       l = aopGet (left, 0, FALSE, FALSE, NULL);
9518       MOVA (l);
9519       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9520       emitcode ("", "!tlabeldef", tlbl->key + 100);
9521       emitcode ("add", "a,acc");
9522       emitcode ("", "!tlabeldef", tlbl1->key + 100);
9523       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9524       popB (pushedB);
9525       aopPut (result, "a", 0);
9526       goto release;
9527     }
9528
9529   reAdjustPreg (AOP (result));
9530
9531   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9532   emitcode ("", "!tlabeldef", tlbl->key + 100);
9533   l = aopGet (result, offset, FALSE, FALSE, NULL);
9534   MOVA (l);
9535   emitcode ("add", "a,acc");
9536   aopPut (result, "a", offset++);
9537   _startLazyDPSEvaluation ();
9538   while (--size)
9539     {
9540       l = aopGet (result, offset, FALSE, FALSE, NULL);
9541       MOVA (l);
9542       emitcode ("rlc", "a");
9543       aopPut (result, "a", offset++);
9544     }
9545   _endLazyDPSEvaluation ();
9546   reAdjustPreg (AOP (result));
9547
9548   emitcode ("", "!tlabeldef", tlbl1->key + 100);
9549   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9550   popB (pushedB);
9551 release:
9552   freeAsmop (result, NULL, ic, TRUE);
9553   freeAsmop (left, NULL, ic, TRUE);
9554 }
9555
9556 #ifdef BETTER_LITERAL_SHIFT
9557 /*-----------------------------------------------------------------*/
9558 /* genrshOne - right shift a one byte quantity by known count      */
9559 /*-----------------------------------------------------------------*/
9560 static void
9561 genrshOne (operand * result, operand * left,
9562            int shCount, int sign)
9563 {
9564   D (emitcode (";", "genrshOne"));
9565   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9566 }
9567 #endif
9568
9569 #ifdef BETTER_LITERAL_SHIFT
9570 /*-----------------------------------------------------------------*/
9571 /* genrshTwo - right shift two bytes by known amount != 0          */
9572 /*-----------------------------------------------------------------*/
9573 static void
9574 genrshTwo (operand * result, operand * left,
9575            int shCount, int sign)
9576 {
9577   D (emitcode (";", "genrshTwo"));
9578
9579   /* if shCount >= 8 */
9580   if (shCount >= 8)
9581     {
9582       shCount -= 8;
9583       _startLazyDPSEvaluation();
9584       if (shCount)
9585         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9586       else
9587         movLeft2Result (left, MSB16, result, LSB, sign);
9588       addSign (result, MSB16, sign);
9589       _endLazyDPSEvaluation();
9590     }
9591
9592   /*  1 <= shCount <= 7 */
9593   else
9594     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9595 }
9596 #endif
9597
9598 /*-----------------------------------------------------------------*/
9599 /* shiftRLong - shift right one long from left to result           */
9600 /* offl = LSB or MSB16                                             */
9601 /*-----------------------------------------------------------------*/
9602 static void
9603 shiftRLong (operand * left, int offl,
9604             operand * result, int sign)
9605 {
9606   int isSameRegs=sameRegs(AOP(left),AOP(result));
9607
9608   if (isSameRegs && offl>1) {
9609     // we are in big trouble, but this shouldn't happen
9610     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9611   }
9612
9613   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9614
9615   if (offl==MSB16)
9616     {
9617       // shift is > 8
9618       if (sign)
9619         {
9620           emitcode ("rlc", "a");
9621           emitcode ("subb", "a,acc");
9622           emitcode ("xch", "a,%s",
9623                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9624         }
9625       else
9626         {
9627           aopPut (result, zero, MSB32);
9628         }
9629     }
9630
9631   if (!sign)
9632     {
9633       emitcode ("clr", "c");
9634     }
9635   else
9636     {
9637       emitcode ("mov", "c,acc.7");
9638     }
9639
9640   emitcode ("rrc", "a");
9641
9642   if (isSameRegs && offl==MSB16) {
9643     emitcode ("xch",
9644               "a,%s",aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9645   } else {
9646     aopPut (result, "a", MSB32);
9647     MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9648   }
9649
9650   emitcode ("rrc", "a");
9651   if (isSameRegs && offl==1) {
9652     emitcode ("xch", "a,%s",
9653               aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9654   } else {
9655     aopPut (result, "a", MSB24);
9656     MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9657   }
9658   emitcode ("rrc", "a");
9659   aopPut (result, "a", MSB16 - offl);
9660
9661   if (offl == LSB)
9662     {
9663       MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9664       emitcode ("rrc", "a");
9665       aopPut (result, "a", LSB);
9666     }
9667 }
9668
9669 /*-----------------------------------------------------------------*/
9670 /* genrshFour - shift four byte by a known amount != 0             */
9671 /*-----------------------------------------------------------------*/
9672 static void
9673 genrshFour (operand * result, operand * left,
9674             int shCount, int sign)
9675 {
9676   D (emitcode (";", "genrshFour"));
9677
9678   /* if shifting more that 3 bytes */
9679   if (shCount >= 24)
9680     {
9681       shCount -= 24;
9682       _startLazyDPSEvaluation();
9683       if (shCount)
9684         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9685       else
9686         movLeft2Result (left, MSB32, result, LSB, sign);
9687       addSign (result, MSB16, sign);
9688       _endLazyDPSEvaluation();
9689     }
9690   else if (shCount >= 16)
9691     {
9692       shCount -= 16;
9693       _startLazyDPSEvaluation();
9694       if (shCount)
9695         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9696       else
9697         {
9698           movLeft2Result (left, MSB24, result, LSB, 0);
9699           movLeft2Result (left, MSB32, result, MSB16, sign);
9700         }
9701       addSign (result, MSB24, sign);
9702       _endLazyDPSEvaluation();
9703     }
9704   else if (shCount >= 8)
9705     {
9706       shCount -= 8;
9707       _startLazyDPSEvaluation();
9708       if (shCount == 1)
9709         {
9710             shiftRLong (left, MSB16, result, sign);
9711         }
9712       else if (shCount == 0)
9713         {
9714           movLeft2Result (left, MSB16, result, LSB, 0);
9715           movLeft2Result (left, MSB24, result, MSB16, 0);
9716           movLeft2Result (left, MSB32, result, MSB24, sign);
9717           addSign (result, MSB32, sign);
9718         }
9719       else
9720         {
9721           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9722           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9723           /* the last shift is signed */
9724           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9725           addSign (result, MSB32, sign);
9726         }
9727         _endLazyDPSEvaluation();
9728     }
9729   else
9730     {
9731         /* 1 <= shCount <= 7 */
9732       if (shCount <= 2)
9733         {
9734           shiftRLong (left, LSB, result, sign);
9735           if (shCount == 2)
9736             shiftRLong (result, LSB, result, sign);
9737         }
9738       else
9739         {
9740           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9741           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9742           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9743         }
9744     }
9745 }
9746
9747 #ifdef BETTER_LITERAL_SHIFT
9748 /*-----------------------------------------------------------------*/
9749 /* genRightShiftLiteral - right shifting by known count            */
9750 /*-----------------------------------------------------------------*/
9751 static bool
9752 genRightShiftLiteral (operand * left,
9753                       operand * right,
9754                       operand * result,
9755                       iCode * ic,
9756                       int sign)
9757 {
9758   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9759   int size;
9760
9761   size = getSize (operandType (result));
9762
9763   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9764
9765   /* We only handle certain easy cases so far. */
9766   if ((shCount != 0)
9767    && (shCount < (size * 8))
9768    && (size != 1)
9769    && (size != 2)
9770    && (size != 4))
9771   {
9772       D(emitcode (";", "genRightShiftLiteral wimping out"););
9773       return FALSE;
9774   }
9775
9776   freeAsmop (right, NULL, ic, TRUE);
9777
9778   aopOp (left, ic, FALSE, FALSE);
9779   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9780
9781 #if VIEW_SIZE
9782   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9783             AOP_SIZE (left));
9784 #endif
9785
9786   /* test the LEFT size !!! */
9787
9788   /* I suppose that the left size >= result size */
9789   if (shCount == 0)
9790   {
9791       size = getDataSize (result);
9792       _startLazyDPSEvaluation();
9793       while (size--)
9794         movLeft2Result (left, size, result, size, 0);
9795       _endLazyDPSEvaluation();
9796   }
9797   else if (shCount >= (size * 8))
9798     {
9799       if (sign)
9800       {
9801         /* get sign in acc.7 */
9802         MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9803       }
9804       addSign (result, LSB, sign);
9805     }
9806   else
9807     {
9808       switch (size)
9809         {
9810         case 1:
9811           genrshOne (result, left, shCount, sign);
9812           break;
9813
9814         case 2:
9815           genrshTwo (result, left, shCount, sign);
9816           break;
9817 #if 1
9818         case 4:
9819           genrshFour (result, left, shCount, sign);
9820           break;
9821 #endif
9822         default:
9823           break;
9824         }
9825     }
9826   freeAsmop (result, NULL, ic, TRUE);
9827   freeAsmop (left, NULL, ic, TRUE);
9828
9829   return TRUE;
9830 }
9831 #endif
9832
9833 /*-----------------------------------------------------------------*/
9834 /* genSignedRightShift - right shift of signed number              */
9835 /*-----------------------------------------------------------------*/
9836 static void
9837 genSignedRightShift (iCode * ic)
9838 {
9839   operand *right, *left, *result;
9840   int size, offset;
9841   char *l;
9842   symbol *tlbl, *tlbl1;
9843   bool pushedB;
9844
9845   D (emitcode (";", "genSignedRightShift"));
9846
9847   /* we do it the hard way put the shift count in b
9848      and loop thru preserving the sign */
9849
9850   right = IC_RIGHT (ic);
9851   left = IC_LEFT (ic);
9852   result = IC_RESULT (ic);
9853
9854   aopOp (right, ic, FALSE, FALSE);
9855
9856 #ifdef BETTER_LITERAL_SHIFT
9857   if (AOP_TYPE (right) == AOP_LIT)
9858     {
9859       if (genRightShiftLiteral (left, right, result, ic, 1))
9860       {
9861         return;
9862       }
9863     }
9864 #endif
9865   /* shift count is unknown then we have to form
9866      a loop get the loop count in B : Note: we take
9867      only the lower order byte since shifting
9868      more that 32 bits make no sense anyway, ( the
9869      largest size of an object can be only 32 bits ) */
9870
9871   pushedB = pushB ();
9872   if (AOP_TYPE (right) == AOP_LIT)
9873   {
9874       /* Really should be handled by genRightShiftLiteral,
9875        * but since I'm too lazy to fix that today, at least we can make
9876        * some small improvement.
9877        */
9878        emitcode("mov", "b,#!constbyte",
9879                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9880   }
9881   else
9882   {
9883         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9884         emitcode ("inc", "b");
9885   }
9886   freeAsmop (right, NULL, ic, TRUE);
9887   aopOp (left, ic, FALSE, FALSE);
9888   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9889
9890   /* now move the left to the result if they are not the
9891      same */
9892   if (!sameRegs (AOP (left), AOP (result)) &&
9893       AOP_SIZE (result) > 1)
9894     {
9895
9896       size = AOP_SIZE (result);
9897       offset = 0;
9898       _startLazyDPSEvaluation ();
9899       while (size--)
9900         {
9901           l = aopGet (left, offset, FALSE, TRUE, NULL);
9902           if (*l == '@' && IS_AOP_PREG (result))
9903             {
9904
9905               emitcode ("mov", "a,%s", l);
9906               aopPut (result, "a", offset);
9907             }
9908           else
9909             aopPut (result, l, offset);
9910           offset++;
9911         }
9912       _endLazyDPSEvaluation ();
9913     }
9914
9915   /* mov the highest order bit to OVR */
9916   tlbl = newiTempLabel (NULL);
9917   tlbl1 = newiTempLabel (NULL);
9918
9919   size = AOP_SIZE (result);
9920   offset = size - 1;
9921   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
9922   emitcode ("rlc", "a");
9923   emitcode ("mov", "ov,c");
9924   /* if it is only one byte then */
9925   if (size == 1)
9926     {
9927       l = aopGet (left, 0, FALSE, FALSE, NULL);
9928       MOVA (l);
9929       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9930       emitcode ("", "!tlabeldef", tlbl->key + 100);
9931       emitcode ("mov", "c,ov");
9932       emitcode ("rrc", "a");
9933       emitcode ("", "!tlabeldef", tlbl1->key + 100);
9934       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9935       popB (pushedB);
9936       aopPut (result, "a", 0);
9937       goto release;
9938     }
9939
9940   reAdjustPreg (AOP (result));
9941   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9942   emitcode ("", "!tlabeldef", tlbl->key + 100);
9943   emitcode ("mov", "c,ov");
9944   _startLazyDPSEvaluation ();
9945   while (size--)
9946     {
9947       l = aopGet (result, offset, FALSE, FALSE, NULL);
9948       MOVA (l);
9949       emitcode ("rrc", "a");
9950       aopPut (result, "a", offset--);
9951     }
9952   _endLazyDPSEvaluation ();
9953   reAdjustPreg (AOP (result));
9954   emitcode ("", "!tlabeldef", tlbl1->key + 100);
9955   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9956   popB (pushedB);
9957
9958 release:
9959   freeAsmop (result, NULL, ic, TRUE);
9960   freeAsmop (left, NULL, ic, TRUE);
9961 }
9962
9963 /*-----------------------------------------------------------------*/
9964 /* genRightShift - generate code for right shifting                */
9965 /*-----------------------------------------------------------------*/
9966 static void
9967 genRightShift (iCode * ic)
9968 {
9969   operand *right, *left, *result;
9970   sym_link *letype;
9971   int size, offset;
9972   char *l;
9973   symbol *tlbl, *tlbl1;
9974   bool pushedB;
9975
9976   D (emitcode (";", "genRightShift"));
9977
9978   /* if signed then we do it the hard way preserve the
9979      sign bit moving it inwards */
9980   letype = getSpec (operandType (IC_LEFT (ic)));
9981
9982   if (!SPEC_USIGN (letype))
9983     {
9984       genSignedRightShift (ic);
9985       return;
9986     }
9987
9988   /* signed & unsigned types are treated the same : i.e. the
9989      signed is NOT propagated inwards : quoting from the
9990      ANSI - standard : "for E1 >> E2, is equivalent to division
9991      by 2**E2 if unsigned or if it has a non-negative value,
9992      otherwise the result is implementation defined ", MY definition
9993      is that the sign does not get propagated */
9994
9995   right = IC_RIGHT (ic);
9996   left = IC_LEFT (ic);
9997   result = IC_RESULT (ic);
9998
9999   aopOp (right, ic, FALSE, FALSE);
10000
10001 #ifdef BETTER_LITERAL_SHIFT
10002   /* if the shift count is known then do it
10003      as efficiently as possible */
10004   if (AOP_TYPE (right) == AOP_LIT)
10005     {
10006       if (genRightShiftLiteral (left, right, result, ic, 0))
10007       {
10008         return;
10009       }
10010     }
10011 #endif
10012
10013   /* shift count is unknown then we have to form
10014      a loop get the loop count in B : Note: we take
10015      only the lower order byte since shifting
10016      more that 32 bits make no sense anyway, ( the
10017      largest size of an object can be only 32 bits ) */
10018
10019   pushedB = pushB ();
10020   if (AOP_TYPE (right) == AOP_LIT)
10021   {
10022       /* Really should be handled by genRightShiftLiteral,
10023        * but since I'm too lazy to fix that today, at least we can make
10024        * some small improvement.
10025        */
10026        emitcode("mov", "b,#!constbyte",
10027                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10028   }
10029   else
10030   {
10031       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10032       emitcode ("inc", "b");
10033   }
10034   freeAsmop (right, NULL, ic, TRUE);
10035   aopOp (left, ic, FALSE, FALSE);
10036   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10037
10038   /* now move the left to the result if they are not the
10039      same */
10040   if (!sameRegs (AOP (left), AOP (result)) &&
10041       AOP_SIZE (result) > 1)
10042     {
10043       size = AOP_SIZE (result);
10044       offset = 0;
10045       _startLazyDPSEvaluation ();
10046       while (size--)
10047         {
10048           l = aopGet (left, offset, FALSE, TRUE, NULL);
10049           if (*l == '@' && IS_AOP_PREG (result))
10050             {
10051
10052               emitcode ("mov", "a,%s", l);
10053               aopPut (result, "a", offset);
10054             }
10055           else
10056             aopPut (result, l, offset);
10057           offset++;
10058         }
10059       _endLazyDPSEvaluation ();
10060     }
10061
10062   tlbl = newiTempLabel (NULL);
10063   tlbl1 = newiTempLabel (NULL);
10064   size = AOP_SIZE (result);
10065   offset = size - 1;
10066
10067   /* if it is only one byte then */
10068   if (size == 1)
10069     {
10070       l = aopGet (left, 0, FALSE, FALSE, NULL);
10071       MOVA (l);
10072       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10073       emitcode ("", "!tlabeldef", tlbl->key + 100);
10074       CLRC;
10075       emitcode ("rrc", "a");
10076       emitcode ("", "!tlabeldef", tlbl1->key + 100);
10077       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10078       popB (pushedB);
10079       aopPut (result, "a", 0);
10080       goto release;
10081     }
10082
10083   reAdjustPreg (AOP (result));
10084   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10085   emitcode ("", "!tlabeldef", tlbl->key + 100);
10086   CLRC;
10087   _startLazyDPSEvaluation ();
10088   while (size--)
10089     {
10090       l = aopGet (result, offset, FALSE, FALSE, NULL);
10091       MOVA (l);
10092       emitcode ("rrc", "a");
10093       aopPut (result, "a", offset--);
10094     }
10095   _endLazyDPSEvaluation ();
10096   reAdjustPreg (AOP (result));
10097
10098   emitcode ("", "!tlabeldef", tlbl1->key + 100);
10099   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10100   popB (pushedB);
10101
10102 release:
10103   freeAsmop (result, NULL, ic, TRUE);
10104   freeAsmop (left, NULL, ic, TRUE);
10105 }
10106
10107 /*-----------------------------------------------------------------*/
10108 /* emitPtrByteGet - emits code to get a byte into A through a      */
10109 /*                  pointer register (R0, R1, or DPTR). The        */
10110 /*                  original value of A can be preserved in B.     */
10111 /*-----------------------------------------------------------------*/
10112 static void
10113 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10114 {
10115   switch (p_type)
10116     {
10117     case IPOINTER:
10118     case POINTER:
10119       if (preserveAinB)
10120         emitcode ("mov", "b,a");
10121       emitcode ("mov", "a,@%s", rname);
10122       break;
10123
10124     case PPOINTER:
10125       if (preserveAinB)
10126         emitcode ("mov", "b,a");
10127       emitcode ("movx", "a,@%s", rname);
10128       break;
10129
10130     case FPOINTER:
10131       if (preserveAinB)
10132         emitcode ("mov", "b,a");
10133       emitcode ("movx", "a,@dptr");
10134       break;
10135
10136     case CPOINTER:
10137       if (preserveAinB)
10138         emitcode ("mov", "b,a");
10139       emitcode ("clr", "a");
10140       emitcode ("movc", "a,@a+dptr");
10141       break;
10142
10143     case GPOINTER:
10144       if (preserveAinB)
10145         {
10146           emitcode ("push", "b");
10147           emitcode ("push", "acc");
10148         }
10149       emitcode ("lcall", "__gptrget");
10150       if (preserveAinB)
10151         emitcode ("pop", "b");
10152       break;
10153     }
10154 }
10155
10156 /*-----------------------------------------------------------------*/
10157 /* emitPtrByteSet - emits code to set a byte from src through a    */
10158 /*                  pointer register (R0, R1, or DPTR).            */
10159 /*-----------------------------------------------------------------*/
10160 static void
10161 emitPtrByteSet (char *rname, int p_type, char *src)
10162 {
10163   switch (p_type)
10164     {
10165     case IPOINTER:
10166     case POINTER:
10167       if (*src=='@')
10168         {
10169           MOVA (src);
10170           emitcode ("mov", "@%s,a", rname);
10171         }
10172       else
10173         emitcode ("mov", "@%s,%s", rname, src);
10174       break;
10175
10176     case PPOINTER:
10177       MOVA (src);
10178       emitcode ("movx", "@%s,a", rname);
10179       break;
10180
10181     case FPOINTER:
10182       MOVA (src);
10183       emitcode ("movx", "@dptr,a");
10184       break;
10185
10186     case GPOINTER:
10187       MOVA (src);
10188       emitcode ("lcall", "__gptrput");
10189       break;
10190     }
10191 }
10192
10193 /*-----------------------------------------------------------------*/
10194 /* genUnpackBits - generates code for unpacking bits               */
10195 /*-----------------------------------------------------------------*/
10196 static void
10197 genUnpackBits (operand * result, char *rname, int ptype)
10198 {
10199   int offset = 0;       /* result byte offset */
10200   int rsize;            /* result size */
10201   int rlen = 0;         /* remaining bitfield length */
10202   sym_link *etype;      /* bitfield type information */
10203   int blen;             /* bitfield length */
10204   int bstr;             /* bitfield starting bit within byte */
10205
10206   D(emitcode (";     genUnpackBits",""));
10207
10208   etype = getSpec (operandType (result));
10209   rsize = getSize (operandType (result));
10210   blen = SPEC_BLEN (etype);
10211   bstr = SPEC_BSTR (etype);
10212
10213   /* If the bitfield length is less than a byte */
10214   if (blen < 8)
10215     {
10216       emitPtrByteGet (rname, ptype, FALSE);
10217       AccRol (8 - bstr);
10218       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10219       if (!SPEC_USIGN (etype))
10220         {
10221           /* signed bitfield */
10222           symbol *tlbl = newiTempLabel (NULL);
10223
10224           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10225           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10226           emitcode ("", "%05d$:", tlbl->key + 100);
10227         }
10228       aopPut (result, "a", offset++);
10229       goto finish;
10230     }
10231
10232   /* Bit field did not fit in a byte. Copy all
10233      but the partial byte at the end.  */
10234   for (rlen=blen;rlen>=8;rlen-=8)
10235     {
10236       emitPtrByteGet (rname, ptype, FALSE);
10237       aopPut (result, "a", offset++);
10238       if (rlen>8)
10239         emitcode ("inc", "%s", rname);
10240     }
10241
10242   /* Handle the partial byte at the end */
10243   if (rlen)
10244     {
10245       emitPtrByteGet (rname, ptype, FALSE);
10246       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10247       if (!SPEC_USIGN (etype))
10248         {
10249           /* signed bitfield */
10250           symbol *tlbl = newiTempLabel (NULL);
10251
10252           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10253           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10254           emitcode ("", "%05d$:", tlbl->key + 100);
10255         }
10256       aopPut (result, "a", offset++);
10257     }
10258
10259 finish:
10260   if (offset < rsize)
10261     {
10262       char *source;
10263
10264       if (SPEC_USIGN (etype))
10265         source = zero;
10266       else
10267         {
10268           /* signed bitfield: sign extension with 0x00 or 0xff */
10269           emitcode ("rlc", "a");
10270           emitcode ("subb", "a,acc");
10271
10272           source = "a";
10273         }
10274       rsize -= offset;
10275       while (rsize--)
10276         aopPut (result, source, offset++);
10277     }
10278 }
10279
10280
10281 /*-----------------------------------------------------------------*/
10282 /* genDataPointerGet - generates code when ptr offset is known     */
10283 /*-----------------------------------------------------------------*/
10284 static void
10285 genDataPointerGet (operand * left,
10286                    operand * result,
10287                    iCode * ic)
10288 {
10289   char *l;
10290   char buffer[256];
10291   int size, offset = 0;
10292   aopOp (result, ic, TRUE, FALSE);
10293
10294   /* get the string representation of the name */
10295   l = aopGet (left, 0, FALSE, TRUE, NULL);
10296   size = AOP_SIZE (result);
10297   _startLazyDPSEvaluation ();
10298   while (size--)
10299     {
10300         if (offset)
10301         {
10302             SNPRINTF (buffer, sizeof(buffer),
10303                       "(%s + %d)", l + 1, offset);
10304         }
10305         else
10306         {
10307             SNPRINTF (buffer, sizeof(buffer),
10308                       "%s", l + 1);
10309         }
10310       aopPut (result, buffer, offset++);
10311     }
10312   _endLazyDPSEvaluation ();
10313
10314   freeAsmop (result, NULL, ic, TRUE);
10315   freeAsmop (left, NULL, ic, TRUE);
10316 }
10317
10318 /*-----------------------------------------------------------------*/
10319 /* genNearPointerGet - emitcode for near pointer fetch             */
10320 /*-----------------------------------------------------------------*/
10321 static void
10322 genNearPointerGet (operand * left,
10323                    operand * result,
10324                    iCode * ic,
10325                    iCode *pi)
10326 {
10327   asmop *aop = NULL;
10328   regs *preg;
10329   char *rname;
10330   sym_link *rtype, *retype, *letype;
10331   sym_link *ltype = operandType (left);
10332   char buffer[80];
10333
10334   rtype = operandType (result);
10335   retype = getSpec (rtype);
10336   letype = getSpec (ltype);
10337
10338   aopOp (left, ic, FALSE, FALSE);
10339
10340   /* if left is rematerialisable and
10341      result is not bitfield variable type and
10342      the left is pointer to data space i.e
10343      lower 128 bytes of space */
10344   if (AOP_TYPE (left) == AOP_IMMD &&
10345       !IS_BITFIELD (retype) &&
10346       !IS_BITFIELD (letype) &&
10347       DCL_TYPE (ltype) == POINTER)
10348     {
10349       genDataPointerGet (left, result, ic);
10350       return;
10351     }
10352
10353   /* if the value is already in a pointer register
10354      then don't need anything more */
10355   if (!AOP_INPREG (AOP (left)))
10356     {
10357       /* otherwise get a free pointer register */
10358       aop = newAsmop (0);
10359       preg = getFreePtr (ic, &aop, FALSE);
10360       emitcode ("mov", "%s,%s",
10361                 preg->name,
10362                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10363       rname = preg->name;
10364     }
10365   else
10366     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10367
10368   freeAsmop (left, NULL, ic, TRUE);
10369   aopOp (result, ic, FALSE, FALSE);
10370
10371   /* if bitfield then unpack the bits */
10372   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10373     genUnpackBits (result, rname, POINTER);
10374   else
10375     {
10376       /* we have can just get the values */
10377       int size = AOP_SIZE (result);
10378       int offset = 0;
10379
10380       while (size--)
10381         {
10382           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10383             {
10384
10385               emitcode ("mov", "a,@%s", rname);
10386               aopPut (result, "a", offset);
10387             }
10388           else
10389             {
10390               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10391               aopPut (result, buffer, offset);
10392             }
10393           offset++;
10394           if (size || pi)
10395                 emitcode ("inc", "%s", rname);
10396             }
10397         }
10398
10399   /* now some housekeeping stuff */
10400   if (aop)      /* we had to allocate for this iCode */
10401     {
10402       if (pi) { /* post increment present */
10403         aopPut (left, rname, 0);
10404       }
10405       freeAsmop (NULL, aop, ic, TRUE);
10406     }
10407   else
10408     {
10409       /* we did not allocate which means left
10410          already in a pointer register, then
10411          if size > 0 && this could be used again
10412          we have to point it back to where it
10413          belongs */
10414       if (AOP_SIZE (result) > 1 &&
10415           !OP_SYMBOL (left)->remat &&
10416           (OP_SYMBOL (left)->liveTo > ic->seq ||
10417            ic->depth) &&
10418           !pi)
10419         {
10420           int size = AOP_SIZE (result) - 1;
10421           while (size--)
10422             emitcode ("dec", "%s", rname);
10423         }
10424     }
10425
10426   /* done */
10427   freeAsmop (result, NULL, ic, TRUE);
10428   if (pi) pi->generated = 1;
10429 }
10430
10431 /*-----------------------------------------------------------------*/
10432 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10433 /*-----------------------------------------------------------------*/
10434 static void
10435 genPagedPointerGet (operand * left,
10436                     operand * result,
10437                     iCode * ic,
10438                     iCode * pi)
10439 {
10440   asmop *aop = NULL;
10441   regs *preg;
10442   char *rname;
10443   sym_link *rtype, *retype, *letype;
10444
10445   rtype = operandType (result);
10446   retype = getSpec (rtype);
10447   letype = getSpec (operandType (left));
10448   aopOp (left, ic, FALSE, FALSE);
10449
10450   /* if the value is already in a pointer register
10451      then don't need anything more */
10452   if (!AOP_INPREG (AOP (left)))
10453     {
10454       /* otherwise get a free pointer register */
10455       aop = newAsmop (0);
10456       preg = getFreePtr (ic, &aop, FALSE);
10457       emitcode ("mov", "%s,%s",
10458                 preg->name,
10459                 aopGet (left, 0, FALSE, TRUE, NULL));
10460       rname = preg->name;
10461     }
10462   else
10463     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10464
10465   freeAsmop (left, NULL, ic, TRUE);
10466   aopOp (result, ic, FALSE, FALSE);
10467
10468   /* if bitfield then unpack the bits */
10469   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10470     genUnpackBits (result, rname, PPOINTER);
10471   else
10472     {
10473       /* we have can just get the values */
10474       int size = AOP_SIZE (result);
10475       int offset = 0;
10476
10477       while (size--)
10478         {
10479
10480           emitcode ("movx", "a,@%s", rname);
10481           aopPut (result, "a", offset);
10482
10483           offset++;
10484
10485           if (size || pi)
10486             emitcode ("inc", "%s", rname);
10487         }
10488     }
10489
10490   /* now some housekeeping stuff */
10491   if (aop)      /* we had to allocate for this iCode */
10492     {
10493       if (pi) aopPut (left, rname, 0);
10494       freeAsmop (NULL, aop, ic, TRUE);
10495     }
10496   else
10497     {
10498       /* we did not allocate which means left
10499          already in a pointer register, then
10500          if size > 0 && this could be used again
10501          we have to point it back to where it
10502          belongs */
10503       if (AOP_SIZE (result) > 1 &&
10504           !OP_SYMBOL (left)->remat &&
10505           (OP_SYMBOL (left)->liveTo > ic->seq ||
10506            ic->depth) &&
10507           !pi)
10508         {
10509           int size = AOP_SIZE (result) - 1;
10510           while (size--)
10511             emitcode ("dec", "%s", rname);
10512         }
10513     }
10514
10515   /* done */
10516   freeAsmop (result, NULL, ic, TRUE);
10517   if (pi) pi->generated = 1;
10518 }
10519
10520 /*-----------------------------------------------------------------*/
10521 /* genFarPointerGet - get value from far space                     */
10522 /*-----------------------------------------------------------------*/
10523 static void
10524 genFarPointerGet (operand * left,
10525                   operand * result, iCode * ic, iCode *pi)
10526 {
10527     int size, offset, dopi=1;
10528   sym_link *retype = getSpec (operandType (result));
10529   sym_link *letype = getSpec (operandType (left));
10530   D (emitcode (";", "genFarPointerGet"););
10531
10532   aopOp (left, ic, FALSE, FALSE);
10533
10534   /* if the operand is already in dptr
10535      then we do nothing else we move the value to dptr */
10536   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10537     {
10538       /* if this is rematerializable */
10539       if (AOP_TYPE (left) == AOP_IMMD)
10540         {
10541           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10542         }
10543       else
10544         {
10545           /* we need to get it byte by byte */
10546           _startLazyDPSEvaluation ();
10547           if (AOP_TYPE (left) != AOP_DPTR)
10548             {
10549               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10550               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10551               if (options.model == MODEL_FLAT24)
10552                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10553             }
10554           else
10555             {
10556               /* We need to generate a load to DPTR indirect through DPTR. */
10557               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10558               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10559               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10560               if (options.model == MODEL_FLAT24)
10561                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10562               emitcode ("pop", "dph");
10563               emitcode ("pop", "dpl");
10564               dopi =0;
10565             }
10566           _endLazyDPSEvaluation ();
10567         }
10568     }
10569   /* so dptr know contains the address */
10570   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10571
10572   /* if bit then unpack */
10573   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10574       if (AOP_INDPTRn(left)) {
10575           genSetDPTR(AOP(left)->aopu.dptr);
10576       }
10577       genUnpackBits (result, "dptr", FPOINTER);
10578       if (AOP_INDPTRn(left)) {
10579           genSetDPTR(0);
10580       }
10581   } else
10582     {
10583       size = AOP_SIZE (result);
10584       offset = 0;
10585
10586       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10587           while (size--) {
10588               genSetDPTR(AOP(left)->aopu.dptr);
10589               emitcode ("movx", "a,@dptr");
10590               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10591                   emitcode ("inc", "dptr");
10592               genSetDPTR (0);
10593               aopPut (result, "a", offset++);
10594           }
10595       } else {
10596           _startLazyDPSEvaluation ();
10597           while (size--) {
10598               if (AOP_INDPTRn(left)) {
10599                   genSetDPTR(AOP(left)->aopu.dptr);
10600               } else {
10601                   genSetDPTR (0);
10602               }
10603               _flushLazyDPS ();
10604
10605               emitcode ("movx", "a,@dptr");
10606               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10607                   emitcode ("inc", "dptr");
10608
10609               aopPut (result, "a", offset++);
10610           }
10611           _endLazyDPSEvaluation ();
10612       }
10613     }
10614   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10615       if (!AOP_INDPTRn(left)) {
10616           _startLazyDPSEvaluation ();
10617           aopPut (left, "dpl", 0);
10618           aopPut (left, "dph", 1);
10619           if (options.model == MODEL_FLAT24)
10620               aopPut (left, "dpx", 2);
10621           _endLazyDPSEvaluation ();
10622       }
10623     pi->generated = 1;
10624   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10625              AOP_SIZE(result) > 1 &&
10626              IS_SYMOP(left) &&
10627              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10628
10629       size = AOP_SIZE (result) - 1;
10630       if (AOP_INDPTRn(left)) {
10631           genSetDPTR(AOP(left)->aopu.dptr);
10632       }
10633       while (size--) emitcode ("lcall","__decdptr");
10634       if (AOP_INDPTRn(left)) {
10635           genSetDPTR(0);
10636       }
10637   }
10638
10639   freeAsmop (left, NULL, ic, TRUE);
10640   freeAsmop (result, NULL, ic, TRUE);
10641 }
10642
10643 /*-----------------------------------------------------------------*/
10644 /* genCodePointerGet - get value from code space                  */
10645 /*-----------------------------------------------------------------*/
10646 static void
10647 genCodePointerGet (operand * left,
10648                     operand * result, iCode * ic, iCode *pi)
10649 {
10650   int size, offset, dopi=1;
10651   sym_link *retype = getSpec (operandType (result));
10652
10653   aopOp (left, ic, FALSE, FALSE);
10654
10655   /* if the operand is already in dptr
10656      then we do nothing else we move the value to dptr */
10657   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10658     {
10659       /* if this is rematerializable */
10660       if (AOP_TYPE (left) == AOP_IMMD)
10661         {
10662           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10663         }
10664       else
10665         {                       /* we need to get it byte by byte */
10666           _startLazyDPSEvaluation ();
10667           if (AOP_TYPE (left) != AOP_DPTR)
10668             {
10669               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10670               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10671               if (options.model == MODEL_FLAT24)
10672                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10673             }
10674           else
10675             {
10676               /* We need to generate a load to DPTR indirect through DPTR. */
10677               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10678               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10679               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10680               if (options.model == MODEL_FLAT24)
10681                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10682               emitcode ("pop", "dph");
10683               emitcode ("pop", "dpl");
10684               dopi=0;
10685             }
10686           _endLazyDPSEvaluation ();
10687         }
10688     }
10689   /* so dptr know contains the address */
10690   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10691
10692   /* if bit then unpack */
10693   if (IS_BITFIELD (retype)) {
10694       if (AOP_INDPTRn(left)) {
10695           genSetDPTR(AOP(left)->aopu.dptr);
10696       }
10697       genUnpackBits (result, "dptr", CPOINTER);
10698       if (AOP_INDPTRn(left)) {
10699           genSetDPTR(0);
10700       }
10701   } else
10702     {
10703       size = AOP_SIZE (result);
10704       offset = 0;
10705       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10706           while (size--) {
10707               genSetDPTR(AOP(left)->aopu.dptr);
10708               emitcode ("clr", "a");
10709               emitcode ("movc", "a,@a+dptr");
10710               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10711                   emitcode ("inc", "dptr");
10712               genSetDPTR (0);
10713               aopPut (result, "a", offset++);
10714           }
10715       } else {
10716           _startLazyDPSEvaluation ();
10717           while (size--)
10718               {
10719                   if (AOP_INDPTRn(left)) {
10720                       genSetDPTR(AOP(left)->aopu.dptr);
10721                   } else {
10722                       genSetDPTR (0);
10723                   }
10724                   _flushLazyDPS ();
10725
10726                   emitcode ("clr", "a");
10727                   emitcode ("movc", "a,@a+dptr");
10728                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10729                       emitcode ("inc", "dptr");
10730                   aopPut (result, "a", offset++);
10731               }
10732           _endLazyDPSEvaluation ();
10733       }
10734     }
10735   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10736       if (!AOP_INDPTRn(left)) {
10737           _startLazyDPSEvaluation ();
10738
10739           aopPut (left, "dpl", 0);
10740           aopPut (left, "dph", 1);
10741           if (options.model == MODEL_FLAT24)
10742               aopPut (left, "dpx", 2);
10743
10744           _endLazyDPSEvaluation ();
10745       }
10746       pi->generated = 1;
10747   } else if ((OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10748              AOP_SIZE(result) > 1 &&
10749              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10750
10751       size = AOP_SIZE (result) - 1;
10752       if (AOP_INDPTRn(left)) {
10753           genSetDPTR(AOP(left)->aopu.dptr);
10754       }
10755       while (size--) emitcode ("lcall","__decdptr");
10756       if (AOP_INDPTRn(left)) {
10757           genSetDPTR(0);
10758       }
10759   }
10760
10761   freeAsmop (result, NULL, ic, TRUE);
10762   freeAsmop (left, NULL, ic, TRUE);
10763 }
10764
10765 /*-----------------------------------------------------------------*/
10766 /* genGenPointerGet - gget value from generic pointer space        */
10767 /*-----------------------------------------------------------------*/
10768 static void
10769 genGenPointerGet (operand * left,
10770                   operand * result, iCode * ic, iCode * pi)
10771 {
10772   int size, offset;
10773   bool pushedB;
10774   sym_link *retype = getSpec (operandType (result));
10775   sym_link *letype = getSpec (operandType (left));
10776
10777   D (emitcode (";", "genGenPointerGet"));
10778
10779   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10780
10781   pushedB = pushB ();
10782   /* if the operand is already in dptr
10783      then we do nothing else we move the value to dptr */
10784   if (AOP_TYPE (left) != AOP_STR)
10785     {
10786       /* if this is rematerializable */
10787       if (AOP_TYPE (left) == AOP_IMMD)
10788         {
10789           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10790           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10791             {
10792               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10793             }
10794           else
10795             {
10796               emitcode ("mov", "b,#%d", pointerCode (retype));
10797             }
10798         }
10799       else
10800         {                       /* we need to get it byte by byte */
10801           _startLazyDPSEvaluation ();
10802           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10803           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10804           if (options.model == MODEL_FLAT24) {
10805               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10806               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10807           } else {
10808               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10809           }
10810           _endLazyDPSEvaluation ();
10811         }
10812     }
10813
10814   /* so dptr-b now contains the address */
10815   aopOp (result, ic, FALSE, TRUE);
10816
10817   /* if bit then unpack */
10818   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10819   {
10820     genUnpackBits (result, "dptr", GPOINTER);
10821   }
10822   else
10823     {
10824         size = AOP_SIZE (result);
10825         offset = 0;
10826
10827         while (size--)
10828         {
10829             if (size)
10830             {
10831                 // Get two bytes at a time, results in _AP & A.
10832                 // dptr will be incremented ONCE by __gptrgetWord.
10833                 //
10834                 // Note: any change here must be coordinated
10835                 // with the implementation of __gptrgetWord
10836                 // in device/lib/_gptrget.c
10837                 emitcode ("lcall", "__gptrgetWord");
10838                 aopPut (result, DP2_RESULT_REG, offset++);
10839                 aopPut (result, "a", offset++);
10840                 size--;
10841             }
10842             else
10843             {
10844                 // Only one byte to get.
10845                 emitcode ("lcall", "__gptrget");
10846                 aopPut (result, "a", offset++);
10847             }
10848
10849             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
10850             {
10851                 emitcode ("inc", "dptr");
10852             }
10853         }
10854     }
10855
10856   if (pi && AOP_TYPE (left) != AOP_IMMD) {
10857     _startLazyDPSEvaluation ();
10858
10859     aopPut (left, "dpl", 0);
10860     aopPut (left, "dph", 1);
10861     if (options.model == MODEL_FLAT24) {
10862         aopPut (left, "dpx", 2);
10863         aopPut (left, "b", 3);
10864     } else  aopPut (left, "b", 2);
10865
10866     _endLazyDPSEvaluation ();
10867
10868     pi->generated = 1;
10869   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
10870              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10871
10872       size = AOP_SIZE (result) - 1;
10873       while (size--) emitcode ("lcall","__decdptr");
10874   }
10875   popB (pushedB);
10876
10877   freeAsmop (result, NULL, ic, TRUE);
10878   freeAsmop (left, NULL, ic, TRUE);
10879 }
10880
10881 /*-----------------------------------------------------------------*/
10882 /* genPointerGet - generate code for pointer get                   */
10883 /*-----------------------------------------------------------------*/
10884 static void
10885 genPointerGet (iCode * ic, iCode *pi)
10886 {
10887   operand *left, *result;
10888   sym_link *type, *etype;
10889   int p_type;
10890
10891   D (emitcode (";", "genPointerGet "));
10892
10893   left = IC_LEFT (ic);
10894   result = IC_RESULT (ic);
10895
10896   /* depending on the type of pointer we need to
10897      move it to the correct pointer register */
10898   type = operandType (left);
10899   etype = getSpec (type);
10900   /* if left is of type of pointer then it is simple */
10901   if (IS_PTR (type) && !IS_FUNC (type->next))
10902     p_type = DCL_TYPE (type);
10903   else
10904     {
10905       /* we have to go by the storage class */
10906       p_type = PTR_TYPE (SPEC_OCLS (etype));
10907     }
10908
10909   /* special case when cast remat */
10910   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10911       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10912     {
10913       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10914       type = operandType (left);
10915       p_type = DCL_TYPE (type);
10916     }
10917   /* now that we have the pointer type we assign
10918      the pointer values */
10919   switch (p_type)
10920     {
10921
10922     case POINTER:
10923     case IPOINTER:
10924       genNearPointerGet (left, result, ic, pi);
10925       break;
10926
10927     case PPOINTER:
10928       genPagedPointerGet (left, result, ic, pi);
10929       break;
10930
10931     case FPOINTER:
10932       genFarPointerGet (left, result, ic, pi);
10933       break;
10934
10935     case CPOINTER:
10936       genCodePointerGet (left, result, ic, pi);
10937       break;
10938
10939     case GPOINTER:
10940       genGenPointerGet (left, result, ic, pi);
10941       break;
10942     }
10943 }
10944
10945 /*-----------------------------------------------------------------*/
10946 /* genPackBits - generates code for packed bit storage             */
10947 /*-----------------------------------------------------------------*/
10948 static void
10949 genPackBits (sym_link * etype,
10950              operand * right,
10951              char *rname, int p_type)
10952 {
10953   int offset = 0;       /* source byte offset */
10954   int rlen = 0;         /* remaining bitfield length */
10955   int blen;             /* bitfield length */
10956   int bstr;             /* bitfield starting bit within byte */
10957   int litval;           /* source literal value (if AOP_LIT) */
10958   unsigned char mask;   /* bitmask within current byte */
10959
10960   D(emitcode (";     genPackBits",""));
10961
10962   blen = SPEC_BLEN (etype);
10963   bstr = SPEC_BSTR (etype);
10964
10965   /* If the bitfield length is less than a byte */
10966   if (blen < 8)
10967     {
10968       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10969               (unsigned char) (0xFF >> (8 - bstr)));
10970
10971       if (AOP_TYPE (right) == AOP_LIT)
10972         {
10973           /* Case with a bitfield length <8 and literal source
10974           */
10975           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10976           litval <<= bstr;
10977           litval &= (~mask) & 0xff;
10978           emitPtrByteGet (rname, p_type, FALSE);
10979           if ((mask|litval)!=0xff)
10980             emitcode ("anl","a,#!constbyte", mask);
10981           if (litval)
10982             emitcode ("orl","a,#!constbyte", litval);
10983         }
10984       else
10985         {
10986           if ((blen==1) && (p_type!=GPOINTER))
10987             {
10988               /* Case with a bitfield length == 1 and no generic pointer
10989               */
10990               if (AOP_TYPE (right) == AOP_CRY)
10991                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10992               else
10993                 {
10994                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
10995                   emitcode ("rrc","a");
10996                 }
10997               emitPtrByteGet (rname, p_type, FALSE);
10998               emitcode ("mov","acc.%d,c",bstr);
10999             }
11000           else
11001             {
11002               bool pushedB;
11003               /* Case with a bitfield length < 8 and arbitrary source
11004               */
11005               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11006               /* shift and mask source value */
11007               AccLsh (bstr);
11008               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11009
11010               pushedB = pushB ();
11011               /* transfer A to B and get next byte */
11012               emitPtrByteGet (rname, p_type, TRUE);
11013
11014               emitcode ("anl", "a,#!constbyte", mask);
11015               emitcode ("orl", "a,b");
11016               if (p_type == GPOINTER)
11017                 emitcode ("pop", "b");
11018
11019               popB (pushedB);
11020            }
11021         }
11022
11023       emitPtrByteSet (rname, p_type, "a");
11024       return;
11025     }
11026
11027   /* Bit length is greater than 7 bits. In this case, copy  */
11028   /* all except the partial byte at the end                 */
11029   for (rlen=blen;rlen>=8;rlen-=8)
11030     {
11031       emitPtrByteSet (rname, p_type,
11032                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11033       if (rlen>8)
11034         emitcode ("inc", "%s", rname);
11035     }
11036
11037   /* If there was a partial byte at the end */
11038   if (rlen)
11039     {
11040       mask = (((unsigned char) -1 << rlen) & 0xff);
11041
11042       if (AOP_TYPE (right) == AOP_LIT)
11043         {
11044           /* Case with partial byte and literal source
11045           */
11046           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11047           litval >>= (blen-rlen);
11048           litval &= (~mask) & 0xff;
11049           emitPtrByteGet (rname, p_type, FALSE);
11050           if ((mask|litval)!=0xff)
11051             emitcode ("anl","a,#!constbyte", mask);
11052           if (litval)
11053             emitcode ("orl","a,#!constbyte", litval);
11054         }
11055       else
11056         {
11057           bool pushedB;
11058           /* Case with partial byte and arbitrary source
11059           */
11060           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11061           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11062
11063           pushedB = pushB ();
11064           /* transfer A to B and get next byte */
11065           emitPtrByteGet (rname, p_type, TRUE);
11066
11067           emitcode ("anl", "a,#!constbyte", mask);
11068           emitcode ("orl", "a,b");
11069           if (p_type == GPOINTER)
11070             emitcode ("pop", "b");
11071
11072           popB (pushedB);
11073         }
11074       emitPtrByteSet (rname, p_type, "a");
11075     }
11076 }
11077
11078
11079 /*-----------------------------------------------------------------*/
11080 /* genDataPointerSet - remat pointer to data space                 */
11081 /*-----------------------------------------------------------------*/
11082 static void
11083 genDataPointerSet (operand * right,
11084                    operand * result,
11085                    iCode * ic)
11086 {
11087   int size, offset = 0;
11088   char *l, buffer[256];
11089
11090   D (emitcode (";", "genDataPointerSet"));
11091
11092   aopOp (right, ic, FALSE, FALSE);
11093
11094   l = aopGet (result, 0, FALSE, TRUE, NULL);
11095   size = AOP_SIZE (right);
11096   while (size--)
11097     {
11098       if (offset)
11099           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11100       else
11101           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11102       emitcode ("mov", "%s,%s", buffer,
11103                 aopGet (right, offset++, FALSE, FALSE, NULL));
11104     }
11105
11106   freeAsmop (result, NULL, ic, TRUE);
11107   freeAsmop (right, NULL, ic, TRUE);
11108 }
11109
11110 /*-----------------------------------------------------------------*/
11111 /* genNearPointerSet - emitcode for near pointer put                */
11112 /*-----------------------------------------------------------------*/
11113 static void
11114 genNearPointerSet (operand * right,
11115                    operand * result,
11116                    iCode * ic,
11117                    iCode * pi)
11118 {
11119   asmop *aop = NULL;
11120   char *rname, *l;
11121   sym_link *retype, *letype;
11122   sym_link *ptype = operandType (result);
11123
11124   D(emitcode (";", "genNearPointerSet"));
11125
11126   retype = getSpec (operandType (right));
11127   letype = getSpec (ptype);
11128
11129   aopOp (result, ic, FALSE, FALSE);
11130
11131   /* if the result is rematerializable &
11132      in data space & not a bit variable */
11133   if (AOP_TYPE (result) == AOP_IMMD &&
11134       DCL_TYPE (ptype) == POINTER &&
11135       !IS_BITVAR (retype) &&
11136       !IS_BITVAR (letype))
11137     {
11138       genDataPointerSet (right, result, ic);
11139       return;
11140     }
11141
11142   /* if the value is already in a pointer register
11143      then don't need anything more */
11144   if (!AOP_INPREG (AOP (result)))
11145     {
11146       /* otherwise get a free pointer register */
11147       regs *preg;
11148
11149       aop = newAsmop (0);
11150       preg = getFreePtr (ic, &aop, FALSE);
11151       emitcode ("mov", "%s,%s",
11152                 preg->name,
11153                 aopGet (result, 0, FALSE, TRUE, NULL));
11154       rname = preg->name;
11155     }
11156   else
11157     {
11158       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11159     }
11160
11161   aopOp (right, ic, FALSE, FALSE);
11162
11163   /* if bitfield then unpack the bits */
11164   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11165     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11166   else
11167     {
11168       /* we have can just get the values */
11169       int size = AOP_SIZE (right);
11170       int offset = 0;
11171
11172       while (size--)
11173         {
11174           l = aopGet (right, offset, FALSE, TRUE, NULL);
11175           if (*l == '@')
11176             {
11177               MOVA (l);
11178               emitcode ("mov", "@%s,a", rname);
11179             }
11180           else
11181             emitcode ("mov", "@%s,%s", rname, l);
11182           if (size || pi)
11183             emitcode ("inc", "%s", rname);
11184           offset++;
11185         }
11186     }
11187
11188   /* now some housekeeping stuff */
11189   if (aop)      /* we had to allocate for this iCode */
11190     {
11191       if (pi) aopPut (result,rname,0);
11192       freeAsmop (NULL, aop, ic, TRUE);
11193     }
11194   else
11195     {
11196       /* we did not allocate which means left
11197          already in a pointer register, then
11198          if size > 0 && this could be used again
11199          we have to point it back to where it
11200          belongs */
11201       if (AOP_SIZE (right) > 1 &&
11202           !OP_SYMBOL (result)->remat &&
11203           (OP_SYMBOL (result)->liveTo > ic->seq ||
11204            ic->depth) &&
11205           !pi)
11206         {
11207           int size = AOP_SIZE (right) - 1;
11208           while (size--)
11209             emitcode ("dec", "%s", rname);
11210         }
11211     }
11212
11213   /* done */
11214   if (pi) pi->generated = 1;
11215   freeAsmop (result, NULL, ic, TRUE);
11216   freeAsmop (right, NULL, ic, TRUE);
11217 }
11218
11219 /*-----------------------------------------------------------------*/
11220 /* genPagedPointerSet - emitcode for Paged pointer put             */
11221 /*-----------------------------------------------------------------*/
11222 static void
11223 genPagedPointerSet (operand * right,
11224                     operand * result,
11225                     iCode * ic,
11226                     iCode *pi)
11227 {
11228   asmop *aop = NULL;
11229   char *rname, *l;
11230   sym_link *retype, *letype;
11231
11232   D (emitcode (";", "genPagedPointerSet"));
11233
11234   retype = getSpec (operandType (right));
11235   letype = getSpec (operandType (result));
11236
11237   aopOp (result, ic, FALSE, FALSE);
11238
11239   /* if the value is already in a pointer register
11240      then don't need anything more */
11241   if (!AOP_INPREG (AOP (result)))
11242     {
11243       /* otherwise get a free pointer register */
11244       regs *preg;
11245
11246       aop = newAsmop (0);
11247       preg = getFreePtr (ic, &aop, FALSE);
11248       emitcode ("mov", "%s,%s",
11249                 preg->name,
11250                 aopGet (result, 0, FALSE, TRUE, NULL));
11251       rname = preg->name;
11252     }
11253   else
11254     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11255
11256   aopOp (right, ic, FALSE, FALSE);
11257
11258   /* if bitfield then unpack the bits */
11259   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11260     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11261   else
11262     {
11263       /* we have can just get the values */
11264       int size = AOP_SIZE (right);
11265       int offset = 0;
11266
11267       while (size--)
11268         {
11269           l = aopGet (right, offset, FALSE, TRUE, NULL);
11270           MOVA (l);
11271           emitcode ("movx", "@%s,a", rname);
11272
11273           if (size || pi)
11274             emitcode ("inc", "%s", rname);
11275
11276           offset++;
11277         }
11278     }
11279
11280   /* now some housekeeping stuff */
11281   if (aop)
11282     {
11283       if (pi)
11284         aopPut (result, rname, 0);
11285       /* we had to allocate for this iCode */
11286       freeAsmop (NULL, aop, ic, TRUE);
11287     }
11288   else
11289     {
11290       /* we did not allocate which means left
11291          already in a pointer register, then
11292          if size > 0 && this could be used again
11293          we have to point it back to where it
11294          belongs */
11295       if (AOP_SIZE (right) > 1 &&
11296           !OP_SYMBOL (result)->remat &&
11297           (OP_SYMBOL (result)->liveTo > ic->seq ||
11298            ic->depth) &&
11299           !pi)
11300         {
11301           int size = AOP_SIZE (right) - 1;
11302           while (size--)
11303             emitcode ("dec", "%s", rname);
11304         }
11305     }
11306
11307   /* done */
11308   if (pi) pi->generated = 1;
11309   freeAsmop (result, NULL, ic, TRUE);
11310   freeAsmop (right, NULL, ic, TRUE);
11311 }
11312
11313 /*-----------------------------------------------------------------*/
11314 /* genFarPointerSet - set value from far space                     */
11315 /*-----------------------------------------------------------------*/
11316 static void
11317 genFarPointerSet (operand * right,
11318                   operand * result, iCode * ic, iCode *pi)
11319 {
11320   int size, offset, dopi=1;
11321   sym_link *retype = getSpec (operandType (right));
11322   sym_link *letype = getSpec (operandType (result));
11323
11324   aopOp (result, ic, FALSE, FALSE);
11325
11326   /* if the operand is already in dptr
11327      then we do nothing else we move the value to dptr */
11328   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11329     {
11330       /* if this is remateriazable */
11331       if (AOP_TYPE (result) == AOP_IMMD)
11332         emitcode ("mov", "dptr,%s",
11333                   aopGet (result, 0, TRUE, FALSE, NULL));
11334       else
11335         {
11336           /* we need to get it byte by byte */
11337           _startLazyDPSEvaluation ();
11338           if (AOP_TYPE (result) != AOP_DPTR)
11339             {
11340               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11341               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11342               if (options.model == MODEL_FLAT24)
11343                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11344             }
11345           else
11346             {
11347               /* We need to generate a load to DPTR indirect through DPTR. */
11348               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11349
11350               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11351               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11352               if (options.model == MODEL_FLAT24)
11353                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11354               emitcode ("pop", "dph");
11355               emitcode ("pop", "dpl");
11356               dopi=0;
11357             }
11358           _endLazyDPSEvaluation ();
11359         }
11360     }
11361   /* so dptr know contains the address */
11362   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11363
11364   /* if bit then unpack */
11365   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11366   {
11367       if (AOP_INDPTRn(result)) {
11368           genSetDPTR(AOP(result)->aopu.dptr);
11369       }
11370       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11371       if (AOP_INDPTRn(result)) {
11372           genSetDPTR(0);
11373       }
11374   } else {
11375       size = AOP_SIZE (right);
11376       offset = 0;
11377       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11378           while (size--) {
11379               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11380
11381               genSetDPTR(AOP(result)->aopu.dptr);
11382               emitcode ("movx", "@dptr,a");
11383               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11384                   emitcode ("inc", "dptr");
11385               genSetDPTR (0);
11386           }
11387       } else {
11388           _startLazyDPSEvaluation ();
11389           while (size--) {
11390               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11391
11392               if (AOP_INDPTRn(result)) {
11393                   genSetDPTR(AOP(result)->aopu.dptr);
11394               } else {
11395                   genSetDPTR (0);
11396               }
11397               _flushLazyDPS ();
11398
11399               emitcode ("movx", "@dptr,a");
11400               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11401                   emitcode ("inc", "dptr");
11402           }
11403           _endLazyDPSEvaluation ();
11404       }
11405   }
11406
11407   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11408       if (!AOP_INDPTRn(result)) {
11409           _startLazyDPSEvaluation ();
11410
11411           aopPut (result,"dpl",0);
11412           aopPut (result,"dph",1);
11413           if (options.model == MODEL_FLAT24)
11414               aopPut (result,"dpx",2);
11415
11416           _endLazyDPSEvaluation ();
11417       }
11418       pi->generated=1;
11419   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11420              AOP_SIZE(right) > 1 &&
11421              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11422
11423       size = AOP_SIZE (right) - 1;
11424       if (AOP_INDPTRn(result)) {
11425           genSetDPTR(AOP(result)->aopu.dptr);
11426       }
11427       while (size--) emitcode ("lcall","__decdptr");
11428       if (AOP_INDPTRn(result)) {
11429           genSetDPTR(0);
11430       }
11431   }
11432   freeAsmop (result, NULL, ic, TRUE);
11433   freeAsmop (right, NULL, ic, TRUE);
11434 }
11435
11436 /*-----------------------------------------------------------------*/
11437 /* genGenPointerSet - set value from generic pointer space         */
11438 /*-----------------------------------------------------------------*/
11439 static void
11440 genGenPointerSet (operand * right,
11441                   operand * result, iCode * ic, iCode *pi)
11442 {
11443   int size, offset;
11444   bool pushedB;
11445   sym_link *retype = getSpec (operandType (right));
11446   sym_link *letype = getSpec (operandType (result));
11447
11448   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11449
11450   pushedB = pushB ();
11451   /* if the operand is already in dptr
11452      then we do nothing else we move the value to dptr */
11453   if (AOP_TYPE (result) != AOP_STR)
11454     {
11455       _startLazyDPSEvaluation ();
11456       /* if this is remateriazable */
11457       if (AOP_TYPE (result) == AOP_IMMD)
11458         {
11459           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11460           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11461           {
11462               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11463           }
11464           else
11465           {
11466               emitcode ("mov",
11467                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11468           }
11469         }
11470       else
11471         {                       /* we need to get it byte by byte */
11472           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11473           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11474           if (options.model == MODEL_FLAT24) {
11475             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11476             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11477           } else {
11478             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11479           }
11480         }
11481       _endLazyDPSEvaluation ();
11482     }
11483   /* so dptr + b now contains the address */
11484   aopOp (right, ic, FALSE, TRUE);
11485
11486   /* if bit then unpack */
11487   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11488     {
11489         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11490     }
11491   else
11492     {
11493         size = AOP_SIZE (right);
11494         offset = 0;
11495
11496         _startLazyDPSEvaluation ();
11497         while (size--)
11498         {
11499             if (size)
11500             {
11501                 // Set two bytes at a time, passed in _AP & A.
11502                 // dptr will be incremented ONCE by __gptrputWord.
11503                 //
11504                 // Note: any change here must be coordinated
11505                 // with the implementation of __gptrputWord
11506                 // in device/lib/_gptrput.c
11507                 emitcode("mov", "_ap, %s",
11508                          aopGet (right, offset++, FALSE, FALSE, NULL));
11509                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11510
11511                 genSetDPTR (0);
11512                 _flushLazyDPS ();
11513                 emitcode ("lcall", "__gptrputWord");
11514                 size--;
11515             }
11516             else
11517             {
11518                 // Only one byte to put.
11519                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11520
11521                 genSetDPTR (0);
11522                 _flushLazyDPS ();
11523                 emitcode ("lcall", "__gptrput");
11524             }
11525
11526             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11527             {
11528                 emitcode ("inc", "dptr");
11529             }
11530         }
11531         _endLazyDPSEvaluation ();
11532     }
11533
11534   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11535       _startLazyDPSEvaluation ();
11536
11537       aopPut (result, "dpl",0);
11538       aopPut (result, "dph",1);
11539       if (options.model == MODEL_FLAT24) {
11540           aopPut (result, "dpx",2);
11541           aopPut (result, "b",3);
11542       } else {
11543           aopPut (result, "b",2);
11544       }
11545       _endLazyDPSEvaluation ();
11546
11547       pi->generated=1;
11548   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11549              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11550
11551       size = AOP_SIZE (right) - 1;
11552       while (size--) emitcode ("lcall","__decdptr");
11553   }
11554   popB (pushedB);
11555
11556   freeAsmop (result, NULL, ic, TRUE);
11557   freeAsmop (right, NULL, ic, TRUE);
11558 }
11559
11560 /*-----------------------------------------------------------------*/
11561 /* genPointerSet - stores the value into a pointer location        */
11562 /*-----------------------------------------------------------------*/
11563 static void
11564 genPointerSet (iCode * ic, iCode *pi)
11565 {
11566   operand *right, *result;
11567   sym_link *type, *etype;
11568   int p_type;
11569
11570   D (emitcode (";", "genPointerSet"));
11571
11572   right = IC_RIGHT (ic);
11573   result = IC_RESULT (ic);
11574
11575   /* depending on the type of pointer we need to
11576      move it to the correct pointer register */
11577   type = operandType (result);
11578   etype = getSpec (type);
11579   /* if left is of type of pointer then it is simple */
11580   if (IS_PTR (type) && !IS_FUNC (type->next))
11581     {
11582       p_type = DCL_TYPE (type);
11583     }
11584   else
11585     {
11586       /* we have to go by the storage class */
11587       p_type = PTR_TYPE (SPEC_OCLS (etype));
11588     }
11589
11590   /* special case when cast remat */
11591   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11592       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11593           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11594           type = operandType (result);
11595           p_type = DCL_TYPE (type);
11596   }
11597
11598   /* now that we have the pointer type we assign
11599      the pointer values */
11600   switch (p_type)
11601     {
11602
11603     case POINTER:
11604     case IPOINTER:
11605       genNearPointerSet (right, result, ic, pi);
11606       break;
11607
11608     case PPOINTER:
11609       genPagedPointerSet (right, result, ic, pi);
11610       break;
11611
11612     case FPOINTER:
11613       genFarPointerSet (right, result, ic, pi);
11614       break;
11615
11616     case GPOINTER:
11617       genGenPointerSet (right, result, ic, pi);
11618       break;
11619
11620     default:
11621       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11622               "genPointerSet: illegal pointer type");
11623     }
11624 }
11625
11626 /*-----------------------------------------------------------------*/
11627 /* genIfx - generate code for Ifx statement                        */
11628 /*-----------------------------------------------------------------*/
11629 static void
11630 genIfx (iCode * ic, iCode * popIc)
11631 {
11632   operand *cond = IC_COND (ic);
11633   int isbit = 0;
11634   char *dup = NULL;
11635
11636   D (emitcode (";", "genIfx "));
11637
11638   aopOp (cond, ic, FALSE, FALSE);
11639
11640   /* get the value into acc */
11641   if (AOP_TYPE (cond) != AOP_CRY)
11642     {
11643         toBoolean (cond);
11644     }
11645   else
11646     {
11647         isbit = 1;
11648       if (AOP(cond)->aopu.aop_dir)
11649         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11650     }
11651
11652   /* the result is now in the accumulator or a directly addressable bit */
11653   freeAsmop (cond, NULL, ic, TRUE);
11654
11655   /* if there was something to be popped then do it */
11656   if (popIc)
11657     genIpop (popIc);
11658
11659   /* if the condition is  a bit variable */
11660   if (isbit && dup)
11661     {
11662         genIfxJump (ic, dup);
11663     }
11664   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11665     {
11666         genIfxJump (ic, SPIL_LOC (cond)->rname);
11667     }
11668   else if (isbit && !IS_ITEMP (cond))
11669     {
11670         genIfxJump (ic, OP_SYMBOL (cond)->rname);
11671     }
11672   else
11673     {
11674         genIfxJump (ic, "a");
11675     }
11676
11677   ic->generated = 1;
11678 }
11679
11680 /*-----------------------------------------------------------------*/
11681 /* genAddrOf - generates code for address of                       */
11682 /*-----------------------------------------------------------------*/
11683 static void
11684 genAddrOf (iCode * ic)
11685 {
11686   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11687   int size, offset;
11688
11689   D (emitcode (";", "genAddrOf"));
11690
11691   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11692
11693   /* if the operand is on the stack then we
11694      need to get the stack offset of this
11695      variable */
11696   if (sym->onStack)
11697   {
11698
11699       /* if 10 bit stack */
11700       if (options.stack10bit) {
11701           char buff[10];
11702           int  offset;
11703
11704           tsprintf(buff, sizeof(buff),
11705                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11706           /* if it has an offset then we need to compute it */
11707 /*        emitcode ("subb", "a,#!constbyte", */
11708 /*                  -((sym->stack < 0) ? */
11709 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11710 /*                    ((short) sym->stack)) & 0xff); */
11711 /*        emitcode ("mov","b,a"); */
11712 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11713 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11714 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11715           if (sym->stack) {
11716               emitcode ("mov", "a,_bpx");
11717               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11718                                              ((char) (sym->stack - _G.nRegsSaved)) :
11719                                              ((char) sym->stack )) & 0xff);
11720               emitcode ("mov", "b,a");
11721               emitcode ("mov", "a,_bpx+1");
11722
11723               offset = (((sym->stack < 0) ?
11724                          ((short) (sym->stack - _G.nRegsSaved)) :
11725                          ((short) sym->stack )) >> 8) & 0xff;
11726
11727               emitcode ("addc","a,#!constbyte", offset);
11728
11729               aopPut (IC_RESULT (ic), "b", 0);
11730               aopPut (IC_RESULT (ic), "a", 1);
11731               aopPut (IC_RESULT (ic), buff, 2);
11732           } else {
11733               /* we can just move _bp */
11734               aopPut (IC_RESULT (ic), "_bpx", 0);
11735               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11736               aopPut (IC_RESULT (ic), buff, 2);
11737           }
11738       } else {
11739           /* if it has an offset then we need to compute it */
11740           if (sym->stack)
11741             {
11742               emitcode ("mov", "a,_bp");
11743               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11744               aopPut (IC_RESULT (ic), "a", 0);
11745             }
11746           else
11747             {
11748               /* we can just move _bp */
11749               aopPut (IC_RESULT (ic), "_bp", 0);
11750             }
11751           /* fill the result with zero */
11752           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11753
11754
11755           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11756               fprintf (stderr,
11757                        "*** warning: pointer to stack var truncated.\n");
11758           }
11759
11760           offset = 1;
11761           while (size--)
11762             {
11763               aopPut (IC_RESULT (ic), zero, offset++);
11764           }
11765       }
11766       goto release;
11767   }
11768
11769   /* object not on stack then we need the name */
11770   size = AOP_SIZE (IC_RESULT (ic));
11771   offset = 0;
11772
11773   while (size--)
11774     {
11775       char s[SDCC_NAME_MAX];
11776       if (offset) {
11777           switch (offset) {
11778           case 1:
11779               tsprintf(s, sizeof(s), "#!his",sym->rname);
11780               break;
11781           case 2:
11782               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11783               break;
11784           case 3:
11785               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11786               break;
11787           default: /* should not need this (just in case) */
11788               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11789                        sym->rname,
11790                        offset * 8);
11791           }
11792       }
11793       else
11794       {
11795           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11796       }
11797
11798       aopPut (IC_RESULT (ic), s, offset++);
11799     }
11800
11801 release:
11802   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11803
11804 }
11805
11806 #if 0 // obsolete, and buggy for != xdata
11807 /*-----------------------------------------------------------------*/
11808 /* genArrayInit - generates code for address of                       */
11809 /*-----------------------------------------------------------------*/
11810 static void
11811 genArrayInit (iCode * ic)
11812 {
11813     literalList *iLoop;
11814     int         ix, count;
11815     int         elementSize = 0, eIndex;
11816     unsigned    val, lastVal;
11817     sym_link    *type;
11818     operand     *left=IC_LEFT(ic);
11819
11820     D (emitcode (";", "genArrayInit "););
11821
11822     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11823
11824     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11825     {
11826         // Load immediate value into DPTR.
11827         emitcode("mov", "dptr, %s",
11828              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11829     }
11830     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11831     {
11832 #if 0
11833       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11834               "Unexpected operand to genArrayInit.\n");
11835       exit(1);
11836 #else
11837       // a regression because of SDCCcse.c:1.52
11838       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
11839       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
11840       if (options.model == MODEL_FLAT24)
11841         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
11842 #endif
11843     }
11844
11845     type = operandType(IC_LEFT(ic));
11846
11847     if (type && type->next)
11848     {
11849         elementSize = getSize(type->next);
11850     }
11851     else
11852     {
11853         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11854                                 "can't determine element size in genArrayInit.\n");
11855         exit(1);
11856     }
11857
11858     iLoop = IC_ARRAYILIST(ic);
11859     lastVal = 0xffff;
11860
11861     while (iLoop)
11862     {
11863         bool firstpass = TRUE;
11864
11865         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
11866                  iLoop->count, (int)iLoop->literalValue, elementSize);
11867
11868         ix = iLoop->count;
11869
11870         while (ix)
11871         {
11872             symbol *tlbl = NULL;
11873
11874             count = ix > 256 ? 256 : ix;
11875
11876             if (count > 1)
11877             {
11878                 tlbl = newiTempLabel (NULL);
11879                 if (firstpass || (count & 0xff))
11880                 {
11881                     emitcode("mov", "b, #!constbyte", count & 0xff);
11882                 }
11883
11884                 emitcode ("", "!tlabeldef", tlbl->key + 100);
11885             }
11886
11887             firstpass = FALSE;
11888
11889             for (eIndex = 0; eIndex < elementSize; eIndex++)
11890             {
11891                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
11892                 if (val != lastVal)
11893                 {
11894                     emitcode("mov", "a, #!constbyte", val);
11895                     lastVal = val;
11896                 }
11897
11898                 emitcode("movx", "@dptr, a");
11899                 emitcode("inc", "dptr");
11900             }
11901
11902             if (count > 1)
11903             {
11904                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
11905             }
11906
11907             ix -= count;
11908         }
11909
11910         iLoop = iLoop->next;
11911     }
11912
11913     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
11914 }
11915 #endif
11916
11917 /*-----------------------------------------------------------------*/
11918 /* genFarFarAssign - assignment when both are in far space         */
11919 /*-----------------------------------------------------------------*/
11920 static void
11921 genFarFarAssign (operand * result, operand * right, iCode * ic)
11922 {
11923   int size = AOP_SIZE (right);
11924   int offset = 0;
11925   symbol *rSym = NULL;
11926
11927   if (size == 1)
11928   {
11929       /* quick & easy case. */
11930       D(emitcode(";","genFarFarAssign (1 byte case)"););
11931       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11932       freeAsmop (right, NULL, ic, FALSE);
11933       /* now assign DPTR to result */
11934       _G.accInUse++;
11935       aopOp(result, ic, FALSE, FALSE);
11936       _G.accInUse--;
11937       aopPut (result, "a", 0);
11938       freeAsmop(result, NULL, ic, FALSE);
11939       return;
11940   }
11941
11942   /* See if we've got an underlying symbol to abuse. */
11943   if (IS_SYMOP(result) && OP_SYMBOL(result))
11944   {
11945       if (IS_TRUE_SYMOP(result))
11946       {
11947           rSym = OP_SYMBOL(result);
11948       }
11949       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
11950       {
11951           rSym = OP_SYMBOL(result)->usl.spillLoc;
11952       }
11953   }
11954
11955   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
11956   {
11957       /* We can use the '390 auto-toggle feature to good effect here. */
11958
11959       D(emitcode(";","genFarFarAssign (390 auto-toggle fun)"););
11960       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
11961       emitcode ("mov", "dptr,#%s", rSym->rname);
11962       /* DP2 = result, DP1 = right, DP1 is current. */
11963       while (size)
11964       {
11965           emitcode("movx", "a,@dptr");
11966           emitcode("movx", "@dptr,a");
11967           if (--size)
11968           {
11969                emitcode("inc", "dptr");
11970                emitcode("inc", "dptr");
11971           }
11972       }
11973       emitcode("mov", "dps,#0");
11974       freeAsmop (right, NULL, ic, FALSE);
11975 #if 0
11976 some alternative code for processors without auto-toggle
11977 no time to test now, so later well put in...kpb
11978         D(emitcode(";","genFarFarAssign (dual-dptr fun)"););
11979         emitcode("mov", "dps,#1");      /* Select DPTR2. */
11980         emitcode ("mov", "dptr,#%s", rSym->rname);
11981         /* DP2 = result, DP1 = right, DP1 is current. */
11982         while (size)
11983         {
11984           --size;
11985           emitcode("movx", "a,@dptr");
11986           if (size)
11987             emitcode("inc", "dptr");
11988           emitcode("inc", "dps");
11989           emitcode("movx", "@dptr,a");
11990           if (size)
11991             emitcode("inc", "dptr");
11992           emitcode("inc", "dps");
11993         }
11994         emitcode("mov", "dps,#0");
11995         freeAsmop (right, NULL, ic, FALSE);
11996 #endif
11997   }
11998   else
11999   {
12000       D (emitcode (";", "genFarFarAssign"););
12001       aopOp (result, ic, TRUE, TRUE);
12002
12003       _startLazyDPSEvaluation ();
12004
12005       while (size--)
12006         {
12007           aopPut (result,
12008                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12009           offset++;
12010         }
12011       _endLazyDPSEvaluation ();
12012       freeAsmop (result, NULL, ic, FALSE);
12013       freeAsmop (right, NULL, ic, FALSE);
12014   }
12015 }
12016
12017 /*-----------------------------------------------------------------*/
12018 /* genAssign - generate code for assignment                        */
12019 /*-----------------------------------------------------------------*/
12020 static void
12021 genAssign (iCode * ic)
12022 {
12023   operand *result, *right;
12024   int size, offset;
12025   unsigned long lit = 0L;
12026
12027   D (emitcode (";", "genAssign "));
12028
12029   result = IC_RESULT (ic);
12030   right = IC_RIGHT (ic);
12031
12032   /* if they are the same */
12033   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12034     return;
12035
12036   aopOp (right, ic, FALSE, FALSE);
12037
12038   emitcode (";", "genAssign: resultIsFar = %s",
12039             isOperandInFarSpace (result) ?
12040             "TRUE" : "FALSE");
12041
12042   /* special case both in far space */
12043   if ((AOP_TYPE (right) == AOP_DPTR ||
12044        AOP_TYPE (right) == AOP_DPTR2) &&
12045   /* IS_TRUE_SYMOP(result)       && */
12046       isOperandInFarSpace (result))
12047     {
12048       genFarFarAssign (result, right, ic);
12049       return;
12050     }
12051
12052   aopOp (result, ic, TRUE, FALSE);
12053
12054   /* if they are the same registers */
12055   if (sameRegs (AOP (right), AOP (result)))
12056     goto release;
12057
12058   /* if the result is a bit */
12059   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12060     {
12061       /* if the right size is a literal then
12062          we know what the value is */
12063       if (AOP_TYPE (right) == AOP_LIT)
12064         {
12065           if (((int) operandLitValue (right)))
12066             aopPut (result, one, 0);
12067           else
12068             aopPut (result, zero, 0);
12069           goto release;
12070         }
12071
12072       /* the right is also a bit variable */
12073       if (AOP_TYPE (right) == AOP_CRY)
12074         {
12075           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12076           aopPut (result, "c", 0);
12077           goto release;
12078         }
12079
12080       /* we need to or */
12081       toBoolean (right);
12082       aopPut (result, "a", 0);
12083       goto release;
12084     }
12085
12086   /* bit variables done */
12087   /* general case */
12088   size = AOP_SIZE (result);
12089   offset = 0;
12090   if (AOP_TYPE (right) == AOP_LIT)
12091     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12092
12093   if ((size > 1) &&
12094       (AOP_TYPE (result) != AOP_REG) &&
12095       (AOP_TYPE (right) == AOP_LIT) &&
12096       !IS_FLOAT (operandType (right)))
12097     {
12098       _startLazyDPSEvaluation ();
12099       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12100         {
12101           aopPut (result,
12102                   aopGet (right, offset, FALSE, FALSE, NULL),
12103                   offset);
12104           offset++;
12105           size--;
12106         }
12107       /* And now fill the rest with zeros. */
12108       if (size)
12109         {
12110           emitcode ("clr", "a");
12111         }
12112       while (size--)
12113         {
12114           aopPut (result, "a", offset++);
12115         }
12116       _endLazyDPSEvaluation ();
12117     }
12118   else
12119     {
12120       _startLazyDPSEvaluation ();
12121       while (size--)
12122         {
12123           aopPut (result,
12124                   aopGet (right, offset, FALSE, FALSE, NULL),
12125                   offset);
12126           offset++;
12127         }
12128       _endLazyDPSEvaluation ();
12129     }
12130
12131 release:
12132   freeAsmop (result, NULL, ic, TRUE);
12133   freeAsmop (right, NULL, ic, TRUE);
12134 }
12135
12136 /*-----------------------------------------------------------------*/
12137 /* genJumpTab - generates code for jump table                      */
12138 /*-----------------------------------------------------------------*/
12139 static void
12140 genJumpTab (iCode * ic)
12141 {
12142   symbol *jtab;
12143   char *l;
12144
12145   D (emitcode (";", "genJumpTab ");
12146     );
12147
12148   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12149   /* get the condition into accumulator */
12150   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12151   MOVA (l);
12152   /* multiply by four! */
12153   emitcode ("add", "a,acc");
12154   emitcode ("add", "a,acc");
12155   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12156
12157   jtab = newiTempLabel (NULL);
12158   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12159   emitcode ("jmp", "@a+dptr");
12160   emitcode ("", "!tlabeldef", jtab->key + 100);
12161   /* now generate the jump labels */
12162   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12163        jtab = setNextItem (IC_JTLABELS (ic)))
12164     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12165
12166 }
12167
12168 /*-----------------------------------------------------------------*/
12169 /* genCast - gen code for casting                                  */
12170 /*-----------------------------------------------------------------*/
12171 static void
12172 genCast (iCode * ic)
12173 {
12174   operand *result = IC_RESULT (ic);
12175   sym_link *ctype = operandType (IC_LEFT (ic));
12176   sym_link *rtype = operandType (IC_RIGHT (ic));
12177   operand *right = IC_RIGHT (ic);
12178   int size, offset;
12179
12180   D (emitcode (";", "genCast "));
12181
12182   /* if they are equivalent then do nothing */
12183   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12184     return;
12185
12186   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12187   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12188
12189   /* if the result is a bit */
12190   if (IS_BITVAR (OP_SYMBOL (result)->type)
12191       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
12192     {
12193       /* if the right size is a literal then
12194          we know what the value is */
12195       if (AOP_TYPE (right) == AOP_LIT)
12196         {
12197           if (((int) operandLitValue (right)))
12198             aopPut (result, one, 0);
12199           else
12200             aopPut (result, zero, 0);
12201
12202           goto release;
12203         }
12204
12205       /* the right is also a bit variable */
12206       if (AOP_TYPE (right) == AOP_CRY)
12207         {
12208           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12209           aopPut (result, "c", 0);
12210           goto release;
12211         }
12212
12213       /* we need to or */
12214       toBoolean (right);
12215       aopPut (result, "a", 0);
12216       goto release;
12217     }
12218
12219   /* if they are the same size : or less */
12220   if (AOP_SIZE (result) <= AOP_SIZE (right))
12221     {
12222
12223       /* if they are in the same place */
12224       if (sameRegs (AOP (right), AOP (result)))
12225         goto release;
12226
12227       /* if they in different places then copy */
12228       size = AOP_SIZE (result);
12229       offset = 0;
12230       _startLazyDPSEvaluation ();
12231       while (size--)
12232         {
12233           aopPut (result,
12234                   aopGet (right, offset, FALSE, FALSE, NULL),
12235                   offset);
12236           offset++;
12237         }
12238       _endLazyDPSEvaluation ();
12239       goto release;
12240     }
12241
12242   /* if the result is of type pointer */
12243   if (IS_PTR (ctype))
12244     {
12245
12246       int p_type;
12247       sym_link *type = operandType (right);
12248
12249       /* pointer to generic pointer */
12250       if (IS_GENPTR (ctype))
12251         {
12252           if (IS_PTR (type))
12253             {
12254               p_type = DCL_TYPE (type);
12255             }
12256           else
12257             {
12258 #if OLD_CAST_BEHAVIOR
12259               /* KV: we are converting a non-pointer type to
12260                * a generic pointer. This (ifdef'd out) code
12261                * says that the resulting generic pointer
12262                * should have the same class as the storage
12263                * location of the non-pointer variable.
12264                *
12265                * For example, converting an int (which happens
12266                * to be stored in DATA space) to a pointer results
12267                * in a DATA generic pointer; if the original int
12268                * in XDATA space, so will be the resulting pointer.
12269                *
12270                * I don't like that behavior, and thus this change:
12271                * all such conversions will be forced to XDATA and
12272                * throw a warning. If you want some non-XDATA
12273                * type, or you want to suppress the warning, you
12274                * must go through an intermediate cast, like so:
12275                *
12276                * char _generic *gp = (char _xdata *)(intVar);
12277                */
12278               sym_link *etype = getSpec (type);
12279
12280               /* we have to go by the storage class */
12281               if (SPEC_OCLS (etype) != generic)
12282                 {
12283                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12284                 }
12285               else
12286 #endif
12287                 {
12288                   /* Converting unknown class (i.e. register variable)
12289                    * to generic pointer. This is not good, but
12290                    * we'll make a guess (and throw a warning).
12291                    */
12292                   p_type = FPOINTER;
12293                   werror (W_INT_TO_GEN_PTR_CAST);
12294                 }
12295             }
12296
12297           /* the first two bytes are known */
12298           size = GPTRSIZE - 1;
12299           offset = 0;
12300           _startLazyDPSEvaluation ();
12301           while (size--)
12302             {
12303               aopPut (result,
12304                       aopGet (right, offset, FALSE, FALSE, NULL),
12305                       offset);
12306               offset++;
12307             }
12308           _endLazyDPSEvaluation ();
12309
12310           /* the last byte depending on type */
12311             {
12312                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12313                 char gpValStr[10];
12314
12315                 if (gpVal == -1)
12316                 {
12317                     // pointerTypeToGPByte will have bitched.
12318                     exit(1);
12319                 }
12320
12321                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12322                 aopPut (result, gpValStr, GPTRSIZE - 1);
12323             }
12324           goto release;
12325         }
12326
12327       /* just copy the pointers */
12328       size = AOP_SIZE (result);
12329       offset = 0;
12330       _startLazyDPSEvaluation ();
12331       while (size--)
12332         {
12333           aopPut (result,
12334                   aopGet (right, offset, FALSE, FALSE, NULL),
12335                   offset);
12336           offset++;
12337         }
12338       _endLazyDPSEvaluation ();
12339       goto release;
12340     }
12341
12342   /* so we now know that the size of destination is greater
12343      than the size of the source */
12344   /* we move to result for the size of source */
12345   size = AOP_SIZE (right);
12346   offset = 0;
12347   _startLazyDPSEvaluation ();
12348   while (size--)
12349     {
12350       aopPut (result,
12351               aopGet (right, offset, FALSE, FALSE, NULL),
12352               offset);
12353       offset++;
12354     }
12355   _endLazyDPSEvaluation ();
12356
12357   /* now depending on the sign of the source && destination */
12358   size = AOP_SIZE (result) - AOP_SIZE (right);
12359   /* if unsigned or not an integral type */
12360   /* also, if the source is a bit, we don't need to sign extend, because
12361    * it can't possibly have set the sign bit.
12362    */
12363   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12364     {
12365       while (size--)
12366         {
12367           aopPut (result, zero, offset++);
12368         }
12369     }
12370   else
12371     {
12372       /* we need to extend the sign :{ */
12373       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12374                         FALSE, FALSE, NULL));
12375       emitcode ("rlc", "a");
12376       emitcode ("subb", "a,acc");
12377       while (size--)
12378         aopPut (result, "a", offset++);
12379     }
12380
12381   /* we are done hurray !!!! */
12382
12383 release:
12384   freeAsmop (right, NULL, ic, TRUE);
12385   freeAsmop (result, NULL, ic, TRUE);
12386
12387 }
12388
12389 /*-----------------------------------------------------------------*/
12390 /* genDjnz - generate decrement & jump if not zero instrucion      */
12391 /*-----------------------------------------------------------------*/
12392 static int
12393 genDjnz (iCode * ic, iCode * ifx)
12394 {
12395   symbol *lbl, *lbl1;
12396   if (!ifx)
12397     return 0;
12398
12399   /* if the if condition has a false label
12400      then we cannot save */
12401   if (IC_FALSE (ifx))
12402     return 0;
12403
12404   /* if the minus is not of the form
12405      a = a - 1 */
12406   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
12407       !IS_OP_LITERAL (IC_RIGHT (ic)))
12408     return 0;
12409
12410   if (operandLitValue (IC_RIGHT (ic)) != 1)
12411     return 0;
12412
12413   /* if the size of this greater than one then no
12414      saving */
12415   if (getSize (operandType (IC_RESULT (ic))) > 1)
12416     return 0;
12417
12418   /* otherwise we can save BIG */
12419   D(emitcode(";", "genDjnz"););
12420
12421   lbl = newiTempLabel (NULL);
12422   lbl1 = newiTempLabel (NULL);
12423
12424   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
12425
12426   if (AOP_NEEDSACC(IC_RESULT(ic)))
12427   {
12428       /* If the result is accessed indirectly via
12429        * the accumulator, we must explicitly write
12430        * it back after the decrement.
12431        */
12432       char *rByte = aopGet(IC_RESULT(ic), 0, FALSE, FALSE, NULL);
12433
12434       if (strcmp(rByte, "a"))
12435       {
12436            /* Something is hopelessly wrong */
12437            fprintf(stderr, "*** warning: internal error at %s:%d\n",
12438                    __FILE__, __LINE__);
12439            /* We can just give up; the generated code will be inefficient,
12440             * but what the hey.
12441             */
12442            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
12443            return 0;
12444       }
12445       emitcode ("dec", "%s", rByte);
12446       aopPut(IC_RESULT(ic), rByte, 0);
12447       emitcode ("jnz", "!tlabel", lbl->key + 100);
12448   }
12449   else if (IS_AOP_PREG (IC_RESULT (ic)))
12450     {
12451       emitcode ("dec", "%s",
12452                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
12453       emitcode ("mov", "a,%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
12454       emitcode ("jnz", "!tlabel", lbl->key + 100);
12455     }
12456   else
12457     {
12458       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
12459                 lbl->key + 100);
12460     }
12461   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
12462   emitcode ("", "!tlabeldef", lbl->key + 100);
12463   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
12464   emitcode ("", "!tlabeldef", lbl1->key + 100);
12465
12466   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
12467   ifx->generated = 1;
12468   return 1;
12469 }
12470
12471 /*-----------------------------------------------------------------*/
12472 /* genReceive - generate code for a receive iCode                  */
12473 /*-----------------------------------------------------------------*/
12474 static void
12475 genReceive (iCode * ic)
12476 {
12477     int size = getSize (operandType (IC_RESULT (ic)));
12478     int offset = 0;
12479     int rb1off ;
12480
12481     D (emitcode (";", "genReceive "));
12482
12483     if (ic->argreg == 1)
12484     {
12485         /* first parameter */
12486         if (AOP_IS_STR(IC_RESULT(ic)))
12487         {
12488             /* Nothing to do: it's already in the proper place. */
12489             return;
12490         }
12491         else
12492         {
12493             bool useDp2;
12494
12495             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
12496                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
12497                  IS_TRUE_SYMOP (IC_RESULT (ic)));
12498
12499             _G.accInUse++;
12500             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
12501             _G.accInUse--;
12502
12503             /* Sanity checking... */
12504             if (AOP_USESDPTR(IC_RESULT(ic)))
12505             {
12506                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12507                         "genReceive got unexpected DPTR.");
12508             }
12509             assignResultValue (IC_RESULT (ic), NULL);
12510         }
12511     }
12512     else if (ic->argreg > 12)
12513     { /* bit parameters */
12514       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
12515         {
12516           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
12517           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
12518           outBitC(IC_RESULT (ic));
12519         }
12520     }
12521     else
12522     {
12523         /* second receive onwards */
12524         /* this gets a little tricky since unused receives will be
12525          eliminated, we have saved the reg in the type field . and
12526          we use that to figure out which register to use */
12527         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
12528         rb1off = ic->argreg;
12529         while (size--)
12530         {
12531             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
12532         }
12533     }
12534     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
12535 }
12536
12537 /*-----------------------------------------------------------------*/
12538 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12539 /*-----------------------------------------------------------------*/
12540 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12541 {
12542     operand *from , *to , *count;
12543     symbol *lbl;
12544     bitVect *rsave;
12545     int i;
12546
12547     /* we know it has to be 3 parameters */
12548     assert (nparms == 3);
12549
12550     rsave = newBitVect(16);
12551     /* save DPTR if it needs to be saved */
12552     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12553             if (bitVectBitValue(ic->rMask,i))
12554                     rsave = bitVectSetBit(rsave,i);
12555     }
12556     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12557                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12558     savermask(rsave);
12559
12560     to = parms[0];
12561     from = parms[1];
12562     count = parms[2];
12563
12564     aopOp (from, ic->next, FALSE, FALSE);
12565
12566     /* get from into DPTR1 */
12567     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12568     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12569     if (options.model == MODEL_FLAT24) {
12570         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12571     }
12572
12573     freeAsmop (from, NULL, ic, FALSE);
12574     aopOp (to, ic, FALSE, FALSE);
12575     /* get "to" into DPTR */
12576     /* if the operand is already in dptr
12577        then we do nothing else we move the value to dptr */
12578     if (AOP_TYPE (to) != AOP_STR) {
12579         /* if already in DPTR then we need to push */
12580         if (AOP_TYPE(to) == AOP_DPTR) {
12581             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12582             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12583             if (options.model == MODEL_FLAT24)
12584                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12585             emitcode ("pop", "dph");
12586             emitcode ("pop", "dpl");
12587         } else {
12588             _startLazyDPSEvaluation ();
12589             /* if this is remateriazable */
12590             if (AOP_TYPE (to) == AOP_IMMD) {
12591                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12592             } else {                    /* we need to get it byte by byte */
12593                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12594                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12595                 if (options.model == MODEL_FLAT24) {
12596                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12597                 }
12598             }
12599             _endLazyDPSEvaluation ();
12600         }
12601     }
12602     freeAsmop (to, NULL, ic, FALSE);
12603     _G.dptrInUse = _G.dptr1InUse = 1;
12604     aopOp (count, ic->next->next, FALSE,FALSE);
12605     lbl =newiTempLabel(NULL);
12606
12607     /* now for the actual copy */
12608     if (AOP_TYPE(count) == AOP_LIT &&
12609         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12610         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12611         if (fromc) {
12612             emitcode ("lcall","__bi_memcpyc2x_s");
12613         } else {
12614             emitcode ("lcall","__bi_memcpyx2x_s");
12615         }
12616         freeAsmop (count, NULL, ic, FALSE);
12617     } else {
12618         symbol *lbl1 = newiTempLabel(NULL);
12619
12620         emitcode (";"," Auto increment but no djnz");
12621         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12622         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12623         freeAsmop (count, NULL, ic, FALSE);
12624         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12625         emitcode ("","!tlabeldef",lbl->key+100);
12626         if (fromc) {
12627             emitcode ("clr","a");
12628             emitcode ("movc", "a,@a+dptr");
12629         } else
12630             emitcode ("movx", "a,@dptr");
12631         emitcode ("movx", "@dptr,a");
12632         emitcode ("inc", "dptr");
12633         emitcode ("inc", "dptr");
12634         emitcode ("mov","a,b");
12635         emitcode ("orl","a,_ap");
12636         emitcode ("jz","!tlabel",lbl1->key+100);
12637         emitcode ("mov","a,_ap");
12638         emitcode ("add","a,#!constbyte",0xFF);
12639         emitcode ("mov","_ap,a");
12640         emitcode ("mov","a,b");
12641         emitcode ("addc","a,#!constbyte",0xFF);
12642         emitcode ("mov","b,a");
12643         emitcode ("sjmp","!tlabel",lbl->key+100);
12644         emitcode ("","!tlabeldef",lbl1->key+100);
12645     }
12646     emitcode ("mov", "dps,#0");
12647     _G.dptrInUse = _G.dptr1InUse = 0;
12648     unsavermask(rsave);
12649
12650 }
12651
12652 /*-----------------------------------------------------------------*/
12653 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12654 /*-----------------------------------------------------------------*/
12655 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12656 {
12657     operand *from , *to , *count;
12658     symbol *lbl,*lbl2;
12659     bitVect *rsave;
12660     int i;
12661
12662     /* we know it has to be 3 parameters */
12663     assert (nparms == 3);
12664
12665     rsave = newBitVect(16);
12666     /* save DPTR if it needs to be saved */
12667     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12668             if (bitVectBitValue(ic->rMask,i))
12669                     rsave = bitVectSetBit(rsave,i);
12670     }
12671     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12672                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12673     savermask(rsave);
12674
12675     to = parms[0];
12676     from = parms[1];
12677     count = parms[2];
12678
12679     aopOp (from, ic->next, FALSE, FALSE);
12680
12681     /* get from into DPTR1 */
12682     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12683     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12684     if (options.model == MODEL_FLAT24) {
12685         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12686     }
12687
12688     freeAsmop (from, NULL, ic, FALSE);
12689     aopOp (to, ic, FALSE, FALSE);
12690     /* get "to" into DPTR */
12691     /* if the operand is already in dptr
12692        then we do nothing else we move the value to dptr */
12693     if (AOP_TYPE (to) != AOP_STR) {
12694         /* if already in DPTR then we need to push */
12695         if (AOP_TYPE(to) == AOP_DPTR) {
12696             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12697             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12698             if (options.model == MODEL_FLAT24)
12699                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12700             emitcode ("pop", "dph");
12701             emitcode ("pop", "dpl");
12702         } else {
12703             _startLazyDPSEvaluation ();
12704             /* if this is remateriazable */
12705             if (AOP_TYPE (to) == AOP_IMMD) {
12706                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12707             } else {                    /* we need to get it byte by byte */
12708                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12709                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12710                 if (options.model == MODEL_FLAT24) {
12711                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12712                 }
12713             }
12714             _endLazyDPSEvaluation ();
12715         }
12716     }
12717     freeAsmop (to, NULL, ic, FALSE);
12718     _G.dptrInUse = _G.dptr1InUse = 1;
12719     aopOp (count, ic->next->next, FALSE,FALSE);
12720     lbl =newiTempLabel(NULL);
12721     lbl2 =newiTempLabel(NULL);
12722
12723     /* now for the actual compare */
12724     if (AOP_TYPE(count) == AOP_LIT &&
12725         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12726         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12727         if (fromc)
12728             emitcode("lcall","__bi_memcmpc2x_s");
12729         else
12730             emitcode("lcall","__bi_memcmpx2x_s");
12731         freeAsmop (count, NULL, ic, FALSE);
12732         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12733         aopPut(IC_RESULT(ic),"a",0);
12734         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12735     } else {
12736         symbol *lbl1 = newiTempLabel(NULL);
12737
12738         emitcode("push","ar0");
12739         emitcode (";"," Auto increment but no djnz");
12740         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12741         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12742         freeAsmop (count, NULL, ic, FALSE);
12743         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12744         emitcode ("","!tlabeldef",lbl->key+100);
12745         if (fromc) {
12746             emitcode ("clr","a");
12747             emitcode ("movc", "a,@a+dptr");
12748         } else
12749             emitcode ("movx", "a,@dptr");
12750         emitcode ("mov","r0,a");
12751         emitcode ("movx", "a,@dptr");
12752         emitcode ("clr","c");
12753         emitcode ("subb","a,r0");
12754         emitcode ("jnz","!tlabel",lbl2->key+100);
12755         emitcode ("inc", "dptr");
12756         emitcode ("inc", "dptr");
12757         emitcode ("mov","a,b");
12758         emitcode ("orl","a,_ap");
12759         emitcode ("jz","!tlabel",lbl1->key+100);
12760         emitcode ("mov","a,_ap");
12761         emitcode ("add","a,#!constbyte",0xFF);
12762         emitcode ("mov","_ap,a");
12763         emitcode ("mov","a,b");
12764         emitcode ("addc","a,#!constbyte",0xFF);
12765         emitcode ("mov","b,a");
12766         emitcode ("sjmp","!tlabel",lbl->key+100);
12767         emitcode ("","!tlabeldef",lbl1->key+100);
12768         emitcode ("clr","a");
12769         emitcode ("","!tlabeldef",lbl2->key+100);
12770         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12771         aopPut(IC_RESULT(ic),"a",0);
12772         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12773         emitcode("pop","ar0");
12774         emitcode ("mov", "dps,#0");
12775     }
12776     _G.dptrInUse = _G.dptr1InUse = 0;
12777     unsavermask(rsave);
12778
12779 }
12780
12781 /*-----------------------------------------------------------------*/
12782 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12783 /* port, first parameter output area second parameter pointer to   */
12784 /* port third parameter count                                      */
12785 /*-----------------------------------------------------------------*/
12786 static void genInp( iCode *ic, int nparms, operand **parms)
12787 {
12788     operand *from , *to , *count;
12789     symbol *lbl;
12790     bitVect *rsave;
12791     int i;
12792
12793     /* we know it has to be 3 parameters */
12794     assert (nparms == 3);
12795
12796     rsave = newBitVect(16);
12797     /* save DPTR if it needs to be saved */
12798     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12799             if (bitVectBitValue(ic->rMask,i))
12800                     rsave = bitVectSetBit(rsave,i);
12801     }
12802     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12803                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12804     savermask(rsave);
12805
12806     to = parms[0];
12807     from = parms[1];
12808     count = parms[2];
12809
12810     aopOp (from, ic->next, FALSE, FALSE);
12811
12812     /* get from into DPTR1 */
12813     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12814     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12815     if (options.model == MODEL_FLAT24) {
12816         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12817     }
12818
12819     freeAsmop (from, NULL, ic, FALSE);
12820     aopOp (to, ic, FALSE, FALSE);
12821     /* get "to" into DPTR */
12822     /* if the operand is already in dptr
12823        then we do nothing else we move the value to dptr */
12824     if (AOP_TYPE (to) != AOP_STR) {
12825         /* if already in DPTR then we need to push */
12826         if (AOP_TYPE(to) == AOP_DPTR) {
12827             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12828             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12829             if (options.model == MODEL_FLAT24)
12830                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12831             emitcode ("pop", "dph");
12832             emitcode ("pop", "dpl");
12833         } else {
12834             _startLazyDPSEvaluation ();
12835             /* if this is remateriazable */
12836             if (AOP_TYPE (to) == AOP_IMMD) {
12837                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12838             } else {                    /* we need to get it byte by byte */
12839                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12840                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12841                 if (options.model == MODEL_FLAT24) {
12842                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12843                 }
12844             }
12845             _endLazyDPSEvaluation ();
12846         }
12847     }
12848     freeAsmop (to, NULL, ic, FALSE);
12849
12850     _G.dptrInUse = _G.dptr1InUse = 1;
12851     aopOp (count, ic->next->next, FALSE,FALSE);
12852     lbl =newiTempLabel(NULL);
12853
12854     /* now for the actual copy */
12855     if (AOP_TYPE(count) == AOP_LIT &&
12856         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12857         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12858         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12859         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12860         freeAsmop (count, NULL, ic, FALSE);
12861         emitcode ("","!tlabeldef",lbl->key+100);
12862         emitcode ("movx", "a,@dptr");   /* read data from port */
12863         emitcode ("dec","dps");         /* switch to DPTR */
12864         emitcode ("movx", "@dptr,a");   /* save into location */
12865         emitcode ("inc", "dptr");       /* point to next area */
12866         emitcode ("inc","dps");         /* switch to DPTR2 */
12867         emitcode ("djnz","b,!tlabel",lbl->key+100);
12868     } else {
12869         symbol *lbl1 = newiTempLabel(NULL);
12870
12871         emitcode (";"," Auto increment but no djnz");
12872         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12873         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12874         freeAsmop (count, NULL, ic, FALSE);
12875         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12876         emitcode ("","!tlabeldef",lbl->key+100);
12877         emitcode ("movx", "a,@dptr");
12878         emitcode ("dec","dps");         /* switch to DPTR */
12879         emitcode ("movx", "@dptr,a");
12880         emitcode ("inc", "dptr");
12881         emitcode ("inc","dps");         /* switch to DPTR2 */
12882 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12883 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12884         emitcode ("mov","a,b");
12885         emitcode ("orl","a,_ap");
12886         emitcode ("jz","!tlabel",lbl1->key+100);
12887         emitcode ("mov","a,_ap");
12888         emitcode ("add","a,#!constbyte",0xFF);
12889         emitcode ("mov","_ap,a");
12890         emitcode ("mov","a,b");
12891         emitcode ("addc","a,#!constbyte",0xFF);
12892         emitcode ("mov","b,a");
12893         emitcode ("sjmp","!tlabel",lbl->key+100);
12894         emitcode ("","!tlabeldef",lbl1->key+100);
12895     }
12896     emitcode ("mov", "dps,#0");
12897     _G.dptrInUse = _G.dptr1InUse = 0;
12898     unsavermask(rsave);
12899
12900 }
12901
12902 /*-----------------------------------------------------------------*/
12903 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12904 /* port, first parameter output area second parameter pointer to   */
12905 /* port third parameter count                                      */
12906 /*-----------------------------------------------------------------*/
12907 static void genOutp( iCode *ic, int nparms, operand **parms)
12908 {
12909     operand *from , *to , *count;
12910     symbol *lbl;
12911     bitVect *rsave;
12912     int i;
12913
12914     /* we know it has to be 3 parameters */
12915     assert (nparms == 3);
12916
12917     rsave = newBitVect(16);
12918     /* save DPTR if it needs to be saved */
12919     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12920             if (bitVectBitValue(ic->rMask,i))
12921                     rsave = bitVectSetBit(rsave,i);
12922     }
12923     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12924                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12925     savermask(rsave);
12926
12927     to = parms[0];
12928     from = parms[1];
12929     count = parms[2];
12930
12931     aopOp (from, ic->next, FALSE, FALSE);
12932
12933     /* get from into DPTR1 */
12934     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12935     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12936     if (options.model == MODEL_FLAT24) {
12937         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12938     }
12939
12940     freeAsmop (from, NULL, ic, FALSE);
12941     aopOp (to, ic, FALSE, FALSE);
12942     /* get "to" into DPTR */
12943     /* if the operand is already in dptr
12944        then we do nothing else we move the value to dptr */
12945     if (AOP_TYPE (to) != AOP_STR) {
12946         /* if already in DPTR then we need to push */
12947         if (AOP_TYPE(to) == AOP_DPTR) {
12948             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12949             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12950             if (options.model == MODEL_FLAT24)
12951                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12952             emitcode ("pop", "dph");
12953             emitcode ("pop", "dpl");
12954         } else {
12955             _startLazyDPSEvaluation ();
12956             /* if this is remateriazable */
12957             if (AOP_TYPE (to) == AOP_IMMD) {
12958                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12959             } else {                    /* we need to get it byte by byte */
12960                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12961                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12962                 if (options.model == MODEL_FLAT24) {
12963                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12964                 }
12965             }
12966             _endLazyDPSEvaluation ();
12967         }
12968     }
12969     freeAsmop (to, NULL, ic, FALSE);
12970
12971     _G.dptrInUse = _G.dptr1InUse = 1;
12972     aopOp (count, ic->next->next, FALSE,FALSE);
12973     lbl =newiTempLabel(NULL);
12974
12975     /* now for the actual copy */
12976     if (AOP_TYPE(count) == AOP_LIT &&
12977         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12978         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12979         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12980         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12981         emitcode ("","!tlabeldef",lbl->key+100);
12982         emitcode ("movx", "a,@dptr");   /* read data from port */
12983         emitcode ("inc","dps");         /* switch to DPTR2 */
12984         emitcode ("movx", "@dptr,a");   /* save into location */
12985         emitcode ("inc", "dptr");       /* point to next area */
12986         emitcode ("dec","dps");         /* switch to DPTR */
12987         emitcode ("djnz","b,!tlabel",lbl->key+100);
12988         freeAsmop (count, NULL, ic, FALSE);
12989     } else {
12990         symbol *lbl1 = newiTempLabel(NULL);
12991
12992         emitcode (";"," Auto increment but no djnz");
12993         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12994         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12995         freeAsmop (count, NULL, ic, FALSE);
12996         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12997         emitcode ("","!tlabeldef",lbl->key+100);
12998         emitcode ("movx", "a,@dptr");
12999         emitcode ("inc", "dptr");
13000         emitcode ("inc","dps");         /* switch to DPTR2 */
13001         emitcode ("movx", "@dptr,a");
13002         emitcode ("dec","dps");         /* switch to DPTR */
13003         emitcode ("mov","a,b");
13004         emitcode ("orl","a,_ap");
13005         emitcode ("jz","!tlabel",lbl1->key+100);
13006         emitcode ("mov","a,_ap");
13007         emitcode ("add","a,#!constbyte",0xFF);
13008         emitcode ("mov","_ap,a");
13009         emitcode ("mov","a,b");
13010         emitcode ("addc","a,#!constbyte",0xFF);
13011         emitcode ("mov","b,a");
13012         emitcode ("sjmp","!tlabel",lbl->key+100);
13013         emitcode ("","!tlabeldef",lbl1->key+100);
13014     }
13015     emitcode ("mov", "dps,#0");
13016     _G.dptrInUse = _G.dptr1InUse = 0;
13017     unsavermask(rsave);
13018
13019 }
13020
13021 /*-----------------------------------------------------------------*/
13022 /* genSwapW - swap lower & high order bytes                        */
13023 /*-----------------------------------------------------------------*/
13024 static void genSwapW(iCode *ic, int nparms, operand **parms)
13025 {
13026     operand *dest;
13027     operand *src;
13028     assert (nparms==1);
13029
13030     src = parms[0];
13031     dest=IC_RESULT(ic);
13032
13033     assert(getSize(operandType(src))==2);
13034
13035     aopOp (src, ic, FALSE, FALSE);
13036     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13037     _G.accInUse++;
13038     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13039     _G.accInUse--;
13040     freeAsmop (src, NULL, ic, FALSE);
13041
13042     aopOp (dest,ic, FALSE, FALSE);
13043     aopPut(dest,"b",0);
13044     aopPut(dest,"a",1);
13045     freeAsmop (dest, NULL, ic, FALSE);
13046 }
13047
13048 /*-----------------------------------------------------------------*/
13049 /* genMemsetX - gencode for memSetX data                           */
13050 /*-----------------------------------------------------------------*/
13051 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13052 {
13053     operand *to , *val , *count;
13054     symbol *lbl;
13055     char *l;
13056     int i;
13057     bitVect *rsave;
13058
13059     /* we know it has to be 3 parameters */
13060     assert (nparms == 3);
13061
13062     to = parms[0];
13063     val = parms[1];
13064     count = parms[2];
13065
13066     /* save DPTR if it needs to be saved */
13067     rsave = newBitVect(16);
13068     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13069             if (bitVectBitValue(ic->rMask,i))
13070                     rsave = bitVectSetBit(rsave,i);
13071     }
13072     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13073                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13074     savermask(rsave);
13075
13076     aopOp (to, ic, FALSE, FALSE);
13077     /* get "to" into DPTR */
13078     /* if the operand is already in dptr
13079        then we do nothing else we move the value to dptr */
13080     if (AOP_TYPE (to) != AOP_STR) {
13081         /* if already in DPTR then we need to push */
13082         if (AOP_TYPE(to) == AOP_DPTR) {
13083             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13084             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13085             if (options.model == MODEL_FLAT24)
13086                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13087             emitcode ("pop", "dph");
13088             emitcode ("pop", "dpl");
13089         } else {
13090             _startLazyDPSEvaluation ();
13091             /* if this is remateriazable */
13092             if (AOP_TYPE (to) == AOP_IMMD) {
13093                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13094             } else {                    /* we need to get it byte by byte */
13095                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13096                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13097                 if (options.model == MODEL_FLAT24) {
13098                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13099                 }
13100             }
13101             _endLazyDPSEvaluation ();
13102         }
13103     }
13104     freeAsmop (to, NULL, ic, FALSE);
13105
13106     aopOp (val, ic->next->next, FALSE,FALSE);
13107     aopOp (count, ic->next->next, FALSE,FALSE);
13108     lbl =newiTempLabel(NULL);
13109     /* now for the actual copy */
13110     if (AOP_TYPE(count) == AOP_LIT &&
13111         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13112         l = aopGet(val, 0, FALSE, FALSE, NULL);
13113         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13114         MOVA(l);
13115         emitcode ("","!tlabeldef",lbl->key+100);
13116         emitcode ("movx", "@dptr,a");
13117         emitcode ("inc", "dptr");
13118         emitcode ("djnz","b,!tlabel",lbl->key+100);
13119     } else {
13120         symbol *lbl1 = newiTempLabel(NULL);
13121
13122         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13123         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13124         emitcode ("","!tlabeldef",lbl->key+100);
13125         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13126         emitcode ("movx", "@dptr,a");
13127         emitcode ("inc", "dptr");
13128         emitcode ("mov","a,b");
13129         emitcode ("orl","a,_ap");
13130         emitcode ("jz","!tlabel",lbl1->key+100);
13131         emitcode ("mov","a,_ap");
13132         emitcode ("add","a,#!constbyte",0xFF);
13133         emitcode ("mov","_ap,a");
13134         emitcode ("mov","a,b");
13135         emitcode ("addc","a,#!constbyte",0xFF);
13136         emitcode ("mov","b,a");
13137         emitcode ("sjmp","!tlabel",lbl->key+100);
13138         emitcode ("","!tlabeldef",lbl1->key+100);
13139     }
13140     freeAsmop (count, NULL, ic, FALSE);
13141     unsavermask(rsave);
13142 }
13143
13144 /*-----------------------------------------------------------------*/
13145 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13146 /*-----------------------------------------------------------------*/
13147 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13148 {
13149         bitVect *rsave ;
13150         operand *pnum, *result;
13151         int i;
13152
13153         assert (nparms==1);
13154         /* save registers that need to be saved */
13155         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13156                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13157
13158         pnum = parms[0];
13159         aopOp (pnum, ic, FALSE, FALSE);
13160         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13161         freeAsmop (pnum, NULL, ic, FALSE);
13162         emitcode ("lcall","NatLib_LoadPrimitive");
13163         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13164         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13165             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13166                 for (i = (size-1) ; i >= 0 ; i-- ) {
13167                         emitcode ("push","a%s",javaRet[i]);
13168                 }
13169                 for (i=0; i < size ; i++ ) {
13170                         emitcode ("pop","a%s",
13171                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13172                 }
13173         } else {
13174                 for (i = 0 ; i < size ; i++ ) {
13175                         aopPut(result,javaRet[i],i);
13176                 }
13177         }
13178         freeAsmop (result, NULL, ic, FALSE);
13179         unsavermask(rsave);
13180 }
13181
13182 /*-----------------------------------------------------------------*/
13183 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13184 /*-----------------------------------------------------------------*/
13185 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13186 {
13187         bitVect *rsave ;
13188         operand *pnum, *result;
13189         int size = 3;
13190         int i;
13191
13192         assert (nparms==1);
13193         /* save registers that need to be saved */
13194         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13195                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13196
13197         pnum = parms[0];
13198         aopOp (pnum, ic, FALSE, FALSE);
13199         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13200         freeAsmop (pnum, NULL, ic, FALSE);
13201         emitcode ("lcall","NatLib_LoadPointer");
13202         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13203         if (AOP_TYPE(result)!=AOP_STR) {
13204                 for (i = 0 ; i < size ; i++ ) {
13205                         aopPut(result,fReturn[i],i);
13206                 }
13207         }
13208         freeAsmop (result, NULL, ic, FALSE);
13209         unsavermask(rsave);
13210 }
13211
13212 /*-----------------------------------------------------------------*/
13213 /* genNatLibInstallStateBlock -                                    */
13214 /*-----------------------------------------------------------------*/
13215 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13216                                        operand **parms, const char *name)
13217 {
13218         bitVect *rsave ;
13219         operand *psb, *handle;
13220         assert (nparms==2);
13221
13222         /* save registers that need to be saved */
13223         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13224                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13225         psb = parms[0];
13226         handle = parms[1];
13227
13228         /* put pointer to state block into DPTR1 */
13229         aopOp (psb, ic, FALSE, FALSE);
13230         if (AOP_TYPE (psb) == AOP_IMMD) {
13231                 emitcode ("mov","dps,#1");
13232                 emitcode ("mov", "dptr,%s",
13233                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13234                 emitcode ("mov","dps,#0");
13235         } else {
13236                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13237                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13238                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13239         }
13240         freeAsmop (psb, NULL, ic, FALSE);
13241
13242         /* put libraryID into DPTR */
13243         emitcode ("mov","dptr,#LibraryID");
13244
13245         /* put handle into r3:r2 */
13246         aopOp (handle, ic, FALSE, FALSE);
13247         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13248                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13249                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13250                 emitcode ("pop","ar3");
13251                 emitcode ("pop","ar2");
13252         } else {
13253                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13254                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13255         }
13256         freeAsmop (psb, NULL, ic, FALSE);
13257
13258         /* make the call */
13259         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13260
13261         /* put return value into place*/
13262         _G.accInUse++;
13263         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13264         _G.accInUse--;
13265         aopPut(IC_RESULT(ic),"a",0);
13266         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13267         unsavermask(rsave);
13268 }
13269
13270 /*-----------------------------------------------------------------*/
13271 /* genNatLibRemoveStateBlock -                                     */
13272 /*-----------------------------------------------------------------*/
13273 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13274 {
13275         bitVect *rsave ;
13276
13277         assert(nparms==0);
13278
13279         /* save registers that need to be saved */
13280         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13281                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13282
13283         /* put libraryID into DPTR */
13284         emitcode ("mov","dptr,#LibraryID");
13285         /* make the call */
13286         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13287         unsavermask(rsave);
13288 }
13289
13290 /*-----------------------------------------------------------------*/
13291 /* genNatLibGetStateBlock -                                        */
13292 /*-----------------------------------------------------------------*/
13293 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13294                                    operand **parms,const char *name)
13295 {
13296         bitVect *rsave ;
13297         symbol *lbl = newiTempLabel(NULL);
13298
13299         assert(nparms==0);
13300         /* save registers that need to be saved */
13301         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13302                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13303
13304         /* put libraryID into DPTR */
13305         emitcode ("mov","dptr,#LibraryID");
13306         /* make the call */
13307         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13308         emitcode ("jnz","!tlabel",lbl->key+100);
13309
13310         /* put return value into place */
13311         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13312         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13313                 emitcode ("push","ar3");
13314                 emitcode ("push","ar2");
13315                 emitcode ("pop","%s",
13316                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13317                 emitcode ("pop","%s",
13318                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13319         } else {
13320                 aopPut(IC_RESULT(ic),"r2",0);
13321                 aopPut(IC_RESULT(ic),"r3",1);
13322         }
13323         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13324         emitcode ("","!tlabeldef",lbl->key+100);
13325         unsavermask(rsave);
13326 }
13327
13328 /*-----------------------------------------------------------------*/
13329 /* genMMMalloc -                                                   */
13330 /*-----------------------------------------------------------------*/
13331 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13332                          int size, const char *name)
13333 {
13334         bitVect *rsave ;
13335         operand *bsize;
13336         symbol *rsym;
13337         symbol *lbl = newiTempLabel(NULL);
13338
13339         assert (nparms == 1);
13340         /* save registers that need to be saved */
13341         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13342                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13343
13344         bsize=parms[0];
13345         aopOp (bsize,ic,FALSE,FALSE);
13346
13347         /* put the size in R4-R2 */
13348         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13349                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13350                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13351                 if (size==3) {
13352                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13353                         emitcode("pop","ar4");
13354                 }
13355                 emitcode("pop","ar3");
13356                 emitcode("pop","ar2");
13357         } else {
13358                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13359                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13360                 if (size==3) {
13361                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13362                 }
13363         }
13364         freeAsmop (bsize, NULL, ic, FALSE);
13365
13366         /* make the call */
13367         emitcode ("lcall","MM_%s",name);
13368         emitcode ("jz","!tlabel",lbl->key+100);
13369         emitcode ("mov","r2,#!constbyte",0xff);
13370         emitcode ("mov","r3,#!constbyte",0xff);
13371         emitcode ("","!tlabeldef",lbl->key+100);
13372         /* we don't care about the pointer : we just save the handle */
13373         rsym = OP_SYMBOL(IC_RESULT(ic));
13374         if (rsym->liveFrom != rsym->liveTo) {
13375                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13376                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13377                         emitcode ("push","ar3");
13378                         emitcode ("push","ar2");
13379                         emitcode ("pop","%s",
13380                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13381                         emitcode ("pop","%s",
13382                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13383                 } else {
13384                         aopPut(IC_RESULT(ic),"r2",0);
13385                         aopPut(IC_RESULT(ic),"r3",1);
13386                 }
13387                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13388         }
13389         unsavermask(rsave);
13390 }
13391
13392 /*-----------------------------------------------------------------*/
13393 /* genMMDeref -                                                    */
13394 /*-----------------------------------------------------------------*/
13395 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13396 {
13397         bitVect *rsave ;
13398         operand *handle;
13399
13400         assert (nparms == 1);
13401         /* save registers that need to be saved */
13402         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13403                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13404
13405         handle=parms[0];
13406         aopOp (handle,ic,FALSE,FALSE);
13407
13408         /* put the size in R4-R2 */
13409         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13410                 emitcode("push","%s",
13411                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13412                 emitcode("push","%s",
13413                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13414                 emitcode("pop","ar3");
13415                 emitcode("pop","ar2");
13416         } else {
13417                 emitcode ("mov","r2,%s",
13418                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13419                 emitcode ("mov","r3,%s",
13420                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13421         }
13422         freeAsmop (handle, NULL, ic, FALSE);
13423
13424         /* make the call */
13425         emitcode ("lcall","MM_Deref");
13426
13427         {
13428                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13429                 if (rsym->liveFrom != rsym->liveTo) {
13430                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13431                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13432                             _startLazyDPSEvaluation ();
13433
13434                                 aopPut(IC_RESULT(ic),"dpl",0);
13435                                 aopPut(IC_RESULT(ic),"dph",1);
13436                                 aopPut(IC_RESULT(ic),"dpx",2);
13437
13438                             _endLazyDPSEvaluation ();
13439
13440                         }
13441                 }
13442         }
13443         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13444         unsavermask(rsave);
13445 }
13446
13447 /*-----------------------------------------------------------------*/
13448 /* genMMUnrestrictedPersist -                                      */
13449 /*-----------------------------------------------------------------*/
13450 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13451 {
13452         bitVect *rsave ;
13453         operand *handle;
13454
13455         assert (nparms == 1);
13456         /* save registers that need to be saved */
13457         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13458                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13459
13460         handle=parms[0];
13461         aopOp (handle,ic,FALSE,FALSE);
13462
13463         /* put the size in R3-R2 */
13464         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13465                 emitcode("push","%s",
13466                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13467                 emitcode("push","%s",
13468                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13469                 emitcode("pop","ar3");
13470                 emitcode("pop","ar2");
13471         } else {
13472                 emitcode ("mov","r2,%s",
13473                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13474                 emitcode ("mov","r3,%s",
13475                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13476         }
13477         freeAsmop (handle, NULL, ic, FALSE);
13478
13479         /* make the call */
13480         emitcode ("lcall","MM_UnrestrictedPersist");
13481
13482         {
13483                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13484                 if (rsym->liveFrom != rsym->liveTo) {
13485                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13486                         aopPut(IC_RESULT(ic),"a",0);
13487                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13488                 }
13489         }
13490         unsavermask(rsave);
13491 }
13492
13493 /*-----------------------------------------------------------------*/
13494 /* genSystemExecJavaProcess -                                      */
13495 /*-----------------------------------------------------------------*/
13496 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13497 {
13498         bitVect *rsave ;
13499         operand *handle, *pp;
13500
13501         assert (nparms==2);
13502         /* save registers that need to be saved */
13503         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13504                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13505
13506         pp = parms[0];
13507         handle = parms[1];
13508
13509         /* put the handle in R3-R2 */
13510         aopOp (handle,ic,FALSE,FALSE);
13511         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13512                 emitcode("push","%s",
13513                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13514                 emitcode("push","%s",
13515                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13516                 emitcode("pop","ar3");
13517                 emitcode("pop","ar2");
13518         } else {
13519                 emitcode ("mov","r2,%s",
13520                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13521                 emitcode ("mov","r3,%s",
13522                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13523         }
13524         freeAsmop (handle, NULL, ic, FALSE);
13525
13526         /* put pointer in DPTR */
13527         aopOp (pp,ic,FALSE,FALSE);
13528         if (AOP_TYPE(pp) == AOP_IMMD) {
13529                 emitcode ("mov", "dptr,%s",
13530                           aopGet (pp, 0, TRUE, FALSE, NULL));
13531         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13532                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13533                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13534                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13535         }
13536         freeAsmop (handle, NULL, ic, FALSE);
13537
13538         /* make the call */
13539         emitcode ("lcall","System_ExecJavaProcess");
13540
13541         /* put result in place */
13542         {
13543                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13544                 if (rsym->liveFrom != rsym->liveTo) {
13545                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13546                         aopPut(IC_RESULT(ic),"a",0);
13547                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13548                 }
13549         }
13550
13551         unsavermask(rsave);
13552 }
13553
13554 /*-----------------------------------------------------------------*/
13555 /* genSystemRTCRegisters -                                         */
13556 /*-----------------------------------------------------------------*/
13557 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13558                                   char *name)
13559 {
13560         bitVect *rsave ;
13561         operand *pp;
13562
13563         assert (nparms==1);
13564         /* save registers that need to be saved */
13565         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13566                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13567
13568         pp=parms[0];
13569         /* put pointer in DPTR */
13570         aopOp (pp,ic,FALSE,FALSE);
13571         if (AOP_TYPE (pp) == AOP_IMMD) {
13572                 emitcode ("mov","dps,#1");
13573                 emitcode ("mov", "dptr,%s",
13574                           aopGet (pp, 0, TRUE, FALSE, NULL));
13575                 emitcode ("mov","dps,#0");
13576         } else {
13577                 emitcode ("mov","dpl1,%s",
13578                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13579                 emitcode ("mov","dph1,%s",
13580                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13581                 emitcode ("mov","dpx1,%s",
13582                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13583         }
13584         freeAsmop (pp, NULL, ic, FALSE);
13585
13586         /* make the call */
13587         emitcode ("lcall","System_%sRTCRegisters",name);
13588
13589         unsavermask(rsave);
13590 }
13591
13592 /*-----------------------------------------------------------------*/
13593 /* genSystemThreadSleep -                                          */
13594 /*-----------------------------------------------------------------*/
13595 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13596 {
13597         bitVect *rsave ;
13598         operand *to, *s;
13599
13600         assert (nparms==1);
13601         /* save registers that need to be saved */
13602         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13603                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13604
13605         to = parms[0];
13606         aopOp(to,ic,FALSE,FALSE);
13607         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13608             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13609                 emitcode ("push","%s",
13610                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13611                 emitcode ("push","%s",
13612                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13613                 emitcode ("push","%s",
13614                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13615                 emitcode ("push","%s",
13616                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13617                 emitcode ("pop","ar3");
13618                 emitcode ("pop","ar2");
13619                 emitcode ("pop","ar1");
13620                 emitcode ("pop","ar0");
13621         } else {
13622                 emitcode ("mov","r0,%s",
13623                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13624                 emitcode ("mov","r1,%s",
13625                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13626                 emitcode ("mov","r2,%s",
13627                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13628                 emitcode ("mov","r3,%s",
13629                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13630         }
13631         freeAsmop (to, NULL, ic, FALSE);
13632
13633         /* suspend in acc */
13634         s = parms[1];
13635         aopOp(s,ic,FALSE,FALSE);
13636         emitcode ("mov","a,%s",
13637                   aopGet(s,0,FALSE,TRUE,NULL));
13638         freeAsmop (s, NULL, ic, FALSE);
13639
13640         /* make the call */
13641         emitcode ("lcall","System_%s",name);
13642
13643         unsavermask(rsave);
13644 }
13645
13646 /*-----------------------------------------------------------------*/
13647 /* genSystemThreadResume -                                         */
13648 /*-----------------------------------------------------------------*/
13649 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13650 {
13651         bitVect *rsave ;
13652         operand *tid,*pid;
13653
13654         assert (nparms==2);
13655         /* save registers that need to be saved */
13656         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13657                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13658
13659         tid = parms[0];
13660         pid = parms[1];
13661
13662         /* PID in R0 */
13663         aopOp(pid,ic,FALSE,FALSE);
13664         emitcode ("mov","r0,%s",
13665                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13666         freeAsmop (pid, NULL, ic, FALSE);
13667
13668         /* tid into ACC */
13669         aopOp(tid,ic,FALSE,FALSE);
13670         emitcode ("mov","a,%s",
13671                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13672         freeAsmop (tid, NULL, ic, FALSE);
13673
13674         emitcode ("lcall","System_ThreadResume");
13675
13676         /* put result into place */
13677         {
13678                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13679                 if (rsym->liveFrom != rsym->liveTo) {
13680                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13681                         aopPut(IC_RESULT(ic),"a",0);
13682                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13683                 }
13684         }
13685         unsavermask(rsave);
13686 }
13687
13688 /*-----------------------------------------------------------------*/
13689 /* genSystemProcessResume -                                        */
13690 /*-----------------------------------------------------------------*/
13691 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13692 {
13693         bitVect *rsave ;
13694         operand *pid;
13695
13696         assert (nparms==1);
13697         /* save registers that need to be saved */
13698         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13699                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13700
13701         pid = parms[0];
13702
13703         /* pid into ACC */
13704         aopOp(pid,ic,FALSE,FALSE);
13705         emitcode ("mov","a,%s",
13706                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13707         freeAsmop (pid, NULL, ic, FALSE);
13708
13709         emitcode ("lcall","System_ProcessResume");
13710
13711         unsavermask(rsave);
13712 }
13713
13714 /*-----------------------------------------------------------------*/
13715 /* genSystem -                                                     */
13716 /*-----------------------------------------------------------------*/
13717 static void genSystem (iCode *ic,int nparms,char *name)
13718 {
13719         assert(nparms == 0);
13720
13721         emitcode ("lcall","System_%s",name);
13722 }
13723
13724 /*-----------------------------------------------------------------*/
13725 /* genSystemPoll -                                                  */
13726 /*-----------------------------------------------------------------*/
13727 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13728 {
13729         bitVect *rsave ;
13730         operand *fp;
13731
13732         assert (nparms==1);
13733         /* save registers that need to be saved */
13734         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13735                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13736
13737         fp = parms[0];
13738         aopOp (fp,ic,FALSE,FALSE);
13739         if (AOP_TYPE (fp) == AOP_IMMD) {
13740                 emitcode ("mov", "dptr,%s",
13741                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13742         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13743                 emitcode ("mov","dpl,%s",
13744                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13745                 emitcode ("mov","dph,%s",
13746                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13747                 emitcode ("mov","dpx,%s",
13748                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13749         }
13750         freeAsmop (fp, NULL, ic, FALSE);
13751
13752         emitcode ("lcall","System_%sPoll",name);
13753
13754         /* put result into place */
13755         {
13756                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13757                 if (rsym->liveFrom != rsym->liveTo) {
13758                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13759                         aopPut(IC_RESULT(ic),"a",0);
13760                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13761                 }
13762         }
13763         unsavermask(rsave);
13764 }
13765
13766 /*-----------------------------------------------------------------*/
13767 /* genSystemGetCurrentID -                                         */
13768 /*-----------------------------------------------------------------*/
13769 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13770 {
13771         assert (nparms==0);
13772
13773         emitcode ("lcall","System_GetCurrent%sId",name);
13774         /* put result into place */
13775         {
13776                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13777                 if (rsym->liveFrom != rsym->liveTo) {
13778                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13779                         aopPut(IC_RESULT(ic),"a",0);
13780                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13781                 }
13782         }
13783 }
13784
13785 /*-----------------------------------------------------------------*/
13786 /* genDummyRead - generate code for dummy read of volatiles        */
13787 /*-----------------------------------------------------------------*/
13788 static void
13789 genDummyRead (iCode * ic)
13790 {
13791   operand *op;
13792   int size, offset;
13793
13794   D (emitcode(";", "genDummyRead"));
13795
13796   op = IC_RIGHT (ic);
13797   if (op && IS_SYMOP (op))
13798     {
13799       aopOp (op, ic, FALSE, FALSE);
13800
13801       /* if the result is a bit */
13802       if (AOP_TYPE (op) == AOP_CRY)
13803         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13804       else
13805         {
13806           /* bit variables done */
13807           /* general case */
13808           size = AOP_SIZE (op);
13809           offset = 0;
13810           while (size--)
13811           {
13812             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13813             offset++;
13814           }
13815         }
13816
13817       freeAsmop (op, NULL, ic, TRUE);
13818     }
13819
13820   op = IC_LEFT (ic);
13821   if (op && IS_SYMOP (op))
13822     {
13823       aopOp (op, ic, FALSE, FALSE);
13824
13825       /* if the result is a bit */
13826       if (AOP_TYPE (op) == AOP_CRY)
13827         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13828       else
13829         {
13830           /* bit variables done */
13831           /* general case */
13832           size = AOP_SIZE (op);
13833           offset = 0;
13834           while (size--)
13835           {
13836             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13837             offset++;
13838           }
13839         }
13840
13841       freeAsmop (op, NULL, ic, TRUE);
13842     }
13843 }
13844
13845 /*-----------------------------------------------------------------*/
13846 /* genCritical - generate code for start of a critical sequence    */
13847 /*-----------------------------------------------------------------*/
13848 static void
13849 genCritical (iCode *ic)
13850 {
13851   symbol *tlbl = newiTempLabel (NULL);
13852
13853   D (emitcode(";", "genCritical"));
13854
13855   if (IC_RESULT (ic))
13856     aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
13857
13858   emitcode ("setb", "c");
13859   emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
13860   emitcode ("clr", "c");
13861   emitcode ("", "%05d$:", (tlbl->key + 100));
13862
13863   if (IC_RESULT (ic))
13864     outBitC (IC_RESULT (ic)); /* save old ea in an operand */
13865   else
13866     emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
13867
13868   if (IC_RESULT (ic))
13869     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13870 }
13871
13872 /*-----------------------------------------------------------------*/
13873 /* genEndCritical - generate code for end of a critical sequence   */
13874 /*-----------------------------------------------------------------*/
13875 static void
13876 genEndCritical (iCode *ic)
13877 {
13878   D(emitcode(";     genEndCritical",""));
13879
13880   if (IC_RIGHT (ic))
13881     {
13882       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
13883       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
13884         {
13885           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
13886           emitcode ("mov", "ea,c");
13887         }
13888       else
13889         {
13890           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
13891           emitcode ("rrc", "a");
13892           emitcode ("mov", "ea,c");
13893         }
13894       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
13895     }
13896   else
13897     {
13898       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
13899       emitcode ("mov", "ea,c");
13900     }
13901 }
13902
13903
13904
13905 /*-----------------------------------------------------------------*/
13906 /* genBuiltIn - calls the appropriate function to  generating code */
13907 /* for a built in function                                         */
13908 /*-----------------------------------------------------------------*/
13909 static void genBuiltIn (iCode *ic)
13910 {
13911         operand *bi_parms[MAX_BUILTIN_ARGS];
13912         int nbi_parms;
13913         iCode *bi_iCode;
13914         symbol *bif;
13915
13916         /* get all the arguments for a built in function */
13917         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
13918
13919         /* which function is it */
13920         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
13921         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
13922                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
13923         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
13924                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
13925         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
13926                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
13927         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
13928                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
13929         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
13930                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
13931         } else if (strcmp(bif->name,"__builtin_inp")==0) {
13932                 genInp(bi_iCode,nbi_parms,bi_parms);
13933         } else if (strcmp(bif->name,"__builtin_outp")==0) {
13934                 genOutp(bi_iCode,nbi_parms,bi_parms);
13935         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
13936                 genSwapW(bi_iCode,nbi_parms,bi_parms);
13937                 /* JavaNative builtIns */
13938         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
13939                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
13940         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
13941                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
13942         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
13943                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
13944         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
13945                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
13946         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
13947                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13948         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
13949                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13950         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
13951                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
13952         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
13953                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
13954         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
13955                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13956         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
13957                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13958         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
13959                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
13960         } else if (strcmp(bif->name,"MM_Malloc")==0) {
13961                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
13962         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
13963                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
13964         } else if (strcmp(bif->name,"MM_Free")==0) {
13965                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
13966         } else if (strcmp(bif->name,"MM_Deref")==0) {
13967                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
13968         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
13969                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
13970         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
13971                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
13972         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
13973                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
13974         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
13975                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
13976         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
13977                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
13978         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
13979                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
13980         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
13981                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
13982         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
13983                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
13984         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
13985                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13986         } else if (strcmp(bif->name,"System_SaveThread")==0) {
13987                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13988         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
13989                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13990         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
13991                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
13992         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
13993                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
13994         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
13995                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
13996         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
13997                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
13998         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
13999                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14000         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14001                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14002         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14003                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14004         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14005                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14006         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14007                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14008         } else {
14009                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14010                 return ;
14011         }
14012         return ;
14013 }
14014
14015 /*-----------------------------------------------------------------*/
14016 /* gen390Code - generate code for Dallas 390 based controllers     */
14017 /*-----------------------------------------------------------------*/
14018 void
14019 gen390Code (iCode * lic)
14020 {
14021   iCode *ic;
14022   int cln = 0;
14023
14024   _G.currentFunc = NULL;
14025   lineHead = lineCurr = NULL;
14026   dptrn[1][0] = "dpl1";
14027   dptrn[1][1] = "dph1";
14028   dptrn[1][2] = "dpx1";
14029
14030   if (options.model == MODEL_FLAT24) {
14031     fReturnSizeDS390 = 5;
14032     fReturn = fReturn24;
14033   } else {
14034     fReturnSizeDS390 = 4;
14035     fReturn = fReturn16;
14036     options.stack10bit=0;
14037   }
14038 #if 1
14039   /* print the allocation information */
14040   if (allocInfo && currFunc)
14041     printAllocInfo (currFunc, codeOutFile);
14042 #endif
14043   /* if debug information required */
14044   if (options.debug && currFunc)
14045     {
14046       debugFile->writeFunction (currFunc, lic);
14047     }
14048   /* stack pointer name */
14049   if (options.useXstack)
14050     spname = "_spx";
14051   else
14052     spname = "sp";
14053
14054
14055   for (ic = lic; ic; ic = ic->next)
14056     {
14057       _G.current_iCode = ic;
14058
14059       if (ic->lineno && cln != ic->lineno)
14060         {
14061           if (options.debug)
14062             {
14063               debugFile->writeCLine (ic);
14064             }
14065           if (!options.noCcodeInAsm) {
14066             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14067                       printCLine(ic->filename, ic->lineno));
14068           }
14069           cln = ic->lineno;
14070         }
14071       if (options.iCodeInAsm) {
14072         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
14073       }
14074       /* if the result is marked as
14075          spilt and rematerializable or code for
14076          this has already been generated then
14077          do nothing */
14078       if (resultRemat (ic) || ic->generated)
14079         continue;
14080
14081       /* depending on the operation */
14082       switch (ic->op)
14083         {
14084         case '!':
14085           genNot (ic);
14086           break;
14087
14088         case '~':
14089           genCpl (ic);
14090           break;
14091
14092         case UNARYMINUS:
14093           genUminus (ic);
14094           break;
14095
14096         case IPUSH:
14097           genIpush (ic);
14098           break;
14099
14100         case IPOP:
14101           /* IPOP happens only when trying to restore a
14102              spilt live range, if there is an ifx statement
14103              following this pop then the if statement might
14104              be using some of the registers being popped which
14105              would destory the contents of the register so
14106              we need to check for this condition and handle it */
14107           if (ic->next &&
14108               ic->next->op == IFX &&
14109               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14110             genIfx (ic->next, ic);
14111           else
14112             genIpop (ic);
14113           break;
14114
14115         case CALL:
14116           genCall (ic);
14117           break;
14118
14119         case PCALL:
14120           genPcall (ic);
14121           break;
14122
14123         case FUNCTION:
14124           genFunction (ic);
14125           break;
14126
14127         case ENDFUNCTION:
14128           genEndFunction (ic);
14129           break;
14130
14131         case RETURN:
14132           genRet (ic);
14133           break;
14134
14135         case LABEL:
14136           genLabel (ic);
14137           break;
14138
14139         case GOTO:
14140           genGoto (ic);
14141           break;
14142
14143         case '+':
14144           genPlus (ic);
14145           break;
14146
14147         case '-':
14148           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14149             genMinus (ic);
14150           break;
14151
14152         case '*':
14153           genMult (ic);
14154           break;
14155
14156         case '/':
14157           genDiv (ic);
14158           break;
14159
14160         case '%':
14161           genMod (ic);
14162           break;
14163
14164         case '>':
14165           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14166           break;
14167
14168         case '<':
14169           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14170           break;
14171
14172         case LE_OP:
14173         case GE_OP:
14174         case NE_OP:
14175
14176           /* note these two are xlated by algebraic equivalence
14177              during parsing SDCC.y */
14178           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14179                   "got '>=' or '<=' shouldn't have come here");
14180           break;
14181
14182         case EQ_OP:
14183           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14184           break;
14185
14186         case AND_OP:
14187           genAndOp (ic);
14188           break;
14189
14190         case OR_OP:
14191           genOrOp (ic);
14192           break;
14193
14194         case '^':
14195           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14196           break;
14197
14198         case '|':
14199           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14200           break;
14201
14202         case BITWISEAND:
14203           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14204           break;
14205
14206         case INLINEASM:
14207           genInline (ic);
14208           break;
14209
14210         case RRC:
14211           genRRC (ic);
14212           break;
14213
14214         case RLC:
14215           genRLC (ic);
14216           break;
14217
14218         case GETHBIT:
14219           genGetHbit (ic);
14220           break;
14221
14222         case LEFT_OP:
14223           genLeftShift (ic);
14224           break;
14225
14226         case RIGHT_OP:
14227           genRightShift (ic);
14228           break;
14229
14230         case GET_VALUE_AT_ADDRESS:
14231           genPointerGet (ic,hasInc(IC_LEFT(ic),ic, getSize(operandType(IC_RESULT(ic)))));
14232           break;
14233
14234         case '=':
14235           if (POINTER_SET (ic))
14236             genPointerSet (ic,hasInc(IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
14237           else
14238             genAssign (ic);
14239           break;
14240
14241         case IFX:
14242           genIfx (ic, NULL);
14243           break;
14244
14245         case ADDRESS_OF:
14246           genAddrOf (ic);
14247           break;
14248
14249         case JUMPTABLE:
14250           genJumpTab (ic);
14251           break;
14252
14253         case CAST:
14254           genCast (ic);
14255           break;
14256
14257         case RECEIVE:
14258           genReceive (ic);
14259           break;
14260
14261         case SEND:
14262           if (ic->builtinSEND)
14263             genBuiltIn(ic);
14264           else
14265             addSet (&_G.sendSet, ic);
14266           break;
14267
14268         case DUMMY_READ_VOLATILE:
14269           genDummyRead (ic);
14270           break;
14271
14272         case CRITICAL:
14273           genCritical (ic);
14274           break;
14275
14276         case ENDCRITICAL:
14277           genEndCritical (ic);
14278           break;
14279
14280         case SWAP:
14281           genSwap (ic);
14282           break;
14283
14284 #if 0 // obsolete, and buggy for != xdata
14285         case ARRAYINIT:
14286             genArrayInit(ic);
14287             break;
14288 #endif
14289
14290         default:
14291           ic = ic;
14292         }
14293     }
14294
14295
14296   /* now we are ready to call the
14297      peep hole optimizer */
14298   if (!options.nopeep)
14299     peepHole (&lineHead);
14300
14301   /* now do the actual printing */
14302   printLine (lineHead, codeOutFile);
14303   return;
14304 }