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