cd669c7c359f3741344515ea5947182b254badd1
[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           /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
1688           emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
1689           emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
1690         }
1691         else if( z80_opts.port_mode == 180 )
1692         { /* z180 in0/out0 mode */
1693           emit2( "in0 a,(%s)", aop->aopu.aop_dir );
1694         }
1695         else
1696         { /* 8 bit mode */
1697           emit2( "in a,(%s)", aop->aopu.aop_dir );
1698         }
1699         
1700         SNPRINTF (buffer, sizeof(buffer), "a");
1701
1702         return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1703       }
1704
1705     case AOP_REG:
1706       return aop->aopu.aop_reg[offset]->name;
1707
1708     case AOP_HL:
1709       wassert (IS_GB);
1710       setupPair (PAIR_HL, aop, offset);
1711       tsprintf (buffer, sizeof(buffer), "!*hl");
1712
1713       return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1714
1715     case AOP_IY:
1716       wassert (IS_Z80);
1717       setupPair (PAIR_IY, aop, offset);
1718       tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1719
1720       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1721
1722     case AOP_EXSTK:
1723       wassert (IS_Z80);
1724       setupPair (PAIR_IY, aop, offset);
1725       tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1726
1727       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1728
1729     case AOP_STK:
1730       if (IS_GB)
1731         {
1732           setupPair (PAIR_HL, aop, offset);
1733           tsprintf (buffer, sizeof(buffer), "!*hl");
1734         }
1735       else
1736         {
1737           if (aop->aopu.aop_stk >= 0)
1738             offset += _G.stack.param_offset;
1739           tsprintf (buffer, sizeof(buffer),
1740                     "!*ixx", aop->aopu.aop_stk + offset);
1741         }
1742
1743       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1744
1745     case AOP_CRY:
1746       wassertl (0, "Tried to fetch from a bit variable");
1747
1748     case AOP_ACC:
1749       if (!offset)
1750         {
1751           return "a";
1752         }
1753       else
1754         {
1755           tsprintf(buffer, sizeof(buffer), "!zero");
1756           return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1757         }
1758
1759     case AOP_HLREG:
1760       wassert (offset < 2);
1761       return aop->aopu.aop_str[offset];
1762
1763     case AOP_LIT:
1764       return aopLiteral (aop->aopu.aop_lit, offset);
1765
1766     case AOP_SIMPLELIT:
1767       {
1768         unsigned long v = aop->aopu.aop_simplelit;
1769         
1770         v >>= (offset * 8);
1771         tsprintf (buffer, sizeof(buffer), 
1772                   "!immedbyte", (unsigned int) v & 0xff);
1773         
1774         return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1775       }
1776     case AOP_STR:
1777       aop->coff = offset;
1778       return aop->aopu.aop_str[offset];
1779
1780     case AOP_PAIRPTR:
1781       setupPair (aop->aopu.aop_pairId, aop, offset);
1782       if (aop->aopu.aop_pairId==PAIR_IX)
1783         SNPRINTF (buffer, sizeof(buffer), 
1784                   "!*ixx", 0);
1785       else if (aop->aopu.aop_pairId==PAIR_IY)
1786         SNPRINTF (buffer, sizeof(buffer), 
1787                   "!*iyx", 0);
1788       else
1789         SNPRINTF (buffer, sizeof(buffer), 
1790                   "(%s)", _pairs[aop->aopu.aop_pairId].name);
1791
1792       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1793
1794     default:
1795       break;
1796     }
1797   wassertl (0, "aopget got unsupported aop->type");
1798   exit (0);
1799 }
1800
1801 bool
1802 isRegString (const char *s)
1803 {
1804   if (!strcmp (s, "b") ||
1805       !strcmp (s, "c") ||
1806       !strcmp (s, "d") ||
1807       !strcmp (s, "e") ||
1808       !strcmp (s, "a") ||
1809       !strcmp (s, "h") ||
1810       !strcmp (s, "l"))
1811     return TRUE;
1812   return FALSE;
1813 }
1814
1815 bool
1816 isConstant (const char *s)
1817 {
1818   /* This is a bit of a hack... */
1819   return (*s == '#' || *s == '$');
1820 }
1821
1822 bool
1823 canAssignToPtr (const char *s)
1824 {
1825   if (isRegString (s))
1826     return TRUE;
1827   if (isConstant (s))
1828     return TRUE;
1829   return FALSE;
1830 }
1831
1832 /*-----------------------------------------------------------------*/
1833 /* aopPut - puts a string for a aop                                */
1834 /*-----------------------------------------------------------------*/
1835 static void
1836 aopPut (asmop * aop, const char *s, int offset)
1837 {
1838   char buffer2[256];
1839
1840   if (aop->size && offset > (aop->size - 1))
1841     {
1842       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1843               "aopPut got offset > aop->size");
1844       exit (0);
1845     }
1846
1847   // PENDING
1848   tsprintf(buffer2, sizeof(buffer2), s);
1849   s = buffer2;
1850
1851   /* will assign value to value */
1852   /* depending on where it is ofcourse */
1853   switch (aop->type)
1854     {
1855     case AOP_DUMMY:
1856       _moveA (s);  /* in case s is volatile */
1857       break;
1858       
1859     case AOP_DIR:
1860       /* Direct.  Hmmm. */
1861       wassert (IS_GB);
1862       if (strcmp (s, "a"))
1863         emit2 ("ld a,%s", s);
1864       emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1865       break;
1866
1867     case AOP_SFR:
1868       if( IS_GB )
1869       {
1870         //  wassert (IS_GB);
1871         if (strcmp (s, "a"))
1872           emit2 ("ld a,%s", s);
1873         emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1874       }
1875       else
1876       { /*.p.t.20030716 handling for i/o port read access for Z80 */
1877         if( aop->paged )
1878         { /* banked mode */
1879           if( aop->bcInUse )  emit2( "push bc" );
1880
1881           emit2( "ld bc,#%s", aop->aopu.aop_dir );
1882
1883           if(( s[0] == '#'    ) /* immediate number */
1884            ||( s[0] == '('    ) /* indirect register (ix or iy ??)*/
1885            ||( isdigit( s[0] )))/* indirect register with offset (ix or iy ??)*/
1886           {
1887             emit2( "ld a,%s", s );
1888             emit2( "out (c),a"  );
1889           }
1890           else
1891           {
1892             emit2( "out (c),%s", s );
1893           }
1894         
1895           if( aop->bcInUse )
1896             emit2( "pop bc"    );
1897           else
1898             spillPair (PAIR_BC);
1899         }
1900         else if( z80_opts.port_mode == 180 )
1901         { /* z180 in0/out0 mode */
1902           emit2( "ld a,%s", s );
1903           emit2( "out0 (%s),a", aop->aopu.aop_dir );
1904         }
1905         else
1906         { /* 8 bit mode */
1907           emit2( "ld a,%s", s );
1908           emit2( "out (%s),a", aop->aopu.aop_dir );
1909         }
1910       }
1911       break;
1912
1913     case AOP_REG:
1914       if (!strcmp (s, "!*hl"))
1915         emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1916       else
1917         emit2 ("ld %s,%s",
1918                aop->aopu.aop_reg[offset]->name, s);
1919       spillPairReg(aop->aopu.aop_reg[offset]->name);
1920       break;
1921
1922     case AOP_IY:
1923       wassert (!IS_GB);
1924       if (!canAssignToPtr (s))
1925         {
1926           emit2 ("ld a,%s", s);
1927           setupPair (PAIR_IY, aop, offset);
1928           emit2 ("ld !*iyx,a", offset);
1929         }
1930       else
1931         {
1932           setupPair (PAIR_IY, aop, offset);
1933           emit2 ("ld !*iyx,%s", offset, s);
1934         }
1935       break;
1936
1937     case AOP_HL:
1938       wassert (IS_GB);
1939       /* PENDING: for re-target */
1940       if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1941         {
1942           emit2 ("ld a,!*hl");
1943           s = "a";
1944         }
1945       setupPair (PAIR_HL, aop, offset);
1946
1947       emit2 ("ld !*hl,%s", s);
1948       break;
1949
1950     case AOP_EXSTK:
1951       wassert (!IS_GB);
1952       if (!canAssignToPtr (s))
1953         {
1954           emit2 ("ld a,%s", s);
1955           setupPair (PAIR_IY, aop, offset);
1956           emit2 ("ld !*iyx,a", offset);
1957         }
1958       else
1959         {
1960           setupPair (PAIR_IY, aop, offset);
1961           emit2 ("ld !*iyx,%s", offset, s);
1962         }
1963       break;
1964
1965     case AOP_STK:
1966       if (IS_GB)
1967         {
1968           /* PENDING: re-target */
1969           if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1970             {
1971               emit2 ("ld a,!*hl");
1972               s = "a";
1973             }
1974           setupPair (PAIR_HL, aop, offset);
1975           if (!canAssignToPtr (s))
1976             {
1977               emit2 ("ld a,%s", s);
1978               emit2 ("ld !*hl,a");
1979             }
1980           else
1981             emit2 ("ld !*hl,%s", s);
1982         }
1983       else
1984         {
1985           if (aop->aopu.aop_stk >= 0)
1986             offset += _G.stack.param_offset;
1987           if (!canAssignToPtr (s))
1988             {
1989               emit2 ("ld a,%s", s);
1990               emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1991             }
1992           else
1993             {
1994               emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1995             }
1996         }
1997       break;
1998
1999     case AOP_CRY:
2000       /* if bit variable */
2001       if (!aop->aopu.aop_dir)
2002         {
2003           emit2 ("ld a,!zero");
2004           emit2 ("rla");
2005         }
2006       else
2007         {
2008           /* In bit space but not in C - cant happen */
2009           wassertl (0, "Tried to write into a bit variable");
2010         }
2011       break;
2012
2013     case AOP_STR:
2014       aop->coff = offset;
2015       if (strcmp (aop->aopu.aop_str[offset], s))
2016         {
2017           emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2018         }
2019       spillPairReg(aop->aopu.aop_str[offset]);
2020       break;
2021
2022     case AOP_ACC:
2023       aop->coff = offset;
2024       if (!offset && (strcmp (s, "acc") == 0))
2025         break;
2026       if (offset > 0)
2027         {
2028           wassertl (0, "Tried to access past the end of A");
2029         }
2030       else
2031         {
2032           if (strcmp (aop->aopu.aop_str[offset], s))
2033             {
2034               emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2035               spillPairReg(aop->aopu.aop_str[offset]);
2036             }
2037         }
2038       break;
2039
2040     case AOP_HLREG:
2041       wassert (offset < 2);
2042       emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
2043       spillPairReg(aop->aopu.aop_str[offset]);
2044       break;
2045
2046     case AOP_PAIRPTR:
2047       setupPair (aop->aopu.aop_pairId, aop, offset);
2048       if (aop->aopu.aop_pairId==PAIR_IX)
2049         emit2 ("ld !*ixx,%s", 0, s);
2050       else if (aop->aopu.aop_pairId==PAIR_IY)
2051         emit2 ("ld !*ixy,%s", 0, s);
2052       else
2053         emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
2054       break;
2055
2056     default:
2057       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
2058               "aopPut got unsupported aop->type");
2059       exit (0);
2060     }
2061 }
2062
2063 #define AOP(op) op->aop
2064 #define AOP_TYPE(op) AOP(op)->type
2065 #define AOP_SIZE(op) AOP(op)->size
2066 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2067
2068 static void
2069 commitPair (asmop * aop, PAIR_ID id)
2070 {
2071   /* PENDING: Verify this. */
2072   if (id == PAIR_HL && requiresHL (aop) && IS_GB)
2073     {
2074       emit2 ("ld a,l");
2075       emit2 ("ld d,h");
2076       aopPut (aop, "a", 0);
2077       aopPut (aop, "d", 1);
2078     }
2079   else
2080     {
2081       /* Special cases */
2082       if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
2083         {
2084           char *l = aopGetLitWordLong (aop, 0, FALSE);
2085           wassert (l);
2086
2087           emit2 ("ld (%s),%s", l, _pairs[id].name);
2088         }
2089       else
2090         {
2091           aopPut (aop, _pairs[id].l, 0);
2092           aopPut (aop, _pairs[id].h, 1);
2093         }
2094     }
2095 }
2096
2097 /*-----------------------------------------------------------------*/
2098 /* getDataSize - get the operand data size                         */
2099 /*-----------------------------------------------------------------*/
2100 int
2101 getDataSize (operand * op)
2102 {
2103   int size;
2104   size = AOP_SIZE (op);
2105   if (size == 3)
2106     {
2107       /* pointer */
2108       wassertl (0, "Somehow got a three byte data pointer");
2109     }
2110   return size;
2111 }
2112
2113 /*-----------------------------------------------------------------*/
2114 /* movLeft2Result - move byte from left to result                  */
2115 /*-----------------------------------------------------------------*/
2116 static void
2117 movLeft2Result (operand * left, int offl,
2118                 operand * result, int offr, int sign)
2119 {
2120   const char *l;
2121
2122   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2123     {
2124       l = aopGet (AOP (left), offl, FALSE);
2125
2126       if (!sign)
2127         {
2128           aopPut (AOP (result), l, offr);
2129         }
2130       else
2131         {
2132           if (getDataSize (left) == offl + 1)
2133             {
2134               emit2 ("ld a,%s", l);
2135               aopPut (AOP (result), "a", offr);
2136             }
2137         }
2138     }
2139 }
2140
2141 static void
2142 movLeft2ResultLong (operand * left, int offl,
2143                 operand * result, int offr, int sign,
2144                 int size)
2145 {
2146   if (size == 1)
2147     {
2148       movLeft2Result (left, offl, result, offr, sign);
2149     }
2150   else
2151     {
2152       wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2153       wassertl (size == 2, "Only implemented for two bytes or one");
2154
2155       if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2156         {
2157           emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2158           emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2159           emit2 ("ld l,a");
2160           spillPair (PAIR_HL);
2161         }
2162       else if ( getPairId ( AOP (result)) == PAIR_IY)
2163         {
2164           PAIR_ID id = getPairId (AOP (left));
2165           if (id != PAIR_INVALID) 
2166             {
2167               emit2("push %s", _pairs[id].name);
2168               emit2("pop iy");
2169             }
2170           else
2171             {
2172               /* PENDING */
2173               emitDebug("Error");
2174             }
2175         }
2176       else
2177         {
2178           movLeft2Result (left, offl, result, offr, sign);
2179           movLeft2Result (left, offl+1, result, offr+1, sign);
2180         }
2181     }
2182 }
2183
2184 /** Put Acc into a register set
2185  */
2186 void
2187 outAcc (operand * result)
2188 {
2189   int size, offset;
2190   size = getDataSize (result);
2191   if (size)
2192     {
2193       aopPut (AOP (result), "a", 0);
2194       size--;
2195       offset = 1;
2196       /* unsigned or positive */
2197       while (size--)
2198         {
2199           aopPut (AOP (result), "!zero", offset++);
2200         }
2201     }
2202 }
2203
2204 /** Take the value in carry and put it into a register
2205  */
2206 void
2207 outBitCLong (operand * result, bool swap_sense)
2208 {
2209   /* if the result is bit */
2210   if (AOP_TYPE (result) == AOP_CRY)
2211     {
2212       wassertl (0, "Tried to write carry to a bit");
2213     }
2214   else
2215     {
2216       emit2 ("ld a,!zero");
2217       emit2 ("rla");
2218       if (swap_sense)
2219         emit2 ("xor a,!immedbyte", 1);
2220       outAcc (result);
2221     }
2222 }
2223
2224 void
2225 outBitC (operand * result)
2226 {
2227   outBitCLong (result, FALSE);
2228 }
2229
2230 /*-----------------------------------------------------------------*/
2231 /* toBoolean - emit code for orl a,operator(sizeop)                */
2232 /*-----------------------------------------------------------------*/
2233 void
2234 _toBoolean (operand * oper)
2235 {
2236   int size = AOP_SIZE (oper);
2237   int offset = 0;
2238   if (size > 1)
2239     {
2240       emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2241       size--;
2242       while (size--)
2243         emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2244     }
2245   else
2246     {
2247       if (AOP (oper)->type != AOP_ACC)
2248         {
2249           _clearCarry();
2250           emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2251         }
2252     }
2253 }
2254
2255
2256 /*-----------------------------------------------------------------*/
2257 /* genNot - generate code for ! operation                          */
2258 /*-----------------------------------------------------------------*/
2259 static void
2260 genNot (iCode * ic)
2261 {
2262
2263   /* assign asmOps to operand & result */
2264   aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2265   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2266
2267   /* if in bit space then a special case */
2268   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2269     {
2270       wassertl (0, "Tried to negate a bit");
2271     }
2272
2273   _toBoolean (IC_LEFT (ic));
2274
2275   /* Not of A:
2276      If A == 0, !A = 1
2277      else A = 0
2278      So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2279   emit2 ("sub a,!one");
2280   outBitC (IC_RESULT (ic));
2281
2282   /* release the aops */
2283   freeAsmop (IC_LEFT (ic), NULL, ic);
2284   freeAsmop (IC_RESULT (ic), NULL, ic);
2285 }
2286
2287 /*-----------------------------------------------------------------*/
2288 /* genCpl - generate code for complement                           */
2289 /*-----------------------------------------------------------------*/
2290 static void
2291 genCpl (iCode * ic)
2292 {
2293   int offset = 0;
2294   int size;
2295
2296
2297   /* assign asmOps to operand & result */
2298   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2299   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2300
2301   /* if both are in bit space then
2302      a special case */
2303   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2304       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2305     {
2306       wassertl (0, "Left and the result are in bit space");
2307     }
2308
2309   size = AOP_SIZE (IC_RESULT (ic));
2310   while (size--)
2311     {
2312       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2313       _moveA (l);
2314       emit2("cpl");
2315       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2316     }
2317
2318   /* release the aops */
2319   freeAsmop (IC_LEFT (ic), NULL, ic);
2320   freeAsmop (IC_RESULT (ic), NULL, ic);
2321 }
2322
2323 static void
2324 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2325 {
2326   /* Logic:
2327        ld de,right.lw
2328        setup hl to left
2329        de = hl - de
2330        push flags
2331        store de into result
2332        pop flags
2333        ld de,right.hw
2334        setup hl
2335        de = hl -de
2336        store de into result
2337   */
2338   const char *first = isAdd ? "add" : "sub";
2339   const char *later = isAdd ? "adc" : "sbc";
2340
2341   wassertl (IS_GB, "Code is only relevent to the gbz80");
2342   wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2343
2344   fetchPair (PAIR_DE, left);
2345
2346   emit2 ("ld a,e");
2347   emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2348   emit2 ("ld e,a");
2349   emit2 ("ld a,d");
2350   emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2351
2352   _push (PAIR_AF);
2353   aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2354   aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2355
2356   fetchPairLong (PAIR_DE, left, NULL, MSB24);
2357   aopGet (right, MSB24, FALSE);
2358
2359   _pop (PAIR_AF);
2360   emit2 ("ld a,e");
2361   emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2362   emit2 ("ld e,a");
2363   emit2 ("ld a,d");
2364   emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2365
2366   aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2367   aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2368 }
2369
2370 static void
2371 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2372 {
2373   _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2374 }
2375
2376 /*-----------------------------------------------------------------*/
2377 /* genUminusFloat - unary minus for floating points                */
2378 /*-----------------------------------------------------------------*/
2379 static void
2380 genUminusFloat (operand * op, operand * result)
2381 {
2382   int size, offset = 0;
2383
2384   emitDebug("; genUminusFloat");
2385
2386   /* for this we just need to flip the
2387      first it then copy the rest in place */
2388   size = AOP_SIZE (op) - 1;
2389
2390   _moveA(aopGet (AOP (op), MSB32, FALSE));
2391
2392   emit2("xor a,!immedbyte", 0x80);
2393   aopPut (AOP (result), "a", MSB32);
2394
2395   while (size--)
2396     {
2397       aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2398       offset++;
2399     }
2400 }
2401
2402 /*-----------------------------------------------------------------*/
2403 /* genUminus - unary minus code generation                         */
2404 /*-----------------------------------------------------------------*/
2405 static void
2406 genUminus (iCode * ic)
2407 {
2408   int offset, size;
2409   sym_link *optype, *rtype;
2410
2411   /* assign asmops */
2412   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2413   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2414
2415   /* if both in bit space then special
2416      case */
2417   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2418       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2419     {
2420       wassertl (0, "Left and right are in bit space");
2421       goto release;
2422     }
2423
2424   optype = operandType (IC_LEFT (ic));
2425   rtype = operandType (IC_RESULT (ic));
2426
2427   /* if float then do float stuff */
2428   if (IS_FLOAT (optype))
2429     {
2430       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2431       goto release;
2432     }
2433
2434   /* otherwise subtract from zero */
2435   size = AOP_SIZE (IC_LEFT (ic));
2436
2437   if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2438     {
2439       /* Create a new asmop with value zero */
2440       asmop *azero = newAsmop (AOP_SIMPLELIT);
2441       azero->aopu.aop_simplelit = 0;
2442       azero->size = size;
2443       _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2444       goto release;
2445     }
2446
2447   offset = 0;
2448   _clearCarry();
2449   while (size--)
2450     {
2451       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2452       emit2 ("ld a,!zero");
2453       emit2 ("sbc a,%s", l);
2454       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2455     }
2456
2457   /* if any remaining bytes in the result */
2458   /* we just need to propagate the sign   */
2459   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2460     {
2461       emit2 ("rlc a");
2462       emit2 ("sbc a,a");
2463       while (size--)
2464         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2465     }
2466
2467 release:
2468   /* release the aops */
2469   freeAsmop (IC_LEFT (ic), NULL, ic);
2470   freeAsmop (IC_RESULT (ic), NULL, ic);
2471 }
2472
2473 /*-----------------------------------------------------------------*/
2474 /* assignResultValue -               */
2475 /*-----------------------------------------------------------------*/
2476 void
2477 assignResultValue (operand * oper)
2478 {
2479   int size = AOP_SIZE (oper);
2480   bool topInA = 0;
2481
2482   wassertl (size <= 4, "Got a result that is bigger than four bytes");
2483   topInA = requiresHL (AOP (oper));
2484
2485   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2486     {
2487       /* We do it the hard way here. */
2488       _push (PAIR_HL);
2489       aopPut (AOP (oper), _fReturn[0], 0);
2490       aopPut (AOP (oper), _fReturn[1], 1);
2491       _pop (PAIR_DE);
2492       aopPut (AOP (oper), _fReturn[0], 2);
2493       aopPut (AOP (oper), _fReturn[1], 3);
2494     }
2495   else
2496     {
2497       while (size--)
2498         {
2499           aopPut (AOP (oper), _fReturn[size], size);
2500         }
2501     }
2502 }
2503
2504 /** Simple restore that doesn't take into account what is used in the
2505     return.
2506 */
2507 static void
2508 _restoreRegsAfterCall(void)
2509 {
2510   if (_G.stack.pushedDE)
2511     {
2512       _pop ( PAIR_DE);
2513       _G.stack.pushedDE = FALSE;
2514     }
2515   if (_G.stack.pushedBC)
2516     {
2517       _pop ( PAIR_BC);
2518       _G.stack.pushedBC = FALSE;
2519     }
2520   _G.saves.saved = FALSE;
2521 }
2522
2523 static void
2524 _saveRegsForCall(iCode *ic, int sendSetSize)
2525 {
2526   /* Rules:
2527       o Stack parameters are pushed before this function enters
2528       o DE and BC may be used in this function.
2529       o HL and DE may be used to return the result.
2530       o HL and DE may be used to send variables.
2531       o DE and BC may be used to store the result value.
2532       o HL may be used in computing the sent value of DE
2533       o The iPushes for other parameters occur before any addSets
2534
2535      Logic: (to be run inside the first iPush or if none, before sending)
2536       o Compute if DE and/or BC are in use over the call
2537       o Compute if DE is used in the send set
2538       o Compute if DE and/or BC are used to hold the result value
2539       o If (DE is used, or in the send set) and is not used in the result, push.
2540       o If BC is used and is not in the result, push
2541       o 
2542       o If DE is used in the send set, fetch
2543       o If HL is used in the send set, fetch
2544       o Call
2545       o ...
2546   */
2547   if (_G.saves.saved == FALSE) {
2548     bool deInUse, bcInUse;
2549     bool deSending;
2550     bool bcInRet = FALSE, deInRet = FALSE;
2551     bitVect *rInUse;
2552
2553     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), 
2554                             z80_rUmaskForOp (IC_RESULT(ic)));
2555
2556     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2557     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2558
2559     deSending = (sendSetSize > 1);
2560
2561     emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2562
2563     if (bcInUse && bcInRet == FALSE) {
2564       _push(PAIR_BC);
2565       _G.stack.pushedBC = TRUE;
2566     }
2567     if (deInUse && deInRet == FALSE) {
2568       _push(PAIR_DE);
2569       _G.stack.pushedDE = TRUE;
2570     }
2571
2572     _G.saves.saved = TRUE;
2573   }
2574   else {
2575     /* Already saved. */
2576   }
2577 }
2578
2579 /*-----------------------------------------------------------------*/
2580 /* genIpush - genrate code for pushing this gets a little complex  */
2581 /*-----------------------------------------------------------------*/
2582 static void
2583 genIpush (iCode * ic)
2584 {
2585   int size, offset = 0;
2586   const char *l;
2587
2588   /* if this is not a parm push : ie. it is spill push
2589      and spill push is always done on the local stack */
2590   if (!ic->parmPush)
2591     {
2592       wassertl(0, "Encountered an unsupported spill push.");
2593       return;
2594     }
2595
2596   if (_G.saves.saved == FALSE) {
2597     /* Caller saves, and this is the first iPush. */
2598     /* Scan ahead until we find the function that we are pushing parameters to.
2599        Count the number of addSets on the way to figure out what registers
2600        are used in the send set.
2601     */
2602     int nAddSets = 0;
2603     iCode *walk = ic->next;
2604     
2605     while (walk) {
2606       if (walk->op == SEND) {
2607         nAddSets++;
2608       }
2609       else if (walk->op == CALL || walk->op == PCALL) {
2610         /* Found it. */
2611         break;
2612       }
2613       else {
2614         /* Keep looking. */
2615       }
2616       walk = walk->next;
2617     }
2618     _saveRegsForCall(walk, nAddSets);
2619   }
2620   else {
2621     /* Already saved by another iPush. */
2622   }
2623
2624   /* then do the push */
2625   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2626
2627   size = AOP_SIZE (IC_LEFT (ic));
2628
2629   if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2630     {
2631       _G.stack.pushed += 2;
2632       emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2633     }
2634   else
2635     {
2636       if (size == 2)
2637         {
2638           fetchHL (AOP (IC_LEFT (ic)));
2639           emit2 ("push hl");
2640           spillPair (PAIR_HL);
2641           _G.stack.pushed += 2;
2642           goto release;
2643         }
2644       if (size == 4)
2645         {
2646           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2647           emit2 ("push hl");
2648           spillPair (PAIR_HL);
2649           _G.stack.pushed += 2;
2650           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2651           emit2 ("push hl");
2652           spillPair (PAIR_HL);
2653           _G.stack.pushed += 2;
2654           goto release;
2655         }
2656       offset = size;
2657       while (size--)
2658         {
2659           if (AOP (IC_LEFT (ic))->type == AOP_IY)
2660             {
2661               char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2662               wassert (l);
2663               emit2 ("ld a,(%s)", l);
2664             }
2665           else
2666             {
2667               l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2668               emit2 ("ld a,%s", l);
2669             }
2670           emit2 ("push af");
2671           emit2 ("inc sp");
2672           _G.stack.pushed++;
2673         }
2674     }
2675 release:
2676   freeAsmop (IC_LEFT (ic), NULL, ic);
2677 }
2678
2679 /*-----------------------------------------------------------------*/
2680 /* genIpop - recover the registers: can happen only for spilling   */
2681 /*-----------------------------------------------------------------*/
2682 static void
2683 genIpop (iCode * ic)
2684 {
2685   int size, offset;
2686
2687
2688   /* if the temp was not pushed then */
2689   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2690     return;
2691
2692   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2693   size = AOP_SIZE (IC_LEFT (ic));
2694   offset = (size - 1);
2695   if (isPair (AOP (IC_LEFT (ic))))
2696     {
2697       emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2698     }
2699   else
2700     {
2701       while (size--)
2702         {
2703           emit2 ("dec sp");
2704           emit2 ("pop hl");
2705           spillPair (PAIR_HL);
2706           aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2707         }
2708     }
2709
2710   freeAsmop (IC_LEFT (ic), NULL, ic);
2711 }
2712
2713 /* This is quite unfortunate */
2714 static void
2715 setArea (int inHome)
2716 {
2717   /*
2718     static int lastArea = 0;
2719
2720      if (_G.in_home != inHome) {
2721      if (inHome) {
2722      const char *sz = port->mem.code_name;
2723      port->mem.code_name = "HOME";
2724      emit2("!area", CODE_NAME);
2725      port->mem.code_name = sz;
2726      }
2727      else
2728      emit2("!area", CODE_NAME); */
2729   _G.in_home = inHome;
2730   //    }
2731 }
2732
2733 static bool
2734 isInHome (void)
2735 {
2736   return _G.in_home;
2737 }
2738
2739 static int
2740 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2741 {
2742   int ret = 0;
2743   asmop *aop;
2744   symbol *sym = OP_SYMBOL (op);
2745
2746   if (sym->isspilt || sym->nRegs == 0)
2747     return 0;
2748
2749   aopOp (op, ic, FALSE, FALSE);
2750
2751   aop = AOP (op);
2752   if (aop->type == AOP_REG)
2753     {
2754       int i;
2755       for (i = 0; i < aop->size; i++)
2756         {
2757           if (pairId == PAIR_DE)
2758             {
2759               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2760               if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2761                 ret++;
2762               if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2763                 ret++;
2764             }
2765           else if (pairId == PAIR_BC)
2766             {
2767               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2768               if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2769                 ret++;
2770               if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2771                 ret++;
2772             }
2773           else
2774             {
2775               wassert (0);
2776             }
2777         }
2778     }
2779
2780   freeAsmop (IC_LEFT (ic), NULL, ic);
2781   return ret;
2782 }
2783
2784 /** Emit the code for a call statement
2785  */
2786 static void
2787 emitCall (iCode * ic, bool ispcall)
2788 {
2789   bool bInRet, cInRet, dInRet, eInRet;
2790   sym_link *dtype = operandType (IC_LEFT (ic));
2791
2792   /* if caller saves & we have not saved then */
2793   if (!ic->regsSaved)
2794     {
2795       /* PENDING */
2796     }
2797
2798   _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2799
2800   /* if send set is not empty then assign */
2801   if (_G.sendSet)
2802     {
2803       iCode *sic;
2804       int send = 0;
2805       int nSend = elementsInSet(_G.sendSet);
2806       bool swapped = FALSE;
2807
2808       int _z80_sendOrder[] = {
2809         PAIR_BC, PAIR_DE
2810       };
2811
2812       if (nSend > 1) {
2813         /* Check if the parameters are swapped.  If so route through hl instead. */
2814         wassertl (nSend == 2, "Pedantic check.  Code only checks for the two send items case.");
2815
2816         sic = setFirstItem(_G.sendSet);
2817         sic = setNextItem(_G.sendSet);
2818
2819         if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2820           /* The second send value is loaded from one the one that holds the first
2821              send, i.e. it is overwritten. */
2822           /* Cache the first in HL, and load the second from HL instead. */
2823           emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2824           emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2825
2826           swapped = TRUE;
2827         }
2828       }
2829
2830       for (sic = setFirstItem (_G.sendSet); sic;
2831            sic = setNextItem (_G.sendSet))
2832         {
2833           int size;
2834           aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2835
2836           size = AOP_SIZE (IC_LEFT (sic));
2837           wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2838           wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2839
2840           // PENDING: Mild hack
2841           if (swapped == TRUE && send == 1) {
2842             if (size > 1) {
2843               emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2844             }
2845             else {
2846               emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2847             }
2848             emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2849           }
2850           else {
2851             fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2852           }
2853
2854           send++;
2855           freeAsmop (IC_LEFT (sic), NULL, sic);
2856         }
2857       _G.sendSet = NULL;
2858     }
2859
2860   if (ispcall)
2861     {
2862       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2863         {
2864           werror (W_INDIR_BANKED);
2865         }
2866       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2867
2868       if (isLitWord (AOP (IC_LEFT (ic))))
2869         {
2870           emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2871         }
2872       else
2873         {
2874           symbol *rlbl = newiTempLabel (NULL);
2875           spillPair (PAIR_HL);
2876           emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2877           emit2 ("push hl");
2878           _G.stack.pushed += 2;
2879
2880           fetchHL (AOP (IC_LEFT (ic)));
2881           emit2 ("jp !*hl");
2882           emit2 ("!tlabeldef", (rlbl->key + 100));
2883           _G.stack.pushed -= 2;
2884         }
2885       freeAsmop (IC_LEFT (ic), NULL, ic);
2886     }
2887   else
2888     {
2889       char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2890       OP_SYMBOL (IC_LEFT (ic))->rname :
2891       OP_SYMBOL (IC_LEFT (ic))->name;
2892       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2893         {
2894           emit2 ("call banked_call");
2895           emit2 ("!dws", name);
2896           emit2 ("!dw !bankimmeds", name);
2897         }
2898       else
2899         {
2900           /* make the call */
2901           emit2 ("call %s", name);
2902         }
2903     }
2904   spillCached ();
2905
2906   /* Mark the regsiters as restored. */
2907   _G.saves.saved = FALSE;
2908
2909   /* if we need assign a result value */
2910   if ((IS_ITEMP (IC_RESULT (ic)) &&
2911        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2912         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2913       IS_TRUE_SYMOP (IC_RESULT (ic)))
2914     {
2915
2916       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2917
2918       assignResultValue (IC_RESULT (ic));
2919
2920       freeAsmop (IC_RESULT (ic), NULL, ic);
2921     }
2922
2923   /* adjust the stack for parameters if required */
2924   if (ic->parmBytes)
2925     {
2926       int i = ic->parmBytes;
2927
2928       _G.stack.pushed -= i;
2929       if (IS_GB)
2930         {
2931           emit2 ("!ldaspsp", i);
2932         }
2933       else
2934         {
2935           spillCached ();
2936           if (i > 8)
2937             {
2938               emit2 ("ld iy,!immedword", i);
2939               emit2 ("add iy,sp");
2940               emit2 ("ld sp,iy");
2941             }
2942           else
2943             {
2944               while (i > 1)
2945                 {
2946                   emit2 ("pop af");
2947                   i -= 2;
2948                 }
2949               if (i)
2950                 {
2951                   emit2 ("inc sp");
2952                 }
2953             }
2954         }
2955     }
2956
2957   spillCached ();
2958   if (IC_RESULT (ic))
2959     {
2960       bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2961       bInRet = bitVectBitValue(result, B_IDX);
2962       cInRet = bitVectBitValue(result, C_IDX);
2963       dInRet = bitVectBitValue(result, D_IDX);
2964       eInRet = bitVectBitValue(result, E_IDX);
2965     }
2966   else
2967     {
2968       bInRet = FALSE;
2969       cInRet = FALSE;
2970       dInRet = FALSE;
2971       eInRet = FALSE;
2972     }
2973
2974   if (_G.stack.pushedDE) 
2975     {
2976       if (dInRet && eInRet)
2977         {
2978           wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2979         }
2980       else if (dInRet)
2981         {
2982           /* Only restore E */
2983           emit2 ("ld a,d");
2984           _pop (PAIR_DE);
2985           emit2 ("ld d,a");
2986         }
2987       else if (eInRet)
2988         {
2989           /* Only restore D */
2990           _pop (PAIR_AF);
2991           emit2 ("ld d,a");
2992         }
2993       else
2994         {
2995           _pop (PAIR_DE);
2996         }
2997       _G.stack.pushedDE = FALSE;
2998     }
2999   
3000   if (_G.stack.pushedBC) 
3001     {
3002       if (bInRet && cInRet)
3003         {
3004           wassertl (0, "Shouldn't push BC if it's wiped out by the return");
3005         }
3006       else if (bInRet)
3007         {
3008           /* Only restore C */
3009           emit2 ("ld a,b");
3010           _pop (PAIR_BC);
3011           emit2 ("ld b,a");
3012         }
3013       else if (cInRet)
3014         {
3015           /* Only restore B */
3016           _pop (PAIR_AF);
3017           emit2 ("ld b,a");
3018         }
3019       else
3020         {
3021           _pop (PAIR_BC);
3022         }
3023       _G.stack.pushedBC = FALSE;
3024     }
3025 }
3026
3027 /*-----------------------------------------------------------------*/
3028 /* genCall - generates a call statement                            */
3029 /*-----------------------------------------------------------------*/
3030 static void
3031 genCall (iCode * ic)
3032 {
3033   emitCall (ic, FALSE);
3034 }
3035
3036 /*-----------------------------------------------------------------*/
3037 /* genPcall - generates a call by pointer statement                */
3038 /*-----------------------------------------------------------------*/
3039 static void
3040 genPcall (iCode * ic)
3041 {
3042   emitCall (ic, TRUE);
3043 }
3044
3045 /*-----------------------------------------------------------------*/
3046 /* resultRemat - result  is rematerializable                       */
3047 /*-----------------------------------------------------------------*/
3048 static int
3049 resultRemat (iCode * ic)
3050 {
3051   if (SKIP_IC (ic) || ic->op == IFX)
3052     return 0;
3053
3054   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3055     {
3056       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3057       if (sym->remat && !POINTER_SET (ic))
3058         return 1;
3059     }
3060
3061   return 0;
3062 }
3063
3064 extern set *publics;
3065
3066 /*-----------------------------------------------------------------*/
3067 /* genFunction - generated code for function entry                 */
3068 /*-----------------------------------------------------------------*/
3069 static void
3070 genFunction (iCode * ic)
3071 {
3072   bool stackParm;
3073   
3074   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3075   sym_link *ftype;
3076
3077   bool bcInUse = FALSE;
3078   bool deInUse = FALSE;
3079
3080   setArea (IFFUNC_NONBANKED (sym->type));
3081
3082   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
3083      else.
3084   */
3085   _G.receiveOffset = 0;
3086
3087   /* Record the last function name for debugging. */
3088   _G.lastFunctionName = sym->rname;
3089   
3090   /* Create the function header */
3091   emit2 ("!functionheader", sym->name);
3092   sprintf (buffer, "%s_start", sym->rname);
3093   emit2 ("!labeldef", buffer);
3094   emit2 ("!functionlabeldef", sym->rname);
3095
3096   if (options.profile) 
3097     {
3098       emit2 ("!profileenter");
3099     }
3100
3101   ftype = operandType (IC_LEFT (ic));
3102
3103   /* if critical function then turn interrupts off */
3104   if (IFFUNC_ISCRITICAL (ftype))
3105     emit2 ("!di");
3106
3107   /* if this is an interrupt service routine then save all potentially used registers. */
3108   if (IFFUNC_ISISR (sym->type))
3109     {
3110       emit2 ("!pusha");
3111     }
3112
3113   /* PENDING: callee-save etc */
3114
3115   _G.stack.param_offset = 0;
3116
3117   if (z80_opts.calleeSavesBC)
3118     {
3119       bcInUse = TRUE;
3120     }
3121
3122   /* Detect which registers are used. */
3123   if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3124     {
3125       int i;
3126       for (i = 0; i < sym->regsUsed->size; i++)
3127         {
3128           if (bitVectBitValue (sym->regsUsed, i))
3129             {
3130               switch (i)
3131                 {
3132                 case C_IDX:
3133                 case B_IDX:
3134                   bcInUse = TRUE;
3135                   break;
3136                 case D_IDX:
3137                 case E_IDX:
3138                   if (IS_Z80) {
3139                     deInUse = TRUE;
3140                   }
3141                   else {
3142                     /* Other systems use DE as a temporary. */
3143                   }
3144                   break;
3145                 }
3146             }
3147         }
3148     }
3149
3150   if (bcInUse) 
3151     {
3152       emit2 ("push bc");
3153       _G.stack.param_offset += 2;
3154     }
3155
3156   _G.calleeSaves.pushedBC = bcInUse;
3157
3158   if (deInUse)
3159     {
3160       emit2 ("push de");
3161       _G.stack.param_offset += 2;
3162     }
3163
3164   _G.calleeSaves.pushedDE = deInUse;
3165
3166   /* adjust the stack for the function */
3167   _G.stack.last = sym->stack;
3168   
3169   stackParm = FALSE;
3170   for (sym = setFirstItem (istack->syms); sym;
3171        sym = setNextItem (istack->syms))
3172     {
3173       if (sym->_isparm && !IS_REGPARM (sym->etype))
3174         {
3175           stackParm = TRUE;
3176           break;
3177         }
3178     }
3179   sym = OP_SYMBOL (IC_LEFT (ic));
3180   
3181   _G.omitFramePtr = options.ommitFramePtr;
3182   if (IS_Z80 && !stackParm && !sym->stack)
3183     {
3184       /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3185       /* the above !sym->stack condition can be removed. -- EEP       */
3186       if (sym->stack)
3187         emit2 ("!ldaspsp", -sym->stack);
3188       _G.omitFramePtr = TRUE;
3189     }
3190   else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3191     emit2 ("!enterxl", sym->stack);
3192   else if (sym->stack)
3193     emit2 ("!enterx", sym->stack);
3194   else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3195     emit2 ("!enter");
3196
3197   _G.stack.offset = sym->stack;
3198 }
3199
3200 /*-----------------------------------------------------------------*/
3201 /* genEndFunction - generates epilogue for functions               */
3202 /*-----------------------------------------------------------------*/
3203 static void
3204 genEndFunction (iCode * ic)
3205 {
3206   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3207
3208   if (IFFUNC_ISISR (sym->type))
3209     {
3210       wassertl (0, "Tried to close an interrupt support function");
3211     }
3212   else
3213     {
3214       if (IFFUNC_ISCRITICAL (sym->type))
3215         emit2 ("!ei");
3216
3217       /* PENDING: calleeSave */
3218
3219       if (IS_Z80 && _G.omitFramePtr)
3220         {
3221           if (_G.stack.offset)
3222             emit2 ("!ldaspsp", _G.stack.offset);
3223         }
3224       else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3225         {
3226           emit2 ("!leavexl", _G.stack.offset);
3227         }
3228       else if (_G.stack.offset)
3229         {
3230           emit2 ("!leavex", _G.stack.offset);
3231         }
3232       else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
3233         {
3234           emit2 ("!leave");
3235         }
3236
3237       if (_G.calleeSaves.pushedDE) 
3238         {
3239           emit2 ("pop de");
3240           _G.calleeSaves.pushedDE = FALSE;
3241         }
3242
3243       if (_G.calleeSaves.pushedBC) 
3244         {
3245           emit2 ("pop bc");
3246           _G.calleeSaves.pushedBC = FALSE;
3247         }
3248
3249       if (options.profile) 
3250         {
3251           emit2 ("!profileexit");
3252         }
3253
3254
3255       if (options.debug && currFunc)
3256         {
3257           _G.lines.isDebug = 1;
3258           sprintf (buffer, "C$%s$%d$%d$%d",
3259                     FileBaseName (ic->filename), currFunc->lastLine,
3260                     ic->level, ic->block);
3261           emit2 ("!labeldef", buffer);
3262           if (IS_STATIC (currFunc->etype))
3263             sprintf (buffer, "XF%s$%s$0$0", moduleName, currFunc->name);
3264           else
3265             sprintf (buffer, "XG$%s$0$0", currFunc->name);
3266           emit2 ("!labeldef", buffer);
3267           _G.lines.isDebug = 0;
3268         }
3269       
3270       /* Both banked and non-banked just ret */
3271       emit2 ("ret");
3272
3273       sprintf (buffer, "%s_end", sym->rname);
3274       emit2 ("!labeldef", buffer);
3275     }
3276   _G.flushStatics = 1;
3277   _G.stack.pushed = 0;
3278   _G.stack.offset = 0;
3279 }
3280
3281 /*-----------------------------------------------------------------*/
3282 /* genRet - generate code for return statement                     */
3283 /*-----------------------------------------------------------------*/
3284 static void
3285 genRet (iCode * ic)
3286 {
3287     const char *l;
3288   /* Errk.  This is a hack until I can figure out how
3289      to cause dehl to spill on a call */
3290   int size, offset = 0;
3291
3292   /* if we have no return value then
3293      just generate the "ret" */
3294   if (!IC_LEFT (ic))
3295     goto jumpret;
3296
3297   /* we have something to return then
3298      move the return value into place */
3299   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3300   size = AOP_SIZE (IC_LEFT (ic));
3301
3302   aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3303
3304   #if 0  
3305   if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3306     {
3307       if (IS_GB)
3308         {
3309           emit2 ("ld de,%s", l);
3310         }
3311       else
3312         {
3313           emit2 ("ld hl,%s", l);
3314         }
3315     }
3316   #endif
3317   if (size==2)
3318     {
3319       fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3320     }
3321   else
3322     {
3323       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3324         {
3325           fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3326           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3327         }
3328       else
3329         {
3330           while (size--)
3331             {
3332               l = aopGet (AOP (IC_LEFT (ic)), offset,
3333                           FALSE);
3334               if (strcmp (_fReturn[offset], l))
3335                 emit2 ("ld %s,%s", _fReturn[offset], l);
3336               offset++;
3337             }
3338         }
3339     }
3340   freeAsmop (IC_LEFT (ic), NULL, ic);
3341
3342 jumpret:
3343   /* generate a jump to the return label
3344      if the next is not the return statement */
3345   if (!(ic->next && ic->next->op == LABEL &&
3346         IC_LABEL (ic->next) == returnLabel))
3347
3348     emit2 ("jp !tlabel", returnLabel->key + 100);
3349 }
3350
3351 /*-----------------------------------------------------------------*/
3352 /* genLabel - generates a label                                    */
3353 /*-----------------------------------------------------------------*/
3354 static void
3355 genLabel (iCode * ic)
3356 {
3357   /* special case never generate */
3358   if (IC_LABEL (ic) == entryLabel)
3359     return;
3360
3361   emitLabel (IC_LABEL (ic)->key + 100);
3362 }
3363
3364 /*-----------------------------------------------------------------*/
3365 /* genGoto - generates a ljmp                                      */
3366 /*-----------------------------------------------------------------*/
3367 static void
3368 genGoto (iCode * ic)
3369 {
3370   emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3371 }
3372
3373 /*-----------------------------------------------------------------*/
3374 /* genPlusIncr :- does addition with increment if possible         */
3375 /*-----------------------------------------------------------------*/
3376 static bool
3377 genPlusIncr (iCode * ic)
3378 {
3379   unsigned int icount;
3380   unsigned int size = getDataSize (IC_RESULT (ic));
3381   PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3382
3383   /* will try to generate an increment */
3384   /* if the right side is not a literal
3385      we cannot */
3386   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3387     return FALSE;
3388
3389   emitDebug ("; genPlusIncr");
3390
3391   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3392
3393   /* If result is a pair */
3394   if (resultId != PAIR_INVALID)
3395     {
3396       if (isLitWord (AOP (IC_LEFT (ic))))
3397         {
3398           fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3399           return TRUE;
3400         }
3401       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3402         {
3403           if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3404             {
3405               PAIR_ID freep = getFreePairId (ic);
3406               if (freep != PAIR_INVALID)
3407                 {
3408                   fetchPair (freep, AOP (IC_RIGHT (ic)));
3409                   emit2 ("add hl,%s", _pairs[freep].name);
3410                   return TRUE;
3411                 }
3412             }
3413           else
3414             {
3415               fetchPair (resultId, AOP (IC_RIGHT (ic)));
3416               emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3417               return TRUE;
3418             }
3419         }
3420       if (icount > 5)
3421         return FALSE;
3422       /* Inc a pair */
3423       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3424         {
3425           if (icount > 2)
3426             return FALSE;
3427           movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3428         }
3429       while (icount--)
3430         {
3431           emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3432         }
3433       return TRUE;
3434     }
3435
3436   if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3437     {
3438       fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3439       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3440       return TRUE;
3441     }
3442
3443   /* if the literal value of the right hand side
3444      is greater than 4 then it is not worth it */
3445   if (icount > 4)
3446     return FALSE;
3447
3448   /* if increment 16 bits in register */
3449   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3450       size > 1 &&
3451       icount == 1
3452     )
3453     {
3454       int offset = 0;
3455       symbol *tlbl = NULL;
3456       tlbl = newiTempLabel (NULL);
3457       while (size--)
3458         {
3459           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3460           if (size)
3461             {
3462               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3463             }
3464         }
3465       emitLabel (tlbl->key + 100);
3466       return TRUE;
3467     }
3468
3469   /* if the sizes are greater than 1 then we cannot */
3470   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3471       AOP_SIZE (IC_LEFT (ic)) > 1)
3472     return FALSE;
3473
3474   /* If the result is in a register then we can load then increment.
3475    */
3476   if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3477     {
3478       aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3479       while (icount--)
3480         {
3481           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3482         }
3483       return TRUE;
3484     }
3485
3486   /* we can if the aops of the left & result match or
3487      if they are in registers and the registers are the
3488      same */
3489   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3490     {
3491       while (icount--)
3492         {
3493           emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3494         }
3495       return TRUE;
3496     }
3497
3498   return FALSE;
3499 }
3500
3501 /*-----------------------------------------------------------------*/
3502 /* outBitAcc - output a bit in acc                                 */
3503 /*-----------------------------------------------------------------*/
3504 void
3505 outBitAcc (operand * result)
3506 {
3507   symbol *tlbl = newiTempLabel (NULL);
3508   /* if the result is a bit */
3509   if (AOP_TYPE (result) == AOP_CRY)
3510     {
3511       wassertl (0, "Tried to write A into a bit");
3512     }
3513   else
3514     {
3515       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3516       emit2 ("ld a,!one");
3517       emitLabel (tlbl->key + 100);
3518       outAcc (result);
3519     }
3520 }
3521
3522 bool
3523 couldDestroyCarry (asmop *aop)
3524 {
3525   if (aop)
3526     {
3527       if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3528         {
3529           return TRUE;
3530         }
3531     }
3532   return FALSE;
3533 }
3534
3535 static void
3536 shiftIntoPair (int idx, asmop *aop)
3537 {
3538   PAIR_ID id = PAIR_INVALID;
3539
3540   wassertl (IS_Z80, "Only implemented for the Z80");
3541   //  wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3542
3543   switch (idx) 
3544     {
3545     case 0:
3546       id = PAIR_HL;
3547       break;
3548     case 1:
3549       id = PAIR_DE;
3550       _push (PAIR_DE);
3551       break;
3552     default:
3553       wassertl (0, "Internal error - hit default case");
3554     }
3555
3556   emitDebug ("; Shift into pair idx %u", idx);
3557
3558   if (id == PAIR_HL)
3559     {
3560       setupPair (PAIR_HL, aop, 0);
3561     }
3562   else
3563     {
3564       setupPair (PAIR_IY, aop, 0);
3565       emit2 ("push iy");
3566       emit2 ("pop %s", _pairs[id].name);
3567     }
3568
3569   aop->type = AOP_PAIRPTR;
3570   aop->aopu.aop_pairId = id;
3571   _G.pairs[id].offset = 0;
3572   _G.pairs[id].last_type = aop->type;
3573 }
3574
3575 static void 
3576 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3577 {
3578   wassert (left && right);
3579
3580   if (IS_Z80)
3581     {
3582       if (couldDestroyCarry (right) && couldDestroyCarry (result))
3583         {
3584           shiftIntoPair (0, right);
3585           /* check result again, in case right == result */
3586           if (couldDestroyCarry (result))
3587             shiftIntoPair (1, result);
3588         }
3589       else if (couldDestroyCarry (right))
3590         {
3591           if (getPairId (result) == PAIR_HL)
3592             _G.preserveCarry = TRUE;
3593           else
3594             shiftIntoPair (0, right);
3595         }
3596       else if (couldDestroyCarry (result))
3597         {
3598           shiftIntoPair (0, result);
3599         }
3600       else
3601         {
3602           /* Fine */
3603         }
3604     }
3605 }
3606
3607 /*-----------------------------------------------------------------*/
3608 /* genPlus - generates code for addition                           */
3609 /*-----------------------------------------------------------------*/
3610 static void
3611 genPlus (iCode * ic)
3612 {
3613   int size, offset = 0;
3614
3615   /* special cases :- */
3616
3617   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3618   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3619   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3620
3621   /* Swap the left and right operands if:
3622
3623      if literal, literal on the right or
3624      if left requires ACC or right is already
3625      in ACC */
3626
3627   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3628       (AOP_NEEDSACC (IC_RIGHT (ic))) ||
3629       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3630     {
3631       operand *t = IC_RIGHT (ic);
3632       IC_RIGHT (ic) = IC_LEFT (ic);
3633       IC_LEFT (ic) = t;
3634     }
3635
3636   /* if both left & right are in bit
3637      space */
3638   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3639       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3640     {
3641       /* Cant happen */
3642       wassertl (0, "Tried to add two bits");
3643     }
3644
3645   /* if left in bit space & right literal */
3646   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3647       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3648     {
3649       /* Can happen I guess */
3650       wassertl (0, "Tried to add a bit to a literal");
3651     }
3652
3653   /* if I can do an increment instead
3654      of add then GOOD for ME */
3655   if (genPlusIncr (ic) == TRUE)
3656     goto release;
3657
3658   emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3659
3660   size = getDataSize (IC_RESULT (ic));
3661
3662   /* Special case when left and right are constant */
3663   if (isPair (AOP (IC_RESULT (ic))))
3664     {
3665       char *left, *right;
3666       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3667       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3668
3669       if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3670           left && right)
3671         {
3672           /* It's a pair */
3673           /* PENDING: fix */
3674           char buffer[100];
3675           sprintf (buffer, "#(%s + %s)", left, right);
3676           emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3677           goto release;
3678         }
3679     }
3680
3681   if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3682     {
3683       /* Fetch into HL then do the add */
3684       PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3685       PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3686
3687       spillPair (PAIR_HL);
3688       
3689       if (left == PAIR_HL && right != PAIR_INVALID)
3690         {
3691           emit2 ("add hl,%s", _pairs[right].name);
3692           goto release;
3693         }
3694       else if (right == PAIR_HL && left != PAIR_INVALID)
3695         {
3696           emit2 ("add hl,%s", _pairs[left].name);
3697           goto release;
3698         }
3699       else if (right != PAIR_INVALID && right != PAIR_HL)
3700         {
3701           fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3702           emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3703           goto release;
3704         }
3705       else if (left != PAIR_INVALID && left != PAIR_HL)
3706         { 
3707           fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3708           emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3709           goto release;
3710         }
3711       else
3712         {
3713           /* Can't do it */
3714         }
3715     }
3716
3717   if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3718     {
3719       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3720       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3721       spillCached();
3722       commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3723       goto release;
3724     }
3725
3726   /* Special case:
3727      ld hl,sp+n trashes C so we cant afford to do it during an
3728      add with stack based varibles.  Worst case is:
3729      ld  hl,sp+left
3730      ld  a,(hl)
3731      ld  hl,sp+right
3732      add (hl)
3733      ld  hl,sp+result
3734      ld  (hl),a
3735      ld  hl,sp+left+1
3736      ld  a,(hl)
3737      ld  hl,sp+right+1
3738      adc (hl)
3739      ld  hl,sp+result+1
3740      ld  (hl),a
3741      So you cant afford to load up hl if either left, right, or result
3742      is on the stack (*sigh*)  The alt is:
3743      ld  hl,sp+left
3744      ld  de,(hl)
3745      ld  hl,sp+right
3746      ld  hl,(hl)
3747      add hl,de
3748      ld  hl,sp+result
3749      ld  (hl),hl
3750      Combinations in here are:
3751      * If left or right are in bc then the loss is small - trap later
3752      * If the result is in bc then the loss is also small
3753    */
3754   if (IS_GB)
3755     {
3756       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3757           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3758           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3759         {
3760           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3761                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3762               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3763                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3764             {
3765               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3766                 {
3767                   /* Swap left and right */
3768                   operand *t = IC_RIGHT (ic);
3769                   IC_RIGHT (ic) = IC_LEFT (ic);
3770                   IC_LEFT (ic) = t;
3771                 }
3772               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3773                 {
3774                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3775                   emit2 ("add hl,bc");
3776                 }
3777               else
3778                 {
3779                   fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3780                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3781                   emit2 ("add hl,de");
3782                 }
3783               commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3784               goto release;
3785             }
3786         }
3787       if (size == 4)
3788         {
3789           /* Be paranoid on the GB with 4 byte variables due to how C
3790              can be trashed by lda hl,n(sp).
3791           */
3792           _gbz80_emitAddSubLong (ic, TRUE);
3793           goto release;
3794         }
3795     }
3796   
3797   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3798
3799   while (size--)
3800     {
3801       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3802         {
3803           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3804           if (offset == 0)
3805             emit2 ("add a,%s",
3806                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3807           else
3808             emit2 ("adc a,%s",
3809                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3810         }
3811       else
3812         {
3813           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3814           if (offset == 0)
3815             emit2 ("add a,%s",
3816                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3817           else
3818             emit2 ("adc a,%s",
3819                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3820         }
3821       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3822     }
3823
3824 release:
3825   _G.preserveCarry = FALSE;
3826   freeAsmop (IC_LEFT (ic), NULL, ic);
3827   freeAsmop (IC_RIGHT (ic), NULL, ic);
3828   freeAsmop (IC_RESULT (ic), NULL, ic);
3829
3830 }
3831
3832 /*-----------------------------------------------------------------*/
3833 /* genMinusDec :- does subtraction with deccrement if possible     */
3834 /*-----------------------------------------------------------------*/
3835 static bool
3836 genMinusDec (iCode * ic)
3837 {
3838   unsigned int icount;
3839   unsigned int size = getDataSize (IC_RESULT (ic));
3840
3841   /* will try to generate an increment */
3842   /* if the right side is not a literal we cannot */
3843   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3844     return FALSE;
3845
3846   /* if the literal value of the right hand side
3847      is greater than 4 then it is not worth it */
3848   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3849     return FALSE;
3850
3851   size = getDataSize (IC_RESULT (ic));
3852
3853   /* if decrement 16 bits in register */
3854   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3855       (size > 1) && isPair (AOP (IC_RESULT (ic))))
3856     {
3857       while (icount--)
3858         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3859       return TRUE;
3860     }
3861
3862   /* If result is a pair */
3863   if (isPair (AOP (IC_RESULT (ic))))
3864     {
3865       movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3866       while (icount--)
3867         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3868       return TRUE;
3869     }
3870
3871   /* if increment 16 bits in register */
3872   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3873       (size == 2)
3874       )
3875     {
3876       fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3877
3878       while (icount--) {
3879         emit2 ("dec %s", _getTempPairName());
3880       }
3881
3882       commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3883
3884       return TRUE;
3885     }
3886
3887
3888   /* if the sizes are greater than 1 then we cannot */
3889   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3890       AOP_SIZE (IC_LEFT (ic)) > 1)
3891     return FALSE;
3892
3893   /* we can if the aops of the left & result match or if they are in
3894      registers and the registers are the same */
3895   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3896     {
3897       while (icount--)
3898         emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3899       return TRUE;
3900     }
3901
3902   return FALSE;
3903 }
3904
3905 /*-----------------------------------------------------------------*/
3906 /* genMinus - generates code for subtraction                       */
3907 /*-----------------------------------------------------------------*/
3908 static void
3909 genMinus (iCode * ic)
3910 {
3911   int size, offset = 0;
3912   unsigned long lit = 0L;
3913
3914   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3915   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3916   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3917
3918   /* special cases :- */
3919   /* if both left & right are in bit space */
3920   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3921       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3922     {
3923       wassertl (0, "Tried to subtract two bits");
3924       goto release;
3925     }
3926
3927   /* if I can do an decrement instead of subtract then GOOD for ME */
3928   if (genMinusDec (ic) == TRUE)
3929     goto release;
3930
3931   size = getDataSize (IC_RESULT (ic));
3932
3933   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3934     {
3935     }
3936   else
3937     {
3938       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3939       lit = -(long) lit;
3940     }
3941
3942   /* Same logic as genPlus */
3943   if (IS_GB)
3944     {
3945       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3946           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3947           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3948         {
3949           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3950                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3951               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3952                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3953             {
3954               PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3955               PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3956
3957               if (left == PAIR_INVALID && right == PAIR_INVALID)
3958                 {
3959                   left = PAIR_DE;
3960                   right = PAIR_HL;
3961                 }
3962               else if (right == PAIR_INVALID)
3963                 right = PAIR_DE;
3964               else if (left == PAIR_INVALID)
3965                 left = PAIR_DE;
3966
3967               fetchPair (left, AOP (IC_LEFT (ic)));
3968               /* Order is important.  Right may be HL */
3969               fetchPair (right, AOP (IC_RIGHT (ic)));
3970
3971               emit2 ("ld a,%s", _pairs[left].l);
3972               emit2 ("sub a,%s", _pairs[right].l);
3973               emit2 ("ld e,a");
3974               emit2 ("ld a,%s", _pairs[left].h);
3975               emit2 ("sbc a,%s", _pairs[right].h);
3976
3977               if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3978                 {
3979                   aopPut (AOP (IC_RESULT (ic)), "a", 1);
3980                 }
3981               aopPut (AOP (IC_RESULT (ic)), "e", 0);
3982               goto release;
3983             }
3984         }
3985       if (size == 4)
3986         {
3987           /* Be paranoid on the GB with 4 byte variables due to how C
3988              can be trashed by lda hl,n(sp).
3989           */
3990           _gbz80_emitAddSubLong (ic, FALSE);
3991           goto release;
3992         }
3993     }
3994
3995   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3996
3997   /* if literal, add a,#-lit, else normal subb */
3998   while (size--)
3999     {
4000       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
4001       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4002         {
4003           if (!offset)
4004             emit2 ("sub a,%s",
4005                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4006           else
4007             emit2 ("sbc a,%s",
4008                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
4009         }
4010       else
4011         {
4012           /* first add without previous c */
4013           if (!offset)
4014             emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
4015           else
4016             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4017         }
4018       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4019     }
4020
4021   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4022       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4023       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4024     {
4025       wassertl (0, "Tried to subtract on a long pointer");
4026     }
4027
4028 release:
4029   _G.preserveCarry = FALSE;
4030   freeAsmop (IC_LEFT (ic), NULL, ic);
4031   freeAsmop (IC_RIGHT (ic), NULL, ic);
4032   freeAsmop (IC_RESULT (ic), NULL, ic);
4033 }
4034
4035 /*-----------------------------------------------------------------*/
4036 /* genMult - generates code for multiplication                     */
4037 /*-----------------------------------------------------------------*/
4038 static void
4039 genMult (iCode * ic)
4040 {
4041   int val;
4042   int count, i;
4043   /* If true then the final operation should be a subtract */
4044   bool active = FALSE;
4045
4046   /* Shouldn't occur - all done through function calls */
4047   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4048   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
4049   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4050
4051   if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
4052       AOP_SIZE (IC_RIGHT (ic)) > 2 ||
4053       AOP_SIZE (IC_RESULT (ic)) > 2)
4054     {
4055       wassertl (0, "Multiplication is handled through support function calls");
4056     }
4057
4058   /* Swap left and right such that right is a literal */
4059   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
4060     {
4061       operand *t = IC_RIGHT (ic);
4062       IC_RIGHT (ic) = IC_LEFT (ic);
4063       IC_LEFT (ic) = t;
4064     }
4065
4066   wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
4067
4068   val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
4069   //  wassertl (val > 0, "Multiply must be positive");
4070   wassertl (val != 1, "Can't multiply by 1");
4071
4072   if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
4073     _push (PAIR_DE);
4074     _G.stack.pushedDE = TRUE;
4075   }
4076
4077   if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
4078     {
4079       emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
4080       emit2 ("ld a,e");
4081       emit2 ("rlc a");
4082       emit2 ("sbc a,a");
4083       emit2 ("ld d,a");
4084     }
4085   else
4086     {
4087       fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4088     }
4089
4090   i = val;
4091
4092   /* Fully unroled version of mul.s.  Not the most efficient.
4093    */
4094   for (count = 0; count < 16; count++)
4095     {
4096       if (count != 0 && active)
4097         {
4098           emit2 ("add hl,hl");
4099         }
4100       if (i & 0x8000U)
4101         {
4102           if (active == FALSE)
4103             {
4104               emit2 ("ld l,e");
4105               emit2 ("ld h,d");
4106             }
4107           else
4108             {
4109               emit2 ("add hl,de");
4110             }
4111           active = TRUE;
4112         }
4113       i <<= 1;
4114     }
4115
4116   spillCached();
4117
4118   if (IS_Z80 && _G.stack.pushedDE)
4119     {
4120       _pop (PAIR_DE);
4121       _G.stack.pushedDE = FALSE;
4122     }
4123
4124   commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4125
4126   freeAsmop (IC_LEFT (ic), NULL, ic);
4127   freeAsmop (IC_RIGHT (ic), NULL, ic);
4128   freeAsmop (IC_RESULT (ic), NULL, ic);
4129 }
4130
4131 /*-----------------------------------------------------------------*/
4132 /* genDiv - generates code for division                            */
4133 /*-----------------------------------------------------------------*/
4134 static void
4135 genDiv (iCode * ic)
4136 {
4137   /* Shouldn't occur - all done through function calls */
4138   wassertl (0, "Division is handled through support function calls");
4139 }
4140
4141 /*-----------------------------------------------------------------*/
4142 /* genMod - generates code for division                            */
4143 /*-----------------------------------------------------------------*/
4144 static void
4145 genMod (iCode * ic)
4146 {
4147   /* Shouldn't occur - all done through function calls */
4148   wassert (0);
4149 }
4150
4151 /*-----------------------------------------------------------------*/
4152 /* genIfxJump :- will create a jump depending on the ifx           */
4153 /*-----------------------------------------------------------------*/
4154 static void
4155 genIfxJump (iCode * ic, char *jval)
4156 {
4157   symbol *jlbl;
4158   const char *inst;
4159
4160   /* if true label then we jump if condition
4161      supplied is true */
4162   if (IC_TRUE (ic))
4163     {
4164       jlbl = IC_TRUE (ic);
4165       if (!strcmp (jval, "a"))
4166         {
4167           inst = "nz";
4168         }
4169       else if (!strcmp (jval, "c"))
4170         {
4171           inst = "c";
4172         }
4173       else if (!strcmp (jval, "nc"))
4174         {
4175           inst = "nc";
4176         }
4177       else if (!strcmp (jval, "m"))
4178         {
4179           inst = "m";
4180         }
4181       else if (!strcmp (jval, "p"))
4182         {
4183           inst = "p";
4184         }
4185       else
4186         {
4187           /* The buffer contains the bit on A that we should test */
4188           inst = "nz";
4189         }
4190     }
4191   else
4192     {
4193       /* false label is present */
4194       jlbl = IC_FALSE (ic);
4195       if (!strcmp (jval, "a"))
4196         {
4197           inst = "z";
4198         }
4199       else if (!strcmp (jval, "c"))
4200         {
4201           inst = "nc";
4202         }
4203       else if (!strcmp (jval, "nc"))
4204         {
4205           inst = "c";
4206         }
4207       else if (!strcmp (jval, "m"))
4208         {
4209           inst = "p";
4210         }
4211       else if (!strcmp (jval, "p"))
4212         {
4213           inst = "m";
4214         }
4215       else
4216         {
4217           /* The buffer contains the bit on A that we should test */
4218           inst = "z";
4219         }
4220     }
4221   /* Z80 can do a conditional long jump */
4222   if (!strcmp (jval, "a"))
4223     {
4224       emit2 ("or a,a");
4225     }
4226   else if (!strcmp (jval, "c"))
4227     {
4228     }
4229   else if (!strcmp (jval, "nc"))
4230     {
4231     }
4232   else if (!strcmp (jval, "m"))
4233     {
4234     }
4235   else if (!strcmp (jval, "p"))
4236     {
4237     }
4238   else
4239     {
4240       emit2 ("bit %s,a", jval);
4241     }
4242   emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4243
4244   /* mark the icode as generated */
4245   ic->generated = 1;
4246 }
4247
4248 #if DISABLED
4249 static const char *
4250 _getPairIdName (PAIR_ID id)
4251 {
4252   return _pairs[id].name;
4253 }
4254 #endif
4255
4256 #if OLD
4257       /* if unsigned char cmp with lit, just compare */
4258       if ((size == 1) &&
4259           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4260         {
4261           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4262           if (sign)
4263             {
4264               emit2 ("xor a,!immedbyte", 0x80);
4265               emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4266             }
4267           else
4268             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4269         }
4270       else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4271         {
4272           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4273           // Pull left into DE and right into HL
4274           aopGet (AOP(left), LSB, FALSE);
4275           emit2 ("ld d,h");
4276           emit2 ("ld e,l");
4277           aopGet (AOP(right), LSB, FALSE);
4278
4279           while (size--)
4280             {
4281               if (size == 0 && sign)
4282                 {
4283                   // Highest byte when signed needs the bits flipped
4284                   // Save the flags
4285                   emit2 ("push af");
4286                   emit2 ("ld a,(de)");
4287                   emit2 ("xor !immedbyte", 0x80);
4288                   emit2 ("ld e,a");
4289                   emit2 ("ld a,(hl)");
4290                   emit2 ("xor !immedbyte", 0x80);
4291                   emit2 ("ld d,a");
4292                   emit2 ("pop af");
4293                   emit2 ("ld a,e");
4294                   emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4295                 }
4296               else
4297                 {
4298                   emit2 ("ld a,(de)");
4299                   emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4300                 }
4301               
4302               if (size != 0)
4303                 {
4304                   emit2 ("inc hl");
4305                   emit2 ("inc de");
4306                 }
4307               offset++;
4308             }
4309           spillPair (PAIR_HL);
4310         }
4311       else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4312         {
4313           setupPair (PAIR_HL, AOP (left), 0);
4314           aopGet (AOP(right), LSB, FALSE);
4315
4316           while (size--)
4317             {
4318               if (size == 0 && sign)
4319                 {
4320                   // Highest byte when signed needs the bits flipped
4321                   // Save the flags
4322                   emit2 ("push af");
4323                   emit2 ("ld a,(hl)");
4324                   emit2 ("xor !immedbyte", 0x80);
4325                   emit2 ("ld l,a");
4326                   emit2 ("ld a,%d(iy)", offset);
4327                   emit2 ("xor !immedbyte", 0x80);
4328                   emit2 ("ld h,a");
4329                   emit2 ("pop af");
4330                   emit2 ("ld a,l");
4331                   emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4332                 }
4333               else
4334                 {
4335                   emit2 ("ld a,(hl)");
4336                   emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4337                 }
4338               
4339               if (size != 0)
4340                 {
4341                   emit2 ("inc hl");
4342                 }
4343               offset++;
4344             }
4345           spillPair (PAIR_HL);
4346           spillPair (PAIR_IY);
4347         }
4348       else
4349         {
4350           if (AOP_TYPE (right) == AOP_LIT)
4351             {
4352               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4353               /* optimize if(x < 0) or if(x >= 0) */
4354               if (lit == 0L)
4355                 {
4356                   if (!sign)
4357                     {
4358                       /* No sign so it's always false */
4359                       _clearCarry();
4360                     }
4361                   else
4362                     {
4363                       /* Just load in the top most bit */
4364                       _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4365                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4366                         {
4367                           genIfxJump (ifx, "7");
4368                           return;
4369                         }
4370                       else
4371                         emit2 ("rlc a");
4372                     }
4373                   goto release;
4374                 }
4375             }
4376           
4377           if (sign)
4378             {
4379               /* First setup h and l contaning the top most bytes XORed */
4380               bool fDidXor = FALSE;
4381               if (AOP_TYPE (left) == AOP_LIT)
4382                 {
4383                   unsigned long lit = (unsigned long)
4384                   floatFromVal (AOP (left)->aopu.aop_lit);
4385                   emit2 ("ld %s,!immedbyte", _fTmp[0],
4386                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4387                 }
4388               else
4389                 {
4390                   emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4391                   emit2 ("xor a,!immedbyte", 0x80);
4392                   emit2 ("ld %s,a", _fTmp[0]);
4393                   fDidXor = TRUE;
4394                 }
4395               if (AOP_TYPE (right) == AOP_LIT)
4396                 {
4397                   unsigned long lit = (unsigned long)
4398                   floatFromVal (AOP (right)->aopu.aop_lit);
4399                   emit2 ("ld %s,!immedbyte", _fTmp[1],
4400                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4401                 }
4402               else
4403                 {
4404                   emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4405                   emit2 ("xor a,!immedbyte", 0x80);
4406                   emit2 ("ld %s,a", _fTmp[1]);
4407                   fDidXor = TRUE;
4408                 }
4409             }
4410           while (size--)
4411             {
4412               /* Do a long subtract */
4413               if (!sign || size)
4414                 {
4415                   _moveA (aopGet (AOP (left), offset, FALSE));
4416                 }
4417               if (sign && size == 0)
4418                 {
4419                   emit2 ("ld a,%s", _fTmp[0]);
4420                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4421                 }
4422               else
4423                 {
4424                   /* Subtract through, propagating the carry */
4425                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4426                   offset++;
4427                 }
4428             }
4429         }
4430     }
4431 #endif
4432
4433 /** Generic compare for > or <
4434  */
4435 static void
4436 genCmp (operand * left, operand * right,
4437         operand * result, iCode * ifx, int sign)
4438 {
4439   int size, offset = 0;
4440   unsigned long lit = 0L;
4441   bool swap_sense = FALSE;
4442
4443   /* if left & right are bit variables */
4444   if (AOP_TYPE (left) == AOP_CRY &&
4445       AOP_TYPE (right) == AOP_CRY)
4446     {
4447       /* Cant happen on the Z80 */
4448       wassertl (0, "Tried to compare two bits");
4449     }
4450   else
4451     {
4452       /* Do a long subtract of right from left. */
4453       size = max (AOP_SIZE (left), AOP_SIZE (right));
4454
4455       if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4456         {
4457           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4458           // Pull left into DE and right into HL
4459           aopGet (AOP(left), LSB, FALSE);
4460           emit2 ("ld d,h");
4461           emit2 ("ld e,l");
4462           aopGet (AOP(right), LSB, FALSE);
4463
4464           while (size--)
4465             {
4466               emit2 ("ld a,(de)");
4467               emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4468               
4469               if (size != 0)
4470                 {
4471                   emit2 ("inc hl");
4472                   emit2 ("inc de");
4473                 }
4474               offset++;
4475             }
4476           spillPair (PAIR_HL);
4477           goto release;
4478         }
4479
4480       if (AOP_TYPE (right) == AOP_LIT)
4481         {
4482           lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4483           /* optimize if(x < 0) or if(x >= 0) */
4484           if (lit == 0)
4485             {
4486               if (!sign)
4487                 {
4488                   /* No sign so it's always false */
4489                   _clearCarry();
4490                 }
4491               else
4492                 {
4493                   /* Just load in the top most bit */
4494                   _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4495                   if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4496                     {
4497                       genIfxJump (ifx, "7");
4498                       return;
4499                     }
4500                   else
4501                     {
4502                       if (!sign) 
4503                         {
4504                           emit2 ("rlc a");
4505                         }
4506                       if (ifx)
4507                         {
4508                           genIfxJump (ifx, swap_sense ? "c" : "nc");
4509                           return;
4510                         }
4511                     }
4512                 }
4513               goto release;
4514             }
4515         }
4516
4517       while (size--)
4518         {
4519           _moveA (aopGet (AOP (left), offset, FALSE));
4520           /* Subtract through, propagating the carry */
4521           emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4522           offset++;
4523         }
4524     }
4525
4526 release:
4527   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4528     {
4529       if (sign)
4530         {
4531           /* Shift the sign bit up into carry */
4532           emit2 ("rlca");
4533         }
4534       outBitCLong (result, swap_sense);
4535     }
4536   else
4537     {
4538       /* if the result is used in the next
4539          ifx conditional branch then generate
4540          code a little differently */
4541       if (ifx)
4542         {
4543           if (sign)
4544             {
4545               if (IS_GB)
4546                 {
4547                   emit2 ("rlca");
4548                   genIfxJump (ifx, swap_sense ? "nc" : "c");
4549                 }
4550               else
4551                 {
4552                   genIfxJump (ifx, swap_sense ? "p" : "m");
4553                 }
4554             }
4555           else
4556             {
4557               genIfxJump (ifx, swap_sense ? "nc" : "c");
4558             }
4559         }
4560       else
4561         {
4562           if (sign)
4563             {
4564               /* Shift the sign bit up into carry */
4565               emit2 ("rlca");
4566             }
4567           outBitCLong (result, swap_sense);
4568         }
4569       /* leave the result in acc */
4570     }
4571 }
4572
4573 /*-----------------------------------------------------------------*/
4574 /* genCmpGt :- greater than comparison                             */
4575 /*-----------------------------------------------------------------*/
4576 static void
4577 genCmpGt (iCode * ic, iCode * ifx)
4578 {
4579   operand *left, *right, *result;
4580   sym_link *letype, *retype;
4581   int sign;
4582
4583   left = IC_LEFT (ic);
4584   right = IC_RIGHT (ic);
4585   result = IC_RESULT (ic);
4586
4587   letype = getSpec (operandType (left));
4588   retype = getSpec (operandType (right));
4589   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4590   /* assign the amsops */
4591   aopOp (left, ic, FALSE, FALSE);
4592   aopOp (right, ic, FALSE, FALSE);
4593   aopOp (result, ic, TRUE, FALSE);
4594
4595   genCmp (right, left, result, ifx, sign);
4596
4597   freeAsmop (left, NULL, ic);
4598   freeAsmop (right, NULL, ic);
4599   freeAsmop (result, NULL, ic);
4600 }
4601
4602 /*-----------------------------------------------------------------*/
4603 /* genCmpLt - less than comparisons                                */
4604 /*-----------------------------------------------------------------*/
4605 static void
4606 genCmpLt (iCode * ic, iCode * ifx)
4607 {
4608   operand *left, *right, *result;
4609   sym_link *letype, *retype;
4610   int sign;
4611
4612   left = IC_LEFT (ic);
4613   right = IC_RIGHT (ic);
4614   result = IC_RESULT (ic);
4615
4616   letype = getSpec (operandType (left));
4617   retype = getSpec (operandType (right));
4618   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4619
4620   /* assign the amsops */
4621   aopOp (left, ic, FALSE, FALSE);
4622   aopOp (right, ic, FALSE, FALSE);
4623   aopOp (result, ic, TRUE, FALSE);
4624
4625   genCmp (left, right, result, ifx, sign);
4626
4627   freeAsmop (left, NULL, ic);
4628   freeAsmop (right, NULL, ic);
4629   freeAsmop (result, NULL, ic);
4630 }
4631
4632 /*-----------------------------------------------------------------*/
4633 /* gencjneshort - compare and jump if not equal                    */
4634 /*-----------------------------------------------------------------*/
4635 static void
4636 gencjneshort (operand * left, operand * right, symbol * lbl)
4637 {
4638   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4639   int offset = 0;
4640   unsigned long lit = 0L;
4641
4642   /* Swap the left and right if it makes the computation easier */
4643   if (AOP_TYPE (left) == AOP_LIT)
4644     {
4645       operand *t = right;
4646       right = left;
4647       left = t;
4648     }
4649
4650   if (AOP_TYPE (right) == AOP_LIT)
4651     {
4652       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4653     }
4654
4655   /* if the right side is a literal then anything goes */
4656   if (AOP_TYPE (right) == AOP_LIT &&
4657       AOP_TYPE (left) != AOP_DIR)
4658     {
4659       if (lit == 0)
4660         {
4661           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4662           if (size > 1)
4663             {
4664               while (--size)
4665                 {
4666                   emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4667                 }
4668             }
4669           else
4670             {
4671               emit2 ("or a,a");
4672             }
4673           emit2 ("jp nz,!tlabel", lbl->key + 100);
4674         }
4675       else
4676         {
4677           while (size--)
4678             {
4679               emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4680               if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4681                 emit2 ("or a,a");
4682               else
4683                 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4684               emit2 ("jp nz,!tlabel", lbl->key + 100);
4685               offset++;
4686             }
4687         }
4688     }
4689   /* if the right side is in a register or in direct space or
4690      if the left is a pointer register & right is not */
4691   else if (AOP_TYPE (right) == AOP_REG ||
4692            AOP_TYPE (right) == AOP_DIR ||
4693            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4694     {
4695       while (size--)
4696         {
4697           _moveA (aopGet (AOP (left), offset, FALSE));
4698           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4699               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4700             /* PENDING */
4701             emit2 ("jp nz,!tlabel", lbl->key + 100);
4702           else
4703             {
4704               emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4705               emit2 ("jp nz,!tlabel", lbl->key + 100);
4706             }
4707           offset++;
4708         }
4709     }
4710   else
4711     {
4712       /* right is a pointer reg need both a & b */
4713       /* PENDING: is this required? */
4714       while (size--)
4715         {
4716           _moveA (aopGet (AOP (right), offset, FALSE));
4717           emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4718           emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4719           offset++;
4720         }
4721     }
4722 }
4723
4724 /*-----------------------------------------------------------------*/
4725 /* gencjne - compare and jump if not equal                         */
4726 /*-----------------------------------------------------------------*/
4727 static void
4728 gencjne (operand * left, operand * right, symbol * lbl)
4729 {
4730   symbol *tlbl = newiTempLabel (NULL);
4731
4732   gencjneshort (left, right, lbl);
4733
4734   /* PENDING: ?? */
4735   emit2 ("ld a,!one");
4736   emit2 ("!shortjp !tlabel", tlbl->key + 100);
4737   emitLabel (lbl->key + 100);
4738   emit2 ("xor a,a");
4739   emitLabel (tlbl->key + 100);
4740 }
4741
4742 /*-----------------------------------------------------------------*/
4743 /* genCmpEq - generates code for equal to                          */
4744 /*-----------------------------------------------------------------*/
4745 static void
4746 genCmpEq (iCode * ic, iCode * ifx)
4747 {
4748   operand *left, *right, *result;
4749
4750   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4751   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4752   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4753
4754   emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4755
4756   /* Swap operands if it makes the operation easier. ie if:
4757      1.  Left is a literal.
4758    */
4759   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4760     {
4761       operand *t = IC_RIGHT (ic);
4762       IC_RIGHT (ic) = IC_LEFT (ic);
4763       IC_LEFT (ic) = t;
4764     }
4765
4766   if (ifx && !AOP_SIZE (result))
4767     {
4768       symbol *tlbl;
4769       /* if they are both bit variables */
4770       if (AOP_TYPE (left) == AOP_CRY &&
4771           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4772         {
4773           wassertl (0, "Tried to compare two bits");
4774         }
4775       else
4776         {
4777           tlbl = newiTempLabel (NULL);
4778           gencjneshort (left, right, tlbl);
4779           if (IC_TRUE (ifx))
4780             {
4781               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4782               emitLabel (tlbl->key + 100);
4783             }
4784           else
4785             {
4786               /* PENDING: do this better */
4787               symbol *lbl = newiTempLabel (NULL);
4788               emit2 ("!shortjp !tlabel", lbl->key + 100);
4789               emitLabel (tlbl->key + 100);
4790               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4791               emitLabel (lbl->key + 100);
4792             }
4793         }
4794       /* mark the icode as generated */
4795       ifx->generated = 1;
4796       goto release;
4797     }
4798
4799   /* if they are both bit variables */
4800   if (AOP_TYPE (left) == AOP_CRY &&
4801       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4802     {
4803       wassertl (0, "Tried to compare a bit to either a literal or another bit");
4804     }
4805   else
4806     {
4807       emitDebug(";4");
4808       
4809       gencjne (left, right, newiTempLabel (NULL));
4810       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4811         {
4812           wassert (0);
4813         }
4814       if (ifx)
4815         {
4816           emitDebug(";5");
4817           genIfxJump (ifx, "a");
4818           goto release;
4819         }
4820       /* if the result is used in an arithmetic operation
4821          then put the result in place */
4822       if (AOP_TYPE (result) != AOP_CRY)
4823         {
4824           emitDebug(";6");
4825           outAcc (result);
4826         }
4827       /* leave the result in acc */
4828     }
4829
4830 release:
4831   freeAsmop (left, NULL, ic);
4832   freeAsmop (right, NULL, ic);
4833   freeAsmop (result, NULL, ic);
4834 }
4835
4836 /*-----------------------------------------------------------------*/
4837 /* ifxForOp - returns the icode containing the ifx for operand     */
4838 /*-----------------------------------------------------------------*/
4839 static iCode *
4840 ifxForOp (operand * op, iCode * ic)
4841 {
4842   /* if true symbol then needs to be assigned */
4843   if (IS_TRUE_SYMOP (op))
4844     return NULL;
4845
4846   /* if this has register type condition and
4847      the next instruction is ifx with the same operand
4848      and live to of the operand is upto the ifx only then */
4849   if (ic->next &&
4850       ic->next->op == IFX &&
4851       IC_COND (ic->next)->key == op->key &&
4852       OP_SYMBOL (op)->liveTo <= ic->next->seq)
4853     return ic->next;
4854
4855   return NULL;
4856 }
4857
4858 /*-----------------------------------------------------------------*/
4859 /* genAndOp - for && operation                                     */
4860 /*-----------------------------------------------------------------*/
4861 static void
4862 genAndOp (iCode * ic)
4863 {
4864   operand *left, *right, *result;
4865   symbol *tlbl;
4866
4867   /* note here that && operations that are in an if statement are
4868      taken away by backPatchLabels only those used in arthmetic
4869      operations remain */
4870   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4871   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4872   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4873
4874   /* if both are bit variables */
4875   if (AOP_TYPE (left) == AOP_CRY &&
4876       AOP_TYPE (right) == AOP_CRY)
4877     {
4878       wassertl (0, "Tried to and two bits");
4879     }
4880   else
4881     {
4882       tlbl = newiTempLabel (NULL);
4883       _toBoolean (left);
4884       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4885       _toBoolean (right);
4886       emitLabel (tlbl->key + 100);
4887       outBitAcc (result);
4888     }
4889
4890   freeAsmop (left, NULL, ic);
4891   freeAsmop (right, NULL, ic);
4892   freeAsmop (result, NULL, ic);
4893 }
4894
4895 /*-----------------------------------------------------------------*/
4896 /* genOrOp - for || operation                                      */
4897 /*-----------------------------------------------------------------*/
4898 static void
4899 genOrOp (iCode * ic)
4900 {
4901   operand *left, *right, *result;
4902   symbol *tlbl;
4903
4904   /* note here that || operations that are in an
4905      if statement are taken away by backPatchLabels
4906      only those used in arthmetic operations remain */
4907   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4908   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4909   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4910
4911   /* if both are bit variables */
4912   if (AOP_TYPE (left) == AOP_CRY &&
4913       AOP_TYPE (right) == AOP_CRY)
4914     {
4915       wassertl (0, "Tried to OR two bits");
4916     }
4917   else
4918     {
4919       tlbl = newiTempLabel (NULL);
4920       _toBoolean (left);
4921       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4922       _toBoolean (right);
4923       emitLabel (tlbl->key + 100);
4924       outBitAcc (result);
4925     }
4926
4927   freeAsmop (left, NULL, ic);
4928   freeAsmop (right, NULL, ic);
4929   freeAsmop (result, NULL, ic);
4930 }
4931
4932 /*-----------------------------------------------------------------*/
4933 /* isLiteralBit - test if lit == 2^n                               */
4934 /*-----------------------------------------------------------------*/
4935 int
4936 isLiteralBit (unsigned long lit)
4937 {
4938   unsigned long pw[32] =
4939   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4940    0x100L, 0x200L, 0x400L, 0x800L,
4941    0x1000L, 0x2000L, 0x4000L, 0x8000L,
4942    0x10000L, 0x20000L, 0x40000L, 0x80000L,
4943    0x100000L, 0x200000L, 0x400000L, 0x800000L,
4944    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4945    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4946   int idx;
4947
4948   for (idx = 0; idx < 32; idx++)
4949     if (lit == pw[idx])
4950       return idx + 1;
4951   return 0;
4952 }
4953
4954 /*-----------------------------------------------------------------*/
4955 /* jmpTrueOrFalse -                                                */
4956 /*-----------------------------------------------------------------*/
4957 static void
4958 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4959 {
4960   // ugly but optimized by peephole
4961   if (IC_TRUE (ic))
4962     {
4963       symbol *nlbl = newiTempLabel (NULL);
4964       emit2 ("jp !tlabel", nlbl->key + 100);
4965       emitLabel (tlbl->key + 100);
4966       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4967       emitLabel (nlbl->key + 100);
4968     }
4969   else
4970     {
4971       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4972       emitLabel (tlbl->key + 100);
4973     }
4974   ic->generated = 1;
4975 }
4976
4977 /*-----------------------------------------------------------------*/
4978 /* genAnd  - code for and                                          */
4979 /*-----------------------------------------------------------------*/
4980 static void
4981 genAnd (iCode * ic, iCode * ifx)
4982 {
4983   operand *left, *right, *result;
4984   int size, offset = 0;
4985   unsigned long lit = 0L;
4986   int bytelit = 0;
4987
4988   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4989   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4990   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4991
4992   /* if left is a literal & right is not then exchange them */
4993   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4994       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
4995     {
4996       operand *tmp = right;
4997       right = left;
4998       left = tmp;
4999     }
5000
5001   /* if result = right then exchange them */
5002   if (sameRegs (AOP (result), AOP (right)))
5003     {
5004       operand *tmp = right;
5005       right = left;
5006       left = tmp;
5007     }
5008
5009   /* if right is bit then exchange them */
5010   if (AOP_TYPE (right) == AOP_CRY &&
5011       AOP_TYPE (left) != AOP_CRY)
5012     {
5013       operand *tmp = right;
5014       right = left;
5015       left = tmp;
5016     }
5017   if (AOP_TYPE (right) == AOP_LIT)
5018     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5019
5020   size = AOP_SIZE (result);
5021
5022   if (AOP_TYPE (left) == AOP_CRY)
5023     {
5024       wassertl (0, "Tried to perform an AND with a bit as an operand");
5025       goto release;
5026     }
5027
5028   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5029   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5030   if ((AOP_TYPE (right) == AOP_LIT) &&
5031       (AOP_TYPE (result) == AOP_CRY) &&
5032       (AOP_TYPE (left) != AOP_CRY))
5033     {
5034       symbol *tlbl = newiTempLabel (NULL);
5035       int sizel = AOP_SIZE (left);
5036       if (size)
5037         {
5038           /* PENDING: Test case for this. */
5039           emit2 ("scf");
5040         }
5041       while (sizel--)
5042         {
5043           if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5044             {
5045               _moveA (aopGet (AOP (left), offset, FALSE));
5046               if (bytelit != 0x0FFL)
5047                 {
5048                   emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5049                 }
5050               else
5051                 {
5052                   /* For the flags */
5053                   emit2 ("or a,a");
5054                 }
5055               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5056             }
5057               offset++;
5058         }
5059       // bit = left & literal
5060       if (size)
5061         {
5062           emit2 ("clr c");
5063           emit2 ("!tlabeldef", tlbl->key + 100);
5064         }
5065       // if(left & literal)
5066       else
5067         {
5068           if (ifx)
5069             {
5070               jmpTrueOrFalse (ifx, tlbl);
5071             }
5072           goto release;
5073         }
5074       outBitC (result);
5075       goto release;
5076     }
5077
5078   /* if left is same as result */
5079   if (sameRegs (AOP (result), AOP (left)))
5080     {
5081       for (; size--; offset++)
5082         {
5083           if (AOP_TYPE (right) == AOP_LIT)
5084             {
5085               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5086                 continue;
5087               else
5088                 {
5089                   if (bytelit == 0)
5090                     aopPut (AOP (result), "!zero", offset);
5091                   else
5092                     {
5093                       _moveA (aopGet (AOP (left), offset, FALSE));
5094                       emit2 ("and a,%s",
5095                                 aopGet (AOP (right), offset, FALSE));
5096                       aopPut (AOP (left), "a", offset);
5097                     }
5098                 }
5099
5100             }
5101           else
5102             {
5103               if (AOP_TYPE (left) == AOP_ACC)
5104                 {
5105                   wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5106                 }
5107               else
5108                 {
5109                   _moveA (aopGet (AOP (left), offset, FALSE));
5110                   emit2 ("and a,%s",
5111                             aopGet (AOP (right), offset, FALSE));
5112                   aopPut (AOP (left), "a", offset);
5113                 }
5114             }
5115         }
5116     }
5117   else
5118     {
5119       // left & result in different registers
5120       if (AOP_TYPE (result) == AOP_CRY)
5121         {
5122           wassertl (0, "Tried to AND where the result is in carry");
5123         }
5124       else
5125         {
5126           for (; (size--); offset++)
5127             {
5128               // normal case
5129               // result = left & right
5130               if (AOP_TYPE (right) == AOP_LIT)
5131                 {
5132                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5133                     {
5134                       aopPut (AOP (result),
5135                               aopGet (AOP (left), offset, FALSE),
5136                               offset);
5137                       continue;
5138                     }
5139                   else if (bytelit == 0)
5140                     {
5141                       aopPut (AOP (result), "!zero", offset);
5142                       continue;
5143                     }
5144                 }
5145               // faster than result <- left, anl result,right
5146               // and better if result is SFR
5147               if (AOP_TYPE (left) == AOP_ACC)
5148                 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5149               else
5150                 {
5151                   _moveA (aopGet (AOP (left), offset, FALSE));
5152                   emit2 ("and a,%s",
5153                             aopGet (AOP (right), offset, FALSE));
5154                 }
5155               aopPut (AOP (result), "a", offset);
5156             }
5157         }
5158
5159     }
5160
5161 release:
5162   freeAsmop (left, NULL, ic);
5163   freeAsmop (right, NULL, ic);
5164   freeAsmop (result, NULL, ic);
5165 }
5166
5167 /*-----------------------------------------------------------------*/
5168 /* genOr  - code for or                                            */
5169 /*-----------------------------------------------------------------*/
5170 static void
5171 genOr (iCode * ic, iCode * ifx)
5172 {
5173   operand *left, *right, *result;
5174   int size, offset = 0;
5175   unsigned long lit = 0L;
5176   int bytelit = 0;
5177
5178   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5179   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5180   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5181
5182   /* if left is a literal & right is not then exchange them */
5183   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5184       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5185     {
5186       operand *tmp = right;
5187       right = left;
5188       left = tmp;
5189     }
5190
5191   /* if result = right then exchange them */
5192   if (sameRegs (AOP (result), AOP (right)))
5193     {
5194       operand *tmp = right;
5195       right = left;
5196       left = tmp;
5197     }
5198
5199   /* if right is bit then exchange them */
5200   if (AOP_TYPE (right) == AOP_CRY &&
5201       AOP_TYPE (left) != AOP_CRY)
5202     {
5203       operand *tmp = right;
5204       right = left;
5205       left = tmp;
5206     }
5207   if (AOP_TYPE (right) == AOP_LIT)
5208     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5209
5210   size = AOP_SIZE (result);
5211
5212   if (AOP_TYPE (left) == AOP_CRY)
5213     {
5214       wassertl (0, "Tried to OR where left is a bit");
5215       goto release;
5216     }
5217
5218   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
5219   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
5220   if ((AOP_TYPE (right) == AOP_LIT) &&
5221       (AOP_TYPE (result) == AOP_CRY) &&
5222       (AOP_TYPE (left) != AOP_CRY))
5223     {
5224       symbol *tlbl = newiTempLabel (NULL);
5225       int sizel = AOP_SIZE (left);
5226
5227       if (size)
5228         {
5229           wassertl (0, "Result is assigned to a bit");
5230         }
5231       /* PENDING: Modeled after the AND code which is inefficent. */
5232       while (sizel--)
5233         {
5234           bytelit = (lit >> (offset * 8)) & 0x0FFL;
5235
5236           _moveA (aopGet (AOP (left), offset, FALSE));
5237           /* OR with any literal is the same as OR with itself. */
5238           emit2 ("or a,a");
5239           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5240
5241           offset++;
5242         }
5243       if (ifx)
5244         {
5245           jmpTrueOrFalse (ifx, tlbl);
5246         }
5247       goto release;
5248     }
5249
5250   /* if left is same as result */
5251   if (sameRegs (AOP (result), AOP (left)))
5252     {
5253       for (; size--; offset++)
5254         {
5255           if (AOP_TYPE (right) == AOP_LIT)
5256             {
5257               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5258                 continue;
5259               else
5260                 {
5261                   _moveA (aopGet (AOP (left), offset, FALSE));
5262                   emit2 ("or a,%s",
5263                             aopGet (AOP (right), offset, FALSE));
5264                   aopPut (AOP (result), "a", offset);
5265                 }
5266             }
5267           else
5268             {
5269               if (AOP_TYPE (left) == AOP_ACC)
5270                 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5271               else
5272                 {
5273                   _moveA (aopGet (AOP (left), offset, FALSE));
5274                   emit2 ("or a,%s",
5275                             aopGet (AOP (right), offset, FALSE));
5276                   aopPut (AOP (result), "a", offset);
5277                 }
5278             }
5279         }
5280     }
5281   else
5282     {
5283       // left & result in different registers
5284       if (AOP_TYPE (result) == AOP_CRY)
5285         {
5286           wassertl (0, "Result of OR is in a bit");
5287         }
5288       else
5289         for (; (size--); offset++)
5290           {
5291             // normal case
5292             // result = left & right
5293             if (AOP_TYPE (right) == AOP_LIT)
5294               {
5295                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5296                   {
5297                     aopPut (AOP (result),
5298                             aopGet (AOP (left), offset, FALSE),
5299                             offset);
5300                     continue;
5301                   }
5302               }
5303             // faster than result <- left, anl result,right
5304             // and better if result is SFR
5305             if (AOP_TYPE (left) == AOP_ACC)
5306               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5307             else
5308               {
5309                 _moveA (aopGet (AOP (left), offset, FALSE));
5310                 emit2 ("or a,%s",
5311                           aopGet (AOP (right), offset, FALSE));
5312               }
5313             aopPut (AOP (result), "a", offset);
5314             /* PENDING: something weird is going on here.  Add exception. */
5315             if (AOP_TYPE (result) == AOP_ACC)
5316               break;
5317           }
5318     }
5319
5320 release:
5321   freeAsmop (left, NULL, ic);
5322   freeAsmop (right, NULL, ic);
5323   freeAsmop (result, NULL, ic);
5324 }
5325
5326 /*-----------------------------------------------------------------*/
5327 /* genXor - code for xclusive or                                   */
5328 /*-----------------------------------------------------------------*/
5329 static void
5330 genXor (iCode * ic, iCode * ifx)
5331 {
5332   operand *left, *right, *result;
5333   int size, offset = 0;
5334   unsigned long lit = 0L;
5335
5336   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5337   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5338   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5339
5340   /* if left is a literal & right is not then exchange them */
5341   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5342       (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
5343     {
5344       operand *tmp = right;
5345       right = left;
5346       left = tmp;
5347     }
5348
5349   /* if result = right then exchange them */
5350   if (sameRegs (AOP (result), AOP (right)))
5351     {
5352       operand *tmp = right;
5353       right = left;
5354       left = tmp;
5355     }
5356
5357   /* if right is bit then exchange them */
5358   if (AOP_TYPE (right) == AOP_CRY &&
5359       AOP_TYPE (left) != AOP_CRY)
5360     {
5361       operand *tmp = right;
5362       right = left;
5363       left = tmp;
5364     }
5365   if (AOP_TYPE (right) == AOP_LIT)
5366     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5367
5368   size = AOP_SIZE (result);
5369
5370   if (AOP_TYPE (left) == AOP_CRY)
5371     {
5372       wassertl (0, "Tried to XOR a bit");
5373       goto release;
5374     }
5375
5376   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5377   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5378   if ((AOP_TYPE (right) == AOP_LIT) &&
5379       (AOP_TYPE (result) == AOP_CRY) &&
5380       (AOP_TYPE (left) != AOP_CRY))
5381     {
5382       symbol *tlbl = newiTempLabel (NULL);
5383       int sizel = AOP_SIZE (left);
5384
5385       if (size)
5386         {
5387           /* PENDING: Test case for this. */
5388           wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5389         }
5390       while (sizel--)
5391         {
5392           _moveA (aopGet (AOP (left), offset, FALSE));
5393           emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5394           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5395           offset++;
5396         }
5397       if (ifx)
5398         {
5399           jmpTrueOrFalse (ifx, tlbl);
5400         }
5401       else
5402         {
5403           wassertl (0, "Result of XOR was destined for a bit");
5404         }
5405       goto release;
5406     }
5407
5408   /* if left is same as result */
5409   if (sameRegs (AOP (result), AOP (left)))
5410     {
5411       for (; size--; offset++)
5412         {
5413           if (AOP_TYPE (right) == AOP_LIT)
5414             {
5415               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5416                 continue;
5417               else
5418                 {
5419                   _moveA (aopGet (AOP (left), offset, FALSE));
5420                   emit2 ("xor a,%s",
5421                             aopGet (AOP (right), offset, FALSE));
5422                   aopPut (AOP (result), "a", offset);
5423                 }
5424             }
5425           else
5426             {
5427               if (AOP_TYPE (left) == AOP_ACC)
5428                 {
5429                   emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5430                 }
5431               else
5432                 {
5433                   _moveA (aopGet (AOP (left), offset, FALSE));
5434                   emit2 ("xor a,%s",
5435                             aopGet (AOP (right), offset, FALSE));
5436                   aopPut (AOP (result), "a", offset);
5437                 }
5438             }
5439         }
5440     }
5441   else
5442     {
5443       // left & result in different registers
5444       if (AOP_TYPE (result) == AOP_CRY)
5445         {
5446           wassertl (0, "Result of XOR is in a bit");
5447         }
5448       else
5449         for (; (size--); offset++)
5450           {
5451             // normal case
5452             // result = left & right
5453             if (AOP_TYPE (right) == AOP_LIT)
5454               {
5455                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5456                   {
5457                     aopPut (AOP (result),
5458                             aopGet (AOP (left), offset, FALSE),
5459                             offset);
5460                     continue;
5461                   }
5462               }
5463             // faster than result <- left, anl result,right
5464             // and better if result is SFR
5465             if (AOP_TYPE (left) == AOP_ACC) 
5466               {
5467                 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5468               }
5469             else
5470               {
5471                 _moveA (aopGet (AOP (left), offset, FALSE));
5472                 emit2 ("xor a,%s",
5473                           aopGet (AOP (right), offset, FALSE));
5474               }
5475             aopPut (AOP (result), "a", offset);
5476           }
5477     }
5478
5479 release:
5480   freeAsmop (left, NULL, ic);
5481   freeAsmop (right, NULL, ic);
5482   freeAsmop (result, NULL, ic);
5483 }
5484
5485 /*-----------------------------------------------------------------*/
5486 /* genInline - write the inline code out                           */
5487 /*-----------------------------------------------------------------*/
5488 static void
5489 genInline (iCode * ic)
5490 {
5491   char *buffer, *bp, *bp1;
5492
5493   _G.lines.isInline += (!options.asmpeep);
5494
5495   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5496   strcpy (buffer, IC_INLINE (ic));
5497
5498   /* emit each line as a code */
5499   while (*bp)
5500     {
5501       if (*bp == '\n')
5502         {
5503           *bp++ = '\0';
5504           emit2 (bp1);
5505           bp1 = bp;
5506         }
5507       else
5508         {
5509           if (*bp == ':')
5510             {
5511               bp++;
5512               *bp = '\0';
5513               bp++;
5514               emit2 (bp1);
5515               bp1 = bp;
5516             }
5517           else
5518             bp++;
5519         }
5520     }
5521   if (bp1 != bp)
5522     emit2 (bp1);
5523   _G.lines.isInline -= (!options.asmpeep);
5524
5525 }
5526
5527 /*-----------------------------------------------------------------*/
5528 /* genRRC - rotate right with carry                                */
5529 /*-----------------------------------------------------------------*/
5530 static void
5531 genRRC (iCode * ic)
5532 {
5533   wassert (0);
5534 }
5535
5536 /*-----------------------------------------------------------------*/
5537 /* genRLC - generate code for rotate left with carry               */
5538 /*-----------------------------------------------------------------*/
5539 static void
5540 genRLC (iCode * ic)
5541 {
5542   wassert (0);
5543 }
5544
5545 /*-----------------------------------------------------------------*/
5546 /* genGetHbit - generates code get highest order bit               */
5547 /*-----------------------------------------------------------------*/
5548 static void
5549 genGetHbit (iCode * ic)
5550 {
5551   operand *left, *result;
5552   left = IC_LEFT (ic);
5553   result = IC_RESULT (ic);
5554
5555   aopOp (left, ic, FALSE, FALSE);
5556   aopOp (result, ic, FALSE, FALSE);
5557
5558   /* get the highest order byte into a */
5559   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5560
5561   if (AOP_TYPE (result) == AOP_CRY)
5562     {
5563       emit2 ("rl a");
5564       outBitC (result);
5565     }
5566   else
5567     {
5568       emit2 ("rlc a");
5569       emit2 ("and a,!one");
5570       outAcc (result);
5571     }
5572
5573
5574   freeAsmop (left, NULL, ic);
5575   freeAsmop (result, NULL, ic);
5576 }
5577
5578 static void
5579 emitRsh2 (asmop *aop, int size, int is_signed)
5580 {
5581   int offset = 0;
5582
5583   while (size--)
5584     {
5585       const char *l = aopGet (aop, size, FALSE);
5586       if (offset == 0)
5587         {
5588           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5589         }
5590       else
5591         {
5592           emit2 ("rr %s", l);
5593         }
5594       offset++;
5595     }
5596 }
5597
5598 /*-----------------------------------------------------------------*/
5599 /* shiftR2Left2Result - shift right two bytes from left to result  */
5600 /*-----------------------------------------------------------------*/
5601 static void
5602 shiftR2Left2Result (operand * left, int offl,
5603                     operand * result, int offr,
5604                     int shCount, int is_signed)
5605 {
5606   int size = 2;
5607   symbol *tlbl, *tlbl1;
5608
5609   movLeft2Result (left, offl, result, offr, 0);
5610   movLeft2Result (left, offl + 1, result, offr + 1, 0);
5611
5612   /*  if (AOP(result)->type == AOP_REG) { */
5613   
5614   tlbl = newiTempLabel (NULL);
5615   tlbl1 = newiTempLabel (NULL);
5616
5617   /* Left is already in result - so now do the shift */
5618   if (shCount <= 4)
5619     {
5620       while (shCount--)
5621         {
5622           emitRsh2 (AOP (result), size, is_signed);
5623         }
5624     }
5625   else
5626     {
5627       emit2 ("ld a,!immedbyte+1", shCount);
5628       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5629       emitLabel (tlbl->key + 100);
5630
5631       emitRsh2 (AOP (result), size, is_signed);
5632
5633       emitLabel (tlbl1->key + 100);
5634       emit2 ("dec a");
5635       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5636     }
5637 }
5638
5639 /*-----------------------------------------------------------------*/
5640 /* shiftL2Left2Result - shift left two bytes from left to result   */
5641 /*-----------------------------------------------------------------*/
5642 static void
5643 shiftL2Left2Result (operand * left, int offl,
5644                     operand * result, int offr, int shCount)
5645 {
5646   if (sameRegs (AOP (result), AOP (left)) &&
5647       ((offl + MSB16) == offr))
5648     {
5649       wassert (0);
5650     }
5651   else
5652     {
5653       /* Copy left into result */
5654       movLeft2Result (left, offl, result, offr, 0);
5655       movLeft2Result (left, offl + 1, result, offr + 1, 0);
5656     }
5657
5658   if (getPairId (AOP (result)) == PAIR_HL)
5659     {
5660       while (shCount--)
5661         {
5662           emit2 ("add hl,hl");
5663         }
5664     }
5665   else
5666     {
5667     int size = 2;
5668     int offset = 0;
5669     symbol *tlbl, *tlbl1;
5670     const char *l;
5671
5672     tlbl = newiTempLabel (NULL);
5673     tlbl1 = newiTempLabel (NULL);
5674
5675     if (AOP (result)->type == AOP_REG)
5676       {
5677         while (shCount--)
5678           {
5679             for (offset = 0; offset < size; offset++)
5680               {
5681                 l = aopGet (AOP (result), offset, FALSE);
5682             
5683                 if (offset == 0)
5684                   {
5685                     emit2 ("sla %s", l);
5686                   }
5687                 else
5688                   {
5689                     emit2 ("rl %s", l);
5690                   }
5691               }
5692           }
5693       }
5694     else
5695       {
5696         /* Left is already in result - so now do the shift */
5697         if (shCount > 1)
5698           {
5699             emit2 ("ld a,!immedbyte+1", shCount);
5700             emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5701             emitLabel (tlbl->key + 100);
5702           }
5703
5704         while (size--)
5705           {
5706             l = aopGet (AOP (result), offset, FALSE);
5707             
5708             if (offset == 0)
5709               {
5710                 emit2 ("sla %s", l);
5711               }
5712             else
5713               {
5714                 emit2 ("rl %s", l);
5715               }
5716             
5717             offset++;
5718           }
5719         if (shCount > 1)
5720           {
5721             emitLabel (tlbl1->key + 100);
5722             emit2 ("dec a");
5723             emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5724           }
5725       }
5726   }
5727 }
5728
5729 /*-----------------------------------------------------------------*/
5730 /* AccRol - rotate left accumulator by known count                 */
5731 /*-----------------------------------------------------------------*/
5732 static void
5733 AccRol (int shCount)
5734 {
5735   shCount &= 0x0007;            // shCount : 0..7
5736
5737 #if 0
5738   switch (shCount)
5739     {
5740     case 0:
5741       break;
5742     case 1:
5743       emit2 ("sla a");
5744       break;
5745     case 2:
5746       emit2 ("sla a");
5747       emit2 ("rl a");
5748       break;
5749     case 3:
5750       emit2 ("sla a");
5751       emit2 ("rl a");
5752       emit2 ("rl a");
5753       break;
5754     case 4:
5755       emit2 ("sla a");
5756       emit2 ("rl a");
5757       emit2 ("rl a");
5758       emit2 ("rl a");
5759       break;
5760     case 5:
5761       emit2 ("srl a");
5762       emit2 ("rr a");
5763       emit2 ("rr a");
5764       break;
5765     case 6:
5766       emit2 ("srl a");
5767       emit2 ("rr a");
5768       break;
5769     case 7:
5770       emit2 ("srl a");
5771       break;
5772     }
5773 #else
5774   switch (shCount)
5775     {
5776     case 0:
5777       break;
5778     case 1:
5779       emit2 ("rlca");
5780       break;
5781     case 2:
5782       emit2 ("rlca");
5783       emit2 ("rlca");
5784       break;
5785     case 3:
5786       emit2 ("rlca");
5787       emit2 ("rlca");
5788       emit2 ("rlca");
5789       break;
5790     case 4:
5791       emit2 ("rlca");
5792       emit2 ("rlca");
5793       emit2 ("rlca");
5794       emit2 ("rlca");
5795       break;
5796     case 5:
5797       emit2 ("rrca");
5798       emit2 ("rrca");
5799       emit2 ("rrca");
5800       break;
5801     case 6:
5802       emit2 ("rrca");
5803       emit2 ("rrca");
5804       break;
5805     case 7:
5806       emit2 ("rrca");
5807       break;
5808     }
5809 #endif
5810 }
5811
5812 /*-----------------------------------------------------------------*/
5813 /* AccLsh - left shift accumulator by known count                  */
5814 /*-----------------------------------------------------------------*/
5815 static void
5816 AccLsh (int shCount)
5817 {
5818   static const unsigned char SLMask[] =
5819     {
5820       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5821     };
5822
5823   if (shCount != 0)
5824     {
5825       if (shCount == 1)
5826         {
5827           emit2 ("add a,a");
5828         }
5829       else if (shCount == 2)
5830         {
5831           emit2 ("add a,a");
5832           emit2 ("add a,a");
5833         }
5834       else
5835         {
5836           /* rotate left accumulator */
5837           AccRol (shCount);
5838           /* and kill the lower order bits */
5839           emit2 ("and a,!immedbyte", SLMask[shCount]);
5840         }
5841     }
5842 }
5843
5844 /*-----------------------------------------------------------------*/
5845 /* shiftL1Left2Result - shift left one byte from left to result    */
5846 /*-----------------------------------------------------------------*/
5847 static void
5848 shiftL1Left2Result (operand * left, int offl,
5849                     operand * result, int offr, int shCount)
5850 {
5851   const char *l;
5852   l = aopGet (AOP (left), offl, FALSE);
5853   _moveA (l);
5854   /* shift left accumulator */
5855   AccLsh (shCount);
5856   aopPut (AOP (result), "a", offr);
5857 }
5858
5859
5860 /*-----------------------------------------------------------------*/
5861 /* genlshTwo - left shift two bytes by known amount != 0           */
5862 /*-----------------------------------------------------------------*/
5863 static void
5864 genlshTwo (operand * result, operand * left, int shCount)
5865 {
5866   int size = AOP_SIZE (result);
5867
5868   wassert (size == 2);
5869
5870   /* if shCount >= 8 */
5871   if (shCount >= 8)
5872     {
5873       shCount -= 8;
5874       if (size > 1)
5875         {
5876           if (shCount)
5877             {
5878               movLeft2Result (left, LSB, result, MSB16, 0);
5879               aopPut (AOP (result), "!zero", 0);
5880               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5881             }
5882           else
5883             {
5884               movLeft2Result (left, LSB, result, MSB16, 0);
5885               aopPut (AOP (result), "!zero", 0);
5886             }
5887         }
5888       else
5889         {
5890           aopPut (AOP (result), "!zero", LSB);
5891         }
5892     }
5893   /*  1 <= shCount <= 7 */
5894   else
5895     {
5896       if (size == 1)
5897         {
5898           wassert (0);
5899         }
5900       else
5901         {
5902           shiftL2Left2Result (left, LSB, result, LSB, shCount);
5903         }
5904     }
5905 }
5906
5907 /*-----------------------------------------------------------------*/
5908 /* genlshOne - left shift a one byte quantity by known count       */
5909 /*-----------------------------------------------------------------*/
5910 static void
5911 genlshOne (operand * result, operand * left, int shCount)
5912 {
5913   shiftL1Left2Result (left, LSB, result, LSB, shCount);
5914 }
5915
5916 /*-----------------------------------------------------------------*/
5917 /* genLeftShiftLiteral - left shifting by known count              */
5918 /*-----------------------------------------------------------------*/
5919 static void
5920 genLeftShiftLiteral (operand * left,
5921                      operand * right,
5922                      operand * result,
5923                      iCode * ic)
5924 {
5925   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5926   int size;
5927
5928   freeAsmop (right, NULL, ic);
5929
5930   aopOp (left, ic, FALSE, FALSE);
5931   aopOp (result, ic, FALSE, FALSE);
5932
5933   size = getSize (operandType (result));
5934
5935   /* I suppose that the left size >= result size */
5936   if (shCount == 0)
5937     {
5938       wassert (0);
5939     }
5940
5941   else if (shCount >= (size * 8)) 
5942     {
5943       while (size--)
5944         {
5945           aopPut (AOP (result), "!zero", size);
5946         }
5947     }
5948   else
5949     {
5950       switch (size)
5951         {
5952         case 1:
5953           genlshOne (result, left, shCount);
5954           break;
5955         case 2:
5956           genlshTwo (result, left, shCount);
5957           break;
5958         case 4:
5959           wassertl (0, "Shifting of longs is currently unsupported");
5960           break;
5961         default:
5962           wassert (0);
5963         }
5964     }
5965   freeAsmop (left, NULL, ic);
5966   freeAsmop (result, NULL, ic);
5967 }
5968
5969 /*-----------------------------------------------------------------*/
5970 /* genLeftShift - generates code for left shifting                 */
5971 /*-----------------------------------------------------------------*/
5972 static void
5973 genLeftShift (iCode * ic)
5974 {
5975   int size, offset;
5976   const char *l;
5977   symbol *tlbl, *tlbl1;
5978   operand *left, *right, *result;
5979
5980   right = IC_RIGHT (ic);
5981   left = IC_LEFT (ic);
5982   result = IC_RESULT (ic);
5983
5984   aopOp (right, ic, FALSE, FALSE);
5985
5986   /* if the shift count is known then do it
5987      as efficiently as possible */
5988   if (AOP_TYPE (right) == AOP_LIT)
5989     {
5990       genLeftShiftLiteral (left, right, result, ic);
5991       return;
5992     }
5993
5994   /* shift count is unknown then we have to form a loop get the loop
5995      count in B : Note: we take only the lower order byte since
5996      shifting more that 32 bits make no sense anyway, ( the largest
5997      size of an object can be only 32 bits ) */
5998   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5999   emit2 ("inc a");
6000   freeAsmop (right, NULL, ic);
6001   aopOp (left, ic, FALSE, FALSE);
6002   aopOp (result, ic, FALSE, FALSE);
6003
6004   /* now move the left to the result if they are not the
6005      same */
6006
6007   if (!sameRegs (AOP (left), AOP (result)))
6008     {
6009
6010       size = AOP_SIZE (result);
6011       offset = 0;
6012       while (size--)
6013         {
6014           l = aopGet (AOP (left), offset, FALSE);
6015           aopPut (AOP (result), l, offset);
6016           offset++;
6017         }
6018     }
6019
6020   tlbl = newiTempLabel (NULL);
6021   size = AOP_SIZE (result);
6022   offset = 0;
6023   tlbl1 = newiTempLabel (NULL);
6024
6025   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6026   emitLabel (tlbl->key + 100);
6027   l = aopGet (AOP (result), offset, FALSE);
6028
6029   while (size--)
6030     {
6031       l = aopGet (AOP (result), offset, FALSE);
6032
6033       if (offset == 0)
6034         {
6035           emit2 ("sla %s", l);
6036         }
6037       else
6038         {
6039           emit2 ("rl %s", l);
6040         }
6041       offset++;
6042     }
6043   emitLabel (tlbl1->key + 100);
6044   emit2 ("dec a");
6045   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6046
6047   freeAsmop (left, NULL, ic);
6048   freeAsmop (result, NULL, ic);
6049 }
6050
6051 /*-----------------------------------------------------------------*/
6052 /* genrshOne - left shift two bytes by known amount != 0           */
6053 /*-----------------------------------------------------------------*/
6054 static void
6055 genrshOne (operand * result, operand * left, int shCount, int is_signed)
6056 {
6057   /* Errk */
6058   int size = AOP_SIZE (result);
6059   const char *l;
6060
6061   wassert (size == 1);
6062   wassert (shCount < 8);
6063
6064   l = aopGet (AOP (left), 0, FALSE);
6065
6066   if (AOP (result)->type == AOP_REG)
6067     {
6068       aopPut (AOP (result), l, 0);
6069       l = aopGet (AOP (result), 0, FALSE);
6070       while (shCount--)
6071         {
6072           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6073         }
6074     }
6075   else
6076     {
6077       _moveA (l);
6078       while (shCount--)
6079         {
6080           emit2 ("%s a", is_signed ? "sra" : "srl");
6081         }
6082       aopPut (AOP (result), "a", 0);
6083     }
6084 }
6085
6086 /*-----------------------------------------------------------------*/
6087 /* AccRsh - right shift accumulator by known count                 */
6088 /*-----------------------------------------------------------------*/
6089 static void
6090 AccRsh (int shCount)
6091 {
6092   static const unsigned char SRMask[] =
6093     {
6094       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6095     };
6096
6097   if (shCount != 0)
6098     {
6099       /* rotate right accumulator */
6100       AccRol (8 - shCount);
6101       /* and kill the higher order bits */
6102       emit2 ("and a,!immedbyte", SRMask[shCount]);
6103     }
6104 }
6105
6106 /*-----------------------------------------------------------------*/
6107 /* shiftR1Left2Result - shift right one byte from left to result   */
6108 /*-----------------------------------------------------------------*/
6109 static void
6110 shiftR1Left2Result (operand * left, int offl,
6111                     operand * result, int offr,
6112                     int shCount, int sign)
6113 {
6114   _moveA (aopGet (AOP (left), offl, FALSE));
6115   if (sign)
6116     {
6117       while (shCount--)
6118         {
6119           emit2 ("%s a", sign ? "sra" : "srl");
6120         }
6121     }
6122   else
6123     {
6124       AccRsh (shCount);
6125     }
6126   aopPut (AOP (result), "a", offr);
6127 }
6128
6129 /*-----------------------------------------------------------------*/
6130 /* genrshTwo - right shift two bytes by known amount != 0          */
6131 /*-----------------------------------------------------------------*/
6132 static void
6133 genrshTwo (operand * result, operand * left,
6134            int shCount, int sign)
6135 {
6136   /* if shCount >= 8 */
6137   if (shCount >= 8)
6138     {
6139       shCount -= 8;
6140       if (shCount)
6141         {
6142           shiftR1Left2Result (left, MSB16, result, LSB,
6143                               shCount, sign);
6144         }
6145       else
6146         {
6147           movLeft2Result (left, MSB16, result, LSB, sign);
6148         }
6149       if (sign)
6150         {
6151           /* Sign extend the result */
6152           _moveA(aopGet (AOP (result), 0, FALSE));
6153           emit2 ("rlc a");
6154           emit2 ("sbc a,a");
6155
6156           aopPut (AOP (result), ACC_NAME, MSB16);
6157         }
6158       else
6159         {
6160           aopPut (AOP (result), "!zero", 1);
6161         }
6162     }
6163   /*  1 <= shCount <= 7 */
6164   else
6165     {
6166       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6167     }
6168 }
6169
6170 /*-----------------------------------------------------------------*/
6171 /* genRightShiftLiteral - left shifting by known count              */
6172 /*-----------------------------------------------------------------*/
6173 static void
6174 genRightShiftLiteral (operand * left,
6175                       operand * right,
6176                       operand * result,
6177                       iCode * ic,
6178                       int sign)
6179 {
6180   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6181   int size;
6182
6183   freeAsmop (right, NULL, ic);
6184
6185   aopOp (left, ic, FALSE, FALSE);
6186   aopOp (result, ic, FALSE, FALSE);
6187
6188   size = getSize (operandType (result));
6189
6190   /* I suppose that the left size >= result size */
6191   if (shCount == 0)
6192     {
6193       wassert (0);
6194     }
6195
6196   else if (shCount >= (size * 8)) {
6197     const char *s;
6198     if (!SPEC_USIGN(getSpec(operandType(left)))) {
6199       _moveA(aopGet (AOP (left), 0, FALSE));
6200       emit2 ("rlc a");
6201       emit2 ("sbc a,a");
6202       s=ACC_NAME;
6203     } else {
6204       s="!zero";
6205     }
6206     while (size--)
6207       aopPut (AOP (result), s, size);
6208   }
6209   else
6210     {
6211       switch (size)
6212         {
6213         case 1:
6214           genrshOne (result, left, shCount, sign);
6215           break;
6216         case 2:
6217           genrshTwo (result, left, shCount, sign);
6218           break;
6219         case 4:
6220           wassertl (0, "Asked to shift right a long which should be a function call");
6221           break;
6222         default:
6223           wassertl (0, "Entered default case in right shift delegate");
6224         }
6225     }
6226   freeAsmop (left, NULL, ic);
6227   freeAsmop (result, NULL, ic);
6228 }
6229
6230 /*-----------------------------------------------------------------*/
6231 /* genRightShift - generate code for right shifting                */
6232 /*-----------------------------------------------------------------*/
6233 static void
6234 genRightShift (iCode * ic)
6235 {
6236   operand *right, *left, *result;
6237   sym_link *retype;
6238   int size, offset, first = 1;
6239   const char *l;
6240   bool is_signed;
6241
6242   symbol *tlbl, *tlbl1;
6243
6244   /* if signed then we do it the hard way preserve the
6245      sign bit moving it inwards */
6246   retype = getSpec (operandType (IC_RESULT (ic)));
6247
6248   is_signed = !SPEC_USIGN (retype);
6249
6250   /* signed & unsigned types are treated the same : i.e. the
6251      signed is NOT propagated inwards : quoting from the
6252      ANSI - standard : "for E1 >> E2, is equivalent to division
6253      by 2**E2 if unsigned or if it has a non-negative value,
6254      otherwise the result is implementation defined ", MY definition
6255      is that the sign does not get propagated */
6256
6257   right = IC_RIGHT (ic);
6258   left = IC_LEFT (ic);
6259   result = IC_RESULT (ic);
6260
6261   aopOp (right, ic, FALSE, FALSE);
6262
6263   /* if the shift count is known then do it
6264      as efficiently as possible */
6265   if (AOP_TYPE (right) == AOP_LIT)
6266     {
6267       genRightShiftLiteral (left, right, result, ic, is_signed);
6268       return;
6269     }
6270
6271   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6272   emit2 ("inc a");
6273   freeAsmop (right, NULL, ic);
6274
6275   aopOp (left, ic, FALSE, FALSE);
6276   aopOp (result, ic, FALSE, FALSE);
6277
6278   /* now move the left to the result if they are not the
6279      same */
6280   if (!sameRegs (AOP (left), AOP (result)))
6281     {
6282
6283       size = AOP_SIZE (result);
6284       offset = 0;
6285       while (size--)
6286         {
6287           l = aopGet (AOP (left), offset, FALSE);
6288           aopPut (AOP (result), l, offset);
6289           offset++;
6290         }
6291     }
6292
6293   tlbl = newiTempLabel (NULL);
6294   tlbl1 = newiTempLabel (NULL);
6295   size = AOP_SIZE (result);
6296   offset = size - 1;
6297
6298   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6299   emitLabel (tlbl->key + 100);
6300   while (size--)
6301     {
6302       l = aopGet (AOP (result), offset--, FALSE);
6303       if (first)
6304         {
6305           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6306           first = 0;
6307         }
6308       else
6309         {
6310           emit2 ("rr %s", l);
6311         }
6312     }
6313   emitLabel (tlbl1->key + 100);
6314   emit2 ("dec a");
6315   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6316
6317   freeAsmop (left, NULL, ic);
6318   freeAsmop (result, NULL, ic);
6319 }
6320
6321
6322 /*-----------------------------------------------------------------*/
6323 /* genUnpackBits - generates code for unpacking bits               */
6324 /*-----------------------------------------------------------------*/
6325 static void
6326 genUnpackBits (operand * result, int pair)
6327 {
6328   int offset = 0;       /* result byte offset */
6329   int rsize;            /* result size */
6330   int rlen = 0;         /* remaining bitfield length */
6331   sym_link *etype;      /* bitfield type information */
6332   int blen;             /* bitfield length */
6333   int bstr;             /* bitfield starting bit within byte */
6334
6335   emitDebug ("; genUnpackBits");
6336
6337   etype = getSpec (operandType (result));
6338   rsize = getSize (operandType (result));
6339   blen = SPEC_BLEN (etype);
6340   bstr = SPEC_BSTR (etype);
6341
6342   /* If the bitfield length is less than a byte */
6343   if (blen < 8)
6344     {
6345       emit2 ("ld a,!*pair", _pairs[pair].name);
6346       AccRsh (bstr);
6347       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6348       aopPut (AOP (result), "a", offset++);
6349       goto finish;
6350     }
6351
6352   /* TODO: what if pair == PAIR_DE ? */
6353   if (getPairId (AOP (result)) == PAIR_HL)
6354     {
6355       wassertl (rsize == 2, "HL must be of size 2");
6356       emit2 ("ld a,!*hl");
6357       emit2 ("inc hl");
6358       emit2 ("ld h,!*hl");
6359       emit2 ("ld l,a");
6360       emit2 ("ld a,h");
6361       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6362       emit2 ("ld h,a");
6363       spillPair (PAIR_HL);
6364       return;
6365     }
6366
6367   /* Bit field did not fit in a byte. Copy all
6368      but the partial byte at the end.  */
6369   for (rlen=blen;rlen>=8;rlen-=8)
6370     {
6371       emit2 ("ld a,!*pair", _pairs[pair].name);
6372       aopPut (AOP (result), "a", offset++);
6373       if (rlen>8)
6374         {
6375           emit2 ("inc %s", _pairs[pair].name);
6376           _G.pairs[pair].offset++;
6377         }
6378     }
6379
6380   /* Handle the partial byte at the end */
6381   if (rlen)
6382     {
6383       emit2 ("ld a,!*pair", _pairs[pair].name);
6384       emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6385       aopPut (AOP (result), "a", offset++);
6386     }
6387
6388 finish:
6389   if (offset < rsize)
6390     {
6391       rsize -= offset;
6392       while (rsize--)
6393         aopPut (AOP (result), "!zero", offset++);
6394     }
6395 }
6396
6397 /*-----------------------------------------------------------------*/
6398 /* genGenPointerGet -  get value from generic pointer space        */
6399 /*-----------------------------------------------------------------*/
6400 static void
6401 genGenPointerGet (operand * left,
6402                   operand * result, iCode * ic)
6403 {
6404   int size, offset;
6405   sym_link *retype = getSpec (operandType (result));
6406   int pair = PAIR_HL;
6407
6408   if (IS_GB)
6409     pair = PAIR_DE;
6410
6411   aopOp (left, ic, FALSE, FALSE);
6412   aopOp (result, ic, FALSE, FALSE);
6413
6414   size = AOP_SIZE (result);
6415
6416   if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6417     {
6418       /* Just do it */
6419       if (isPtrPair (AOP (left)))
6420         {
6421           tsprintf (buffer, sizeof(buffer), 
6422                     "!*pair", getPairName (AOP (left)));
6423           aopPut (AOP (result), buffer, 0);
6424         }
6425       else
6426         {
6427           emit2 ("ld a,!*pair", getPairName (AOP (left)));
6428           aopPut (AOP (result), "a", 0);
6429         }
6430       freeAsmop (left, NULL, ic);
6431       goto release;
6432     }
6433
6434   if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6435     {
6436       /* Just do it */
6437       offset = 0;
6438       while (size--) 
6439         {
6440           char at[20];
6441           tsprintf (at, sizeof(at), "!*iyx", offset);
6442           aopPut (AOP (result), at, offset);
6443           offset++;
6444         }
6445  
6446       freeAsmop (left, NULL, ic);
6447       goto release;
6448     }
6449
6450   /* For now we always load into IY */
6451   /* if this is remateriazable */
6452   fetchPair (pair, AOP (left));
6453
6454   /* if bit then unpack */
6455   if (IS_BITVAR (retype))
6456     {
6457       genUnpackBits (result, pair);
6458       freeAsmop (left, NULL, ic);
6459       goto release;
6460       //wassert (0);
6461     }
6462   else if (getPairId (AOP (result)) == PAIR_HL)
6463     {
6464       wassertl (size == 2, "HL must be of size 2");
6465       emit2 ("ld a,!*hl");
6466       emit2 ("inc hl");
6467       emit2 ("ld h,!*hl");
6468       emit2 ("ld l,a");
6469       spillPair (PAIR_HL);
6470     }
6471   else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6472     {
6473       size = AOP_SIZE (result);
6474       offset = 0;
6475
6476       while (size--)
6477         {
6478           /* PENDING: make this better */
6479           if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6480             {
6481               aopPut (AOP (result), "!*hl", offset++);
6482             }
6483           else
6484             {
6485               emit2 ("ld a,!*pair", _pairs[pair].name);
6486               aopPut (AOP (result), "a", offset++);
6487             }
6488           if (size)
6489             {
6490               emit2 ("inc %s", _pairs[pair].name);
6491               _G.pairs[pair].offset++;
6492             }
6493         }
6494       /* Fixup HL back down */
6495       for (size = AOP_SIZE (result)-1; size; size--)
6496         {
6497           emit2 ("dec %s", _pairs[pair].name);
6498         }
6499     }
6500   else
6501     {
6502       size = AOP_SIZE (result);
6503       offset = 0;
6504
6505       while (size--)
6506         {
6507           /* PENDING: make this better */
6508           if (!IS_GB && 
6509               (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6510             {
6511               aopPut (AOP (result), "!*hl", offset++);
6512             }
6513           else
6514             {
6515               emit2 ("ld a,!*pair", _pairs[pair].name);
6516               aopPut (AOP (result), "a", offset++);
6517             }
6518           if (size)
6519             {
6520               emit2 ("inc %s", _pairs[pair].name);
6521               _G.pairs[pair].offset++;
6522             }
6523         }
6524     }
6525
6526   freeAsmop (left, NULL, ic);
6527
6528 release:
6529   freeAsmop (result, NULL, ic);
6530 }
6531
6532 /*-----------------------------------------------------------------*/
6533 /* genPointerGet - generate code for pointer get                   */
6534 /*-----------------------------------------------------------------*/
6535 static void
6536 genPointerGet (iCode * ic)
6537 {
6538   operand *left, *result;
6539   sym_link *type, *etype;
6540
6541   left = IC_LEFT (ic);
6542   result = IC_RESULT (ic);
6543
6544   /* depending on the type of pointer we need to
6545      move it to the correct pointer register */
6546   type = operandType (left);
6547   etype = getSpec (type);
6548
6549   genGenPointerGet (left, result, ic);
6550 }
6551
6552 bool
6553 isRegOrLit (asmop * aop)
6554 {
6555   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6556     return TRUE;
6557   return FALSE;
6558 }
6559
6560
6561 /*-----------------------------------------------------------------*/
6562 /* genPackBits - generates code for packed bit storage             */
6563 /*-----------------------------------------------------------------*/
6564 static void
6565 genPackBits (sym_link * etype,
6566              operand * right,
6567              int pair,
6568              iCode *ic)
6569 {
6570   int offset = 0;       /* source byte offset */
6571   int rlen = 0;         /* remaining bitfield length */
6572   int blen;             /* bitfield length */
6573   int bstr;             /* bitfield starting bit within byte */
6574   int litval;           /* source literal value (if AOP_LIT) */
6575   unsigned char mask;   /* bitmask within current byte */
6576   int extraPair;        /* a tempory register */
6577   bool needPopExtra=0;  /* need to restore original value of temp reg */
6578
6579   emitDebug (";     genPackBits","");
6580
6581   blen = SPEC_BLEN (etype);
6582   bstr = SPEC_BSTR (etype);
6583
6584   /* If the bitfield length is less than a byte */
6585   if (blen < 8)
6586     {
6587       mask = ((unsigned char) (0xFF << (blen + bstr)) |
6588               (unsigned char) (0xFF >> (8 - bstr)));
6589
6590       if (AOP_TYPE (right) == AOP_LIT)
6591         {
6592           /* Case with a bitfield length <8 and literal source
6593           */
6594           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6595           litval <<= bstr;
6596           litval &= (~mask) & 0xff;
6597           emit2 ("ld a,!*pair", _pairs[pair].name);
6598           if ((mask|litval)!=0xff)
6599             emit2 ("and a,!immedbyte", mask);
6600           if (litval)
6601             emit2 ("or a,!immedbyte", litval);
6602           emit2 ("ld !*pair,a", _pairs[pair].name);
6603           return;
6604         }
6605       else
6606         {
6607           /* Case with a bitfield length <8 and arbitrary source
6608           */
6609           _moveA (aopGet (AOP (right), 0, FALSE));
6610           /* shift and mask source value */
6611           AccLsh (bstr);
6612           emit2 ("and a,!immedbyte", (~mask) & 0xff);
6613
6614           extraPair = getFreePairId(ic);
6615           if (extraPair == PAIR_INVALID)
6616             {
6617               extraPair = PAIR_BC;
6618               if (getPairId (AOP (right)) != PAIR_BC
6619                   || !isLastUse (ic, right))
6620                 {
6621                   _push (extraPair);
6622                   needPopExtra = 1;
6623                 }
6624             }
6625           emit2 ("ld %s,a", _pairs[extraPair].l);
6626           emit2 ("ld a,!*pair", _pairs[pair].name);
6627
6628           emit2 ("and a,!immedbyte", mask);
6629           emit2 ("or a,%s", _pairs[extraPair].l);
6630           emit2 ("ld !*pair,a", _pairs[pair].name);
6631           if (needPopExtra)
6632             _pop (extraPair);
6633           return;
6634         }
6635     }
6636
6637   /* Bit length is greater than 7 bits. In this case, copy  */
6638   /* all except the partial byte at the end                 */
6639   for (rlen=blen;rlen>=8;rlen-=8)
6640     {
6641       emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6642       emit2 ("ld !*pair,a", _pairs[pair].name);
6643       if (rlen>8)
6644         {
6645           emit2 ("inc %s", _pairs[pair].name);
6646           _G.pairs[pair].offset++;
6647         }
6648     }
6649
6650   /* If there was a partial byte at the end */
6651   if (rlen)
6652     {
6653       mask = (((unsigned char) -1 << rlen) & 0xff);
6654       
6655       if (AOP_TYPE (right) == AOP_LIT)
6656         {
6657           /* Case with partial byte and literal source
6658           */
6659           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6660           litval >>= (blen-rlen);
6661           litval &= (~mask) & 0xff;
6662           emit2 ("ld a,!*pair", _pairs[pair].name);
6663           if ((mask|litval)!=0xff)
6664             emit2 ("and a,!immedbyte", mask);
6665           if (litval)
6666             emit2 ("or a,!immedbyte", litval);
6667         }
6668       else
6669         {
6670           /* Case with partial byte and arbitrary source
6671           */
6672           _moveA (aopGet (AOP (right), offset++, FALSE));
6673           emit2 ("and a,!immedbyte", (~mask) & 0xff);
6674
6675           extraPair = getFreePairId(ic);
6676           if (extraPair == PAIR_INVALID)
6677             {
6678               extraPair = getPairId (AOP (right));
6679               if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6680                 extraPair = PAIR_BC;
6681
6682               if (getPairId (AOP (right)) != PAIR_BC
6683                   || !isLastUse (ic, right))
6684                 {
6685                   _push (extraPair);
6686                   needPopExtra = 1;
6687                 }
6688             }
6689           emit2 ("ld %s,a", _pairs[extraPair].l);
6690           emit2 ("ld a,!*pair", _pairs[pair].name);
6691
6692           emit2 ("and a,!immedbyte", mask);
6693           emit2 ("or a,%s", _pairs[extraPair].l);
6694           if (needPopExtra)
6695             _pop (extraPair);
6696
6697         }
6698       emit2 ("ld !*pair,a", _pairs[pair].name);
6699     }
6700 }
6701
6702
6703 /*-----------------------------------------------------------------*/
6704 /* genGenPointerSet - stores the value into a pointer location        */
6705 /*-----------------------------------------------------------------*/
6706 static void
6707 genGenPointerSet (operand * right,
6708                   operand * result, iCode * ic)
6709 {
6710   int size, offset;
6711   sym_link *retype = getSpec (operandType (right));
6712   sym_link *letype = getSpec (operandType (result));
6713   PAIR_ID pairId = PAIR_HL;
6714   bool isBitvar;
6715   
6716   aopOp (result, ic, FALSE, FALSE);
6717   aopOp (right, ic, FALSE, FALSE);
6718
6719   if (IS_GB)
6720     pairId = PAIR_DE;
6721
6722   size = AOP_SIZE (right);
6723
6724   isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6725   emitDebug("; isBitvar = %d", isBitvar);
6726
6727   /* Handle the exceptions first */
6728   if (isPair (AOP (result)) && size == 1 && !isBitvar)
6729     {
6730       /* Just do it */
6731       const char *l = aopGet (AOP (right), 0, FALSE);
6732       const char *pair = getPairName (AOP (result));
6733       if (canAssignToPtr (l) && isPtr (pair))
6734         {
6735           emit2 ("ld !*pair,%s", pair, l);
6736         }
6737       else
6738         {
6739           _moveA (l);
6740           emit2 ("ld !*pair,a", pair);
6741         }
6742       goto release;
6743     }
6744   
6745   if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6746     {
6747       /* Just do it */
6748       const char *l = aopGet (AOP (right), 0, FALSE);
6749
6750       offset = 0;
6751       while (size--) 
6752         {
6753           if (canAssignToPtr (l))
6754             {
6755               emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6756             }
6757           else
6758             {
6759               _moveA (aopGet (AOP (right), offset, FALSE));
6760               emit2 ("ld !*iyx,a", offset);
6761             }
6762           offset++;
6763         }
6764       goto release;
6765     }
6766   else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6767            && !isBitvar)
6768     {
6769       offset = 0;
6770
6771       while (size--)
6772         {
6773           const char *l = aopGet (AOP (right), offset, FALSE);
6774           if (isRegOrLit (AOP (right)) && !IS_GB)
6775             {
6776               emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6777             }
6778           else
6779             {
6780               _moveA (l);
6781               emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6782             }
6783           if (size)
6784             {
6785               emit2 ("inc %s", _pairs[PAIR_HL].name);
6786               _G.pairs[PAIR_HL].offset++;
6787             }
6788           offset++;
6789         }
6790
6791       /* Fixup HL back down */
6792       for (size = AOP_SIZE (right)-1; size; size--)
6793         {
6794           emit2 ("dec %s", _pairs[PAIR_HL].name);
6795         }
6796       goto release;
6797     }
6798
6799   /* if the operand is already in dptr
6800      then we do nothing else we move the value to dptr */
6801   if (AOP_TYPE (result) != AOP_STR)
6802     {
6803       fetchPair (pairId, AOP (result));
6804     }
6805   /* so hl know contains the address */
6806   freeAsmop (result, NULL, ic);
6807
6808   /* if bit then unpack */
6809   if (isBitvar)
6810     {
6811       genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6812       goto release;
6813       //wassert (0);
6814     }
6815   else
6816     {
6817       offset = 0;
6818
6819       while (size--)
6820         {
6821           const char *l = aopGet (AOP (right), offset, FALSE);
6822           if (isRegOrLit (AOP (right)) && !IS_GB)
6823             {
6824               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6825             }
6826           else
6827             {
6828               _moveA (l);
6829               emit2 ("ld !*pair,a", _pairs[pairId].name);
6830             }
6831           if (size)
6832             {
6833               emit2 ("inc %s", _pairs[pairId].name);
6834               _G.pairs[pairId].offset++;
6835             }
6836           offset++;
6837         }
6838     }
6839 release:
6840   freeAsmop (right, NULL, ic);
6841 }
6842
6843 /*-----------------------------------------------------------------*/
6844 /* genPointerSet - stores the value into a pointer location        */
6845 /*-----------------------------------------------------------------*/
6846 static void
6847 genPointerSet (iCode * ic)
6848 {
6849   operand *right, *result;
6850   sym_link *type, *etype;
6851
6852   right = IC_RIGHT (ic);
6853   result = IC_RESULT (ic);
6854
6855   /* depending on the type of pointer we need to
6856      move it to the correct pointer register */
6857   type = operandType (result);
6858   etype = getSpec (type);
6859
6860   genGenPointerSet (right, result, ic);
6861 }
6862
6863 /*-----------------------------------------------------------------*/
6864 /* genIfx - generate code for Ifx statement                        */
6865 /*-----------------------------------------------------------------*/
6866 static void
6867 genIfx (iCode * ic, iCode * popIc)
6868 {
6869   operand *cond = IC_COND (ic);
6870   int isbit = 0;
6871
6872   aopOp (cond, ic, FALSE, TRUE);
6873
6874   /* get the value into acc */
6875   if (AOP_TYPE (cond) != AOP_CRY)
6876     _toBoolean (cond);
6877   else
6878     isbit = 1;
6879   /* the result is now in the accumulator */
6880   freeAsmop (cond, NULL, ic);
6881
6882   /* if there was something to be popped then do it */
6883   if (popIc)
6884     genIpop (popIc);
6885
6886   /* if the condition is  a bit variable */
6887   if (isbit && IS_ITEMP (cond) &&
6888       SPIL_LOC (cond))
6889     genIfxJump (ic, SPIL_LOC (cond)->rname);
6890   else if (isbit && !IS_ITEMP (cond))
6891     genIfxJump (ic, OP_SYMBOL (cond)->rname);
6892   else
6893     genIfxJump (ic, "a");
6894
6895   ic->generated = 1;
6896 }
6897
6898 /*-----------------------------------------------------------------*/
6899 /* genAddrOf - generates code for address of                       */
6900 /*-----------------------------------------------------------------*/
6901 static void
6902 genAddrOf (iCode * ic)
6903 {
6904   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6905
6906   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6907
6908   /* if the operand is on the stack then we
6909      need to get the stack offset of this
6910      variable */
6911   if (IS_GB)
6912     {
6913       if (sym->onStack)
6914         {
6915           spillCached ();
6916           if (sym->stack <= 0)
6917             {
6918               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6919             }
6920           else
6921             {
6922               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6923             }
6924           commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6925         }
6926       else
6927         {
6928           emit2 ("ld de,!hashedstr", sym->rname);
6929           commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6930         }
6931     }
6932   else
6933     {
6934       spillCached ();
6935       if (sym->onStack)
6936         {
6937           /* if it has an offset  then we need to compute it */
6938           if (sym->stack > 0)
6939             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6940           else
6941             emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6942           emit2 ("add hl,sp");
6943         }
6944       else
6945         {
6946           emit2 ("ld hl,!hashedstr", sym->rname);
6947         }
6948       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6949     }
6950   freeAsmop (IC_RESULT (ic), NULL, ic);
6951 }
6952
6953 /*-----------------------------------------------------------------*/
6954 /* genAssign - generate code for assignment                        */
6955 /*-----------------------------------------------------------------*/
6956 static void
6957 genAssign (iCode * ic)
6958 {
6959   operand *result, *right;
6960   int size, offset;
6961   unsigned long lit = 0L;
6962
6963   result = IC_RESULT (ic);
6964   right = IC_RIGHT (ic);
6965
6966   /* Dont bother assigning if they are the same */
6967   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6968     {
6969       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6970       return;
6971     }
6972
6973   aopOp (right, ic, FALSE, FALSE);
6974   aopOp (result, ic, TRUE, FALSE);
6975
6976   /* if they are the same registers */
6977   if (sameRegs (AOP (right), AOP (result)))
6978     {
6979       emitDebug ("; (registers are the same)");
6980       goto release;
6981     }
6982
6983   /* if the result is a bit */
6984   if (AOP_TYPE (result) == AOP_CRY)
6985     {
6986       wassertl (0, "Tried to assign to a bit");
6987     }
6988
6989   /* general case */
6990   size = AOP_SIZE (result);
6991   offset = 0;
6992
6993   if (AOP_TYPE (right) == AOP_LIT)
6994     {
6995       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6996     }
6997
6998   if (isPair (AOP (result)))
6999     {
7000       fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
7001     }
7002   else if ((size > 1) &&
7003            (AOP_TYPE (result) != AOP_REG) &&
7004            (AOP_TYPE (right) == AOP_LIT) &&
7005            !IS_FLOAT (operandType (right)) &&
7006            (lit < 256L))
7007     {
7008       bool fXored = FALSE;
7009       offset = 0;
7010       /* Work from the top down.
7011          Done this way so that we can use the cached copy of 0
7012          in A for a fast clear */
7013       while (size--)
7014         {
7015           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
7016             {
7017               if (!fXored && size > 1)
7018                 {
7019                   emit2 ("xor a,a");
7020                   fXored = TRUE;
7021                 }
7022               if (fXored)
7023                 {
7024                   aopPut (AOP (result), "a", offset);
7025                 }
7026               else
7027                 {
7028                   aopPut (AOP (result), "!zero", offset);
7029                 }
7030             }
7031           else
7032             aopPut (AOP (result),
7033                     aopGet (AOP (right), offset, FALSE),
7034                     offset);
7035           offset++;
7036         }
7037     }
7038   else if (size == 2 && AOP_TYPE (right) == AOP_IY)
7039     {
7040       emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
7041       aopPut (AOP (result), "l", LSB);
7042       aopPut (AOP (result), "h", MSB16);
7043     }
7044   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7045     {
7046       /* Special case.  Load into a and d, then load out. */
7047       _moveA (aopGet (AOP (right), 0, FALSE));
7048       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
7049       aopPut (AOP (result), "a", 0);
7050       aopPut (AOP (result), "e", 1);
7051     }
7052   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
7053     {
7054       /* Special case - simple memcpy */
7055       aopGet (AOP (right), LSB, FALSE);
7056       emit2 ("ld d,h");
7057       emit2 ("ld e,l");
7058       aopGet (AOP (result), LSB, FALSE);
7059
7060       while (size--)
7061         {
7062           emit2 ("ld a,(de)");
7063           /* Peephole will optimise this. */
7064           emit2 ("ld (hl),a");
7065
7066           if (size != 0)
7067             {
7068               emit2 ("inc hl");
7069               emit2 ("inc de");
7070             }
7071         }
7072       spillPair (PAIR_HL);
7073     }
7074   else
7075     {
7076       while (size--)
7077         {
7078           /* PENDING: do this check better */
7079           if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
7080             {
7081               _moveA (aopGet (AOP (right), offset, FALSE));
7082               aopPut (AOP (result), "a", offset);
7083             }
7084           else
7085             aopPut (AOP (result),
7086                     aopGet (AOP (right), offset, FALSE),
7087                     offset);
7088           offset++;
7089         }
7090     }
7091
7092 release:
7093   freeAsmop (right, NULL, ic);
7094   freeAsmop (result, NULL, ic);
7095 }
7096
7097 /*-----------------------------------------------------------------*/
7098 /* genJumpTab - genrates code for jump table                       */
7099 /*-----------------------------------------------------------------*/
7100 static void
7101 genJumpTab (iCode * ic)
7102 {
7103   symbol *jtab;
7104   const char *l;
7105
7106   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7107   /* get the condition into accumulator */
7108   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7109   if (!IS_GB)
7110     emit2 ("push de");
7111   emit2 ("ld e,%s", l);
7112   emit2 ("ld d,!zero");
7113   jtab = newiTempLabel (NULL);
7114   spillCached ();
7115   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7116   emit2 ("add hl,de");
7117   emit2 ("add hl,de");
7118   emit2 ("add hl,de");
7119   freeAsmop (IC_JTCOND (ic), NULL, ic);
7120   if (!IS_GB)
7121     emit2 ("pop de");
7122   emit2 ("jp !*hl");
7123   emitLabel (jtab->key + 100);
7124   /* now generate the jump labels */
7125   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7126        jtab = setNextItem (IC_JTLABELS (ic)))
7127     emit2 ("jp !tlabel", jtab->key + 100);
7128 }
7129
7130 /*-----------------------------------------------------------------*/
7131 /* genCast - gen code for casting                                  */
7132 /*-----------------------------------------------------------------*/
7133 static void
7134 genCast (iCode * ic)
7135 {
7136   operand *result = IC_RESULT (ic);
7137   sym_link *rtype = operandType (IC_RIGHT (ic));
7138   operand *right = IC_RIGHT (ic);
7139   int size, offset;
7140
7141   /* if they are equivalent then do nothing */
7142   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7143     return;
7144
7145   aopOp (right, ic, FALSE, FALSE);
7146   aopOp (result, ic, FALSE, FALSE);
7147
7148   /* if the result is a bit */
7149   if (AOP_TYPE (result) == AOP_CRY)
7150     {
7151       wassertl (0, "Tried to cast to a bit");
7152     }
7153
7154   /* if they are the same size : or less */
7155   if (AOP_SIZE (result) <= AOP_SIZE (right))
7156     {
7157
7158       /* if they are in the same place */
7159       if (sameRegs (AOP (right), AOP (result)))
7160         goto release;
7161
7162       /* if they in different places then copy */
7163       size = AOP_SIZE (result);
7164       offset = 0;
7165       while (size--)
7166         {
7167           aopPut (AOP (result),
7168                   aopGet (AOP (right), offset, FALSE),
7169                   offset);
7170           offset++;
7171         }
7172       goto release;
7173     }
7174
7175   /* So we now know that the size of destination is greater
7176      than the size of the source */
7177   /* we move to result for the size of source */
7178   size = AOP_SIZE (right);
7179   offset = 0;
7180   while (size--)
7181     {
7182       aopPut (AOP (result),
7183               aopGet (AOP (right), offset, FALSE),
7184               offset);
7185       offset++;
7186     }
7187
7188   /* now depending on the sign of the destination */
7189   size = AOP_SIZE (result) - AOP_SIZE (right);
7190   /* Unsigned or not an integral type - right fill with zeros */
7191   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7192     {
7193       while (size--)
7194         aopPut (AOP (result), "!zero", offset++);
7195     }
7196   else
7197     {
7198       /* we need to extend the sign :{ */
7199         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7200                         FALSE);
7201       _moveA (l);
7202       emit2 ("rla ");
7203       emit2 ("sbc a,a");
7204       while (size--)
7205         aopPut (AOP (result), "a", offset++);
7206     }
7207
7208 release:
7209   freeAsmop (right, NULL, ic);
7210   freeAsmop (result, NULL, ic);
7211 }
7212
7213 /*-----------------------------------------------------------------*/
7214 /* genReceive - generate code for a receive iCode                  */
7215 /*-----------------------------------------------------------------*/
7216 static void
7217 genReceive (iCode * ic)
7218 {
7219   if (isOperandInFarSpace (IC_RESULT (ic)) &&
7220       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7221        IS_TRUE_SYMOP (IC_RESULT (ic))))
7222     {
7223       wassert (0);
7224     }
7225   else
7226     {
7227         // PENDING: HACK
7228         int size;
7229         int i;
7230
7231         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7232         size = AOP_SIZE(IC_RESULT(ic));
7233
7234         for (i = 0; i < size; i++) {
7235             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7236         }
7237     }
7238
7239   freeAsmop (IC_RESULT (ic), NULL, ic);
7240 }
7241
7242 /*-----------------------------------------------------------------*/
7243 /* genDummyRead - generate code for dummy read of volatiles        */
7244 /*-----------------------------------------------------------------*/
7245 static void
7246 genDummyRead (iCode * ic)
7247 {
7248   operand *op;
7249   int size, offset;
7250
7251   op = IC_RIGHT (ic);
7252   if (op && IS_SYMOP (op))
7253     {
7254       aopOp (op, ic, FALSE, FALSE);
7255   
7256       /* general case */
7257       size = AOP_SIZE (op);
7258       offset = 0;
7259
7260       while (size--)
7261         {
7262           _moveA (aopGet (AOP (op), offset, FALSE));
7263           offset++;
7264         }
7265
7266       freeAsmop (op, NULL, ic);
7267     }
7268   
7269   op = IC_LEFT (ic);
7270   if (op && IS_SYMOP (op))
7271     {
7272       aopOp (op, ic, FALSE, FALSE);
7273   
7274       /* general case */
7275       size = AOP_SIZE (op);
7276       offset = 0;
7277
7278       while (size--)
7279         {
7280           _moveA (aopGet (AOP (op), offset, FALSE));
7281           offset++;
7282         }
7283
7284       freeAsmop (op, NULL, ic);
7285     }
7286 }
7287
7288 enum
7289   {
7290     /** Maximum number of bytes to emit per line. */
7291     DBEMIT_MAX_RUN = 8
7292   };
7293
7294 /** Context for the byte output chunker. */
7295 typedef struct
7296 {
7297   unsigned char buffer[DBEMIT_MAX_RUN];
7298   int pos;
7299 } DBEMITCTX;
7300
7301
7302 /** Flushes a byte chunker by writing out all in the buffer and
7303     reseting. 
7304 */
7305 static void
7306 _dbFlush(DBEMITCTX *self)
7307 {
7308   char line[256];
7309
7310   if (self->pos > 0)
7311     {
7312       int i;
7313       sprintf(line, ".db 0x%02X", self->buffer[0]);
7314
7315       for (i = 1; i < self->pos; i++)
7316         {
7317           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7318         }
7319       emit2(line);
7320     }
7321   self->pos = 0;
7322 }
7323
7324 /** Write out another byte, buffering until a decent line is
7325     generated.
7326 */
7327 static void
7328 _dbEmit(DBEMITCTX *self, int c)
7329 {
7330   if (self->pos == DBEMIT_MAX_RUN)
7331     {
7332       _dbFlush(self);
7333     }
7334   self->buffer[self->pos++] = c;
7335 }
7336
7337 /** Context for a simple run length encoder. */
7338 typedef struct
7339 {
7340   unsigned last;
7341   unsigned char buffer[128];
7342   int pos;
7343   /** runLen may be equivalent to pos. */
7344   int runLen;
7345 } RLECTX;
7346
7347 enum
7348   {
7349     RLE_CHANGE_COST = 4,
7350     RLE_MAX_BLOCK = 127
7351   };
7352
7353 /** Flush the buffer of a run length encoder by writing out the run or
7354     data that it currently contains.
7355 */
7356 static void
7357 _rleCommit(RLECTX *self)
7358 {
7359   int i;
7360   if (self->pos != 0)
7361     {
7362       DBEMITCTX db;
7363       memset(&db, 0, sizeof(db));
7364           
7365       emit2(".db %u", self->pos);
7366       
7367       for (i = 0; i < self->pos; i++)
7368         {
7369           _dbEmit(&db, self->buffer[i]);
7370         }
7371       _dbFlush(&db);
7372     }
7373   /* Reset */
7374   self->pos = 0;
7375 }
7376
7377 /* Encoder design:
7378    Can get either a run or a block of random stuff.
7379    Only want to change state if a good run comes in or a run ends.
7380    Detecting run end is easy.
7381    Initial state?
7382
7383    Say initial state is in run, len zero, last zero.  Then if you get a
7384    few zeros then something else then a short run will be output.
7385    Seems OK.  While in run mode, keep counting.  While in random mode,
7386    keep a count of the run.  If run hits margin, output all up to run,
7387    restart, enter run mode.
7388 */
7389
7390 /** Add another byte into the run length encoder, flushing as
7391     required.  The run length encoder uses the Amiga IFF style, where
7392     a block is prefixed by its run length.  A positive length means
7393     the next n bytes pass straight through.  A negative length means
7394     that the next byte is repeated -n times.  A zero terminates the
7395     chunks.
7396 */
7397 static void
7398 _rleAppend(RLECTX *self, int c)
7399 {
7400   int i;
7401
7402   if (c != self->last)
7403     {
7404       /* The run has stopped.  See if it is worthwhile writing it out
7405          as a run.  Note that the random data comes in as runs of
7406          length one.
7407       */
7408       if (self->runLen > RLE_CHANGE_COST)
7409         {
7410           /* Yes, worthwhile. */
7411           /* Commit whatever was in the buffer. */
7412           _rleCommit(self);
7413           emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7414         }
7415       else
7416         {
7417           /* Not worthwhile.  Append to the end of the random list. */
7418           for (i = 0; i < self->runLen; i++)
7419             {
7420               if (self->pos >= RLE_MAX_BLOCK)
7421                 {
7422                   /* Commit. */
7423                   _rleCommit(self);
7424                 }
7425               self->buffer[self->pos++] = self->last;
7426             }
7427         }
7428       self->runLen = 1;
7429       self->last = c;
7430     }
7431   else
7432     {
7433       if (self->runLen >= RLE_MAX_BLOCK)
7434         {
7435           /* Commit whatever was in the buffer. */
7436           _rleCommit(self);
7437
7438           emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7439           self->runLen = 0;
7440         }
7441       self->runLen++;
7442     }
7443 }
7444
7445 static void
7446 _rleFlush(RLECTX *self)
7447 {
7448   _rleAppend(self, -1);
7449   _rleCommit(self);
7450   self->pos = 0;
7451   self->last = 0;
7452   self->runLen = 0;
7453 }
7454
7455 /** genArrayInit - Special code for initialising an array with constant
7456    data.
7457 */
7458 static void
7459 genArrayInit (iCode * ic)
7460 {
7461   literalList *iLoop;
7462   int         ix;
7463   int         elementSize = 0, eIndex, i;
7464   unsigned    val, lastVal;
7465   sym_link    *type;
7466   RLECTX      rle;
7467
7468   memset(&rle, 0, sizeof(rle));
7469
7470   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7471
7472   _saveRegsForCall(ic, 0);
7473
7474   fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7475   emit2 ("call __initrleblock");
7476     
7477   type = operandType(IC_LEFT(ic));
7478     
7479   if (type && type->next)
7480     {
7481       elementSize = getSize(type->next);
7482     }
7483   else
7484     {
7485       wassertl (0, "Can't determine element size in genArrayInit.");
7486     }
7487
7488   iLoop = IC_ARRAYILIST(ic);
7489   lastVal = (unsigned)-1;
7490
7491   /* Feed all the bytes into the run length encoder which will handle
7492      the actual output.
7493      This works well for mixed char data, and for random int and long
7494      data.
7495   */
7496   while (iLoop)
7497     {
7498       ix = iLoop->count;
7499
7500       if (ix != 0)
7501         {
7502           for (i = 0; i < ix; i++)
7503             {
7504               for (eIndex = 0; eIndex < elementSize; eIndex++)
7505                 {
7506                   val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7507                   _rleAppend(&rle, val);
7508                 }
7509             }
7510         }
7511         
7512       iLoop = iLoop->next;
7513     }
7514
7515   _rleFlush(&rle);
7516   /* Mark the end of the run. */
7517   emit2(".db 0");
7518
7519   _restoreRegsAfterCall();
7520
7521   spillCached ();
7522
7523   freeAsmop (IC_LEFT(ic), NULL, ic);
7524 }
7525
7526 static void
7527 _swap (PAIR_ID one, PAIR_ID two)
7528 {
7529   if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7530     {
7531       emit2 ("ex de,hl");
7532     }
7533   else
7534     {
7535       emit2 ("ld a,%s", _pairs[one].l);
7536       emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7537       emit2 ("ld %s,a", _pairs[two].l);
7538       emit2 ("ld a,%s", _pairs[one].h);
7539       emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7540       emit2 ("ld %s,a", _pairs[two].h);
7541     }
7542 }
7543
7544 /* The problem is that we may have all three pairs used and they may
7545    be needed in a different order.
7546
7547    Note: Have ex de,hl
7548
7549    Combinations:
7550      hl = hl            => unity, fine
7551      bc = bc
7552      de = de
7553
7554      hl = hl            hl = hl, swap de <=> bc
7555      bc = de
7556      de = bc
7557
7558      hl = bc            Worst case
7559      bc = de
7560      de = hl
7561      
7562      hl = bc            de = de, swap bc <=> hl
7563      bc = hl
7564      de = de
7565
7566      hl = de            Worst case
7567      bc = hl
7568      de = bc
7569
7570      hl = de            bc = bc, swap hl <=> de
7571      bc = bc
7572      de = hl
7573
7574    Break it down into:
7575     * Any pair = pair are done last
7576     * Any pair = iTemp are done last
7577     * Any swaps can be done any time
7578
7579    A worst case:
7580     push p1
7581     p1 = p2
7582     p2 = p3
7583     pop  p3
7584
7585    So how do we detect the cases?
7586    How about a 3x3 matrix?
7587         source
7588    dest x x x x
7589         x x x x
7590         x x x x (Fourth for iTemp/other)
7591
7592    First determin which mode to use by counting the number of unity and
7593    iTemp assigns.
7594      Three - any order
7595      Two - Assign the pair first, then the rest
7596      One - Swap the two, then the rest
7597      Zero - Worst case.
7598 */
7599 static void
7600 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7601 {
7602   PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7603   PAIR_ID dest[3] = {
7604     PAIR_BC, PAIR_HL, PAIR_DE
7605   };
7606   int i, j, nunity = 0;
7607   memset (ids, PAIR_INVALID, sizeof (ids));
7608
7609   /* Sanity checks */
7610   wassert (nparams == 3);
7611
7612   /* First save everything that needs to be saved. */
7613   _saveRegsForCall (ic, 0);
7614
7615   /* Loading HL first means that DE is always fine. */
7616   for (i = 0; i < nparams; i++)
7617     {
7618       aopOp (pparams[i], ic, FALSE, FALSE);
7619       ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7620     }
7621
7622   /* Count the number of unity or iTemp assigns. */
7623   for (i = 0; i < 3; i++) 
7624     {
7625       if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7626         {
7627           nunity++;
7628         }
7629     }
7630
7631   if (nunity == 3)
7632     {
7633       /* Any order, fall through. */
7634     }
7635   else if (nunity == 2)
7636     {
7637       /* One is assigned.  Pull it out and assign. */
7638       for (i = 0; i < 3; i++)
7639         {
7640           for (j = 0; j < NUM_PAIRS; j++)
7641             {
7642               if (ids[dest[i]][j] == TRUE)
7643                 {
7644                   /* Found it.  See if it's the right one. */
7645                   if (j == PAIR_INVALID || j == dest[i])
7646                     {
7647                       /* Keep looking. */
7648                     }
7649                   else
7650                     {
7651                       fetchPair(dest[i], AOP (pparams[i]));
7652                       goto done;
7653                     }
7654                 }
7655             }
7656         }
7657     }
7658   else if (nunity == 1)
7659     {
7660       /* Find the pairs to swap. */
7661       for (i = 0; i < 3; i++)
7662         {
7663           for (j = 0; j < NUM_PAIRS; j++)
7664             {
7665               if (ids[dest[i]][j] == TRUE)
7666                 {
7667                   if (j == PAIR_INVALID || j == dest[i])
7668                     {
7669                       /* Keep looking. */
7670                     }
7671                   else
7672                     {
7673                       _swap (j, dest[i]);
7674                       goto done;
7675                     }
7676                 }
7677             }
7678         }
7679     }
7680   else
7681     {
7682       int next = getPairId (AOP (pparams[0]));
7683       emit2 ("push %s", _pairs[next].name);
7684
7685       if (next == dest[1])
7686         {
7687           fetchPair (dest[1], AOP (pparams[1]));
7688           fetchPair (dest[2], AOP (pparams[2]));
7689         }
7690       else
7691         {
7692           fetchPair (dest[2], AOP (pparams[2]));
7693           fetchPair (dest[1], AOP (pparams[1]));
7694         }
7695       emit2 ("pop %s", _pairs[dest[0]].name);
7696     }
7697  done:
7698   /* Finally pull out all of the iTemps */
7699   for (i = 0; i < 3; i++)
7700     {
7701       if (ids[dest[i]][PAIR_INVALID] == 1)
7702         {
7703           fetchPair (dest[i], AOP (pparams[i]));
7704         }
7705     }
7706 }
7707
7708 static void
7709 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7710 {
7711   operand *from, *to;
7712   symbol *label;
7713   bool deInUse;
7714
7715   wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7716   to = pparams[0];
7717   from = pparams[1];
7718
7719   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7720
7721   setupForBuiltin3 (ic, nParams, pparams);
7722
7723   label = newiTempLabel(NULL);
7724
7725   emitLabel (label->key);
7726   emit2 ("ld a,(hl)");
7727   emit2 ("ldi");
7728   emit2 ("or a");
7729   emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7730
7731   freeAsmop (from, NULL, ic->next);
7732   freeAsmop (to, NULL, ic);
7733 }
7734
7735 static void
7736 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7737 {
7738   operand *from, *to, *count;
7739   bool deInUse;
7740
7741   wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7742   to = pparams[2];
7743   from = pparams[1];
7744   count = pparams[0];
7745
7746   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7747
7748   setupForBuiltin3 (ic, nParams, pparams);
7749
7750   emit2 ("ldir");
7751
7752   freeAsmop (count, NULL, ic->next->next);
7753   freeAsmop (from, NULL, ic);
7754
7755   _restoreRegsAfterCall();
7756
7757   /* if we need assign a result value */
7758   if ((IS_ITEMP (IC_RESULT (ic)) &&
7759        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7760         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7761       IS_TRUE_SYMOP (IC_RESULT (ic)))
7762     {
7763       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7764       movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7765       freeAsmop (IC_RESULT (ic), NULL, ic);
7766     }
7767
7768   freeAsmop (to, NULL, ic->next);
7769 }
7770
7771 /*-----------------------------------------------------------------*/
7772 /* genBuiltIn - calls the appropriate function to  generating code */
7773 /* for a built in function                                         */
7774 /*-----------------------------------------------------------------*/
7775 static void genBuiltIn (iCode *ic)
7776 {
7777     operand *bi_parms[MAX_BUILTIN_ARGS];
7778     int nbi_parms;
7779     iCode *bi_iCode;
7780     symbol *bif;
7781
7782     /* get all the arguments for a built in function */
7783     bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7784
7785     /* which function is it */
7786     bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7787
7788     if (strcmp(bif->name,"__builtin_strcpy")==0) 
7789       {
7790         genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7791       } 
7792     else if (strcmp(bif->name,"__builtin_memcpy")==0) 
7793       {
7794         genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7795       } 
7796     else 
7797       {
7798         wassertl (0, "Unknown builtin function encountered");
7799       }
7800 }
7801
7802 /*-----------------------------------------------------------------*/
7803 /* genZ80Code - generate code for Z80 based controllers            */
7804 /*-----------------------------------------------------------------*/
7805 void
7806 genZ80Code (iCode * lic)
7807 {
7808   iCode *ic;
7809   int cln = 0;
7810
7811   /* Hack */
7812   if (IS_GB)
7813     {
7814       _fReturn = _gbz80_return;
7815       _fTmp = _gbz80_return;
7816     }
7817   else
7818     {
7819       _fReturn = _z80_return;
7820       _fTmp = _z80_return;
7821     }
7822
7823   _G.lines.head = _G.lines.current = NULL;
7824   
7825   /* if debug information required */
7826   if (options.debug && currFunc)
7827     {
7828       debugFile->writeFunction(currFunc);
7829       _G.lines.isDebug = 1;
7830       if (IS_STATIC (currFunc->etype))
7831         sprintf (buffer, "F%s$%s$0$0", moduleName, currFunc->name);
7832       else
7833         sprintf (buffer, "G$%s$0$0", currFunc->name);
7834       emit2 ("!labeldef", buffer);
7835       _G.lines.isDebug = 0;
7836     }
7837
7838   for (ic = lic; ic; ic = ic->next)
7839     {
7840       _G.current_iCode = ic;
7841
7842       if (ic->lineno && cln != ic->lineno)
7843         {
7844           if (options.debug)
7845             {
7846               _G.lines.isDebug = 1;
7847               sprintf (buffer, "C$%s$%d$%d$%d",
7848                         FileBaseName (ic->filename), ic->lineno,
7849                         ic->level, ic->block);
7850               emit2 ("%s !equ .", buffer);
7851               emit2 ("!global", buffer);
7852               _G.lines.isDebug = 0;
7853             }
7854           if (!options.noCcodeInAsm) {
7855             emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7856                    printCLine(ic->filename, ic->lineno));
7857           }
7858           cln = ic->lineno;
7859         }
7860       if (options.iCodeInAsm) {
7861         emit2 (";ic:%d: %s", ic->key, printILine(ic));
7862       }
7863       /* if the result is marked as
7864          spilt and rematerializable or code for
7865          this has already been generated then
7866          do nothing */
7867       if (resultRemat (ic) || ic->generated)
7868         continue;
7869
7870       /* depending on the operation */
7871       switch (ic->op)
7872         {
7873         case '!':
7874           emitDebug ("; genNot");
7875           genNot (ic);
7876           break;
7877
7878         case '~':
7879           emitDebug ("; genCpl");
7880           genCpl (ic);
7881           break;
7882
7883         case UNARYMINUS:
7884           emitDebug ("; genUminus");
7885           genUminus (ic);
7886           break;
7887
7888         case IPUSH:
7889           emitDebug ("; genIpush");
7890           genIpush (ic);
7891           break;
7892
7893         case IPOP:
7894           /* IPOP happens only when trying to restore a
7895              spilt live range, if there is an ifx statement
7896              following this pop then the if statement might
7897              be using some of the registers being popped which
7898              would destory the contents of the register so
7899              we need to check for this condition and handle it */
7900           if (ic->next &&
7901               ic->next->op == IFX &&
7902               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7903             {
7904               emitDebug ("; genIfx");
7905               genIfx (ic->next, ic);
7906             }
7907           else
7908             {
7909               emitDebug ("; genIpop");
7910               genIpop (ic);
7911             }
7912           break;
7913
7914         case CALL:
7915           emitDebug ("; genCall");
7916           genCall (ic);
7917           break;
7918
7919         case PCALL:
7920           emitDebug ("; genPcall");
7921           genPcall (ic);
7922           break;
7923
7924         case FUNCTION:
7925           emitDebug ("; genFunction");
7926           genFunction (ic);
7927           break;
7928
7929         case ENDFUNCTION:
7930           emitDebug ("; genEndFunction");
7931           genEndFunction (ic);
7932           break;
7933
7934         case RETURN:
7935           emitDebug ("; genRet");
7936           genRet (ic);
7937           break;
7938
7939         case LABEL:
7940           emitDebug ("; genLabel");
7941           genLabel (ic);
7942           break;
7943
7944         case GOTO:
7945           emitDebug ("; genGoto");
7946           genGoto (ic);
7947           break;
7948
7949         case '+':
7950           emitDebug ("; genPlus");
7951           genPlus (ic);
7952           break;
7953
7954         case '-':
7955           emitDebug ("; genMinus");
7956           genMinus (ic);
7957           break;
7958
7959         case '*':
7960           emitDebug ("; genMult");
7961           genMult (ic);
7962           break;
7963
7964         case '/':
7965           emitDebug ("; genDiv");
7966           genDiv (ic);
7967           break;
7968
7969         case '%':
7970           emitDebug ("; genMod");
7971           genMod (ic);
7972           break;
7973
7974         case '>':
7975           emitDebug ("; genCmpGt");
7976           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7977           break;
7978
7979         case '<':
7980           emitDebug ("; genCmpLt");
7981           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7982           break;
7983
7984         case LE_OP:
7985         case GE_OP:
7986         case NE_OP:
7987
7988           /* note these two are xlated by algebraic equivalence
7989              during parsing SDCC.y */
7990           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7991                   "got '>=' or '<=' shouldn't have come here");
7992           break;
7993
7994         case EQ_OP:
7995           emitDebug ("; genCmpEq");
7996           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7997           break;
7998
7999         case AND_OP:
8000           emitDebug ("; genAndOp");
8001           genAndOp (ic);
8002           break;
8003
8004         case OR_OP:
8005           emitDebug ("; genOrOp");
8006           genOrOp (ic);
8007           break;
8008
8009         case '^':
8010           emitDebug ("; genXor");
8011           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
8012           break;
8013
8014         case '|':
8015           emitDebug ("; genOr");
8016           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
8017           break;
8018
8019         case BITWISEAND:
8020           emitDebug ("; genAnd");
8021           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
8022           break;
8023
8024         case INLINEASM:
8025           emitDebug ("; genInline");
8026           genInline (ic);
8027           break;
8028
8029         case RRC:
8030           emitDebug ("; genRRC");
8031           genRRC (ic);
8032           break;
8033
8034         case RLC:
8035           emitDebug ("; genRLC");
8036           genRLC (ic);
8037           break;
8038
8039         case GETHBIT:
8040           emitDebug ("; genGetHBIT");
8041           genGetHbit (ic);
8042           break;
8043
8044         case LEFT_OP:
8045           emitDebug ("; genLeftShift");
8046           genLeftShift (ic);
8047           break;
8048
8049         case RIGHT_OP:
8050           emitDebug ("; genRightShift");
8051           genRightShift (ic);
8052           break;
8053
8054         case GET_VALUE_AT_ADDRESS:
8055           emitDebug ("; genPointerGet");
8056           genPointerGet (ic);
8057           break;
8058
8059         case '=':
8060
8061           if (POINTER_SET (ic))
8062             {
8063               emitDebug ("; genAssign (pointer)");
8064               genPointerSet (ic);
8065             }
8066           else
8067             {
8068               emitDebug ("; genAssign");
8069               genAssign (ic);
8070             }
8071           break;
8072
8073         case IFX:
8074           emitDebug ("; genIfx");
8075           genIfx (ic, NULL);
8076           break;
8077
8078         case ADDRESS_OF:
8079           emitDebug ("; genAddrOf");
8080           genAddrOf (ic);
8081           break;
8082
8083         case JUMPTABLE:
8084           emitDebug ("; genJumpTab");
8085           genJumpTab (ic);
8086           break;
8087
8088         case CAST:
8089           emitDebug ("; genCast");
8090           genCast (ic);
8091           break;
8092
8093         case RECEIVE:
8094           emitDebug ("; genReceive");
8095           genReceive (ic);
8096           break;
8097
8098         case SEND:
8099           if (ic->builtinSEND)
8100             {
8101               emitDebug ("; genBuiltIn");
8102               genBuiltIn(ic);
8103             }
8104           else
8105             {
8106               emitDebug ("; addSet");
8107               addSet (&_G.sendSet, ic);
8108             }
8109           break;
8110
8111         case ARRAYINIT:
8112           emitDebug ("; genArrayInit");
8113           genArrayInit(ic);
8114           break;
8115
8116         case DUMMY_READ_VOLATILE:
8117           emitDebug ("; genDummyRead");
8118           genDummyRead (ic);
8119           break;
8120
8121         default:
8122           ic = ic;
8123         }
8124     }
8125
8126
8127   /* now we are ready to call the
8128      peep hole optimizer */
8129   if (!options.nopeep)
8130     peepHole (&_G.lines.head);
8131
8132   /* This is unfortunate */
8133   /* now do the actual printing */
8134   {
8135     FILE *fp = codeOutFile;
8136     if (isInHome () && codeOutFile == code->oFile)
8137       codeOutFile = home->oFile;
8138     printLine (_G.lines.head, codeOutFile);
8139     if (_G.flushStatics)
8140       {
8141         flushStatics ();
8142         _G.flushStatics = 0;
8143       }
8144     codeOutFile = fp;
8145   }
8146
8147   freeTrace(&_G.lines.trace);
8148   freeTrace(&_G.trace.aops);
8149 }
8150
8151 /*
8152   Attic
8153 static int
8154 _isPairUsed (iCode * ic, PAIR_ID pairId)
8155 {
8156   int ret = 0;
8157   switch (pairId)
8158     {
8159     case PAIR_DE:
8160       if (bitVectBitValue (ic->rMask, D_IDX))
8161         ret++;
8162       if (bitVectBitValue (ic->rMask, E_IDX))
8163         ret++;
8164       break;
8165     default:
8166       wassert (0);
8167     }
8168   return ret;
8169 }
8170
8171 static char *
8172 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8173 {
8174   unsigned long v;
8175   value *val = aop->aopu.aop_lit;
8176
8177   wassert (aop->type == AOP_LIT);
8178   wassert (!IS_FLOAT (val->type));
8179
8180   v = (unsigned long) floatFromVal (val);
8181
8182   if (xor)
8183     v ^= 0x8000;
8184   if (negate)
8185     v = 0-v;
8186   v &= 0xFFFF;
8187
8188   tsprintf (buffer, sizeof(buffer), "!immedword", v);
8189   return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
8190 }
8191
8192
8193 */