0c4517c2ba2752e36a0680eb01c8184e3e473dd3
[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 #include "dbuf_string.h"
38
39 #include "common.h"
40 #include "main.h"
41 #include "ralloc.h"
42 #include "gen.h"
43
44 #define BETTER_LITERAL_SHIFT
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0";
55 static char *one = "#1";
56 static char *spname;
57
58 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
59 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
60
61 unsigned fReturnSizeDS390 = 5;
62 static char *fReturn24[] =
63 {"dpl", "dph", "dpx", "b", "a"};
64 static char *fReturn16[] =
65 {"dpl", "dph", "b", "a"};
66 static char **fReturn = fReturn24;
67 static char *accUse[] =
68 {"a", "b"};
69 static char *dptrn[2][3];
70 static char *javaRet[] = { "r0","r1","r2","r3"};
71 static short rbank = -1;
72
73 #define REG_WITH_INDEX   ds390_regWithIdx
74
75 #define AOP(op) op->aop
76 #define AOP_TYPE(op) AOP(op)->type
77 #define AOP_SIZE(op) AOP(op)->size
78 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
79                        AOP_TYPE(x) == AOP_R0))
80
81 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
82                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
83                          AOP(x)->paged))
84
85 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
86                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
87                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
88 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
89 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
90 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
91
92 // The following two macros can be used even if the aop has not yet been aopOp'd.
93 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
94 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
95
96 /* Workaround for DS80C390 bug: div ab may return bogus results
97  * if A is accessed in instruction immediately before the div.
98  *
99  * Will be fixed in B4 rev of processor, Dallas claims.
100  */
101
102 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
103     if (!AOP_NEEDSACC(RIGHT))         \
104     {               \
105       /* We can load A first, then B, since     \
106        * B (the RIGHT operand) won't clobber A,   \
107        * thus avoiding touching A right before the div. \
108        */             \
109       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
110       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
111       MOVA(L);            \
112       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
113       MOVB(L); \
114     }               \
115     else              \
116     {               \
117       /* Just stuff in a nop after loading A. */    \
118       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
119       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
120       MOVA(L);            \
121       emitcode("nop", "; workaround for DS80C390 div bug.");  \
122     }
123
124 #define R0INB   _G.bu.bs.r0InB
125 #define R1INB   _G.bu.bs.r1InB
126 #define OPINB   _G.bu.bs.OpInB
127 #define BINUSE  _G.bu.BInUse
128
129 static struct
130   {
131     short r0Pushed;
132     short r1Pushed;
133     union
134       {
135         struct
136           {
137             short r0InB : 2;//2 so we can see it overflow
138             short r1InB : 2;//2 so we can see it overflow
139             short OpInB : 2;//2 so we can see it overflow
140           } bs;
141         short BInUse;
142       } bu;
143     short accInUse;
144     short inLine;
145     short debugLine;
146     short nRegsSaved;
147     short dptrInUse;
148     short dptr1InUse;
149     set *sendSet;
150     iCode *current_iCode;
151     symbol *currentFunc;
152   }
153 _G;
154
155 static char *rb1regs[] = {
156     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
157     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
158 };
159
160 static void saveRBank (int, iCode *, bool);
161
162 #define RESULTONSTACK(x) \
163                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
164                          IC_RESULT(x)->aop->type == AOP_STK )
165
166 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
167 #define MOVB(x)  movb(x)
168
169 #define CLRC    emitcode("clr","c")
170 #define SETC    emitcode("setb","c")
171
172 // A scratch register which will be used to hold
173 // result bytes from operands in far space via DPTR2.
174 #define DP2_RESULT_REG  "_ap"
175
176 static lineNode *lineHead = NULL;
177 static lineNode *lineCurr = NULL;
178
179 static unsigned char SLMask[] =
180 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
181  0xE0, 0xC0, 0x80, 0x00};
182 static unsigned char SRMask[] =
183 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
184  0x07, 0x03, 0x01, 0x00};
185
186 #define LSB     0
187 #define MSB16   1
188 #define MSB24   2
189 #define MSB32   3
190 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
191                                 symbol *lbl = newiTempLabel(NULL);              \
192                                 emitcode ("setb","F1");                         \
193                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
194                                 emitcode ("clr","F1");                          \
195                                 emitLabel (lbl);                                \
196                         }}
197 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
198                                 emitcode ("mov","EA,F1");                       \
199                         }}
200
201 static int _currentDPS;         /* Current processor DPS. */
202 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
203 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
204
205 /*-----------------------------------------------------------------*/
206 /* emitcode - writes the code into a file : for now it is simple    */
207 /*-----------------------------------------------------------------*/
208 static void
209 emitcode (const char *inst, const char *fmt,...)
210 {
211   va_list ap;
212   struct dbuf_s dbuf;
213   const char *lbp, *lb;
214
215   dbuf_init (&dbuf, INITIAL_INLINEASM);
216
217   va_start (ap, fmt);
218
219   if (inst && *inst)
220     {
221       dbuf_append_str (&dbuf, inst);
222
223       if (fmt && *fmt)
224         {
225           dbuf_append_char (&dbuf, '\t');
226           dbuf_tvprintf (&dbuf, fmt, ap);
227       }
228     }
229   else
230     {
231       dbuf_tvprintf (&dbuf, fmt, ap);
232     }
233
234   lbp = lb = dbuf_c_str(&dbuf);
235
236   while (isspace ((unsigned char)*lbp))
237     {
238       lbp++;
239     }
240
241   if (lbp && *lbp)
242     {
243       lineCurr = (lineCurr ?
244                   connectLine (lineCurr, newLineNode (lb)) :
245                   (lineHead = newLineNode (lb)));
246     }
247
248   lineCurr->isInline = _G.inLine;
249   lineCurr->isDebug = _G.debugLine;
250   lineCurr->ic = _G.current_iCode;
251   lineCurr->aln = ds390newAsmLineNode(_currentDPS);
252   lineCurr->isComment = (*lbp == ';');
253   va_end (ap);
254
255   dbuf_destroy(&dbuf);
256 }
257
258 static void
259 emitLabel (symbol *tlbl)
260 {
261   emitcode ("", "!tlabeldef", tlbl->key + 100);
262   lineCurr->isLabel = 1;
263 }
264
265 /*-----------------------------------------------------------------*/
266 /* ds390_emitDebuggerSymbol - associate the current code location  */
267 /*   with a debugger symbol                                        */
268 /*-----------------------------------------------------------------*/
269 void
270 ds390_emitDebuggerSymbol (char * debugSym)
271 {
272   _G.debugLine = 1;
273   emitcode ("", "%s ==.", debugSym);
274   _G.debugLine = 0;
275 }
276
277 /*-----------------------------------------------------------------*/
278 /* mova - moves specified value into accumulator                   */
279 /*-----------------------------------------------------------------*/
280 static void
281 mova (const char *x)
282 {
283   /* do some early peephole optimization */
284   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
285     return;
286
287   emitcode("mov", "a,%s", x);
288 }
289
290 /*-----------------------------------------------------------------*/
291 /* movb - moves specified value into register b                    */
292 /*-----------------------------------------------------------------*/
293 static void
294 movb (const char *x)
295 {
296   /* do some early peephole optimization */
297   if (!strncmp(x, "b", 2))
298     return;
299
300   emitcode("mov","b,%s", x);
301 }
302
303 /*-----------------------------------------------------------------*/
304 /* movc - moves specified value into the carry                     */
305 /*-----------------------------------------------------------------*/
306 static void
307 movc (const char *s)
308 {
309   if (s == zero)
310     CLRC;
311   else if (s == one)
312     SETC;
313   else if (strcmp (s, "c"))
314     {/* it's not in carry already */
315       MOVA (s);
316       /* set C, if a >= 1 */
317       emitcode ("add", "a,#0xff");
318     }
319 }
320
321 /*-----------------------------------------------------------------*/
322 /* pushB - saves register B if necessary                           */
323 /*-----------------------------------------------------------------*/
324 static bool
325 pushB (void)
326 {
327   bool pushedB = FALSE;
328
329   if (BINUSE)
330     {
331       emitcode ("push", "b");
332 //    printf("B was in use !\n");
333       pushedB = TRUE;
334     }
335   else
336     {
337       OPINB++;
338     }
339   return pushedB;
340 }
341
342 /*-----------------------------------------------------------------*/
343 /* popB - restores value of register B if necessary                */
344 /*-----------------------------------------------------------------*/
345 static void
346 popB (bool pushedB)
347 {
348   if (pushedB)
349     {
350       emitcode ("pop", "b");
351     }
352   else
353     {
354       OPINB--;
355     }
356 }
357
358 /*-----------------------------------------------------------------*/
359 /* pushReg - saves register                                        */
360 /*-----------------------------------------------------------------*/
361 static bool
362 pushReg (int index, bool bits_pushed)
363 {
364   regs * reg = REG_WITH_INDEX (index);
365   if (reg->type == REG_BIT)
366     {
367       if (!bits_pushed)
368         emitcode ("push", "%s", reg->base);
369       return TRUE;
370     }
371   else
372     emitcode ("push", "%s", reg->dname);
373   return bits_pushed;
374 }
375
376 /*-----------------------------------------------------------------*/
377 /* popReg - restores register                                      */
378 /*-----------------------------------------------------------------*/
379 static bool
380 popReg (int index, bool bits_popped)
381 {
382   regs * reg = REG_WITH_INDEX (index);
383   if (reg->type == REG_BIT)
384     {
385       if (!bits_popped)
386         emitcode ("pop", "%s", reg->base);
387       return TRUE;
388     }
389   else
390     emitcode ("pop", "%s", reg->dname);
391   return bits_popped;
392 }
393
394 /*-----------------------------------------------------------------*/
395 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
396 /*-----------------------------------------------------------------*/
397 static regs *
398 getFreePtr (iCode * ic, asmop ** aopp, bool result)
399 {
400   bool r0iu, r1iu;
401   bool r0ou, r1ou;
402
403   /* the logic: if r0 & r1 used in the instruction
404      then we are in trouble otherwise */
405
406   /* first check if r0 & r1 are used by this
407      instruction, in which case we are in trouble */
408   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
409   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
410   if (r0iu && r1iu) {
411       goto endOfWorld;
412     }
413
414   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
415   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
416
417   /* if no usage of r0 then return it */
418   if (!r0iu && !r0ou)
419     {
420       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
421       (*aopp)->type = AOP_R0;
422
423       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
424     }
425
426   /* if no usage of r1 then return it */
427   if (!r1iu && !r1ou)
428     {
429       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
430       (*aopp)->type = AOP_R1;
431
432       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
433     }
434
435   /* now we know they both have usage */
436   /* if r0 not used in this instruction */
437   if (!r0iu)
438     {
439       /* push it if not already pushed */
440       if (!_G.r0Pushed)
441         {
442           emitcode ("push", "%s",
443                     REG_WITH_INDEX (R0_IDX)->dname);
444           _G.r0Pushed++;
445         }
446
447       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
448       (*aopp)->type = AOP_R0;
449
450       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
451     }
452
453   /* if r1 not used then */
454
455   if (!r1iu)
456     {
457       /* push it if not already pushed */
458       if (!_G.r1Pushed)
459         {
460           emitcode ("push", "%s",
461                     REG_WITH_INDEX (R1_IDX)->dname);
462           _G.r1Pushed++;
463         }
464
465       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
466       (*aopp)->type = AOP_R1;
467       return REG_WITH_INDEX (R1_IDX);
468     }
469
470 endOfWorld:
471   /* I said end of world, but not quite end of world yet */
472   /* if this is a result then we can push it on the stack */
473   if (result)
474     {
475       (*aopp)->type = AOP_STK;
476       return NULL;
477     }
478
479   /* now this is REALLY the end of the world */
480   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
481           "getFreePtr should never reach here");
482   exit (1);
483
484   return NULL; // notreached, but makes compiler happy.
485 }
486
487
488 /*-----------------------------------------------------------------*/
489 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
490 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
491 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
492 /*-----------------------------------------------------------------*/
493 static void
494 genSetDPTR (int n)
495 {
496
497   /* If we are doing lazy evaluation, simply note the desired
498    * change, but don't emit any code yet.
499    */
500   if (_lazyDPS)
501     {
502       _desiredDPS = n;
503       return;
504     }
505
506   if (!n)
507     {
508       emitcode ("mov", "dps,#0");
509     }
510   else
511     {
512       TR_DPTR("#1");
513       emitcode ("mov", "dps,#1");
514     }
515 }
516
517 /*------------------------------------------------------------------*/
518 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
519 /*                                                                  */
520 /* Any code that operates on DPTR (NB: not on the individual        */
521 /* components, like DPH) *must* call _flushLazyDPS() before using   */
522 /* DPTR within a lazy DPS evaluation block.                         */
523 /*                                                                  */
524 /* Note that aopPut and aopGet already contain the proper calls to  */
525 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
526 /* DPS evaluation block.                                            */
527 /*                                                                  */
528 /* Also, _flushLazyDPS must be called before any flow control       */
529 /* operations that could potentially branch out of the block.       */
530 /*                                                                  */
531 /* Lazy DPS evaluation is simply an optimization (though an         */
532 /* important one), so if in doubt, leave it out.                    */
533 /*------------------------------------------------------------------*/
534 static void
535 _startLazyDPSEvaluation (void)
536 {
537   _currentDPS = 0;
538   _desiredDPS = 0;
539 #ifdef BETTER_LITERAL_SHIFT
540   _lazyDPS++;
541 #else
542   _lazyDPS = 1;
543 #endif
544 }
545
546 /*------------------------------------------------------------------*/
547 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
548 /* desired one. Call before using DPTR within a lazy DPS evaluation */
549 /* block.                                                           */
550 /*------------------------------------------------------------------*/
551 static void
552 _flushLazyDPS (void)
553 {
554   if (!_lazyDPS)
555     {
556       /* nothing to do. */
557       return;
558     }
559
560   if (_desiredDPS != _currentDPS)
561     {
562       if (_desiredDPS)
563         {
564           emitcode ("inc", "dps");
565         }
566       else
567         {
568           emitcode ("dec", "dps");
569         }
570       _currentDPS = _desiredDPS;
571     }
572 }
573
574 /*-----------------------------------------------------------------*/
575 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
576 /*                                                                 */
577 /* Forces us back to the safe state (standard DPTR selected).      */
578 /*-----------------------------------------------------------------*/
579 static void
580 _endLazyDPSEvaluation (void)
581 {
582 #ifdef BETTER_LITERAL_SHIFT
583   _lazyDPS--;
584 #else
585   _lazyDPS = 0;
586 #endif
587   if (!_lazyDPS)
588   {
589     if (_currentDPS)
590     {
591       genSetDPTR (0);
592       _flushLazyDPS ();
593     }
594     _currentDPS = 0;
595     _desiredDPS = 0;
596   }
597 }
598
599
600 /*-----------------------------------------------------------------*/
601 /* newAsmop - creates a new asmOp                                  */
602 /*-----------------------------------------------------------------*/
603 static asmop *
604 newAsmop (short type)
605 {
606   asmop *aop;
607
608   aop = Safe_calloc (1, sizeof (asmop));
609   aop->type = type;
610   aop->allocated = 1;
611   return aop;
612 }
613
614 /*-----------------------------------------------------------------*/
615 /* pointerCode - returns the code for a pointer type               */
616 /*-----------------------------------------------------------------*/
617 static int
618 pointerCode (sym_link * etype)
619 {
620
621   return PTR_TYPE (SPEC_OCLS (etype));
622
623 }
624
625 /*-----------------------------------------------------------------*/
626 /* leftRightUseAcc - returns size of accumulator use by operands   */
627 /*-----------------------------------------------------------------*/
628 static int
629 leftRightUseAcc(iCode *ic)
630 {
631   operand *op;
632   int size;
633   int accuseSize = 0;
634   int accuse = 0;
635
636   if (!ic)
637     {
638       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
639               "null iCode pointer");
640       return 0;
641     }
642
643   if (ic->op == IFX)
644     {
645       op = IC_COND (ic);
646       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
647         {
648           accuse = 1;
649           size = getSize (OP_SYMBOL (op)->type);
650           if (size>accuseSize)
651             accuseSize = size;
652         }
653     }
654   else if (ic->op == JUMPTABLE)
655     {
656       op = IC_JTCOND (ic);
657       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
658         {
659           accuse = 1;
660           size = getSize (OP_SYMBOL (op)->type);
661           if (size>accuseSize)
662             accuseSize = size;
663         }
664     }
665   else
666     {
667       op = IC_LEFT (ic);
668       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
669         {
670           accuse = 1;
671           size = getSize (OP_SYMBOL (op)->type);
672           if (size>accuseSize)
673             accuseSize = size;
674         }
675       op = IC_RIGHT (ic);
676       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
677         {
678           accuse = 1;
679           size = getSize (OP_SYMBOL (op)->type);
680           if (size>accuseSize)
681             accuseSize = size;
682         }
683     }
684
685   if (accuseSize)
686     return accuseSize;
687   else
688     return accuse;
689 }
690
691 /*-----------------------------------------------------------------*/
692 /* aopForSym - for a true symbol                                   */
693 /*-----------------------------------------------------------------*/
694 static asmop *
695 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
696 {
697   asmop *aop;
698   memmap *space;
699   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
700   char *dpl = useDP2 ? "dpl1" : "dpl";
701   char *dph = useDP2 ? "dph1" : "dph";
702   char *dpx = useDP2 ? "dpx1" : "dpx";
703
704   wassertl (ic != NULL, "Got a null iCode");
705   wassertl (sym != NULL, "Got a null symbol");
706
707   space = SPEC_OCLS (sym->etype);
708
709   /* if already has one */
710   if (sym->aop)
711     {
712       if ((sym->aop->type == AOP_DPTR && useDP2)
713           || (sym->aop->type == AOP_DPTR2 && !useDP2))
714         sym->aop = NULL;
715       else
716         {
717           sym->aop->allocated++;
718           return sym->aop;
719         }
720     }
721
722   /* assign depending on the storage class */
723   /* if it is on the stack or indirectly addressable */
724   /* space we need to assign either r0 or r1 to it   */
725   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
726     {
727       sym->aop = aop = newAsmop (0);
728       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
729       aop->size = getSize (sym->type);
730
731       /* now assign the address of the variable to
732          the pointer register */
733       if (aop->type != AOP_STK)
734         {
735           if (sym->onStack)
736             {
737               signed char offset = ((sym->stack < 0) ?
738                          ((signed char) (sym->stack - _G.nRegsSaved)) :
739                          ((signed char) sym->stack)) & 0xff;
740
741               if ((abs(offset) <= 3) ||
742                   (accuse && (abs(offset) <= 7)))
743                 {
744                   emitcode ("mov", "%s,_bp",
745                             aop->aopu.aop_ptr->name);
746                   while (offset < 0)
747                     {
748                       emitcode ("dec", aop->aopu.aop_ptr->name);
749                       offset++;
750                     }
751                   while (offset > 0)
752                     {
753                       emitcode ("inc", aop->aopu.aop_ptr->name);
754                       offset--;
755                     }
756                 }
757               else
758                 {
759                   if (accuse)
760                     emitcode ("push", "acc");
761                   emitcode ("mov", "a,_bp");
762                   emitcode ("add", "a,#!constbyte", offset);
763                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
764                   if (accuse)
765                     emitcode ("pop", "acc");
766                 }
767             }
768           else
769             {
770               emitcode ("mov", "%s,#%s",
771                         aop->aopu.aop_ptr->name,
772                         sym->rname);
773             }
774           aop->paged = space->paged;
775         }
776       else
777         aop->aopu.aop_stk = sym->stack;
778       return aop;
779     }
780
781   if (sym->onStack && options.stack10bit)
782     {
783       short stack_val = -((sym->stack < 0) ?
784                           ((short) (sym->stack - _G.nRegsSaved)) :
785                           ((short) sym->stack)) ;
786       if (_G.dptrInUse ) {
787           emitcode ("push",dpl);
788           emitcode ("push",dph);
789           emitcode ("push",dpx);
790       }
791       /* It's on the 10 bit stack, which is located in
792        * far data space.
793        */
794       if (stack_val < 0 && stack_val > -5)
795         { /* between -5 & -1 */
796           if (options.model == MODEL_FLAT24)
797             {
798               emitcode ("mov", "%s,#!constbyte", dpx,
799                         (options.stack_loc >> 16) & 0xff);
800             }
801           emitcode ("mov", "%s,_bpx+1", dph);
802           emitcode ("mov", "%s,_bpx", dpl);
803           if (useDP2) {
804               emitcode ("mov","dps,#1");
805           }
806           stack_val = -stack_val;
807           while (stack_val--) {
808               emitcode ("inc","dptr");
809           }
810           if (useDP2) {
811               emitcode("mov","dps,#0");
812           }
813         }
814       else
815         {
816           if (accuse)
817               emitcode ("push", "acc");
818
819           emitcode ("mov", "a,_bpx");
820           emitcode ("clr","c");
821           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
822           emitcode ("mov","%s,a", dpl);
823           emitcode ("mov","a,_bpx+1");
824           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
825           emitcode ("mov", "%s,a", dph);
826           if (options.model == MODEL_FLAT24)
827             {
828               emitcode ("mov", "%s,#!constbyte", dpx,
829                         (options.stack_loc >> 16) & 0xff);
830             }
831
832           if (accuse)
833               emitcode ("pop", "acc");
834         }
835       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
836       aop->size = getSize (sym->type);
837       return aop;
838     }
839
840   /* if in bit space */
841   if (IN_BITSPACE (space))
842     {
843       sym->aop = aop = newAsmop (AOP_CRY);
844       aop->aopu.aop_dir = sym->rname;
845       aop->size = getSize (sym->type);
846       return aop;
847     }
848   /* if it is in direct space */
849   if (IN_DIRSPACE (space))
850     {
851       sym->aop = aop = newAsmop (AOP_DIR);
852       aop->aopu.aop_dir = sym->rname;
853       aop->size = getSize (sym->type);
854       return aop;
855     }
856
857   /* special case for a function */
858   if (IS_FUNC (sym->type) && !(sym->isitmp))
859     {
860       sym->aop = aop = newAsmop (AOP_IMMD);
861       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
862       aop->size = FPTRSIZE;
863       return aop;
864     }
865
866   /* only remaining is far space */
867   /* in which case DPTR gets the address */
868   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
869   if (useDP2)
870     {
871       genSetDPTR (1);
872       _flushLazyDPS ();
873       emitcode ("mov", "dptr,#%s", sym->rname);
874       genSetDPTR (0);
875     }
876   else
877     {
878       emitcode ("mov", "dptr,#%s", sym->rname);
879     }
880   aop->size = getSize (sym->type);
881
882   /* if it is in code space */
883   if (IN_CODESPACE (space))
884     aop->code = 1;
885
886   return aop;
887 }
888
889 /*-----------------------------------------------------------------*/
890 /* aopForRemat - rematerialzes an object                           */
891 /*-----------------------------------------------------------------*/
892 static asmop *
893 aopForRemat (symbol * sym)
894 {
895   iCode *ic = sym->rematiCode;
896   asmop *aop = newAsmop (AOP_IMMD);
897   int ptr_type = 0;
898   int val = 0;
899
900   for (;;)
901     {
902       if (ic->op == '+')
903         val += (int) operandLitValue (IC_RIGHT (ic));
904       else if (ic->op == '-')
905         val -= (int) operandLitValue (IC_RIGHT (ic));
906       else if (IS_CAST_ICODE(ic)) {
907               sym_link *from_type = operandType(IC_RIGHT(ic));
908               aop->aopu.aop_immd.from_cast_remat = 1;
909               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
910               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
911               continue;
912       } else break;
913
914       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
915     }
916
917   if (val)
918   {
919       SNPRINTF (buffer, sizeof(buffer),
920                 "(%s %c 0x%06x)",
921                 OP_SYMBOL (IC_LEFT (ic))->rname,
922                 val >= 0 ? '+' : '-',
923                 abs (val) & 0xffffff);
924   }
925   else
926   {
927       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
928       {
929           SNPRINTF(buffer, sizeof(buffer),
930                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
931       }
932       else
933       {
934           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
935       }
936   }
937
938   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
939   /* set immd2 field if required */
940   if (aop->aopu.aop_immd.from_cast_remat)
941   {
942       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
943       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
944   }
945
946   return aop;
947 }
948
949 /*-----------------------------------------------------------------*/
950 /* aopHasRegs - returns true if aop has regs between from-to       */
951 /*-----------------------------------------------------------------*/
952 static int aopHasRegs(asmop *aop, int from, int to)
953 {
954     int size =0;
955
956     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
957
958     for (; size < aop->size ; size++) {
959         int reg;
960         for (reg = from ; reg <= to ; reg++)
961             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
962     }
963     return 0;
964 }
965
966 /*-----------------------------------------------------------------*/
967 /* regsInCommon - two operands have some registers in common       */
968 /*-----------------------------------------------------------------*/
969 static bool
970 regsInCommon (operand * op1, operand * op2)
971 {
972   symbol *sym1, *sym2;
973   int i;
974
975   /* if they have registers in common */
976   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
977     return FALSE;
978
979   sym1 = OP_SYMBOL (op1);
980   sym2 = OP_SYMBOL (op2);
981
982   if (sym1->nRegs == 0 || sym2->nRegs == 0)
983     return FALSE;
984
985   for (i = 0; i < sym1->nRegs; i++)
986     {
987       int j;
988       if (!sym1->regs[i])
989         continue;
990
991       for (j = 0; j < sym2->nRegs; j++)
992         {
993           if (!sym2->regs[j])
994             continue;
995
996           if (sym2->regs[j] == sym1->regs[i])
997             return TRUE;
998         }
999     }
1000
1001   return FALSE;
1002 }
1003
1004 /*-----------------------------------------------------------------*/
1005 /* operandsEqu - equivalent                                        */
1006 /*-----------------------------------------------------------------*/
1007 static bool
1008 operandsEqu (operand * op1, operand * op2)
1009 {
1010   symbol *sym1, *sym2;
1011
1012   /* if they're not symbols */
1013   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1014     return FALSE;
1015
1016   sym1 = OP_SYMBOL (op1);
1017   sym2 = OP_SYMBOL (op2);
1018
1019   /* if both are itemps & one is spilt
1020      and the other is not then false */
1021   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1022       sym1->isspilt != sym2->isspilt)
1023     return FALSE;
1024
1025   /* if they are the same */
1026   if (sym1 == sym2)
1027     return TRUE;
1028
1029   /* if they have the same rname */
1030   if (sym1->rname[0] && sym2->rname[0] &&
1031       strcmp (sym1->rname, sym2->rname) == 0 &&
1032       !(IS_PARM (op2) && IS_ITEMP (op1)))
1033     return TRUE;
1034
1035   /* if left is a tmp & right is not */
1036   if (IS_ITEMP (op1) &&
1037       !IS_ITEMP (op2) &&
1038       sym1->isspilt &&
1039       (sym1->usl.spillLoc == sym2))
1040     return TRUE;
1041
1042   if (IS_ITEMP (op2) &&
1043       !IS_ITEMP (op1) &&
1044       sym2->isspilt &&
1045       sym1->level > 0 &&
1046       (sym2->usl.spillLoc == sym1))
1047     return TRUE;
1048
1049   /* are they spilt to the same location */
1050   if (IS_ITEMP (op2) &&
1051       IS_ITEMP (op1) &&
1052       sym2->isspilt &&
1053       sym1->isspilt &&
1054       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1055     return TRUE;
1056
1057   return FALSE;
1058 }
1059
1060 /*-----------------------------------------------------------------*/
1061 /* sameRegs - two asmops have the same registers                   */
1062 /*-----------------------------------------------------------------*/
1063 static bool
1064 sameRegs (asmop * aop1, asmop * aop2)
1065 {
1066   int i;
1067
1068   if (aop1 == aop2)
1069     {
1070       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1071         {
1072           return FALSE;
1073         }
1074       return TRUE;
1075     }
1076
1077   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1078     return FALSE;
1079
1080   if (aop1->type != aop2->type)
1081     return FALSE;
1082
1083   if (aop1->size != aop2->size)
1084     return FALSE;
1085
1086   for (i = 0; i < aop1->size; i++)
1087     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1088       return FALSE;
1089
1090   return TRUE;
1091 }
1092
1093 /*-----------------------------------------------------------------*/
1094 /* aopOp - allocates an asmop for an operand  :                    */
1095 /*-----------------------------------------------------------------*/
1096 static void
1097 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1098 {
1099   asmop *aop;
1100   symbol *sym;
1101   int i;
1102
1103   if (!op)
1104     return;
1105
1106   /* if this a literal */
1107   if (IS_OP_LITERAL (op))
1108     {
1109       op->aop = aop = newAsmop (AOP_LIT);
1110       aop->aopu.aop_lit = op->operand.valOperand;
1111       aop->size = getSize (operandType (op));
1112       return;
1113     }
1114
1115   /* if already has a asmop then continue */
1116   if (op->aop)
1117     {
1118       if ((op->aop->type == AOP_DPTR && useDP2)
1119           || (op->aop->type == AOP_DPTR2 && !useDP2))
1120         op->aop = NULL;
1121       else
1122         {
1123           op->aop->allocated++;
1124           return;
1125         }
1126     }
1127
1128   /* if the underlying symbol has a aop */
1129   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1130     {
1131       op->aop = OP_SYMBOL (op)->aop;
1132       if ((op->aop->type == AOP_DPTR && useDP2)
1133           || (op->aop->type == AOP_DPTR2 && !useDP2))
1134         op->aop = NULL;
1135       else
1136         {
1137           op->aop->allocated++;
1138           return;
1139         }
1140     }
1141
1142   /* if this is a true symbol */
1143   if (IS_TRUE_SYMOP (op))
1144     {
1145       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1146       return;
1147     }
1148
1149   /* this is a temporary : this has
1150      only five choices :
1151      a) register
1152      b) spillocation
1153      c) rematerialize
1154      d) conditional
1155      e) can be a return use only */
1156
1157   sym = OP_SYMBOL (op);
1158
1159   /* if the type is a conditional */
1160   if (sym->regType == REG_CND)
1161     {
1162       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1163       aop->size = 0;
1164       return;
1165     }
1166
1167   /* if it is spilt then two situations
1168      a) is rematerialize
1169      b) has a spill location */
1170   if (sym->isspilt || sym->nRegs == 0)
1171     {
1172
1173       /* rematerialize it NOW */
1174       if (sym->remat)
1175         {
1176           sym->aop = op->aop = aop =
1177             aopForRemat (sym);
1178           aop->size = getSize (sym->type);
1179           return;
1180         }
1181
1182       if (sym->accuse)
1183         {
1184           int i;
1185           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1186           aop->size = getSize (sym->type);
1187           for (i = 0; i < 2; i++)
1188             aop->aopu.aop_str[i] = accUse[i];
1189           return;
1190         }
1191
1192       if (sym->ruonly)
1193         {
1194           unsigned i;
1195
1196           if (useDP2)
1197             {
1198               /* a AOP_STR uses DPTR, but DPTR is already in use;
1199                * we're just hosed.
1200                */
1201                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1202             }
1203
1204           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1205           aop->size = getSize (sym->type);
1206           for (i = 0; i < fReturnSizeDS390; i++)
1207             aop->aopu.aop_str[i] = fReturn[i];
1208           return;
1209         }
1210
1211       if (sym->dptr) { /* has been allocated to a DPTRn */
1212           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1213           aop->size = getSize (sym->type);
1214           aop->aopu.dptr = sym->dptr;
1215           return ;
1216       }
1217
1218       if (sym->usl.spillLoc)
1219         {
1220           asmop *oldAsmOp = NULL;
1221
1222           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1223             {
1224               /* force a new aop if sizes differ */
1225               oldAsmOp = sym->usl.spillLoc->aop;
1226               sym->usl.spillLoc->aop = NULL;
1227             }
1228           sym->aop = op->aop = aop =
1229                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1230           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1231             {
1232               /* Don't reuse the new aop, go with the last one */
1233               sym->usl.spillLoc->aop = oldAsmOp;
1234             }
1235           aop->size = getSize (sym->type);
1236           return;
1237         }
1238
1239       /* else must be a dummy iTemp */
1240       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1241       aop->size = getSize (sym->type);
1242       return;
1243     }
1244
1245   /* if the type is a bit register */
1246   if (sym->regType == REG_BIT)
1247     {
1248       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1249       aop->size = sym->nRegs;//1???
1250       aop->aopu.aop_reg[0] = sym->regs[0];
1251       aop->aopu.aop_dir = sym->regs[0]->name;
1252       return;
1253     }
1254
1255   /* must be in a register */
1256   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1257   aop->size = sym->nRegs;
1258   for (i = 0; i < sym->nRegs; i++)
1259     aop->aopu.aop_reg[i] = sym->regs[i];
1260 }
1261
1262 /*-----------------------------------------------------------------*/
1263 /* freeAsmop - free up the asmop given to an operand               */
1264 /*----------------------------------------------------------------*/
1265 static void
1266 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1267 {
1268   asmop *aop;
1269
1270   if (!op)
1271     aop = aaop;
1272   else
1273     aop = op->aop;
1274
1275   if (!aop)
1276     return;
1277
1278   aop->allocated--;
1279
1280   if (aop->allocated)
1281     goto dealloc;
1282
1283   /* depending on the asmop type only three cases need work
1284      AOP_R0, AOP_R1 & AOP_STK */
1285   switch (aop->type)
1286     {
1287     case AOP_R0:
1288       if (_G.r0Pushed)
1289         {
1290           if (pop)
1291             {
1292               emitcode ("pop", "ar0");
1293               _G.r0Pushed--;
1294             }
1295         }
1296       bitVectUnSetBit (ic->rUsed, R0_IDX);
1297       break;
1298
1299     case AOP_R1:
1300       if (_G.r1Pushed)
1301         {
1302           if (pop)
1303             {
1304               emitcode ("pop", "ar1");
1305               _G.r1Pushed--;
1306             }
1307         }
1308       bitVectUnSetBit (ic->rUsed, R1_IDX);
1309       break;
1310
1311     case AOP_STK:
1312       {
1313         int sz = aop->size;
1314         int stk = aop->aopu.aop_stk + aop->size;
1315         bitVectUnSetBit (ic->rUsed, R0_IDX);
1316         bitVectUnSetBit (ic->rUsed, R1_IDX);
1317
1318         getFreePtr (ic, &aop, FALSE);
1319
1320         if (options.stack10bit)
1321           {
1322             /* I'm not sure what to do here yet... */
1323             /* #STUB */
1324             fprintf (stderr,
1325                      "*** Warning: probably generating bad code for "
1326                      "10 bit stack mode.\n");
1327           }
1328
1329         if (stk)
1330           {
1331             emitcode ("mov", "a,_bp");
1332             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1333             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1334           }
1335         else
1336           {
1337             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1338           }
1339
1340         while (sz--)
1341           {
1342             emitcode ("pop", "acc");
1343             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1344             if (!sz)
1345               break;
1346             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1347           }
1348         op->aop = aop;
1349         freeAsmop (op, NULL, ic, TRUE);
1350         if (_G.r1Pushed)
1351           {
1352             emitcode ("pop", "ar1");
1353             _G.r1Pushed--;
1354           }
1355         if (_G.r0Pushed)
1356           {
1357             emitcode ("pop", "ar0");
1358             _G.r0Pushed--;
1359           }
1360       }
1361     case AOP_DPTR2:
1362         if (_G.dptr1InUse) {
1363             emitcode ("pop","dpx1");
1364             emitcode ("pop","dph1");
1365             emitcode ("pop","dpl1");
1366         }
1367         break;
1368     case AOP_DPTR:
1369         if (_G.dptrInUse) {
1370             emitcode ("pop","dpx");
1371             emitcode ("pop","dph");
1372             emitcode ("pop","dpl");
1373         }
1374         break;
1375     }
1376
1377 dealloc:
1378   /* all other cases just dealloc */
1379   if (op)
1380     {
1381       op->aop = NULL;
1382       if (IS_SYMOP (op))
1383         {
1384           OP_SYMBOL (op)->aop = NULL;
1385           /* if the symbol has a spill */
1386           if (SPIL_LOC (op))
1387             SPIL_LOC (op)->aop = NULL;
1388         }
1389     }
1390 }
1391
1392 #define DEFAULT_ACC_WARNING 0
1393 static int saveAccWarn = DEFAULT_ACC_WARNING;
1394
1395
1396 /*-----------------------------------------------------------------*/
1397 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1398 /*                 clobber the accumulator                         */
1399 /*-----------------------------------------------------------------*/
1400 static bool
1401 aopGetUsesAcc (operand * oper, int offset)
1402 {
1403   asmop * aop = AOP (oper);
1404
1405   if (offset > (aop->size - 1))
1406     return FALSE;
1407
1408   switch (aop->type)
1409     {
1410
1411     case AOP_R0:
1412     case AOP_R1:
1413       if (aop->paged)
1414         return TRUE;
1415       return FALSE;
1416     case AOP_DPTR:
1417     case AOP_DPTR2:
1418     case AOP_DPTRn:
1419       return TRUE;
1420     case AOP_IMMD:
1421       return FALSE;
1422     case AOP_DIR:
1423       return FALSE;
1424     case AOP_REG:
1425       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1426       return FALSE;
1427     case AOP_CRY:
1428       return TRUE;
1429     case AOP_ACC:
1430       if (offset)
1431         return FALSE;
1432       return TRUE;
1433     case AOP_LIT:
1434       return FALSE;
1435     case AOP_STR:
1436       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1437         return TRUE;
1438       return FALSE;
1439     case AOP_DUMMY:
1440       return FALSE;
1441     default:
1442       /* Error case --- will have been caught already */
1443       wassert(0);
1444       return FALSE;
1445     }
1446 }
1447
1448 /*-------------------------------------------------------------------*/
1449 /* aopGet - for fetching value of the aop                            */
1450 /*                                                                   */
1451 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1452 /* in the accumulator. Set it to the name of a free register         */
1453 /* if acc must be preserved; the register will be used to preserve   */
1454 /* acc temporarily and to return the result byte.                    */
1455 /*-------------------------------------------------------------------*/
1456 static char *
1457 aopGet (operand * oper,
1458         int   offset,
1459         bool  bit16,
1460         bool  dname,
1461         char  *saveAcc)
1462 {
1463   asmop * aop = AOP (oper);
1464
1465   /* offset is greater than
1466      size then zero */
1467   if (offset > (aop->size - 1) &&
1468       aop->type != AOP_LIT)
1469     return zero;
1470
1471   /* depending on type */
1472   switch (aop->type)
1473     {
1474     case AOP_DUMMY:
1475       return zero;
1476
1477     case AOP_R0:
1478     case AOP_R1:
1479       /* if we need to increment it */
1480       while (offset > aop->coff)
1481         {
1482           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1483           aop->coff++;
1484         }
1485
1486       while (offset < aop->coff)
1487         {
1488           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1489           aop->coff--;
1490         }
1491
1492       aop->coff = offset;
1493       if (aop->paged)
1494         {
1495           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1496           return (dname ? "acc" : "a");
1497         }
1498       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1499       return Safe_strdup(buffer);
1500
1501     case AOP_DPTRn:
1502         assert(offset <= 3);
1503         return dptrn[aop->aopu.dptr][offset];
1504
1505     case AOP_DPTR:
1506     case AOP_DPTR2:
1507
1508       if (aop->type == AOP_DPTR2)
1509         {
1510           genSetDPTR (1);
1511         }
1512
1513       if (saveAcc)
1514         {
1515             TR_AP("#1");
1516 //          if (aop->type != AOP_DPTR2)
1517 //          {
1518 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1519 //              emitcode(";", "spanky: saveAcc for DPTR");
1520 //          }
1521
1522             emitcode ("xch", "a, %s", saveAcc);
1523         }
1524
1525       _flushLazyDPS ();
1526
1527       while (offset > aop->coff)
1528         {
1529           emitcode ("inc", "dptr");
1530           aop->coff++;
1531         }
1532
1533       while (offset < aop->coff)
1534         {
1535           emitcode ("lcall", "__decdptr");
1536           aop->coff--;
1537         }
1538
1539       aop->coff = offset;
1540       if (aop->code)
1541         {
1542           emitcode ("clr", "a");
1543           emitcode ("movc", "a,@a+dptr");
1544         }
1545       else
1546         {
1547           emitcode ("movx", "a,@dptr");
1548         }
1549
1550       if (aop->type == AOP_DPTR2)
1551         {
1552           genSetDPTR (0);
1553         }
1554
1555       if (saveAcc)
1556         {
1557           TR_AP("#2");
1558           emitcode ("xch", "a, %s", saveAcc);
1559 //        if (strcmp(saveAcc, "_ap"))
1560 //          {
1561 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1562 //          }
1563
1564           return saveAcc;
1565         }
1566       return (dname ? "acc" : "a");
1567
1568     case AOP_IMMD:
1569       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1570         {
1571           SNPRINTF(buffer, sizeof(buffer),
1572                    "%s",aop->aopu.aop_immd.aop_immd2);
1573         }
1574       else if (bit16)
1575         {
1576           SNPRINTF(buffer, sizeof(buffer),
1577                    "#%s", aop->aopu.aop_immd.aop_immd1);
1578         }
1579       else if (offset)
1580         {
1581           switch (offset) {
1582           case 1:
1583               tsprintf(buffer, sizeof(buffer),
1584                        "#!his",aop->aopu.aop_immd.aop_immd1);
1585               break;
1586           case 2:
1587               tsprintf(buffer, sizeof(buffer),
1588                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1589               break;
1590           case 3:
1591               tsprintf(buffer, sizeof(buffer),
1592                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1593               break;
1594           default: /* should not need this (just in case) */
1595               SNPRINTF (buffer, sizeof(buffer),
1596                         "#(%s >> %d)",
1597                        aop->aopu.aop_immd.aop_immd1,
1598                        offset * 8);
1599           }
1600         }
1601       else
1602         {
1603           SNPRINTF (buffer, sizeof(buffer),
1604                     "#%s",
1605                     aop->aopu.aop_immd.aop_immd1);
1606         }
1607       return Safe_strdup(buffer);
1608
1609     case AOP_DIR:
1610       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1611         {
1612           SNPRINTF (buffer, sizeof(buffer),
1613                     "(%s >> %d)",
1614                     aop->aopu.aop_dir, offset * 8);
1615         }
1616       else if (offset)
1617         {
1618           SNPRINTF (buffer, sizeof(buffer),
1619                     "(%s + %d)",
1620                    aop->aopu.aop_dir,
1621                    offset);
1622         }
1623       else
1624         {
1625           SNPRINTF (buffer, sizeof(buffer),
1626                     "%s",
1627                     aop->aopu.aop_dir);
1628         }
1629
1630       return Safe_strdup(buffer);
1631
1632     case AOP_REG:
1633       if (dname)
1634         return aop->aopu.aop_reg[offset]->dname;
1635       else
1636         return aop->aopu.aop_reg[offset]->name;
1637
1638     case AOP_CRY:
1639       emitcode ("clr", "a");
1640       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1641       emitcode ("rlc", "a");
1642       return (dname ? "acc" : "a");
1643
1644     case AOP_ACC:
1645       if (!offset && dname)
1646         return "acc";
1647       return aop->aopu.aop_str[offset];
1648
1649     case AOP_LIT:
1650       return aopLiteral (aop->aopu.aop_lit, offset);
1651
1652     case AOP_STR:
1653       aop->coff = offset;
1654       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1655           dname)
1656         return "acc";
1657
1658       return aop->aopu.aop_str[offset];
1659
1660     }
1661
1662   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1663           "aopget got unsupported aop->type");
1664   exit (1);
1665
1666   return NULL;  // not reached, but makes compiler happy.
1667 }
1668
1669 /*-----------------------------------------------------------------*/
1670 /* aopPut - puts a string for a aop and indicates if acc is in use */
1671 /*-----------------------------------------------------------------*/
1672 static bool
1673 aopPut (operand * result, const char *s, int offset)
1674 {
1675   bool bvolatile = isOperandVolatile (result, FALSE);
1676   bool accuse = FALSE;
1677   asmop * aop = AOP (result);
1678
1679   if (aop->size && offset > (aop->size - 1))
1680     {
1681       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1682               "aopPut got offset > aop->size");
1683       exit (1);
1684     }
1685
1686   /* will assign value to value */
1687   /* depending on where it is ofcourse */
1688   switch (aop->type)
1689     {
1690     case AOP_DUMMY:
1691       MOVA (s);         /* read s in case it was volatile */
1692       accuse = TRUE;
1693       break;
1694
1695     case AOP_DIR:
1696       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1697         {
1698           SNPRINTF (buffer, sizeof(buffer),
1699                     "(%s >> %d)",
1700                     aop->aopu.aop_dir, offset * 8);
1701         }
1702       else if (offset)
1703         {
1704           SNPRINTF (buffer, sizeof(buffer),
1705                     "(%s + %d)",
1706                     aop->aopu.aop_dir, offset);
1707         }
1708       else
1709         {
1710           SNPRINTF (buffer, sizeof(buffer),
1711                     "%s",
1712                     aop->aopu.aop_dir);
1713         }
1714
1715       if (strcmp (buffer, s) || bvolatile)
1716         {
1717           emitcode ("mov", "%s,%s", buffer, s);
1718         }
1719       if (!strcmp (buffer, "acc"))
1720         {
1721           accuse = TRUE;
1722         }
1723       break;
1724
1725     case AOP_REG:
1726       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1727           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1728         {
1729           if (*s == '@' ||
1730               strcmp (s, "r0") == 0 ||
1731               strcmp (s, "r1") == 0 ||
1732               strcmp (s, "r2") == 0 ||
1733               strcmp (s, "r3") == 0 ||
1734               strcmp (s, "r4") == 0 ||
1735               strcmp (s, "r5") == 0 ||
1736               strcmp (s, "r6") == 0 ||
1737               strcmp (s, "r7") == 0)
1738             {
1739               emitcode ("mov", "%s,%s",
1740                         aop->aopu.aop_reg[offset]->dname, s);
1741             }
1742             else
1743             {
1744               emitcode ("mov", "%s,%s",
1745                         aop->aopu.aop_reg[offset]->name, s);
1746             }
1747         }
1748       break;
1749
1750     case AOP_DPTRn:
1751         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1752         break;
1753
1754     case AOP_DPTR:
1755     case AOP_DPTR2:
1756
1757       if (aop->type == AOP_DPTR2)
1758         {
1759           genSetDPTR (1);
1760         }
1761       _flushLazyDPS ();
1762
1763       if (aop->code)
1764         {
1765           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1766                   "aopPut writing to code space");
1767           exit (1);
1768         }
1769
1770       while (offset > aop->coff)
1771         {
1772           aop->coff++;
1773           emitcode ("inc", "dptr");
1774         }
1775
1776       while (offset < aop->coff)
1777         {
1778           aop->coff--;
1779           emitcode ("lcall", "__decdptr");
1780         }
1781
1782       aop->coff = offset;
1783
1784       /* if not in accumulator */
1785       MOVA (s);
1786
1787       emitcode ("movx", "@dptr,a");
1788
1789       if (aop->type == AOP_DPTR2)
1790         {
1791           genSetDPTR (0);
1792         }
1793       break;
1794
1795     case AOP_R0:
1796     case AOP_R1:
1797       while (offset > aop->coff)
1798         {
1799           aop->coff++;
1800           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1801         }
1802       while (offset < aop->coff)
1803         {
1804           aop->coff--;
1805           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1806         }
1807       aop->coff = offset;
1808
1809       if (aop->paged)
1810         {
1811           MOVA (s);
1812           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1813         }
1814       else if (*s == '@')
1815         {
1816           MOVA (s);
1817           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1818         }
1819       else if (strcmp (s, "r0") == 0 ||
1820                strcmp (s, "r1") == 0 ||
1821                strcmp (s, "r2") == 0 ||
1822                strcmp (s, "r3") == 0 ||
1823                strcmp (s, "r4") == 0 ||
1824                strcmp (s, "r5") == 0 ||
1825                strcmp (s, "r6") == 0 ||
1826                strcmp (s, "r7") == 0)
1827         {
1828           char buffer[10];
1829           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1830           emitcode ("mov", "@%s,%s",
1831                     aop->aopu.aop_ptr->name, buffer);
1832         }
1833         else
1834         {
1835             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1836         }
1837       break;
1838
1839     case AOP_STK:
1840       if (strcmp (s, "a") == 0)
1841         emitcode ("push", "acc");
1842       else
1843         if (*s=='@') {
1844           MOVA(s);
1845           emitcode ("push", "acc");
1846         } else {
1847           emitcode ("push", s);
1848         }
1849
1850       break;
1851
1852     case AOP_CRY:
1853       /* if not bit variable */
1854       if (!aop->aopu.aop_dir)
1855         {
1856           /* inefficient: move carry into A and use jz/jnz */
1857           emitcode ("clr", "a");
1858           emitcode ("rlc", "a");
1859           accuse = TRUE;
1860         }
1861       else
1862         {
1863           if (s == zero)
1864             emitcode ("clr", "%s", aop->aopu.aop_dir);
1865           else if (s == one)
1866             emitcode ("setb", "%s", aop->aopu.aop_dir);
1867           else if (!strcmp (s, "c"))
1868             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1869           else if (strcmp (s, aop->aopu.aop_dir))
1870             {
1871               MOVA (s);
1872               /* set C, if a >= 1 */
1873               emitcode ("add", "a,#!constbyte",0xff);
1874               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1875             }
1876         }
1877       break;
1878
1879     case AOP_STR:
1880       aop->coff = offset;
1881       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1882         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1883       break;
1884
1885     case AOP_ACC:
1886       accuse = TRUE;
1887       aop->coff = offset;
1888       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1889         break;
1890
1891       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1892         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1893       break;
1894
1895     default:
1896       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1897               "aopPut got unsupported aop->type");
1898       exit (1);
1899     }
1900
1901     return accuse;
1902 }
1903
1904
1905 /*--------------------------------------------------------------------*/
1906 /* reAdjustPreg - points a register back to where it should (coff==0) */
1907 /*--------------------------------------------------------------------*/
1908 static void
1909 reAdjustPreg (asmop * aop)
1910 {
1911   if ((aop->coff==0) || (aop->size <= 1))
1912     return;
1913
1914   switch (aop->type)
1915     {
1916     case AOP_R0:
1917     case AOP_R1:
1918       while (aop->coff--)
1919         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1920       break;
1921     case AOP_DPTR:
1922     case AOP_DPTR2:
1923       if (aop->type == AOP_DPTR2)
1924         {
1925           genSetDPTR (1);
1926           _flushLazyDPS ();
1927         }
1928       while (aop->coff--)
1929         {
1930           emitcode ("lcall", "__decdptr");
1931         }
1932
1933       if (aop->type == AOP_DPTR2)
1934         {
1935           genSetDPTR (0);
1936         }
1937       break;
1938     }
1939   aop->coff = 0;
1940 }
1941
1942 /*-----------------------------------------------------------------*/
1943 /* opIsGptr: returns non-zero if the passed operand is       */
1944 /* a generic pointer type.             */
1945 /*-----------------------------------------------------------------*/
1946 static int
1947 opIsGptr (operand * op)
1948 {
1949   sym_link *type = operandType (op);
1950
1951   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1952     {
1953       return 1;
1954     }
1955   return 0;
1956 }
1957
1958 /*-----------------------------------------------------------------*/
1959 /* getDataSize - get the operand data size                         */
1960 /*-----------------------------------------------------------------*/
1961 static int
1962 getDataSize (operand * op)
1963 {
1964   int size;
1965   size = AOP_SIZE (op);
1966   if (size == GPTRSIZE)
1967     {
1968       sym_link *type = operandType (op);
1969       if (IS_GENPTR (type))
1970         {
1971           /* generic pointer; arithmetic operations
1972            * should ignore the high byte (pointer type).
1973            */
1974           size--;
1975         }
1976     }
1977   return size;
1978 }
1979
1980 /*-----------------------------------------------------------------*/
1981 /* outAcc - output Acc                                             */
1982 /*-----------------------------------------------------------------*/
1983 static void
1984 outAcc (operand * result)
1985 {
1986   int size, offset;
1987   size = getDataSize (result);
1988   if (size)
1989     {
1990       aopPut (result, "a", 0);
1991       size--;
1992       offset = 1;
1993       /* unsigned or positive */
1994       while (size--)
1995         {
1996           aopPut (result, zero, offset++);
1997         }
1998     }
1999 }
2000
2001 /*-----------------------------------------------------------------*/
2002 /* outBitC - output a bit C                                        */
2003 /*-----------------------------------------------------------------*/
2004 static void
2005 outBitC (operand * result)
2006 {
2007   /* if the result is bit */
2008   if (AOP_TYPE (result) == AOP_CRY)
2009     {
2010       aopPut (result, "c", 0);
2011     }
2012   else
2013     {
2014       emitcode ("clr", "a");
2015       emitcode ("rlc", "a");
2016       outAcc (result);
2017     }
2018 }
2019
2020 /*-----------------------------------------------------------------*/
2021 /* toBoolean - emit code for orl a,operator(sizeop)                */
2022 /*-----------------------------------------------------------------*/
2023 static void
2024 toBoolean (operand * oper)
2025 {
2026   int  size = AOP_SIZE (oper) - 1;
2027   int  offset = 1;
2028   bool pushedB;
2029
2030   /* The generic part of a generic pointer should
2031    * not participate in it's truth value.
2032    *
2033    * i.e. 0x10000000 is zero.
2034    */
2035   if (opIsGptr (oper))
2036     {
2037       D (emitcode (";", "toBoolean: generic ptr special case."));
2038       size--;
2039     }
2040
2041   _startLazyDPSEvaluation ();
2042   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2043   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2044     {
2045       pushedB = pushB ();
2046       emitcode("mov", "b,a");
2047       while (--size)
2048         {
2049           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2050           emitcode ("orl", "b,a");
2051         }
2052       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2053       emitcode ("orl", "a,b");
2054       popB (pushedB);
2055     }
2056   else
2057     {
2058       while (size--)
2059         {
2060           emitcode ("orl", "a,%s",
2061                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2062         }
2063     }
2064   _endLazyDPSEvaluation ();
2065 }
2066
2067
2068 /*-----------------------------------------------------------------*/
2069 /* genNot - generate code for ! operation                          */
2070 /*-----------------------------------------------------------------*/
2071 static void
2072 genNot (iCode * ic)
2073 {
2074   symbol *tlbl;
2075
2076   D (emitcode (";", "genNot"));
2077
2078   /* assign asmOps to operand & result */
2079   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2080   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2081
2082   /* if in bit space then a special case */
2083   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2084     {
2085       /* if left==result then cpl bit */
2086       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2087         {
2088           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2089         }
2090       else
2091         {
2092           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2093           emitcode ("cpl", "c");
2094           outBitC (IC_RESULT (ic));
2095         }
2096       goto release;
2097     }
2098
2099   toBoolean (IC_LEFT (ic));
2100
2101   /* set C, if a == 0 */
2102   tlbl = newiTempLabel (NULL);
2103   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2104   emitLabel (tlbl);
2105   outBitC (IC_RESULT (ic));
2106
2107 release:
2108   /* release the aops */
2109   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2110   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2111 }
2112
2113
2114 /*-----------------------------------------------------------------*/
2115 /* genCpl - generate code for complement                           */
2116 /*-----------------------------------------------------------------*/
2117 static void
2118 genCpl (iCode * ic)
2119 {
2120   int offset = 0;
2121   int size;
2122   symbol *tlbl;
2123   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2124
2125   D(emitcode (";", "genCpl"));
2126
2127   /* assign asmOps to operand & result */
2128   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2129   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2130
2131   /* special case if in bit space */
2132   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2133     {
2134       char *l;
2135
2136       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2137           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2138         {
2139           /* promotion rules are responsible for this strange result:
2140              bit -> int -> ~int -> bit
2141              uchar -> int -> ~int -> bit
2142           */
2143           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2144           goto release;
2145         }
2146
2147       tlbl=newiTempLabel(NULL);
2148       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2149       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2150           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2151           IS_AOP_PREG (IC_LEFT (ic)))
2152         {
2153           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2154         }
2155       else
2156         {
2157           MOVA (l);
2158           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2159         }
2160       emitLabel (tlbl);
2161       outBitC (IC_RESULT(ic));
2162       goto release;
2163     }
2164
2165   size = AOP_SIZE (IC_RESULT (ic));
2166   _startLazyDPSEvaluation ();
2167   while (size--)
2168     {
2169       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2170       MOVA (l);
2171       emitcode ("cpl", "a");
2172       aopPut (IC_RESULT (ic), "a", offset++);
2173     }
2174   _endLazyDPSEvaluation ();
2175
2176
2177 release:
2178   /* release the aops */
2179   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2180   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2181 }
2182
2183 /*-----------------------------------------------------------------*/
2184 /* genUminusFloat - unary minus for floating points                */
2185 /*-----------------------------------------------------------------*/
2186 static void
2187 genUminusFloat (operand * op, operand * result)
2188 {
2189   int size, offset = 0;
2190   char *l;
2191
2192   D (emitcode (";", "genUminusFloat"));
2193
2194   /* for this we just copy and then flip the bit */
2195
2196   _startLazyDPSEvaluation ();
2197   size = AOP_SIZE (op) - 1;
2198
2199   while (size--)
2200     {
2201       aopPut (result,
2202               aopGet (op, offset, FALSE, FALSE, NULL),
2203               offset);
2204       offset++;
2205     }
2206
2207   l = aopGet (op, offset, FALSE, FALSE, NULL);
2208   MOVA (l);
2209
2210   emitcode ("cpl", "acc.7");
2211   aopPut (result, "a", offset);
2212   _endLazyDPSEvaluation ();
2213 }
2214
2215 /*-----------------------------------------------------------------*/
2216 /* genUminus - unary minus code generation                         */
2217 /*-----------------------------------------------------------------*/
2218 static void
2219 genUminus (iCode * ic)
2220 {
2221   int offset, size;
2222   sym_link *optype;
2223
2224   D (emitcode (";", "genUminus"));
2225
2226   /* assign asmops */
2227   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2228   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2229
2230   /* if both in bit space then special
2231      case */
2232   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2233       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2234     {
2235
2236       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2237       emitcode ("cpl", "c");
2238       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2239       goto release;
2240     }
2241
2242   optype = operandType (IC_LEFT (ic));
2243
2244   /* if float then do float stuff */
2245   if (IS_FLOAT (optype))
2246     {
2247       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2248       goto release;
2249     }
2250
2251   /* otherwise subtract from zero */
2252   size = AOP_SIZE (IC_LEFT (ic));
2253   offset = 0;
2254   _startLazyDPSEvaluation ();
2255   while (size--)
2256     {
2257       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2258       if (!strcmp (l, "a"))
2259         {
2260           if (offset == 0)
2261             SETC;
2262           emitcode ("cpl", "a");
2263           emitcode ("addc", "a,#0");
2264         }
2265       else
2266         {
2267           if (offset == 0)
2268             CLRC;
2269           emitcode ("clr", "a");
2270           emitcode ("subb", "a,%s", l);
2271         }
2272       aopPut (IC_RESULT (ic), "a", offset++);
2273     }
2274   _endLazyDPSEvaluation ();
2275
2276   /* if any remaining bytes in the result */
2277   /* we just need to propagate the sign   */
2278   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2279     {
2280       emitcode ("rlc", "a");
2281       emitcode ("subb", "a,acc");
2282       while (size--)
2283         aopPut (IC_RESULT (ic), "a", offset++);
2284     }
2285
2286 release:
2287   /* release the aops */
2288   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2289   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2290 }
2291
2292 /*-----------------------------------------------------------------*/
2293 /* savermask - saves registers in the mask                         */
2294 /*-----------------------------------------------------------------*/
2295 static void savermask(bitVect *rs_mask)
2296 {
2297   int i;
2298
2299   if (options.useXstack)
2300     {
2301       if (bitVectBitValue (rs_mask, R0_IDX))
2302           emitcode ("mov", "b,r0");
2303       emitcode ("mov", "r0,%s", spname);
2304       for (i = 0; i < ds390_nRegs; i++)
2305         {
2306           if (bitVectBitValue (rs_mask, i))
2307             {
2308               if (i == R0_IDX)
2309                   emitcode ("mov", "a,b");
2310               else
2311                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2312               emitcode ("movx", "@r0,a");
2313               emitcode ("inc", "r0");
2314             }
2315         }
2316       emitcode ("mov", "%s,r0", spname);
2317       if (bitVectBitValue (rs_mask, R0_IDX))
2318           emitcode ("mov", "r0,b");
2319     }
2320   else
2321     {
2322       bool bits_pushed = FALSE;
2323       for (i = 0; i < ds390_nRegs; i++)
2324         {
2325           if (bitVectBitValue (rs_mask, i))
2326             {
2327               bits_pushed = pushReg (i, bits_pushed);
2328             }
2329         }
2330     }
2331 }
2332
2333 /*-----------------------------------------------------------------*/
2334 /* saveRegisters - will look for a call and save the registers     */
2335 /*-----------------------------------------------------------------*/
2336 static void
2337 saveRegisters (iCode * lic)
2338 {
2339   iCode *ic;
2340   bitVect *rsave;
2341
2342   /* look for call */
2343   for (ic = lic; ic; ic = ic->next)
2344     if (ic->op == CALL || ic->op == PCALL)
2345       break;
2346
2347   if (!ic)
2348     {
2349       fprintf (stderr, "found parameter push with no function call\n");
2350       return;
2351     }
2352
2353   /* if the registers have been saved already or don't need to be then
2354      do nothing */
2355   if (ic->regsSaved
2356       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2357     return;
2358
2359   /* special case if DPTR alive across a function call then must save it
2360      even though callee saves */
2361   if (IS_SYMOP(IC_LEFT(ic)) &&
2362       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2363     {
2364       int i;
2365       rsave = newBitVect(ic->rMask->size);
2366       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2367           if (bitVectBitValue(ic->rMask,i))
2368               rsave = bitVectSetBit(rsave,i);
2369       }
2370       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2371     }
2372   else
2373     {
2374       /* save the registers in use at this time but skip the
2375          ones for the result */
2376       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2377                              ds390_rUmaskForOp (IC_RESULT(ic)));
2378     }
2379   ic->regsSaved = 1;
2380   savermask(rsave);
2381 }
2382
2383 /*-----------------------------------------------------------------*/
2384 /* usavermask - restore registers with mask                        */
2385 /*-----------------------------------------------------------------*/
2386 static void unsavermask(bitVect *rs_mask)
2387 {
2388   int i;
2389
2390   if (options.useXstack)
2391     {
2392       emitcode ("mov", "r0,%s", spname);
2393       for (i = ds390_nRegs; i >= 0; i--)
2394         {
2395           if (bitVectBitValue (rs_mask, i))
2396             {
2397               regs * reg = REG_WITH_INDEX (i);
2398               emitcode ("dec", "r0");
2399               emitcode ("movx", "a,@r0");
2400               if (i == R0_IDX)
2401                 {
2402                   emitcode ("push", "acc");
2403                 }
2404               else
2405                 {
2406                   emitcode ("mov", "%s,a", reg->name);
2407                 }
2408             }
2409         }
2410       emitcode ("mov", "%s,r0", spname);
2411       if (bitVectBitValue (rs_mask, R0_IDX))
2412         {
2413           emitcode ("pop", "ar0");
2414         }
2415     }
2416   else
2417     {
2418       bool bits_popped = FALSE;
2419       for (i = ds390_nRegs; i >= 0; i--)
2420         {
2421           if (bitVectBitValue (rs_mask, i))
2422             {
2423               bits_popped = popReg (i, bits_popped);
2424             }
2425         }
2426     }
2427 }
2428
2429 /*-----------------------------------------------------------------*/
2430 /* unsaveRegisters - pop the pushed registers                      */
2431 /*-----------------------------------------------------------------*/
2432 static void
2433 unsaveRegisters (iCode * ic)
2434 {
2435   bitVect *rsave;
2436
2437   if (IS_SYMOP(IC_LEFT (ic)) &&
2438       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2439       int i;
2440       rsave = newBitVect(ic->rMask->size);
2441       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2442           if (bitVectBitValue(ic->rMask,i))
2443               rsave = bitVectSetBit(rsave,i);
2444       }
2445       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2446   } else {
2447     /* restore the registers in use at this time but skip the
2448        ones for the result */
2449     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2450                            ds390_rUmaskForOp (IC_RESULT(ic)));
2451   }
2452   unsavermask(rsave);
2453 }
2454
2455
2456 /*-----------------------------------------------------------------*/
2457 /* pushSide -                */
2458 /*-----------------------------------------------------------------*/
2459 static void
2460 pushSide (operand * oper, int size)
2461 {
2462   int offset = 0;
2463   _startLazyDPSEvaluation ();
2464   while (size--)
2465     {
2466       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2467       if (AOP_TYPE (oper) != AOP_REG &&
2468           AOP_TYPE (oper) != AOP_DIR &&
2469           strcmp (l, "a"))
2470         {
2471           MOVA (l);
2472           emitcode ("push", "acc");
2473         }
2474       else
2475         {
2476           emitcode ("push", "%s", l);
2477         }
2478     }
2479   _endLazyDPSEvaluation ();
2480 }
2481
2482 /*-----------------------------------------------------------------*/
2483 /* assignResultValue - also indicates if acc is in use afterwards  */
2484 /*-----------------------------------------------------------------*/
2485 static bool
2486 assignResultValue (operand * oper, operand * func)
2487 {
2488   int offset = 0;
2489   unsigned size = AOP_SIZE (oper);
2490   bool accuse = FALSE;
2491   bool pushedA = FALSE;
2492
2493   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2494     {
2495       outBitC (oper);
2496       return FALSE;
2497     }
2498
2499   if (size == fReturnSizeDS390)
2500   {
2501       /* I don't think this case can ever happen... */
2502       /* ACC is the last part of this. If writing the result
2503        * uses ACC, we must preserve it.
2504        */
2505       if (AOP_NEEDSACC(oper))
2506       {
2507           emitcode(";", "assignResultValue special case for ACC.");
2508           emitcode("push", "acc");
2509           pushedA = TRUE;
2510           size--;
2511       }
2512   }
2513
2514   _startLazyDPSEvaluation ();
2515   while (size--)
2516     {
2517       accuse |= aopPut (oper, fReturn[offset], offset);
2518       offset++;
2519     }
2520   _endLazyDPSEvaluation ();
2521
2522   if (pushedA)
2523     {
2524         emitcode ("pop", "acc");
2525         accuse |= aopPut (oper, "a", offset);
2526     }
2527   return accuse;
2528 }
2529
2530
2531 /*-----------------------------------------------------------------*/
2532 /* genXpush - pushes onto the external stack                       */
2533 /*-----------------------------------------------------------------*/
2534 static void
2535 genXpush (iCode * ic)
2536 {
2537   asmop *aop = newAsmop (0);
2538   regs *r;
2539   int size, offset = 0;
2540
2541   D (emitcode (";", "genXpush"));
2542
2543   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2544   r = getFreePtr (ic, &aop, FALSE);
2545
2546   size = AOP_SIZE (IC_LEFT (ic));
2547
2548   if (size == 1)
2549     {
2550       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2551       emitcode ("mov", "%s,_spx", r->name);
2552       emitcode ("inc", "_spx"); // allocate space first
2553       emitcode ("movx", "@%s,a", r->name);
2554     }
2555   else
2556     {
2557       // allocate space first
2558       emitcode ("mov", "%s,_spx", r->name);
2559       MOVA (r->name);
2560       emitcode ("add", "a,#%d", size);
2561       emitcode ("mov", "_spx,a");
2562
2563       _startLazyDPSEvaluation ();
2564       while (size--)
2565         {
2566           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2567           emitcode ("movx", "@%s,a", r->name);
2568           emitcode ("inc", "%s", r->name);
2569         }
2570       _endLazyDPSEvaluation ();
2571     }
2572
2573   freeAsmop (NULL, aop, ic, TRUE);
2574   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2575 }
2576
2577 /*-----------------------------------------------------------------*/
2578 /* genIpush - generate code for pushing this gets a little complex  */
2579 /*-----------------------------------------------------------------*/
2580 static void
2581 genIpush (iCode * ic)
2582 {
2583   int size, offset = 0;
2584   char *l;
2585   char *prev = "";
2586
2587   D (emitcode (";", "genIpush"));
2588
2589   /* if this is not a parm push : ie. it is spill push
2590      and spill push is always done on the local stack */
2591   if (!ic->parmPush)
2592     {
2593
2594       /* and the item is spilt then do nothing */
2595       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2596         return;
2597
2598       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2599       size = AOP_SIZE (IC_LEFT (ic));
2600       /* push it on the stack */
2601       _startLazyDPSEvaluation ();
2602       while (size--)
2603         {
2604           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2605           if (*l == '#')
2606             {
2607               MOVA (l);
2608               l = "acc";
2609             }
2610           emitcode ("push", "%s", l);
2611         }
2612       _endLazyDPSEvaluation ();
2613       return;
2614     }
2615
2616   /* this is a parameter push: in this case we call
2617      the routine to find the call and save those
2618      registers that need to be saved */
2619   saveRegisters (ic);
2620
2621   /* if use external stack then call the external
2622      stack pushing routine */
2623   if (options.useXstack)
2624     {
2625       genXpush (ic);
2626       return;
2627     }
2628
2629   /* then do the push */
2630   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2631
2632   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2633   size = AOP_SIZE (IC_LEFT (ic));
2634
2635   _startLazyDPSEvaluation ();
2636   while (size--)
2637     {
2638       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2639       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2640           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2641           strcmp (l, "acc"))
2642         {
2643           if (strcmp (l, prev) || *l == '@')
2644             MOVA (l);
2645           emitcode ("push", "acc");
2646         }
2647       else
2648         {
2649             emitcode ("push", "%s", l);
2650         }
2651       prev = l;
2652     }
2653   _endLazyDPSEvaluation ();
2654
2655   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2656 }
2657
2658 /*-----------------------------------------------------------------*/
2659 /* genIpop - recover the registers: can happen only for spilling   */
2660 /*-----------------------------------------------------------------*/
2661 static void
2662 genIpop (iCode * ic)
2663 {
2664   int size, offset;
2665
2666   D (emitcode (";", "genIpop"));
2667
2668   /* if the temp was not pushed then */
2669   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2670     return;
2671
2672   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2673   size = AOP_SIZE (IC_LEFT (ic));
2674   offset = (size - 1);
2675   _startLazyDPSEvaluation ();
2676   while (size--)
2677     {
2678       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2679                                      FALSE, TRUE, NULL));
2680     }
2681   _endLazyDPSEvaluation ();
2682
2683   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2684 }
2685
2686 /*-----------------------------------------------------------------*/
2687 /* saveRBank - saves an entire register bank on the stack          */
2688 /*-----------------------------------------------------------------*/
2689 static void
2690 saveRBank (int bank, iCode * ic, bool pushPsw)
2691 {
2692   int i;
2693   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2694   asmop *aop = NULL;
2695   regs *r = NULL;
2696
2697   if (options.useXstack)
2698     {
2699       if (!ic)
2700         {
2701           /* Assume r0 is available for use. */
2702           r = REG_WITH_INDEX (R0_IDX);;
2703         }
2704       else
2705         {
2706           aop = newAsmop (0);
2707           r = getFreePtr (ic, &aop, FALSE);
2708         }
2709       // allocate space first
2710       emitcode ("mov", "%s,_spx", r->name);
2711       MOVA (r->name);
2712       emitcode ("add", "a,#%d", count);
2713       emitcode ("mov", "_spx,a");
2714     }
2715
2716   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2717     {
2718       if (options.useXstack)
2719         {
2720           emitcode ("mov", "a,(%s+%d)",
2721                     regs390[i].base, 8 * bank + regs390[i].offset);
2722           emitcode ("movx", "@%s,a", r->name);
2723           if (--count)
2724             emitcode ("inc", "%s", r->name);
2725         }
2726       else
2727         emitcode ("push", "(%s+%d)",
2728                   regs390[i].base, 8 * bank + regs390[i].offset);
2729     }
2730
2731   if (ds390_nBitRegs > 0)
2732     {
2733       if (options.useXstack)
2734         {
2735           emitcode ("mov", "a,bits");
2736           emitcode ("movx", "@%s,a", r->name);
2737           if (--count)
2738             emitcode ("inc", "%s", r->name);
2739         }
2740       else
2741         {
2742           emitcode ("push", "bits");
2743         }
2744       BitBankUsed = 1;
2745     }
2746
2747   if (pushPsw)
2748     {
2749       if (options.useXstack)
2750         {
2751           emitcode ("mov", "a,psw");
2752           emitcode ("movx", "@%s,a", r->name);
2753         }
2754       else
2755       {
2756         emitcode ("push", "psw");
2757       }
2758
2759       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2760     }
2761
2762   if (aop)
2763     {
2764       freeAsmop (NULL, aop, ic, TRUE);
2765     }
2766
2767   if (ic)
2768   {
2769     ic->bankSaved = 1;
2770   }
2771 }
2772
2773 /*-----------------------------------------------------------------*/
2774 /* unsaveRBank - restores the register bank from stack             */
2775 /*-----------------------------------------------------------------*/
2776 static void
2777 unsaveRBank (int bank, iCode * ic, bool popPsw)
2778 {
2779   int i;
2780   asmop *aop = NULL;
2781   regs *r = NULL;
2782
2783   if (options.useXstack)
2784     {
2785       if (!ic)
2786         {
2787           /* Assume r0 is available for use. */
2788           r = REG_WITH_INDEX (R0_IDX);;
2789         }
2790       else
2791         {
2792           aop = newAsmop (0);
2793           r = getFreePtr (ic, &aop, FALSE);
2794         }
2795       emitcode ("mov", "%s,_spx", r->name);
2796     }
2797
2798   if (popPsw)
2799     {
2800       if (options.useXstack)
2801         {
2802           emitcode ("dec", "%s", r->name);
2803           emitcode ("movx", "a,@%s", r->name);
2804           emitcode ("mov", "psw,a");
2805         }
2806       else
2807       {
2808         emitcode ("pop", "psw");
2809       }
2810     }
2811
2812   if (ds390_nBitRegs > 0)
2813     {
2814       if (options.useXstack)
2815         {
2816           emitcode ("dec", "%s", r->name);
2817           emitcode ("movx", "a,@%s", r->name);
2818           emitcode ("mov", "bits,a");
2819         }
2820       else
2821         {
2822           emitcode ("pop", "bits");
2823         }
2824     }
2825
2826   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2827     {
2828       if (options.useXstack)
2829         {
2830           emitcode ("dec", "%s", r->name);
2831           emitcode ("movx", "a,@%s", r->name);
2832           emitcode ("mov", "(%s+%d),a",
2833                     regs390[i].base, 8 * bank + regs390[i].offset);
2834         }
2835       else
2836         {
2837           emitcode ("pop", "(%s+%d)",
2838                     regs390[i].base, 8 * bank + regs390[i].offset);
2839         }
2840     }
2841
2842   if (options.useXstack)
2843     {
2844       emitcode ("mov", "_spx,%s", r->name);
2845     }
2846
2847   if (aop)
2848     {
2849       freeAsmop (NULL, aop, ic, TRUE);
2850     }
2851 }
2852
2853 /*-----------------------------------------------------------------*/
2854 /* genSend - gen code for SEND                                     */
2855 /*-----------------------------------------------------------------*/
2856 static void genSend(set *sendSet)
2857 {
2858   iCode *sic;
2859   int bit_count = 0;
2860   int sendCount = 0 ;
2861   static int rb1_count = 0;
2862
2863   /* first we do all bit parameters */
2864   for (sic = setFirstItem (sendSet); sic;
2865        sic = setNextItem (sendSet))
2866     {
2867       if (sic->argreg > 12)
2868         {
2869           int bit = sic->argreg-13;
2870
2871           aopOp (IC_LEFT (sic), sic, FALSE,
2872                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2873
2874           /* if left is a literal then
2875              we know what the value is */
2876           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2877             {
2878               if (((int) operandLitValue (IC_LEFT (sic))))
2879                   emitcode ("setb", "b[%d]", bit);
2880               else
2881                   emitcode ("clr", "b[%d]", bit);
2882             }
2883           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2884             {
2885               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2886                 if (strcmp (l, "c"))
2887                     emitcode ("mov", "c,%s", l);
2888                 emitcode ("mov", "b[%d],c", bit);
2889             }
2890           else
2891             {
2892               /* we need to or */
2893               toBoolean (IC_LEFT (sic));
2894               /* set C, if a >= 1 */
2895               emitcode ("add", "a,#0xff");
2896               emitcode ("mov", "b[%d],c", bit);
2897             }
2898           bit_count++;
2899           BitBankUsed = 1;
2900
2901           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2902         }
2903     }
2904
2905   if (bit_count)
2906     {
2907       saveRegisters (setFirstItem (sendSet));
2908       emitcode ("mov", "bits,b");
2909     }
2910
2911   /* then we do all other parameters */
2912   for (sic = setFirstItem (sendSet); sic;
2913        sic = setNextItem (sendSet))
2914     {
2915       if (sic->argreg <= 12)
2916       {
2917         int size, offset = 0;
2918
2919         size = getSize (operandType (IC_LEFT (sic)));
2920         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2921         if (sendCount == 0) { /* first parameter */
2922             // we know that dpl(hxb) is the result, so
2923             rb1_count = 0 ;
2924             _startLazyDPSEvaluation ();
2925             if (size>1) {
2926                 aopOp (IC_LEFT (sic), sic, FALSE,
2927                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2928             } else {
2929                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2930             }
2931             while (size--)
2932               {
2933                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2934                 if (strcmp (l, fReturn[offset]))
2935                   {
2936                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2937                   }
2938                 offset++;
2939               }
2940             _endLazyDPSEvaluation ();
2941             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2942             rb1_count =0;
2943         } else { /* if more parameter in registers */
2944             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2945             while (size--) {
2946                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2947                                                                 FALSE, FALSE, NULL));
2948             }
2949             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2950         }
2951         sendCount++;
2952       }
2953     }
2954 }
2955
2956 static void
2957 adjustEsp(const char *reg)
2958 {
2959     emitcode ("anl","%s,#3", reg);
2960     if (TARGET_IS_DS400)
2961     {
2962         emitcode ("orl","%s,#!constbyte",
2963                   reg,
2964                   (options.stack_loc >> 8) & 0xff);
2965     }
2966 }
2967
2968 /*-----------------------------------------------------------------*/
2969 /* selectRegBank - emit code to select the register bank           */
2970 /*-----------------------------------------------------------------*/
2971 static void
2972 selectRegBank (short bank, bool keepFlags)
2973 {
2974   /* if f.e. result is in carry */
2975   if (keepFlags)
2976     {
2977       emitcode ("anl", "psw,#0xE7");
2978       if (bank)
2979         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2980     }
2981   else
2982     {
2983       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2984     }
2985 }
2986
2987 /*-----------------------------------------------------------------*/
2988 /* genCall - generates a call statement                            */
2989 /*-----------------------------------------------------------------*/
2990 static void
2991 genCall (iCode * ic)
2992 {
2993   sym_link *dtype;
2994   sym_link *etype;
2995   bool restoreBank = FALSE;
2996   bool swapBanks = FALSE;
2997   bool accuse = FALSE;
2998   bool accPushed = FALSE;
2999   bool resultInF0 = FALSE;
3000   bool assignResultGenerated = FALSE;
3001
3002   D (emitcode (";", "genCall"));
3003
3004   /* if we are calling a not _naked function that is not using
3005      the same register bank then we need to save the
3006      destination registers on the stack */
3007   dtype = operandType (IC_LEFT (ic));
3008   etype = getSpec(dtype);
3009   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3010       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3011       IFFUNC_ISISR (currFunc->type))
3012   {
3013       if (!ic->bankSaved)
3014       {
3015            /* This is unexpected; the bank should have been saved in
3016             * genFunction.
3017             */
3018            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3019            restoreBank = TRUE;
3020       }
3021       swapBanks = TRUE;
3022   }
3023
3024   /* if caller saves & we have not saved then */
3025   if (!ic->regsSaved)
3026       saveRegisters (ic);
3027
3028   /* if send set is not empty then assign */
3029   /* We've saved all the registers we care about;
3030   * therefore, we may clobber any register not used
3031   * in the calling convention (i.e. anything not in
3032   * fReturn.
3033   */
3034   if (_G.sendSet)
3035     {
3036         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3037             genSend(reverseSet(_G.sendSet));
3038         } else {
3039             genSend(_G.sendSet);
3040         }
3041       _G.sendSet = NULL;
3042     }
3043
3044   if (swapBanks)
3045     {
3046       emitcode ("mov", "psw,#!constbyte",
3047          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3048     }
3049
3050   /* make the call */
3051   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3052                             OP_SYMBOL (IC_LEFT (ic))->rname :
3053                             OP_SYMBOL (IC_LEFT (ic))->name));
3054
3055   if (swapBanks)
3056     {
3057       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3058     }
3059
3060   /* if we need assign a result value */
3061   if ((IS_ITEMP (IC_RESULT (ic)) &&
3062        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3063        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3064         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3065         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3066       IS_TRUE_SYMOP (IC_RESULT (ic)))
3067     {
3068       if (isOperandInFarSpace (IC_RESULT (ic))
3069           && getSize (operandType (IC_RESULT (ic))) <= 2)
3070         {
3071           int size = getSize (operandType (IC_RESULT (ic)));
3072           bool pushedB = FALSE;
3073
3074           /* Special case for 1 or 2 byte return in far space. */
3075           MOVA (fReturn[0]);
3076           if (size > 1)
3077             {
3078               pushedB = pushB ();
3079               emitcode ("mov", "b,%s", fReturn[1]);
3080             }
3081
3082           _G.accInUse++;
3083           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3084           _G.accInUse--;
3085
3086           popB (pushedB);
3087
3088           aopPut (IC_RESULT (ic), "a", 0);
3089
3090           if (size > 1)
3091             {
3092               aopPut (IC_RESULT (ic), "b", 1);
3093             }
3094           assignResultGenerated = TRUE;
3095           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3096         }
3097       else
3098         {
3099           bool pushedB = pushB ();
3100           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3101           popB (pushedB);
3102
3103           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3104           assignResultGenerated = TRUE;
3105           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3106         }
3107     }
3108
3109   /* adjust the stack for parameters if required */
3110   if (ic->parmBytes)
3111     {
3112       int i;
3113       if (options.stack10bit) {
3114           if (ic->parmBytes <= 10) {
3115               emitcode(";","stack adjustment for parms");
3116               for (i=0; i < ic->parmBytes ; i++) {
3117                   emitcode("pop","acc");
3118               }
3119           } else {
3120               PROTECT_SP;
3121               emitcode ("clr","c");
3122               emitcode ("mov","a,sp");
3123               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3124               emitcode ("mov","sp,a");
3125               emitcode ("mov","a,esp");
3126               adjustEsp("a");
3127               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3128               emitcode ("mov","esp,a");
3129               UNPROTECT_SP;
3130           }
3131       } else {
3132           if (ic->parmBytes > 3)
3133             {
3134               if (accuse)
3135                 {
3136                   emitcode ("push", "acc");
3137                   accPushed = TRUE;
3138                 }
3139               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3140                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3141                   !assignResultGenerated)
3142                 {
3143                   emitcode ("mov", "F0,c");
3144                   resultInF0 = TRUE;
3145                 }
3146
3147               emitcode ("mov", "a,%s", spname);
3148               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3149               emitcode ("mov", "%s,a", spname);
3150
3151               /* unsaveRegisters from xstack needs acc, but */
3152               /* unsaveRegisters from stack needs this popped */
3153               if (accPushed && !options.useXstack)
3154                 {
3155                   emitcode ("pop", "acc");
3156                   accPushed = FALSE;
3157                 }
3158             }
3159           else
3160               for (i = 0; i < ic->parmBytes; i++)
3161                   emitcode ("dec", "%s", spname);
3162       }
3163   }
3164
3165   /* if we had saved some registers then unsave them */
3166   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3167     {
3168       if (accuse && !accPushed && options.useXstack)
3169         {
3170           /* xstack needs acc, but doesn't touch normal stack */
3171           emitcode ("push", "acc");
3172           accPushed = TRUE;
3173         }
3174       unsaveRegisters (ic);
3175     }
3176
3177   /* if register bank was saved then pop them */
3178   if (restoreBank)
3179     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3180
3181   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3182     {
3183       if (resultInF0)
3184           emitcode ("mov", "c,F0");
3185
3186       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3187       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3188       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3189     }
3190
3191   if (accPushed)
3192     emitcode ("pop", "acc");
3193 }
3194
3195 /*-----------------------------------------------------------------*/
3196 /* genPcall - generates a call by pointer statement                */
3197 /*-----------------------------------------------------------------*/
3198 static void
3199 genPcall (iCode * ic)
3200 {
3201   sym_link *dtype;
3202   sym_link *etype;
3203   symbol *rlbl = newiTempLabel (NULL);
3204   bool restoreBank=FALSE;
3205   bool resultInF0 = FALSE;
3206
3207   D (emitcode (";", "genPcall"));
3208
3209   dtype = operandType (IC_LEFT (ic))->next;
3210   etype = getSpec(dtype);
3211   /* if caller saves & we have not saved then */
3212   if (!ic->regsSaved)
3213     saveRegisters (ic);
3214
3215   /* if we are calling a not _naked function that is not using
3216      the same register bank then we need to save the
3217      destination registers on the stack */
3218   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3219       IFFUNC_ISISR (currFunc->type) &&
3220       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3221     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3222     restoreBank=TRUE;
3223   }
3224
3225   /* push the return address on to the stack */
3226   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3227   emitcode ("push", "acc");
3228   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3229   emitcode ("push", "acc");
3230
3231   if (options.model == MODEL_FLAT24)
3232     {
3233       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3234       emitcode ("push", "acc");
3235     }
3236
3237   /* now push the calling address */
3238   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3239
3240   pushSide (IC_LEFT (ic), FPTRSIZE);
3241
3242   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3243
3244   /* if send set is not empty the assign */
3245   if (_G.sendSet)
3246     {
3247         genSend(reverseSet(_G.sendSet));
3248         _G.sendSet = NULL;
3249     }
3250
3251   /* make the call */
3252   emitcode ("ret", "");
3253   emitLabel (rlbl);
3254
3255
3256   /* if we need assign a result value */
3257   if ((IS_ITEMP (IC_RESULT (ic)) &&
3258        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3259        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3260         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3261       IS_TRUE_SYMOP (IC_RESULT (ic)))
3262     {
3263
3264       _G.accInUse++;
3265       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3266       _G.accInUse--;
3267
3268       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3269
3270       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3271     }
3272
3273   /* adjust the stack for parameters if required */
3274   if (ic->parmBytes)
3275     {
3276       int i;
3277       if (options.stack10bit) {
3278           if (ic->parmBytes <= 10) {
3279               emitcode(";","stack adjustment for parms");
3280               for (i=0; i < ic->parmBytes ; i++) {
3281                   emitcode("pop","acc");
3282               }
3283           } else {
3284               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3285                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3286                 {
3287                   emitcode ("mov", "F0,c");
3288                   resultInF0 = TRUE;
3289                 }
3290
3291               PROTECT_SP;
3292               emitcode ("clr","c");
3293               emitcode ("mov","a,sp");
3294               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3295               emitcode ("mov","sp,a");
3296               emitcode ("mov","a,esp");
3297               adjustEsp("a");
3298               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3299               emitcode ("mov","esp,a");
3300               UNPROTECT_SP;
3301           }
3302       } else {
3303           if (ic->parmBytes > 3) {
3304               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3305                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3306                 {
3307                   emitcode ("mov", "F0,c");
3308                   resultInF0 = TRUE;
3309                 }
3310
3311               emitcode ("mov", "a,%s", spname);
3312               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3313               emitcode ("mov", "%s,a", spname);
3314           }
3315           else
3316               for (i = 0; i < ic->parmBytes; i++)
3317                   emitcode ("dec", "%s", spname);
3318       }
3319     }
3320   /* if register bank was saved then unsave them */
3321   if (restoreBank)
3322     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3323
3324   /* if we had saved some registers then unsave them */
3325   if (ic->regsSaved)
3326     unsaveRegisters (ic);
3327
3328   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3329     {
3330       if (resultInF0)
3331           emitcode ("mov", "c,F0");
3332
3333       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3334       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3335       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3336     }
3337 }
3338
3339 /*-----------------------------------------------------------------*/
3340 /* resultRemat - result  is rematerializable                       */
3341 /*-----------------------------------------------------------------*/
3342 static int
3343 resultRemat (iCode * ic)
3344 {
3345   if (SKIP_IC (ic) || ic->op == IFX)
3346     return 0;
3347
3348   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3349     {
3350       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3351       if (sym->remat && !POINTER_SET (ic))
3352         return 1;
3353     }
3354
3355   return 0;
3356 }
3357
3358 #if defined(__BORLANDC__) || defined(_MSC_VER)
3359 #define STRCASECMP stricmp
3360 #else
3361 #define STRCASECMP strcasecmp
3362 #endif
3363
3364 /*-----------------------------------------------------------------*/
3365 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3366 /*-----------------------------------------------------------------*/
3367 static int
3368 regsCmp(void *p1, void *p2)
3369 {
3370   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3371 }
3372
3373 static bool
3374 inExcludeList (char *s)
3375 {
3376   const char *p = setFirstItem(options.excludeRegsSet);
3377
3378   if (p == NULL || STRCASECMP(p, "none") == 0)
3379     return FALSE;
3380
3381
3382   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3383 }
3384
3385 /*-----------------------------------------------------------------*/
3386 /* genFunction - generated code for function entry                 */
3387 /*-----------------------------------------------------------------*/
3388 static void
3389 genFunction (iCode * ic)
3390 {
3391   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3392   sym_link *ftype;
3393   bool     switchedPSW = FALSE;
3394   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3395
3396   D (emitcode (";", "genFunction"));
3397
3398   _G.nRegsSaved = 0;
3399   /* create the function header */
3400   emitcode (";", "-----------------------------------------");
3401   emitcode (";", " function %s", sym->name);
3402   emitcode (";", "-----------------------------------------");
3403
3404   emitcode ("", "%s:", sym->rname);
3405   lineCurr->isLabel = 1;
3406   ftype = operandType (IC_LEFT (ic));
3407   _G.currentFunc = sym;
3408
3409   if (IFFUNC_ISNAKED(ftype))
3410   {
3411       emitcode(";", "naked function: no prologue.");
3412       return;
3413   }
3414
3415   if (options.stack_probe)
3416       emitcode ("lcall","__stack_probe");
3417
3418   /* here we need to generate the equates for the
3419      register bank if required */
3420   if (FUNC_REGBANK (ftype) != rbank)
3421     {
3422       int i;
3423
3424       rbank = FUNC_REGBANK (ftype);
3425       for (i = 0; i < ds390_nRegs; i++)
3426         {
3427           if (regs390[i].print) {
3428               if (strcmp (regs390[i].base, "0") == 0)
3429                   emitcode ("", "%s !equ !constbyte",
3430                             regs390[i].dname,
3431                             8 * rbank + regs390[i].offset);
3432               else
3433                   emitcode ("", "%s !equ %s + !constbyte",
3434                             regs390[i].dname,
3435                             regs390[i].base,
3436                             8 * rbank + regs390[i].offset);
3437           }
3438         }
3439     }
3440
3441   /* if this is an interrupt service routine then
3442      save acc, b, dpl, dph  */
3443   if (IFFUNC_ISISR (sym->type))
3444       { /* is ISR */
3445       if (!inExcludeList ("acc"))
3446         emitcode ("push", "acc");
3447       if (!inExcludeList ("b"))
3448         emitcode ("push", "b");
3449       if (!inExcludeList ("dpl"))
3450         emitcode ("push", "dpl");
3451       if (!inExcludeList ("dph"))
3452         emitcode ("push", "dph");
3453       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3454         {
3455           emitcode ("push", "dpx");
3456           /* Make sure we're using standard DPTR */
3457           emitcode ("push", "dps");
3458           emitcode ("mov", "dps,#0");
3459           if (options.stack10bit)
3460             {
3461               /* This ISR could conceivably use DPTR2. Better save it. */
3462               emitcode ("push", "dpl1");
3463               emitcode ("push", "dph1");
3464               emitcode ("push", "dpx1");
3465               emitcode ("push",  DP2_RESULT_REG);
3466             }
3467         }
3468       /* if this isr has no bank i.e. is going to
3469          run with bank 0 , then we need to save more
3470          registers :-) */
3471       if (!FUNC_REGBANK (sym->type))
3472         {
3473             int i;
3474
3475           /* if this function does not call any other
3476              function then we can be economical and
3477              save only those registers that are used */
3478           if (!IFFUNC_HASFCALL(sym->type))
3479             {
3480               /* if any registers used */
3481               if (sym->regsUsed)
3482                 {
3483                   bool bits_pushed = FALSE;
3484                   /* save the registers used */
3485                   for (i = 0; i < sym->regsUsed->size; i++)
3486                     {
3487                       if (bitVectBitValue (sym->regsUsed, i))
3488                         bits_pushed = pushReg (i, bits_pushed);
3489                     }
3490                 }
3491             }
3492           else
3493             {
3494               /* this function has a function call. We cannot
3495                  determine register usage so we will have to push the
3496                  entire bank */
3497               saveRBank (0, ic, FALSE);
3498               if (options.parms_in_bank1) {
3499                   for (i=0; i < 8 ; i++ ) {
3500                       emitcode ("push","%s",rb1regs[i]);
3501                   }
3502               }
3503             }
3504         }
3505         else
3506         {
3507             /* This ISR uses a non-zero bank.
3508              *
3509              * We assume that the bank is available for our
3510              * exclusive use.
3511              *
3512              * However, if this ISR calls a function which uses some
3513              * other bank, we must save that bank entirely.
3514              */
3515             unsigned long banksToSave = 0;
3516
3517             if (IFFUNC_HASFCALL(sym->type))
3518             {
3519
3520 #define MAX_REGISTER_BANKS 4
3521
3522                 iCode *i;
3523                 int ix;
3524
3525                 for (i = ic; i; i = i->next)
3526                 {
3527                     if (i->op == ENDFUNCTION)
3528                     {
3529                         /* we got to the end OK. */
3530                         break;
3531                     }
3532
3533                     if (i->op == CALL)
3534                     {
3535                         sym_link *dtype;
3536
3537                         dtype = operandType (IC_LEFT(i));
3538                         if (dtype
3539                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3540                         {
3541                              /* Mark this bank for saving. */
3542                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3543                              {
3544                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3545                              }
3546                              else
3547                              {
3548                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3549                              }
3550
3551                              /* And note that we don't need to do it in
3552                               * genCall.
3553                               */
3554                              i->bankSaved = 1;
3555                         }
3556                     }
3557                     if (i->op == PCALL)
3558                     {
3559                         /* This is a mess; we have no idea what
3560                          * register bank the called function might
3561                          * use.
3562                          *
3563                          * The only thing I can think of to do is
3564                          * throw a warning and hope.
3565                          */
3566                         werror(W_FUNCPTR_IN_USING_ISR);
3567                     }
3568                 }
3569
3570                 if (banksToSave && options.useXstack)
3571                 {
3572                     /* Since we aren't passing it an ic,
3573                      * saveRBank will assume r0 is available to abuse.
3574                      *
3575                      * So switch to our (trashable) bank now, so
3576                      * the caller's R0 isn't trashed.
3577                      */
3578                     emitcode ("push", "psw");
3579                     emitcode ("mov", "psw,#!constbyte",
3580                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3581                     switchedPSW = TRUE;
3582                 }
3583
3584                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3585                 {
3586                      if (banksToSave & (1 << ix))
3587                      {
3588                          saveRBank(ix, NULL, FALSE);
3589                      }
3590                 }
3591             }
3592             // TODO: this needs a closer look
3593             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3594         }
3595     }
3596   else
3597     {
3598       /* if callee-save to be used for this function
3599          then save the registers being used in this function */
3600       if (IFFUNC_CALLEESAVES(sym->type))
3601         {
3602           int i;
3603
3604           /* if any registers used */
3605           if (sym->regsUsed)
3606             {
3607               bool bits_pushed = FALSE;
3608               /* save the registers used */
3609               for (i = 0; i < sym->regsUsed->size; i++)
3610                 {
3611                   if (bitVectBitValue (sym->regsUsed, i))
3612                     {
3613                       bits_pushed = pushReg (i, bits_pushed);
3614                       _G.nRegsSaved++;
3615                     }
3616                 }
3617             }
3618         }
3619     }
3620
3621   /* set the register bank to the desired value */
3622   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3623    && !switchedPSW)
3624     {
3625       emitcode ("push", "psw");
3626       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3627     }
3628
3629   if (fReentrant &&
3630        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3631       if (options.stack10bit) {
3632           emitcode ("push","_bpx");
3633           emitcode ("push","_bpx+1");
3634           emitcode ("mov","_bpx,%s",spname);
3635           emitcode ("mov","_bpx+1,esp");
3636           adjustEsp("_bpx+1");
3637       } else {
3638           if (options.useXstack)
3639           {
3640               emitcode ("mov", "r0,%s", spname);
3641               emitcode ("mov", "a,_bp");
3642               emitcode ("movx", "@r0,a");
3643               emitcode ("inc", "%s", spname);
3644           } else {
3645               /* set up the stack */
3646               emitcode ("push", "_bp"); /* save the callers stack  */
3647           }
3648           emitcode ("mov", "_bp,%s", spname);
3649       }
3650   }
3651
3652   /* adjust the stack for the function */
3653   if (sym->stack) {
3654       int i = sym->stack;
3655       if (options.stack10bit) {
3656           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3657           assert (sym->recvSize <= 4);
3658           if (sym->stack <= 8) {
3659               while (i--) emitcode ("push","acc");
3660           } else {
3661               PROTECT_SP;
3662               emitcode ("mov","a,sp");
3663               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3664               emitcode ("mov","sp,a");
3665               emitcode ("mov","a,esp");
3666               adjustEsp("a");
3667               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3668               emitcode ("mov","esp,a");
3669               UNPROTECT_SP;
3670           }
3671       } else {
3672           if (i > 256)
3673               werror (W_STACK_OVERFLOW, sym->name);
3674
3675           if (i > 3 && sym->recvSize < 4) {
3676
3677               emitcode ("mov", "a,sp");
3678               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3679               emitcode ("mov", "sp,a");
3680
3681           } else
3682               while (i--)
3683                   emitcode ("inc", "sp");
3684       }
3685   }
3686
3687   if (sym->xstack)
3688     {
3689
3690       emitcode ("mov", "a,_spx");
3691       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3692       emitcode ("mov", "_spx,a");
3693     }
3694
3695   /* if critical function then turn interrupts off */
3696   if (IFFUNC_ISCRITICAL (ftype))
3697     {
3698       symbol *tlbl = newiTempLabel (NULL);
3699       emitcode ("setb", "c");
3700       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3701       emitcode ("clr", "c");
3702       emitLabel (tlbl);
3703       emitcode ("push", "psw"); /* save old ea via c in psw */
3704     }
3705 }
3706
3707 /*-----------------------------------------------------------------*/
3708 /* genEndFunction - generates epilogue for functions               */
3709 /*-----------------------------------------------------------------*/
3710 static void
3711 genEndFunction (iCode * ic)
3712 {
3713   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3714   lineNode *lnp = lineCurr;
3715   bitVect *regsUsed;
3716   bitVect *regsUsedPrologue;
3717   bitVect *regsUnneeded;
3718   int idx;
3719
3720   D (emitcode (";", "genEndFunction"));
3721
3722   _G.currentFunc = NULL;
3723   if (IFFUNC_ISNAKED(sym->type))
3724   {
3725       emitcode(";", "naked function: no epilogue.");
3726       if (options.debug && currFunc)
3727         debugFile->writeEndFunction (currFunc, ic, 0);
3728       return;
3729   }
3730
3731   if (IFFUNC_ISCRITICAL (sym->type))
3732     {
3733       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3734         {
3735           emitcode ("rlc", "a");   /* save c in a */
3736           emitcode ("pop", "psw"); /* restore ea via c in psw */
3737           emitcode ("mov", "ea,c");
3738           emitcode ("rrc", "a");   /* restore c from a */
3739         }
3740       else
3741         {
3742           emitcode ("pop", "psw"); /* restore ea via c in psw */
3743           emitcode ("mov", "ea,c");
3744         }
3745     }
3746
3747   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3748        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3749
3750       if (options.stack10bit) {
3751           PROTECT_SP;
3752           emitcode ("mov", "sp,_bpx", spname);
3753           emitcode ("mov", "esp,_bpx+1", spname);
3754           UNPROTECT_SP;
3755       } else {
3756           emitcode ("mov", "%s,_bp", spname);
3757       }
3758   }
3759
3760   /* if use external stack but some variables were
3761      added to the local stack then decrement the
3762      local stack */
3763   if (options.useXstack && sym->stack) {
3764       emitcode ("mov", "a,sp");
3765       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3766       emitcode ("mov", "sp,a");
3767   }
3768
3769
3770   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3771        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3772
3773       if (options.useXstack) {
3774           emitcode ("mov", "r0,%s", spname);
3775           emitcode ("movx", "a,@r0");
3776           emitcode ("mov", "_bp,a");
3777           emitcode ("dec", "%s", spname);
3778       } else {
3779           if (options.stack10bit) {
3780               emitcode ("pop", "_bpx+1");
3781               emitcode ("pop", "_bpx");
3782           } else {
3783               emitcode ("pop", "_bp");
3784           }
3785       }
3786   }
3787
3788   /* restore the register bank  */
3789   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3790   {
3791     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3792      || !options.useXstack)
3793     {
3794         /* Special case of ISR using non-zero bank with useXstack
3795          * is handled below.
3796          */
3797         emitcode ("pop", "psw");
3798     }
3799   }
3800
3801   if (IFFUNC_ISISR (sym->type))
3802     { /* is ISR */
3803
3804       /* now we need to restore the registers */
3805       /* if this isr has no bank i.e. is going to
3806          run with bank 0 , then we need to save more
3807          registers :-) */
3808       if (!FUNC_REGBANK (sym->type))
3809         {
3810           int i;
3811           /* if this function does not call any other
3812              function then we can be economical and
3813              save only those registers that are used */
3814           if (!IFFUNC_HASFCALL(sym->type))
3815             {
3816               /* if any registers used */
3817               if (sym->regsUsed)
3818                 {
3819                   bool bits_popped = FALSE;
3820                   /* save the registers used */
3821                   for (i = sym->regsUsed->size; i >= 0; i--)
3822                     {
3823                       if (bitVectBitValue (sym->regsUsed, i))
3824                         bits_popped = popReg (i, bits_popped);
3825                     }
3826                 }
3827             }
3828           else
3829             {
3830               /* this function has a function call. We cannot
3831                  determine register usage so we will have to pop the
3832                  entire bank */
3833               if (options.parms_in_bank1) {
3834                   for (i = 7 ; i >= 0 ; i-- ) {
3835                       emitcode ("pop","%s",rb1regs[i]);
3836                   }
3837               }
3838               unsaveRBank (0, ic, FALSE);
3839             }
3840         }
3841       else
3842         {
3843             /* This ISR uses a non-zero bank.
3844              *
3845              * Restore any register banks saved by genFunction
3846              * in reverse order.
3847              */
3848             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3849             int ix;
3850
3851             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3852             {
3853                 if (savedBanks & (1 << ix))
3854                 {
3855                     unsaveRBank(ix, NULL, FALSE);
3856                 }
3857             }
3858
3859             if (options.useXstack)
3860             {
3861                 /* Restore bank AFTER calling unsaveRBank,
3862                  * since it can trash r0.
3863                  */
3864                 emitcode ("pop", "psw");
3865             }
3866         }
3867
3868       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3869         {
3870           if (options.stack10bit)
3871             {
3872               emitcode ("pop", DP2_RESULT_REG);
3873               emitcode ("pop", "dpx1");
3874               emitcode ("pop", "dph1");
3875               emitcode ("pop", "dpl1");
3876             }
3877           emitcode ("pop", "dps");
3878           emitcode ("pop", "dpx");
3879         }
3880       if (!inExcludeList ("dph"))
3881         emitcode ("pop", "dph");
3882       if (!inExcludeList ("dpl"))
3883         emitcode ("pop", "dpl");
3884       if (!inExcludeList ("b"))
3885         emitcode ("pop", "b");
3886       if (!inExcludeList ("acc"))
3887         emitcode ("pop", "acc");
3888
3889       /* if debug then send end of function */
3890       if (options.debug && currFunc)
3891         {
3892           debugFile->writeEndFunction (currFunc, ic, 1);
3893         }
3894
3895       emitcode ("reti", "");
3896     }
3897   else
3898     {
3899       if (IFFUNC_CALLEESAVES(sym->type))
3900         {
3901           int i;
3902
3903           /* if any registers used */
3904           if (sym->regsUsed)
3905             {
3906               /* save the registers used */
3907               for (i = sym->regsUsed->size; i >= 0; i--)
3908                 {
3909                   if (bitVectBitValue (sym->regsUsed, i))
3910                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3911                 }
3912             }
3913         }
3914
3915       /* if debug then send end of function */
3916       if (options.debug && currFunc)
3917         {
3918           debugFile->writeEndFunction (currFunc, ic, 1);
3919         }
3920
3921       emitcode ("ret", "");
3922     }
3923
3924   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3925     return;
3926
3927   /* If this was an interrupt handler using bank 0 that called another */
3928   /* function, then all registers must be saved; nothing to optimized. */
3929   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3930       && !FUNC_REGBANK(sym->type))
3931     return;
3932
3933   /* There are no push/pops to optimize if not callee-saves or ISR */
3934   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3935     return;
3936
3937   /* If there were stack parameters, we cannot optimize without also    */
3938   /* fixing all of the stack offsets; this is too dificult to consider. */
3939   if (FUNC_HASSTACKPARM(sym->type))
3940     return;
3941
3942   /* Compute the registers actually used */
3943   regsUsed = newBitVect (ds390_nRegs);
3944   regsUsedPrologue = newBitVect (ds390_nRegs);
3945   while (lnp)
3946     {
3947       if (lnp->ic && lnp->ic->op == FUNCTION)
3948         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3949       else
3950         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3951
3952       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3953           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3954         break;
3955       if (!lnp->prev)
3956         break;
3957       lnp = lnp->prev;
3958     }
3959
3960   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3961       && !bitVectBitValue (regsUsed, DPS_IDX))
3962     {
3963       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3964     }
3965
3966   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3967       && !bitVectBitValue (regsUsed, CND_IDX))
3968     {
3969       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3970       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3971           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3972         bitVectUnSetBit (regsUsed, CND_IDX);
3973     }
3974   else
3975     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3976
3977   /* If this was an interrupt handler that called another function */
3978   /* function, then assume working registers may be modified by it. */
3979   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3980     {
3981       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3982       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3983       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3984       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3985       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3986       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3987       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3988       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3989       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3990       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3991       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3992     }
3993
3994   /* Remove the unneeded push/pops */
3995   regsUnneeded = newBitVect (ds390_nRegs);
3996   while (lnp)
3997     {
3998       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3999         {
4000           if (!strncmp(lnp->line, "push", 4))
4001             {
4002               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4003               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4004                 {
4005                   connectLine (lnp->prev, lnp->next);
4006                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4007                 }
4008             }
4009           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4010             {
4011               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4012               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4013                 {
4014                   connectLine (lnp->prev, lnp->next);
4015                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4016                 }
4017             }
4018         }
4019       lnp = lnp->next;
4020     }
4021
4022   for (idx = 0; idx < regsUnneeded->size; idx++)
4023     if (bitVectBitValue (regsUnneeded, idx))
4024       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4025
4026   freeBitVect (regsUnneeded);
4027   freeBitVect (regsUsed);
4028   freeBitVect (regsUsedPrologue);
4029 }
4030
4031 /*-----------------------------------------------------------------*/
4032 /* genJavaNativeRet - generate code for return JavaNative          */
4033 /*-----------------------------------------------------------------*/
4034 static void genJavaNativeRet(iCode *ic)
4035 {
4036     int i, size;
4037
4038     aopOp (IC_LEFT (ic), ic, FALSE,
4039            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4040     size = AOP_SIZE (IC_LEFT (ic));
4041
4042     assert (size <= 4);
4043
4044     /* it is assigned to GPR0-R3 then push them */
4045     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4046         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4047         for (i = 0 ; i < size ; i++ ) {
4048             emitcode ("push","%s",
4049                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4050         }
4051         for (i = (size-1) ; i >= 0 ; i--) {
4052             emitcode ("pop","a%s",javaRet[i]);
4053         }
4054     } else {
4055         for (i = 0 ; i < size ; i++)
4056             emitcode ("mov","%s,%s",javaRet[i],
4057                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4058     }
4059     for (i = size ; i < 4 ; i++ )
4060             emitcode ("mov","%s,#0",javaRet[i]);
4061     return;
4062 }
4063
4064 /*-----------------------------------------------------------------*/
4065 /* genRet - generate code for return statement                     */
4066 /*-----------------------------------------------------------------*/
4067 static void
4068 genRet (iCode * ic)
4069 {
4070   int size, offset = 0, pushed = 0;
4071
4072   D (emitcode (";", "genRet"));
4073
4074   /* if we have no return value then
4075      just generate the "ret" */
4076   if (!IC_LEFT (ic))
4077     goto jumpret;
4078
4079   /* if this is a JavaNative function then return
4080      value in different register */
4081   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4082       genJavaNativeRet(ic);
4083       goto jumpret;
4084   }
4085   /* we have something to return then
4086      move the return value into place */
4087   aopOp (IC_LEFT (ic), ic, FALSE,
4088          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4089   size = AOP_SIZE (IC_LEFT (ic));
4090
4091   _startLazyDPSEvaluation ();
4092
4093   if (IS_BIT(_G.currentFunc->etype))
4094     {
4095       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4096       size = 0;
4097     }
4098
4099   while (size--)
4100     {
4101       char *l;
4102       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4103         {
4104           l = aopGet (IC_LEFT (ic), offset++,
4105                       FALSE, TRUE, NULL);
4106           emitcode ("push", "%s", l);
4107           pushed++;
4108         }
4109       else
4110         {
4111           /* Since A is the last element of fReturn,
4112            * it is OK to clobber it in the aopGet.
4113            */
4114           l = aopGet (IC_LEFT (ic), offset,
4115                       FALSE, FALSE, NULL);
4116           if (strcmp (fReturn[offset], l))
4117             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4118         }
4119     }
4120   _endLazyDPSEvaluation ();
4121
4122   while (pushed)
4123     {
4124       pushed--;
4125       if (strcmp (fReturn[pushed], "a"))
4126         emitcode ("pop", fReturn[pushed]);
4127       else
4128         emitcode ("pop", "acc");
4129     }
4130   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4131
4132 jumpret:
4133   /* generate a jump to the return label
4134      if the next is not the return statement */
4135   if (!(ic->next && ic->next->op == LABEL &&
4136         IC_LABEL (ic->next) == returnLabel))
4137
4138     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4139
4140 }
4141
4142 /*-----------------------------------------------------------------*/
4143 /* genLabel - generates a label                                    */
4144 /*-----------------------------------------------------------------*/
4145 static void
4146 genLabel (iCode * ic)
4147 {
4148   /* special case never generate */
4149   if (IC_LABEL (ic) == entryLabel)
4150     return;
4151
4152   D (emitcode (";", "genLabel"));
4153
4154   emitLabel (IC_LABEL (ic));
4155 }
4156
4157 /*-----------------------------------------------------------------*/
4158 /* genGoto - generates a ljmp                                      */
4159 /*-----------------------------------------------------------------*/
4160 static void
4161 genGoto (iCode * ic)
4162 {
4163   D (emitcode (";", "genGoto"));
4164
4165   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4166 }
4167
4168 /*-----------------------------------------------------------------*/
4169 /* findLabelBackwards: walks back through the iCode chain looking  */
4170 /* for the given label. Returns number of iCode instructions     */
4171 /* between that label and given ic.          */
4172 /* Returns zero if label not found.          */
4173 /*-----------------------------------------------------------------*/
4174 static int
4175 findLabelBackwards (iCode * ic, int key)
4176 {
4177   int count = 0;
4178
4179   while (ic->prev)
4180     {
4181       ic = ic->prev;
4182       count++;
4183
4184       /* If we have any pushes or pops, we cannot predict the distance.
4185          I don't like this at all, this should be dealt with in the
4186          back-end */
4187       if (ic->op == IPUSH || ic->op == IPOP) {
4188         return 0;
4189       }
4190
4191       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4192         {
4193           /* printf("findLabelBackwards = %d\n", count); */
4194           return count;
4195         }
4196     }
4197
4198   return 0;
4199 }
4200
4201 /*-----------------------------------------------------------------*/
4202 /* genPlusIncr :- does addition with increment if possible         */
4203 /*-----------------------------------------------------------------*/
4204 static bool
4205 genPlusIncr (iCode * ic)
4206 {
4207   unsigned int icount;
4208   unsigned int size = getDataSize (IC_RESULT (ic));
4209
4210   /* will try to generate an increment */
4211   /* if the right side is not a literal
4212      we cannot */
4213   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4214     return FALSE;
4215
4216   /* if the literal value of the right hand side
4217      is greater than 4 then it is not worth it */
4218   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4219     return FALSE;
4220
4221   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4222       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4223       while (icount--) {
4224           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4225       }
4226       return TRUE;
4227   }
4228   /* if increment 16 bits in register */
4229   if (
4230        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4231        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4232        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4233        (size > 1) &&
4234        (icount == 1))
4235     {
4236       symbol  *tlbl;
4237       int     emitTlbl;
4238       int     labelRange;
4239       char    *l;
4240
4241       /* If the next instruction is a goto and the goto target
4242        * is <= 5 instructions previous to this, we can generate
4243        * jumps straight to that target.
4244        */
4245       if (ic->next && ic->next->op == GOTO
4246           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4247           && labelRange <= 5)
4248         {
4249           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4250           tlbl = IC_LABEL (ic->next);
4251           emitTlbl = 0;
4252         }
4253       else
4254         {
4255           tlbl = newiTempLabel (NULL);
4256           emitTlbl = 1;
4257         }
4258       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4259       emitcode ("inc", "%s", l);
4260
4261       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4262           IS_AOP_PREG (IC_RESULT (ic)))
4263         {
4264           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4265         }
4266       else
4267         {
4268           emitcode ("clr", "a");
4269           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4270         }
4271
4272       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4273       emitcode ("inc", "%s", l);
4274       if (size > 2)
4275         {
4276           if (!strcmp(l, "acc"))
4277             {
4278                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4279             }
4280           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4281                    IS_AOP_PREG (IC_RESULT (ic)))
4282             {
4283                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4284             }
4285           else
4286             {
4287                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4288             }
4289
4290           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4291           emitcode ("inc", "%s", l);
4292         }
4293       if (size > 3)
4294         {
4295           if (!strcmp(l, "acc"))
4296             {
4297                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4298             }
4299           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4300                    IS_AOP_PREG (IC_RESULT (ic)))
4301             {
4302                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4303             }
4304           else
4305             {
4306                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4307             }
4308
4309           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4310           emitcode ("inc", "%s", l);
4311         }
4312
4313       if (emitTlbl)
4314         {
4315           emitLabel (tlbl);
4316         }
4317       return TRUE;
4318     }
4319
4320   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4321       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4322       options.model == MODEL_FLAT24 )
4323     {
4324       if (IC_RESULT(ic)->isGptr)
4325         {
4326           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4327         }
4328       switch (size) {
4329       case 3:
4330           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4331       case 2:
4332           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4333       case 1:
4334           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4335           break;
4336       }
4337       while (icount--)
4338         emitcode ("inc", "dptr");
4339       return TRUE;
4340   }
4341
4342   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4343       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4344       icount <= 5 ) {
4345       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4346       while (icount--)
4347         emitcode ("inc", "dptr");
4348       emitcode ("mov", "dps,#0");
4349       return TRUE;
4350   }
4351
4352   /* if the sizes are greater than 1 then we cannot */
4353   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4354       AOP_SIZE (IC_LEFT (ic)) > 1)
4355     return FALSE;
4356
4357   /* we can if the aops of the left & result match or
4358      if they are in registers and the registers are the
4359      same */
4360   if (
4361        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4362        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4363        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4364     {
4365       if (icount > 3)
4366         {
4367           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4368           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4369           aopPut (IC_RESULT (ic), "a", 0);
4370         }
4371       else
4372         {
4373           _startLazyDPSEvaluation ();
4374           while (icount--)
4375             {
4376               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4377             }
4378           _endLazyDPSEvaluation ();
4379         }
4380
4381       return TRUE;
4382     }
4383
4384   return FALSE;
4385 }
4386
4387 /*-----------------------------------------------------------------*/
4388 /* outBitAcc - output a bit in acc                                 */
4389 /*-----------------------------------------------------------------*/
4390 static void
4391 outBitAcc (operand * result)
4392 {
4393   symbol *tlbl = newiTempLabel (NULL);
4394   /* if the result is a bit */
4395   if (AOP_TYPE (result) == AOP_CRY)
4396     {
4397       aopPut (result, "a", 0);
4398     }
4399   else
4400     {
4401       emitcode ("jz", "!tlabel", tlbl->key + 100);
4402       emitcode ("mov", "a,%s", one);
4403       emitLabel (tlbl);
4404       outAcc (result);
4405     }
4406 }
4407
4408 /*-----------------------------------------------------------------*/
4409 /* genPlusBits - generates code for addition of two bits           */
4410 /*-----------------------------------------------------------------*/
4411 static void
4412 genPlusBits (iCode * ic)
4413 {
4414   D (emitcode (";", "genPlusBits"));
4415
4416   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4417     {
4418       symbol *lbl = newiTempLabel (NULL);
4419       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4420       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4421       emitcode ("cpl", "c");
4422       emitLabel (lbl);
4423       outBitC (IC_RESULT (ic));
4424     }
4425   else
4426     {
4427       emitcode ("clr", "a");
4428       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4429       emitcode ("rlc", "a");
4430       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4431       emitcode ("addc", "a,%s", zero);
4432       outAcc (IC_RESULT (ic));
4433     }
4434 }
4435
4436 static void
4437 adjustArithmeticResult (iCode * ic)
4438 {
4439   if (opIsGptr (IC_RESULT (ic)) &&
4440       opIsGptr (IC_LEFT (ic)) &&
4441       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4442     {
4443       aopPut (IC_RESULT (ic),
4444               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4445               GPTRSIZE - 1);
4446     }
4447
4448   if (opIsGptr (IC_RESULT (ic)) &&
4449       opIsGptr (IC_RIGHT (ic)) &&
4450       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4451     {
4452       aopPut (IC_RESULT (ic),
4453               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4454               GPTRSIZE - 1);
4455     }
4456
4457   if (opIsGptr (IC_RESULT (ic)) &&
4458       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4459       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4460       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4461       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4462     {
4463       char buffer[5];
4464       SNPRINTF (buffer, sizeof(buffer),
4465                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4466       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4467     }
4468 }
4469
4470 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4471 // generates the result if possible. If result is generated, returns TRUE; otherwise
4472 // returns false and caller must deal with fact that result isn't aopOp'd.
4473 bool aopOp3(iCode * ic)
4474 {
4475     bool dp1InUse, dp2InUse;
4476     bool useDp2;
4477
4478     // First, generate the right opcode. DPTR may be used if neither left nor result are
4479     // of type AOP_STR.
4480
4481 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4482 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4483 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4484 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4485 //      );
4486 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4487 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4488 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4489 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4490 //      );
4491
4492     // Right uses DPTR unless left or result is an AOP_STR; however,
4493     // if right is an AOP_STR, it must use DPTR regardless.
4494     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4495      && !AOP_IS_STR (IC_RIGHT (ic)))
4496     {
4497         useDp2 = TRUE;
4498     }
4499     else
4500     {
4501         useDp2 = FALSE;
4502     }
4503
4504     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4505
4506     // if the right used DPTR, left MUST use DPTR2.
4507     // if the right used DPTR2, left MUST use DPTR.
4508     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4509     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4510     // enabling us to assign DPTR to result.
4511
4512     if (AOP_USESDPTR (IC_RIGHT (ic)))
4513     {
4514         useDp2 = TRUE;
4515     }
4516     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4517     {
4518         useDp2 = FALSE;
4519     }
4520     else
4521     {
4522         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4523         {
4524             useDp2 = TRUE;
4525         }
4526         else
4527         {
4528             useDp2 = FALSE;
4529         }
4530     }
4531
4532     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4533
4534
4535     // We've op'd the left & right. So, if left or right are the same operand as result,
4536     // we know aopOp will succeed, and we can just do it & bail.
4537     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4538       {
4539         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4540         return TRUE;
4541       }
4542     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4543       {
4544 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4545         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4546         return TRUE;
4547       }
4548
4549     // Operands may be equivalent (but not equal) if they share a spill location. If
4550     // so, use the same DPTR or DPTR2.
4551     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4552       {
4553         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4554         return TRUE;
4555       }
4556     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4557       {
4558         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4559         return TRUE;
4560       }
4561
4562     // Note which dptrs are currently in use.
4563     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4564     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4565
4566     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4567     // generate it.
4568     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4569     {
4570         return FALSE;
4571     }
4572
4573     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4574     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4575     {
4576         return FALSE;
4577     }
4578
4579     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4580     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4581     {
4582         return FALSE;
4583     }
4584
4585     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4586
4587     // Some sanity checking...
4588     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4589     {
4590         fprintf(stderr,
4591                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4592                 __FILE__, __LINE__, ic->filename, ic->lineno);
4593         emitcode(";", ">>> unexpected DPTR here.");
4594     }
4595
4596     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4597     {
4598         fprintf(stderr,
4599                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4600                 __FILE__, __LINE__, ic->filename, ic->lineno);
4601         emitcode(";", ">>> unexpected DPTR2 here.");
4602     }
4603
4604     return TRUE;
4605 }
4606
4607 // Macro to aopOp all three operands of an ic. If this cannot be done,
4608 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4609 // will be set TRUE. The caller must then handle the case specially, noting
4610 // that the IC_RESULT operand is not aopOp'd.
4611 //
4612 #define AOP_OP_3_NOFATAL(ic, rc) \
4613             do { rc = !aopOp3(ic); } while (0)
4614
4615 // aopOp the left & right operands of an ic.
4616 #define AOP_OP_2(ic) \
4617     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4618     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4619
4620 // convienience macro.
4621 #define AOP_SET_LOCALS(ic) \
4622     left = IC_LEFT(ic); \
4623     right = IC_RIGHT(ic); \
4624     result = IC_RESULT(ic);
4625
4626
4627 // Given an integer value of pushedSize bytes on the stack,
4628 // adjust it to be resultSize bytes, either by discarding
4629 // the most significant bytes or by zero-padding.
4630 //
4631 // On exit from this macro, pushedSize will have been adjusted to
4632 // equal resultSize, and ACC may be trashed.
4633 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4634       /* If the pushed data is bigger than the result,          \
4635        * simply discard unused bytes. Icky, but works.          \
4636        */                                                       \
4637       while (pushedSize > resultSize)                           \
4638       {                                                         \
4639           D (emitcode (";", "discarding unused result byte.")); \
4640           emitcode ("pop", "acc");                              \
4641           pushedSize--;                                         \
4642       }                                                         \
4643       if (pushedSize < resultSize)                              \
4644       {                                                         \
4645           emitcode ("clr", "a");                                \
4646           /* Conversly, we haven't pushed enough here.          \
4647            * just zero-pad, and all is well.                    \
4648            */                                                   \
4649           while (pushedSize < resultSize)                       \
4650           {                                                     \
4651               emitcode("push", "acc");                          \
4652               pushedSize++;                                     \
4653           }                                                     \
4654       }                                                         \
4655       assert(pushedSize == resultSize);
4656
4657 /*-----------------------------------------------------------------*/
4658 /* genPlus - generates code for addition                           */
4659 /*-----------------------------------------------------------------*/
4660 static void
4661 genPlus (iCode * ic)
4662 {
4663   int size, offset = 0;
4664   bool pushResult;
4665   int rSize;
4666   bool swappedLR = FALSE;
4667
4668   D (emitcode (";", "genPlus"));
4669
4670   /* special cases :- */
4671   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4672       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4673       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4674       size = (int)floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4675       if (size <= 9) {
4676           while (size--) emitcode ("inc","dptr");
4677       } else {
4678           emitcode ("mov", "a,dpl");
4679           emitcode ("add", "a,#!constbyte", size & 0xff);
4680           emitcode ("mov", "dpl,a");
4681           emitcode ("mov", "a,dph");
4682           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4683           emitcode ("mov", "dph,a");
4684           emitcode ("mov", "a,dpx");
4685           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4686           emitcode ("mov", "dpx,a");
4687       }
4688       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4689       return ;
4690   }
4691   if ( IS_SYMOP (IC_LEFT (ic)) &&
4692        OP_SYMBOL (IC_LEFT (ic))->remat &&
4693        isOperandInFarSpace (IC_RIGHT (ic))) {
4694       operand *op = IC_RIGHT(ic);
4695       IC_RIGHT(ic) = IC_LEFT(ic);
4696       IC_LEFT(ic) = op;
4697   }
4698
4699   AOP_OP_3_NOFATAL (ic, pushResult);
4700
4701   if (pushResult)
4702     {
4703       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4704     }
4705
4706   if (!pushResult)
4707     {
4708       /* if literal, literal on the right or
4709          if left requires ACC or right is already
4710          in ACC */
4711       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4712           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4713           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4714         {
4715           operand *t = IC_RIGHT (ic);
4716           IC_RIGHT (ic) = IC_LEFT (ic);
4717           IC_LEFT (ic) = t;
4718           swappedLR = TRUE;
4719           D (emitcode (";", "Swapped plus args."));
4720         }
4721
4722       /* if both left & right are in bit
4723          space */
4724       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4725           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4726         {
4727           genPlusBits (ic);
4728           goto release;
4729         }
4730
4731       /* if left in bit space & right literal */
4732       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4733           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4734         {
4735           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4736           /* if result in bit space */
4737           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4738             {
4739               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4740                 emitcode ("cpl", "c");
4741               outBitC (IC_RESULT (ic));
4742             }
4743           else
4744             {
4745               size = getDataSize (IC_RESULT (ic));
4746               _startLazyDPSEvaluation ();
4747               while (size--)
4748                 {
4749                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4750                   emitcode ("addc", "a,%s", zero);
4751                   aopPut (IC_RESULT (ic), "a", offset++);
4752                 }
4753               _endLazyDPSEvaluation ();
4754             }
4755           goto release;
4756         }
4757
4758       /* if I can do an increment instead
4759          of add then GOOD for ME */
4760       if (genPlusIncr (ic) == TRUE)
4761         {
4762           D (emitcode (";", "did genPlusIncr"));
4763           goto release;
4764         }
4765
4766     }
4767   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4768
4769   _startLazyDPSEvaluation ();
4770   while (size--)
4771     {
4772       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4773         {
4774           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4775           if (offset == 0)
4776             emitcode ("add", "a,%s",
4777                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4778           else
4779             emitcode ("addc", "a,%s",
4780                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4781         }
4782       else
4783         {
4784           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4785           {
4786               /* right is going to use ACC or we would have taken the
4787                * above branch.
4788                */
4789               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4790               TR_AP("#3");
4791               D(emitcode(";", "+ AOP_ACC special case."););
4792               emitcode("xch", "a, %s", DP2_RESULT_REG);
4793           }
4794           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4795           if (offset == 0)
4796           {
4797             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4798             {
4799                 TR_AP("#4");
4800                 emitcode("add", "a, %s", DP2_RESULT_REG);
4801             }
4802             else
4803             {
4804                 emitcode ("add", "a,%s",
4805                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4806                                   DP2_RESULT_REG));
4807             }
4808           }
4809           else
4810           {
4811             emitcode ("addc", "a,%s",
4812                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4813                           DP2_RESULT_REG));
4814           }
4815         }
4816       if (!pushResult)
4817         {
4818           aopPut (IC_RESULT (ic), "a", offset);
4819         }
4820       else
4821         {
4822           emitcode ("push", "acc");
4823         }
4824       offset++;
4825     }
4826   _endLazyDPSEvaluation ();
4827
4828   if (pushResult)
4829     {
4830       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4831
4832       size = getDataSize (IC_LEFT (ic));
4833       rSize = getDataSize (IC_RESULT (ic));
4834
4835       ADJUST_PUSHED_RESULT(size, rSize);
4836
4837       _startLazyDPSEvaluation ();
4838       while (size--)
4839         {
4840           emitcode ("pop", "acc");
4841           aopPut (IC_RESULT (ic), "a", size);
4842         }
4843       _endLazyDPSEvaluation ();
4844     }
4845
4846   adjustArithmeticResult (ic);
4847
4848 release:
4849   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4850   if (!swappedLR)
4851     {
4852       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4853       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4854     }
4855   else
4856     {
4857       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4858       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4859     }
4860 }
4861
4862 /*-----------------------------------------------------------------*/
4863 /* genMinusDec :- does subtraction with decrement if possible      */
4864 /*-----------------------------------------------------------------*/
4865 static bool
4866 genMinusDec (iCode * ic)
4867 {
4868   unsigned int icount;
4869   unsigned int size = getDataSize (IC_RESULT (ic));
4870
4871   /* will try to generate an increment */
4872   /* if the right side is not a literal
4873      we cannot */
4874   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4875     return FALSE;
4876
4877   /* if the literal value of the right hand side
4878      is greater than 4 then it is not worth it */
4879   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4880     return FALSE;
4881
4882   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4883       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4884       while (icount--) {
4885           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4886       }
4887       return TRUE;
4888   }
4889   /* if decrement 16 bits in register */
4890   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4891       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4892       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4893       (size > 1) &&
4894       (icount == 1))
4895     {
4896       symbol *tlbl;
4897       int    emitTlbl;
4898       int    labelRange;
4899       char   *l;
4900
4901       /* If the next instruction is a goto and the goto target
4902          * is <= 5 instructions previous to this, we can generate
4903          * jumps straight to that target.
4904        */
4905       if (ic->next && ic->next->op == GOTO
4906           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4907           && labelRange <= 5)
4908         {
4909           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4910           tlbl = IC_LABEL (ic->next);
4911           emitTlbl = 0;
4912         }
4913       else
4914         {
4915           tlbl = newiTempLabel (NULL);
4916           emitTlbl = 1;
4917         }
4918
4919       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4920       emitcode ("dec", "%s", l);
4921
4922       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4923           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4924           IS_AOP_PREG (IC_RESULT (ic)))
4925       {
4926           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4927       }
4928       else
4929       {
4930           emitcode ("mov", "a,#!constbyte",0xff);
4931           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4932       }
4933       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4934       emitcode ("dec", "%s", l);
4935       if (size > 2)
4936         {
4937             if (!strcmp(l, "acc"))
4938             {
4939                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4940             }
4941             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4942                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4943                      IS_AOP_PREG (IC_RESULT (ic)))
4944             {
4945                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4946             }
4947             else
4948             {
4949                 emitcode ("mov", "a,#!constbyte",0xff);
4950                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4951             }
4952             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4953             emitcode ("dec", "%s", l);
4954         }
4955       if (size > 3)
4956         {
4957             if (!strcmp(l, "acc"))
4958             {
4959                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4960             }
4961             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4962                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4963                      IS_AOP_PREG (IC_RESULT (ic)))
4964             {
4965                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4966             }
4967             else
4968             {
4969                 emitcode ("mov", "a,#!constbyte",0xff);
4970                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4971             }
4972             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4973             emitcode ("dec", "%s", l);
4974         }
4975       if (emitTlbl)
4976         {
4977           emitLabel (tlbl);
4978         }
4979       return TRUE;
4980     }
4981
4982   /* if the sizes are greater than 1 then we cannot */
4983   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4984       AOP_SIZE (IC_LEFT (ic)) > 1)
4985     return FALSE;
4986
4987   /* we can if the aops of the left & result match or
4988      if they are in registers and the registers are the
4989      same */
4990   if (
4991        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4992        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4993        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4994     {
4995       char *l;
4996
4997       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4998         {
4999           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
5000           l = "a";
5001         }
5002       else
5003         {
5004           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5005         }
5006
5007       _startLazyDPSEvaluation ();
5008       while (icount--)
5009         {
5010           emitcode ("dec", "%s", l);
5011         }
5012       _endLazyDPSEvaluation ();
5013
5014       if (AOP_NEEDSACC (IC_RESULT (ic)))
5015         aopPut (IC_RESULT (ic), "a", 0);
5016
5017       return TRUE;
5018     }
5019
5020   return FALSE;
5021 }
5022
5023 /*-----------------------------------------------------------------*/
5024 /* addSign - complete with sign                                    */
5025 /*-----------------------------------------------------------------*/
5026 static void
5027 addSign (operand * result, int offset, int sign)
5028 {
5029   int size = (getDataSize (result) - offset);
5030   if (size > 0)
5031     {
5032       _startLazyDPSEvaluation();
5033       if (sign)
5034         {
5035           emitcode ("rlc", "a");
5036           emitcode ("subb", "a,acc");
5037           while (size--)
5038             {
5039               aopPut (result, "a", offset++);
5040             }
5041         }
5042       else
5043       {
5044         while (size--)
5045         {
5046           aopPut (result, zero, offset++);
5047         }
5048       }
5049       _endLazyDPSEvaluation();
5050     }
5051 }
5052
5053 /*-----------------------------------------------------------------*/
5054 /* genMinusBits - generates code for subtraction  of two bits      */
5055 /*-----------------------------------------------------------------*/
5056 static void
5057 genMinusBits (iCode * ic)
5058 {
5059   symbol *lbl = newiTempLabel (NULL);
5060
5061   D (emitcode (";", "genMinusBits"));
5062
5063   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5064     {
5065       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5066       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5067       emitcode ("cpl", "c");
5068       emitLabel (lbl);
5069       outBitC (IC_RESULT (ic));
5070     }
5071   else
5072     {
5073       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5074       emitcode ("subb", "a,acc");
5075       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5076       emitcode ("inc", "a");
5077       emitLabel (lbl);
5078       aopPut (IC_RESULT (ic), "a", 0);
5079       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5080     }
5081 }
5082
5083 /*-----------------------------------------------------------------*/
5084 /* genMinus - generates code for subtraction                       */
5085 /*-----------------------------------------------------------------*/
5086 static void
5087 genMinus (iCode * ic)
5088 {
5089     int size, offset = 0;
5090     int rSize;
5091     long lit = 0L;
5092     bool pushResult;
5093
5094     D (emitcode (";", "genMinus"));
5095
5096     AOP_OP_3_NOFATAL(ic, pushResult);
5097
5098     if (!pushResult)
5099     {
5100       /* special cases :- */
5101       /* if both left & right are in bit space */
5102       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5103           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5104         {
5105           genMinusBits (ic);
5106           goto release;
5107         }
5108
5109       /* if I can do an decrement instead
5110          of subtract then GOOD for ME */
5111       if (genMinusDec (ic) == TRUE)
5112         goto release;
5113
5114     }
5115
5116   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5117
5118   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5119     {
5120       CLRC;
5121     }
5122   else
5123     {
5124       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5125       lit = -lit;
5126     }
5127
5128
5129   /* if literal, add a,#-lit, else normal subb */
5130   _startLazyDPSEvaluation ();
5131   while (size--) {
5132       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5133           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5134               emitcode ("mov","b,%s",
5135                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5136               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5137               emitcode ("subb","a,b");
5138           } else {
5139               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5140               emitcode ("subb", "a,%s",
5141                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5142                                 DP2_RESULT_REG));
5143           }
5144       } else {
5145           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5146           /* first add without previous c */
5147           if (!offset) {
5148               if (!size && lit==-1) {
5149                   emitcode ("dec", "a");
5150               } else {
5151                   emitcode ("add", "a,#!constbyte",
5152                             (unsigned int) (lit & 0x0FFL));
5153               }
5154           } else {
5155               emitcode ("addc", "a,#!constbyte",
5156                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5157           }
5158       }
5159
5160       if (pushResult) {
5161           emitcode ("push", "acc");
5162       } else {
5163           aopPut (IC_RESULT (ic), "a", offset);
5164       }
5165       offset++;
5166   }
5167   _endLazyDPSEvaluation ();
5168
5169   if (pushResult)
5170     {
5171       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5172
5173       size = getDataSize (IC_LEFT (ic));
5174       rSize = getDataSize (IC_RESULT (ic));
5175
5176       ADJUST_PUSHED_RESULT(size, rSize);
5177
5178       _startLazyDPSEvaluation ();
5179       while (size--)
5180         {
5181           emitcode ("pop", "acc");
5182           aopPut (IC_RESULT (ic), "a", size);
5183         }
5184       _endLazyDPSEvaluation ();
5185     }
5186
5187   adjustArithmeticResult (ic);
5188
5189 release:
5190   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5191   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5192   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5193 }
5194
5195
5196 /*-----------------------------------------------------------------*/
5197 /* genMultbits :- multiplication of bits                           */
5198 /*-----------------------------------------------------------------*/
5199 static void
5200 genMultbits (operand * left,
5201              operand * right,
5202              operand * result,
5203              iCode   * ic)
5204 {
5205   D (emitcode (";", "genMultbits"));
5206
5207   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5208   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5209   aopOp(result, ic, TRUE, FALSE);
5210   outBitC (result);
5211 }
5212
5213 /*-----------------------------------------------------------------*/
5214 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5215 /*-----------------------------------------------------------------*/
5216 static void
5217 genMultOneByte (operand * left,
5218                 operand * right,
5219                 operand * result,
5220                 iCode   * ic)
5221 {
5222   symbol *lbl;
5223   int size;
5224   bool runtimeSign, compiletimeSign;
5225   bool lUnsigned, rUnsigned, pushedB;
5226
5227   /* (if two literals: the value is computed before) */
5228   /* if one literal, literal on the right */
5229   if (AOP_TYPE (left) == AOP_LIT)
5230     {
5231       operand *t = right;
5232       right = left;
5233       left = t;
5234       /* emitcode (";", "swapped left and right"); */
5235     }
5236   /* if no literal, unsigned on the right: shorter code */
5237   if (   AOP_TYPE (right) != AOP_LIT
5238       && SPEC_USIGN (getSpec (operandType (left))))
5239     {
5240       operand *t = right;
5241       right = left;
5242       left = t;
5243     }
5244
5245   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5246   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5247
5248   pushedB = pushB ();
5249
5250   if ((lUnsigned && rUnsigned)
5251 /* sorry, I don't know how to get size
5252    without calling aopOp (result,...);
5253    see Feature Request  */
5254       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5255                    no need to take care about the signedness! */
5256     {
5257       /* just an unsigned 8 * 8 = 8 multiply
5258          or 8u * 8u = 16u */
5259       /* emitcode (";","unsigned"); */
5260       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5261       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5262       emitcode ("mul", "ab");
5263
5264       _G.accInUse++;
5265       aopOp (result, ic, TRUE, FALSE);
5266       size = AOP_SIZE (result);
5267
5268       if (size < 1 || size > 2)
5269         {
5270           /* this should never happen */
5271           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5272                    size, __FILE__, lineno);
5273           exit (1);
5274         }
5275
5276       aopPut (result, "a", 0);
5277       _G.accInUse--;
5278       if (size == 2)
5279         aopPut (result, "b", 1);
5280
5281       popB (pushedB);
5282       return;
5283     }
5284
5285   /* we have to do a signed multiply */
5286   /* emitcode (";", "signed"); */
5287
5288   /* now sign adjust for both left & right */
5289
5290   /* let's see what's needed: */
5291   /* apply negative sign during runtime */
5292   runtimeSign = FALSE;
5293   /* negative sign from literals */
5294   compiletimeSign = FALSE;
5295
5296   if (!lUnsigned)
5297     {
5298       if (AOP_TYPE(left) == AOP_LIT)
5299         {
5300           /* signed literal */
5301           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5302           if (val < 0)
5303             compiletimeSign = TRUE;
5304         }
5305       else
5306         /* signed but not literal */
5307         runtimeSign = TRUE;
5308     }
5309
5310   if (!rUnsigned)
5311     {
5312       if (AOP_TYPE(right) == AOP_LIT)
5313         {
5314           /* signed literal */
5315           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5316           if (val < 0)
5317             compiletimeSign ^= TRUE;
5318         }
5319       else
5320         /* signed but not literal */
5321         runtimeSign = TRUE;
5322     }
5323
5324   /* initialize F0, which stores the runtime sign */
5325   if (runtimeSign)
5326     {
5327       if (compiletimeSign)
5328         emitcode ("setb", "F0"); /* set sign flag */
5329       else
5330         emitcode ("clr", "F0"); /* reset sign flag */
5331     }
5332
5333   /* save the signs of the operands */
5334   if (AOP_TYPE(right) == AOP_LIT)
5335     {
5336       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5337
5338       if (!rUnsigned && val < 0)
5339         emitcode ("mov", "b,#!constbyte", -val);
5340       else
5341         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5342     }
5343   else /* ! literal */
5344     {
5345       if (rUnsigned)  /* emitcode (";", "signed"); */
5346         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5347       else
5348         {
5349           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5350           lbl = newiTempLabel (NULL);
5351           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5352           emitcode ("cpl", "F0"); /* complement sign flag */
5353           emitcode ("cpl", "a");  /* 2's complement */
5354           emitcode ("inc", "a");
5355           emitLabel (lbl);
5356           emitcode ("mov", "b,a");
5357         }
5358     }
5359
5360   if (AOP_TYPE(left) == AOP_LIT)
5361     {
5362       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5363
5364       if (!lUnsigned && val < 0)
5365         emitcode ("mov", "a,#!constbyte", -val);
5366       else
5367         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5368     }
5369   else /* ! literal */
5370     {
5371       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5372
5373       if (!lUnsigned)  /* emitcode (";", "signed"); */
5374         {
5375           lbl = newiTempLabel (NULL);
5376           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5377           emitcode ("cpl", "F0"); /* complement sign flag */
5378           emitcode ("cpl", "a");  /* 2's complement */
5379           emitcode ("inc", "a");
5380           emitLabel (lbl);
5381         }
5382     }
5383
5384   /* now the multiplication */
5385   emitcode ("mul", "ab");
5386   _G.accInUse++;
5387   aopOp(result, ic, TRUE, FALSE);
5388   size = AOP_SIZE (result);
5389
5390   if (size < 1 || size > 2)
5391     {
5392       /* this should never happen */
5393       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5394                size, __FILE__, lineno);
5395       exit (1);
5396     }
5397
5398   if (runtimeSign || compiletimeSign)
5399     {
5400       lbl = newiTempLabel (NULL);
5401       if (runtimeSign)
5402         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5403       emitcode ("cpl", "a"); /* lsb 2's complement */
5404       if (size != 2)
5405         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5406       else
5407         {
5408           emitcode ("add", "a,#1"); /* this sets carry flag */
5409           emitcode ("xch", "a,b");
5410           emitcode ("cpl", "a"); /* msb 2's complement */
5411           emitcode ("addc", "a,#0");
5412           emitcode ("xch", "a,b");
5413         }
5414       emitLabel (lbl);
5415     }
5416   aopPut (result, "a", 0);
5417   _G.accInUse--;
5418   if (size == 2)
5419     aopPut (result, "b", 1);
5420
5421   popB (pushedB);
5422 }
5423
5424 /*-----------------------------------------------------------------*/
5425 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5426 /*-----------------------------------------------------------------*/
5427 static void genMultTwoByte (operand *left, operand *right,
5428                             operand *result, iCode *ic)
5429 {
5430         sym_link *retype = getSpec(operandType(right));
5431         sym_link *letype = getSpec(operandType(left));
5432         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5433         symbol *lbl;
5434
5435         if (AOP_TYPE (left) == AOP_LIT) {
5436                 operand *t = right;
5437                 right = left;
5438                 left = t;
5439         }
5440         /* save EA bit in F1 */
5441         lbl = newiTempLabel(NULL);
5442         emitcode ("setb","F1");
5443         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5444         emitcode ("clr","F1");
5445         emitLabel (lbl);
5446
5447         /* load up MB with right */
5448         if (!umult) {
5449                 emitcode("clr","F0");
5450                 if (AOP_TYPE(right) == AOP_LIT) {
5451                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5452                         if (val < 0) {
5453                                 emitcode("setb","F0");
5454                                 val = -val;
5455                         }
5456                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5457                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5458                 } else {
5459                         lbl = newiTempLabel(NULL);
5460                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5461                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5462                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5463                         emitcode ("xch", "a,b");
5464                         emitcode ("cpl","a");
5465                         emitcode ("add", "a,#1");
5466                         emitcode ("xch", "a,b");
5467                         emitcode ("cpl", "a"); // msb
5468                         emitcode ("addc", "a,#0");
5469                         emitcode ("setb","F0");
5470                         emitLabel (lbl);
5471                         emitcode ("mov","mb,b");
5472                         emitcode ("mov","mb,a");
5473                 }
5474         } else {
5475                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5476                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5477         }
5478         /* load up MA with left */
5479         if (!umult) {
5480                 lbl = newiTempLabel(NULL);
5481                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5482                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5483                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5484                 emitcode ("xch", "a,b");
5485                 emitcode ("cpl","a");
5486                 emitcode ("add", "a,#1");
5487                 emitcode ("xch", "a,b");
5488                 emitcode ("cpl", "a"); // msb
5489                 emitcode ("addc","a,#0");
5490                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5491                 emitcode ("setb","F0");
5492                 emitLabel (lbl);
5493                 emitcode ("mov","ma,b");
5494                 emitcode ("mov","ma,a");
5495         } else {
5496                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5497                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5498         }
5499         /* wait for multiplication to finish */
5500         lbl = newiTempLabel(NULL);
5501         emitLabel (lbl);
5502         emitcode("mov","a,mcnt1");
5503         emitcode("anl","a,#!constbyte",0x80);
5504         emitcode("jnz","!tlabel",lbl->key+100);
5505
5506         freeAsmop (left, NULL, ic, TRUE);
5507         freeAsmop (right, NULL, ic,TRUE);
5508         aopOp(result, ic, TRUE, FALSE);
5509
5510         /* if unsigned then simple */
5511         if (umult) {
5512                 emitcode ("mov","a,ma");
5513                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5514                 emitcode ("mov","a,ma");
5515                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5516                 aopPut(result,"ma",1);
5517                 aopPut(result,"ma",0);
5518         } else {
5519                 emitcode("push","ma");
5520                 emitcode("push","ma");
5521                 emitcode("push","ma");
5522                 MOVA("ma");
5523                 /* negate result if needed */
5524                 lbl = newiTempLabel(NULL);
5525                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5526                 emitcode("cpl","a");
5527                 emitcode("add","a,#1");
5528                 emitLabel (lbl);
5529                 if (AOP_TYPE(result) == AOP_ACC)
5530                 {
5531                     D (emitcode(";", "ACC special case."));
5532                     /* We know result is the only live aop, and
5533                      * it's obviously not a DPTR2, so AP is available.
5534                      */
5535                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5536                 }
5537                 else
5538                 {
5539                     aopPut(result,"a",0);
5540                 }
5541
5542                 emitcode("pop","acc");
5543                 lbl = newiTempLabel(NULL);
5544                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5545                 emitcode("cpl","a");
5546                 emitcode("addc","a,#0");
5547                 emitLabel (lbl);
5548                 aopPut(result,"a",1);
5549                 emitcode("pop","acc");
5550                 if (AOP_SIZE(result) >= 3) {
5551                         lbl = newiTempLabel(NULL);
5552                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5553                         emitcode("cpl","a");
5554                         emitcode("addc","a,#0");
5555                         emitLabel (lbl);
5556                         aopPut(result,"a",2);
5557                 }
5558                 emitcode("pop","acc");
5559                 if (AOP_SIZE(result) >= 4) {
5560                         lbl = newiTempLabel(NULL);
5561                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5562                         emitcode("cpl","a");
5563                         emitcode("addc","a,#0");
5564                         emitLabel (lbl);
5565                         aopPut(result,"a",3);
5566                 }
5567                 if (AOP_TYPE(result) == AOP_ACC)
5568                 {
5569                     /* We stashed the result away above. */
5570                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5571                 }
5572
5573         }
5574         freeAsmop (result, NULL, ic, TRUE);
5575
5576         /* restore EA bit in F1 */
5577         lbl = newiTempLabel(NULL);
5578         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5579         emitcode ("setb","EA");
5580         emitLabel (lbl);
5581         return ;
5582 }
5583
5584 /*-----------------------------------------------------------------*/
5585 /* genMult - generates code for multiplication                     */
5586 /*-----------------------------------------------------------------*/
5587 static void
5588 genMult (iCode * ic)
5589 {
5590   operand *left = IC_LEFT (ic);
5591   operand *right = IC_RIGHT (ic);
5592   operand *result = IC_RESULT (ic);
5593
5594   D (emitcode (";", "genMult"));
5595
5596   /* assign the asmops */
5597   AOP_OP_2 (ic);
5598
5599   /* special cases first */
5600   /* both are bits */
5601   if (AOP_TYPE (left) == AOP_CRY &&
5602       AOP_TYPE (right) == AOP_CRY)
5603     {
5604       genMultbits (left, right, result, ic);
5605       goto release;
5606     }
5607
5608   /* if both are of size == 1 */
5609   if (AOP_SIZE (left) == 1 &&
5610       AOP_SIZE (right) == 1)
5611     {
5612       genMultOneByte (left, right, result, ic);
5613       goto release;
5614     }
5615
5616   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5617           /* use the ds390 ARITHMETIC accel UNIT */
5618           genMultTwoByte (left, right, result, ic);
5619           return ;
5620   }
5621   /* should have been converted to function call */
5622   assert (0);
5623
5624 release:
5625   freeAsmop (result, NULL, ic, TRUE);
5626   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5627   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5628 }
5629
5630 /*-----------------------------------------------------------------*/
5631 /* genDivbits :- division of bits                                  */
5632 /*-----------------------------------------------------------------*/
5633 static void
5634 genDivbits (operand * left,
5635             operand * right,
5636             operand * result,
5637             iCode   * ic)
5638 {
5639   char *l;
5640   bool pushedB;
5641
5642   D(emitcode (";     genDivbits",""));
5643
5644   pushedB = pushB ();
5645
5646   /* the result must be bit */
5647   LOAD_AB_FOR_DIV (left, right, l);
5648   emitcode ("div", "ab");
5649   emitcode ("rrc", "a");
5650   aopOp(result, ic, TRUE, FALSE);
5651
5652   popB (pushedB);
5653
5654   aopPut (result, "c", 0);
5655 }
5656
5657 /*-----------------------------------------------------------------*/
5658 /* genDivOneByte : 8 bit division                                  */
5659 /*-----------------------------------------------------------------*/
5660 static void
5661 genDivOneByte (operand * left,
5662                operand * right,
5663                operand * result,
5664                iCode   * ic)
5665 {
5666   bool lUnsigned, rUnsigned, pushedB;
5667   bool runtimeSign, compiletimeSign;
5668   char *l;
5669   symbol *lbl;
5670   int size, offset;
5671
5672   D(emitcode (";     genDivOneByte",""));
5673
5674   offset = 1;
5675   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5676   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5677
5678   pushedB = pushB ();
5679
5680   /* signed or unsigned */
5681   if (lUnsigned && rUnsigned)
5682     {
5683       /* unsigned is easy */
5684       LOAD_AB_FOR_DIV (left, right, l);
5685       emitcode ("div", "ab");
5686
5687       _G.accInUse++;
5688       aopOp (result, ic, TRUE, FALSE);
5689       aopPut (result, "a", 0);
5690       _G.accInUse--;
5691
5692       size = AOP_SIZE (result) - 1;
5693
5694       while (size--)
5695         aopPut (result, zero, offset++);
5696
5697       popB (pushedB);
5698       return;
5699     }
5700
5701   /* signed is a little bit more difficult */
5702
5703   /* now sign adjust for both left & right */
5704
5705   /* let's see what's needed: */
5706   /* apply negative sign during runtime */
5707   runtimeSign = FALSE;
5708   /* negative sign from literals */
5709   compiletimeSign = FALSE;
5710
5711   if (!lUnsigned)
5712     {
5713       if (AOP_TYPE(left) == AOP_LIT)
5714         {
5715           /* signed literal */
5716           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5717           if (val < 0)
5718             compiletimeSign = TRUE;
5719         }
5720       else
5721         /* signed but not literal */
5722         runtimeSign = TRUE;
5723     }
5724
5725   if (!rUnsigned)
5726     {
5727       if (AOP_TYPE(right) == AOP_LIT)
5728         {
5729           /* signed literal */
5730           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5731           if (val < 0)
5732             compiletimeSign ^= TRUE;
5733         }
5734       else
5735         /* signed but not literal */
5736         runtimeSign = TRUE;
5737     }
5738
5739   /* initialize F0, which stores the runtime sign */
5740   if (runtimeSign)
5741     {
5742       if (compiletimeSign)
5743         emitcode ("setb", "F0"); /* set sign flag */
5744       else
5745         emitcode ("clr", "F0"); /* reset sign flag */
5746     }
5747
5748   /* save the signs of the operands */
5749   if (AOP_TYPE(right) == AOP_LIT)
5750     {
5751       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5752
5753       if (!rUnsigned && val < 0)
5754         emitcode ("mov", "b,#0x%02x", -val);
5755       else
5756         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5757     }
5758   else /* ! literal */
5759     {
5760       if (rUnsigned)
5761         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5762       else
5763         {
5764           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5765           lbl = newiTempLabel (NULL);
5766           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5767           emitcode ("cpl", "F0"); /* complement sign flag */
5768           emitcode ("cpl", "a");  /* 2's complement */
5769           emitcode ("inc", "a");
5770           emitLabel (lbl);
5771           emitcode ("mov", "b,a");
5772         }
5773     }
5774
5775   if (AOP_TYPE(left) == AOP_LIT)
5776     {
5777       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5778
5779       if (!lUnsigned && val < 0)
5780         emitcode ("mov", "a,#0x%02x", -val);
5781       else
5782         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5783     }
5784   else /* ! literal */
5785     {
5786       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5787
5788       if (!lUnsigned)
5789         {
5790           lbl = newiTempLabel (NULL);
5791           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5792           emitcode ("cpl", "F0"); /* complement sign flag */
5793           emitcode ("cpl", "a");  /* 2's complement */
5794           emitcode ("inc", "a");
5795           emitLabel (lbl);
5796         }
5797     }
5798
5799   /* now the division */
5800   emitcode ("nop", "; workaround for DS80C390 div bug.");
5801   emitcode ("div", "ab");
5802
5803   if (runtimeSign || compiletimeSign)
5804     {
5805       lbl = newiTempLabel (NULL);
5806       if (runtimeSign)
5807         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5808       emitcode ("cpl", "a"); /* lsb 2's complement */
5809       emitcode ("inc", "a");
5810       emitLabel (lbl);
5811
5812       _G.accInUse++;
5813       aopOp (result, ic, TRUE, FALSE);
5814       size = AOP_SIZE (result) - 1;
5815
5816       if (size > 0)
5817         {
5818           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5819              then the result will be in b, a */
5820           emitcode ("mov", "b,a"); /* 1 */
5821           /* msb is 0x00 or 0xff depending on the sign */
5822           if (runtimeSign)
5823             {
5824               emitcode ("mov",  "c,F0");
5825               emitcode ("subb", "a,acc");
5826               emitcode ("xch",  "a,b"); /* 2 */
5827               while (size--)
5828                 aopPut (result, "b", offset++); /* write msb's */
5829             }
5830           else /* compiletimeSign */
5831             while (size--)
5832               aopPut (result, "#0xff", offset++); /* write msb's */
5833         }
5834       aopPut (result, "a", 0); /* 3: write lsb */
5835     }
5836   else
5837     {
5838       _G.accInUse++;
5839       aopOp(result, ic, TRUE, FALSE);
5840       size = AOP_SIZE (result) - 1;
5841
5842       aopPut (result, "a", 0);
5843       while (size--)
5844         aopPut (result, zero, offset++);
5845     }
5846   _G.accInUse--;
5847   popB (pushedB);
5848 }
5849
5850 /*-----------------------------------------------------------------*/
5851 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5852 /*-----------------------------------------------------------------*/
5853 static void genDivTwoByte (operand *left, operand *right,
5854                             operand *result, iCode *ic)
5855 {
5856         sym_link *retype = getSpec(operandType(right));
5857         sym_link *letype = getSpec(operandType(left));
5858         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5859         symbol *lbl;
5860
5861         /* save EA bit in F1 */
5862         lbl = newiTempLabel(NULL);
5863         emitcode ("setb","F1");
5864         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5865         emitcode ("clr","F1");
5866         emitLabel (lbl);
5867
5868         /* load up MA with left */
5869         if (!umult) {
5870                 emitcode("clr","F0");
5871                 lbl = newiTempLabel(NULL);
5872                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5873                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5874                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5875                 emitcode ("xch", "a,b");
5876                 emitcode ("cpl","a");
5877                 emitcode ("add", "a,#1");
5878                 emitcode ("xch", "a,b");
5879                 emitcode ("cpl", "a"); // msb
5880                 emitcode ("addc","a,#0");
5881                 emitcode ("setb","F0");
5882                 emitLabel (lbl);
5883                 emitcode ("mov","ma,b");
5884                 emitcode ("mov","ma,a");
5885         } else {
5886                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5887                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5888         }
5889
5890         /* load up MB with right */
5891         if (!umult) {
5892                 if (AOP_TYPE(right) == AOP_LIT) {
5893                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5894                         if (val < 0) {
5895                                 lbl = newiTempLabel(NULL);
5896                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5897                                 emitcode("setb","F0");
5898                                 emitLabel (lbl);
5899                                 val = -val;
5900                         }
5901                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5902                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5903                 } else {
5904                         lbl = newiTempLabel(NULL);
5905                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5906                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5907                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5908                         emitcode ("xch", "a,b");
5909                         emitcode ("cpl","a");
5910                         emitcode ("add", "a,#1");
5911                         emitcode ("xch", "a,b");
5912                         emitcode ("cpl", "a"); // msb
5913                         emitcode ("addc", "a,#0");
5914                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5915                         emitcode ("setb","F0");
5916                         emitLabel (lbl);
5917                         emitcode ("mov","mb,b");
5918                         emitcode ("mov","mb,a");
5919                 }
5920         } else {
5921                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5922                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5923         }
5924
5925         /* wait for multiplication to finish */
5926         lbl = newiTempLabel(NULL);
5927         emitLabel (lbl);
5928         emitcode("mov","a,mcnt1");
5929         emitcode("anl","a,#!constbyte",0x80);
5930         emitcode("jnz","!tlabel",lbl->key+100);
5931
5932         freeAsmop (left, NULL, ic, TRUE);
5933         freeAsmop (right, NULL, ic,TRUE);
5934         aopOp(result, ic, TRUE, FALSE);
5935
5936         /* if unsigned then simple */
5937         if (umult) {
5938                 aopPut(result,"ma",1);
5939                 aopPut(result,"ma",0);
5940         } else {
5941                 emitcode("push","ma");
5942                 MOVA("ma");
5943                 /* negate result if needed */
5944                 lbl = newiTempLabel(NULL);
5945                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5946                 emitcode("cpl","a");
5947                 emitcode("add","a,#1");
5948                 emitLabel (lbl);
5949                 aopPut(result,"a",0);
5950                 emitcode("pop","acc");
5951                 lbl = newiTempLabel(NULL);
5952                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5953                 emitcode("cpl","a");
5954                 emitcode("addc","a,#0");
5955                 emitLabel (lbl);
5956                 aopPut(result,"a",1);
5957         }
5958         freeAsmop (result, NULL, ic, TRUE);
5959         /* restore EA bit in F1 */
5960         lbl = newiTempLabel(NULL);
5961         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5962         emitcode ("setb","EA");
5963         emitLabel (lbl);
5964         return ;
5965 }
5966
5967 /*-----------------------------------------------------------------*/
5968 /* genDiv - generates code for division                            */
5969 /*-----------------------------------------------------------------*/
5970 static void
5971 genDiv (iCode * ic)
5972 {
5973   operand *left = IC_LEFT (ic);
5974   operand *right = IC_RIGHT (ic);
5975   operand *result = IC_RESULT (ic);
5976
5977   D (emitcode (";", "genDiv"));
5978
5979   /* assign the amsops */
5980   AOP_OP_2 (ic);
5981
5982   /* special cases first */
5983   /* both are bits */
5984   if (AOP_TYPE (left) == AOP_CRY &&
5985       AOP_TYPE (right) == AOP_CRY)
5986     {
5987       genDivbits (left, right, result, ic);
5988       goto release;
5989     }
5990
5991   /* if both are of size == 1 */
5992   if (AOP_SIZE (left) == 1 &&
5993       AOP_SIZE (right) == 1)
5994     {
5995       genDivOneByte (left, right, result, ic);
5996       goto release;
5997     }
5998
5999   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6000           /* use the ds390 ARITHMETIC accel UNIT */
6001           genDivTwoByte (left, right, result, ic);
6002           return ;
6003   }
6004   /* should have been converted to function call */
6005   assert (0);
6006 release:
6007   freeAsmop (result, NULL, ic, TRUE);
6008   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6009   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6010 }
6011
6012 /*-----------------------------------------------------------------*/
6013 /* genModbits :- modulus of bits                                   */
6014 /*-----------------------------------------------------------------*/
6015 static void
6016 genModbits (operand * left,
6017             operand * right,
6018             operand * result,
6019             iCode   * ic)
6020 {
6021   char *l;
6022   bool pushedB;
6023
6024   D (emitcode (";", "genModbits"));
6025
6026   pushedB = pushB ();
6027
6028   /* the result must be bit */
6029   LOAD_AB_FOR_DIV (left, right, l);
6030   emitcode ("div", "ab");
6031   emitcode ("mov", "a,b");
6032   emitcode ("rrc", "a");
6033   aopOp(result, ic, TRUE, FALSE);
6034
6035   popB (pushedB);
6036
6037   aopPut (result, "c", 0);
6038 }
6039
6040 /*-----------------------------------------------------------------*/
6041 /* genModOneByte : 8 bit modulus                                   */
6042 /*-----------------------------------------------------------------*/
6043 static void
6044 genModOneByte (operand * left,
6045                operand * right,
6046                operand * result,
6047                iCode   * ic)
6048 {
6049   bool lUnsigned, rUnsigned, pushedB;
6050   bool runtimeSign, compiletimeSign;
6051   char *l;
6052   symbol *lbl;
6053   int size, offset;
6054
6055   D (emitcode (";", "genModOneByte"));
6056
6057   offset = 1;
6058   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6059   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6060
6061   pushedB = pushB ();
6062
6063   /* signed or unsigned */
6064   if (lUnsigned && rUnsigned)
6065     {
6066       /* unsigned is easy */
6067       LOAD_AB_FOR_DIV (left, right, l);
6068       emitcode ("div", "ab");
6069       aopOp (result, ic, TRUE, FALSE);
6070       aopPut (result, "b", 0);
6071
6072       for (size = AOP_SIZE (result) - 1; size--;)
6073         aopPut (result, zero, offset++);
6074
6075       popB (pushedB);
6076       return;
6077     }
6078
6079   /* signed is a little bit more difficult */
6080
6081   /* now sign adjust for both left & right */
6082
6083   /* modulus: sign of the right operand has no influence on the result! */
6084   if (AOP_TYPE(right) == AOP_LIT)
6085     {
6086       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
6087
6088       if (!rUnsigned && val < 0)
6089         emitcode ("mov", "b,#0x%02x", -val);
6090       else
6091         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6092     }
6093   else /* not literal */
6094     {
6095       if (rUnsigned)
6096         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6097       else
6098         {
6099           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6100           lbl = newiTempLabel (NULL);
6101           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6102           emitcode ("cpl", "a");  /* 2's complement */
6103           emitcode ("inc", "a");
6104           emitLabel (lbl);
6105           emitcode ("mov", "b,a");
6106         }
6107     }
6108
6109   /* let's see what's needed: */
6110   /* apply negative sign during runtime */
6111   runtimeSign = FALSE;
6112   /* negative sign from literals */
6113   compiletimeSign = FALSE;
6114
6115   /* sign adjust left side */
6116   if (AOP_TYPE(left) == AOP_LIT)
6117     {
6118       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
6119
6120       if (!lUnsigned && val < 0)
6121         {
6122           compiletimeSign = TRUE; /* set sign flag */
6123           emitcode ("mov", "a,#0x%02x", -val);
6124         }
6125       else
6126         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6127     }
6128   else /* ! literal */
6129     {
6130       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6131
6132       if (!lUnsigned)
6133         {
6134           runtimeSign = TRUE;
6135           emitcode ("clr", "F0"); /* clear sign flag */
6136
6137           lbl = newiTempLabel (NULL);
6138           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6139           emitcode ("setb", "F0"); /* set sign flag */
6140           emitcode ("cpl", "a");   /* 2's complement */
6141           emitcode ("inc", "a");
6142           emitLabel (lbl);
6143         }
6144     }
6145
6146   /* now the modulus */
6147   emitcode ("nop", "; workaround for DS80C390 div bug.");
6148   emitcode ("div", "ab");
6149
6150   if (runtimeSign || compiletimeSign)
6151     {
6152       emitcode ("mov", "a,b");
6153       lbl = newiTempLabel (NULL);
6154       if (runtimeSign)
6155         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6156       emitcode ("cpl", "a"); /* lsb 2's complement */
6157       emitcode ("inc", "a");
6158       emitLabel (lbl);
6159
6160       _G.accInUse++;
6161       aopOp (result, ic, TRUE, FALSE);
6162       size = AOP_SIZE (result) - 1;
6163
6164       if (size > 0)
6165         {
6166           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6167              then the result will be in b, a */
6168           emitcode ("mov", "b,a"); /* 1 */
6169           /* msb is 0x00 or 0xff depending on the sign */
6170           if (runtimeSign)
6171             {
6172               emitcode ("mov",  "c,F0");
6173               emitcode ("subb", "a,acc");
6174               emitcode ("xch",  "a,b"); /* 2 */
6175               while (size--)
6176                 aopPut (result, "b", offset++); /* write msb's */
6177             }
6178           else /* compiletimeSign */
6179             while (size--)
6180               aopPut (result, "#0xff", offset++); /* write msb's */
6181         }
6182       aopPut (result, "a", 0); /* 3: write lsb */
6183     }
6184   else
6185     {
6186       _G.accInUse++;
6187       aopOp(result, ic, TRUE, FALSE);
6188       size = AOP_SIZE (result) - 1;
6189
6190       aopPut (result, "b", 0);
6191       while (size--)
6192         aopPut (result, zero, offset++);
6193     }
6194   _G.accInUse--;
6195   popB (pushedB);
6196 }
6197
6198 /*-----------------------------------------------------------------*/
6199 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6200 /*-----------------------------------------------------------------*/
6201 static void genModTwoByte (operand *left, operand *right,
6202                             operand *result, iCode *ic)
6203 {
6204         sym_link *retype = getSpec(operandType(right));
6205         sym_link *letype = getSpec(operandType(left));
6206         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6207         symbol *lbl;
6208
6209         /* load up MA with left */
6210         /* save EA bit in F1 */
6211         lbl = newiTempLabel(NULL);
6212         emitcode ("setb","F1");
6213         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6214         emitcode ("clr","F1");
6215         emitLabel (lbl);
6216
6217         if (!umult) {
6218                 lbl = newiTempLabel(NULL);
6219                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6220                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6221                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6222                 emitcode ("xch", "a,b");
6223                 emitcode ("cpl","a");
6224                 emitcode ("add", "a,#1");
6225                 emitcode ("xch", "a,b");
6226                 emitcode ("cpl", "a"); // msb
6227                 emitcode ("addc","a,#0");
6228                 emitLabel (lbl);
6229                 emitcode ("mov","ma,b");
6230                 emitcode ("mov","ma,a");
6231         } else {
6232                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6233                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6234         }
6235
6236         /* load up MB with right */
6237         if (!umult) {
6238                 if (AOP_TYPE(right) == AOP_LIT) {
6239                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
6240                         if (val < 0) {
6241                                 val = -val;
6242                         }
6243                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6244                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6245                 } else {
6246                         lbl = newiTempLabel(NULL);
6247                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6248                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6249                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6250                         emitcode ("xch", "a,b");
6251                         emitcode ("cpl","a");
6252                         emitcode ("add", "a,#1");
6253                         emitcode ("xch", "a,b");
6254                         emitcode ("cpl", "a"); // msb
6255                         emitcode ("addc", "a,#0");
6256                         emitLabel (lbl);
6257                         emitcode ("mov","mb,b");
6258                         emitcode ("mov","mb,a");
6259                 }
6260         } else {
6261                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6262                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6263         }
6264
6265         /* wait for multiplication to finish */
6266         lbl = newiTempLabel(NULL);
6267         emitLabel (lbl);
6268         emitcode("mov","a,mcnt1");
6269         emitcode("anl","a,#!constbyte",0x80);
6270         emitcode("jnz","!tlabel",lbl->key+100);
6271
6272         freeAsmop (left, NULL, ic, TRUE);
6273         freeAsmop (right, NULL, ic,TRUE);
6274         aopOp(result, ic, TRUE, FALSE);
6275
6276         aopPut(result,"mb",1);
6277         aopPut(result,"mb",0);
6278         freeAsmop (result, NULL, ic, TRUE);
6279
6280         /* restore EA bit in F1 */
6281         lbl = newiTempLabel(NULL);
6282         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6283         emitcode ("setb","EA");
6284         emitLabel (lbl);
6285 }
6286
6287 /*-----------------------------------------------------------------*/
6288 /* genMod - generates code for division                            */
6289 /*-----------------------------------------------------------------*/
6290 static void
6291 genMod (iCode * ic)
6292 {
6293   operand *left = IC_LEFT (ic);
6294   operand *right = IC_RIGHT (ic);
6295   operand *result = IC_RESULT (ic);
6296
6297   D (emitcode (";", "genMod"));
6298
6299   /* assign the asmops */
6300   AOP_OP_2 (ic);
6301
6302   /* special cases first */
6303   /* both are bits */
6304   if (AOP_TYPE (left) == AOP_CRY &&
6305       AOP_TYPE (right) == AOP_CRY)
6306     {
6307       genModbits (left, right, result, ic);
6308       goto release;
6309     }
6310
6311   /* if both are of size == 1 */
6312   if (AOP_SIZE (left) == 1 &&
6313       AOP_SIZE (right) == 1)
6314     {
6315       genModOneByte (left, right, result, ic);
6316       goto release;
6317     }
6318
6319   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6320           /* use the ds390 ARITHMETIC accel UNIT */
6321           genModTwoByte (left, right, result, ic);
6322           return ;
6323   }
6324
6325   /* should have been converted to function call */
6326   assert (0);
6327
6328 release:
6329   freeAsmop (result, NULL, ic, TRUE);
6330   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6331   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6332 }
6333
6334 /*-----------------------------------------------------------------*/
6335 /* genIfxJump :- will create a jump depending on the ifx           */
6336 /*-----------------------------------------------------------------*/
6337 static void
6338 genIfxJump (iCode * ic, char *jval)
6339 {
6340   symbol *jlbl;
6341   symbol *tlbl = newiTempLabel (NULL);
6342   char *inst;
6343
6344   D (emitcode (";", "genIfxJump"));
6345
6346   /* if true label then we jump if condition
6347      supplied is true */
6348   if (IC_TRUE (ic))
6349     {
6350       jlbl = IC_TRUE (ic);
6351       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6352                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6353     }
6354   else
6355     {
6356       /* false label is present */
6357       jlbl = IC_FALSE (ic);
6358       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6359                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6360     }
6361   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6362     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6363   else
6364     emitcode (inst, "!tlabel", tlbl->key + 100);
6365   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6366   emitLabel (tlbl);
6367
6368   /* mark the icode as generated */
6369   ic->generated = 1;
6370 }
6371
6372 /*-----------------------------------------------------------------*/
6373 /* genCmp :- greater or less than comparison                       */
6374 /*-----------------------------------------------------------------*/
6375 static void
6376 genCmp (operand * left, operand * right,
6377         iCode * ic, iCode * ifx, int sign)
6378 {
6379   int size, offset = 0;
6380   unsigned long lit = 0L;
6381   operand *result;
6382
6383   D (emitcode (";", "genCmp"));
6384
6385   result = IC_RESULT (ic);
6386
6387   /* if left & right are bit variables */
6388   if (AOP_TYPE (left) == AOP_CRY &&
6389       AOP_TYPE (right) == AOP_CRY)
6390     {
6391       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6392       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6393     }
6394   else
6395     {
6396       /* subtract right from left if at the
6397          end the carry flag is set then we know that
6398          left is greater than right */
6399       size = max (AOP_SIZE (left), AOP_SIZE (right));
6400
6401       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6402       if ((size == 1) && !sign &&
6403           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6404         {
6405           symbol *lbl = newiTempLabel (NULL);
6406           emitcode ("cjne", "%s,%s,!tlabel",
6407                     aopGet (left, offset, FALSE, FALSE, NULL),
6408                     aopGet (right, offset, FALSE, FALSE, NULL),
6409                     lbl->key + 100);
6410           emitLabel (lbl);
6411         }
6412       else
6413         {
6414           if (AOP_TYPE (right) == AOP_LIT)
6415             {
6416               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6417               /* optimize if(x < 0) or if(x >= 0) */
6418               if (lit == 0L)
6419                 {
6420                   if (!sign)
6421                     {
6422                       CLRC;
6423                     }
6424                   else
6425                     {
6426                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6427
6428                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6429                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6430
6431                       aopOp (result, ic, FALSE, FALSE);
6432
6433                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6434                         {
6435                           freeAsmop (result, NULL, ic, TRUE);
6436                           genIfxJump (ifx, "acc.7");
6437                           return;
6438                         }
6439                       else
6440                         {
6441                           emitcode ("rlc", "a");
6442                         }
6443                       goto release_freedLR;
6444                     }
6445                   goto release;
6446                 }
6447             }
6448           CLRC;
6449           while (size--)
6450             {
6451               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6452               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6453               // emitcode (";", "genCmp #2");
6454               if (sign && (size == 0))
6455                 {
6456                   // emitcode (";", "genCmp #3");
6457                   emitcode ("xrl", "a,#!constbyte",0x80);
6458                   if (AOP_TYPE (right) == AOP_LIT)
6459                     {
6460                       unsigned long lit = (unsigned long)
6461                       floatFromVal (AOP (right)->aopu.aop_lit);
6462                       // emitcode (";", "genCmp #3.1");
6463                       emitcode ("subb", "a,#!constbyte",
6464                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6465                     }
6466                   else
6467                     {
6468                       // emitcode (";", "genCmp #3.2");
6469                       saveAccWarn = 0;
6470                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6471                       saveAccWarn = DEFAULT_ACC_WARNING;
6472                       emitcode ("xrl", "b,#!constbyte",0x80);
6473                       emitcode ("subb", "a,b");
6474                     }
6475                 }
6476               else
6477                 {
6478                   const char *s;
6479
6480                   // emitcode (";", "genCmp #4");
6481                   saveAccWarn = 0;
6482                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6483                   saveAccWarn = DEFAULT_ACC_WARNING;
6484
6485                   emitcode ("subb", "a,%s", s);
6486                 }
6487             }
6488         }
6489     }
6490
6491 release:
6492 /* Don't need the left & right operands any more; do need the result. */
6493   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6494   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6495
6496   aopOp (result, ic, FALSE, FALSE);
6497
6498 release_freedLR:
6499
6500   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6501     {
6502       outBitC (result);
6503     }
6504   else
6505     {
6506       /* if the result is used in the next
6507          ifx conditional branch then generate
6508          code a little differently */
6509       if (ifx)
6510         {
6511           genIfxJump (ifx, "c");
6512         }
6513       else
6514         {
6515           outBitC (result);
6516         }
6517       /* leave the result in acc */
6518     }
6519   freeAsmop (result, NULL, ic, TRUE);
6520 }
6521
6522 /*-----------------------------------------------------------------*/
6523 /* genCmpGt :- greater than comparison                             */
6524 /*-----------------------------------------------------------------*/
6525 static void
6526 genCmpGt (iCode * ic, iCode * ifx)
6527 {
6528   operand *left, *right;
6529   sym_link *letype, *retype;
6530   int sign;
6531
6532   D (emitcode (";", "genCmpGt"));
6533
6534   left = IC_LEFT (ic);
6535   right = IC_RIGHT (ic);
6536
6537   letype = getSpec (operandType (left));
6538   retype = getSpec (operandType (right));
6539   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6540
6541   /* assign the left & right amsops */
6542   AOP_OP_2 (ic);
6543
6544   genCmp (right, left, ic, ifx, sign);
6545 }
6546
6547 /*-----------------------------------------------------------------*/
6548 /* genCmpLt - less than comparisons                                */
6549 /*-----------------------------------------------------------------*/
6550 static void
6551 genCmpLt (iCode * ic, iCode * ifx)
6552 {
6553   operand *left, *right;
6554   sym_link *letype, *retype;
6555   int sign;
6556
6557   D (emitcode (";", "genCmpLt"));
6558
6559   left = IC_LEFT (ic);
6560   right = IC_RIGHT (ic);
6561
6562   letype = getSpec (operandType (left));
6563   retype = getSpec (operandType (right));
6564   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6565
6566   /* assign the left & right amsops */
6567   AOP_OP_2 (ic);
6568
6569   genCmp (left, right, ic, ifx, sign);
6570 }
6571
6572 /*-----------------------------------------------------------------*/
6573 /* gencjneshort - compare and jump if not equal                    */
6574 /*-----------------------------------------------------------------*/
6575 static void
6576 gencjneshort (operand * left, operand * right, symbol * lbl)
6577 {
6578   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6579   int offset = 0;
6580   unsigned long lit = 0L;
6581
6582   D (emitcode (";", "gencjneshort"));
6583
6584   /* if the left side is a literal or
6585      if the right is in a pointer register and left
6586      is not */
6587   if ((AOP_TYPE (left) == AOP_LIT) ||
6588       (AOP_TYPE (left) == AOP_IMMD) ||
6589       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6590     {
6591       operand *t = right;
6592       right = left;
6593       left = t;
6594     }
6595
6596   if (AOP_TYPE (right) == AOP_LIT)
6597     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6598
6599   if (opIsGptr (left) || opIsGptr (right))
6600     {
6601       /* We are comparing a generic pointer to something.
6602        * Exclude the generic type byte from the comparison.
6603        */
6604       size--;
6605       D (emitcode (";", "cjneshort: generic ptr special case."););
6606     }
6607
6608
6609   /* if the right side is a literal then anything goes */
6610   if (AOP_TYPE (right) == AOP_LIT &&
6611       AOP_TYPE (left) != AOP_DIR)
6612     {
6613       while (size--)
6614         {
6615           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6616           emitcode ("cjne", "a,%s,!tlabel",
6617                     aopGet (right, offset, FALSE, FALSE, NULL),
6618                     lbl->key + 100);
6619           offset++;
6620         }
6621     }
6622
6623   /* if the right side is in a register or in direct space or
6624      if the left is a pointer register & right is not */
6625   else if (AOP_TYPE (right) == AOP_REG ||
6626            AOP_TYPE (right) == AOP_DIR ||
6627            AOP_TYPE (right) == AOP_LIT ||
6628            AOP_TYPE (right) == AOP_IMMD ||
6629            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6630            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6631     {
6632       while (size--)
6633         {
6634           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6635           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6636               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6637             emitcode ("jnz", "!tlabel", lbl->key + 100);
6638           else
6639             emitcode ("cjne", "a,%s,!tlabel",
6640                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6641                       lbl->key + 100);
6642           offset++;
6643         }
6644     }
6645   else
6646     {
6647       /* right is a pointer reg need both a & b */
6648       while (size--)
6649         {
6650           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6651           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6652           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6653           offset++;
6654         }
6655     }
6656 }
6657
6658 /*-----------------------------------------------------------------*/
6659 /* gencjne - compare and jump if not equal                         */
6660 /*-----------------------------------------------------------------*/
6661 static void
6662 gencjne (operand * left, operand * right, symbol * lbl)
6663 {
6664   symbol *tlbl = newiTempLabel (NULL);
6665
6666   D (emitcode (";", "gencjne"));
6667
6668   gencjneshort (left, right, lbl);
6669
6670   emitcode ("mov", "a,%s", one);
6671   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6672   emitLabel (lbl);
6673   emitcode ("clr", "a");
6674   emitLabel (tlbl);
6675 }
6676
6677 /*-----------------------------------------------------------------*/
6678 /* genCmpEq - generates code for equal to                          */
6679 /*-----------------------------------------------------------------*/
6680 static void
6681 genCmpEq (iCode * ic, iCode * ifx)
6682 {
6683   operand *left, *right, *result;
6684
6685   D (emitcode (";", "genCmpEq"));
6686
6687   AOP_OP_2 (ic);
6688   AOP_SET_LOCALS (ic);
6689
6690   /* if literal, literal on the right or
6691      if the right is in a pointer register and left
6692      is not */
6693   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6694       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6695     {
6696       operand *t = IC_RIGHT (ic);
6697       IC_RIGHT (ic) = IC_LEFT (ic);
6698       IC_LEFT (ic) = t;
6699     }
6700
6701   if (ifx &&                    /* !AOP_SIZE(result) */
6702       OP_SYMBOL (result) &&
6703       OP_SYMBOL (result)->regType == REG_CND)
6704     {
6705       symbol *tlbl;
6706       /* if they are both bit variables */
6707       if (AOP_TYPE (left) == AOP_CRY &&
6708           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6709         {
6710           if (AOP_TYPE (right) == AOP_LIT)
6711             {
6712               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6713               if (lit == 0L)
6714                 {
6715                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6716                   emitcode ("cpl", "c");
6717                 }
6718               else if (lit == 1L)
6719                 {
6720                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6721                 }
6722               else
6723                 {
6724                   emitcode ("clr", "c");
6725                 }
6726               /* AOP_TYPE(right) == AOP_CRY */
6727             }
6728           else
6729             {
6730               symbol *lbl = newiTempLabel (NULL);
6731               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6732               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6733               emitcode ("cpl", "c");
6734               emitLabel (lbl);
6735             }
6736           /* if true label then we jump if condition
6737              supplied is true */
6738           tlbl = newiTempLabel (NULL);
6739           if (IC_TRUE (ifx))
6740             {
6741               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6742               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6743             }
6744           else
6745             {
6746               emitcode ("jc", "!tlabel", tlbl->key + 100);
6747               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6748             }
6749           emitLabel (tlbl);
6750         }
6751       else
6752         {
6753           tlbl = newiTempLabel (NULL);
6754           gencjneshort (left, right, tlbl);
6755           if (IC_TRUE (ifx))
6756             {
6757               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6758               emitLabel (tlbl);
6759             }
6760           else
6761             {
6762               symbol *lbl = newiTempLabel (NULL);
6763               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6764               emitLabel (tlbl);
6765               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6766               emitLabel (lbl);
6767             }
6768         }
6769       /* mark the icode as generated */
6770       ifx->generated = 1;
6771
6772       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6773       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6774       return;
6775     }
6776
6777   /* if they are both bit variables */
6778   if (AOP_TYPE (left) == AOP_CRY &&
6779       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6780     {
6781       if (AOP_TYPE (right) == AOP_LIT)
6782         {
6783           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6784           if (lit == 0L)
6785             {
6786               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6787               emitcode ("cpl", "c");
6788             }
6789           else if (lit == 1L)
6790             {
6791               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6792             }
6793           else
6794             {
6795               emitcode ("clr", "c");
6796             }
6797           /* AOP_TYPE(right) == AOP_CRY */
6798         }
6799       else
6800         {
6801           symbol *lbl = newiTempLabel (NULL);
6802           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6803           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6804           emitcode ("cpl", "c");
6805           emitLabel (lbl);
6806         }
6807
6808       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6809       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6810
6811       aopOp (result, ic, TRUE, FALSE);
6812
6813       /* c = 1 if egal */
6814       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6815         {
6816           outBitC (result);
6817           goto release;
6818         }
6819       if (ifx)
6820         {
6821           genIfxJump (ifx, "c");
6822           goto release;
6823         }
6824       /* if the result is used in an arithmetic operation
6825          then put the result in place */
6826       outBitC (result);
6827     }
6828   else
6829     {
6830       gencjne (left, right, newiTempLabel (NULL));
6831
6832       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6833       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6834
6835       aopOp (result, ic, TRUE, FALSE);
6836
6837       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6838         {
6839           aopPut (result, "a", 0);
6840           goto release;
6841         }
6842       if (ifx)
6843         {
6844           genIfxJump (ifx, "a");
6845           goto release;
6846         }
6847       /* if the result is used in an arithmetic operation
6848          then put the result in place */
6849       if (AOP_TYPE (result) != AOP_CRY)
6850         outAcc (result);
6851       /* leave the result in acc */
6852     }
6853
6854 release:
6855   freeAsmop (result, NULL, ic, TRUE);
6856 }
6857
6858 /*-----------------------------------------------------------------*/
6859 /* ifxForOp - returns the icode containing the ifx for operand     */
6860 /*-----------------------------------------------------------------*/
6861 static iCode *
6862 ifxForOp (operand * op, iCode * ic)
6863 {
6864   /* if true symbol then needs to be assigned */
6865   if (IS_TRUE_SYMOP (op))
6866     return NULL;
6867
6868   /* if this has register type condition and
6869      the next instruction is ifx with the same operand
6870      and live to of the operand is upto the ifx only then */
6871   if (ic->next &&
6872       ic->next->op == IFX &&
6873       IC_COND (ic->next)->key == op->key &&
6874       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6875     return ic->next;
6876
6877   return NULL;
6878 }
6879
6880 /*-----------------------------------------------------------------*/
6881 /* hasInc - operand is incremented before any other use            */
6882 /*-----------------------------------------------------------------*/
6883 static iCode *
6884 hasInc (operand *op, iCode *ic, int osize)
6885 {
6886   sym_link *type = operandType(op);
6887   sym_link *retype = getSpec (type);
6888   iCode *lic = ic->next;
6889   int isize ;
6890
6891   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6892   if (!IS_SYMOP(op)) return NULL;
6893
6894   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6895   if (IS_AGGREGATE(type->next)) return NULL;
6896   if (osize != (isize = getSize(type->next))) return NULL;
6897
6898   while (lic) {
6899       /* if operand of the form op = op + <sizeof *op> */
6900       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6901           isOperandEqual(IC_RESULT(lic),op) &&
6902           isOperandLiteral(IC_RIGHT(lic)) &&
6903           operandLitValue(IC_RIGHT(lic)) == isize) {
6904           return lic;
6905       }
6906       /* if the operand used or deffed */
6907       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6908           return NULL;
6909       }
6910       /* if GOTO or IFX */
6911       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6912       lic = lic->next;
6913   }
6914   return NULL;
6915 }
6916
6917 /*-----------------------------------------------------------------*/
6918 /* genAndOp - for && operation                                     */
6919 /*-----------------------------------------------------------------*/
6920 static void
6921 genAndOp (iCode * ic)
6922 {
6923   operand *left, *right, *result;
6924   symbol *tlbl;
6925
6926   D (emitcode (";", "genAndOp"));
6927
6928   /* note here that && operations that are in an
6929      if statement are taken away by backPatchLabels
6930      only those used in arthmetic operations remain */
6931   AOP_OP_2 (ic);
6932   AOP_SET_LOCALS (ic);
6933
6934   /* if both are bit variables */
6935   if (AOP_TYPE (left) == AOP_CRY &&
6936       AOP_TYPE (right) == AOP_CRY)
6937     {
6938       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6939       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6940       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6941       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6942
6943       aopOp (result,ic,FALSE, FALSE);
6944       outBitC (result);
6945     }
6946   else
6947     {
6948       tlbl = newiTempLabel (NULL);
6949       toBoolean (left);
6950       emitcode ("jz", "!tlabel", tlbl->key + 100);
6951       toBoolean (right);
6952       emitLabel (tlbl);
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       outBitAcc (result);
6958     }
6959
6960     freeAsmop (result, NULL, ic, TRUE);
6961 }
6962
6963
6964 /*-----------------------------------------------------------------*/
6965 /* genOrOp - for || operation                                      */
6966 /*-----------------------------------------------------------------*/
6967 static void
6968 genOrOp (iCode * ic)
6969 {
6970   operand *left, *right, *result;
6971   symbol *tlbl;
6972
6973   D (emitcode (";", "genOrOp"));
6974
6975   /* note here that || operations that are in an
6976      if statement are taken away by backPatchLabels
6977      only those used in arthmetic operations remain */
6978   AOP_OP_2 (ic);
6979   AOP_SET_LOCALS (ic);
6980
6981   /* if both are bit variables */
6982   if (AOP_TYPE (left) == AOP_CRY &&
6983       AOP_TYPE (right) == AOP_CRY)
6984     {
6985       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6986       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6987       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6988       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6989
6990       aopOp (result,ic,FALSE, FALSE);
6991
6992       outBitC (result);
6993     }
6994   else
6995     {
6996       tlbl = newiTempLabel (NULL);
6997       toBoolean (left);
6998       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6999       toBoolean (right);
7000       emitLabel (tlbl);
7001       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7002       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7003
7004       aopOp (result,ic,FALSE, FALSE);
7005
7006       outBitAcc (result);
7007     }
7008
7009   freeAsmop (result, NULL, ic, TRUE);
7010 }
7011
7012 /*-----------------------------------------------------------------*/
7013 /* isLiteralBit - test if lit == 2^n                               */
7014 /*-----------------------------------------------------------------*/
7015 static int
7016 isLiteralBit (unsigned long lit)
7017 {
7018   unsigned long pw[32] =
7019   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7020    0x100L, 0x200L, 0x400L, 0x800L,
7021    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7022    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7023    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7024    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7025    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7026   int idx;
7027
7028   for (idx = 0; idx < 32; idx++)
7029     if (lit == pw[idx])
7030       return idx + 1;
7031   return 0;
7032 }
7033
7034 /*-----------------------------------------------------------------*/
7035 /* continueIfTrue -                                                */
7036 /*-----------------------------------------------------------------*/
7037 static void
7038 continueIfTrue (iCode * ic)
7039 {
7040   if (IC_TRUE (ic))
7041     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7042   ic->generated = 1;
7043 }
7044
7045 /*-----------------------------------------------------------------*/
7046 /* jmpIfTrue -                                                     */
7047 /*-----------------------------------------------------------------*/
7048 static void
7049 jumpIfTrue (iCode * ic)
7050 {
7051   if (!IC_TRUE (ic))
7052     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7053   ic->generated = 1;
7054 }
7055
7056 /*-----------------------------------------------------------------*/
7057 /* jmpTrueOrFalse -                                                */
7058 /*-----------------------------------------------------------------*/
7059 static void
7060 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7061 {
7062   // ugly but optimized by peephole
7063   if (IC_TRUE (ic))
7064     {
7065       symbol *nlbl = newiTempLabel (NULL);
7066       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7067       emitLabel (tlbl);
7068       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7069       emitLabel (nlbl);
7070     }
7071   else
7072     {
7073       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7074       emitLabel (tlbl);
7075     }
7076   ic->generated = 1;
7077 }
7078
7079 // Generate code to perform a bit-wise logic operation
7080 // on two operands in far space (assumed to already have been
7081 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7082 // in far space. This requires pushing the result on the stack
7083 // then popping it into the result.
7084 static void
7085 genFarFarLogicOp(iCode *ic, char *logicOp)
7086 {
7087       int size, resultSize, compSize;
7088       int offset = 0;
7089
7090       TR_AP("#5");
7091       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7092       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7093                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7094
7095       _startLazyDPSEvaluation();
7096       for (size = compSize; (size--); offset++)
7097       {
7098           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7099           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7100           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7101
7102           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7103           emitcode ("push", "acc");
7104       }
7105       _endLazyDPSEvaluation();
7106
7107       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7108       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7109       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7110
7111       resultSize = AOP_SIZE(IC_RESULT(ic));
7112
7113       ADJUST_PUSHED_RESULT(compSize, resultSize);
7114
7115       _startLazyDPSEvaluation();
7116       while (compSize--)
7117       {
7118           emitcode ("pop", "acc");
7119           aopPut (IC_RESULT (ic), "a", compSize);
7120       }
7121       _endLazyDPSEvaluation();
7122       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7123 }
7124
7125
7126 /*-----------------------------------------------------------------*/
7127 /* genAnd  - code for and                                          */
7128 /*-----------------------------------------------------------------*/
7129 static void
7130 genAnd (iCode * ic, iCode * ifx)
7131 {
7132   operand *left, *right, *result;
7133   int size, offset = 0;
7134   unsigned long lit = 0L;
7135   int bytelit = 0;
7136   char buffer[10];
7137   bool pushResult;
7138
7139   D (emitcode (";", "genAnd"));
7140
7141   AOP_OP_3_NOFATAL (ic, pushResult);
7142   AOP_SET_LOCALS (ic);
7143
7144   if (pushResult)
7145   {
7146       genFarFarLogicOp(ic, "anl");
7147       return;
7148   }
7149
7150 #ifdef DEBUG_TYPE
7151   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7152             AOP_TYPE (result),
7153             AOP_TYPE (left), AOP_TYPE (right));
7154   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7155             AOP_SIZE (result),
7156             AOP_SIZE (left), AOP_SIZE (right));
7157 #endif
7158
7159   /* if left is a literal & right is not then exchange them */
7160   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7161 #ifdef LOGIC_OPS_BROKEN
7162     ||  AOP_NEEDSACC (left)
7163 #endif
7164     )
7165     {
7166       operand *tmp = right;
7167       right = left;
7168       left = tmp;
7169     }
7170
7171   /* if result = right then exchange left and right */
7172   if (sameRegs (AOP (result), AOP (right)))
7173     {
7174       operand *tmp = right;
7175       right = left;
7176       left = tmp;
7177     }
7178
7179   /* if right is bit then exchange them */
7180   if (AOP_TYPE (right) == AOP_CRY &&
7181       AOP_TYPE (left) != AOP_CRY)
7182     {
7183       operand *tmp = right;
7184       right = left;
7185       left = tmp;
7186     }
7187   if (AOP_TYPE (right) == AOP_LIT)
7188     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7189
7190   size = AOP_SIZE (result);
7191
7192   // if(bit & yy)
7193   // result = bit & yy;
7194   if (AOP_TYPE (left) == AOP_CRY)
7195     {
7196       // c = bit & literal;
7197       if (AOP_TYPE (right) == AOP_LIT)
7198         {
7199           if (lit & 1)
7200             {
7201               if (size && sameRegs (AOP (result), AOP (left)))
7202                 // no change
7203                 goto release;
7204               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7205             }
7206           else
7207             {
7208               // bit(result) = 0;
7209               if (size && (AOP_TYPE (result) == AOP_CRY))
7210                 {
7211                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7212                   goto release;
7213                 }
7214               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7215                 {
7216                   jumpIfTrue (ifx);
7217                   goto release;
7218                 }
7219               emitcode ("clr", "c");
7220             }
7221         }
7222       else
7223         {
7224           if (AOP_TYPE (right) == AOP_CRY)
7225             {
7226               // c = bit & bit;
7227               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7228               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7229             }
7230           else
7231             {
7232               // c = bit & val;
7233               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7234               // c = lsb
7235               emitcode ("rrc", "a");
7236               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7237             }
7238         }
7239       // bit = c
7240       // val = c
7241       if (size)
7242         outBitC (result);
7243       // if(bit & ...)
7244       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7245         genIfxJump (ifx, "c");
7246       goto release;
7247     }
7248
7249   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7250   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7251   if ((AOP_TYPE (right) == AOP_LIT) &&
7252       (AOP_TYPE (result) == AOP_CRY) &&
7253       (AOP_TYPE (left) != AOP_CRY))
7254     {
7255       int posbit = isLiteralBit (lit);
7256       /* left &  2^n */
7257       if (posbit)
7258         {
7259           posbit--;
7260           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7261           // bit = left & 2^n
7262           if (size)
7263             {
7264               switch (posbit & 0x07)
7265                 {
7266                   case 0: emitcode ("rrc", "a");
7267                           break;
7268                   case 7: emitcode ("rlc", "a");
7269                           break;
7270                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7271                           break;
7272                 }
7273             }
7274           // if(left &  2^n)
7275           else
7276             {
7277               if (ifx)
7278                 {
7279                   SNPRINTF (buffer, sizeof(buffer),
7280                             "acc.%d", posbit & 0x07);
7281                   genIfxJump (ifx, buffer);
7282                 }
7283               else
7284                 {
7285                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7286                 }
7287               goto release;
7288             }
7289         }
7290       else
7291         {
7292           symbol *tlbl = newiTempLabel (NULL);
7293           int sizel = AOP_SIZE (left);
7294           if (size)
7295             emitcode ("setb", "c");
7296           while (sizel--)
7297             {
7298               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7299                 {
7300                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7301                   // byte ==  2^n ?
7302                   if ((posbit = isLiteralBit (bytelit)) != 0)
7303                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7304                   else
7305                     {
7306                       if (bytelit != 0x0FFL)
7307                         emitcode ("anl", "a,%s",
7308                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7309                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7310                     }
7311                 }
7312               offset++;
7313             }
7314           // bit = left & literal
7315           if (size)
7316             {
7317               emitcode ("clr", "c");
7318               emitLabel (tlbl);
7319             }
7320           // if(left & literal)
7321           else
7322             {
7323               if (ifx)
7324                 jmpTrueOrFalse (ifx, tlbl);
7325               else
7326                 emitLabel (tlbl);
7327               goto release;
7328             }
7329         }
7330       outBitC (result);
7331       goto release;
7332     }
7333
7334   /* if left is same as result */
7335   if (sameRegs (AOP (result), AOP (left)))
7336     {
7337       for (; size--; offset++)
7338         {
7339           if (AOP_TYPE (right) == AOP_LIT)
7340             {
7341               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7342               if (bytelit == 0x0FF)
7343                 {
7344                   /* dummy read of volatile operand */
7345                   if (isOperandVolatile (left, FALSE))
7346                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7347                   else
7348                     continue;
7349                 }
7350               else if (bytelit == 0)
7351                 {
7352                   aopPut (result, zero, offset);
7353                 }
7354               else if (IS_AOP_PREG (result))
7355                 {
7356                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7357                   emitcode ("anl", "a,%s",
7358                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7359                   aopPut (result, "a", offset);
7360                 }
7361               else
7362                 emitcode ("anl", "%s,%s",
7363                           aopGet (left, offset, FALSE, TRUE, NULL),
7364                           aopGet (right, offset, FALSE, FALSE, NULL));
7365             }
7366           else
7367             {
7368               if (AOP_TYPE (left) == AOP_ACC)
7369                 {
7370                   if (offset)
7371                     emitcode("mov", "a,b");
7372                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7373                 }
7374               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7375                 {
7376                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7377                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7378                   emitcode ("anl", "a,b");
7379                   aopPut (result, "a", offset);
7380                 }
7381               else if (aopGetUsesAcc (left, offset))
7382                 {
7383                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7384                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7385                   aopPut (result, "a", offset);
7386                 }
7387               else
7388                 {
7389                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7390                   if (IS_AOP_PREG (result))
7391                     {
7392                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7393                       aopPut (result, "a", offset);
7394                     }
7395                   else
7396                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7397                 }
7398             }
7399         }
7400     }
7401   else
7402     {
7403       // left & result in different registers
7404       if (AOP_TYPE (result) == AOP_CRY)
7405         {
7406           // result = bit
7407           // if(size), result in bit
7408           // if(!size && ifx), conditional oper: if(left & right)
7409           symbol *tlbl = newiTempLabel (NULL);
7410           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7411           if (size)
7412             emitcode ("setb", "c");
7413           while (sizer--)
7414             {
7415               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7416                   && AOP_TYPE(left)==AOP_ACC)
7417                 {
7418                   if (offset)
7419                     emitcode("mov", "a,b");
7420                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7421                 }
7422               else if (AOP_TYPE(left)==AOP_ACC)
7423                 {
7424                   if (!offset)
7425                     {
7426                       bool pushedB = pushB ();
7427                       emitcode("mov", "b,a");
7428                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7429                       emitcode("anl", "a,b");
7430                       popB (pushedB);
7431                     }
7432                   else
7433                     {
7434                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7435                       emitcode("anl", "a,b");
7436                     }
7437                 }
7438               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7439                 {
7440                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7441                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7442                   emitcode ("anl", "a,b");
7443                 }
7444               else if (aopGetUsesAcc (left, offset))
7445                 {
7446                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7447                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7448                 }
7449               else
7450                 {
7451                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7452                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7453                 }
7454
7455               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7456               offset++;
7457             }
7458           if (size)
7459             {
7460               CLRC;
7461               emitLabel (tlbl);
7462               outBitC (result);
7463             }
7464           else if (ifx)
7465             jmpTrueOrFalse (ifx, tlbl);
7466           else
7467             emitLabel (tlbl);
7468         }
7469       else
7470         {
7471           for (; (size--); offset++)
7472             {
7473               // normal case
7474               // result = left & right
7475               if (AOP_TYPE (right) == AOP_LIT)
7476                 {
7477                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7478                   if (bytelit == 0x0FF)
7479                     {
7480                       aopPut (result,
7481                               aopGet (left, offset, FALSE, FALSE, NULL),
7482                               offset);
7483                       continue;
7484                     }
7485                   else if (bytelit == 0)
7486                     {
7487                       /* dummy read of volatile operand */
7488                       if (isOperandVolatile (left, FALSE))
7489                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7490                       aopPut (result, zero, offset);
7491                       continue;
7492                     }
7493                   else if (AOP_TYPE (left) == AOP_ACC)
7494                     {
7495                       if (!offset)
7496                         {
7497                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7498                           aopPut (result, "a", offset);
7499                           continue;
7500                         }
7501                       else
7502                         {
7503                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7504                           aopPut (result, "b", offset);
7505                           continue;
7506                         }
7507                     }
7508                 }
7509               // faster than result <- left, anl result,right
7510               // and better if result is SFR
7511               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7512                   && AOP_TYPE(left)==AOP_ACC)
7513                 {
7514                   if (offset)
7515                     emitcode("mov", "a,b");
7516                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7517                 }
7518               else if (AOP_TYPE(left)==AOP_ACC)
7519                 {
7520                   if (!offset)
7521                     {
7522                       bool pushedB = pushB ();
7523                       emitcode("mov", "b,a");
7524                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7525                       emitcode("anl", "a,b");
7526                       popB (pushedB);
7527                     }
7528                   else
7529                     {
7530                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7531                       emitcode("anl", "a,b");
7532                     }
7533                 }
7534               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7535                 {
7536                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7537                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7538                   emitcode ("anl", "a,b");
7539                 }
7540               else if (aopGetUsesAcc (left, offset))
7541                 {
7542                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7543                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7544                 }
7545               else
7546                 {
7547                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7548                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7549                 }
7550               aopPut (result, "a", offset);
7551             }
7552         }
7553     }
7554
7555 release:
7556   freeAsmop (result, NULL, ic, TRUE);
7557   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7558   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7559 }
7560
7561 /*-----------------------------------------------------------------*/
7562 /* genOr  - code for or                                            */
7563 /*-----------------------------------------------------------------*/
7564 static void
7565 genOr (iCode * ic, iCode * ifx)
7566 {
7567   operand *left, *right, *result;
7568   int size, offset = 0;
7569   unsigned long lit = 0L;
7570   int bytelit = 0;
7571   bool     pushResult;
7572
7573   D (emitcode (";", "genOr"));
7574
7575   AOP_OP_3_NOFATAL (ic, pushResult);
7576   AOP_SET_LOCALS (ic);
7577
7578   if (pushResult)
7579   {
7580       genFarFarLogicOp(ic, "orl");
7581       return;
7582   }
7583
7584
7585 #ifdef DEBUG_TYPE
7586   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7587             AOP_TYPE (result),
7588             AOP_TYPE (left), AOP_TYPE (right));
7589   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7590             AOP_SIZE (result),
7591             AOP_SIZE (left), AOP_SIZE (right));
7592 #endif
7593
7594   /* if left is a literal & right is not then exchange them */
7595   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7596 #ifdef LOGIC_OPS_BROKEN
7597    || AOP_NEEDSACC (left) // I think this is a net loss now.
7598 #endif
7599       )
7600     {
7601       operand *tmp = right;
7602       right = left;
7603       left = tmp;
7604     }
7605
7606   /* if result = right then exchange them */
7607   if (sameRegs (AOP (result), AOP (right)))
7608     {
7609       operand *tmp = right;
7610       right = left;
7611       left = tmp;
7612     }
7613
7614   /* if right is bit then exchange them */
7615   if (AOP_TYPE (right) == AOP_CRY &&
7616       AOP_TYPE (left) != AOP_CRY)
7617     {
7618       operand *tmp = right;
7619       right = left;
7620       left = tmp;
7621     }
7622   if (AOP_TYPE (right) == AOP_LIT)
7623     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7624
7625   size = AOP_SIZE (result);
7626
7627   // if(bit | yy)
7628   // xx = bit | yy;
7629   if (AOP_TYPE (left) == AOP_CRY)
7630     {
7631       if (AOP_TYPE (right) == AOP_LIT)
7632         {
7633           // c = bit | literal;
7634           if (lit)
7635             {
7636               // lit != 0 => result = 1
7637               if (AOP_TYPE (result) == AOP_CRY)
7638                 {
7639                   if (size)
7640                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7641                   else if (ifx)
7642                     continueIfTrue (ifx);
7643                   goto release;
7644                 }
7645               emitcode ("setb", "c");
7646             }
7647           else
7648             {
7649               // lit == 0 => result = left
7650               if (size && sameRegs (AOP (result), AOP (left)))
7651                 goto release;
7652               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7653             }
7654         }
7655       else
7656         {
7657           if (AOP_TYPE (right) == AOP_CRY)
7658             {
7659               // c = bit | bit;
7660               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7661               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7662             }
7663           else
7664             {
7665               // c = bit | val;
7666               symbol *tlbl = newiTempLabel (NULL);
7667               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7668                 emitcode ("setb", "c");
7669               emitcode ("jb", "%s,!tlabel",
7670                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7671               toBoolean (right);
7672               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7673               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7674                 {
7675                   jmpTrueOrFalse (ifx, tlbl);
7676                   goto release;
7677                 }
7678               else
7679                 {
7680                   CLRC;
7681                   emitLabel (tlbl);
7682                 }
7683             }
7684         }
7685       // bit = c
7686       // val = c
7687       if (size)
7688         outBitC (result);
7689       // if(bit | ...)
7690       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7691            genIfxJump (ifx, "c");
7692       goto release;
7693     }
7694
7695   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7696   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7697   if ((AOP_TYPE (right) == AOP_LIT) &&
7698       (AOP_TYPE (result) == AOP_CRY) &&
7699       (AOP_TYPE (left) != AOP_CRY))
7700     {
7701       if (lit)
7702         {
7703           // result = 1
7704           if (size)
7705             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7706           else
7707             continueIfTrue (ifx);
7708           goto release;
7709         }
7710       else
7711         {
7712           // lit = 0, result = boolean(left)
7713           if (size)
7714             emitcode ("setb", "c");
7715           toBoolean (right);
7716           if (size)
7717             {
7718               symbol *tlbl = newiTempLabel (NULL);
7719               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7720               CLRC;
7721               emitLabel (tlbl);
7722             }
7723           else
7724             {
7725               genIfxJump (ifx, "a");
7726               goto release;
7727             }
7728         }
7729       outBitC (result);
7730       goto release;
7731     }
7732
7733   /* if left is same as result */
7734   if (sameRegs (AOP (result), AOP (left)))
7735     {
7736       for (; size--; offset++)
7737         {
7738           if (AOP_TYPE (right) == AOP_LIT)
7739             {
7740               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7741               if (bytelit == 0)
7742                 {
7743                   /* dummy read of volatile operand */
7744                   if (isOperandVolatile (left, FALSE))
7745                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7746                   else
7747                     continue;
7748                 }
7749               else if (bytelit == 0x0FF)
7750                 {
7751                   aopPut (result, "#0xFF", offset);
7752                 }
7753               else if (IS_AOP_PREG (left))
7754                 {
7755                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7756                   emitcode ("orl", "a,%s",
7757                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7758                   aopPut (result, "a", offset);
7759                 }
7760               else
7761                 {
7762                   emitcode ("orl", "%s,%s",
7763                             aopGet (left, offset, FALSE, TRUE, NULL),
7764                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7765                 }
7766             }
7767           else
7768             {
7769               if (AOP_TYPE (left) == AOP_ACC)
7770                 {
7771                   if (offset)
7772                     emitcode("mov", "a,b");
7773                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7774                 }
7775               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7776                 {
7777                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7778                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7779                   emitcode ("orl", "a,b");
7780                   aopPut (result, "a", offset);
7781                 }
7782               else if (aopGetUsesAcc (left, offset))
7783                 {
7784                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7785                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7786                   aopPut (result, "a", offset);
7787                 }
7788               else
7789                 {
7790                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7791                   if (IS_AOP_PREG (left))
7792                     {
7793                       emitcode ("orl", "a,%s",
7794                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7795                       aopPut (result, "a", offset);
7796                     }
7797                   else
7798                     {
7799                       emitcode ("orl", "%s,a",
7800                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7801                     }
7802                 }
7803             }
7804         }
7805     }
7806   else
7807     {
7808       // left & result in different registers
7809       if (AOP_TYPE (result) == AOP_CRY)
7810         {
7811           // result = bit
7812           // if(size), result in bit
7813           // if(!size && ifx), conditional oper: if(left | right)
7814           symbol *tlbl = newiTempLabel (NULL);
7815           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7816           if (size)
7817             emitcode ("setb", "c");
7818           while (sizer--)
7819             {
7820               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7821                   && AOP_TYPE(left)==AOP_ACC)
7822                 {
7823                   if (offset)
7824                     emitcode("mov", "a,b");
7825                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7826                 }
7827               else if (AOP_TYPE(left)==AOP_ACC)
7828                 {
7829                   if (!offset)
7830                     {
7831                       bool pushedB = pushB ();
7832                       emitcode("mov", "b,a");
7833                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7834                       emitcode("orl", "a,b");
7835                       popB (pushedB);
7836                     }
7837                   else
7838                     {
7839                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7840                       emitcode("orl", "a,b");
7841                     }
7842                 }
7843               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7844                 {
7845                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7846                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7847                   emitcode ("orl", "a,b");
7848                 }
7849               else if (aopGetUsesAcc (left, offset))
7850                 {
7851                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7852                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7853                 }
7854               else
7855                 {
7856                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7857                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7858               }
7859
7860               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7861               offset++;
7862             }
7863           if (size)
7864             {
7865               CLRC;
7866               emitLabel (tlbl);
7867               outBitC (result);
7868             }
7869           else if (ifx)
7870             jmpTrueOrFalse (ifx, tlbl);
7871           else
7872             emitLabel (tlbl);
7873         }
7874       else
7875         {
7876             _startLazyDPSEvaluation();
7877           for (; (size--); offset++)
7878             {
7879               // normal case
7880               // result = left | right
7881               if (AOP_TYPE (right) == AOP_LIT)
7882                 {
7883                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7884                   if (bytelit == 0)
7885                     {
7886                       aopPut (result,
7887                               aopGet (left, offset, FALSE, FALSE, NULL),
7888                               offset);
7889                       continue;
7890                     }
7891                   else if (bytelit == 0x0FF)
7892                     {
7893                       /* dummy read of volatile operand */
7894                       if (isOperandVolatile (left, FALSE))
7895                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7896                       aopPut (result, "#0xFF", offset);
7897                       continue;
7898                     }
7899                 }
7900               // faster than result <- left, orl result,right
7901               // and better if result is SFR
7902               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7903                   && AOP_TYPE(left)==AOP_ACC)
7904                 {
7905                   if (offset)
7906                     emitcode("mov", "a,b");
7907                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7908                 }
7909               else if (AOP_TYPE(left)==AOP_ACC)
7910                 {
7911                   if (!offset)
7912                     {
7913                       bool pushedB = pushB ();
7914                       emitcode("mov", "b,a");
7915                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7916                       emitcode("orl", "a,b");
7917                       popB (pushedB);
7918                     }
7919                   else
7920                     {
7921                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7922                       emitcode("orl", "a,b");
7923                     }
7924                 }
7925               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7926                 {
7927                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7928                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7929                   emitcode ("orl", "a,b");
7930                 }
7931               else if (aopGetUsesAcc (left, offset))
7932                 {
7933                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7934                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7935                 }
7936               else
7937                 {
7938                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7939                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7940                 }
7941               aopPut (result, "a", offset);
7942             }
7943             _endLazyDPSEvaluation();
7944         }
7945     }
7946
7947 release:
7948   freeAsmop (result, NULL, ic, TRUE);
7949   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7950   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7951 }
7952
7953 /*-----------------------------------------------------------------*/
7954 /* genXor - code for xclusive or                                   */
7955 /*-----------------------------------------------------------------*/
7956 static void
7957 genXor (iCode * ic, iCode * ifx)
7958 {
7959   operand *left, *right, *result;
7960   int size, offset = 0;
7961   unsigned long lit = 0L;
7962   int bytelit = 0;
7963   bool pushResult;
7964
7965   D (emitcode (";", "genXor"));
7966
7967   AOP_OP_3_NOFATAL (ic, pushResult);
7968   AOP_SET_LOCALS (ic);
7969
7970   if (pushResult)
7971   {
7972       genFarFarLogicOp(ic, "xrl");
7973       return;
7974   }
7975
7976 #ifdef DEBUG_TYPE
7977   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7978             AOP_TYPE (result),
7979             AOP_TYPE (left), AOP_TYPE (right));
7980   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7981             AOP_SIZE (result),
7982             AOP_SIZE (left), AOP_SIZE (right));
7983 #endif
7984
7985   /* if left is a literal & right is not ||
7986      if left needs acc & right does not */
7987   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7988 #ifdef LOGIC_OPS_BROKEN
7989       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7990 #endif
7991      )
7992     {
7993       operand *tmp = right;
7994       right = left;
7995       left = tmp;
7996     }
7997
7998   /* if result = right then exchange them */
7999   if (sameRegs (AOP (result), AOP (right)))
8000     {
8001       operand *tmp = right;
8002       right = left;
8003       left = tmp;
8004     }
8005
8006   /* if right is bit then exchange them */
8007   if (AOP_TYPE (right) == AOP_CRY &&
8008       AOP_TYPE (left) != AOP_CRY)
8009     {
8010       operand *tmp = right;
8011       right = left;
8012       left = tmp;
8013     }
8014   if (AOP_TYPE (right) == AOP_LIT)
8015     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
8016
8017   size = AOP_SIZE (result);
8018
8019   // if(bit ^ yy)
8020   // xx = bit ^ yy;
8021   if (AOP_TYPE (left) == AOP_CRY)
8022     {
8023       if (AOP_TYPE (right) == AOP_LIT)
8024         {
8025           // c = bit & literal;
8026           if (lit >> 1)
8027             {
8028               // lit>>1  != 0 => result = 1
8029               if (AOP_TYPE (result) == AOP_CRY)
8030                 {
8031                   if (size)
8032                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8033                   else if (ifx)
8034                     continueIfTrue (ifx);
8035                   goto release;
8036                 }
8037               emitcode ("setb", "c");
8038             }
8039           else
8040             {
8041               // lit == (0 or 1)
8042               if (lit == 0)
8043                 {
8044                   // lit == 0, result = left
8045                   if (size && sameRegs (AOP (result), AOP (left)))
8046                     goto release;
8047                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8048                 }
8049               else
8050                 {
8051                   // lit == 1, result = not(left)
8052                   if (size && sameRegs (AOP (result), AOP (left)))
8053                     {
8054                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8055                       goto release;
8056                     }
8057                   else
8058                     {
8059                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8060                       emitcode ("cpl", "c");
8061                     }
8062                 }
8063             }
8064         }
8065       else
8066         {
8067           // right != literal
8068           symbol *tlbl = newiTempLabel (NULL);
8069           if (AOP_TYPE (right) == AOP_CRY)
8070             {
8071               // c = bit ^ bit;
8072               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8073             }
8074           else
8075             {
8076               int sizer = AOP_SIZE (right);
8077               // c = bit ^ val
8078               // if val>>1 != 0, result = 1
8079               emitcode ("setb", "c");
8080               while (sizer)
8081                 {
8082                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8083                   if (sizer == 1)
8084                     // test the msb of the lsb
8085                     emitcode ("anl", "a,#!constbyte",0xfe);
8086                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8087                   sizer--;
8088                 }
8089               // val = (0,1)
8090               emitcode ("rrc", "a");
8091             }
8092           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8093           emitcode ("cpl", "c");
8094           emitLabel (tlbl);
8095         }
8096       // bit = c
8097       // val = c
8098       if (size)
8099         outBitC (result);
8100       // if(bit | ...)
8101       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8102         genIfxJump (ifx, "c");
8103       goto release;
8104     }
8105
8106   /* if left is same as result */
8107   if (sameRegs (AOP (result), AOP (left)))
8108     {
8109       for (; size--; offset++)
8110         {
8111           if (AOP_TYPE (right) == AOP_LIT)
8112             {
8113               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8114               if (bytelit == 0)
8115                 {
8116                   /* dummy read of volatile operand */
8117                   if (isOperandVolatile (left, FALSE))
8118                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8119                   else
8120                     continue;
8121                 }
8122               else if (IS_AOP_PREG (left))
8123                 {
8124                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8125                   emitcode ("xrl", "a,%s",
8126                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8127                   aopPut (result, "a", offset);
8128                 }
8129               else
8130                 {
8131                   emitcode ("xrl", "%s,%s",
8132                             aopGet (left, offset, FALSE, TRUE, NULL),
8133                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8134                 }
8135             }
8136           else
8137             {
8138               if (AOP_TYPE (left) == AOP_ACC)
8139                 {
8140                   if (offset)
8141                     emitcode("mov", "a,b");
8142                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8143                 }
8144               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8145                 {
8146                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8147                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8148                   emitcode ("xrl", "a,b");
8149                   aopPut (result, "a", offset);
8150                 }
8151               else if (aopGetUsesAcc (left, offset))
8152                 {
8153                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8154                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8155                   aopPut (result, "a", offset);
8156                 }
8157               else
8158                 {
8159                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8160                   if (IS_AOP_PREG (left))
8161                     {
8162                       emitcode ("xrl", "a,%s",
8163                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8164                       aopPut (result, "a", offset);
8165                     }
8166                   else
8167                     emitcode ("xrl", "%s,a",
8168                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8169                 }
8170             }
8171         }
8172     }
8173   else
8174     {
8175       // left & result in different registers
8176       if (AOP_TYPE (result) == AOP_CRY)
8177         {
8178           // result = bit
8179           // if(size), result in bit
8180           // if(!size && ifx), conditional oper: if(left ^ right)
8181           symbol *tlbl = newiTempLabel (NULL);
8182           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8183
8184           if (size)
8185             emitcode ("setb", "c");
8186           while (sizer--)
8187             {
8188               if ((AOP_TYPE (right) == AOP_LIT) &&
8189                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8190                 {
8191                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8192                 }
8193               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8194                   && AOP_TYPE(left)==AOP_ACC)
8195                 {
8196                   if (offset)
8197                     emitcode("mov", "a,b");
8198                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8199                 }
8200               else if (AOP_TYPE(left)==AOP_ACC)
8201                 {
8202                   if (!offset)
8203                     {
8204                       bool pushedB = pushB ();
8205                       emitcode("mov", "b,a");
8206                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8207                       emitcode("xrl", "a,b");
8208                       popB (pushedB);
8209                     }
8210                   else
8211                     {
8212                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8213                       emitcode("xrl", "a,b");
8214                     }
8215                 }
8216               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8217                 {
8218                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8219                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8220                   emitcode ("xrl", "a,b");
8221                 }
8222               else if (aopGetUsesAcc (left, offset))
8223                 {
8224                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8225                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8226                 }
8227               else
8228                 {
8229                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8230                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8231                 }
8232
8233               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8234               offset++;
8235             }
8236           if (size)
8237             {
8238               CLRC;
8239               emitLabel (tlbl);
8240               outBitC (result);
8241             }
8242           else if (ifx)
8243             jmpTrueOrFalse (ifx, tlbl);
8244         }
8245       else
8246         {
8247         for (; (size--); offset++)
8248           {
8249             // normal case
8250             // result = left ^ right
8251             if (AOP_TYPE (right) == AOP_LIT)
8252               {
8253                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8254                 if (bytelit == 0)
8255                   {
8256                     aopPut (result,
8257                             aopGet (left, offset, FALSE, FALSE, NULL),
8258                             offset);
8259                     continue;
8260                   }
8261                 D (emitcode (";", "better literal XOR."));
8262                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8263                 emitcode ("xrl", "a, %s",
8264                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8265               }
8266             else
8267               {
8268                 // faster than result <- left, anl result,right
8269                 // and better if result is SFR
8270                 if (AOP_TYPE (left) == AOP_ACC)
8271                   {
8272                     emitcode ("xrl", "a,%s",
8273                               aopGet (right, offset,
8274                                       FALSE, FALSE, DP2_RESULT_REG));
8275                   }
8276                 else
8277                   {
8278                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8279                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8280                       {
8281                           emitcode("mov", "b,a");
8282                           rOp = "b";
8283                       }
8284
8285                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8286                       emitcode ("xrl", "a,%s", rOp);
8287                   }
8288               }
8289             aopPut (result, "a", offset);
8290           }
8291         }
8292     }
8293
8294 release:
8295   freeAsmop (result, NULL, ic, TRUE);
8296   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8297   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8298 }
8299
8300 /*-----------------------------------------------------------------*/
8301 /* genInline - write the inline code out                           */
8302 /*-----------------------------------------------------------------*/
8303 static void
8304 genInline (iCode * ic)
8305 {
8306   char *buffer, *bp, *bp1;
8307
8308   D (emitcode (";", "genInline"));
8309
8310   _G.inLine += (!options.asmpeep);
8311
8312   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
8313
8314   /* emit each line as a code */
8315   while (*bp)
8316     {
8317       if (*bp == '\n')
8318         {
8319           *bp++ = '\0';
8320           emitcode (bp1, "");
8321           bp1 = bp;
8322         }
8323       else
8324         {
8325           /* Add \n for labels, not dirs such as c:\mydir */
8326           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
8327             {
8328               bp++;
8329               *bp = '\0';
8330               bp++;
8331               emitcode (bp1, "");
8332               bp1 = bp;
8333             }
8334           else
8335             bp++;
8336         }
8337     }
8338   if (bp1 != bp)
8339     emitcode (bp1, "");
8340   /*     emitcode("",buffer); */
8341   _G.inLine -= (!options.asmpeep);
8342 }
8343
8344 /*-----------------------------------------------------------------*/
8345 /* genRRC - rotate right with carry                                */
8346 /*-----------------------------------------------------------------*/
8347 static void
8348 genRRC (iCode * ic)
8349 {
8350   operand *left, *result;
8351   int     size, offset;
8352   char *l;
8353
8354   D (emitcode (";", "genRRC"));
8355
8356   /* rotate right with carry */
8357   left = IC_LEFT (ic);
8358   result = IC_RESULT (ic);
8359   aopOp (left, ic, FALSE, FALSE);
8360   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8361
8362   /* move it to the result */
8363   size = AOP_SIZE (result);
8364   offset = size - 1;
8365   CLRC;
8366
8367   _startLazyDPSEvaluation ();
8368   while (size--)
8369     {
8370       l = aopGet (left, offset, FALSE, FALSE, NULL);
8371       MOVA (l);
8372       emitcode ("rrc", "a");
8373       if (AOP_SIZE (result) > 1)
8374         aopPut (result, "a", offset--);
8375     }
8376   _endLazyDPSEvaluation ();
8377
8378   /* now we need to put the carry into the
8379      highest order byte of the result */
8380   if (AOP_SIZE (result) > 1)
8381     {
8382       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8383       MOVA (l);
8384     }
8385   emitcode ("mov", "acc.7,c");
8386   aopPut (result, "a", AOP_SIZE (result) - 1);
8387   freeAsmop (result, NULL, ic, TRUE);
8388   freeAsmop (left, NULL, ic, TRUE);
8389 }
8390
8391 /*-----------------------------------------------------------------*/
8392 /* genRLC - generate code for rotate left with carry               */
8393 /*-----------------------------------------------------------------*/
8394 static void
8395 genRLC (iCode * ic)
8396 {
8397   operand *left, *result;
8398   int size, offset;
8399   char *l;
8400
8401   D (emitcode (";", "genRLC"));
8402
8403   /* rotate right with carry */
8404   left = IC_LEFT (ic);
8405   result = IC_RESULT (ic);
8406   aopOp (left, ic, FALSE, FALSE);
8407   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8408
8409   /* move it to the result */
8410   size = AOP_SIZE (result);
8411   offset = 0;
8412   if (size--)
8413     {
8414       l = aopGet (left, offset, FALSE, FALSE, NULL);
8415       MOVA (l);
8416       emitcode ("add", "a,acc");
8417       if (AOP_SIZE (result) > 1)
8418         {
8419           aopPut (result, "a", offset++);
8420         }
8421
8422       _startLazyDPSEvaluation ();
8423       while (size--)
8424         {
8425           l = aopGet (left, offset, FALSE, FALSE, NULL);
8426           MOVA (l);
8427           emitcode ("rlc", "a");
8428           if (AOP_SIZE (result) > 1)
8429             aopPut (result, "a", offset++);
8430         }
8431       _endLazyDPSEvaluation ();
8432     }
8433   /* now we need to put the carry into the
8434      highest order byte of the result */
8435   if (AOP_SIZE (result) > 1)
8436     {
8437       l = aopGet (result, 0, FALSE, FALSE, NULL);
8438       MOVA (l);
8439     }
8440   emitcode ("mov", "acc.0,c");
8441   aopPut (result, "a", 0);
8442   freeAsmop (result, NULL, ic, TRUE);
8443   freeAsmop (left, NULL, ic, TRUE);
8444 }
8445
8446 /*-----------------------------------------------------------------*/
8447 /* genGetHbit - generates code get highest order bit               */
8448 /*-----------------------------------------------------------------*/
8449 static void
8450 genGetHbit (iCode * ic)
8451 {
8452   operand *left, *result;
8453
8454   D (emitcode (";", "genGetHbit"));
8455
8456   left = IC_LEFT (ic);
8457   result = IC_RESULT (ic);
8458   aopOp (left, ic, FALSE, FALSE);
8459   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8460
8461   /* get the highest order byte into a */
8462   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8463   if (AOP_TYPE (result) == AOP_CRY)
8464     {
8465       emitcode ("rlc", "a");
8466       outBitC (result);
8467     }
8468   else
8469     {
8470       emitcode ("rl", "a");
8471       emitcode ("anl", "a,#1");
8472       outAcc (result);
8473     }
8474
8475
8476   freeAsmop (result, NULL, ic, TRUE);
8477   freeAsmop (left, NULL, ic, TRUE);
8478 }
8479
8480 /*-----------------------------------------------------------------*/
8481 /* genSwap - generates code to swap nibbles or bytes               */
8482 /*-----------------------------------------------------------------*/
8483 static void
8484 genSwap (iCode * ic)
8485 {
8486   operand *left, *result;
8487
8488   D(emitcode (";     genSwap",""));
8489
8490   left = IC_LEFT (ic);
8491   result = IC_RESULT (ic);
8492   aopOp (left, ic, FALSE, FALSE);
8493   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8494
8495   _startLazyDPSEvaluation ();
8496   switch (AOP_SIZE (left))
8497     {
8498     case 1: /* swap nibbles in byte */
8499       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8500       emitcode ("swap", "a");
8501       aopPut (result, "a", 0);
8502       break;
8503     case 2: /* swap bytes in word */
8504       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8505         {
8506           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8507           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8508           aopPut (result, "a", 1);
8509         }
8510       else if (operandsEqu (left, result))
8511         {
8512           char * reg = "a";
8513           bool pushedB = FALSE, leftInB = FALSE;
8514
8515           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8516           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8517             {
8518               pushedB = pushB ();
8519               emitcode ("mov", "b,a");
8520               reg = "b";
8521               leftInB = TRUE;
8522             }
8523           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8524           aopPut (result, reg, 1);
8525
8526           if (leftInB)
8527             popB (pushedB);
8528         }
8529       else
8530         {
8531           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8532           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8533         }
8534       break;
8535     default:
8536       wassertl(FALSE, "unsupported SWAP operand size");
8537     }
8538   _endLazyDPSEvaluation ();
8539
8540   freeAsmop (result, NULL, ic, TRUE);
8541   freeAsmop (left, NULL, ic, TRUE);
8542 }
8543
8544 /*-----------------------------------------------------------------*/
8545 /* AccRol - rotate left accumulator by known count                 */
8546 /*-----------------------------------------------------------------*/
8547 static void
8548 AccRol (int shCount)
8549 {
8550   shCount &= 0x0007;            // shCount : 0..7
8551
8552   switch (shCount)
8553     {
8554     case 0:
8555       break;
8556     case 1:
8557       emitcode ("rl", "a");
8558       break;
8559     case 2:
8560       emitcode ("rl", "a");
8561       emitcode ("rl", "a");
8562       break;
8563     case 3:
8564       emitcode ("swap", "a");
8565       emitcode ("rr", "a");
8566       break;
8567     case 4:
8568       emitcode ("swap", "a");
8569       break;
8570     case 5:
8571       emitcode ("swap", "a");
8572       emitcode ("rl", "a");
8573       break;
8574     case 6:
8575       emitcode ("rr", "a");
8576       emitcode ("rr", "a");
8577       break;
8578     case 7:
8579       emitcode ("rr", "a");
8580       break;
8581     }
8582 }
8583
8584 /*-----------------------------------------------------------------*/
8585 /* AccLsh - left shift accumulator by known count                  */
8586 /*-----------------------------------------------------------------*/
8587 static void
8588 AccLsh (int shCount)
8589 {
8590   if (shCount != 0)
8591     {
8592       if (shCount == 1)
8593         emitcode ("add", "a,acc");
8594       else if (shCount == 2)
8595         {
8596           emitcode ("add", "a,acc");
8597           emitcode ("add", "a,acc");
8598         }
8599       else
8600         {
8601           /* rotate left accumulator */
8602           AccRol (shCount);
8603           /* and kill the lower order bits */
8604           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8605         }
8606     }
8607 }
8608
8609 /*-----------------------------------------------------------------*/
8610 /* AccRsh - right shift accumulator by known count                 */
8611 /*-----------------------------------------------------------------*/
8612 static void
8613 AccRsh (int shCount)
8614 {
8615   if (shCount != 0)
8616     {
8617       if (shCount == 1)
8618         {
8619           CLRC;
8620           emitcode ("rrc", "a");
8621         }
8622       else
8623         {
8624           /* rotate right accumulator */
8625           AccRol (8 - shCount);
8626           /* and kill the higher order bits */
8627           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8628         }
8629     }
8630 }
8631
8632 #ifdef BETTER_LITERAL_SHIFT
8633 /*-----------------------------------------------------------------*/
8634 /* AccSRsh - signed right shift accumulator by known count                 */
8635 /*-----------------------------------------------------------------*/
8636 static void
8637 AccSRsh (int shCount)
8638 {
8639   symbol *tlbl;
8640   if (shCount != 0)
8641     {
8642       if (shCount == 1)
8643         {
8644           emitcode ("mov", "c,acc.7");
8645           emitcode ("rrc", "a");
8646         }
8647       else if (shCount == 2)
8648         {
8649           emitcode ("mov", "c,acc.7");
8650           emitcode ("rrc", "a");
8651           emitcode ("mov", "c,acc.7");
8652           emitcode ("rrc", "a");
8653         }
8654       else
8655         {
8656           tlbl = newiTempLabel (NULL);
8657           /* rotate right accumulator */
8658           AccRol (8 - shCount);
8659           /* and kill the higher order bits */
8660           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8661           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8662           emitcode ("orl", "a,#!constbyte",
8663                     (unsigned char) ~SRMask[shCount]);
8664           emitLabel (tlbl);
8665         }
8666     }
8667 }
8668 #endif
8669
8670 #ifdef BETTER_LITERAL_SHIFT
8671 /*-----------------------------------------------------------------*/
8672 /* shiftR1Left2Result - shift right one byte from left to result   */
8673 /*-----------------------------------------------------------------*/
8674 static void
8675 shiftR1Left2Result (operand * left, int offl,
8676                     operand * result, int offr,
8677                     int shCount, int sign)
8678 {
8679   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8680   /* shift right accumulator */
8681   if (sign)
8682     AccSRsh (shCount);
8683   else
8684     AccRsh (shCount);
8685   aopPut (result, "a", offr);
8686 }
8687 #endif
8688
8689 #ifdef BETTER_LITERAL_SHIFT
8690 /*-----------------------------------------------------------------*/
8691 /* shiftL1Left2Result - shift left one byte from left to result    */
8692 /*-----------------------------------------------------------------*/
8693 static void
8694 shiftL1Left2Result (operand * left, int offl,
8695                     operand * result, int offr, int shCount)
8696 {
8697   char *l;
8698   l = aopGet (left, offl, FALSE, FALSE, NULL);
8699   MOVA (l);
8700   /* shift left accumulator */
8701   AccLsh (shCount);
8702   aopPut (result, "a", offr);
8703 }
8704 #endif
8705
8706 #ifdef BETTER_LITERAL_SHIFT
8707 /*-----------------------------------------------------------------*/
8708 /* movLeft2Result - move byte from left to result                  */
8709 /*-----------------------------------------------------------------*/
8710 static void
8711 movLeft2Result (operand * left, int offl,
8712                 operand * result, int offr, int sign)
8713 {
8714   char *l;
8715   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8716   {
8717       l = aopGet (left, offl, FALSE, FALSE, NULL);
8718
8719       if (*l == '@' && (IS_AOP_PREG (result)))
8720       {
8721           emitcode ("mov", "a,%s", l);
8722           aopPut (result, "a", offr);
8723       }
8724       else
8725       {
8726           if (!sign)
8727             {
8728               aopPut (result, l, offr);
8729             }
8730           else
8731             {
8732               /* MSB sign in acc.7 ! */
8733               if (getDataSize (left) == offl + 1)
8734                 {
8735                   MOVA (l);
8736                   aopPut (result, "a", offr);
8737                 }
8738             }
8739       }
8740   }
8741 }
8742 #endif
8743
8744 #ifdef BETTER_LITERAL_SHIFT
8745 /*-----------------------------------------------------------------*/
8746 /* AccAXRrl1 - right rotate a:x by 1                               */
8747 /*-----------------------------------------------------------------*/
8748 static void
8749 AccAXRrl1 (char *x)
8750 {
8751   emitcode ("mov", "c,acc.0");
8752   emitcode ("xch", "a,%s", x);
8753   emitcode ("rrc", "a");
8754   emitcode ("xch", "a,%s", x);
8755   emitcode ("rrc", "a");
8756 }
8757 #endif
8758
8759 #ifdef BETTER_LITERAL_SHIFT
8760 //REMOVE ME!!!
8761 /*-----------------------------------------------------------------*/
8762 /* AccAXLrl1 - left rotate a:x by 1                                */
8763 /*-----------------------------------------------------------------*/
8764 static void
8765 AccAXLrl1 (char *x)
8766 {
8767   emitcode ("mov", "c,acc.7");
8768   emitcode ("xch", "a,%s", x);
8769   emitcode ("rlc", "a");
8770   emitcode ("xch", "a,%s", x);
8771   emitcode ("rlc", "a");
8772 }
8773 #endif
8774
8775 #ifdef BETTER_LITERAL_SHIFT
8776 /*-----------------------------------------------------------------*/
8777 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8778 /*-----------------------------------------------------------------*/
8779 static void
8780 AccAXRsh1 (char *x)
8781 {
8782   emitcode ("rrc", "a");
8783   emitcode ("xch", "a,%s", x);
8784   emitcode ("rrc", "a");
8785   emitcode ("xch", "a,%s", x);
8786 }
8787 #endif
8788
8789 #ifdef BETTER_LITERAL_SHIFT
8790 /*-----------------------------------------------------------------*/
8791 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8792 /*-----------------------------------------------------------------*/
8793 static void
8794 AccAXLsh1 (char *x)
8795 {
8796   emitcode ("xch", "a,%s", x);
8797   emitcode ("add", "a,acc");
8798   emitcode ("xch", "a,%s", x);
8799   emitcode ("rlc", "a");
8800 }
8801 #endif
8802
8803 #ifdef BETTER_LITERAL_SHIFT
8804 /*-----------------------------------------------------------------*/
8805 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8806 /*-----------------------------------------------------------------*/
8807 static void
8808 AccAXLsh (char *x, int shCount)
8809 {
8810   switch (shCount)
8811     {
8812     case 0:
8813       break;
8814     case 1:
8815       AccAXLsh1 (x);
8816       break;
8817     case 2:
8818       AccAXLsh1 (x);
8819       AccAXLsh1 (x);
8820       break;
8821     case 3:
8822     case 4:
8823     case 5:                             // AAAAABBB:CCCCCDDD
8824
8825       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8826
8827       emitcode ("anl", "a,#!constbyte",
8828                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8829
8830       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8831
8832       AccRol (shCount);                 // DDDCCCCC:BBB00000
8833
8834       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8835
8836       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8837
8838       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8839
8840       emitcode ("anl", "a,#!constbyte",
8841                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8842
8843       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8844
8845       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8846
8847       break;
8848     case 6:                             // AAAAAABB:CCCCCCDD
8849       emitcode ("anl", "a,#!constbyte",
8850                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8851 #if 1
8852       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8853       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8854       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8855 #else
8856       emitcode ("mov", "c,acc.0");      // c = B
8857       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8858       emitcode("rrc","a");
8859       emitcode("xch","a,%s", x);
8860       emitcode("rrc","a");
8861       emitcode("mov","c,acc.0"); //<< get correct bit
8862       emitcode("xch","a,%s", x);
8863
8864       emitcode("rrc","a");
8865       emitcode("xch","a,%s", x);
8866       emitcode("rrc","a");
8867       emitcode("xch","a,%s", x);
8868 #endif
8869       break;
8870     case 7:                             // a:x <<= 7
8871
8872       emitcode ("anl", "a,#!constbyte",
8873                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8874
8875       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8876
8877       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8878
8879       break;
8880     default:
8881       break;
8882     }
8883 }
8884 #endif
8885
8886 #ifdef BETTER_LITERAL_SHIFT
8887 //REMOVE ME!!!
8888 /*-----------------------------------------------------------------*/
8889 /* AccAXRsh - right shift a:x known count (0..7)                   */
8890 /*-----------------------------------------------------------------*/
8891 static void
8892 AccAXRsh (char *x, int shCount)
8893 {
8894   switch (shCount)
8895     {
8896     case 0:
8897       break;
8898     case 1:
8899       CLRC;
8900       AccAXRsh1 (x);                    // 0->a:x
8901
8902       break;
8903     case 2:
8904       CLRC;
8905       AccAXRsh1 (x);                    // 0->a:x
8906
8907       CLRC;
8908       AccAXRsh1 (x);                    // 0->a:x
8909
8910       break;
8911     case 3:
8912     case 4:
8913     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8914
8915       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8916
8917       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8918
8919       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8920
8921       emitcode ("anl", "a,#!constbyte",
8922                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8923
8924       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8925
8926       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8927
8928       emitcode ("anl", "a,#!constbyte",
8929                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8930
8931       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8932
8933       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8934
8935       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8936
8937       break;
8938     case 6:                             // AABBBBBB:CCDDDDDD
8939
8940       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8941       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8942
8943       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8944
8945       emitcode ("anl", "a,#!constbyte",
8946                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8947
8948       break;
8949     case 7:                             // ABBBBBBB:CDDDDDDD
8950
8951       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8952
8953       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8954
8955       emitcode ("anl", "a,#!constbyte",
8956                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8957
8958       break;
8959     default:
8960       break;
8961     }
8962 }
8963 #endif
8964
8965 #ifdef BETTER_LITERAL_SHIFT
8966 /*-----------------------------------------------------------------*/
8967 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8968 /*-----------------------------------------------------------------*/
8969 static void
8970 AccAXRshS (char *x, int shCount)
8971 {
8972   symbol *tlbl;
8973   switch (shCount)
8974     {
8975     case 0:
8976       break;
8977     case 1:
8978       emitcode ("mov", "c,acc.7");
8979       AccAXRsh1 (x);                    // s->a:x
8980
8981       break;
8982     case 2:
8983       emitcode ("mov", "c,acc.7");
8984       AccAXRsh1 (x);                    // s->a:x
8985
8986       emitcode ("mov", "c,acc.7");
8987       AccAXRsh1 (x);                    // s->a:x
8988
8989       break;
8990     case 3:
8991     case 4:
8992     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8993
8994       tlbl = newiTempLabel (NULL);
8995       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8996
8997       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8998
8999       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
9000
9001       emitcode ("anl", "a,#!constbyte",
9002                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
9003
9004       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9005
9006       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9007
9008       emitcode ("anl", "a,#!constbyte",
9009                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9010
9011       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9012
9013       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9014
9015       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9016
9017       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9018       emitcode ("orl", "a,#!constbyte",
9019                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9020
9021       emitLabel (tlbl);
9022       break;                            // SSSSAAAA:BBBCCCCC
9023
9024     case 6:                             // AABBBBBB:CCDDDDDD
9025
9026       tlbl = newiTempLabel (NULL);
9027
9028       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9029       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9030
9031       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9032
9033       emitcode ("anl", "a,#!constbyte",
9034                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9035
9036       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9037       emitcode ("orl", "a,#!constbyte",
9038                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9039
9040       emitLabel (tlbl);
9041       break;
9042     case 7:                             // ABBBBBBB:CDDDDDDD
9043
9044       tlbl = newiTempLabel (NULL);
9045
9046       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9047
9048       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9049
9050       emitcode ("anl", "a,#!constbyte",
9051                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9052
9053       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9054       emitcode ("orl", "a,#!constbyte",
9055                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9056
9057       emitLabel (tlbl);
9058       break;
9059     default:
9060       break;
9061     }
9062 }
9063 #endif
9064
9065 #ifdef BETTER_LITERAL_SHIFT
9066 static void
9067 _loadLeftIntoAx(char    **lsb,
9068                 operand *left,
9069                 operand *result,
9070                 int     offl,
9071                 int     offr)
9072 {
9073   // Get the initial value from left into a pair of registers.
9074   // MSB must be in A, LSB can be any register.
9075   //
9076   // If the result is held in registers, it is an optimization
9077   // if the LSB can be held in the register which will hold the,
9078   // result LSB since this saves us from having to copy it into
9079   // the result following AccAXLsh.
9080   //
9081   // If the result is addressed indirectly, this is not a gain.
9082   if (AOP_NEEDSACC(result))
9083   {
9084        char *leftByte;
9085
9086        _startLazyDPSEvaluation();
9087       if (AOP_TYPE(left) == AOP_DPTR2)
9088        {
9089            // Get MSB in A.
9090            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9091            // get LSB in DP2_RESULT_REG.
9092            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9093            assert(!strcmp(leftByte, DP2_RESULT_REG));
9094        }
9095        else
9096        {
9097            // get LSB into DP2_RESULT_REG
9098            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9099            if (strcmp(leftByte, DP2_RESULT_REG))
9100            {
9101                TR_AP("#7");
9102                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9103            }
9104            // And MSB in A.
9105            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9106            assert(strcmp(leftByte, DP2_RESULT_REG));
9107            MOVA (leftByte);
9108        }
9109        _endLazyDPSEvaluation();
9110        *lsb = DP2_RESULT_REG;
9111   }
9112   else
9113   {
9114       if (sameRegs (AOP (result), AOP (left)) &&
9115         ((offl + MSB16) == offr))
9116       {
9117           /* don't crash result[offr] */
9118           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9119           emitcode ("xch", "a,%s",
9120                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9121       }
9122       else
9123       {
9124           movLeft2Result (left, offl, result, offr, 0);
9125           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9126       }
9127       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9128       assert(strcmp(*lsb,"a"));
9129   }
9130 }
9131
9132 static void
9133 _storeAxResults(char    *lsb,
9134                 operand *result,
9135                 int     offr)
9136 {
9137   _startLazyDPSEvaluation();
9138   if (AOP_NEEDSACC(result))
9139   {
9140       /* We have to explicitly update the result LSB.
9141        */
9142       emitcode ("xch","a,%s", lsb);
9143       aopPut (result, "a", offr);
9144       emitcode ("mov","a,%s", lsb);
9145   }
9146   if (getDataSize (result) > 1)
9147   {
9148       aopPut (result, "a", offr + MSB16);
9149   }
9150   _endLazyDPSEvaluation();
9151 }
9152
9153 /*-----------------------------------------------------------------*/
9154 /* shiftL2Left2Result - shift left two bytes from left to result   */
9155 /*-----------------------------------------------------------------*/
9156 static void
9157 shiftL2Left2Result (operand * left, int offl,
9158                     operand * result, int offr, int shCount)
9159 {
9160   char *lsb;
9161
9162   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9163
9164   AccAXLsh (lsb, shCount);
9165
9166   _storeAxResults(lsb, result, offr);
9167 }
9168 #endif
9169
9170 #ifdef BETTER_LITERAL_SHIFT
9171 /*-----------------------------------------------------------------*/
9172 /* shiftR2Left2Result - shift right two bytes from left to result  */
9173 /*-----------------------------------------------------------------*/
9174 static void
9175 shiftR2Left2Result (operand * left, int offl,
9176                     operand * result, int offr,
9177                     int shCount, int sign)
9178 {
9179   char *lsb;
9180
9181   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9182
9183   /* a:x >> shCount (x = lsb(result)) */
9184   if (sign)
9185   {
9186      AccAXRshS(lsb, shCount);
9187   }
9188   else
9189   {
9190     AccAXRsh(lsb, shCount);
9191   }
9192
9193   _storeAxResults(lsb, result, offr);
9194 }
9195 #endif
9196
9197 /*-----------------------------------------------------------------*/
9198 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9199 /*-----------------------------------------------------------------*/
9200 static void
9201 shiftLLeftOrResult (operand * left, int offl,
9202                     operand * result, int offr, int shCount)
9203 {
9204   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9205   /* shift left accumulator */
9206   AccLsh (shCount);
9207   /* or with result */
9208   emitcode ("orl", "a,%s",
9209             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9210   /* back to result */
9211   aopPut (result, "a", offr);
9212 }
9213
9214 #if 0
9215 //REMOVE ME!!!
9216 /*-----------------------------------------------------------------*/
9217 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9218 /*-----------------------------------------------------------------*/
9219 static void
9220 shiftRLeftOrResult (operand * left, int offl,
9221                     operand * result, int offr, int shCount)
9222 {
9223   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9224   /* shift right accumulator */
9225   AccRsh (shCount);
9226   /* or with result */
9227   emitcode ("orl", "a,%s",
9228             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9229   /* back to result */
9230   aopPut (result, "a", offr);
9231 }
9232 #endif
9233
9234 #ifdef BETTER_LITERAL_SHIFT
9235 /*-----------------------------------------------------------------*/
9236 /* genlshOne - left shift a one byte quantity by known count       */
9237 /*-----------------------------------------------------------------*/
9238 static void
9239 genlshOne (operand * result, operand * left, int shCount)
9240 {
9241   D (emitcode (";", "genlshOne"));
9242
9243   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9244 }
9245 #endif
9246
9247 #ifdef BETTER_LITERAL_SHIFT
9248 /*-----------------------------------------------------------------*/
9249 /* genlshTwo - left shift two bytes by known amount != 0           */
9250 /*-----------------------------------------------------------------*/
9251 static void
9252 genlshTwo (operand * result, operand * left, int shCount)
9253 {
9254   int size;
9255
9256   D (emitcode (";", "genlshTwo"));
9257
9258   size = getDataSize (result);
9259
9260   /* if shCount >= 8 */
9261   if (shCount >= 8)
9262   {
9263       shCount -= 8;
9264
9265       _startLazyDPSEvaluation();
9266
9267       if (size > 1)
9268         {
9269           if (shCount)
9270           {
9271             _endLazyDPSEvaluation();
9272             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9273             aopPut (result, zero, LSB);
9274           }
9275           else
9276           {
9277             movLeft2Result (left, LSB, result, MSB16, 0);
9278             aopPut (result, zero, LSB);
9279             _endLazyDPSEvaluation();
9280           }
9281         }
9282         else
9283         {
9284           aopPut (result, zero, LSB);
9285           _endLazyDPSEvaluation();
9286         }
9287   }
9288
9289   /*  1 <= shCount <= 7 */
9290   else
9291     {
9292       if (size == 1)
9293         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9294       else
9295         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9296     }
9297 }
9298 #endif
9299
9300 #if 0
9301 //REMOVE ME!!!
9302 /*-----------------------------------------------------------------*/
9303 /* shiftLLong - shift left one long from left to result            */
9304 /* offl = LSB or MSB16                                             */
9305 /*-----------------------------------------------------------------*/
9306 static void
9307 shiftLLong (operand * left, operand * result, int offr)
9308 {
9309   char *l;
9310   int size = AOP_SIZE (result);
9311
9312   if (size >= LSB + offr)
9313     {
9314       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9315       MOVA (l);
9316       emitcode ("add", "a,acc");
9317       if (sameRegs (AOP (left), AOP (result)) &&
9318           size >= MSB16 + offr && offr != LSB)
9319         emitcode ("xch", "a,%s",
9320                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9321       else
9322         aopPut (result, "a", LSB + offr);
9323     }
9324
9325   if (size >= MSB16 + offr)
9326     {
9327       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9328         {
9329           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9330           MOVA (l);
9331         }
9332       emitcode ("rlc", "a");
9333       if (sameRegs (AOP (left), AOP (result)) &&
9334           size >= MSB24 + offr && offr != LSB)
9335         emitcode ("xch", "a,%s",
9336                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9337       else
9338         aopPut (result, "a", MSB16 + offr);
9339     }
9340
9341   if (size >= MSB24 + offr)
9342     {
9343       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9344         {
9345           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9346           MOVA (l);
9347         }
9348       emitcode ("rlc", "a");
9349       if (sameRegs (AOP (left), AOP (result)) &&
9350           size >= MSB32 + offr && offr != LSB)
9351         emitcode ("xch", "a,%s",
9352                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9353       else
9354         aopPut (result, "a", MSB24 + offr);
9355     }
9356
9357   if (size > MSB32 + offr)
9358     {
9359       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9360         {
9361           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9362           MOVA (l);
9363         }
9364       emitcode ("rlc", "a");
9365       aopPut (result, "a", MSB32 + offr);
9366     }
9367   if (offr != LSB)
9368     aopPut (result, zero, LSB);
9369 }
9370 #endif
9371
9372 #if 0
9373 //REMOVE ME!!!
9374 /*-----------------------------------------------------------------*/
9375 /* genlshFour - shift four byte by a known amount != 0             */
9376 /*-----------------------------------------------------------------*/
9377 static void
9378 genlshFour (operand * result, operand * left, int shCount)
9379 {
9380   int size;
9381
9382   D (emitcode (";", "genlshFour"));
9383
9384   size = AOP_SIZE (result);
9385
9386   /* if shifting more that 3 bytes */
9387   if (shCount >= 24)
9388     {
9389       shCount -= 24;
9390       if (shCount)
9391         /* lowest order of left goes to the highest
9392            order of the destination */
9393         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9394       else
9395         movLeft2Result (left, LSB, result, MSB32, 0);
9396       aopPut (result, zero, LSB);
9397       aopPut (result, zero, MSB16);
9398       aopPut (result, zero, MSB24);
9399       return;
9400     }
9401
9402   /* more than two bytes */
9403   else if (shCount >= 16)
9404     {
9405       /* lower order two bytes goes to higher order two bytes */
9406       shCount -= 16;
9407       /* if some more remaining */
9408       if (shCount)
9409         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9410       else
9411         {
9412           movLeft2Result (left, MSB16, result, MSB32, 0);
9413           movLeft2Result (left, LSB, result, MSB24, 0);
9414         }
9415       aopPut (result, zero, MSB16);
9416       aopPut (result, zero, LSB);
9417       return;
9418     }
9419
9420   /* if more than 1 byte */
9421   else if (shCount >= 8)
9422     {
9423       /* lower order three bytes goes to higher order  three bytes */
9424       shCount -= 8;
9425       if (size == 2)
9426         {
9427           if (shCount)
9428             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9429           else
9430             movLeft2Result (left, LSB, result, MSB16, 0);
9431         }
9432       else
9433         {                       /* size = 4 */
9434           if (shCount == 0)
9435             {
9436               movLeft2Result (left, MSB24, result, MSB32, 0);
9437               movLeft2Result (left, MSB16, result, MSB24, 0);
9438               movLeft2Result (left, LSB, result, MSB16, 0);
9439               aopPut (result, zero, LSB);
9440             }
9441           else if (shCount == 1)
9442             shiftLLong (left, result, MSB16);
9443           else
9444             {
9445               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9446               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9447               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9448               aopPut (result, zero, LSB);
9449             }
9450         }
9451     }
9452
9453   /* 1 <= shCount <= 7 */
9454   else if (shCount <= 2)
9455     {
9456       shiftLLong (left, result, LSB);
9457       if (shCount == 2)
9458         shiftLLong (result, result, LSB);
9459     }
9460   /* 3 <= shCount <= 7, optimize */
9461   else
9462     {
9463       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9464       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9465       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9466     }
9467 }
9468 #endif
9469
9470 #ifdef BETTER_LITERAL_SHIFT
9471 /*-----------------------------------------------------------------*/
9472 /* genLeftShiftLiteral - left shifting by known count              */
9473 /*-----------------------------------------------------------------*/
9474 static bool
9475 genLeftShiftLiteral (operand * left,
9476                      operand * right,
9477                      operand * result,
9478                      iCode * ic)
9479 {
9480   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9481   int size;
9482
9483   size = getSize (operandType (result));
9484
9485   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9486
9487   /* We only handle certain easy cases so far. */
9488   if ((shCount != 0)
9489    && (shCount < (size * 8))
9490    && (size != 1)
9491    && (size != 2))
9492   {
9493       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9494       return FALSE;
9495   }
9496
9497   freeAsmop (right, NULL, ic, TRUE);
9498
9499   aopOp(left, ic, FALSE, FALSE);
9500   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9501
9502 #if 0 // debug spew
9503   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9504   {
9505         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9506         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9507         {
9508            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9509         }
9510   }
9511   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9512   {
9513         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9514         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9515         {
9516            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9517         }
9518   }
9519 #endif
9520
9521 #if VIEW_SIZE
9522   emitcode ("; shift left ", "result %d, left %d", size,
9523             AOP_SIZE (left));
9524 #endif
9525
9526   /* I suppose that the left size >= result size */
9527   if (shCount == 0)
9528   {
9529         _startLazyDPSEvaluation();
9530         while (size--)
9531         {
9532           movLeft2Result (left, size, result, size, 0);
9533         }
9534         _endLazyDPSEvaluation();
9535   }
9536   else if (shCount >= (size * 8))
9537   {
9538     _startLazyDPSEvaluation();
9539     while (size--)
9540     {
9541       aopPut (result, zero, size);
9542     }
9543     _endLazyDPSEvaluation();
9544   }
9545   else
9546   {
9547       switch (size)
9548         {
9549         case 1:
9550           genlshOne (result, left, shCount);
9551           break;
9552
9553         case 2:
9554           genlshTwo (result, left, shCount);
9555           break;
9556 #if 0
9557         case 4:
9558           genlshFour (result, left, shCount);
9559           break;
9560 #endif
9561         default:
9562           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9563                   "*** ack! mystery literal shift!\n");
9564           break;
9565         }
9566     }
9567   freeAsmop (result, NULL, ic, TRUE);
9568   freeAsmop (left, NULL, ic, TRUE);
9569   return TRUE;
9570 }
9571 #endif
9572
9573 /*-----------------------------------------------------------------*/
9574 /* genLeftShift - generates code for left shifting                 */
9575 /*-----------------------------------------------------------------*/
9576 static void
9577 genLeftShift (iCode * ic)
9578 {
9579   operand *left, *right, *result;
9580   int size, offset;
9581   char *l;
9582   symbol *tlbl, *tlbl1;
9583   bool pushedB;
9584
9585   D (emitcode (";", "genLeftShift"));
9586
9587   right = IC_RIGHT (ic);
9588   left = IC_LEFT (ic);
9589   result = IC_RESULT (ic);
9590
9591   aopOp (right, ic, FALSE, FALSE);
9592
9593
9594 #ifdef BETTER_LITERAL_SHIFT
9595   /* if the shift count is known then do it
9596      as efficiently as possible */
9597   if (AOP_TYPE (right) == AOP_LIT)
9598     {
9599       if (genLeftShiftLiteral (left, right, result, ic))
9600       {
9601         return;
9602       }
9603     }
9604 #endif
9605
9606   /* shift count is unknown then we have to form
9607      a loop get the loop count in B : Note: we take
9608      only the lower order byte since shifting
9609      more that 32 bits make no sense anyway, ( the
9610      largest size of an object can be only 32 bits ) */
9611
9612   pushedB = pushB ();
9613   if (AOP_TYPE (right) == AOP_LIT)
9614   {
9615       /* Really should be handled by genLeftShiftLiteral,
9616        * but since I'm too lazy to fix that today, at least we can make
9617        * some small improvement.
9618        */
9619        emitcode("mov", "b,#!constbyte",
9620                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9621   }
9622   else
9623   {
9624       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9625       emitcode ("inc", "b");
9626   }
9627   freeAsmop (right, NULL, ic, TRUE);
9628   aopOp (left, ic, FALSE, FALSE);
9629   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9630
9631   /* now move the left to the result if they are not the same */
9632   if (!sameRegs (AOP (left), AOP (result)) &&
9633       AOP_SIZE (result) > 1)
9634     {
9635
9636       size = AOP_SIZE (result);
9637       offset = 0;
9638       _startLazyDPSEvaluation ();
9639       while (size--)
9640         {
9641           l = aopGet (left, offset, FALSE, TRUE, NULL);
9642           if (*l == '@' && (IS_AOP_PREG (result)))
9643             {
9644
9645               emitcode ("mov", "a,%s", l);
9646               aopPut (result, "a", offset);
9647             }
9648           else
9649             aopPut (result, l, offset);
9650           offset++;
9651         }
9652       _endLazyDPSEvaluation ();
9653     }
9654
9655   tlbl = newiTempLabel (NULL);
9656   size = AOP_SIZE (result);
9657   offset = 0;
9658   tlbl1 = newiTempLabel (NULL);
9659
9660   /* if it is only one byte then */
9661   if (size == 1)
9662     {
9663       symbol *tlbl1 = newiTempLabel (NULL);
9664
9665       l = aopGet (left, 0, FALSE, FALSE, NULL);
9666       MOVA (l);
9667       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9668       emitLabel (tlbl);
9669       emitcode ("add", "a,acc");
9670       emitLabel (tlbl1);
9671       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9672       popB (pushedB);
9673       aopPut (result, "a", 0);
9674       goto release;
9675     }
9676
9677   reAdjustPreg (AOP (result));
9678
9679   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9680   emitLabel (tlbl);
9681   l = aopGet (result, offset, FALSE, FALSE, NULL);
9682   MOVA (l);
9683   emitcode ("add", "a,acc");
9684   aopPut (result, "a", offset++);
9685   _startLazyDPSEvaluation ();
9686   while (--size)
9687     {
9688       l = aopGet (result, offset, FALSE, FALSE, NULL);
9689       MOVA (l);
9690       emitcode ("rlc", "a");
9691       aopPut (result, "a", offset++);
9692     }
9693   _endLazyDPSEvaluation ();
9694   reAdjustPreg (AOP (result));
9695
9696   emitLabel (tlbl1);
9697   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9698   popB (pushedB);
9699 release:
9700   freeAsmop (result, NULL, ic, TRUE);
9701   freeAsmop (left, NULL, ic, TRUE);
9702 }
9703
9704 #ifdef BETTER_LITERAL_SHIFT
9705 /*-----------------------------------------------------------------*/
9706 /* genrshOne - right shift a one byte quantity by known count      */
9707 /*-----------------------------------------------------------------*/
9708 static void
9709 genrshOne (operand * result, operand * left,
9710            int shCount, int sign)
9711 {
9712   D (emitcode (";", "genrshOne"));
9713
9714   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9715 }
9716 #endif
9717
9718 #ifdef BETTER_LITERAL_SHIFT
9719 /*-----------------------------------------------------------------*/
9720 /* genrshTwo - right shift two bytes by known amount != 0          */
9721 /*-----------------------------------------------------------------*/
9722 static void
9723 genrshTwo (operand * result, operand * left,
9724            int shCount, int sign)
9725 {
9726   D (emitcode (";", "genrshTwo"));
9727
9728   /* if shCount >= 8 */
9729   if (shCount >= 8)
9730     {
9731       shCount -= 8;
9732       _startLazyDPSEvaluation();
9733       if (shCount)
9734         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9735       else
9736         movLeft2Result (left, MSB16, result, LSB, sign);
9737       addSign (result, MSB16, sign);
9738       _endLazyDPSEvaluation();
9739     }
9740
9741   /*  1 <= shCount <= 7 */
9742   else
9743     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9744 }
9745 #endif
9746
9747 /*-----------------------------------------------------------------*/
9748 /* shiftRLong - shift right one long from left to result           */
9749 /* offl = LSB or MSB16                                             */
9750 /*-----------------------------------------------------------------*/
9751 static void
9752 shiftRLong (operand * left, int offl,
9753             operand * result, int sign)
9754 {
9755   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9756
9757   if (overlapping && offl>1)
9758     {
9759       // we are in big trouble, but this shouldn't happen
9760       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9761     }
9762
9763   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9764
9765   if (offl==MSB16)
9766     {
9767       // shift is > 8
9768       if (sign)
9769         {
9770           emitcode ("rlc", "a");
9771           emitcode ("subb", "a,acc");
9772           emitcode ("xch", "a,%s",
9773                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9774         }
9775       else
9776         {
9777           aopPut (result, zero, MSB32);
9778         }
9779     }
9780
9781   if (!sign)
9782     {
9783       emitcode ("clr", "c");
9784     }
9785   else
9786     {
9787       emitcode ("mov", "c,acc.7");
9788     }
9789
9790   emitcode ("rrc", "a");
9791
9792   if (overlapping && offl==MSB16)
9793     {
9794       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9795     }
9796   else
9797     {
9798       aopPut (result, "a", MSB32 - offl);
9799       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9800     }
9801
9802   emitcode ("rrc", "a");
9803
9804   if (overlapping && offl==MSB16)
9805     {
9806       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9807     }
9808   else
9809     {
9810       aopPut (result, "a", MSB24 - offl);
9811       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9812     }
9813
9814   emitcode ("rrc", "a");
9815   if (offl != LSB)
9816     {
9817       aopPut (result, "a", MSB16 - offl);
9818     }
9819   else
9820     {
9821       if (overlapping && offl==MSB16)
9822         {
9823           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9824         }
9825       else
9826         {
9827           aopPut (result, "a", MSB16 - offl);
9828           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9829         }
9830       emitcode ("rrc", "a");
9831       aopPut (result, "a", LSB);
9832     }
9833 }
9834
9835 /*-----------------------------------------------------------------*/
9836 /* genrshFour - shift four byte by a known amount != 0             */
9837 /*-----------------------------------------------------------------*/
9838 static void
9839 genrshFour (operand * result, operand * left,
9840             int shCount, int sign)
9841 {
9842   D (emitcode (";", "genrshFour"));
9843
9844   /* if shifting more that 3 bytes */
9845   if (shCount >= 24)
9846     {
9847       shCount -= 24;
9848       _startLazyDPSEvaluation();
9849       if (shCount)
9850         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9851       else
9852         movLeft2Result (left, MSB32, result, LSB, sign);
9853       addSign (result, MSB16, sign);
9854       _endLazyDPSEvaluation();
9855     }
9856   else if (shCount >= 16)
9857     {
9858       shCount -= 16;
9859       _startLazyDPSEvaluation();
9860       if (shCount)
9861         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9862       else
9863         {
9864           movLeft2Result (left, MSB24, result, LSB, 0);
9865           movLeft2Result (left, MSB32, result, MSB16, sign);
9866         }
9867       addSign (result, MSB24, sign);
9868       _endLazyDPSEvaluation();
9869     }
9870   else if (shCount >= 8)
9871     {
9872       shCount -= 8;
9873       _startLazyDPSEvaluation();
9874       if (shCount == 1)
9875         {
9876             shiftRLong (left, MSB16, result, sign);
9877         }
9878       else if (shCount == 0)
9879         {
9880           movLeft2Result (left, MSB16, result, LSB, 0);
9881           movLeft2Result (left, MSB24, result, MSB16, 0);
9882           movLeft2Result (left, MSB32, result, MSB24, sign);
9883           addSign (result, MSB32, sign);
9884         }
9885       else
9886         {
9887           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9888           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9889           /* the last shift is signed */
9890           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9891           addSign (result, MSB32, sign);
9892         }
9893         _endLazyDPSEvaluation();
9894     }
9895   else
9896     {
9897       /* 1 <= shCount <= 7 */
9898       if (shCount <= 2)
9899         {
9900           shiftRLong (left, LSB, result, sign);
9901           if (shCount == 2)
9902             shiftRLong (result, LSB, result, sign);
9903         }
9904       else
9905         {
9906           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9907           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9908           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9909         }
9910     }
9911 }
9912
9913 #ifdef BETTER_LITERAL_SHIFT
9914 /*-----------------------------------------------------------------*/
9915 /* genRightShiftLiteral - right shifting by known count            */
9916 /*-----------------------------------------------------------------*/
9917 static bool
9918 genRightShiftLiteral (operand * left,
9919                       operand * right,
9920                       operand * result,
9921                       iCode * ic,
9922                       int sign)
9923 {
9924   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9925   int size;
9926
9927   size = getSize (operandType (result));
9928
9929   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9930
9931   /* We only handle certain easy cases so far. */
9932   if ((shCount != 0)
9933    && (shCount < (size * 8))
9934    && (size != 1)
9935    && (size != 2)
9936    && (size != 4))
9937   {
9938       D(emitcode (";", "genRightShiftLiteral wimping out"););
9939       return FALSE;
9940   }
9941
9942   freeAsmop (right, NULL, ic, TRUE);
9943
9944   aopOp (left, ic, FALSE, FALSE);
9945   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9946
9947 #if VIEW_SIZE
9948   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9949             AOP_SIZE (left));
9950 #endif
9951
9952   /* test the LEFT size !!! */
9953
9954   /* I suppose that the left size >= result size */
9955   if (shCount == 0)
9956   {
9957       size = getDataSize (result);
9958       _startLazyDPSEvaluation();
9959       while (size--)
9960         movLeft2Result (left, size, result, size, 0);
9961       _endLazyDPSEvaluation();
9962   }
9963   else if (shCount >= (size * 8))
9964     {
9965       if (sign)
9966         {
9967           /* get sign in acc.7 */
9968           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9969         }
9970       addSign (result, LSB, sign);
9971     }
9972   else
9973     {
9974       switch (size)
9975         {
9976         case 1:
9977           genrshOne (result, left, shCount, sign);
9978           break;
9979
9980         case 2:
9981           genrshTwo (result, left, shCount, sign);
9982           break;
9983 #if 1
9984         case 4:
9985           genrshFour (result, left, shCount, sign);
9986           break;
9987 #endif
9988         default:
9989           break;
9990         }
9991     }
9992   freeAsmop (result, NULL, ic, TRUE);
9993   freeAsmop (left, NULL, ic, TRUE);
9994
9995   return TRUE;
9996 }
9997 #endif
9998
9999 /*-----------------------------------------------------------------*/
10000 /* genSignedRightShift - right shift of signed number              */
10001 /*-----------------------------------------------------------------*/
10002 static void
10003 genSignedRightShift (iCode * ic)
10004 {
10005   operand *right, *left, *result;
10006   int size, offset;
10007   char *l;
10008   symbol *tlbl, *tlbl1;
10009   bool pushedB;
10010
10011   D (emitcode (";", "genSignedRightShift"));
10012
10013   /* we do it the hard way put the shift count in b
10014      and loop thru preserving the sign */
10015
10016   right = IC_RIGHT (ic);
10017   left = IC_LEFT (ic);
10018   result = IC_RESULT (ic);
10019
10020   aopOp (right, ic, FALSE, FALSE);
10021
10022 #ifdef BETTER_LITERAL_SHIFT
10023   if (AOP_TYPE (right) == AOP_LIT)
10024     {
10025       if (genRightShiftLiteral (left, right, result, ic, 1))
10026       {
10027         return;
10028       }
10029     }
10030 #endif
10031   /* shift count is unknown then we have to form
10032      a loop get the loop count in B : Note: we take
10033      only the lower order byte since shifting
10034      more that 32 bits make no sense anyway, ( the
10035      largest size of an object can be only 32 bits ) */
10036
10037   pushedB = pushB ();
10038   if (AOP_TYPE (right) == AOP_LIT)
10039   {
10040       /* Really should be handled by genRightShiftLiteral,
10041        * but since I'm too lazy to fix that today, at least we can make
10042        * some small improvement.
10043        */
10044        emitcode("mov", "b,#!constbyte",
10045                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10046   }
10047   else
10048   {
10049         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10050         emitcode ("inc", "b");
10051   }
10052   freeAsmop (right, NULL, ic, TRUE);
10053   aopOp (left, ic, FALSE, FALSE);
10054   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10055
10056   /* now move the left to the result if they are not the
10057      same */
10058   if (!sameRegs (AOP (left), AOP (result)) &&
10059       AOP_SIZE (result) > 1)
10060     {
10061
10062       size = AOP_SIZE (result);
10063       offset = 0;
10064       _startLazyDPSEvaluation ();
10065       while (size--)
10066         {
10067           l = aopGet (left, offset, FALSE, TRUE, NULL);
10068           if (*l == '@' && IS_AOP_PREG (result))
10069             {
10070
10071               emitcode ("mov", "a,%s", l);
10072               aopPut (result, "a", offset);
10073             }
10074           else
10075             aopPut (result, l, offset);
10076           offset++;
10077         }
10078       _endLazyDPSEvaluation ();
10079     }
10080
10081   /* mov the highest order bit to OVR */
10082   tlbl = newiTempLabel (NULL);
10083   tlbl1 = newiTempLabel (NULL);
10084
10085   size = AOP_SIZE (result);
10086   offset = size - 1;
10087   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10088   emitcode ("rlc", "a");
10089   emitcode ("mov", "ov,c");
10090   /* if it is only one byte then */
10091   if (size == 1)
10092     {
10093       l = aopGet (left, 0, FALSE, FALSE, NULL);
10094       MOVA (l);
10095       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10096       emitLabel (tlbl);
10097       emitcode ("mov", "c,ov");
10098       emitcode ("rrc", "a");
10099       emitLabel (tlbl1);
10100       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10101       popB (pushedB);
10102       aopPut (result, "a", 0);
10103       goto release;
10104     }
10105
10106   reAdjustPreg (AOP (result));
10107   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10108   emitLabel (tlbl);
10109   emitcode ("mov", "c,ov");
10110   _startLazyDPSEvaluation ();
10111   while (size--)
10112     {
10113       l = aopGet (result, offset, FALSE, FALSE, NULL);
10114       MOVA (l);
10115       emitcode ("rrc", "a");
10116       aopPut (result, "a", offset--);
10117     }
10118   _endLazyDPSEvaluation ();
10119   reAdjustPreg (AOP (result));
10120   emitLabel (tlbl1);
10121   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10122   popB (pushedB);
10123
10124 release:
10125   freeAsmop (result, NULL, ic, TRUE);
10126   freeAsmop (left, NULL, ic, TRUE);
10127 }
10128
10129 /*-----------------------------------------------------------------*/
10130 /* genRightShift - generate code for right shifting                */
10131 /*-----------------------------------------------------------------*/
10132 static void
10133 genRightShift (iCode * ic)
10134 {
10135   operand *right, *left, *result;
10136   sym_link *letype;
10137   int size, offset;
10138   char *l;
10139   symbol *tlbl, *tlbl1;
10140   bool pushedB;
10141
10142   D (emitcode (";", "genRightShift"));
10143
10144   /* if signed then we do it the hard way preserve the
10145      sign bit moving it inwards */
10146   letype = getSpec (operandType (IC_LEFT (ic)));
10147
10148   if (!SPEC_USIGN (letype))
10149     {
10150       genSignedRightShift (ic);
10151       return;
10152     }
10153
10154   /* signed & unsigned types are treated the same : i.e. the
10155      signed is NOT propagated inwards : quoting from the
10156      ANSI - standard : "for E1 >> E2, is equivalent to division
10157      by 2**E2 if unsigned or if it has a non-negative value,
10158      otherwise the result is implementation defined ", MY definition
10159      is that the sign does not get propagated */
10160
10161   right = IC_RIGHT (ic);
10162   left = IC_LEFT (ic);
10163   result = IC_RESULT (ic);
10164
10165   aopOp (right, ic, FALSE, FALSE);
10166
10167 #ifdef BETTER_LITERAL_SHIFT
10168   /* if the shift count is known then do it
10169      as efficiently as possible */
10170   if (AOP_TYPE (right) == AOP_LIT)
10171     {
10172       if (genRightShiftLiteral (left, right, result, ic, 0))
10173       {
10174         return;
10175       }
10176     }
10177 #endif
10178
10179   /* shift count is unknown then we have to form
10180      a loop get the loop count in B : Note: we take
10181      only the lower order byte since shifting
10182      more that 32 bits make no sense anyway, ( the
10183      largest size of an object can be only 32 bits ) */
10184
10185   pushedB = pushB ();
10186   if (AOP_TYPE (right) == AOP_LIT)
10187   {
10188       /* Really should be handled by genRightShiftLiteral,
10189        * but since I'm too lazy to fix that today, at least we can make
10190        * some small improvement.
10191        */
10192        emitcode("mov", "b,#!constbyte",
10193                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
10194   }
10195   else
10196   {
10197       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10198       emitcode ("inc", "b");
10199   }
10200   freeAsmop (right, NULL, ic, TRUE);
10201   aopOp (left, ic, FALSE, FALSE);
10202   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10203
10204   /* now move the left to the result if they are not the
10205      same */
10206   if (!sameRegs (AOP (left), AOP (result)) &&
10207       AOP_SIZE (result) > 1)
10208     {
10209       size = AOP_SIZE (result);
10210       offset = 0;
10211       _startLazyDPSEvaluation ();
10212       while (size--)
10213         {
10214           l = aopGet (left, offset, FALSE, TRUE, NULL);
10215           if (*l == '@' && IS_AOP_PREG (result))
10216             {
10217
10218               emitcode ("mov", "a,%s", l);
10219               aopPut (result, "a", offset);
10220             }
10221           else
10222             aopPut (result, l, offset);
10223           offset++;
10224         }
10225       _endLazyDPSEvaluation ();
10226     }
10227
10228   tlbl = newiTempLabel (NULL);
10229   tlbl1 = newiTempLabel (NULL);
10230   size = AOP_SIZE (result);
10231   offset = size - 1;
10232
10233   /* if it is only one byte then */
10234   if (size == 1)
10235     {
10236       l = aopGet (left, 0, FALSE, FALSE, NULL);
10237       MOVA (l);
10238       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10239       emitLabel (tlbl);
10240       CLRC;
10241       emitcode ("rrc", "a");
10242       emitLabel (tlbl1);
10243       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10244       popB (pushedB);
10245       aopPut (result, "a", 0);
10246       goto release;
10247     }
10248
10249   reAdjustPreg (AOP (result));
10250   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10251   emitLabel (tlbl);
10252   CLRC;
10253   _startLazyDPSEvaluation ();
10254   while (size--)
10255     {
10256       l = aopGet (result, offset, FALSE, FALSE, NULL);
10257       MOVA (l);
10258       emitcode ("rrc", "a");
10259       aopPut (result, "a", offset--);
10260     }
10261   _endLazyDPSEvaluation ();
10262   reAdjustPreg (AOP (result));
10263
10264   emitLabel (tlbl1);
10265   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10266   popB (pushedB);
10267
10268 release:
10269   freeAsmop (result, NULL, ic, TRUE);
10270   freeAsmop (left, NULL, ic, TRUE);
10271 }
10272
10273 /*-----------------------------------------------------------------*/
10274 /* emitPtrByteGet - emits code to get a byte into A through a      */
10275 /*                  pointer register (R0, R1, or DPTR). The        */
10276 /*                  original value of A can be preserved in B.     */
10277 /*-----------------------------------------------------------------*/
10278 static void
10279 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10280 {
10281   switch (p_type)
10282     {
10283     case IPOINTER:
10284     case POINTER:
10285       if (preserveAinB)
10286         emitcode ("mov", "b,a");
10287       emitcode ("mov", "a,@%s", rname);
10288       break;
10289
10290     case PPOINTER:
10291       if (preserveAinB)
10292         emitcode ("mov", "b,a");
10293       emitcode ("movx", "a,@%s", rname);
10294       break;
10295
10296     case FPOINTER:
10297       if (preserveAinB)
10298         emitcode ("mov", "b,a");
10299       emitcode ("movx", "a,@dptr");
10300       break;
10301
10302     case CPOINTER:
10303       if (preserveAinB)
10304         emitcode ("mov", "b,a");
10305       emitcode ("clr", "a");
10306       emitcode ("movc", "a,@a+dptr");
10307       break;
10308
10309     case GPOINTER:
10310       if (preserveAinB)
10311         {
10312           emitcode ("push", "b");
10313           emitcode ("push", "acc");
10314         }
10315       emitcode ("lcall", "__gptrget");
10316       if (preserveAinB)
10317         emitcode ("pop", "b");
10318       break;
10319     }
10320 }
10321
10322 /*-----------------------------------------------------------------*/
10323 /* emitPtrByteSet - emits code to set a byte from src through a    */
10324 /*                  pointer register (R0, R1, or DPTR).            */
10325 /*-----------------------------------------------------------------*/
10326 static void
10327 emitPtrByteSet (char *rname, int p_type, char *src)
10328 {
10329   switch (p_type)
10330     {
10331     case IPOINTER:
10332     case POINTER:
10333       if (*src=='@')
10334         {
10335           MOVA (src);
10336           emitcode ("mov", "@%s,a", rname);
10337         }
10338       else
10339         emitcode ("mov", "@%s,%s", rname, src);
10340       break;
10341
10342     case PPOINTER:
10343       MOVA (src);
10344       emitcode ("movx", "@%s,a", rname);
10345       break;
10346
10347     case FPOINTER:
10348       MOVA (src);
10349       emitcode ("movx", "@dptr,a");
10350       break;
10351
10352     case GPOINTER:
10353       MOVA (src);
10354       emitcode ("lcall", "__gptrput");
10355       break;
10356     }
10357 }
10358
10359 /*-----------------------------------------------------------------*/
10360 /* genUnpackBits - generates code for unpacking bits               */
10361 /*-----------------------------------------------------------------*/
10362 static void
10363 genUnpackBits (operand * result, char *rname, int ptype)
10364 {
10365   int offset = 0;       /* result byte offset */
10366   int rsize;            /* result size */
10367   int rlen = 0;         /* remaining bitfield length */
10368   sym_link *etype;      /* bitfield type information */
10369   int blen;             /* bitfield length */
10370   int bstr;             /* bitfield starting bit within byte */
10371
10372   D(emitcode (";     genUnpackBits",""));
10373
10374   etype = getSpec (operandType (result));
10375   rsize = getSize (operandType (result));
10376   blen = SPEC_BLEN (etype);
10377   bstr = SPEC_BSTR (etype);
10378
10379   /* If the bitfield length is less than a byte */
10380   if (blen < 8)
10381     {
10382       emitPtrByteGet (rname, ptype, FALSE);
10383       AccRol (8 - bstr);
10384       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10385       if (!SPEC_USIGN (etype))
10386         {
10387           /* signed bitfield */
10388           symbol *tlbl = newiTempLabel (NULL);
10389
10390           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10391           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10392           emitLabel (tlbl);
10393         }
10394       aopPut (result, "a", offset++);
10395       goto finish;
10396     }
10397
10398   /* Bit field did not fit in a byte. Copy all
10399      but the partial byte at the end.  */
10400   for (rlen=blen;rlen>=8;rlen-=8)
10401     {
10402       emitPtrByteGet (rname, ptype, FALSE);
10403       aopPut (result, "a", offset++);
10404       if (rlen>8)
10405         emitcode ("inc", "%s", rname);
10406     }
10407
10408   /* Handle the partial byte at the end */
10409   if (rlen)
10410     {
10411       emitPtrByteGet (rname, ptype, FALSE);
10412       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10413       if (!SPEC_USIGN (etype))
10414         {
10415           /* signed bitfield */
10416           symbol *tlbl = newiTempLabel (NULL);
10417
10418           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10419           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10420           emitLabel (tlbl);
10421         }
10422       aopPut (result, "a", offset++);
10423     }
10424
10425 finish:
10426   if (offset < rsize)
10427     {
10428       char *source;
10429
10430       if (SPEC_USIGN (etype))
10431         source = zero;
10432       else
10433         {
10434           /* signed bitfield: sign extension with 0x00 or 0xff */
10435           emitcode ("rlc", "a");
10436           emitcode ("subb", "a,acc");
10437
10438           source = "a";
10439         }
10440       rsize -= offset;
10441       while (rsize--)
10442         aopPut (result, source, offset++);
10443     }
10444 }
10445
10446
10447 /*-----------------------------------------------------------------*/
10448 /* genDataPointerGet - generates code when ptr offset is known     */
10449 /*-----------------------------------------------------------------*/
10450 static void
10451 genDataPointerGet (operand * left,
10452                    operand * result,
10453                    iCode * ic)
10454 {
10455   char *l;
10456   char buffer[256];
10457   int size, offset = 0;
10458   aopOp (result, ic, TRUE, FALSE);
10459
10460   /* get the string representation of the name */
10461   l = aopGet (left, 0, FALSE, TRUE, NULL);
10462   size = AOP_SIZE (result);
10463   _startLazyDPSEvaluation ();
10464   while (size--)
10465     {
10466         if (offset)
10467         {
10468             SNPRINTF (buffer, sizeof(buffer),
10469                       "(%s + %d)", l + 1, offset);
10470         }
10471         else
10472         {
10473             SNPRINTF (buffer, sizeof(buffer),
10474                       "%s", l + 1);
10475         }
10476       aopPut (result, buffer, offset++);
10477     }
10478   _endLazyDPSEvaluation ();
10479
10480   freeAsmop (result, NULL, ic, TRUE);
10481   freeAsmop (left, NULL, ic, TRUE);
10482 }
10483
10484 /*-----------------------------------------------------------------*/
10485 /* genNearPointerGet - emitcode for near pointer fetch             */
10486 /*-----------------------------------------------------------------*/
10487 static void
10488 genNearPointerGet (operand * left,
10489                    operand * result,
10490                    iCode * ic,
10491                    iCode *pi)
10492 {
10493   asmop *aop = NULL;
10494   regs *preg;
10495   char *rname;
10496   sym_link *rtype, *retype, *letype;
10497   sym_link *ltype = operandType (left);
10498   char buffer[80];
10499
10500   rtype = operandType (result);
10501   retype = getSpec (rtype);
10502   letype = getSpec (ltype);
10503
10504   aopOp (left, ic, FALSE, FALSE);
10505
10506   /* if left is rematerialisable and
10507      result is not bitfield variable type and
10508      the left is pointer to data space i.e
10509      lower 128 bytes of space */
10510   if (AOP_TYPE (left) == AOP_IMMD &&
10511       !IS_BITFIELD (retype) &&
10512       !IS_BITFIELD (letype) &&
10513       DCL_TYPE (ltype) == POINTER)
10514     {
10515       genDataPointerGet (left, result, ic);
10516       return;
10517     }
10518
10519   /* if the value is already in a pointer register
10520      then don't need anything more */
10521   if (!AOP_INPREG (AOP (left)))
10522     {
10523       /* otherwise get a free pointer register */
10524       aop = newAsmop (0);
10525       preg = getFreePtr (ic, &aop, FALSE);
10526       emitcode ("mov", "%s,%s",
10527                 preg->name,
10528                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10529       rname = preg->name;
10530     }
10531   else
10532     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10533
10534   freeAsmop (left, NULL, ic, TRUE);
10535   aopOp (result, ic, FALSE, FALSE);
10536
10537   /* if bitfield then unpack the bits */
10538   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10539     genUnpackBits (result, rname, POINTER);
10540   else
10541     {
10542       /* we have can just get the values */
10543       int size = AOP_SIZE (result);
10544       int offset = 0;
10545
10546       while (size--)
10547         {
10548           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10549             {
10550
10551               emitcode ("mov", "a,@%s", rname);
10552               aopPut (result, "a", offset);
10553             }
10554           else
10555             {
10556               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10557               aopPut (result, buffer, offset);
10558             }
10559           offset++;
10560           if (size || pi)
10561             emitcode ("inc", "%s", rname);
10562         }
10563     }
10564
10565   /* now some housekeeping stuff */
10566   if (aop)      /* we had to allocate for this iCode */
10567     {
10568       if (pi) { /* post increment present */
10569         aopPut (left, rname, 0);
10570       }
10571       freeAsmop (NULL, aop, ic, TRUE);
10572     }
10573   else
10574     {
10575       /* we did not allocate which means left
10576          already in a pointer register, then
10577          if size > 0 && this could be used again
10578          we have to point it back to where it
10579          belongs */
10580       if (AOP_SIZE (result) > 1 &&
10581           !OP_SYMBOL (left)->remat &&
10582           (OP_SYMBOL (left)->liveTo > ic->seq ||
10583            ic->depth) &&
10584           !pi)
10585         {
10586           int size = AOP_SIZE (result) - 1;
10587           while (size--)
10588             emitcode ("dec", "%s", rname);
10589         }
10590     }
10591
10592   /* done */
10593   freeAsmop (result, NULL, ic, TRUE);
10594   if (pi) pi->generated = 1;
10595 }
10596
10597 /*-----------------------------------------------------------------*/
10598 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10599 /*-----------------------------------------------------------------*/
10600 static void
10601 genPagedPointerGet (operand * left,
10602                     operand * result,
10603                     iCode * ic,
10604                     iCode * pi)
10605 {
10606   asmop *aop = NULL;
10607   regs *preg;
10608   char *rname;
10609   sym_link *rtype, *retype, *letype;
10610
10611   rtype = operandType (result);
10612   retype = getSpec (rtype);
10613   letype = getSpec (operandType (left));
10614   aopOp (left, ic, FALSE, FALSE);
10615
10616   /* if the value is already in a pointer register
10617      then don't need anything more */
10618   if (!AOP_INPREG (AOP (left)))
10619     {
10620       /* otherwise get a free pointer register */
10621       aop = newAsmop (0);
10622       preg = getFreePtr (ic, &aop, FALSE);
10623       emitcode ("mov", "%s,%s",
10624                 preg->name,
10625                 aopGet (left, 0, FALSE, TRUE, NULL));
10626       rname = preg->name;
10627     }
10628   else
10629     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10630
10631   freeAsmop (left, NULL, ic, TRUE);
10632   aopOp (result, ic, FALSE, FALSE);
10633
10634   /* if bitfield then unpack the bits */
10635   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10636     genUnpackBits (result, rname, PPOINTER);
10637   else
10638     {
10639       /* we have can just get the values */
10640       int size = AOP_SIZE (result);
10641       int offset = 0;
10642
10643       while (size--)
10644         {
10645
10646           emitcode ("movx", "a,@%s", rname);
10647           aopPut (result, "a", offset);
10648
10649           offset++;
10650
10651           if (size || pi)
10652             emitcode ("inc", "%s", rname);
10653         }
10654     }
10655
10656   /* now some housekeeping stuff */
10657   if (aop)      /* we had to allocate for this iCode */
10658     {
10659       if (pi)
10660         aopPut (left, rname, 0);
10661       freeAsmop (NULL, aop, ic, TRUE);
10662     }
10663   else
10664     {
10665       /* we did not allocate which means left
10666          already in a pointer register, then
10667          if size > 0 && this could be used again
10668          we have to point it back to where it
10669          belongs */
10670       if (AOP_SIZE (result) > 1 &&
10671           !OP_SYMBOL (left)->remat &&
10672           (OP_SYMBOL (left)->liveTo > ic->seq ||
10673            ic->depth) &&
10674           !pi)
10675         {
10676           int size = AOP_SIZE (result) - 1;
10677           while (size--)
10678             emitcode ("dec", "%s", rname);
10679         }
10680     }
10681
10682   /* done */
10683   freeAsmop (result, NULL, ic, TRUE);
10684   if (pi) pi->generated = 1;
10685 }
10686
10687 /*-----------------------------------------------------------------*/
10688 /* genFarPointerGet - get value from far space                     */
10689 /*-----------------------------------------------------------------*/
10690 static void
10691 genFarPointerGet (operand * left,
10692                   operand * result, iCode * ic, iCode *pi)
10693 {
10694   int size, offset, dopi=1;
10695   sym_link *retype = getSpec (operandType (result));
10696   sym_link *letype = getSpec (operandType (left));
10697   D (emitcode (";", "genFarPointerGet"););
10698
10699   aopOp (left, ic, FALSE, FALSE);
10700
10701   /* if the operand is already in dptr
10702      then we do nothing else we move the value to dptr */
10703   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10704     {
10705       /* if this is rematerializable */
10706       if (AOP_TYPE (left) == AOP_IMMD)
10707         {
10708           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10709         }
10710       else
10711         {
10712           /* we need to get it byte by byte */
10713           _startLazyDPSEvaluation ();
10714           if (AOP_TYPE (left) != AOP_DPTR)
10715             {
10716               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10717               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10718               if (options.model == MODEL_FLAT24)
10719                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10720             }
10721           else
10722             {
10723               /* We need to generate a load to DPTR indirect through DPTR. */
10724               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10725               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10726               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10727               if (options.model == MODEL_FLAT24)
10728                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10729               emitcode ("pop", "dph");
10730               emitcode ("pop", "dpl");
10731               dopi =0;
10732             }
10733           _endLazyDPSEvaluation ();
10734         }
10735     }
10736   /* so dptr now contains the address */
10737   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10738
10739   /* if bit then unpack */
10740   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10741       if (AOP_INDPTRn(left)) {
10742           genSetDPTR(AOP(left)->aopu.dptr);
10743       }
10744       genUnpackBits (result, "dptr", FPOINTER);
10745       if (AOP_INDPTRn(left)) {
10746           genSetDPTR(0);
10747       }
10748   } else
10749     {
10750       size = AOP_SIZE (result);
10751       offset = 0;
10752
10753       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10754           while (size--) {
10755               genSetDPTR(AOP(left)->aopu.dptr);
10756               emitcode ("movx", "a,@dptr");
10757               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10758                   emitcode ("inc", "dptr");
10759               genSetDPTR (0);
10760               aopPut (result, "a", offset++);
10761           }
10762       } else {
10763           _startLazyDPSEvaluation ();
10764           while (size--) {
10765               if (AOP_INDPTRn(left)) {
10766                   genSetDPTR(AOP(left)->aopu.dptr);
10767               } else {
10768                   genSetDPTR (0);
10769               }
10770               _flushLazyDPS ();
10771
10772               emitcode ("movx", "a,@dptr");
10773               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10774                   emitcode ("inc", "dptr");
10775
10776               aopPut (result, "a", offset++);
10777           }
10778           _endLazyDPSEvaluation ();
10779       }
10780     }
10781   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10782       if (!AOP_INDPTRn(left)) {
10783           _startLazyDPSEvaluation ();
10784           aopPut (left, "dpl", 0);
10785           aopPut (left, "dph", 1);
10786           if (options.model == MODEL_FLAT24)
10787               aopPut (left, "dpx", 2);
10788           _endLazyDPSEvaluation ();
10789       }
10790     pi->generated = 1;
10791   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10792              AOP_SIZE(result) > 1 &&
10793              IS_SYMOP(left) &&
10794              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10795
10796       size = AOP_SIZE (result) - 1;
10797       if (AOP_INDPTRn(left)) {
10798           genSetDPTR(AOP(left)->aopu.dptr);
10799       }
10800       while (size--) emitcode ("lcall","__decdptr");
10801       if (AOP_INDPTRn(left)) {
10802           genSetDPTR(0);
10803       }
10804   }
10805
10806   freeAsmop (result, NULL, ic, TRUE);
10807   freeAsmop (left, NULL, ic, TRUE);
10808 }
10809
10810 /*-----------------------------------------------------------------*/
10811 /* genCodePointerGet - get value from code space                   */
10812 /*-----------------------------------------------------------------*/
10813 static void
10814 genCodePointerGet (operand * left,
10815                     operand * result, iCode * ic, iCode *pi)
10816 {
10817   int size, offset, dopi=1;
10818   sym_link *retype = getSpec (operandType (result));
10819
10820   aopOp (left, ic, FALSE, FALSE);
10821
10822   /* if the operand is already in dptr
10823      then we do nothing else we move the value to dptr */
10824   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10825     {
10826       /* if this is rematerializable */
10827       if (AOP_TYPE (left) == AOP_IMMD)
10828         {
10829           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10830         }
10831       else
10832         {                       /* we need to get it byte by byte */
10833           _startLazyDPSEvaluation ();
10834           if (AOP_TYPE (left) != AOP_DPTR)
10835             {
10836               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10837               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10838               if (options.model == MODEL_FLAT24)
10839                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10840             }
10841           else
10842             {
10843               /* We need to generate a load to DPTR indirect through DPTR. */
10844               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10845               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10846               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10847               if (options.model == MODEL_FLAT24)
10848                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10849               emitcode ("pop", "dph");
10850               emitcode ("pop", "dpl");
10851               dopi=0;
10852             }
10853           _endLazyDPSEvaluation ();
10854         }
10855     }
10856   /* so dptr now contains the address */
10857   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10858
10859   /* if bit then unpack */
10860   if (IS_BITFIELD (retype)) {
10861       if (AOP_INDPTRn(left)) {
10862           genSetDPTR(AOP(left)->aopu.dptr);
10863       }
10864       genUnpackBits (result, "dptr", CPOINTER);
10865       if (AOP_INDPTRn(left)) {
10866           genSetDPTR(0);
10867       }
10868   } else
10869     {
10870       size = AOP_SIZE (result);
10871       offset = 0;
10872       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10873           while (size--) {
10874               genSetDPTR(AOP(left)->aopu.dptr);
10875               emitcode ("clr", "a");
10876               emitcode ("movc", "a,@a+dptr");
10877               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10878                   emitcode ("inc", "dptr");
10879               genSetDPTR (0);
10880               aopPut (result, "a", offset++);
10881           }
10882       } else {
10883           _startLazyDPSEvaluation ();
10884           while (size--)
10885               {
10886                   if (AOP_INDPTRn(left)) {
10887                       genSetDPTR(AOP(left)->aopu.dptr);
10888                   } else {
10889                       genSetDPTR (0);
10890                   }
10891                   _flushLazyDPS ();
10892
10893                   emitcode ("clr", "a");
10894                   emitcode ("movc", "a,@a+dptr");
10895                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10896                       emitcode ("inc", "dptr");
10897                   aopPut (result, "a", offset++);
10898               }
10899           _endLazyDPSEvaluation ();
10900       }
10901     }
10902   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10903       if (!AOP_INDPTRn(left)) {
10904           _startLazyDPSEvaluation ();
10905
10906           aopPut (left, "dpl", 0);
10907           aopPut (left, "dph", 1);
10908           if (options.model == MODEL_FLAT24)
10909               aopPut (left, "dpx", 2);
10910
10911           _endLazyDPSEvaluation ();
10912       }
10913       pi->generated = 1;
10914   } else if (IS_SYMOP(left) &&
10915              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10916              AOP_SIZE(result) > 1 &&
10917              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10918
10919       size = AOP_SIZE (result) - 1;
10920       if (AOP_INDPTRn(left)) {
10921           genSetDPTR(AOP(left)->aopu.dptr);
10922       }
10923       while (size--) emitcode ("lcall","__decdptr");
10924       if (AOP_INDPTRn(left)) {
10925           genSetDPTR(0);
10926       }
10927   }
10928
10929   freeAsmop (result, NULL, ic, TRUE);
10930   freeAsmop (left, NULL, ic, TRUE);
10931 }
10932
10933 /*-----------------------------------------------------------------*/
10934 /* genGenPointerGet - get value from generic pointer space         */
10935 /*-----------------------------------------------------------------*/
10936 static void
10937 genGenPointerGet (operand * left,
10938                   operand * result, iCode * ic, iCode * pi)
10939 {
10940   int size, offset;
10941   bool pushedB;
10942   sym_link *retype = getSpec (operandType (result));
10943   sym_link *letype = getSpec (operandType (left));
10944
10945   D (emitcode (";", "genGenPointerGet"));
10946
10947   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10948
10949   pushedB = pushB ();
10950   /* if the operand is already in dptr
10951      then we do nothing else we move the value to dptr */
10952   if (AOP_TYPE (left) != AOP_STR)
10953     {
10954       /* if this is rematerializable */
10955       if (AOP_TYPE (left) == AOP_IMMD)
10956         {
10957           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10958           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10959             {
10960               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10961             }
10962           else
10963             {
10964               emitcode ("mov", "b,#%d", pointerCode (retype));
10965             }
10966         }
10967       else
10968         {                       /* we need to get it byte by byte */
10969           _startLazyDPSEvaluation ();
10970           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10971           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10972           if (options.model == MODEL_FLAT24) {
10973               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10974               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10975           } else {
10976               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10977           }
10978           _endLazyDPSEvaluation ();
10979         }
10980     }
10981
10982   /* so dptr-b now contains the address */
10983   aopOp (result, ic, FALSE, TRUE);
10984
10985   /* if bit then unpack */
10986   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10987   {
10988     genUnpackBits (result, "dptr", GPOINTER);
10989   }
10990   else
10991     {
10992         size = AOP_SIZE (result);
10993         offset = 0;
10994
10995         while (size--)
10996         {
10997             if (size)
10998             {
10999                 // Get two bytes at a time, results in _AP & A.
11000                 // dptr will be incremented ONCE by __gptrgetWord.
11001                 //
11002                 // Note: any change here must be coordinated
11003                 // with the implementation of __gptrgetWord
11004                 // in device/lib/_gptrget.c
11005                 emitcode ("lcall", "__gptrgetWord");
11006                 aopPut (result, DP2_RESULT_REG, offset++);
11007                 aopPut (result, "a", offset++);
11008                 size--;
11009             }
11010             else
11011             {
11012                 // Only one byte to get.
11013                 emitcode ("lcall", "__gptrget");
11014                 aopPut (result, "a", offset++);
11015             }
11016
11017             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11018             {
11019                 emitcode ("inc", "dptr");
11020             }
11021         }
11022     }
11023
11024   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11025     _startLazyDPSEvaluation ();
11026
11027     aopPut (left, "dpl", 0);
11028     aopPut (left, "dph", 1);
11029     if (options.model == MODEL_FLAT24) {
11030         aopPut (left, "dpx", 2);
11031         aopPut (left, "b", 3);
11032     } else  aopPut (left, "b", 2);
11033
11034     _endLazyDPSEvaluation ();
11035
11036     pi->generated = 1;
11037   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11038              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11039
11040       size = AOP_SIZE (result) - 1;
11041       while (size--) emitcode ("lcall","__decdptr");
11042   }
11043   popB (pushedB);
11044
11045   freeAsmop (result, NULL, ic, TRUE);
11046   freeAsmop (left, NULL, ic, TRUE);
11047 }
11048
11049 /*-----------------------------------------------------------------*/
11050 /* genPointerGet - generate code for pointer get                   */
11051 /*-----------------------------------------------------------------*/
11052 static void
11053 genPointerGet (iCode * ic, iCode *pi)
11054 {
11055   operand *left, *result;
11056   sym_link *type, *etype;
11057   int p_type;
11058
11059   D (emitcode (";", "genPointerGet"));
11060
11061   left = IC_LEFT (ic);
11062   result = IC_RESULT (ic);
11063
11064   /* depending on the type of pointer we need to
11065      move it to the correct pointer register */
11066   type = operandType (left);
11067   etype = getSpec (type);
11068   /* if left is of type of pointer then it is simple */
11069   if (IS_PTR (type) && !IS_FUNC (type->next))
11070     p_type = DCL_TYPE (type);
11071   else
11072     {
11073       /* we have to go by the storage class */
11074       p_type = PTR_TYPE (SPEC_OCLS (etype));
11075     }
11076
11077   /* special case when cast remat */
11078   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11079       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11080     {
11081       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11082       type = operandType (left);
11083       p_type = DCL_TYPE (type);
11084     }
11085   /* now that we have the pointer type we assign
11086      the pointer values */
11087   switch (p_type)
11088     {
11089
11090     case POINTER:
11091     case IPOINTER:
11092       genNearPointerGet (left, result, ic, pi);
11093       break;
11094
11095     case PPOINTER:
11096       genPagedPointerGet (left, result, ic, pi);
11097       break;
11098
11099     case FPOINTER:
11100       genFarPointerGet (left, result, ic, pi);
11101       break;
11102
11103     case CPOINTER:
11104       genCodePointerGet (left, result, ic, pi);
11105       break;
11106
11107     case GPOINTER:
11108       genGenPointerGet (left, result, ic, pi);
11109       break;
11110     }
11111 }
11112
11113
11114 /*-----------------------------------------------------------------*/
11115 /* genPackBits - generates code for packed bit storage             */
11116 /*-----------------------------------------------------------------*/
11117 static void
11118 genPackBits (sym_link * etype,
11119              operand * right,
11120              char *rname, int p_type)
11121 {
11122   int offset = 0;       /* source byte offset */
11123   int rlen = 0;         /* remaining bitfield length */
11124   int blen;             /* bitfield length */
11125   int bstr;             /* bitfield starting bit within byte */
11126   int litval;           /* source literal value (if AOP_LIT) */
11127   unsigned char mask;   /* bitmask within current byte */
11128
11129   D(emitcode (";     genPackBits",""));
11130
11131   blen = SPEC_BLEN (etype);
11132   bstr = SPEC_BSTR (etype);
11133
11134   /* If the bitfield length is less than a byte */
11135   if (blen < 8)
11136     {
11137       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11138               (unsigned char) (0xFF >> (8 - bstr)));
11139
11140       if (AOP_TYPE (right) == AOP_LIT)
11141         {
11142           /* Case with a bitfield length <8 and literal source
11143           */
11144           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11145           litval <<= bstr;
11146           litval &= (~mask) & 0xff;
11147           emitPtrByteGet (rname, p_type, FALSE);
11148           if ((mask|litval)!=0xff)
11149             emitcode ("anl","a,#!constbyte", mask);
11150           if (litval)
11151             emitcode ("orl","a,#!constbyte", litval);
11152         }
11153       else
11154         {
11155           if ((blen==1) && (p_type!=GPOINTER))
11156             {
11157               /* Case with a bitfield length == 1 and no generic pointer
11158               */
11159               if (AOP_TYPE (right) == AOP_CRY)
11160                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11161               else
11162                 {
11163                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11164                   emitcode ("rrc","a");
11165                 }
11166               emitPtrByteGet (rname, p_type, FALSE);
11167               emitcode ("mov","acc.%d,c",bstr);
11168             }
11169           else
11170             {
11171               bool pushedB;
11172               /* Case with a bitfield length < 8 and arbitrary source
11173               */
11174               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11175               /* shift and mask source value */
11176               AccLsh (bstr);
11177               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11178
11179               pushedB = pushB ();
11180               /* transfer A to B and get next byte */
11181               emitPtrByteGet (rname, p_type, TRUE);
11182
11183               emitcode ("anl", "a,#!constbyte", mask);
11184               emitcode ("orl", "a,b");
11185               if (p_type == GPOINTER)
11186                 emitcode ("pop", "b");
11187
11188               popB (pushedB);
11189            }
11190         }
11191
11192       emitPtrByteSet (rname, p_type, "a");
11193       return;
11194     }
11195
11196   /* Bit length is greater than 7 bits. In this case, copy  */
11197   /* all except the partial byte at the end                 */
11198   for (rlen=blen;rlen>=8;rlen-=8)
11199     {
11200       emitPtrByteSet (rname, p_type,
11201                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11202       if (rlen>8)
11203         emitcode ("inc", "%s", rname);
11204     }
11205
11206   /* If there was a partial byte at the end */
11207   if (rlen)
11208     {
11209       mask = (((unsigned char) -1 << rlen) & 0xff);
11210
11211       if (AOP_TYPE (right) == AOP_LIT)
11212         {
11213           /* Case with partial byte and literal source
11214           */
11215           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
11216           litval >>= (blen-rlen);
11217           litval &= (~mask) & 0xff;
11218           emitPtrByteGet (rname, p_type, FALSE);
11219           if ((mask|litval)!=0xff)
11220             emitcode ("anl","a,#!constbyte", mask);
11221           if (litval)
11222             emitcode ("orl","a,#!constbyte", litval);
11223         }
11224       else
11225         {
11226           bool pushedB;
11227           /* Case with partial byte and arbitrary source
11228           */
11229           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11230           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11231
11232           pushedB = pushB ();
11233           /* transfer A to B and get next byte */
11234           emitPtrByteGet (rname, p_type, TRUE);
11235
11236           emitcode ("anl", "a,#!constbyte", mask);
11237           emitcode ("orl", "a,b");
11238           if (p_type == GPOINTER)
11239             emitcode ("pop", "b");
11240
11241           popB (pushedB);
11242         }
11243       emitPtrByteSet (rname, p_type, "a");
11244     }
11245 }
11246
11247
11248 /*-----------------------------------------------------------------*/
11249 /* genDataPointerSet - remat pointer to data space                 */
11250 /*-----------------------------------------------------------------*/
11251 static void
11252 genDataPointerSet (operand * right,
11253                    operand * result,
11254                    iCode * ic)
11255 {
11256   int size, offset = 0;
11257   char *l, buffer[256];
11258
11259   D (emitcode (";", "genDataPointerSet"));
11260
11261   aopOp (right, ic, FALSE, FALSE);
11262
11263   l = aopGet (result, 0, FALSE, TRUE, NULL);
11264   size = AOP_SIZE (right);
11265   while (size--)
11266     {
11267       if (offset)
11268           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11269       else
11270           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11271       emitcode ("mov", "%s,%s", buffer,
11272                 aopGet (right, offset++, FALSE, FALSE, NULL));
11273     }
11274
11275   freeAsmop (result, NULL, ic, TRUE);
11276   freeAsmop (right, NULL, ic, TRUE);
11277 }
11278
11279 /*-----------------------------------------------------------------*/
11280 /* genNearPointerSet - emitcode for near pointer put                */
11281 /*-----------------------------------------------------------------*/
11282 static void
11283 genNearPointerSet (operand * right,
11284                    operand * result,
11285                    iCode * ic,
11286                    iCode * pi)
11287 {
11288   asmop *aop = NULL;
11289   char *rname, *l;
11290   sym_link *retype, *letype;
11291   sym_link *ptype = operandType (result);
11292
11293   D (emitcode (";", "genNearPointerSet"));
11294
11295   retype = getSpec (operandType (right));
11296   letype = getSpec (ptype);
11297
11298   aopOp (result, ic, FALSE, FALSE);
11299
11300   /* if the result is rematerializable &
11301      in data space & not a bit variable */
11302   if (AOP_TYPE (result) == AOP_IMMD &&
11303       DCL_TYPE (ptype) == POINTER &&
11304       !IS_BITVAR (retype) &&
11305       !IS_BITVAR (letype))
11306     {
11307       genDataPointerSet (right, result, ic);
11308       return;
11309     }
11310
11311   /* if the value is already in a pointer register
11312      then don't need anything more */
11313   if (!AOP_INPREG (AOP (result)))
11314     {
11315       /* otherwise get a free pointer register */
11316       regs *preg;
11317
11318       aop = newAsmop (0);
11319       preg = getFreePtr (ic, &aop, FALSE);
11320       emitcode ("mov", "%s,%s",
11321                 preg->name,
11322                 aopGet (result, 0, FALSE, TRUE, NULL));
11323       rname = preg->name;
11324     }
11325   else
11326     {
11327       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11328     }
11329
11330   aopOp (right, ic, FALSE, FALSE);
11331
11332   /* if bitfield then unpack the bits */
11333   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11334     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11335   else
11336     {
11337       /* we can just get the values */
11338       int size = AOP_SIZE (right);
11339       int offset = 0;
11340
11341       while (size--)
11342         {
11343           l = aopGet (right, offset, FALSE, TRUE, NULL);
11344           if ((*l == '@') || (strcmp (l, "acc") == 0))
11345             {
11346               MOVA (l);
11347               emitcode ("mov", "@%s,a", rname);
11348             }
11349           else
11350             emitcode ("mov", "@%s,%s", rname, l);
11351           if (size || pi)
11352             emitcode ("inc", "%s", rname);
11353           offset++;
11354         }
11355     }
11356
11357   /* now some housekeeping stuff */
11358   if (aop)      /* we had to allocate for this iCode */
11359     {
11360       if (pi)
11361         aopPut (result, rname, 0);
11362       freeAsmop (NULL, aop, ic, TRUE);
11363     }
11364   else
11365     {
11366       /* we did not allocate which means left
11367          already in a pointer register, then
11368          if size > 0 && this could be used again
11369          we have to point it back to where it
11370          belongs */
11371       if (AOP_SIZE (right) > 1 &&
11372           !OP_SYMBOL (result)->remat &&
11373           (OP_SYMBOL (result)->liveTo > ic->seq ||
11374            ic->depth) &&
11375           !pi)
11376         {
11377           int size = AOP_SIZE (right) - 1;
11378           while (size--)
11379             emitcode ("dec", "%s", rname);
11380         }
11381     }
11382
11383   /* done */
11384   if (pi) pi->generated = 1;
11385   freeAsmop (result, NULL, ic, TRUE);
11386   freeAsmop (right, NULL, ic, TRUE);
11387 }
11388
11389 /*-----------------------------------------------------------------*/
11390 /* genPagedPointerSet - emitcode for Paged pointer put             */
11391 /*-----------------------------------------------------------------*/
11392 static void
11393 genPagedPointerSet (operand * right,
11394                     operand * result,
11395                     iCode * ic,
11396                     iCode *pi)
11397 {
11398   asmop *aop = NULL;
11399   char *rname, *l;
11400   sym_link *retype, *letype;
11401
11402   D (emitcode (";", "genPagedPointerSet"));
11403
11404   retype = getSpec (operandType (right));
11405   letype = getSpec (operandType (result));
11406
11407   aopOp (result, ic, FALSE, FALSE);
11408
11409   /* if the value is already in a pointer register
11410      then don't need anything more */
11411   if (!AOP_INPREG (AOP (result)))
11412     {
11413       /* otherwise get a free pointer register */
11414       regs *preg;
11415
11416       aop = newAsmop (0);
11417       preg = getFreePtr (ic, &aop, FALSE);
11418       emitcode ("mov", "%s,%s",
11419                 preg->name,
11420                 aopGet (result, 0, FALSE, TRUE, NULL));
11421       rname = preg->name;
11422     }
11423   else
11424     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11425
11426   aopOp (right, ic, FALSE, FALSE);
11427
11428   /* if bitfield then unpack the bits */
11429   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11430     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11431   else
11432     {
11433       /* we have can just get the values */
11434       int size = AOP_SIZE (right);
11435       int offset = 0;
11436
11437       while (size--)
11438         {
11439           l = aopGet (right, offset, FALSE, TRUE, NULL);
11440           MOVA (l);
11441           emitcode ("movx", "@%s,a", rname);
11442
11443           if (size || pi)
11444             emitcode ("inc", "%s", rname);
11445
11446           offset++;
11447         }
11448     }
11449
11450   /* now some housekeeping stuff */
11451   if (aop)
11452     {
11453       if (pi)
11454         aopPut (result, rname, 0);
11455       /* we had to allocate for this iCode */
11456       freeAsmop (NULL, aop, ic, TRUE);
11457     }
11458   else
11459     {
11460       /* we did not allocate which means left
11461          already in a pointer register, then
11462          if size > 0 && this could be used again
11463          we have to point it back to where it
11464          belongs */
11465       if (AOP_SIZE (right) > 1 &&
11466           !OP_SYMBOL (result)->remat &&
11467           (OP_SYMBOL (result)->liveTo > ic->seq ||
11468            ic->depth) &&
11469           !pi)
11470         {
11471           int size = AOP_SIZE (right) - 1;
11472           while (size--)
11473             emitcode ("dec", "%s", rname);
11474         }
11475     }
11476
11477   /* done */
11478   if (pi) pi->generated = 1;
11479   freeAsmop (result, NULL, ic, TRUE);
11480   freeAsmop (right, NULL, ic, TRUE);
11481 }
11482
11483 /*-----------------------------------------------------------------*/
11484 /* genFarPointerSet - set value from far space                     */
11485 /*-----------------------------------------------------------------*/
11486 static void
11487 genFarPointerSet (operand * right,
11488                   operand * result, iCode * ic, iCode *pi)
11489 {
11490   int size, offset, dopi=1;
11491   sym_link *retype = getSpec (operandType (right));
11492   sym_link *letype = getSpec (operandType (result));
11493
11494   aopOp (result, ic, FALSE, FALSE);
11495
11496   /* if the operand is already in dptr
11497      then we do nothing else we move the value to dptr */
11498   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11499     {
11500       /* if this is remateriazable */
11501       if (AOP_TYPE (result) == AOP_IMMD)
11502         emitcode ("mov", "dptr,%s",
11503                   aopGet (result, 0, TRUE, FALSE, NULL));
11504       else
11505         {
11506           /* we need to get it byte by byte */
11507           _startLazyDPSEvaluation ();
11508           if (AOP_TYPE (result) != AOP_DPTR)
11509             {
11510               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11511               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11512               if (options.model == MODEL_FLAT24)
11513                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11514             }
11515           else
11516             {
11517               /* We need to generate a load to DPTR indirect through DPTR. */
11518               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11519
11520               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11521               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11522               if (options.model == MODEL_FLAT24)
11523                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11524               emitcode ("pop", "dph");
11525               emitcode ("pop", "dpl");
11526               dopi=0;
11527             }
11528           _endLazyDPSEvaluation ();
11529         }
11530     }
11531   /* so dptr now contains the address */
11532   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11533
11534   /* if bit then unpack */
11535   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11536   {
11537       if (AOP_INDPTRn(result)) {
11538           genSetDPTR(AOP(result)->aopu.dptr);
11539       }
11540       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11541       if (AOP_INDPTRn(result)) {
11542           genSetDPTR(0);
11543       }
11544   } else {
11545       size = AOP_SIZE (right);
11546       offset = 0;
11547       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11548           while (size--) {
11549               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11550
11551               genSetDPTR(AOP(result)->aopu.dptr);
11552               emitcode ("movx", "@dptr,a");
11553               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11554                   emitcode ("inc", "dptr");
11555               genSetDPTR (0);
11556           }
11557       } else {
11558           _startLazyDPSEvaluation ();
11559           while (size--) {
11560               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11561
11562               if (AOP_INDPTRn(result)) {
11563                   genSetDPTR(AOP(result)->aopu.dptr);
11564               } else {
11565                   genSetDPTR (0);
11566               }
11567               _flushLazyDPS ();
11568
11569               emitcode ("movx", "@dptr,a");
11570               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11571                   emitcode ("inc", "dptr");
11572           }
11573           _endLazyDPSEvaluation ();
11574       }
11575   }
11576
11577   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11578       if (!AOP_INDPTRn(result)) {
11579           _startLazyDPSEvaluation ();
11580
11581           aopPut (result,"dpl",0);
11582           aopPut (result,"dph",1);
11583           if (options.model == MODEL_FLAT24)
11584               aopPut (result,"dpx",2);
11585
11586           _endLazyDPSEvaluation ();
11587       }
11588       pi->generated=1;
11589   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11590              AOP_SIZE(right) > 1 &&
11591              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11592
11593       size = AOP_SIZE (right) - 1;
11594       if (AOP_INDPTRn(result)) {
11595           genSetDPTR(AOP(result)->aopu.dptr);
11596       }
11597       while (size--) emitcode ("lcall","__decdptr");
11598       if (AOP_INDPTRn(result)) {
11599           genSetDPTR(0);
11600       }
11601   }
11602   freeAsmop (result, NULL, ic, TRUE);
11603   freeAsmop (right, NULL, ic, TRUE);
11604 }
11605
11606 /*-----------------------------------------------------------------*/
11607 /* genGenPointerSet - set value from generic pointer space         */
11608 /*-----------------------------------------------------------------*/
11609 static void
11610 genGenPointerSet (operand * right,
11611                   operand * result, iCode * ic, iCode *pi)
11612 {
11613   int size, offset;
11614   bool pushedB;
11615   sym_link *retype = getSpec (operandType (right));
11616   sym_link *letype = getSpec (operandType (result));
11617
11618   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11619
11620   pushedB = pushB ();
11621   /* if the operand is already in dptr
11622      then we do nothing else we move the value to dptr */
11623   if (AOP_TYPE (result) != AOP_STR)
11624     {
11625       _startLazyDPSEvaluation ();
11626       /* if this is remateriazable */
11627       if (AOP_TYPE (result) == AOP_IMMD)
11628         {
11629           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11630           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11631           {
11632               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11633           }
11634           else
11635           {
11636               emitcode ("mov",
11637                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11638           }
11639         }
11640       else
11641         {                       /* we need to get it byte by byte */
11642           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11643           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11644           if (options.model == MODEL_FLAT24) {
11645             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11646             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11647           } else {
11648             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11649           }
11650         }
11651       _endLazyDPSEvaluation ();
11652     }
11653   /* so dptr + b now contains the address */
11654   aopOp (right, ic, FALSE, TRUE);
11655
11656   /* if bit then unpack */
11657   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11658     {
11659         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11660     }
11661   else
11662     {
11663         size = AOP_SIZE (right);
11664         offset = 0;
11665
11666         _startLazyDPSEvaluation ();
11667         while (size--)
11668         {
11669             if (size)
11670             {
11671                 // Set two bytes at a time, passed in _AP & A.
11672                 // dptr will be incremented ONCE by __gptrputWord.
11673                 //
11674                 // Note: any change here must be coordinated
11675                 // with the implementation of __gptrputWord
11676                 // in device/lib/_gptrput.c
11677                 emitcode("mov", "_ap, %s",
11678                          aopGet (right, offset++, FALSE, FALSE, NULL));
11679                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11680
11681                 genSetDPTR (0);
11682                 _flushLazyDPS ();
11683                 emitcode ("lcall", "__gptrputWord");
11684                 size--;
11685             }
11686             else
11687             {
11688                 // Only one byte to put.
11689                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11690
11691                 genSetDPTR (0);
11692                 _flushLazyDPS ();
11693                 emitcode ("lcall", "__gptrput");
11694             }
11695
11696             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11697             {
11698                 emitcode ("inc", "dptr");
11699             }
11700         }
11701         _endLazyDPSEvaluation ();
11702     }
11703
11704   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11705       _startLazyDPSEvaluation ();
11706
11707       aopPut (result, "dpl",0);
11708       aopPut (result, "dph",1);
11709       if (options.model == MODEL_FLAT24) {
11710           aopPut (result, "dpx",2);
11711           aopPut (result, "b",3);
11712       } else {
11713           aopPut (result, "b",2);
11714       }
11715       _endLazyDPSEvaluation ();
11716
11717       pi->generated=1;
11718   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11719              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11720
11721       size = AOP_SIZE (right) - 1;
11722       while (size--) emitcode ("lcall","__decdptr");
11723   }
11724   popB (pushedB);
11725
11726   freeAsmop (result, NULL, ic, TRUE);
11727   freeAsmop (right, NULL, ic, TRUE);
11728 }
11729
11730 /*-----------------------------------------------------------------*/
11731 /* genPointerSet - stores the value into a pointer location        */
11732 /*-----------------------------------------------------------------*/
11733 static void
11734 genPointerSet (iCode * ic, iCode *pi)
11735 {
11736   operand *right, *result;
11737   sym_link *type, *etype;
11738   int p_type;
11739
11740   D (emitcode (";", "genPointerSet"));
11741
11742   right = IC_RIGHT (ic);
11743   result = IC_RESULT (ic);
11744
11745   /* depending on the type of pointer we need to
11746      move it to the correct pointer register */
11747   type = operandType (result);
11748   etype = getSpec (type);
11749   /* if left is of type of pointer then it is simple */
11750   if (IS_PTR (type) && !IS_FUNC (type->next))
11751     {
11752       p_type = DCL_TYPE (type);
11753     }
11754   else
11755     {
11756       /* we have to go by the storage class */
11757       p_type = PTR_TYPE (SPEC_OCLS (etype));
11758     }
11759
11760   /* special case when cast remat */
11761   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11762       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11763           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11764           type = operandType (result);
11765           p_type = DCL_TYPE (type);
11766   }
11767
11768   /* now that we have the pointer type we assign
11769      the pointer values */
11770   switch (p_type)
11771     {
11772
11773     case POINTER:
11774     case IPOINTER:
11775       genNearPointerSet (right, result, ic, pi);
11776       break;
11777
11778     case PPOINTER:
11779       genPagedPointerSet (right, result, ic, pi);
11780       break;
11781
11782     case FPOINTER:
11783       genFarPointerSet (right, result, ic, pi);
11784       break;
11785
11786     case GPOINTER:
11787       genGenPointerSet (right, result, ic, pi);
11788       break;
11789
11790     default:
11791       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11792               "genPointerSet: illegal pointer type");
11793     }
11794 }
11795
11796 /*-----------------------------------------------------------------*/
11797 /* genIfx - generate code for Ifx statement                        */
11798 /*-----------------------------------------------------------------*/
11799 static void
11800 genIfx (iCode * ic, iCode * popIc)
11801 {
11802   operand *cond = IC_COND (ic);
11803   int isbit = 0;
11804   char *dup = NULL;
11805
11806   D (emitcode (";", "genIfx"));
11807
11808   aopOp (cond, ic, FALSE, FALSE);
11809
11810   /* get the value into acc */
11811   if (AOP_TYPE (cond) != AOP_CRY)
11812     {
11813       toBoolean (cond);
11814     }
11815   else
11816     {
11817       isbit = 1;
11818       if (AOP(cond)->aopu.aop_dir)
11819         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11820     }
11821
11822   /* the result is now in the accumulator or a directly addressable bit */
11823   freeAsmop (cond, NULL, ic, TRUE);
11824
11825   /* if there was something to be popped then do it */
11826   if (popIc)
11827     genIpop (popIc);
11828
11829   /* if the condition is a bit variable */
11830   if (isbit && dup)
11831     genIfxJump (ic, dup);
11832   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11833     genIfxJump (ic, SPIL_LOC (cond)->rname);
11834   else if (isbit && !IS_ITEMP (cond))
11835     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11836   else
11837     genIfxJump (ic, "a");
11838
11839   ic->generated = 1;
11840 }
11841
11842 /*-----------------------------------------------------------------*/
11843 /* genAddrOf - generates code for address of                       */
11844 /*-----------------------------------------------------------------*/
11845 static void
11846 genAddrOf (iCode * ic)
11847 {
11848   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11849   int size, offset;
11850
11851   D (emitcode (";", "genAddrOf"));
11852
11853   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11854
11855   /* if the operand is on the stack then we
11856      need to get the stack offset of this
11857      variable */
11858   if (sym->onStack)
11859   {
11860
11861       /* if 10 bit stack */
11862       if (options.stack10bit) {
11863           char buff[10];
11864           int  offset;
11865
11866           tsprintf(buff, sizeof(buff),
11867                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11868           /* if it has an offset then we need to compute it */
11869 /*        emitcode ("subb", "a,#!constbyte", */
11870 /*                  -((sym->stack < 0) ? */
11871 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11872 /*                    ((short) sym->stack)) & 0xff); */
11873 /*        emitcode ("mov","b,a"); */
11874 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11875 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11876 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11877           if (sym->stack) {
11878               emitcode ("mov", "a,_bpx");
11879               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11880                                              ((char) (sym->stack - _G.nRegsSaved)) :
11881                                              ((char) sym->stack )) & 0xff);
11882               emitcode ("mov", "b,a");
11883               emitcode ("mov", "a,_bpx+1");
11884
11885               offset = (((sym->stack < 0) ?
11886                          ((short) (sym->stack - _G.nRegsSaved)) :
11887                          ((short) sym->stack )) >> 8) & 0xff;
11888
11889               emitcode ("addc","a,#!constbyte", offset);
11890
11891               aopPut (IC_RESULT (ic), "b", 0);
11892               aopPut (IC_RESULT (ic), "a", 1);
11893               aopPut (IC_RESULT (ic), buff, 2);
11894           } else {
11895               /* we can just move _bp */
11896               aopPut (IC_RESULT (ic), "_bpx", 0);
11897               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11898               aopPut (IC_RESULT (ic), buff, 2);
11899           }
11900       } else {
11901           /* if it has an offset then we need to compute it */
11902           if (sym->stack)
11903             {
11904               emitcode ("mov", "a,_bp");
11905               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11906               aopPut (IC_RESULT (ic), "a", 0);
11907             }
11908           else
11909             {
11910               /* we can just move _bp */
11911               aopPut (IC_RESULT (ic), "_bp", 0);
11912             }
11913           /* fill the result with zero */
11914           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11915
11916
11917           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11918               fprintf (stderr,
11919                        "*** warning: pointer to stack var truncated.\n");
11920           }
11921
11922           offset = 1;
11923           while (size--)
11924             {
11925               aopPut (IC_RESULT (ic), zero, offset++);
11926             }
11927       }
11928       goto release;
11929   }
11930
11931   /* object not on stack then we need the name */
11932   size = AOP_SIZE (IC_RESULT (ic));
11933   offset = 0;
11934
11935   while (size--)
11936     {
11937       char s[SDCC_NAME_MAX];
11938       if (offset) {
11939           switch (offset) {
11940           case 1:
11941               tsprintf(s, sizeof(s), "#!his",sym->rname);
11942               break;
11943           case 2:
11944               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11945               break;
11946           case 3:
11947               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11948               break;
11949           default: /* should not need this (just in case) */
11950               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11951                        sym->rname,
11952                        offset * 8);
11953           }
11954       }
11955       else
11956       {
11957           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11958       }
11959
11960       aopPut (IC_RESULT (ic), s, offset++);
11961     }
11962
11963 release:
11964   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11965
11966 }
11967
11968 #if 0 // obsolete, and buggy for != xdata
11969 /*-----------------------------------------------------------------*/
11970 /* genArrayInit - generates code for address of                       */
11971 /*-----------------------------------------------------------------*/
11972 static void
11973 genArrayInit (iCode * ic)
11974 {
11975     literalList *iLoop;
11976     int         ix, count;
11977     int         elementSize = 0, eIndex;
11978     unsigned    val, lastVal;
11979     sym_link    *type;
11980     operand     *left=IC_LEFT(ic);
11981
11982     D (emitcode (";", "genArrayInit"));
11983
11984     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11985
11986     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11987     {
11988         // Load immediate value into DPTR.
11989         emitcode("mov", "dptr, %s",
11990              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11991     }
11992     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11993     {
11994 #if 0
11995       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11996               "Unexpected operand to genArrayInit.\n");
11997       exit(1);
11998 #else
11999       // a regression because of SDCCcse.c:1.52
12000       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
12001       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
12002       if (options.model == MODEL_FLAT24)
12003         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
12004 #endif
12005     }
12006
12007     type = operandType(IC_LEFT(ic));
12008
12009     if (type && type->next)
12010     {
12011         elementSize = getSize(type->next);
12012     }
12013     else
12014     {
12015         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12016                                 "can't determine element size in genArrayInit.\n");
12017         exit(1);
12018     }
12019
12020     iLoop = IC_ARRAYILIST(ic);
12021     lastVal = 0xffff;
12022
12023     while (iLoop)
12024     {
12025         bool firstpass = TRUE;
12026
12027         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12028                  iLoop->count, (int)iLoop->literalValue, elementSize);
12029
12030         ix = iLoop->count;
12031
12032         while (ix)
12033         {
12034             symbol *tlbl = NULL;
12035
12036             count = ix > 256 ? 256 : ix;
12037
12038             if (count > 1)
12039             {
12040                 tlbl = newiTempLabel (NULL);
12041                 if (firstpass || (count & 0xff))
12042                 {
12043                     emitcode("mov", "b, #!constbyte", count & 0xff);
12044                 }
12045
12046                 emitLabel (tlbl);
12047             }
12048
12049             firstpass = FALSE;
12050
12051             for (eIndex = 0; eIndex < elementSize; eIndex++)
12052             {
12053                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12054                 if (val != lastVal)
12055                 {
12056                     emitcode("mov", "a, #!constbyte", val);
12057                     lastVal = val;
12058                 }
12059
12060                 emitcode("movx", "@dptr, a");
12061                 emitcode("inc", "dptr");
12062             }
12063
12064             if (count > 1)
12065             {
12066                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12067             }
12068
12069             ix -= count;
12070         }
12071
12072         iLoop = iLoop->next;
12073     }
12074
12075     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12076 }
12077 #endif
12078
12079 /*-----------------------------------------------------------------*/
12080 /* genFarFarAssign - assignment when both are in far space         */
12081 /*-----------------------------------------------------------------*/
12082 static void
12083 genFarFarAssign (operand * result, operand * right, iCode * ic)
12084 {
12085   int size = AOP_SIZE (right);
12086   int offset = 0;
12087   symbol *rSym = NULL;
12088
12089   if (size == 1)
12090   {
12091       /* quick & easy case. */
12092       D (emitcode(";","genFarFarAssign (1 byte case)"));
12093       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12094       freeAsmop (right, NULL, ic, FALSE);
12095       /* now assign DPTR to result */
12096       _G.accInUse++;
12097       aopOp(result, ic, FALSE, FALSE);
12098       _G.accInUse--;
12099       aopPut (result, "a", 0);
12100       freeAsmop(result, NULL, ic, FALSE);
12101       return;
12102   }
12103
12104   /* See if we've got an underlying symbol to abuse. */
12105   if (IS_SYMOP(result) && OP_SYMBOL(result))
12106   {
12107       if (IS_TRUE_SYMOP(result))
12108       {
12109           rSym = OP_SYMBOL(result);
12110       }
12111       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12112       {
12113           rSym = OP_SYMBOL(result)->usl.spillLoc;
12114       }
12115   }
12116
12117   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12118   {
12119       /* We can use the '390 auto-toggle feature to good effect here. */
12120
12121       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12122       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12123       emitcode ("mov", "dptr,#%s", rSym->rname);
12124       /* DP2 = result, DP1 = right, DP1 is current. */
12125       while (size)
12126       {
12127           emitcode("movx", "a,@dptr");
12128           emitcode("movx", "@dptr,a");
12129           if (--size)
12130           {
12131                emitcode("inc", "dptr");
12132                emitcode("inc", "dptr");
12133           }
12134       }
12135       emitcode("mov", "dps,#0");
12136       freeAsmop (right, NULL, ic, FALSE);
12137 #if 0
12138 some alternative code for processors without auto-toggle
12139 no time to test now, so later well put in...kpb
12140         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12141         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12142         emitcode ("mov", "dptr,#%s", rSym->rname);
12143         /* DP2 = result, DP1 = right, DP1 is current. */
12144         while (size)
12145         {
12146           --size;
12147           emitcode("movx", "a,@dptr");
12148           if (size)
12149             emitcode("inc", "dptr");
12150           emitcode("inc", "dps");
12151           emitcode("movx", "@dptr,a");
12152           if (size)
12153             emitcode("inc", "dptr");
12154           emitcode("inc", "dps");
12155         }
12156         emitcode("mov", "dps,#0");
12157         freeAsmop (right, NULL, ic, FALSE);
12158 #endif
12159   }
12160   else
12161   {
12162       D (emitcode (";", "genFarFarAssign"));
12163       aopOp (result, ic, TRUE, TRUE);
12164
12165       _startLazyDPSEvaluation ();
12166
12167       while (size--)
12168         {
12169           aopPut (result,
12170                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12171           offset++;
12172         }
12173       _endLazyDPSEvaluation ();
12174       freeAsmop (result, NULL, ic, FALSE);
12175       freeAsmop (right, NULL, ic, FALSE);
12176   }
12177 }
12178
12179 /*-----------------------------------------------------------------*/
12180 /* genAssign - generate code for assignment                        */
12181 /*-----------------------------------------------------------------*/
12182 static void
12183 genAssign (iCode * ic)
12184 {
12185   operand *result, *right;
12186   int size, offset;
12187   unsigned long lit = 0L;
12188
12189   D (emitcode (";", "genAssign"));
12190
12191   result = IC_RESULT (ic);
12192   right = IC_RIGHT (ic);
12193
12194   /* if they are the same */
12195   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12196     return;
12197
12198   aopOp (right, ic, FALSE, FALSE);
12199
12200   emitcode (";", "genAssign: resultIsFar = %s",
12201             isOperandInFarSpace (result) ?
12202             "TRUE" : "FALSE");
12203
12204   /* special case both in far space */
12205   if ((AOP_TYPE (right) == AOP_DPTR ||
12206        AOP_TYPE (right) == AOP_DPTR2) &&
12207   /* IS_TRUE_SYMOP(result)       && */
12208       isOperandInFarSpace (result))
12209     {
12210       genFarFarAssign (result, right, ic);
12211       return;
12212     }
12213
12214   aopOp (result, ic, TRUE, FALSE);
12215
12216   /* if they are the same registers */
12217   if (sameRegs (AOP (right), AOP (result)))
12218     goto release;
12219
12220   /* if the result is a bit */
12221   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12222     {
12223       /* if the right size is a literal then
12224          we know what the value is */
12225       if (AOP_TYPE (right) == AOP_LIT)
12226         {
12227           if (((int) operandLitValue (right)))
12228             aopPut (result, one, 0);
12229           else
12230             aopPut (result, zero, 0);
12231           goto release;
12232         }
12233
12234       /* the right is also a bit variable */
12235       if (AOP_TYPE (right) == AOP_CRY)
12236         {
12237           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12238           aopPut (result, "c", 0);
12239           goto release;
12240         }
12241
12242       /* we need to or */
12243       toBoolean (right);
12244       aopPut (result, "a", 0);
12245       goto release;
12246     }
12247
12248   /* bit variables done */
12249   /* general case */
12250   size = AOP_SIZE (result);
12251   offset = 0;
12252   if (AOP_TYPE (right) == AOP_LIT)
12253     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
12254
12255   if ((size > 1) &&
12256       (AOP_TYPE (result) != AOP_REG) &&
12257       (AOP_TYPE (right) == AOP_LIT) &&
12258       !IS_FLOAT (operandType (right)))
12259     {
12260       _startLazyDPSEvaluation ();
12261       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12262         {
12263           aopPut (result,
12264                   aopGet (right, offset, FALSE, FALSE, NULL),
12265                   offset);
12266           offset++;
12267           size--;
12268         }
12269       /* And now fill the rest with zeros. */
12270       if (size)
12271         {
12272           emitcode ("clr", "a");
12273         }
12274       while (size--)
12275         {
12276           aopPut (result, "a", offset++);
12277         }
12278       _endLazyDPSEvaluation ();
12279     }
12280   else
12281     {
12282       _startLazyDPSEvaluation ();
12283       while (size--)
12284         {
12285           aopPut (result,
12286                   aopGet (right, offset, FALSE, FALSE, NULL),
12287                   offset);
12288           offset++;
12289         }
12290       _endLazyDPSEvaluation ();
12291     }
12292
12293 release:
12294   freeAsmop (result, NULL, ic, TRUE);
12295   freeAsmop (right, NULL, ic, TRUE);
12296 }
12297
12298 /*-----------------------------------------------------------------*/
12299 /* genJumpTab - generates code for jump table                      */
12300 /*-----------------------------------------------------------------*/
12301 static void
12302 genJumpTab (iCode * ic)
12303 {
12304   symbol *jtab;
12305   char *l;
12306
12307   D (emitcode (";", "genJumpTab"));
12308
12309   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12310   /* get the condition into accumulator */
12311   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12312   MOVA (l);
12313   /* multiply by four! */
12314   emitcode ("add", "a,acc");
12315   emitcode ("add", "a,acc");
12316   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12317
12318   jtab = newiTempLabel (NULL);
12319   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12320   emitcode ("jmp", "@a+dptr");
12321   emitLabel (jtab);
12322   /* now generate the jump labels */
12323   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12324        jtab = setNextItem (IC_JTLABELS (ic)))
12325     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12326
12327 }
12328
12329 /*-----------------------------------------------------------------*/
12330 /* genCast - gen code for casting                                  */
12331 /*-----------------------------------------------------------------*/
12332 static void
12333 genCast (iCode * ic)
12334 {
12335   operand *result = IC_RESULT (ic);
12336   sym_link *ctype = operandType (IC_LEFT (ic));
12337   sym_link *rtype = operandType (IC_RIGHT (ic));
12338   operand *right = IC_RIGHT (ic);
12339   int size, offset;
12340
12341   D (emitcode (";", "genCast"));
12342
12343   /* if they are equivalent then do nothing */
12344   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12345     return;
12346
12347   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12348   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12349
12350   /* if the result is a bit (and not a bitfield) */
12351   if (IS_BIT (OP_SYMBOL (result)->type))
12352     {
12353       /* if the right size is a literal then
12354          we know what the value is */
12355       if (AOP_TYPE (right) == AOP_LIT)
12356         {
12357           if (((int) operandLitValue (right)))
12358             aopPut (result, one, 0);
12359           else
12360             aopPut (result, zero, 0);
12361
12362           goto release;
12363         }
12364
12365       /* the right is also a bit variable */
12366       if (AOP_TYPE (right) == AOP_CRY)
12367         {
12368           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12369           aopPut (result, "c", 0);
12370           goto release;
12371         }
12372
12373       /* we need to or */
12374       toBoolean (right);
12375       aopPut (result, "a", 0);
12376       goto release;
12377     }
12378
12379   /* if they are the same size : or less */
12380   if (AOP_SIZE (result) <= AOP_SIZE (right))
12381     {
12382
12383       /* if they are in the same place */
12384       if (sameRegs (AOP (right), AOP (result)))
12385         goto release;
12386
12387       /* if they in different places then copy */
12388       size = AOP_SIZE (result);
12389       offset = 0;
12390       _startLazyDPSEvaluation ();
12391       while (size--)
12392         {
12393           aopPut (result,
12394                   aopGet (right, offset, FALSE, FALSE, NULL),
12395                   offset);
12396           offset++;
12397         }
12398       _endLazyDPSEvaluation ();
12399       goto release;
12400     }
12401
12402   /* if the result is of type pointer */
12403   if (IS_PTR (ctype))
12404     {
12405
12406       int p_type;
12407       sym_link *type = operandType (right);
12408
12409       /* pointer to generic pointer */
12410       if (IS_GENPTR (ctype))
12411         {
12412           if (IS_PTR (type))
12413             {
12414               p_type = DCL_TYPE (type);
12415             }
12416           else
12417             {
12418 #if OLD_CAST_BEHAVIOR
12419               /* KV: we are converting a non-pointer type to
12420                * a generic pointer. This (ifdef'd out) code
12421                * says that the resulting generic pointer
12422                * should have the same class as the storage
12423                * location of the non-pointer variable.
12424                *
12425                * For example, converting an int (which happens
12426                * to be stored in DATA space) to a pointer results
12427                * in a DATA generic pointer; if the original int
12428                * in XDATA space, so will be the resulting pointer.
12429                *
12430                * I don't like that behavior, and thus this change:
12431                * all such conversions will be forced to XDATA and
12432                * throw a warning. If you want some non-XDATA
12433                * type, or you want to suppress the warning, you
12434                * must go through an intermediate cast, like so:
12435                *
12436                * char _generic *gp = (char _xdata *)(intVar);
12437                */
12438               sym_link *etype = getSpec (type);
12439
12440               /* we have to go by the storage class */
12441               if (SPEC_OCLS (etype) != generic)
12442                 {
12443                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12444                 }
12445               else
12446 #endif
12447                 {
12448                   /* Converting unknown class (i.e. register variable)
12449                    * to generic pointer. This is not good, but
12450                    * we'll make a guess (and throw a warning).
12451                    */
12452                   p_type = FPOINTER;
12453                   werror (W_INT_TO_GEN_PTR_CAST);
12454                 }
12455             }
12456
12457           /* the first two bytes are known */
12458           size = GPTRSIZE - 1;
12459           offset = 0;
12460           _startLazyDPSEvaluation ();
12461           while (size--)
12462             {
12463               aopPut (result,
12464                       aopGet (right, offset, FALSE, FALSE, NULL),
12465                       offset);
12466               offset++;
12467             }
12468           _endLazyDPSEvaluation ();
12469
12470           /* the last byte depending on type */
12471             {
12472                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12473                 char gpValStr[10];
12474
12475                 if (gpVal == -1)
12476                 {
12477                     // pointerTypeToGPByte will have bitched.
12478                     exit(1);
12479                 }
12480
12481                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12482                 aopPut (result, gpValStr, GPTRSIZE - 1);
12483             }
12484           goto release;
12485         }
12486
12487       /* just copy the pointers */
12488       size = AOP_SIZE (result);
12489       offset = 0;
12490       _startLazyDPSEvaluation ();
12491       while (size--)
12492         {
12493           aopPut (result,
12494                   aopGet (right, offset, FALSE, FALSE, NULL),
12495                   offset);
12496           offset++;
12497         }
12498       _endLazyDPSEvaluation ();
12499       goto release;
12500     }
12501
12502   /* so we now know that the size of destination is greater
12503      than the size of the source */
12504   /* we move to result for the size of source */
12505   size = AOP_SIZE (right);
12506   offset = 0;
12507   _startLazyDPSEvaluation ();
12508   while (size--)
12509     {
12510       aopPut (result,
12511               aopGet (right, offset, FALSE, FALSE, NULL),
12512               offset);
12513       offset++;
12514     }
12515   _endLazyDPSEvaluation ();
12516
12517   /* now depending on the sign of the source && destination */
12518   size = AOP_SIZE (result) - AOP_SIZE (right);
12519   /* if unsigned or not an integral type */
12520   /* also, if the source is a bit, we don't need to sign extend, because
12521    * it can't possibly have set the sign bit.
12522    */
12523   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12524     {
12525       while (size--)
12526         {
12527           aopPut (result, zero, offset++);
12528         }
12529     }
12530   else
12531     {
12532       /* we need to extend the sign :{ */
12533       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12534                         FALSE, FALSE, NULL));
12535       emitcode ("rlc", "a");
12536       emitcode ("subb", "a,acc");
12537       while (size--)
12538         aopPut (result, "a", offset++);
12539     }
12540
12541   /* we are done hurray !!!! */
12542
12543 release:
12544   freeAsmop (right, NULL, ic, TRUE);
12545   freeAsmop (result, NULL, ic, TRUE);
12546
12547 }
12548
12549 /*-----------------------------------------------------------------*/
12550 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12551 /*-----------------------------------------------------------------*/
12552 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12553 {
12554     operand *from , *to , *count;
12555     symbol *lbl;
12556     bitVect *rsave;
12557     int i;
12558
12559     /* we know it has to be 3 parameters */
12560     assert (nparms == 3);
12561
12562     rsave = newBitVect(16);
12563     /* save DPTR if it needs to be saved */
12564     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12565             if (bitVectBitValue(ic->rMask,i))
12566                     rsave = bitVectSetBit(rsave,i);
12567     }
12568     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12569                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12570     savermask(rsave);
12571
12572     to = parms[0];
12573     from = parms[1];
12574     count = parms[2];
12575
12576     aopOp (from, ic->next, FALSE, FALSE);
12577
12578     /* get from into DPTR1 */
12579     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12580     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12581     if (options.model == MODEL_FLAT24) {
12582         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12583     }
12584
12585     freeAsmop (from, NULL, ic, FALSE);
12586     aopOp (to, ic, FALSE, FALSE);
12587     /* get "to" into DPTR */
12588     /* if the operand is already in dptr
12589        then we do nothing else we move the value to dptr */
12590     if (AOP_TYPE (to) != AOP_STR) {
12591         /* if already in DPTR then we need to push */
12592         if (AOP_TYPE(to) == AOP_DPTR) {
12593             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12594             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12595             if (options.model == MODEL_FLAT24)
12596                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12597             emitcode ("pop", "dph");
12598             emitcode ("pop", "dpl");
12599         } else {
12600             _startLazyDPSEvaluation ();
12601             /* if this is remateriazable */
12602             if (AOP_TYPE (to) == AOP_IMMD) {
12603                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12604             } else {                    /* we need to get it byte by byte */
12605                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12606                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12607                 if (options.model == MODEL_FLAT24) {
12608                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12609                 }
12610             }
12611             _endLazyDPSEvaluation ();
12612         }
12613     }
12614     freeAsmop (to, NULL, ic, FALSE);
12615     _G.dptrInUse = _G.dptr1InUse = 1;
12616     aopOp (count, ic->next->next, FALSE,FALSE);
12617     lbl =newiTempLabel(NULL);
12618
12619     /* now for the actual copy */
12620     if (AOP_TYPE(count) == AOP_LIT &&
12621         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12622         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12623         if (fromc) {
12624             emitcode ("lcall","__bi_memcpyc2x_s");
12625         } else {
12626             emitcode ("lcall","__bi_memcpyx2x_s");
12627         }
12628         freeAsmop (count, NULL, ic, FALSE);
12629     } else {
12630         symbol *lbl1 = newiTempLabel(NULL);
12631
12632         emitcode (";"," Auto increment but no djnz");
12633         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12634         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12635         freeAsmop (count, NULL, ic, FALSE);
12636         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12637         emitLabel (lbl);
12638         if (fromc) {
12639             emitcode ("clr","a");
12640             emitcode ("movc", "a,@a+dptr");
12641         } else
12642             emitcode ("movx", "a,@dptr");
12643         emitcode ("movx", "@dptr,a");
12644         emitcode ("inc", "dptr");
12645         emitcode ("inc", "dptr");
12646         emitcode ("mov","a,b");
12647         emitcode ("orl","a,_ap");
12648         emitcode ("jz","!tlabel",lbl1->key+100);
12649         emitcode ("mov","a,_ap");
12650         emitcode ("add","a,#!constbyte",0xFF);
12651         emitcode ("mov","_ap,a");
12652         emitcode ("mov","a,b");
12653         emitcode ("addc","a,#!constbyte",0xFF);
12654         emitcode ("mov","b,a");
12655         emitcode ("sjmp","!tlabel",lbl->key+100);
12656         emitLabel (lbl1);
12657     }
12658     emitcode ("mov", "dps,#0");
12659     _G.dptrInUse = _G.dptr1InUse = 0;
12660     unsavermask(rsave);
12661
12662 }
12663
12664 /*-----------------------------------------------------------------*/
12665 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12666 /*-----------------------------------------------------------------*/
12667 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12668 {
12669     operand *from , *to , *count;
12670     symbol *lbl,*lbl2;
12671     bitVect *rsave;
12672     int i;
12673
12674     /* we know it has to be 3 parameters */
12675     assert (nparms == 3);
12676
12677     rsave = newBitVect(16);
12678     /* save DPTR if it needs to be saved */
12679     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12680             if (bitVectBitValue(ic->rMask,i))
12681                     rsave = bitVectSetBit(rsave,i);
12682     }
12683     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12684                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12685     savermask(rsave);
12686
12687     to = parms[0];
12688     from = parms[1];
12689     count = parms[2];
12690
12691     aopOp (from, ic->next, FALSE, FALSE);
12692
12693     /* get from into DPTR1 */
12694     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12695     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12696     if (options.model == MODEL_FLAT24) {
12697         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12698     }
12699
12700     freeAsmop (from, NULL, ic, FALSE);
12701     aopOp (to, ic, FALSE, FALSE);
12702     /* get "to" into DPTR */
12703     /* if the operand is already in dptr
12704        then we do nothing else we move the value to dptr */
12705     if (AOP_TYPE (to) != AOP_STR) {
12706         /* if already in DPTR then we need to push */
12707         if (AOP_TYPE(to) == AOP_DPTR) {
12708             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12709             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12710             if (options.model == MODEL_FLAT24)
12711                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12712             emitcode ("pop", "dph");
12713             emitcode ("pop", "dpl");
12714         } else {
12715             _startLazyDPSEvaluation ();
12716             /* if this is remateriazable */
12717             if (AOP_TYPE (to) == AOP_IMMD) {
12718                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12719             } else {                    /* we need to get it byte by byte */
12720                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12721                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12722                 if (options.model == MODEL_FLAT24) {
12723                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12724                 }
12725             }
12726             _endLazyDPSEvaluation ();
12727         }
12728     }
12729     freeAsmop (to, NULL, ic, FALSE);
12730     _G.dptrInUse = _G.dptr1InUse = 1;
12731     aopOp (count, ic->next->next, FALSE,FALSE);
12732     lbl =newiTempLabel(NULL);
12733     lbl2 =newiTempLabel(NULL);
12734
12735     /* now for the actual compare */
12736     if (AOP_TYPE(count) == AOP_LIT &&
12737         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12738         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12739         if (fromc)
12740             emitcode("lcall","__bi_memcmpc2x_s");
12741         else
12742             emitcode("lcall","__bi_memcmpx2x_s");
12743         freeAsmop (count, NULL, ic, FALSE);
12744         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12745         aopPut(IC_RESULT(ic),"a",0);
12746         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12747     } else {
12748         symbol *lbl1 = newiTempLabel(NULL);
12749
12750         emitcode("push","ar0");
12751         emitcode (";"," Auto increment but no djnz");
12752         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12753         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12754         freeAsmop (count, NULL, ic, FALSE);
12755         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12756         emitLabel (lbl);
12757         if (fromc) {
12758             emitcode ("clr","a");
12759             emitcode ("movc", "a,@a+dptr");
12760         } else
12761             emitcode ("movx", "a,@dptr");
12762         emitcode ("mov","r0,a");
12763         emitcode ("movx", "a,@dptr");
12764         emitcode ("clr","c");
12765         emitcode ("subb","a,r0");
12766         emitcode ("jnz","!tlabel",lbl2->key+100);
12767         emitcode ("inc", "dptr");
12768         emitcode ("inc", "dptr");
12769         emitcode ("mov","a,b");
12770         emitcode ("orl","a,_ap");
12771         emitcode ("jz","!tlabel",lbl1->key+100);
12772         emitcode ("mov","a,_ap");
12773         emitcode ("add","a,#!constbyte",0xFF);
12774         emitcode ("mov","_ap,a");
12775         emitcode ("mov","a,b");
12776         emitcode ("addc","a,#!constbyte",0xFF);
12777         emitcode ("mov","b,a");
12778         emitcode ("sjmp","!tlabel",lbl->key+100);
12779         emitLabel (lbl1);
12780         emitcode ("clr","a");
12781         emitLabel (lbl2);
12782         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12783         aopPut(IC_RESULT(ic),"a",0);
12784         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12785         emitcode("pop","ar0");
12786         emitcode ("mov", "dps,#0");
12787     }
12788     _G.dptrInUse = _G.dptr1InUse = 0;
12789     unsavermask(rsave);
12790
12791 }
12792
12793 /*-----------------------------------------------------------------*/
12794 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12795 /* port, first parameter output area second parameter pointer to   */
12796 /* port third parameter count                                      */
12797 /*-----------------------------------------------------------------*/
12798 static void genInp( iCode *ic, int nparms, operand **parms)
12799 {
12800     operand *from , *to , *count;
12801     symbol *lbl;
12802     bitVect *rsave;
12803     int i;
12804
12805     /* we know it has to be 3 parameters */
12806     assert (nparms == 3);
12807
12808     rsave = newBitVect(16);
12809     /* save DPTR if it needs to be saved */
12810     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12811             if (bitVectBitValue(ic->rMask,i))
12812                     rsave = bitVectSetBit(rsave,i);
12813     }
12814     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12815                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12816     savermask(rsave);
12817
12818     to = parms[0];
12819     from = parms[1];
12820     count = parms[2];
12821
12822     aopOp (from, ic->next, FALSE, FALSE);
12823
12824     /* get from into DPTR1 */
12825     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12826     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12827     if (options.model == MODEL_FLAT24) {
12828         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12829     }
12830
12831     freeAsmop (from, NULL, ic, FALSE);
12832     aopOp (to, ic, FALSE, FALSE);
12833     /* get "to" into DPTR */
12834     /* if the operand is already in dptr
12835        then we do nothing else we move the value to dptr */
12836     if (AOP_TYPE (to) != AOP_STR) {
12837         /* if already in DPTR then we need to push */
12838         if (AOP_TYPE(to) == AOP_DPTR) {
12839             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12840             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12841             if (options.model == MODEL_FLAT24)
12842                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12843             emitcode ("pop", "dph");
12844             emitcode ("pop", "dpl");
12845         } else {
12846             _startLazyDPSEvaluation ();
12847             /* if this is remateriazable */
12848             if (AOP_TYPE (to) == AOP_IMMD) {
12849                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12850             } else {                    /* we need to get it byte by byte */
12851                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12852                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12853                 if (options.model == MODEL_FLAT24) {
12854                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12855                 }
12856             }
12857             _endLazyDPSEvaluation ();
12858         }
12859     }
12860     freeAsmop (to, NULL, ic, FALSE);
12861
12862     _G.dptrInUse = _G.dptr1InUse = 1;
12863     aopOp (count, ic->next->next, FALSE,FALSE);
12864     lbl =newiTempLabel(NULL);
12865
12866     /* now for the actual copy */
12867     if (AOP_TYPE(count) == AOP_LIT &&
12868         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12869         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12870         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12871         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12872         freeAsmop (count, NULL, ic, FALSE);
12873         emitLabel (lbl);
12874         emitcode ("movx", "a,@dptr");   /* read data from port */
12875         emitcode ("dec","dps");         /* switch to DPTR */
12876         emitcode ("movx", "@dptr,a");   /* save into location */
12877         emitcode ("inc", "dptr");       /* point to next area */
12878         emitcode ("inc","dps");         /* switch to DPTR2 */
12879         emitcode ("djnz","b,!tlabel",lbl->key+100);
12880     } else {
12881         symbol *lbl1 = newiTempLabel(NULL);
12882
12883         emitcode (";"," Auto increment but no djnz");
12884         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12885         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12886         freeAsmop (count, NULL, ic, FALSE);
12887         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12888         emitLabel (lbl);
12889         emitcode ("movx", "a,@dptr");
12890         emitcode ("dec","dps");         /* switch to DPTR */
12891         emitcode ("movx", "@dptr,a");
12892         emitcode ("inc", "dptr");
12893         emitcode ("inc","dps");         /* switch to DPTR2 */
12894 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12895 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12896         emitcode ("mov","a,b");
12897         emitcode ("orl","a,_ap");
12898         emitcode ("jz","!tlabel",lbl1->key+100);
12899         emitcode ("mov","a,_ap");
12900         emitcode ("add","a,#!constbyte",0xFF);
12901         emitcode ("mov","_ap,a");
12902         emitcode ("mov","a,b");
12903         emitcode ("addc","a,#!constbyte",0xFF);
12904         emitcode ("mov","b,a");
12905         emitcode ("sjmp","!tlabel",lbl->key+100);
12906         emitLabel (lbl1);
12907     }
12908     emitcode ("mov", "dps,#0");
12909     _G.dptrInUse = _G.dptr1InUse = 0;
12910     unsavermask(rsave);
12911
12912 }
12913
12914 /*-----------------------------------------------------------------*/
12915 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12916 /* port, first parameter output area second parameter pointer to   */
12917 /* port third parameter count                                      */
12918 /*-----------------------------------------------------------------*/
12919 static void genOutp( iCode *ic, int nparms, operand **parms)
12920 {
12921     operand *from , *to , *count;
12922     symbol *lbl;
12923     bitVect *rsave;
12924     int i;
12925
12926     /* we know it has to be 3 parameters */
12927     assert (nparms == 3);
12928
12929     rsave = newBitVect(16);
12930     /* save DPTR if it needs to be saved */
12931     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12932             if (bitVectBitValue(ic->rMask,i))
12933                     rsave = bitVectSetBit(rsave,i);
12934     }
12935     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12936                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12937     savermask(rsave);
12938
12939     to = parms[0];
12940     from = parms[1];
12941     count = parms[2];
12942
12943     aopOp (from, ic->next, FALSE, FALSE);
12944
12945     /* get from into DPTR1 */
12946     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12947     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12948     if (options.model == MODEL_FLAT24) {
12949         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12950     }
12951
12952     freeAsmop (from, NULL, ic, FALSE);
12953     aopOp (to, ic, FALSE, FALSE);
12954     /* get "to" into DPTR */
12955     /* if the operand is already in dptr
12956        then we do nothing else we move the value to dptr */
12957     if (AOP_TYPE (to) != AOP_STR) {
12958         /* if already in DPTR then we need to push */
12959         if (AOP_TYPE(to) == AOP_DPTR) {
12960             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12961             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12962             if (options.model == MODEL_FLAT24)
12963                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12964             emitcode ("pop", "dph");
12965             emitcode ("pop", "dpl");
12966         } else {
12967             _startLazyDPSEvaluation ();
12968             /* if this is remateriazable */
12969             if (AOP_TYPE (to) == AOP_IMMD) {
12970                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12971             } else {                    /* we need to get it byte by byte */
12972                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12973                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12974                 if (options.model == MODEL_FLAT24) {
12975                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12976                 }
12977             }
12978             _endLazyDPSEvaluation ();
12979         }
12980     }
12981     freeAsmop (to, NULL, ic, FALSE);
12982
12983     _G.dptrInUse = _G.dptr1InUse = 1;
12984     aopOp (count, ic->next->next, FALSE,FALSE);
12985     lbl =newiTempLabel(NULL);
12986
12987     /* now for the actual copy */
12988     if (AOP_TYPE(count) == AOP_LIT &&
12989         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12990         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12991         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12992         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12993         emitLabel (lbl);
12994         emitcode ("movx", "a,@dptr");   /* read data from port */
12995         emitcode ("inc","dps");         /* switch to DPTR2 */
12996         emitcode ("movx", "@dptr,a");   /* save into location */
12997         emitcode ("inc", "dptr");       /* point to next area */
12998         emitcode ("dec","dps");         /* switch to DPTR */
12999         emitcode ("djnz","b,!tlabel",lbl->key+100);
13000         freeAsmop (count, NULL, ic, FALSE);
13001     } else {
13002         symbol *lbl1 = newiTempLabel(NULL);
13003
13004         emitcode (";"," Auto increment but no djnz");
13005         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13006         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13007         freeAsmop (count, NULL, ic, FALSE);
13008         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13009         emitLabel (lbl);
13010         emitcode ("movx", "a,@dptr");
13011         emitcode ("inc", "dptr");
13012         emitcode ("inc","dps");         /* switch to DPTR2 */
13013         emitcode ("movx", "@dptr,a");
13014         emitcode ("dec","dps");         /* switch to DPTR */
13015         emitcode ("mov","a,b");
13016         emitcode ("orl","a,_ap");
13017         emitcode ("jz","!tlabel",lbl1->key+100);
13018         emitcode ("mov","a,_ap");
13019         emitcode ("add","a,#!constbyte",0xFF);
13020         emitcode ("mov","_ap,a");
13021         emitcode ("mov","a,b");
13022         emitcode ("addc","a,#!constbyte",0xFF);
13023         emitcode ("mov","b,a");
13024         emitcode ("sjmp","!tlabel",lbl->key+100);
13025         emitLabel (lbl1);
13026     }
13027     emitcode ("mov", "dps,#0");
13028     _G.dptrInUse = _G.dptr1InUse = 0;
13029     unsavermask(rsave);
13030
13031 }
13032
13033 /*-----------------------------------------------------------------*/
13034 /* genSwapW - swap lower & high order bytes                        */
13035 /*-----------------------------------------------------------------*/
13036 static void genSwapW(iCode *ic, int nparms, operand **parms)
13037 {
13038     operand *dest;
13039     operand *src;
13040     assert (nparms==1);
13041
13042     src = parms[0];
13043     dest=IC_RESULT(ic);
13044
13045     assert(getSize(operandType(src))==2);
13046
13047     aopOp (src, ic, FALSE, FALSE);
13048     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13049     _G.accInUse++;
13050     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13051     _G.accInUse--;
13052     freeAsmop (src, NULL, ic, FALSE);
13053
13054     aopOp (dest,ic, FALSE, FALSE);
13055     aopPut(dest,"b",0);
13056     aopPut(dest,"a",1);
13057     freeAsmop (dest, NULL, ic, FALSE);
13058 }
13059
13060 /*-----------------------------------------------------------------*/
13061 /* genMemsetX - gencode for memSetX data                           */
13062 /*-----------------------------------------------------------------*/
13063 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13064 {
13065     operand *to , *val , *count;
13066     symbol *lbl;
13067     char *l;
13068     int i;
13069     bitVect *rsave;
13070
13071     /* we know it has to be 3 parameters */
13072     assert (nparms == 3);
13073
13074     to = parms[0];
13075     val = parms[1];
13076     count = parms[2];
13077
13078     /* save DPTR if it needs to be saved */
13079     rsave = newBitVect(16);
13080     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13081             if (bitVectBitValue(ic->rMask,i))
13082                     rsave = bitVectSetBit(rsave,i);
13083     }
13084     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13085                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13086     savermask(rsave);
13087
13088     aopOp (to, ic, FALSE, FALSE);
13089     /* get "to" into DPTR */
13090     /* if the operand is already in dptr
13091        then we do nothing else we move the value to dptr */
13092     if (AOP_TYPE (to) != AOP_STR) {
13093         /* if already in DPTR then we need to push */
13094         if (AOP_TYPE(to) == AOP_DPTR) {
13095             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13096             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13097             if (options.model == MODEL_FLAT24)
13098                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13099             emitcode ("pop", "dph");
13100             emitcode ("pop", "dpl");
13101         } else {
13102             _startLazyDPSEvaluation ();
13103             /* if this is remateriazable */
13104             if (AOP_TYPE (to) == AOP_IMMD) {
13105                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13106             } else {                    /* we need to get it byte by byte */
13107                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13108                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13109                 if (options.model == MODEL_FLAT24) {
13110                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13111                 }
13112             }
13113             _endLazyDPSEvaluation ();
13114         }
13115     }
13116     freeAsmop (to, NULL, ic, FALSE);
13117
13118     aopOp (val, ic->next->next, FALSE,FALSE);
13119     aopOp (count, ic->next->next, FALSE,FALSE);
13120     lbl =newiTempLabel(NULL);
13121     /* now for the actual copy */
13122     if (AOP_TYPE(count) == AOP_LIT &&
13123         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13124         l = aopGet(val, 0, FALSE, FALSE, NULL);
13125         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13126         MOVA(l);
13127         emitLabel (lbl);
13128         emitcode ("movx", "@dptr,a");
13129         emitcode ("inc", "dptr");
13130         emitcode ("djnz","b,!tlabel",lbl->key+100);
13131     } else {
13132         symbol *lbl1 = newiTempLabel(NULL);
13133
13134         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13135         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13136         emitLabel (lbl);
13137         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13138         emitcode ("movx", "@dptr,a");
13139         emitcode ("inc", "dptr");
13140         emitcode ("mov","a,b");
13141         emitcode ("orl","a,_ap");
13142         emitcode ("jz","!tlabel",lbl1->key+100);
13143         emitcode ("mov","a,_ap");
13144         emitcode ("add","a,#!constbyte",0xFF);
13145         emitcode ("mov","_ap,a");
13146         emitcode ("mov","a,b");
13147         emitcode ("addc","a,#!constbyte",0xFF);
13148         emitcode ("mov","b,a");
13149         emitcode ("sjmp","!tlabel",lbl->key+100);
13150         emitLabel (lbl1);
13151     }
13152     freeAsmop (count, NULL, ic, FALSE);
13153     unsavermask(rsave);
13154 }
13155
13156 /*-----------------------------------------------------------------*/
13157 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13158 /*-----------------------------------------------------------------*/
13159 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13160 {
13161         bitVect *rsave ;
13162         operand *pnum, *result;
13163         int i;
13164
13165         assert (nparms==1);
13166         /* save registers that need to be saved */
13167         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13168                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13169
13170         pnum = parms[0];
13171         aopOp (pnum, ic, FALSE, FALSE);
13172         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13173         freeAsmop (pnum, NULL, ic, FALSE);
13174         emitcode ("lcall","NatLib_LoadPrimitive");
13175         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13176         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13177             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13178                 for (i = (size-1) ; i >= 0 ; i-- ) {
13179                         emitcode ("push","a%s",javaRet[i]);
13180                 }
13181                 for (i=0; i < size ; i++ ) {
13182                         emitcode ("pop","a%s",
13183                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13184                 }
13185         } else {
13186                 for (i = 0 ; i < size ; i++ ) {
13187                         aopPut(result,javaRet[i],i);
13188                 }
13189         }
13190         freeAsmop (result, NULL, ic, FALSE);
13191         unsavermask(rsave);
13192 }
13193
13194 /*-----------------------------------------------------------------*/
13195 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13196 /*-----------------------------------------------------------------*/
13197 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13198 {
13199         bitVect *rsave ;
13200         operand *pnum, *result;
13201         int size = 3;
13202         int i;
13203
13204         assert (nparms==1);
13205         /* save registers that need to be saved */
13206         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13207                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13208
13209         pnum = parms[0];
13210         aopOp (pnum, ic, FALSE, FALSE);
13211         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13212         freeAsmop (pnum, NULL, ic, FALSE);
13213         emitcode ("lcall","NatLib_LoadPointer");
13214         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13215         if (AOP_TYPE(result)!=AOP_STR) {
13216                 for (i = 0 ; i < size ; i++ ) {
13217                         aopPut(result,fReturn[i],i);
13218                 }
13219         }
13220         freeAsmop (result, NULL, ic, FALSE);
13221         unsavermask(rsave);
13222 }
13223
13224 /*-----------------------------------------------------------------*/
13225 /* genNatLibInstallStateBlock -                                    */
13226 /*-----------------------------------------------------------------*/
13227 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13228                                        operand **parms, const char *name)
13229 {
13230         bitVect *rsave ;
13231         operand *psb, *handle;
13232         assert (nparms==2);
13233
13234         /* save registers that need to be saved */
13235         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13236                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13237         psb = parms[0];
13238         handle = parms[1];
13239
13240         /* put pointer to state block into DPTR1 */
13241         aopOp (psb, ic, FALSE, FALSE);
13242         if (AOP_TYPE (psb) == AOP_IMMD) {
13243                 emitcode ("mov","dps,#1");
13244                 emitcode ("mov", "dptr,%s",
13245                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13246                 emitcode ("mov","dps,#0");
13247         } else {
13248                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13249                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13250                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13251         }
13252         freeAsmop (psb, NULL, ic, FALSE);
13253
13254         /* put libraryID into DPTR */
13255         emitcode ("mov","dptr,#LibraryID");
13256
13257         /* put handle into r3:r2 */
13258         aopOp (handle, ic, FALSE, FALSE);
13259         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13260                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13261                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13262                 emitcode ("pop","ar3");
13263                 emitcode ("pop","ar2");
13264         } else {
13265                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13266                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13267         }
13268         freeAsmop (psb, NULL, ic, FALSE);
13269
13270         /* make the call */
13271         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13272
13273         /* put return value into place*/
13274         _G.accInUse++;
13275         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13276         _G.accInUse--;
13277         aopPut(IC_RESULT(ic),"a",0);
13278         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13279         unsavermask(rsave);
13280 }
13281
13282 /*-----------------------------------------------------------------*/
13283 /* genNatLibRemoveStateBlock -                                     */
13284 /*-----------------------------------------------------------------*/
13285 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13286 {
13287         bitVect *rsave ;
13288
13289         assert(nparms==0);
13290
13291         /* save registers that need to be saved */
13292         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13293                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13294
13295         /* put libraryID into DPTR */
13296         emitcode ("mov","dptr,#LibraryID");
13297         /* make the call */
13298         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13299         unsavermask(rsave);
13300 }
13301
13302 /*-----------------------------------------------------------------*/
13303 /* genNatLibGetStateBlock -                                        */
13304 /*-----------------------------------------------------------------*/
13305 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13306                                    operand **parms,const char *name)
13307 {
13308         bitVect *rsave ;
13309         symbol *lbl = newiTempLabel(NULL);
13310
13311         assert(nparms==0);
13312         /* save registers that need to be saved */
13313         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13314                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13315
13316         /* put libraryID into DPTR */
13317         emitcode ("mov","dptr,#LibraryID");
13318         /* make the call */
13319         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13320         emitcode ("jnz","!tlabel",lbl->key+100);
13321
13322         /* put return value into place */
13323         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13324         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13325                 emitcode ("push","ar3");
13326                 emitcode ("push","ar2");
13327                 emitcode ("pop","%s",
13328                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13329                 emitcode ("pop","%s",
13330                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13331         } else {
13332                 aopPut(IC_RESULT(ic),"r2",0);
13333                 aopPut(IC_RESULT(ic),"r3",1);
13334         }
13335         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13336         emitLabel (lbl);
13337         unsavermask(rsave);
13338 }
13339
13340 /*-----------------------------------------------------------------*/
13341 /* genMMMalloc -                                                   */
13342 /*-----------------------------------------------------------------*/
13343 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13344                          int size, const char *name)
13345 {
13346         bitVect *rsave ;
13347         operand *bsize;
13348         symbol *rsym;
13349         symbol *lbl = newiTempLabel(NULL);
13350
13351         assert (nparms == 1);
13352         /* save registers that need to be saved */
13353         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13354                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13355
13356         bsize=parms[0];
13357         aopOp (bsize,ic,FALSE,FALSE);
13358
13359         /* put the size in R4-R2 */
13360         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13361                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13362                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13363                 if (size==3) {
13364                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13365                         emitcode("pop","ar4");
13366                 }
13367                 emitcode("pop","ar3");
13368                 emitcode("pop","ar2");
13369         } else {
13370                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13371                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13372                 if (size==3) {
13373                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13374                 }
13375         }
13376         freeAsmop (bsize, NULL, ic, FALSE);
13377
13378         /* make the call */
13379         emitcode ("lcall","MM_%s",name);
13380         emitcode ("jz","!tlabel",lbl->key+100);
13381         emitcode ("mov","r2,#!constbyte",0xff);
13382         emitcode ("mov","r3,#!constbyte",0xff);
13383         emitLabel (lbl);
13384         /* we don't care about the pointer : we just save the handle */
13385         rsym = OP_SYMBOL(IC_RESULT(ic));
13386         if (rsym->liveFrom != rsym->liveTo) {
13387                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13388                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13389                         emitcode ("push","ar3");
13390                         emitcode ("push","ar2");
13391                         emitcode ("pop","%s",
13392                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13393                         emitcode ("pop","%s",
13394                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13395                 } else {
13396                         aopPut(IC_RESULT(ic),"r2",0);
13397                         aopPut(IC_RESULT(ic),"r3",1);
13398                 }
13399                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13400         }
13401         unsavermask(rsave);
13402 }
13403
13404 /*-----------------------------------------------------------------*/
13405 /* genMMDeref -                                                    */
13406 /*-----------------------------------------------------------------*/
13407 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13408 {
13409         bitVect *rsave ;
13410         operand *handle;
13411
13412         assert (nparms == 1);
13413         /* save registers that need to be saved */
13414         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13415                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13416
13417         handle=parms[0];
13418         aopOp (handle,ic,FALSE,FALSE);
13419
13420         /* put the size in R4-R2 */
13421         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13422                 emitcode("push","%s",
13423                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13424                 emitcode("push","%s",
13425                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13426                 emitcode("pop","ar3");
13427                 emitcode("pop","ar2");
13428         } else {
13429                 emitcode ("mov","r2,%s",
13430                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13431                 emitcode ("mov","r3,%s",
13432                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13433         }
13434         freeAsmop (handle, NULL, ic, FALSE);
13435
13436         /* make the call */
13437         emitcode ("lcall","MM_Deref");
13438
13439         {
13440                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13441                 if (rsym->liveFrom != rsym->liveTo) {
13442                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13443                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13444                             _startLazyDPSEvaluation ();
13445
13446                             aopPut(IC_RESULT(ic),"dpl",0);
13447                             aopPut(IC_RESULT(ic),"dph",1);
13448                             aopPut(IC_RESULT(ic),"dpx",2);
13449
13450                             _endLazyDPSEvaluation ();
13451
13452                         }
13453                 }
13454         }
13455         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13456         unsavermask(rsave);
13457 }
13458
13459 /*-----------------------------------------------------------------*/
13460 /* genMMUnrestrictedPersist -                                      */
13461 /*-----------------------------------------------------------------*/
13462 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13463 {
13464         bitVect *rsave ;
13465         operand *handle;
13466
13467         assert (nparms == 1);
13468         /* save registers that need to be saved */
13469         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13470                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13471
13472         handle=parms[0];
13473         aopOp (handle,ic,FALSE,FALSE);
13474
13475         /* put the size in R3-R2 */
13476         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13477                 emitcode("push","%s",
13478                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13479                 emitcode("push","%s",
13480                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13481                 emitcode("pop","ar3");
13482                 emitcode("pop","ar2");
13483         } else {
13484                 emitcode ("mov","r2,%s",
13485                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13486                 emitcode ("mov","r3,%s",
13487                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13488         }
13489         freeAsmop (handle, NULL, ic, FALSE);
13490
13491         /* make the call */
13492         emitcode ("lcall","MM_UnrestrictedPersist");
13493
13494         {
13495                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13496                 if (rsym->liveFrom != rsym->liveTo) {
13497                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13498                         aopPut(IC_RESULT(ic),"a",0);
13499                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13500                 }
13501         }
13502         unsavermask(rsave);
13503 }
13504
13505 /*-----------------------------------------------------------------*/
13506 /* genSystemExecJavaProcess -                                      */
13507 /*-----------------------------------------------------------------*/
13508 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13509 {
13510         bitVect *rsave ;
13511         operand *handle, *pp;
13512
13513         assert (nparms==2);
13514         /* save registers that need to be saved */
13515         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13516                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13517
13518         pp = parms[0];
13519         handle = parms[1];
13520
13521         /* put the handle in R3-R2 */
13522         aopOp (handle,ic,FALSE,FALSE);
13523         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13524                 emitcode("push","%s",
13525                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13526                 emitcode("push","%s",
13527                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13528                 emitcode("pop","ar3");
13529                 emitcode("pop","ar2");
13530         } else {
13531                 emitcode ("mov","r2,%s",
13532                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13533                 emitcode ("mov","r3,%s",
13534                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13535         }
13536         freeAsmop (handle, NULL, ic, FALSE);
13537
13538         /* put pointer in DPTR */
13539         aopOp (pp,ic,FALSE,FALSE);
13540         if (AOP_TYPE(pp) == AOP_IMMD) {
13541                 emitcode ("mov", "dptr,%s",
13542                           aopGet (pp, 0, TRUE, FALSE, NULL));
13543         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13544                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13545                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13546                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13547         }
13548         freeAsmop (handle, NULL, ic, FALSE);
13549
13550         /* make the call */
13551         emitcode ("lcall","System_ExecJavaProcess");
13552
13553         /* put result in place */
13554         {
13555                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13556                 if (rsym->liveFrom != rsym->liveTo) {
13557                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13558                         aopPut(IC_RESULT(ic),"a",0);
13559                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13560                 }
13561         }
13562
13563         unsavermask(rsave);
13564 }
13565
13566 /*-----------------------------------------------------------------*/
13567 /* genSystemRTCRegisters -                                         */
13568 /*-----------------------------------------------------------------*/
13569 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13570                                   char *name)
13571 {
13572         bitVect *rsave ;
13573         operand *pp;
13574
13575         assert (nparms==1);
13576         /* save registers that need to be saved */
13577         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13578                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13579
13580         pp=parms[0];
13581         /* put pointer in DPTR */
13582         aopOp (pp,ic,FALSE,FALSE);
13583         if (AOP_TYPE (pp) == AOP_IMMD) {
13584                 emitcode ("mov","dps,#1");
13585                 emitcode ("mov", "dptr,%s",
13586                           aopGet (pp, 0, TRUE, FALSE, NULL));
13587                 emitcode ("mov","dps,#0");
13588         } else {
13589                 emitcode ("mov","dpl1,%s",
13590                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13591                 emitcode ("mov","dph1,%s",
13592                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13593                 emitcode ("mov","dpx1,%s",
13594                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13595         }
13596         freeAsmop (pp, NULL, ic, FALSE);
13597
13598         /* make the call */
13599         emitcode ("lcall","System_%sRTCRegisters",name);
13600
13601         unsavermask(rsave);
13602 }
13603
13604 /*-----------------------------------------------------------------*/
13605 /* genSystemThreadSleep -                                          */
13606 /*-----------------------------------------------------------------*/
13607 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13608 {
13609         bitVect *rsave ;
13610         operand *to, *s;
13611
13612         assert (nparms==1);
13613         /* save registers that need to be saved */
13614         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13615                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13616
13617         to = parms[0];
13618         aopOp(to,ic,FALSE,FALSE);
13619         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13620             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13621                 emitcode ("push","%s",
13622                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13623                 emitcode ("push","%s",
13624                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13625                 emitcode ("push","%s",
13626                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13627                 emitcode ("push","%s",
13628                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13629                 emitcode ("pop","ar3");
13630                 emitcode ("pop","ar2");
13631                 emitcode ("pop","ar1");
13632                 emitcode ("pop","ar0");
13633         } else {
13634                 emitcode ("mov","r0,%s",
13635                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13636                 emitcode ("mov","r1,%s",
13637                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13638                 emitcode ("mov","r2,%s",
13639                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13640                 emitcode ("mov","r3,%s",
13641                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13642         }
13643         freeAsmop (to, NULL, ic, FALSE);
13644
13645         /* suspend in acc */
13646         s = parms[1];
13647         aopOp(s,ic,FALSE,FALSE);
13648         emitcode ("mov","a,%s",
13649                   aopGet(s,0,FALSE,TRUE,NULL));
13650         freeAsmop (s, NULL, ic, FALSE);
13651
13652         /* make the call */
13653         emitcode ("lcall","System_%s",name);
13654
13655         unsavermask(rsave);
13656 }
13657
13658 /*-----------------------------------------------------------------*/
13659 /* genSystemThreadResume -                                         */
13660 /*-----------------------------------------------------------------*/
13661 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13662 {
13663         bitVect *rsave ;
13664         operand *tid,*pid;
13665
13666         assert (nparms==2);
13667         /* save registers that need to be saved */
13668         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13669                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13670
13671         tid = parms[0];
13672         pid = parms[1];
13673
13674         /* PID in R0 */
13675         aopOp(pid,ic,FALSE,FALSE);
13676         emitcode ("mov","r0,%s",
13677                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13678         freeAsmop (pid, NULL, ic, FALSE);
13679
13680         /* tid into ACC */
13681         aopOp(tid,ic,FALSE,FALSE);
13682         emitcode ("mov","a,%s",
13683                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13684         freeAsmop (tid, NULL, ic, FALSE);
13685
13686         emitcode ("lcall","System_ThreadResume");
13687
13688         /* put result into place */
13689         {
13690                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13691                 if (rsym->liveFrom != rsym->liveTo) {
13692                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13693                         aopPut(IC_RESULT(ic),"a",0);
13694                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13695                 }
13696         }
13697         unsavermask(rsave);
13698 }
13699
13700 /*-----------------------------------------------------------------*/
13701 /* genSystemProcessResume -                                        */
13702 /*-----------------------------------------------------------------*/
13703 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13704 {
13705         bitVect *rsave ;
13706         operand *pid;
13707
13708         assert (nparms==1);
13709         /* save registers that need to be saved */
13710         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13711                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13712
13713         pid = parms[0];
13714
13715         /* pid into ACC */
13716         aopOp(pid,ic,FALSE,FALSE);
13717         emitcode ("mov","a,%s",
13718                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13719         freeAsmop (pid, NULL, ic, FALSE);
13720
13721         emitcode ("lcall","System_ProcessResume");
13722
13723         unsavermask(rsave);
13724 }
13725
13726 /*-----------------------------------------------------------------*/
13727 /* genSystem -                                                     */
13728 /*-----------------------------------------------------------------*/
13729 static void genSystem (iCode *ic,int nparms,char *name)
13730 {
13731         assert(nparms == 0);
13732
13733         emitcode ("lcall","System_%s",name);
13734 }
13735
13736 /*-----------------------------------------------------------------*/
13737 /* genSystemPoll -                                                  */
13738 /*-----------------------------------------------------------------*/
13739 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13740 {
13741         bitVect *rsave ;
13742         operand *fp;
13743
13744         assert (nparms==1);
13745         /* save registers that need to be saved */
13746         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13747                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13748
13749         fp = parms[0];
13750         aopOp (fp,ic,FALSE,FALSE);
13751         if (AOP_TYPE (fp) == AOP_IMMD) {
13752                 emitcode ("mov", "dptr,%s",
13753                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13754         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13755                 emitcode ("mov","dpl,%s",
13756                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13757                 emitcode ("mov","dph,%s",
13758                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13759                 emitcode ("mov","dpx,%s",
13760                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13761         }
13762         freeAsmop (fp, NULL, ic, FALSE);
13763
13764         emitcode ("lcall","System_%sPoll",name);
13765
13766         /* put result into place */
13767         {
13768                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13769                 if (rsym->liveFrom != rsym->liveTo) {
13770                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13771                         aopPut(IC_RESULT(ic),"a",0);
13772                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13773                 }
13774         }
13775         unsavermask(rsave);
13776 }
13777
13778 /*-----------------------------------------------------------------*/
13779 /* genSystemGetCurrentID -                                         */
13780 /*-----------------------------------------------------------------*/
13781 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13782 {
13783         assert (nparms==0);
13784
13785         emitcode ("lcall","System_GetCurrent%sId",name);
13786         /* put result into place */
13787         {
13788                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13789                 if (rsym->liveFrom != rsym->liveTo) {
13790                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13791                         aopPut(IC_RESULT(ic),"a",0);
13792                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13793                 }
13794         }
13795 }
13796
13797 /*-----------------------------------------------------------------*/
13798 /* genDjnz - generate decrement & jump if not zero instrucion      */
13799 /*-----------------------------------------------------------------*/
13800 static int
13801 genDjnz (iCode * ic, iCode * ifx)
13802 {
13803   symbol *lbl, *lbl1;
13804   if (!ifx)
13805     return 0;
13806
13807   /* if the if condition has a false label
13808      then we cannot save */
13809   if (IC_FALSE (ifx))
13810     return 0;
13811
13812   /* if the minus is not of the form a = a - 1 */
13813   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13814       !IS_OP_LITERAL (IC_RIGHT (ic)))
13815     return 0;
13816
13817   if (operandLitValue (IC_RIGHT (ic)) != 1)
13818     return 0;
13819
13820   /* if the size of this greater than one then no
13821      saving */
13822   if (getSize (operandType (IC_RESULT (ic))) > 1)
13823     return 0;
13824
13825   /* otherwise we can save BIG */
13826
13827   D (emitcode (";", "genDjnz"));
13828
13829   lbl = newiTempLabel (NULL);
13830   lbl1 = newiTempLabel (NULL);
13831
13832   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13833
13834   if (AOP_NEEDSACC(IC_RESULT(ic)))
13835   {
13836       /* If the result is accessed indirectly via
13837        * the accumulator, we must explicitly write
13838        * it back after the decrement.
13839        */
13840       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13841
13842       if (strcmp(rByte, "a"))
13843       {
13844            /* Something is hopelessly wrong */
13845            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13846                    __FILE__, __LINE__);
13847            /* We can just give up; the generated code will be inefficient,
13848             * but what the hey.
13849             */
13850            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13851            return 0;
13852       }
13853       emitcode ("dec", "%s", rByte);
13854       aopPut (IC_RESULT (ic), rByte, 0);
13855       emitcode ("jnz", "!tlabel", lbl->key + 100);
13856   }
13857   else if (IS_AOP_PREG (IC_RESULT (ic)))
13858     {
13859       emitcode ("dec", "%s",
13860                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13861       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13862       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13863       ifx->generated = 1;
13864       emitcode ("jnz", "!tlabel", lbl->key + 100);
13865     }
13866   else
13867     {
13868       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13869                 lbl->key + 100);
13870     }
13871   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13872   emitLabel (lbl);
13873   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13874   emitLabel (lbl1);
13875
13876   if (!ifx->generated)
13877       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13878   ifx->generated = 1;
13879   return 1;
13880 }
13881
13882 /*-----------------------------------------------------------------*/
13883 /* genReceive - generate code for a receive iCode                  */
13884 /*-----------------------------------------------------------------*/
13885 static void
13886 genReceive (iCode * ic)
13887 {
13888     int size = getSize (operandType (IC_RESULT (ic)));
13889     int offset = 0;
13890     int rb1off ;
13891
13892     D (emitcode (";", "genReceive"));
13893
13894     if (ic->argreg == 1)
13895     {
13896         /* first parameter */
13897         if (AOP_IS_STR(IC_RESULT(ic)))
13898         {
13899             /* Nothing to do: it's already in the proper place. */
13900             return;
13901         }
13902         else
13903         {
13904             bool useDp2;
13905
13906             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13907                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13908                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13909
13910             _G.accInUse++;
13911             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13912             _G.accInUse--;
13913
13914             /* Sanity checking... */
13915             if (AOP_USESDPTR(IC_RESULT(ic)))
13916             {
13917                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13918                         "genReceive got unexpected DPTR.");
13919             }
13920             assignResultValue (IC_RESULT (ic), NULL);
13921         }
13922     }
13923     else if (ic->argreg > 12)
13924     { /* bit parameters */
13925       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13926         {
13927           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13928           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13929           outBitC(IC_RESULT (ic));
13930         }
13931     }
13932     else
13933     {
13934         /* second receive onwards */
13935         /* this gets a little tricky since unused receives will be
13936          eliminated, we have saved the reg in the type field . and
13937          we use that to figure out which register to use */
13938         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13939         rb1off = ic->argreg;
13940         while (size--)
13941         {
13942             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13943         }
13944     }
13945     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13946 }
13947
13948 /*-----------------------------------------------------------------*/
13949 /* genDummyRead - generate code for dummy read of volatiles        */
13950 /*-----------------------------------------------------------------*/
13951 static void
13952 genDummyRead (iCode * ic)
13953 {
13954   operand *op;
13955   int size, offset;
13956
13957   D (emitcode(";", "genDummyRead"));
13958
13959   op = IC_RIGHT (ic);
13960   if (op && IS_SYMOP (op))
13961     {
13962       aopOp (op, ic, FALSE, FALSE);
13963
13964       /* if the result is a bit */
13965       if (AOP_TYPE (op) == AOP_CRY)
13966         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13967       else
13968         {
13969           /* bit variables done */
13970           /* general case */
13971           size = AOP_SIZE (op);
13972           offset = 0;
13973           while (size--)
13974           {
13975             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13976             offset++;
13977           }
13978         }
13979
13980       freeAsmop (op, NULL, ic, TRUE);
13981     }
13982
13983   op = IC_LEFT (ic);
13984   if (op && IS_SYMOP (op))
13985     {
13986       aopOp (op, ic, FALSE, FALSE);
13987
13988       /* if the result is a bit */
13989       if (AOP_TYPE (op) == AOP_CRY)
13990         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13991       else
13992         {
13993           /* bit variables done */
13994           /* general case */
13995           size = AOP_SIZE (op);
13996           offset = 0;
13997           while (size--)
13998           {
13999             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
14000             offset++;
14001           }
14002         }
14003
14004       freeAsmop (op, NULL, ic, TRUE);
14005     }
14006 }
14007
14008 /*-----------------------------------------------------------------*/
14009 /* genCritical - generate code for start of a critical sequence    */
14010 /*-----------------------------------------------------------------*/
14011 static void
14012 genCritical (iCode *ic)
14013 {
14014   symbol *tlbl = newiTempLabel (NULL);
14015
14016   D (emitcode(";", "genCritical"));
14017
14018   if (IC_RESULT (ic))
14019     {
14020       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14021       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14022       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14023       aopPut (IC_RESULT (ic), zero, 0);
14024       emitLabel (tlbl);
14025       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14026     }
14027   else
14028     {
14029       emitcode ("setb", "c");
14030       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14031       emitcode ("clr", "c");
14032       emitLabel (tlbl);
14033       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14034     }
14035 }
14036
14037 /*-----------------------------------------------------------------*/
14038 /* genEndCritical - generate code for end of a critical sequence   */
14039 /*-----------------------------------------------------------------*/
14040 static void
14041 genEndCritical (iCode *ic)
14042 {
14043   D(emitcode(";     genEndCritical",""));
14044
14045   if (IC_RIGHT (ic))
14046     {
14047       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14048       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14049         {
14050           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14051           emitcode ("mov", "ea,c");
14052         }
14053       else
14054         {
14055           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14056           emitcode ("rrc", "a");
14057           emitcode ("mov", "ea,c");
14058         }
14059       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14060     }
14061   else
14062     {
14063       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14064       emitcode ("mov", "ea,c");
14065     }
14066 }
14067
14068
14069
14070 /*-----------------------------------------------------------------*/
14071 /* genBuiltIn - calls the appropriate function to  generating code */
14072 /* for a built in function                                         */
14073 /*-----------------------------------------------------------------*/
14074 static void genBuiltIn (iCode *ic)
14075 {
14076         operand *bi_parms[MAX_BUILTIN_ARGS];
14077         int nbi_parms;
14078         iCode *bi_iCode;
14079         symbol *bif;
14080
14081         /* get all the arguments for a built in function */
14082         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14083
14084         /* which function is it */
14085         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14086         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14087                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14088         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14089                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14090         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14091                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14092         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14093                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14094         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14095                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14096         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14097                 genInp(bi_iCode,nbi_parms,bi_parms);
14098         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14099                 genOutp(bi_iCode,nbi_parms,bi_parms);
14100         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14101                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14102                 /* JavaNative builtIns */
14103         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14104                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14105         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14106                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14107         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14108                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14109         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14110                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14111         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14112                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14113         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14114                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14115         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14116                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14117         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14118                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14119         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14120                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14121         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14122                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14123         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14124                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14125         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14126                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14127         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14128                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14129         } else if (strcmp(bif->name,"MM_Free")==0) {
14130                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14131         } else if (strcmp(bif->name,"MM_Deref")==0) {
14132                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14133         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14134                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14135         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14136                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14137         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14138                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14139         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14140                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14141         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14142                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14143         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14144                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14145         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14146                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14147         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14148                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14149         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14150                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14151         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14152                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14153         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14154                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14155         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14156                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14157         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14158                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14159         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14160                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14161         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14162                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14163         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14164                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14165         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14166                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14167         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14168                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14169         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14170                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14171         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14172                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14173         } else {
14174                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14175                 return ;
14176         }
14177         return ;
14178 }
14179
14180 /*-----------------------------------------------------------------*/
14181 /* gen390Code - generate code for Dallas 390 based controllers     */
14182 /*-----------------------------------------------------------------*/
14183 void
14184 gen390Code (iCode * lic)
14185 {
14186   iCode *ic;
14187   int cln = 0;
14188
14189   _G.currentFunc = NULL;
14190   lineHead = lineCurr = NULL;
14191   dptrn[1][0] = "dpl1";
14192   dptrn[1][1] = "dph1";
14193   dptrn[1][2] = "dpx1";
14194
14195   if (options.model == MODEL_FLAT24) {
14196     fReturnSizeDS390 = 5;
14197     fReturn = fReturn24;
14198   } else {
14199     fReturnSizeDS390 = 4;
14200     fReturn = fReturn16;
14201     options.stack10bit=0;
14202   }
14203 #if 1
14204   /* print the allocation information */
14205   if (allocInfo && currFunc)
14206     printAllocInfo (currFunc, codeOutBuf);
14207 #endif
14208   /* if debug information required */
14209   if (options.debug && currFunc)
14210     {
14211       debugFile->writeFunction (currFunc, lic);
14212     }
14213   /* stack pointer name */
14214   if (options.useXstack)
14215     spname = "_spx";
14216   else
14217     spname = "sp";
14218
14219
14220   for (ic = lic; ic; ic = ic->next)
14221     {
14222       _G.current_iCode = ic;
14223
14224       if (ic->lineno && cln != ic->lineno)
14225         {
14226           if (options.debug)
14227             {
14228               debugFile->writeCLine (ic);
14229             }
14230           if (!options.noCcodeInAsm) {
14231             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
14232                       printCLine(ic->filename, ic->lineno));
14233           }
14234           cln = ic->lineno;
14235         }
14236       if (options.iCodeInAsm) {
14237         char *iLine = printILine(ic);
14238         emitcode("", ";ic:%d: %s", ic->key, iLine);
14239         dbuf_free(iLine);
14240       }
14241       /* if the result is marked as
14242          spilt and rematerializable or code for
14243          this has already been generated then
14244          do nothing */
14245       if (resultRemat (ic) || ic->generated)
14246         continue;
14247
14248       /* depending on the operation */
14249       switch (ic->op)
14250         {
14251         case '!':
14252           genNot (ic);
14253           break;
14254
14255         case '~':
14256           genCpl (ic);
14257           break;
14258
14259         case UNARYMINUS:
14260           genUminus (ic);
14261           break;
14262
14263         case IPUSH:
14264           genIpush (ic);
14265           break;
14266
14267         case IPOP:
14268           /* IPOP happens only when trying to restore a
14269              spilt live range, if there is an ifx statement
14270              following this pop then the if statement might
14271              be using some of the registers being popped which
14272              would destory the contents of the register so
14273              we need to check for this condition and handle it */
14274           if (ic->next &&
14275               ic->next->op == IFX &&
14276               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14277             genIfx (ic->next, ic);
14278           else
14279             genIpop (ic);
14280           break;
14281
14282         case CALL:
14283           genCall (ic);
14284           break;
14285
14286         case PCALL:
14287           genPcall (ic);
14288           break;
14289
14290         case FUNCTION:
14291           genFunction (ic);
14292           break;
14293
14294         case ENDFUNCTION:
14295           genEndFunction (ic);
14296           break;
14297
14298         case RETURN:
14299           genRet (ic);
14300           break;
14301
14302         case LABEL:
14303           genLabel (ic);
14304           break;
14305
14306         case GOTO:
14307           genGoto (ic);
14308           break;
14309
14310         case '+':
14311           genPlus (ic);
14312           break;
14313
14314         case '-':
14315           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14316             genMinus (ic);
14317           break;
14318
14319         case '*':
14320           genMult (ic);
14321           break;
14322
14323         case '/':
14324           genDiv (ic);
14325           break;
14326
14327         case '%':
14328           genMod (ic);
14329           break;
14330
14331         case '>':
14332           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14333           break;
14334
14335         case '<':
14336           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14337           break;
14338
14339         case LE_OP:
14340         case GE_OP:
14341         case NE_OP:
14342
14343           /* note these two are xlated by algebraic equivalence
14344              during parsing SDCC.y */
14345           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14346                   "got '>=' or '<=' shouldn't have come here");
14347           break;
14348
14349         case EQ_OP:
14350           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14351           break;
14352
14353         case AND_OP:
14354           genAndOp (ic);
14355           break;
14356
14357         case OR_OP:
14358           genOrOp (ic);
14359           break;
14360
14361         case '^':
14362           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14363           break;
14364
14365         case '|':
14366           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14367           break;
14368
14369         case BITWISEAND:
14370           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14371           break;
14372
14373         case INLINEASM:
14374           genInline (ic);
14375           break;
14376
14377         case RRC:
14378           genRRC (ic);
14379           break;
14380
14381         case RLC:
14382           genRLC (ic);
14383           break;
14384
14385         case GETHBIT:
14386           genGetHbit (ic);
14387           break;
14388
14389         case LEFT_OP:
14390           genLeftShift (ic);
14391           break;
14392
14393         case RIGHT_OP:
14394           genRightShift (ic);
14395           break;
14396
14397         case GET_VALUE_AT_ADDRESS:
14398           genPointerGet (ic,
14399                          hasInc (IC_LEFT (ic), ic,
14400                                  getSize (operandType (IC_RESULT (ic)))));
14401           break;
14402
14403         case '=':
14404           if (POINTER_SET (ic))
14405             genPointerSet (ic,
14406                            hasInc (IC_RESULT (ic), ic,
14407                                    getSize (operandType (IC_RIGHT (ic)))));
14408           else
14409             genAssign (ic);
14410           break;
14411
14412         case IFX:
14413           genIfx (ic, NULL);
14414           break;
14415
14416         case ADDRESS_OF:
14417           genAddrOf (ic);
14418           break;
14419
14420         case JUMPTABLE:
14421           genJumpTab (ic);
14422           break;
14423
14424         case CAST:
14425           genCast (ic);
14426           break;
14427
14428         case RECEIVE:
14429           genReceive (ic);
14430           break;
14431
14432         case SEND:
14433           if (ic->builtinSEND)
14434             genBuiltIn(ic);
14435           else
14436             addSet (&_G.sendSet, ic);
14437           break;
14438
14439         case DUMMY_READ_VOLATILE:
14440           genDummyRead (ic);
14441           break;
14442
14443         case CRITICAL:
14444           genCritical (ic);
14445           break;
14446
14447         case ENDCRITICAL:
14448           genEndCritical (ic);
14449           break;
14450
14451         case SWAP:
14452           genSwap (ic);
14453           break;
14454
14455 #if 0 // obsolete, and buggy for != xdata
14456         case ARRAYINIT:
14457             genArrayInit(ic);
14458             break;
14459 #endif
14460
14461         default:
14462           ic = ic;
14463         }
14464     }
14465
14466
14467   /* now we are ready to call the
14468      peep hole optimizer */
14469   if (!options.nopeep)
14470     peepHole (&lineHead);
14471
14472   /* now do the actual printing */
14473   printLine (lineHead, codeOutBuf);
14474   return;
14475 }