* src/SDCCopt.c (killDeadCode): change iCode type to DUMMY_READ_VOLATILE
[fw/sdcc] / src / z80 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - Z80 specific code generator.
3      
4   Michael Hope <michaelh@juju.net.nz> 2000
5   Based on the mcs51 generator -
6       Sandeep Dutta . sandeep.dutta@usa.net (1998)
7    and -  Jean-Louis VERN.jlvern@writeme.com (1999)
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
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24   In other words, you are welcome to use, share and improve this program.
25   You are forbidden to forbid anyone else to use, share and improve
26   what you give them.   Help stamp out software-hoarding!
27
28 -------------------------------------------------------------------------*/
29
30 /*
31   Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
32                                        ticks dhry  size
33   Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34   Improved WORD push                    22784 144 19AE
35   With label1 on                        22694 144 197E
36   With label2 on                        22743 144 198A
37   With label3 on                        22776 144 1999
38   With label4 on                        22776 144 1999
39   With all 'label' on                   22661 144 196F
40   With loopInvariant on                 20919 156 19AB
41   With loopInduction on                 Breaks    198B
42   With all working on                   20796 158 196C
43   Slightly better genCmp(signed)        20597 159 195B
44   Better reg packing, first peephole    20038 163 1873
45   With assign packing                   19281 165 1849
46   5/3/00                                17741 185 17B6
47   With reg params for mul and div       16234 202 162D
48
49   1. Starting again at 3 Aug 01         34965  93 219C
50    No asm strings
51    Includes long mul/div in code
52   2. Optimised memcpy for acc use       32102 102 226B
53   3. Optimised strcpy for acc use       27819 117 2237
54   3a Optimised memcpy fun
55   4. Optimised strcmp fun               21999 149 2294
56   5. Optimised strcmp further           21660 151 228C
57   6. Optimised memcpy by unroling       20885 157 2201
58   7. After turning loop induction on    19862 165 236D
59   8. Same as 7 but with more info       
60   9. With asm optimised strings         17030 192 2223
61
62   10 and below are with asm strings off.
63
64   10 Mucho optimisations                13562 201 1FCC
65
66   Apparent advantage of turning on regparams:
67   1.  Cost of push
68         Decent case is push of a constant 
69           - ld hl,#n; push hl: (10+11)*nargs
70   2.  Cost of pull from stack
71         Using asm with ld hl, etc
72           - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
73             10+11+(7+6+7+6)*nargs
74   3.  Cost of fixing stack
75           - pop hl*nargs
76             10*nargs
77   
78   So cost is (10+11+7+6+7+10)*nargs+10+11 
79       = 51*nargs+21
80       = 123 for mul, div, strcmp, strcpy
81   Saving of (98298+32766+32766+32766)*123 = 24181308
82   At 192 d/s for 682411768t, speed up to 199.  Hmm.
83 */
84
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <ctype.h>
89
90 #if defined(__BORLANDC__) || defined(_MSC_VER)
91 #define STRCASECMP stricmp
92 #else
93 #define STRCASECMP strcasecmp
94 #endif
95
96 #include "z80.h"
97 #include "SDCCglobl.h"
98 #include "SDCCpeeph.h"
99 #include "gen.h"
100 #include "SDCCglue.h"
101 #include "newalloc.h"
102
103 /* This is the down and dirty file with all kinds of kludgy & hacky
104    stuff. This is what it is all about CODE GENERATION for a specific MCU.
105    Some of the routines may be reusable, will have to see */
106
107 /* Z80 calling convention description.
108    Parameters are passed right to left.  As the stack grows downwards,
109    the parameters are arranged in left to right in memory.
110    Parameters may be passed in the HL and DE registers with one
111    parameter per pair.
112    PENDING: What if the parameter is a long?
113    Everything is caller saves. i.e. the caller must save any registers
114    that it wants to preserve over the call.
115    GB: The return value is returned in DEHL.  DE is normally used as a
116    working register pair.  Caller saves allows it to be used for a
117    return value.
118    va args functions do not use register parameters.  All arguments
119    are passed on the stack.
120    IX is used as an index register to the top of the local variable
121    area.  ix-0 is the top most local variable.
122 */
123
124 enum 
125 {
126   /* Set to enable debugging trace statements in the output assembly code. */
127   DISABLE_DEBUG = 0
128 };
129
130 static char *_z80_return[] =
131 {"l", "h", "e", "d"};
132 static char *_gbz80_return[] =
133 {"e", "d", "l", "h"};
134 static char *_fReceive[] =
135   { "c", "b", "e", "d" };
136
137 static char **_fReturn;
138 static char **_fTmp;
139
140 extern FILE *codeOutFile;
141
142 enum
143   {
144     INT8MIN = -128,
145     INT8MAX = 127
146   };
147
148 /** Enum covering all the possible register pairs.
149  */
150 typedef enum
151   {
152     PAIR_INVALID,
153     PAIR_AF,
154     PAIR_BC,
155     PAIR_DE,
156     PAIR_HL,
157     PAIR_IY,
158     PAIR_IX,
159     NUM_PAIRS
160   } PAIR_ID;
161
162 static struct
163 {
164   const char *name;
165   const char *l;
166   const char *h;
167 } _pairs[NUM_PAIRS] = {
168   {    "??1", "?2", "?3" },
169   {    "af", "f", "a" },
170   {    "bc", "c", "b" },
171   {    "de", "e", "d" },
172   {    "hl", "l", "h" },
173   {    "iy", "iyl", "iyh" },
174   {    "ix", "ixl", "ixh" }
175 };
176
177 // PENDING
178 #define ACC_NAME        _pairs[PAIR_AF].h
179
180 enum 
181   {
182     LSB,
183     MSB16,
184     MSB24,
185     MSB32
186   };
187
188 /** Code generator persistent data.
189  */
190 static struct 
191 {
192   /** Used to optimised setting up of a pair by remebering what it
193       contains and adjusting instead of reloading where possible.
194   */
195   struct 
196   {
197     AOP_TYPE last_type;
198     const char *base;
199     int offset;
200   } pairs[NUM_PAIRS];
201   struct 
202   {
203     int last;
204     int pushed;
205     int param_offset;
206     int offset;
207     int pushedBC;
208     int pushedDE;
209   } stack;
210
211   struct
212   {
213     int pushedBC;
214     int pushedDE;
215   } calleeSaves;
216
217   bool omitFramePtr;
218   int frameId;
219   int receiveOffset;
220   bool flushStatics;
221   bool in_home;
222   const char *lastFunctionName;
223   iCode *current_iCode;
224   bool preserveCarry;
225   
226   set *sendSet;
227
228   struct
229   {
230     /** TRUE if the registers have already been saved. */
231     bool saved;
232   } saves;
233
234   struct 
235   {
236     lineNode *head;
237     lineNode *current;
238     int isInline;
239     int isDebug;
240     allocTrace trace;
241   } lines;
242
243   struct
244   {
245     allocTrace aops;
246   } trace;
247 } _G;
248
249 static const char *aopGet (asmop * aop, int offset, bool bit16);
250
251 static const char *aopNames[] = {
252   "AOP_INVALID",
253   "AOP_LIT",
254   "AOP_REG",
255   "AOP_DIR",
256   "AOP_SFR",
257   "AOP_STK",
258   "AOP_IMMD",
259   "AOP_STR",
260   "AOP_CRY",
261   "AOP_IY",
262   "AOP_HL",
263   "AOP_ACC",
264   "AOP_HLREG",
265   "AOP_SIMPLELIT",
266   "AOP_EXSTK",
267   "AOP_PAIRPT",
268   "AOP_DUMMY"
269 };
270
271 static bool
272 isLastUse (iCode *ic, operand *op)
273 {
274   bitVect *uses = bitVectCopy (OP_USES (op));
275
276   while (!bitVectIsZero (uses))
277     {
278       if (bitVectFirstBit (uses) == ic->key)
279         {
280           if (bitVectnBitsOn (uses) == 1)
281             {
282               return TRUE;
283             }
284           else
285             {
286               return FALSE;
287             }
288         }
289       bitVectUnSetBit (uses, bitVectFirstBit (uses));
290     }
291
292   return FALSE;
293 }
294
295 static PAIR_ID
296 _getTempPairId(void)
297 {
298   if (IS_GB)
299     {
300       return PAIR_DE;
301     }
302   else
303     {
304       return PAIR_HL;
305     }
306 }
307
308 static const char *
309 _getTempPairName(void)
310 {
311   return _pairs[_getTempPairId()].name;
312 }
313
314 static bool
315 isPairInUse (PAIR_ID id, iCode *ic)
316 {
317   if (id == PAIR_DE)
318     {
319       return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
320     }
321   else if (id == PAIR_BC)
322     {
323       return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
324     }
325   else
326     {
327       wassertl (0, "Only implemented for DE and BC");
328       return TRUE;
329     }
330 }
331
332 static bool
333 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
334 {
335   bitVect *rInUse;
336   
337   rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
338   
339   if (id == PAIR_DE)
340     {
341       return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
342     }
343   else
344     {
345       wassertl (0, "Only implemented for DE");
346       return TRUE;
347     }
348 }
349
350 static PAIR_ID
351 getFreePairId (iCode *ic)
352 {
353   if (!isPairInUse (PAIR_BC, ic))
354     {
355       return PAIR_BC;
356     }
357   else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
358     {
359       return PAIR_DE;
360     }
361   else
362     {
363       return PAIR_INVALID;
364     }
365 }         
366
367 static void
368 _tidyUp (char *buf)
369 {
370   /* Clean up the line so that it is 'prettier' */
371   if (strchr (buf, ':'))
372     {
373       /* Is a label - cant do anything */
374       return;
375     }
376   /* Change the first (and probably only) ' ' to a tab so
377      everything lines up.
378   */
379   while (*buf)
380     {
381       if (*buf == ' ')
382         {
383           *buf = '\t';
384           break;
385         }
386       buf++;
387     }
388 }
389
390 static lineNode *
391 _newLineNode (char *line)
392 {
393   lineNode *pl;
394
395   pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
396   pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
397
398   return pl;
399 }
400
401 static void
402 _vemit2 (const char *szFormat, va_list ap)
403 {
404   char buffer[INITIAL_INLINEASM];
405
406   tvsprintf (buffer, sizeof(buffer), szFormat, ap);
407
408   _tidyUp (buffer);
409   _G.lines.current = (_G.lines.current ?
410               connectLine (_G.lines.current, _newLineNode (buffer)) :
411               (_G.lines.head = _newLineNode (buffer)));
412
413   _G.lines.current->isInline = _G.lines.isInline;
414   _G.lines.current->isDebug = _G.lines.isDebug;
415   _G.lines.current->ic = _G.current_iCode;
416 }
417
418 static void
419 emit2 (const char *szFormat,...)
420 {
421   va_list ap;
422
423   va_start (ap, szFormat);
424
425   _vemit2 (szFormat, ap);
426
427   va_end (ap);
428 }
429
430 static void
431 emitDebug (const char *szFormat,...)
432 {
433   if (!DISABLE_DEBUG)
434     {
435       va_list ap;
436
437       va_start (ap, szFormat);
438
439       _vemit2 (szFormat, ap);
440
441       va_end (ap);
442     }
443 }
444
445 /*-----------------------------------------------------------------*/
446 /* emit2 - writes the code into a file : for now it is simple    */
447 /*-----------------------------------------------------------------*/
448 void
449 _emit2 (const char *inst, const char *fmt,...)
450 {
451   va_list ap;
452   char lb[INITIAL_INLINEASM];
453   char *lbp = lb;
454
455   va_start (ap, fmt);
456
457   if (*inst != '\0')
458     {
459       sprintf (lb, "%s\t", inst);
460       vsprintf (lb + (strlen (lb)), fmt, ap);
461     }
462   else
463     vsprintf (lb, fmt, ap);
464
465   while (isspace (*lbp))
466     lbp++;
467
468   if (lbp && *lbp)
469     {
470       _G.lines.current = (_G.lines.current ?
471                   connectLine (_G.lines.current, _newLineNode (lb)) :
472                   (_G.lines.head = _newLineNode (lb)));
473     }
474   _G.lines.current->isInline = _G.lines.isInline;
475   _G.lines.current->ic = _G.current_iCode;
476   va_end (ap);
477 }
478
479 static void
480 _emitMove(const char *to, const char *from)
481 {
482   if (STRCASECMP(to, from) != 0) 
483     {
484       emit2("ld %s,%s", to, from);
485     }
486   else 
487     {
488       // Optimise it out.
489       // Could leave this to the peephole, but sometimes the peephole is inhibited.
490     }
491 }
492
493 void
494 aopDump(const char *plabel, asmop *aop)
495 {
496   int i;
497   char regbuf[9];
498   char *rbp = regbuf;
499   
500   emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
501   switch (aop->type)
502     {
503     case AOP_EXSTK:
504     case AOP_STK:
505       emitDebug(";  aop_stk %d", aop->aopu.aop_stk);
506       break;
507     case AOP_REG:
508       for (i=aop->size-1;i>=0;i--)
509         *rbp++ = *(aop->aopu.aop_reg[i]->name);
510       *rbp = '\0';
511       emitDebug(";  reg = %s", regbuf);
512       break;
513     case AOP_PAIRPTR:
514       emitDebug(";  pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
515         
516     default:
517       /* No information. */
518       break;
519     }
520 }
521
522 static void
523 _moveA(const char *moveFrom)
524 {
525     // Let the peephole optimiser take care of redundent loads
526     _emitMove(ACC_NAME, moveFrom);
527 }
528
529 static void
530 _clearCarry(void)
531 {
532     emit2("xor a,a");
533 }
534
535 const char *
536 getPairName (asmop * aop)
537 {
538   if (aop->type == AOP_REG)
539     {
540       switch (aop->aopu.aop_reg[0]->rIdx)
541         {
542         case C_IDX:
543           return "bc";
544           break;
545         case E_IDX:
546           return "de";
547           break;
548         case L_IDX:
549           return "hl";
550           break;
551         }
552     }
553   else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
554     {
555       int i;
556       for (i = 0; i < NUM_PAIRS; i++)
557         {
558           if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
559             {
560               return _pairs[i].name;
561             }
562         }
563     }
564   wassertl (0, "Tried to get the pair name of something that isn't a pair");
565   return NULL;
566 }
567
568 static PAIR_ID
569 getPairId (asmop * aop)
570 {
571   if (aop->size == 2)
572     {
573       if (aop->type == AOP_REG)
574         {
575           if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
576             {
577               return PAIR_BC;
578             }
579           if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
580             {
581               return PAIR_DE;
582             }
583           if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
584             {
585               return PAIR_HL;
586             }
587         }
588       else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
589         {
590           int i;
591           for (i = 0; i < NUM_PAIRS; i++)
592             {
593               if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
594                 {
595                   return i;
596                 }
597             }
598         }
599     }
600   return PAIR_INVALID;
601 }
602
603 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
604 bool
605 isPair (asmop * aop)
606 {
607   return (getPairId (aop) != PAIR_INVALID);
608 }
609
610 /** Returns TRUE if the registers used in aop cannot be split into high
611     and low halves */
612 bool
613 isUnsplitable (asmop * aop)
614 {
615   switch (getPairId (aop))
616     {
617     case PAIR_IX:
618     case PAIR_IY:
619       return TRUE;
620     default:
621       return FALSE;
622     }
623   return FALSE;
624 }
625
626 bool
627 isPtrPair (asmop * aop)
628 {
629   PAIR_ID pairId = getPairId (aop);
630   switch (pairId)
631     {
632     case PAIR_HL:
633     case PAIR_IY:
634     case PAIR_IX:
635       return TRUE;
636     default:
637       return FALSE;
638     }
639 }
640
641 static void
642 spillPair (PAIR_ID pairId)
643 {
644   _G.pairs[pairId].last_type = AOP_INVALID;
645   _G.pairs[pairId].base = NULL;
646 }
647
648 /* Given a register name, spill the pair (if any) the register is part of */
649 static void
650 spillPairReg (const char *regname)
651 {      
652   if (strlen(regname)==1)
653     {
654       switch (*regname)
655         {
656         case 'h':
657         case 'l':
658           spillPair(PAIR_HL);
659           break;
660         case 'd':
661         case 'e':
662           spillPair(PAIR_DE);
663           break;
664         case 'b':
665         case 'c':
666           spillPair(PAIR_BC);
667           break;
668         }
669     }
670 }
671
672 /** Push a register pair onto the stack */
673 void
674 genPairPush (asmop * aop)
675 {
676   emit2 ("push %s", getPairName (aop));
677 }
678
679 static void
680 _push (PAIR_ID pairId)
681 {
682   emit2 ("push %s", _pairs[pairId].name);
683   _G.stack.pushed += 2;
684 }
685
686 static void
687 _pop (PAIR_ID pairId)
688 {
689   emit2 ("pop %s", _pairs[pairId].name);
690   _G.stack.pushed -= 2;
691   spillPair (pairId);
692 }
693
694 void
695 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
696 {
697   switch (dstPair)
698     {
699     case PAIR_IX:
700     case PAIR_IY:
701     case PAIR_AF:
702       _push(srcPair);
703       _pop(dstPair);
704       break;
705     case PAIR_BC:
706     case PAIR_DE:
707     case PAIR_HL:
708       if (srcPair == PAIR_IX || srcPair == PAIR_IY)
709         {
710           _push(srcPair);
711           _pop(dstPair);
712         }
713       else
714         {
715           emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
716           emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
717         }
718      default:
719        wassertl (0, "Tried to move a nonphysical pair");
720     }
721   _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
722   _G.pairs[dstPair].base = _G.pairs[srcPair].base;
723   _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
724 }
725
726
727 /*-----------------------------------------------------------------*/
728 /* newAsmop - creates a new asmOp                                  */
729 /*-----------------------------------------------------------------*/
730 static asmop *
731 newAsmop (short type)
732 {
733   asmop *aop;
734
735   aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
736   aop->type = type;
737   return aop;
738 }
739
740 /*-----------------------------------------------------------------*/
741 /* aopForSym - for a true symbol                                   */
742 /*-----------------------------------------------------------------*/
743 static asmop *
744 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
745 {
746   asmop *aop;
747   memmap *space;
748
749   wassert (ic);
750   wassert (sym);
751   wassert (sym->etype);
752
753   space = SPEC_OCLS (sym->etype);
754
755   /* if already has one */
756   if (sym->aop)
757     {
758       return sym->aop;
759     }
760
761   /* Assign depending on the storage class */
762   if (sym->onStack || sym->iaccess)
763     {
764       /* The pointer that is used depends on how big the offset is.
765          Normally everything is AOP_STK, but for offsets of < -128 or
766          > 127 on the Z80 an extended stack pointer is used.
767       */
768       if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
769         {
770           emitDebug ("; AOP_EXSTK for %s", sym->rname);
771           sym->aop = aop = newAsmop (AOP_EXSTK);
772         }
773       else
774         {
775           emitDebug ("; AOP_STK for %s", sym->rname);
776           sym->aop = aop = newAsmop (AOP_STK);
777         }
778
779       aop->size = getSize (sym->type);
780       aop->aopu.aop_stk = sym->stack;
781       return aop;
782     }
783
784   /* special case for a function */
785   if (IS_FUNC (sym->type))
786     {
787       sym->aop = aop = newAsmop (AOP_IMMD);
788       aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
789       aop->size = 2;
790       return aop;
791     }
792
793   if( IN_REGSP( space ))
794   { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
795     if (IS_GB)
796     {
797       /* if it is in direct space */
798       if( !requires_a )
799       {
800         sym->aop = aop = newAsmop (AOP_SFR);
801         aop->aopu.aop_dir = sym->rname;
802         aop->size = getSize (sym->type);
803           emitDebug ("; AOP_SFR for %s", sym->rname);
804         return aop;
805       }
806     }
807     else
808     { /*.p.t.20030716 adding SFR support to the Z80 port */
809       aop = newAsmop (AOP_SFR);
810       sym->aop          = aop;
811       aop->aopu.aop_dir = sym->rname;
812       aop->size         = getSize( sym->type );
813       aop->paged        = FUNC_REGBANK(sym->type);
814       aop->bcInUse      = isPairInUse( PAIR_BC, ic );
815       aop->deInUse      = isPairInUse( PAIR_DE, ic );
816       emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
817
818       return( aop );
819     }
820   }
821
822   /* only remaining is far space */
823   /* in which case DPTR gets the address */
824   if (IS_GB)
825     {
826       emitDebug ("; AOP_HL for %s", sym->rname);
827       sym->aop = aop = newAsmop (AOP_HL);
828     }
829   else
830     {
831       sym->aop = aop = newAsmop (AOP_IY);
832     }
833   aop->size = getSize (sym->type);
834   aop->aopu.aop_dir = sym->rname;
835
836   /* if it is in code space */
837   if (IN_CODESPACE (space))
838     aop->code = 1;
839
840   return aop;
841 }
842
843 /*-----------------------------------------------------------------*/
844 /* aopForRemat - rematerialzes an object                           */
845 /*-----------------------------------------------------------------*/
846 static asmop *
847 aopForRemat (symbol * sym)
848 {
849   char *s = buffer;
850   iCode *ic = sym->rematiCode;
851   asmop *aop = newAsmop (AOP_IMMD);
852
853   while (1)
854     {
855       /* if plus or minus print the right hand side */
856       if (ic->op == '+' || ic->op == '-')
857         {
858           /* PENDING: for re-target */
859           sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
860                    ic->op);
861           s += strlen (s);
862           ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
863           continue;
864         }
865       /* we reached the end */
866       sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
867       break;
868     }
869
870   aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
871   return aop;
872 }
873
874 /*-----------------------------------------------------------------*/
875 /* regsInCommon - two operands have some registers in common       */
876 /*-----------------------------------------------------------------*/
877 bool
878 regsInCommon (operand * op1, operand * op2)
879 {
880   symbol *sym1, *sym2;
881   int i;
882
883   /* if they have registers in common */
884   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
885     return FALSE;
886
887   sym1 = OP_SYMBOL (op1);
888   sym2 = OP_SYMBOL (op2);
889
890   if (sym1->nRegs == 0 || sym2->nRegs == 0)
891     return FALSE;
892
893   for (i = 0; i < sym1->nRegs; i++)
894     {
895       int j;
896       if (!sym1->regs[i])
897         continue;
898
899       for (j = 0; j < sym2->nRegs; j++)
900         {
901           if (!sym2->regs[j])
902             continue;
903
904           if (sym2->regs[j] == sym1->regs[i])
905             return TRUE;
906         }
907     }
908
909   return FALSE;
910 }
911
912 /*-----------------------------------------------------------------*/
913 /* operandsEqu - equivalent                                        */
914 /*-----------------------------------------------------------------*/
915 bool
916 operandsEqu (operand * op1, operand * op2)
917 {
918   symbol *sym1, *sym2;
919
920   /* if they not symbols */
921   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
922     return FALSE;
923
924   sym1 = OP_SYMBOL (op1);
925   sym2 = OP_SYMBOL (op2);
926
927   /* if both are itemps & one is spilt
928      and the other is not then false */
929   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
930       sym1->isspilt != sym2->isspilt)
931     return FALSE;
932
933   /* if they are the same */
934   if (sym1 == sym2)
935     return 1;
936
937   if (strcmp (sym1->rname, sym2->rname) == 0)
938     return 2;
939
940
941   /* if left is a tmp & right is not */
942   if (IS_ITEMP (op1) &&
943       !IS_ITEMP (op2) &&
944       sym1->isspilt &&
945       (sym1->usl.spillLoc == sym2))
946     return 3;
947
948   if (IS_ITEMP (op2) &&
949       !IS_ITEMP (op1) &&
950       sym2->isspilt &&
951       sym1->level > 0 &&
952       (sym2->usl.spillLoc == sym1))
953     return 4;
954
955   return FALSE;
956 }
957
958 /*-----------------------------------------------------------------*/
959 /* sameRegs - two asmops have the same registers                   */
960 /*-----------------------------------------------------------------*/
961 bool
962 sameRegs (asmop * aop1, asmop * aop2)
963 {
964   int i;
965
966   if (aop1->type == AOP_SFR ||
967       aop2->type == AOP_SFR)
968     return FALSE;
969
970   if (aop1 == aop2)
971     return TRUE;
972
973   if (aop1->type != AOP_REG ||
974       aop2->type != AOP_REG)
975     return FALSE;
976
977   if (aop1->size != aop2->size)
978     return FALSE;
979
980   for (i = 0; i < aop1->size; i++)
981     if (aop1->aopu.aop_reg[i] !=
982         aop2->aopu.aop_reg[i])
983       return FALSE;
984
985   return TRUE;
986 }
987
988 /*-----------------------------------------------------------------*/
989 /* aopOp - allocates an asmop for an operand  :                    */
990 /*-----------------------------------------------------------------*/
991 static void
992 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
993 {
994   asmop *aop;
995   symbol *sym;
996   int i;
997
998   if (!op)
999     return;
1000
1001   /* if this a literal */
1002   if (IS_OP_LITERAL (op))
1003     {
1004       op->aop = aop = newAsmop (AOP_LIT);
1005       aop->aopu.aop_lit = op->operand.valOperand;
1006       aop->size = getSize (operandType (op));
1007       return;
1008     }
1009
1010   /* if already has a asmop then continue */
1011   if (op->aop)
1012     {
1013       if (op->aop->type == AOP_SFR)
1014         {
1015           op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1016           op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1017         }
1018       return;
1019     }
1020
1021   /* if the underlying symbol has a aop */
1022   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1023     {
1024       op->aop = OP_SYMBOL (op)->aop;
1025       if (op->aop->type == AOP_SFR)
1026         {
1027           op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
1028           op->aop->deInUse = isPairInUse( PAIR_DE, ic );
1029         }
1030       return;
1031     }
1032
1033   /* if this is a true symbol */
1034   if (IS_TRUE_SYMOP (op))
1035     {
1036       op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1037       return;
1038     }
1039
1040   /* this is a temporary : this has
1041      only four choices :
1042      a) register
1043      b) spillocation
1044      c) rematerialize
1045      d) conditional
1046      e) can be a return use only */
1047
1048   sym = OP_SYMBOL (op);
1049
1050   /* if the type is a conditional */
1051   if (sym->regType == REG_CND)
1052     {
1053       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1054       aop->size = 0;
1055       return;
1056     }
1057
1058   /* if it is spilt then two situations
1059      a) is rematerialize
1060      b) has a spill location */
1061   if (sym->isspilt || sym->nRegs == 0)
1062     {
1063       /* rematerialize it NOW */
1064       if (sym->remat)
1065         {
1066           sym->aop = op->aop = aop =
1067             aopForRemat (sym);
1068           aop->size = getSize (sym->type);
1069           return;
1070         }
1071
1072       if (sym->ruonly)
1073         {
1074           int i;
1075           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1076           aop->size = getSize (sym->type);
1077           for (i = 0; i < 4; i++)
1078             aop->aopu.aop_str[i] = _fReturn[i];
1079           return;
1080         }
1081
1082       if (sym->accuse)
1083         {
1084           if (sym->accuse == ACCUSE_A)
1085             {
1086               aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1087               aop->size = getSize (sym->type);
1088               wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1089
1090               aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1091             }
1092           else if (sym->accuse == ACCUSE_SCRATCH)
1093             {
1094               aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1095               aop->size = getSize (sym->type);
1096               wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1097               aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1098               aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1099             }
1100           else if (sym->accuse == ACCUSE_IY)
1101             {
1102               aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1103               aop->size = getSize (sym->type);
1104               wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1105               aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1106               aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1107             }
1108           else 
1109               {
1110                   wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1111               }
1112           return;
1113         }
1114
1115       if (sym->usl.spillLoc)
1116         {
1117           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1118             {
1119               /* force a new aop if sizes differ */
1120               sym->usl.spillLoc->aop = NULL;
1121             }
1122           sym->aop = op->aop = aop =
1123                      aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1124           aop->size = getSize (sym->type);
1125           return;
1126         }
1127       
1128       /* else must be a dummy iTemp */
1129       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1130       aop->size = getSize (sym->type);
1131       return;
1132     }
1133
1134   /* must be in a register */
1135   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1136   aop->size = sym->nRegs;
1137   for (i = 0; i < sym->nRegs; i++)
1138     aop->aopu.aop_reg[i] = sym->regs[i];
1139 }
1140
1141 /*-----------------------------------------------------------------*/
1142 /* freeAsmop - free up the asmop given to an operand               */
1143 /*----------------------------------------------------------------*/
1144 static void
1145 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1146 {
1147   asmop *aop;
1148
1149   if (!op)
1150     aop = aaop;
1151   else
1152     aop = op->aop;
1153
1154   if (!aop)
1155     return;
1156
1157   if (aop->freed)
1158     goto dealloc;
1159
1160   aop->freed = 1;
1161
1162   if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1163     {
1164       _pop (aop->aopu.aop_pairId);
1165     }
1166
1167   if (getPairId (aop) == PAIR_HL)
1168     {
1169       spillPair (PAIR_HL);
1170     }
1171
1172 dealloc:
1173   /* all other cases just dealloc */
1174   if (op)
1175     {
1176       op->aop = NULL;
1177       if (IS_SYMOP (op))
1178         {
1179           OP_SYMBOL (op)->aop = NULL;
1180           /* if the symbol has a spill */
1181           if (SPIL_LOC (op))
1182             SPIL_LOC (op)->aop = NULL;
1183         }
1184     }
1185
1186 }
1187
1188 bool
1189 isLitWord (asmop * aop)
1190 {
1191   /*    if (aop->size != 2)
1192      return FALSE; */
1193   switch (aop->type)
1194     {
1195     case AOP_IMMD:
1196     case AOP_LIT:
1197       return TRUE;
1198     default:
1199       return FALSE;
1200     }
1201 }
1202
1203 char *
1204 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1205 {
1206   /* depending on type */
1207   switch (aop->type)
1208     {
1209     case AOP_HL:
1210     case AOP_IY:
1211     case AOP_IMMD:
1212       /* PENDING: for re-target */
1213       if (with_hash)
1214         {
1215           tsprintf (buffer, sizeof(buffer), 
1216                     "!hashedstr + %d", aop->aopu.aop_immd, offset);
1217         }
1218       else if (offset == 0)
1219         {
1220           tsprintf (buffer, sizeof(buffer),
1221                     "%s", aop->aopu.aop_immd);
1222         }
1223       else
1224         {
1225           tsprintf (buffer, sizeof(buffer), 
1226                     "%s + %d", aop->aopu.aop_immd, offset);
1227         }
1228       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1229
1230     case AOP_LIT:
1231       {
1232         value *val = aop->aopu.aop_lit;
1233         /* if it is a float then it gets tricky */
1234         /* otherwise it is fairly simple */
1235         if (!IS_FLOAT (val->type))
1236           {
1237             unsigned long v = (unsigned long) floatFromVal (val);
1238
1239             if (offset == 2)
1240               {
1241                 v >>= 16;
1242               }
1243             else if (offset == 0)
1244               {
1245                 // OK
1246               }
1247             else 
1248               {
1249                 wassertl(0, "Encountered an invalid offset while fetching a literal");
1250               }
1251
1252             if (with_hash)
1253               tsprintf (buffer, sizeof(buffer), "!immedword", v);
1254             else
1255               tsprintf (buffer, sizeof(buffer), "!constword", v);
1256
1257             return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1258           }
1259         else
1260           {
1261             union {
1262               float f;
1263               unsigned char c[4];
1264             }
1265             fl;
1266             unsigned int i;
1267
1268             /* it is type float */
1269             fl.f = (float) floatFromVal (val);
1270
1271 #ifdef WORDS_BIGENDIAN
1272             i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1273 #else
1274             i = fl.c[offset] | (fl.c[offset+1]<<8);
1275 #endif
1276             if (with_hash)
1277               tsprintf (buffer, sizeof(buffer), "!immedword", i);
1278             else
1279               tsprintf (buffer, sizeof(buffer), "!constword", i);
1280
1281             return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1282           }
1283       }
1284     default:
1285       return NULL;
1286     }
1287 }
1288
1289 char *
1290 aopGetWord (asmop * aop, int offset)
1291 {
1292   return aopGetLitWordLong (aop, offset, TRUE);
1293 }
1294
1295 bool
1296 isPtr (const char *s)
1297 {
1298   if (!strcmp (s, "hl"))
1299     return TRUE;
1300   if (!strcmp (s, "ix"))
1301     return TRUE;
1302   if (!strcmp (s, "iy"))
1303     return TRUE;
1304   return FALSE;
1305 }
1306
1307 static void
1308 adjustPair (const char *pair, int *pold, int new)
1309 {
1310   wassert (pair);
1311
1312   while (*pold < new)
1313     {
1314       emit2 ("inc %s", pair);
1315       (*pold)++;
1316     }
1317   while (*pold > new)
1318     {
1319       emit2 ("dec %s", pair);
1320       (*pold)--;
1321     }
1322 }
1323
1324 static void
1325 spillCached (void)
1326 {
1327   spillPair (PAIR_HL);
1328   spillPair (PAIR_IY);
1329 }
1330
1331 static bool
1332 requiresHL (asmop * aop)
1333 {
1334   switch (aop->type)
1335     {
1336     case AOP_IY:
1337     case AOP_HL:
1338     case AOP_STK:
1339     case AOP_EXSTK:
1340     case AOP_HLREG:
1341       return TRUE;
1342     default:
1343       return FALSE;
1344     }
1345 }
1346
1347 static void
1348 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1349 {
1350   const char *l, *base;
1351   const char *pair = _pairs[pairId].name;
1352   l = aopGetLitWordLong (left, offset, FALSE);
1353   base = aopGetLitWordLong (left, 0, FALSE);
1354   wassert (l && pair && base);
1355
1356   if (isPtr (pair))
1357     {
1358       if (pairId == PAIR_HL || pairId == PAIR_IY)
1359         {
1360           if (_G.pairs[pairId].last_type == left->type)
1361             {
1362               if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1363                 {
1364                   if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1365                     {
1366                       adjustPair (pair, &_G.pairs[pairId].offset, offset);
1367                       return;
1368                     }
1369                   if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1370                     {
1371                       return;
1372                     }
1373                 }
1374             }
1375         }
1376       _G.pairs[pairId].last_type = left->type;
1377       _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1378       _G.pairs[pairId].offset = offset;
1379     }
1380   /* Both a lit on the right and a true symbol on the left */
1381   emit2 ("ld %s,!hashedstr", pair, l);
1382 }
1383
1384 static PAIR_ID
1385 makeFreePairId (iCode *ic, bool *pisUsed)
1386 {
1387   *pisUsed = FALSE;
1388
1389   if (ic != NULL)
1390     {
1391       if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1392         {
1393           return PAIR_BC;
1394         }
1395       else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1396         {
1397           return PAIR_DE;
1398         }
1399       else
1400         {
1401           *pisUsed = TRUE;
1402           return PAIR_HL;
1403         }
1404     }
1405   else
1406     {
1407       *pisUsed = TRUE;
1408       return PAIR_HL;
1409     }
1410 }
1411
1412 static void
1413 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1414 {
1415     /* if this is remateriazable */
1416     if (isLitWord (aop)) {
1417         fetchLitPair (pairId, aop, offset);
1418     }
1419     else 
1420       {
1421         if (getPairId (aop) == pairId)
1422           {
1423             /* Do nothing */
1424           }
1425         /* we need to get it byte by byte */
1426         else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1427             aopGet (aop, offset, FALSE);
1428             switch (aop->size - offset) {
1429             case 1:
1430                 emit2 ("ld l,!*hl");
1431                 emit2 ("ld h,!immedbyte", 0);
1432                             break;
1433             case 2:
1434               // PENDING: Requires that you are only fetching two bytes.
1435             case 4:
1436                 emit2 ("!ldahli");
1437                 emit2 ("ld h,!*hl");
1438                 emit2 ("ld l,a");
1439                 break;
1440             default:
1441               wassertl (0, "Attempted to fetch too much data into HL");
1442               break;
1443             }
1444         }
1445         else if (IS_Z80 && aop->type == AOP_IY) {
1446             /* Instead of fetching relative to IY, just grab directly
1447                from the address IY refers to */
1448             char *l = aopGetLitWordLong (aop, offset, FALSE);
1449             wassert (l);
1450             emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1451
1452             if (aop->size < 2) {
1453                 emit2("ld %s,!zero", _pairs[pairId].h);
1454             }
1455         }
1456         else if (pairId == PAIR_IY)
1457           {
1458             if (isPair (aop))
1459               {
1460                 emit2 ("push %s", _pairs[getPairId(aop)].name);
1461                 emit2 ("pop iy");
1462               }
1463             else
1464               {
1465                 bool isUsed;
1466                 PAIR_ID id = makeFreePairId (ic, &isUsed);
1467                 if (isUsed)
1468                   _push (id);
1469                 /* Can't load into parts, so load into HL then exchange. */
1470                 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1471                 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1472                 emit2 ("push %s", _pairs[id].name);
1473                 emit2 ("pop iy");
1474                 if (isUsed)
1475                   _pop (id);
1476               }
1477           }
1478         else if (isUnsplitable(aop))
1479           {
1480             emit2("push %s", _pairs[getPairId(aop)].name);
1481             emit2("pop %s", _pairs[pairId].name);
1482           }
1483         else 
1484           {
1485             emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1486             emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1487           }
1488         /* PENDING: check? */
1489         if (pairId == PAIR_HL)
1490             spillPair (PAIR_HL);
1491     }
1492 }
1493
1494 static void
1495 fetchPair (PAIR_ID pairId, asmop * aop)
1496 {
1497   fetchPairLong (pairId, aop, NULL, 0);
1498 }
1499
1500 static void
1501 fetchHL (asmop * aop)
1502 {
1503   fetchPair (PAIR_HL, aop);
1504 }
1505
1506 static void
1507 setupPairFromSP (PAIR_ID id, int offset)
1508 {
1509   wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1510
1511   if (_G.preserveCarry)
1512     {
1513       _push (PAIR_AF);
1514       offset += 2;
1515     }
1516   
1517   if (offset < INT8MIN || offset > INT8MAX)
1518     {
1519       emit2 ("ld hl,!immedword", offset);
1520       emit2 ("add hl,sp");
1521     }
1522   else
1523     {
1524           emit2 ("!ldahlsp", offset);
1525     }
1526
1527   if (_G.preserveCarry)
1528     {
1529       _pop (PAIR_AF);
1530       offset -= 2;
1531     }
1532 }
1533
1534 static void
1535 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1536 {
1537   switch (aop->type)
1538     {
1539     case AOP_IY:
1540       wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1541       fetchLitPair (pairId, aop, 0);
1542       break;
1543
1544     case AOP_HL:
1545       wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1546       
1547       fetchLitPair (pairId, aop, offset);
1548       _G.pairs[pairId].offset = offset;
1549       break;
1550
1551     case AOP_EXSTK:
1552       wassertl (IS_Z80, "Only the Z80 has an extended stack");
1553       wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1554
1555       {
1556         int offset = aop->aopu.aop_stk + _G.stack.offset;
1557
1558         if (_G.pairs[pairId].last_type == aop->type &&
1559             _G.pairs[pairId].offset == offset)
1560           {
1561             /* Already setup */
1562           }
1563         else
1564           {
1565             /* PENDING: Do this better. */
1566             if (_G.preserveCarry)
1567               _push (PAIR_AF);
1568             sprintf (buffer, "%d", offset + _G.stack.pushed);
1569             emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1570             emit2 ("add %s,sp", _pairs[pairId].name);
1571             _G.pairs[pairId].last_type = aop->type;
1572             _G.pairs[pairId].offset = offset;
1573             if (_G.preserveCarry)
1574               _pop (PAIR_AF);
1575           }
1576       }
1577       break;
1578
1579     case AOP_STK:
1580       {
1581         /* Doesnt include _G.stack.pushed */
1582         int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1583
1584         if (aop->aopu.aop_stk > 0)
1585           {
1586             abso += _G.stack.param_offset;
1587           }
1588         assert (pairId == PAIR_HL);
1589         /* In some cases we can still inc or dec hl */
1590         if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1591           {
1592             adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1593           }
1594         else
1595           {
1596             setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1597           }
1598         _G.pairs[pairId].offset = abso;
1599         break;
1600       }
1601
1602     case AOP_PAIRPTR:
1603       if (pairId != aop->aopu.aop_pairId)
1604         genMovePairPair(aop->aopu.aop_pairId, pairId);
1605       adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1606       break;
1607       
1608     default:
1609       wassert (0);
1610     }
1611   _G.pairs[pairId].last_type = aop->type;
1612 }
1613
1614 static void
1615 emitLabel (int key)
1616 {
1617   emit2 ("!tlabeldef", key);
1618   spillCached ();
1619 }
1620
1621 /*-----------------------------------------------------------------*/
1622 /* aopGet - for fetching value of the aop                          */
1623 /*-----------------------------------------------------------------*/
1624 static const char *
1625 aopGet (asmop * aop, int offset, bool bit16)
1626 {
1627   // char *s = buffer;
1628
1629   /* offset is greater than size then zero */
1630   /* PENDING: this seems a bit screwed in some pointer cases. */
1631   if (offset > (aop->size - 1) &&
1632       aop->type != AOP_LIT) 
1633     {
1634       tsprintf (buffer, sizeof(buffer), "!zero");
1635       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1636     }
1637
1638   /* depending on type */
1639   switch (aop->type)
1640     {
1641     case AOP_DUMMY:
1642       tsprintf (buffer, sizeof(buffer), "!zero");
1643       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1644     
1645     case AOP_IMMD:
1646       /* PENDING: re-target */
1647       if (bit16)
1648         tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1649       else
1650         switch (offset)
1651           {
1652           case 2:
1653             tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1654             break;
1655           case 1:
1656             tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1657             break;
1658           case 0:
1659             tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1660             break;
1661           default:
1662             wassertl (0, "Fetching from beyond the limits of an immediate value.");
1663           }
1664
1665       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1666
1667     case AOP_DIR:
1668       wassert (IS_GB);
1669       emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1670       SNPRINTF (buffer, sizeof(buffer), "a");
1671
1672       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1673
1674     case AOP_SFR:
1675       if( IS_GB )
1676       {
1677         // wassert (IS_GB);
1678         emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1679         SNPRINTF (buffer, sizeof(buffer), "a");
1680
1681         return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1682       }
1683       else
1684       { /*.p.t.20030716 handling for i/o port read access for Z80 */
1685         if( aop->paged )
1686         { /* banked mode */
1687           if( aop->bcInUse )  emit2( "push bc" );
1688
1689           emit2( "ld bc,#%s", aop->aopu.aop_dir );
1690           emit2( "in a,(c)" );
1691
1692           if( aop->bcInUse )
1693             emit2( "pop bc" );
1694           else
1695             spillPair (PAIR_BC);
1696         }
1697         else if( z80_opts.port_mode == 180 )
1698         { /* z180 in0/out0 mode */
1699           emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1700         }
1701         else
1702         { /* 8 bit mode */
1703           emit2( "in a,(%s)", aop->aopu.aop_dir );
1704         }
1705         
1706         SNPRINTF (buffer, sizeof(buffer), "a");
1707
1708         return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1709       }
1710
1711     case AOP_REG:
1712       return aop->aopu.aop_reg[offset]->name;
1713
1714     case AOP_HL:
1715       wassert (IS_GB);
1716       setupPair (PAIR_HL, aop, offset);
1717       tsprintf (buffer, sizeof(buffer), "!*hl");
1718
1719       return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1720
1721     case AOP_IY:
1722       wassert (IS_Z80);
1723       setupPair (PAIR_IY, aop, offset);
1724       tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1725
1726       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1727
1728     case AOP_EXSTK:
1729       wassert (IS_Z80);
1730       setupPair (PAIR_IY, aop, offset);
1731       tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1732
1733       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1734
1735     case AOP_STK:
1736       if (IS_GB)
1737         {
1738           setupPair (PAIR_HL, aop, offset);
1739           tsprintf (buffer, sizeof(buffer), "!*hl");
1740         }
1741       else
1742         {
1743           if (aop->aopu.aop_stk >= 0)
1744             offset += _G.stack.param_offset;
1745           tsprintf (buffer, sizeof(buffer),
1746                     "!*ixx", aop->aopu.aop_stk + offset);
1747         }
1748
1749       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1750
1751     case AOP_CRY:
1752       wassertl (0, "Tried to fetch from a bit variable");
1753
1754     case AOP_ACC:
1755       if (!offset)
1756         {
1757           return "a";
1758         }
1759       else
1760         {
1761           tsprintf(buffer, sizeof(buffer), "!zero");
1762           return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1763         }
1764
1765     case AOP_HLREG:
1766       wassert (offset < 2);
1767       return aop->aopu.aop_str[offset];
1768
1769     case AOP_LIT:
1770       return aopLiteral (aop->aopu.aop_lit, offset);
1771
1772     case AOP_SIMPLELIT:
1773       {
1774         unsigned long v = aop->aopu.aop_simplelit;
1775         
1776         v >>= (offset * 8);
1777         tsprintf (buffer, sizeof(buffer), 
1778                   "!immedbyte", (unsigned int) v & 0xff);
1779         
1780         return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1781       }
1782     case AOP_STR:
1783       aop->coff = offset;
1784       return aop->aopu.aop_str[offset];
1785
1786     case AOP_PAIRPTR:
1787       setupPair (aop->aopu.aop_pairId, aop, offset);
1788       if (aop->aopu.aop_pairId==PAIR_IX)
1789         SNPRINTF (buffer, sizeof(buffer), 
1790                   "!*ixx", 0);
1791       else if (aop->aopu.aop_pairId==PAIR_IY)
1792         SNPRINTF (buffer, sizeof(buffer), 
1793                   "!*iyx", 0);
1794       else
1795         SNPRINTF (buffer, sizeof(buffer), 
1796                   "(%s)", _pairs[aop->aopu.aop_pairId].name);
1797
1798       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1799
1800     default:
1801       break;
1802     }
1803   wassertl (0, "aopget got unsupported aop->type");
1804   exit (0);
1805 }
1806
1807 bool
1808 isRegString (const char *s)
1809 {
1810   if (!strcmp (s, "b") ||
1811       !strcmp (s, "c") ||
1812       !strcmp (s, "d") ||
1813       !strcmp (s, "e") ||
1814       !strcmp (s, "a") ||
1815       !strcmp (s, "h") ||
1816       !strcmp (s, "l"))
1817     return TRUE;
1818   return FALSE;
1819 }
1820
1821 bool
1822 isConstant (const char *s)
1823 {
1824   /* This is a bit of a hack... */
1825   return (*s == '#' || *s == '$');
1826 }
1827
1828 bool
1829 canAssignToPtr (const char *s)
1830 {
1831   if (isRegString (s))
1832     return TRUE;
1833   if (isConstant (s))
1834     return TRUE;
1835   return FALSE;
1836 }
1837
1838 /*-----------------------------------------------------------------*/
1839 /* aopPut - puts a string for a aop                                */
1840 /*-----------------------------------------------------------------*/
1841 static void
1842 aopPut (asmop * aop, const char *s, int offset)
1843 {
1844   char buffer2[256];
1845
1846   if (aop->size && offset > (aop->size - 1))
1847     {
1848       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1849               "aopPut got offset > aop->size");
1850       exit (0);
1851     }
1852
1853   // PENDING
1854   tsprintf(buffer2, sizeof(buffer2), s);
1855   s = buffer2;
1856
1857   /* will assign value to value */
1858   /* depending on where it is ofcourse */
1859   switch (aop->type)
1860     {
1861     case AOP_DUMMY:
1862       _moveA (s);  /* in case s is volatile */
1863       break;
1864       
1865     case AOP_DIR:
1866       /* Direct.  Hmmm. */
1867       wassert (IS_GB);
1868       if (strcmp (s, "a"))
1869         emit2 ("ld a,%s", s);
1870       emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1871       break;
1872
1873     case AOP_SFR:
1874       if( IS_GB )
1875       {
1876         //  wassert (IS_GB);
1877         if (strcmp (s, "a"))
1878           emit2 ("ld a,%s", s);
1879         emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1880       }
1881       else
1882       { /*.p.t.20030716 handling for i/o port read access for Z80 */
1883         if( aop->paged )
1884         { /* banked mode */
1885           if( aop->bcInUse )  emit2( "push bc" );
1886
1887           emit2( "ld bc,#%s", aop->aopu.aop_dir );
1888
1889           if(( s[0] == '#'    ) /* immediate number */
1890            ||( s[0] == '('    ) /* indirect register (ix or iy ??)*/
1891            ||( isdigit( s[0] )))/* indirect register with offset (ix or iy ??)*/
1892           {
1893             emit2( "ld a,%s", s );
1894             emit2( "out (c),a"  );
1895           }
1896           else
1897           {
1898             emit2( "out (c),%s", s );
1899           }
1900         
1901           if( aop->bcInUse )
1902             emit2( "pop bc"    );
1903           else
1904             spillPair (PAIR_BC);
1905         }
1906         else if( z80_opts.port_mode == 180 )
1907         { /* z180 in0/out0 mode */
1908           emit2( "ld a,%s", s );
1909           emit2( "out0 (%s),a", aop->aopu.aop_dir );
1910         }
1911         else
1912         { /* 8 bit mode */
1913           emit2( "ld a,%s", s );
1914           emit2( "out (%s),a", aop->aopu.aop_dir );
1915         }
1916       }
1917       break;
1918
1919     case AOP_REG:
1920       if (!strcmp (s, "!*hl"))
1921         emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1922       else
1923         emit2 ("ld %s,%s",
1924                aop->aopu.aop_reg[offset]->name, s);
1925       spillPairReg(aop->aopu.aop_reg[offset]->name);
1926       break;
1927
1928     case AOP_IY:
1929       wassert (!IS_GB);
1930       if (!canAssignToPtr (s))
1931         {
1932           emit2 ("ld a,%s", s);
1933           setupPair (PAIR_IY, aop, offset);
1934           emit2 ("ld !*iyx,a", offset);
1935         }
1936       else
1937         {
1938           setupPair (PAIR_IY, aop, offset);
1939           emit2 ("ld !*iyx,%s", offset, s);
1940         }
1941       break;
1942
1943     case AOP_HL:
1944       wassert (IS_GB);
1945       /* PENDING: for re-target */
1946       if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1947         {
1948           emit2 ("ld a,!*hl");
1949           s = "a";
1950         }
1951       setupPair (PAIR_HL, aop, offset);
1952
1953       emit2 ("ld !*hl,%s", s);
1954       break;
1955
1956     case AOP_EXSTK:
1957       wassert (!IS_GB);
1958       if (!canAssignToPtr (s))
1959         {
1960           emit2 ("ld a,%s", s);
1961           setupPair (PAIR_IY, aop, offset);
1962           emit2 ("ld !*iyx,a", offset);
1963         }
1964       else
1965         {
1966           setupPair (PAIR_IY, aop, offset);
1967           emit2 ("ld !*iyx,%s", offset, s);
1968         }
1969       break;
1970
1971     case AOP_STK:
1972       if (IS_GB)
1973         {
1974           /* PENDING: re-target */
1975           if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1976             {
1977               emit2 ("ld a,!*hl");
1978               s = "a";
1979             }
1980           setupPair (PAIR_HL, aop, offset);
1981           if (!canAssignToPtr (s))
1982             {
1983               emit2 ("ld a,%s", s);
1984               emit2 ("ld !*hl,a");
1985             }
1986           else
1987             emit2 ("ld !*hl,%s", s);
1988         }
1989       else
1990         {
1991           if (aop->aopu.aop_stk >= 0)
1992             offset += _G.stack.param_offset;
1993           if (!canAssignToPtr (s))
1994             {
1995               emit2 ("ld a,%s", s);
1996               emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1997             }
1998           else
1999             {
2000               emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
2001             }
2002         }
2003       break;
2004
2005     case AOP_CRY:
2006       /* if bit variable */
2007       if (!aop->aopu.aop_dir)
2008         {
2009           emit2 ("ld a,!zero");
2010           emit2 ("rla");
2011         }
2012       else
2013         {
2014           /* In bit space but not in C - cant happen */
2015           wassertl (0, "Tried to write into a bit variable");
2016         }
2017       break;
2018
2019     case AOP_STR:
2020       aop->coff = offset;
2021       if (strcmp (aop->aopu.aop_str[offset], s))
2022         {
2023           emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2024         }
2025       spillPairReg(aop->aopu.aop_str[offset]);
2026       break;
2027
2028     case AOP_ACC:
2029       aop->coff = offset;
2030       if (!offset && (strcmp (s, "acc") == 0))
2031         break;
2032       if (offset > 0)
2033         {
2034           wassertl (0, "Tried to access past the end of A");
2035         }
2036       else
2037         {
2038           if (strcmp (aop->aopu.aop_str[offset], s))
2039             {
2040               emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2041               spillPairReg(aop->aopu.aop_str[offset]);
2042             }
2043         }
2044       break;
2045
2046     case AOP_HLREG:
2047       wassert (offset < 2);
2048       emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2049       spillPairReg(aop->aopu.aop_str[offset]);
2050       break;
2051
2052     case AOP_PAIRPTR:
2053       setupPair (aop->aopu.aop_pairId, aop, offset);
2054       if (aop->aopu.aop_pairId==PAIR_IX)
2055         emit2 ("ld !*ixx,%s", 0, s);
2056       else if (aop->aopu.aop_pairId==PAIR_IY)
2057         emit2 ("ld !*ixy,%s", 0, s);
2058       else
2059         emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2060       break;
2061
2062     default:
2063       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2064               "aopPut got unsupported aop->type");
2065       exit (0);
2066     }
2067 }
2068
2069 #define AOP(op) op->aop
2070 #define AOP_TYPE(op) AOP(op)->type
2071 #define AOP_SIZE(op) AOP(op)->size
2072 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2073
2074 static void
2075 commitPair (asmop * aop, PAIR_ID id)
2076 {
2077   /* PENDING: Verify this. */
2078   if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2079     {
2080       emit2 ("ld a,l");
2081       emit2 ("ld d,h");
2082       aopPut (aop, "a", 0);
2083       aopPut (aop, "d", 1);
2084     }
2085   else
2086     {
2087       /* Special cases */
2088       if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2089         {
2090           char *l = aopGetLitWordLong (aop, 0, FALSE);
2091           wassert (l);
2092
2093           emit2 ("ld (%s),%s", l, _pairs[id].name);
2094         }
2095       else
2096         {
2097           aopPut (aop, _pairs[id].l, 0);
2098           aopPut (aop, _pairs[id].h, 1);
2099         }
2100     }
2101 }
2102
2103 /*-----------------------------------------------------------------*/
2104 /* getDataSize - get the operand data size                         */
2105 /*-----------------------------------------------------------------*/
2106 int
2107 getDataSize (operand * op)
2108 {
2109   int size;
2110   size = AOP_SIZE (op);
2111   if (size == 3)
2112     {
2113       /* pointer */
2114       wassertl (0, "Somehow got a three byte data pointer");
2115     }
2116   return size;
2117 }
2118
2119 /*-----------------------------------------------------------------*/
2120 /* movLeft2Result - move byte from left to result                  */
2121 /*-----------------------------------------------------------------*/
2122 static void
2123 movLeft2Result (operand * left, int offl,
2124                 operand * result, int offr, int sign)
2125 {
2126   const char *l;
2127
2128   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2129     {
2130       l = aopGet (AOP (left), offl, FALSE);
2131
2132       if (!sign)
2133         {
2134           aopPut (AOP (result), l, offr);
2135         }
2136       else
2137         {
2138           if (getDataSize (left) == offl + 1)
2139             {
2140               emit2 ("ld a,%s", l);
2141               aopPut (AOP (result), "a", offr);
2142             }
2143         }
2144     }
2145 }
2146
2147 static void
2148 movLeft2ResultLong (operand * left, int offl,
2149                 operand * result, int offr, int sign,
2150                 int size)
2151 {
2152   if (size == 1)
2153     {
2154       movLeft2Result (left, offl, result, offr, sign);
2155     }
2156   else
2157     {
2158       wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2159       wassertl (size == 2, "Only implemented for two bytes or one");
2160
2161       if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2162         {
2163           emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2164           emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2165           emit2 ("ld l,a");
2166           spillPair (PAIR_HL);
2167         }
2168       else if ( getPairId ( AOP (result)) == PAIR_IY)
2169         {
2170           PAIR_ID id = getPairId (AOP (left));
2171           if (id != PAIR_INVALID) 
2172             {
2173               emit2("push %s", _pairs[id].name);
2174               emit2("pop iy");
2175             }
2176           else
2177             {
2178               /* PENDING */
2179               emitDebug("Error");
2180             }
2181         }
2182       else
2183         {
2184           movLeft2Result (left, offl, result, offr, sign);
2185           movLeft2Result (left, offl+1, result, offr+1, sign);
2186         }
2187     }
2188 }
2189
2190 /** Put Acc into a register set
2191  */
2192 void
2193 outAcc (operand * result)
2194 {
2195   int size, offset;
2196   size = getDataSize (result);
2197   if (size)
2198     {
2199       aopPut (AOP (result), "a", 0);
2200       size--;
2201       offset = 1;
2202       /* unsigned or positive */
2203       while (size--)
2204         {
2205           aopPut (AOP (result), "!zero", offset++);
2206         }
2207     }
2208 }
2209
2210 /** Take the value in carry and put it into a register
2211  */
2212 void
2213 outBitCLong (operand * result, bool swap_sense)
2214 {
2215   /* if the result is bit */
2216   if (AOP_TYPE (result) == AOP_CRY)
2217     {
2218       wassertl (0, "Tried to write carry to a bit");
2219     }
2220   else
2221     {
2222       emit2 ("ld a,!zero");
2223       emit2 ("rla");
2224       if (swap_sense)
2225         emit2 ("xor a,!immedbyte", 1);
2226       outAcc (result);
2227     }
2228 }
2229
2230 void
2231 outBitC (operand * result)
2232 {
2233   outBitCLong (result, FALSE);
2234 }
2235
2236 /*-----------------------------------------------------------------*/
2237 /* toBoolean - emit code for orl a,operator(sizeop)                */
2238 /*-----------------------------------------------------------------*/
2239 void
2240 _toBoolean (operand * oper)
2241 {
2242   int size = AOP_SIZE (oper);
2243   int offset = 0;
2244   if (size > 1)
2245     {
2246       emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2247       size--;
2248       while (size--)
2249         emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2250     }
2251   else
2252     {
2253       if (AOP (oper)->type != AOP_ACC)
2254         {
2255           _clearCarry();
2256           emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2257         }
2258     }
2259 }
2260
2261
2262 /*-----------------------------------------------------------------*/
2263 /* genNot - generate code for ! operation                          */
2264 /*-----------------------------------------------------------------*/
2265 static void
2266 genNot (iCode * ic)
2267 {
2268
2269   /* assign asmOps to operand & result */
2270   aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2271   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2272
2273   /* if in bit space then a special case */
2274   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2275     {
2276       wassertl (0, "Tried to negate a bit");
2277     }
2278
2279   _toBoolean (IC_LEFT (ic));
2280
2281   /* Not of A:
2282      If A == 0, !A = 1
2283      else A = 0
2284      So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2285   emit2 ("sub a,!one");
2286   outBitC (IC_RESULT (ic));
2287
2288   /* release the aops */
2289   freeAsmop (IC_LEFT (ic), NULL, ic);
2290   freeAsmop (IC_RESULT (ic), NULL, ic);
2291 }
2292
2293 /*-----------------------------------------------------------------*/
2294 /* genCpl - generate code for complement                           */
2295 /*-----------------------------------------------------------------*/
2296 static void
2297 genCpl (iCode * ic)
2298 {
2299   int offset = 0;
2300   int size;
2301
2302
2303   /* assign asmOps to operand & result */
2304   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2305   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2306
2307   /* if both are in bit space then
2308      a special case */
2309   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2310       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2311     {
2312       wassertl (0, "Left and the result are in bit space");
2313     }
2314
2315   size = AOP_SIZE (IC_RESULT (ic));
2316   while (size--)
2317     {
2318       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2319       _moveA (l);
2320       emit2("cpl");
2321       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2322     }
2323
2324   /* release the aops */
2325   freeAsmop (IC_LEFT (ic), NULL, ic);
2326   freeAsmop (IC_RESULT (ic), NULL, ic);
2327 }
2328
2329 static void
2330 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2331 {
2332   /* Logic:
2333        ld de,right.lw
2334        setup hl to left
2335        de = hl - de
2336        push flags
2337        store de into result
2338        pop flags
2339        ld de,right.hw
2340        setup hl
2341        de = hl -de
2342        store de into result
2343   */
2344   const char *first = isAdd ? "add" : "sub";
2345   const char *later = isAdd ? "adc" : "sbc";
2346
2347   wassertl (IS_GB, "Code is only relevent to the gbz80");
2348   wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2349
2350   fetchPair (PAIR_DE, left);
2351
2352   emit2 ("ld a,e");
2353   emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2354   emit2 ("ld e,a");
2355   emit2 ("ld a,d");
2356   emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2357
2358   _push (PAIR_AF);
2359   aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2360   aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2361
2362   fetchPairLong (PAIR_DE, left, NULL, MSB24);
2363   aopGet (right, MSB24, FALSE);
2364
2365   _pop (PAIR_AF);
2366   emit2 ("ld a,e");
2367   emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2368   emit2 ("ld e,a");
2369   emit2 ("ld a,d");
2370   emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2371
2372   aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2373   aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2374 }
2375
2376 static void
2377 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2378 {
2379   _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2380 }
2381
2382 /*-----------------------------------------------------------------*/
2383 /* genUminusFloat - unary minus for floating points                */
2384 /*-----------------------------------------------------------------*/
2385 static void
2386 genUminusFloat (operand * op, operand * result)
2387 {
2388   int size, offset = 0;
2389
2390   emitDebug("; genUminusFloat");
2391
2392   /* for this we just need to flip the
2393      first it then copy the rest in place */
2394   size = AOP_SIZE (op) - 1;
2395
2396   _moveA(aopGet (AOP (op), MSB32, FALSE));
2397
2398   emit2("xor a,!immedbyte", 0x80);
2399   aopPut (AOP (result), "a", MSB32);
2400
2401   while (size--)
2402     {
2403       aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2404       offset++;
2405     }
2406 }
2407
2408 /*-----------------------------------------------------------------*/
2409 /* genUminus - unary minus code generation                         */
2410 /*-----------------------------------------------------------------*/
2411 static void
2412 genUminus (iCode * ic)
2413 {
2414   int offset, size;
2415   sym_link *optype, *rtype;
2416
2417   /* assign asmops */
2418   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2419   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2420
2421   /* if both in bit space then special
2422      case */
2423   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2424       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2425     {
2426       wassertl (0, "Left and right are in bit space");
2427       goto release;
2428     }
2429
2430   optype = operandType (IC_LEFT (ic));
2431   rtype = operandType (IC_RESULT (ic));
2432
2433   /* if float then do float stuff */
2434   if (IS_FLOAT (optype))
2435     {
2436       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2437       goto release;
2438     }
2439
2440   /* otherwise subtract from zero */
2441   size = AOP_SIZE (IC_LEFT (ic));
2442
2443   if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2444     {
2445       /* Create a new asmop with value zero */
2446       asmop *azero = newAsmop (AOP_SIMPLELIT);
2447       azero->aopu.aop_simplelit = 0;
2448       azero->size = size;
2449       _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2450       goto release;
2451     }
2452
2453   offset = 0;
2454   _clearCarry();
2455   while (size--)
2456     {
2457       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2458       emit2 ("ld a,!zero");
2459       emit2 ("sbc a,%s", l);
2460       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2461     }
2462
2463   /* if any remaining bytes in the result */
2464   /* we just need to propagate the sign   */
2465   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2466     {
2467       emit2 ("rlc a");
2468       emit2 ("sbc a,a");
2469       while (size--)
2470         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2471     }
2472
2473 release:
2474   /* release the aops */
2475   freeAsmop (IC_LEFT (ic), NULL, ic);
2476   freeAsmop (IC_RESULT (ic), NULL, ic);
2477 }
2478
2479 /*-----------------------------------------------------------------*/
2480 /* assignResultValue -               */
2481 /*-----------------------------------------------------------------*/
2482 void
2483 assignResultValue (operand * oper)
2484 {
2485   int size = AOP_SIZE (oper);
2486   bool topInA = 0;
2487
2488   wassertl (size <= 4, "Got a result that is bigger than four bytes");
2489   topInA = requiresHL (AOP (oper));
2490
2491   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2492     {
2493       /* We do it the hard way here. */
2494       _push (PAIR_HL);
2495       aopPut (AOP (oper), _fReturn[0], 0);
2496       aopPut (AOP (oper), _fReturn[1], 1);
2497       _pop (PAIR_DE);
2498       aopPut (AOP (oper), _fReturn[0], 2);
2499       aopPut (AOP (oper), _fReturn[1], 3);
2500     }
2501   else
2502     {
2503       while (size--)
2504         {
2505           aopPut (AOP (oper), _fReturn[size], size);
2506         }
2507     }
2508 }
2509
2510 /** Simple restore that doesn't take into account what is used in the
2511     return.
2512 */
2513 static void
2514 _restoreRegsAfterCall(void)
2515 {
2516   if (_G.stack.pushedDE)
2517     {
2518       _pop ( PAIR_DE);
2519       _G.stack.pushedDE = FALSE;
2520     }
2521   if (_G.stack.pushedBC)
2522     {
2523       _pop ( PAIR_BC);
2524       _G.stack.pushedBC = FALSE;
2525     }
2526   _G.saves.saved = FALSE;
2527 }
2528
2529 static void
2530 _saveRegsForCall(iCode *ic, int sendSetSize)
2531 {
2532   /* Rules:
2533       o Stack parameters are pushed before this function enters
2534       o DE and BC may be used in this function.
2535       o HL and DE may be used to return the result.
2536       o HL and DE may be used to send variables.
2537       o DE and BC may be used to store the result value.
2538       o HL may be used in computing the sent value of DE
2539       o The iPushes for other parameters occur before any addSets
2540
2541      Logic: (to be run inside the first iPush or if none, before sending)
2542       o Compute if DE and/or BC are in use over the call
2543       o Compute if DE is used in the send set
2544       o Compute if DE and/or BC are used to hold the result value
2545       o If (DE is used, or in the send set) and is not used in the result, push.
2546       o If BC is used and is not in the result, push
2547       o 
2548       o If DE is used in the send set, fetch
2549       o If HL is used in the send set, fetch
2550       o Call
2551       o ...
2552   */
2553   if (_G.saves.saved == FALSE) {
2554     bool deInUse, bcInUse;
2555     bool deSending;
2556     bool bcInRet = FALSE, deInRet = FALSE;
2557     bitVect *rInUse;
2558
2559     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), 
2560                             z80_rUmaskForOp (IC_RESULT(ic)));
2561
2562     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2563     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2564
2565     deSending = (sendSetSize > 1);
2566
2567     emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2568
2569     if (bcInUse && bcInRet == FALSE) {
2570       _push(PAIR_BC);
2571       _G.stack.pushedBC = TRUE;
2572     }
2573     if (deInUse && deInRet == FALSE) {
2574       _push(PAIR_DE);
2575       _G.stack.pushedDE = TRUE;
2576     }
2577
2578     _G.saves.saved = TRUE;
2579   }
2580   else {
2581     /* Already saved. */
2582   }
2583 }
2584
2585 /*-----------------------------------------------------------------*/
2586 /* genIpush - genrate code for pushing this gets a little complex  */
2587 /*-----------------------------------------------------------------*/
2588 static void
2589 genIpush (iCode * ic)
2590 {
2591   int size, offset = 0;
2592   const char *l;
2593
2594   /* if this is not a parm push : ie. it is spill push
2595      and spill push is always done on the local stack */
2596   if (!ic->parmPush)
2597     {
2598       wassertl(0, "Encountered an unsupported spill push.");
2599       return;
2600     }
2601
2602   if (_G.saves.saved == FALSE) {
2603     /* Caller saves, and this is the first iPush. */
2604     /* Scan ahead until we find the function that we are pushing parameters to.
2605        Count the number of addSets on the way to figure out what registers
2606        are used in the send set.
2607     */
2608     int nAddSets = 0;
2609     iCode *walk = ic->next;
2610     
2611     while (walk) {
2612       if (walk->op == SEND) {
2613         nAddSets++;
2614       }
2615       else if (walk->op == CALL || walk->op == PCALL) {
2616         /* Found it. */
2617         break;
2618       }
2619       else {
2620         /* Keep looking. */
2621       }
2622       walk = walk->next;
2623     }
2624     _saveRegsForCall(walk, nAddSets);
2625   }
2626   else {
2627     /* Already saved by another iPush. */
2628   }
2629
2630   /* then do the push */
2631   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2632
2633   size = AOP_SIZE (IC_LEFT (ic));
2634
2635   if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2636     {
2637       _G.stack.pushed += 2;
2638       emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2639     }
2640   else
2641     {
2642       if (size == 2)
2643         {
2644           fetchHL (AOP (IC_LEFT (ic)));
2645           emit2 ("push hl");
2646           spillPair (PAIR_HL);
2647           _G.stack.pushed += 2;
2648           goto release;
2649         }
2650       if (size == 4)
2651         {
2652           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2653           emit2 ("push hl");
2654           spillPair (PAIR_HL);
2655           _G.stack.pushed += 2;
2656           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2657           emit2 ("push hl");
2658           spillPair (PAIR_HL);
2659           _G.stack.pushed += 2;
2660           goto release;
2661         }
2662       offset = size;
2663       while (size--)
2664         {
2665           if (AOP (IC_LEFT (ic))->type == AOP_IY)
2666             {
2667               char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2668               wassert (l);
2669               emit2 ("ld a,(%s)", l);
2670             }
2671           else
2672             {
2673               l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2674               emit2 ("ld a,%s", l);
2675             }
2676           emit2 ("push af");
2677           emit2 ("inc sp");
2678           _G.stack.pushed++;
2679         }
2680     }
2681 release:
2682   freeAsmop (IC_LEFT (ic), NULL, ic);
2683 }
2684
2685 /*-----------------------------------------------------------------*/
2686 /* genIpop - recover the registers: can happen only for spilling   */
2687 /*-----------------------------------------------------------------*/
2688 static void
2689 genIpop (iCode * ic)
2690 {
2691   int size, offset;
2692
2693
2694   /* if the temp was not pushed then */
2695   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2696     return;
2697
2698   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2699   size = AOP_SIZE (IC_LEFT (ic));
2700   offset = (size - 1);
2701   if (isPair (AOP (IC_LEFT (ic))))
2702     {
2703       emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2704     }
2705   else
2706     {
2707       while (size--)
2708         {
2709           emit2 ("dec sp");
2710           emit2 ("pop hl");
2711           spillPair (PAIR_HL);
2712           aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2713         }
2714     }
2715
2716   freeAsmop (IC_LEFT (ic), NULL, ic);
2717 }
2718
2719 /* This is quite unfortunate */
2720 static void
2721 setArea (int inHome)
2722 {
2723   /*
2724     static int lastArea = 0;
2725
2726      if (_G.in_home != inHome) {
2727      if (inHome) {
2728      const char *sz = port->mem.code_name;
2729      port->mem.code_name = "HOME";
2730      emit2("!area", CODE_NAME);
2731      port->mem.code_name = sz;
2732      }
2733      else
2734      emit2("!area", CODE_NAME); */
2735   _G.in_home = inHome;
2736   //    }
2737 }
2738
2739 static bool
2740 isInHome (void)
2741 {
2742   return _G.in_home;
2743 }
2744
2745 static int
2746 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2747 {
2748   int ret = 0;
2749   asmop *aop;
2750   symbol *sym = OP_SYMBOL (op);
2751
2752   if (sym->isspilt || sym->nRegs == 0)
2753     return 0;
2754
2755   aopOp (op, ic, FALSE, FALSE);
2756
2757   aop = AOP (op);
2758   if (aop->type == AOP_REG)
2759     {
2760       int i;
2761       for (i = 0; i < aop->size; i++)
2762         {
2763           if (pairId == PAIR_DE)
2764             {
2765               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2766               if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2767                 ret++;
2768               if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2769                 ret++;
2770             }
2771           else if (pairId == PAIR_BC)
2772             {
2773               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2774               if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2775                 ret++;
2776               if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2777                 ret++;
2778             }
2779           else
2780             {
2781               wassert (0);
2782             }
2783         }
2784     }
2785
2786   freeAsmop (IC_LEFT (ic), NULL, ic);
2787   return ret;
2788 }
2789
2790 /** Emit the code for a call statement
2791  */
2792 static void
2793 emitCall (iCode * ic, bool ispcall)
2794 {
2795   bool bInRet, cInRet, dInRet, eInRet;
2796   sym_link *dtype = operandType (IC_LEFT (ic));
2797
2798   /* if caller saves & we have not saved then */
2799   if (!ic->regsSaved)
2800     {
2801       /* PENDING */
2802     }
2803
2804   _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2805
2806   /* if send set is not empty then assign */
2807   if (_G.sendSet)
2808     {
2809       iCode *sic;
2810       int send = 0;
2811       int nSend = elementsInSet(_G.sendSet);
2812       bool swapped = FALSE;
2813
2814       int _z80_sendOrder[] = {
2815         PAIR_BC, PAIR_DE
2816       };
2817
2818       if (nSend > 1) {
2819         /* Check if the parameters are swapped.  If so route through hl instead. */
2820         wassertl (nSend == 2, "Pedantic check.  Code only checks for the two send items case.");
2821
2822         sic = setFirstItem(_G.sendSet);
2823         sic = setNextItem(_G.sendSet);
2824
2825         if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2826           /* The second send value is loaded from one the one that holds the first
2827              send, i.e. it is overwritten. */
2828           /* Cache the first in HL, and load the second from HL instead. */
2829           emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2830           emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2831
2832           swapped = TRUE;
2833         }
2834       }
2835
2836       for (sic = setFirstItem (_G.sendSet); sic;
2837            sic = setNextItem (_G.sendSet))
2838         {
2839           int size;
2840           aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2841
2842           size = AOP_SIZE (IC_LEFT (sic));
2843           wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2844           wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2845
2846           // PENDING: Mild hack
2847           if (swapped == TRUE && send == 1) {
2848             if (size > 1) {
2849               emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2850             }
2851             else {
2852               emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2853             }
2854             emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2855           }
2856           else {
2857             fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2858           }
2859
2860           send++;
2861           freeAsmop (IC_LEFT (sic), NULL, sic);
2862         }
2863       _G.sendSet = NULL;
2864     }
2865
2866   if (ispcall)
2867     {
2868       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2869         {
2870           werror (W_INDIR_BANKED);
2871         }
2872       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2873
2874       if (isLitWord (AOP (IC_LEFT (ic))))
2875         {
2876           emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2877         }
2878       else
2879         {
2880           symbol *rlbl = newiTempLabel (NULL);
2881           spillPair (PAIR_HL);
2882           emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2883           emit2 ("push hl");
2884           _G.stack.pushed += 2;
2885
2886           fetchHL (AOP (IC_LEFT (ic)));
2887           emit2 ("jp !*hl");
2888           emit2 ("!tlabeldef", (rlbl->key + 100));
2889           _G.stack.pushed -= 2;
2890         }
2891       freeAsmop (IC_LEFT (ic), NULL, ic);
2892     }
2893   else
2894     {
2895       char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2896       OP_SYMBOL (IC_LEFT (ic))->rname :
2897       OP_SYMBOL (IC_LEFT (ic))->name;
2898       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2899         {
2900           emit2 ("call banked_call");
2901           emit2 ("!dws", name);
2902           emit2 ("!dw !bankimmeds", name);
2903         }
2904       else
2905         {
2906           /* make the call */
2907           emit2 ("call %s", name);
2908         }
2909     }
2910   spillCached ();
2911
2912   /* Mark the regsiters as restored. */
2913   _G.saves.saved = FALSE;
2914
2915   /* if we need assign a result value */
2916   if ((IS_ITEMP (IC_RESULT (ic)) &&
2917        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2918         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2919       IS_TRUE_SYMOP (IC_RESULT (ic)))
2920     {
2921
2922       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2923
2924       assignResultValue (IC_RESULT (ic));
2925
2926       freeAsmop (IC_RESULT (ic), NULL, ic);
2927     }
2928
2929   /* adjust the stack for parameters if required */
2930   if (ic->parmBytes)
2931     {
2932       int i = ic->parmBytes;
2933
2934       _G.stack.pushed -= i;
2935       if (IS_GB)
2936         {
2937           emit2 ("!ldaspsp", i);
2938         }
2939       else
2940         {
2941           spillCached ();
2942           if (i > 8)
2943             {
2944               emit2 ("ld iy,!immedword", i);
2945               emit2 ("add iy,sp");
2946               emit2 ("ld sp,iy");
2947             }
2948           else
2949             {
2950               while (i > 1)
2951                 {
2952                   emit2 ("pop af");
2953                   i -= 2;
2954                 }
2955               if (i)
2956                 {
2957                   emit2 ("inc sp");
2958                 }
2959             }
2960         }
2961     }
2962
2963   spillCached ();
2964   if (IC_RESULT (ic))
2965     {
2966       bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2967       bInRet = bitVectBitValue(result, B_IDX);
2968       cInRet = bitVectBitValue(result, C_IDX);
2969       dInRet = bitVectBitValue(result, D_IDX);
2970       eInRet = bitVectBitValue(result, E_IDX);
2971     }
2972   else
2973     {
2974       bInRet = FALSE;
2975       cInRet = FALSE;
2976       dInRet = FALSE;
2977       eInRet = FALSE;
2978     }
2979
2980   if (_G.stack.pushedDE) 
2981     {
2982       if (dInRet && eInRet)
2983         {
2984           wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2985         }
2986       else if (dInRet)
2987         {
2988           /* Only restore E */
2989           emit2 ("ld a,d");
2990           _pop (PAIR_DE);
2991           emit2 ("ld d,a");
2992         }
2993       else if (eInRet)
2994         {
2995           /* Only restore D */
2996           _pop (PAIR_AF);
2997           emit2 ("ld d,a");
2998         }
2999       else
3000         {
3001           _pop (PAIR_DE);
3002         }
3003       _G.stack.pushedDE = FALSE;
3004     }
3005   
3006   if (_G.stack.pushedBC) 
3007     {
3008       if (bInRet && cInRet)
3009         {
3010           wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3011         }
3012       else if (bInRet)
3013         {
3014           /* Only restore C */
3015           emit2 ("ld a,b");
3016           _pop (PAIR_BC);
3017           emit2 ("ld b,a");
3018         }
3019       else if (cInRet)
3020         {
3021           /* Only restore B */
3022           _pop (PAIR_AF);
3023           emit2 ("ld b,a");
3024         }
3025       else
3026         {
3027           _pop (PAIR_BC);
3028         }
3029       _G.stack.pushedBC = FALSE;
3030     }
3031 }
3032
3033 /*-----------------------------------------------------------------*/
3034 /* genCall - generates a call statement                            */
3035 /*-----------------------------------------------------------------*/
3036 static void
3037 genCall (iCode * ic)
3038 {
3039   emitCall (ic, FALSE);
3040 }
3041
3042 /*-----------------------------------------------------------------*/
3043 /* genPcall - generates a call by pointer statement                */
3044 /*-----------------------------------------------------------------*/
3045 static void
3046 genPcall (iCode * ic)
3047 {
3048   emitCall (ic, TRUE);
3049 }
3050
3051 /*-----------------------------------------------------------------*/
3052 /* resultRemat - result  is rematerializable                       */
3053 /*-----------------------------------------------------------------*/
3054 static int
3055 resultRemat (iCode * ic)
3056 {
3057   if (SKIP_IC (ic) || ic->op == IFX)
3058     return 0;
3059
3060   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3061     {
3062       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3063       if (sym->remat && !POINTER_SET (ic))
3064         return 1;
3065     }
3066
3067   return 0;
3068 }
3069
3070 extern set *publics;
3071
3072 /*-----------------------------------------------------------------*/
3073 /* genFunction - generated code for function entry                 */
3074 /*-----------------------------------------------------------------*/
3075 static void
3076 genFunction (iCode * ic)
3077 {
3078   bool stackParm;
3079   
3080   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3081   sym_link *ftype;
3082
3083   bool bcInUse = FALSE;
3084   bool deInUse = FALSE;
3085
3086   setArea (IFFUNC_NONBANKED (sym->type));
3087
3088   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
3089      else.
3090   */
3091   _G.receiveOffset = 0;
3092
3093   /* Record the last function name for debugging. */
3094   _G.lastFunctionName = sym->rname;
3095   
3096   /* Create the function header */
3097   emit2 ("!functionheader", sym->name);
3098   sprintf (buffer, "%s_start", sym->rname);
3099   emit2 ("!labeldef", buffer);
3100   emit2 ("!functionlabeldef", sym->rname);
3101
3102   if (options.profile) 
3103     {
3104       emit2 ("!profileenter");
3105     }
3106
3107   ftype = operandType (IC_LEFT (ic));
3108
3109   /* if critical function then turn interrupts off */
3110   if (IFFUNC_ISCRITICAL (ftype))
3111     emit2 ("!di");
3112
3113   /* if this is an interrupt service routine then save all potentially used registers. */
3114   if (IFFUNC_ISISR (sym->type))
3115     {
3116       emit2 ("!pusha");
3117     }
3118
3119   /* PENDING: callee-save etc */
3120
3121   _G.stack.param_offset = 0;
3122
3123   if (z80_opts.calleeSavesBC)
3124     {
3125       bcInUse = TRUE;
3126     }
3127
3128   /* Detect which registers are used. */
3129   if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3130     {
3131       int i;
3132       for (i = 0; i < sym->regsUsed->size; i++)
3133         {
3134           if (bitVectBitValue (sym->regsUsed, i))
3135             {
3136               switch (i)
3137                 {
3138                 case C_IDX:
3139                 case B_IDX:
3140                   bcInUse = TRUE;
3141                   break;
3142                 case D_IDX:
3143                 case E_IDX:
3144                   if (IS_Z80) {
3145                     deInUse = TRUE;
3146                   }
3147                   else {
3148                     /* Other systems use DE as a temporary. */
3149                   }
3150                   break;
3151                 }
3152             }
3153         }
3154     }
3155
3156   if (bcInUse) 
3157     {
3158       emit2 ("push bc");
3159       _G.stack.param_offset += 2;
3160     }
3161
3162   _G.calleeSaves.pushedBC = bcInUse;
3163
3164   if (deInUse)
3165     {
3166       emit2 ("push de");
3167       _G.stack.param_offset += 2;
3168     }
3169
3170   _G.calleeSaves.pushedDE = deInUse;
3171
3172   /* adjust the stack for the function */
3173   _G.stack.last = sym->stack;
3174   
3175   stackParm = FALSE;
3176   for (sym = setFirstItem (istack->syms); sym;
3177        sym = setNextItem (istack->syms))
3178     {
3179       if (sym->_isparm && !IS_REGPARM (sym->etype))
3180         {
3181           stackParm = TRUE;
3182           break;
3183         }
3184     }
3185   sym = OP_SYMBOL (IC_LEFT (ic));
3186   
3187   _G.omitFramePtr = options.ommitFramePtr;
3188   if (IS_Z80 && !stackParm && !sym->stack)
3189     {
3190       /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3191       /* the above !sym->stack condition can be removed. -- EEP       */
3192       if (sym->stack)
3193         emit2 ("!ldaspsp", -sym->stack);
3194       _G.omitFramePtr = TRUE;
3195     }
3196   else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3197     emit2 ("!enterxl", sym->stack);
3198   else if (sym->stack)
3199     emit2 ("!enterx", sym->stack);
3200   else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3201     emit2 ("!enter");
3202
3203   _G.stack.offset = sym->stack;
3204 }
3205
3206 /*-----------------------------------------------------------------*/
3207 /* genEndFunction - generates epilogue for functions               */
3208 /*-----------------------------------------------------------------*/
3209 static void
3210 genEndFunction (iCode * ic)
3211 {
3212   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3213
3214   if (IFFUNC_ISISR (sym->type))
3215     {
3216       wassertl (0, "Tried to close an interrupt support function");
3217     }
3218   else
3219     {
3220       if (IFFUNC_ISCRITICAL (sym->type))
3221         emit2 ("!ei");
3222
3223       /* PENDING: calleeSave */
3224
3225       if (IS_Z80 && _G.omitFramePtr)
3226         {
3227           if (_G.stack.offset)
3228             emit2 ("!ldaspsp", _G.stack.offset);
3229         }
3230       else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3231         {
3232           emit2 ("!leavexl", _G.stack.offset);
3233         }
3234       else if (_G.stack.offset)
3235         {
3236           emit2 ("!leavex", _G.stack.offset);
3237         }
3238       else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3239         {
3240           emit2 ("!leave");
3241         }
3242
3243       if (_G.calleeSaves.pushedDE) 
3244         {
3245           emit2 ("pop de");
3246           _G.calleeSaves.pushedDE = FALSE;
3247         }
3248
3249       if (_G.calleeSaves.pushedBC) 
3250         {
3251           emit2 ("pop bc");
3252           _G.calleeSaves.pushedBC = FALSE;
3253         }
3254
3255       if (options.profile) 
3256         {
3257           emit2 ("!profileexit");
3258         }
3259
3260
3261       if (options.debug && currFunc)
3262         {
3263           _G.lines.isDebug = 1;
3264           sprintf (buffer, "C$%s$%d$%d$%d",
3265                     FileBaseName (ic->filename), currFunc->lastLine,
3266                     ic->level, ic->block);
3267           emit2 ("!labeldef", buffer);
3268           if (IS_STATIC (currFunc->etype))
3269             sprintf (buffer, "XF%s$%s$0$0", moduleName, currFunc->name);
3270           else
3271             sprintf (buffer, "XG$%s$0$0", currFunc->name);
3272           emit2 ("!labeldef", buffer);
3273           _G.lines.isDebug = 0;
3274         }
3275       
3276       /* Both banked and non-banked just ret */
3277       emit2 ("ret");
3278
3279       sprintf (buffer, "%s_end", sym->rname);
3280       emit2 ("!labeldef", buffer);
3281     }
3282   _G.flushStatics = 1;
3283   _G.stack.pushed = 0;
3284   _G.stack.offset = 0;
3285 }
3286
3287 /*-----------------------------------------------------------------*/
3288 /* genRet - generate code for return statement                     */
3289 /*-----------------------------------------------------------------*/
3290 static void
3291 genRet (iCode * ic)
3292 {
3293     const char *l;
3294   /* Errk.  This is a hack until I can figure out how
3295      to cause dehl to spill on a call */
3296   int size, offset = 0;
3297
3298   /* if we have no return value then
3299      just generate the "ret" */
3300   if (!IC_LEFT (ic))
3301     goto jumpret;
3302
3303   /* we have something to return then
3304      move the return value into place */
3305   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3306   size = AOP_SIZE (IC_LEFT (ic));
3307
3308   aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3309
3310   #if 0  
3311   if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3312     {
3313       if (IS_GB)
3314         {
3315           emit2 ("ld de,%s", l);
3316         }
3317       else
3318         {
3319           emit2 ("ld hl,%s", l);
3320         }
3321     }
3322   #endif
3323   if (size==2)
3324     {
3325       fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3326     }
3327   else
3328     {
3329       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3330         {
3331           fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3332           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3333         }
3334       else
3335         {
3336           while (size--)
3337             {
3338               l = aopGet (AOP (IC_LEFT (ic)), offset,
3339                           FALSE);
3340               if (strcmp (_fReturn[offset], l))
3341                 emit2 ("ld %s,%s", _fReturn[offset], l);
3342               offset++;
3343             }
3344         }
3345     }
3346   freeAsmop (IC_LEFT (ic), NULL, ic);
3347
3348 jumpret:
3349   /* generate a jump to the return label
3350      if the next is not the return statement */
3351   if (!(ic->next && ic->next->op == LABEL &&
3352         IC_LABEL (ic->next) == returnLabel))
3353
3354     emit2 ("jp !tlabel", returnLabel->key + 100);
3355 }
3356
3357 /*-----------------------------------------------------------------*/
3358 /* genLabel - generates a label                                    */
3359 /*-----------------------------------------------------------------*/
3360 static void
3361 genLabel (iCode * ic)
3362 {
3363   /* special case never generate */
3364   if (IC_LABEL (ic) == entryLabel)
3365     return;
3366
3367   emitLabel (IC_LABEL (ic)->key + 100);
3368 }
3369
3370 /*-----------------------------------------------------------------*/
3371 /* genGoto - generates a ljmp                                      */
3372 /*-----------------------------------------------------------------*/
3373 static void
3374 genGoto (iCode * ic)
3375 {
3376   emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3377 }
3378
3379 /*-----------------------------------------------------------------*/
3380 /* genPlusIncr :- does addition with increment if possible         */
3381 /*-----------------------------------------------------------------*/
3382 static bool
3383 genPlusIncr (iCode * ic)
3384 {
3385   unsigned int icount;
3386   unsigned int size = getDataSize (IC_RESULT (ic));
3387   PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3388
3389   /* will try to generate an increment */
3390   /* if the right side is not a literal
3391      we cannot */
3392   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3393     return FALSE;
3394
3395   emitDebug ("; genPlusIncr");
3396
3397   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3398
3399   /* If result is a pair */
3400   if (resultId != PAIR_INVALID)
3401     {
3402       if (isLitWord (AOP (IC_LEFT (ic))))
3403         {
3404           fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3405           return TRUE;
3406         }
3407       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3408         {
3409           if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3410             {
3411               PAIR_ID freep = getFreePairId (ic);
3412               if (freep != PAIR_INVALID)
3413                 {
3414                   fetchPair (freep, AOP (IC_RIGHT (ic)));
3415                   emit2 ("add hl,%s", _pairs[freep].name);
3416                   return TRUE;
3417                 }
3418             }
3419           else
3420             {
3421               fetchPair (resultId, AOP (IC_RIGHT (ic)));
3422               emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3423               return TRUE;
3424             }
3425         }
3426       if (icount > 5)
3427         return FALSE;
3428       /* Inc a pair */
3429       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3430         {
3431           if (icount > 2)
3432             return FALSE;
3433           movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3434         }
3435       while (icount--)
3436         {
3437           emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3438         }
3439       return TRUE;
3440     }
3441
3442   if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3443     {
3444       fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3445       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3446       return TRUE;
3447     }
3448
3449   /* if the literal value of the right hand side
3450      is greater than 4 then it is not worth it */
3451   if (icount > 4)
3452     return FALSE;
3453
3454   /* if increment 16 bits in register */
3455   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3456       size > 1 &&
3457       icount == 1
3458     )
3459     {
3460       int offset = 0;
3461       symbol *tlbl = NULL;
3462       tlbl = newiTempLabel (NULL);
3463       while (size--)
3464         {
3465           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3466           if (size)
3467             {
3468               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3469             }
3470         }
3471       emitLabel (tlbl->key + 100);
3472       return TRUE;
3473     }
3474
3475   /* if the sizes are greater than 1 then we cannot */
3476   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3477       AOP_SIZE (IC_LEFT (ic)) > 1)
3478     return FALSE;
3479
3480   /* If the result is in a register then we can load then increment.
3481    */
3482   if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3483     {
3484       aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3485       while (icount--)
3486         {
3487           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3488         }
3489       return TRUE;
3490     }
3491
3492   /* we can if the aops of the left & result match or
3493      if they are in registers and the registers are the
3494      same */
3495   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3496     {
3497       while (icount--)
3498         {
3499           emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3500         }
3501       return TRUE;
3502     }
3503
3504   return FALSE;
3505 }
3506
3507 /*-----------------------------------------------------------------*/
3508 /* outBitAcc - output a bit in acc                                 */
3509 /*-----------------------------------------------------------------*/
3510 void
3511 outBitAcc (operand * result)
3512 {
3513   symbol *tlbl = newiTempLabel (NULL);
3514   /* if the result is a bit */
3515   if (AOP_TYPE (result) == AOP_CRY)
3516     {
3517       wassertl (0, "Tried to write A into a bit");
3518     }
3519   else
3520     {
3521       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3522       emit2 ("ld a,!one");
3523       emitLabel (tlbl->key + 100);
3524       outAcc (result);
3525     }
3526 }
3527
3528 bool
3529 couldDestroyCarry (asmop *aop)
3530 {
3531   if (aop)
3532     {
3533       if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3534         {
3535           return TRUE;
3536         }
3537     }
3538   return FALSE;
3539 }
3540
3541 static void
3542 shiftIntoPair (int idx, asmop *aop)
3543 {
3544   PAIR_ID id = PAIR_INVALID;
3545
3546   wassertl (IS_Z80, "Only implemented for the Z80");
3547   //  wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3548
3549   switch (idx) 
3550     {
3551     case 0:
3552       id = PAIR_HL;
3553       break;
3554     case 1:
3555       id = PAIR_DE;
3556       _push (PAIR_DE);
3557       break;
3558     default:
3559       wassertl (0, "Internal error - hit default case");
3560     }
3561
3562   emitDebug ("; Shift into pair idx %u", idx);
3563
3564   if (id == PAIR_HL)
3565     {
3566       setupPair (PAIR_HL, aop, 0);
3567     }
3568   else
3569     {
3570       setupPair (PAIR_IY, aop, 0);
3571       emit2 ("push iy");
3572       emit2 ("pop %s", _pairs[id].name);
3573     }
3574
3575   aop->type = AOP_PAIRPTR;
3576   aop->aopu.aop_pairId = id;
3577   _G.pairs[id].offset = 0;
3578   _G.pairs[id].last_type = aop->type;
3579 }
3580
3581 static void 
3582 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3583 {
3584   wassert (left && right);
3585
3586   if (IS_Z80)
3587     {
3588       if (couldDestroyCarry (right) && couldDestroyCarry (result))
3589         {
3590           shiftIntoPair (0, right);
3591           /* check result again, in case right == result */
3592           if (couldDestroyCarry (result))
3593             shiftIntoPair (1, result);
3594         }
3595       else if (couldDestroyCarry (right))
3596         {
3597           if (getPairId (result) == PAIR_HL)
3598             _G.preserveCarry = TRUE;
3599           else
3600             shiftIntoPair (0, right);
3601         }
3602       else if (couldDestroyCarry (result))
3603         {
3604           shiftIntoPair (0, result);
3605         }
3606       else
3607         {
3608           /* Fine */
3609         }
3610     }
3611 }
3612
3613 /*-----------------------------------------------------------------*/
3614 /* genPlus - generates code for addition                           */
3615 /*-----------------------------------------------------------------*/
3616 static void
3617 genPlus (iCode * ic)
3618 {
3619   int size, offset = 0;
3620
3621   /* special cases :- */
3622
3623   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3624   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3625   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3626
3627   /* Swap the left and right operands if:
3628
3629      if literal, literal on the right or
3630      if left requires ACC or right is already
3631      in ACC */
3632
3633   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3634       (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3635       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3636     {
3637       operand *t = IC_RIGHT (ic);
3638       IC_RIGHT (ic) = IC_LEFT (ic);
3639       IC_LEFT (ic) = t;
3640     }
3641
3642   /* if both left & right are in bit
3643      space */
3644   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3645       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3646     {
3647       /* Cant happen */
3648       wassertl (0, "Tried to add two bits");
3649     }
3650
3651   /* if left in bit space & right literal */
3652   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3653       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3654     {
3655       /* Can happen I guess */
3656       wassertl (0, "Tried to add a bit to a literal");
3657     }
3658
3659   /* if I can do an increment instead
3660      of add then GOOD for ME */
3661   if (genPlusIncr (ic) == TRUE)
3662     goto release;
3663
3664   emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3665
3666   size = getDataSize (IC_RESULT (ic));
3667
3668   /* Special case when left and right are constant */
3669   if (isPair (AOP (IC_RESULT (ic))))
3670     {
3671       char *left, *right;
3672       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3673       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3674
3675       if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3676           left && right)
3677         {
3678           /* It's a pair */
3679           /* PENDING: fix */
3680           char buffer[100];
3681           sprintf (buffer, "#(%s + %s)", left, right);
3682           emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3683           goto release;
3684         }
3685     }
3686
3687   if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3688     {
3689       /* Fetch into HL then do the add */
3690       PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3691       PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3692
3693       spillPair (PAIR_HL);
3694       
3695       if (left == PAIR_HL && right != PAIR_INVALID)
3696         {
3697           emit2 ("add hl,%s", _pairs[right].name);
3698           goto release;
3699         }
3700       else if (right == PAIR_HL && left != PAIR_INVALID)
3701         {
3702           emit2 ("add hl,%s", _pairs[left].name);
3703           goto release;
3704         }
3705       else if (right != PAIR_INVALID && right != PAIR_HL)
3706         {
3707           fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3708           emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3709           goto release;
3710         }
3711       else if (left != PAIR_INVALID && left != PAIR_HL)
3712         { 
3713           fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3714           emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3715           goto release;
3716         }
3717       else
3718         {
3719           /* Can't do it */
3720         }
3721     }
3722
3723   if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3724     {
3725       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3726       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3727       spillCached();
3728       commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3729       goto release;
3730     }
3731
3732   /* Special case:
3733      ld hl,sp+n trashes C so we cant afford to do it during an
3734      add with stack based varibles.  Worst case is:
3735      ld  hl,sp+left
3736      ld  a,(hl)
3737      ld  hl,sp+right
3738      add (hl)
3739      ld  hl,sp+result
3740      ld  (hl),a
3741      ld  hl,sp+left+1
3742      ld  a,(hl)
3743      ld  hl,sp+right+1
3744      adc (hl)
3745      ld  hl,sp+result+1
3746      ld  (hl),a
3747      So you cant afford to load up hl if either left, right, or result
3748      is on the stack (*sigh*)  The alt is:
3749      ld  hl,sp+left
3750      ld  de,(hl)
3751      ld  hl,sp+right
3752      ld  hl,(hl)
3753      add hl,de
3754      ld  hl,sp+result
3755      ld  (hl),hl
3756      Combinations in here are:
3757      * If left or right are in bc then the loss is small - trap later
3758      * If the result is in bc then the loss is also small
3759    */
3760   if (IS_GB)
3761     {
3762       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3763           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3764           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3765         {
3766           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3767                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3768               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3769                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3770             {
3771               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3772                 {
3773                   /* Swap left and right */
3774                   operand *t = IC_RIGHT (ic);
3775                   IC_RIGHT (ic) = IC_LEFT (ic);
3776                   IC_LEFT (ic) = t;
3777                 }
3778               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3779                 {
3780                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3781                   emit2 ("add hl,bc");
3782                 }
3783               else
3784                 {
3785                   fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3786                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3787                   emit2 ("add hl,de");
3788                 }
3789               commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3790               goto release;
3791             }
3792         }
3793       if (size == 4)
3794         {
3795           /* Be paranoid on the GB with 4 byte variables due to how C
3796              can be trashed by lda hl,n(sp).
3797           */
3798           _gbz80_emitAddSubLong (ic, TRUE);
3799           goto release;
3800         }
3801     }
3802   
3803   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3804
3805   while (size--)
3806     {
3807       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3808         {
3809           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3810           if (offset == 0)
3811             emit2 ("add a,%s",
3812                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3813           else
3814             emit2 ("adc a,%s",
3815                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3816         }
3817       else
3818         {
3819           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3820           if (offset == 0)
3821             emit2 ("add a,%s",
3822                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3823           else
3824             emit2 ("adc a,%s",
3825                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3826         }
3827       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3828     }
3829
3830 release:
3831   _G.preserveCarry = FALSE;
3832   freeAsmop (IC_LEFT (ic), NULL, ic);
3833   freeAsmop (IC_RIGHT (ic), NULL, ic);
3834   freeAsmop (IC_RESULT (ic), NULL, ic);
3835
3836 }
3837
3838 /*-----------------------------------------------------------------*/
3839 /* genMinusDec :- does subtraction with deccrement if possible     */
3840 /*-----------------------------------------------------------------*/
3841 static bool
3842 genMinusDec (iCode * ic)
3843 {
3844   unsigned int icount;
3845   unsigned int size = getDataSize (IC_RESULT (ic));
3846
3847   /* will try to generate an increment */
3848   /* if the right side is not a literal we cannot */
3849   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3850     return FALSE;
3851
3852   /* if the literal value of the right hand side
3853      is greater than 4 then it is not worth it */
3854   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3855     return FALSE;
3856
3857   size = getDataSize (IC_RESULT (ic));
3858
3859   /* if decrement 16 bits in register */
3860   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3861       (size > 1) && isPair (AOP (IC_RESULT (ic))))
3862     {
3863       while (icount--)
3864         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3865       return TRUE;
3866     }
3867
3868   /* If result is a pair */
3869   if (isPair (AOP (IC_RESULT (ic))))
3870     {
3871       movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3872       while (icount--)
3873         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3874       return TRUE;
3875     }
3876
3877   /* if increment 16 bits in register */
3878   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3879       (size == 2)
3880       )
3881     {
3882       fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3883
3884       while (icount--) {
3885         emit2 ("dec %s", _getTempPairName());
3886       }
3887
3888       commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3889
3890       return TRUE;
3891     }
3892
3893
3894   /* if the sizes are greater than 1 then we cannot */
3895   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3896       AOP_SIZE (IC_LEFT (ic)) > 1)
3897     return FALSE;
3898
3899   /* we can if the aops of the left & result match or if they are in
3900      registers and the registers are the same */
3901   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3902     {
3903       while (icount--)
3904         emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3905       return TRUE;
3906     }
3907
3908   return FALSE;
3909 }
3910
3911 /*-----------------------------------------------------------------*/
3912 /* genMinus - generates code for subtraction                       */
3913 /*-----------------------------------------------------------------*/
3914 static void
3915 genMinus (iCode * ic)
3916 {
3917   int size, offset = 0;
3918   unsigned long lit = 0L;
3919
3920   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3921   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3922   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3923
3924   /* special cases :- */
3925   /* if both left & right are in bit space */
3926   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3927       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3928     {
3929       wassertl (0, "Tried to subtract two bits");
3930       goto release;
3931     }
3932
3933   /* if I can do an decrement instead of subtract then GOOD for ME */
3934   if (genMinusDec (ic) == TRUE)
3935     goto release;
3936
3937   size = getDataSize (IC_RESULT (ic));
3938
3939   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3940     {
3941     }
3942   else
3943     {
3944       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3945       lit = -(long) lit;
3946     }
3947
3948   /* Same logic as genPlus */
3949   if (IS_GB)
3950     {
3951       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3952           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3953           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3954         {
3955           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3956                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3957               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3958                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3959             {
3960               PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3961               PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3962
3963               if (left == PAIR_INVALID && right == PAIR_INVALID)
3964                 {
3965                   left = PAIR_DE;
3966                   right = PAIR_HL;
3967                 }
3968               else if (right == PAIR_INVALID)
3969                 right = PAIR_DE;
3970               else if (left == PAIR_INVALID)
3971                 left = PAIR_DE;
3972
3973               fetchPair (left, AOP (IC_LEFT (ic)));
3974               /* Order is important.  Right may be HL */
3975               fetchPair (right, AOP (IC_RIGHT (ic)));
3976
3977               emit2 ("ld a,%s", _pairs[left].l);
3978               emit2 ("sub a,%s", _pairs[right].l);
3979               emit2 ("ld e,a");
3980               emit2 ("ld a,%s", _pairs[left].h);
3981               emit2 ("sbc a,%s", _pairs[right].h);
3982
3983               if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3984                 {
3985                   aopPut (AOP (IC_RESULT (ic)), "a", 1);
3986                 }
3987               aopPut (AOP (IC_RESULT (ic)), "e", 0);
3988               goto release;
3989             }
3990         }
3991       if (size == 4)
3992         {
3993           /* Be paranoid on the GB with 4 byte variables due to how C
3994              can be trashed by lda hl,n(sp).
3995           */
3996           _gbz80_emitAddSubLong (ic, FALSE);
3997           goto release;
3998         }
3999     }
4000
4001   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
4002
4003   /* if literal, add a,#-lit, else normal subb */
4004   while (size--)
4005     {
4006       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4007       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4008         {
4009           if (!offset)
4010             emit2 ("sub a,%s",
4011                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4012           else
4013             emit2 ("sbc a,%s",
4014                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4015         }
4016       else
4017         {
4018           /* first add without previous c */
4019           if (!offset)
4020             emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4021           else
4022             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4023         }
4024       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4025     }
4026
4027   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4028       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4029       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4030     {
4031       wassertl (0, "Tried to subtract on a long pointer");
4032     }
4033
4034 release:
4035   _G.preserveCarry = FALSE;
4036   freeAsmop (IC_LEFT (ic), NULL, ic);
4037   freeAsmop (IC_RIGHT (ic), NULL, ic);
4038   freeAsmop (IC_RESULT (ic), NULL, ic);
4039 }
4040
4041 /*-----------------------------------------------------------------*/
4042 /* genMult - generates code for multiplication                     */
4043 /*-----------------------------------------------------------------*/
4044 static void
4045 genMult (iCode * ic)
4046 {
4047   int val;
4048   int count, i;
4049   /* If true then the final operation should be a subtract */
4050   bool active = FALSE;
4051
4052   /* Shouldn't occur - all done through function calls */
4053   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4054   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4055   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4056
4057   if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4058       AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4059       AOP_SIZE (IC_RESULT (ic)) > 2)
4060     {
4061       wassertl (0, "Multiplication is handled through support function calls");
4062     }
4063
4064   /* Swap left and right such that right is a literal */
4065   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4066     {
4067       operand *t = IC_RIGHT (ic);
4068       IC_RIGHT (ic) = IC_LEFT (ic);
4069       IC_LEFT (ic) = t;
4070     }
4071
4072   wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4073
4074   val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4075   //  wassertl (val > 0, "Multiply must be positive");
4076   wassertl (val != 1, "Can't multiply by 1");
4077
4078   if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4079     _push (PAIR_DE);
4080     _G.stack.pushedDE = TRUE;
4081   }
4082
4083   if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4084     {
4085       emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4086       emit2 ("ld a,e");
4087       emit2 ("rlc a");
4088       emit2 ("sbc a,a");
4089       emit2 ("ld d,a");
4090     }
4091   else
4092     {
4093       fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4094     }
4095
4096   i = val;
4097
4098   /* Fully unroled version of mul.s.  Not the most efficient.
4099    */
4100   for (count = 0; count < 16; count++)
4101     {
4102       if (count != 0 && active)
4103         {
4104           emit2 ("add hl,hl");
4105         }
4106       if (i & 0x8000U)
4107         {
4108           if (active == FALSE)
4109             {
4110               emit2 ("ld l,e");
4111               emit2 ("ld h,d");
4112             }
4113           else
4114             {
4115               emit2 ("add hl,de");
4116             }
4117           active = TRUE;
4118         }
4119       i <<= 1;
4120     }
4121
4122   spillCached();
4123
4124   if (IS_Z80 && _G.stack.pushedDE)
4125     {
4126       _pop (PAIR_DE);
4127       _G.stack.pushedDE = FALSE;
4128     }
4129
4130   commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4131
4132   freeAsmop (IC_LEFT (ic), NULL, ic);
4133   freeAsmop (IC_RIGHT (ic), NULL, ic);
4134   freeAsmop (IC_RESULT (ic), NULL, ic);
4135 }
4136
4137 /*-----------------------------------------------------------------*/
4138 /* genDiv - generates code for division                            */
4139 /*-----------------------------------------------------------------*/
4140 static void
4141 genDiv (iCode * ic)
4142 {
4143   /* Shouldn't occur - all done through function calls */
4144   wassertl (0, "Division is handled through support function calls");
4145 }
4146
4147 /*-----------------------------------------------------------------*/
4148 /* genMod - generates code for division                            */
4149 /*-----------------------------------------------------------------*/
4150 static void
4151 genMod (iCode * ic)
4152 {
4153   /* Shouldn't occur - all done through function calls */
4154   wassert (0);
4155 }
4156
4157 /*-----------------------------------------------------------------*/
4158 /* genIfxJump :- will create a jump depending on the ifx           */
4159 /*-----------------------------------------------------------------*/
4160 static void
4161 genIfxJump (iCode * ic, char *jval)
4162 {
4163   symbol *jlbl;
4164   const char *inst;
4165
4166   /* if true label then we jump if condition
4167      supplied is true */
4168   if (IC_TRUE (ic))
4169     {
4170       jlbl = IC_TRUE (ic);
4171       if (!strcmp (jval, "a"))
4172         {
4173           inst = "nz";
4174         }
4175       else if (!strcmp (jval, "c"))
4176         {
4177           inst = "c";
4178         }
4179       else if (!strcmp (jval, "nc"))
4180         {
4181           inst = "nc";
4182         }
4183       else if (!strcmp (jval, "m"))
4184         {
4185           inst = "m";
4186         }
4187       else if (!strcmp (jval, "p"))
4188         {
4189           inst = "p";
4190         }
4191       else
4192         {
4193           /* The buffer contains the bit on A that we should test */
4194           inst = "nz";
4195         }
4196     }
4197   else
4198     {
4199       /* false label is present */
4200       jlbl = IC_FALSE (ic);
4201       if (!strcmp (jval, "a"))
4202         {
4203           inst = "z";
4204         }
4205       else if (!strcmp (jval, "c"))
4206         {
4207           inst = "nc";
4208         }
4209       else if (!strcmp (jval, "nc"))
4210         {
4211           inst = "c";
4212         }
4213       else if (!strcmp (jval, "m"))
4214         {
4215           inst = "p";
4216         }
4217       else if (!strcmp (jval, "p"))
4218         {
4219           inst = "m";
4220         }
4221       else
4222         {
4223           /* The buffer contains the bit on A that we should test */
4224           inst = "z";
4225         }
4226     }
4227   /* Z80 can do a conditional long jump */
4228   if (!strcmp (jval, "a"))
4229     {
4230       emit2 ("or a,a");
4231     }
4232   else if (!strcmp (jval, "c"))
4233     {
4234     }
4235   else if (!strcmp (jval, "nc"))
4236     {
4237     }
4238   else if (!strcmp (jval, "m"))
4239     {
4240     }
4241   else if (!strcmp (jval, "p"))
4242     {
4243     }
4244   else
4245     {
4246       emit2 ("bit %s,a", jval);
4247     }
4248   emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4249
4250   /* mark the icode as generated */
4251   ic->generated = 1;
4252 }
4253
4254 #if DISABLED
4255 static const char *
4256 _getPairIdName (PAIR_ID id)
4257 {
4258   return _pairs[id].name;
4259 }
4260 #endif
4261
4262 #if OLD
4263       /* if unsigned char cmp with lit, just compare */
4264       if ((size == 1) &&
4265           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4266         {
4267           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4268           if (sign)
4269             {
4270               emit2 ("xor a,!immedbyte", 0x80);
4271               emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4272             }
4273           else
4274             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4275         }
4276       else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4277         {
4278           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4279           // Pull left into DE and right into HL
4280           aopGet (AOP(left), LSB, FALSE);
4281           emit2 ("ld d,h");
4282           emit2 ("ld e,l");
4283           aopGet (AOP(right), LSB, FALSE);
4284
4285           while (size--)
4286             {
4287               if (size == 0 && sign)
4288                 {
4289                   // Highest byte when signed needs the bits flipped
4290                   // Save the flags
4291                   emit2 ("push af");
4292                   emit2 ("ld a,(de)");
4293                   emit2 ("xor !immedbyte", 0x80);
4294                   emit2 ("ld e,a");
4295                   emit2 ("ld a,(hl)");
4296                   emit2 ("xor !immedbyte", 0x80);
4297                   emit2 ("ld d,a");
4298                   emit2 ("pop af");
4299                   emit2 ("ld a,e");
4300                   emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4301                 }
4302               else
4303                 {
4304                   emit2 ("ld a,(de)");
4305                   emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4306                 }
4307               
4308               if (size != 0)
4309                 {
4310                   emit2 ("inc hl");
4311                   emit2 ("inc de");
4312                 }
4313               offset++;
4314             }
4315           spillPair (PAIR_HL);
4316         }
4317       else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4318         {
4319           setupPair (PAIR_HL, AOP (left), 0);
4320           aopGet (AOP(right), LSB, FALSE);
4321
4322           while (size--)
4323             {
4324               if (size == 0 && sign)
4325                 {
4326                   // Highest byte when signed needs the bits flipped
4327                   // Save the flags
4328                   emit2 ("push af");
4329                   emit2 ("ld a,(hl)");
4330                   emit2 ("xor !immedbyte", 0x80);
4331                   emit2 ("ld l,a");
4332                   emit2 ("ld a,%d(iy)", offset);
4333                   emit2 ("xor !immedbyte", 0x80);
4334                   emit2 ("ld h,a");
4335                   emit2 ("pop af");
4336                   emit2 ("ld a,l");
4337                   emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4338                 }
4339               else
4340                 {
4341                   emit2 ("ld a,(hl)");
4342                   emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4343                 }
4344               
4345               if (size != 0)
4346                 {
4347                   emit2 ("inc hl");
4348                 }
4349               offset++;
4350             }
4351           spillPair (PAIR_HL);
4352           spillPair (PAIR_IY);
4353         }
4354       else
4355         {
4356           if (AOP_TYPE (right) == AOP_LIT)
4357             {
4358               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4359               /* optimize if(x < 0) or if(x >= 0) */
4360               if (lit == 0L)
4361                 {
4362                   if (!sign)
4363                     {
4364                       /* No sign so it's always false */
4365                       _clearCarry();
4366                     }
4367                   else
4368                     {
4369                       /* Just load in the top most bit */
4370                       _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4371                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4372                         {
4373                           genIfxJump (ifx, "7");
4374                           return;
4375                         }
4376                       else
4377                         emit2 ("rlc a");
4378                     }
4379                   goto release;
4380                 }
4381             }
4382           
4383           if (sign)
4384             {
4385               /* First setup h and l contaning the top most bytes XORed */
4386               bool fDidXor = FALSE;
4387               if (AOP_TYPE (left) == AOP_LIT)
4388                 {
4389                   unsigned long lit = (unsigned long)
4390                   floatFromVal (AOP (left)->aopu.aop_lit);
4391                   emit2 ("ld %s,!immedbyte", _fTmp[0],
4392                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4393                 }
4394               else
4395                 {
4396                   emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4397                   emit2 ("xor a,!immedbyte", 0x80);
4398                   emit2 ("ld %s,a", _fTmp[0]);
4399                   fDidXor = TRUE;
4400                 }
4401               if (AOP_TYPE (right) == AOP_LIT)
4402                 {
4403                   unsigned long lit = (unsigned long)
4404                   floatFromVal (AOP (right)->aopu.aop_lit);
4405                   emit2 ("ld %s,!immedbyte", _fTmp[1],
4406                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4407                 }
4408               else
4409                 {
4410                   emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4411                   emit2 ("xor a,!immedbyte", 0x80);
4412                   emit2 ("ld %s,a", _fTmp[1]);
4413                   fDidXor = TRUE;
4414                 }
4415             }
4416           while (size--)
4417             {
4418               /* Do a long subtract */
4419               if (!sign || size)
4420                 {
4421                   _moveA (aopGet (AOP (left), offset, FALSE));
4422                 }
4423               if (sign && size == 0)
4424                 {
4425                   emit2 ("ld a,%s", _fTmp[0]);
4426                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4427                 }
4428               else
4429                 {
4430                   /* Subtract through, propagating the carry */
4431                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4432                   offset++;
4433                 }
4434             }
4435         }
4436     }
4437 #endif
4438
4439 /** Generic compare for > or <
4440  */
4441 static void
4442 genCmp (operand * left, operand * right,
4443         operand * result, iCode * ifx, int sign)
4444 {
4445   int size, offset = 0;
4446   unsigned long lit = 0L;
4447   bool swap_sense = FALSE;
4448
4449   /* if left & right are bit variables */
4450   if (AOP_TYPE (left) == AOP_CRY &&
4451       AOP_TYPE (right) == AOP_CRY)
4452     {
4453       /* Cant happen on the Z80 */
4454       wassertl (0, "Tried to compare two bits");
4455     }
4456   else
4457     {
4458       /* Do a long subtract of right from left. */
4459       size = max (AOP_SIZE (left), AOP_SIZE (right));
4460
4461       if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4462         {
4463           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4464           // Pull left into DE and right into HL
4465           aopGet (AOP(left), LSB, FALSE);
4466           emit2 ("ld d,h");
4467           emit2 ("ld e,l");
4468           aopGet (AOP(right), LSB, FALSE);
4469
4470           while (size--)
4471             {
4472               emit2 ("ld a,(de)");
4473               emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4474               
4475               if (size != 0)
4476                 {
4477                   emit2 ("inc hl");
4478                   emit2 ("inc de");
4479                 }
4480               offset++;
4481             }
4482           spillPair (PAIR_HL);
4483           goto release;
4484         }
4485
4486       if (AOP_TYPE (right) == AOP_LIT)
4487         {
4488           lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4489           /* optimize if(x < 0) or if(x >= 0) */
4490           if (lit == 0)
4491             {
4492               if (!sign)
4493                 {
4494                   /* No sign so it's always false */
4495                   _clearCarry();
4496                 }
4497               else
4498                 {
4499                   /* Just load in the top most bit */
4500                   _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4501                   if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4502                     {
4503                       genIfxJump (ifx, "7");
4504                       return;
4505                     }
4506                   else
4507                     {
4508                       if (!sign) 
4509                         {
4510                           emit2 ("rlc a");
4511                         }
4512                       if (ifx)
4513                         {
4514                           genIfxJump (ifx, swap_sense ? "c" : "nc");
4515                           return;
4516                         }
4517                     }
4518                 }
4519               goto release;
4520             }
4521         }
4522
4523       while (size--)
4524         {
4525           _moveA (aopGet (AOP (left), offset, FALSE));
4526           /* Subtract through, propagating the carry */
4527           emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4528           offset++;
4529         }
4530     }
4531
4532 release:
4533   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4534     {
4535       if (sign)
4536         {
4537           /* Shift the sign bit up into carry */
4538           emit2 ("rlca");
4539         }
4540       outBitCLong (result, swap_sense);
4541     }
4542   else
4543     {
4544       /* if the result is used in the next
4545          ifx conditional branch then generate
4546          code a little differently */
4547       if (ifx)
4548         {
4549           if (sign)
4550             {
4551               if (IS_GB)
4552                 {
4553                   emit2 ("rlca");
4554                   genIfxJump (ifx, swap_sense ? "nc" : "c");
4555                 }
4556               else
4557                 {
4558                   genIfxJump (ifx, swap_sense ? "p" : "m");
4559                 }
4560             }
4561           else
4562             {
4563               genIfxJump (ifx, swap_sense ? "nc" : "c");
4564             }
4565         }
4566       else
4567         {
4568           if (sign)
4569             {
4570               /* Shift the sign bit up into carry */
4571               emit2 ("rlca");
4572             }
4573           outBitCLong (result, swap_sense);
4574         }
4575       /* leave the result in acc */
4576     }
4577 }
4578
4579 /*-----------------------------------------------------------------*/
4580 /* genCmpGt :- greater than comparison                             */
4581 /*-----------------------------------------------------------------*/
4582 static void
4583 genCmpGt (iCode * ic, iCode * ifx)
4584 {
4585   operand *left, *right, *result;
4586   sym_link *letype, *retype;
4587   int sign;
4588
4589   left = IC_LEFT (ic);
4590   right = IC_RIGHT (ic);
4591   result = IC_RESULT (ic);
4592
4593   letype = getSpec (operandType (left));
4594   retype = getSpec (operandType (right));
4595   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4596   /* assign the amsops */
4597   aopOp (left, ic, FALSE, FALSE);
4598   aopOp (right, ic, FALSE, FALSE);
4599   aopOp (result, ic, TRUE, FALSE);
4600
4601   genCmp (right, left, result, ifx, sign);
4602
4603   freeAsmop (left, NULL, ic);
4604   freeAsmop (right, NULL, ic);
4605   freeAsmop (result, NULL, ic);
4606 }
4607
4608 /*-----------------------------------------------------------------*/
4609 /* genCmpLt - less than comparisons                                */
4610 /*-----------------------------------------------------------------*/
4611 static void
4612 genCmpLt (iCode * ic, iCode * ifx)
4613 {
4614   operand *left, *right, *result;
4615   sym_link *letype, *retype;
4616   int sign;
4617
4618   left = IC_LEFT (ic);
4619   right = IC_RIGHT (ic);
4620   result = IC_RESULT (ic);
4621
4622   letype = getSpec (operandType (left));
4623   retype = getSpec (operandType (right));
4624   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4625
4626   /* assign the amsops */
4627   aopOp (left, ic, FALSE, FALSE);
4628   aopOp (right, ic, FALSE, FALSE);
4629   aopOp (result, ic, TRUE, FALSE);
4630
4631   genCmp (left, right, result, ifx, sign);
4632
4633   freeAsmop (left, NULL, ic);
4634   freeAsmop (right, NULL, ic);
4635   freeAsmop (result, NULL, ic);
4636 }
4637
4638 /*-----------------------------------------------------------------*/
4639 /* gencjneshort - compare and jump if not equal                    */
4640 /*-----------------------------------------------------------------*/
4641 static void
4642 gencjneshort (operand * left, operand * right, symbol * lbl)
4643 {
4644   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4645   int offset = 0;
4646   unsigned long lit = 0L;
4647
4648   /* Swap the left and right if it makes the computation easier */
4649   if (AOP_TYPE (left) == AOP_LIT)
4650     {
4651       operand *t = right;
4652       right = left;
4653       left = t;
4654     }
4655
4656   if (AOP_TYPE (right) == AOP_LIT)
4657     {
4658       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4659     }
4660
4661   /* if the right side is a literal then anything goes */
4662   if (AOP_TYPE (right) == AOP_LIT &&
4663       AOP_TYPE (left) != AOP_DIR)
4664     {
4665       if (lit == 0)
4666         {
4667           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4668           if (size > 1)
4669             {
4670               while (--size)
4671                 {
4672                   emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4673                 }
4674             }
4675           else
4676             {
4677               emit2 ("or a,a");
4678             }
4679           emit2 ("jp nz,!tlabel", lbl->key + 100);
4680         }
4681       else
4682         {
4683           while (size--)
4684             {
4685               emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4686               if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4687                 emit2 ("or a,a");
4688               else
4689                 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4690               emit2 ("jp nz,!tlabel", lbl->key + 100);
4691               offset++;
4692             }
4693         }
4694     }
4695   /* if the right side is in a register or in direct space or
4696      if the left is a pointer register & right is not */
4697   else if (AOP_TYPE (right) == AOP_REG ||
4698            AOP_TYPE (right) == AOP_DIR ||
4699            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4700     {
4701       while (size--)
4702         {
4703           _moveA (aopGet (AOP (left), offset, FALSE));
4704           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4705               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4706             /* PENDING */
4707             emit2 ("jp nz,!tlabel", lbl->key + 100);
4708           else
4709             {
4710               emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4711               emit2 ("jp nz,!tlabel", lbl->key + 100);
4712             }
4713           offset++;
4714         }
4715     }
4716   else
4717     {
4718       /* right is a pointer reg need both a & b */
4719       /* PENDING: is this required? */
4720       while (size--)
4721         {
4722           _moveA (aopGet (AOP (right), offset, FALSE));
4723           emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4724           emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4725           offset++;
4726         }
4727     }
4728 }
4729
4730 /*-----------------------------------------------------------------*/
4731 /* gencjne - compare and jump if not equal                         */
4732 /*-----------------------------------------------------------------*/
4733 static void
4734 gencjne (operand * left, operand * right, symbol * lbl)
4735 {
4736   symbol *tlbl = newiTempLabel (NULL);
4737
4738   gencjneshort (left, right, lbl);
4739
4740   /* PENDING: ?? */
4741   emit2 ("ld a,!one");
4742   emit2 ("!shortjp !tlabel", tlbl->key + 100);
4743   emitLabel (lbl->key + 100);
4744   emit2 ("xor a,a");
4745   emitLabel (tlbl->key + 100);
4746 }
4747
4748 /*-----------------------------------------------------------------*/
4749 /* genCmpEq - generates code for equal to                          */
4750 /*-----------------------------------------------------------------*/
4751 static void
4752 genCmpEq (iCode * ic, iCode * ifx)
4753 {
4754   operand *left, *right, *result;
4755
4756   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4757   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4758   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4759
4760   emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4761
4762   /* Swap operands if it makes the operation easier. ie if:
4763      1.  Left is a literal.
4764    */
4765   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4766     {
4767       operand *t = IC_RIGHT (ic);
4768       IC_RIGHT (ic) = IC_LEFT (ic);
4769       IC_LEFT (ic) = t;
4770     }
4771
4772   if (ifx && !AOP_SIZE (result))
4773     {
4774       symbol *tlbl;
4775       /* if they are both bit variables */
4776       if (AOP_TYPE (left) == AOP_CRY &&
4777           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4778         {
4779           wassertl (0, "Tried to compare two bits");
4780         }
4781       else
4782         {
4783           tlbl = newiTempLabel (NULL);
4784           gencjneshort (left, right, tlbl);
4785           if (IC_TRUE (ifx))
4786             {
4787               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4788               emitLabel (tlbl->key + 100);
4789             }
4790           else
4791             {
4792               /* PENDING: do this better */
4793               symbol *lbl = newiTempLabel (NULL);
4794               emit2 ("!shortjp !tlabel", lbl->key + 100);
4795               emitLabel (tlbl->key + 100);
4796               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4797               emitLabel (lbl->key + 100);
4798             }
4799         }
4800       /* mark the icode as generated */
4801       ifx->generated = 1;
4802       goto release;
4803     }
4804
4805   /* if they are both bit variables */
4806   if (AOP_TYPE (left) == AOP_CRY &&
4807       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4808     {
4809       wassertl (0, "Tried to compare a bit to either a literal or another bit");
4810     }
4811   else
4812     {
4813       emitDebug(";4");
4814       
4815       gencjne (left, right, newiTempLabel (NULL));
4816       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4817         {
4818           wassert (0);
4819         }
4820       if (ifx)
4821         {
4822           emitDebug(";5");
4823           genIfxJump (ifx, "a");
4824           goto release;
4825         }
4826       /* if the result is used in an arithmetic operation
4827          then put the result in place */
4828       if (AOP_TYPE (result) != AOP_CRY)
4829         {
4830           emitDebug(";6");
4831           outAcc (result);
4832         }
4833       /* leave the result in acc */
4834     }
4835
4836 release:
4837   freeAsmop (left, NULL, ic);
4838   freeAsmop (right, NULL, ic);
4839   freeAsmop (result, NULL, ic);
4840 }
4841
4842 /*-----------------------------------------------------------------*/
4843 /* ifxForOp - returns the icode containing the ifx for operand     */
4844 /*-----------------------------------------------------------------*/
4845 static iCode *
4846 ifxForOp (operand * op, iCode * ic)
4847 {
4848   /* if true symbol then needs to be assigned */
4849   if (IS_TRUE_SYMOP (op))
4850     return NULL;
4851
4852   /* if this has register type condition and
4853      the next instruction is ifx with the same operand
4854      and live to of the operand is upto the ifx only then */
4855   if (ic->next &&
4856       ic->next->op == IFX &&
4857       IC_COND (ic->next)->key == op->key &&
4858       OP_SYMBOL (op)->liveTo <= ic->next->seq)
4859     return ic->next;
4860
4861   return NULL;
4862 }
4863
4864 /*-----------------------------------------------------------------*/
4865 /* genAndOp - for && operation                                     */
4866 /*-----------------------------------------------------------------*/
4867 static void
4868 genAndOp (iCode * ic)
4869 {
4870   operand *left, *right, *result;
4871   symbol *tlbl;
4872
4873   /* note here that && operations that are in an if statement are
4874      taken away by backPatchLabels only those used in arthmetic
4875      operations remain */
4876   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4877   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4878   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4879
4880   /* if both are bit variables */
4881   if (AOP_TYPE (left) == AOP_CRY &&
4882       AOP_TYPE (right) == AOP_CRY)
4883     {
4884       wassertl (0, "Tried to and two bits");
4885     }
4886   else
4887     {
4888       tlbl = newiTempLabel (NULL);
4889       _toBoolean (left);
4890       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4891       _toBoolean (right);
4892       emitLabel (tlbl->key + 100);
4893       outBitAcc (result);
4894     }
4895
4896   freeAsmop (left, NULL, ic);
4897   freeAsmop (right, NULL, ic);
4898   freeAsmop (result, NULL, ic);
4899 }
4900
4901 /*-----------------------------------------------------------------*/
4902 /* genOrOp - for || operation                                      */
4903 /*-----------------------------------------------------------------*/
4904 static void
4905 genOrOp (iCode * ic)
4906 {
4907   operand *left, *right, *result;
4908   symbol *tlbl;
4909
4910   /* note here that || operations that are in an
4911      if statement are taken away by backPatchLabels
4912      only those used in arthmetic operations remain */
4913   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4914   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4915   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4916
4917   /* if both are bit variables */
4918   if (AOP_TYPE (left) == AOP_CRY &&
4919       AOP_TYPE (right) == AOP_CRY)
4920     {
4921       wassertl (0, "Tried to OR two bits");
4922     }
4923   else
4924     {
4925       tlbl = newiTempLabel (NULL);
4926       _toBoolean (left);
4927       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4928       _toBoolean (right);
4929       emitLabel (tlbl->key + 100);
4930       outBitAcc (result);
4931     }
4932
4933   freeAsmop (left, NULL, ic);
4934   freeAsmop (right, NULL, ic);
4935   freeAsmop (result, NULL, ic);
4936 }
4937
4938 /*-----------------------------------------------------------------*/
4939 /* isLiteralBit - test if lit == 2^n                               */
4940 /*-----------------------------------------------------------------*/
4941 int
4942 isLiteralBit (unsigned long lit)
4943 {
4944   unsigned long pw[32] =
4945   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4946    0x100L, 0x200L, 0x400L, 0x800L,
4947    0x1000L, 0x2000L, 0x4000L, 0x8000L,
4948    0x10000L, 0x20000L, 0x40000L, 0x80000L,
4949    0x100000L, 0x200000L, 0x400000L, 0x800000L,
4950    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4951    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4952   int idx;
4953
4954   for (idx = 0; idx < 32; idx++)
4955     if (lit == pw[idx])
4956       return idx + 1;
4957   return 0;
4958 }
4959
4960 /*-----------------------------------------------------------------*/
4961 /* jmpTrueOrFalse -                                                */
4962 /*-----------------------------------------------------------------*/
4963 static void
4964 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4965 {
4966   // ugly but optimized by peephole
4967   if (IC_TRUE (ic))
4968     {
4969       symbol *nlbl = newiTempLabel (NULL);
4970       emit2 ("jp !tlabel", nlbl->key + 100);
4971       emitLabel (tlbl->key + 100);
4972       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4973       emitLabel (nlbl->key + 100);
4974     }
4975   else
4976     {
4977       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4978       emitLabel (tlbl->key + 100);
4979     }
4980   ic->generated = 1;
4981 }
4982
4983 /*-----------------------------------------------------------------*/
4984 /* genAnd  - code for and                                          */
4985 /*-----------------------------------------------------------------*/
4986 static void
4987 genAnd (iCode * ic, iCode * ifx)
4988 {
4989   operand *left, *right, *result;
4990   int size, offset = 0;
4991   unsigned long lit = 0L;
4992   int bytelit = 0;
4993
4994   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4995   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4996   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4997
4998   /* if left is a literal & right is not then exchange them */
4999   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5000       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5001     {
5002       operand *tmp = right;
5003       right = left;
5004       left = tmp;
5005     }
5006
5007   /* if result = right then exchange them */
5008   if (sameRegs (AOP (result), AOP (right)))
5009     {
5010       operand *tmp = right;
5011       right = left;
5012       left = tmp;
5013     }
5014
5015   /* if right is bit then exchange them */
5016   if (AOP_TYPE (right) == AOP_CRY &&
5017       AOP_TYPE (left) != AOP_CRY)
5018     {
5019       operand *tmp = right;
5020       right = left;
5021       left = tmp;
5022     }
5023   if (AOP_TYPE (right) == AOP_LIT)
5024     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5025
5026   size = AOP_SIZE (result);
5027
5028   if (AOP_TYPE (left) == AOP_CRY)
5029     {
5030       wassertl (0, "Tried to perform an AND with a bit as an operand");
5031       goto release;
5032     }
5033
5034   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5035   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5036   if ((AOP_TYPE (right) == AOP_LIT) &&
5037       (AOP_TYPE (result) == AOP_CRY) &&
5038       (AOP_TYPE (left) != AOP_CRY))
5039     {
5040       symbol *tlbl = newiTempLabel (NULL);
5041       int sizel = AOP_SIZE (left);
5042       if (size)
5043         {
5044           /* PENDING: Test case for this. */
5045           emit2 ("scf");
5046         }
5047       while (sizel--)
5048         {
5049           if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5050             {
5051               _moveA (aopGet (AOP (left), offset, FALSE));
5052               if (bytelit != 0x0FFL)
5053                 {
5054                   emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5055                 }
5056               else
5057                 {
5058                   /* For the flags */
5059                   emit2 ("or a,a");
5060                 }
5061               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5062             }
5063               offset++;
5064         }
5065       // bit = left & literal
5066       if (size)
5067         {
5068           emit2 ("clr c");
5069           emit2 ("!tlabeldef", tlbl->key + 100);
5070         }
5071       // if(left & literal)
5072       else
5073         {
5074           if (ifx)
5075             {
5076               jmpTrueOrFalse (ifx, tlbl);
5077             }
5078           goto release;
5079         }
5080       outBitC (result);
5081       goto release;
5082     }
5083
5084   /* if left is same as result */
5085   if (sameRegs (AOP (result), AOP (left)))
5086     {
5087       for (; size--; offset++)
5088         {
5089           if (AOP_TYPE (right) == AOP_LIT)
5090             {
5091               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5092                 continue;
5093               else
5094                 {
5095                   if (bytelit == 0)
5096                     aopPut (AOP (result), "!zero", offset);
5097                   else
5098                     {
5099                       _moveA (aopGet (AOP (left), offset, FALSE));
5100                       emit2 ("and a,%s",
5101                                 aopGet (AOP (right), offset, FALSE));
5102                       aopPut (AOP (left), "a", offset);
5103                     }
5104                 }
5105
5106             }
5107           else
5108             {
5109               if (AOP_TYPE (left) == AOP_ACC)
5110                 {
5111                   wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5112                 }
5113               else
5114                 {
5115                   _moveA (aopGet (AOP (left), offset, FALSE));
5116                   emit2 ("and a,%s",
5117                             aopGet (AOP (right), offset, FALSE));
5118                   aopPut (AOP (left), "a", offset);
5119                 }
5120             }
5121         }
5122     }
5123   else
5124     {
5125       // left & result in different registers
5126       if (AOP_TYPE (result) == AOP_CRY)
5127         {
5128           wassertl (0, "Tried to AND where the result is in carry");
5129         }
5130       else
5131         {
5132           for (; (size--); offset++)
5133             {
5134               // normal case
5135               // result = left & right
5136               if (AOP_TYPE (right) == AOP_LIT)
5137                 {
5138                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5139                     {
5140                       aopPut (AOP (result),
5141                               aopGet (AOP (left), offset, FALSE),
5142                               offset);
5143                       continue;
5144                     }
5145                   else if (bytelit == 0)
5146                     {
5147                       aopPut (AOP (result), "!zero", offset);
5148                       continue;
5149                     }
5150                 }
5151               // faster than result <- left, anl result,right
5152               // and better if result is SFR
5153               if (AOP_TYPE (left) == AOP_ACC)
5154                 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5155               else
5156                 {
5157                   _moveA (aopGet (AOP (left), offset, FALSE));
5158                   emit2 ("and a,%s",
5159                             aopGet (AOP (right), offset, FALSE));
5160                 }
5161               aopPut (AOP (result), "a", offset);
5162             }
5163         }
5164
5165     }
5166
5167 release:
5168   freeAsmop (left, NULL, ic);
5169   freeAsmop (right, NULL, ic);
5170   freeAsmop (result, NULL, ic);
5171 }
5172
5173 /*-----------------------------------------------------------------*/
5174 /* genOr  - code for or                                            */
5175 /*-----------------------------------------------------------------*/
5176 static void
5177 genOr (iCode * ic, iCode * ifx)
5178 {
5179   operand *left, *right, *result;
5180   int size, offset = 0;
5181   unsigned long lit = 0L;
5182   int bytelit = 0;
5183
5184   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5185   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5186   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5187
5188   /* if left is a literal & right is not then exchange them */
5189   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5190       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5191     {
5192       operand *tmp = right;
5193       right = left;
5194       left = tmp;
5195     }
5196
5197   /* if result = right then exchange them */
5198   if (sameRegs (AOP (result), AOP (right)))
5199     {
5200       operand *tmp = right;
5201       right = left;
5202       left = tmp;
5203     }
5204
5205   /* if right is bit then exchange them */
5206   if (AOP_TYPE (right) == AOP_CRY &&
5207       AOP_TYPE (left) != AOP_CRY)
5208     {
5209       operand *tmp = right;
5210       right = left;
5211       left = tmp;
5212     }
5213   if (AOP_TYPE (right) == AOP_LIT)
5214     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5215
5216   size = AOP_SIZE (result);
5217
5218   if (AOP_TYPE (left) == AOP_CRY)
5219     {
5220       wassertl (0, "Tried to OR where left is a bit");
5221       goto release;
5222     }
5223
5224   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
5225   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
5226   if ((AOP_TYPE (right) == AOP_LIT) &&
5227       (AOP_TYPE (result) == AOP_CRY) &&
5228       (AOP_TYPE (left) != AOP_CRY))
5229     {
5230       symbol *tlbl = newiTempLabel (NULL);
5231       int sizel = AOP_SIZE (left);
5232
5233       if (size)
5234         {
5235           wassertl (0, "Result is assigned to a bit");
5236         }
5237       /* PENDING: Modeled after the AND code which is inefficent. */
5238       while (sizel--)
5239         {
5240           bytelit = (lit >> (offset * 8)) & 0x0FFL;
5241
5242           _moveA (aopGet (AOP (left), offset, FALSE));
5243           /* OR with any literal is the same as OR with itself. */
5244           emit2 ("or a,a");
5245           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5246
5247           offset++;
5248         }
5249       if (ifx)
5250         {
5251           jmpTrueOrFalse (ifx, tlbl);
5252         }
5253       goto release;
5254     }
5255
5256   /* if left is same as result */
5257   if (sameRegs (AOP (result), AOP (left)))
5258     {
5259       for (; size--; offset++)
5260         {
5261           if (AOP_TYPE (right) == AOP_LIT)
5262             {
5263               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5264                 continue;
5265               else
5266                 {
5267                   _moveA (aopGet (AOP (left), offset, FALSE));
5268                   emit2 ("or a,%s",
5269                             aopGet (AOP (right), offset, FALSE));
5270                   aopPut (AOP (result), "a", offset);
5271                 }
5272             }
5273           else
5274             {
5275               if (AOP_TYPE (left) == AOP_ACC)
5276                 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5277               else
5278                 {
5279                   _moveA (aopGet (AOP (left), offset, FALSE));
5280                   emit2 ("or a,%s",
5281                             aopGet (AOP (right), offset, FALSE));
5282                   aopPut (AOP (result), "a", offset);
5283                 }
5284             }
5285         }
5286     }
5287   else
5288     {
5289       // left & result in different registers
5290       if (AOP_TYPE (result) == AOP_CRY)
5291         {
5292           wassertl (0, "Result of OR is in a bit");
5293         }
5294       else
5295         for (; (size--); offset++)
5296           {
5297             // normal case
5298             // result = left & right
5299             if (AOP_TYPE (right) == AOP_LIT)
5300               {
5301                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5302                   {
5303                     aopPut (AOP (result),
5304                             aopGet (AOP (left), offset, FALSE),
5305                             offset);
5306                     continue;
5307                   }
5308               }
5309             // faster than result <- left, anl result,right
5310             // and better if result is SFR
5311             if (AOP_TYPE (left) == AOP_ACC)
5312               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5313             else
5314               {
5315                 _moveA (aopGet (AOP (left), offset, FALSE));
5316                 emit2 ("or a,%s",
5317                           aopGet (AOP (right), offset, FALSE));
5318               }
5319             aopPut (AOP (result), "a", offset);
5320             /* PENDING: something weird is going on here.  Add exception. */
5321             if (AOP_TYPE (result) == AOP_ACC)
5322               break;
5323           }
5324     }
5325
5326 release:
5327   freeAsmop (left, NULL, ic);
5328   freeAsmop (right, NULL, ic);
5329   freeAsmop (result, NULL, ic);
5330 }
5331
5332 /*-----------------------------------------------------------------*/
5333 /* genXor - code for xclusive or                                   */
5334 /*-----------------------------------------------------------------*/
5335 static void
5336 genXor (iCode * ic, iCode * ifx)
5337 {
5338   operand *left, *right, *result;
5339   int size, offset = 0;
5340   unsigned long lit = 0L;
5341
5342   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5343   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5344   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5345
5346   /* if left is a literal & right is not then exchange them */
5347   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5348       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5349     {
5350       operand *tmp = right;
5351       right = left;
5352       left = tmp;
5353     }
5354
5355   /* if result = right then exchange them */
5356   if (sameRegs (AOP (result), AOP (right)))
5357     {
5358       operand *tmp = right;
5359       right = left;
5360       left = tmp;
5361     }
5362
5363   /* if right is bit then exchange them */
5364   if (AOP_TYPE (right) == AOP_CRY &&
5365       AOP_TYPE (left) != AOP_CRY)
5366     {
5367       operand *tmp = right;
5368       right = left;
5369       left = tmp;
5370     }
5371   if (AOP_TYPE (right) == AOP_LIT)
5372     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5373
5374   size = AOP_SIZE (result);
5375
5376   if (AOP_TYPE (left) == AOP_CRY)
5377     {
5378       wassertl (0, "Tried to XOR a bit");
5379       goto release;
5380     }
5381
5382   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5383   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5384   if ((AOP_TYPE (right) == AOP_LIT) &&
5385       (AOP_TYPE (result) == AOP_CRY) &&
5386       (AOP_TYPE (left) != AOP_CRY))
5387     {
5388       symbol *tlbl = newiTempLabel (NULL);
5389       int sizel = AOP_SIZE (left);
5390
5391       if (size)
5392         {
5393           /* PENDING: Test case for this. */
5394           wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5395         }
5396       while (sizel--)
5397         {
5398           _moveA (aopGet (AOP (left), offset, FALSE));
5399           emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5400           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5401           offset++;
5402         }
5403       if (ifx)
5404         {
5405           jmpTrueOrFalse (ifx, tlbl);
5406         }
5407       else
5408         {
5409           wassertl (0, "Result of XOR was destined for a bit");
5410         }
5411       goto release;
5412     }
5413
5414   /* if left is same as result */
5415   if (sameRegs (AOP (result), AOP (left)))
5416     {
5417       for (; size--; offset++)
5418         {
5419           if (AOP_TYPE (right) == AOP_LIT)
5420             {
5421               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5422                 continue;
5423               else
5424                 {
5425                   _moveA (aopGet (AOP (left), offset, FALSE));
5426                   emit2 ("xor a,%s",
5427                             aopGet (AOP (right), offset, FALSE));
5428                   aopPut (AOP (result), "a", offset);
5429                 }
5430             }
5431           else
5432             {
5433               if (AOP_TYPE (left) == AOP_ACC)
5434                 {
5435                   emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5436                 }
5437               else
5438                 {
5439                   _moveA (aopGet (AOP (left), offset, FALSE));
5440                   emit2 ("xor a,%s",
5441                             aopGet (AOP (right), offset, FALSE));
5442                   aopPut (AOP (result), "a", offset);
5443                 }
5444             }
5445         }
5446     }
5447   else
5448     {
5449       // left & result in different registers
5450       if (AOP_TYPE (result) == AOP_CRY)
5451         {
5452           wassertl (0, "Result of XOR is in a bit");
5453         }
5454       else
5455         for (; (size--); offset++)
5456           {
5457             // normal case
5458             // result = left & right
5459             if (AOP_TYPE (right) == AOP_LIT)
5460               {
5461                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5462                   {
5463                     aopPut (AOP (result),
5464                             aopGet (AOP (left), offset, FALSE),
5465                             offset);
5466                     continue;
5467                   }
5468               }
5469             // faster than result <- left, anl result,right
5470             // and better if result is SFR
5471             if (AOP_TYPE (left) == AOP_ACC) 
5472               {
5473                 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5474               }
5475             else
5476               {
5477                 _moveA (aopGet (AOP (left), offset, FALSE));
5478                 emit2 ("xor a,%s",
5479                           aopGet (AOP (right), offset, FALSE));
5480               }
5481             aopPut (AOP (result), "a", offset);
5482           }
5483     }
5484
5485 release:
5486   freeAsmop (left, NULL, ic);
5487   freeAsmop (right, NULL, ic);
5488   freeAsmop (result, NULL, ic);
5489 }
5490
5491 /*-----------------------------------------------------------------*/
5492 /* genInline - write the inline code out                           */
5493 /*-----------------------------------------------------------------*/
5494 static void
5495 genInline (iCode * ic)
5496 {
5497   char *buffer, *bp, *bp1;
5498
5499   _G.lines.isInline += (!options.asmpeep);
5500
5501   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5502   strcpy (buffer, IC_INLINE (ic));
5503
5504   /* emit each line as a code */
5505   while (*bp)
5506     {
5507       if (*bp == '\n')
5508         {
5509           *bp++ = '\0';
5510           emit2 (bp1);
5511           bp1 = bp;
5512         }
5513       else
5514         {
5515           if (*bp == ':')
5516             {
5517               bp++;
5518               *bp = '\0';
5519               bp++;
5520               emit2 (bp1);
5521               bp1 = bp;
5522             }
5523           else
5524             bp++;
5525         }
5526     }
5527   if (bp1 != bp)
5528     emit2 (bp1);
5529   _G.lines.isInline -= (!options.asmpeep);
5530
5531 }
5532
5533 /*-----------------------------------------------------------------*/
5534 /* genRRC - rotate right with carry                                */
5535 /*-----------------------------------------------------------------*/
5536 static void
5537 genRRC (iCode * ic)
5538 {
5539   wassert (0);
5540 }
5541
5542 /*-----------------------------------------------------------------*/
5543 /* genRLC - generate code for rotate left with carry               */
5544 /*-----------------------------------------------------------------*/
5545 static void
5546 genRLC (iCode * ic)
5547 {
5548   wassert (0);
5549 }
5550
5551 /*-----------------------------------------------------------------*/
5552 /* genGetHbit - generates code get highest order bit               */
5553 /*-----------------------------------------------------------------*/
5554 static void
5555 genGetHbit (iCode * ic)
5556 {
5557   operand *left, *result;
5558   left = IC_LEFT (ic);
5559   result = IC_RESULT (ic);
5560
5561   aopOp (left, ic, FALSE, FALSE);
5562   aopOp (result, ic, FALSE, FALSE);
5563
5564   /* get the highest order byte into a */
5565   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5566
5567   if (AOP_TYPE (result) == AOP_CRY)
5568     {
5569       emit2 ("rl a");
5570       outBitC (result);
5571     }
5572   else
5573     {
5574       emit2 ("rlc a");
5575       emit2 ("and a,!one");
5576       outAcc (result);
5577     }
5578
5579
5580   freeAsmop (left, NULL, ic);
5581   freeAsmop (result, NULL, ic);
5582 }
5583
5584 static void
5585 emitRsh2 (asmop *aop, int size, int is_signed)
5586 {
5587   int offset = 0;
5588
5589   while (size--)
5590     {
5591       const char *l = aopGet (aop, size, FALSE);
5592       if (offset == 0)
5593         {
5594           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5595         }
5596       else
5597         {
5598           emit2 ("rr %s", l);
5599         }
5600       offset++;
5601     }
5602 }
5603
5604 /*-----------------------------------------------------------------*/
5605 /* shiftR2Left2Result - shift right two bytes from left to result  */
5606 /*-----------------------------------------------------------------*/
5607 static void
5608 shiftR2Left2Result (operand * left, int offl,
5609                     operand * result, int offr,
5610                     int shCount, int is_signed)
5611 {
5612   int size = 2;
5613   symbol *tlbl, *tlbl1;
5614
5615   movLeft2Result (left, offl, result, offr, 0);
5616   movLeft2Result (left, offl + 1, result, offr + 1, 0);
5617
5618   /*  if (AOP(result)->type == AOP_REG) { */
5619   
5620   tlbl = newiTempLabel (NULL);
5621   tlbl1 = newiTempLabel (NULL);
5622
5623   /* Left is already in result - so now do the shift */
5624   if (shCount <= 4)
5625     {
5626       while (shCount--)
5627         {
5628           emitRsh2 (AOP (result), size, is_signed);
5629         }
5630     }
5631   else
5632     {
5633       emit2 ("ld a,!immedbyte+1", shCount);
5634       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5635       emitLabel (tlbl->key + 100);
5636
5637       emitRsh2 (AOP (result), size, is_signed);
5638
5639       emitLabel (tlbl1->key + 100);
5640       emit2 ("dec a");
5641       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5642     }
5643 }
5644
5645 /*-----------------------------------------------------------------*/
5646 /* shiftL2Left2Result - shift left two bytes from left to result   */
5647 /*-----------------------------------------------------------------*/
5648 static void
5649 shiftL2Left2Result (operand * left, int offl,
5650                     operand * result, int offr, int shCount)
5651 {
5652   if (sameRegs (AOP (result), AOP (left)) &&
5653       ((offl + MSB16) == offr))
5654     {
5655       wassert (0);
5656     }
5657   else
5658     {
5659       /* Copy left into result */
5660       movLeft2Result (left, offl, result, offr, 0);
5661       movLeft2Result (left, offl + 1, result, offr + 1, 0);
5662     }
5663
5664   if (getPairId (AOP (result)) == PAIR_HL)
5665     {
5666       while (shCount--)
5667         {
5668           emit2 ("add hl,hl");
5669         }
5670     }
5671   else
5672     {
5673     int size = 2;
5674     int offset = 0;
5675     symbol *tlbl, *tlbl1;
5676     const char *l;
5677
5678     tlbl = newiTempLabel (NULL);
5679     tlbl1 = newiTempLabel (NULL);
5680
5681     if (AOP (result)->type == AOP_REG)
5682       {
5683         while (shCount--)
5684           {
5685             for (offset = 0; offset < size; offset++)
5686               {
5687                 l = aopGet (AOP (result), offset, FALSE);
5688             
5689                 if (offset == 0)
5690                   {
5691                     emit2 ("sla %s", l);
5692                   }
5693                 else
5694                   {
5695                     emit2 ("rl %s", l);
5696                   }
5697               }
5698           }
5699       }
5700     else
5701       {
5702         /* Left is already in result - so now do the shift */
5703         if (shCount > 1)
5704           {
5705             emit2 ("ld a,!immedbyte+1", shCount);
5706             emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5707             emitLabel (tlbl->key + 100);
5708           }
5709
5710         while (size--)
5711           {
5712             l = aopGet (AOP (result), offset, FALSE);
5713             
5714             if (offset == 0)
5715               {
5716                 emit2 ("sla %s", l);
5717               }
5718             else
5719               {
5720                 emit2 ("rl %s", l);
5721               }
5722             
5723             offset++;
5724           }
5725         if (shCount > 1)
5726           {
5727             emitLabel (tlbl1->key + 100);
5728             emit2 ("dec a");
5729             emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5730           }
5731       }
5732   }
5733 }
5734
5735 /*-----------------------------------------------------------------*/
5736 /* AccRol - rotate left accumulator by known count                 */
5737 /*-----------------------------------------------------------------*/
5738 static void
5739 AccRol (int shCount)
5740 {
5741   shCount &= 0x0007;            // shCount : 0..7
5742
5743 #if 0
5744   switch (shCount)
5745     {
5746     case 0:
5747       break;
5748     case 1:
5749       emit2 ("sla a");
5750       break;
5751     case 2:
5752       emit2 ("sla a");
5753       emit2 ("rl a");
5754       break;
5755     case 3:
5756       emit2 ("sla a");
5757       emit2 ("rl a");
5758       emit2 ("rl a");
5759       break;
5760     case 4:
5761       emit2 ("sla a");
5762       emit2 ("rl a");
5763       emit2 ("rl a");
5764       emit2 ("rl a");
5765       break;
5766     case 5:
5767       emit2 ("srl a");
5768       emit2 ("rr a");
5769       emit2 ("rr a");
5770       break;
5771     case 6:
5772       emit2 ("srl a");
5773       emit2 ("rr a");
5774       break;
5775     case 7:
5776       emit2 ("srl a");
5777       break;
5778     }
5779 #else
5780   switch (shCount)
5781     {
5782     case 0:
5783       break;
5784     case 1:
5785       emit2 ("rlca");
5786       break;
5787     case 2:
5788       emit2 ("rlca");
5789       emit2 ("rlca");
5790       break;
5791     case 3:
5792       emit2 ("rlca");
5793       emit2 ("rlca");
5794       emit2 ("rlca");
5795       break;
5796     case 4:
5797       emit2 ("rlca");
5798       emit2 ("rlca");
5799       emit2 ("rlca");
5800       emit2 ("rlca");
5801       break;
5802     case 5:
5803       emit2 ("rrca");
5804       emit2 ("rrca");
5805       emit2 ("rrca");
5806       break;
5807     case 6:
5808       emit2 ("rrca");
5809       emit2 ("rrca");
5810       break;
5811     case 7:
5812       emit2 ("rrca");
5813       break;
5814     }
5815 #endif
5816 }
5817
5818 /*-----------------------------------------------------------------*/
5819 /* AccLsh - left shift accumulator by known count                  */
5820 /*-----------------------------------------------------------------*/
5821 static void
5822 AccLsh (int shCount)
5823 {
5824   static const unsigned char SLMask[] =
5825     {
5826       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5827     };
5828
5829   if (shCount != 0)
5830     {
5831       if (shCount == 1)
5832         {
5833           emit2 ("add a,a");
5834         }
5835       else if (shCount == 2)
5836         {
5837           emit2 ("add a,a");
5838           emit2 ("add a,a");
5839         }
5840       else
5841         {
5842           /* rotate left accumulator */
5843           AccRol (shCount);
5844           /* and kill the lower order bits */
5845           emit2 ("and a,!immedbyte", SLMask[shCount]);
5846         }
5847     }
5848 }
5849
5850 /*-----------------------------------------------------------------*/
5851 /* shiftL1Left2Result - shift left one byte from left to result    */
5852 /*-----------------------------------------------------------------*/
5853 static void
5854 shiftL1Left2Result (operand * left, int offl,
5855                     operand * result, int offr, int shCount)
5856 {
5857   const char *l;
5858   l = aopGet (AOP (left), offl, FALSE);
5859   _moveA (l);
5860   /* shift left accumulator */
5861   AccLsh (shCount);
5862   aopPut (AOP (result), "a", offr);
5863 }
5864
5865
5866 /*-----------------------------------------------------------------*/
5867 /* genlshTwo - left shift two bytes by known amount != 0           */
5868 /*-----------------------------------------------------------------*/
5869 static void
5870 genlshTwo (operand * result, operand * left, int shCount)
5871 {
5872   int size = AOP_SIZE (result);
5873
5874   wassert (size == 2);
5875
5876   /* if shCount >= 8 */
5877   if (shCount >= 8)
5878     {
5879       shCount -= 8;
5880       if (size > 1)
5881         {
5882           if (shCount)
5883             {
5884               movLeft2Result (left, LSB, result, MSB16, 0);
5885               aopPut (AOP (result), "!zero", 0);
5886               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5887             }
5888           else
5889             {
5890               movLeft2Result (left, LSB, result, MSB16, 0);
5891               aopPut (AOP (result), "!zero", 0);
5892             }
5893         }
5894       else
5895         {
5896           aopPut (AOP (result), "!zero", LSB);
5897         }
5898     }
5899   /*  1 <= shCount <= 7 */
5900   else
5901     {
5902       if (size == 1)
5903         {
5904           wassert (0);
5905         }
5906       else
5907         {
5908           shiftL2Left2Result (left, LSB, result, LSB, shCount);
5909         }
5910     }
5911 }
5912
5913 /*-----------------------------------------------------------------*/
5914 /* genlshOne - left shift a one byte quantity by known count       */
5915 /*-----------------------------------------------------------------*/
5916 static void
5917 genlshOne (operand * result, operand * left, int shCount)
5918 {
5919   shiftL1Left2Result (left, LSB, result, LSB, shCount);
5920 }
5921
5922 /*-----------------------------------------------------------------*/
5923 /* genLeftShiftLiteral - left shifting by known count              */
5924 /*-----------------------------------------------------------------*/
5925 static void
5926 genLeftShiftLiteral (operand * left,
5927                      operand * right,
5928                      operand * result,
5929                      iCode * ic)
5930 {
5931   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5932   int size;
5933
5934   freeAsmop (right, NULL, ic);
5935
5936   aopOp (left, ic, FALSE, FALSE);
5937   aopOp (result, ic, FALSE, FALSE);
5938
5939   size = getSize (operandType (result));
5940
5941   /* I suppose that the left size >= result size */
5942   if (shCount == 0)
5943     {
5944       wassert (0);
5945     }
5946
5947   else if (shCount >= (size * 8)) 
5948     {
5949       while (size--)
5950         {
5951           aopPut (AOP (result), "!zero", size);
5952         }
5953     }
5954   else
5955     {
5956       switch (size)
5957         {
5958         case 1:
5959           genlshOne (result, left, shCount);
5960           break;
5961         case 2:
5962           genlshTwo (result, left, shCount);
5963           break;
5964         case 4:
5965           wassertl (0, "Shifting of longs is currently unsupported");
5966           break;
5967         default:
5968           wassert (0);
5969         }
5970     }
5971   freeAsmop (left, NULL, ic);
5972   freeAsmop (result, NULL, ic);
5973 }
5974
5975 /*-----------------------------------------------------------------*/
5976 /* genLeftShift - generates code for left shifting                 */
5977 /*-----------------------------------------------------------------*/
5978 static void
5979 genLeftShift (iCode * ic)
5980 {
5981   int size, offset;
5982   const char *l;
5983   symbol *tlbl, *tlbl1;
5984   operand *left, *right, *result;
5985
5986   right = IC_RIGHT (ic);
5987   left = IC_LEFT (ic);
5988   result = IC_RESULT (ic);
5989
5990   aopOp (right, ic, FALSE, FALSE);
5991
5992   /* if the shift count is known then do it
5993      as efficiently as possible */
5994   if (AOP_TYPE (right) == AOP_LIT)
5995     {
5996       genLeftShiftLiteral (left, right, result, ic);
5997       return;
5998     }
5999
6000   /* shift count is unknown then we have to form a loop get the loop
6001      count in B : Note: we take only the lower order byte since
6002      shifting more that 32 bits make no sense anyway, ( the largest
6003      size of an object can be only 32 bits ) */
6004   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6005   emit2 ("inc a");
6006   freeAsmop (right, NULL, ic);
6007   aopOp (left, ic, FALSE, FALSE);
6008   aopOp (result, ic, FALSE, FALSE);
6009
6010   /* now move the left to the result if they are not the
6011      same */
6012
6013   if (!sameRegs (AOP (left), AOP (result)))
6014     {
6015
6016       size = AOP_SIZE (result);
6017       offset = 0;
6018       while (size--)
6019         {
6020           l = aopGet (AOP (left), offset, FALSE);
6021           aopPut (AOP (result), l, offset);
6022           offset++;
6023         }
6024     }
6025
6026   tlbl = newiTempLabel (NULL);
6027   size = AOP_SIZE (result);
6028   offset = 0;
6029   tlbl1 = newiTempLabel (NULL);
6030
6031   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6032   emitLabel (tlbl->key + 100);
6033   l = aopGet (AOP (result), offset, FALSE);
6034
6035   while (size--)
6036     {
6037       l = aopGet (AOP (result), offset, FALSE);
6038
6039       if (offset == 0)
6040         {
6041           emit2 ("sla %s", l);
6042         }
6043       else
6044         {
6045           emit2 ("rl %s", l);
6046         }
6047       offset++;
6048     }
6049   emitLabel (tlbl1->key + 100);
6050   emit2 ("dec a");
6051   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6052
6053   freeAsmop (left, NULL, ic);
6054   freeAsmop (result, NULL, ic);
6055 }
6056
6057 /*-----------------------------------------------------------------*/
6058 /* genrshOne - left shift two bytes by known amount != 0           */
6059 /*-----------------------------------------------------------------*/
6060 static void
6061 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6062 {
6063   /* Errk */
6064   int size = AOP_SIZE (result);
6065   const char *l;
6066
6067   wassert (size == 1);
6068   wassert (shCount < 8);
6069
6070   l = aopGet (AOP (left), 0, FALSE);
6071
6072   if (AOP (result)->type == AOP_REG)
6073     {
6074       aopPut (AOP (result), l, 0);
6075       l = aopGet (AOP (result), 0, FALSE);
6076       while (shCount--)
6077         {
6078           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6079         }
6080     }
6081   else
6082     {
6083       _moveA (l);
6084       while (shCount--)
6085         {
6086           emit2 ("%s a", is_signed ? "sra" : "srl");
6087         }
6088       aopPut (AOP (result), "a", 0);
6089     }
6090 }
6091
6092 /*-----------------------------------------------------------------*/
6093 /* AccRsh - right shift accumulator by known count                 */
6094 /*-----------------------------------------------------------------*/
6095 static void
6096 AccRsh (int shCount)
6097 {
6098   static const unsigned char SRMask[] =
6099     {
6100       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6101     };
6102
6103   if (shCount != 0)
6104     {
6105       /* rotate right accumulator */
6106       AccRol (8 - shCount);
6107       /* and kill the higher order bits */
6108       emit2 ("and a,!immedbyte", SRMask[shCount]);
6109     }
6110 }
6111
6112 /*-----------------------------------------------------------------*/
6113 /* shiftR1Left2Result - shift right one byte from left to result   */
6114 /*-----------------------------------------------------------------*/
6115 static void
6116 shiftR1Left2Result (operand * left, int offl,
6117                     operand * result, int offr,
6118                     int shCount, int sign)
6119 {
6120   _moveA (aopGet (AOP (left), offl, FALSE));
6121   if (sign)
6122     {
6123       while (shCount--)
6124         {
6125           emit2 ("%s a", sign ? "sra" : "srl");
6126         }
6127     }
6128   else
6129     {
6130       AccRsh (shCount);
6131     }
6132   aopPut (AOP (result), "a", offr);
6133 }
6134
6135 /*-----------------------------------------------------------------*/
6136 /* genrshTwo - right shift two bytes by known amount != 0          */
6137 /*-----------------------------------------------------------------*/
6138 static void
6139 genrshTwo (operand * result, operand * left,
6140            int shCount, int sign)
6141 {
6142   /* if shCount >= 8 */
6143   if (shCount >= 8)
6144     {
6145       shCount -= 8;
6146       if (shCount)
6147         {
6148           shiftR1Left2Result (left, MSB16, result, LSB,
6149                               shCount, sign);
6150         }
6151       else
6152         {
6153           movLeft2Result (left, MSB16, result, LSB, sign);
6154         }
6155       if (sign)
6156         {
6157           /* Sign extend the result */
6158           _moveA(aopGet (AOP (result), 0, FALSE));
6159           emit2 ("rlc a");
6160           emit2 ("sbc a,a");
6161
6162           aopPut (AOP (result), ACC_NAME, MSB16);
6163         }
6164       else
6165         {
6166           aopPut (AOP (result), "!zero", 1);
6167         }
6168     }
6169   /*  1 <= shCount <= 7 */
6170   else
6171     {
6172       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6173     }
6174 }
6175
6176 /*-----------------------------------------------------------------*/
6177 /* genRightShiftLiteral - left shifting by known count              */
6178 /*-----------------------------------------------------------------*/
6179 static void
6180 genRightShiftLiteral (operand * left,
6181                       operand * right,
6182                       operand * result,
6183                       iCode * ic,
6184                       int sign)
6185 {
6186   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6187   int size;
6188
6189   freeAsmop (right, NULL, ic);
6190
6191   aopOp (left, ic, FALSE, FALSE);
6192   aopOp (result, ic, FALSE, FALSE);
6193
6194   size = getSize (operandType (result));
6195
6196   /* I suppose that the left size >= result size */
6197   if (shCount == 0)
6198     {
6199       wassert (0);
6200     }
6201
6202   else if (shCount >= (size * 8)) {
6203     const char *s;
6204     if (!SPEC_USIGN(getSpec(operandType(left)))) {
6205       _moveA(aopGet (AOP (left), 0, FALSE));
6206       emit2 ("rlc a");
6207       emit2 ("sbc a,a");
6208       s=ACC_NAME;
6209     } else {
6210       s="!zero";
6211     }
6212     while (size--)
6213       aopPut (AOP (result), s, size);
6214   }
6215   else
6216     {
6217       switch (size)
6218         {
6219         case 1:
6220           genrshOne (result, left, shCount, sign);
6221           break;
6222         case 2:
6223           genrshTwo (result, left, shCount, sign);
6224           break;
6225         case 4:
6226           wassertl (0, "Asked to shift right a long which should be a function call");
6227           break;
6228         default:
6229           wassertl (0, "Entered default case in right shift delegate");
6230         }
6231     }
6232   freeAsmop (left, NULL, ic);
6233   freeAsmop (result, NULL, ic);
6234 }
6235
6236 /*-----------------------------------------------------------------*/
6237 /* genRightShift - generate code for right shifting                */
6238 /*-----------------------------------------------------------------*/
6239 static void
6240 genRightShift (iCode * ic)
6241 {
6242   operand *right, *left, *result;
6243   sym_link *retype;
6244   int size, offset, first = 1;
6245   const char *l;
6246   bool is_signed;
6247
6248   symbol *tlbl, *tlbl1;
6249
6250   /* if signed then we do it the hard way preserve the
6251      sign bit moving it inwards */
6252   retype = getSpec (operandType (IC_RESULT (ic)));
6253
6254   is_signed = !SPEC_USIGN (retype);
6255
6256   /* signed & unsigned types are treated the same : i.e. the
6257      signed is NOT propagated inwards : quoting from the
6258      ANSI - standard : "for E1 >> E2, is equivalent to division
6259      by 2**E2 if unsigned or if it has a non-negative value,
6260      otherwise the result is implementation defined ", MY definition
6261      is that the sign does not get propagated */
6262
6263   right = IC_RIGHT (ic);
6264   left = IC_LEFT (ic);
6265   result = IC_RESULT (ic);
6266
6267   aopOp (right, ic, FALSE, FALSE);
6268
6269   /* if the shift count is known then do it
6270      as efficiently as possible */
6271   if (AOP_TYPE (right) == AOP_LIT)
6272     {
6273       genRightShiftLiteral (left, right, result, ic, is_signed);
6274       return;
6275     }
6276
6277   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6278   emit2 ("inc a");
6279   freeAsmop (right, NULL, ic);
6280
6281   aopOp (left, ic, FALSE, FALSE);
6282   aopOp (result, ic, FALSE, FALSE);
6283
6284   /* now move the left to the result if they are not the
6285      same */
6286   if (!sameRegs (AOP (left), AOP (result)))
6287     {
6288
6289       size = AOP_SIZE (result);
6290       offset = 0;
6291       while (size--)
6292         {
6293           l = aopGet (AOP (left), offset, FALSE);
6294           aopPut (AOP (result), l, offset);
6295           offset++;
6296         }
6297     }
6298
6299   tlbl = newiTempLabel (NULL);
6300   tlbl1 = newiTempLabel (NULL);
6301   size = AOP_SIZE (result);
6302   offset = size - 1;
6303
6304   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6305   emitLabel (tlbl->key + 100);
6306   while (size--)
6307     {
6308       l = aopGet (AOP (result), offset--, FALSE);
6309       if (first)
6310         {
6311           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6312           first = 0;
6313         }
6314       else
6315         {
6316           emit2 ("rr %s", l);
6317         }
6318     }
6319   emitLabel (tlbl1->key + 100);
6320   emit2 ("dec a");
6321   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6322
6323   freeAsmop (left, NULL, ic);
6324   freeAsmop (result, NULL, ic);
6325 }
6326
6327
6328 /*-----------------------------------------------------------------*/
6329 /* genUnpackBits - generates code for unpacking bits               */
6330 /*-----------------------------------------------------------------*/
6331 static void
6332 genUnpackBits (operand * result, int pair)
6333 {
6334   int offset = 0;       /* result byte offset */
6335   int rsize;            /* result size */
6336   int rlen = 0;         /* remaining bitfield length */
6337   sym_link *etype;      /* bitfield type information */
6338   int blen;             /* bitfield length */
6339   int bstr;             /* bitfield starting bit within byte */
6340
6341   emitDebug ("; genUnpackBits");
6342
6343   etype = getSpec (operandType (result));
6344   rsize = getSize (operandType (result));
6345   blen = SPEC_BLEN (etype);
6346   bstr = SPEC_BSTR (etype);
6347
6348   /* If the bitfield length is less than a byte */
6349   if (blen < 8)
6350     {
6351       emit2 ("ld a,!*pair", _pairs[pair].name);
6352       AccRsh (bstr);
6353       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6354       aopPut (AOP (result), "a", offset++);
6355       goto finish;
6356     }
6357
6358   /* TODO: what if pair == PAIR_DE ? */
6359   if (getPairId (AOP (result)) == PAIR_HL)
6360     {
6361       wassertl (rsize == 2, "HL must be of size 2");
6362       emit2 ("ld a,!*hl");
6363       emit2 ("inc hl");
6364       emit2 ("ld h,!*hl");
6365       emit2 ("ld l,a");
6366       emit2 ("ld a,h");
6367       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6368       emit2 ("ld h,a");
6369       spillPair (PAIR_HL);
6370       return;
6371     }
6372
6373   /* Bit field did not fit in a byte. Copy all
6374      but the partial byte at the end.  */
6375   for (rlen=blen;rlen>=8;rlen-=8)
6376     {
6377       emit2 ("ld a,!*pair", _pairs[pair].name);
6378       aopPut (AOP (result), "a", offset++);
6379       if (rlen>8)
6380         {
6381           emit2 ("inc %s", _pairs[pair].name);
6382           _G.pairs[pair].offset++;
6383         }
6384     }
6385
6386   /* Handle the partial byte at the end */
6387   if (rlen)
6388     {
6389       emit2 ("ld a,!*pair", _pairs[pair].name);
6390       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6391       aopPut (AOP (result), "a", offset++);
6392     }
6393
6394 finish:
6395   if (offset < rsize)
6396     {
6397       rsize -= offset;
6398       while (rsize--)
6399         aopPut (AOP (result), "!zero", offset++);
6400     }
6401 }
6402
6403 /*-----------------------------------------------------------------*/
6404 /* genGenPointerGet -  get value from generic pointer space        */
6405 /*-----------------------------------------------------------------*/
6406 static void
6407 genGenPointerGet (operand * left,
6408                   operand * result, iCode * ic)
6409 {
6410   int size, offset;
6411   sym_link *retype = getSpec (operandType (result));
6412   int pair = PAIR_HL;
6413
6414   if (IS_GB)
6415     pair = PAIR_DE;
6416
6417   aopOp (left, ic, FALSE, FALSE);
6418   aopOp (result, ic, FALSE, FALSE);
6419
6420   size = AOP_SIZE (result);
6421
6422   if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6423     {
6424       /* Just do it */
6425       if (isPtrPair (AOP (left)))
6426         {
6427           tsprintf (buffer, sizeof(buffer), 
6428                     "!*pair", getPairName (AOP (left)));
6429           aopPut (AOP (result), buffer, 0);
6430         }
6431       else
6432         {
6433           emit2 ("ld a,!*pair", getPairName (AOP (left)));
6434           aopPut (AOP (result), "a", 0);
6435         }
6436       freeAsmop (left, NULL, ic);
6437       goto release;
6438     }
6439
6440   if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6441     {
6442       /* Just do it */
6443       offset = 0;
6444       while (size--) 
6445         {
6446           char at[20];
6447           tsprintf (at, sizeof(at), "!*iyx", offset);
6448           aopPut (AOP (result), at, offset);
6449           offset++;
6450         }
6451  
6452       freeAsmop (left, NULL, ic);
6453       goto release;
6454     }
6455
6456   /* For now we always load into IY */
6457   /* if this is remateriazable */
6458   fetchPair (pair, AOP (left));
6459
6460   /* if bit then unpack */
6461   if (IS_BITVAR (retype))
6462     {
6463       genUnpackBits (result, pair);
6464       freeAsmop (left, NULL, ic);
6465       goto release;
6466       //wassert (0);
6467     }
6468   else if (getPairId (AOP (result)) == PAIR_HL)
6469     {
6470       wassertl (size == 2, "HL must be of size 2");
6471       emit2 ("ld a,!*hl");
6472       emit2 ("inc hl");
6473       emit2 ("ld h,!*hl");
6474       emit2 ("ld l,a");
6475       spillPair (PAIR_HL);
6476     }
6477   else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6478     {
6479       size = AOP_SIZE (result);
6480       offset = 0;
6481
6482       while (size--)
6483         {
6484           /* PENDING: make this better */
6485           if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6486             {
6487               aopPut (AOP (result), "!*hl", offset++);
6488             }
6489           else
6490             {
6491               emit2 ("ld a,!*pair", _pairs[pair].name);
6492               aopPut (AOP (result), "a", offset++);
6493             }
6494           if (size)
6495             {
6496               emit2 ("inc %s", _pairs[pair].name);
6497               _G.pairs[pair].offset++;
6498             }
6499         }
6500       /* Fixup HL back down */
6501       for (size = AOP_SIZE (result)-1; size; size--)
6502         {
6503           emit2 ("dec %s", _pairs[pair].name);
6504         }
6505     }
6506   else
6507     {
6508       size = AOP_SIZE (result);
6509       offset = 0;
6510
6511       while (size--)
6512         {
6513           /* PENDING: make this better */
6514           if (!IS_GB && 
6515               (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6516             {
6517               aopPut (AOP (result), "!*hl", offset++);
6518             }
6519           else
6520             {
6521               emit2 ("ld a,!*pair", _pairs[pair].name);
6522               aopPut (AOP (result), "a", offset++);
6523             }
6524           if (size)
6525             {
6526               emit2 ("inc %s", _pairs[pair].name);
6527               _G.pairs[pair].offset++;
6528             }
6529         }
6530     }
6531
6532   freeAsmop (left, NULL, ic);
6533
6534 release:
6535   freeAsmop (result, NULL, ic);
6536 }
6537
6538 /*-----------------------------------------------------------------*/
6539 /* genPointerGet - generate code for pointer get                   */
6540 /*-----------------------------------------------------------------*/
6541 static void
6542 genPointerGet (iCode * ic)
6543 {
6544   operand *left, *result;
6545   sym_link *type, *etype;
6546
6547   left = IC_LEFT (ic);
6548   result = IC_RESULT (ic);
6549
6550   /* depending on the type of pointer we need to
6551      move it to the correct pointer register */
6552   type = operandType (left);
6553   etype = getSpec (type);
6554
6555   genGenPointerGet (left, result, ic);
6556 }
6557
6558 bool
6559 isRegOrLit (asmop * aop)
6560 {
6561   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6562     return TRUE;
6563   return FALSE;
6564 }
6565
6566
6567 /*-----------------------------------------------------------------*/
6568 /* genPackBits - generates code for packed bit storage             */
6569 /*-----------------------------------------------------------------*/
6570 static void
6571 genPackBits (sym_link * etype,
6572              operand * right,
6573              int pair,
6574              iCode *ic)
6575 {
6576   int offset = 0;       /* source byte offset */
6577   int rlen = 0;         /* remaining bitfield length */
6578   int blen;             /* bitfield length */
6579   int bstr;             /* bitfield starting bit within byte */
6580   int litval;           /* source literal value (if AOP_LIT) */
6581   unsigned char mask;   /* bitmask within current byte */
6582   int extraPair;        /* a tempory register */
6583   bool needPopExtra=0;  /* need to restore original value of temp reg */
6584
6585   emitDebug (";     genPackBits","");
6586
6587   blen = SPEC_BLEN (etype);
6588   bstr = SPEC_BSTR (etype);
6589
6590   /* If the bitfield length is less than a byte */
6591   if (blen < 8)
6592     {
6593       mask = ((unsigned char) (0xFF << (blen + bstr)) |
6594               (unsigned char) (0xFF >> (8 - bstr)));
6595
6596       if (AOP_TYPE (right) == AOP_LIT)
6597         {
6598           /* Case with a bitfield length <8 and literal source
6599           */
6600           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6601           litval <<= bstr;
6602           litval &= (~mask) & 0xff;
6603           emit2 ("ld a,!*pair", _pairs[pair].name);
6604           if ((mask|litval)!=0xff)
6605             emit2 ("and a,!immedbyte", mask);
6606           if (litval)
6607             emit2 ("or a,!immedbyte", litval);
6608           emit2 ("ld !*pair,a", _pairs[pair].name);
6609           return;
6610         }
6611       else
6612         {
6613           /* Case with a bitfield length <8 and arbitrary source
6614           */
6615           _moveA (aopGet (AOP (right), 0, FALSE));
6616           /* shift and mask source value */
6617           AccLsh (bstr);
6618           emit2 ("and a,!immedbyte", (~mask) & 0xff);
6619
6620           extraPair = getFreePairId(ic);
6621           if (extraPair == PAIR_INVALID)
6622             {
6623               extraPair = PAIR_BC;
6624               if (getPairId (AOP (right)) != PAIR_BC
6625                   || !isLastUse (ic, right))
6626                 {
6627                   _push (extraPair);
6628                   needPopExtra = 1;
6629                 }
6630             }
6631           emit2 ("ld %s,a", _pairs[extraPair].l);
6632           emit2 ("ld a,!*pair", _pairs[pair].name);
6633
6634           emit2 ("and a,!immedbyte", mask);
6635           emit2 ("or a,%s", _pairs[extraPair].l);
6636           emit2 ("ld !*pair,a", _pairs[pair].name);
6637           if (needPopExtra)
6638             _pop (extraPair);
6639           return;
6640         }
6641     }
6642
6643   /* Bit length is greater than 7 bits. In this case, copy  */
6644   /* all except the partial byte at the end                 */
6645   for (rlen=blen;rlen>=8;rlen-=8)
6646     {
6647       emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6648       emit2 ("ld !*pair,a", _pairs[pair].name);
6649       if (rlen>8)
6650         {
6651           emit2 ("inc %s", _pairs[pair].name);
6652           _G.pairs[pair].offset++;
6653         }
6654     }
6655
6656   /* If there was a partial byte at the end */
6657   if (rlen)
6658     {
6659       mask = (((unsigned char) -1 << rlen) & 0xff);
6660       
6661       if (AOP_TYPE (right) == AOP_LIT)
6662         {
6663           /* Case with partial byte and literal source
6664           */
6665           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6666           litval >>= (blen-rlen);
6667           litval &= (~mask) & 0xff;
6668           emit2 ("ld a,!*pair", _pairs[pair].name);
6669           if ((mask|litval)!=0xff)
6670             emit2 ("and a,!immedbyte", mask);
6671           if (litval)
6672             emit2 ("or a,!immedbyte", litval);
6673         }
6674       else
6675         {
6676           /* Case with partial byte and arbitrary source
6677           */
6678           _moveA (aopGet (AOP (right), offset++, FALSE));
6679           emit2 ("and a,!immedbyte", (~mask) & 0xff);
6680
6681           extraPair = getFreePairId(ic);
6682           if (extraPair == PAIR_INVALID)
6683             {
6684               extraPair = getPairId (AOP (right));
6685               if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6686                 extraPair = PAIR_BC;
6687
6688               if (getPairId (AOP (right)) != PAIR_BC
6689                   || !isLastUse (ic, right))
6690                 {
6691                   _push (extraPair);
6692                   needPopExtra = 1;
6693                 }
6694             }
6695           emit2 ("ld %s,a", _pairs[extraPair].l);
6696           emit2 ("ld a,!*pair", _pairs[pair].name);
6697
6698           emit2 ("and a,!immedbyte", mask);
6699           emit2 ("or a,%s", _pairs[extraPair].l);
6700           if (needPopExtra)
6701             _pop (extraPair);
6702
6703         }
6704       emit2 ("ld !*pair,a", _pairs[pair].name);
6705     }
6706 }
6707
6708
6709 /*-----------------------------------------------------------------*/
6710 /* genGenPointerSet - stores the value into a pointer location        */
6711 /*-----------------------------------------------------------------*/
6712 static void
6713 genGenPointerSet (operand * right,
6714                   operand * result, iCode * ic)
6715 {
6716   int size, offset;
6717   sym_link *retype = getSpec (operandType (right));
6718   sym_link *letype = getSpec (operandType (result));
6719   PAIR_ID pairId = PAIR_HL;
6720   bool isBitvar;
6721   
6722   aopOp (result, ic, FALSE, FALSE);
6723   aopOp (right, ic, FALSE, FALSE);
6724
6725   if (IS_GB)
6726     pairId = PAIR_DE;
6727
6728   size = AOP_SIZE (right);
6729
6730   isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6731   emitDebug("; isBitvar = %d", isBitvar);
6732
6733   /* Handle the exceptions first */
6734   if (isPair (AOP (result)) && size == 1 && !isBitvar)
6735     {
6736       /* Just do it */
6737       const char *l = aopGet (AOP (right), 0, FALSE);
6738       const char *pair = getPairName (AOP (result));
6739       if (canAssignToPtr (l) && isPtr (pair))
6740         {
6741           emit2 ("ld !*pair,%s", pair, l);
6742         }
6743       else
6744         {
6745           _moveA (l);
6746           emit2 ("ld !*pair,a", pair);
6747         }
6748       goto release;
6749     }
6750   
6751   if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6752     {
6753       /* Just do it */
6754       const char *l = aopGet (AOP (right), 0, FALSE);
6755
6756       offset = 0;
6757       while (size--) 
6758         {
6759           if (canAssignToPtr (l))
6760             {
6761               emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6762             }
6763           else
6764             {
6765               _moveA (aopGet (AOP (right), offset, FALSE));
6766               emit2 ("ld !*iyx,a", offset);
6767             }
6768           offset++;
6769         }
6770       goto release;
6771     }
6772   else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6773            && !isBitvar)
6774     {
6775       offset = 0;
6776
6777       while (size--)
6778         {
6779           const char *l = aopGet (AOP (right), offset, FALSE);
6780           if (isRegOrLit (AOP (right)) && !IS_GB)
6781             {
6782               emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6783             }
6784           else
6785             {
6786               _moveA (l);
6787               emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6788             }
6789           if (size)
6790             {
6791               emit2 ("inc %s", _pairs[PAIR_HL].name);
6792               _G.pairs[PAIR_HL].offset++;
6793             }
6794           offset++;
6795         }
6796
6797       /* Fixup HL back down */
6798       for (size = AOP_SIZE (right)-1; size; size--)
6799         {
6800           emit2 ("dec %s", _pairs[PAIR_HL].name);
6801         }
6802       goto release;
6803     }
6804
6805   /* if the operand is already in dptr
6806      then we do nothing else we move the value to dptr */
6807   if (AOP_TYPE (result) != AOP_STR)
6808     {
6809       fetchPair (pairId, AOP (result));
6810     }
6811   /* so hl know contains the address */
6812   freeAsmop (result, NULL, ic);
6813
6814   /* if bit then unpack */
6815   if (isBitvar)
6816     {
6817       genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6818       goto release;
6819       //wassert (0);
6820     }
6821   else
6822     {
6823       offset = 0;
6824
6825       while (size--)
6826         {
6827           const char *l = aopGet (AOP (right), offset, FALSE);
6828           if (isRegOrLit (AOP (right)) && !IS_GB)
6829             {
6830               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6831             }
6832           else
6833             {
6834               _moveA (l);
6835               emit2 ("ld !*pair,a", _pairs[pairId].name);
6836             }
6837           if (size)
6838             {
6839               emit2 ("inc %s", _pairs[pairId].name);
6840               _G.pairs[pairId].offset++;
6841             }
6842           offset++;
6843         }
6844     }
6845 release:
6846   freeAsmop (right, NULL, ic);
6847 }
6848
6849 /*-----------------------------------------------------------------*/
6850 /* genPointerSet - stores the value into a pointer location        */
6851 /*-----------------------------------------------------------------*/
6852 static void
6853 genPointerSet (iCode * ic)
6854 {
6855   operand *right, *result;
6856   sym_link *type, *etype;
6857
6858   right = IC_RIGHT (ic);
6859   result = IC_RESULT (ic);
6860
6861   /* depending on the type of pointer we need to
6862      move it to the correct pointer register */
6863   type = operandType (result);
6864   etype = getSpec (type);
6865
6866   genGenPointerSet (right, result, ic);
6867 }
6868
6869 /*-----------------------------------------------------------------*/
6870 /* genIfx - generate code for Ifx statement                        */
6871 /*-----------------------------------------------------------------*/
6872 static void
6873 genIfx (iCode * ic, iCode * popIc)
6874 {
6875   operand *cond = IC_COND (ic);
6876   int isbit = 0;
6877
6878   aopOp (cond, ic, FALSE, TRUE);
6879
6880   /* get the value into acc */
6881   if (AOP_TYPE (cond) != AOP_CRY)
6882     _toBoolean (cond);
6883   else
6884     isbit = 1;
6885   /* the result is now in the accumulator */
6886   freeAsmop (cond, NULL, ic);
6887
6888   /* if there was something to be popped then do it */
6889   if (popIc)
6890     genIpop (popIc);
6891
6892   /* if the condition is  a bit variable */
6893   if (isbit && IS_ITEMP (cond) &&
6894       SPIL_LOC (cond))
6895     genIfxJump (ic, SPIL_LOC (cond)->rname);
6896   else if (isbit && !IS_ITEMP (cond))
6897     genIfxJump (ic, OP_SYMBOL (cond)->rname);
6898   else
6899     genIfxJump (ic, "a");
6900
6901   ic->generated = 1;
6902 }
6903
6904 /*-----------------------------------------------------------------*/
6905 /* genAddrOf - generates code for address of                       */
6906 /*-----------------------------------------------------------------*/
6907 static void
6908 genAddrOf (iCode * ic)
6909 {
6910   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6911
6912   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6913
6914   /* if the operand is on the stack then we
6915      need to get the stack offset of this
6916      variable */
6917   if (IS_GB)
6918     {
6919       if (sym->onStack)
6920         {
6921           spillCached ();
6922           if (sym->stack <= 0)
6923             {
6924               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6925             }
6926           else
6927             {
6928               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6929             }
6930           commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6931         }
6932       else
6933         {
6934           emit2 ("ld de,!hashedstr", sym->rname);
6935           commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6936         }
6937     }
6938   else
6939     {
6940       spillCached ();
6941       if (sym->onStack)
6942         {
6943           /* if it has an offset  then we need to compute it */
6944           if (sym->stack > 0)
6945             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6946           else
6947             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6948           emit2 ("add hl,sp");
6949         }
6950       else
6951         {
6952           emit2 ("ld hl,!hashedstr", sym->rname);
6953         }
6954       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6955     }
6956   freeAsmop (IC_RESULT (ic), NULL, ic);
6957 }
6958
6959 /*-----------------------------------------------------------------*/
6960 /* genAssign - generate code for assignment                        */
6961 /*-----------------------------------------------------------------*/
6962 static void
6963 genAssign (iCode * ic)
6964 {
6965   operand *result, *right;
6966   int size, offset;
6967   unsigned long lit = 0L;
6968
6969   result = IC_RESULT (ic);
6970   right = IC_RIGHT (ic);
6971
6972   /* Dont bother assigning if they are the same */
6973   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6974     {
6975       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6976       return;
6977     }
6978
6979   aopOp (right, ic, FALSE, FALSE);
6980   aopOp (result, ic, TRUE, FALSE);
6981
6982   /* if they are the same registers */
6983   if (sameRegs (AOP (right), AOP (result)))
6984     {
6985       emitDebug ("; (registers are the same)");
6986       goto release;
6987     }
6988
6989   /* if the result is a bit */
6990   if (AOP_TYPE (result) == AOP_CRY)
6991     {
6992       wassertl (0, "Tried to assign to a bit");
6993     }
6994
6995   /* general case */
6996   size = AOP_SIZE (result);
6997   offset = 0;
6998
6999   if (AOP_TYPE (right) == AOP_LIT)
7000     {
7001       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7002     }
7003
7004   if (isPair (AOP (result)))
7005     {
7006       fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7007     }
7008   else if ((size > 1) &&
7009            (AOP_TYPE (result) != AOP_REG) &&
7010            (AOP_TYPE (right) == AOP_LIT) &&
7011            !IS_FLOAT (operandType (right)) &&
7012            (lit < 256L))
7013     {
7014       bool fXored = FALSE;
7015       offset = 0;
7016       /* Work from the top down.
7017          Done this way so that we can use the cached copy of 0
7018          in A for a fast clear */
7019       while (size--)
7020         {
7021           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7022             {
7023               if (!fXored && size > 1)
7024                 {
7025                   emit2 ("xor a,a");
7026                   fXored = TRUE;
7027                 }
7028               if (fXored)
7029                 {
7030                   aopPut (AOP (result), "a", offset);
7031                 }
7032               else
7033                 {
7034                   aopPut (AOP (result), "!zero", offset);
7035                 }
7036             }
7037           else
7038             aopPut (AOP (result),
7039                     aopGet (AOP (right), offset, FALSE),
7040                     offset);
7041           offset++;
7042         }
7043     }
7044   else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7045     {
7046       emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7047       aopPut (AOP (result), "l", LSB);
7048       aopPut (AOP (result), "h", MSB16);
7049     }
7050   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7051     {
7052       /* Special case.  Load into a and d, then load out. */
7053       _moveA (aopGet (AOP (right), 0, FALSE));
7054       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7055       aopPut (AOP (result), "a", 0);
7056       aopPut (AOP (result), "e", 1);
7057     }
7058   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7059     {
7060       /* Special case - simple memcpy */
7061       aopGet (AOP (right), LSB, FALSE);
7062       emit2 ("ld d,h");
7063       emit2 ("ld e,l");
7064       aopGet (AOP (result), LSB, FALSE);
7065
7066       while (size--)
7067         {
7068           emit2 ("ld a,(de)");
7069           /* Peephole will optimise this. */
7070           emit2 ("ld (hl),a");
7071
7072           if (size != 0)
7073             {
7074               emit2 ("inc hl");
7075               emit2 ("inc de");
7076             }
7077         }
7078       spillPair (PAIR_HL);
7079     }
7080   else
7081     {
7082       while (size--)
7083         {
7084           /* PENDING: do this check better */
7085           if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7086             {
7087               _moveA (aopGet (AOP (right), offset, FALSE));
7088               aopPut (AOP (result), "a", offset);
7089             }
7090           else
7091             aopPut (AOP (result),
7092                     aopGet (AOP (right), offset, FALSE),
7093                     offset);
7094           offset++;
7095         }
7096     }
7097
7098 release:
7099   freeAsmop (right, NULL, ic);
7100   freeAsmop (result, NULL, ic);
7101 }
7102
7103 /*-----------------------------------------------------------------*/
7104 /* genJumpTab - genrates code for jump table                       */
7105 /*-----------------------------------------------------------------*/
7106 static void
7107 genJumpTab (iCode * ic)
7108 {
7109   symbol *jtab;
7110   const char *l;
7111
7112   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7113   /* get the condition into accumulator */
7114   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7115   if (!IS_GB)
7116     emit2 ("push de");
7117   emit2 ("ld e,%s", l);
7118   emit2 ("ld d,!zero");
7119   jtab = newiTempLabel (NULL);
7120   spillCached ();
7121   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7122   emit2 ("add hl,de");
7123   emit2 ("add hl,de");
7124   emit2 ("add hl,de");
7125   freeAsmop (IC_JTCOND (ic), NULL, ic);
7126   if (!IS_GB)
7127     emit2 ("pop de");
7128   emit2 ("jp !*hl");
7129   emitLabel (jtab->key + 100);
7130   /* now generate the jump labels */
7131   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7132        jtab = setNextItem (IC_JTLABELS (ic)))
7133     emit2 ("jp !tlabel", jtab->key + 100);
7134 }
7135
7136 /*-----------------------------------------------------------------*/
7137 /* genCast - gen code for casting                                  */
7138 /*-----------------------------------------------------------------*/
7139 static void
7140 genCast (iCode * ic)
7141 {
7142   operand *result = IC_RESULT (ic);
7143   sym_link *rtype = operandType (IC_RIGHT (ic));
7144   operand *right = IC_RIGHT (ic);
7145   int size, offset;
7146
7147   /* if they are equivalent then do nothing */
7148   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7149     return;
7150
7151   aopOp (right, ic, FALSE, FALSE);
7152   aopOp (result, ic, FALSE, FALSE);
7153
7154   /* if the result is a bit */
7155   if (AOP_TYPE (result) == AOP_CRY)
7156     {
7157       wassertl (0, "Tried to cast to a bit");
7158     }
7159
7160   /* if they are the same size : or less */
7161   if (AOP_SIZE (result) <= AOP_SIZE (right))
7162     {
7163
7164       /* if they are in the same place */
7165       if (sameRegs (AOP (right), AOP (result)))
7166         goto release;
7167
7168       /* if they in different places then copy */
7169       size = AOP_SIZE (result);
7170       offset = 0;
7171       while (size--)
7172         {
7173           aopPut (AOP (result),
7174                   aopGet (AOP (right), offset, FALSE),
7175                   offset);
7176           offset++;
7177         }
7178       goto release;
7179     }
7180
7181   /* So we now know that the size of destination is greater
7182      than the size of the source */
7183   /* we move to result for the size of source */
7184   size = AOP_SIZE (right);
7185   offset = 0;
7186   while (size--)
7187     {
7188       aopPut (AOP (result),
7189               aopGet (AOP (right), offset, FALSE),
7190               offset);
7191       offset++;
7192     }
7193
7194   /* now depending on the sign of the destination */
7195   size = AOP_SIZE (result) - AOP_SIZE (right);
7196   /* Unsigned or not an integral type - right fill with zeros */
7197   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7198     {
7199       while (size--)
7200         aopPut (AOP (result), "!zero", offset++);
7201     }
7202   else
7203     {
7204       /* we need to extend the sign :{ */
7205         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7206                         FALSE);
7207       _moveA (l);
7208       emit2 ("rla ");
7209       emit2 ("sbc a,a");
7210       while (size--)
7211         aopPut (AOP (result), "a", offset++);
7212     }
7213
7214 release:
7215   freeAsmop (right, NULL, ic);
7216   freeAsmop (result, NULL, ic);
7217 }
7218
7219 /*-----------------------------------------------------------------*/
7220 /* genReceive - generate code for a receive iCode                  */
7221 /*-----------------------------------------------------------------*/
7222 static void
7223 genReceive (iCode * ic)
7224 {
7225   if (isOperandInFarSpace (IC_RESULT (ic)) &&
7226       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7227        IS_TRUE_SYMOP (IC_RESULT (ic))))
7228     {
7229       wassert (0);
7230     }
7231   else
7232     {
7233         // PENDING: HACK
7234         int size;
7235         int i;
7236
7237         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7238         size = AOP_SIZE(IC_RESULT(ic));
7239
7240         for (i = 0; i < size; i++) {
7241             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7242         }
7243     }
7244
7245   freeAsmop (IC_RESULT (ic), NULL, ic);
7246 }
7247
7248 /*-----------------------------------------------------------------*/
7249 /* genDummyRead - generate code for dummy read of volatiles        */
7250 /*-----------------------------------------------------------------*/
7251 static void
7252 genDummyRead (iCode * ic)
7253 {
7254   operand *op;
7255   int size, offset;
7256
7257   op = IC_RIGHT (ic);
7258   if (op && IS_SYMOP (op))
7259     {
7260       aopOp (op, ic, FALSE, FALSE);
7261   
7262       /* general case */
7263       size = AOP_SIZE (op);
7264       offset = 0;
7265
7266       while (size--)
7267         {
7268           _moveA (aopGet (AOP (op), offset, FALSE));
7269           offset++;
7270         }
7271
7272       freeAsmop (op, NULL, ic);
7273     }
7274   
7275   op = IC_LEFT (ic);
7276   if (op && IS_SYMOP (op))
7277     {
7278       aopOp (op, ic, FALSE, FALSE);
7279   
7280       /* general case */
7281       size = AOP_SIZE (op);
7282       offset = 0;
7283
7284       while (size--)
7285         {
7286           _moveA (aopGet (AOP (op), offset, FALSE));
7287           offset++;
7288         }
7289
7290       freeAsmop (op, NULL, ic);
7291     }
7292 }
7293
7294 enum
7295   {
7296     /** Maximum number of bytes to emit per line. */
7297     DBEMIT_MAX_RUN = 8
7298   };
7299
7300 /** Context for the byte output chunker. */
7301 typedef struct
7302 {
7303   unsigned char buffer[DBEMIT_MAX_RUN];
7304   int pos;
7305 } DBEMITCTX;
7306
7307
7308 /** Flushes a byte chunker by writing out all in the buffer and
7309     reseting. 
7310 */
7311 static void
7312 _dbFlush(DBEMITCTX *self)
7313 {
7314   char line[256];
7315
7316   if (self->pos > 0)
7317     {
7318       int i;
7319       sprintf(line, ".db 0x%02X", self->buffer[0]);
7320
7321       for (i = 1; i < self->pos; i++)
7322         {
7323           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7324         }
7325       emit2(line);
7326     }
7327   self->pos = 0;
7328 }
7329
7330 /** Write out another byte, buffering until a decent line is
7331     generated.
7332 */
7333 static void
7334 _dbEmit(DBEMITCTX *self, int c)
7335 {
7336   if (self->pos == DBEMIT_MAX_RUN)
7337     {
7338       _dbFlush(self);
7339     }
7340   self->buffer[self->pos++] = c;
7341 }
7342
7343 /** Context for a simple run length encoder. */
7344 typedef struct
7345 {
7346   unsigned last;
7347   unsigned char buffer[128];
7348   int pos;
7349   /** runLen may be equivalent to pos. */
7350   int runLen;
7351 } RLECTX;
7352
7353 enum
7354   {
7355     RLE_CHANGE_COST = 4,
7356     RLE_MAX_BLOCK = 127
7357   };
7358
7359 /** Flush the buffer of a run length encoder by writing out the run or
7360     data that it currently contains.
7361 */
7362 static void
7363 _rleCommit(RLECTX *self)
7364 {
7365   int i;
7366   if (self->pos != 0)
7367     {
7368       DBEMITCTX db;
7369       memset(&db, 0, sizeof(db));
7370           
7371       emit2(".db %u", self->pos);
7372       
7373       for (i = 0; i < self->pos; i++)
7374         {
7375           _dbEmit(&db, self->buffer[i]);
7376         }
7377       _dbFlush(&db);
7378     }
7379   /* Reset */
7380   self->pos = 0;
7381 }
7382
7383 /* Encoder design:
7384    Can get either a run or a block of random stuff.
7385    Only want to change state if a good run comes in or a run ends.
7386    Detecting run end is easy.
7387    Initial state?
7388
7389    Say initial state is in run, len zero, last zero.  Then if you get a
7390    few zeros then something else then a short run will be output.
7391    Seems OK.  While in run mode, keep counting.  While in random mode,
7392    keep a count of the run.  If run hits margin, output all up to run,
7393    restart, enter run mode.
7394 */
7395
7396 /** Add another byte into the run length encoder, flushing as
7397     required.  The run length encoder uses the Amiga IFF style, where
7398     a block is prefixed by its run length.  A positive length means
7399     the next n bytes pass straight through.  A negative length means
7400     that the next byte is repeated -n times.  A zero terminates the
7401     chunks.
7402 */
7403 static void
7404 _rleAppend(RLECTX *self, int c)
7405 {
7406   int i;
7407
7408   if (c != self->last)
7409     {
7410       /* The run has stopped.  See if it is worthwhile writing it out
7411          as a run.  Note that the random data comes in as runs of
7412          length one.
7413       */
7414       if (self->runLen > RLE_CHANGE_COST)
7415         {
7416           /* Yes, worthwhile. */
7417           /* Commit whatever was in the buffer. */
7418           _rleCommit(self);
7419           emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7420         }
7421       else
7422         {
7423           /* Not worthwhile.  Append to the end of the random list. */
7424           for (i = 0; i < self->runLen; i++)
7425             {
7426               if (self->pos >= RLE_MAX_BLOCK)
7427                 {
7428                   /* Commit. */
7429                   _rleCommit(self);
7430                 }
7431               self->buffer[self->pos++] = self->last;
7432             }
7433         }
7434       self->runLen = 1;
7435       self->last = c;
7436     }
7437   else
7438     {
7439       if (self->runLen >= RLE_MAX_BLOCK)
7440         {
7441           /* Commit whatever was in the buffer. */
7442           _rleCommit(self);
7443
7444           emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7445           self->runLen = 0;
7446         }
7447       self->runLen++;
7448     }
7449 }
7450
7451 static void
7452 _rleFlush(RLECTX *self)
7453 {
7454   _rleAppend(self, -1);
7455   _rleCommit(self);
7456   self->pos = 0;
7457   self->last = 0;
7458   self->runLen = 0;
7459 }
7460
7461 /** genArrayInit - Special code for initialising an array with constant
7462    data.
7463 */
7464 static void
7465 genArrayInit (iCode * ic)
7466 {
7467   literalList *iLoop;
7468   int         ix;
7469   int         elementSize = 0, eIndex, i;
7470   unsigned    val, lastVal;
7471   sym_link    *type;
7472   RLECTX      rle;
7473
7474   memset(&rle, 0, sizeof(rle));
7475
7476   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7477
7478   _saveRegsForCall(ic, 0);
7479
7480   fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7481   emit2 ("call __initrleblock");
7482     
7483   type = operandType(IC_LEFT(ic));
7484     
7485   if (type && type->next)
7486     {
7487       elementSize = getSize(type->next);
7488     }
7489   else
7490     {
7491       wassertl (0, "Can't determine element size in genArrayInit.");
7492     }
7493
7494   iLoop = IC_ARRAYILIST(ic);
7495   lastVal = (unsigned)-1;
7496
7497   /* Feed all the bytes into the run length encoder which will handle
7498      the actual output.
7499      This works well for mixed char data, and for random int and long
7500      data.
7501   */
7502   while (iLoop)
7503     {
7504       ix = iLoop->count;
7505
7506       if (ix != 0)
7507         {
7508           for (i = 0; i < ix; i++)
7509             {
7510               for (eIndex = 0; eIndex < elementSize; eIndex++)
7511                 {
7512                   val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7513                   _rleAppend(&rle, val);
7514                 }
7515             }
7516         }
7517         
7518       iLoop = iLoop->next;
7519     }
7520
7521   _rleFlush(&rle);
7522   /* Mark the end of the run. */
7523   emit2(".db 0");
7524
7525   _restoreRegsAfterCall();
7526
7527   spillCached ();
7528
7529   freeAsmop (IC_LEFT(ic), NULL, ic);
7530 }
7531
7532 static void
7533 _swap (PAIR_ID one, PAIR_ID two)
7534 {
7535   if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7536     {
7537       emit2 ("ex de,hl");
7538     }
7539   else
7540     {
7541       emit2 ("ld a,%s", _pairs[one].l);
7542       emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7543       emit2 ("ld %s,a", _pairs[two].l);
7544       emit2 ("ld a,%s", _pairs[one].h);
7545       emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7546       emit2 ("ld %s,a", _pairs[two].h);
7547     }
7548 }
7549
7550 /* The problem is that we may have all three pairs used and they may
7551    be needed in a different order.
7552
7553    Note: Have ex de,hl
7554
7555    Combinations:
7556      hl = hl            => unity, fine
7557      bc = bc
7558      de = de
7559
7560      hl = hl            hl = hl, swap de <=> bc
7561      bc = de
7562      de = bc
7563
7564      hl = bc            Worst case
7565      bc = de
7566      de = hl
7567      
7568      hl = bc            de = de, swap bc <=> hl
7569      bc = hl
7570      de = de
7571
7572      hl = de            Worst case
7573      bc = hl
7574      de = bc
7575
7576      hl = de            bc = bc, swap hl <=> de
7577      bc = bc
7578      de = hl
7579
7580    Break it down into:
7581     * Any pair = pair are done last
7582     * Any pair = iTemp are done last
7583     * Any swaps can be done any time
7584
7585    A worst case:
7586     push p1
7587     p1 = p2
7588     p2 = p3
7589     pop  p3
7590
7591    So how do we detect the cases?
7592    How about a 3x3 matrix?
7593         source
7594    dest x x x x
7595         x x x x
7596         x x x x (Fourth for iTemp/other)
7597
7598    First determin which mode to use by counting the number of unity and
7599    iTemp assigns.
7600      Three - any order
7601      Two - Assign the pair first, then the rest
7602      One - Swap the two, then the rest
7603      Zero - Worst case.
7604 */
7605 static void
7606 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7607 {
7608   PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7609   PAIR_ID dest[3] = {
7610     PAIR_BC, PAIR_HL, PAIR_DE
7611   };
7612   int i, j, nunity = 0;
7613   memset (ids, PAIR_INVALID, sizeof (ids));
7614
7615   /* Sanity checks */
7616   wassert (nparams == 3);
7617
7618   /* First save everything that needs to be saved. */
7619   _saveRegsForCall (ic, 0);
7620
7621   /* Loading HL first means that DE is always fine. */
7622   for (i = 0; i < nparams; i++)
7623     {
7624       aopOp (pparams[i], ic, FALSE, FALSE);
7625       ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7626     }
7627
7628   /* Count the number of unity or iTemp assigns. */
7629   for (i = 0; i < 3; i++) 
7630     {
7631       if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7632         {
7633           nunity++;
7634         }
7635     }
7636
7637   if (nunity == 3)
7638     {
7639       /* Any order, fall through. */
7640     }
7641   else if (nunity == 2)
7642     {
7643       /* One is assigned.  Pull it out and assign. */
7644       for (i = 0; i < 3; i++)
7645         {
7646           for (j = 0; j < NUM_PAIRS; j++)
7647             {
7648               if (ids[dest[i]][j] == TRUE)
7649                 {
7650                   /* Found it.  See if it's the right one. */
7651                   if (j == PAIR_INVALID || j == dest[i])
7652                     {
7653                       /* Keep looking. */
7654                     }
7655                   else
7656                     {
7657                       fetchPair(dest[i], AOP (pparams[i]));
7658                       goto done;
7659                     }
7660                 }
7661             }
7662         }
7663     }
7664   else if (nunity == 1)
7665     {
7666       /* Find the pairs to swap. */
7667       for (i = 0; i < 3; i++)
7668         {
7669           for (j = 0; j < NUM_PAIRS; j++)
7670             {
7671               if (ids[dest[i]][j] == TRUE)
7672                 {
7673                   if (j == PAIR_INVALID || j == dest[i])
7674                     {
7675                       /* Keep looking. */
7676                     }
7677                   else
7678                     {
7679                       _swap (j, dest[i]);
7680                       goto done;
7681                     }
7682                 }
7683             }
7684         }
7685     }
7686   else
7687     {
7688       int next = getPairId (AOP (pparams[0]));
7689       emit2 ("push %s", _pairs[next].name);
7690
7691       if (next == dest[1])
7692         {
7693           fetchPair (dest[1], AOP (pparams[1]));
7694           fetchPair (dest[2], AOP (pparams[2]));
7695         }
7696       else
7697         {
7698           fetchPair (dest[2], AOP (pparams[2]));
7699           fetchPair (dest[1], AOP (pparams[1]));
7700         }
7701       emit2 ("pop %s", _pairs[dest[0]].name);
7702     }
7703  done:
7704   /* Finally pull out all of the iTemps */
7705   for (i = 0; i < 3; i++)
7706     {
7707       if (ids[dest[i]][PAIR_INVALID] == 1)
7708         {
7709           fetchPair (dest[i], AOP (pparams[i]));
7710         }
7711     }
7712 }
7713
7714 static void
7715 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7716 {
7717   operand *from, *to;
7718   symbol *label;
7719   bool deInUse;
7720
7721   wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7722   to = pparams[0];
7723   from = pparams[1];
7724
7725   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7726
7727   setupForBuiltin3 (ic, nParams, pparams);
7728
7729   label = newiTempLabel(NULL);
7730
7731   emitLabel (label->key);
7732   emit2 ("ld a,(hl)");
7733   emit2 ("ldi");
7734   emit2 ("or a");
7735   emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7736
7737   freeAsmop (from, NULL, ic->next);
7738   freeAsmop (to, NULL, ic);
7739 }
7740
7741 static void
7742 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7743 {
7744   operand *from, *to, *count;
7745   bool deInUse;
7746
7747   wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7748   to = pparams[2];
7749   from = pparams[1];
7750   count = pparams[0];
7751
7752   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7753
7754   setupForBuiltin3 (ic, nParams, pparams);
7755
7756   emit2 ("ldir");
7757
7758   freeAsmop (count, NULL, ic->next->next);
7759   freeAsmop (from, NULL, ic);
7760
7761   _restoreRegsAfterCall();
7762
7763   /* if we need assign a result value */
7764   if ((IS_ITEMP (IC_RESULT (ic)) &&
7765        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7766         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7767       IS_TRUE_SYMOP (IC_RESULT (ic)))
7768     {
7769       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7770       movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7771       freeAsmop (IC_RESULT (ic), NULL, ic);
7772     }
7773
7774   freeAsmop (to, NULL, ic->next);
7775 }
7776
7777 /*-----------------------------------------------------------------*/
7778 /* genBuiltIn - calls the appropriate function to  generating code */
7779 /* for a built in function                                         */
7780 /*-----------------------------------------------------------------*/
7781 static void genBuiltIn (iCode *ic)
7782 {
7783     operand *bi_parms[MAX_BUILTIN_ARGS];
7784     int nbi_parms;
7785     iCode *bi_iCode;
7786     symbol *bif;
7787
7788     /* get all the arguments for a built in function */
7789     bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7790
7791     /* which function is it */
7792     bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7793
7794     if (strcmp(bif->name,"__builtin_strcpy")==0) 
7795       {
7796         genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7797       } 
7798     else if (strcmp(bif->name,"__builtin_memcpy")==0) 
7799       {
7800         genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7801       } 
7802     else 
7803       {
7804         wassertl (0, "Unknown builtin function encountered");
7805       }
7806 }
7807
7808 /*-----------------------------------------------------------------*/
7809 /* genZ80Code - generate code for Z80 based controllers            */
7810 /*-----------------------------------------------------------------*/
7811 void
7812 genZ80Code (iCode * lic)
7813 {
7814   iCode *ic;
7815   int cln = 0;
7816
7817   /* Hack */
7818   if (IS_GB)
7819     {
7820       _fReturn = _gbz80_return;
7821       _fTmp = _gbz80_return;
7822     }
7823   else
7824     {
7825       _fReturn = _z80_return;
7826       _fTmp = _z80_return;
7827     }
7828
7829   _G.lines.head = _G.lines.current = NULL;
7830   
7831   /* if debug information required */
7832   if (options.debug && currFunc)
7833     {
7834       debugFile->writeFunction(currFunc);
7835       _G.lines.isDebug = 1;
7836       if (IS_STATIC (currFunc->etype))
7837         sprintf (buffer, "F%s$%s$0$0", moduleName, currFunc->name);
7838       else
7839         sprintf (buffer, "G$%s$0$0", currFunc->name);
7840       emit2 ("!labeldef", buffer);
7841       _G.lines.isDebug = 0;
7842     }
7843
7844   for (ic = lic; ic; ic = ic->next)
7845     {
7846       _G.current_iCode = ic;
7847
7848       if (ic->lineno && cln != ic->lineno)
7849         {
7850           if (options.debug)
7851             {
7852               _G.lines.isDebug = 1;
7853               sprintf (buffer, "C$%s$%d$%d$%d",
7854                         FileBaseName (ic->filename), ic->lineno,
7855                         ic->level, ic->block);
7856               emit2 ("%s !equ .", buffer);
7857               emit2 ("!global", buffer);
7858               _G.lines.isDebug = 0;
7859             }
7860           if (!options.noCcodeInAsm) {
7861             emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7862                    printCLine(ic->filename, ic->lineno));
7863           }
7864           cln = ic->lineno;
7865         }
7866       if (options.iCodeInAsm) {
7867         emit2 (";ic:%d: %s", ic->key, printILine(ic));
7868       }
7869       /* if the result is marked as
7870          spilt and rematerializable or code for
7871          this has already been generated then
7872          do nothing */
7873       if (resultRemat (ic) || ic->generated)
7874         continue;
7875
7876       /* depending on the operation */
7877       switch (ic->op)
7878         {
7879         case '!':
7880           emitDebug ("; genNot");
7881           genNot (ic);
7882           break;
7883
7884         case '~':
7885           emitDebug ("; genCpl");
7886           genCpl (ic);
7887           break;
7888
7889         case UNARYMINUS:
7890           emitDebug ("; genUminus");
7891           genUminus (ic);
7892           break;
7893
7894         case IPUSH:
7895           emitDebug ("; genIpush");
7896           genIpush (ic);
7897           break;
7898
7899         case IPOP:
7900           /* IPOP happens only when trying to restore a
7901              spilt live range, if there is an ifx statement
7902              following this pop then the if statement might
7903              be using some of the registers being popped which
7904              would destory the contents of the register so
7905              we need to check for this condition and handle it */
7906           if (ic->next &&
7907               ic->next->op == IFX &&
7908               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7909             {
7910               emitDebug ("; genIfx");
7911               genIfx (ic->next, ic);
7912             }
7913           else
7914             {
7915               emitDebug ("; genIpop");
7916               genIpop (ic);
7917             }
7918           break;
7919
7920         case CALL:
7921           emitDebug ("; genCall");
7922           genCall (ic);
7923           break;
7924
7925         case PCALL:
7926           emitDebug ("; genPcall");
7927           genPcall (ic);
7928           break;
7929
7930         case FUNCTION:
7931           emitDebug ("; genFunction");
7932           genFunction (ic);
7933           break;
7934
7935         case ENDFUNCTION:
7936           emitDebug ("; genEndFunction");
7937           genEndFunction (ic);
7938           break;
7939
7940         case RETURN:
7941           emitDebug ("; genRet");
7942           genRet (ic);
7943           break;
7944
7945         case LABEL:
7946           emitDebug ("; genLabel");
7947           genLabel (ic);
7948           break;
7949
7950         case GOTO:
7951           emitDebug ("; genGoto");
7952           genGoto (ic);
7953           break;
7954
7955         case '+':
7956           emitDebug ("; genPlus");
7957           genPlus (ic);
7958           break;
7959
7960         case '-':
7961           emitDebug ("; genMinus");
7962           genMinus (ic);
7963           break;
7964
7965         case '*':
7966           emitDebug ("; genMult");
7967           genMult (ic);
7968           break;
7969
7970         case '/':
7971           emitDebug ("; genDiv");
7972           genDiv (ic);
7973           break;
7974
7975         case '%':
7976           emitDebug ("; genMod");
7977           genMod (ic);
7978           break;
7979
7980         case '>':
7981           emitDebug ("; genCmpGt");
7982           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7983           break;
7984
7985         case '<':
7986           emitDebug ("; genCmpLt");
7987           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7988           break;
7989
7990         case LE_OP:
7991         case GE_OP:
7992         case NE_OP:
7993
7994           /* note these two are xlated by algebraic equivalence
7995              during parsing SDCC.y */
7996           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7997                   "got '>=' or '<=' shouldn't have come here");
7998           break;
7999
8000         case EQ_OP:
8001           emitDebug ("; genCmpEq");
8002           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
8003           break;
8004
8005         case AND_OP:
8006           emitDebug ("; genAndOp");
8007           genAndOp (ic);
8008           break;
8009
8010         case OR_OP:
8011           emitDebug ("; genOrOp");
8012           genOrOp (ic);
8013           break;
8014
8015         case '^':
8016           emitDebug ("; genXor");
8017           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8018           break;
8019
8020         case '|':
8021           emitDebug ("; genOr");
8022           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8023           break;
8024
8025         case BITWISEAND:
8026           emitDebug ("; genAnd");
8027           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8028           break;
8029
8030         case INLINEASM:
8031           emitDebug ("; genInline");
8032           genInline (ic);
8033           break;
8034
8035         case RRC:
8036           emitDebug ("; genRRC");
8037           genRRC (ic);
8038           break;
8039
8040         case RLC:
8041           emitDebug ("; genRLC");
8042           genRLC (ic);
8043           break;
8044
8045         case GETHBIT:
8046           emitDebug ("; genGetHBIT");
8047           genGetHbit (ic);
8048           break;
8049
8050         case LEFT_OP:
8051           emitDebug ("; genLeftShift");
8052           genLeftShift (ic);
8053           break;
8054
8055         case RIGHT_OP:
8056           emitDebug ("; genRightShift");
8057           genRightShift (ic);
8058           break;
8059
8060         case GET_VALUE_AT_ADDRESS:
8061           emitDebug ("; genPointerGet");
8062           genPointerGet (ic);
8063           break;
8064
8065         case '=':
8066
8067           if (POINTER_SET (ic))
8068             {
8069               emitDebug ("; genAssign (pointer)");
8070               genPointerSet (ic);
8071             }
8072           else
8073             {
8074               emitDebug ("; genAssign");
8075               genAssign (ic);
8076             }
8077           break;
8078
8079         case IFX:
8080           emitDebug ("; genIfx");
8081           genIfx (ic, NULL);
8082           break;
8083
8084         case ADDRESS_OF:
8085           emitDebug ("; genAddrOf");
8086           genAddrOf (ic);
8087           break;
8088
8089         case JUMPTABLE:
8090           emitDebug ("; genJumpTab");
8091           genJumpTab (ic);
8092           break;
8093
8094         case CAST:
8095           emitDebug ("; genCast");
8096           genCast (ic);
8097           break;
8098
8099         case RECEIVE:
8100           emitDebug ("; genReceive");
8101           genReceive (ic);
8102           break;
8103
8104         case SEND:
8105           if (ic->builtinSEND)
8106             {
8107               emitDebug ("; genBuiltIn");
8108               genBuiltIn(ic);
8109             }
8110           else
8111             {
8112               emitDebug ("; addSet");
8113               addSet (&_G.sendSet, ic);
8114             }
8115           break;
8116
8117         case ARRAYINIT:
8118           emitDebug ("; genArrayInit");
8119           genArrayInit(ic);
8120           break;
8121
8122         case DUMMY_READ_VOLATILE:
8123           emitDebug ("; genDummyRead");
8124           genDummyRead (ic);
8125           break;
8126
8127         default:
8128           ic = ic;
8129         }
8130     }
8131
8132
8133   /* now we are ready to call the
8134      peep hole optimizer */
8135   if (!options.nopeep)
8136     peepHole (&_G.lines.head);
8137
8138   /* This is unfortunate */
8139   /* now do the actual printing */
8140   {
8141     FILE *fp = codeOutFile;
8142     if (isInHome () && codeOutFile == code->oFile)
8143       codeOutFile = home->oFile;
8144     printLine (_G.lines.head, codeOutFile);
8145     if (_G.flushStatics)
8146       {
8147         flushStatics ();
8148         _G.flushStatics = 0;
8149       }
8150     codeOutFile = fp;
8151   }
8152
8153   freeTrace(&_G.lines.trace);
8154   freeTrace(&_G.trace.aops);
8155 }
8156
8157 /*
8158   Attic
8159 static int
8160 _isPairUsed (iCode * ic, PAIR_ID pairId)
8161 {
8162   int ret = 0;
8163   switch (pairId)
8164     {
8165     case PAIR_DE:
8166       if (bitVectBitValue (ic->rMask, D_IDX))
8167         ret++;
8168       if (bitVectBitValue (ic->rMask, E_IDX))
8169         ret++;
8170       break;
8171     default:
8172       wassert (0);
8173     }
8174   return ret;
8175 }
8176
8177 static char *
8178 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8179 {
8180   unsigned long v;
8181   value *val = aop->aopu.aop_lit;
8182
8183   wassert (aop->type == AOP_LIT);
8184   wassert (!IS_FLOAT (val->type));
8185
8186   v = (unsigned long) floatFromVal (val);
8187
8188   if (xor)
8189     v ^= 0x8000;
8190   if (negate)
8191     v = 0-v;
8192   v &= 0xFFFF;
8193
8194   tsprintf (buffer, sizeof(buffer), "!immedword", v);
8195   return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
8196 }
8197
8198
8199 */